Skip to content

Commit b0433f0

Browse files
authored
Merge AAsyncCallContext, cleanup for SqlDataReader merge (#2383)
Thanks again to @edwardneal ! * Merged AAsyncCallContext. Also changed netfx SqlDataReader to use the common class hierarchy, and made whitespace changes to SqlDataReader to make the netcore/netfx diff slightly shorter * Expanding use of CallerMemberName in SqlDataReader * Adjusted comments and variable names, added conditional compilation blocks. These aren't functional changes, but they do pare down the diff between netcore and netfx. Also sealed the Snapshot class in both codebases for performance improvements. * Reverted change to ObjectID following compilation and testing * Corrected a failing manual test * Further post-merge changes Keeps SqlDataReader in sync with main * Code review comments Also one AlwaysEncrypted sync/bugfix in SqlDataReader from netfx to netcore * Corrected conditional compilation directive
1 parent ca9272d commit b0433f0

File tree

5 files changed

+589
-503
lines changed

5 files changed

+589
-503
lines changed

src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@
156156
<Compile Include="$(CommonSourceRoot)Microsoft\Data\Sql\SqlNotificationRequest.cs">
157157
<Link>Microsoft\Data\Sql\SqlNotificationRequest.cs</Link>
158158
</Compile>
159+
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AAsyncCallContext.cs">
160+
<Link>Microsoft\Data\SqlClient\AAsyncCallContext.cs</Link>
161+
</Compile>
159162
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationProvider.cs">
160163
<Link>Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationProvider.cs</Link>
161164
</Compile>
@@ -647,7 +650,6 @@
647650
<Compile Include="Microsoft\Data\Common\DbConnectionOptions.cs" />
648651
<Compile Include="Microsoft\Data\ProviderBase\DbConnectionInternal.cs" />
649652
<Compile Include="Microsoft\Data\ProviderBase\DbConnectionPool.cs" />
650-
<Compile Include="Microsoft\Data\SqlClient\AAsyncCallContext.cs" />
651653
<Compile Include="Microsoft\Data\SqlClient\LocalDBAPI.cs" />
652654
<Compile Include="Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.NetCoreApp.cs" />
653655
<Compile Include="Microsoft\Data\SqlClient\SNI\ConcurrentQueueSemaphore.cs" />

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

Lines changed: 68 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,9 @@ internal virtual SmiExtendedMetaData[] GetInternalSmiMetaData()
323323
collation != null ? collation.LCID : _defaultLCID,
324324
collation != null ? collation.SqlCompareOptions : SqlCompareOptions.None,
325325
colMetaData.udt?.Type,
326-
false, // isMultiValued
327-
null, // fieldmetadata
328-
null, // extended properties
326+
isMultiValued: false,
327+
fieldMetaData: null,
328+
extendedProperties: null,
329329
colMetaData.column,
330330
typeSpecificNamePart1,
331331
typeSpecificNamePart2,
@@ -443,7 +443,7 @@ internal void Bind(TdsParserStateObject stateObj)
443443
_defaultLCID = _parser.DefaultLCID;
444444
}
445445

446-
#if NET6_0_OR_GREATER
446+
#if !NETFRAMEWORK
447447
[SuppressMessage("ReflectionAnalysis", "IL2111",
448448
Justification = "System.Type.TypeInitializer would not be used in dataType and providerSpecificDataType columns.")]
449449
#endif
@@ -763,11 +763,10 @@ private TdsOperationStatus TryCleanPartialRead()
763763
{
764764
AssertReaderState(requireData: true, permitAsync: true);
765765

766-
TdsOperationStatus result;
767-
768766
// VSTS DEVDIV2 380446: It is possible that read attempt we are cleaning after ended with partially
769767
// processed header (if it falls between network packets). In this case the first thing to do is to
770768
// finish reading the header, otherwise code will start treating unread header as TDS payload.
769+
TdsOperationStatus result;
771770
if (_stateObj._partialHeaderBytesRead > 0)
772771
{
773772
result = _stateObj.TryProcessHeader();
@@ -1154,7 +1153,9 @@ private TdsOperationStatus TryConsumeMetaData()
11541153
// NOTE: We doom connection for TdsParserState.Closed since it indicates that it is in some abnormal and unstable state, probably as a result of
11551154
// closing from another thread. In general, TdsParserState.Closed does not necessitate dooming the connection.
11561155
if (_parser.Connection != null)
1156+
{
11571157
_parser.Connection.DoomThisConnection();
1158+
}
11581159
throw SQL.ConnectionDoomed();
11591160
}
11601161
bool ignored;
@@ -1252,7 +1253,7 @@ override public IEnumerator GetEnumerator()
12521253
}
12531254

