Skip to content

Commit 1aeed38

Browse files
authored
DB2 dialect enhancements
* Add schema update capability * Fix generating parameter names * Register bit operations * Fix substring function registration * Fix current_timestamp function registration * Fix round function registration * Fix Timestamp resolution in ticks * Fix DbType.Guid type registration * Fix DbType.Byte handling
1 parent bd761ff commit 1aeed38

File tree

5 files changed

+162
-9
lines changed

5 files changed

+162
-9
lines changed

src/NHibernate.Test/DialectTest/FunctionTests/SubstringSupportFixture.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,10 @@ public void DialectShouldUseCorrectSubstringImplementation(System.Type dialectTy
4141
case SybaseASE15Dialect _:
4242
Assert.That(substringFunction, Is.TypeOf<EmulatedLengthSubstringFunction>());
4343
break;
44-
case DB2Dialect _:
45-
Assert.That(substringFunction, Is.TypeOf<SQLFunctionTemplate>());
46-
break;
4744
case SybaseSQLAnywhere10Dialect _:
4845
Assert.That(substringFunction, Is.TypeOf<VarArgsSQLFunction>());
4946
break;
47+
case DB2Dialect _:
5048
case Oracle8iDialect _:
5149
case SQLiteDialect _:
5250
case HanaDialectBase _:
@@ -56,7 +54,6 @@ public void DialectShouldUseCorrectSubstringImplementation(System.Type dialectTy
5654
Assert.That(substringFunction, Is.TypeOf<AnsiSubstringFunction>());
5755
break;
5856
}
59-
6057
}
6158
}
6259
}

src/NHibernate/Dialect/DB2Dialect.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
using System.Data;
2+
using System.Data.Common;
23
using System.Text;
34
using NHibernate.Cfg;
45
using NHibernate.Dialect.Function;
6+
using NHibernate.Dialect.Schema;
57
using NHibernate.SqlCommand;
68

79
namespace NHibernate.Dialect
@@ -53,6 +55,7 @@ public DB2Dialect()
5355
RegisterColumnType(DbType.String, 8000, "VARCHAR($l)");
5456
RegisterColumnType(DbType.String, 2147483647, "CLOB");
5557
RegisterColumnType(DbType.Time, "TIME");
58+
RegisterColumnType(DbType.Guid, "CHAR(16) FOR BIT DATA");
5659

5760
RegisterFunction("abs", new StandardSQLFunction("abs"));
5861
RegisterFunction("absval", new StandardSQLFunction("absval"));
@@ -61,7 +64,7 @@ public DB2Dialect()
6164
RegisterFunction("ceiling", new StandardSQLFunction("ceiling"));
6265
RegisterFunction("ceil", new StandardSQLFunction("ceil"));
6366
RegisterFunction("floor", new StandardSQLFunction("floor"));
64-
RegisterFunction("round", new StandardSQLFunction("round"));
67+
RegisterFunction("round", new StandardSQLFunctionWithRequiredParameters("round", new object[] { null, "0" }));
6568

6669
RegisterFunction("acos", new StandardSQLFunction("acos", NHibernateUtil.Double));
6770
RegisterFunction("asin", new StandardSQLFunction("asin", NHibernateUtil.Double));
@@ -127,8 +130,15 @@ public DB2Dialect()
127130

128131
RegisterFunction("mod", new StandardSQLFunction("mod", NHibernateUtil.Int32));
129132

130-
// DB2 does not support ANSI substring syntax.
131-
RegisterFunction("substring", new SQLFunctionTemplate(NHibernateUtil.String, "substring(?1, ?2, ?3)"));
133+
RegisterFunction("substring", new StandardSQLFunction("substr", NHibernateUtil.String));
134+
135+
// Bitwise operations
136+
RegisterFunction("band", new Function.BitwiseFunctionOperation("bitand"));
137+
RegisterFunction("bor", new Function.BitwiseFunctionOperation("bitor"));
138+
RegisterFunction("bxor", new Function.BitwiseFunctionOperation("bitxor"));
139+
RegisterFunction("bnot", new Function.BitwiseFunctionOperation("bitnot"));
140+
141+
RegisterFunction("current_timestamp", new NoArgSQLFunction("current_timestamp", NHibernateUtil.DateTime, false));
132142

133143
DefaultProperties[Environment.ConnectionDriver] = "NHibernate.Driver.DB2Driver";
134144
}
@@ -193,6 +203,11 @@ public override string GetDropSequenceString(string sequenceName)
193203
return string.Concat("drop sequence ", sequenceName, " restrict");
194204
}
195205

