Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move to Shared - SqlTransaction #1353

Merged
merged 22 commits into from
Jun 9, 2022
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,12 @@
<Compile Include="Microsoft\Data\SqlClient\SqlInternalConnectionTds.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlParameter.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlSequentialTextReader.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlTransaction.cs" />
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlTransaction.netcore.cs">
<Link>Microsoft\Data\SqlClient\SqlTransaction.netcore.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlTransaction.cs">
<Link>Microsoft\Data\SqlClient\SqlTransaction.cs</Link>
</Compile>
<Compile Include="Microsoft\Data\SqlClient\SqlUtil.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsEnums.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParser.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,12 @@
<Compile Include="Microsoft\Data\SqlClient\SqlSequentialStreamSmi.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlSequentialTextReader.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlSequentialTextReaderSmi.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlTransaction.cs" />
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlTransaction.netfx.cs">
<Link>Microsoft\Data\SqlClient\SqlTransaction.netfx.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlTransaction.cs">
<Link>Microsoft\Data\SqlClient\SqlTransaction.cs</Link>
</Compile>
<Compile Include="Microsoft\Data\SqlClient\SqlUtil.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsEnums.cs" />
<Compile Include="Microsoft\Data\SqlClient\TdsParser.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Data;
using System.Data.Common;
using System.Diagnostics;
using Microsoft.Data.Common;

