Skip to content

Commit 4045925

Browse files
NH-4088 - Dialect.GetCastTypeName is buggy (#709)
* Fix TypeNames.Get for decimal capacity * Compare capacity against precision for precision based types * Fix dialects declarations for max precision * Fix dialects declarations for precision based types which were using length as precision or scale It is a prerequisite to the fix of GetTypeCastName. * Fix GetCastTypeName * Use type length/precision/scale when defined * Use maximal capacity types otherwise when it makes sens * Use configurable default length/precision/scale otherwise
1 parent c7845d8 commit 4045925

25 files changed

+535
-282
lines changed

src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs

+61
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
//------------------------------------------------------------------------------
99

1010

11+
using System;
1112
using System.Collections;
1213
using System.Collections.Generic;
14+
using System.Text.RegularExpressions;
1315
using NHibernate.Criterion;
1416
using NHibernate.Dialect;
17+
using NHibernate.SqlTypes;
18+
using NHibernate.Type;
1519
using NUnit.Framework;
1620

1721
namespace NHibernate.Test.Criteria
@@ -100,6 +104,63 @@ public async Task UsingSqlFunctions_Concat_WithCastAsync()
100104
}
101105
}
102106

107+
[Test]
108+
public async Task CastWithLengthAsync()
109+
{
110+
if (Regex.IsMatch(Dialect.GetCastTypeName(SqlTypeFactory.GetString(3)), @"^[^(]*$"))
111+
{
112+
Assert.Ignore($"Dialect {Dialect} does not seem to handle string length in cast");
113+
}
114+
115+
using (var s = OpenSession())
116+
{
117+
try
118+
{
119+
var shortName = await (s
120+
.CreateCriteria<Student>()
121+
.SetProjection(
122+
Projections.Cast(
123+
TypeFactory.GetStringType(3),
124+
Projections.Property("Name")))
125+
.UniqueResultAsync<string>());
126+
Assert.That(shortName, Is.EqualTo("aye"));
127+
}
128+
catch (Exception e)
129+
{
130+
if (e.InnerException == null || !e.InnerException.Message.Contains("truncation"))
131+
throw;
132+
}
133+
}
134+
}
135+
136+
[Test]
137+
public async Task CastWithPrecisionScaleAsync()
138+
{
139+
if (TestDialect.HasBrokenDecimalType)
140+
Assert.Ignore("Dialect does not correctly handle decimal.");
141+
142+
using (var s = OpenSession())
143+
{
144+
var value = await (s
145+
.CreateCriteria<Student>()
146+
.SetProjection(
147+
Projections.Cast(
148+
TypeFactory.Basic("decimal(18,9)"),
149+
Projections.Constant(123456789.123456789m, TypeFactory.Basic("decimal(18,9)"))))
150+
.UniqueResultAsync<decimal>());
151+
Assert.That(value, Is.EqualTo(123456789.123456789m), "Same type cast");
152+
153+
value = await (s
154+
.CreateCriteria<Student>()
155+
.SetProjection(
156+
Projections.Cast(
157+
TypeFactory.Basic("decimal(18,7)"),
158+
Projections.Constant(123456789.987654321m, TypeFactory.Basic("decimal(18,9)"))))
159+
.UniqueResultAsync<decimal>());
160+
Assert.That(value, Is.EqualTo(123456789.9876543m), "Reduced scale cast");
161+
}
162+
}
163+
103164
[Test]
104165
public async Task CanUseParametersWithProjectionsAsync()
105166
{

src/NHibernate.Test/Async/DialectTest/DialectFixture.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
using System;
1212
using System.Collections.Generic;
1313
using System.Data;
14-
using System.Data.Common;
1514
using NHibernate.Dialect;
1615
using NHibernate.Driver;
1716
using NHibernate.Engine;
@@ -79,4 +78,4 @@ public async Task CurrentTimestampSelectionAsync()
7978
}
8079
}
8180
}
82-
}
81+
}

src/NHibernate.Test/Async/DriverTest/FirebirdClientDriverFixture.cs

+66-64
Original file line numberDiff line numberDiff line change
@@ -26,73 +26,74 @@ public class FirebirdClientDriverFixtureAsync
2626
private string _connectionString;
2727
private FirebirdClientDriver _driver;
2828

