Skip to content

Commit b1d3a82

Browse files
authored
Port double clean fix to netfx (#2843)
1 parent 069c052 commit b1d3a82

File tree

3 files changed

+26
-9
lines changed

3 files changed

+26
-9
lines changed

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

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7223,16 +7223,34 @@ internal TdsOperationStatus TryReadSqlValue(SqlBuffer value,
72237223
{
72247224
if (stateObj is not null)
72257225
{
7226-
// call to decrypt column keys has failed. The data wont be decrypted.
7227-
// Not setting the value to false, forces the driver to look for column value.
7228-
// Packet received from Key Vault will throws invalid token header.
7229-
if (stateObj.HasPendingData)
7226+
// Throwing an exception here circumvents the normal pending data checks and cleanup processes,
7227+
// so we need to ensure the appropriate state. Increment the _nextColumnDataToRead index because
7228+
// we already read the encrypted column data; Otherwise we'll double count and attempt to drain a
7229+
// corresponding number of bytes a second time. We don't want the rest of the pending data to
7230+
// interfere with future operations, so we must drain it. Set HasPendingData to false to indicate
7231+
// that we successfully drained the data.
7232+
7233+
// The SqlDataReader also maintains a state called dataReady. We need to set that to false if we've
7234+
// drained the data off the connection. Otherwise, a consumer that catches the exception may
7235+
// continue to use the reader and will timeout waiting to read data that doesn't exist.
7236+
7237+
// Order matters here. Must increment column before draining data.
7238+
// Update state objects after draining data.
7239+
7240+
if (stateObj._readerState != null)
72307241
{
7231-
// Drain the pending data now if setting the HasPendingData to false.
7232-
// SqlDataReader.TryCloseInternal can not drain if HasPendingData = false.
7233-
DrainData(stateObj);
7242+
stateObj._readerState._nextColumnDataToRead++;
72347243
}
7244+
7245+
DrainData(stateObj);
7246+
7247+
if (stateObj._readerState != null)
7248+
{
7249+
stateObj._readerState._dataReady = false;
7250+
}
7251+
72357252
stateObj.HasPendingData = false;
7253+
72367254
}
72377255
throw SQL.ColumnDecryptionFailed(columnName, null, e);
72387256
}

src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ColumnDecryptErrorTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Collections;
77
using System.Collections.Generic;
88
using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup;
9-
using Microsoft.Data.SqlClient.ManualTesting.Tests.SystemDataInternals;
109
using Xunit;
1110

1211
namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted

src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
<Compile Include="AlwaysEncrypted\ApiShould.cs" />
4848
<Compile Include="AlwaysEncrypted\BulkCopyAE.cs" />
4949
<Compile Include="AlwaysEncrypted\BulkCopyAEErrorMessage.cs" />
50+
<Compile Include="AlwaysEncrypted\ColumnDecryptErrorTests.cs" />
5051
<Compile Include="AlwaysEncrypted\End2EndSmokeTests.cs" />
5152
<Compile Include="AlwaysEncrypted\SqlBulkCopyTruncation.cs" />
5253
<Compile Include="AlwaysEncrypted\SqlNullValues.cs" />
@@ -74,7 +75,6 @@
7475
</ItemGroup>
7576
<ItemGroup Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net6.0')) AND ('$(TestSet)' == '' OR '$(TestSet)' == 'AE')">
7677
<Compile Include="AlwaysEncrypted\DateOnlyReadTests.cs" />
77-
<Compile Include="AlwaysEncrypted\ColumnDecryptErrorTests.cs" />
7878
</ItemGroup>
7979
<ItemGroup Condition="'$(TestSet)' == '' OR '$(TestSet)' == '1'">
8080
<Compile Include="SQL\AsyncTest\AsyncTimeoutTest.cs" />

0 commit comments

Comments
 (0)