Skip to content

Commit 4e9472a

Browse files
author
SqlClient Azure DevOps
committed
Merge in 'release/5.2' changes
2 parents e5ba166 + f059577 commit 4e9472a

File tree

14 files changed

+235
-92
lines changed

14 files changed

+235
-92
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6776,7 +6776,7 @@ internal SqlBatchCommand GetCurrentBatchCommand()
67766776
}
67776777
else
67786778
{
6779-
return _rpcArrayOf1[0].batchCommand;
6779+
return _rpcArrayOf1?[0].batchCommand;
67806780
}
67816781
}
67826782

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ private SqlConnection(SqlConnection connection)
227227
}
228228

229229
_accessToken = connection._accessToken;
230+
_accessTokenCallback = connection._accessTokenCallback;
230231
CacheConnectionStringProperties();
231232
}
232233

@@ -1940,7 +1941,7 @@ private bool TryOpen(TaskCompletionSource<DbConnectionInternal> retry, SqlConnec
19401941
}
19411942
}
19421943

1943-
_applyTransientFaultHandling = (!overrides.HasFlag(SqlConnectionOverrides.OpenWithoutRetry) && connectionOptions != null && connectionOptions.ConnectRetryCount > 0);
1944+
_applyTransientFaultHandling = (!overrides.HasFlag(SqlConnectionOverrides.OpenWithoutRetry) && retry == null && connectionOptions != null && connectionOptions.ConnectRetryCount > 0);
19441945

