Skip to content

Commit a469c15

Browse files
[Release 1.1] Revert ReadAsync changes that caused issues (#550)
1 parent bfe3155 commit a469c15

File tree

3 files changed

+96
-6
lines changed

3 files changed

+96
-6
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2756,6 +2756,12 @@ private bool TryProcessDone(SqlCommand cmd, SqlDataReader reader, ref RunBehavio
27562756
ushort status;
27572757
int count;
27582758

2759+
// This is added back since removing it from here introduces regressions in Managed SNI.
2760+
// It forces SqlDataReader.ReadAsync() method to run synchronously,
2761+
// and will block the calling thread until data is fed from SQL Server.
2762+
// TODO Investigate better solution to support non-blocking ReadAsync().
2763+
stateObj._syncOverAsync = true;
2764+
27592765
// status
27602766
// command
27612767
// rowcount (valid only if DONE_COUNT bit is set)
@@ -2855,11 +2861,10 @@ private bool TryProcessDone(SqlCommand cmd, SqlDataReader reader, ref RunBehavio
28552861
}
28562862
}
28572863

2858-
// _attentionSent set by 'SendAttention'
2859-
// _pendingData set by e.g. 'TdsExecuteSQLBatch'
2860-
// _hasOpenResult always set to true by 'WriteMarsHeader'
2864+
// HasPendingData set by e.g. 'TdsExecuteSQLBatch'
2865+
// HasOpenResult always set to true by 'WriteMarsHeader'
28612866
//
2862-
if (!stateObj._attentionSent && !stateObj.HasPendingData && stateObj.HasOpenResult)
2867+
if (!stateObj.HasPendingData && stateObj.HasOpenResult)
28632868
{
28642869
/*
28652870
Debug.Assert(!((sqlTransaction != null && _distributedTransaction != null) ||

src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3324,11 +3324,10 @@ private bool TryProcessDone(SqlCommand cmd, SqlDataReader reader, ref RunBehavio
33243324
}
33253325
}
33263326

3327-
// _attentionSent set by 'SendAttention'
33283327
// _pendingData set by e.g. 'TdsExecuteSQLBatch'
33293328
// _hasOpenResult always set to true by 'WriteMarsHeader'
33303329
//
3331-
if (!stateObj._attentionSent && !stateObj._pendingData && stateObj._hasOpenResult)
3330+
if (!stateObj._pendingData && stateObj._hasOpenResult)
33323331
{
33333332
/*
33343333
Debug.Assert(!((sqlTransaction != null && _distributedTransaction != null) ||

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlCommand/SqlCommandCancelTest.cs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,92 @@ public static void TimeOutDuringRead()
120120
TimeOutDuringRead(s_connStr);
121121
}
122122

123+
[CheckConnStrSetupFact]
124+
public static void TCPAttentionPacketTestTransaction()
125+
{
126+
CancelFollowedByTransaction(s_connStr);
127+
}
128+
129+
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer))]
130+
public static void TCPAttentionPacketTestAlerts()
131+
{
132+
CancelFollowedByAlert(s_connStr);
133+
}
134+
135+
private static void CancelFollowedByTransaction(string constr)
136+
{
137+
using (SqlConnection connection = new SqlConnection(constr))
138+
{
139+
connection.Open();
140+
using (SqlCommand cmd = connection.CreateCommand())
141+
{
142+
cmd.CommandText = @"SELECT @@VERSION";
143+
using (var r = cmd.ExecuteReader())
144+
{
145+
cmd.Cancel();
146+
}
147+
}
148+
using (SqlTransaction transaction = connection.BeginTransaction())
149+
{ }
150+
}
151+
}
152+
153+
private static void CancelFollowedByAlert(string constr)
154+
{
155+
var alertName = "myAlert" + Guid.NewGuid().ToString();
156+
// Since Alert conditions are randomly generated,
157+
// we will retry on unexpected error messages to avoid collision in pipelines.
158+
var n = new Random().Next(1, 100);
159+
bool retry = true;
160+
int retryAttempt = 0;
161+
while (retry && retryAttempt < 3)
162+
{
163+
try
164+
{
165+
using (var conn = new SqlConnection(constr))
166+
{
167+
conn.Open();
168+
using (SqlCommand cmd = conn.CreateCommand())
169+
{
170+
cmd.CommandText = "SELECT @@VERSION";
171+
using (var reader = cmd.ExecuteReader())
172+
{
173+
cmd.Cancel(); // Sends Attention
174+
}
175+
}
176+
using (SqlCommand cmd = conn.CreateCommand())
177+
{
178+
cmd.CommandText = $@"EXEC msdb.dbo.sp_add_alert @name=N'{alertName}',
179+
@performance_condition = N'SQLServer:General Statistics|User Connections||>|{n}'";
180+
cmd.ExecuteNonQuery();
181+
cmd.CommandText = @"USE [msdb]";
182+
cmd.ExecuteNonQuery();
183+
cmd.CommandText = $@"/****** Object: Alert [{alertName}] Script Date: {DateTime.Now} ******/
184+
IF EXISTS (SELECT name FROM msdb.dbo.sysalerts WHERE name = N'{alertName}')
185+
EXEC msdb.dbo.sp_delete_alert @name=N'{alertName}'";
186+
cmd.ExecuteNonQuery();
187+
}
188+
}
189+
}
190+
catch (Exception e)
191+
{
192+
if (retryAttempt >= 3 || e.Message.Contains("The transaction operation cannot be performed"))
193+
{
194+
Assert.False(true, $"Retry Attempt: {retryAttempt} | Unexpected Exception occurred: {e.Message}");
195+
}
196+
else
197+
{
198+
retry = true;
199+
retryAttempt++;
200+
Console.WriteLine($"CancelFollowedByAlert Test retry attempt : {retryAttempt}");
201+
Thread.Sleep(500);
202+
continue;
203+
}
204+
}
205+
retry = false;
206+
}
207+
}
208+
123209
private static void MultiThreadedCancel(string constr, bool async)
124210
{
125211
using (SqlConnection con = new SqlConnection(constr))

0 commit comments

Comments
 (0)