Skip to content

Commit 55f0f4f

Browse files
NH-2176 - fixing db specific issues
1 parent 678e335 commit 55f0f4f

File tree

15 files changed

+449
-218
lines changed

15 files changed

+449
-218
lines changed

src/NHibernate.Test/NHSpecificTest/DtcFailures/DtcFailuresFixture.cs

Lines changed: 280 additions & 131 deletions
Large diffs are not rendered by default.

src/NHibernate.Test/NHSpecificTest/NH1632/Fixture.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,8 @@ public void Will_not_save_when_flush_mode_is_never()
184184
[Test]
185185
public void When_using_two_sessions_with_explicit_flush()
186186
{
187-
if (!TestDialect.SupportsConcurrentTransactions)
188-
Assert.Ignore(Dialect.GetType().Name + " does not support concurrent transactions.");
187+
if (!Dialect.SupportsConcurrentWritingConnectionsInSameTransaction)
188+
Assert.Ignore(Dialect.GetType().Name + " does not support concurrent connections in same transaction.");
189189

190190
object id1, id2;
191191
using (var tx = new TransactionScope())
@@ -222,8 +222,8 @@ public void When_using_two_sessions_with_explicit_flush()
222222
[Test]
223223
public void When_using_two_sessions()
224224
{
225-
if (!TestDialect.SupportsConcurrentTransactions)
226-
Assert.Ignore(Dialect.GetType().Name + " does not support concurrent transactions.");
225+
if (!Dialect.SupportsConcurrentWritingConnectionsInSameTransaction)
226+
Assert.Ignore(Dialect.GetType().Name + " does not support concurrent connections in same transaction.");
227227

228228
object id1, id2;
229229
using (var tx = new TransactionScope())

src/NHibernate.Test/NHSpecificTest/NH2420/Fixture.cs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
using System;
2-
using System.Data.Common;
1+
using System.Data.Common;
32
using System.Data.Odbc;
43
using System.Data.SqlClient;
54
using System.Configuration;
6-
using System.Threading;
75
using System.Transactions;
86
using NHibernate.Dialect;
97
using NHibernate.Driver;
10-
using NHibernate.Engine;
118
using NUnit.Framework;
129

1310
using Environment = NHibernate.Cfg.Environment;
@@ -98,7 +95,7 @@ public void ShouldBeAbleToReleaseSuppliedConnectionAfterDistributedTransaction()
9895
// here. When having TransactionCompleted event, this event and the second phase
9996
// tend to occur before reaching here. But some other NH cases demonstrate that
10097
// TransactionCompleted may also occur "too late".
101-
((ISessionImplementor) s).TransactionContext?.WaitOne();
98+
s.GetSessionImplementation().TransactionContext?.WaitOne();
10299

103100
// Prior to the patch, an InvalidOperationException exception would occur in the
104101
// TransactionCompleted delegate at this point with the message, "Disconnect cannot
@@ -107,8 +104,8 @@ public void ShouldBeAbleToReleaseSuppliedConnectionAfterDistributedTransaction()
107104
// fires *after* the transaction is committed and so it doesn't affect the success
108105
// of the transaction.
109106
Assert.That(s.IsConnected, Is.False);
110-
Assert.That(((ISessionImplementor)s).ConnectionManager.IsConnected, Is.False);
111-
Assert.That(((ISessionImplementor)s).IsClosed, Is.True);
107+
Assert.That(s.GetSessionImplementation().ConnectionManager.IsConnected, Is.False);
108+
Assert.That(s.GetSessionImplementation().IsClosed, Is.True);
112109
}
113110

114111
protected override void OnTearDown()

src/NHibernate.Test/SystemTransactions/TransactionFixture.cs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,38 @@ namespace NHibernate.Test.SystemTransactions
99
public class TransactionFixture : TestCase
1010
{
1111
protected override IList Mappings
12+
=> new [] { "WZ.hbm.xml" };
13+
14+
protected override void OnTearDown()
1215
{
13-
get { return new string[] { "WZ.hbm.xml" }; }
16+
using (var s = sessions.OpenSession())
17+
using (var t = s.BeginTransaction())
18+
{
19+
s.CreateQuery("delete from System.Object").ExecuteUpdate();
20+
t.Commit();
21+
}
1422
}
1523

1624
[Test]
1725
public void CanUseSystemTransactionsToCommit()
1826
{
1927
object identifier;
20-
using(ISession session = sessions.OpenSession())
21-
using(TransactionScope tx = new TransactionScope())
28+
using(var session = sessions.OpenSession())
29+
using(var tx = new TransactionScope())
2230
{
23-
W s = new W();
31+
var s = new W();
2432
session.Save(s);
2533
identifier = s.Id;
2634
tx.Complete();
2735
}
2836

29-
using (ISession session = sessions.OpenSession())
30-
using (TransactionScope tx = new TransactionScope())
37+
using (var session = sessions.OpenSession())
38+
using (var tx = new TransactionScope())
3139
{
32-
W w = session.Get<W>(identifier);
40+
var w = session.Get<W>(identifier);
3341
Assert.IsNotNull(w);
42+
// Without explicit Flush, this delay the delete to prepare phase, and test flushing from there
43+
// while having already acquired a connection due to the Get.
3444
session.Delete(w);
3545
tx.Complete();
3646
}

src/NHibernate.Test/TestDialect.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,6 @@ public TestDialect(Dialect.Dialect dialect)
3333
public virtual bool SupportsOperatorSome { get { return true; } }
3434
public virtual bool SupportsLocate { get { return true; } }
3535

36-
public virtual bool SupportsDistributedTransactions { get { return true; } }
37-
38-
/// <summary>
39-
/// Whether two transactions can be run at the same time. For example, with SQLite
40-
/// the database is locked when one transaction is run, so running a second transaction
41-
/// will cause a "database is locked" error message.
42-
/// </summary>
43-
public virtual bool SupportsConcurrentTransactions { get { return true; } }
44-
4536
public virtual bool SupportsFullJoin { get { return true; } }
4637

4738
public virtual bool HasBrokenDecimalType { get { return false; } }

src/NHibernate.Test/TestDialects/PostgreSQL83TestDialect.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,5 @@ public override bool SupportsNullCharactersInUtfStrings
2121
{
2222
get { return false; }
2323
}
24-
25-
/// <summary>
26-
/// Npgsql's DTC code seems to be somewhat broken as of 2.0.11.
27-
/// </summary>
28-
public override bool SupportsDistributedTransactions
29-
{
30-
get { return false; }
31-
}
3224
}
3325
}

src/NHibernate.Test/TestDialects/SQLiteTestDialect.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,6 @@ public override bool SupportsLocate
2727
get { return false; }
2828
}
2929

