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 89f6c305fdc..9a830de2c4e 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 @@ -53,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")); @@ -61,7 +64,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)); @@ -127,8 +130,15 @@ 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")); + 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"; } @@ -193,6 +203,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 { @@ -278,6 +293,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; 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"]); + } + } +} diff --git a/src/NHibernate/Driver/DB2DriverBase.cs b/src/NHibernate/Driver/DB2DriverBase.cs index cc92fbfc2e2..b7ea3f00208 100644 --- a/src/NHibernate/Driver/DB2DriverBase.cs +++ b/src/NHibernate/Driver/DB2DriverBase.cs @@ -1,4 +1,8 @@ +using System; +using System.Data; +using System.Data.Common; using NHibernate.Engine; +using NHibernate.SqlTypes; namespace NHibernate.Driver { @@ -41,5 +45,21 @@ public override IResultSetsCommand GetResultSetsCommand(ISessionImplementor sess { return new BasicResultSetsCommand(session); } + + protected override void InitializeParameter(DbParameter dbParam, string name, SqlType sqlType) + { + switch (sqlType.DbType) + { + 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"; }