29+
[OneTimeSetUp]
30+
public void OneTimeSetup()
31+
{
32+
var cfg = TestConfigurationHelper.GetDefaultConfiguration();
33+
34+
var dlct = cfg.GetProperty("dialect");
35+
if (!dlct.Contains("Firebird"))
36+
Assert.Ignore("Applies only to Firebird");
37+
38+
_driver = new FirebirdClientDriver();
39+
_driver.Configure(cfg.Properties);
40+
_connectionString = cfg.GetProperty("connection.connection_string");
41+
}
42+
2943
[Test]
3044
public async Task ConnectionPooling_OpenThenCloseThenOpenAnotherOne_OnlyOneConnectionIsPooledAsync()
3145
{
32-
MakeDriver();
33-
3446
_driver.ClearPool(_connectionString);
3547

3648
var allreadyEstablished = await (GetEstablishedConnectionsAsync());
3749

38-
var connection1 = MakeConnection();
39-
var connection2 = MakeConnection();
40-
41-
//open first connection
42-
await (connection1.OpenAsync());
43-
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After first open"));
50+
using (var connection1 = MakeConnection())
51+
using (var connection2 = MakeConnection())
52+
{
53+
//open first connection
54+
await (connection1.OpenAsync());
55+
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After first open"));
4456

45-
//return it to the pool
46-
connection1.Close();
47-
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After first close"));
57+
//return it to the pool
58+
connection1.Close();
59+
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After first close"));
4860

49-
//open the second connection
50-
await (connection2.OpenAsync());
51-
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After second open"));
61+
//open the second connection
62+
await (connection2.OpenAsync());
63+
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After second open"));
5264

53-
//return it to the pool
54-
connection2.Close();
55-
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After second close"));
65+
//return it to the pool
66+
connection2.Close();
67+
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After second close"));
68+
}
5669
}
5770

5871
[Test]
5972
public async Task ConnectionPooling_OpenThenCloseTwoAtTheSameTime_TowConnectionsArePooledAsync()
6073
{
61-
MakeDriver();
62-
6374
_driver.ClearPool(_connectionString);
6475

6576
var allreadyEstablished = await (GetEstablishedConnectionsAsync());
6677

67-
var connection1 = MakeConnection();
68-
var connection2 = MakeConnection();
69-
70-
//open first connection
71-
await (connection1.OpenAsync());
72-
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After first open"));
73-
74-
//open second one
75-
await (connection2.OpenAsync());
76-
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 2, "After second open"));
77-
78-
//return connection1 to the pool
79-
connection1.Close();
80-
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 2, "After first close"));
78+
using (var connection1 = MakeConnection())
79+
using (var connection2 = MakeConnection())
80+
{
81+
//open first connection
82+
await (connection1.OpenAsync());
83+
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 1, "After first open"));
8184

82-
//return connection2 to the pool
83-
connection2.Close();
84-
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 2, "After second close"));
85-
}
85+
//open second one
86+
await (connection2.OpenAsync());
87+
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 2, "After second open"));
8688

87-
private void MakeDriver()
88-
{
89-
var cfg = TestConfigurationHelper.GetDefaultConfiguration();
90-
var dlct = cfg.GetProperty("dialect");
91-
if (!dlct.Contains("Firebird"))
92-
Assert.Ignore("Applies only to Firebird");
89+
//return connection1 to the pool
90+
connection1.Close();
91+
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 2, "After first close"));
9392

94-
_driver = new FirebirdClientDriver();
95-
_connectionString = cfg.GetProperty("connection.connection_string");
93+
//return connection2 to the pool
94+
connection2.Close();
95+
await (VerifyCountOfEstablishedConnectionsIsAsync(allreadyEstablished + 2, "After second close"));
96+
}
9697
}
9798

9899
private DbConnection MakeConnection()
@@ -125,38 +126,38 @@ private DbConnection MakeConnection()
125126
private DbCommand BuildSelectCaseCommand(SqlType paramType)
126127
{
127128
var sqlString = new SqlStringBuilder()
128-
.Add("select (case when col = ")
129-
.AddParameter()
130-
.Add(" then ")
131-
.AddParameter()
132-
.Add(" else ")
133-
.AddParameter()
134-
.Add(" end) from table")
135-
.ToSqlString();
129+
.Add("select (case when col = ")
130+
.AddParameter()
131+
.Add(" then ")
132+
.AddParameter()
133+
.Add(" else ")
134+
.AddParameter()
135+
.Add(" end) from table")
136+
.ToSqlString();
136137

137138
return _driver.GenerateCommand(CommandType.Text, sqlString, new[] { paramType, paramType, paramType });
138139
}
139140

140141
private DbCommand BuildSelectConcatCommand(SqlType paramType)
141142
{
142143
var sqlString = new SqlStringBuilder()
143-
.Add("select col || ")
144-
.AddParameter()
145-
.Add(" || ")
146-
.Add("col ")
147-
.Add("from table")
148-
.ToSqlString();
144+
.Add("select col || ")
145+
.AddParameter()
146+
.Add(" || ")
147+
.Add("col ")
148+
.Add("from table")
149+
.ToSqlString();
149150

150151
return _driver.GenerateCommand(CommandType.Text, sqlString, new[] { paramType });
151152
}
152153

