From 6fdc1f31ea817c93cbe7e067728b467e2ed9ed30 Mon Sep 17 00:00:00 2001 From: Javad Date: Fri, 12 Aug 2022 14:16:04 -0700 Subject: [PATCH 01/78] 3.1.1 release notes for main branch (#1716) Co-authored-by: Parminder Kaur <88398605+Kaur-Parminder@users.noreply.github.com> --- CHANGELOG.md | 9 +++++ release-notes/3.1/3.1.1.md | 77 +++++++++++++++++++++++++++++++++++++ release-notes/3.1/3.1.md | 1 + release-notes/3.1/README.md | 1 + 4 files changed, 88 insertions(+) create mode 100644 release-notes/3.1/3.1.1.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 596ec8a5e3..9e7cbfc70d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -232,6 +232,15 @@ This update brings the below changes over the previous release: - Optimized async method allocations in .NET Framework by porting changes from .NET Core. [#1084](https://github.com/dotnet/SqlClient/pull/1084) - Various code improvements [#902](https://github.com/dotnet/SqlClient/pull/902) [#925](https://github.com/dotnet/SqlClient/pull/925) [#933](https://github.com/dotnet/SqlClient/pull/933) [#934](https://github.com/dotnet/SqlClient/pull/934) [#1024](https://github.com/dotnet/SqlClient/pull/1024) [#1057](https://github.com/dotnet/SqlClient/pull/1057) [#1122](https://github.com/dotnet/SqlClient/pull/1122) [#1133]((https://github.com/dotnet/SqlClient/pull/1133)) [#1134](https://github.com/dotnet/SqlClient/pull/1134) [#1141](https://github.com/dotnet/SqlClient/pull/1141) [#1187](https://github.com/dotnet/SqlClient/pull/1187) [#1188](https://github.com/dotnet/SqlClient/pull/1188) [#1223](https://github.com/dotnet/SqlClient/pull/1223) [#1225](https://github.com/dotnet/SqlClient/pull/1225) [#1226](https://github.com/dotnet/SqlClient/pull/1226) +## [Stable release 3.1.1] - 2022-08-12 + +### Fixed + +- Fixed null SqlBinary as rowversion. [#1700](https://github.com/dotnet/SqlClient/pull/1700) +- Fixed Kerberos authentication failure when using .NET 6. [#1696](https://github.com/dotnet/SqlClient/pull/1696) +- Fixed NullReferenceException during Azure Active Directory authentication. [#1695](https://github.com/dotnet/SqlClient/pull/1695) +- Removed union overlay design and use reflection in `SqlTypeWorkarounds`. [#1699](https://github.com/dotnet/SqlClient/pull/1699) + ## [Stable release 3.1.0] - 2022-03-30 ### Added diff --git a/release-notes/3.1/3.1.1.md b/release-notes/3.1/3.1.1.md new file mode 100644 index 0000000000..d7cb669712 --- /dev/null +++ b/release-notes/3.1/3.1.1.md @@ -0,0 +1,77 @@ +# Release Notes + +## Microsoft.Data.SqlClient 3.1.1 released 12 August 2022 + +This update brings the below changes over the previous release: + +### Fixed + +- Fixed null SqlBinary as rowversion. [#1700](https://github.com/dotnet/SqlClient/pull/1700) +- Fixed Kerberos authentication failure when using .NET 6. [#1696](https://github.com/dotnet/SqlClient/pull/1696) +- Fixed NullReferenceException during Azure Active Directory authentication. [#1695](https://github.com/dotnet/SqlClient/pull/1695) +- Removed union overlay design and use reflection in `SqlTypeWorkarounds`. [#1699](https://github.com/dotnet/SqlClient/pull/1699) + +## Target Platform Support + +- .NET Framework 4.6+ (Windows x86, Windows x64) +- .NET Core 2.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) +- .NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Dependencies + +#### .NET Framework 4.61 + +- Microsoft.Data.SqlClient.SNI 3.0.0 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.14.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 5.6.0 +- Microsoft.IdentityModel.JsonWebTokens 5.6.0 +- System.Configuration.ConfigurationManager 4.7.0 +- System.Text.Encodings.Web 4.7.2 + +#### .NET Core 2.1 + +- Microsoft.Data.SqlClient.SNI.runtime 3.0.0 +- Microsoft.Win32.Registry 4.7.0 +- System.Security.Principal.Windows 4.7.0 +- System.Text.Encoding.CodePages 4.7.0 +- System.Text.Encodings.Web 4.7.2 +- System.Diagnostics.DiagnosticSource 4.7.0 +- System.Configuration.ConfigurationManager 4.7.0 +- System.Runtime.Caching 4.7.0 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.14.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 5.6.0 +- Microsoft.IdentityModel.JsonWebTokens 5.6.0 + +#### .NET Core 3.1 + +- Microsoft.Data.SqlClient.SNI.runtime 3.0.0 +- Microsoft.Win32.Registry 4.7.0 +- System.Security.Principal.Windows 4.7.0 +- System.Text.Encoding.CodePages 4.7.0 +- System.Text.Encodings.Web 4.7.2 +- System.Diagnostics.DiagnosticSource 4.7.0 +- System.Configuration.ConfigurationManager 4.7.0 +- System.Runtime.Caching 4.7.0 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.14.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 5.6.0 +- Microsoft.IdentityModel.JsonWebTokens 5.6.0 + +#### .NET Standard + +- Microsoft.Data.SqlClient.SNI.runtime 3.0.0 +- Microsoft.Win32.Registry 4.7.0 +- System.Buffers 4.5.1 +- System.Memory 4.5.4 +- System.Security.Principal.Windows 4.7.0 +- System.Text.Encoding.CodePages 4.7.0 +- System.Text.Encodings.Web 4.7.2 +- System.Runtime.Caching 4.7.0 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.14.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 5.6.0 +- Microsoft.IdentityModel.JsonWebTokens 5.6.0 +- System.Configuration.ConfigurationManager 4.7.0 +- System.Runtime.Loader 4.3.0 diff --git a/release-notes/3.1/3.1.md b/release-notes/3.1/3.1.md index d6a478c0ef..6e4d68e534 100644 --- a/release-notes/3.1/3.1.md +++ b/release-notes/3.1/3.1.md @@ -4,4 +4,5 @@ The following Microsoft.Data.SqlClient 3.1 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/08/12 | 3.1.1 | [release notes](3.1.1.md) | | 2022/03/30 | 3.1.0 | [release notes](3.1.0.md) | diff --git a/release-notes/3.1/README.md b/release-notes/3.1/README.md index d6a478c0ef..6e4d68e534 100644 --- a/release-notes/3.1/README.md +++ b/release-notes/3.1/README.md @@ -4,4 +4,5 @@ The following Microsoft.Data.SqlClient 3.1 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/08/12 | 3.1.1 | [release notes](3.1.1.md) | | 2022/03/30 | 3.1.0 | [release notes](3.1.0.md) | From bd21d762e2362256aab49866e5ad9797b4a037b4 Mon Sep 17 00:00:00 2001 From: Parminder Kaur <88398605+Kaur-Parminder@users.noreply.github.com> Date: Thu, 18 Aug 2022 17:34:43 -0700 Subject: [PATCH 02/78] Test | Replacing Binary formatter with DataContractSerializer (#1590) --- .../tests/FunctionalTests/SqlErrorTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs index 7c9208ac2a..13b78449f4 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs @@ -5,7 +5,7 @@ using System; using System.IO; using System.Reflection; -using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Serialization; using Xunit; namespace Microsoft.Data.SqlClient.Tests @@ -20,16 +20,16 @@ public class SqlErrorTest [Fact] public static void SqlErrorSerializationTest() { - var formatter = new BinaryFormatter(); + DataContractSerializer serializer = new DataContractSerializer(typeof(SqlError)); SqlError expected = CreateError(); SqlError actual = null; using (var stream = new MemoryStream()) { try { - formatter.Serialize(stream, expected); + serializer.WriteObject(stream, expected); stream.Position = 0; - actual = (SqlError)formatter.Deserialize(stream); + actual = (SqlError)serializer.ReadObject(stream); } catch (Exception ex) { From 2cd34d66888145b53335e2cf02bf1ccde04ce806 Mon Sep 17 00:00:00 2001 From: Javad Date: Thu, 25 Aug 2022 15:27:11 -0700 Subject: [PATCH 03/78] Documentation | Improve AAD link and consistency. (#1738) --- doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml index 3e30e1cae6..d139d0e1ec 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml @@ -528,7 +528,7 @@ End Module |Application Name|N/A|The name of the application. If no application name is provided, 'Framework Microsoft SqlClient Data Provider' when running on .NET Framework and 'Core Microsoft SqlClient Data Provider' otherwise.

An application name can be 128 characters or less.| |AttachDBFilename

-or-

Extended Properties

-or-

Initial File Name|N/A|The name of the primary database file, including the full path name of an attachable database. AttachDBFilename is only supported for primary data files with an .mdf extension.

If the value of the AttachDBFileName key is specified in the connection string, the database is attached and becomes the default database for the connection.

If this key is not specified and if the database was previously attached, the database will not be reattached. The previously attached database will be used as the default database for the connection.

If this key is specified together with the AttachDBFileName key, the value of this key will be used as the alias. However, if the name is already used in another attached database, the connection will fail.

The path may be absolute or relative by using the DataDirectory substitution string. If DataDirectory is used, the database file must exist within a subdirectory of the directory pointed to by the substitution string. **Note:** Remote server, HTTP, and UNC path names are not supported.

The database name must be specified with the keyword 'database' (or one of its aliases) as in the following:

"AttachDbFileName=|DataDirectory|\data\YourDB.mdf;integrated security=true;database=YourDatabase"

An error will be generated if a log file exists in the same directory as the data file and the 'database' keyword is used when attaching the primary data file. In this case, remove the log file. Once the database is attached, a new log file will be automatically generated based on the physical path.| |Attestation Protocol|NotSpecified|Gets or sets the value of Attestation Protocol.

When no value is specified, secure enclaves are disabled on the connection.

Valid values are:
`AAS`
`HGS`
`None` (Only valid in v3.1 and v4.1+))| -|Authentication|N/A|The authentication method used for [Connecting to SQL Database By Using Azure Active Directory Authentication](https://azure.microsoft.com/documentation/articles/sql-database-aad-authentication/#7-connect-to-your-database-by-using-azure-active-directory-identities).

Valid values are:

`Active Directory Integrated`, `Active Directory Interactive`, `Active Directory Password`, `Active Directory Service Principal`, `Active Directory Device Code Flow`, `Active Directory Managed Identity`, `Active Directory MSI`, `Active Directory Default`, `Sql Password`.| +|Authentication|N/A|The authentication method used for [Connecting to SQL Database By Using Azure Active Directory Authentication](https://azure.microsoft.com/documentation/articles/sql-database-aad-authentication/#7-connect-to-your-database-by-using-azure-active-directory-identities).

Valid values are:

`Active Directory Integrated`, `Active Directory Interactive`, `Active Directory Password`, `Active Directory Service Principal`, `Active Directory Device Code Flow`, `Active Directory Managed Identity`, `Active Directory MSI`, `Active Directory Default`, `Sql Password`.

For additional information see [Using Azure Active Directory authentication with SqlClient](https://docs.microsoft.com/sql/connect/ado-net/sql/azure-active-directory-authentication?view=sql-server-ver15).| |Column Encryption Setting|disabled|Enables or disables [Always Encrypted](/sql/relational-databases/security/encryption/always-encrypted-database-engine) functionality for the connection. Supported values are: `enabled` and `disabled`| |Command Timeout|30|The default wait time (in seconds) before terminating the attempt to execute a command and generating an error.

Valid values are greater than or equal to 0 and less than or equal to 2147483647.| |Connect Retry Count

-or-

ConnectRetryCount|1|Controls the number of reconnection attempts after the client identifies an idle connection failure. Valid values are 0 to 255. The default is 1. 0 means do not attempt to reconnect (disable connection resiliency).

For additional information about idle connection resiliency, see [Technical Article - Idle Connection Resiliency](https://go.microsoft.com/fwlink/?LinkId=393996).| @@ -541,7 +541,7 @@ End Module |Enlist|'true'|`true` indicates that the SQL Server connection pooler automatically enlists the connection in the creation thread's current transaction context.| |Failover Partner|N/A|The name of the failover partner server where database mirroring is configured.

If the value of this key is "", then **Initial Catalog** must be present, and its value must not be "".

The server name can be 128 characters or less.

If you specify a failover partner but the failover partner server is not configured for database mirroring and the primary server (specified with the Server keyword) is not available, then the connection will fail.

If you specify a failover partner and the primary server is not configured for database mirroring, the connection to the primary server (specified with the Server keyword) will succeed if the primary server is available.| |Failover Partner SPN

-or-

FailoverPartnerSPN|N/A|The SPN for the failover partner. The default value is an empty string, which causes SqlClient to use the default, driver-generated SPN.

(Only available in v5.0+)| -|Host Name In Certificate

-or-

HostNameInCertificate|N/A|Available starting in version 5.0.

The host name to use when validating the server certificate. When not specified, the server name from the Data Source is used for certificate validation.| +|Host Name In Certificate

-or-

HostNameInCertificate|N/A|The host name to use when validating the server certificate. When not specified, the server name from the Data Source is used for certificate validation.

(Only available in v5.0+)| |Initial Catalog

-or-

Database|N/A|The name of the database.

The database name can be 128 characters or less.| |Integrated Security

-or-

Trusted_Connection|'false'|When `false`, User ID and Password are specified in the connection. When `true`, the current Windows account credentials are used for authentication.

Recognized values are `true`, `false`, `yes`, `no`, and `sspi` (strongly recommended), which is equivalent to `true`.

If User ID and Password are specified and Integrated Security is set to true, the User ID and Password will be ignored and Integrated Security will be used.

is a more secure way to specify credentials for a connection that uses SQL Server Authentication (`Integrated Security=false`).| |IP Address Preference

-or-

IPAddressPreference|IPv4First|The IP address family preference when establishing TCP connections. If `Transparent Network IP Resolution` (in .NET Framework) or `Multi Subnet Failover` is set to true, this setting has no effect. Supported values include:

`IPAddressPreference=IPv4First`

`IPAddressPreference=IPv6First`

`IPAddressPreference=UsePlatformDefault`| From ceaa33d023c9e80c25744dbe7b9e578ce61d5068 Mon Sep 17 00:00:00 2001 From: David Engel Date: Tue, 30 Aug 2022 09:32:09 -0700 Subject: [PATCH 04/78] [Fix] Hang on infinite timeout and managed SNI (#1742) * Fix for issue #1733 - hang on infinite timeout Also fix SSRP when DataSource is an IP address --- .../Microsoft/Data/SqlClient/SNI/SNICommon.cs | 10 ++++++ .../Data/SqlClient/SNI/SNITcpHandle.cs | 18 ++-------- .../src/Microsoft/Data/SqlClient/SNI/SSRP.cs | 35 +++++++------------ .../SQL/ConnectivityTests/ConnectivityTest.cs | 15 ++++++++ .../SQL/InstanceNameTest/InstanceNameTest.cs | 16 +++++++-- 5 files changed, 53 insertions(+), 41 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs index 6980eb09f2..815f4e13d7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Net; using System.Net.Security; using System.Security.Cryptography.X509Certificates; @@ -194,6 +195,15 @@ internal static bool ValidateSslServerCertificate(string targetServerName, X509C } } + internal static IPAddress[] GetDnsIpAddresses(string serverName) + { + using (TrySNIEventScope.Create(nameof(GetDnsIpAddresses))) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Getting DNS host entries for serverName {0}.", args0: serverName); + return Dns.GetHostAddresses(serverName); + } + } + /// /// Sets last error encountered for SNI /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index df34f6c31b..02445d83b1 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -299,14 +299,7 @@ private Socket TryConnectParallel(string hostName, int port, TimeSpan ts, bool i Socket availableSocket = null; Task connectTask; - Task serverAddrTask = Dns.GetHostAddressesAsync(hostName); - bool complete = serverAddrTask.Wait(ts); - - // DNS timed out - don't block - if (!complete) - return null; - - IPAddress[] serverAddresses = serverAddrTask.Result; + IPAddress[] serverAddresses = SNICommon.GetDnsIpAddresses(hostName); if (serverAddresses.Length > MaxParallelIpAddresses) { @@ -358,14 +351,7 @@ private static Socket Connect(string serverName, int port, TimeSpan timeout, boo { SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "IP preference : {0}", Enum.GetName(typeof(SqlConnectionIPAddressPreference), ipPreference)); - Task serverAddrTask = Dns.GetHostAddressesAsync(serverName); - bool complete = serverAddrTask.Wait(timeout); - - // DNS timed out - don't block - if (!complete) - return null; - - IPAddress[] ipAddresses = serverAddrTask.Result; + IPAddress[] ipAddresses = SNICommon.GetDnsIpAddresses(serverName); string IPv4String = null; string IPv6String = null; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs index 655a54df7e..e51175059a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SSRP.cs @@ -170,7 +170,16 @@ private static byte[] SendUDPRequest(string browserHostname, int port, byte[] re Debug.Assert(port >= 0 && port <= 65535, "Invalid port"); Debug.Assert(requestPacket != null && requestPacket.Length > 0, "requestPacket should not be null or 0-length array"); - bool isIpAddress = IPAddress.TryParse(browserHostname, out IPAddress address); + if (IPAddress.TryParse(browserHostname, out IPAddress address)) + { + SsrpResult response = SendUDPRequest(new IPAddress[] { address }, port, requestPacket, allIPsInParallel); + if (response != null && response.ResponsePacket != null) + return response.ResponsePacket; + else if (response != null && response.Error != null) + throw response.Error; + else + return null; + } TimeSpan ts = default; // In case the Timeout is Infinite, we will receive the max value of Int64 as the tick count @@ -181,27 +190,7 @@ private static byte[] SendUDPRequest(string browserHostname, int port, byte[] re ts = ts.Ticks < 0 ? TimeSpan.FromTicks(0) : ts; } - IPAddress[] ipAddresses = null; - if (!isIpAddress) - { - Task serverAddrTask = Dns.GetHostAddressesAsync(browserHostname); - bool taskComplete; - try - { - taskComplete = serverAddrTask.Wait(ts); - } - catch (AggregateException ae) - { - throw ae.InnerException; - } - - // If DNS took too long, need to return instead of blocking - if (!taskComplete) - return null; - - ipAddresses = serverAddrTask.Result; - } - + IPAddress[] ipAddresses = SNICommon.GetDnsIpAddresses(browserHostname); Debug.Assert(ipAddresses.Length > 0, "DNS should throw if zero addresses resolve"); switch (ipPreference) @@ -278,7 +267,7 @@ private static SsrpResult SendUDPRequest(IPAddress[] ipAddresses, int port, byte for (int i = 0; i < ipAddresses.Length; i++) { IPEndPoint endPoint = new IPEndPoint(ipAddresses[i], port); - tasks.Add(Task.Factory.StartNew(() => SendUDPRequest(endPoint, requestPacket))); + tasks.Add(Task.Factory.StartNew(() => SendUDPRequest(endPoint, requestPacket), cts.Token)); } List> completedTasks = new(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs index 32115b96d1..08113cbd3a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs @@ -88,6 +88,21 @@ public static void EnvironmentHostNameSPIDTest() Assert.True(false, "No non-empty hostname found for the application"); } + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public static async void ConnectionTimeoutInfiniteTest() + { + // Exercise the special-case infinite connect timeout code path + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString) + { + ConnectTimeout = 0 // Infinite + }; + + using SqlConnection conn = new(builder.ConnectionString); + CancellationTokenSource cts = new(30000); + // Will throw TaskCanceledException and fail the test in the event of a hang + await conn.OpenAsync(cts.Token); + } + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] public static void ConnectionTimeoutTestWithThread() { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs index 1c1869f7f1..6edc9f00a6 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; @@ -12,7 +13,7 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests { public static class InstanceNameTest { - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse), nameof(DataTestUtility.AreConnStringsSetup))] public static void ConnectToSQLWithInstanceNameTest() { SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); @@ -20,9 +21,9 @@ public static void ConnectToSQLWithInstanceNameTest() bool proceed = true; string dataSourceStr = builder.DataSource.Replace("tcp:", ""); string[] serverNamePartsByBackSlash = dataSourceStr.Split('\\'); + string hostname = serverNamePartsByBackSlash[0]; if (!dataSourceStr.Contains(",") && serverNamePartsByBackSlash.Length == 2) { - string hostname = serverNamePartsByBackSlash[0]; proceed = !string.IsNullOrWhiteSpace(hostname) && IsBrowserAlive(hostname); } @@ -31,6 +32,17 @@ public static void ConnectToSQLWithInstanceNameTest() using SqlConnection connection = new(builder.ConnectionString); connection.Open(); connection.Close(); + + if (builder.Encrypt != SqlConnectionEncryptOption.Strict) + { + // Exercise the IP address-specific code in SSRP + IPAddress[] addresses = Dns.GetHostAddresses(hostname); + builder.DataSource = builder.DataSource.Replace(hostname, addresses[0].ToString()); + builder.TrustServerCertificate = true; + using SqlConnection connection2 = new(builder.ConnectionString); + connection2.Open(); + connection2.Close(); + } } } From 81231cef246fa2c28a7371d40fd52c6065ea41bd Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Tue, 30 Aug 2022 16:26:00 -0700 Subject: [PATCH 05/78] 2.1.5 release notes [main branch] (#1730) --- CHANGELOG.md | 8 ++++ release-notes/2.1/2.1.5.md | 82 +++++++++++++++++++++++++++++++++++++ release-notes/2.1/2.1.md | 1 + release-notes/2.1/README.md | 1 + 4 files changed, 92 insertions(+) create mode 100644 release-notes/2.1/2.1.5.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e7cbfc70d..27b71bf962 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -278,6 +278,14 @@ This update brings the below changes over the previous release: ### Breaking Changes - Modified column encryption key store provider registrations to give built-in system providers precedence over providers registered on connection and command instances. [#1101](https://github.com/dotnet/SqlClient/pull/1101) +## [Stable Release 2.1.5] - 2022-08-30 + +### Fixed + +- Added CommandText length validation when using stored procedure command types. [#1726](https://github.com/dotnet/SqlClient/pull/1726) +- Fixed Kerberos authentication failure when using .NET 6. [#1727](https://github.com/dotnet/SqlClient/pull/1727) +- Removed union overlay design and use reflection in `SqlTypeWorkarounds`. [#1729](https://github.com/dotnet/SqlClient/pull/1729) + ## [Stable Release 2.1.4] - 2021-09-20 ### Fixed diff --git a/release-notes/2.1/2.1.5.md b/release-notes/2.1/2.1.5.md new file mode 100644 index 0000000000..1617db1db9 --- /dev/null +++ b/release-notes/2.1/2.1.5.md @@ -0,0 +1,82 @@ +# Release Notes + +## Microsoft.Data.SqlClient 2.1.5 released 30 August 2022 + +This update brings the below changes over the previous stable release: + +### Fixed + +- Added CommandText length validation when using stored procedure command types. [#1726](https://github.com/dotnet/SqlClient/pull/1726) +- Fixed Kerberos authentication failure when using .NET 6. [#1727](https://github.com/dotnet/SqlClient/pull/1727) +- Removed union overlay design and used reflection in `SqlTypeWorkarounds`. [#1729](https://github.com/dotnet/SqlClient/pull/1729) + +### Target Platform Support + +- .NET Framework 4.6+ (Windows x86, Windows x64) +- .NET Core 2.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) +- .NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Ensure connections fail when encryption is required + +In scenarios where client encryption libraries were disabled or unavailable, it was possible for unencrypted connections to be made when Encrypt was set to true or the server required encryption. + +### Dependencies + +#### .NET Framework + +- Microsoft.Data.SqlClient.SNI 2.1.1 +- Microsoft.Identity.Client 4.21.1 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 + +#### .NET Core 2.1 + +- Microsoft.Data.SqlClient.SNI.runtime 2.1.1 +- Microsoft.Win32.Registry 4.7.0 +- System.Security.Principal.Windows 4.7.0 +- System.Text.Encoding.CodePages 4.7.0 +- System.Diagnostics.DiagnosticSource 4.7.0 +- System.Configuration.ConfigurationManager 4.7.0 +- System.Runtime.Caching 4.7.0 +- Microsoft.Identity.Client 4.21.1 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 + +#### .NET Core 3.1 + +- Microsoft.Data.SqlClient.SNI.runtime 2.1.1 +- Microsoft.Win32.Registry 4.7.0 +- System.Security.Principal.Windows 4.7.0 +- System.Text.Encoding.CodePages 4.7.0 +- System.Diagnostics.DiagnosticSource 4.7.0 +- System.Configuration.ConfigurationManager 4.7.0 +- System.Runtime.Caching 4.7.0 +- Microsoft.Identity.Client 4.21.1 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 + +#### .NET Standard 2.0 + +- Microsoft.Data.SqlClient.SNI.runtime 2.1.1 +- Microsoft.Win32.Registry 4.7.0 +- System.Buffers 4.5.1 +- System.Memory 4.5.4 +- System.Security.Principal.Windows 4.7.0 +- System.Text.Encoding.CodePages 4.7.0 +- System.Runtime.Caching 4.7.0 +- Microsoft.Identity.Client 4.21.1 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 + +#### .NET Standard 2.1 + +- Microsoft.Data.SqlClient.SNI.runtime 2.1.1 +- Microsoft.Win32.Registry 4.7.0 +- System.Buffers 4.5.1 +- System.Memory 4.5.4 +- System.Security.Principal.Windows 4.7.0 +- System.Text.Encoding.CodePages 4.7.0 +- System.Runtime.Caching 4.7.0 +- Microsoft.Identity.Client 4.21.1 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 diff --git a/release-notes/2.1/2.1.md b/release-notes/2.1/2.1.md index e35a6f987b..2c149e041b 100644 --- a/release-notes/2.1/2.1.md +++ b/release-notes/2.1/2.1.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 2.1 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/08/30 | 2.1.5 | [release notes](2.1.5.md) | | 2021/09/20 | 2.1.4 | [release notes](2.1.4.md) | | 2021/05/21 | 2.1.3 | [release notes](2.1.3.md) | | 2021/03/03 | 2.1.2 | [release notes](2.1.2.md) | diff --git a/release-notes/2.1/README.md b/release-notes/2.1/README.md index e35a6f987b..2c149e041b 100644 --- a/release-notes/2.1/README.md +++ b/release-notes/2.1/README.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 2.1 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/08/30 | 2.1.5 | [release notes](2.1.5.md) | | 2021/09/20 | 2.1.4 | [release notes](2.1.4.md) | | 2021/05/21 | 2.1.3 | [release notes](2.1.3.md) | | 2021/03/03 | 2.1.2 | [release notes](2.1.2.md) | From 4cb2b6728b0895de339d643390c0a01ff84e3d80 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Wed, 31 Aug 2022 16:01:17 -0700 Subject: [PATCH 06/78] Fix | Default UTF8 collation conflict (#1739) --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 8 +-- .../SQL/Utf8SupportTest/Utf8SupportTest.cs | 63 ++++++++++++++++++- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index e116885cd2..6daca4d771 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -3136,21 +3136,15 @@ private bool TryProcessEnvChange(int tokenLength, TdsParserStateObject stateObj, _defaultCollation = env._newCollation; _defaultLCID = env._newCollation.LCID; - int newCodePage = GetCodePage(env._newCollation, stateObj); // UTF8 collation if (env._newCollation.IsUTF8) { _defaultEncoding = Encoding.UTF8; - - if (newCodePage != _defaultCodePage) - { - _defaultCodePage = newCodePage; - } } else { - + int newCodePage = GetCodePage(env._newCollation, stateObj); if (newCodePage != _defaultCodePage) { _defaultCodePage = newCodePage; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Utf8SupportTest/Utf8SupportTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Utf8SupportTest/Utf8SupportTest.cs index c6bc56d9f4..6aae0c555a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Utf8SupportTest/Utf8SupportTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Utf8SupportTest/Utf8SupportTest.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; +using System.Text; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -29,6 +31,65 @@ public static void CheckSupportUtf8ConnectionProperty() } } - // TODO: Write tests using UTF8 collations + + // skip creating database on Azure + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse))] + public static void UTF8databaseTest() + { + const string letters = @"!\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f€\u0081‚ƒ„…†‡ˆ‰Š‹Œ\u008dŽ\u008f\u0090‘’“”•–—˜™š›œ\u009džŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"; + string dbName = DataTestUtility.GetUniqueNameForSqlServer("UTF8databaseTest", false); + string tblName = "Table1"; + + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); + builder.InitialCatalog = "master"; + + using SqlConnection cn = new(builder.ConnectionString); + cn.Open(); + + try + { + PrepareDatabaseUTF8(cn, dbName, tblName, letters); + + builder.InitialCatalog = dbName; + using SqlConnection cnnTest = new(builder.ConnectionString); + // creating a databse is a time consumer action and could be retried. + SqlRetryLogicOption retryOption = new() { NumberOfTries = 3, DeltaTime = TimeSpan.FromMilliseconds(200) }; + cnnTest.RetryLogicProvider = SqlConfigurableRetryFactory.CreateIncrementalRetryProvider(retryOption); + cnnTest.Open(); + + using SqlCommand cmd = cnnTest.CreateCommand(); + cmd.CommandText = $"SELECT * FROM {tblName}"; + + using SqlDataReader reader = cmd.ExecuteReader(); + + Assert.True(reader.Read(), "The test table should have a row!"); + object[] data = new object[1]; + reader.GetSqlValues(data); + Assert.Equal(letters, data[0].ToString()); + reader.Close(); + cnnTest.Close(); + } + finally + { + DataTestUtility.DropDatabase(cn, dbName); + } + } + + private static void PrepareDatabaseUTF8(SqlConnection cnn, string dbName, string tblName, string letters) + { + StringBuilder sb = new(); + + using SqlCommand cmd = cnn.CreateCommand(); + + cmd.CommandText = $"CREATE DATABASE [{dbName}] COLLATE Latin1_General_100_CI_AS_SC_UTF8;"; + cmd.ExecuteNonQuery(); + + sb.AppendLine($"CREATE TABLE [{dbName}].dbo.[{tblName}] (col VARCHAR(7633) COLLATE Latin1_General_100_CI_AS_SC);"); + sb.AppendLine($"INSERT INTO [{dbName}].dbo.[{tblName}] VALUES (@letters);"); + + cmd.Parameters.Add(new SqlParameter("letters", letters)); + cmd.CommandText = sb.ToString(); + cmd.ExecuteNonQuery(); + } } } From 2c3eb19bd71e8e33ef6ecc39bbee76f5b59fc6e5 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Tue, 13 Sep 2022 13:13:17 -0700 Subject: [PATCH 07/78] 4.0.2 release notes [main branch] (#1756) --- CHANGELOG.md | 16 ++++++++ release-notes/4.0/4.0.2.md | 80 +++++++++++++++++++++++++++++++++++++ release-notes/4.0/4.0.md | 1 + release-notes/4.0/README.md | 1 + 4 files changed, 98 insertions(+) create mode 100644 release-notes/4.0/4.0.2.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 27b71bf962..a64e3f9175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -119,6 +119,22 @@ This update brings the below changes over the previous release: - Added new Attestation Protocol `None` for `VBS` enclave types. This protocol will allow users to forgo enclave attestation for VBS enclaves. [#1419](https://github.com/dotnet/SqlClient/pull/1419) [#1425](https://github.com/dotnet/SqlClient/pull/1425) +## [Stable release 4.0.2] - 2022-09-13 + +### Fixed + +- Fixed connection failure by not requiring Certificate Revocation List (CRL) check during authentication. [#1718](https://github.com/dotnet/SqlClient/pull/1718) +- Parallelize SSRP requests on Linux and macOS when MultiSubNetFailover is specified. [#1720](https://github.com/dotnet/SqlClient/pull/1720), [#1747](https://github.com/dotnet/SqlClient/pull/1747) +- Added CommandText length validation when using stored procedure command types. [#1721](https://github.com/dotnet/SqlClient/pull/1721) +- Fixed NullReferenceException during Azure Active Directory authentication. [#1722](https://github.com/dotnet/SqlClient/pull/1722) +- Fixed null SqlBinary as rowversion. [#1724](https://github.com/dotnet/SqlClient/pull/1724) +- Fixed table's collation overriding with default UTF8 collation. [#1750](https://github.com/dotnet/SqlClient/pull/1750) + +## Changed + +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET Core/Standard dependency) version to `v4.0.1` [#1754](https://github.com/dotnet/SqlClient/pull/1754), which includes the fix for AppDomain crash introducing in issue [#1418](https://github.com/dotnet/SqlClient/issues/1418) +- Various code improvements: [#1723](https://github.com/dotnet/SqlClient/pull/1723) + ## [Stable release 4.0.1] - 2022-01-17 ### Added diff --git a/release-notes/4.0/4.0.2.md b/release-notes/4.0/4.0.2.md new file mode 100644 index 0000000000..96c485a613 --- /dev/null +++ b/release-notes/4.0/4.0.2.md @@ -0,0 +1,80 @@ +# Release Notes + +## Microsoft.Data.SqlClient 4.0.2 released 13 September 2022 + +This update brings the below changes over the previous preview release: + +### Fixed + +- Fixed connection failure by not requiring Certificate Revocation List (CRL) check during authentication. [#1718](https://github.com/dotnet/SqlClient/pull/1718) +- Parallelize SSRP requests on Linux and macOS when MultiSubNetFailover is specified. [#1720](https://github.com/dotnet/SqlClient/pull/1720), [#1747](https://github.com/dotnet/SqlClient/pull/1747) +- Added CommandText length validation when using stored procedure command types. [#1721](https://github.com/dotnet/SqlClient/pull/1721) +- Fixed NullReferenceException during Azure Active Directory authentication. [#1722](https://github.com/dotnet/SqlClient/pull/1722) +- Fixed null SqlBinary as rowversion. [#1724](https://github.com/dotnet/SqlClient/pull/1724) +- Fixed table's collation overriding with default UTF8 collation. [#1750](https://github.com/dotnet/SqlClient/pull/1750) + +## Changed + +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET Core/Standard dependency) version to `v4.0.1` [#1754](https://github.com/dotnet/SqlClient/pull/1754), which includes the fix for AppDomain crash introducing in issue [#1418](https://github.com/dotnet/SqlClient/issues/1418) +- Various code improvements: [#1723](https://github.com/dotnet/SqlClient/pull/1723) + +## Target Platform Support + +- .NET Framework 4.6.1+ (Windows x86, Windows x64) +- .NET Core 3.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) +- .NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Dependencies + +#### .NET Framework + +- Microsoft.Data.SqlClient.SNI 4.0.1 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.22.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.IO 4.3.0 +- System.Runtime.InteropServices.RuntimeInformation 4.3.0 +- System.Security.Cryptography.Algorithms 4.3.1 +- System.Security.Cryptography.Primitives 4.3.0 +- System.Text.Encodings.Web 4.7.2 + +#### .NET Core + +- Microsoft.Data.SqlClient.SNI.runtime 4.0.1 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.22.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.Diagnostics.DiagnosticSource 5.0.0 +- System.IO 4.3.0 +- System.Runtime.Caching 5.0.0 +- System.Text.Encoding.CodePages 5.0.0 +- System.Text.Encodings.Web 4.7.2 +- System.Resources.ResourceManager 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 + +#### .NET Standard + +- Microsoft.Data.SqlClient.SNI.runtime 4.0.1 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.22.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.IO 4.3.0 +- System.Runtime.Caching 5.0.0 +- System.Text.Encoding.CodePages 5.0.0 +- System.Text.Encodings.Web 4.7.2 +- System.Resources.ResourceManager 4.3.0 +- System.Runtime.Loader 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 diff --git a/release-notes/4.0/4.0.md b/release-notes/4.0/4.0.md index c6a93a0724..8d0ffeceb8 100644 --- a/release-notes/4.0/4.0.md +++ b/release-notes/4.0/4.0.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 4.0 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/09/13 | 4.0.2 | [release notes](4.0.2.md) | | 2022/01/17 | 4.0.1 | [release notes](4.0.1.md) | | 2021/11/18 | 4.0.0 | [release notes](4.0.0.md) | diff --git a/release-notes/4.0/README.md b/release-notes/4.0/README.md index c6a93a0724..8d0ffeceb8 100644 --- a/release-notes/4.0/README.md +++ b/release-notes/4.0/README.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 4.0 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/09/13 | 4.0.2 | [release notes](4.0.2.md) | | 2022/01/17 | 4.0.1 | [release notes](4.0.1.md) | | 2021/11/18 | 4.0.0 | [release notes](4.0.0.md) | From 7d348eb0c985b34ce5b76a9330c57bc1015c93ff Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Tue, 13 Sep 2022 15:52:23 -0700 Subject: [PATCH 08/78] 4.1.1 release notes [main branch] (#1759) --- CHANGELOG.md | 16 ++++++++ release-notes/4.1/4.1.1.md | 80 +++++++++++++++++++++++++++++++++++++ release-notes/4.1/4.1.md | 1 + release-notes/4.1/README.md | 1 + 4 files changed, 98 insertions(+) create mode 100644 release-notes/4.1/4.1.1.md diff --git a/CHANGELOG.md b/CHANGELOG.md index a64e3f9175..8209ff0d2e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -113,6 +113,22 @@ This update brings the below changes over the previous release: - Sqlstream, SqlInternalTransaction and MetaDataUtilsSmi are moved to shared folder. [#1337](https://github.com/dotnet/SqlClient/pull/1337), [#1346](https://github.com/dotnet/SqlClient/pull/1346) and [#1339](https://github.com/dotnet/SqlClient/pull/1339) - Various code improvements: [#1197](https://github.com/dotnet/SqlClient/pull/1197), [#1313](https://github.com/dotnet/SqlClient/pull/1313),[#1330](https://github.com/dotnet/SqlClient/pull/1330),[#1366](https://github.com/dotnet/SqlClient/pull/1366), [#1435](https://github.com/dotnet/SqlClient/pull/1435),[#1478](https://github.com/dotnet/SqlClient/pull/1478) +## [Stable release 4.1.1] - 2022-09-13 + +### Fixed + +- Fixed connection failure by not requiring Certificate Revocation List (CRL) check during authentication. [#1706](https://github.com/dotnet/SqlClient/pull/1706) +- Parallelize SSRP requests on Linux and macOS when MultiSubNetFailover is specified. [#1708](https://github.com/dotnet/SqlClient/pull/1708), [#1746](https://github.com/dotnet/SqlClient/pull/1746) +- Added CommandText length validation when using stored procedure command types. [#1709](https://github.com/dotnet/SqlClient/pull/1709) +- Fixed NullReferenceException during Azure Active Directory authentication. [#1710](https://github.com/dotnet/SqlClient/pull/1710) +- Fixed null SqlBinary as rowversion. [#1712](https://github.com/dotnet/SqlClient/pull/1712) +- Fixed table's collation overriding with default UTF8 collation. [#1749](https://github.com/dotnet/SqlClient/pull/1749) + +## Changed + +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET Core/Standard dependency) version to `v4.0.1` [#1755](https://github.com/dotnet/SqlClient/pull/1755), which includes the fix for AppDomain crash introducing in issue [#1418](https://github.com/dotnet/SqlClient/issues/1418) +- Various code improvements: [#1711](https://github.com/dotnet/SqlClient/pull/1711) + ## [Stable release 4.1.0] - 2022-01-31 ### Added diff --git a/release-notes/4.1/4.1.1.md b/release-notes/4.1/4.1.1.md new file mode 100644 index 0000000000..f6fbc70f19 --- /dev/null +++ b/release-notes/4.1/4.1.1.md @@ -0,0 +1,80 @@ +# Release Notes + +## Microsoft.Data.SqlClient 4.1.1 released 13 September 2022 + +This update brings the below changes over the previous preview release: + +### Fixed + +- Fixed connection failure by not requiring Certificate Revocation List (CRL) check during authentication. [#1706](https://github.com/dotnet/SqlClient/pull/1706) +- Parallelize SSRP requests on Linux and macOS when MultiSubNetFailover is specified. [#1708](https://github.com/dotnet/SqlClient/pull/1708), [#1746](https://github.com/dotnet/SqlClient/pull/1746) +- Added CommandText length validation when using stored procedure command types. [#1709](https://github.com/dotnet/SqlClient/pull/1709) +- Fixed NullReferenceException during Azure Active Directory authentication. [#1710](https://github.com/dotnet/SqlClient/pull/1710) +- Fixed null SqlBinary as rowversion. [#1712](https://github.com/dotnet/SqlClient/pull/1712) +- Fixed table's collation overriding with default UTF8 collation. [#1749](https://github.com/dotnet/SqlClient/pull/1749) + +## Changed + +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET Core/Standard dependency) version to `v4.0.1` [#1755](https://github.com/dotnet/SqlClient/pull/1755), which includes the fix for AppDomain crash introducing in issue [#1418](https://github.com/dotnet/SqlClient/issues/1418) +- Various code improvements: [#1711](https://github.com/dotnet/SqlClient/pull/1711) + +## Target Platform Support + +- .NET Framework 4.6.1+ (Windows x86, Windows x64) +- .NET Core 3.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) +- .NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Dependencies + +#### .NET Framework + +- Microsoft.Data.SqlClient.SNI 4.0.1 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.22.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.IO 4.3.0 +- System.Runtime.InteropServices.RuntimeInformation 4.3.0 +- System.Security.Cryptography.Algorithms 4.3.1 +- System.Security.Cryptography.Primitives 4.3.0 +- System.Text.Encodings.Web 4.7.2 + +#### .NET Core + +- Microsoft.Data.SqlClient.SNI.runtime 4.0.1 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.22.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.Diagnostics.DiagnosticSource 5.0.0 +- System.IO 4.3.0 +- System.Runtime.Caching 5.0.0 +- System.Text.Encoding.CodePages 5.0.0 +- System.Text.Encodings.Web 4.7.2 +- System.Resources.ResourceManager 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 + +#### .NET Standard + +- Microsoft.Data.SqlClient.SNI.runtime 4.0.1 +- Azure.Identity 1.3.0 +- Microsoft.Identity.Client 4.22.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.8.0 +- Microsoft.IdentityModel.JsonWebTokens 6.8.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.IO 4.3.0 +- System.Runtime.Caching 5.0.0 +- System.Text.Encoding.CodePages 5.0.0 +- System.Text.Encodings.Web 4.7.2 +- System.Resources.ResourceManager 4.3.0 +- System.Runtime.Loader 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 \ No newline at end of file diff --git a/release-notes/4.1/4.1.md b/release-notes/4.1/4.1.md index 86560228d7..a310caa5f7 100644 --- a/release-notes/4.1/4.1.md +++ b/release-notes/4.1/4.1.md @@ -4,4 +4,5 @@ The following Microsoft.Data.SqlClient 4.1 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/09/13 | 4.1.1 | [release notes](4.1.1.md) | | 2022/01/31 | 4.1.0 | [release notes](4.1.0.md) | diff --git a/release-notes/4.1/README.md b/release-notes/4.1/README.md index 86560228d7..a310caa5f7 100644 --- a/release-notes/4.1/README.md +++ b/release-notes/4.1/README.md @@ -4,4 +4,5 @@ The following Microsoft.Data.SqlClient 4.1 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/09/13 | 4.1.1 | [release notes](4.1.1.md) | | 2022/01/31 | 4.1.0 | [release notes](4.1.0.md) | From 4dafe91c793436ac43a933b646b3b24dc2477143 Mon Sep 17 00:00:00 2001 From: David Engel Date: Mon, 26 Sep 2022 12:42:33 -0700 Subject: [PATCH 09/78] Doc | Porting guide addition (#1769) --- porting-cheat-sheet.md | 1 + 1 file changed, 1 insertion(+) diff --git a/porting-cheat-sheet.md b/porting-cheat-sheet.md index e27836717f..d09c16c77e 100644 --- a/porting-cheat-sheet.md +++ b/porting-cheat-sheet.md @@ -51,6 +51,7 @@ For .NET Framework projects it may be necessary to include the following in your |--|--| | Can use DateTime object as value for SqlParameter with type `DbType.Time`. | Must use TimeSpan object as value for SqlParameter with type `DbType.Time`. | | Using DateTime object as value for SqlParameter with type `DbType.Date` would send date and time to SQL Server. | DateTime object's time components will be truncated when sent to SQL Server using `DbType.Date`. | +| `Encrypt` defaults to `false`. | Starting in v4.0, default encryption settings were made more secure, requiring opt-in to non-encrypted connections. `Encrypt` defaults to `true` and the driver will always validate the server certificate based on `TrustServerCertificate`. (Previously, server certificates would only be validated if `Encrypt` was also `true`.)

If you need to turn off encryption, you must specify `Encrypt=false`. If you use encryption with a self-signed certificate on the server, you must specify `TrustServerCertificate=true`.

In v5.0, `SqlConnectionStringBuilder.Encrypt` is no longer a `bool`. It's a `SqlConnectionEncryptOption` with multiple values to support `Strict` encryption mode (TDS 8.0). It uses implicit conversion operators to remain code-backwards compatible, but it was a binary breaking change, requiring a recompile of applications. | ## Contribute to this Cheat Sheet From 50ec923cec1d768ac1e4753ad484edc5c5fe6914 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com> Date: Tue, 27 Sep 2022 09:58:04 -0700 Subject: [PATCH 10/78] Make SqlConnectionEncryptOption string parser public (#1771) * Make SqlConnectionEncryptOption string parser public * Address feedback * Fix non-nullables * Fix docs * Apply suggestions from code review Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Co-authored-by: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> --- .../SqlConnectionEncryptOption.xml | 25 +++++++++++ .../netcore/ref/Microsoft.Data.SqlClient.cs | 4 ++ .../netfx/ref/Microsoft.Data.SqlClient.cs | 6 +++ .../SqlClient/SqlConnectionEncryptOption.cs | 31 +++++++++++--- .../SqlConnectionStringBuilderTest.cs | 41 +++++++++++++++++++ 5 files changed, 101 insertions(+), 6 deletions(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml index f5f40255a3..6db9533606 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml @@ -12,6 +12,31 @@ Implicit conversions have been added to maintain backwards compatibility with bo ]]> + + + Converts the specified string representation of a logical value to its equivalent. + + A string containing the value to convert. + + An object that is equivalent to contained in . + + + Throws exception if provided is not convertible to type. + + + + + Converts the specified string representation of a logical value to its equivalent and returns a value that indicates whether the conversion succeeded. + + A string containing the value to convert. + + An object that is equivalent to contained in . if conversion fails. + + + if the parameter was converted successfully; otherwise, . + + This method does not throw an exception if conversion fails. + Specifies that TLS encryption is optional when connecting to the server. If the server requires encryption, encryption will be negotiated. diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs index deb4ad0bf9..db0842d4f2 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs @@ -506,6 +506,10 @@ public enum SqlConnectionIPAddressPreference /// public sealed class SqlConnectionEncryptOption { + /// + public static SqlConnectionEncryptOption Parse(string value) => throw null; + /// + public static bool TryParse(string value, out SqlConnectionEncryptOption result) => throw null; /// public static SqlConnectionEncryptOption Optional => throw null; diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs index 29cd583c94..5d78fb574e 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs @@ -923,6 +923,12 @@ public enum SqlConnectionIPAddressPreference /// public sealed class SqlConnectionEncryptOption { + /// + public static SqlConnectionEncryptOption Parse(string value) => throw null; + + /// + public static bool TryParse(string value, out SqlConnectionEncryptOption result) => throw null; + /// public static SqlConnectionEncryptOption Optional => throw null; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionEncryptOption.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionEncryptOption.cs index 6d488ce872..fde49b3980 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionEncryptOption.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionEncryptOption.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System; using Microsoft.Data.Common; namespace Microsoft.Data.SqlClient @@ -29,28 +30,46 @@ private SqlConnectionEncryptOption(string value) _value = value; } - internal static SqlConnectionEncryptOption Parse(string value) + /// + public static SqlConnectionEncryptOption Parse(string value) { - switch (value.ToLower()) + if (TryParse(value, out SqlConnectionEncryptOption result)) + { + return result; + } + else + { + throw ADP.InvalidConnectionOptionValue(SqlConnectionString.KEY.Encrypt); + } + } + + /// + public static bool TryParse(string value, out SqlConnectionEncryptOption result) + { + switch (value?.ToLower()) { case TRUE_LOWER: case YES_LOWER: case MANDATORY_LOWER: { - return Mandatory; + result = Mandatory; + return true; } case FALSE_LOWER: case NO_LOWER: case OPTIONAL_LOWER: { - return Optional; + result = Optional; + return true; } case STRICT_LOWER: { - return Strict; + result = Strict; + return true; } default: - throw ADP.InvalidConnectionOptionValue(SqlConnectionString.KEY.Encrypt); + result = null; + return false; } } diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs index 14247ac8a5..828152c4ab 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs @@ -385,6 +385,47 @@ public void ConnectionBuilderEncryptBackwardsCompatibility() Assert.True(builder.Encrypt); } + [Theory] + [InlineData("true", "True")] + [InlineData("mandatory", "True")] + [InlineData("yes", "True")] + [InlineData("false", "False")] + [InlineData("optional", "False")] + [InlineData("no", "False")] + [InlineData("strict", "Strict")] + public void EncryptParserValidValuesParsesSuccessfully(string value, string expectedValue) + => Assert.Equal(expectedValue, SqlConnectionEncryptOption.Parse(value).ToString()); + + [Theory] + [InlineData("something")] + [InlineData("")] + [InlineData(null)] + [InlineData(" true ")] + public void EncryptParserInvalidValuesThrowsException(string value) + => Assert.Throws(() => SqlConnectionEncryptOption.Parse(value)); + + [Theory] + [InlineData("true", "True")] + [InlineData("mandatory", "True")] + [InlineData("yes", "True")] + [InlineData("false", "False")] + [InlineData("optional", "False")] + [InlineData("no", "False")] + [InlineData("strict", "Strict")] + public void EncryptTryParseValidValuesReturnsTrue(string value, string expectedValue) + { + Assert.True(SqlConnectionEncryptOption.TryParse(value, out var result)); + Assert.Equal(expectedValue, result.ToString()); + } + + [Theory] + [InlineData("something")] + [InlineData("")] + [InlineData(null)] + [InlineData(" true ")] + public void EncryptTryParseInvalidValuesReturnsFalse(string value) + => Assert.False(SqlConnectionEncryptOption.TryParse(value, out _)); + internal void ExecuteConnectionStringTests(string connectionString) { SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectionString); From f62ac3bcf393d94cbd26aaf335a4611c5df357dc Mon Sep 17 00:00:00 2001 From: sorensenmatias Date: Tue, 27 Sep 2022 20:38:46 +0200 Subject: [PATCH 11/78] For failed connection requests in ConnectionPool in case of PoolBlockingPeriod not enabled, ensure stacktrace of the exception is not swallowed (#1768) --- .../Data/ProviderBase/DbConnectionPool.NetCoreApp.cs | 8 -------- .../Microsoft/Data/ProviderBase/DbConnectionPool.cs | 10 ++++++---- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.NetCoreApp.cs index 11c153e5b3..c85d042b2a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.NetCoreApp.cs @@ -11,14 +11,6 @@ namespace Microsoft.Data.ProviderBase { sealed internal partial class DbConnectionPool { - partial void CheckPoolBlockingPeriod(Exception e) - { - if (!IsBlockingPeriodEnabled()) - { - throw e; - } - } - private bool IsBlockingPeriodEnabled() { var poolGroupConnectionOptions = _connectionPoolGroup.ConnectionOptions as SqlConnectionString; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs index c6f5a39693..7858adc93c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/ProviderBase/DbConnectionPool.cs @@ -776,7 +776,12 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio throw; } - CheckPoolBlockingPeriod(e); +#if NETCOREAPP + if (!IsBlockingPeriodEnabled()) + { + throw; + } +#endif // Close associated Parser if connection already established. if (newObj?.IsConnectionAlive() == true) @@ -824,9 +829,6 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio return newObj; } - //This method is implemented in DbConnectionPool.NetCoreApp - partial void CheckPoolBlockingPeriod(Exception e); - private void DeactivateObject(DbConnectionInternal obj) { SqlClientEventSource.Log.TryPoolerTraceEvent(" {0}, Connection {1}, Deactivating.", ObjectID, obj.ObjectID); From f2517d46cd1b0d98624e87bc6317e4e4f28e3e83 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Tue, 4 Oct 2022 09:43:28 -0700 Subject: [PATCH 12/78] Fix | NRE on assigning null to SqlConnectionStringBuilder.Encrypt (#1778) --- .../SqlConnectionEncryptOption.xml | 2 +- .../Data/SqlClient/SqlConnectionStringBuilder.cs | 5 +++-- .../FunctionalTests/SqlConnectionStringBuilderTest.cs | 11 +++++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml index 6db9533606..35b8d24ab6 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml @@ -7,7 +7,7 @@ property. When converting from a boolean, a value of `true` converts to and a value of `false` converts to . When converting to a boolean, and convert to `true` and converts `false`. +Implicit conversions have been added to maintain backwards compatibility with boolean behahavior for the property. When converting from a boolean, a value of `true` converts to and a value of `false` converts to . When converting to a boolean, , , and `null` convert to `true` and converts `false`. ]]> diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs index 28a8fbc6fe..f89224cd97 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs @@ -1237,8 +1237,9 @@ public SqlConnectionEncryptOption Encrypt get => _encrypt; set { - SetSqlConnectionEncryptionValue(value); - _encrypt = value; + SqlConnectionEncryptOption newValue = value ?? DbConnectionStringDefaults.Encrypt; + SetSqlConnectionEncryptionValue(newValue); + _encrypt = newValue; } } diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs index 828152c4ab..1608525404 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs @@ -383,6 +383,10 @@ public void ConnectionBuilderEncryptBackwardsCompatibility() builder.Encrypt = SqlConnectionEncryptOption.Strict; Assert.Equal("Encrypt=Strict", builder.ConnectionString); Assert.True(builder.Encrypt); + + builder.Encrypt = null; + Assert.Equal("Encrypt=True", builder.ConnectionString); + Assert.True(builder.Encrypt); } [Theory] @@ -414,7 +418,7 @@ public void EncryptParserInvalidValuesThrowsException(string value) [InlineData("strict", "Strict")] public void EncryptTryParseValidValuesReturnsTrue(string value, string expectedValue) { - Assert.True(SqlConnectionEncryptOption.TryParse(value, out var result)); + Assert.True(SqlConnectionEncryptOption.TryParse(value, out SqlConnectionEncryptOption result)); Assert.Equal(expectedValue, result.ToString()); } @@ -424,7 +428,10 @@ public void EncryptTryParseValidValuesReturnsTrue(string value, string expectedV [InlineData(null)] [InlineData(" true ")] public void EncryptTryParseInvalidValuesReturnsFalse(string value) - => Assert.False(SqlConnectionEncryptOption.TryParse(value, out _)); + { + Assert.False(SqlConnectionEncryptOption.TryParse(value, out SqlConnectionEncryptOption result)); + Assert.Null(result); + } internal void ExecuteConnectionStringTests(string connectionString) { From 81055cf4b48f36a48199c7569e9308fc5be96b7c Mon Sep 17 00:00:00 2001 From: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com> Date: Tue, 4 Oct 2022 09:44:26 -0700 Subject: [PATCH 13/78] Fix async deadlock issue when sending attention fails due to network failure (#1766) --- .../Data/SqlClient/TdsParserStateObject.cs | 25 ++++++++++--------- .../Data/SqlClient/TdsParserStateObject.cs | 21 ++++++++-------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 21f4e9b61b..fbaa3dc480 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -55,7 +55,7 @@ public TimeoutState(int value) private const int AttentionTimeoutSeconds = 5; - private static readonly ContextCallback s_readAdyncCallbackComplete = ReadAsyncCallbackComplete; + private static readonly ContextCallback s_readAsyncCallbackComplete = ReadAsyncCallbackComplete; // Ticks to consider a connection "good" after a successful I/O (10,000 ticks = 1 ms) // The resolution of the timer is typically in the range 10 to 16 milliseconds according to msdn. @@ -2337,9 +2337,9 @@ private void OnTimeoutAsync(object state) } } - private bool OnTimeoutSync() + private bool OnTimeoutSync(bool asyncClose = false) { - return OnTimeoutCore(TimeoutState.Running, TimeoutState.ExpiredSync); + return OnTimeoutCore(TimeoutState.Running, TimeoutState.ExpiredSync, asyncClose); } /// @@ -2348,8 +2348,9 @@ private bool OnTimeoutSync() /// /// the state that is the expected current state, state will change only if this is correct /// the state that will be changed to if the expected state is correct + /// any close action to be taken by an async task to avoid deadlock. /// boolean value indicating whether the call changed the timeout state - private bool OnTimeoutCore(int expectedState, int targetState) + private bool OnTimeoutCore(int expectedState, int targetState, bool asyncClose = false) { Debug.Assert(targetState == TimeoutState.ExpiredAsync || targetState == TimeoutState.ExpiredSync, "OnTimeoutCore must have an expiry state as the targetState"); @@ -2382,7 +2383,7 @@ private bool OnTimeoutCore(int expectedState, int targetState) { try { - SendAttention(mustTakeWriteLock: true); + SendAttention(mustTakeWriteLock: true, asyncClose); } catch (Exception e) { @@ -2927,7 +2928,7 @@ public void ReadAsyncCallback(IntPtr key, PacketHandle packet, uint error) // synchrnously and then call OnTimeoutSync to force an atomic change of state. if (TimeoutHasExpired) { - OnTimeoutSync(); + OnTimeoutSync(true); } // try to change to the stopped state but only do so if currently in the running state @@ -2958,7 +2959,7 @@ public void ReadAsyncCallback(IntPtr key, PacketHandle packet, uint error) { if (_executionContext != null) { - ExecutionContext.Run(_executionContext, s_readAdyncCallbackComplete, source); + ExecutionContext.Run(_executionContext, s_readAsyncCallbackComplete, source); } else { @@ -3441,7 +3442,7 @@ private void CancelWritePacket() #pragma warning disable 0420 // a reference to a volatile field will not be treated as volatile - private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccumulate, bool callerHasConnectionLock) + private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccumulate, bool callerHasConnectionLock, bool asyncClose = false) { // Check for a stored exception var delayedException = Interlocked.Exchange(ref _delayedWriteAsyncCallbackException, null); @@ -3534,7 +3535,7 @@ private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccu { SqlClientEventSource.Log.TryTraceEvent("TdsParserStateObject.SNIWritePacket | Info | State Object Id {0}, Write async returned error code {1}", _objectID, (int)error); AddError(_parser.ProcessSNIError(this)); - ThrowExceptionAndWarning(); + ThrowExceptionAndWarning(false, asyncClose); } AssertValidState(); completion.SetResult(null); @@ -3569,7 +3570,7 @@ private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccu { SqlClientEventSource.Log.TryTraceEvent("TdsParserStateObject.SNIWritePacket | Info | State Object Id {0}, Write async returned error code {1}", _objectID, (int)sniError); AddError(_parser.ProcessSNIError(this)); - ThrowExceptionAndWarning(callerHasConnectionLock); + ThrowExceptionAndWarning(callerHasConnectionLock, asyncClose); } AssertValidState(); } @@ -3581,7 +3582,7 @@ private Task SNIWritePacket(PacketHandle packet, out uint sniError, bool canAccu internal abstract uint WritePacket(PacketHandle packet, bool sync); // Sends an attention signal - executing thread will consume attn. - internal void SendAttention(bool mustTakeWriteLock = false) + internal void SendAttention(bool mustTakeWriteLock = false, bool asyncClose = false) { if (!_attentionSent) { @@ -3623,7 +3624,7 @@ internal void SendAttention(bool mustTakeWriteLock = false) uint sniError; _parser._asyncWrite = false; // stop async write - SNIWritePacket(attnPacket, out sniError, canAccumulate: false, callerHasConnectionLock: false); + SNIWritePacket(attnPacket, out sniError, canAccumulate: false, callerHasConnectionLock: false, asyncClose); SqlClientEventSource.Log.TryTraceEvent("TdsParserStateObject.SendAttention | Info | State Object Id {0}, Sent Attention.", _objectID); } finally diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 6e8afce1ea..8d9057bc02 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -2401,9 +2401,9 @@ private void OnTimeoutAsync(object state) } } - private bool OnTimeoutSync() + private bool OnTimeoutSync(bool asyncClose = false) { - return OnTimeoutCore(TimeoutState.Running, TimeoutState.ExpiredSync); + return OnTimeoutCore(TimeoutState.Running, TimeoutState.ExpiredSync, asyncClose); } /// @@ -2412,8 +2412,9 @@ private bool OnTimeoutSync() /// /// the state that is the expected current state, state will change only if this is correct /// the state that will be changed to if the expected state is correct + /// any close action to be taken by an async task to avoid deadlock. /// boolean value indicating whether the call changed the timeout state - private bool OnTimeoutCore(int expectedState, int targetState) + private bool OnTimeoutCore(int expectedState, int targetState, bool asyncClose = false) { Debug.Assert(targetState == TimeoutState.ExpiredAsync || targetState == TimeoutState.ExpiredSync, "OnTimeoutCore must have an expiry state as the targetState"); @@ -2447,7 +2448,7 @@ private bool OnTimeoutCore(int expectedState, int targetState) { try { - SendAttention(mustTakeWriteLock: true); + SendAttention(mustTakeWriteLock: true, asyncClose); } catch (Exception e) { @@ -2988,7 +2989,7 @@ public void ReadAsyncCallback(IntPtr key, IntPtr packet, UInt32 error) // synchrnously and then call OnTimeoutSync to force an atomic change of state. if (TimeoutHasExpired) { - OnTimeoutSync(); + OnTimeoutSync(asyncClose: true); } // try to change to the stopped state but only do so if currently in the running state @@ -3475,7 +3476,7 @@ private void CancelWritePacket() #pragma warning disable 420 // a reference to a volatile field will not be treated as volatile - private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniError, bool canAccumulate, bool callerHasConnectionLock) + private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniError, bool canAccumulate, bool callerHasConnectionLock, bool asyncClose = false) { // Check for a stored exception var delayedException = Interlocked.Exchange(ref _delayedWriteAsyncCallbackException, null); @@ -3566,7 +3567,7 @@ private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniEr SqlClientEventSource.Log.TryTraceEvent(" write async returned error code {0}", (int)error); AddError(_parser.ProcessSNIError(this)); - ThrowExceptionAndWarning(); + ThrowExceptionAndWarning(false, asyncClose); } AssertValidState(); completion.SetResult(null); @@ -3603,7 +3604,7 @@ private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniEr { SqlClientEventSource.Log.TryTraceEvent(" write async returned error code {0}", (int)sniError); AddError(_parser.ProcessSNIError(this)); - ThrowExceptionAndWarning(callerHasConnectionLock); + ThrowExceptionAndWarning(callerHasConnectionLock, false); } AssertValidState(); } @@ -3613,7 +3614,7 @@ private Task SNIWritePacket(SNIHandle handle, SNIPacket packet, out UInt32 sniEr #pragma warning restore 420 // Sends an attention signal - executing thread will consume attn. - internal void SendAttention(bool mustTakeWriteLock = false) + internal void SendAttention(bool mustTakeWriteLock = false, bool asyncClose = false) { if (!_attentionSent) { @@ -3660,7 +3661,7 @@ internal void SendAttention(bool mustTakeWriteLock = false) UInt32 sniError; _parser._asyncWrite = false; // stop async write - SNIWritePacket(Handle, attnPacket, out sniError, canAccumulate: false, callerHasConnectionLock: false); + SNIWritePacket(Handle, attnPacket, out sniError, canAccumulate: false, callerHasConnectionLock: false, asyncClose); SqlClientEventSource.Log.TryTraceEvent(" Send Attention ASync.", "Info"); } finally From 871c0d2d7ce93048dc8b9d325f6c84731117a991 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com> Date: Tue, 4 Oct 2022 14:11:02 -0700 Subject: [PATCH 14/78] Fixes ReadAsync() behavior to register Cancellation token action before streaming results (#1781) --- .../Microsoft/Data/SqlClient/SqlDataReader.cs | 13 +-- .../Microsoft/Data/SqlClient/SqlDataReader.cs | 13 +-- ....Data.SqlClient.ManualTesting.Tests.csproj | 1 + .../DataReaderCancellationTest.cs | 83 +++++++++++++++++++ 4 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderCancellationTest.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs index a801697d8f..f24f374644 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -4733,6 +4733,13 @@ public override Task ReadAsync(CancellationToken cancellationToken) return Task.FromException(ADP.ExceptionWithStackTrace(ADP.DataReaderClosed())); } + // Register first to catch any already expired tokens to be able to trigger cancellation event. + IDisposable registration = null; + if (cancellationToken.CanBeCanceled) + { + registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); + } + // If user's token is canceled, return a canceled task if (cancellationToken.IsCancellationRequested) { @@ -4831,12 +4838,6 @@ public override Task ReadAsync(CancellationToken cancellationToken) return source.Task; } - IDisposable registration = null; - if (cancellationToken.CanBeCanceled) - { - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); - } - ReadAsyncCallContext context = null; if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs index 09061277e0..090b0f7bfb 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -5326,6 +5326,13 @@ public override Task ReadAsync(CancellationToken cancellationToken) return ADP.CreatedTaskWithException(ADP.ExceptionWithStackTrace(ADP.DataReaderClosed("ReadAsync"))); } + // Register first to catch any already expired tokens to be able to trigger cancellation event. + IDisposable registration = null; + if (cancellationToken.CanBeCanceled) + { + registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); + } + // If user's token is canceled, return a canceled task if (cancellationToken.IsCancellationRequested) { @@ -5425,12 +5432,6 @@ public override Task ReadAsync(CancellationToken cancellationToken) return source.Task; } - IDisposable registration = null; - if (cancellationToken.CanBeCanceled) - { - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); - } - var context = Interlocked.Exchange(ref _cachedReadAsyncContext, null) ?? new ReadAsyncCallContext(); Debug.Assert(context._reader == null && context._source == null && context._disposable == null, "cached ReadAsyncCallContext was not properly disposed"); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 704d4a28f0..1efdfeb5fc 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -86,6 +86,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderCancellationTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderCancellationTest.cs new file mode 100644 index 0000000000..38d7da418e --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderCancellationTest.cs @@ -0,0 +1,83 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public class DataReaderCancellationTest + { + /// + /// Test ensures cancellation token is registered before ReadAsync starts processing results from TDS Stream, + /// such that when Cancel is triggered, the token is capable of canceling reading further results. + /// + /// Async Task + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public static async Task CancellationTokenIsRespected_ReadAsync() + { + const string longRunningQuery = @" +with TenRows as (select Value from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) as TenRows (Value)), + ThousandRows as (select A.Value as A, B.Value as B, C.Value as C from TenRows as A, TenRows as B, TenRows as C) +select * +from ThousandRows as A, ThousandRows as B, ThousandRows as C;"; + + using (var source = new CancellationTokenSource()) + using (var connection = new SqlConnection(DataTestUtility.TCPConnectionString)) + { + await connection.OpenAsync(source.Token); + + Stopwatch stopwatch = Stopwatch.StartNew(); + await Assert.ThrowsAsync(async () => + { + using (var command = new SqlCommand(longRunningQuery, connection)) + using (var reader = await command.ExecuteReaderAsync(source.Token)) + { + while (await reader.ReadAsync(source.Token)) + { + source.Cancel(); + } + } + }); + Assert.True(stopwatch.ElapsedMilliseconds < 10000, "Cancellation did not trigger on time."); + } + } + + /// + /// Test ensures cancellation token is registered before ReadAsync starts processing results from TDS Stream, + /// such that when Cancel is triggered, the token is capable of canceling reading further results. + /// + /// Async Task + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + public static async Task CancelledCancellationTokenIsRespected_ReadAsync() + { + const string longRunningQuery = @" +with TenRows as (select Value from (values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10)) as TenRows (Value)), + ThousandRows as (select A.Value as A, B.Value as B, C.Value as C from TenRows as A, TenRows as B, TenRows as C) +select * +from ThousandRows as A, ThousandRows as B, ThousandRows as C;"; + + using (var source = new CancellationTokenSource()) + using (var connection = new SqlConnection(DataTestUtility.TCPConnectionString)) + { + await connection.OpenAsync(source.Token); + + Stopwatch stopwatch = Stopwatch.StartNew(); + await Assert.ThrowsAsync(async () => + { + using (var command = new SqlCommand(longRunningQuery, connection)) + using (var reader = await command.ExecuteReaderAsync(source.Token)) + { + source.Cancel(); + while (await reader.ReadAsync(source.Token)) + { } + } + }); + Assert.True(stopwatch.ElapsedMilliseconds < 10000, "Cancellation did not trigger on time."); + } + } + } +} From 0eeb135774f90645183e3be5e98a370c260c5925 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra <13396919+cheenamalhotra@users.noreply.github.com> Date: Tue, 4 Oct 2022 14:11:21 -0700 Subject: [PATCH 15/78] Add missing HostNameInCertificate property in NetFx Ref (#1776) --- .../netfx/ref/Microsoft.Data.SqlClient.cs | 4 ++++ .../FunctionalTests/SqlConnectionStringBuilderTest.cs | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs index 5d78fb574e..9cc91a1c38 100644 --- a/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netfx/ref/Microsoft.Data.SqlClient.cs @@ -1043,6 +1043,10 @@ public SqlConnectionStringBuilder(string connectionString) { } [System.ComponentModel.DisplayNameAttribute("Encrypt")] [System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.All)] public SqlConnectionEncryptOption Encrypt { get { throw null; } set { } } + /// + [System.ComponentModel.DisplayNameAttribute("Host Name In Certificate")] + [System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.All)] + public string HostNameInCertificate { get { throw null; } set { } } /// [System.ComponentModel.DisplayNameAttribute("Enlist")] [System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.All)] diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs index 1608525404..133b0d91d8 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs @@ -360,6 +360,17 @@ public void SetEncryptOnConnectionBuilderMapsToString() } } + [Fact] + public void AbleToSetHostNameInCertificate() + { + var testhostname = "somedomain.net"; + var builder = new SqlConnectionStringBuilder + { + HostNameInCertificate = testhostname + }; + Assert.Equal(testhostname, builder.HostNameInCertificate); + } + [Fact] public void ConnectionBuilderEncryptBackwardsCompatibility() { From a4974d448c42c29ee56d5295540eb5a81886d006 Mon Sep 17 00:00:00 2001 From: Wraith Date: Wed, 5 Oct 2022 01:21:04 +0100 Subject: [PATCH 16/78] Port lazy initialize hidden column map to netfx (#1443) --- .../Microsoft/Data/SqlClient/SqlDataReader.cs | 59 ++++------ .../src/Microsoft/Data/SqlClient/TdsParser.cs | 5 - .../Data/SqlClient/TdsParserHelperClasses.cs | 105 ++++++++++++++---- 3 files changed, 102 insertions(+), 67 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs index 090b0f7bfb..c733b7fc8a 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -329,8 +329,8 @@ internal virtual SmiExtendedMetaData[] GetInternalSmiMetaData() if (null != metaData && 0 < metaData.Length) { - metaDataReturn = new SmiExtendedMetaData[metaData.visibleColumns]; - + metaDataReturn = new SmiExtendedMetaData[metaData.VisibleColumnCount]; + int returnIndex = 0; for (int index = 0; index < metaData.Length; index++) { _SqlMetaData colMetaData = metaData[index]; @@ -369,7 +369,7 @@ internal virtual SmiExtendedMetaData[] GetInternalSmiMetaData() length /= ADP.CharSize; } - metaDataReturn[index] = new SmiQueryMetaData( + metaDataReturn[returnIndex] = new SmiQueryMetaData( colMetaData.type, length, colMetaData.precision, @@ -397,6 +397,7 @@ internal virtual SmiExtendedMetaData[] GetInternalSmiMetaData() colMetaData.IsDifferentName, colMetaData.IsHidden ); + returnIndex += 1; } } } @@ -458,7 +459,7 @@ override public int VisibleFieldCount { return 0; } - return (md.visibleColumns); + return md.VisibleColumnCount; } } @@ -1352,31 +1353,6 @@ private bool TryConsumeMetaData() Debug.Assert(!ignored, "Parser read a row token while trying to read metadata"); } - // we hide hidden columns from the user so build an internal map - // that compacts all hidden columns from the array - if (null != _metaData) - { - - if (_snapshot != null && object.ReferenceEquals(_snapshot._metadata, _metaData)) - { - _metaData = (_SqlMetaDataSet)_metaData.Clone(); - } - - _metaData.visibleColumns = 0; - - Debug.Assert(null == _metaData.indexMap, "non-null metaData indexmap"); - int[] indexMap = new int[_metaData.Length]; - for (int i = 0; i < indexMap.Length; ++i) - { - indexMap[i] = _metaData.visibleColumns; - - if (!(_metaData[i].IsHidden)) - { - _metaData.visibleColumns++; - } - } - _metaData.indexMap = indexMap; - } return true; } @@ -1690,15 +1666,15 @@ override public DataTable GetSchemaTable() try { statistics = SqlStatistics.StartTimer(Statistics); - if (null == _metaData || null == _metaData.schemaTable) + if (null == _metaData || null == _metaData._schemaTable) { if (null != this.MetaData) { - _metaData.schemaTable = BuildSchemaTable(); - Debug.Assert(null != _metaData.schemaTable, "No schema information yet!"); + _metaData._schemaTable = BuildSchemaTable(); + Debug.Assert(null != _metaData._schemaTable, "No schema information yet!"); } } - return _metaData?.schemaTable; + return _metaData?._schemaTable; } finally { @@ -2994,11 +2970,11 @@ virtual public int GetSqlValues(object[] values) SetTimeout(_defaultTimeoutMilliseconds); - int copyLen = (values.Length < _metaData.visibleColumns) ? values.Length : _metaData.visibleColumns; + int copyLen = (values.Length < _metaData.VisibleColumnCount) ? values.Length : _metaData.VisibleColumnCount; for (int i = 0; i < copyLen; i++) { - values[_metaData.indexMap[i]] = GetSqlValueInternal(i); + values[_metaData.GetVisibleColumnIndex(i)] = GetSqlValueInternal(i); } return copyLen; } @@ -3398,7 +3374,7 @@ override public int GetValues(object[] values) CheckMetaDataIsReady(); - int copyLen = (values.Length < _metaData.visibleColumns) ? values.Length : _metaData.visibleColumns; + int copyLen = (values.Length < _metaData.VisibleColumnCount) ? values.Length : _metaData.VisibleColumnCount; int maximumColumn = copyLen - 1; SetTimeout(_defaultTimeoutMilliseconds); @@ -3414,12 +3390,19 @@ override public int GetValues(object[] values) for (int i = 0; i < copyLen; i++) { // Get the usable, TypeSystem-compatible value from the iternal buffer - values[_metaData.indexMap[i]] = GetValueFromSqlBufferInternal(_data[i], _metaData[i]); + int fieldIndex = _metaData.GetVisibleColumnIndex(i); + values[i] = GetValueFromSqlBufferInternal(_data[fieldIndex], _metaData[fieldIndex]); // If this is sequential access, then we need to wipe the internal buffer if ((sequentialAccess) && (i < maximumColumn)) { _data[i].Clear(); + if (fieldIndex > i && fieldIndex > 0) + { + // if we jumped an index forward because of a hidden column see if the buffer before the + // current one was populated by the seek forward and clear it if it was + _data[fieldIndex - 1].Clear(); + } } } @@ -4767,7 +4750,7 @@ internal bool TrySetMetaData(_SqlMetaDataSet metaData, bool moreInfo) _tableNames = null; if (_metaData != null) { - _metaData.schemaTable = null; + _metaData._schemaTable = null; _data = SqlBuffer.CreateBufferArray(metaData.Length); } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 6daca4d771..cd0fab3e2d 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -5094,7 +5094,6 @@ internal bool TryProcessAltMetaData(int cColumns, TdsParserStateObject stateObj, metaData = null; _SqlMetaDataSet altMetaDataSet = new _SqlMetaDataSet(cColumns, null); - int[] indexMap = new int[cColumns]; if (!stateObj.TryReadUInt16(out altMetaDataSet.id)) { @@ -5191,12 +5190,8 @@ internal bool TryProcessAltMetaData(int cColumns, TdsParserStateObject stateObj, break; } } - indexMap[i] = i; } - altMetaDataSet.indexMap = indexMap; - altMetaDataSet.visibleColumns = cColumns; - metaData = altMetaDataSet; return true; } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index 21004f4be2..bf113efe3b 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -511,51 +511,63 @@ public object Clone() } } - sealed internal class _SqlMetaDataSet : ICloneable + sealed internal class _SqlMetaDataSet { internal ushort id; // for altrow-columns only - internal int[] indexMap; - internal int visibleColumns; - internal DataTable schemaTable; + internal DataTable _schemaTable; internal readonly SqlTceCipherInfoTable cekTable; // table of "column encryption keys" used for this metadataset - internal readonly _SqlMetaData[] metaDataArray; + internal readonly _SqlMetaData[] _metaDataArray; + private int _hiddenColumnCount; + private int[] _visibleColumnMap; internal _SqlMetaDataSet(int count, SqlTceCipherInfoTable cipherTable) { + _hiddenColumnCount = -1; cekTable = cipherTable; - metaDataArray = new _SqlMetaData[count]; - for (int i = 0; i < metaDataArray.Length; ++i) + _metaDataArray = new _SqlMetaData[count]; + for (int i = 0; i < _metaDataArray.Length; ++i) { - metaDataArray[i] = new _SqlMetaData(i); + _metaDataArray[i] = new _SqlMetaData(i); } } private _SqlMetaDataSet(_SqlMetaDataSet original) { - this.id = original.id; - // although indexMap is not immutable, in practice it is initialized once and then passed around - this.indexMap = original.indexMap; - this.visibleColumns = original.visibleColumns; - this.schemaTable = original.schemaTable; - if (original.metaDataArray == null) + id = original.id; + _hiddenColumnCount = original._hiddenColumnCount; + _visibleColumnMap = original._visibleColumnMap; + _schemaTable = original._schemaTable; + if (original._metaDataArray == null) { - metaDataArray = null; + _metaDataArray = null; } else { - metaDataArray = new _SqlMetaData[original.metaDataArray.Length]; - for (int idx = 0; idx < metaDataArray.Length; idx++) + _metaDataArray = new _SqlMetaData[original._metaDataArray.Length]; + for (int idx = 0; idx < _metaDataArray.Length; idx++) { - metaDataArray[idx] = (_SqlMetaData)original.metaDataArray[idx].Clone(); + _metaDataArray[idx] = (_SqlMetaData)original._metaDataArray[idx].Clone(); } } } + internal int VisibleColumnCount + { + get + { + if (_hiddenColumnCount == -1) + { + SetupHiddenColumns(); + } + return Length - _hiddenColumnCount; + } + } + internal int Length { get { - return metaDataArray.Length; + return _metaDataArray.Length; } } @@ -563,21 +575,66 @@ internal _SqlMetaData this[int index] { get { - return metaDataArray[index]; + return _metaDataArray[index]; } set { Debug.Assert(null == value, "used only by SqlBulkCopy"); - metaDataArray[index] = value; + _metaDataArray[index] = value; } } - public object Clone() + public int GetVisibleColumnIndex(int index) + { + if (_hiddenColumnCount == -1) + { + SetupHiddenColumns(); + } + if (_visibleColumnMap is null) + { + return index; + } + else + { + return _visibleColumnMap[index]; + } + } + + public _SqlMetaDataSet Clone() { return new _SqlMetaDataSet(this); } + + private void SetupHiddenColumns() + { + int hiddenColumnCount = 0; + for (int index = 0; index < Length; index++) + { + if (_metaDataArray[index].IsHidden) + { + hiddenColumnCount += 1; + } + } + + if (hiddenColumnCount > 0) + { + int[] visibleColumnMap = new int[Length - hiddenColumnCount]; + int mapIndex = 0; + for (int metaDataIndex = 0; metaDataIndex < Length; metaDataIndex++) + { + if (!_metaDataArray[metaDataIndex].IsHidden) + { + visibleColumnMap[mapIndex] = metaDataIndex; + mapIndex += 1; + } + } + _visibleColumnMap = visibleColumnMap; + } + _hiddenColumnCount = hiddenColumnCount; + } } + sealed internal class _SqlMetaDataSetCollection : ICloneable { private readonly List<_SqlMetaDataSet> altMetaDataSetArray; @@ -622,10 +679,10 @@ internal _SqlMetaDataSet GetAltMetaData(int id) public object Clone() { _SqlMetaDataSetCollection result = new _SqlMetaDataSetCollection(); - result.metaDataSet = metaDataSet == null ? null : (_SqlMetaDataSet)metaDataSet.Clone(); + result.metaDataSet = metaDataSet == null ? null : metaDataSet.Clone(); foreach (_SqlMetaDataSet set in altMetaDataSetArray) { - result.altMetaDataSetArray.Add((_SqlMetaDataSet)set.Clone()); + result.altMetaDataSetArray.Add(set.Clone()); } return result; } From ac7c1a4a6bc18fdc4892118a2d07211f990c6286 Mon Sep 17 00:00:00 2001 From: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com> Date: Tue, 4 Oct 2022 17:45:22 -0700 Subject: [PATCH 17/78] Merge to shared - TdsParserSafeHandles (#1604) --- .../src/Microsoft.Data.SqlClient.csproj | 4 ++- .../netfx/src/Microsoft.Data.SqlClient.csproj | 4 ++- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 2 +- .../TdsParserSafeHandles.Windows.cs} | 35 ++++++++++++++++--- 4 files changed, 38 insertions(+), 7 deletions(-) rename src/Microsoft.Data.SqlClient/{netcore/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs => src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs} (85%) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 5b72e28c18..611018d788 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -660,6 +660,9 @@ + + Microsoft\Data\SqlClient\TdsParserSafeHandles.Windows.cs + @@ -745,7 +748,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 12323365bf..95ff75b838 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -554,6 +554,9 @@ Microsoft\Data\SqlClient\TdsParameterSetter.cs + + Microsoft\Data\SqlClient\TdsParserSafeHandles.Windows.cs + Microsoft\Data\SqlClient\TdsParserStaticMethods.cs @@ -648,7 +651,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index cd0fab3e2d..1edad799ae 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -523,7 +523,7 @@ internal void Connect(ServerInfo serverInfo, // Clean up IsSQLDNSCachingSupported flag from previous status _connHandler.IsSQLDNSCachingSupported = false; - UInt32 sniStatus = SNILoadHandle.SingletonInstance.SNIStatus; + UInt32 sniStatus = SNILoadHandle.SingletonInstance.Status; if (sniStatus != TdsEnums.SNI_SUCCESS) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs similarity index 85% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs index 3db0f07fcf..8d2716c63e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs @@ -5,8 +5,12 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; +#if NETFRAMEWORK +using Microsoft.Data.Common; +#endif namespace Microsoft.Data.SqlClient { @@ -23,7 +27,7 @@ internal sealed partial class SNILoadHandle : SafeHandle private SNILoadHandle() : base(IntPtr.Zero, true) { - // From security review - SafeHandle guarantees this is only called once. + // SQL BU DT 346588 - from security review - SafeHandle guarantees this is only called once. // The reason for the safehandle is guaranteed initialization and termination of SNI to // ensure SNI terminates and cleans up properly. try @@ -49,7 +53,7 @@ public bool ClientOSEncryptionSupport { try { - UInt32 value = 0; + uint value = 0; // Query OS to find out whether encryption is supported. SNINativeMethodWrapper.SNIQueryInfo(SNINativeMethodWrapper.QTypes.SNI_QUERY_CLIENT_ENCRYPT_POSSIBLE, ref value); _clientOSEncryptionSupport = value != 0; @@ -101,7 +105,11 @@ private static void ReadDispatcher(IntPtr key, IntPtr packet, uint error) if (null != stateObj) { +#if NETFRAMEWORK + stateObj.ReadAsyncCallback(IntPtr.Zero, packet, error); +#else stateObj.ReadAsyncCallback(IntPtr.Zero, PacketHandle.FromNativePointer(packet), error); +#endif // NETFRAMEWORK } } } @@ -122,7 +130,11 @@ private static void WriteDispatcher(IntPtr key, IntPtr packet, uint error) if (null != stateObj) { +#if NETFRAMEWORK + stateObj.WriteAsyncCallback(IntPtr.Zero, packet, error); +#else stateObj.WriteAsyncCallback(IntPtr.Zero, PacketHandle.FromNativePointer(packet), error); +#endif // NETFRAMEWORK } } } @@ -144,12 +156,17 @@ internal SNIHandle( bool flushCache, bool fSync, bool fParallel, +#if NETFRAMEWORK + TransparentNetworkResolutionState transparentNetworkResolutionState, + int totalTimeout, +#endif SqlConnectionIPAddressPreference ipPreference, SQLDNSInfo cachedDNSInfo, bool tlsFirst, string hostNameInCertificate) : base(IntPtr.Zero, true) { + RuntimeHelpers.PrepareConstrainedRegions(); try { } finally @@ -158,11 +175,21 @@ internal SNIHandle( instanceName = new byte[256]; // Size as specified by netlibs. if (ignoreSniOpenTimeout) { + // UNDONE: ITEM12001110 (DB Mirroring Reconnect) Old behavior of not truly honoring timeout presevered + // for non-failover scenarios to avoid breaking changes as part of a QFE. Consider fixing timeout + // handling in next full release and removing ignoreSniOpenTimeout parameter. timeout = Timeout.Infinite; // -1 == native SNIOPEN_TIMEOUT_VALUE / INFINITE } - _status = SNINativeMethodWrapper.SNIOpenSyncEx(myInfo, serverName, ref base.handle, spnBuffer, instanceName, flushCache, - fSync, timeout, fParallel, ipPreference, cachedDNSInfo, hostNameInCertificate); +#if NETFRAMEWORK + int transparentNetworkResolutionStateNo = (int)transparentNetworkResolutionState; + _status = SNINativeMethodWrapper.SNIOpenSyncEx(myInfo, serverName, ref base.handle, + spnBuffer, instanceName, flushCache, fSync, timeout, fParallel, transparentNetworkResolutionStateNo, totalTimeout, + ADP.IsAzureSqlServerEndpoint(serverName), ipPreference, cachedDNSInfo, hostNameInCertificate); +#else + _status = SNINativeMethodWrapper.SNIOpenSyncEx(myInfo, serverName, ref base.handle, + spnBuffer, instanceName, flushCache, fSync, timeout, fParallel, ipPreference, cachedDNSInfo, hostNameInCertificate); +#endif // NETFRAMEWORK } } From eb1b92285152ea36533dc506a0ba82ea6fb7248b Mon Sep 17 00:00:00 2001 From: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com> Date: Wed, 5 Oct 2022 11:33:45 -0700 Subject: [PATCH 18/78] Merge to shared - SqlInternalConnection (#1598) --- .../src/Microsoft.Data.SqlClient.csproj | 4 +- .../netfx/src/Microsoft.Data.SqlClient.csproj | 4 +- .../Data/SqlClient/SqlInternalConnection.cs | 776 ------------------ .../Data/SqlClient/SqlInternalConnection.cs | 255 +++++- 4 files changed, 226 insertions(+), 813 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs rename src/Microsoft.Data.SqlClient/{netcore => }/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs (76%) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 611018d788..a64464e1a4 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -394,6 +394,9 @@ Microsoft\Data\SqlClient\SqlInfoMessageEventHandler.cs + + Microsoft\Data\SqlClient\SqlInternalConnection.cs + Microsoft\Data\SqlClient\SqlInternalTransaction.cs @@ -634,7 +637,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 95ff75b838..71f1d54125 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -482,6 +482,9 @@ Microsoft\Data\SqlClient\SqlInfoMessageEventHandler.cs + + Microsoft\Data\SqlClient\SqlInternalConnection.cs + Microsoft\Data\SqlClient\SqlInternalTransaction.cs @@ -642,7 +645,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs deleted file mode 100644 index aa78a60fc8..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs +++ /dev/null @@ -1,776 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Data; -using System.Data.Common; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using System.Runtime.ConstrainedExecution; -using Microsoft.Data.Common; -using Microsoft.Data.ProviderBase; -using SysTx = System.Transactions; - -namespace Microsoft.Data.SqlClient -{ - abstract internal class SqlInternalConnection : DbConnectionInternal - { - private readonly SqlConnectionString _connectionOptions; - private bool _isEnlistedInTransaction; // is the server-side connection enlisted? true while we're enlisted, reset only after we send a null... - private byte[] _promotedDTCToken; // token returned by the server when we promote transaction - private byte[] _whereAbouts; // cache the whereabouts (DTC Address) for exporting - - private bool _isGlobalTransaction = false; // Whether this is a Global Transaction (Non-MSDTC, Azure SQL DB Transaction) - private bool _isGlobalTransactionEnabledForServer = false; // Whether Global Transactions are enabled for this Azure SQL DB Server - private static readonly Guid _globalTransactionTMID = new Guid("1c742caf-6680-40ea-9c26-6b6846079764"); // ID of the Non-MSDTC, Azure SQL DB Transaction Manager - - private bool _isAzureSQLConnection = false; // If connected to Azure SQL - - // if connection is not open: null - // if connection is open: currently active database - internal string CurrentDatabase { get; set; } - - // if connection is not open yet, CurrentDataSource is null - // if connection is open: - // * for regular connections, it is set to Data Source value from connection string - // * for connections with FailoverPartner, it is set to the FailoverPartner value from connection string if the connection was opened to it. - internal string CurrentDataSource { get; set; } - - // the delegated (or promoted) transaction we're responsible for. - internal SqlDelegatedTransaction DelegatedTransaction { get; set; } - - internal enum TransactionRequest - { - Begin, - Promote, - Commit, - Rollback, - IfRollback, - Save - }; - - internal SqlInternalConnection(SqlConnectionString connectionOptions) : base() - { - Debug.Assert(null != connectionOptions, "null connectionOptions?"); - _connectionOptions = connectionOptions; - } - - internal SqlConnection Connection - { - get - { - return (SqlConnection)Owner; - } - } - - internal SqlConnectionString ConnectionOptions - { - get - { - return _connectionOptions; - } - } - - abstract internal SqlInternalTransaction CurrentTransaction - { - get; - } - - // SQLBU 415870 - // Get the internal transaction that should be hooked to a new outer transaction - // during a BeginTransaction API call. In some cases (i.e. connection is going to - // be reset), CurrentTransaction should not be hooked up this way. - virtual internal SqlInternalTransaction AvailableInternalTransaction - { - get - { - return CurrentTransaction; - } - } - - abstract internal SqlInternalTransaction PendingTransaction - { - get; - } - - override protected internal bool IsNonPoolableTransactionRoot - { - get - { - return IsTransactionRoot; // default behavior is that root transactions are NOT poolable. Subclasses may override. - } - } - - override internal bool IsTransactionRoot - { - get - { - var delegatedTransaction = DelegatedTransaction; - return ((null != delegatedTransaction) && (delegatedTransaction.IsActive)); - } - } - - internal bool HasLocalTransaction - { - get - { - SqlInternalTransaction currentTransaction = CurrentTransaction; - bool result = (null != currentTransaction && currentTransaction.IsLocal); - return result; - } - } - - internal bool HasLocalTransactionFromAPI - { - get - { - SqlInternalTransaction currentTransaction = CurrentTransaction; - bool result = (null != currentTransaction && currentTransaction.HasParentTransaction); - return result; - } - } - - internal bool IsEnlistedInTransaction - { - get - { - return _isEnlistedInTransaction; - } - } - - abstract internal bool IsLockedForBulkCopy - { - get; - } - - abstract internal bool Is2000 - { - get; - } - - abstract internal bool Is2005OrNewer - { - get; - } - - abstract internal bool Is2008OrNewer - { - get; - } - - internal byte[] PromotedDTCToken - { - get - { - return _promotedDTCToken; - } - set - { - _promotedDTCToken = value; - } - } - - internal bool IsGlobalTransaction - { - get - { - return _isGlobalTransaction; - } - set - { - _isGlobalTransaction = value; - } - } - - internal bool IsGlobalTransactionsEnabledForServer - { - get - { - return _isGlobalTransactionEnabledForServer; - } - set - { - _isGlobalTransactionEnabledForServer = value; - } - } - - internal bool IsAzureSQLConnection - { - get - { - return _isAzureSQLConnection; - } - set - { - _isAzureSQLConnection = value; - } - } - - override public DbTransaction BeginTransaction(IsolationLevel iso) - { - return BeginSqlTransaction(iso, null, false); - } - - virtual internal SqlTransaction BeginSqlTransaction(IsolationLevel iso, string transactionName, bool shouldReconnect) - { - SqlStatistics statistics = null; - TdsParser bestEffortCleanupTarget = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(Connection); - statistics = SqlStatistics.StartTimer(Connection.Statistics); - - SqlConnection.ExecutePermission.Demand(); // MDAC 81476 - - ValidateConnectionForExecute(null); - - if (HasLocalTransactionFromAPI) - throw ADP.ParallelTransactionsNotSupported(Connection); - - if (iso == IsolationLevel.Unspecified) - { - iso = IsolationLevel.ReadCommitted; // Default to ReadCommitted if unspecified. - } - - SqlTransaction transaction = new SqlTransaction(this, Connection, iso, AvailableInternalTransaction); - transaction.InternalTransaction.RestoreBrokenConnection = shouldReconnect; - ExecuteTransaction(TransactionRequest.Begin, transactionName, iso, transaction.InternalTransaction, false); - transaction.InternalTransaction.RestoreBrokenConnection = false; - return transaction; - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - Connection.Abort(e); - throw; - } - catch (System.StackOverflowException e) - { - Connection.Abort(e); - throw; - } - catch (System.Threading.ThreadAbortException e) - { - Connection.Abort(e); - SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); - throw; - } - finally - { - SqlStatistics.StopTimer(statistics); - } - } - - override public void ChangeDatabase(string database) - { - SqlConnection.ExecutePermission.Demand(); // MDAC 80961 - - if (ADP.IsEmpty(database)) - { - throw ADP.EmptyDatabaseName(); - } - - ValidateConnectionForExecute(null); // TODO: Do we need this for InProc? - - ChangeDatabaseInternal(database); // do the real work... - } - - abstract protected void ChangeDatabaseInternal(string database); - - override protected void CleanupTransactionOnCompletion(SysTx.Transaction transaction) - { - // Note: unlocked, potentially multi-threaded code, so pull delegate to local to - // ensure it doesn't change between test and call. - SqlDelegatedTransaction delegatedTransaction = DelegatedTransaction; - if (null != delegatedTransaction) - { - delegatedTransaction.TransactionEnded(transaction); - } - } - - override protected DbReferenceCollection CreateReferenceCollection() - { - return new SqlReferenceCollection(); - } - - override protected void Deactivate() - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} deactivating", ObjectID); - TdsParser bestEffortCleanupTarget = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(Connection); - SqlReferenceCollection referenceCollection = (SqlReferenceCollection)ReferenceCollection; - if (null != referenceCollection) - { - referenceCollection.Deactivate(); - } - - // Invoke subclass-specific deactivation logic - InternalDeactivate(); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG - } - catch (System.OutOfMemoryException) - { - DoomThisConnection(); - throw; - } - catch (System.StackOverflowException) - { - DoomThisConnection(); - throw; - } - catch (System.Threading.ThreadAbortException) - { - DoomThisConnection(); - SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); - throw; - } - catch (Exception e) - { - // UNDONE - should not be catching all exceptions!!! - if (!ADP.IsCatchableExceptionType(e)) - { - throw; - } - - // if an exception occurred, the inner connection will be - // marked as unusable and destroyed upon returning to the - // pool - DoomThisConnection(); - - ADP.TraceExceptionWithoutRethrow(e); - } - } - - abstract internal void DisconnectTransaction(SqlInternalTransaction internalTransaction); - - override public void Dispose() - { - _whereAbouts = null; - base.Dispose(); - } - - protected void Enlist(SysTx.Transaction tx) - { - // This method should not be called while the connection has a - // reference to an active delegated transaction. - // Manual enlistment via SqlConnection.EnlistTransaction - // should catch this case and throw an exception. - // - // Automatic enlistment isn't possible because - // Sys.Tx keeps the connection alive until the transaction is completed. - Debug.Assert(!IsNonPoolableTransactionRoot, "cannot defect an active delegated transaction!"); // potential race condition, but it's an assert - - if (null == tx) - { - if (IsEnlistedInTransaction) - { - EnlistNull(); - } - else - { - // When IsEnlistedInTransaction is false, it means we are in one of two states: - // 1. EnlistTransaction is null, so the connection is truly not enlisted in a transaction, or - // 2. Connection is enlisted in a SqlDelegatedTransaction. - // - // For #2, we have to consider whether or not the delegated transaction is active. - // If it is not active, we allow the enlistment in the NULL transaction. - // - // If it is active, technically this is an error. - // However, no exception is thrown as this was the precedent (and this case is silently ignored, no error, but no enlistment either). - // There are two mitigations for this: - // 1. SqlConnection.EnlistTransaction checks that the enlisted transaction has completed before allowing a different enlistment. - // 2. For debug builds, the assert at the beginning of this method checks for an enlistment in an active delegated transaction. - SysTx.Transaction enlistedTransaction = EnlistedTransaction; - if (enlistedTransaction != null && enlistedTransaction.TransactionInformation.Status != SysTx.TransactionStatus.Active) - { - EnlistNull(); - } - } - } - // Only enlist if it's different... - else if (!tx.Equals(EnlistedTransaction)) - { // WebData 20000024 - Must use Equals, not != - EnlistNonNull(tx); - } - } - - private void EnlistNonNull(SysTx.Transaction tx) - { - Debug.Assert(null != tx, "null transaction?"); - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, transaction {1}.", ObjectID, tx.GetHashCode()); - bool hasDelegatedTransaction = false; - - if (Is2005OrNewer) - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, attempting to delegate", ObjectID); - - // Promotable transactions are only supported on 2005 - // servers or newer. - SqlDelegatedTransaction delegatedTransaction = new SqlDelegatedTransaction(this, tx); - - try - { - // NOTE: System.Transactions claims to resolve all - // potential race conditions between multiple delegate - // requests of the same transaction to different - // connections in their code, such that only one - // attempt to delegate will succeed. - - // NOTE: PromotableSinglePhaseEnlist will eventually - // make a round trip to the server; doing this inside - // a lock is not the best choice. We presume that you - // aren't trying to enlist concurrently on two threads - // and leave it at that -- We don't claim any thread - // safety with regard to multiple concurrent requests - // to enlist the same connection in different - // transactions, which is good, because we don't have - // it anyway. - - // PromotableSinglePhaseEnlist may not actually promote - // the transaction when it is already delegated (this is - // the way they resolve the race condition when two - // threads attempt to delegate the same Lightweight - // Transaction) In that case, we can safely ignore - // our delegated transaction, and proceed to enlist - // in the promoted one. - - // NOTE: Global Transactions is an Azure SQL DB only - // feature where the Transaction Manager (TM) is not - // MS-DTC. Sys.Tx added APIs to support Non MS-DTC - // promoter types/TM in .NET 4.6.2. Following directions - // from .NETFX shiproom, to avoid a "hard-dependency" - // (compile time) on Sys.Tx, we use reflection to invoke - // the new APIs. Further, the _isGlobalTransaction flag - // indicates that this is an Azure SQL DB Transaction - // that could be promoted to a Global Transaction (it's - // always false for on-prem Sql Server). The Promote() - // call in SqlDelegatedTransaction makes sure that the - // right Sys.Tx.dll is loaded and that Global Transactions - // are actually allowed for this Azure SQL DB. - - if (_isGlobalTransaction) - { - if (SysTxForGlobalTransactions.EnlistPromotableSinglePhase == null) - { - // This could be a local Azure SQL DB transaction. - hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction); - } - else - { - hasDelegatedTransaction = (bool)SysTxForGlobalTransactions.EnlistPromotableSinglePhase.Invoke(tx, new object[] { delegatedTransaction, _globalTransactionTMID }); - } - } - else - { - // This is an MS-DTC distributed transaction - hasDelegatedTransaction = tx.EnlistPromotableSinglePhase(delegatedTransaction); - } - - if (hasDelegatedTransaction) - { - this.DelegatedTransaction = delegatedTransaction; - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, delegated to transaction {1} with transactionId=0x{2}", ObjectID, null != CurrentTransaction ? CurrentTransaction.ObjectID : 0, null != CurrentTransaction ? CurrentTransaction.TransactionId : SqlInternalTransaction.NullTransactionId); - } - } - catch (SqlException e) - { - // we do not want to eat the error if it is a fatal one - if (e.Class >= TdsEnums.FATAL_ERROR_CLASS) - { - throw; - } - - // if the parser is null or its state is not openloggedin, the connection is no longer good. - SqlInternalConnectionTds tdsConnection = this as SqlInternalConnectionTds; - if (tdsConnection != null) - { - TdsParser parser = tdsConnection.Parser; - if (parser == null || parser.State != TdsParserState.OpenLoggedIn) - { - throw; - } - } - - ADP.TraceExceptionWithoutRethrow(e); - - // In this case, SqlDelegatedTransaction.Initialize - // failed and we don't necessarily want to reject - // things -- there may have been a legitimate reason - // for the failure. - } - } - - if (!hasDelegatedTransaction) - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, delegation not possible, enlisting.", ObjectID); - byte[] cookie = null; - - if (_isGlobalTransaction) - { - if (SysTxForGlobalTransactions.GetPromotedToken == null) - { - throw SQL.UnsupportedSysTxForGlobalTransactions(); - } - - cookie = (byte[])SysTxForGlobalTransactions.GetPromotedToken.Invoke(tx, null); - } - else - { - if (null == _whereAbouts) - { - byte[] dtcAddress = GetDTCAddress(); - - if (null == dtcAddress) - { - throw SQL.CannotGetDTCAddress(); - } - _whereAbouts = dtcAddress; - } - cookie = GetTransactionCookie(tx, _whereAbouts); - } - - // send cookie to server to finish enlistment - PropagateTransactionCookie(cookie); - _isEnlistedInTransaction = true; - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, enlisted with transaction {1} with transactionId=0x{2}", ObjectID, null != CurrentTransaction ? CurrentTransaction.ObjectID : 0, null != CurrentTransaction ? CurrentTransaction.TransactionId : SqlInternalTransaction.NullTransactionId); - } - - EnlistedTransaction = tx; // Tell the base class about our enlistment - - // If we're on a 2005 or newer server, and we we delegate the - // transaction successfully, we will have done a begin transaction, - // which produces a transaction id that we should execute all requests - // on. The TdsParser or SmiEventSink will store this information as - // the current transaction. - // - // Likewise, propagating a transaction to a 2005 or newer server will - // produce a transaction id that The TdsParser or SmiEventSink will - // store as the current transaction. - // - // In either case, when we're working with a 2005 or newer server - // we better have a current transaction by now. - - Debug.Assert(!Is2005OrNewer || null != CurrentTransaction, "delegated/enlisted transaction with null current transaction?"); - } - - internal void EnlistNull() - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, unenlisting.", ObjectID); - - // We were in a transaction, but now we are not - so send - // message to server with empty transaction - confirmed proper - // behavior from Sameet Agarwal - // - // The connection pooler maintains separate pools for enlisted - // transactions, and only when that transaction is committed or - // rolled back will those connections be taken from that - // separate pool and returned to the general pool of connections - // that are not affiliated with any transactions. When this - // occurs, we will have a new transaction of null and we are - // required to send an empty transaction payload to the server. - PropagateTransactionCookie(null); - - _isEnlistedInTransaction = false; - EnlistedTransaction = null; // Tell the base class about our enlistment - - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, unenlisted.", ObjectID); - - // The EnlistTransaction above will return an TransactionEnded event, - // which causes the TdsParser or SmiEventSink should to clear the - // current transaction. - // - // In either case, when we're working with a 2005 or newer server - // we better not have a current transaction at this point. - - Debug.Assert(!Is2005OrNewer || null == CurrentTransaction, "unenlisted transaction with non-null current transaction?"); // verify it! - } - - override public void EnlistTransaction(SysTx.Transaction transaction) - { - SqlConnection.VerifyExecutePermission(); - - ValidateConnectionForExecute(null); - - // If a connection has a local transaction outstanding and you try - // to enlist in a DTC transaction, SQL Server will rollback the - // local transaction and then do the enlist (7.0 and 2000). So, if - // the user tries to do this, throw. - if (HasLocalTransaction) - { - throw ADP.LocalTransactionPresent(); - } - - if (null != transaction && transaction.Equals(EnlistedTransaction)) - { - // No-op if this is the current transaction - return; - } - - // If a connection is already enlisted in a DTC transaction and you - // try to enlist in another one, in 7.0 the existing DTC transaction - // would roll back and then the connection would enlist in the new - // one. In SQL 2000 & 2005, when you enlist in a DTC transaction - // while the connection is already enlisted in a DTC transaction, - // the connection simply switches enlistments. Regardless, simply - // enlist in the user specified distributed transaction. This - // behavior matches OLEDB and ODBC. - - TdsParser bestEffortCleanupTarget = null; - RuntimeHelpers.PrepareConstrainedRegions(); - try - { -#if DEBUG - TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); - - RuntimeHelpers.PrepareConstrainedRegions(); - try - { - tdsReliabilitySection.Start(); -#else - { -#endif //DEBUG - bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(Connection); - Enlist(transaction); - } -#if DEBUG - finally - { - tdsReliabilitySection.Stop(); - } -#endif //DEBUG - } - catch (System.OutOfMemoryException e) - { - Connection.Abort(e); - throw; - } - catch (System.StackOverflowException e) - { - Connection.Abort(e); - throw; - } - catch (System.Threading.ThreadAbortException e) - { - Connection.Abort(e); - SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); - throw; - } - } - - abstract internal void ExecuteTransaction(TransactionRequest transactionRequest, string name, IsolationLevel iso, SqlInternalTransaction internalTransaction, bool isDelegateControlRequest); - - internal SqlDataReader FindLiveReader(SqlCommand command) - { - SqlDataReader reader = null; - SqlReferenceCollection referenceCollection = (SqlReferenceCollection)ReferenceCollection; - if (null != referenceCollection) - { - reader = referenceCollection.FindLiveReader(command); - } - return reader; - } - - static internal TdsParser GetBestEffortCleanupTarget(SqlConnection connection) - { - if (null != connection) - { - SqlInternalConnectionTds innerConnection = (connection.InnerConnection as SqlInternalConnectionTds); - if (null != innerConnection) - { - return innerConnection.Parser; - } - } - - return null; - } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - static internal void BestEffortCleanup(TdsParser target) - { - if (null != target) - { - target.BestEffortCleanup(); - } - } - - abstract protected byte[] GetDTCAddress(); - - static private byte[] GetTransactionCookie(SysTx.Transaction transaction, byte[] whereAbouts) - { - byte[] transactionCookie = null; - if (null != transaction) - { - transactionCookie = SysTx.TransactionInterop.GetExportCookie(transaction, whereAbouts); - } - return transactionCookie; - } - - virtual protected void InternalDeactivate() - { - } - - // If wrapCloseInAction is defined, then the action it defines will be run with the connection close action passed in as a parameter - // The close action also supports being run asynchronously - internal void OnError(SqlException exception, bool breakConnection, Action wrapCloseInAction = null) - { - if (breakConnection) - { - DoomThisConnection(); - } - - var connection = Connection; - if (null != connection) - { - connection.OnError(exception, breakConnection, wrapCloseInAction); - } - else if (exception.Class >= TdsEnums.MIN_ERROR_CLASS) - { - // It is an error, and should be thrown. Class of TdsEnums.MIN_ERROR_CLASS - // or above is an error, below TdsEnums.MIN_ERROR_CLASS denotes an info message. - throw exception; - } - } - - abstract protected void PropagateTransactionCookie(byte[] transactionCookie); - - abstract internal void ValidateConnectionForExecute(SqlCommand command); - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs similarity index 76% rename from src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs index 20eb221f96..a6da618583 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs @@ -9,6 +9,11 @@ using Microsoft.Data.Common; using Microsoft.Data.ProviderBase; +#if NETFRAMEWORK +using System.Runtime.CompilerServices; +using System.Runtime.ConstrainedExecution; +#endif + namespace Microsoft.Data.SqlClient { internal abstract class SqlInternalConnection : DbConnectionInternal @@ -20,12 +25,14 @@ internal abstract class SqlInternalConnection : DbConnectionInternal private bool _isGlobalTransaction; // Whether this is a Global Transaction (Non-MSDTC, Azure SQL DB Transaction) private bool _isGlobalTransactionEnabledForServer; // Whether Global Transactions are enabled for this Azure SQL DB Server - private static readonly Guid _globalTransactionTMID = new Guid("1c742caf-6680-40ea-9c26-6b6846079764"); // ID of the Non-MSDTC, Azure SQL DB Transaction Manager + private static readonly Guid s_globalTransactionTMID = new("1c742caf-6680-40ea-9c26-6b6846079764"); // ID of the Non-MSDTC, Azure SQL DB Transaction Manager +#if NETCOREAPP || NETSTANDARD internal SqlCommand.ExecuteReaderAsyncCallContext CachedCommandExecuteReaderAsyncContext; internal SqlDataReader.Snapshot CachedDataReaderSnapshot; internal SqlDataReader.IsDBNullAsyncCallContext CachedDataReaderIsDBNullContext; internal SqlDataReader.ReadAsyncCallContext CachedDataReaderReadAsyncContext; +#endif // if connection is not open: null // if connection is open: currently active database @@ -77,6 +84,7 @@ abstract internal SqlInternalTransaction CurrentTransaction get; } + // SQLBU 415870 // Get the internal transaction that should be hooked to a new outer transaction // during a BeginTransaction API call. In some cases (i.e. connection is going to // be reset), CurrentTransaction should not be hooked up this way. @@ -105,7 +113,7 @@ override internal bool IsTransactionRoot { get { - var delegatedTransaction = DelegatedTransaction; + SqlDelegatedTransaction delegatedTransaction = DelegatedTransaction; return ((null != delegatedTransaction) && (delegatedTransaction.IsActive)); } } @@ -144,7 +152,6 @@ abstract internal bool IsLockedForBulkCopy get; } - abstract internal bool Is2008OrNewer { get; @@ -186,6 +193,32 @@ internal bool IsGlobalTransactionsEnabledForServer } } +#if NETFRAMEWORK + private bool _isAzureSQLConnection = false; // If connected to Azure SQL + + abstract internal bool Is2000 + { + get; + } + + abstract internal bool Is2005OrNewer + { + get; + } + + internal bool IsAzureSQLConnection + { + get + { + return _isAzureSQLConnection; + } + set + { + _isAzureSQLConnection = value; + } + } +#endif + override public DbTransaction BeginTransaction(System.Data.IsolationLevel iso) { return BeginSqlTransaction(iso, null, false); @@ -194,25 +227,74 @@ override public DbTransaction BeginTransaction(System.Data.IsolationLevel iso) virtual internal SqlTransaction BeginSqlTransaction(System.Data.IsolationLevel iso, string transactionName, bool shouldReconnect) { SqlStatistics statistics = null; +#if NETFRAMEWORK + TdsParser bestEffortCleanupTarget = null; + RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { - statistics = SqlStatistics.StartTimer(Connection.Statistics); +#if NETFRAMEWORK +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#else + { +#endif // DEBUG + bestEffortCleanupTarget = GetBestEffortCleanupTarget(Connection); +#endif // NETFRAMEWORK + statistics = SqlStatistics.StartTimer(Connection.Statistics); + +#if NETFRAMEWORK + SqlConnection.ExecutePermission.Demand(); // MDAC 81476 +#endif // NETFRAMEWORK + ValidateConnectionForExecute(null); - ValidateConnectionForExecute(null); + if (HasLocalTransactionFromAPI) + { + throw ADP.ParallelTransactionsNotSupported(Connection); + } - if (HasLocalTransactionFromAPI) - throw ADP.ParallelTransactionsNotSupported(Connection); + if (iso == System.Data.IsolationLevel.Unspecified) + { + iso = System.Data.IsolationLevel.ReadCommitted; // Default to ReadCommitted if unspecified. + } - if (iso == System.Data.IsolationLevel.Unspecified) + SqlTransaction transaction = new(this, Connection, iso, AvailableInternalTransaction); + transaction.InternalTransaction.RestoreBrokenConnection = shouldReconnect; + ExecuteTransaction(TransactionRequest.Begin, transactionName, iso, transaction.InternalTransaction, false); + transaction.InternalTransaction.RestoreBrokenConnection = false; + return transaction; +#if NETFRAMEWORK + } +#if DEBUG + finally { - iso = System.Data.IsolationLevel.ReadCommitted; // Default to ReadCommitted if unspecified. + tdsReliabilitySection.Stop(); } - - SqlTransaction transaction = new SqlTransaction(this, Connection, iso, AvailableInternalTransaction); - transaction.InternalTransaction.RestoreBrokenConnection = shouldReconnect; - ExecuteTransaction(TransactionRequest.Begin, transactionName, iso, transaction.InternalTransaction, false); - transaction.InternalTransaction.RestoreBrokenConnection = false; - return transaction; +#endif // DEBUG +#endif // NETFRAMEWORK + } + catch (OutOfMemoryException e) + { + Connection.Abort(e); + throw; + } + catch (StackOverflowException e) + { + Connection.Abort(e); + throw; + } + catch (System.Threading.ThreadAbortException e) + { + Connection.Abort(e); +#if NETFRAMEWORK + BestEffortCleanup(bestEffortCleanupTarget); +#endif // NETFRAMEWORK + throw; } finally { @@ -252,17 +334,62 @@ override protected DbReferenceCollection CreateReferenceCollection() override protected void Deactivate() { +#if NETFRAMEWORK + TdsParser bestEffortCleanupTarget = null; + RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { SqlClientEventSource.Log.TryAdvancedTraceEvent("SqlInternalConnection.Deactivate | ADV | Object Id {0} deactivating, Client Connection Id {1}", ObjectID, Connection?.ClientConnectionId); - SqlReferenceCollection referenceCollection = (SqlReferenceCollection)ReferenceCollection; - if (null != referenceCollection) + +#if NETFRAMEWORK +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try { - referenceCollection.Deactivate(); - } + tdsReliabilitySection.Start(); +#else + { +#endif // DEBUG + bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(Connection); +#endif // NETFRAMEWORK + SqlReferenceCollection referenceCollection = (SqlReferenceCollection)ReferenceCollection; + if (null != referenceCollection) + { + referenceCollection.Deactivate(); + } - // Invoke subclass-specific deactivation logic - InternalDeactivate(); + // Invoke subclass-specific deactivation logic + InternalDeactivate(); +#if NETFRAMEWORK + } +#if DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif // DEBUG +#endif // NETFRAMEWORK + } + catch (OutOfMemoryException) + { + DoomThisConnection(); + throw; + } + catch (StackOverflowException) + { + DoomThisConnection(); + throw; + } + catch (System.Threading.ThreadAbortException) + { + DoomThisConnection(); +#if NETFRAMEWORK + BestEffortCleanup(bestEffortCleanupTarget); +#endif + throw; } catch (Exception e) { @@ -275,6 +402,9 @@ override protected void Deactivate() // marked as unusable and destroyed upon returning to the // pool DoomThisConnection(); +#if NETFRAMEWORK + ADP.TraceExceptionWithoutRethrow(e); +#endif } } @@ -339,7 +469,7 @@ private void EnlistNonNull(Transaction tx) // Promotable transactions are only supported on 2005 // servers or newer. - SqlDelegatedTransaction delegatedTransaction = new SqlDelegatedTransaction(this, tx); + SqlDelegatedTransaction delegatedTransaction = new(this, tx); try { @@ -390,7 +520,7 @@ private void EnlistNonNull(Transaction tx) } else { - hasDelegatedTransaction = (bool)SysTxForGlobalTransactions.EnlistPromotableSinglePhase.Invoke(tx, new object[] { delegatedTransaction, _globalTransactionTMID }); + hasDelegatedTransaction = (bool)SysTxForGlobalTransactions.EnlistPromotableSinglePhase.Invoke(tx, new object[] { delegatedTransaction, s_globalTransactionTMID }); } } else @@ -401,7 +531,7 @@ private void EnlistNonNull(Transaction tx) if (hasDelegatedTransaction) { - this.DelegatedTransaction = delegatedTransaction; + DelegatedTransaction = delegatedTransaction; SqlClientEventSource.Log.TryAdvancedTraceEvent("SqlInternalConnection.EnlistNonNull | ADV | Object Id {0}, Client Connection Id {1} delegated to transaction {1} with transactionId {2}", ObjectID, Connection?.ClientConnectionId, delegatedTransaction?.ObjectID, delegatedTransaction?.Transaction?.TransactionInformation?.LocalIdentifier); } } @@ -414,8 +544,7 @@ private void EnlistNonNull(Transaction tx) } // if the parser is null or its state is not openloggedin, the connection is no longer good. - SqlInternalConnectionTds tdsConnection = this as SqlInternalConnectionTds; - if (tdsConnection != null) + if (this is SqlInternalConnectionTds tdsConnection) { TdsParser parser = tdsConnection.Parser; if (parser == null || parser.State != TdsParserState.OpenLoggedIn) @@ -424,6 +553,9 @@ private void EnlistNonNull(Transaction tx) } } +#if NETFRAMEWORK + ADP.TraceExceptionWithoutRethrow(e); +#endif // In this case, SqlDelegatedTransaction.Initialize // failed and we don't necessarily want to reject // things -- there may have been a legitimate reason @@ -449,12 +581,7 @@ private void EnlistNonNull(Transaction tx) if (null == _whereAbouts) { byte[] dtcAddress = GetDTCAddress(); - - if (null == dtcAddress) - { - throw SQL.CannotGetDTCAddress(); - } - _whereAbouts = dtcAddress; + _whereAbouts = dtcAddress ?? throw SQL.CannotGetDTCAddress(); } cookie = GetTransactionCookie(tx, _whereAbouts); } @@ -519,6 +646,9 @@ internal void EnlistNull() override public void EnlistTransaction(Transaction transaction) { +#if NETFRAMEWORK + SqlConnection.VerifyExecutePermission(); +#endif ValidateConnectionForExecute(null); // If a connection has a local transaction outstanding and you try @@ -545,16 +675,43 @@ override public void EnlistTransaction(Transaction transaction) // enlist in the user specified distributed transaction. This // behavior matches OLEDB and ODBC. +#if NETFRAMEWORK + TdsParser bestEffortCleanupTarget = null; + RuntimeHelpers.PrepareConstrainedRegions(); + try + { +#if DEBUG + TdsParser.ReliabilitySection tdsReliabilitySection = new(); + + RuntimeHelpers.PrepareConstrainedRegions(); + try + { + tdsReliabilitySection.Start(); +#else + { +#endif // DEBUG + bestEffortCleanupTarget = GetBestEffortCleanupTarget(Connection); + Enlist(transaction); + } +#if DEBUG + finally + { + tdsReliabilitySection.Stop(); + } +#endif // DEBUG + } +#else try { Enlist(transaction); } - catch (System.OutOfMemoryException e) +#endif // NETFRAMEWORK + catch (OutOfMemoryException e) { Connection.Abort(e); throw; } - catch (System.StackOverflowException e) + catch (StackOverflowException e) { Connection.Abort(e); throw; @@ -562,6 +719,9 @@ override public void EnlistTransaction(Transaction transaction) catch (System.Threading.ThreadAbortException e) { Connection.Abort(e); +#if NETFRAMEWORK + BestEffortCleanup(bestEffortCleanupTarget); +#endif throw; } } @@ -604,7 +764,7 @@ internal void OnError(SqlException exception, bool breakConnection, Action Date: Wed, 5 Oct 2022 19:56:25 +0100 Subject: [PATCH 19/78] Convert ExecuteNonQueryAsync to use async context object (#1692) --- .../Data/SqlClient/AAsyncCallContext.cs | 69 +++++++++++---- .../Microsoft/Data/SqlClient/SqlCommand.cs | 66 ++++++++++++--- .../Microsoft/Data/SqlClient/SqlDataReader.cs | 84 +++++++++++-------- 3 files changed, 154 insertions(+), 65 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AAsyncCallContext.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AAsyncCallContext.cs index 56e369593a..76710ff980 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AAsyncCallContext.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/AAsyncCallContext.cs @@ -17,38 +17,68 @@ namespace Microsoft.Data.SqlClient // CONSIDER creating your own Set method that calls the base Set rather than providing a parameterized ctor, it is friendlier to caching // DO NOT use this class' state after Dispose has been called. It will not throw ObjectDisposedException but it will be a cleared object - internal abstract class AAsyncCallContext : IDisposable + internal abstract class AAsyncCallContext : AAsyncBaseCallContext where TOwner : class + where TDisposable : IDisposable { - protected TOwner _owner; - protected TaskCompletionSource _source; - protected IDisposable _disposable; + protected TDisposable _disposable; protected AAsyncCallContext() { } - protected AAsyncCallContext(TOwner owner, TaskCompletionSource source, IDisposable disposable = null) + protected AAsyncCallContext(TOwner owner, TaskCompletionSource source, TDisposable disposable = default) { Set(owner, source, disposable); } - protected void Set(TOwner owner, TaskCompletionSource source, IDisposable disposable = null) + protected void Set(TOwner owner, TaskCompletionSource source, TDisposable disposable = default) + { + base.Set(owner, source); + _disposable = disposable; + } + + protected override void DisposeCore() + { + TDisposable copyDisposable = _disposable; + _disposable = default; + copyDisposable?.Dispose(); + } + } + + internal abstract class AAsyncBaseCallContext + { + protected TOwner _owner; + protected TaskCompletionSource _source; + protected bool _isDisposed; + + protected AAsyncBaseCallContext() + { + } + + protected void Set(TOwner owner, TaskCompletionSource source) { _owner = owner ?? throw new ArgumentNullException(nameof(owner)); _source = source ?? throw new ArgumentNullException(nameof(source)); - _disposable = disposable; + _isDisposed = false; } protected void ClearCore() { _source = null; _owner = default; - IDisposable copyDisposable = _disposable; - _disposable = null; - copyDisposable?.Dispose(); + try + { + DisposeCore(); + } + finally + { + _isDisposed = true; + } } + protected abstract void DisposeCore(); + /// /// override this method to cleanup instance data before ClearCore is called which will blank the base data /// @@ -65,16 +95,19 @@ protected virtual void AfterCleared(TOwner owner) public void Dispose() { - TOwner owner = _owner; - try - { - Clear(); - } - finally + if (!_isDisposed) { - ClearCore(); + TOwner owner = _owner; + try + { + Clear(); + } + finally + { + ClearCore(); + } + AfterCleared(owner); } - AfterCleared(owner); } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index 6c8140000e..4effb98e59 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -46,7 +46,7 @@ public sealed partial class SqlCommand : DbCommand, ICloneable private static readonly Func s_beginExecuteXmlReaderInternal = BeginExecuteXmlReaderInternalCallback; private static readonly Func s_beginExecuteNonQueryInternal = BeginExecuteNonQueryInternalCallback; - internal sealed class ExecuteReaderAsyncCallContext : AAsyncCallContext + internal sealed class ExecuteReaderAsyncCallContext : AAsyncCallContext { public Guid OperationID; public CommandBehavior CommandBehavior; @@ -54,7 +54,7 @@ internal sealed class ExecuteReaderAsyncCallContext : AAsyncCallContext _owner; public TaskCompletionSource TaskCompletionSource => _source; - public void Set(SqlCommand command, TaskCompletionSource source, IDisposable disposable, CommandBehavior behavior, Guid operationID) + public void Set(SqlCommand command, TaskCompletionSource source, CancellationTokenRegistration disposable, CommandBehavior behavior, Guid operationID) { base.Set(command, source, disposable); CommandBehavior = behavior; @@ -73,6 +73,31 @@ protected override void AfterCleared(SqlCommand owner) } } + internal sealed class ExecuteNonQueryAsyncCallContext : AAsyncCallContext + { + public Guid OperationID; + + public SqlCommand Command => _owner; + + public TaskCompletionSource TaskCompletionSource => _source; + + public void Set(SqlCommand command, TaskCompletionSource source, CancellationTokenRegistration disposable, Guid operationID) + { + base.Set(command, source, disposable); + OperationID = operationID; + } + + protected override void Clear() + { + OperationID = default; + } + + protected override void AfterCleared(SqlCommand owner) + { + + } + } + private CommandType _commandType; private int? _commandTimeout; private UpdateRowSource _updatedRowSource = UpdateRowSource.Both; @@ -2540,23 +2565,36 @@ private Task InternalExecuteNonQueryAsync(CancellationToken cancellationTok } Task returnedTask = source.Task; + returnedTask = RegisterForConnectionCloseNotification(returnedTask); + + ExecuteNonQueryAsyncCallContext context = new ExecuteNonQueryAsyncCallContext(); + context.Set(this, source, registration, operationId); try { - returnedTask = RegisterForConnectionCloseNotification(returnedTask); - - Task.Factory.FromAsync(BeginExecuteNonQueryAsync, EndExecuteNonQueryAsync, null) - .ContinueWith((Task task) => + Task.Factory.FromAsync( + static (AsyncCallback callback, object stateObject) => ((ExecuteNonQueryAsyncCallContext)stateObject).Command.BeginExecuteNonQueryAsync(callback, stateObject), + static (IAsyncResult result) => ((ExecuteNonQueryAsyncCallContext)result.AsyncState).Command.EndExecuteNonQueryAsync(result), + state: context + ).ContinueWith( + static (Task task, object state) => { - registration.Dispose(); + ExecuteNonQueryAsyncCallContext context = (ExecuteNonQueryAsyncCallContext)state; + + Guid operationId = context.OperationID; + SqlCommand command = context.Command; + TaskCompletionSource source = context.TaskCompletionSource; + + context.Dispose(); + context = null; + if (task.IsFaulted) { Exception e = task.Exception.InnerException; - s_diagnosticListener.WriteCommandError(operationId, this, _transaction, e); + s_diagnosticListener.WriteCommandError(operationId, command, command._transaction, e); source.SetException(e); } else { - s_diagnosticListener.WriteCommandAfter(operationId, this, _transaction); if (task.IsCanceled) { source.SetCanceled(); @@ -2565,15 +2603,18 @@ private Task InternalExecuteNonQueryAsync(CancellationToken cancellationTok { source.SetResult(task.Result); } + s_diagnosticListener.WriteCommandAfter(operationId, command, command._transaction); } - }, - TaskScheduler.Default + }, + state: context, + scheduler: TaskScheduler.Default ); } catch (Exception e) { s_diagnosticListener.WriteCommandError(operationId, this, _transaction, e); source.SetException(e); + context.Dispose(); } return returnedTask; @@ -2648,11 +2689,11 @@ private Task InternalExecuteReaderAsync(CommandBehavior behavior, } Task returnedTask = source.Task; + ExecuteReaderAsyncCallContext context = null; try { returnedTask = RegisterForConnectionCloseNotification(returnedTask); - ExecuteReaderAsyncCallContext context = null; if (_activeConnection?.InnerConnection is SqlInternalConnection sqlInternalConnection) { context = Interlocked.Exchange(ref sqlInternalConnection.CachedCommandExecuteReaderAsyncContext, null); @@ -2680,6 +2721,7 @@ private Task InternalExecuteReaderAsync(CommandBehavior behavior, } source.SetException(e); + context.Dispose(); } return returnedTask; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs index f24f374644..0e03e86286 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -4406,7 +4406,7 @@ public override Task NextResultAsync(CancellationToken cancellationToken) return source.Task; } - IDisposable registration = null; + CancellationTokenRegistration registration = default; if (cancellationToken.CanBeCanceled) { if (cancellationToken.IsCancellationRequested) @@ -4706,7 +4706,7 @@ out bytesRead Debug.Assert(context.Source != null, "context._source should not be null when continuing"); // setup for cleanup/completing retryTask.ContinueWith( - continuationAction: SqlDataReaderAsyncCallContext.s_completeCallback, + continuationAction: SqlDataReaderBaseAsyncCallContext.s_completeCallback, state: context, TaskScheduler.Default ); @@ -4734,7 +4734,7 @@ public override Task ReadAsync(CancellationToken cancellationToken) } // Register first to catch any already expired tokens to be able to trigger cancellation event. - IDisposable registration = null; + CancellationTokenRegistration registration = default; if (cancellationToken.CanBeCanceled) { registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); @@ -5006,7 +5006,7 @@ override public Task IsDBNullAsync(int i, CancellationToken cancellationTo } // Setup cancellations - IDisposable registration = null; + CancellationTokenRegistration registration = default; if (cancellationToken.CanBeCanceled) { registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); @@ -5022,7 +5022,7 @@ override public Task IsDBNullAsync(int i, CancellationToken cancellationTo context = new IsDBNullAsyncCallContext(); } - Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == null, "cached ISDBNullAsync context not properly disposed"); + Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ISDBNullAsync context not properly disposed"); context.Set(this, source, registration); context._columnIndex = i; @@ -5153,7 +5153,7 @@ override public Task GetFieldValueAsync(int i, CancellationToken cancellat } // Setup cancellations - IDisposable registration = null; + CancellationTokenRegistration registration = default; if (cancellationToken.CanBeCanceled) { registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); @@ -5217,49 +5217,63 @@ internal void CompletePendingReadWithFailure(int errorCode, bool resetForcePendi } #endif - - internal abstract class SqlDataReaderAsyncCallContext : AAsyncCallContext + + internal abstract class SqlDataReaderBaseAsyncCallContext : AAsyncBaseCallContext { internal static readonly Action, object> s_completeCallback = CompleteAsyncCallCallback; internal static readonly Func> s_executeCallback = ExecuteAsyncCallCallback; - protected SqlDataReaderAsyncCallContext() + protected SqlDataReaderBaseAsyncCallContext() { } - protected SqlDataReaderAsyncCallContext(SqlDataReader owner, TaskCompletionSource source, IDisposable disposable = null) + protected SqlDataReaderBaseAsyncCallContext(SqlDataReader owner, TaskCompletionSource source) { - Set(owner, source, disposable); + Set(owner, source); } internal abstract Func> Execute { get; } internal SqlDataReader Reader { get => _owner; set => _owner = value; } - public IDisposable Disposable { get => _disposable; set => _disposable = value; } - public TaskCompletionSource Source { get => _source; set => _source = value; } - new public void Set(SqlDataReader reader, TaskCompletionSource source, IDisposable disposable) - { - base.Set(reader, source, disposable); - } - private static Task ExecuteAsyncCallCallback(Task task, object state) { - SqlDataReaderAsyncCallContext context = (SqlDataReaderAsyncCallContext)state; + SqlDataReaderBaseAsyncCallContext context = (SqlDataReaderBaseAsyncCallContext)state; return context.Reader.ContinueAsyncCall(task, context); } private static void CompleteAsyncCallCallback(Task task, object state) { - SqlDataReaderAsyncCallContext context = (SqlDataReaderAsyncCallContext)state; + SqlDataReaderBaseAsyncCallContext context = (SqlDataReaderBaseAsyncCallContext)state; context.Reader.CompleteAsyncCall(task, context); } } - internal sealed class ReadAsyncCallContext : SqlDataReaderAsyncCallContext + internal abstract class SqlDataReaderAsyncCallContext : SqlDataReaderBaseAsyncCallContext + where TDisposable : IDisposable + { + private TDisposable _disposable; + + public TDisposable Disposable { get => _disposable; set => _disposable = value; } + + public void Set(SqlDataReader owner, TaskCompletionSource source, TDisposable disposable) + { + base.Set(owner, source); + _disposable = disposable; + } + + protected override void DisposeCore() + { + TDisposable copy = _disposable; + _disposable = default; + copy.Dispose(); + } + } + + internal sealed class ReadAsyncCallContext : SqlDataReaderAsyncCallContext { internal static readonly Func> s_execute = SqlDataReader.ReadAsyncExecute; @@ -5278,7 +5292,7 @@ protected override void AfterCleared(SqlDataReader owner) } } - internal sealed class IsDBNullAsyncCallContext : SqlDataReaderAsyncCallContext + internal sealed class IsDBNullAsyncCallContext : SqlDataReaderAsyncCallContext { internal static readonly Func> s_execute = SqlDataReader.IsDBNullAsyncExecute; @@ -5294,19 +5308,19 @@ protected override void AfterCleared(SqlDataReader owner) } } - private sealed class HasNextResultAsyncCallContext : SqlDataReaderAsyncCallContext + private sealed class HasNextResultAsyncCallContext : SqlDataReaderAsyncCallContext { private static readonly Func> s_execute = SqlDataReader.NextResultAsyncExecute; - public HasNextResultAsyncCallContext(SqlDataReader reader, TaskCompletionSource source, IDisposable disposable) - : base(reader, source, disposable) + public HasNextResultAsyncCallContext(SqlDataReader reader, TaskCompletionSource source, CancellationTokenRegistration disposable) { + Set(reader, source, disposable); } internal override Func> Execute => s_execute; } - private sealed class GetBytesAsyncCallContext : SqlDataReaderAsyncCallContext + private sealed class GetBytesAsyncCallContext : SqlDataReaderAsyncCallContext { internal enum OperationMode { @@ -5344,7 +5358,7 @@ protected override void Clear() } } - private sealed class GetFieldValueAsyncCallContext : SqlDataReaderAsyncCallContext + private sealed class GetFieldValueAsyncCallContext : SqlDataReaderAsyncCallContext { private static readonly Func> s_execute = SqlDataReader.GetFieldValueAsyncExecute; @@ -5352,9 +5366,9 @@ private sealed class GetFieldValueAsyncCallContext : SqlDataReaderAsyncCallCo internal GetFieldValueAsyncCallContext() { } - internal GetFieldValueAsyncCallContext(SqlDataReader reader, TaskCompletionSource source, IDisposable disposable) - : base(reader, source, disposable) + internal GetFieldValueAsyncCallContext(SqlDataReader reader, TaskCompletionSource source, CancellationTokenRegistration disposable) { + Set(reader, source, disposable); } protected override void Clear() @@ -5374,7 +5388,7 @@ protected override void Clear() /// /// /// - private Task InvokeAsyncCall(SqlDataReaderAsyncCallContext context) + private Task InvokeAsyncCall(SqlDataReaderBaseAsyncCallContext context) { TaskCompletionSource source = context.Source; try @@ -5396,7 +5410,7 @@ private Task InvokeAsyncCall(SqlDataReaderAsyncCallContext context) else { task.ContinueWith( - continuationAction: SqlDataReaderAsyncCallContext.s_completeCallback, + continuationAction: SqlDataReaderBaseAsyncCallContext.s_completeCallback, state: context, TaskScheduler.Default ); @@ -5421,7 +5435,7 @@ private Task InvokeAsyncCall(SqlDataReaderAsyncCallContext context) /// /// /// - private Task ExecuteAsyncCall(SqlDataReaderAsyncCallContext context) + private Task ExecuteAsyncCall(AAsyncBaseCallContext context) { // _networkPacketTaskSource could be null if the connection was closed // while an async invocation was outstanding. @@ -5434,7 +5448,7 @@ private Task ExecuteAsyncCall(SqlDataReaderAsyncCallContext context) else { return completionSource.Task.ContinueWith( - continuationFunction: SqlDataReaderAsyncCallContext.s_executeCallback, + continuationFunction: SqlDataReaderBaseAsyncCallContext.s_executeCallback, state: context, TaskScheduler.Default ).Unwrap(); @@ -5450,7 +5464,7 @@ private Task ExecuteAsyncCall(SqlDataReaderAsyncCallContext context) /// /// /// - private Task ContinueAsyncCall(Task task, SqlDataReaderAsyncCallContext context) + private Task ContinueAsyncCall(Task task, SqlDataReaderBaseAsyncCallContext context) { // this function must be an instance function called from the static callback because otherwise a compiler error // is caused by accessing the _cancelAsyncOnCloseToken field of a MarshalByRefObject derived class @@ -5510,7 +5524,7 @@ private Task ContinueAsyncCall(Task task, SqlDataReaderAsyncCallContext /// /// /// - private void CompleteAsyncCall(Task task, SqlDataReaderAsyncCallContext context) + private void CompleteAsyncCall(Task task, SqlDataReaderBaseAsyncCallContext context) { TaskCompletionSource source = context.Source; context.Dispose(); From c68dd0ee2233fd839e330fe4d6a2683889d2d991 Mon Sep 17 00:00:00 2001 From: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com> Date: Wed, 5 Oct 2022 12:43:30 -0700 Subject: [PATCH 20/78] Merge to shared - TdsParserSessionPool (#1595) --- .../src/Microsoft.Data.SqlClient.csproj | 4 +- .../Data/SqlClient/TdsParserSessionPool.cs | 225 ------------------ .../netfx/src/Microsoft.Data.SqlClient.csproj | 4 +- .../Data/SqlClient/TdsParserSessionPool.cs | 54 ++--- 4 files changed, 33 insertions(+), 254 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs rename src/Microsoft.Data.SqlClient/{netfx => }/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs (94%) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index a64464e1a4..90a417a5ca 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -475,6 +475,9 @@ Microsoft\Data\SqlClient\TdsRecordBufferSetter.cs + + Microsoft\Data\SqlClient\TdsParserSessionPool.cs + Microsoft\Data\SqlClient\TdsValueSetter.cs @@ -643,7 +646,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs deleted file mode 100644 index be3cd1404d..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs +++ /dev/null @@ -1,225 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using Microsoft.Data.Common; - -namespace Microsoft.Data.SqlClient -{ - internal class TdsParserSessionPool - { - // NOTE: This is a very simplistic, lightweight pooler. It wasn't - // intended to handle huge number of items, just to keep track - // of the session objects to ensure that they're cleaned up in - // a timely manner, to avoid holding on to an unacceptable - // amount of server-side resources in the event that consumers - // let their data readers be GC'd, instead of explicitly - // closing or disposing of them - - private const int MaxInactiveCount = 10; // pick something, preferably small... - - private static int _objectTypeCount; // EventSource Counter - private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); - - private readonly TdsParser _parser; // parser that owns us - private readonly List _cache; // collection of all known sessions - private int _cachedCount; // lock-free _cache.Count - private TdsParserStateObject[] _freeStateObjects; // collection of all sessions available for reuse - private int _freeStateObjectCount; // Number of available free sessions - - internal TdsParserSessionPool(TdsParser parser) - { - _parser = parser; - _cache = new List(); - _freeStateObjects = new TdsParserStateObject[MaxInactiveCount]; - _freeStateObjectCount = 0; - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} created session pool for parser {1}", ObjectID, parser.ObjectID); - } - - private bool IsDisposed - { - get - { - return (null == _freeStateObjects); - } - } - - internal int ObjectID - { - get - { - return _objectID; - } - } - - internal void Deactivate() - { - // When being deactivated, we check all the sessions in the - // cache to make sure they're cleaned up and then we dispose of - // sessions that are past what we want to keep around. - using (TryEventScope.Create(" {0} deactivating cachedCount={1}", ObjectID, _cachedCount)) - { - lock (_cache) - { - // NOTE: The PutSession call below may choose to remove the - // session from the cache, which will throw off our - // enumerator. We avoid that by simply indexing backward - // through the array. - - for (int i = _cache.Count - 1; i >= 0; i--) - { - TdsParserStateObject session = _cache[i]; - - if (null != session) - { - if (session.IsOrphaned) - { - // TODO: consider adding a performance counter for the number of sessions we reclaim - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} reclaiming session {1}", ObjectID, session.ObjectID); - PutSession(session); - } - } - } - // TODO: re-enable this assert when the connection isn't doomed. - //Debug.Assert (_cachedCount < MaxInactiveCount, "non-orphaned connection past initial allocation?"); - } - } - } - - internal void Dispose() - { - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} disposing cachedCount={1}", ObjectID, _cachedCount); - lock (_cache) - { - // Dispose free sessions - for (int i = 0; i < _freeStateObjectCount; i++) - { - if (_freeStateObjects[i] != null) - { - _freeStateObjects[i].Dispose(); - } - } - _freeStateObjects = null; - _freeStateObjectCount = 0; - - // Dispose orphaned sessions - for (int i = 0; i < _cache.Count; i++) - { - if (_cache[i] != null) - { - if (_cache[i].IsOrphaned) - { - _cache[i].Dispose(); - } - else - { - // Remove the "initial" callback (this will allow the stateObj to be GC collected if need be) - _cache[i].DecrementPendingCallbacks(false); - } - } - } - _cache.Clear(); - _cachedCount = 0; - // Any active sessions will take care of themselves - // (It's too dangerous to dispose them, as this can cause AVs) - } - } - - internal TdsParserStateObject GetSession(object owner) - { - TdsParserStateObject session; - lock (_cache) - { - if (IsDisposed) - { - throw ADP.ClosedConnectionError(); - } - else if (_freeStateObjectCount > 0) - { - // Free state object - grab it - _freeStateObjectCount--; - session = _freeStateObjects[_freeStateObjectCount]; - _freeStateObjects[_freeStateObjectCount] = null; - Debug.Assert(session != null, "There was a null session in the free session list?"); - } - else - { - // No free objects, create a new one - session = _parser.CreateSession(); - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} adding session {1} to pool", ObjectID, session.ObjectID); - - _cache.Add(session); - _cachedCount = _cache.Count; - } - - session.Activate(owner); - } - - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} using session {1}", ObjectID, session.ObjectID); - return session; - } - - internal void PutSession(TdsParserStateObject session) - { - Debug.Assert(null != session, "null session?"); - //Debug.Assert(null != session.Owner, "session without owner?"); - - bool okToReuse = session.Deactivate(); - - lock (_cache) - { - if (IsDisposed) - { - // We're disposed - just clean out the session - Debug.Assert(_cachedCount == 0, "SessionPool is disposed, but there are still sessions in the cache?"); - session.Dispose(); - } - else if ((okToReuse) && (_freeStateObjectCount < MaxInactiveCount)) - { - // Session is good to re-use and our cache has space - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} keeping session {1} cachedCount={2}", ObjectID, session.ObjectID, _cachedCount); - Debug.Assert(!session.HasPendingData, "pending data on a pooled session?"); - - _freeStateObjects[_freeStateObjectCount] = session; - _freeStateObjectCount++; - } - else - { - // Either the session is bad, or we have no cache space - so dispose the session and remove it - SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} disposing session {1} cachedCount={2}", ObjectID, session.ObjectID, _cachedCount); - - bool removed = _cache.Remove(session); - Debug.Assert(removed, "session not in pool?"); - _cachedCount = _cache.Count; - session.Dispose(); - } - - session.RemoveOwner(); - } - } - - - internal int ActiveSessionsCount - { - get - { - return _cachedCount - _freeStateObjectCount; - } - } - - internal string TraceString() - { - return string.Format(/*IFormatProvider*/ null, - "(ObjID={0}, free={1}, cached={2}, total={3})", - _objectID, - null == _freeStateObjects ? "(null)" : _freeStateObjectCount.ToString((IFormatProvider)null), - _cachedCount, - _cache.Count); - } - } -} - - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 71f1d54125..bf6b3f3ff2 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -566,6 +566,9 @@ Microsoft\Data\SqlClient\TdsRecordBufferSetter.cs + + Microsoft\Data\SqlClient\TdsParserSessionPool.cs + Microsoft\Data\SqlClient\TdsValueSetter.cs @@ -653,7 +656,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs similarity index 94% rename from src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs index 5c1f64aa09..ed53a831c4 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSessionPool.cs @@ -14,15 +14,15 @@ internal class TdsParserSessionPool // NOTE: This is a very simplistic, lightweight pooler. It wasn't // intended to handle huge number of items, just to keep track // of the session objects to ensure that they're cleaned up in - // a timely manner, to avoid holding on to an unacceptible + // a timely manner, to avoid holding on to an unacceptable // amount of server-side resources in the event that consumers // let their data readers be GC'd, instead of explicitly // closing or disposing of them private const int MaxInactiveCount = 10; // pick something, preferably small... - private static int _objectTypeCount; // EventSource Counter - private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); + private static int s_objectTypeCount; // EventSource Counter + private readonly int _objectID = System.Threading.Interlocked.Increment(ref s_objectTypeCount); private readonly TdsParser _parser; // parser that owns us private readonly List _cache; // collection of all known sessions @@ -89,23 +89,6 @@ internal void Deactivate() } } - // This is called from a ThreadAbort - ensure that it can be run from a CER Catch - internal void BestEffortCleanup() - { - for (int i = 0; i < _cache.Count; i++) - { - TdsParserStateObject session = _cache[i]; - if (null != session) - { - var sessionHandle = session.Handle; - if (sessionHandle != null) - { - sessionHandle.Dispose(); - } - } - } - } - internal void Dispose() { SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} disposing cachedCount={1}", ObjectID, _cachedCount); @@ -140,7 +123,6 @@ internal void Dispose() } _cache.Clear(); _cachedCount = 0; - // Any active sessions will take care of themselves // (It's too dangerous to dispose them, as this can cause AVs) } @@ -175,6 +157,7 @@ internal TdsParserStateObject GetSession(object owner) session.Activate(owner); } + SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} using session {1}", ObjectID, session.ObjectID); return session; } @@ -190,7 +173,7 @@ internal void PutSession(TdsParserStateObject session) { if (IsDisposed) { - // We're diposed - just clean out the session + // We're disposed - just clean out the session Debug.Assert(_cachedCount == 0, "SessionPool is disposed, but there are still sessions in the cache?"); session.Dispose(); } @@ -198,8 +181,11 @@ internal void PutSession(TdsParserStateObject session) { // Session is good to re-use and our cache has space SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0} keeping session {1} cachedCount={2}", ObjectID, session.ObjectID, _cachedCount); +#if NETFRAMEWORK Debug.Assert(!session._pendingData, "pending data on a pooled session?"); - +#else + Debug.Assert(!session.HasPendingData, "pending data on a pooled session?"); +#endif _freeStateObjects[_freeStateObjectCount] = session; _freeStateObjectCount++; } @@ -218,9 +204,12 @@ internal void PutSession(TdsParserStateObject session) } } + + internal int ActiveSessionsCount => _cachedCount - _freeStateObjectCount; + internal string TraceString() { - return String.Format(/*IFormatProvider*/ null, + return string.Format(/*IFormatProvider*/ null, "(ObjID={0}, free={1}, cached={2}, total={3})", _objectID, null == _freeStateObjects ? "(null)" : _freeStateObjectCount.ToString((IFormatProvider)null), @@ -228,13 +217,24 @@ internal string TraceString() _cache.Count); } - internal int ActiveSessionsCount +#if NETFRAMEWORK + // This is called from a ThreadAbort - ensure that it can be run from a CER Catch + internal void BestEffortCleanup() { - get + for (int i = 0; i < _cache.Count; i++) { - return _cachedCount - _freeStateObjectCount; + TdsParserStateObject session = _cache[i]; + if (null != session) + { + SNIHandle sessionHandle = session.Handle; + if (sessionHandle != null) + { + sessionHandle.Dispose(); + } + } } } +#endif } } From fe8d1c11e4f47886e015b5c1a56adae7ffbac967 Mon Sep 17 00:00:00 2001 From: Javad Date: Thu, 6 Oct 2022 07:42:17 -0700 Subject: [PATCH 21/78] Release | Updating SNI version for 5.1.0-preview1 release (#1787) --- tools/props/Versions.props | 6 +++--- tools/specs/Microsoft.Data.SqlClient.nuspec | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/props/Versions.props b/tools/props/Versions.props index 23a1eb61ff..68a9ed0beb 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -6,7 +6,7 @@ 5.0.0.0 - 5.0.0-dev + 5.1.0-dev $(NugetPackageVersion) @@ -20,7 +20,7 @@ - 5.0.0 + 5.1.0-preview1.22278.1 4.3.1 4.3.0 @@ -38,7 +38,7 @@ 5.0.0 - 5.0.0 + 5.1.0-preview1.22278.1 5.0.0 1.0.0 5.0.0 diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index a9f0b2d6c7..c69ab3eb08 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -11,7 +11,7 @@ dotnet.png Provides the data provider for SQL Server. These classes provide access to versions of SQL Server and encapsulate database-specific protocols, including tabular data stream (TDS) - + Commonly Used Types: Microsoft.Data.SqlClient.SqlConnection Microsoft.Data.SqlClient.SqlException @@ -28,7 +28,7 @@ When using NuGet 3.x this package requires at least version 3.4. sqlclient microsoft.data.sqlclient - + @@ -42,7 +42,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -61,7 +61,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -80,7 +80,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + From f361a67e6304deb192945e14f29ac64646d3d35b Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Tue, 11 Oct 2022 09:56:54 -0700 Subject: [PATCH 22/78] 5.0.1 Release notes [main branch] (#1794) Release notes 5.0.1 --- CHANGELOG.md | 15 +++++++ release-notes/5.0/5.0.0.md | 2 +- release-notes/5.0/5.0.1.md | 81 +++++++++++++++++++++++++++++++++++++ release-notes/5.0/5.0.md | 1 + release-notes/5.0/README.md | 1 + 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 release-notes/5.0/5.0.1.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 8209ff0d2e..76f7de12e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## [Stable release 5.0.1] - 2022-10-07 + +### Fixed + +- Fixed missing `HostNameInCertificate` connection string property in .NET Framework. [#1782](https://github.com/dotnet/SqlClient/pull/1782) +- Fixed async deadlock issue when sending attention fails due to network failure. [#1783](https://github.com/dotnet/SqlClient/pull/1783) +- Fixed **Null Reference Exception** on assigning `null` to `SqlConnectionStringBuilder.Encrypt`. [#1784](https://github.com/dotnet/SqlClient/pull/1784) +- Fixed `ReadAsync()` behavior to register Cancellation token action before streaming results. [#1785](https://github.com/dotnet/SqlClient/pull/1785) +- Fixed hang on infinite timeout and managed SNI. [#1798](https://github.com/dotnet/SqlClient/pull/1798) +- Fixed Default UTF8 collation conflict. [#1799](https://github.com/dotnet/SqlClient/pull/1799) + +### Changed + +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET Core/Standard dependency) version to `5.0.1` [#1795](https://github.com/dotnet/SqlClient/pull/1795), which includes the fix for AppDomain crash introducing in issue [#1418](https://github.com/dotnet/SqlClient/issues/1418). + ## [Stable release 5.0.0] - 2022-08-05 This update brings the below changes over the previous release: diff --git a/release-notes/5.0/5.0.0.md b/release-notes/5.0/5.0.0.md index ecc981ce64..1bf0f071c5 100644 --- a/release-notes/5.0/5.0.0.md +++ b/release-notes/5.0/5.0.0.md @@ -142,7 +142,7 @@ Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning #### .NET Framework -- Microsoft.Data.SqlClient.SNI.runtime 5.0.0 +- Microsoft.Data.SqlClient.SNI 5.0.0 - Azure.Identity 1.6.0 - Microsoft.Identity.Client 4.45.0 - Microsoft.IdentityModel.JsonWebTokens 6.21.0 diff --git a/release-notes/5.0/5.0.1.md b/release-notes/5.0/5.0.1.md new file mode 100644 index 0000000000..39d36cc579 --- /dev/null +++ b/release-notes/5.0/5.0.1.md @@ -0,0 +1,81 @@ +# Release Notes + +## Microsoft.Data.SqlClient 5.0.1 released 7 October 2022 + +This update includes the following changes over the 5.0.0 release: + +### Fixed + +- Fixed missing `HostNameInCertificate` connection string property in .NET Framework. [#1782](https://github.com/dotnet/SqlClient/pull/1782) +- Fixed async deadlock issue when sending attention fails due to network failure. [#1783](https://github.com/dotnet/SqlClient/pull/1783) +- Fixed **Null Reference Exception** on assigning `null` to `SqlConnectionStringBuilder.Encrypt`. [#1784](https://github.com/dotnet/SqlClient/pull/1784) +- Fixed `ReadAsync()` behavior to register Cancellation token action before streaming results. [#1785](https://github.com/dotnet/SqlClient/pull/1785) +- Fixed hang on infinite timeout and managed SNI. [#1798](https://github.com/dotnet/SqlClient/pull/1798) +- Fixed Default UTF8 collation conflict. [#1799](https://github.com/dotnet/SqlClient/pull/1799) + +### Changed + +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET Core/Standard dependency) version to `5.0.1` [#1795](https://github.com/dotnet/SqlClient/pull/1795), which includes the fix for AppDomain crash introducing in issue [#1418](https://github.com/dotnet/SqlClient/issues/1418). + +## Target Platform Support + +- .NET Framework 4.6.2+ (Windows x86, Windows x64) +- .NET Core 3.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) +- .NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Dependencies + +#### .NET Framework + +- Microsoft.Data.SqlClient.SNI 5.0.1 +- Azure.Identity 1.6.0 +- Microsoft.Identity.Client 4.45.0 +- Microsoft.IdentityModel.JsonWebTokens 6.21.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.21.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.IO 4.3.0 +- System.Runtime.InteropServices.RuntimeInformation 4.3.0 +- System.Security.Cryptography.Algorithms 4.3.1 +- System.Security.Cryptography.Primitives 4.3.0 +- System.Text.Encoding.Web 4.7.2 + +#### .NET Core + +- Microsoft.Data.SqlClient.SNI.runtime 5.0.1 +- Azure.Identity 1.6.0 +- Microsoft.Identity.Client 4.45.0 +- Microsoft.IdentityModel.JsonWebTokens 6.21.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.21.0 +- Microsoft.SqlServer.Server 1.0.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.Diagnostics.DiagnosticSource 5.0.0 +- System.IO 4.3.0 +- System.Runtime.Caching 5.0.0 +- System.Text.Encoding.CodePages 5.0.0 +- System.Text.Encodings.Web 4.7.2 +- System.Resources.ResourceManager 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 + +#### .NET Standard + +- Microsoft.Data.SqlClient.SNI.runtime 5.0.1 +- Azure.Identity 1.6.0 +- Microsoft.Identity.Client 4.45.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.21.0 +- Microsoft.IdentityModel.JsonWebTokens 6.21.0 +- Microsoft.SqlServer.Server 1.0.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.IO 4.3.0 +- System.Runtime.Caching 5.0.0 +- System.Text.Encoding.CodePages 5.0.0 +- System.Text.Encodings.Web 4.7.2 +- System.Runtime.Loader 4.3.0 +- System.Resources.ResourceManager 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 diff --git a/release-notes/5.0/5.0.md b/release-notes/5.0/5.0.md index 6fa437317c..ec3dbc7eb6 100644 --- a/release-notes/5.0/5.0.md +++ b/release-notes/5.0/5.0.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 5.0 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/10/07 | 5.0.1 | [release notes](5.0.1.md) | | 2022/08/05 | 5.0.0 | [release notes](5.0.0.md) | The following Microsoft.Data.SqlClient 5.0 preview releases have been shipped: diff --git a/release-notes/5.0/README.md b/release-notes/5.0/README.md index 6fa437317c..ec3dbc7eb6 100644 --- a/release-notes/5.0/README.md +++ b/release-notes/5.0/README.md @@ -4,6 +4,7 @@ The following Microsoft.Data.SqlClient 5.0 stable releases have been shipped: | Release Date | Version | Notes | | :-- | :-- | :--: | +| 2022/10/07 | 5.0.1 | [release notes](5.0.1.md) | | 2022/08/05 | 5.0.0 | [release notes](5.0.0.md) | The following Microsoft.Data.SqlClient 5.0 preview releases have been shipped: From 1e9cd3ab0a60f3fb9496184b948de43a7bd7721c Mon Sep 17 00:00:00 2001 From: Ken Dale Date: Fri, 14 Oct 2022 12:20:08 -0400 Subject: [PATCH 23/78] Documentation Fix | Small spelling fix --- .../Microsoft.Data.SqlClient/SqlRetryLogicBaseProvider.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlRetryLogicBaseProvider.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlRetryLogicBaseProvider.xml index 9828d34437..031c2b1ff7 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlRetryLogicBaseProvider.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlRetryLogicBaseProvider.xml @@ -11,7 +11,7 @@ [IMPORTAMT!] +> [IMPORTANT!] > Don't block execution with a time consuming action when an event occurs. For instance, if you log data to a file, run it in a new thread to avoid blocking the main execution thread. ]]> From 02daa6fc0b12ee4099aab3419ea31832f5483d4c Mon Sep 17 00:00:00 2001 From: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com> Date: Wed, 19 Oct 2022 13:22:41 -0700 Subject: [PATCH 24/78] Release notes v5.1.0-preview1 (#1788) --- CHANGELOG.md | 25 ++++++++ release-notes/5.1/5.1.0-preview1.md | 90 +++++++++++++++++++++++++++++ release-notes/5.1/5.1.md | 7 +++ release-notes/5.1/README.md | 8 +++ release-notes/README.md | 1 + 5 files changed, 131 insertions(+) create mode 100644 release-notes/5.1/5.1.0-preview1.md create mode 100644 release-notes/5.1/5.1.md create mode 100644 release-notes/5.1/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 76f7de12e6..ad69ad6d57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,31 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) +## [Preview Release 5.1.0-preview1.22279.3] - 2022-10-19 + +This update brings the below changes over the previous release: + +### Fixed + +- Fixed `ReadAsync()` behavior to register Cancellation token action before streaming results. [#1781](https://github.com/dotnet/SqlClient/pull/1781) +- Fixed `NullReferenceException` when assigning `null` to `SqlConnectionStringBuilder.Encrypt`. [#1778](https://github.com/dotnet/SqlClient/pull/1778) +- Fixed missing `HostNameInCertificate` property in .NET Framework Reference Project. [#1776](https://github.com/dotnet/SqlClient/pull/1776) +- Fixed async deadlock issue when sending attention fails due to network failure. [#1766](https://github.com/dotnet/SqlClient/pull/1766) +- Fixed failed connection requests in ConnectionPool in case of PoolBlock. [#1768](https://github.com/dotnet/SqlClient/pull/1768) +- Fixed hang on infinite timeout and managed SNI. [#1742](https://github.com/dotnet/SqlClient/pull/1742) +- Fixed Default UTF8 collation conflict. [#1739](https://github.com/dotnet/SqlClient/pull/1739) + +### Changed + +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET Core/Standard dependency) version to `5.1.0-preview1.22278.1`. [#1787](https://github.com/dotnet/SqlClient/pull/1787) which includes TLS 1.3 Support and fix for AppDomain crash in issue [#1418](https://github.com/dotnet/SqlClient/issues/1418) +- Changed the `SqlConnectionEncryptOption` string parser to public. [#1771](https://github.com/dotnet/SqlClient/pull/1771) +- Converted `ExecuteNonQueryAsync` to use async context object. [#1692](https://github.com/dotnet/SqlClient/pull/1692) +- Code health improvements [#1604](https://github.com/dotnet/SqlClient/pull/1604) [#1598](https://github.com/dotnet/SqlClient/pull/1598) [#1595](https://github.com/dotnet/SqlClient/pull/1595) [#1443](https://github.com/dotnet/SqlClient/pull/1443) + +### Known issues + +- When using `Encrypt=Strict` with TLS v1.3, the TLS handshake occurs twice on initial connection on .NET Framework due to a timeout during the TLS handshake and a retry helper re-establishes the connection; however, on .NET Core, it will throw a `System.ComponentModel.Win32Exception (258): The wait operation timed out.` and is being investigated. If you're using Microsoft.Data.SqlClient with .NET Core on Windows 11, you will need to enable the managed SNI on Windows context switch using following statement `AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true);` to use TLS v1.3 or disabling TLS 1.3 from the registry by assigning `0` to the following `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client\Enabled` registry key and it'll use TLS v1.2 for the connection. This will be fixed in a future release. + ## [Stable release 5.0.1] - 2022-10-07 ### Fixed diff --git a/release-notes/5.1/5.1.0-preview1.md b/release-notes/5.1/5.1.0-preview1.md new file mode 100644 index 0000000000..aec532ecf0 --- /dev/null +++ b/release-notes/5.1/5.1.0-preview1.md @@ -0,0 +1,90 @@ +# Release Notes + +## Microsoft.Data.SqlClient 5.1.0-preview1.22279.3 released 19 October 2022 + +This update brings the below changes over the previous release: + + +### Fixed + +- Fixed `ReadAsync()` behavior to register Cancellation token action before streaming results. [#1781](https://github.com/dotnet/SqlClient/pull/1781) +- Fixed `NullReferenceException` when assigning `null` to `SqlConnectionStringBuilder.Encrypt`. [#1778](https://github.com/dotnet/SqlClient/pull/1778) +- Fixed missing `HostNameInCertificate` property in .NET Framework Reference Project. [#1776](https://github.com/dotnet/SqlClient/pull/1776) +- Fixed async deadlock issue when sending attention fails due to network failure. [#1766](https://github.com/dotnet/SqlClient/pull/1766) +- Fixed failed connection requests in ConnectionPool in case of PoolBlock. [#1768](https://github.com/dotnet/SqlClient/pull/1768) +- Fixed hang on infinite timeout and managed SNI. [#1742](https://github.com/dotnet/SqlClient/pull/1742) +- Fixed Default UTF8 collation conflict. [#1739](https://github.com/dotnet/SqlClient/pull/1739) + +### Changed + +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET Core/Standard dependency) version to `5.1.0-preview1.22278.1`. [#1787](https://github.com/dotnet/SqlClient/pull/1787) which includes TLS 1.3 Support and fix for AppDomain crash in issue [#1418](https://github.com/dotnet/SqlClient/issues/1418) +- Changed the `SqlConnectionEncryptOption` string parser to public. [#1771](https://github.com/dotnet/SqlClient/pull/1771) +- Converted `ExecuteNonQueryAsync` to use async context object. [#1692](https://github.com/dotnet/SqlClient/pull/1692) +- Code health improvements [#1604](https://github.com/dotnet/SqlClient/pull/1604) [#1598](https://github.com/dotnet/SqlClient/pull/1598) [#1595](https://github.com/dotnet/SqlClient/pull/1595) [#1443](https://github.com/dotnet/SqlClient/pull/1443) + +### Known issues + +- When using `Encrypt=Strict` with TLS v1.3, the TLS handshake occurs twice on initial connection on .NET Framework due to a timeout during the TLS handshake and a retry helper re-establishes the connection; however, on .NET Core, it will throw a `System.ComponentModel.Win32Exception (258): The wait operation timed out.` and is being investigated. If you're using Microsoft.Data.SqlClient with .NET Core on Windows 11, you will need to enable the managed SNI on Windows context switch using following statement `AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true);` to use TLS v1.3 or disabling TLS 1.3 from the registry by assigning `0` to the following `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client\Enabled` registry key and it'll use TLS v1.2 for the connection. This will be fixed in a future release. + +## Target Platform Support + +- .NET Framework 4.6.2+ (Windows x86, Windows x64) +- .NET Core 3.1+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) +- .NET Standard 2.0+ (Windows x86, Windows x64, Windows ARM64, Windows ARM, Linux, macOS) + +### Dependencies + +#### .NET Framework + +- Microsoft.Data.SqlClient.SNI 5.1.0.preview1.22278.1 +- Azure.Identity 1.6.0 +- Microsoft.Identity.Client 4.45.0 +- Microsoft.IdentityModel.JsonWebTokens 6.21.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.21.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.IO 4.3.0 +- System.Runtime.InteropServices.RuntimeInformation 4.3.0 +- System.Security.Cryptography.Algorithms 4.3.1 +- System.Security.Cryptography.Primitives 4.3.0 +- System.Text.Encoding.Web 4.7.2 + +#### .NET Core + +- Microsoft.Data.SqlClient.SNI 5.1.0.preview1.22278.1 +- Azure.Identity 1.6.0 +- Microsoft.Identity.Client 4.45.0 +- Microsoft.IdentityModel.JsonWebTokens 6.21.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.21.0 +- Microsoft.SqlServer.Server 1.0.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.Diagnostics.DiagnosticSource 5.0.0 +- System.IO 4.3.0 +- System.Runtime.Caching 5.0.0 +- System.Text.Encoding.CodePages 5.0.0 +- System.Text.Encodings.Web 4.7.2 +- System.Resources.ResourceManager 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 + +#### .NET Standard + +- Microsoft.Data.SqlClient.SNI 5.1.0.preview1.22278.1 +- Azure.Identity 1.6.0 +- Microsoft.Identity.Client 4.45.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.21.0 +- Microsoft.IdentityModel.JsonWebTokens 6.21.0 +- Microsoft.SqlServer.Server 1.0.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 5.0.0 +- System.IO 4.3.0 +- System.Runtime.Caching 5.0.0 +- System.Text.Encoding.CodePages 5.0.0 +- System.Text.Encodings.Web 4.7.2 +- System.Runtime.Loader 4.3.0 +- System.Resources.ResourceManager 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 diff --git a/release-notes/5.1/5.1.md b/release-notes/5.1/5.1.md new file mode 100644 index 0000000000..d0d9de410a --- /dev/null +++ b/release-notes/5.1/5.1.md @@ -0,0 +1,7 @@ +# Microsoft.Data.SqlClient 5.1 Releases + +The following Microsoft.Data.SqlClient 5.1 preview releases have been shipped: + +| Release Date | Version | Notes | +| :-- | :-- | :--: | +| 2022/10/19 | 5.1.0-preview1.22279.3 | [release notes](5.1.0-preview1.md) | diff --git a/release-notes/5.1/README.md b/release-notes/5.1/README.md new file mode 100644 index 0000000000..1cbc5afaa1 --- /dev/null +++ b/release-notes/5.1/README.md @@ -0,0 +1,8 @@ +# Microsoft.Data.SqlClient 5.1 Releases + +The following Microsoft.Data.SqlClient 5.1 preview releases have been shipped: + +| Release Date | Version | Notes | +| :-- | :-- | :--: | +| 2022/10/19 | 5.1.0-preview1.22279.3 | [release notes](5.1.0-preview1.md) | + diff --git a/release-notes/README.md b/release-notes/README.md index cff1b6b88d..ba76fe8433 100644 --- a/release-notes/README.md +++ b/release-notes/README.md @@ -4,6 +4,7 @@ The latest stable release is [Microsoft.Data.SqlClient 5.0](5.0). ## Release Information +- [Microsoft.Data.SqlClient 5.1](5.1) - [Microsoft.Data.SqlClient 5.0](5.0) - [Microsoft.Data.SqlClient 4.1](4.1) - [Microsoft.Data.SqlClient 4.0](4.0) From f5eb391e71a9fc559163d38093f71e98dc867c56 Mon Sep 17 00:00:00 2001 From: David Engel Date: Thu, 20 Oct 2022 10:21:38 -0700 Subject: [PATCH 25/78] Add link to connection resiliency article (#1808) --- doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml index d139d0e1ec..0d6e9ea969 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml @@ -531,8 +531,8 @@ End Module |Authentication|N/A|The authentication method used for [Connecting to SQL Database By Using Azure Active Directory Authentication](https://azure.microsoft.com/documentation/articles/sql-database-aad-authentication/#7-connect-to-your-database-by-using-azure-active-directory-identities).

Valid values are:

`Active Directory Integrated`, `Active Directory Interactive`, `Active Directory Password`, `Active Directory Service Principal`, `Active Directory Device Code Flow`, `Active Directory Managed Identity`, `Active Directory MSI`, `Active Directory Default`, `Sql Password`.

For additional information see [Using Azure Active Directory authentication with SqlClient](https://docs.microsoft.com/sql/connect/ado-net/sql/azure-active-directory-authentication?view=sql-server-ver15).| |Column Encryption Setting|disabled|Enables or disables [Always Encrypted](/sql/relational-databases/security/encryption/always-encrypted-database-engine) functionality for the connection. Supported values are: `enabled` and `disabled`| |Command Timeout|30|The default wait time (in seconds) before terminating the attempt to execute a command and generating an error.

Valid values are greater than or equal to 0 and less than or equal to 2147483647.| -|Connect Retry Count

-or-

ConnectRetryCount|1|Controls the number of reconnection attempts after the client identifies an idle connection failure. Valid values are 0 to 255. The default is 1. 0 means do not attempt to reconnect (disable connection resiliency).

For additional information about idle connection resiliency, see [Technical Article - Idle Connection Resiliency](https://go.microsoft.com/fwlink/?LinkId=393996).| -|Connect Retry Interval

-or-

ConnectRetryInterval|10|Specifies the time between each connection retry attempt (`ConnectRetryCount`). Valid values are 1 to 60 seconds (default=10), applied after the first reconnection attempt. When a broken connection is detected, the client immediately attempts to reconnect; this is the first reconnection attempt and only occurs if `ConnectRetryCount` is greater than 0. If the first reconnection attempt fails and `ConnectRetryCount` is greater than 1, the client waits `ConnectRetryInterval` to try the second and subsequent reconnection attempts.

For additional information about idle connection resiliency, see [Technical Article - Idle Connection Resiliency](https://go.microsoft.com/fwlink/?LinkId=393996).| +|Connect Retry Count

-or-

ConnectRetryCount|1|Controls the number of reconnection attempts after the client identifies an idle connection failure. Valid values are 0 to 255. The default is 1. 0 means do not attempt to reconnect (disable connection resiliency).

For additional information about idle connection resiliency, see[.NET SqlConnection parameters for connection retry](https://learn.microsoft.com/azure/azure-sql/database/troubleshoot-common-connectivity-issues?view=azuresql#net-sqlconnection-parameters-for-connection-retry) and [Technical Article - Idle Connection Resiliency](https://go.microsoft.com/fwlink/?LinkId=393996).| +|Connect Retry Interval

-or-

ConnectRetryInterval|10|Specifies the time between each connection retry attempt (`ConnectRetryCount`). Valid values are 1 to 60 seconds (default=10), applied after the first reconnection attempt. When a broken connection is detected, the client immediately attempts to reconnect; this is the first reconnection attempt and only occurs if `ConnectRetryCount` is greater than 0. If the first reconnection attempt fails and `ConnectRetryCount` is greater than 1, the client waits `ConnectRetryInterval` to try the second and subsequent reconnection attempts.

For additional information about idle connection resiliency, see[.NET SqlConnection parameters for connection retry](https://learn.microsoft.com/azure/azure-sql/database/troubleshoot-common-connectivity-issues?view=azuresql#net-sqlconnection-parameters-for-connection-retry) and [Technical Article - Idle Connection Resiliency](https://go.microsoft.com/fwlink/?LinkId=393996).| |Connect Timeout

-or-

Connection Timeout

-or-

Timeout|15|The length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error.

Valid values are greater than or equal to 0 and less than or equal to 2147483647.

When opening a connection to a Azure SQL Database, set the connection timeout to 30 seconds.| |Current Language

-or-

Language|N/A|Sets the language used for database server warning or error messages.

The language name can be 128 characters or less.| |Data Source

-or-

Server

-or-

Address

-or-

Addr

-or-

Network Address|N/A|The name or network address of the instance of SQL Server to which to connect. The port number can be specified after the server name:

`server=tcp:servername, portnumber`

When specifying a local instance, always use (local). To force a protocol, add one of the following prefixes:

`np:(local), tcp:(local), lpc:(local)`

You can also connect to a LocalDB database as follows:

`server=(localdb)\\myInstance`

For more information about LocalDB, see [SqlClient Support for LocalDB](/sql/connect/ado-net/sql/sqlclient-support-localdb).

**Data Source** must use the TCP format or the Named Pipes format.

TCP format is as follows:

- tcp:\\\
- tcp:\,\

The TCP format must start with the prefix "tcp:" and is followed by the database instance, as specified by a host name and an instance name. This format is not applicable when connecting to Azure SQL Database. TCP is automatically selected for connections to Azure SQL Database when no protocol is specified.

The host name MUST be specified in one of the following ways:

- NetBIOSName
- IPv4Address
- IPv6Address

The instance name is used to resolve to a particular TCP/IP port number on which a database instance is hosted. Alternatively, specifying a TCP/IP port number directly is also allowed. If both instance name and port number are not present, the default database instance is used.

The Named Pipes format is as follows:

- np:\\\\\pipe\\

The Named Pipes format MUST start with the prefix "np:" and is followed by a named pipe name.

The host name MUST be specified in one of the following ways:

- NetBIOSName
- IPv4Address
- IPv6Address

The pipe name is used to identify the database instance to which the .NET application will connect.

If the value of the **Network** key is specified, the prefixes "tcp:" and "np:" should not be specified. **Note:** You can force the use of TCP instead of shared memory, either by prefixing **tcp:** to the server name in the connection string, or by using **localhost**.| From 20d4c199923c9b4ea2ffd44d9304fcb306c5efb5 Mon Sep 17 00:00:00 2001 From: Javad Date: Fri, 21 Oct 2022 23:41:47 -0700 Subject: [PATCH 26/78] Add | Adding Net6 support and dropping netcoreapp3.1 (#1704) --- .editorconfig | 3 + BUILDGUIDE.md | 12 +-- RunTests.cmd | 94 +++++++++---------- build.proj | 10 +- ...waysEncrypted.AzureKeyVaultProvider.csproj | 4 +- .../add-ons/Directory.Build.props | 4 +- .../netcore/ref/Microsoft.Data.SqlClient.cs | 11 +++ .../ref/Microsoft.Data.SqlClient.csproj | 14 +-- .../src/Microsoft.Data.SqlClient.csproj | 12 +-- ...ryptionCertificateStoreProvider.Windows.cs | 20 +++- .../Microsoft/Data/SqlClient/SqlCommand.cs | 5 +- .../Microsoft/Data/SqlClient/SqlDataReader.cs | 4 +- .../Data/SqlClient/SqlDelegatedTransaction.cs | 8 ++ .../SqlClient/SqlInternalConnectionTds.cs | 2 + .../Data/SqlClient/SqlTransaction.cs | 8 ++ .../Data/SqlTypes/SqlFileStream.Windows.cs | 6 +- .../Data/Common/AdapterUtil.Windows.cs | 4 + .../src/Microsoft/Data/Common/AdapterUtil.cs | 2 + .../DbConnectionPoolAuthenticationContext.cs | 2 + .../SqlDataSourceEnumeratorNativeHelper.cs | 7 +- .../ActiveDirectoryAuthenticationProvider.cs | 15 ++- .../SqlAeadAes256CbcHmac256Algorithm.cs | 14 ++- .../Data/SqlClient/SqlCommandBuilder.cs | 2 + .../Microsoft/Data/SqlClient/SqlDependency.cs | 6 +- .../Data/SqlClient/SqlDependencyListener.cs | 3 + .../Data/SqlClient/SqlDependencyUtils.cs | 3 + .../SqlClient/TdsParserSafeHandles.Windows.cs | 2 + .../VirtualSecureModeEnclaveProvider.cs | 10 +- .../tests/Directory.Build.props | 2 +- ...soft.Data.SqlClient.DockerLinuxTest.csproj | 2 +- .../Microsoft.Data.SqlClient.Tests.csproj | 2 +- .../tests/FunctionalTests/SqlExceptionTest.cs | 2 +- .../ManualTests/DataCommon/DataTestUtility.cs | 4 +- .../ConnectivityTests/AADConnectionTest.cs | 5 +- .../SQL/ParameterTest/ParametersTest.cs | 2 +- .../SQL/WeakRefTest/WeakRefTest.cs | 4 +- ...oft.Data.SqlClient.PerformanceTests.csproj | 2 +- ...crosoft.Data.SqlClient.ExtUtilities.csproj | 2 +- .../Microsoft.DotNet.XUnitExtensions.csproj | 2 +- .../Microsoft.DotNet.GenAPI.csproj | 2 +- tools/props/Versions.props | 49 +++++----- tools/specs/Microsoft.Data.SqlClient.nuspec | 86 ++++++++--------- ...waysEncrypted.AzureKeyVaultProvider.nuspec | 40 ++++---- tools/targets/NotSupported.targets | 4 +- 44 files changed, 280 insertions(+), 217 deletions(-) diff --git a/.editorconfig b/.editorconfig index 7acdd43c13..db85dde7fd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -140,6 +140,9 @@ dotnet_diagnostic.CA1063.severity = silent # CA2100: Review SQL queries for security vulnerabilities dotnet_diagnostic.CA2100.severity = silent +# CA1416: Validate platform compatibility +dotnet_diagnostic.CA1416.severity = silent + [*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}] indent_size = 2 diff --git a/BUILDGUIDE.md b/BUILDGUIDE.md index 05b0920307..055243c115 100644 --- a/BUILDGUIDE.md +++ b/BUILDGUIDE.md @@ -102,7 +102,7 @@ msbuild -t:RunTests -p:configuration=Release To specify custom target framework, use `TF` property: ```bash -msbuild -t:RunTests -p:configuration=Release -p:TF=net5.0 +msbuild -t:RunTests -p:configuration=Release -p:TF=net7.0 msbuild -t:RunTests -p:configuration=Release -p:TF=net48 # Runs tests for specified target framework. # TargetNetCoreVersion and TargetNetFxVersion are not to be used with TF property, they will take precedence over TF if provided. @@ -285,9 +285,9 @@ msbuild -t:BuildTestsNetFx -p:TargetNetFxVersion=net462 ``` ```bash -msbuild -t:BuildTestsNetCore -p:TargetNetCoreVersion=netcoreapp3.1 +msbuild -t:BuildTestsNetCore -p:TargetNetCoreVersion=net6.0 # Build the tests for custom TargetFramework (.NET Core) -# Applicable values: netcoreapp3.1 | net5.0 | net6.0 +# Applicable values: net6.0 | net7.0 | net6.0 ``` ### Running Tests with custom target framework (traditional) @@ -297,9 +297,9 @@ dotnet test -p:TargetNetFxVersion=net462 ... # Use above property to run Functional Tests with custom TargetFramework (.NET Framework) # Applicable values: net462 (Default) | net462 | net47 | net471 net472 | net48 -dotnet test -p:TargetNetCoreVersion=netcoreapp3.1 ... +dotnet test -p:TargetNetCoreVersion=net6.0 ... # Use above property to run Functional Tests with custom TargetFramework (.NET Core) -# Applicable values: netcoreapp3.1 | net5.0 | net6.0 +# Applicable values: net6.0 | net7.0 | net6.0 ``` ## Using Managed SNI on Windows @@ -389,7 +389,7 @@ Configure `runnerconfig.json` file with connection string and preferred settings ```bash cd src\Microsoft.Data.SqlClient\tests\PerformanceTests -dotnet run -c Release -f netcoreapp3.1|net5.0 +dotnet run -c Release -f net6.0|net7.0 ``` _Only "**Release** Configuration" applies to Performance Tests_ diff --git a/RunTests.cmd b/RunTests.cmd index 663c3da9b4..c80b385513 100644 --- a/RunTests.cmd +++ b/RunTests.cmd @@ -13,38 +13,38 @@ call :pauseOnError msbuild -p:Configuration="Release" -t:BuildAKVNetFx -p:Refere call :pauseOnError msbuild -p:Configuration="Release" -t:BuildAKVNetCore -p:ReferenceType=Package call :pauseOnError msbuild -p:Configuration="Release" -t:BuildAKVNetSt -p:ReferenceType=Package -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:TargetNetCoreVersion=netcoreapp3.1 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-functional-anycpu.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-manual-anycpu.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:TargetNetCoreVersion=net6.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-manual-anycpu.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:TargetNetCoreVersion=net5.0 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-functional-anycpu.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-net5.0-manual-anycpu.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:TargetNetCoreVersion=net7.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-net7.0-manual-anycpu.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:Platform=x64 -p:TargetNetCoreVersion=netcoreapp3.1 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-functional-x64.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-manual-x64.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:Platform=x64 -p:TargetNetCoreVersion=net6.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-manual-x64.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:Platform=x64 -p:TargetNetCoreVersion=net5.0 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-functional-x64.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-manual-x64.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:Platform=x64 -p:TargetNetCoreVersion=net7.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-manual-x64.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:Platform=Win32 -p:TargetNetCoreVersion=netcoreapp3.1 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-functional-win32.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-manual-win32.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:Platform=Win32 -p:TargetNetCoreVersion=net6.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore3.1-manual-win32.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:Platform=Win32 -p:TargetNetCoreVersion=net5.0 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-functional-win32.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-manual-win32.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=Package -p:Platform=Win32 -p:TargetNetCoreVersion=net7.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-netcore5.0-manual-win32.xml :: REFERENCE TYPE "NETSTANDARDPACKAGE" -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:TargetNetCoreVersion=netcoreapp3.1 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-functional-anycpu.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-manual-anycpu.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:TargetNetCoreVersion=net6.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-manual-anycpu.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:TargetNetCoreVersion=net5.0 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-functional-anycpu.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-manual-anycpu.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:TargetNetCoreVersion=net7.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-manual-anycpu.xml call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetFx -p:ReferenceType=NetStandardPackage -p:TargetNetFxVersion=net462 call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetFxVersion=net462 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net462-functional-anycpu.xml @@ -54,13 +54,13 @@ call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetFx -p:Refe call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetFxVersion=net48 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-functional-anycpu.xml call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetFxVersion=net48 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-manual-anycpu.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=x64 -p:TargetNetCoreVersion=netcoreapp3.1 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-functional-x64.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-manual-x64.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=x64 -p:TargetNetCoreVersion=net6.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-manual-x64.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=x64 -p:TargetNetCoreVersion=net5.0 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-functional-x64.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-manual-x64.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=x64 -p:TargetNetCoreVersion=net7.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-functional-x64.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-manual-x64.xml call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetFx -p:ReferenceType=NetStandardPackage -p:Platform=x64 -p:TargetNetFxVersion=net462 call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetFxVersion=net462 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net462-functional-x64.xml @@ -70,13 +70,13 @@ call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetFx -p:Refe call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetFxVersion=net48 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-functional-x64.xml call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -p:Platform="x64" -p:TargetNetFxVersion=net48 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-manual-x64.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=Win32 -p:TargetNetCoreVersion=netcoreapp3.1 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-functional-win32.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-manual-win32.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=Win32 -p:TargetNetCoreVersion=net6.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore3.1-manual-win32.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=Win32 -p:TargetNetCoreVersion=net5.0 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-functional-win32.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-manual-win32.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=Win32 -p:TargetNetCoreVersion=net7.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-functional-win32.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-netcore5.0-manual-win32.xml call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetFx -p:ReferenceType=NetStandardPackage -p:Platform=Win32 -p:TargetNetFxVersion=net462 call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -p:Platform="Win32" -p:TargetNetFxVersion=net462 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net462-functional-win32.xml @@ -89,13 +89,13 @@ call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\M :: REFERENCE TYPE "NETSTANDARD" (We only build and test AnyCPU with Project Reference) :: NUGET PACKAGE GENERATION IS NOT SUPPORTED FOR REFERNCE TYPE 'NETSTANDARD' call :pauseOnError msbuild -p:Configuration="Release" -p:ReferenceType=NetStandard -p:GenerateNuget=false -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandard -p:TargetNetCoreVersion=netcoreapp3.1 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore3.1-functional-anycpu.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore3.1-manual-anycpu.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandard -p:TargetNetCoreVersion=net6.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore3.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore3.1-manual-anycpu.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandard -p:TargetNetCoreVersion=net5.0 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore5.0-functional-anycpu.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore5.0-manual-anycpu.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandard -p:TargetNetCoreVersion=net7.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore5.0-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-netcore5.0-manual-anycpu.xml :: TESTING 'NETSTANDARD' REFERENCE TYPE WITH .NET FRAMEWORK 4.6.2+ AS TARGET FRAMEWORK IS INVALID CASE AS PROJECT REFERENCE DOES NOT LOAD SNI.DLL IN .NET FRAMEWORK RUNTIME. :: CASE IS VERIFIED WITH RUNTIME.NATIVE.SYSTEM.DATA.SQLCLIENT.SNI AS WELL. TO TEST .NET FRAMEWORK TARGETS, USE 'NETSTANDARDPACKAGE' REFERENCE TYPE ONLY. @@ -107,12 +107,12 @@ call :pauseOnError msbuild -p:Configuration="Release" -t:BuildAKVNetCoreAllOS call :pauseOnError msbuild -p:Configuration="Release" -t:BuildAKVNetStAllOS call :pauseOnError msbuild -p:Configuration="Release" -t:GenerateAKVProviderNugetPackage call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore3.1-functional-anycpu.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=netcoreapp3.1 -p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore3.1-manual-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore3.1-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net6.0 -p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore3.1-manual-anycpu.xml -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:TargetNetCoreVersion=net5.0 -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore5.0-functional-anycpu.xml -call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net5.0 -p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore5.0-manual-anycpu.xml +call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:TargetNetCoreVersion=net7.0 +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore5.0-functional-anycpu.xml +call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Configuration="Release" -p:TestTargetOS="Windowsnetcoreapp" --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests" -p:Platform="AnyCPU" -p:TargetNetCoreVersion=net7.0 -p:ReferenceType=Project -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\project-netcore5.0-manual-anycpu.xml :: .NET FRAMEWORK REFERENCE TYPE "PROJECT" echo Building .NET Framework Tests diff --git a/build.proj b/build.proj index 14efda3f4a..6d7f3b608c 100644 --- a/build.proj +++ b/build.proj @@ -16,11 +16,11 @@ false Windows Unix - netcoreapp3.1 - netfx - netcore - netfx - netcoreapp + net6.0 + netfx + netcore + netfx + netcoreapp $(TF) $(TF) true diff --git a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj index bbc2efc19f..07b6f1996d 100644 --- a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj +++ b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj @@ -4,8 +4,8 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider AzureKeyVaultProvider {9073ABEF-92E0-4702-BB23-2C99CEF9BDD7} - netcoreapp - netfx + netcoreapp + netfx Debug;Release; AnyCPU;x86;x64 $(ObjFolder)$(Configuration).$(Platform)\$(AddOnName) diff --git a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props index d2d8fc7400..762c5f9ed8 100644 --- a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props +++ b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props @@ -18,7 +18,7 @@ net462 netstandard2.0 - netcoreapp3.1 + net6.0 @@ -36,7 +36,7 @@ netstandard2.0;netstandard2.1 - netcoreapp3.1 + net6.0 net462 diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs index db0842d4f2..59fb424178 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs @@ -1432,7 +1432,9 @@ internal SqlException() { } /// public byte State { get { throw null; } } /// +#if !NET6_0_OR_GREATER [System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)] +#endif public override void GetObjectData(System.Runtime.Serialization.SerializationInfo si, System.Runtime.Serialization.StreamingContext context) { } /// public override string ToString() { throw null; } @@ -1762,9 +1764,18 @@ protected override void Dispose(bool disposing) { } /// public override void Rollback() { } /// +#if NET6_0_OR_GREATER + public override void Rollback(string transactionName) { } +#else public void Rollback(string transactionName) { } +#endif + /// +#if NET6_0_OR_GREATER + public override void Save(string savePointName) { } +#else public void Save(string savePointName) { } +#endif } /// public sealed class SqlRetryingEventArgs : System.EventArgs diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj index 1b3863ec7e..41e1263abc 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj @@ -1,23 +1,17 @@  false - netcoreapp3.1;netstandard2.0;netstandard2.1 + net6.0;netstandard2.0;netstandard2.1 netstandard2.1 $(ObjFolder)$(Configuration)\$(AssemblyName)\ref\ $(BinFolder)$(Configuration)\$(AssemblyName)\ref\ $(OutputPath)\$(TargetFramework)\Microsoft.Data.SqlClient.xml Core $(BaseProduct) Debug;Release; - netcoreapp - netstandard + netcoreapp + netstandard AnyCPU;x64;x86 - - $(DefineConstants);NETSTANDARD21_AND_ABOVE - - - $(DefineConstants);NETCOREAPP - @@ -31,4 +25,4 @@ - \ No newline at end of file + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 90a417a5ca..242b636730 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -1,7 +1,7 @@  Microsoft.Data.SqlClient - netcoreapp3.1;netstandard2.0;netstandard2.1 + net6.0;netstandard2.0;netstandard2.1 netstandard2.1 Microsoft.Data.SqlClient is not supported on this platform. $(OS) @@ -9,8 +9,8 @@ true false - netcoreapp - netstandard + netcoreapp + netstandard Debug;Release; AnyCPU;x64;x86 $(ObjFolder)$(Configuration).$(Platform)\$(AssemblyName)\netcore\ @@ -19,12 +19,6 @@ true Core $(BaseProduct) - - $(DefineConstants);NETCOREAPP; - - - $(DefineConstants);NETSTANDARD; - portable true diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionCertificateStoreProvider.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionCertificateStoreProvider.Windows.cs index c6f2786583..d644acbea7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionCertificateStoreProvider.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlColumnEncryptionCertificateStoreProvider.Windows.cs @@ -79,7 +79,15 @@ public override byte[] DecryptColumnEncryptionKey(string masterKeyPath, string e // Parse the path and get the X509 cert X509Certificate2 certificate = GetCertificateByPath(masterKeyPath, isSystemOp: true); - int keySizeInBytes = certificate.PublicKey.Key.KeySize / 8; + + RSA RSAPublicKey = certificate.GetRSAPublicKey(); + int keySizeInBytes; +#if NETCOREAPP || NETSTANDARD2_1 + DSA DSAPublicKey = certificate.GetDSAPublicKey(); + keySizeInBytes = RSAPublicKey is not null ? RSAPublicKey.KeySize / 8 : DSAPublicKey.KeySize / 8; +#else + keySizeInBytes= RSAPublicKey.KeySize / 8; +#endif // Validate and decrypt the EncryptedColumnEncryptionKey // Format is @@ -172,7 +180,15 @@ public override byte[] EncryptColumnEncryptionKey(string masterKeyPath, string e // Parse the certificate path and get the X509 cert X509Certificate2 certificate = GetCertificateByPath(masterKeyPath, isSystemOp: false); - int keySizeInBytes = certificate.PublicKey.Key.KeySize / 8; + + RSA RSAPublicKey = certificate.GetRSAPublicKey(); + int keySizeInBytes; +#if NETCOREAPP || NETSTANDARD2_1 + DSA DSAPublicKey = certificate.GetDSAPublicKey(); + keySizeInBytes = RSAPublicKey is not null ? RSAPublicKey.KeySize / 8 : DSAPublicKey.KeySize / 8; +#else + keySizeInBytes= RSAPublicKey.KeySize / 8; +#endif // Construct the encryptedColumnEncryptionKey // Format is diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index 4effb98e59..bca9f13ea7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -3769,8 +3769,9 @@ private SqlDataReader GetParameterEncryptionDataReader(out Task returnTask, Task SqlCommand command = (SqlCommand)state; bool processFinallyBlockAsync = true; bool decrementAsyncCountInFinallyBlockAsync = true; - +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { // Check for any exceptions on network write, before reading. @@ -3842,7 +3843,9 @@ private SqlDataReader GetParameterEncryptionDataReaderAsync(out Task returnTask, bool processFinallyBlockAsync = true; bool decrementAsyncCountInFinallyBlockAsync = true; +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { // Check for any exceptions on network write, before reading. diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs index 0e03e86286..cf271ea749 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -3472,7 +3472,9 @@ private bool TryReadInternal(bool setTimeout, out bool more) SqlStatistics statistics = null; using (TryEventScope.Create("SqlDataReader.TryReadInternal | API | Object Id {0}", ObjectID)) { +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { @@ -4848,7 +4850,7 @@ public override Task ReadAsync(CancellationToken cancellationToken) context = new ReadAsyncCallContext(); } - Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == null, "cached ReadAsyncCallContext was not properly disposed"); + Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ReadAsyncCallContext was not properly disposed"); context.Set(this, source, registration); context._hasMoreData = more; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.cs index 3c289bb790..2b9fc6f472 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.cs @@ -81,7 +81,9 @@ public void Initialize() SqlInternalConnection connection = _connection; SqlConnection usersConnection = connection.Connection; SqlClientEventSource.Log.TryTraceEvent("SqlDelegatedTransaction.Initialize | RES | CPOOL | Object Id {0}, Client Connection Id {1}, delegating transaction.", ObjectID, usersConnection?.ClientConnectionId); +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { if (connection.IsEnlistedInTransaction) @@ -144,7 +146,9 @@ public byte[] Promote() { SqlConnection usersConnection = connection.Connection; SqlClientEventSource.Log.TryTraceEvent("SqlDelegatedTransaction.Promote | RES | CPOOL | Object Id {0}, Client Connection Id {1}, promoting transaction.", ObjectID, usersConnection?.ClientConnectionId); +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { lock (connection) @@ -252,7 +256,9 @@ public void Rollback(SinglePhaseEnlistment enlistment) { SqlConnection usersConnection = connection.Connection; SqlClientEventSource.Log.TryTraceEvent("SqlDelegatedTransaction.Rollback | RES | CPOOL | Object Id {0}, Client Connection Id {1}, rolling back transaction.", ObjectID, usersConnection?.ClientConnectionId); +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { lock (connection) @@ -337,7 +343,9 @@ public void SinglePhaseCommit(SinglePhaseEnlistment enlistment) { SqlConnection usersConnection = connection.Connection; SqlClientEventSource.Log.TryTraceEvent("SqlDelegatedTransaction.SinglePhaseCommit | RES | CPOOL | Object Id {0}, Client Connection Id {1}, committing transaction.", ObjectID, usersConnection?.ClientConnectionId); +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { lock (connection) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index 83bf554c2c..e977641175 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -2283,7 +2283,9 @@ internal bool TryGetFedAuthTokenLocked(SqlFedAuthInfo fedAuthInfo, DbConnectionP bool authenticationContextLocked = false; // Prepare CER to ensure the lock on authentication context is released. +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { // Try to obtain a lock on the context. If acquired, this thread got the opportunity to update. diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlTransaction.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlTransaction.cs index 1c3df017dd..07472db42b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlTransaction.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlTransaction.cs @@ -119,7 +119,11 @@ public override void Rollback() } /// +#if NET6_0_OR_GREATER + public override void Rollback(string transactionName) +#else public void Rollback(string transactionName) +#endif { using (DiagnosticTransactionScope diagnosticScope = s_diagnosticListener.CreateTransactionRollbackScope(_isolationLevel, _connection, InternalTransaction, transactionName)) { @@ -151,7 +155,11 @@ public void Rollback(string transactionName) } /// +#if NET6_0_OR_GREATER + public override void Save(string savePointName) +#else public void Save(string savePointName) +#endif { ZombieCheck(); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlTypes/SqlFileStream.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlTypes/SqlFileStream.Windows.cs index f1f29b4697..97cabfe674 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlTypes/SqlFileStream.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlTypes/SqlFileStream.Windows.cs @@ -297,7 +297,9 @@ public override void Flush() } /// +#if !NET6_0_OR_GREATER [HostProtection(ExternalThreading = true)] +#endif public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (_m_disposed) @@ -316,7 +318,9 @@ public override int EndRead(IAsyncResult asyncResult) } /// +#if !NET6_0_OR_GREATER [HostProtection(ExternalThreading = true)] +#endif public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { if (_m_disposed) @@ -422,7 +426,7 @@ public override void WriteByte(byte value) _m_fs.Flush(); } - #endregion +#endregion [Conditional("DEBUG")] static private void AssertPathFormat(string path) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.Windows.cs index c9d0f8d91a..9b9c0f3341 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.Windows.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.Windows.cs @@ -25,7 +25,9 @@ internal static partial class ADP [ResourceConsumption(ResourceScope.Machine)] internal static object LocalMachineRegistryValue(string subkey, string queryvalue) { // MDAC 77697 +#if !NET6_0_OR_GREATER (new RegistryPermission(RegistryPermissionAccess.Read, "HKEY_LOCAL_MACHINE\\" + subkey)).Assert(); // MDAC 62028 +#endif try { using (RegistryKey key = Registry.LocalMachine.OpenSubKey(subkey, false)) @@ -40,10 +42,12 @@ internal static object LocalMachineRegistryValue(string subkey, string queryvalu ADP.TraceExceptionWithoutRethrow(e); return null; } +#if !NET6_0_OR_GREATER finally { RegistryPermission.RevertAssert(); } +#endif } } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs index 1866aa7fb3..24f56b4b32 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs @@ -635,7 +635,9 @@ private static long TimerToSeconds(long timerValue) /// Note: In Longhorn you'll be able to rename a machine without /// rebooting. Therefore, don't cache this machine name. /// +#if !NET6_0_OR_GREATER [EnvironmentPermission(SecurityAction.Assert, Read = "COMPUTERNAME")] +#endif internal static string MachineName() => Environment.MachineName; internal static Transaction GetCurrentTransaction() diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPoolAuthenticationContext.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPoolAuthenticationContext.cs index ec6b695429..213f4b8b25 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPoolAuthenticationContext.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbConnectionPoolAuthenticationContext.cs @@ -102,7 +102,9 @@ internal bool LockToUpdate() /// /// Release the lock which was obtained through LockToUpdate. /// +#if !NET6_0_OR_GREATER [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] +#endif internal void ReleaseLockToUpdate() { int oldValue = Interlocked.CompareExchange(ref _isUpdateInProgress, STATUS_UNLOCKED, STATUS_LOCKED); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs index f6ebfc4b8f..9118e341af 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumeratorNativeHelper.cs @@ -25,7 +25,9 @@ internal static class SqlDataSourceEnumeratorNativeHelper /// internal static DataTable GetDataSources() { +#if !NET6_0_OR_GREATER (new NamedPermissionSet("FullTrust")).Demand(); // SQLBUDT 244304 +#endif char[] buffer = null; StringBuilder strbldr = new(); @@ -35,12 +37,15 @@ internal static DataTable GetDataSources() bool more = true; bool failure = false; IntPtr handle = ADP.s_ptrZero; - +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { long s_timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(ADP.DefaultCommandTimeout); +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { } finally diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs index a8fdf219d3..573c36ee55 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs @@ -109,6 +109,7 @@ public override void BeforeUnload(SqlAuthenticationMethod authentication) #endif /// + public override async Task AcquireTokenAsync(SqlAuthenticationParameters parameters) { CancellationTokenSource cts = new CancellationTokenSource(); @@ -226,15 +227,11 @@ public override async Task AcquireTokenAsync(SqlAuthenti } else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryPassword) { - SecureString password = new SecureString(); - foreach (char c in parameters.Password) - password.AppendChar(c); - password.MakeReadOnly(); - - result = await app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, password) - .WithCorrelationId(parameters.ConnectionId) - .ExecuteAsync(cancellationToken: cts.Token) - .ConfigureAwait(false); + result = await app.AcquireTokenByUsernamePassword(scopes, parameters.UserId, parameters.Password) + .WithCorrelationId(parameters.ConnectionId) + .ExecuteAsync(cancellationToken: cts.Token) + .ConfigureAwait(false); + SqlClientEventSource.Log.TryTraceEvent("AcquireTokenAsync | Acquired access token for Active Directory Password auth mode. Expiry Time: {0}", result?.ExpiresOn); } else if (parameters.AuthenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive || diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAeadAes256CbcHmac256Algorithm.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAeadAes256CbcHmac256Algorithm.cs index b4bba80fc0..2ff168a25b 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAeadAes256CbcHmac256Algorithm.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlAeadAes256CbcHmac256Algorithm.cs @@ -72,7 +72,7 @@ internal class SqlAeadAes256CbcHmac256Algorithm : SqlClientEncryptionAlgorithm /// /// The pool of crypto providers to use for encrypt/decrypt operations. /// - private readonly ConcurrentQueue _cryptoProviderPool; + private readonly ConcurrentQueue _cryptoProviderPool; /// /// Byte array with algorithm version used for authentication tag computation. @@ -117,7 +117,7 @@ internal SqlAeadAes256CbcHmac256Algorithm(SqlAeadAes256CbcHmac256EncryptionKey e Debug.Assert(SqlClientEncryptionType.Randomized == encryptionType, "Invalid Encryption Type detected in SqlAeadAes256CbcHmac256Algorithm, this should've been caught in factory class"); } - _cryptoProviderPool = new ConcurrentQueue(); + _cryptoProviderPool = new ConcurrentQueue(); } /// @@ -178,13 +178,12 @@ protected byte[] EncryptData(byte[] plainText, bool hasAuthenticationTag) outBuffer[0] = _algorithmVersion; Buffer.BlockCopy(iv, 0, outBuffer, ivStartIndex, iv.Length); - AesCryptoServiceProvider aesAlg; // Try to get a provider from the pool. // If no provider is available, create a new one. - if (!_cryptoProviderPool.TryDequeue(out aesAlg)) + if (!_cryptoProviderPool.TryDequeue(out Aes aesAlg)) { - aesAlg = new AesCryptoServiceProvider(); + aesAlg = Aes.Create(); try { @@ -342,13 +341,12 @@ private byte[] DecryptData(byte[] iv, byte[] cipherText, int offset, int count) Debug.Assert((count + offset) <= cipherText.Length); byte[] plainText; - AesCryptoServiceProvider aesAlg; // Try to get a provider from the pool. // If no provider is available, create a new one. - if (!_cryptoProviderPool.TryDequeue(out aesAlg)) + if (!_cryptoProviderPool.TryDequeue(out Aes aesAlg)) { - aesAlg = new AesCryptoServiceProvider(); + aesAlg = Aes.Create(); try { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs index 07f834a749..90546993a6 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs @@ -257,7 +257,9 @@ public static void DeriveParameters(SqlCommand command) #if NETFRAMEWORK TdsParser bestEffortCleanupTarget = null; #endif +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { #if NETFRAMEWORK diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs index 6a14a5ef8e..401cde2fa2 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs @@ -629,8 +629,9 @@ internal static bool Start(string connectionString, string queue, bool useDefaul string database = null; string service = null; bool appDomainStart = false; - +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { // CER to ensure that if Start succeeds we add to hash completing setup. // Start using process wide default service/queue & database from connection string. @@ -774,8 +775,9 @@ internal static bool Stop(string connectionString, string queue, bool useDefault if (useDefaults) { bool appDomainStop = false; - +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { // CER to ensure that if Stop succeeds we remove from hash completing teardown. // Start using process wide default service/queue & database from connection string. diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyListener.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyListener.cs index 440755ddca..0dbdb28c42 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyListener.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyListener.cs @@ -1451,6 +1451,9 @@ private static SqlConnectionContainerHashHelper GetHashHelper( } // Needed for remoting to prevent lifetime issues and default GC cleanup. +#if NET6_0_OR_GREATER + [Obsolete("InitializeLifetimeService() is not supported after .Net5.0 and throws PlatformNotSupportedException.")] +#endif public override object InitializeLifetimeService() { return null; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.cs index 404e27d788..506b45faac 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.cs @@ -132,6 +132,9 @@ private void UnloadEventHandler(object sender, EventArgs e) // When remoted across appdomains, MarshalByRefObject links by default time out if there is no activity // within a few minutes. Add this override to prevent marshaled links from timing out. +#if NET6_0_OR_GREATER + [Obsolete("InitializeLifetimeService() is not supported after .Net5.0 and throws PlatformNotSupportedException.")] +#endif public override object InitializeLifetimeService() { return null; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs index 8d2716c63e..5d70f7a601 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserSafeHandles.Windows.cs @@ -166,7 +166,9 @@ internal SNIHandle( string hostNameInCertificate) : base(IntPtr.Zero, true) { +#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); +#endif try { } finally diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProvider.cs index 1ef8541721..66bb63c31d 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProvider.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProvider.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Runtime.Serialization.Json; using System.Security.Cryptography.X509Certificates; using System.Threading; @@ -18,6 +19,10 @@ internal class HostGuardianServiceEnclaveProvider : VirtualizationBasedSecurityE { #region Members + // HttpClient is intended to be instantiated once per application, rather than per-use. + // see https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-6.0#remarks + private static readonly HttpClient s_client = new HttpClient(); + // this is endpoint given to us by HGS team from windows private const string AttestationUrlSuffix = @"/v2.0/signingCertificates"; @@ -66,10 +71,7 @@ protected override byte[] MakeRequest(string url) Thread.Sleep(EnclaveRetrySleepInSeconds * 1000); } - WebRequest request = WebRequest.Create(url); - - using (WebResponse response = request.GetResponse()) - using (Stream stream = response.GetResponseStream()) + using (Stream stream = s_client.GetStreamAsync(url).ConfigureAwait(false).GetAwaiter().GetResult()) { var deserializer = new DataContractJsonSerializer(typeof(byte[])); return (byte[])deserializer.ReadObject(stream); diff --git a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props index 2861d6f2e2..d7fa230271 100644 --- a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props +++ b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props @@ -17,7 +17,7 @@ net462 - netcoreapp3.1 + net6.0 diff --git a/src/Microsoft.Data.SqlClient/tests/Docker/DockerLinuxTest/Microsoft.Data.SqlClient.DockerLinuxTest.csproj b/src/Microsoft.Data.SqlClient/tests/Docker/DockerLinuxTest/Microsoft.Data.SqlClient.DockerLinuxTest.csproj index 1a452df62f..8eea5116aa 100644 --- a/src/Microsoft.Data.SqlClient/tests/Docker/DockerLinuxTest/Microsoft.Data.SqlClient.DockerLinuxTest.csproj +++ b/src/Microsoft.Data.SqlClient/tests/Docker/DockerLinuxTest/Microsoft.Data.SqlClient.DockerLinuxTest.csproj @@ -1,7 +1,7 @@  Exe - netcoreapp3.1 + net6.0 Linux ..\..\..\.. Unix diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 5b1ec82808..129d832488 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -101,7 +101,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlExceptionTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlExceptionTest.cs index 3d749374ef..71975db7a5 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlExceptionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlExceptionTest.cs @@ -33,7 +33,7 @@ public void SerializationTest() Assert.Equal(e.StackTrace, sqlEx.StackTrace); } -#if !NET50_OR_LATER +#if !NET6_0_OR_GREATER [Fact] [ActiveIssue("12161", TestPlatforms.AnyUnix)] public static void SqlExcpetionSerializationTest() diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 9dd199da33..f696e5ee3d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -223,10 +223,8 @@ private static Task AcquireTokenAsync(string authorityURL, string userID SecureString securePassword = new SecureString(); - foreach (char c in password) - securePassword.AppendChar(c); securePassword.MakeReadOnly(); - result = app.AcquireTokenByUsernamePassword(scopes, userID, securePassword).ExecuteAsync().Result; + result = app.AcquireTokenByUsernamePassword(scopes, userID, password).ExecuteAsync().Result; return result.AccessToken; }); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs index b236ddfec5..b85adfff21 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs @@ -37,13 +37,10 @@ public override async Task AcquireTokenAsync(SqlAuthenti string[] scopes = new string[] { scope }; SecureString password = new SecureString(); - foreach (char c in parameters.Password) - password.AppendChar(c); - password.MakeReadOnly(); AuthenticationResult result = await PublicClientApplicationBuilder.Create(_appClientId) .WithAuthority(parameters.Authority) - .Build().AcquireTokenByUsernamePassword(scopes, parameters.UserId, password) + .Build().AcquireTokenByUsernamePassword(scopes, parameters.UserId, parameters.Password) .WithCorrelationId(parameters.ConnectionId) .ExecuteAsync(cancellationToken: cts.Token); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs index 49cb91792e..93f31bf9f1 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs @@ -223,7 +223,7 @@ public static void Test_WithDecimalValue_ShouldReturnDecimal() var cmd = new SqlCommand("select @foo", conn); cmd.Parameters.AddWithValue("@foo", new SqlDecimal(0.5)); var result = (decimal)cmd.ExecuteScalar(); - Assert.Equal(result, (decimal)0.5); + Assert.Equal((decimal)0.5, result); } // Synapse: Unsupported parameter type found while parsing RPC request. The request has been terminated. diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/WeakRefTest/WeakRefTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/WeakRefTest/WeakRefTest.cs index 13692fac8d..357e302789 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/WeakRefTest/WeakRefTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/WeakRefTest/WeakRefTest.cs @@ -147,13 +147,13 @@ private static void TestReaderNonMarsCase(string caseName, string connectionStri { rdr.Read(); Assert.Equal(1, rdr.FieldCount); - Assert.Equal(rdr.GetName(0), COLUMN_NAME_2); + Assert.Equal(COLUMN_NAME_2, rdr.GetName(0)); } break; case ReaderVerificationType.ChangeDatabase: con.ChangeDatabase(CHANGE_DATABASE_NAME); - Assert.Equal(con.Database, CHANGE_DATABASE_NAME); + Assert.Equal(CHANGE_DATABASE_NAME, con.Database); break; case ReaderVerificationType.BeginTransaction: diff --git a/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj b/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj index 2ad4b53604..b8b83efb00 100644 --- a/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj @@ -2,7 +2,7 @@ Exe PerformanceTests - netcoreapp3.1;net5.0 + net6.0;net5.0 false Debug;Release; $(ObjFolder)$(Configuration).$(Platform).$(AssemblyName) diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/Microsoft.Data.SqlClient.ExtUtilities.csproj b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/Microsoft.Data.SqlClient.ExtUtilities.csproj index da345f4e21..ab120d549f 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/Microsoft.Data.SqlClient.ExtUtilities.csproj +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/Microsoft.Data.SqlClient.ExtUtilities.csproj @@ -1,7 +1,7 @@  Exe - netcoreapp3.1;net5.0 + net6.0 Microsoft.Data.SqlClient.ExtUtilities.Runner diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.DotNet.XUnitExtensions/Microsoft.DotNet.XUnitExtensions.csproj b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.DotNet.XUnitExtensions/Microsoft.DotNet.XUnitExtensions.csproj index 9d3f813a99..7ca0c9a23f 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.DotNet.XUnitExtensions/Microsoft.DotNet.XUnitExtensions.csproj +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.DotNet.XUnitExtensions/Microsoft.DotNet.XUnitExtensions.csproj @@ -48,7 +48,7 @@ - + diff --git a/tools/GenAPI/Microsoft.DotNet.GenAPI/Microsoft.DotNet.GenAPI.csproj b/tools/GenAPI/Microsoft.DotNet.GenAPI/Microsoft.DotNet.GenAPI.csproj index 9b2dc0b6fd..8bfcd7ad1e 100644 --- a/tools/GenAPI/Microsoft.DotNet.GenAPI/Microsoft.DotNet.GenAPI.csproj +++ b/tools/GenAPI/Microsoft.DotNet.GenAPI/Microsoft.DotNet.GenAPI.csproj @@ -2,7 +2,7 @@ Exe - net472;netcoreapp3.1 + net472;net6.0 true MSBuildSdk false diff --git a/tools/props/Versions.props b/tools/props/Versions.props index 68a9ed0beb..54547cc71b 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -26,29 +26,29 @@ - 1.6.0 - 4.45.0 - 6.21.0 - 6.21.0 + 1.7.0 + 4.47.2 + 6.24.0 + 6.24.0 4.5.1 4.3.0 - 4.7.2 - 1.0.0 + 6.0.0 + 1.1.0 5.0.0 5.1.0-preview1.22278.1 - 5.0.0 + 6.0.1 1.0.0 - 5.0.0 - 5.0.0 + 6.0.0 + 6.0.1 4.3.0 - 5.0.0 + 6.0.0 5.0.0 - 5.0.0 + 6.0.0 5.0.0 - 5.0.0 + 6.0.0 @@ -56,28 +56,29 @@ - [1.24.0,2.0.0) - [4.0.3,5.0.0) - 5.0.0 + [1.25.0,2.0.0) + [4.4.0,5.0.0) + 6.0.1 - 3.1.1 - 5.2.6 - 15.9.0 + 3.1.6 + 5.2.9 + 17.3.2 13.0.1 4.3.0 4.3.0 4.5.0 - 4.6.0 + 6.0.1 4.3.0 - 6.21.0 - 2.4.1 - 5.0.0-beta.20206.4 + 6.24.0 + 2.4.2 + 2.4.5 + 7.0.0-beta.22316.1 2.0.8 - 161.41011.9 + 170.8.0 10.50.1600.1 - 0.12.1 + 0.13.2 6.0.0 diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index c69ab3eb08..c77b6f8fac 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -29,51 +29,51 @@ When using NuGet 3.x this package requires at least version 3.4. - - - - + + + + - + - + - + - - - - + + + + - - + + - - - + + + - - - - + + + + - + - - - + + + @@ -81,18 +81,18 @@ When using NuGet 3.x this package requires at least version 3.4. - - - - + + + + - + - - - + + + @@ -109,7 +109,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -135,9 +135,9 @@ When using NuGet 3.x this package requires at least version 3.4. - - - + + + @@ -166,9 +166,9 @@ When using NuGet 3.x this package requires at least version 3.4. - - - + + + @@ -184,10 +184,10 @@ When using NuGet 3.x this package requires at least version 3.4. - - - - + + + + diff --git a/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec b/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec index ec14dc0276..e243d20e26 100644 --- a/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec +++ b/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec @@ -26,24 +26,24 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyStoreProvider.SqlColumnEncrypti - - - - + + + + - + - - - - + + + + - - - - + + + + @@ -62,15 +62,15 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyStoreProvider.SqlColumnEncrypti - - - + + + - - - + + + - + diff --git a/tools/targets/NotSupported.targets b/tools/targets/NotSupported.targets index 94be9dc6a5..3be0460dd1 100644 --- a/tools/targets/NotSupported.targets +++ b/tools/targets/NotSupported.targets @@ -3,7 +3,7 @@ true - $(IntermediateOutputPath)$(AssemblyName).notsupported.cs + $(IntermediateOutputPath)\$(TargetFramework)\$(AssemblyName).notsupported.cs $(CoreCompileDependsOn);GenerateNotSupportedSource false @@ -42,7 +42,7 @@ $(GenAPIArgs) -o:"$(NotSupportedSourceFile)" $(GenAPIArgs) -t:"$(GeneratePlatformNotSupportedAssemblyMessage)" $(GenAPIArgs) -global - "$(DotNetCmd) $(ToolsArtifactsDir)netcoreapp3.1\Microsoft.DotNet.GenAPI.dll" + "$(DotNetCmd) $(ToolsArtifactsDir)net6.0\Microsoft.DotNet.GenAPI.dll" "$(ToolsArtifactsDir)net472\Microsoft.DotNet.GenAPI.exe" From c6821c35c2c4038f4ab74c8da615434c81d682a4 Mon Sep 17 00:00:00 2001 From: Javad Date: Tue, 25 Oct 2022 18:28:34 -0700 Subject: [PATCH 27/78] Test | Fix Mac OS test failures (#1817) --- BUILDGUIDE.md | 1 + .../tests/ManualTests/DataCommon/DataTestUtility.cs | 1 + .../SQL/ConnectivityTests/AADConnectionTest.cs | 8 ++++---- .../Microsoft.Data.SqlClient.TestUtilities/Config.cs | 1 + .../config.default.json | 1 + 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/BUILDGUIDE.md b/BUILDGUIDE.md index 055243c115..1e63539c01 100644 --- a/BUILDGUIDE.md +++ b/BUILDGUIDE.md @@ -184,6 +184,7 @@ Manual Tests require the below setup to run: |DNSCachingConnString | Connection string for a server that supports DNS Caching| |IsAzureSynpase | (Optional) When set to 'true', test suite runs compatible tests for Azure Synapse/Parallel Data Warehouse. | `true` OR `false`| |EnclaveAzureDatabaseConnString | (Optional) Connection string for Azure database with enclaves | + |ManagedIdentitySupported | (Optional) When set to `false` **Managed Identity** related tests won't run. The default value is `true`. | |MakecertPath | The full path to makecert.exe. This is not required if the path is present in the PATH environment variable. | `D:\\escaped\\absolute\\path\\to\\makecert.exe` | ### Commands to run Manual Tests diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index f696e5ee3d..0740d0cbad 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -113,6 +113,7 @@ static DataTestUtility() MakecertPath = c.MakecertPath; KerberosDomainPassword = c.KerberosDomainPassword; KerberosDomainUser = c.KerberosDomainUser; + ManagedIdentitySupported = c.ManagedIdentitySupported; System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs index b85adfff21..70cae84d73 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/AADConnectionTest.cs @@ -658,7 +658,7 @@ public static void AccessToken_UserManagedIdentityTest() } } - [ConditionalFact(nameof(AreConnStringsSetup), nameof(IsAzure))] + [ConditionalFact(nameof(AreConnStringsSetup), nameof(IsAzure), nameof(IsManagedIdentitySetup))] public static void Azure_SystemManagedIdentityTest() { string[] removeKeys = { "Authentication", "User ID", "Password", "UID", "PWD", "Trusted_Connection", "Integrated Security" }; @@ -673,7 +673,7 @@ public static void Azure_SystemManagedIdentityTest() } } - [ConditionalFact(nameof(AreConnStringsSetup), nameof(IsAzure))] + [ConditionalFact(nameof(AreConnStringsSetup), nameof(IsAzure), nameof(IsManagedIdentitySetup))] public static void Azure_UserManagedIdentityTest() { string[] removeKeys = { "Authentication", "User ID", "Password", "UID", "PWD", "Trusted_Connection", "Integrated Security" }; @@ -688,7 +688,7 @@ public static void Azure_UserManagedIdentityTest() } } - [ConditionalFact(nameof(AreConnStringsSetup), nameof(IsAzure), nameof(IsAccessTokenSetup))] + [ConditionalFact(nameof(AreConnStringsSetup), nameof(IsAzure), nameof(IsAccessTokenSetup), nameof(IsManagedIdentitySetup))] public static void Azure_AccessToken_SystemManagedIdentityTest() { string[] removeKeys = { "Authentication", "User ID", "Password", "UID", "PWD", "Trusted_Connection", "Integrated Security" }; @@ -702,7 +702,7 @@ public static void Azure_AccessToken_SystemManagedIdentityTest() } } - [ConditionalFact(nameof(AreConnStringsSetup), nameof(IsAzure), nameof(IsAccessTokenSetup))] + [ConditionalFact(nameof(AreConnStringsSetup), nameof(IsAzure), nameof(IsAccessTokenSetup), nameof(IsManagedIdentitySetup))] public static void Azure_AccessToken_UserManagedIdentityTest() { string[] removeKeys = { "Authentication", "User ID", "Password", "UID", "PWD", "Trusted_Connection", "Integrated Security" }; diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs index 101b0c0606..74b1d7a370 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Config.cs @@ -29,6 +29,7 @@ public class Config public bool EnclaveEnabled = false; public bool TracingEnabled = false; public bool SupportsIntegratedSecurity = false; + public bool ManagedIdentitySupported = true; public string FileStreamDirectory = null; public bool UseManagedSNIOnWindows = false; public string DNSCachingConnString = null; diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json index cbe4c15e70..7ab0368edc 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/config.default.json @@ -28,6 +28,7 @@ "IsDNSCachingSupportedTR": false, "IsAzureSynapse": false, "EnclaveAzureDatabaseConnString": "", + "ManagedIdentitySupported": true, "UserManagedIdentityClientId": "", "MakecertPath": "" } From fe403ffc0d05ba790469a91d8dac2a7b481d5d5e Mon Sep 17 00:00:00 2001 From: Wraith Date: Wed, 2 Nov 2022 00:23:13 +0000 Subject: [PATCH 28/78] Port SqlParameter changes from netcore to netfx (#1812) --- .../Microsoft/Data/SqlClient/SqlCommand.cs | 10 +- .../Microsoft/Data/SqlClient/SqlCommand.cs | 437 ++++++++---------- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 13 +- .../Data/SqlClient/TdsParserHelperClasses.cs | 32 +- 4 files changed, 244 insertions(+), 248 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index bca9f13ea7..b576ef3510 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -4058,6 +4058,7 @@ private void PrepareDescribeParameterEncryptionRequest(_SqlRPC originalRpcReques tsqlParam.SqlDbType = ((text.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; tsqlParam.Value = text; tsqlParam.Size = text.Length; + tsqlParam.Direction = ParameterDirection.Input; } else { @@ -4075,6 +4076,7 @@ private void PrepareDescribeParameterEncryptionRequest(_SqlRPC originalRpcReques tsqlParam.SqlDbType = ((text.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; tsqlParam.Value = text; tsqlParam.Size = text.Length; + tsqlParam.Direction = ParameterDirection.Input; } } @@ -4151,13 +4153,15 @@ private void PrepareDescribeParameterEncryptionRequest(_SqlRPC originalRpcReques paramsParam.SqlDbType = ((parameterList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; paramsParam.Size = parameterList.Length; paramsParam.Value = parameterList; + paramsParam.Direction = ParameterDirection.Input; if (attestationParameters != null) { SqlParameter attestationParametersParam = describeParameterEncryptionRequest.systemParams[2]; - attestationParametersParam.Direction = ParameterDirection.Input; + attestationParametersParam.SqlDbType = SqlDbType.VarBinary; attestationParametersParam.Size = attestationParameters.Length; attestationParametersParam.Value = attestationParameters; + attestationParametersParam.Direction = ParameterDirection.Input; } } @@ -5791,6 +5795,7 @@ private _SqlRPC BuildPrepExec(CommandBehavior behavior) sqlParam.SqlDbType = ((paramList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; sqlParam.Value = paramList; sqlParam.Size = paramList.Length; + sqlParam.Direction = ParameterDirection.Input; //@batch_text string text = GetCommandText(behavior); @@ -5798,6 +5803,7 @@ private _SqlRPC BuildPrepExec(CommandBehavior behavior) sqlParam.SqlDbType = ((text.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; sqlParam.Size = text.Length; sqlParam.Value = text; + sqlParam.Direction = ParameterDirection.Input; SetUpRPCParameters(rpc, false, _parameters); return rpc; @@ -5899,6 +5905,7 @@ private _SqlRPC BuildExecute(bool inSchema) //@handle SqlParameter sqlParam = rpc.systemParams[0]; sqlParam.SqlDbType = SqlDbType.Int; + sqlParam.Size = 4; sqlParam.Value = _prepareHandle; sqlParam.Direction = ParameterDirection.Input; @@ -5951,6 +5958,7 @@ private void BuildExecuteSql(CommandBehavior behavior, string commandText, SqlPa sqlParam.SqlDbType = ((paramList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; sqlParam.Size = paramList.Length; sqlParam.Value = paramList; + sqlParam.Direction = ParameterDirection.Input; bool inSchema = (0 != (behavior & CommandBehavior.SchemaOnly)); SetUpRPCParameters(rpc, inSchema, parameters); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs index 7294c745d1..fdfa0772ea 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -4449,7 +4449,7 @@ private SqlDataReader TryFetchInputParameterEncryptionInfo(int timeout, { // In BatchRPCMode, the actual T-SQL query is in the first parameter and not present as the rpcName, as is the case with non-BatchRPCMode. // So input parameters start at parameters[1]. parameters[0] is the actual T-SQL Statement. rpcName is sp_executesql. - if (_SqlRPCBatchArray[i].parameters.Length > 1) + if (_SqlRPCBatchArray[i].systemParams.Length > 1) { _SqlRPCBatchArray[i].needsFetchParameterEncryptionMetadata = true; @@ -4494,20 +4494,11 @@ private SqlDataReader TryFetchInputParameterEncryptionInfo(int timeout, _sqlRPCParameterEncryptionReqArray = new _SqlRPC[1]; _SqlRPC rpc = null; - GetRPCObject(GetParameterCount(_parameters), ref rpc); + GetRPCObject(0, GetParameterCount(_parameters), ref rpc); Debug.Assert(rpc != null, "GetRPCObject should not return rpc as null."); rpc.rpcName = CommandText; - - int i = 0; - - if (_parameters != null) - { - foreach (SqlParameter sqlParam in _parameters) - { - rpc.parameters[i++] = sqlParam; - } - } + rpc.userParams = _parameters; // Prepare the RPC request for describe parameter encryption procedure. PrepareDescribeParameterEncryptionRequest(rpc, ref _sqlRPCParameterEncryptionReqArray[0], serializedAttestationParameters); @@ -4573,20 +4564,24 @@ private void PrepareDescribeParameterEncryptionRequest(_SqlRPC originalRpcReques // Construct the RPC request for sp_describe_parameter_encryption // sp_describe_parameter_encryption always has 2 parameters (stmt, paramlist). //sp_describe_parameter_encryption can have an optional 3rd parameter (attestationParametes), used to identify and execute attestation protocol - GetRPCObject(attestationParameters == null ? 2 : 3, ref describeParameterEncryptionRequest, forSpDescribeParameterEncryption: true); + GetRPCObject(attestationParameters == null ? 2 : 3, 0, ref describeParameterEncryptionRequest, forSpDescribeParameterEncryption: true); describeParameterEncryptionRequest.rpcName = "sp_describe_parameter_encryption"; // Prepare @tsql parameter - SqlParameter sqlParam; string text; // In BatchRPCMode, The actual T-SQL query is in the first parameter and not present as the rpcName, as is the case with non-BatchRPCMode. if (BatchRPCMode) { - Debug.Assert(originalRpcRequest.parameters != null && originalRpcRequest.parameters.Length > 0, + Debug.Assert(originalRpcRequest.systemParamCount > 0, "originalRpcRequest didn't have at-least 1 parameter in BatchRPCMode, in PrepareDescribeParameterEncryptionRequest."); - text = (string)originalRpcRequest.parameters[0].Value; - sqlParam = GetSqlParameterWithQueryText(text); + text = (string)originalRpcRequest.systemParams[0].Value; + //@tsql + SqlParameter tsqlParam = describeParameterEncryptionRequest.systemParams[0]; + tsqlParam.SqlDbType = ((text.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; + tsqlParam.Value = text; + tsqlParam.Size = text.Length; + tsqlParam.Direction = ParameterDirection.Input; } else { @@ -4595,42 +4590,58 @@ private void PrepareDescribeParameterEncryptionRequest(_SqlRPC originalRpcReques { // For stored procedures, we need to prepare @tsql in the following format // N'EXEC sp_name @param1=@param1, @param1=@param2, ..., @paramN=@paramN' - sqlParam = BuildStoredProcedureStatementForColumnEncryption(text, originalRpcRequest.parameters); + describeParameterEncryptionRequest.systemParams[0] = BuildStoredProcedureStatementForColumnEncryption(text, originalRpcRequest.userParams); } else { - sqlParam = GetSqlParameterWithQueryText(text); + //@tsql + SqlParameter tsqlParam = describeParameterEncryptionRequest.systemParams[0]; + tsqlParam.SqlDbType = ((text.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; + tsqlParam.Value = text; + tsqlParam.Size = text.Length; + tsqlParam.Direction = ParameterDirection.Input; } } Debug.Assert(text != null, "@tsql parameter is null in PrepareDescribeParameterEncryptionRequest."); - describeParameterEncryptionRequest.parameters[0] = sqlParam; string parameterList = null; // In BatchRPCMode, the input parameters start at parameters[1]. parameters[0] is the T-SQL statement. rpcName is sp_executesql. // And it is already in the format expected out of BuildParamList, which is not the case with Non-BatchRPCMode. if (BatchRPCMode) { - if (originalRpcRequest.parameters.Length > 1) + if (originalRpcRequest.systemParamCount > 1) { - parameterList = (string)originalRpcRequest.parameters[1].Value; + parameterList = (string)originalRpcRequest.systemParams[1].Value; } } else { // Prepare @params parameter // Need to create new parameters as we cannot have the same parameter being part of two SqlCommand objects - SqlParameter paramCopy; SqlParameterCollection tempCollection = new SqlParameterCollection(); - if (_parameters != null) - { - for (int i = 0; i < _parameters.Count; i++) - { - SqlParameter param = originalRpcRequest.parameters[i]; - paramCopy = new SqlParameter(param.ParameterName, param.SqlDbType, param.Size, param.Direction, param.Precision, param.Scale, param.SourceColumn, param.SourceVersion, - param.SourceColumnNullMapping, param.Value, param.XmlSchemaCollectionDatabase, param.XmlSchemaCollectionOwningSchema, param.XmlSchemaCollectionName); + if (originalRpcRequest.userParams != null) + { + for (int i = 0; i < originalRpcRequest.userParams.Count; i++) + { + SqlParameter param = originalRpcRequest.userParams[i]; + SqlParameter paramCopy = new SqlParameter( + param.ParameterName, + param.SqlDbType, + param.Size, + param.Direction, + param.Precision, + param.Scale, + param.SourceColumn, + param.SourceVersion, + param.SourceColumnNullMapping, + param.Value, + param.XmlSchemaCollectionDatabase, + param.XmlSchemaCollectionOwningSchema, + param.XmlSchemaCollectionName + ); paramCopy.CompareInfo = param.CompareInfo; paramCopy.TypeName = param.TypeName; paramCopy.UdtTypeName = param.UdtTypeName; @@ -4659,20 +4670,19 @@ private void PrepareDescribeParameterEncryptionRequest(_SqlRPC originalRpcReques parameterList = BuildParamList(tdsParser, tempCollection, includeReturnValue: true); } - sqlParam = new SqlParameter(null, ((parameterList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText, parameterList.Length); - sqlParam.Value = parameterList; - describeParameterEncryptionRequest.parameters[1] = sqlParam; + SqlParameter paramsParam = describeParameterEncryptionRequest.systemParams[1]; + paramsParam.SqlDbType = ((parameterList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; + paramsParam.Size = parameterList.Length; + paramsParam.Value = parameterList; + paramsParam.Direction = ParameterDirection.Input; if (attestationParameters != null) { - var attestationParametersParam = new SqlParameter(null, SqlDbType.VarBinary) - { - Direction = ParameterDirection.Input, - Size = attestationParameters.Length, - Value = attestationParameters - }; - - describeParameterEncryptionRequest.parameters[2] = attestationParametersParam; + SqlParameter attestationParametersParam = describeParameterEncryptionRequest.systemParams[2]; + attestationParametersParam.SqlDbType = SqlDbType.VarBinary; + attestationParametersParam.Size = attestationParameters.Length; + attestationParametersParam.Value = attestationParameters; + attestationParametersParam.Direction = ParameterDirection.Input; } } @@ -4824,9 +4834,6 @@ private void ReadDescribeEncryptionParameterResults(SqlDataReader ds, ReadOnlyDi throw SQL.UnexpectedDescribeParamFormatParameterMetadata(); } - int paramIdx = 0; - int parameterStartIndex = 0; - // Find the RPC command that generated this tce request if (BatchRPCMode) { @@ -4849,10 +4856,8 @@ private void ReadDescribeEncryptionParameterResults(SqlDataReader ds, ReadOnlyDi Debug.Assert(rpc != null, "rpc should not be null here."); - // This is the index in the parameters array where the actual parameters start. - // In BatchRPCMode, parameters[0] has the t-sql, parameters[1] has the param list - // and actual parameters of the query start at parameters[2]. - parameterStartIndex = (BatchRPCMode ? 2 : 0); + int userParamCount = rpc.userParams?.Count ?? 0; + int recievedMetadataCount = 0; if (!enclaveMetadataExists || ds.NextResult()) { @@ -4867,16 +4872,16 @@ private void ReadDescribeEncryptionParameterResults(SqlDataReader ds, ReadOnlyDi // When the RPC object gets reused, the parameter array has more parameters that the valid params for the command. // Null is used to indicate the end of the valid part of the array. Refer to GetRPCObject(). - for (paramIdx = parameterStartIndex; paramIdx < rpc.parameters.Length && rpc.parameters[paramIdx] != null; paramIdx++) + for (int index = 0; index < userParamCount; index++) { - SqlParameter sqlParameter = rpc.parameters[paramIdx]; + SqlParameter sqlParameter = rpc.userParams[index]; Debug.Assert(sqlParameter != null, "sqlParameter should not be null."); if (sqlParameter.ParameterNameFixed.Equals(parameterName, StringComparison.Ordinal)) { Debug.Assert(sqlParameter.CipherMetadata == null, "param.CipherMetadata should be null."); sqlParameter.HasReceivedMetadata = true; - + recievedMetadataCount += 1; // Found the param, setup the encryption info. byte columnEncryptionType = ds.GetByte((int)DescribeParameterEncryptionResultSet2.ColumnEncryptionType); if ((byte)SqlClientEncryptionType.PlainText != columnEncryptionType) @@ -4904,7 +4909,9 @@ private void ReadDescribeEncryptionParameterResults(SqlDataReader ds, ReadOnlyDi // This is effective only for BatchRPCMode even though we set it for non-BatchRPCMode also, // since for non-BatchRPCMode mode, paramoptions gets thrown away and reconstructed in BuildExecuteSql. - rpc.paramoptions[paramIdx] |= TdsEnums.RPC_PARAM_ENCRYPTED; + int options = (int)(rpc.userParamMap[index] >> 32); + options |= TdsEnums.RPC_PARAM_ENCRYPTED; + rpc.userParamMap[index] = ((((long)options) << 32) | (long)index); } break; @@ -4915,15 +4922,19 @@ private void ReadDescribeEncryptionParameterResults(SqlDataReader ds, ReadOnlyDi // When the RPC object gets reused, the parameter array has more parameters that the valid params for the command. // Null is used to indicate the end of the valid part of the array. Refer to GetRPCObject(). - for (paramIdx = parameterStartIndex; paramIdx < rpc.parameters.Length && rpc.parameters[paramIdx] != null; paramIdx++) + if (recievedMetadataCount != userParamCount) { - if (!rpc.parameters[paramIdx].HasReceivedMetadata && rpc.parameters[paramIdx].Direction != ParameterDirection.ReturnValue) + for (int index = 0; index < userParamCount; index++) { - // Encryption MD wasn't sent by the server - we expect the metadata to be sent for all the parameters - // that were sent in the original sp_describe_parameter_encryption but not necessarily for return values, - // since there might be multiple return values but server will only send for one of them. - // For parameters that don't need encryption, the encryption type is set to plaintext. - throw SQL.ParamEncryptionMetadataMissing(rpc.parameters[paramIdx].ParameterName, rpc.GetCommandTextOrRpcName()); + SqlParameter sqlParameter = rpc.userParams[index]; + if (!sqlParameter.HasReceivedMetadata && sqlParameter.Direction != ParameterDirection.ReturnValue) + { + // Encryption MD wasn't sent by the server - we expect the metadata to be sent for all the parameters + // that were sent in the original sp_describe_parameter_encryption but not necessarily for return values, + // since there might be multiple return values but server will only send for one of them. + // For parameters that don't need encryption, the encryption type is set to plaintext. + throw SQL.ParamEncryptionMetadataMissing(sqlParameter.ParameterName, rpc.GetCommandTextOrRpcName()); + } } } @@ -6093,40 +6104,41 @@ internal void OnDoneDescribeParameterEncryptionProc(TdsParserStateObject stateOb /// Please consider the changes being done in this function for the above function as well. /// internal void OnDoneProc() - { // called per rpc batch complete + { + // called per rpc batch complete if (BatchRPCMode) { + OnDone(_stateObj, _currentlyExecutingBatch, _SqlRPCBatchArray, _rowsAffected); + _currentlyExecutingBatch++; + Debug.Assert(_parameterCollectionList.Count >= _currentlyExecutingBatch, "OnDoneProc: Too many DONEPROC events"); + } + } - // track the records affected for the just completed rpc batch - // _rowsAffected is cumulative for ExecuteNonQuery across all rpc batches - _SqlRPCBatchArray[_currentlyExecutingBatch].cumulativeRecordsAffected = _rowsAffected; + private static void OnDone(TdsParserStateObject stateObj, int index, _SqlRPC[] array, int rowsAffected) + { + _SqlRPC current = array[index]; + _SqlRPC previous = (index > 0) ? array[index - 1] : null; - _SqlRPCBatchArray[_currentlyExecutingBatch].recordsAffected = - (((0 < _currentlyExecutingBatch) && (0 <= _rowsAffected)) - ? (_rowsAffected - Math.Max(_SqlRPCBatchArray[_currentlyExecutingBatch - 1].cumulativeRecordsAffected, 0)) - : _rowsAffected); + // track the records affected for the just completed rpc batch + // _rowsAffected is cumulative for ExecuteNonQuery across all rpc batches + current.cumulativeRecordsAffected = rowsAffected; - // track the error collection (not available from TdsParser after ExecuteNonQuery) - // and the which errors are associated with the just completed rpc batch - _SqlRPCBatchArray[_currentlyExecutingBatch].errorsIndexStart = - ((0 < _currentlyExecutingBatch) - ? _SqlRPCBatchArray[_currentlyExecutingBatch - 1].errorsIndexEnd - : 0); - _SqlRPCBatchArray[_currentlyExecutingBatch].errorsIndexEnd = _stateObj.ErrorCount; - _SqlRPCBatchArray[_currentlyExecutingBatch].errors = _stateObj._errors; + current.recordsAffected = + (((previous != null) && (0 <= rowsAffected)) + ? (rowsAffected - Math.Max(previous.cumulativeRecordsAffected, 0)) + : rowsAffected); - // track the warning collection (not available from TdsParser after ExecuteNonQuery) - // and the which warnings are associated with the just completed rpc batch - _SqlRPCBatchArray[_currentlyExecutingBatch].warningsIndexStart = - ((0 < _currentlyExecutingBatch) - ? _SqlRPCBatchArray[_currentlyExecutingBatch - 1].warningsIndexEnd - : 0); - _SqlRPCBatchArray[_currentlyExecutingBatch].warningsIndexEnd = _stateObj.WarningCount; - _SqlRPCBatchArray[_currentlyExecutingBatch].warnings = _stateObj._warnings; + // track the error collection (not available from TdsParser after ExecuteNonQuery) + // and the which errors are associated with the just completed rpc batch + current.errorsIndexStart = previous?.errorsIndexEnd ?? 0; + current.errorsIndexEnd = stateObj.ErrorCount; + current.errors = stateObj._errors; - _currentlyExecutingBatch++; - Debug.Assert(_parameterCollectionList.Count >= _currentlyExecutingBatch, "OnDoneProc: Too many DONEPROC events"); - } + // track the warning collection (not available from TdsParser after ExecuteNonQuery) + // and the which warnings are associated with the just completed rpc batch + current.warningsIndexStart = previous?.warningsIndexEnd ?? 0; + current.warningsIndexEnd = stateObj.WarningCount; + current.warnings = stateObj._warnings; } // @@ -6459,10 +6471,10 @@ private SqlParameter GetParameterForOutputValueExtraction(SqlParameterCollection return null; } - private void GetRPCObject(int paramCount, ref _SqlRPC rpc, bool forSpDescribeParameterEncryption = false) + private void GetRPCObject(int systemParamCount, int userParamCount, ref _SqlRPC rpc, bool forSpDescribeParameterEncryption = false) { // Designed to minimize necessary allocations - int ii; + if (rpc == null) { if (!forSpDescribeParameterEncryption) @@ -6489,6 +6501,7 @@ private void GetRPCObject(int paramCount, ref _SqlRPC rpc, bool forSpDescribePar rpc.ProcID = 0; rpc.rpcName = null; rpc.options = 0; + rpc.systemParamCount = systemParamCount; rpc.recordsAffected = default(int?); rpc.cumulativeRecordsAffected = -1; @@ -6502,37 +6515,39 @@ private void GetRPCObject(int paramCount, ref _SqlRPC rpc, bool forSpDescribePar rpc.warnings = null; rpc.needsFetchParameterEncryptionMetadata = false; + int currentCount = rpc.systemParams?.Length ?? 0; + // Make sure there is enough space in the parameters and paramoptions arrays - if (rpc.parameters == null || rpc.parameters.Length < paramCount) - { - rpc.parameters = new SqlParameter[paramCount]; - } - else if (rpc.parameters.Length > paramCount) + if (currentCount < systemParamCount) { - rpc.parameters[paramCount] = null; // Terminator + Array.Resize(ref rpc.systemParams, systemParamCount); + Array.Resize(ref rpc.systemParamOptions, systemParamCount); + for (int index = currentCount; index < systemParamCount; index++) + { + rpc.systemParams[index] = new SqlParameter(); + } } - if (rpc.paramoptions == null || (rpc.paramoptions.Length < paramCount)) + + for (int ii = 0; ii < systemParamCount; ii++) { - rpc.paramoptions = new byte[paramCount]; + rpc.systemParamOptions[ii] = 0; } - else + + if ((rpc.userParamMap?.Length ?? 0) < userParamCount) { - for (ii = 0; ii < paramCount; ii++) - rpc.paramoptions[ii] = 0; + Array.Resize(ref rpc.userParamMap, userParamCount); } } - private void SetUpRPCParameters(_SqlRPC rpc, int startCount, bool inSchema, SqlParameterCollection parameters) + private void SetUpRPCParameters(_SqlRPC rpc, bool inSchema, SqlParameterCollection parameters) { - int ii; int paramCount = GetParameterCount(parameters); - int j = startCount; - TdsParser parser = _activeConnection.Parser; + int userParamCount = 0; - for (ii = 0; ii < paramCount; ii++) + for (int index = 0; index < paramCount; index++) { - SqlParameter parameter = parameters[ii]; - parameter.Validate(ii, CommandType.StoredProcedure == CommandType); + SqlParameter parameter = parameters[index]; + parameter.Validate(index, CommandType.StoredProcedure == CommandType); // func will change type to that with a 4 byte length if the type has a two // byte length and a parameter length > than that expressable in 2 bytes @@ -6543,17 +6558,18 @@ private void SetUpRPCParameters(_SqlRPC rpc, int startCount, bool inSchema, SqlP if (ShouldSendParameter(parameter)) { - rpc.parameters[j] = parameter; + byte options = 0; // set output bit - if (parameter.Direction == ParameterDirection.InputOutput || - parameter.Direction == ParameterDirection.Output) - rpc.paramoptions[j] = TdsEnums.RPC_PARAM_BYREF; + if (parameter.Direction == ParameterDirection.InputOutput || parameter.Direction == ParameterDirection.Output) + { + options = TdsEnums.RPC_PARAM_BYREF; + } // Set the encryped bit, if the parameter is to be encrypted. if (parameter.CipherMetadata != null) { - rpc.paramoptions[j] |= TdsEnums.RPC_PARAM_ENCRYPTED; + options |= TdsEnums.RPC_PARAM_ENCRYPTED; } // set default value bit @@ -6566,7 +6582,7 @@ private void SetUpRPCParameters(_SqlRPC rpc, int startCount, bool inSchema, SqlP // SQLBUVSTS 179488 TVPs use DEFAULT and do not allow NULL, even for schema only. if (null == parameter.Value && (!inSchema || SqlDbType.Structured == parameter.SqlDbType)) { - rpc.paramoptions[j] |= TdsEnums.RPC_PARAM_DEFAULT; + options |= TdsEnums.RPC_PARAM_DEFAULT; } // detect incorrectly derived type names unchanged by the caller and fix them @@ -6587,11 +6603,15 @@ private void SetUpRPCParameters(_SqlRPC rpc, int startCount, bool inSchema, SqlP } } + rpc.userParamMap[userParamCount] = ((((long)options) << 32) | (long)index); + userParamCount += 1; + // Must set parameter option bit for LOB_COOKIE if unfilled LazyMat blob - j++; } } + rpc.userParamCount = userParamCount; + rpc.userParams = parameters; } // @@ -6603,36 +6623,41 @@ private _SqlRPC BuildPrepExec(CommandBehavior behavior) { Debug.Assert(System.Data.CommandType.Text == this.CommandType, "invalid use of sp_prepexec for stored proc invocation!"); SqlParameter sqlParam; - int j = 3; - int count = CountSendableParameters(_parameters); + const int systemParameterCount = 3; + int userParameterCount = CountSendableParameters(_parameters); _SqlRPC rpc = null; - GetRPCObject(count + j, ref rpc); + GetRPCObject(systemParameterCount, userParameterCount, ref rpc); rpc.ProcID = TdsEnums.RPC_PROCID_PREPEXEC; rpc.rpcName = TdsEnums.SP_PREPEXEC; //@handle - sqlParam = new SqlParameter(null, SqlDbType.Int); - sqlParam.Direction = ParameterDirection.InputOutput; + sqlParam = rpc.systemParams[0]; + sqlParam.SqlDbType = SqlDbType.Int; sqlParam.Value = _prepareHandle; - rpc.parameters[0] = sqlParam; - rpc.paramoptions[0] = TdsEnums.RPC_PARAM_BYREF; + sqlParam.Size = 4; + sqlParam.Direction = ParameterDirection.InputOutput; + rpc.systemParamOptions[0] = TdsEnums.RPC_PARAM_BYREF; //@batch_params string paramList = BuildParamList(_stateObj.Parser, _parameters); - sqlParam = new SqlParameter(null, ((paramList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText, paramList.Length); + sqlParam = rpc.systemParams[1]; + sqlParam.SqlDbType = ((paramList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; sqlParam.Value = paramList; - rpc.parameters[1] = sqlParam; + sqlParam.Size = paramList.Length; + sqlParam.Direction = ParameterDirection.Input; //@batch_text string text = GetCommandText(behavior); - sqlParam = new SqlParameter(null, ((text.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText, text.Length); + sqlParam = rpc.systemParams[2]; + sqlParam.SqlDbType = ((text.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; + sqlParam.Size = text.Length; sqlParam.Value = text; - rpc.parameters[2] = sqlParam; + sqlParam.Direction = ParameterDirection.Input; - SetUpRPCParameters(rpc, j, false, _parameters); + SetUpRPCParameters(rpc, false, _parameters); return rpc; } @@ -6689,14 +6714,14 @@ private int GetParameterCount(SqlParameterCollection parameters) private void BuildRPC(bool inSchema, SqlParameterCollection parameters, ref _SqlRPC rpc) { Debug.Assert(this.CommandType == System.Data.CommandType.StoredProcedure, "Command must be a stored proc to execute an RPC"); - int count = CountSendableParameters(parameters); - GetRPCObject(count, ref rpc); + int userParameterCount = CountSendableParameters(parameters); + GetRPCObject(0, userParameterCount, ref rpc); // TDS Protocol allows rpc name with maximum length of 1046 bytes for ProcName // 4-part name 1 + 128 + 1 + 1 + 1 + 128 + 1 + 1 + 1 + 128 + 1 + 1 + 1 + 128 + 1 = 523 // each char takes 2 bytes. 523 * 2 = 1046 int commandTextLength = ADP.CharSize * CommandText.Length; - + rpc.ProcID = 0; if (commandTextLength <= MaxRPCNameLength) { rpc.rpcName = CommandText; // just get the raw command text @@ -6706,33 +6731,7 @@ private void BuildRPC(bool inSchema, SqlParameterCollection parameters, ref _Sql throw ADP.InvalidArgumentLength(nameof(CommandText), MaxRPCNameLength); } - SetUpRPCParameters(rpc, 0, inSchema, parameters); - } - - // - // build the RPC record header for sp_unprepare - // - // prototype for sp_unprepare is: - // sp_unprepare(@handle) - // - // CONSIDER: instead of creating each time, define at load time and then put the new value in - private _SqlRPC BuildUnprepare() - { - Debug.Assert(_prepareHandle != 0, "Invalid call to sp_unprepare without a valid handle!"); - - _SqlRPC rpc = null; - GetRPCObject(1, ref rpc); - SqlParameter sqlParam; - - rpc.ProcID = TdsEnums.RPC_PROCID_UNPREPARE; - rpc.rpcName = TdsEnums.SP_UNPREPARE; - - //@handle - sqlParam = new SqlParameter(null, SqlDbType.Int); - sqlParam.Value = _prepareHandle; - rpc.parameters[0] = sqlParam; - - return rpc; + SetUpRPCParameters(rpc, inSchema, parameters); } // @@ -6744,24 +6743,24 @@ private _SqlRPC BuildUnprepare() private _SqlRPC BuildExecute(bool inSchema) { Debug.Assert(_prepareHandle != -1, "Invalid call to sp_execute without a valid handle!"); - int j = 1; - int count = CountSendableParameters(_parameters); + const int systemParameterCount = 1; + int userParameterCount = CountSendableParameters(_parameters); _SqlRPC rpc = null; - GetRPCObject(count + j, ref rpc); - - SqlParameter sqlParam; + GetRPCObject(systemParameterCount, userParameterCount, ref rpc); rpc.ProcID = TdsEnums.RPC_PROCID_EXECUTE; rpc.rpcName = TdsEnums.SP_EXECUTE; //@handle - sqlParam = new SqlParameter(null, SqlDbType.Int); + SqlParameter sqlParam = rpc.systemParams[0]; + sqlParam.SqlDbType = SqlDbType.Int; sqlParam.Value = _prepareHandle; - rpc.parameters[0] = sqlParam; + sqlParam.Size = 4; + sqlParam.Direction = ParameterDirection.Input; - SetUpRPCParameters(rpc, j, inSchema, _parameters); + SetUpRPCParameters(rpc, inSchema, _parameters); return rpc; } @@ -6775,20 +6774,20 @@ private void BuildExecuteSql(CommandBehavior behavior, string commandText, SqlPa Debug.Assert(_prepareHandle == -1, "This command has an existing handle, use sp_execute!"); Debug.Assert(CommandType.Text == this.CommandType, "invalid use of sp_executesql for stored proc invocation!"); - int j; + int systemParamCount; SqlParameter sqlParam; - int cParams = CountSendableParameters(parameters); - if (cParams > 0) + int userParamCount = CountSendableParameters(parameters); + if (userParamCount > 0) { - j = 2; + systemParamCount = 2; } else { - j = 1; + systemParamCount = 1; } - GetRPCObject(cParams + j, ref rpc); + GetRPCObject(systemParamCount, userParamCount, ref rpc); rpc.ProcID = TdsEnums.RPC_PROCID_EXECUTESQL; rpc.rpcName = TdsEnums.SP_EXECUTESQL; @@ -6797,19 +6796,23 @@ private void BuildExecuteSql(CommandBehavior behavior, string commandText, SqlPa { commandText = GetCommandText(behavior); } - sqlParam = new SqlParameter(null, ((commandText.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText, commandText.Length); + sqlParam = rpc.systemParams[0]; + sqlParam.SqlDbType = ((commandText.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; + sqlParam.Size = commandText.Length; sqlParam.Value = commandText; - rpc.parameters[0] = sqlParam; + sqlParam.Direction = ParameterDirection.Input; - if (cParams > 0) + if (userParamCount > 0) { string paramList = BuildParamList(_stateObj.Parser, BatchRPCMode ? parameters : _parameters); - sqlParam = new SqlParameter(null, ((paramList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText, paramList.Length); + sqlParam = rpc.systemParams[1]; + sqlParam.SqlDbType = ((paramList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText; + sqlParam.Size = paramList.Length; sqlParam.Value = paramList; - rpc.parameters[1] = sqlParam; + sqlParam.Direction = ParameterDirection.Input; bool inSchema = (0 != (behavior & CommandBehavior.SchemaOnly)); - SetUpRPCParameters(rpc, j, inSchema, parameters); + SetUpRPCParameters(rpc, inSchema, parameters); } } @@ -6821,7 +6824,7 @@ private void BuildExecuteSql(CommandBehavior behavior, string commandText, SqlPa /// Stored procedure name /// SqlParameter list /// A string SqlParameter containing the constructed sql statement value - private SqlParameter BuildStoredProcedureStatementForColumnEncryption(string storedProcedureName, SqlParameter[] parameters) + private SqlParameter BuildStoredProcedureStatementForColumnEncryption(string storedProcedureName, SqlParameterCollection parameters) { Debug.Assert(CommandType == CommandType.StoredProcedure, "BuildStoredProcedureStatementForColumnEncryption() should only be called for stored procedures"); Debug.Assert(!string.IsNullOrWhiteSpace(storedProcedureName), "storedProcedureName cannot be null or empty in BuildStoredProcedureStatementForColumnEncryption"); @@ -6865,27 +6868,29 @@ private SqlParameter BuildStoredProcedureStatementForColumnEncryption(string sto // @param1=@param1, @param1=@param2, ..., @paramn=@paramn // Append the first parameter - int i = 0; - - if (parameters.Count() > 0) + int index = 0; + int count = parameters.Count; + if (count > 0) { // Skip the return value parameters. - while (i < parameters.Count() && parameters[i].Direction == ParameterDirection.ReturnValue) + while (index < parameters.Count && parameters[index].Direction == ParameterDirection.ReturnValue) { - i++; + index++; } - if (i < parameters.Count()) + if (index < count) { // Possibility of a SQL Injection issue through parameter names and how to construct valid identifier for parameters. // Since the parameters comes from application itself, there should not be a security vulnerability. // Also since the query is not executed, but only analyzed there is no possibility for elevation of priviledge, but only for // incorrect results which would only affect the user that attempts the injection. - execStatement.AppendFormat(@" {0}={0}", parameters[i].ParameterNameFixed); + execStatement.AppendFormat(@" {0}={0}", parameters[index].ParameterNameFixed); // InputOutput and Output parameters need to be marked as such. - if (parameters[i].Direction == ParameterDirection.Output || - parameters[i].Direction == ParameterDirection.InputOutput) + if ( + parameters[index].Direction == ParameterDirection.Output || + parameters[index].Direction == ParameterDirection.InputOutput + ) { execStatement.AppendFormat(@" OUTPUT"); } @@ -6893,18 +6898,20 @@ private SqlParameter BuildStoredProcedureStatementForColumnEncryption(string sto } // Move to the next parameter. - i++; + index++; // Append the rest of parameters - for (; i < parameters.Count(); i++) + for (; index < count; index++) { - if (parameters[i].Direction != ParameterDirection.ReturnValue) + if (parameters[index].Direction != ParameterDirection.ReturnValue) { - execStatement.AppendFormat(@", {0}={0}", parameters[i].ParameterNameFixed); + execStatement.AppendFormat(@", {0}={0}", parameters[index].ParameterNameFixed); // InputOutput and Output parameters need to be marked as such. - if (parameters[i].Direction == ParameterDirection.Output || - parameters[i].Direction == ParameterDirection.InputOutput) + if ( + parameters[index].Direction == ParameterDirection.Output || + parameters[index].Direction == ParameterDirection.InputOutput + ) { execStatement.AppendFormat(@" OUTPUT"); } @@ -6924,9 +6931,7 @@ internal string BuildParamList(TdsParser parser, SqlParameterCollection paramete StringBuilder paramList = new StringBuilder(); bool fAddSeparator = false; - int count = 0; - - count = parameters.Count; + int count = parameters.Count; for (int i = 0; i < count; i++) { SqlParameter sqlParam = parameters[i]; @@ -7073,7 +7078,7 @@ internal string BuildParamList(TdsParser parser, SqlParameterCollection paramete // Adds quotes to each part of a SQL identifier that may be multi-part, while leaving // the result as a single composite name. - private string ParseAndQuoteIdentifier(string identifier, bool isUdtTypeName) + private static string ParseAndQuoteIdentifier(string identifier, bool isUdtTypeName) { string[] strings = SqlParameter.ParseTypeName(identifier, isUdtTypeName); return ADP.BuildMultiPartName(strings); @@ -7159,48 +7164,6 @@ private string GetCommandText(CommandBehavior behavior) return GetSetOptionsString(behavior) + this.CommandText; } - // - // build the RPC record header for sp_executesql and add the parameters - // - // the prototype for sp_prepare is: - // sp_prepare(@handle int OUTPUT, @batch_params ntext, @batch_text ntext, @options int default 0x1) - private _SqlRPC BuildPrepare(CommandBehavior behavior) - { - Debug.Assert(System.Data.CommandType.Text == this.CommandType, "invalid use of sp_prepare for stored proc invocation!"); - - _SqlRPC rpc = null; - GetRPCObject(3, ref rpc); - SqlParameter sqlParam; - - rpc.ProcID = TdsEnums.RPC_PROCID_PREPARE; - rpc.rpcName = TdsEnums.SP_PREPARE; - - //@handle - sqlParam = new SqlParameter(null, SqlDbType.Int); - sqlParam.Direction = ParameterDirection.Output; - rpc.parameters[0] = sqlParam; - rpc.paramoptions[0] = TdsEnums.RPC_PARAM_BYREF; - - //@batch_params - string paramList = BuildParamList(_stateObj.Parser, _parameters); - sqlParam = new SqlParameter(null, ((paramList.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText, paramList.Length); - sqlParam.Value = paramList; - rpc.parameters[1] = sqlParam; - - //@batch_text - string text = GetCommandText(behavior); - sqlParam = new SqlParameter(null, ((text.Length << 1) <= TdsEnums.TYPE_SIZE_LIMIT) ? SqlDbType.NVarChar : SqlDbType.NText, text.Length); - sqlParam.Value = text; - rpc.parameters[2] = sqlParam; - - /* - //@options - sqlParam = new SqlParameter(null, SqlDbType.Int); - rpc.Parameters[3] = sqlParam; - */ - return rpc; - } - internal void CheckThrowSNIException() { var stateObj = _stateObj; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index 1edad799ae..c35ae13e63 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -9963,16 +9963,17 @@ internal Task TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, int timeout, boo WriteEnclaveInfo(stateObj, enclavePackage); // Stream out parameters - SqlParameter[] parameters = rpcext.parameters; + int parametersLength = rpcext.userParamCount + rpcext.systemParamCount; bool isAdvancedTraceOn = SqlClientEventSource.Log.IsAdvancedTraceOn(); bool enableOptimizedParameterBinding = cmd.EnableOptimizedParameterBinding; - for (int i = (ii == startRpc) ? startParam : 0; i < parameters.Length; i++) + for (int i = (ii == startRpc) ? startParam : 0; i < parametersLength; i++) { // Debug.WriteLine("i: " + i.ToString(CultureInfo.InvariantCulture)); // parameters can be unnamed - SqlParameter param = parameters[i]; + byte options = 0; + SqlParameter param = rpcext.GetParameterByIndex(i, out options); // Since we are reusing the parameters array, we cannot rely on length to indicate no of parameters. if (param == null) { @@ -10010,7 +10011,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, int timeout, boo if (mt.Is2008Type) { - WriteSmiParameter(param, i, 0 != (rpcext.paramoptions[i] & TdsEnums.RPC_PARAM_DEFAULT), stateObj, enableOptimizedParameterBinding, isAdvancedTraceOn); + WriteSmiParameter(param, i, 0 != (options & TdsEnums.RPC_PARAM_DEFAULT), stateObj, enableOptimizedParameterBinding, isAdvancedTraceOn); continue; } @@ -10045,7 +10046,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, int timeout, boo WriteParameterName(param.ParameterNameFixed, stateObj, enableOptimizedParameterBinding); // Write parameter status - stateObj.WriteByte(rpcext.paramoptions[i]); + stateObj.WriteByte(options); // MaxLen field is only written out for non-fixed length data types // use the greater of the two sizes for maxLen @@ -10108,7 +10109,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, int timeout, boo } } - bool isParameterEncrypted = 0 != (rpcext.paramoptions[i] & TdsEnums.RPC_PARAM_ENCRYPTED); + bool isParameterEncrypted = 0 != (options & TdsEnums.RPC_PARAM_ENCRYPTED); // Additional information we need to send over wire to the server when writing encrypted parameters. SqlColumnEncryptionInputParameterInfo encryptedParameterInfoToWrite = null; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index bf113efe3b..62f7f59b91 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -1158,11 +1158,16 @@ private void SerializeIntIntoBuffer(int value, byte[] buffer, ref int offset) sealed internal class _SqlRPC { internal string rpcName; - internal string databaseName; // Used for UDTs internal ushort ProcID; // Used instead of name internal ushort options; - internal SqlParameter[] parameters; - internal byte[] paramoptions; + + internal SqlParameter[] systemParams; + internal byte[] systemParamOptions; + internal int systemParamCount; + + internal SqlParameterCollection userParams; + internal long[] userParamMap; + internal int userParamCount; internal int? recordsAffected; internal int cumulativeRecordsAffected; @@ -1175,18 +1180,37 @@ sealed internal class _SqlRPC internal int warningsIndexEnd; internal SqlErrorCollection warnings; internal bool needsFetchParameterEncryptionMetadata; + internal string GetCommandTextOrRpcName() { if (TdsEnums.RPC_PROCID_EXECUTESQL == ProcID) { // Param 0 is the actual sql executing - return (string)parameters[0].Value; + return (string)systemParams[0].Value; } else { return rpcName; } } + + internal SqlParameter GetParameterByIndex(int index, out byte options) + { + SqlParameter retval; + if (index < systemParamCount) + { + retval = systemParams[index]; + options = systemParamOptions[index]; + } + else + { + long data = userParamMap[index - systemParamCount]; + int paramIndex = (int)(data & int.MaxValue); + options = (byte)((data >> 32) & 0xFF); + retval = userParams[paramIndex]; + } + return retval; + } } sealed internal class SqlReturnValue : SqlMetaDataPriv From 146c34ead598ac8d97c410a1120dca8f8c6f1604 Mon Sep 17 00:00:00 2001 From: Lawrence Cheung <31262254+lcheunglci@users.noreply.github.com> Date: Tue, 1 Nov 2022 17:28:43 -0700 Subject: [PATCH 29/78] TDS8 - Enable retrieval of TLS 1.3 SSL Protocol from SNI on .NET Core (#1821) --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 18 ++++++++++++++++-- .../SqlClient/TdsParserStateObjectNative.cs | 13 +++++++------ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 36ecb2cd72..ae6e6995cb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -519,8 +519,20 @@ internal void Connect( // On Instance failure re-connect and flush SNI named instance cache. _physicalStateObj.SniContext = SniContext.Snix_Connect; - _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, ignoreSniOpenTimeout, timerExpire, out instanceName, ref _sniSpnBuffer, true, true, fParallel, - _connHandler.ConnectionOptions.IPAddressPreference, FQDNforDNSCache, ref _connHandler.pendingSQLDNSObject, serverInfo.ServerSPN, integratedSecurity); + _physicalStateObj.CreatePhysicalSNIHandle(serverInfo.ExtendedServerName, + ignoreSniOpenTimeout, + timerExpire, + out instanceName, + ref _sniSpnBuffer, + true, + true, fParallel, + _connHandler.ConnectionOptions.IPAddressPreference, + FQDNforDNSCache, + ref _connHandler.pendingSQLDNSObject, + serverInfo.ServerSPN, + integratedSecurity, + encrypt == SqlConnectionEncryptOption.Strict, + hostNameInCertificate); if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { @@ -552,6 +564,7 @@ internal void Connect( throw SQL.InstanceFailure(); } } + SqlClientEventSource.Log.TryTraceEvent(" Prelogin handshake successful"); if (_fMARS && marsCapable) { @@ -1010,6 +1023,7 @@ private PreLoginHandshakeStatus ConsumePreLoginHandshake( uint info = (shouldValidateServerCert ? TdsEnums.SNI_SSL_VALIDATE_CERTIFICATE : 0) | (is2005OrLater ? TdsEnums.SNI_SSL_USE_SCHANNEL_CACHE : 0); + EnableSsl(info, encrypt, integratedSecurity); } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs index 99bbc9bf53..32e364b7e7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectNative.cs @@ -424,16 +424,17 @@ internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) uint returnValue = SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining(), out uint nativeProtocolVersion); var nativeProtocol = (NativeProtocols)nativeProtocolVersion; - /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later - * This driver does not support this version yet! - if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_SERVER)) - { - protocolVersion = (int)SslProtocols.Tls13; - }*/ if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_2_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_2_SERVER)) { protocolVersion = (int)SslProtocols.Tls12; } +#if NETCOREAPP + else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_3_SERVER)) + { + /* The SslProtocols.Tls13 is supported by netcoreapp3.1 and later */ + protocolVersion = (int)SslProtocols.Tls13; + } +#endif else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_1_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_TLS1_1_SERVER)) { protocolVersion = (int)SslProtocols.Tls11; From 708cf3a2503886c4fa3b2d3d804fdf8c5df79193 Mon Sep 17 00:00:00 2001 From: Javad Date: Wed, 2 Nov 2022 16:03:58 -0700 Subject: [PATCH 30/78] Test | Removing all net5 references from the driver (#1823) --- .../src/System/Diagnostics/CodeAnalysis.cs | 2 +- .../SqlColumnEncryptionCertificateStoreProviderShould.cs | 2 +- .../SqlColumnEncryptionCngProviderShould.cs | 4 ++-- .../SqlColumnEncryptionCspProviderShould.cs | 4 ++-- .../FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj | 1 - .../tests/ManualTests/AlwaysEncrypted/CspProviderExt.cs | 4 ++-- .../TestFixtures/Setup/CertificateUtilityWin.cs | 4 ++-- .../tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs | 7 ++++--- .../SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs | 2 +- .../Microsoft.Data.SqlClient.PerformanceTests.csproj | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/src/System/Diagnostics/CodeAnalysis.cs b/src/Microsoft.Data.SqlClient/src/System/Diagnostics/CodeAnalysis.cs index 256f7cd1e0..e62544d06d 100644 --- a/src/Microsoft.Data.SqlClient/src/System/Diagnostics/CodeAnalysis.cs +++ b/src/Microsoft.Data.SqlClient/src/System/Diagnostics/CodeAnalysis.cs @@ -59,7 +59,7 @@ internal sealed class NotNullWhenAttribute : Attribute } #endif -#if !NET5_0_OR_GREATER +#if !NET6_0_OR_GREATER [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true, Inherited = false)] internal sealed class MemberNotNullAttribute : Attribute { diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs index b0c6297cda..5b7dd192ef 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs @@ -634,7 +634,7 @@ public static bool IsAdmin { get { -#if NET5_0_OR_GREATER +#if NET6_0_OR_GREATER System.Diagnostics.Debug.Assert(OperatingSystem.IsWindows()); #endif return new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCngProviderShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCngProviderShould.cs index 9d1c698f17..08a71335d9 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCngProviderShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCngProviderShould.cs @@ -182,7 +182,7 @@ public void Dispose() public static void AddKeyToCng(string providerName, string containerName) { -#if NET5_0_OR_GREATER +#if NET6_0_OR_GREATER System.Diagnostics.Debug.Assert(OperatingSystem.IsWindows()); #endif CngKeyCreationParameters keyParams = new CngKeyCreationParameters(); @@ -202,7 +202,7 @@ public static void AddKeyToCng(string providerName, string containerName) public static void RemoveKeyFromCng(string providerName, string containerName) { -#if NET5_0_OR_GREATER +#if NET6_0_OR_GREATER System.Diagnostics.Debug.Assert(OperatingSystem.IsWindows()); #endif CngProvider cngProvider = new CngProvider(providerName); diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCspProviderShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCspProviderShould.cs index a71fe5c473..609c62ea53 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCspProviderShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCspProviderShould.cs @@ -183,7 +183,7 @@ public void Dispose() public static void AddKeyToCsp(string containerName) { -#if NET5_0_OR_GREATER +#if NET6_0_OR_GREATER System.Diagnostics.Debug.Assert(OperatingSystem.IsWindows()); #endif CspParameters cspParams = new(); @@ -194,7 +194,7 @@ public static void AddKeyToCsp(string containerName) public static void RemoveKeyFromCsp(string containerName) { -#if NET5_0_OR_GREATER +#if NET6_0_OR_GREATER System.Diagnostics.Debug.Assert(OperatingSystem.IsWindows()); #endif CspParameters cspParams = new CspParameters(); diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 129d832488..2871cf9434 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -7,7 +7,6 @@ win $(DefineConstants);NETFRAMEWORK $(DefineConstants);NETCOREAPP - $(DefineConstants);NET50_OR_LATER NETSTANDARDREFERNCE $(ObjFolder)$(Configuration).$(Platform).$(AssemblyName) $(BinFolder)$(Configuration).$(Platform).$(AssemblyName) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/CspProviderExt.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/CspProviderExt.cs index 387f364f56..5e998d057a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/CspProviderExt.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/CspProviderExt.cs @@ -7,7 +7,7 @@ using System.Security.Cryptography.X509Certificates; using Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted.Setup; using Xunit; -#if NET50_OR_LATER +#if NET6_0_OR_GREATER using System.Runtime.Versioning; #endif @@ -17,7 +17,7 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted /// Always Encrypted public CspProvider Manual tests. /// TODO: These tests are marked as Windows only for now but should be run for all platforms once the Master Key is accessible to this app from Azure Key Vault. /// -#if NET50_OR_LATER +#if NET6_0_OR_GREATER [SupportedOSPlatform("windows")] #endif [PlatformSpecific(TestPlatforms.Windows)] diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtilityWin.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtilityWin.cs index 72b14c8f51..5a1249434a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtilityWin.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtilityWin.cs @@ -7,13 +7,13 @@ using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using Xunit; -#if NET50_OR_LATER +#if NET6_0_OR_GREATER using System.Runtime.Versioning; #endif namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted { -#if NET50_OR_LATER +#if NET6_0_OR_GREATER [SupportedOSPlatform("windows")] #endif [PlatformSpecific(TestPlatforms.Windows)] diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs index dba70d5fcd..30a1505442 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataStreamTest/DataStreamTest.cs @@ -1556,13 +1556,14 @@ private static void ReadStream(string connectionString) DataTestUtility.AssertThrowsWrapper(() => stream.Read(buffer, -1, 2)); DataTestUtility.AssertThrowsWrapper(() => stream.Read(buffer, 2, -1)); - // ArgumentException is thrown in net5 and earlier. ArgumentOutOfRangeException in net6 and later + // Prior to net6 comment:ArgumentException is thrown in net5 and earlier. ArgumentOutOfRangeException in net6 and later + // After adding net6: Running tests against netstandard2.1 still showing ArgumentException, but the rest works fine. ArgumentException ex = Assert.ThrowsAny(() => stream.Read(buffer, buffer.Length, buffer.Length)); Assert.True(ex.GetType() == typeof(ArgumentException) || ex.GetType() == typeof(ArgumentOutOfRangeException), - "Expected: ArgumentException in net5 and earlier. ArgumentOutOfRangeException in net6 and later."); + "Expected: ArgumentException in net5 and earlier. ArgumentOutOfRangeException in net6 and later."); ex = Assert.ThrowsAny(() => stream.Read(buffer, int.MaxValue, int.MaxValue)); Assert.True(ex.GetType() == typeof(ArgumentException) || ex.GetType() == typeof(ArgumentOutOfRangeException), - "Expected: ArgumentException in net5 and earlier. ArgumentOutOfRangeException in net6 and later."); + "Expected: ArgumentException in net5 and earlier. ArgumentOutOfRangeException in net6 and later."); } // Once Reader is closed diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs index f5a9a063ac..2726f5441d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlDSEnumeratorTest/SqlDataSourceEnumeratorTest.cs @@ -10,7 +10,7 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests { -#if NET50_OR_LATER +#if NET6_0_OR_GREATER [System.Runtime.Versioning.SupportedOSPlatform("windows")] #endif public class SqlDataSourceEnumeratorTest diff --git a/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj b/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj index b8b83efb00..c751a82c39 100644 --- a/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/PerformanceTests/Microsoft.Data.SqlClient.PerformanceTests.csproj @@ -2,7 +2,7 @@ Exe PerformanceTests - net6.0;net5.0 + net6.0 false Debug;Release; $(ObjFolder)$(Configuration).$(Platform).$(AssemblyName) From 1c03b1d0a1424ac0190568f0f71091f521ca27c7 Mon Sep 17 00:00:00 2001 From: Erik Ejlskov Jensen Date: Thu, 3 Nov 2022 17:52:01 +0100 Subject: [PATCH 31/78] Add support for DateOnly and TimeOnly (SqlParameter value and GetFieldValue(Async) ) (#1813) --- .../SqlDataReader.xml | 32 +-- .../Microsoft/Data/SqlClient/SqlDataReader.cs | 10 + .../src/Microsoft/Data/SqlClient/SqlBuffer.cs | 37 ++- .../src/Microsoft/Data/SqlClient/SqlEnums.cs | 16 +- .../Microsoft/Data/SqlClient/SqlParameter.cs | 10 + .../tests/FunctionalTests/SqlParameterTest.cs | 110 ++++++++ .../ProviderAgnostic/ReaderTest/ReaderTest.cs | 111 +++++++- .../SQL/DateTimeTest/DateTimeTest.cs | 261 +++++++++++++++++- 8 files changed, 566 insertions(+), 21 deletions(-) diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml index 8a789962d3..b0ce159fbf 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlDataReader.xml @@ -327,14 +327,14 @@ ||||| |-|-|-|-| -|Boolean|Byte|Char|DateTime| -|DateTimeOffset|Decimal|Double|Float| -|Guid|Int16|Int32|Int64| -|SqlBoolean|SqlByte|SqlDateTime|SqlDecimal| -|SqlDouble|SqlGuid|SqlInt16|SqlInt32| -|SqlInt64|SqlMoney|SqlSingle|SqlString| -|Stream|String|TextReader|UDT, which can be any CLR type marked with .| -|XmlReader|||| +|Boolean|Byte|Char|DateOnly (.NET 6 or later)| +|DateTime|DateTimeOffset|Decimal|Double| +|Float|Guid|Int16|Int32| +|Int64|SqlBoolean|SqlByte|SqlDateTime| +|SqlDecimal|SqlDouble|SqlGuid|SqlInt16| +|SqlInt32|SqlInt64|SqlMoney|SqlSingle| +|SqlString|Stream|String|TextReader| +|TimeOnly (.NET 6 or later)|XmlReader||UDT, which can be any CLR type marked with .| For more information, see [SqlClient Streaming Support](/sql/connect/ado-net/sqlclient-streaming-support). @@ -369,14 +369,14 @@ ||||| |-|-|-|-| -|Boolean|Byte|Char|DateTime| -|DateTimeOffset|Decimal|Double|Float| -|Guid|Int16|Int32|Int64| -|SqlBoolean|SqlByte|SqlDateTime|SqlDecimal| -|SqlDouble|SqlGuid|SqlInt16|SqlInt32| -|SqlInt64|SqlMoney|SqlSingle|SqlString| -|Stream|String|TextReader|UDT, which can be any CLR type marked with .| -|XmlReader|||| +|Boolean|Byte|Char|DateOnly (.NET 6 or later)| +|DateTime|DateTimeOffset|Decimal|Double| +|Float|Guid|Int16|Int32| +|Int64|SqlBoolean|SqlByte|SqlDateTime| +|SqlDecimal|SqlDouble|SqlGuid|SqlInt16| +|SqlInt32|SqlInt64|SqlMoney|SqlSingle| +|SqlString|Stream|String|TextReader| +|TimeOnly (.NET 6 or later)|XmlReader||UDT, which can be any CLR type marked with .| For more information, see [SqlClient Streaming Support](/sql/connect/ado-net/sqlclient-streaming-support). diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs index cf271ea749..3ea74785f0 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -2843,6 +2843,16 @@ private T GetFieldValueFromSqlBufferInternal(SqlBuffer data, _SqlMetaData met { return (T)(object)data.DateTime; } +#if NET6_0_OR_GREATER + else if (typeof(T) == typeof(DateOnly) && dataType == typeof(DateTime) && _typeSystem > SqlConnectionString.TypeSystem.SQLServer2005 && metaData.Is2008DateTimeType) + { + return (T)(object)data.DateOnly; + } + else if (typeof(T) == typeof(TimeOnly) && dataType == typeof(TimeOnly) && _typeSystem > SqlConnectionString.TypeSystem.SQLServer2005 && metaData.Is2008DateTimeType) + { + return (T)(object)data.TimeOnly; + } +#endif else if (typeof(T) == typeof(XmlReader)) { // XmlReader only allowed on XML types diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBuffer.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBuffer.cs index 56ae335e46..686c5157ef 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBuffer.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBuffer.cs @@ -596,6 +596,37 @@ internal TimeSpan Time } } +#if NET6_0_OR_GREATER + internal TimeOnly TimeOnly + { + get + { + ThrowIfNull(); + + if (StorageType.Time == _type) + { + return new TimeOnly(_value._timeInfo._ticks); + } + + return (TimeOnly)Value; // anything else we haven't thought of goes through boxing. + } + } + + internal DateOnly DateOnly + { + get + { + ThrowIfNull(); + + if (StorageType.Date == _type) + { + return DateOnly.MinValue.AddDays(_value._int32); + } + return (DateOnly)Value; // anything else we haven't thought of goes through boxing. + } + } +#endif + internal DateTimeOffset DateTimeOffset { get @@ -1097,7 +1128,7 @@ internal Type GetTypeFromStorageType(bool isSqlType) return typeof(SqlGuid); case StorageType.SqlXml: return typeof(SqlXml); - // Date DateTime2 and DateTimeOffset have no direct Sql type to contain them + // Time Date DateTime2 and DateTimeOffset have no direct Sql type to contain them } } else @@ -1144,6 +1175,10 @@ internal Type GetTypeFromStorageType(bool isSqlType) return typeof(DateTime); case StorageType.DateTimeOffset: return typeof(DateTimeOffset); +#if NET6_0_OR_GREATER + case StorageType.Time: + return typeof(TimeOnly); +#endif } } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs index bb474a0465..efd0083a9f 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs @@ -365,6 +365,16 @@ private static MetaType GetMetaTypeFromValue(Type dataType, object value, bool i { return MetaDateTimeOffset; } +#if NET6_0_OR_GREATER + else if (dataType == typeof(DateOnly)) + { + return s_metaDate; + } + else if (dataType == typeof(TimeOnly)) + { + return MetaTime; + } +#endif else { // UDT ? @@ -630,6 +640,10 @@ internal static object GetSqlValueFromComVariant(object comVal) break; case TimeSpan: case DateTimeOffset: +#if NET6_0_OR_GREATER + case TimeOnly: + case DateOnly: +#endif sqlVal = comVal; break; default: @@ -739,7 +753,7 @@ internal static SqlDbType GetSqlDbTypeFromOleDbType(short dbType, string typeNam break; // no direct mapping, just use SqlDbType.Variant; } return sqlType; -#else +#else // OleDbTypes not supported return SqlDbType.Variant; #endif // NETFRAMEWORK diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs index c78ef7dfc7..3eb0ce5ba2 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs @@ -2252,6 +2252,16 @@ internal static object CoerceValue(object value, MetaType destinationType, out b { value = new DateTimeOffset((DateTime)value); } +#if NET6_0_OR_GREATER + else if ((currentType == typeof(DateOnly)) && (destinationType.SqlDbType == SqlDbType.Date)) + { + value = ((DateOnly)value).ToDateTime(new TimeOnly(0, 0)); + } + else if ((currentType == typeof(TimeOnly)) && (destinationType.SqlDbType == SqlDbType.Time)) + { + value = ((TimeOnly)value).ToTimeSpan(); + } +#endif else if ( TdsEnums.SQLTABLE == destinationType.TDSType && ( diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs index 2f29b1bd15..7a6abdded6 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlParameterTest.cs @@ -97,6 +97,64 @@ public void Constructor2_Value_DateTime() Assert.Equal(string.Empty, p.XmlSchemaCollectionOwningSchema); } +#if NET6_0_OR_GREATER + [Fact] + public void Constructor2_Value_DateOnly() + { + DateOnly value = new DateOnly(2004, 8, 24); + SqlParameter p = new SqlParameter("dateonly", value); + + Assert.Equal(DbType.Date, p.DbType); + Assert.Equal(ParameterDirection.Input, p.Direction); + Assert.False(p.IsNullable); + Assert.Equal(0, p.LocaleId); + Assert.Equal(0, p.Offset); + Assert.Equal("dateonly", p.ParameterName); + Assert.Equal(0, p.Precision); + Assert.Equal(0, p.Scale); + Assert.Equal(0, p.Size); + Assert.Equal(string.Empty, p.SourceColumn); + Assert.False(p.SourceColumnNullMapping); + Assert.Equal(DataRowVersion.Current, p.SourceVersion); + Assert.Equal(SqlDbType.Date, p.SqlDbType); + Assert.Equal(value, p.SqlValue); + Assert.Equal(string.Empty, p.TypeName); + Assert.Equal(string.Empty, p.UdtTypeName); + Assert.Equal(value, p.Value); + Assert.Equal(string.Empty, p.XmlSchemaCollectionDatabase); + Assert.Equal(string.Empty, p.XmlSchemaCollectionName); + Assert.Equal(string.Empty, p.XmlSchemaCollectionOwningSchema); + } + + [Fact] + public void Constructor2_Value_TimeOnly() + { + TimeOnly value = new TimeOnly(9, 7, 42, 321); + SqlParameter p = new SqlParameter("timeonly", value); + + Assert.Equal(DbType.Time, p.DbType); + Assert.Equal(ParameterDirection.Input, p.Direction); + Assert.False(p.IsNullable); + Assert.Equal(0, p.LocaleId); + Assert.Equal(0, p.Offset); + Assert.Equal("timeonly", p.ParameterName); + Assert.Equal(0, p.Precision); + Assert.Equal(0, p.Scale); + Assert.Equal(0, p.Size); + Assert.Equal(string.Empty, p.SourceColumn); + Assert.False(p.SourceColumnNullMapping); + Assert.Equal(DataRowVersion.Current, p.SourceVersion); + Assert.Equal(SqlDbType.Time, p.SqlDbType); + Assert.Equal(value, p.SqlValue); + Assert.Equal(string.Empty, p.TypeName); + Assert.Equal(string.Empty, p.UdtTypeName); + Assert.Equal(value, p.Value); + Assert.Equal(string.Empty, p.XmlSchemaCollectionDatabase); + Assert.Equal(string.Empty, p.XmlSchemaCollectionName); + Assert.Equal(string.Empty, p.XmlSchemaCollectionOwningSchema); + } +#endif + [Fact] public void Constructor2_Value_Null() { @@ -383,6 +441,58 @@ public void InferType_CharArray() Assert.Equal(value, p.Value); } +#if NET6_0_OR_GREATER + [Fact] + public void InferType_DateOnly() + { + DateOnly value; + SqlParameter param; + + value = DateOnly.FromDateTime(DateTime.Now.Date); + param = new SqlParameter(); + param.Value = value; + Assert.Equal(SqlDbType.Date, param.SqlDbType); + Assert.Equal(DbType.Date, param.DbType); + + value = DateOnly.FromDateTime(DateTime.Now.Date); + param = new SqlParameter(); + param.Value = value; + Assert.Equal(SqlDbType.Date, param.SqlDbType); + Assert.Equal(DbType.Date, param.DbType); + + value = DateOnly.FromDateTime(new DateTime(1973, 8, 13)); + param = new SqlParameter(); + param.Value = value; + Assert.Equal(SqlDbType.Date, param.SqlDbType); + Assert.Equal(DbType.Date, param.DbType); + } + + [Fact] + public void InferType_TimeOnly() + { + TimeOnly value; + SqlParameter param; + + value = TimeOnly.FromDateTime(DateTime.Now); + param = new SqlParameter(); + param.Value = value; + Assert.Equal(SqlDbType.Time, param.SqlDbType); + Assert.Equal(DbType.Time, param.DbType); + + value = TimeOnly.FromDateTime(DateTime.Now); + param = new SqlParameter(); + param.Value = value; + Assert.Equal(SqlDbType.Time, param.SqlDbType); + Assert.Equal(DbType.Time, param.DbType); + + value = TimeOnly.FromDateTime(new DateTime(2022, 10, 22, 15, 27, 38)); + param = new SqlParameter(); + param.Value = value; + Assert.Equal(SqlDbType.Time, param.SqlDbType); + Assert.Equal(DbType.Time, param.DbType); + } +#endif + [Fact] public void InferType_DateTime() { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs index 697e57cb01..5d09be77f4 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/ProviderAgnostic/ReaderTest/ReaderTest.cs @@ -6,6 +6,7 @@ using System.Data.Common; using System.IO; using System.Text; +using System.Threading.Tasks; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -286,7 +287,7 @@ public static void SqlDataReader_SqlBuffer_GetFieldValue() con.ConnectionString = DataTestUtility.TCPConnectionString; con.Open(); string sqlQueryOne = $"CREATE TABLE {tableName} ([CustomerId] [int],[FirstName] [nvarchar](50),[BoolCol] [BIT],[ShortCol] [SMALLINT],[ByteCol] [TINYINT],[LongCol] [BIGINT]);"; - string sqlQueryTwo = $"ALTER TABLE {tableName} ADD [DoubleCol] [FLOAT],[SingleCol] [REAL],[GUIDCol] [uniqueidentifier],[DateTimeCol] [DateTime],[DecimalCol] [SmallMoney],[DateTimeOffsetCol] [DateTimeOffset];"; + string sqlQueryTwo = $"ALTER TABLE {tableName} ADD [DoubleCol] [FLOAT],[SingleCol] [REAL],[GUIDCol] [uniqueidentifier],[DateTimeCol] [DateTime],[DecimalCol] [SmallMoney],[DateTimeOffsetCol] [DateTimeOffset], [DateCol] [Date], [TimeCol] [Time];"; try { @@ -309,7 +310,7 @@ public static void SqlDataReader_SqlBuffer_GetFieldValue() { sqlCommand.CommandText = $"INSERT INTO {tableName} " + "VALUES (@CustomerId,@FirstName,@BoolCol,@ShortCol,@ByteCol,@LongCol,@DoubleCol,@SingleCol" - + ",@GUIDCol,@DateTimeCol,@DecimalCol,@DateTimeOffsetCol)"; + + ",@GUIDCol,@DateTimeCol,@DecimalCol,@DateTimeOffsetCol,@DateCol,@TimeCol)"; sqlCommand.Parameters.AddWithValue(@"CustomerId", 1); sqlCommand.Parameters.AddWithValue(@"FirstName", "Microsoft"); sqlCommand.Parameters.AddWithValue(@"BoolCol", true); @@ -322,6 +323,8 @@ public static void SqlDataReader_SqlBuffer_GetFieldValue() sqlCommand.Parameters.AddWithValue(@"DateTimeCol", dateTime); sqlCommand.Parameters.AddWithValue(@"DecimalCol", 280); sqlCommand.Parameters.AddWithValue(@"DateTimeOffsetCol", dtoffset); + sqlCommand.Parameters.AddWithValue(@"DateCol", new DateTime(2022, 10, 23)); + sqlCommand.Parameters.AddWithValue(@"TimeCol", new TimeSpan(0, 22, 7, 44)); sqlCommand.ExecuteNonQuery(); } using (SqlCommand sqlCommand = new SqlCommand("", con as SqlConnection)) @@ -343,6 +346,12 @@ public static void SqlDataReader_SqlBuffer_GetFieldValue() Assert.Equal(dateTime.ToString("dd/MM/yyyy HH:mm:ss.fff"), reader.GetFieldValue(9).ToString("dd/MM/yyyy HH:mm:ss.fff")); Assert.Equal(280, reader.GetFieldValue(10)); Assert.Equal(dtoffset, reader.GetFieldValue(11)); + Assert.Equal(new DateTime(2022, 10, 23), reader.GetFieldValue(12)); + Assert.Equal(new TimeSpan(0, 22, 7, 44), reader.GetFieldValue(13)); +#if NET6_0_OR_GREATER + Assert.Equal(new DateOnly(2022, 10, 23), reader.GetFieldValue(12)); + Assert.Equal(new TimeOnly(22, 7, 44), reader.GetFieldValue(13)); +#endif } } } @@ -357,5 +366,103 @@ public static void SqlDataReader_SqlBuffer_GetFieldValue() } } } + +#if NET6_0_OR_GREATER + /// + /// Covers GetFieldValue for SqlBuffer class + /// + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] + public static async Task SqlDataReader_SqlBuffer_GetFieldValue_Async() + { + string tableName = DataTestUtility.GetUniqueNameForSqlServer("SqlBuffer_GetFieldValue_Async"); + DateTimeOffset dtoffset = DateTimeOffset.Now; + DateTime dt = DateTime.Now; + //Exclude the millisecond because of rounding at some points by SQL Server. + DateTime dateTime = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second); + //Arrange + DbProviderFactory provider = SqlClientFactory.Instance; + + using DbConnection con = provider.CreateConnection(); + con.ConnectionString = DataTestUtility.TCPConnectionString; + con.Open(); + string sqlQueryOne = $"CREATE TABLE {tableName} ([CustomerId] [int],[FirstName] [nvarchar](50),[BoolCol] [BIT],[ShortCol] [SMALLINT],[ByteCol] [TINYINT],[LongCol] [BIGINT]);"; + string sqlQueryTwo = $"ALTER TABLE {tableName} ADD [DoubleCol] [FLOAT],[SingleCol] [REAL],[GUIDCol] [uniqueidentifier],[DateTimeCol] [DateTime],[DecimalCol] [SmallMoney],[DateTimeOffsetCol] [DateTimeOffset], [DateCol] [Date], [TimeCol] [Time];"; + + try + { + using (DbCommand command = provider.CreateCommand()) + { + command.Connection = con; + command.CommandText = sqlQueryOne; + await command.ExecuteNonQueryAsync(); + } + using (DbCommand command = provider.CreateCommand()) + { + command.Connection = con; + command.CommandText = sqlQueryTwo; + await command.ExecuteNonQueryAsync(); + } + + System.Data.SqlTypes.SqlGuid sqlguid = new System.Data.SqlTypes.SqlGuid(Guid.NewGuid()); + + using (SqlCommand sqlCommand = new SqlCommand("", con as SqlConnection)) + { + sqlCommand.CommandText = $"INSERT INTO {tableName} " + + "VALUES (@CustomerId,@FirstName,@BoolCol,@ShortCol,@ByteCol,@LongCol,@DoubleCol,@SingleCol" + + ",@GUIDCol,@DateTimeCol,@DecimalCol,@DateTimeOffsetCol,@DateCol,@TimeCol)"; + sqlCommand.Parameters.AddWithValue(@"CustomerId", 1); + sqlCommand.Parameters.AddWithValue(@"FirstName", "Microsoft"); + sqlCommand.Parameters.AddWithValue(@"BoolCol", true); + sqlCommand.Parameters.AddWithValue(@"ShortCol", 3274); + sqlCommand.Parameters.AddWithValue(@"ByteCol", 253); + sqlCommand.Parameters.AddWithValue(@"LongCol", 922222222222); + sqlCommand.Parameters.AddWithValue(@"DoubleCol", 10.7); + sqlCommand.Parameters.AddWithValue(@"SingleCol", 123.546f); + sqlCommand.Parameters.AddWithValue(@"GUIDCol", sqlguid); + sqlCommand.Parameters.AddWithValue(@"DateTimeCol", dateTime); + sqlCommand.Parameters.AddWithValue(@"DecimalCol", 280); + sqlCommand.Parameters.AddWithValue(@"DateTimeOffsetCol", dtoffset); + sqlCommand.Parameters.AddWithValue(@"DateCol", new DateOnly(2022, 10, 23)); + sqlCommand.Parameters.AddWithValue(@"TimeCol", new TimeOnly(22, 7, 44)); + await sqlCommand.ExecuteNonQueryAsync(); + } + using (SqlCommand sqlCommand = new SqlCommand("", con as SqlConnection)) + { + sqlCommand.CommandText = "select top 1 * from " + tableName; + using (DbDataReader reader = await sqlCommand.ExecuteReaderAsync()) + { + Assert.True(reader.Read()); + Assert.Equal(1, await reader.GetFieldValueAsync(0)); + Assert.Equal("Microsoft", await reader.GetFieldValueAsync(1)); + Assert.True(await reader.GetFieldValueAsync(2)); + Assert.Equal(3274, await reader.GetFieldValueAsync(3)); + Assert.Equal(253, await reader.GetFieldValueAsync(4)); + Assert.Equal(922222222222, await reader.GetFieldValueAsync(5)); + Assert.Equal(10.7, await reader.GetFieldValueAsync(6)); + Assert.Equal(123.546f, await reader.GetFieldValueAsync(7)); + Assert.Equal(sqlguid, await reader.GetFieldValueAsync(8)); + Assert.Equal(sqlguid.Value, (await reader.GetFieldValueAsync(8)).Value); + Assert.Equal(dateTime.ToString("dd/MM/yyyy HH:mm:ss.fff"), (await reader.GetFieldValueAsync(9)).ToString("dd/MM/yyyy HH:mm:ss.fff")); + Assert.Equal(280, await reader.GetFieldValueAsync(10)); + Assert.Equal(dtoffset, await reader.GetFieldValueAsync(11)); + Assert.Equal(new DateTime(2022, 10, 23), await reader.GetFieldValueAsync(12)); + Assert.Equal(new TimeSpan(0, 22, 7, 44), await reader.GetFieldValueAsync(13)); + Assert.Equal(new DateOnly(2022, 10, 23), await reader.GetFieldValueAsync(12)); + Assert.Equal(new TimeOnly(22, 7, 44), await reader.GetFieldValueAsync(13)); + } + } + } + finally + { + //cleanup + using (DbCommand cmd = provider.CreateCommand()) + { + cmd.Connection = con; + cmd.CommandText = "drop table " + tableName; + await cmd.ExecuteNonQueryAsync(); + } + } + } +#endif } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DateTimeTest/DateTimeTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DateTimeTest/DateTimeTest.cs index f89017c811..f5e58ab015 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DateTimeTest/DateTimeTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DateTimeTest/DateTimeTest.cs @@ -188,7 +188,7 @@ public static void ReaderParameterTest() Assert.True(p0.Value.Equals((new SqlDateTime(1753, 1, 1, 0, 0, 0)).Value), "FAILED: SqlParameter p0 contained incorrect value"); Assert.True(p1.Value.Equals(new DateTime(1753, 1, 1, 0, 0, 0)), "FAILED: SqlParameter p1 contained incorrect value"); Assert.True(p2.Value.Equals(new TimeSpan(0, 20, 12, 13, 360)), "FAILED: SqlParameter p2 contained incorrect value"); - Assert.True(p2.Scale.Equals(7), "FAILED: SqlParameter p0 contained incorrect scale"); + Assert.True(p2.Scale.Equals(7), "FAILED: SqlParameter p2 contained incorrect scale"); Assert.True(p3.Value.Equals(new DateTime(2000, 12, 31, 23, 59, 59, 997)), "FAILED: SqlParameter p3 contained incorrect value"); Assert.True(p3.Scale.Equals(7), "FAILED: SqlParameter p3 contained incorrect scale"); Assert.True(p4.Value.Equals(new DateTimeOffset(9999, 12, 31, 23, 59, 59, 997, TimeSpan.Zero)), "FAILED: SqlParameter p4 contained incorrect value"); @@ -212,6 +212,10 @@ public static void ReaderParameterTest() Assert.True(IsValidParam(SqlDbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); Assert.False(IsValidParam(SqlDbType.Date, "c1", new TimeSpan(), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); Assert.True(IsValidParam(SqlDbType.Date, "c1", "1753-1-1", conn, tableName), "FAILED: Invalid param for Date SqlDbType"); +#if NET6_0_OR_GREATER + Assert.True(IsValidParam(SqlDbType.Date, "c1", new DateOnly(1753, 1, 1), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + Assert.False(IsValidParam(SqlDbType.Date, "c1", new TimeOnly(), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); +#endif // Time Assert.False(IsValidParam(SqlDbType.Time, "c2", new DateTimeOffset(1753, 1, 1, 0, 0, 0, TimeSpan.Zero), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); @@ -221,6 +225,10 @@ public static void ReaderParameterTest() Assert.False(IsValidParam(SqlDbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); Assert.True(IsValidParam(SqlDbType.Time, "c2", TimeSpan.Parse("20:12:13.36"), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); Assert.True(IsValidParam(SqlDbType.Time, "c2", "20:12:13.36", conn, tableName), "FAILED: Invalid param for Time SqlDbType"); +#if NET6_0_OR_GREATER + Assert.False(IsValidParam(SqlDbType.Time, "c2", new DateOnly(1753, 1, 1), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + Assert.True(IsValidParam(SqlDbType.Time, "c2", new TimeOnly(20, 12, 13, 360), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); +#endif // DateTime2 DateTime dt = DateTime.Parse("2000-12-31 23:59:59.997"); @@ -374,6 +382,10 @@ public static void ReaderParameterTest() Assert.True(IsValidParam(DbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Date DbType"); Assert.False(IsValidParam(DbType.Date, "c1", new TimeSpan(), conn, tableName), "FAILED: Invalid param for Date DbType"); Assert.True(IsValidParam(DbType.Date, "c1", "1753-1-1", conn, tableName), "FAILED: Invalid param for Date DbType"); +#if NET6_0_OR_GREATER + Assert.True(IsValidParam(DbType.Date, "c1", new DateOnly(1753, 1, 1), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.False(IsValidParam(DbType.Date, "c1", new TimeOnly(), conn, tableName), "FAILED: Invalid param for Date DbType"); +#endif // Time // These 7 Asserts used to be broken for before removing back-compat code for DbType.Date and DbType.Time parameters @@ -384,6 +396,10 @@ public static void ReaderParameterTest() Assert.False(IsValidParam(DbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Time DbType"); Assert.True(IsValidParam(DbType.Time, "c2", TimeSpan.Parse("20:12:13.36"), conn, tableName), "FAILED: Invalid param for Time DbType"); Assert.True(IsValidParam(DbType.Time, "c2", "20:12:13.36", conn, tableName), "FAILED: Invalid param for Time DbType"); +#if NET6_0_OR_GREATER + Assert.False(IsValidParam(DbType.Time, "c2", new DateOnly(1753, 1, 1), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.True(IsValidParam(DbType.Time, "c2", new TimeOnly(20, 12, 13, 360), conn, tableName), "FAILED: Invalid param for Time DbType"); +#endif // DateTime2 DateTime dt = DateTime.Parse("2000-12-31 23:59:59.997"); @@ -504,6 +520,249 @@ public static void ReaderParameterTest() } } +#if NET6_0_OR_GREATER + // Synapse: CREATE or ALTER PROCEDURE statement uses syntax or features that are not supported in SQL Server PDW. + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] + public static void ReaderParameterTest_DateOnly_TimeOnly() + { + string tableName = "#t_" + Guid.NewGuid().ToString().Replace('-', '_'); + string procName = "#p_" + Guid.NewGuid().ToString().Replace('-', '_'); + string procNullName = "#pn_" + Guid.NewGuid().ToString().Replace('-', '_'); + + string tempTableCreate = "CREATE TABLE " + tableName + " (ci int, c1 date, c2 time(7) )"; + string tempTableInsert1 = "INSERT INTO " + tableName + " VALUES (0, " + + "'1753-01-01', " + + "'20:12:13.36')"; + string tempTableInsert2 = "INSERT INTO " + tableName + " VALUES (@pi, @p1, @p2)"; + + string createProc = "CREATE PROCEDURE " + procName + " @p1 date OUTPUT, @p2 time(7) OUTPUT"; + createProc += " AS "; + createProc += " SET @p1 = '1753-01-01'"; + createProc += " SET @p2 = '20:12:13.36'"; + + string createProcN = "CREATE PROCEDURE " + procNullName + " @p1 date OUTPUT, @p2 time(7) OUTPUT"; + createProcN += " AS "; + createProcN += " SET @p1 = NULL"; + createProcN += " SET @p2 = NULL"; + + using (SqlConnection conn = new SqlConnection(DataTestUtility.TCPConnectionString)) + { + try + { + // ReaderParameterTest Setup + conn.Open(); + using (SqlCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = tempTableCreate; + cmd.ExecuteNonQuery(); + cmd.CommandText = tempTableInsert1; + cmd.ExecuteNonQuery(); + + #region parameter + // Parameter Tests + // Test 1 + using (SqlCommand cmd2 = conn.CreateCommand()) + { + cmd2.CommandText = tempTableInsert2; + SqlParameter pi = cmd2.Parameters.Add("@pi", SqlDbType.Int); + SqlParameter p1 = cmd2.Parameters.Add("@p1", SqlDbType.Date); + SqlParameter p2 = cmd2.Parameters.Add("@p2", SqlDbType.Time); + pi.Value = DBNull.Value; + p1.Value = DBNull.Value; + p2.Value = DBNull.Value; + + cmd2.ExecuteNonQuery(); + pi.Value = 1; + p1.Value = new DateOnly(2000, 12, 31); + p2.Value = new TimeOnly(23, 59, 59); + cmd2.ExecuteNonQuery(); + + // Test 2 + cmd2.CommandText = "SELECT COUNT(*) FROM " + tableName + " WHERE @pi = ci AND @p1 = c1 AND @p2 = c2"; + pi.Value = 0; + p1.Value = new DateOnly(1753, 1, 1); + p2.Value = new TimeOnly(20, 12, 13, 360); + object scalarResult = cmd2.ExecuteScalar(); + Assert.True(scalarResult.Equals(1), string.Format("FAILED: Execute scalar returned unexpected result. Expected: {0}. Actual: {1}.", 1, scalarResult)); + + cmd2.Parameters.Clear(); + pi = cmd2.Parameters.Add("@pi", SqlDbType.Int); + p1 = cmd2.Parameters.Add("@p1", SqlDbType.Date); + p2 = cmd2.Parameters.Add("@p2", SqlDbType.Time); + pi.SqlValue = new SqlInt32(0); + p1.SqlValue = new DateOnly(1753, 1, 1); + p2.SqlValue = new TimeOnly(20, 12, 13, 360); + p2.Scale = 3; + scalarResult = cmd2.ExecuteScalar(); + Assert.True(scalarResult.Equals(1), string.Format("FAILED: ExecutScalar returned unexpected result. Expected: {0}. Actual: {1}.", 1, scalarResult)); + + // Test 3 + + cmd.CommandText = createProc; + cmd.ExecuteNonQuery(); + cmd.CommandText = createProcN; + cmd.ExecuteNonQuery(); + using (SqlCommand cmd3 = conn.CreateCommand()) + { + cmd3.CommandType = CommandType.StoredProcedure; + cmd3.CommandText = procName; + p1 = cmd3.Parameters.Add("@p1", SqlDbType.Date); + p2 = cmd3.Parameters.Add("@p2", SqlDbType.Time); + p1.Direction = ParameterDirection.Output; + p2.Direction = ParameterDirection.Output; + p2.Scale = 7; + cmd3.ExecuteNonQuery(); + + Assert.True(p1.Value.Equals(new DateTime(1753, 1, 1)), "FAILED: SqlParameter p1 contained incorrect value"); + Assert.True(p2.Value.Equals(new TimeSpan(0, 20, 12, 13, 360)), "FAILED: SqlParameter p2 contained incorrect value"); + Assert.True(p2.Scale.Equals(7), "FAILED: SqlParameter p0 contained incorrect scale"); + + // Test 4 + cmd3.CommandText = procNullName; + cmd3.ExecuteNonQuery(); + } + Assert.True(p1.Value.Equals(DBNull.Value), "FAILED: SqlParameter p1 expected to be NULL"); + Assert.True(p2.Value.Equals(DBNull.Value), "FAILED: SqlParameter p2 expected to be NULL"); + + // Date + Assert.False(IsValidParam(SqlDbType.Date, "c1", new DateTimeOffset(1753, 1, 1, 0, 0, 0, TimeSpan.Zero), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + Assert.False(IsValidParam(SqlDbType.Date, "c1", new SqlDateTime(1753, 1, 1, 0, 0, 0), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + Assert.True(IsValidParam(SqlDbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + Assert.True(IsValidParam(SqlDbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Utc), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + Assert.True(IsValidParam(SqlDbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + Assert.False(IsValidParam(SqlDbType.Date, "c1", new TimeSpan(), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + Assert.True(IsValidParam(SqlDbType.Date, "c1", "1753-1-1", conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + Assert.True(IsValidParam(SqlDbType.Date, "c1", new DateOnly(1753, 1, 1), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + Assert.False(IsValidParam(SqlDbType.Date, "c1", new TimeOnly(), conn, tableName), "FAILED: Invalid param for Date SqlDbType"); + + // Time + Assert.False(IsValidParam(SqlDbType.Time, "c2", new DateTimeOffset(1753, 1, 1, 0, 0, 0, TimeSpan.Zero), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + Assert.False(IsValidParam(SqlDbType.Time, "c2", new SqlDateTime(1753, 1, 1, 0, 0, 0), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + Assert.False(IsValidParam(SqlDbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + Assert.False(IsValidParam(SqlDbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Utc), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + Assert.False(IsValidParam(SqlDbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + Assert.True(IsValidParam(SqlDbType.Time, "c2", TimeSpan.Parse("20:12:13.36"), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + Assert.True(IsValidParam(SqlDbType.Time, "c2", "20:12:13.36", conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + Assert.False(IsValidParam(SqlDbType.Time, "c2", new DateOnly(1753, 1, 1), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + Assert.True(IsValidParam(SqlDbType.Time, "c2", new TimeOnly(20, 12, 13, 360), conn, tableName), "FAILED: Invalid param for Time SqlDbType"); + } + + // Do the same thing as above except using DbType now + using (DbCommand cmd3 = conn.CreateCommand()) + { + cmd3.CommandText = tempTableInsert2; + DbParameter pi = cmd3.CreateParameter(); + pi.DbType = DbType.Int32; + pi.ParameterName = "@pi"; + DbParameter p1 = cmd3.CreateParameter(); + p1.DbType = DbType.Date; + p1.ParameterName = "@p1"; + DbParameter p2 = cmd3.CreateParameter(); + p2.DbType = DbType.Time; + p2.ParameterName = "@p2"; + pi.Value = DBNull.Value; + p1.Value = DBNull.Value; + p2.Value = DBNull.Value; + + cmd3.Parameters.Add(pi); + cmd3.Parameters.Add(p1); + cmd3.Parameters.Add(p2); + cmd3.ExecuteNonQuery(); + pi.Value = 1; + p1.Value = new DateOnly(2000, 12, 31); + p2.Value = new TimeOnly(23, 59, 59); + + // This used to be broken for p2/TimeSpan before removing back-compat code for DbType.Date and DbType.Time parameters + cmd3.ExecuteNonQuery(); + + // Test 2 + cmd3.CommandText = "SELECT COUNT(*) FROM " + tableName + " WHERE @pi = ci AND @p1 = c1 AND @p2 = c2"; + pi.Value = 0; + p1.Value = new DateOnly(1753, 1, 1); + p2.Value = new TimeOnly(20, 12, 13, 360); + cmd3.Parameters.Clear(); + cmd3.Parameters.Add(pi); + cmd3.Parameters.Add(p1); + cmd3.Parameters.Add(p2); + + // This used to be broken for p2/TimeSpan before removing back-compat code for DbType.Date and DbType.Time parameters + object scalarResult = cmd3.ExecuteScalar(); + Assert.True(scalarResult.Equals(1), string.Format("FAILED: Execute scalar returned unexpected result. Expected: {0}. Actual: {1}.", 1, scalarResult)); + + // Test 3 + + using (SqlCommand cmd4 = conn.CreateCommand()) + { + cmd4.CommandType = CommandType.StoredProcedure; + cmd4.CommandText = procName; + p1 = cmd3.CreateParameter(); + p1.DbType = DbType.Date; + p1.ParameterName = "@p1"; + cmd4.Parameters.Add(p1); + p2 = cmd3.CreateParameter(); + p2.DbType = DbType.Time; + p2.ParameterName = "@p2"; + cmd4.Parameters.Add(p2); + p1.Direction = ParameterDirection.Output; + p2.Direction = ParameterDirection.Output; + p2.Scale = 7; + cmd4.ExecuteNonQuery(); + + Assert.True(p1.Value.Equals(new DateTime(1753, 1, 1, 0, 0, 0)), "FAILED: SqlParameter p1 contained incorrect value"); + // This used to be broken for p2/TimeSpan before removing back-compat code for DbType.Date and DbType.Time parameters + Assert.True(p2.Value.Equals(new TimeSpan(0, 20, 12, 13, 360)), "FAILED: SqlParameter p2 contained incorrect value"); + Assert.True(p2.Scale.Equals(7), "FAILED: SqlParameter p0 contained incorrect scale"); + + // Test 4 + cmd4.CommandText = procNullName; + cmd4.ExecuteNonQuery(); + } + Assert.True(p1.Value.Equals(DBNull.Value), "FAILED: SqlParameter p1 expected to be NULL"); + Assert.True(p2.Value.Equals(DBNull.Value), "FAILED: SqlParameter p2 expected to be NULL"); + + // Date + Assert.False(IsValidParam(DbType.Date, "c1", new DateTimeOffset(1753, 1, 1, 0, 0, 0, TimeSpan.Zero), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.False(IsValidParam(DbType.Date, "c1", new SqlDateTime(1753, 1, 1, 0, 0, 0), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.True(IsValidParam(DbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.True(IsValidParam(DbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Utc), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.True(IsValidParam(DbType.Date, "c1", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.False(IsValidParam(DbType.Date, "c1", new TimeSpan(), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.True(IsValidParam(DbType.Date, "c1", "1753-1-1", conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.True(IsValidParam(DbType.Date, "c1", new DateOnly(1753, 1, 1), conn, tableName), "FAILED: Invalid param for Date DbType"); + Assert.False(IsValidParam(DbType.Date, "c1", new TimeOnly(), conn, tableName), "FAILED: Invalid param for Date DbType"); + + // Time + // These 7 Asserts used to be broken for before removing back-compat code for DbType.Date and DbType.Time parameters + Assert.False(IsValidParam(DbType.Time, "c2", new DateTimeOffset(1753, 1, 1, 0, 0, 0, TimeSpan.Zero), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.False(IsValidParam(DbType.Time, "c2", new SqlDateTime(1753, 1, 1, 0, 0, 0), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.False(IsValidParam(DbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.False(IsValidParam(DbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Utc), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.False(IsValidParam(DbType.Time, "c2", new DateTime(1753, 1, 1, 0, 0, 0, DateTimeKind.Local), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.True(IsValidParam(DbType.Time, "c2", TimeSpan.Parse("20:12:13.36"), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.True(IsValidParam(DbType.Time, "c2", "20:12:13.36", conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.False(IsValidParam(DbType.Time, "c2", new DateOnly(1753, 1, 1), conn, tableName), "FAILED: Invalid param for Time DbType"); + Assert.True(IsValidParam(DbType.Time, "c2", new TimeOnly(20, 12, 13, 360), conn, tableName), "FAILED: Invalid param for Time DbType"); + } + #endregion + + } + } + finally + { + using (SqlCommand cmd = conn.CreateCommand()) + { + cmd.CommandText = "DROP TABLE " + tableName; + cmd.ExecuteNonQuery(); + cmd.CommandText = "DROP PROCEDURE " + procName; + cmd.ExecuteNonQuery(); + cmd.CommandText = "DROP PROCEDURE " + procNullName; + cmd.ExecuteNonQuery(); + } + } + } + } +#endif + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] public static void TypeVersionKnobTest() { From f6841855c976a7b3cc713c67bec23f9226a17671 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Thu, 3 Nov 2022 10:58:57 -0700 Subject: [PATCH 32/78] Revert excluding unsupported protocols (#1824) --- BUILDGUIDE.md | 6 ------ .../Interop/SNINativeMethodWrapper.Windows.cs | 4 ++-- .../Microsoft/Data/SqlClient/SNI/SNIHandle.cs | 10 +--------- .../Interop/SNINativeManagedWrapperX64.cs | 2 +- .../Interop/SNINativeManagedWrapperX86.cs | 2 +- .../Data/Interop/SNINativeMethodWrapper.cs | 8 ++++---- .../Data/SqlClient/LocalAppContextSwitches.cs | 19 ------------------- 7 files changed, 9 insertions(+), 42 deletions(-) diff --git a/BUILDGUIDE.md b/BUILDGUIDE.md index 1e63539c01..5a678937c8 100644 --- a/BUILDGUIDE.md +++ b/BUILDGUIDE.md @@ -321,12 +321,6 @@ Scaled decimal parameter truncation can be enabled by enabling the below AppCont `Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior` -## Enabling OS secure protocols preference - -TLS 1.3 has been excluded due to the fact that the driver lacks full support. To enable OS preferences as before, enable the following AppContext switch on application startup: - -`Switch.Microsoft.Data.SqlClient.EnableSecureProtocolsByOS` - ## Suppressing TLS security warning When connecting to a server, if a protocol lower than TLS 1.2 is negotiated, a security warning is output to the console. This warning can be suppressed on SQL connections with `Encrypt = false` by enabling the following AppContext switch on application startup: diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs index eae47ef2f6..87e6e9e19e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -287,7 +287,7 @@ internal struct SNI_Error private static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ProviderEnum provNum); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] - private static extern uint SNIInitialize([In] bool useSystemDefaultSecureProtocols, [In] IntPtr pmo); + private static extern uint SNIInitialize([In] IntPtr pmo); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] private static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); @@ -375,7 +375,7 @@ internal static uint SniGetConnectionIPString(SNIHandle pConn, ref string connIP internal static uint SNIInitialize() { - return SNIInitialize(LocalAppContextSwitches.UseSystemDefaultSecureProtocols, IntPtr.Zero); + return SNIInitialize(IntPtr.Zero); } internal static unsafe uint SNIOpenMarsSession(ConsumerInfo consumerInfo, SNIHandle parent, ref IntPtr pConn, bool fSync, SqlConnectionIPAddressPreference ipPreference, SQLDNSInfo cachedDNSInfo) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs index 7613817a23..354ce3eff5 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIHandle.cs @@ -17,15 +17,7 @@ namespace Microsoft.Data.SqlClient.SNI /// internal abstract class SNIHandle { - /// - /// Exclude TLS 1.3 in TLS-over-TDS modes (TDS 7.4 and below) - /// - protected static readonly SslProtocols s_supportedProtocols = LocalAppContextSwitches.UseSystemDefaultSecureProtocols ? SslProtocols.None : SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls - //protected readonly SslProtocols SupportedProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls -#pragma warning disable CS0618 // Type or member is obsolete - | SslProtocols.Ssl2 | SslProtocols.Ssl3 -#pragma warning restore CS0618 // Type or member is obsolete - ; + protected static readonly SslProtocols s_supportedProtocols = SslProtocols.None; #if !NETSTANDARD2_0 protected static readonly List s_tdsProtocols = new List(1) { new(TdsEnums.TDS8_Protocol) }; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs index 13e35363a8..f4970e1cda 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX64.cs @@ -89,7 +89,7 @@ internal static class SNINativeManagedWrapperX64 internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ProviderEnum provNum); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIInitialize")] - internal static extern uint SNIInitialize([In] bool useSystemDefaultSecureProtocols, [In] IntPtr pmo); + internal static extern uint SNIInitialize([In] IntPtr pmo); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs index 5517ba8c0e..6e1a0abf5f 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperX86.cs @@ -89,7 +89,7 @@ internal static class SNINativeManagedWrapperX86 internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ProviderEnum provNum); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIInitialize")] - internal static extern uint SNIInitialize([In] bool useSystemDefaultSecureProtocols, [In] IntPtr pmo); + internal static extern uint SNIInitialize([In] IntPtr pmo); [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] internal static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index 18ca7c68c2..5424fbdb11 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -593,11 +593,11 @@ private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapp SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out provNum); } - private static uint SNIInitialize([In] bool useSystemDefaultSecureProtocols, [In] IntPtr pmo) + private static uint SNIInitialize([In] IntPtr pmo) { return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIInitialize(useSystemDefaultSecureProtocols, pmo) : - SNINativeManagedWrapperX86.SNIInitialize(useSystemDefaultSecureProtocols, pmo); + SNINativeManagedWrapperX64.SNIInitialize(pmo) : + SNINativeManagedWrapperX86.SNIInitialize(pmo); } private static uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn) @@ -765,7 +765,7 @@ internal static uint SniGetConnectionIPString(SNIHandle pConn, ref string connIP internal static uint SNIInitialize() { - return SNIInitialize(LocalAppContextSwitches.UseSystemDefaultSecureProtocols, IntPtr.Zero); + return SNIInitialize(IntPtr.Zero); } internal static IntPtr SNIServerEnumOpen() => s_is64bitProcess ? diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs index 8e390b21d6..1791ad5d52 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs @@ -13,12 +13,10 @@ internal static partial class LocalAppContextSwitches private const string TypeName = nameof(LocalAppContextSwitches); internal const string MakeReadAsyncBlockingString = @"Switch.Microsoft.Data.SqlClient.MakeReadAsyncBlocking"; internal const string LegacyRowVersionNullString = @"Switch.Microsoft.Data.SqlClient.LegacyRowVersionNullBehavior"; - internal const string UseSystemDefaultSecureProtocolsString = @"Switch.Microsoft.Data.SqlClient.UseSystemDefaultSecureProtocols"; internal const string SuppressInsecureTLSWarningString = @"Switch.Microsoft.Data.SqlClient.SuppressInsecureTLSWarning"; private static bool s_makeReadAsyncBlocking; private static bool? s_LegacyRowVersionNullBehavior; - private static bool? s_UseSystemDefaultSecureProtocols; private static bool? s_SuppressInsecureTLSWarning; #if !NETFRAMEWORK @@ -78,22 +76,5 @@ public static bool LegacyRowVersionNullBehavior return s_LegacyRowVersionNullBehavior.Value; } } - - /// - /// For backward compatibility, this switch can be on to jump back on OS preferences. - /// - public static bool UseSystemDefaultSecureProtocols - { - get - { - if (s_UseSystemDefaultSecureProtocols is null) - { - bool result; - result = AppContext.TryGetSwitch(UseSystemDefaultSecureProtocolsString, out result) ? result : false; - s_UseSystemDefaultSecureProtocols = result; - } - return s_UseSystemDefaultSecureProtocols.Value; - } - } } } From 760510ce231e5ecd1a4bd1dc616fabd4c7073090 Mon Sep 17 00:00:00 2001 From: Wraith Date: Thu, 3 Nov 2022 20:54:27 +0000 Subject: [PATCH 33/78] Add | Adding disposable stack temp ref struct and use (#1818) --- .../src/Microsoft.Data.SqlClient.csproj | 3 + .../Microsoft/Data/SqlClient/SqlDataReader.cs | 136 +++++++++--------- .../netfx/src/Microsoft.Data.SqlClient.csproj | 3 + .../Microsoft/Data/SqlClient/SqlDataReader.cs | 112 ++++++++------- .../SqlClient/DisposableTemporaryOnStack.cs | 40 ++++++ 5 files changed, 174 insertions(+), 120 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/DisposableTemporaryOnStack.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 242b636730..07644b1355 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -109,6 +109,9 @@ Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs + + Microsoft\Data\SqlClient\DisposableTemporaryOnStack.cs + Microsoft\Data\SqlClient\EnclaveDelegate.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs index 3ea74785f0..8d43d72685 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -4409,6 +4409,7 @@ private void AssertReaderState(bool requireData, bool permitAsync, int? columnIn public override Task NextResultAsync(CancellationToken cancellationToken) { using (TryEventScope.Create("SqlDataReader.NextResultAsync | API | Object Id {0}", ObjectID)) + using (var registrationHolder = new DisposableTemporaryOnStack()) { TaskCompletionSource source = new TaskCompletionSource(); @@ -4418,7 +4419,6 @@ public override Task NextResultAsync(CancellationToken cancellationToken) return source.Task; } - CancellationTokenRegistration registration = default; if (cancellationToken.CanBeCanceled) { if (cancellationToken.IsCancellationRequested) @@ -4426,7 +4426,7 @@ public override Task NextResultAsync(CancellationToken cancellationToken) source.SetCanceled(); return source.Task; } - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); + registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command)); } Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); @@ -4444,7 +4444,7 @@ public override Task NextResultAsync(CancellationToken cancellationToken) return source.Task; } - return InvokeAsyncCall(new HasNextResultAsyncCallContext(this, source, registration)); + return InvokeAsyncCall(new HasNextResultAsyncCallContext(this, source, registrationHolder.Take())); } } @@ -4739,6 +4739,7 @@ out bytesRead public override Task ReadAsync(CancellationToken cancellationToken) { using (TryEventScope.Create("SqlDataReader.ReadAsync | API | Object Id {0}", ObjectID)) + using (var registrationHolder = new DisposableTemporaryOnStack()) { if (IsClosed) { @@ -4746,10 +4747,9 @@ public override Task ReadAsync(CancellationToken cancellationToken) } // Register first to catch any already expired tokens to be able to trigger cancellation event. - CancellationTokenRegistration registration = default; if (cancellationToken.CanBeCanceled) { - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); + registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command)); } // If user's token is canceled, return a canceled task @@ -4862,7 +4862,7 @@ public override Task ReadAsync(CancellationToken cancellationToken) Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ReadAsyncCallContext was not properly disposed"); - context.Set(this, source, registration); + context.Set(this, source, registrationHolder.Take()); context._hasMoreData = more; context._hasReadRowToken = rowTokenRead; @@ -5000,49 +5000,51 @@ override public Task IsDBNullAsync(int i, CancellationToken cancellationTo return Task.FromException(ex); } - // Setup and check for pending task - TaskCompletionSource source = new TaskCompletionSource(); - Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); - if (original != null) + using (var registrationHolder = new DisposableTemporaryOnStack()) { - source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); - return source.Task; - } + // Setup and check for pending task + TaskCompletionSource source = new TaskCompletionSource(); + Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); + if (original != null) + { + source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); + return source.Task; + } - // Check if cancellation due to close is requested (this needs to be done after setting _currentTask) - if (_cancelAsyncOnCloseToken.IsCancellationRequested) - { - source.SetCanceled(); - _currentTask = null; - return source.Task; - } + // Check if cancellation due to close is requested (this needs to be done after setting _currentTask) + if (_cancelAsyncOnCloseToken.IsCancellationRequested) + { + source.SetCanceled(); + _currentTask = null; + return source.Task; + } - // Setup cancellations - CancellationTokenRegistration registration = default; - if (cancellationToken.CanBeCanceled) - { - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); - } + // Setup cancellations + if (cancellationToken.CanBeCanceled) + { + registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command)); + } - IsDBNullAsyncCallContext context = null; - if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection) - { - context = Interlocked.Exchange(ref sqlInternalConnection.CachedDataReaderIsDBNullContext, null); - } - if (context is null) - { - context = new IsDBNullAsyncCallContext(); - } + IsDBNullAsyncCallContext context = null; + if (_connection?.InnerConnection is SqlInternalConnection sqlInternalConnection) + { + context = Interlocked.Exchange(ref sqlInternalConnection.CachedDataReaderIsDBNullContext, null); + } + if (context is null) + { + context = new IsDBNullAsyncCallContext(); + } - Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ISDBNullAsync context not properly disposed"); + Debug.Assert(context.Reader == null && context.Source == null && context.Disposable == default, "cached ISDBNullAsync context not properly disposed"); - context.Set(this, source, registration); - context._columnIndex = i; + context.Set(this, source, registrationHolder.Take()); + context._columnIndex = i; - // Setup async - PrepareAsyncInvocation(useSnapshot: true); + // Setup async + PrepareAsyncInvocation(useSnapshot: true); - return InvokeAsyncCall(context); + return InvokeAsyncCall(context); + } } } @@ -5147,37 +5149,39 @@ override public Task GetFieldValueAsync(int i, CancellationToken cancellat return Task.FromException(ex); } - // Setup and check for pending task - TaskCompletionSource source = new TaskCompletionSource(); - Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); - if (original != null) + using (var registrationHolder = new DisposableTemporaryOnStack()) { - source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); - return source.Task; - } + // Setup and check for pending task + TaskCompletionSource source = new TaskCompletionSource(); + Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); + if (original != null) + { + source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); + return source.Task; + } - // Check if cancellation due to close is requested (this needs to be done after setting _currentTask) - if (_cancelAsyncOnCloseToken.IsCancellationRequested) - { - source.SetCanceled(); - _currentTask = null; - return source.Task; - } + // Check if cancellation due to close is requested (this needs to be done after setting _currentTask) + if (_cancelAsyncOnCloseToken.IsCancellationRequested) + { + source.SetCanceled(); + _currentTask = null; + return source.Task; + } - // Setup cancellations - CancellationTokenRegistration registration = default; - if (cancellationToken.CanBeCanceled) - { - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); - } + // Setup cancellations + if (cancellationToken.CanBeCanceled) + { + registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command)); + } - // Setup async - PrepareAsyncInvocation(useSnapshot: true); + // Setup async + PrepareAsyncInvocation(useSnapshot: true); - GetFieldValueAsyncCallContext context = new GetFieldValueAsyncCallContext(this, source, registration); - context._columnIndex = i; + GetFieldValueAsyncCallContext context = new GetFieldValueAsyncCallContext(this, source, registrationHolder.Take()); + context._columnIndex = i; - return InvokeAsyncCall(context); + return InvokeAsyncCall(context); + } } private static Task GetFieldValueAsyncExecute(Task task, object state) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index bf6b3f3ff2..ff5b7e3c63 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -185,6 +185,9 @@ Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs + + Microsoft\Data\SqlClient\DisposableTemporaryOnStack.cs + Microsoft\Data\SqlClient\EnclaveDelegate.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs index c733b7fc8a..fd7306a8f7 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlDataReader.cs @@ -4966,6 +4966,7 @@ private void AssertReaderState(bool requireData, bool permitAsync, int? columnIn public override Task NextResultAsync(CancellationToken cancellationToken) { using (TryEventScope.Create(" {0}", ObjectID)) + using (var registrationHolder = new DisposableTemporaryOnStack()) { TaskCompletionSource source = new TaskCompletionSource(); @@ -4976,7 +4977,6 @@ public override Task NextResultAsync(CancellationToken cancellationToken) return source.Task; } - IDisposable registration = null; if (cancellationToken.CanBeCanceled) { if (cancellationToken.IsCancellationRequested) @@ -4984,7 +4984,7 @@ public override Task NextResultAsync(CancellationToken cancellationToken) source.SetCanceled(); return source.Task; } - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); + registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command)); } Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); @@ -5002,7 +5002,7 @@ public override Task NextResultAsync(CancellationToken cancellationToken) return source.Task; } - return InvokeAsyncCall(new HasNextResultAsyncCallContext(this, source, registration)); + return InvokeAsyncCall(new HasNextResultAsyncCallContext(this, source, registrationHolder.Take())); } } @@ -5303,6 +5303,7 @@ out bytesRead public override Task ReadAsync(CancellationToken cancellationToken) { using (TryEventScope.Create(" {0}", ObjectID)) + using (var registrationHolder = new DisposableTemporaryOnStack()) { if (IsClosed) { @@ -5310,10 +5311,9 @@ public override Task ReadAsync(CancellationToken cancellationToken) } // Register first to catch any already expired tokens to be able to trigger cancellation event. - IDisposable registration = null; if (cancellationToken.CanBeCanceled) { - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); + registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command)); } // If user's token is canceled, return a canceled task @@ -5419,7 +5419,7 @@ public override Task ReadAsync(CancellationToken cancellationToken) Debug.Assert(context._reader == null && context._source == null && context._disposable == null, "cached ReadAsyncCallContext was not properly disposed"); - context.Set(this, source, registration); + context.Set(this, source, registrationHolder.Take()); context._hasMoreData = more; context._hasReadRowToken = rowTokenRead; @@ -5551,41 +5551,43 @@ override public Task IsDBNullAsync(int i, CancellationToken cancellationTo return ADP.CreatedTaskWithException(ex); } - // Setup and check for pending task - TaskCompletionSource source = new TaskCompletionSource(); - Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); - if (original != null) + using (var registrationHolder = new DisposableTemporaryOnStack()) { - source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); - return source.Task; - } + // Setup and check for pending task + TaskCompletionSource source = new TaskCompletionSource(); + Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); + if (original != null) + { + source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); + return source.Task; + } - // Check if cancellation due to close is requested (this needs to be done after setting _currentTask) - if (_cancelAsyncOnCloseToken.IsCancellationRequested) - { - source.SetCanceled(); - _currentTask = null; - return source.Task; - } + // Check if cancellation due to close is requested (this needs to be done after setting _currentTask) + if (_cancelAsyncOnCloseToken.IsCancellationRequested) + { + source.SetCanceled(); + _currentTask = null; + return source.Task; + } - // Setup cancellations - IDisposable registration = null; - if (cancellationToken.CanBeCanceled) - { - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); - } + // Setup cancellations + if (cancellationToken.CanBeCanceled) + { + registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command)); + } - IsDBNullAsyncCallContext context = Interlocked.Exchange(ref _cachedIsDBNullContext, null) ?? new IsDBNullAsyncCallContext(); + IsDBNullAsyncCallContext context = Interlocked.Exchange(ref _cachedIsDBNullContext, null) ?? new IsDBNullAsyncCallContext(); - Debug.Assert(context._reader == null && context._source == null && context._disposable == null, "cached ISDBNullAsync context not properly disposed"); + Debug.Assert(context._reader == null && context._source == null && context._disposable == null, "cached ISDBNullAsync context not properly disposed"); - context.Set(this, source, registration); - context._columnIndex = i; + context.Set(this, source, registrationHolder.Take()); + context._columnIndex = i; - // Setup async - PrepareAsyncInvocation(useSnapshot: true); + // Setup async + PrepareAsyncInvocation(useSnapshot: true); - return InvokeAsyncCall(context); + return InvokeAsyncCall(context); + } } } @@ -5687,31 +5689,33 @@ override public Task GetFieldValueAsync(int i, CancellationToken cancellat return ADP.CreatedTaskWithException(ex); } - // Setup and check for pending task - TaskCompletionSource source = new TaskCompletionSource(); - Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); - if (original != null) + using (var registrationHolder = new DisposableTemporaryOnStack()) { - source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); - return source.Task; - } + // Setup and check for pending task + TaskCompletionSource source = new TaskCompletionSource(); + Task original = Interlocked.CompareExchange(ref _currentTask, source.Task, null); + if (original != null) + { + source.SetException(ADP.ExceptionWithStackTrace(ADP.AsyncOperationPending())); + return source.Task; + } - // Check if cancellation due to close is requested (this needs to be done after setting _currentTask) - if (_cancelAsyncOnCloseToken.IsCancellationRequested) - { - source.SetCanceled(); - _currentTask = null; - return source.Task; - } + // Check if cancellation due to close is requested (this needs to be done after setting _currentTask) + if (_cancelAsyncOnCloseToken.IsCancellationRequested) + { + source.SetCanceled(); + _currentTask = null; + return source.Task; + } - // Setup cancellations - IDisposable registration = null; - if (cancellationToken.CanBeCanceled) - { - registration = cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command); - } + // Setup cancellations + if (cancellationToken.CanBeCanceled) + { + registrationHolder.Set(cancellationToken.Register(SqlCommand.s_cancelIgnoreFailure, _command)); + } - return InvokeAsyncCall(new GetFieldValueAsyncCallContext(this, source, registration, i)); + return InvokeAsyncCall(new GetFieldValueAsyncCallContext(this, source, registrationHolder.Take(), i)); + } } private static Task GetFieldValueAsyncExecute(Task task, object state) diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/DisposableTemporaryOnStack.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/DisposableTemporaryOnStack.cs new file mode 100644 index 0000000000..b57b80d78f --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/DisposableTemporaryOnStack.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +using System; + +namespace Microsoft.Data.SqlClient +{ + internal ref struct DisposableTemporaryOnStack + where T : IDisposable + { + private T _value; + private bool _hasValue; + + public void Set(T value) + { + _value = value; + _hasValue = true; + } + + public T Take() + { + T value = _value; + _value = default; + _hasValue = false; + return value; + } + + public void Dispose() + { + if (_hasValue) + { + _value.Dispose(); + _value = default; + _hasValue = false; + } + } + } +} From f4568ce68da21db3fe88c0e72e1287368aaa1dc8 Mon Sep 17 00:00:00 2001 From: DavoudEshtehari <61173489+DavoudEshtehari@users.noreply.github.com> Date: Tue, 8 Nov 2022 09:30:48 -0800 Subject: [PATCH 34/78] Update native SNI version (#1831) --- tools/props/Versions.props | 4 ++-- tools/specs/Microsoft.Data.SqlClient.nuspec | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/props/Versions.props b/tools/props/Versions.props index 54547cc71b..b36aa6386a 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -20,7 +20,7 @@ - 5.1.0-preview1.22278.1 + 5.1.0-preview2.22311.2 4.3.1 4.3.0 @@ -38,7 +38,7 @@ 5.0.0 - 5.1.0-preview1.22278.1 + 5.1.0-preview2.22311.2 6.0.1 1.0.0 6.0.0 diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index c77b6f8fac..8f2ca372e1 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -28,7 +28,7 @@ When using NuGet 3.x this package requires at least version 3.4. sqlclient microsoft.data.sqlclient - + @@ -42,7 +42,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -61,7 +61,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -80,7 +80,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + From 9876329e5f8d46afeaeb6cf1c12ede623e12339e Mon Sep 17 00:00:00 2001 From: David Engel Date: Wed, 9 Nov 2022 14:24:59 -0800 Subject: [PATCH 35/78] SUPPORT doc tweak (#1830) --- SUPPORT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SUPPORT.md b/SUPPORT.md index 861787eb5b..51a3996cca 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -4,7 +4,7 @@ Microsoft.Data.SqlClient library follows the latest .NET Core support policy for [View the .NET Core Support Policy](https://dotnet.microsoft.com/platform/support/policy/dotnet-core) -[View SqlClient Support Policy on Microsoft Documentation](https://docs.microsoft.com/sql/connect/ado-net/sqlclient-driver-support-lifecycle) +View GA released version LTS/Current status and support dates here: [SqlClient Support Policy on Microsoft Documentation](https://docs.microsoft.com/sql/connect/ado-net/sqlclient-driver-support-lifecycle) ## Microsoft.Data.SqlClient release cadence From 1bb1890b6812199a13d611f5cc8b9e5bcb630feb Mon Sep 17 00:00:00 2001 From: David Engel Date: Wed, 9 Nov 2022 17:59:57 -0800 Subject: [PATCH 36/78] Experimental: Add ARM64 support when targeting .NET Framework (#1828) --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 1 + .../Interop/SNINativeManagedWrapperARM64.cs | 150 +++++ .../Data/Interop/SNINativeMethodWrapper.cs | 564 +++++++++++++----- .../netfx/src/Resources/Strings.Designer.cs | 9 + .../netfx/src/Resources/Strings.resx | 3 + .../src/Microsoft/Data/Common/AdapterUtil.cs | 5 + 6 files changed, 599 insertions(+), 133 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperARM64.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index ff5b7e3c63..88b0cd276c 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -603,6 +603,7 @@ + diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperARM64.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperARM64.cs new file mode 100644 index 0000000000..50552a3fb3 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperARM64.cs @@ -0,0 +1,150 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.InteropServices; +using System.Text; +using static Microsoft.Data.SqlClient.SNINativeMethodWrapper; + +namespace Microsoft.Data.SqlClient +{ + internal static class SNINativeManagedWrapperARM64 + { + private const string SNI = "Microsoft.Data.SqlClient.SNI.arm64.dll"; + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] + internal static extern uint SNIAddProvider(SNIHandle pConn, ProviderEnum ProvNum, [In] ref uint pInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] + internal static extern uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref SNICTAIPProviderInfo pInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIAddProviderWrapper")] + internal static extern uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref AuthProviderInfo pInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNICheckConnectionWrapper")] + internal static extern uint SNICheckConnection([In] SNIHandle pConn); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNICloseWrapper")] + internal static extern uint SNIClose(IntPtr pConn); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern void SNIGetLastError(out SNI_Error pErrorStruct); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern void SNIPacketRelease(IntPtr pPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIPacketResetWrapper")] + internal static extern void SNIPacketReset([In] SNIHandle pConn, IOType IOType, SNIPacket pPacket, ConsumerNumber ConsNum); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIQueryInfo(QTypes QType, ref uint pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIQueryInfo(QTypes QType, ref IntPtr pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIReadAsyncWrapper")] + internal static extern uint SNIReadAsync(SNIHandle pConn, ref IntPtr ppNewPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIReadSyncOverAsync(SNIHandle pConn, ref IntPtr ppNewPacket, int timeout); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIRemoveProviderWrapper")] + internal static extern uint SNIRemoveProvider(SNIHandle pConn, ProviderEnum ProvNum); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNISecInitPackage(ref uint pcbMaxToken); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISetInfoWrapper")] + internal static extern uint SNISetInfo(SNIHandle pConn, QTypes QType, [In] ref uint pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNITerminate(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIWaitForSSLHandshakeToCompleteWrapper")] + internal static extern uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint pProtocolVersion); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint GetSniMaxComposedSpnLength(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out Guid pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, [MarshalAs(UnmanagedType.Bool)] out bool pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, ref IntPtr pbQInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ushort portNum); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] + internal static extern uint SNIGetPeerAddrStrWrapper([In] SNIHandle pConn, int bufferSize, StringBuilder addrBuffer, out uint addrLen); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ProviderEnum provNum); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIInitialize")] + internal static extern uint SNIInitialize([In] IntPtr pmo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIOpenWrapper( + [In] ref Sni_Consumer_Info pConsumerInfo, + [MarshalAs(UnmanagedType.LPWStr)] string szConnect, + [In] SNIHandle pConn, + out IntPtr ppConn, + [MarshalAs(UnmanagedType.Bool)] bool fSync, + SqlConnectionIPAddressPreference ipPreference, + [In] ref SNI_DNSCache_Info pDNSCachedInfo); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr SNIPacketAllocateWrapper([In] SafeHandle pConn, IOType IOType); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIPacketGetDataWrapper([In] IntPtr packet, [In, Out] byte[] readBuffer, uint readBufferLength, out uint dataSize); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern unsafe void SNIPacketSetData(SNIPacket pPacket, [In] byte* pbBuf, uint cbBuf); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISecGenClientContextWrapper")] + internal static extern unsafe uint SNISecGenClientContextWrapper( + [In] SNIHandle pConn, + [In, Out] byte[] pIn, + uint cbIn, + [In, Out] byte[] pOut, + [In] ref uint pcbOut, + [MarshalAsAttribute(UnmanagedType.Bool)] out bool pfDone, + byte* szServerInfo, + uint cbServerInfo, + [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszUserName, + [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszPassword); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIWriteAsyncWrapper(SNIHandle pConn, [In] SNIPacket pPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] + internal static extern IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumOpenWrapper")] + internal static extern IntPtr SNIServerEnumOpen(); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumCloseWrapper")] + internal static extern void SNIServerEnumClose([In] IntPtr packet); + + [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNIServerEnumReadWrapper", CharSet = CharSet.Unicode)] + internal static extern int SNIServerEnumRead([In] IntPtr packet, + [In, Out][MarshalAs(UnmanagedType.LPArray)] char[] readBuffer, + [In] int bufferLength, + [MarshalAs(UnmanagedType.Bool)] out bool more); + } +} diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs index 5424fbdb11..c9bd6fbc21 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeMethodWrapper.cs @@ -4,23 +4,22 @@ using System; using System.Diagnostics; -using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography.X509Certificates; +using System.Text; using System.Threading; using Microsoft.Data.Common; using Microsoft.Data.SqlClient; -using System.Text; namespace Microsoft.Data.SqlClient { internal static class SNINativeMethodWrapper { private static int s_sniMaxComposedSpnLength = -1; - private static readonly bool s_is64bitProcess = Environment.Is64BitProcess; + private static readonly System.Runtime.InteropServices.Architecture s_architecture = System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture; private const int SniOpenTimeOut = -1; // infinite @@ -405,206 +404,416 @@ internal struct SNI_Error internal static uint SNIAddProvider(SNIHandle pConn, ProviderEnum ProvNum, [In] ref uint pInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIAddProvider(pConn, ProvNum, ref pInfo) : - SNINativeManagedWrapperX86.SNIAddProvider(pConn, ProvNum, ref pInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIAddProvider(pConn, ProvNum, ref pInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIAddProvider(pConn, ProvNum, ref pInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIAddProvider(pConn, ProvNum, ref pInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref SNICTAIPProviderInfo pInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo) : - SNINativeManagedWrapperX86.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNIAddProviderWrapper(SNIHandle pConn, ProviderEnum ProvNum, [In] ref AuthProviderInfo pInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo) : - SNINativeManagedWrapperX86.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIAddProviderWrapper(pConn, ProvNum, ref pInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNICheckConnection([In] SNIHandle pConn) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNICheckConnection(pConn) : - SNINativeManagedWrapperX86.SNICheckConnection(pConn); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNICheckConnection(pConn); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNICheckConnection(pConn); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNICheckConnection(pConn); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNIClose(IntPtr pConn) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIClose(pConn) : - SNINativeManagedWrapperX86.SNIClose(pConn); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIClose(pConn); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIClose(pConn); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIClose(pConn); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static void SNIGetLastError(out SNI_Error pErrorStruct) { - if (s_is64bitProcess) - { - SNINativeManagedWrapperX64.SNIGetLastError(out pErrorStruct); - } - else + switch (s_architecture) { - SNINativeManagedWrapperX86.SNIGetLastError(out pErrorStruct); + case System.Runtime.InteropServices.Architecture.Arm64: + SNINativeManagedWrapperARM64.SNIGetLastError(out pErrorStruct); + break; + case System.Runtime.InteropServices.Architecture.X64: + SNINativeManagedWrapperX64.SNIGetLastError(out pErrorStruct); + break; + case System.Runtime.InteropServices.Architecture.X86: + SNINativeManagedWrapperX86.SNIGetLastError(out pErrorStruct); + break; + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); } } internal static void SNIPacketRelease(IntPtr pPacket) { - if (s_is64bitProcess) + switch (s_architecture) { - SNINativeManagedWrapperX64.SNIPacketRelease(pPacket); - } - else - { - SNINativeManagedWrapperX86.SNIPacketRelease(pPacket); + case System.Runtime.InteropServices.Architecture.Arm64: + SNINativeManagedWrapperARM64.SNIPacketRelease(pPacket); + break; + case System.Runtime.InteropServices.Architecture.X64: + SNINativeManagedWrapperX64.SNIPacketRelease(pPacket); + break; + case System.Runtime.InteropServices.Architecture.X86: + SNINativeManagedWrapperX86.SNIPacketRelease(pPacket); + break; + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); } } internal static void SNIPacketReset([In] SNIHandle pConn, IOType IOType, SNIPacket pPacket, ConsumerNumber ConsNum) { - if (s_is64bitProcess) + switch (s_architecture) { - SNINativeManagedWrapperX64.SNIPacketReset(pConn, IOType, pPacket, ConsNum); - } - else - { - SNINativeManagedWrapperX86.SNIPacketReset(pConn, IOType, pPacket, ConsNum); + case System.Runtime.InteropServices.Architecture.Arm64: + SNINativeManagedWrapperARM64.SNIPacketReset(pConn, IOType, pPacket, ConsNum); + break; + case System.Runtime.InteropServices.Architecture.X64: + SNINativeManagedWrapperX64.SNIPacketReset(pConn, IOType, pPacket, ConsNum); + break; + case System.Runtime.InteropServices.Architecture.X86: + SNINativeManagedWrapperX86.SNIPacketReset(pConn, IOType, pPacket, ConsNum); + break; + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); } } internal static uint SNIQueryInfo(QTypes QType, ref uint pbQInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIQueryInfo(QType, ref pbQInfo) : - SNINativeManagedWrapperX86.SNIQueryInfo(QType, ref pbQInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIQueryInfo(QType, ref pbQInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIQueryInfo(QType, ref pbQInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIQueryInfo(QType, ref pbQInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNIQueryInfo(QTypes QType, ref IntPtr pbQInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIQueryInfo(QType, ref pbQInfo) : - SNINativeManagedWrapperX86.SNIQueryInfo(QType, ref pbQInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIQueryInfo(QType, ref pbQInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIQueryInfo(QType, ref pbQInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIQueryInfo(QType, ref pbQInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNIReadAsync(SNIHandle pConn, ref IntPtr ppNewPacket) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIReadAsync(pConn, ref ppNewPacket) : - SNINativeManagedWrapperX86.SNIReadAsync(pConn, ref ppNewPacket); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIReadAsync(pConn, ref ppNewPacket); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIReadAsync(pConn, ref ppNewPacket); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIReadAsync(pConn, ref ppNewPacket); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNIReadSyncOverAsync(SNIHandle pConn, ref IntPtr ppNewPacket, int timeout) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIReadSyncOverAsync(pConn, ref ppNewPacket, timeout) : - SNINativeManagedWrapperX86.SNIReadSyncOverAsync(pConn, ref ppNewPacket, timeout); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIReadSyncOverAsync(pConn, ref ppNewPacket, timeout); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIReadSyncOverAsync(pConn, ref ppNewPacket, timeout); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIReadSyncOverAsync(pConn, ref ppNewPacket, timeout); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNIRemoveProvider(SNIHandle pConn, ProviderEnum ProvNum) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIRemoveProvider(pConn, ProvNum) : - SNINativeManagedWrapperX86.SNIRemoveProvider(pConn, ProvNum); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIRemoveProvider(pConn, ProvNum); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIRemoveProvider(pConn, ProvNum); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIRemoveProvider(pConn, ProvNum); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNISecInitPackage(ref uint pcbMaxToken) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNISecInitPackage(ref pcbMaxToken) : - SNINativeManagedWrapperX86.SNISecInitPackage(ref pcbMaxToken); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNISecInitPackage(ref pcbMaxToken); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNISecInitPackage(ref pcbMaxToken); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNISecInitPackage(ref pcbMaxToken); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNISetInfo(SNIHandle pConn, QTypes QType, [In] ref uint pbQInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNISetInfo(pConn, QType, ref pbQInfo) : - SNINativeManagedWrapperX86.SNISetInfo(pConn, QType, ref pbQInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNISetInfo(pConn, QType, ref pbQInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNISetInfo(pConn, QType, ref pbQInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNISetInfo(pConn, QType, ref pbQInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNITerminate() { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNITerminate() : - SNINativeManagedWrapperX86.SNITerminate(); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNITerminate(); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNITerminate(); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNITerminate(); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint SNIWaitForSSLHandshakeToComplete([In] SNIHandle pConn, int dwMilliseconds, out uint pProtocolVersion) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out pProtocolVersion) : - SNINativeManagedWrapperX86.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out pProtocolVersion); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out pProtocolVersion); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out pProtocolVersion); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIWaitForSSLHandshakeToComplete(pConn, dwMilliseconds, out pProtocolVersion); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } internal static uint UnmanagedIsTokenRestricted([In] IntPtr token, [MarshalAs(UnmanagedType.Bool)] out bool isRestricted) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.UnmanagedIsTokenRestricted(token, out isRestricted) : - SNINativeManagedWrapperX86.UnmanagedIsTokenRestricted(token, out isRestricted); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.UnmanagedIsTokenRestricted(token, out isRestricted); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.UnmanagedIsTokenRestricted(token, out isRestricted); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.UnmanagedIsTokenRestricted(token, out isRestricted); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint GetSniMaxComposedSpnLength() { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.GetSniMaxComposedSpnLength() : - SNINativeManagedWrapperX86.GetSniMaxComposedSpnLength(); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.GetSniMaxComposedSpnLength(); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.GetSniMaxComposedSpnLength(); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.GetSniMaxComposedSpnLength(); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out Guid pbQInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out pbQInfo) : - SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, [MarshalAs(UnmanagedType.Bool)] out bool pbQInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out pbQInfo) : - SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out pbQInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, ref IntPtr pbQInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, ref pbQInfo) : - SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, ref pbQInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIGetInfoWrapper(pConn, QType, ref pbQInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, ref pbQInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, ref pbQInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ushort portNum) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out portNum) : - SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out portNum); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIGetInfoWrapper(pConn, QType, out portNum); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out portNum); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out portNum); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIGetPeerAddrStrWrapper([In] SNIHandle pConn, int bufferSize, StringBuilder addrBuffer, out uint addrLen) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIGetPeerAddrStrWrapper(pConn, bufferSize, addrBuffer, out addrLen) : - SNINativeManagedWrapperX86.SNIGetPeerAddrStrWrapper(pConn, bufferSize, addrBuffer, out addrLen); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIGetPeerAddrStrWrapper(pConn, bufferSize, addrBuffer, out addrLen); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIGetPeerAddrStrWrapper(pConn, bufferSize, addrBuffer, out addrLen); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIGetPeerAddrStrWrapper(pConn, bufferSize, addrBuffer, out addrLen); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIGetInfoWrapper([In] SNIHandle pConn, SNINativeMethodWrapper.QTypes QType, out ProviderEnum provNum) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out provNum) : - SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out provNum); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIGetInfoWrapper(pConn, QType, out provNum); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIGetInfoWrapper(pConn, QType, out provNum); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIGetInfoWrapper(pConn, QType, out provNum); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIInitialize([In] IntPtr pmo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIInitialize(pmo) : - SNINativeManagedWrapperX86.SNIInitialize(pmo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIInitialize(pmo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIInitialize(pmo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIInitialize(pmo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIOpenSyncExWrapper(ref SNI_CLIENT_CONSUMER_INFO pClientConsumerInfo, out IntPtr ppConn) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIOpenSyncExWrapper(ref pClientConsumerInfo, out ppConn) : - SNINativeManagedWrapperX86.SNIOpenSyncExWrapper(ref pClientConsumerInfo, out ppConn); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIOpenSyncExWrapper(ref pClientConsumerInfo, out ppConn); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIOpenSyncExWrapper(ref pClientConsumerInfo, out ppConn); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIOpenSyncExWrapper(ref pClientConsumerInfo, out ppConn); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIOpenWrapper( @@ -616,34 +825,64 @@ private static uint SNIOpenWrapper( SqlConnectionIPAddressPreference ipPreference, [In] ref SNI_DNSCache_Info pDNSCachedInfo) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIOpenWrapper(ref pConsumerInfo, szConnect, pConn, out ppConn, fSync, ipPreference, ref pDNSCachedInfo) : - SNINativeManagedWrapperX86.SNIOpenWrapper(ref pConsumerInfo, szConnect, pConn, out ppConn, fSync, ipPreference, ref pDNSCachedInfo); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIOpenWrapper(ref pConsumerInfo, szConnect, pConn, out ppConn, fSync, ipPreference, ref pDNSCachedInfo); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIOpenWrapper(ref pConsumerInfo, szConnect, pConn, out ppConn, fSync, ipPreference, ref pDNSCachedInfo); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIOpenWrapper(ref pConsumerInfo, szConnect, pConn, out ppConn, fSync, ipPreference, ref pDNSCachedInfo); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static IntPtr SNIPacketAllocateWrapper([In] SafeHandle pConn, IOType IOType) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIPacketAllocateWrapper(pConn, IOType) : - SNINativeManagedWrapperX86.SNIPacketAllocateWrapper(pConn, IOType); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIPacketAllocateWrapper(pConn, IOType); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIPacketAllocateWrapper(pConn, IOType); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIPacketAllocateWrapper(pConn, IOType); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIPacketGetDataWrapper([In] IntPtr packet, [In, Out] byte[] readBuffer, uint readBufferLength, out uint dataSize) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIPacketGetDataWrapper(packet, readBuffer, readBufferLength, out dataSize) : - SNINativeManagedWrapperX86.SNIPacketGetDataWrapper(packet, readBuffer, readBufferLength, out dataSize); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIPacketGetDataWrapper(packet, readBuffer, readBufferLength, out dataSize); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIPacketGetDataWrapper(packet, readBuffer, readBufferLength, out dataSize); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIPacketGetDataWrapper(packet, readBuffer, readBufferLength, out dataSize); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static unsafe void SNIPacketSetData(SNIPacket pPacket, [In] byte* pbBuf, uint cbBuf) { - if (s_is64bitProcess) - { - SNINativeManagedWrapperX64.SNIPacketSetData(pPacket, pbBuf, cbBuf); - } - else + switch (s_architecture) { - SNINativeManagedWrapperX86.SNIPacketSetData(pPacket, pbBuf, cbBuf); + case System.Runtime.InteropServices.Architecture.Arm64: + SNINativeManagedWrapperARM64.SNIPacketSetData(pPacket, pbBuf, cbBuf); + break; + case System.Runtime.InteropServices.Architecture.X64: + SNINativeManagedWrapperX64.SNIPacketSetData(pPacket, pbBuf, cbBuf); + break; + case System.Runtime.InteropServices.Architecture.X86: + SNINativeManagedWrapperX86.SNIPacketSetData(pPacket, pbBuf, cbBuf); + break; + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); } } @@ -659,30 +898,62 @@ private static unsafe uint SNISecGenClientContextWrapper( [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszUserName, [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszPassword) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNISecGenClientContextWrapper(pConn, pIn, cbIn, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword) : - SNINativeManagedWrapperX86.SNISecGenClientContextWrapper(pConn, pIn, cbIn, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNISecGenClientContextWrapper(pConn, pIn, cbIn, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNISecGenClientContextWrapper(pConn, pIn, cbIn, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNISecGenClientContextWrapper(pConn, pIn, cbIn, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIWriteAsyncWrapper(SNIHandle pConn, [In] SNIPacket pPacket) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIWriteAsyncWrapper(pConn, pPacket) : - SNINativeManagedWrapperX86.SNIWriteAsyncWrapper(pConn, pPacket); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIWriteAsyncWrapper(pConn, pPacket); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIWriteAsyncWrapper(pConn, pPacket); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIWriteAsyncWrapper(pConn, pPacket); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static uint SNIWriteSyncOverAsync(SNIHandle pConn, [In] SNIPacket pPacket) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIWriteSyncOverAsync(pConn, pPacket) : - SNINativeManagedWrapperX86.SNIWriteSyncOverAsync(pConn, pPacket); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIWriteSyncOverAsync(pConn, pPacket); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIWriteSyncOverAsync(pConn, pPacket); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIWriteSyncOverAsync(pConn, pPacket); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } private static IntPtr SNIClientCertificateFallbackWrapper(IntPtr pCallbackContext) { - return s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIClientCertificateFallbackWrapper(pCallbackContext) : - SNINativeManagedWrapperX86.SNIClientCertificateFallbackWrapper(pCallbackContext); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIClientCertificateFallbackWrapper(pCallbackContext); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIClientCertificateFallbackWrapper(pCallbackContext); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIClientCertificateFallbackWrapper(pCallbackContext); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } #endregion @@ -768,23 +1039,50 @@ internal static uint SNIInitialize() return SNIInitialize(IntPtr.Zero); } - internal static IntPtr SNIServerEnumOpen() => s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIServerEnumOpen() : - SNINativeManagedWrapperX86.SNIServerEnumOpen(); - - internal static int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readbuffer, int bufferLength, out bool more) => s_is64bitProcess ? - SNINativeManagedWrapperX64.SNIServerEnumRead(packet, readbuffer, bufferLength, out more) : - SNINativeManagedWrapperX86.SNIServerEnumRead(packet, readbuffer, bufferLength, out more); - - internal static void SNIServerEnumClose([In] IntPtr packet) + internal static IntPtr SNIServerEnumOpen() { - if (s_is64bitProcess) + switch (s_architecture) { - SNINativeManagedWrapperX64.SNIServerEnumClose(packet); + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIServerEnumOpen(); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIServerEnumOpen(); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIServerEnumOpen(); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); } - else + } + internal static int SNIServerEnumRead([In] IntPtr packet, [In, Out] char[] readbuffer, int bufferLength, out bool more) + { + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNIServerEnumRead(packet, readbuffer, bufferLength, out more); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNIServerEnumRead(packet, readbuffer, bufferLength, out more); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNIServerEnumRead(packet, readbuffer, bufferLength, out more); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } + } + + internal static void SNIServerEnumClose([In] IntPtr packet) + { + switch (s_architecture) { - SNINativeManagedWrapperX86.SNIServerEnumClose(packet); + case System.Runtime.InteropServices.Architecture.Arm64: + SNINativeManagedWrapperARM64.SNIServerEnumClose(packet); + break; + case System.Runtime.InteropServices.Architecture.X64: + SNINativeManagedWrapperX64.SNIServerEnumClose(packet); + break; + case System.Runtime.InteropServices.Architecture.X86: + SNINativeManagedWrapperX86.SNIServerEnumClose(packet); + break; + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs index fdbc830cb6..79c4c8f2eb 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.Designer.cs @@ -8649,6 +8649,15 @@ internal static string SNI_ERROR_9 { } } + /// + /// Looks up a localized string similar to The '{0}' platform is not supported when targeting .NET Framework.. + /// + internal static string SNI_PlatformNotSupportedNetFx { + get { + return ResourceManager.GetString("SNI_PlatformNotSupportedNetFx", resourceCulture); + } + } + /// /// Looks up a localized string similar to HTTP Provider. /// diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx index 66683219cc..4408ffcf78 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/netfx/src/Resources/Strings.resx @@ -4626,4 +4626,7 @@ The service principal name (SPN) of the server. + + The '{0}' platform is not supported when targeting .NET Framework. + diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs index 24f56b4b32..8f48131f8d 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs @@ -1421,6 +1421,11 @@ internal static InvalidOperationException ComputerNameEx(int lastError) return InvalidOperation(StringsHelper.GetString(Strings.ADP_ComputerNameEx, lastError)); } + // + // : SNI + // + internal static PlatformNotSupportedException SNIPlatformNotSupported(string platform) => new(StringsHelper.GetString(Strings.SNI_PlatformNotSupportedNetFx, platform)); + // global constant strings internal const float FailoverTimeoutStepForTnir = 0.125F; // Fraction of timeout to use in case of Transparent Network IP resolution. internal const int MinimumTimeoutForTnirMs = 500; // The first login attempt in Transparent network IP Resolution From e316a68734878f9929d9835df621bc50ba25b108 Mon Sep 17 00:00:00 2001 From: panoskj <37297673+panoskj@users.noreply.github.com> Date: Thu, 10 Nov 2022 04:23:38 +0200 Subject: [PATCH 37/78] Merge common code bases for TdsParserStateObject.cs (#1520) --- .../src/Microsoft.Data.SqlClient.csproj | 3 + .../src/Microsoft/Data/SqlClient/TdsParser.cs | 26 +- .../Data/SqlClient/TdsParserStateObject.cs | 1140 +--------------- .../netfx/src/Microsoft.Data.SqlClient.csproj | 3 + .../src/Microsoft/Data/SqlClient/SqlUtil.cs | 22 + .../Data/SqlClient/TdsParserStateObject.cs | 1172 ++--------------- .../Data/SqlClient/TdsParserStateObject.cs | 1060 +++++++++++++++ 7 files changed, 1238 insertions(+), 2188 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 07644b1355..a6be328a3a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -466,6 +466,9 @@ Microsoft\Data\SqlClient\TdsParameterSetter.cs + + Microsoft\Data\SqlClient\TdsParserStateObject.cs + Microsoft\Data\SqlClient\TdsParserStaticMethods.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index ae6e6995cb..d1233d164a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -259,6 +259,8 @@ internal EncryptionOptions EncryptionOptions } } + internal bool Is2005OrNewer => true; + internal bool Is2008OrNewer { get @@ -1327,7 +1329,7 @@ internal void ThrowExceptionAndWarning(TdsParserStateObject stateObj, bool calle // report exception to pending async operation // before OnConnectionClosed overrides the exception // due to connection close notification through references - var taskSource = stateObj._networkPacketTaskSource; + TaskCompletionSource taskSource = stateObj._networkPacketTaskSource; if (taskSource != null) { taskSource.TrySetException(ADP.ExceptionWithStackTrace(exception)); @@ -1337,7 +1339,7 @@ internal void ThrowExceptionAndWarning(TdsParserStateObject stateObj, bool calle if (asyncClose) { // Wait until we have the parser lock, then try to close - var connHandler = _connHandler; + SqlInternalConnectionTds connHandler = _connHandler; Action wrapCloseAction = closeAction => { Task.Factory.StartNew(() => @@ -2607,7 +2609,7 @@ private bool TryProcessEnvChange(int tokenLength, TdsParserStateObject stateObj, while (tokenLength > processedLength) { - var env = new SqlEnvChange(); + SqlEnvChange env = new SqlEnvChange(); if (!stateObj.TryReadByte(out env._type)) { return false; @@ -3370,7 +3372,7 @@ private bool TryProcessDataClassification(TdsParserStateObject stateObj, out Sen { return false; } - var labels = new List