Skip to content

Commit 42a1999

Browse files
authored
Merge | Merge netfx-specific exception handling (#3179)
* Exception handling merge Merge exception handling for SqlBulkCopy, SqlCommandBuilder, SqlDataReader, SqlInternalConnection, SqlTransaction and (partially) SqlConnection * Code review changes Wrapped each call to SqlInternalConnection.BestEffortCleanup in #if, rather than having an empty BestEffortCleanup method. * Added missing PrepareConstrainedRegions calls These were part of the netfx exception handling
1 parent 0a77b64 commit 42a1999

File tree

10 files changed

+856
-345
lines changed

10 files changed

+856
-345
lines changed

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

+34-13
Original file line numberDiff line numberDiff line change
@@ -1988,8 +1988,13 @@ private Task WriteRowSourceToServerAsync(int columnCount, CancellationToken ctok
19881988
_parserLock = internalConnection._parserLock;
19891989
_parserLock.Wait(canReleaseFromAnyThread: _isAsyncBulkCopy);
19901990

1991+
TdsParser bestEffortCleanupTarget = null;
1992+
#if NETFRAMEWORK
1993+
RuntimeHelpers.PrepareConstrainedRegions();
1994+
#endif
19911995
try
19921996
{
1997+
bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_connection);
19931998
WriteRowSourceToServerCommon(columnCount); // This is common in both sync and async
19941999
Task resultTask = WriteToServerInternalAsync(ctoken); // resultTask is null for sync, but Task for async.
19952000
if (resultTask != null)
@@ -2037,6 +2042,9 @@ private Task WriteRowSourceToServerAsync(int columnCount, CancellationToken ctok
20372042
catch (System.Threading.ThreadAbortException e)
20382043
{
20392044
_connection.Abort(e);
2045+
#if NETFRAMEWORK
2046+
SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
2047+
#endif
20402048
throw;
20412049
}
20422050
finally
@@ -2297,7 +2305,8 @@ private void CopyColumnsAsyncSetupContinuation(TaskCompletionSource<object> sour
22972305
{
22982306
source.SetResult(null);
22992307
}
2300-
}
2308+
},
2309+
connectionToDoom: _connection.GetOpenTdsConnection()
23012310
);
23022311
}
23032312

@@ -2434,8 +2443,8 @@ private Task CopyRowsAsync(int rowsSoFar, int totalRows, CancellationToken cts,
24342443
resultTask = source.Task;
24352444

24362445
AsyncHelper.ContinueTaskWithState(readTask, source, this,
2437-
onSuccess: (object state) => ((SqlBulkCopy)state).CopyRowsAsync(i + 1, totalRows, cts, source)
2438-
2446+
onSuccess: (object state) => ((SqlBulkCopy)state).CopyRowsAsync(i + 1, totalRows, cts, source),
2447+
connectionToDoom: _connection.GetOpenTdsConnection()
24392448
);
24402449
return resultTask; // Associated task will be completed when all rows are copied to server/exception/cancelled.
24412450
}
@@ -2459,12 +2468,14 @@ private Task CopyRowsAsync(int rowsSoFar, int totalRows, CancellationToken cts,
24592468
else
24602469
{
24612470
AsyncHelper.ContinueTaskWithState(readTask, source, sqlBulkCopy,
2462-
onSuccess: (object state2) => ((SqlBulkCopy)state2).CopyRowsAsync(i + 1, totalRows, cts, source)
2471+
onSuccess: (object state2) => ((SqlBulkCopy)state2).CopyRowsAsync(i + 1, totalRows, cts, source),
2472+
connectionToDoom: _connection.GetOpenTdsConnection()
24632473
);
24642474
}
2465-
}
2466-
);
2467-
return resultTask;
2475+
},
2476+
connectionToDoom: _connection.GetOpenTdsConnection()
2477+
);
2478+
return resultTask;
24682479
}
24692480
}
24702481