12541255
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml' path='docs/members[@name="SqlDataReader"]/GetFieldType/*' />
1255-
#if NET6_0_OR_GREATER
1256+
#if !NETFRAMEWORK
12561257
[SuppressMessage("ReflectionAnalysis", "IL2093:MismatchOnMethodReturnValueBetweenOverrides",
12571258
Justification = "Annotations for DbDataReader was not shipped in net6.0")]
12581259
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)]
@@ -1273,7 +1274,7 @@ override public Type GetFieldType(int i)
12731274
}
12741275
}
12751276

1276-
#if NET6_0_OR_GREATER
1277+
#if !NETFRAMEWORK
12771278
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)]
12781279
#endif
12791280
private Type GetFieldTypeInternal(_SqlMetaData metaData)
@@ -1368,7 +1369,7 @@ override public string GetName(int i)
13681369
}
13691370

13701371
/// <include file='../../../../../../../doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml' path='docs/members[@name="SqlDataReader"]/GetProviderSpecificFieldType/*' />
1371-
#if NET8_0_OR_GREATER
1372+
#if !NETFRAMEWORK && NET8_0_OR_GREATER
13721373
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)]
13731374
#endif
13741375
override public Type GetProviderSpecificFieldType(int i)
@@ -1387,7 +1388,7 @@ override public Type GetProviderSpecificFieldType(int i)
13871388
}
13881389
}
13891390

1390-
#if NET6_0_OR_GREATER
1391+
#if !NETFRAMEWORK
13911392
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)]
13921393
#endif
13931394
private Type GetProviderSpecificFieldTypeInternal(_SqlMetaData metaData)
@@ -1712,7 +1713,9 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf
17121713
}
17131714

17141715
if (dataIndex < 0)
1716+
{
17151717
throw ADP.NegativeParameter(nameof(dataIndex));
1718+
}
17161719

17171720
if (dataIndex < _columnDataBytesRead)
17181721
{
@@ -1730,14 +1733,20 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf
17301733

17311734
// if bad buffer index, throw
17321735
if (bufferIndex < 0 || bufferIndex >= buffer.Length)
1736+
{
17331737
throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, nameof(bufferIndex));
1738+
}
17341739

17351740
// if there is not enough room in the buffer for data
17361741
if (length + bufferIndex > buffer.Length)
1742+
{
17371743
throw ADP.InvalidBufferSizeOrIndex(length, bufferIndex);
1744+
}
17381745

17391746
if (length < 0)
1747+
{
17401748
throw ADP.InvalidDataLength(length);
1749+
}
17411750

17421751
// Skip if needed
17431752
if (cb > 0)
@@ -1774,7 +1783,9 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf
17741783
// note that since we are caching in an array, and arrays aren't 64 bit ready yet,
17751784
// we need can cast to int if the dataIndex is in range
17761785
if (dataIndex < 0)
1786+
{
17771787
throw ADP.NegativeParameter(nameof(dataIndex));
1788+
}
17781789

17791790
if (dataIndex > int.MaxValue)
17801791
{
@@ -1828,9 +1839,13 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf
18281839
{
18291840
// help the user out in the case where there's less data than requested
18301841
if ((ndataIndex + length) > cbytes)
1842+
{
18311843
cbytes = cbytes - ndataIndex;
1844+
}
18321845
else
1846+
{
18331847
cbytes = length;
1848+
}
18341849
}
18351850

18361851
Buffer.BlockCopy(data, ndataIndex, buffer, bufferIndex, cbytes);
@@ -1844,15 +1859,21 @@ private TdsOperationStatus TryGetBytesInternal(int i, long dataIndex, byte[] buf
18441859
cbytes = data.Length;
18451860

18461861
if (length < 0)
1862+
{
18471863
throw ADP.InvalidDataLength(length);
1864+
}
18481865

18491866
// if bad buffer index, throw
18501867
if (bufferIndex < 0 || bufferIndex >= buffer.Length)
1868+
{
18511869
throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, nameof(bufferIndex));
1870+
}
18521871

18531872
// if there is not enough room in the buffer for data
18541873
if (cbytes + bufferIndex > buffer.Length)
1874+
{
18551875
throw ADP.InvalidBufferSizeOrIndex(cbytes, bufferIndex);
1876+
}
18561877

18571878
throw;
18581879
}
@@ -1868,7 +1889,6 @@ internal int GetBytesInternalSequential(int i, byte[] buffer, int index, int len
18681889
throw ADP.AsyncOperationPending();
18691890
}
18701891

1871-
TdsOperationStatus result;
18721892
int value;
18731893
SqlStatistics statistics = null;
18741894
Debug.Assert(_stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
@@ -1877,7 +1897,7 @@ internal int GetBytesInternalSequential(int i, byte[] buffer, int index, int len
18771897
statistics = SqlStatistics.StartTimer(Statistics);
18781898
SetTimeout(timeoutMilliseconds ?? _defaultTimeoutMilliseconds);
18791899

1880-
result = TryReadColumnHeader(i);
1900+
TdsOperationStatus result = TryReadColumnHeader(i);
18811901
if (result != TdsOperationStatus.Done)
18821902
{
18831903
throw SQL.SynchronousCallMayNotPend();
@@ -2161,17 +2181,23 @@ override public long GetChars(int i, long dataIndex, char[] buffer, int bufferIn
21612181

21622182
// if dataIndex outside of data range, return 0
21632183
if (ndataIndex < 0 || ndataIndex >= cchars)
2184+
{
21642185
return 0;
2186+
}
21652187

21662188
try
21672189
{
21682190
if (ndataIndex < cchars)
21692191
{
21702192
// help the user out in the case where there's less data than requested
21712193
if ((ndataIndex + length) > cchars)
2194+
{
21722195
cchars = cchars - ndataIndex;
2196+
}
21732197
else
2198+
{
21742199
cchars = length;
2200+
}
21752201
}
21762202

21772203
Array.Copy(_columnDataChars, ndataIndex, buffer, bufferIndex, cchars);
@@ -2186,15 +2212,21 @@ override public long GetChars(int i, long dataIndex, char[] buffer, int bufferIn
21862212
cchars = _columnDataChars.Length;
21872213

21882214
if (length < 0)
2215+
{
21892216
throw ADP.InvalidDataLength(length);
2217+
}
21902218

21912219
// if bad buffer index, throw
21922220
if (bufferIndex < 0 || bufferIndex >= buffer.Length)
2221+
{
21932222
throw ADP.InvalidDestinationBufferIndex(buffer.Length, bufferIndex, nameof(bufferIndex));
2223+
}
21942224

21952225
// if there is not enough room in the buffer for data
21962226
if (cchars + bufferIndex > buffer.Length)
2227+
{
21972228
throw ADP.InvalidBufferSizeOrIndex(cchars, bufferIndex);
2229+
}
21982230

21992231
throw;
22002232
}
@@ -2244,7 +2276,9 @@ private long GetCharsFromPlpData(int i, long dataIndex, char[] buffer, int buffe
22442276
// _columnDataCharsRead is 0 and dataIndex > _columnDataCharsRead is true below.
22452277
// In both cases we will clean decoder
22462278
if (dataIndex == 0)
2279+
{
22472280
_stateObj._plpdecoder = null;
2281+
}
22482282

22492283
bool isUnicode = _metaData[i].metaType.IsNCharType;
22502284

@@ -2617,7 +2651,7 @@ private object GetSqlValueFromSqlBufferInternal(SqlBuffer data, _SqlMetaData met
26172651
}
26182652
else
26192653
{
2620-
throw ADP.DataReaderClosed(nameof(GetSqlValueFromSqlBufferInternal));
2654+
throw ADP.DataReaderClosed();
26212655
}
26222656
}
26232657
else
@@ -2817,7 +2851,7 @@ private object GetValueFromSqlBufferInternal(SqlBuffer data, _SqlMetaData metaDa
28172851
}
28182852
else
28192853
{
2820-
throw ADP.DataReaderClosed(nameof(GetValueFromSqlBufferInternal));
2854+
throw ADP.DataReaderClosed();
28212855
}
28222856
}
28232857
}
@@ -2896,7 +2930,7 @@ private T GetFieldValueFromSqlBufferInternal<T>(SqlBuffer data, _SqlMetaData met
28962930
{
28972931
return (T)(object)data.DateTime;
28982932
}
2899-
#if NET6_0_OR_GREATER
2933+
#if !NETFRAMEWORK
29002934
else if (typeof(T) == typeof(DateOnly) && dataType == typeof(DateTime) && _typeSystem > SqlConnectionString.TypeSystem.SQLServer2005)
29012935
{
29022936
return (T)(object)data.DateOnly;
@@ -3557,7 +3591,7 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more)
35573591
SqlStatistics statistics = null;
35583592
using (TryEventScope.Create("SqlDataReader.TryReadInternal | API | Object Id {0}", ObjectID))
35593593
{
3560-
#if !NET6_0_OR_GREATER
3594+
#if NETFRAMEWORK
35613595
RuntimeHelpers.PrepareConstrainedRegions();
35623596
#endif
35633597

@@ -3708,10 +3742,10 @@ private TdsOperationStatus TryReadInternal(bool setTimeout, out bool more)
37083742
if ((!_sharedState._dataReady) && (_stateObj.HasPendingData))
37093743
{
37103744
byte token;
3711-
TdsOperationStatus debugResult = _stateObj.TryPeekByte(out token);
3712-
if (debugResult != TdsOperationStatus.Done)
3745+
result = _stateObj.TryPeekByte(out token);
3746+
if (result != TdsOperationStatus.Done)
37133747
{
3714-
return debugResult;
3748+
return result;
37153749
}
37163750

37173751
Debug.Assert(TdsParser.IsValidTdsToken(token), $"DataReady is false, but next token is invalid: {token,-2:X2}");
@@ -3808,7 +3842,7 @@ private TdsOperationStatus TryReadColumnData()
38083842

38093843
TdsOperationStatus result = _parser.TryReadSqlValue(_data[_sharedState._nextColumnDataToRead], columnMetaData, (int)_sharedState._columnDataBytesRemaining, _stateObj,
38103844
_command != null ? _command.ColumnEncryptionSetting : SqlCommandColumnEncryptionSetting.UseConnectionSetting,
3811-
columnMetaData.column);
3845+
columnMetaData.column, _command);
38123846
if (result != TdsOperationStatus.Done)
38133847
{
38143848
// will read UDTs as VARBINARY.
@@ -3970,7 +4004,6 @@ internal TdsOperationStatus TryReadColumnInternal(int i, bool readHeaderOnly = f
39704004
}
39714005
else
39724006
{
3973-
// we have read past the column somehow, this is an error
39744007
Debug.Assert(false, "We have read past the column somehow, this is an error");
39754008
}
39764009
}
@@ -4310,7 +4343,6 @@ internal TdsOperationStatus TrySetMetaData(_SqlMetaDataSet metaData, bool moreIn
43104343

43114344
if (metaData != null)
43124345
{
4313-
TdsOperationStatus result;
43144346
// we are done consuming metadata only if there is no moreInfo
43154347
if (!moreInfo)
43164348
{
@@ -4321,7 +4353,7 @@ internal TdsOperationStatus TrySetMetaData(_SqlMetaDataSet metaData, bool moreIn
43214353
// Peek, and if row token present, set _hasRows true since there is a
43224354
// row in the result
43234355
byte b;
4324-
result = _stateObj.TryPeekByte(out b);
4356+
TdsOperationStatus result = _stateObj.TryPeekByte(out b);
43254357
if (result != TdsOperationStatus.Done)
43264358
{
43274359
return result;
@@ -5201,7 +5233,7 @@ override public Task<T> GetFieldValueAsync<T>(int i, CancellationToken cancellat
52015233
var metaData = _metaData;
52025234
if ((data != null) && (metaData != null))
52035235
{
5204-
return Task.FromResult<T>(GetFieldValueFromSqlBufferInternal<T>(data[i], metaData[i], isAsync:false));
5236+
return Task.FromResult<T>(GetFieldValueFromSqlBufferInternal<T>(data[i], metaData[i], isAsync: false));
52055237
}
52065238
else
52075239
{
@@ -5241,7 +5273,7 @@ override public Task<T> GetFieldValueAsync<T>(int i, CancellationToken cancellat
52415273
{
52425274
_stateObj._shouldHaveEnoughData = true;
52435275
#endif
5244-
return Task.FromResult(GetFieldValueInternal<T>(i, isAsync:true));
5276+
return Task.FromResult(GetFieldValueInternal<T>(i, isAsync: true));
52455277
#if DEBUG
52465278
}
52475279
finally
@@ -5305,19 +5337,24 @@ private static Task<T> GetFieldValueAsyncExecute<T>(Task task, object state)
53055337
reader.PrepareForAsyncContinuation();
53065338
}
53075339

5308-
TdsOperationStatus result;
53095340
if (typeof(T) == typeof(Stream) || typeof(T) == typeof(TextReader) || typeof(T) == typeof(XmlReader))
53105341
{
5311-
if (reader.IsCommandBehavior(CommandBehavior.SequentialAccess) && reader._sharedState._dataReady && reader.TryReadColumnInternal(context._columnIndex, readHeaderOnly: true) == TdsOperationStatus.Done)
5342+
if (reader.IsCommandBehavior(CommandBehavior.SequentialAccess) && reader._sharedState._dataReady)
53125343
{
5313-
return Task.FromResult<T>(reader.GetFieldValueFromSqlBufferInternal<T>(reader._data[columnIndex], reader._metaData[columnIndex], isAsync: true));
5344+
bool internalReadSuccess = false;
5345+
internalReadSuccess = reader.TryReadColumnInternal(context._columnIndex, readHeaderOnly: true) == TdsOperationStatus.Done;
5346+
5347+
if (internalReadSuccess)
5348+
{
5349+
return Task.FromResult<T>(reader.GetFieldValueFromSqlBufferInternal<T>(reader._data[columnIndex], reader._metaData[columnIndex], isAsync: true));
5350+
}
53145351
}
53155352
}
53165353

5317-
result = reader.TryReadColumn(columnIndex, setTimeout: false);
5354+
TdsOperationStatus result = reader.TryReadColumn(columnIndex, setTimeout: false);
53185355
if (result == TdsOperationStatus.Done)
53195356
{
5320-
return Task.FromResult<T>(reader.GetFieldValueFromSqlBufferInternal<T>(reader._data[columnIndex], reader._metaData[columnIndex], isAsync:false));
5357+
return Task.FromResult<T>(reader.GetFieldValueFromSqlBufferInternal<T>(reader._data[columnIndex], reader._metaData[columnIndex], isAsync: false));
53215358
}
53225359
else
53235360
{
@@ -5683,7 +5720,7 @@ private void CompleteAsyncCall<T>(Task<T> task, SqlDataReaderBaseAsyncCallContex
56835720
}
56845721

56855722

5686-
internal class Snapshot
5723+
internal sealed class Snapshot
56875724
{
56885725
public bool _dataReady;
56895726
public bool _haltRead;

src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@
202202
<Compile Include="$(CommonSourceRoot)Microsoft\Data\Sql\SqlNotificationRequest.cs">
203203
<Link>Microsoft\Data\Sql\SqlNotificationRequest.cs</Link>
204204
</Compile>
205+
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AAsyncCallContext.cs">
206+
<Link>Microsoft\Data\SqlClient\AAsyncCallContext.cs</Link>
207+
</Compile>
205208
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationTimeoutRetryHelper.cs">
206209
<Link>Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationTimeoutRetryHelper.cs</Link>
207210
</Compile>

0 commit comments

Comments
 (0)