namespace Microsoft.Data.SqlClient
{
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/SqlTransaction/*' />
public sealed partial class SqlTransaction : DbTransaction
{
private static int s_objectTypeCount; // EventSource Counter
internal readonly int _objectID = System.Threading.Interlocked.Increment(ref s_objectTypeCount);
internal readonly IsolationLevel _isolationLevel = IsolationLevel.ReadCommitted;

private SqlInternalTransaction _internalTransaction;
private readonly SqlConnection _connection;

private bool _isFromAPI;

internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con,
IsolationLevel iso, SqlInternalTransaction internalTransaction)
{
#if NETFRAMEWORK
SqlConnection.VerifyExecutePermission();
#endif
_isolationLevel = iso;
_connection = con;

if (internalTransaction == null)
{
_internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this);
}
else
{
Debug.Assert(internalConnection.CurrentTransaction == internalTransaction, "Unexpected Parser.CurrentTransaction state!");
_internalTransaction = internalTransaction;
_internalTransaction.InitParent(this);
}
}

////////////////////////////////////////////////////////////////////////////////////////
// PROPERTIES
////////////////////////////////////////////////////////////////////////////////////////

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Connection/*' />
new public SqlConnection Connection
Kaur-Parminder marked this conversation as resolved.
Show resolved Hide resolved
{// MDAC 66655
get
{
if (IsZombied)
{
return null;
}
else
{
return _connection;
}
}
}

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/DbConnection/*' />
override protected DbConnection DbConnection => Connection;
Kaur-Parminder marked this conversation as resolved.
Show resolved Hide resolved

internal SqlInternalTransaction InternalTransaction => _internalTransaction;

/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/IsolationLevel/*' />
override public IsolationLevel IsolationLevel
Kaur-Parminder marked this conversation as resolved.
Show resolved Hide resolved
{
get
{
ZombieCheck();
return _isolationLevel;
}
}

private bool Is2005PartialZombie => _internalTransaction !=null && _internalTransaction.IsCompleted;

internal bool IsZombied => _internalTransaction == null || _internalTransaction.IsCompleted;

internal int ObjectID => _objectID;

internal SqlStatistics Statistics
{
get
{
if (null != _connection)
{
if (_connection.StatisticsEnabled)
{
return _connection.Statistics;
}
}
return null;
}
}

////////////////////////////////////////////////////////////////////////////////////////
// INTERNAL METHODS
////////////////////////////////////////////////////////////////////////////////////////

internal void Zombie()
{
// For Yukon, we have to defer "zombification" until
// we get past the users' next rollback, else we'll
// throw an exception there that is a breaking change.
// Of course, if the connection is already closed,
// then we're free to zombify...
SqlInternalConnection internalConnection = (_connection.InnerConnection as SqlInternalConnection);
if (null != internalConnection
#if NETFRAMEWORK
&& internalConnection.Is2005OrNewer
#endif
&& !_isFromAPI)
{
SqlClientEventSource.Log.TryAdvancedTraceEvent("SqlTransaction.Zombie | ADV | Object Id {0} yukon deferred zombie", ObjectID);
}
else
{
_internalTransaction = null; // pre-yukon zombification
Kaur-Parminder marked this conversation as resolved.
Show resolved Hide resolved
}
}

////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
////////////////////////////////////////////////////////////////////////////////////////

private void ZombieCheck()
{
// If this transaction has been completed, throw exception since it is unusable.
if (IsZombied)
{
if (Is2005PartialZombie)
{
_internalTransaction = null; // yukon zombification
Kaur-Parminder marked this conversation as resolved.
Show resolved Hide resolved
}

throw ADP.TransactionZombied(this);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,135 +4,21 @@

using System;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using Microsoft.Data.Common;

namespace Microsoft.Data.SqlClient
{
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/SqlTransaction/*' />
public sealed class SqlTransaction : DbTransaction
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/SqlTransaction/*' />
public sealed partial class SqlTransaction : DbTransaction
{
private static readonly SqlDiagnosticListener s_diagnosticListener = new SqlDiagnosticListener(SqlClientDiagnosticListenerExtensions.DiagnosticListenerName);
private static int _objectTypeCount; // EventSource Counter
internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
internal readonly IsolationLevel _isolationLevel = IsolationLevel.ReadCommitted;

private SqlInternalTransaction _internalTransaction;
private SqlConnection _connection;

private bool _isFromAPI;

internal SqlTransaction(SqlInternalConnection internalConnection, SqlConnection con,
IsolationLevel iso, SqlInternalTransaction internalTransaction)
{
_isolationLevel = iso;
_connection = con;

if (internalTransaction == null)
{
_internalTransaction = new SqlInternalTransaction(internalConnection, TransactionType.LocalFromAPI, this);
}
else
{
Debug.Assert(internalConnection.CurrentTransaction == internalTransaction, "Unexpected Parser.CurrentTransaction state!");
_internalTransaction = internalTransaction;
_internalTransaction.InitParent(this);
}
}

////////////////////////////////////////////////////////////////////////////////////////
// PROPERTIES
////////////////////////////////////////////////////////////////////////////////////////

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Connection/*' />
new public SqlConnection Connection
{
get
{
if (IsZombied)
{
return null;
}
else
{
return _connection;
}
}
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/DbConnection/*' />
override protected DbConnection DbConnection
{
get
{
return Connection;
}
}

internal SqlInternalTransaction InternalTransaction
{
get
{
return _internalTransaction;
}
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/IsolationLevel/*' />
override public IsolationLevel IsolationLevel
{
get
{
ZombieCheck();
return _isolationLevel;
}
}

private bool Is2005PartialZombie
{
get
{
return (null != _internalTransaction && _internalTransaction.IsCompleted);
}
}

internal bool IsZombied
{
get
{
return (null == _internalTransaction || _internalTransaction.IsCompleted);
}
}

internal int ObjectID
{
get
{
return _objectID;
}
}

internal SqlStatistics Statistics
{
get
{
if (null != _connection)
{
if (_connection.StatisticsEnabled)
{
return _connection.Statistics;
}
}
return null;
}
}
private static readonly SqlDiagnosticListener s_diagnosticListener = new(SqlClientDiagnosticListenerExtensions.DiagnosticListenerName);

////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
////////////////////////////////////////////////////////////////////////////////////////

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Commit/*' />
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Commit/*' />
override public void Commit()
Kaur-Parminder marked this conversation as resolved.
Show resolved Hide resolved
{
using (DiagnosticTransactionScope diagnosticScope = s_diagnosticListener.CreateTransactionCommitScope(_isolationLevel, _connection, InternalTransaction))
Expand Down Expand Up @@ -177,7 +63,7 @@ override public void Commit()
}
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/DisposeDisposing/*' />
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/DisposeDisposing/*' />
protected override void Dispose(bool disposing)
{
if (disposing)
Expand All @@ -190,7 +76,7 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Rollback2/*' />
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Rollback2/*' />
override public void Rollback()
Kaur-Parminder marked this conversation as resolved.
Show resolved Hide resolved
{
using (DiagnosticTransactionScope diagnosticScope = s_diagnosticListener.CreateTransactionRollbackScope(_isolationLevel, _connection, InternalTransaction, null))
Expand Down Expand Up @@ -232,7 +118,7 @@ override public void Rollback()
}
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/RollbackTransactionName/*' />
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/RollbackTransactionName/*' />
public void Rollback(string transactionName)
{
using (DiagnosticTransactionScope diagnosticScope = s_diagnosticListener.CreateTransactionRollbackScope(_isolationLevel, _connection, InternalTransaction, transactionName))
Expand Down Expand Up @@ -264,7 +150,7 @@ public void Rollback(string transactionName)
}
}

/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Save/*' />
/// <include file='../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlTransaction.xml' path='docs/members[@name="SqlTransaction"]/Save/*' />
public void Save(string savePointName)
{
ZombieCheck();
Expand All @@ -284,45 +170,5 @@ public void Save(string savePointName)
}
}
}

////////////////////////////////////////////////////////////////////////////////////////
// INTERNAL METHODS
////////////////////////////////////////////////////////////////////////////////////////

internal void Zombie()
{
// For 2005, we have to defer "zombification" until
// we get past the users' next rollback, else we'll
// throw an exception there that is a breaking change.
// Of course, if the connection is already closed,
// then we're free to zombify...
SqlInternalConnection internalConnection = (_connection.InnerConnection as SqlInternalConnection);
if (null != internalConnection && !_isFromAPI)
{
SqlClientEventSource.Log.TryAdvancedTraceEvent("SqlTransaction.Zombie | ADV | Object Id {0} 2005 deferred zombie", ObjectID);
}
else
{
_internalTransaction = null; // pre-2005 zombification
}
}

////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE METHODS
////////////////////////////////////////////////////////////////////////////////////////

private void ZombieCheck()
{
// If this transaction has been completed, throw exception since it is unusable.
if (IsZombied)
{
if (Is2005PartialZombie)
{
_internalTransaction = null; // 2005 zombification
}

throw ADP.TransactionZombied(this);
}
}
}
}
Loading