@@ -2542,7 +2553,8 @@ private Task CopyBatchesAsync(BulkCopySimpleResultSet internalResults, string up
25422553
// Continuation finished sync, recall into CopyBatchesAsync to continue
25432554
sqlBulkCopy.CopyBatchesAsync(internalResults, updateBulkCommandText, cts, source);
25442555
}
2545-
}
2556+
},
2557+
connectionToDoom: _connection.GetOpenTdsConnection()
25462558
);
25472559
return source.Task;
25482560
}
@@ -2609,7 +2621,8 @@ private Task CopyBatchesAsyncContinued(BulkCopySimpleResultSet internalResults,
26092621
}
26102622
},
26112623
onFailure: static (Exception _, object state) => ((SqlBulkCopy)state).CopyBatchesAsyncContinuedOnError(cleanupParser: false),
2612-
onCancellation: static (object state) => ((SqlBulkCopy)state).CopyBatchesAsyncContinuedOnError(cleanupParser: true)
2624+
onCancellation: static (object state) => ((SqlBulkCopy)state).CopyBatchesAsyncContinuedOnError(cleanupParser: true),
2625+
connectionToDoom: _connection.GetOpenTdsConnection()
26132626
);
26142627

26152628
return source.Task;
@@ -2675,7 +2688,8 @@ private Task CopyBatchesAsyncContinuedOnSuccess(BulkCopySimpleResultSet internal
26752688
// Always call back into CopyBatchesAsync
26762689
sqlBulkCopy.CopyBatchesAsync(internalResults, updateBulkCommandText, cts, source);
26772690
},
2678-
onFailure: static (Exception _, object state) => ((SqlBulkCopy)state).CopyBatchesAsyncContinuedOnError(cleanupParser: false)
2691+
onFailure: static (Exception _, object state) => ((SqlBulkCopy)state).CopyBatchesAsyncContinuedOnError(cleanupParser: false),
2692+
connectionToDoom: _connection.GetOpenTdsConnection()
26792693
);
26802694
return source.Task;
26812695
}
@@ -2698,6 +2712,9 @@ private Task CopyBatchesAsyncContinuedOnSuccess(BulkCopySimpleResultSet internal
26982712
private void CopyBatchesAsyncContinuedOnError(bool cleanupParser)
26992713
{
27002714
SqlInternalConnectionTds internalConnection = _connection.GetOpenTdsConnection();
2715+
#if NETFRAMEWORK
2716+
RuntimeHelpers.PrepareConstrainedRegions();
2717+
#endif
27012718
try
27022719
{
27032720
if ((cleanupParser) && (_parser != null) && (_stateObj != null))
@@ -2838,7 +2855,8 @@ private void WriteToServerInternalRestContinuedAsync(BulkCopySimpleResultSet int
28382855
}
28392856
}
28402857
}
2841-
}
2858+
},
2859+
connectionToDoom: _connection.GetOpenTdsConnection()
28422860
);
28432861
return;
28442862
}
@@ -2957,6 +2975,7 @@ private void WriteToServerInternalRestAsync(CancellationToken cts, TaskCompletio
29572975
_parserLock.Wait(canReleaseFromAnyThread: true);
29582976
WriteToServerInternalRestAsync(cts, source);
29592977
},
2978+
connectionToAbort: _connection,
29602979
onFailure: static (Exception _, object state) => ((StrongBox<CancellationTokenRegistration>)state).Value.Dispose(),
29612980
onCancellation: static (object state) => ((StrongBox<CancellationTokenRegistration>)state).Value.Dispose(),
29622981
exceptionConverter: (ex) => SQL.BulkLoadInvalidDestinationTable(_destinationTableName, ex));
@@ -3008,7 +3027,8 @@ private void WriteToServerInternalRestAsync(CancellationToken cts, TaskCompletio
30083027
if (internalResultsTask != null)
30093028
{
30103029
AsyncHelper.ContinueTaskWithState(internalResultsTask, source, this,
3011-
onSuccess: (object state) => ((SqlBulkCopy)state).WriteToServerInternalRestContinuedAsync(internalResultsTask.Result, cts, source)
3030+
onSuccess: (object state) => ((SqlBulkCopy)state).WriteToServerInternalRestContinuedAsync(internalResultsTask.Result, cts, source),
3031+
connectionToDoom: _connection.GetOpenTdsConnection()
30123032
);
30133033
}
30143034
else
@@ -3092,7 +3112,8 @@ private Task WriteToServerInternalAsync(CancellationToken ctoken)
30923112
{
30933113
sqlBulkCopy.WriteToServerInternalRestAsync(ctoken, source); // Passing the same completion which will be completed by the Callee.
30943114
}
3095-
}
3115+
},
3116+
connectionToDoom: _connection.GetOpenTdsConnection()
30963117
);
30973118
return resultTask;
30983119
}

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