19451946
if (connectionOptions != null &&
19461947
(connectionOptions.Authentication == SqlAuthenticationMethod.SqlPassword ||
@@ -1969,7 +1970,7 @@ private bool TryOpen(TaskCompletionSource<DbConnectionInternal> retry, SqlConnec
19691970
// does not require GC.KeepAlive(this) because of ReRegisterForFinalize below.
19701971

19711972
// Set future transient fault handling based on connection options
1972-
_applyTransientFaultHandling = connectionOptions != null && connectionOptions.ConnectRetryCount > 0;
1973+
_applyTransientFaultHandling = (retry == null && connectionOptions != null && connectionOptions.ConnectRetryCount > 0);
19731974

19741975
var tdsInnerConnection = (SqlInternalConnectionTds)InnerConnection;
19751976

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7487,7 +7487,7 @@ internal SqlBatchCommand GetCurrentBatchCommand()
74877487
}
74887488
else
74897489
{
7490-
return _rpcArrayOf1[0].batchCommand;
7490+
return _rpcArrayOf1?[0].batchCommand;
74917491
}
74927492
}
74937493

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ private SqlConnection(SqlConnection connection)
429429
_credential = new SqlCredential(connection._credential.UserId, password);
430430
}
431431
_accessToken = connection._accessToken;
432+
_accessTokenCallback = connection._accessTokenCallback;
432433
_serverCertificateValidationCallback = connection._serverCertificateValidationCallback;
433434
_clientCertificateRetrievalCallback = connection._clientCertificateRetrievalCallback;
434435
_originalNetworkAddressInfo = connection._originalNetworkAddressInfo;
@@ -2144,7 +2145,7 @@ private bool TryOpen(TaskCompletionSource<DbConnectionInternal> retry, SqlConnec
21442145

21452146
bool result = false;
21462147

2147-
_applyTransientFaultHandling = (!overrides.HasFlag(SqlConnectionOverrides.OpenWithoutRetry) && connectionOptions != null && connectionOptions.ConnectRetryCount > 0);
2148+
_applyTransientFaultHandling = (!overrides.HasFlag(SqlConnectionOverrides.OpenWithoutRetry) && retry == null && connectionOptions != null && connectionOptions.ConnectRetryCount > 0);
21482149

21492150
if (connectionOptions != null &&
21502151
(connectionOptions.Authentication == SqlAuthenticationMethod.SqlPassword ||
@@ -2187,7 +2188,7 @@ private bool TryOpen(TaskCompletionSource<DbConnectionInternal> retry, SqlConnec
21872188
}
21882189

21892190
// Set future transient fault handling based on connection options
2190-
_applyTransientFaultHandling = connectionOptions != null && connectionOptions.ConnectRetryCount > 0;
2191+
_applyTransientFaultHandling = (retry == null && connectionOptions != null && connectionOptions.ConnectRetryCount > 0);
21912192

21922193
return result;
21932194
}

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsValueSetter.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -697,10 +697,34 @@ internal void SetDateTimeOffset(DateTimeOffset value)
697697
short offset = (short)value.Offset.TotalMinutes;
698698

699699
#if NETCOREAPP
700-
Span<byte> result = stackalloc byte[9];
700+
// In TDS protocol:
701+
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/786f5b8a-f87d-4980-9070-b9b7274c681d
702+
//
703+
// date is represented as one 3 - byte unsigned integer that represents the number of days since January 1, year 1.
704+
//
705+
// time(n) is represented as one unsigned integer that represents the number of 10^-n,
706+
// (10 to the power of negative n), second increments since 12 AM within a day.
707+
// The length, in bytes, of that integer depends on the scale n as follows:
708+
// 3 bytes if 0 <= n < = 2.
709+
// 4 bytes if 3 <= n < = 4.
710+
// 5 bytes if 5 <= n < = 7.
711+
// For example:
712+
// DateTimeOffset dateTimeOffset = new DateTimeOffset(2024, 1, 1, 23, 59, 59, TimeSpan.Zero); // using scale of 0
713+
// time = 23:59:59, scale is 1, is represented as 863990 in 3 bytes or { 246, 46, 13, 0, 0, 0, 0, 0 } in bytes array
714+
715+
Span<byte> result = stackalloc byte[8];
716+
717+
// https://learn.microsoft.com/en-us/dotnet/api/system.buffers.binary.binaryprimitives.writeint64bigendian?view=net-8.0
718+
// WriteInt64LittleEndian requires 8 bytes to write the value.
701719
BinaryPrimitives.WriteInt64LittleEndian(result, time);
702-
BinaryPrimitives.WriteInt32LittleEndian(result.Slice(5), days);
703-
_stateObj.WriteByteSpan(result.Slice(0, 8));
720+
// The DateTimeOffset length is variable depending on the scale, 1 to 7, used.
721+
// If length = 8, 8 - 5 = 3 bytes is used for time.
722+
// If length = 10, 10 - 5 = 5 bytes is used for time.
723+
_stateObj.WriteByteSpan(result.Slice(0, length - 5)); // this writes the time value to the state object using dynamic length based on the scale.
724+
725+
// Date is represented as 3 bytes. So, 3 bytes are written to the state object.
726+
BinaryPrimitives.WriteInt32LittleEndian(result, days);
727+
_stateObj.WriteByteSpan(result.Slice(0, 3));
704728
#else
705729
_stateObj.WriteByteArray(BitConverter.GetBytes(time), length - 5, 0); // time
706730
_stateObj.WriteByteArray(BitConverter.GetBytes(days), 3, 0); // date

src/Microsoft.Data.SqlClient/tests/FunctionalTests/CloneTests.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using System;
66
using System.Data;
7+
using System.Threading.Tasks;
78
using Xunit;
89

910
namespace Microsoft.Data.SqlClient.Tests
@@ -18,10 +19,19 @@ public void CloneSqlConnection()
1819
builder.ConnectTimeout = 1;
1920
builder.InitialCatalog = "northwinddb";
2021
SqlConnection connection = new SqlConnection(builder.ConnectionString);
22+
connection.AccessToken = Guid.NewGuid().ToString();
2123

2224
SqlConnection clonedConnection = (connection as ICloneable).Clone() as SqlConnection;
2325
Assert.Equal(connection.ConnectionString, clonedConnection.ConnectionString);
2426
Assert.Equal(connection.ConnectionTimeout, clonedConnection.ConnectionTimeout);
27+
Assert.Equal(connection.AccessToken, clonedConnection.AccessToken);
28+
Assert.NotEqual(connection, clonedConnection);
29+
30+
connection = new SqlConnection(builder.ConnectionString);
31+
connection.AccessTokenCallback = (ctx, token) =>
32+
Task.FromResult(new SqlAuthenticationToken(Guid.NewGuid().ToString(), DateTimeOffset.MaxValue));
33+
clonedConnection = (connection as ICloneable).Clone() as SqlConnection;
34+
Assert.Equal(connection.AccessTokenCallback, clonedConnection.AccessTokenCallback);
2535
Assert.NotEqual(connection, clonedConnection);
2636
}
2737

src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs

Lines changed: 4 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,6 @@ public async Task PreLoginEncryptionExcludedTest()
5757
Assert.Contains("The instance of SQL Server you attempted to connect to does not support encryption.", ex.Message, StringComparison.OrdinalIgnoreCase);
5858
}
5959

