From 85e191c0a15dc569ba453c7f69c2584af5b3bb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20K=C3=B6bel?= Date: Wed, 18 May 2016 09:24:52 +0200 Subject: [PATCH] Added compatibility for db2 schema update. --- src/NHibernate/Dialect/DB2Dialect.cs | 66 +++++++++++- src/NHibernate/Dialect/Schema/DB2MetaData.cs | 103 +++++++++++++++++++ src/NHibernate/Driver/DB2Driver.cs | 22 ++++ src/NHibernate/NHibernate.csproj | 8 +- src/NHibernate/NHibernateUtil.cs | 5 + src/NHibernate/Type/IntBooleanType.cs | 74 +++++++++++++ src/NHibernate/Type/TypeFactory.cs | 3 +- 7 files changed, 276 insertions(+), 5 deletions(-) create mode 100644 src/NHibernate/Dialect/Schema/DB2MetaData.cs create mode 100644 src/NHibernate/Type/IntBooleanType.cs diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index 5dd78d65360..b866805cf62 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -1,8 +1,12 @@ +using System; using System.Data; +using System.Data.Common; using System.Text; -using NHibernate.Cfg; using NHibernate.Dialect.Function; using NHibernate.SqlCommand; +using NHibernate.Type; +using NHibernate.Util; +using Environment = NHibernate.Cfg.Environment; namespace NHibernate.Dialect { @@ -27,6 +31,8 @@ public class DB2Dialect : Dialect /// public DB2Dialect() { + TypeFactory.RegisterType(typeof(Boolean), NHibernateUtil.IntBoolean, new[] { "boolean", "bool" }); + RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(254)"); RegisterColumnType(DbType.AnsiStringFixedLength, 254, "CHAR($l)"); RegisterColumnType(DbType.AnsiString, "VARCHAR(254)"); @@ -128,6 +134,12 @@ public DB2Dialect() RegisterFunction("substring", new SQLFunctionTemplate(NHibernateUtil.String, "substring(?1, ?2, ?3)")); DefaultProperties[Environment.ConnectionDriver] = "NHibernate.Driver.DB2Driver"; + DefaultProperties[Environment.QuerySubstitutions] = "true 1, false 0, yes 1, no 0"; + } + + public override Schema.IDataBaseSchema GetDataBaseSchema(DbConnection connection) + { + return new Schema.DB2MetaData(connection); } /// @@ -270,5 +282,57 @@ public override string ForUpdateString { get { return " for read only with rs"; } } + + public override string Qualify(string catalog, string schema, string table) + { + StringBuilder qualifiedName = new StringBuilder(); + bool quoted = false; + + if (!string.IsNullOrEmpty(catalog)) + { + if (catalog.StartsWith(OpenQuote.ToString())) + { + catalog = catalog.Substring(1, catalog.Length - 1); + quoted = true; + } + if (catalog.EndsWith(CloseQuote.ToString())) + { + catalog = catalog.Substring(0, catalog.Length - 1); + quoted = true; + } + qualifiedName.Append(catalog).Append(StringHelper.Underscore); + } + if (!string.IsNullOrEmpty(schema)) + { + if (schema.StartsWith(OpenQuote.ToString())) + { + schema = schema.Substring(1, schema.Length - 1); + quoted = true; + } + if (schema.EndsWith(CloseQuote.ToString())) + { + schema = schema.Substring(0, schema.Length - 1); + quoted = true; + } + qualifiedName.Append(schema).Append(StringHelper.Underscore); + } + + if (table.StartsWith(OpenQuote.ToString())) + { + table = table.Substring(1, table.Length - 1); + quoted = true; + } + if (table.EndsWith(CloseQuote.ToString())) + { + table = table.Substring(0, table.Length - 1); + quoted = true; + } + + string name = qualifiedName.Append(table).ToString(); + if (quoted) + return OpenQuote + name + CloseQuote; + return name; + + } } } \ No newline at end of file diff --git a/src/NHibernate/Dialect/Schema/DB2MetaData.cs b/src/NHibernate/Dialect/Schema/DB2MetaData.cs new file mode 100644 index 00000000000..cc99be675a4 --- /dev/null +++ b/src/NHibernate/Dialect/Schema/DB2MetaData.cs @@ -0,0 +1,103 @@ +using System; +using System.Data; +using System.Data.Common; + +namespace NHibernate.Dialect.Schema +{ + public class DB2MetaData : AbstractDataBaseSchema + { + public DB2MetaData(DbConnection connection) : base(connection) + { + } + + public override ITableMetadata GetTableMetadata(DataRow rs, bool extras) + { + return new DB2TableMetaData(rs, this, extras); + } + + public override DataTable GetIndexColumns(string catalog, string schemaPattern, string tableName, string indexName) + { + var restrictions = new[] { tableName, indexName}; + return Connection.GetSchema("Indexes", restrictions); + } + } + + public class DB2TableMetaData : AbstractTableMetadata + { + public DB2TableMetaData(DataRow rs, IDataBaseSchema meta, bool extras) : base(rs, meta, extras) {} + + protected override IColumnMetadata GetColumnMetadata(DataRow rs) + { + return new DB2ColumnMetaData(rs); + } + + protected override string GetColumnName(DataRow rs) + { + return Convert.ToString(rs["COLUMN_NAME"]); + } + + protected override string GetConstraintName(DataRow rs) + { + //TODO validate + return Convert.ToString(rs[11]); + //return Convert.ToString(rs["CONSTRAINT_NAME"]); + } + + protected override IForeignKeyMetadata GetForeignKeyMetadata(DataRow rs) + { + return new DB2ForeignKeyMetaData(rs); + } + + protected override IIndexMetadata GetIndexMetadata(DataRow rs) + { + return new DB2IndexMetaData(rs); + } + + protected override string GetIndexName(DataRow rs) + { + return Convert.ToString(rs["INDEX_NAME"]); + } + + protected override void ParseTableInfo(DataRow rs) + { + Catalog = Convert.ToString(rs["TABLE_CATALOG"]); + Schema = Convert.ToString(rs["TABLE_SCHEMA"]); + if (string.IsNullOrEmpty(Catalog)) + { + Catalog = null; + } + if (string.IsNullOrEmpty(Schema)) + { + Schema = null; + } + Name = Convert.ToString(rs["TABLE_NAME"]); + } + } + + public class DB2ColumnMetaData : AbstractColumnMetaData + { + public DB2ColumnMetaData(DataRow rs) : base(rs) + { + Name = Convert.ToString(rs["COLUMN_NAME"]); + + Nullable = Convert.ToString(rs["IS_NULLABLE"]); + TypeName = Convert.ToString(rs["DATA_TYPE"]); + } + } + + public class DB2IndexMetaData : AbstractIndexMetadata + { + public DB2IndexMetaData(DataRow rs) : base(rs) + { + Name = Convert.ToString(rs["INDEX_NAME"]); + } + } + + public class DB2ForeignKeyMetaData : AbstractForeignKeyMetadata + { + public DB2ForeignKeyMetaData(DataRow rs) : base(rs) + { + Name = Convert.ToString(rs[11]); + } + } +} \ No newline at end of file diff --git a/src/NHibernate/Driver/DB2Driver.cs b/src/NHibernate/Driver/DB2Driver.cs index 93c1b26bd1f..101556595b6 100644 --- a/src/NHibernate/Driver/DB2Driver.cs +++ b/src/NHibernate/Driver/DB2Driver.cs @@ -1,4 +1,12 @@ using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Text.RegularExpressions; +using NHibernate.Dialect; +using NHibernate.SqlCommand; +using NHibernate.SqlTypes; +using NHibernate.Util; namespace NHibernate.Driver { @@ -7,6 +15,8 @@ namespace NHibernate.Driver /// public class DB2Driver : ReflectionBasedDriver { + private readonly DB2Dialect _db2Dialect = new DB2Dialect(); + /// /// Initializes a new instance of the class. /// @@ -40,5 +50,17 @@ public override bool SupportsMultipleOpenReaders { get { return false; } } + + protected override void InitializeParameter(IDbDataParameter dbParam, string name, SqlType sqlType) + { + var convertedSqlType = sqlType; + + if (convertedSqlType.DbType == DbType.Boolean) + { + convertedSqlType = new SqlType(DbType.Int16); + } + + base.InitializeParameter(dbParam, name, convertedSqlType); + } } } \ No newline at end of file diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index 5d13cb4324b..07aad5417a9 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -89,9 +89,9 @@ - - SharedAssemblyInfo.cs - + + SharedAssemblyInfo.cs + @@ -164,6 +164,7 @@ + @@ -703,6 +704,7 @@ + diff --git a/src/NHibernate/NHibernateUtil.cs b/src/NHibernate/NHibernateUtil.cs index 72f74c6999b..1384ca63746 100644 --- a/src/NHibernate/NHibernateUtil.cs +++ b/src/NHibernate/NHibernateUtil.cs @@ -247,6 +247,11 @@ public static IType GuessType(System.Type type) /// public static readonly YesNoType YesNo = new YesNoType(); + /// + /// NHibernate IntBoolean type + /// + public static readonly IntBooleanType IntBoolean = new IntBooleanType(); + /// /// NHibernate class type /// diff --git a/src/NHibernate/Type/IntBooleanType.cs b/src/NHibernate/Type/IntBooleanType.cs new file mode 100644 index 00000000000..a7dec8f9aa6 --- /dev/null +++ b/src/NHibernate/Type/IntBooleanType.cs @@ -0,0 +1,74 @@ +using System.Data; +using NHibernate.SqlTypes; +using NHibernate.UserTypes; + +namespace NHibernate.Type +{ + public class IntBooleanType : BooleanType, IUserType + { + public override SqlType SqlType + { + get { return new SqlType(DbType.Int32);} + } + + public SqlType[] SqlTypes + { + get { return new SqlType[] { SqlType};} + } + + public System.Type ReturnedType + { + get { return typeof (bool); } + } + public bool Equals(object x, object y) + { + if (ReferenceEquals(x, y)) return true; + + if (x == null || y == null) return false; + + return x.Equals(y); + } + + public int GetHashCode(object x) + { + return x.GetHashCode(); + } + + public new void NullSafeSet(IDbCommand cmd, object value, int index) + { + var val = !((bool) value) ? 0 : 1; + NHibernateUtil.Int32.NullSafeSet(cmd, val, index); + } + + public override void Set(IDbCommand cmd, object value, int index) + { + var val = !((bool) value) ? 0 : 1; + ((IDataParameter) cmd.Parameters[index]).Value = val; + } + + public object NullSafeGet(IDataReader rs, string[] names, object owner) + { + return NHibernateUtil.Int32.NullSafeGet(rs, names[0]); + } + + public object DeepCopy(object value) + { + return value; + } + + public object Replace(object original, object target, object owner) + { + return original; + } + + public object Assemble(object cached, object owner) + { + return cached; + } + + public object Disassemble(object value) + { + return value; + } + } +} \ No newline at end of file diff --git a/src/NHibernate/Type/TypeFactory.cs b/src/NHibernate/Type/TypeFactory.cs index 84214dc31a6..66c238c36ce 100644 --- a/src/NHibernate/Type/TypeFactory.cs +++ b/src/NHibernate/Type/TypeFactory.cs @@ -75,7 +75,7 @@ private enum TypeClassification private delegate NullableType NullableTypeCreatorDelegate(SqlType sqlType); - private static void RegisterType(System.Type systemType, IType nhibernateType, IEnumerable aliases) + public static void RegisterType(System.Type systemType, IType nhibernateType, IEnumerable aliases) { var typeAliases = new List(aliases); typeAliases.AddRange(GetClrTypeAliases(systemType)); @@ -242,6 +242,7 @@ private static void RegisterBuiltInTypes() RegisterType(NHibernateUtil.Time, new[] { "time" }); RegisterType(NHibernateUtil.TrueFalse, new[] { "true_false" }); RegisterType(NHibernateUtil.YesNo, new[] { "yes_no" }); + RegisterType(NHibernateUtil.IntBoolean, new[] {"int_bool"}); RegisterType(NHibernateUtil.Ticks, new[] { "ticks" }); RegisterType(NHibernateUtil.TimeAsTimeSpan, EmptyAliases); RegisterType(NHibernateUtil.LocalDateTime, new[] { "localdatetime" });