30-
public override bool SupportsDistributedTransactions
31-
{
32-
get { return false; }
33-
}
34-
35-
public override bool SupportsConcurrentTransactions
36-
{
37-
get { return false; }
38-
}
39-
4030
public override bool SupportsFullJoin
4131
{
4232
get { return false; }

src/NHibernate/AdoNet/ConnectionManager.cs

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,11 @@ public ConnectionManager(
6969
ownConnection = suppliedConnection == null;
7070
}
7171

72+
public bool IsInActiveExplicitTransaction
73+
=> transaction != null && transaction.IsActive;
74+
7275
public bool IsInActiveTransaction
73-
{
74-
get
75-
{
76-
if (transaction != null && transaction.IsActive)
77-
return true;
78-
return Factory.TransactionFactory.IsInDistributedActiveTransaction(session);
79-
}
80-
}
76+
=> IsInActiveExplicitTransaction || Factory.TransactionFactory.IsInDistributedActiveTransaction(session);
8177

8278
public bool IsConnected
8379
{
@@ -402,19 +398,31 @@ public IBatcher Batcher
402398
}
403399

404400
/// <summary>
405-
/// Tell if according to current ambient transaction, the connection should be explicitly enlisted
406-
/// for ensuring it to participate in transaction. Always <see langword="false" /> for supplied
407-
/// connection, enlistment is user business in such case.
401+
/// Enlist the connection into current ambient transaction if the connection should be explicitly enlisted
402+
/// for ensuring it to participate in the ambient transaction. Does nothing for supplied connection,
403+
/// enlistment is user business in such case. Does nothing in case an explicit transaction ongoing.
408404
/// </summary>
409-
public bool RequireExplicitEnlistment
410-
=> ownConnection && connection != null &&
411-
_connectionAmbientTransaction != System.Transactions.Transaction.Current;
405+
public void EnlistIfRequired()
406+
{
407+
if (!ownConnection || connection == null || IsInActiveExplicitTransaction)
408+
return;
409+
var tran = System.Transactions.Transaction.Current;
410+
if (tran == _connectionAmbientTransaction)
411+
return;
412+
// Will fail if the connection is already enlisted in another not yet completed transaction.
413+
// Probable case: nested transaction scope. Supporting this could be done by releasing the
414+
// connection instead of enlisting.
415+
session.Connection.EnlistTransaction(tran);
416+
}
417+
418+
private bool RequireConnectionSwapInDtc
419+
=> _ownConnection && Factory.Dialect.SupportsConcurrentWritingConnectionsInSameTransaction;
412420

413421
public IDisposable FlushingFromDtcTransaction
414422
{
415423
get
416424
{
417-
if (ownConnection)
425+
if (RequireConnectionSwapInDtc)
418426
{
419427
if (Batcher.HasOpenResources)
420428
throw new InvalidOperationException("Batcher still has opened ressources at time of Flush from DTC.");
@@ -431,26 +439,26 @@ public IDisposable FlushingFromDtcTransaction
431439

432440
private class StopFlushingFromDtcTransaction : IDisposable
433441
{
434-
private readonly ConnectionManager manager;
442+
private readonly ConnectionManager _manager;
435443

436444
public StopFlushingFromDtcTransaction(ConnectionManager manager)
437445
{
438-
this.manager = manager;
446+
_manager = manager;
439447
}
440448

441449
public void Dispose()
442450
{
443-
manager.flushingFromDtcTransaction = false;
451+
_manager.flushingFromDtcTransaction = false;
444452

445-
if (manager.ownConnection)
453+
if (_manager.RequireConnectionSwapInDtc)
446454
{
447455
// Release the connection potentially acquired for flushing from DTC.
448-
manager.DisconnectOwnConnection();
456+
_manager.DisconnectOwnConnection();
449457
// Swap back current connection
450-
manager.connection = manager._dtcBackupConnection;
451-
manager._connectionAmbientTransaction = manager._dtcBackupConnectionAmbientTransaction;
452-
manager._dtcBackupConnection = null;
453-
manager._dtcBackupConnectionAmbientTransaction = null;
458+
_manager.connection = _manager._dtcBackupConnection;
459+
_manager._connectionAmbientTransaction = _manager._dtcBackupConnectionAmbientTransaction;
460+
_manager._dtcBackupConnection = null;
461+
_manager._dtcBackupConnectionAmbientTransaction = null;
454462
}
455463
}
456464
}

src/NHibernate/Dialect/Dialect.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Data;
55
using System.Data.Common;
66
using System.Text;
7+
using System.Transactions;
78
using NHibernate.Dialect.Function;
89
using NHibernate.Dialect.Lock;
910
using NHibernate.Dialect.Schema;
@@ -1399,6 +1400,16 @@ public IList<SqlString> GetTokens()
13991400
}
14001401
}
14011402

1403+
/// <summary>
1404+
/// Does this dialect supports concurrent writing connections?
1405+
/// </summary>
1406+
public virtual bool SupportsConcurrentWritingConnections => true;
1407+
1408+
/// <summary>
1409+
/// Does this dialect supports concurrent writing connections in the same transaction?
1410+
/// </summary>
1411+
public virtual bool SupportsConcurrentWritingConnectionsInSameTransaction => SupportsConcurrentWritingConnections;
1412+
14021413
#endregion
14031414

14041415
#region Limit/offset support
@@ -2063,6 +2074,15 @@ public virtual bool SupportsSubSelects
20632074
/// </summary>
20642075
public virtual bool SupportsPoolingParameter => true;
20652076

2077+
/// <summary>
2078+
/// Does this dialect support distributed transaction?
2079+
/// </summary>
2080+
/// <remarks>
2081+
/// Distributed transactions usually imply the use of<see cref="TransactionScope"/>, but using
2082+
/// <c>TransactionScope</c> does not imply the transaction will be distributed.
2083+
/// </remarks>
2084+
public virtual bool SupportsDistributedTransactions => true;
2085+
20662086
#endregion
20672087

20682088
/// <summary>

src/NHibernate/Dialect/FirebirdDialect.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public override SqlString GetLimitString(SqlString queryString, SqlString offset
129129
return queryString.Insert(insertIndex, limitFragment.ToSqlString());
130130
}
131131

132-
#region Temporaray Table Support
132+
#region Temporary Table Support
133133

134134
public override bool SupportsTemporaryTables
135135
{
@@ -424,5 +424,17 @@ private static bool IsUnallowedDecimal(DbType dbType, int precision)
424424
{
425425
return dbType == DbType.Decimal && precision > MAX_DECIMAL_PRECISION;
426426
}
427+
428+
#region Informational metadata
429+
430+
/// <summary>
431+
/// Does this dialect support distributed transaction?
432+
/// </summary>
433+
/// <remarks>
434+
/// As of v2.5, fails rollback-ing changes when distributed: changes are instead persisted in database.
435+
/// </remarks>
436+
public override bool SupportsDistributedTransactions => false;
437+
438+
#endregion
427439
}
428440
}

src/NHibernate/Dialect/MsSqlCeDialect.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,14 @@ private static int GetAfterSelectInsertPoint(SqlString sql)
199199
throw new NotSupportedException("The query should start with 'SELECT' or 'SELECT DISTINCT'");
200200
}
201201