+51-1
Original file line numberDiff line numberDiff line change
@@ -1233,11 +1233,35 @@ public override void ChangeDatabase(string database)
12331233
SqlStatistics statistics = null;
12341234
RepairInnerConnection();
12351235
SqlClientEventSource.Log.TryCorrelationTraceEvent("SqlConnection.ChangeDatabase | API | Correlation | Object Id {0}, Activity Id {1}, Database {2}", ObjectID, ActivityCorrelator.Current, database);
1236+
TdsParser bestEffortCleanupTarget = null;
1237+
1238+
#if NETFRAMEWORK
1239+
RuntimeHelpers.PrepareConstrainedRegions();
1240+
#endif
12361241
try
12371242
{
1243+
bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this);
12381244
statistics = SqlStatistics.StartTimer(Statistics);
12391245
InnerConnection.ChangeDatabase(database);
12401246
}
1247+
catch (System.OutOfMemoryException e)
1248+
{
1249+
Abort(e);
1250+
throw;
1251+
}
1252+
catch (System.StackOverflowException e)
1253+
{
1254+
Abort(e);
1255+
throw;
1256+
}
1257+
catch (System.Threading.ThreadAbortException e)
1258+
{
1259+
Abort(e);
1260+
#if NETFRAMEWORK
1261+
SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
1262+
#endif
1263+
throw;
1264+
}
12411265
finally
12421266
{
12431267
SqlStatistics.StopTimer(statistics);
@@ -1301,10 +1325,15 @@ public override void Close()
13011325
}
13021326

13031327
SqlStatistics statistics = null;
1304-
1328+
TdsParser bestEffortCleanupTarget = null;
13051329
Exception e = null;
1330+
1331+
#if NETFRAMEWORK
1332+
RuntimeHelpers.PrepareConstrainedRegions();
1333+
#endif
13061334
try
13071335
{
1336+
bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(this);
13081337
statistics = SqlStatistics.StartTimer(Statistics);
13091338

13101339
Task reconnectTask = _currentReconnectionTask;
@@ -1330,6 +1359,27 @@ public override void Close()
13301359
_statistics._closeTimestamp = ADP.TimerCurrent();
13311360
}
13321361
}
1362+
catch (System.OutOfMemoryException ex)
1363+
{
1364+
e = ex;
1365+
Abort(ex);
1366+
throw;
1367+
}
1368+
catch (System.StackOverflowException ex)
1369+
{
1370+
e = ex;
1371+
Abort(ex);
1372+
throw;
1373+
}
1374+
catch (System.Threading.ThreadAbortException ex)
1375+
{
1376+
e = ex;
1377+
Abort(ex);
1378+
#if NETFRAMEWORK
1379+
SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget);
1380+
#endif
1381+
throw;
1382+
}
13331383
catch (Exception ex)
13341384
{
13351385
e = ex;

0 commit comments

Comments
 (0)