206+
public override IDataBaseSchema GetDataBaseSchema(DbConnection connection)
207+
{
208+
return new DB2MetaData(connection);
209+
}
210+
196211
/// <summary></summary>
197212
public override bool SupportsSequences
198213
{
@@ -278,6 +293,8 @@ public override string ForUpdateString
278293
/// <inheritdoc />
279294
public override int MaxAliasLength => 32;
280295

296+
public override long TimestampResolutionInTicks => 10L; // Microseconds.
297+
281298
#region Overridden informational metadata
282299

283300
public override bool SupportsEmptyInList => false;
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data;
4+
using System.Data.Common;
5+
6+
namespace NHibernate.Dialect.Schema
7+
{
8+
public class DB2MetaData : AbstractDataBaseSchema
9+
{
10+
public DB2MetaData(DbConnection connection) : base(connection)
11+
{
12+
}
13+
14+
public override ITableMetadata GetTableMetadata(DataRow rs, bool extras)
15+
{
16+
return new DB2TableMetaData(rs, this, extras);
17+
}
18+
19+
public override DataTable GetIndexColumns(string catalog, string schemaPattern, string tableName, string indexName)
20+
{
21+
var restrictions = new[] {tableName, indexName};
22+
return Connection.GetSchema("Indexes", restrictions);
23+
}
24+
25+
public override ISet<string> GetReservedWords()
26+
{
27+
var result = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
28+
var dtReservedWords = Connection.GetSchema(DbMetaDataCollectionNames.ReservedWords);
29+
foreach (DataRow row in dtReservedWords.Rows)
30+
{
31+
result.Add(row["ReservedWord"].ToString());
32+
}
33+
34+
if (IncludeDataTypesInReservedWords)
35+
{
36+
var dtTypes = Connection.GetSchema(DbMetaDataCollectionNames.DataTypes);
37+
foreach (DataRow row in dtTypes.Rows)
38+
{
39+
result.Add(row["SQL_TYPE_NAME"].ToString());
40+
}
41+
}
42+
43+
return result;
44+
}
45+
}
46+
47+
public class DB2TableMetaData : AbstractTableMetadata
48+
{
49+
public DB2TableMetaData(DataRow rs, IDataBaseSchema meta, bool extras) : base(rs, meta, extras)
50+
{
51+
}
52+
53+
protected override IColumnMetadata GetColumnMetadata(DataRow rs)
54+
{
55+
return new DB2ColumnMetaData(rs);
56+
}
57+
58+
protected override string GetColumnName(DataRow rs)
59+
{
60+
return Convert.ToString(rs["COLUMN_NAME"]);
61+
}
62+
63+
protected override string GetConstraintName(DataRow rs)
64+
{
65+
return Convert.ToString(rs["FK_NAME"]);
66+
}
67+
68+
protected override IForeignKeyMetadata GetForeignKeyMetadata(DataRow rs)
69+
{
70+
return new DB2ForeignKeyMetaData(rs);
71+
}
72+
73+
protected override IIndexMetadata GetIndexMetadata(DataRow rs)
74+
{
75+
return new DB2IndexMetaData(rs);
76+
}
77+
78+
protected override string GetIndexName(DataRow rs)
79+
{
80+
return Convert.ToString(rs["INDEX_NAME"]);
81+
}
82+
83+
protected override void ParseTableInfo(DataRow rs)
84+
{
85+
Catalog = Convert.ToString(rs["TABLE_CATALOG"]);
86+
Schema = Convert.ToString(rs["TABLE_SCHEMA"]);
87+
if (string.IsNullOrEmpty(Catalog)) Catalog = null;
88+
if (string.IsNullOrEmpty(Schema)) Schema = null;
89+
Name = Convert.ToString(rs["TABLE_NAME"]);
90+
}
91+
}
92+
93+
public class DB2ColumnMetaData : AbstractColumnMetaData
94+
{
95+
public DB2ColumnMetaData(DataRow rs) : base(rs)
96+
{
97+
Name = Convert.ToString(rs["COLUMN_NAME"]);
98+
Nullable = Convert.ToString(rs["IS_NULLABLE"]);
99+
TypeName = Convert.ToString(rs["DATA_TYPE_NAME"]);
100+
}
101+
}
102+
103+
public class DB2IndexMetaData : AbstractIndexMetadata
104+
{
105+
public DB2IndexMetaData(DataRow rs) : base(rs)
106+
{
107+
Name = Convert.ToString(rs["INDEX_NAME"]);
108+
}
109+
}
110+
111+
public class DB2ForeignKeyMetaData : AbstractForeignKeyMetadata
112+
{
113+
public DB2ForeignKeyMetaData(DataRow rs) : base(rs)
114+
{
115+
Name = Convert.ToString(rs["FK_NAME"]);
116+
}
117+
}
118+
}

src/NHibernate/Driver/DB2DriverBase.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
using System;
2+
using System.Data;
3+
using System.Data.Common;
14
using NHibernate.Engine;
5+
using NHibernate.SqlTypes;
26

37
namespace NHibernate.Driver
48
{
@@ -41,5 +45,21 @@ public override IResultSetsCommand GetResultSetsCommand(ISessionImplementor sess
4145
{
4246
return new BasicResultSetsCommand(session);
4347
}
48+
49+
protected override void InitializeParameter(DbParameter dbParam, string name, SqlType sqlType)
50+
{
51+
switch (sqlType.DbType)
52+
{
53+
case DbType.Guid:
54+
dbParam.DbType = DbType.Binary;
55+
break;
56+
case DbType.Byte:
57+
dbParam.DbType = DbType.Int16;
58+
break;
59+
default:
60+
dbParam.DbType = sqlType.DbType;
61+
break;
62+
}
63+
}
4464
}
4565
}

src/NHibernate/Type/ByteType.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ public override System.Type PrimitiveClass
4343

4444
public override void Set(DbCommand cmd, object value, int index, ISessionImplementor session)
4545
{
46-
cmd.Parameters[index].Value = Convert.ToByte(value);
47-
}
46+
var dp = cmd.Parameters[index];
47+
dp.Value = dp.DbType == DbType.Int16 ? Convert.ToInt16(value) : Convert.ToByte(value);
4848

49+
}
4950
public override string Name
5051
{
5152
get { return "Byte"; }

0 commit comments

Comments
 (0)