153154
private DbCommand BuildSelectAddCommand(SqlType paramType)
154155
{
155156
var sqlString = new SqlStringBuilder()
156-
.Add("select col + ")
157-
.AddParameter()
158-
.Add(" from table")
159-
.ToSqlString();
157+
.Add("select col + ")
158+
.AddParameter()
159+
.Add(" from table")
160+
.ToSqlString();
160161

161162
return _driver.GenerateCommand(CommandType.Text, sqlString, new[] { paramType });
162163
}
@@ -172,6 +173,7 @@ private DbCommand BuildInsertWithParamsInSelectCommand(SqlType paramType)
172173

173174
return _driver.GenerateCommand(CommandType.Text, sqlString, new[] { paramType });
174175
}
176+
175177
private DbCommand BuildInsertWithParamsInSelectCommandWithSelectInColumnName(SqlType paramType)
176178
{
177179
var sqlString = new SqlStringBuilder()
@@ -184,7 +186,7 @@ private DbCommand BuildInsertWithParamsInSelectCommandWithSelectInColumnName(Sql
184186
return _driver.GenerateCommand(CommandType.Text, sqlString, new[] { paramType });
185187
}
186188

187-
private DbCommand BuildInsertWithParamsInSelectCommandWithWhereInColumnName(SqlType paramType)
189+
private DbCommand BuildInsertWithParamsInSelectCommandWithWhereInColumnName(SqlType paramType)
188190
{
189191
var sqlString = new SqlStringBuilder()
190192
.Add("insert into table1 (col1_where_aaa) ")

src/NHibernate.Test/Criteria/ProjectionsTest.cs

+61
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
using System;
12
using System.Collections;
23
using System.Collections.Generic;
4+
using System.Text.RegularExpressions;
35
using NHibernate.Criterion;
46
using NHibernate.Dialect;
7+
using NHibernate.SqlTypes;
8+
using NHibernate.Type;
59
using NUnit.Framework;
610

711
namespace NHibernate.Test.Criteria
@@ -89,6 +93,63 @@ public void UsingSqlFunctions_Concat_WithCast()
8993
}
9094
}
9195

96+
[Test]
97+
public void CastWithLength()
98+
{
99+
if (Regex.IsMatch(Dialect.GetCastTypeName(SqlTypeFactory.GetString(3)), @"^[^(]*$"))
100+
{
101+
Assert.Ignore($"Dialect {Dialect} does not seem to handle string length in cast");
102+
}
103+
104+
using (var s = OpenSession())
105+
{
106+
try
107+
{
108+
var shortName = s
109+
.CreateCriteria<Student>()
110+
.SetProjection(
111+
Projections.Cast(
112+
TypeFactory.GetStringType(3),
113+
Projections.Property("Name")))
114+
.UniqueResult<string>();
115+
Assert.That(shortName, Is.EqualTo("aye"));
116+
}
117+
catch (Exception e)
118+
{
119+
if (e.InnerException == null || !e.InnerException.Message.Contains("truncation"))
120+
throw;
121+
}
122+
}
123+
}
124+
125+
[Test]
126+
public void CastWithPrecisionScale()
127+
{
128+
if (TestDialect.HasBrokenDecimalType)
129+
Assert.Ignore("Dialect does not correctly handle decimal.");
130+
131+
using (var s = OpenSession())
132+
{
133+
var value = s
134+
.CreateCriteria<Student>()
135+
.SetProjection(
136+
Projections.Cast(
137+
TypeFactory.Basic("decimal(18,9)"),
138+
Projections.Constant(123456789.123456789m, TypeFactory.Basic("decimal(18,9)"))))
139+
.UniqueResult<decimal>();
140+
Assert.That(value, Is.EqualTo(123456789.123456789m), "Same type cast");
141+
142+
value = s
143+
.CreateCriteria<Student>()
144+
.SetProjection(
145+
Projections.Cast(
146+
TypeFactory.Basic("decimal(18,7)"),
147+
Projections.Constant(123456789.987654321m, TypeFactory.Basic("decimal(18,9)"))))
148+
.UniqueResult<decimal>();
149+
Assert.That(value, Is.EqualTo(123456789.9876543m), "Reduced scale cast");
150+
}
151+
}
152+
92153
[Test]
93154
public void CanUseParametersWithProjections()
94155
{

0 commit comments

Comments
 (0)