202+
/// <summary>
203+
/// Does this dialect supports concurrent writing connections in the same transaction?
204+
/// </summary>
205+
/// <remarks>
206+
/// Likely because this is seen as mandating promotion to distributed, which SQL Ce does not support.
207+
/// </remarks>
208+
public override bool SupportsConcurrentWritingConnectionsInSameTransaction => false;
209+
202210
public override long TimestampResolutionInTicks
203211
{
204212
get
@@ -215,6 +223,15 @@ public override long TimestampResolutionInTicks
215223
/// </summary>
216224
public override bool SupportsPoolingParameter => false;
217225

226+
/// <summary>
227+
/// Does this dialect support distributed transaction?
228+
/// </summary>
229+
/// <remarks>
230+
/// Fails enlisting a connection into a distributed transaction, fails promoting a transaction
231+
/// to distributed when it has already a connection enlisted.
232+
/// </remarks>
233+
public override bool SupportsDistributedTransactions => false;
234+
218235
#endregion
219236
}
220237
}

src/NHibernate/Dialect/MySQLDialect.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,15 @@ public override long TimestampResolutionInTicks
387387
}
388388
}
389389

390+
/// <summary>
391+
/// Does this dialect supports concurrent writing connections in the same transaction?
392+
/// </summary>
393+
/// <remarks>
394+
/// NotSupportedException : Multiple simultaneous connections or connections with different
395+
/// connection strings inside the same transaction are not currently supported.
396+
/// </remarks>
397+
public override bool SupportsConcurrentWritingConnectionsInSameTransaction => false;
398+
390399
#region Overridden informational metadata
391400

392401
public override bool SupportsEmptyInList => false;
@@ -398,6 +407,15 @@ public override long TimestampResolutionInTicks
398407

399408
public override bool SupportsSubqueryOnMutatingTable => false;
400409

410+
/// <summary>
411+
/// Does this dialect support distributed transaction?
412+
/// </summary>
413+
/// <remarks>
414+
/// Fails enlisting a connection into a distributed transaction, fails promoting a transaction
415+
/// to distributed when it has already a connection enlisted.
416+
/// </remarks>
417+
public override bool SupportsDistributedTransactions => false;
418+
401419
#endregion
402420
}
403421
}

src/NHibernate/Dialect/PostgreSQLDialect.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,14 @@ public override string CurrentTimestampSelectString
265265

266266
public override bool SupportsUnboundedLobLocatorMaterialization => false;
267267

268+
/// <summary>
269+
/// Does this dialect support distributed transaction?
270+
/// </summary>
271+
/// <remarks>
272+
/// Fails rollback-ing changes in DTC transaction: changes stay persisted.
273+
/// </remarks>
274+
public override bool SupportsDistributedTransactions => false;
275+
268276
#endregion
269277
}
270278
}

0 commit comments

Comments
 (0)