60-
[ConditionalTheory(typeof(TestUtility), nameof(TestUtility.IsNotArmProcess))]
61-
[InlineData(40613)]
62-
[InlineData(42108)]
63-
[InlineData(42109)]
64-
[PlatformSpecific(TestPlatforms.Windows)]
65-
public async Task TransientFaultTestAsync(uint errorCode)
66-
{
67-
using TransientFaultTDSServer server = TransientFaultTDSServer.StartTestServer(true, true, errorCode);
68-
SqlConnectionStringBuilder builder = new()
69-
{
70-
DataSource = "localhost," + server.Port,
71-
IntegratedSecurity = true,
72-
Encrypt = SqlConnectionEncryptOption.Optional
73-
};
74-
75-
using SqlConnection connection = new(builder.ConnectionString);
76-
await connection.OpenAsync();
77-
Assert.Equal(ConnectionState.Open, connection.State);
78-
}
79-
8060
[ConditionalTheory(typeof(TestUtility), nameof(TestUtility.IsNotArmProcess))]
8161
[InlineData(40613)]
8262
[InlineData(42108)]
@@ -100,54 +80,14 @@ public void TransientFaultTest(uint errorCode)
10080
}
10181
catch (Exception e)
10282
{
83+
if (null != connection)
84+
{
85+
Assert.Equal(ConnectionState.Closed, connection.State);
86+
}
10387
Assert.Fail(e.Message);
10488
}
10589
}
10690

107-
[ConditionalTheory(typeof(TestUtility), nameof(TestUtility.IsNotArmProcess))]
108-
[InlineData(40613)]
109-
[InlineData(42108)]
110-
[InlineData(42109)]
111-
[PlatformSpecific(TestPlatforms.Windows)]
112-
public void TransientFaultDisabledTestAsync(uint errorCode)
113-
{
114-
using TransientFaultTDSServer server = TransientFaultTDSServer.StartTestServer(true, true, errorCode);
115-
SqlConnectionStringBuilder builder = new()
116-
{
117-
DataSource = "localhost," + server.Port,
118-
IntegratedSecurity = true,
119-
ConnectRetryCount = 0,
120-
Encrypt = SqlConnectionEncryptOption.Optional
121-
};
122-
123-
using SqlConnection connection = new(builder.ConnectionString);
124-
Task<SqlException> e = Assert.ThrowsAsync<SqlException>(async () => await connection.OpenAsync());
125-
Assert.Equal(20, e.Result.Class);
126-
Assert.Equal(ConnectionState.Closed, connection.State);
127-
}
128-
129-
[ConditionalTheory(typeof(TestUtility), nameof(TestUtility.IsNotArmProcess))]
130-
[InlineData(40613)]
131-
[InlineData(42108)]
132-
[InlineData(42109)]
133-
[PlatformSpecific(TestPlatforms.Windows)]
134-
public void TransientFaultDisabledTest(uint errorCode)
135-
{
136-
using TransientFaultTDSServer server = TransientFaultTDSServer.StartTestServer(true, true, errorCode);
137-
SqlConnectionStringBuilder builder = new()
138-
{
139-
DataSource = "localhost," + server.Port,
140-
IntegratedSecurity = true,
141-
ConnectRetryCount = 0,
142-
Encrypt = SqlConnectionEncryptOption.Optional
143-
};
144-
145-
using SqlConnection connection = new(builder.ConnectionString);
146-
SqlException e = Assert.Throws<SqlException>(() => connection.Open());
147-
Assert.Equal(20, e.Class);
148-
Assert.Equal(ConnectionState.Closed, connection.State);
149-
}
150-
15191
[Fact]
15292
public void SqlConnectionDbProviderFactoryTest()
15393
{

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@
202202
<Compile Include="SQL\TransactionTest\TransactionEnlistmentTest.cs" />
203203
<Compile Include="SQL\UdtTest\SqlServerTypesTest.cs" />
204204
<Compile Include="SQL\UdtTest\UdtBulkCopyTest.cs" />
205+
<Compile Include="SQL\UdtTest\UdtDateTimeOffsetTest.cs" />
205206
<Compile Include="SQL\UdtTest\UdtTest.cs" />
206207
<Compile Include="SQL\UdtTest\UdtTest2.cs" />
207208
<Compile Include="SQL\UdtTest\UdtTestHelpers.cs" />

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,5 +474,29 @@ public static void SqlPasswordConnectionTest()
474474
using SqlConnection sqlConnection = new(b.ConnectionString);
475475
sqlConnection.Open();
476476
}
477+
478+
[ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))]
479+
public static void ConnectionFireInfoMessageEventOnUserErrorsShouldSucceed()
480+
{
481+
using (var connection = new SqlConnection(DataTestUtility.TCPConnectionString))
482+
{
483+
string command = "print";
484+
string commandParam = "OK";
485+
486+
connection.FireInfoMessageEventOnUserErrors = true;
487+
488+
connection.InfoMessage += (sender, args) =>
489+
{
490+
Assert.Equal(commandParam, args.Message);
491+
};
492+
493+
connection.Open();
494+
495+
using SqlCommand cmd = connection.CreateCommand();
496+
cmd.CommandType = System.Data.CommandType.Text;
497+
cmd.CommandText = $"{command} '{commandParam}'";
498+
cmd.ExecuteNonQuery();
499+
}
500+
}
477501
}
478502
}

0 commit comments

Comments
 (0)