From e08bcd7dcc1f54c78b0250d0695fffbd8a357495 Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Sun, 10 Jun 2018 20:32:02 +1200 Subject: [PATCH 1/9] Add schema update capability --- src/NHibernate/Dialect/DB2Dialect.cs | 7 ++ src/NHibernate/Dialect/Schema/DB2MetaData.cs | 118 +++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/NHibernate/Dialect/Schema/DB2MetaData.cs diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index 89f6c305fdc..533616e9f70 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -1,7 +1,9 @@ using System.Data; +using System.Data.Common; using System.Text; using NHibernate.Cfg; using NHibernate.Dialect.Function; +using NHibernate.Dialect.Schema; using NHibernate.SqlCommand; namespace NHibernate.Dialect @@ -193,6 +195,11 @@ public override string GetDropSequenceString(string sequenceName) return string.Concat("drop sequence ", sequenceName, " restrict"); } + public override IDataBaseSchema GetDataBaseSchema(DbConnection connection) + { + return new DB2MetaData(connection); + } + /// public override bool SupportsSequences { diff --git a/src/NHibernate/Dialect/Schema/DB2MetaData.cs b/src/NHibernate/Dialect/Schema/DB2MetaData.cs new file mode 100644 index 00000000000..fd02b4aec5b --- /dev/null +++ b/src/NHibernate/Dialect/Schema/DB2MetaData.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +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 override ISet GetReservedWords() + { + var result = new HashSet(StringComparer.OrdinalIgnoreCase); + var dtReservedWords = Connection.GetSchema(DbMetaDataCollectionNames.ReservedWords); + foreach (DataRow row in dtReservedWords.Rows) + { + result.Add(row["ReservedWord"].ToString()); + } + + if (IncludeDataTypesInReservedWords) + { + var dtTypes = Connection.GetSchema(DbMetaDataCollectionNames.DataTypes); + foreach (DataRow row in dtTypes.Rows) + { + result.Add(row["SQL_TYPE_NAME"].ToString()); + } + } + + return result; + } + } + + 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) + { + return Convert.ToString(rs["FK_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_NAME"]); + } + } + + 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["FK_NAME"]); + } + } +} From 74904ffba9748d25c88a82bc91cbb0dc2d1185aa Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Sun, 10 Jun 2018 20:45:03 +1200 Subject: [PATCH 2/9] Fix generating parameter names --- src/NHibernate/Driver/DB2DriverBase.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/NHibernate/Driver/DB2DriverBase.cs b/src/NHibernate/Driver/DB2DriverBase.cs index cc92fbfc2e2..0040ae88b33 100644 --- a/src/NHibernate/Driver/DB2DriverBase.cs +++ b/src/NHibernate/Driver/DB2DriverBase.cs @@ -1,3 +1,6 @@ +using System; +using System.Data; +using System.Data.Common; using NHibernate.Engine; namespace NHibernate.Driver @@ -41,5 +44,10 @@ public override IResultSetsCommand GetResultSetsCommand(ISessionImplementor sess { return new BasicResultSetsCommand(session); } + + protected override void InitializeParameter(DbParameter dbParam, string name, SqlType sqlType) + { + dbParam.DbType = sqlType.DbType; + } } } From 3b0f904d3c1c89234bba698f2141805e9af29544 Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Sun, 10 Jun 2018 20:54:20 +1200 Subject: [PATCH 3/9] Register bit operations --- src/NHibernate/Dialect/DB2Dialect.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index 533616e9f70..32ef997b860 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -131,6 +131,12 @@ public DB2Dialect() // DB2 does not support ANSI substring syntax. RegisterFunction("substring", new SQLFunctionTemplate(NHibernateUtil.String, "substring(?1, ?2, ?3)")); + + // Bitwise operations + RegisterFunction("band", new Function.BitwiseFunctionOperation("bitand")); + RegisterFunction("bor", new Function.BitwiseFunctionOperation("bitor")); + RegisterFunction("bxor", new Function.BitwiseFunctionOperation("bitxor")); + RegisterFunction("bnot", new Function.BitwiseFunctionOperation("bitnot")); DefaultProperties[Environment.ConnectionDriver] = "NHibernate.Driver.DB2Driver"; } From 661cd0f69918dc0dc072752ddcced86f79bea023 Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Sun, 5 Aug 2018 23:26:33 +1200 Subject: [PATCH 4/9] Fix substring function registration --- .../DialectTest/FunctionTests/SubstringSupportFixture.cs | 5 +---- src/NHibernate/Dialect/DB2Dialect.cs | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/NHibernate.Test/DialectTest/FunctionTests/SubstringSupportFixture.cs b/src/NHibernate.Test/DialectTest/FunctionTests/SubstringSupportFixture.cs index 8644493b502..d80744439e2 100644 --- a/src/NHibernate.Test/DialectTest/FunctionTests/SubstringSupportFixture.cs +++ b/src/NHibernate.Test/DialectTest/FunctionTests/SubstringSupportFixture.cs @@ -41,12 +41,10 @@ public void DialectShouldUseCorrectSubstringImplementation(System.Type dialectTy case SybaseASE15Dialect _: Assert.That(substringFunction, Is.TypeOf()); break; - case DB2Dialect _: - Assert.That(substringFunction, Is.TypeOf()); - break; case SybaseSQLAnywhere10Dialect _: Assert.That(substringFunction, Is.TypeOf()); break; + case DB2Dialect _: case Oracle8iDialect _: case SQLiteDialect _: case HanaDialectBase _: @@ -56,7 +54,6 @@ public void DialectShouldUseCorrectSubstringImplementation(System.Type dialectTy Assert.That(substringFunction, Is.TypeOf()); break; } - } } } diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index 32ef997b860..724cd786073 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -129,9 +129,8 @@ public DB2Dialect() RegisterFunction("mod", new StandardSQLFunction("mod", NHibernateUtil.Int32)); - // DB2 does not support ANSI substring syntax. - RegisterFunction("substring", new SQLFunctionTemplate(NHibernateUtil.String, "substring(?1, ?2, ?3)")); - + RegisterFunction("substring", new StandardSQLFunction("substr", NHibernateUtil.String)); + // Bitwise operations RegisterFunction("band", new Function.BitwiseFunctionOperation("bitand")); RegisterFunction("bor", new Function.BitwiseFunctionOperation("bitor")); From a634fe690e2d50a4a46a99e8a9ddbc85392f0740 Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Sun, 5 Aug 2018 23:53:35 +1200 Subject: [PATCH 5/9] Fix current_timestamp function registration --- src/NHibernate/Dialect/DB2Dialect.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index 724cd786073..c260d1e7258 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -137,6 +137,8 @@ public DB2Dialect() RegisterFunction("bxor", new Function.BitwiseFunctionOperation("bitxor")); RegisterFunction("bnot", new Function.BitwiseFunctionOperation("bitnot")); + RegisterFunction("current_timestamp", new NoArgSQLFunction("current_timestamp", NHibernateUtil.DateTime, false)); + DefaultProperties[Environment.ConnectionDriver] = "NHibernate.Driver.DB2Driver"; } From 6b780b37e48f64784707e55a6f46f018b75805ee Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Mon, 6 Aug 2018 00:06:12 +1200 Subject: [PATCH 6/9] Fix round function registration --- src/NHibernate/Dialect/DB2Dialect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index c260d1e7258..0b53060f35d 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -63,7 +63,7 @@ public DB2Dialect() RegisterFunction("ceiling", new StandardSQLFunction("ceiling")); RegisterFunction("ceil", new StandardSQLFunction("ceil")); RegisterFunction("floor", new StandardSQLFunction("floor")); - RegisterFunction("round", new StandardSQLFunction("round")); + RegisterFunction("round", new StandardSQLFunctionWithRequiredParameters("round", new object[] { null, "0" })); RegisterFunction("acos", new StandardSQLFunction("acos", NHibernateUtil.Double)); RegisterFunction("asin", new StandardSQLFunction("asin", NHibernateUtil.Double)); From 8675d2dce3046f75249d5f5154c6fa7688d753c8 Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Fri, 15 Mar 2019 12:14:31 +1300 Subject: [PATCH 7/9] Fix Timestamp resolution in ticks --- src/NHibernate/Dialect/DB2Dialect.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index 0b53060f35d..283197f9c51 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -292,6 +292,8 @@ public override string ForUpdateString /// public override int MaxAliasLength => 32; + public override long TimestampResolutionInTicks => 10L; // Microseconds. + #region Overridden informational metadata public override bool SupportsEmptyInList => false; From ab0148f1a62fec2eaf1317feb41b21b33eb252aa Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Fri, 15 Mar 2019 12:18:09 +1300 Subject: [PATCH 8/9] Fix DbType.Guid type registration --- src/NHibernate/Dialect/DB2Dialect.cs | 1 + src/NHibernate/Driver/DB2DriverBase.cs | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/NHibernate/Dialect/DB2Dialect.cs b/src/NHibernate/Dialect/DB2Dialect.cs index 283197f9c51..9a830de2c4e 100644 --- a/src/NHibernate/Dialect/DB2Dialect.cs +++ b/src/NHibernate/Dialect/DB2Dialect.cs @@ -55,6 +55,7 @@ public DB2Dialect() RegisterColumnType(DbType.String, 8000, "VARCHAR($l)"); RegisterColumnType(DbType.String, 2147483647, "CLOB"); RegisterColumnType(DbType.Time, "TIME"); + RegisterColumnType(DbType.Guid, "CHAR(16) FOR BIT DATA"); RegisterFunction("abs", new StandardSQLFunction("abs")); RegisterFunction("absval", new StandardSQLFunction("absval")); diff --git a/src/NHibernate/Driver/DB2DriverBase.cs b/src/NHibernate/Driver/DB2DriverBase.cs index 0040ae88b33..bc3127230f5 100644 --- a/src/NHibernate/Driver/DB2DriverBase.cs +++ b/src/NHibernate/Driver/DB2DriverBase.cs @@ -2,6 +2,7 @@ using System.Data; using System.Data.Common; using NHibernate.Engine; +using NHibernate.SqlTypes; namespace NHibernate.Driver { @@ -47,7 +48,15 @@ public override IResultSetsCommand GetResultSetsCommand(ISessionImplementor sess protected override void InitializeParameter(DbParameter dbParam, string name, SqlType sqlType) { - dbParam.DbType = sqlType.DbType; + switch (sqlType.DbType) + { + case DbType.Guid: + dbParam.DbType = DbType.Binary; + break; + default: + dbParam.DbType = sqlType.DbType; + break; + } } } } From 3edcb5d656c8917df4adad75a8f1388b2e36e13d Mon Sep 17 00:00:00 2001 From: Alexander Zaytsev Date: Mon, 18 Mar 2019 22:13:31 +1300 Subject: [PATCH 9/9] Fix DbType.Byte handling --- src/NHibernate/Driver/DB2DriverBase.cs | 3 +++ src/NHibernate/Type/ByteType.cs | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/NHibernate/Driver/DB2DriverBase.cs b/src/NHibernate/Driver/DB2DriverBase.cs index bc3127230f5..b7ea3f00208 100644 --- a/src/NHibernate/Driver/DB2DriverBase.cs +++ b/src/NHibernate/Driver/DB2DriverBase.cs @@ -53,6 +53,9 @@ protected override void InitializeParameter(DbParameter dbParam, string name, Sq case DbType.Guid: dbParam.DbType = DbType.Binary; break; + case DbType.Byte: + dbParam.DbType = DbType.Int16; + break; default: dbParam.DbType = sqlType.DbType; break; diff --git a/src/NHibernate/Type/ByteType.cs b/src/NHibernate/Type/ByteType.cs index 36e57aba713..6c77d87325a 100644 --- a/src/NHibernate/Type/ByteType.cs +++ b/src/NHibernate/Type/ByteType.cs @@ -43,9 +43,10 @@ public override System.Type PrimitiveClass public override void Set(DbCommand cmd, object value, int index, ISessionImplementor session) { - cmd.Parameters[index].Value = Convert.ToByte(value); - } + var dp = cmd.Parameters[index]; + dp.Value = dp.DbType == DbType.Int16 ? Convert.ToInt16(value) : Convert.ToByte(value); + } public override string Name { get { return "Byte"; }