diff --git a/.config/CredScanSuppressions.json b/.config/CredScanSuppressions.json new file mode 100644 index 0000000000..ffc7e87789 --- /dev/null +++ b/.config/CredScanSuppressions.json @@ -0,0 +1,25 @@ +{ + "tool": "Credential Scanner", + "suppressions": [ + { + "file": "src/Microsoft.Data.SqlClient/tests/Docker/DockerLinuxTest/Program.cs", + "justification": "Test projects should be skipped" + }, + { + "file": "src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/TDSServerArguments.cs", + "justification": "Test projects should be skipped" + }, + { + "file": "src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/TdsServerCertificate.pfx", + "justification": "Test projects should be skipped" + }, + { + "file": "src/docker-compose.yml", + "justification": "Docker test project should be excluded" + }, + { + "file": "doc/samples/SqlConnectionStringBuilder.cs", + "justification": "Documentation could include sample data and can be ignored" + } + ] +} diff --git a/.config/PolicheckExclusions.xml b/.config/PolicheckExclusions.xml new file mode 100644 index 0000000000..d8c47d335d --- /dev/null +++ b/.config/PolicheckExclusions.xml @@ -0,0 +1,5 @@ + + SRC/MICROSOFT.DATA.SQLCLIENT/TESTS + .YML|.MD|.SQL + NOTICE.TXT + \ No newline at end of file diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json index a9be6f5aae..c9e3a2cfb6 100644 --- a/.config/tsaoptions.json +++ b/.config/tsaoptions.json @@ -1,11 +1,14 @@ { "instanceUrl": "https://sqlclientdrivers.visualstudio.com/", - "projectName": "ADO.NET", - "areaPath": "ADO.NET", - "iterationPath": "ADO.NET", + "projectName": "ADO.Net", + "areaPath": "ADO.Net", + "iterationPath": "ADO.Net\\TSA\\SqlClient", "notificationAliases": [ "SqlClient@microsoft.com" ], "repositoryName": "SqlClient", "codebaseName": "SqlClient", "allTools": true, - "template": "MSDATA_RevolutionR" + "template": "MSDATA_RevolutionR", + "language": "csharp", + "includePathPatterns": "src/Microsoft.Data.SqlClient/*, src/Microsoft.SqlServer.Server/*, tools/*", + "excludePathPatterns": "src/Microsoft.Data.SqlClient/tests/*" } diff --git a/.gitignore b/.gitignore index daeaf68c7a..bb6f58f9bd 100644 --- a/.gitignore +++ b/.gitignore @@ -353,6 +353,9 @@ healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ +# JetBrains Rider (cross platform .NET IDE) working folder +.idea/ + # Ionide (cross platform F# VS Code tools) working folder .ionide/ diff --git a/BUILDGUIDE.md b/BUILDGUIDE.md index 4434af3f1a..09143c84cf 100644 --- a/BUILDGUIDE.md +++ b/BUILDGUIDE.md @@ -8,6 +8,8 @@ This project should be built with Visual Studio 2019+ for the best compatibility - **Visual Studio 2019** with imported components: [VS19Components](/tools/vsconfig/VS19Components.vsconfig) +- **Powershell**: To build SqlClient on Linux, powershell is needed as well. Follow the distro specific instructions at [Install Powershell on Linux](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-linux?view=powershell-7.4) + Once the environment is setup properly, execute the desired set of commands below from the _root_ folder to perform the respective operations: ## Building the driver @@ -165,7 +167,6 @@ Manual Tests require the below setup to run: |TCPConnectionString | Connection String for a TCP enabled SQL Server instance. | `Server={servername};Database={Database_Name};Trusted_Connection=True;`
OR `Data Source={servername};Initial Catalog={Database_Name};Integrated Security=True;`| |NPConnectionString | Connection String for a Named Pipes enabled SQL Server instance.| `Server=\\{servername}\pipe\sql\query;Database={Database_Name};Trusted_Connection=True;`
OR
`Data Source=np:{servername};Initial Catalog={Database_Name};Integrated Security=True;`| |TCPConnectionStringHGSVBS | (Optional) Connection String for a TCP enabled SQL Server with Host Guardian Service (HGS) attestation protocol configuration. | `Server=tcp:{servername}; Database={Database_Name}; UID={UID}; PWD={PWD}; Attestation Protocol = HGS; Enclave Attestation Url = {AttestationURL};`| - |TCPConnectionStringAASVBS | (Optional) Connection String for a TCP enabled SQL Server with a VBS Enclave and using Microsoft Azure Attestation (AAS) attestation protocol configuration. | `Server=tcp:{servername}; Database={Database_Name}; UID={UID}; PWD={PWD}; Attestation Protocol = AAS; Enclave Attestation Url = {AttestationURL};`| |TCPConnectionStringNoneVBS | (Optional) Connection String for a TCP enabled SQL Server with a VBS Enclave and using None Attestation protocol configuration. | `Server=tcp:{servername}; Database={Database_Name}; UID={UID}; PWD={PWD}; Attestation Protocol = NONE;`| |TCPConnectionStringAASSGX | (Optional) Connection String for a TCP enabled SQL Server with a SGX Enclave and using Microsoft Azure Attestation (AAS) attestation protocol configuration. | `Server=tcp:{servername}; Database={Database_Name}; UID={UID}; PWD={PWD}; Attestation Protocol = AAS; Enclave Attestation Url = {AttestationURL};`| |EnclaveEnabled | Enables tests requiring an enclave-configured server.| @@ -176,8 +177,6 @@ Manual Tests require the below setup to run: |AADSecurePrincipalSecret | (Optional) A Secret defined for a registered application which has been granted permission to the database defined in the AADPasswordConnectionString. | {Secret} | |AzureKeyVaultURL | (Optional) Azure Key Vault Identifier URL | `https://{keyvaultname}.vault.azure.net/` | |AzureKeyVaultTenantId | (Optional) The Azure Active Directory tenant (directory) Id of the service principal. | _{Tenant ID of Active Directory}_ | - |AzureKeyVaultClientId | (Optional) "Application (client) ID" of an Active Directory registered application, granted access to the Azure Key Vault specified in `AZURE_KEY_VAULT_URL`. Requires the key permissions Get, List, Import, Decrypt, Encrypt, Unwrap, Wrap, Verify, and Sign. | _{Client Application ID}_ | - |AzureKeyVaultClientSecret | (Optional) "Client Secret" of the Active Directory registered application, granted access to the Azure Key Vault specified in `AZURE_KEY_VAULT_URL` | _{Client Application Secret}_ | |SupportsIntegratedSecurity | (Optional) Whether or not the USER running tests has integrated security access to the target SQL Server.| `true` OR `false`| |LocalDbAppName | (Optional) If Local Db Testing is supported, this property configures the name of Local DB App instance available in client environment. Empty string value disables Local Db testing. | Name of Local Db App to connect to.| |LocalDbSharedInstanceName | (Optional) If LocalDB testing is supported and the instance is shared, this property configures the name of the shared instance of LocalDB to connect to. | Name of shared instance of LocalDB. | @@ -233,17 +232,15 @@ Tests can be built and run with custom "Reference Type" property that enables di - "Project" => Build and run tests with Microsoft.Data.SqlClient as Project Reference - "Package" => Build and run tests with Microsoft.Data.SqlClient as Package Reference with configured "TestMicrosoftDataSqlClientVersion" in "Versions.props" file. -- "NetStandard" => Build and run tests with Microsoft.Data.SqlClient as Project Reference via .NET Standard Library -- "NetStandardPackage" => Build and run tests with Microsoft.Data.SqlClient as Package Reference via .NET Standard Library -> ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" AND "NETSTANDARDPACKAGE" REFERENCE TYPES *************** +> ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" REFERENCE TYPE *************** > CREATE A NUGET PACKAGE WITH BELOW COMMAND AND ADD TO LOCAL FOLDER + UPDATE NUGET CONFIG FILE TO READ FROM THAT LOCATION > > ```bash > msbuild -p:configuration=Release > ``` -A non-AnyCPU platform reference can only be used with package and NetStandardPackage reference types. Otherwise, the specified platform will be replaced with AnyCPU in the build process. +A non-AnyCPU platform reference can only be used with package reference type. Otherwise, the specified platform will be replaced with AnyCPU in the build process. ### Building Tests with Reference Type @@ -254,10 +251,6 @@ msbuild -t:BuildTestsNetCore -p:ReferenceType=Project # Default setting uses Project Reference. msbuild -t:BuildTestsNetCore -p:ReferenceType=Package - -msbuild -t:BuildTestsNetCore -p:ReferenceType=NetStandard - -msbuild -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage ``` For .NET Framework, below reference types are supported: diff --git a/CHANGELOG.md b/CHANGELOG.md index d0e4d1acc3..29c1c394af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,73 @@ 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.2.0] - 2024-02-28 + +### Added + +- Added a new `AccessTokenCallBack` API to `SqlConnection`. [#1260](https://github.com/dotnet/SqlClient/pull/1260) +- Added `SqlBatch` support on .NET 6+ [#1825](https://github.com/dotnet/SqlClient/pull/1825), [#2223](https://github.com/dotnet/SqlClient/pull/2223),[#2371](https://github.com/dotnet/SqlClient/pull/2371), [#2373](https://github.com/dotnet/SqlClient/pull/2373) +- Added support of `SqlDiagnosticListener` on **.NET Standard**. [#1931](https://github.com/dotnet/SqlClient/pull/1931) +- Added new property `RowsCopied64` to `SqlBulkCopy`. [#2004](https://github.com/dotnet/SqlClient/pull/2004) +- Added support for the `SuperSocketNetLib` registry option for Encrypt on .NET on Windows. [#2047](https://github.com/dotnet/SqlClient/pull/2047) +- Added the ability to generate debugging symbols in a separate package file [#2137](https://github.com/dotnet/SqlClient/pull/2137) +- Added Workload Identity authentication support [#2159](https://github.com/dotnet/SqlClient/pull/2159), [#2264](https://github.com/dotnet/SqlClient/pull/2264) +- Added support for Big Endian systems [#2170](https://github.com/dotnet/SqlClient/pull/2170) +- Added support for Georgian collation [#2194](https://github.com/dotnet/SqlClient/pull/2194) +- Added Localization support on .NET [#2210](https://github.com/dotnet/SqlClient/pull/2110) +- Added .NET 8 support [#2230](https://github.com/dotnet/SqlClient/pull/2230) +- Added explicit version for major .NET version dependencies on System.Runtime.Caching 8.0.0, System.Configuration.ConfigurationManager 8.0.0, and System.Diagnostics. +- DiagnosticSource 8.0.0 [#2303](https://github.com/dotnet/SqlClient/pull/2303) + +### Changed + +- Improved parsing buffered characters in `TdsParser`. [#1544](https://github.com/dotnet/SqlClient/pull/1544) +- Added Microsoft.SqlServer.Types to verify support for SqlHierarchyId and Spatial for .NET Core. [#1848](https://github.com/dotnet/SqlClient/pull/1848) +- Moved to new System.Data.SqlTypes APIs on **.NET 7** and up. [#1934](https://github.com/dotnet/SqlClient/pull/1934) and [#1981](https://github.com/dotnet/SqlClient/pull/1981) +- Removed reference to Microsoft.Win32.Registry since it's shipped starting with .NET 6.0. [#1974](https://github.com/dotnet/SqlClient/pull/1974) +- Changed **[UseOneSecFloorInTimeoutCalculationDuringLogin](https://learn.microsoft.com/sql/connect/ado-net/appcontext-switches#enable-a-minimum-timeout-during-login)** App Context switch default to **true** and extended its effect to .NET and .NET Standard. [#2012](https://github.com/dotnet/SqlClient/pull/2012) +- Updated `Microsoft.Identity.Client` version from 4.47.2 to 4.53.0. [#2031](https://github.com/dotnet/SqlClient/pull/2031), [#2055](https://github.com/dotnet/SqlClient/pull/2055) +- Switched to the new .NET [NegotiateAuthentication](https://learn.microsoft.com/en-us/dotnet/api/system.net.security.negotiateauthentication?view=net-7.0) API on .NET 7.0 and above for SSPI token negotiation using Managed SNI. [#2063](https://github.com/dotnet/SqlClient/pull/2063) +- Removed `ignoreSniOpenTimeout` in open connection process on Windows. [#2067](https://github.com/dotnet/SqlClient/pull/2067) +- Enforce explicit ordinal for internal `StringComparison` operations. [#2068](https://github.com/dotnet/SqlClient/pull/2068) +- Improved error messages when validating server certificates in managed SNI (Linux/macOS) [#2060](https://github.com/dotnet/SqlClient/pull/2060) +- Improved CPU usage when `AppContext` switches are in use [#2227](https://github.com/dotnet/SqlClient/pull/2227) +- Upgraded `Azure.Identity` dependency version to [1.10.3](https://www.nuget.org/packages/Azure.Identity/1.10.3) to address [CVE-2023-36414](https://github.com/advisories/GHSA-5mfx-4wcx-rv27), [#2189](https://github.com/dotnet/SqlClient/pull/2189) +- Changed Microsoft.IdentityModel.JsonWebTokens and Microsoft.IdentityModel.Protocols.OpenIdConnect version 6.24.0 to 6.35.0 [#2290](https://github.com/dotnet/SqlClient/pull/2290) to address [CVE-2024-21319](https://www.cve.org/CVERecord?id=CVE-2024-21319) +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET/.NET Standard dependency) version to `v5.2.0`. [#2363](https://github.com/dotnet/SqlClient/pull/2363), which includes removing dead code and addressing static analysis warnings +- Code health improvements: [#1198](https://github.com/dotnet/SqlClient/pull/1198), [#1829](https://github.com/dotnet/SqlClient/pull/1829), [#1943](https://github.com/dotnet/SqlClient/pull/1943), [#1949](https://github.com/dotnet/SqlClient/pull/1949), [#1959](https://github.com/dotnet/SqlClient/pull/1959), [#1985](https://github.com/dotnet/SqlClient/pull/1985), [#2071](https://github.com/dotnet/SqlClient/pull/2071), [#2073](https://github.com/dotnet/SqlClient/pull/2073), [#2088](https://github.com/dotnet/SqlClient/pull/2088), [#2091](https://github.com/dotnet/SqlClient/pull/2091), [#2098](https://github.com/dotnet/SqlClient/pull/2098), [#2121](https://github.com/dotnet/SqlClient/pull/2121), [#2122](https://github.com/dotnet/SqlClient/pull/2122), [#2132](https://github.com/dotnet/SqlClient/pull/2132), [#2136](https://github.com/dotnet/SqlClient/pull/2136), [#2144](https://github.com/dotnet/SqlClient/pull/2144), [#2147](https://github.com/dotnet/SqlClient/pull/2147), [#2157](https://github.com/dotnet/SqlClient/pull/2157), [#2164](https://github.com/dotnet/SqlClient/pull/2164), [#2166](https://github.com/dotnet/SqlClient/pull/2166), [#2168](https://github.com/dotnet/SqlClient/pull/2168), [#2186](https://github.com/dotnet/SqlClient/pull/2186), [#2254](https://github.com/dotnet/SqlClient/pull/2254), [#2288](https://github.com/dotnet/SqlClient/pull/2288), [#2305](https://github.com/dotnet/SqlClient/pull/2305), [#2317](https://github.com/dotnet/SqlClient/pull/2317) + +### Fixed + +- Fixed Always Encrypted secure enclave retry logic for async queries. [#1988](https://github.com/dotnet/SqlClient/pull/1988) +- Fixed activity correlator to continue use of same GUID for connection activity. [#1997](https://github.com/dotnet/SqlClient/pull/1997) +- Fixed behavior when error class is greater than 20 on connection retry. [#1953](https://github.com/dotnet/SqlClient/pull/1953) +- Fixed error message when symmetric key decryption failed using Always Encrypted. [#1948](https://github.com/dotnet/SqlClient/pull/1948) +- Fixed TransactionScope connection issue when Enlist is enable, Pooling is disabled and network connection type is Redirect. [#1960](https://github.com/dotnet/SqlClient/pull/1960) +- Fixed TDS RPC error on large queries in SqlCommand.ExecuteReaderAsync. [#1936](https://github.com/dotnet/SqlClient/pull/1936) +- Fixed throttling of token requests by calling AcquireTokenSilent. [#1925](https://github.com/dotnet/SqlClient/pull/1925) +- Fixed Linux code coverage result in Build proj. [#1950](https://github.com/dotnet/SqlClient/pull/1950) +- Fixed NullReferenceException in GetBytesAsync. [#1906](https://github.com/dotnet/SqlClient/pull/1906) +- Fixed Transient fault handling issue with OpenAsync. [#1983](https://github.com/dotnet/SqlClient/pull/1983) +- Fixed invariant mode checks. [#1917](https://github.com/dotnet/SqlClient/pull/1917) +- Fixed GC behavior in TdsParser by adding array rental capability in TryReadPlpUnicodeChars. [#1866](https://github.com/dotnet/SqlClient/pull/1866) +- Fixed socket synchronization issue during connect in managed SNI. [#1029](https://github.com/dotnet/SqlClient/pull/1029) +- Fixed issue with `SqlConnectionStringBuilder` property indexer not supporting non-string values. [#2018](https://github.com/dotnet/SqlClient/pull/2018) +- Fixed `SqlDataAdapter.Fill` and configurable retry logic issue on .NET Framework. [#2084](https://github.com/dotnet/SqlClient/pull/2084) +- Fixed `SqlConnectionEncryptOption` type conversion by introducing the `SqlConnectionEncryptOptionConverter` attribute when using **appsettings.json** files. [#2057](https://github.com/dotnet/SqlClient/pull/2057) +- Fixed th-TH culture info issue on Managed SNI. [#2066](https://github.com/dotnet/SqlClient/pull/2066) +- Fixed an issue when using the Authentication option, but not encrypting on .NET Framework where the server certificate was being incorrectly validated [#2224](https://github.com/dotnet/SqlClient/pull/2224) +- Fixed a deadlock problem for distributed transactions when on .NET [#2161](https://github.com/dotnet/SqlClient/pull/2161) +- Fixed an issue with connecting to named instances on named pipes in managed SNI (Linux/macOS) [#2142](https://github.com/dotnet/SqlClient/pull/2142) +- Fixed LocalDb connection issue with an invalid source when using managed SNI [#2129](https://github.com/dotnet/SqlClient/pull/2129) +- Fixed an `AccessViolationException` when using a SQL Express user instance [#2101](https://github.com/dotnet/SqlClient/pull/2101) +- Fixed a metadata query issue when connecting to Azure SQL Edge [#2099](https://github.com/dotnet/SqlClient/pull/2099) +- Fixed file version information for .NET and .NET Standard binaries [#2093](https://github.com/dotnet/SqlClient/pull/2093) +- Fixed the SPN sent for a named instance when using Kerberos authentication on Linux/macOS [#2240](https://github.com/dotnet/SqlClient/pull/2240) +- Fixed connection to unsubscribe from transaction completion events before returning it to the connection pool [#2301](https://github.com/dotnet/SqlClient/pull/2301) +- Fixed InvalidCastException when reading an Always Encrypted date or time column [#2275](https://github.com/dotnet/SqlClient/pull/2275) +- Fixed token caching to prevent expired access tokens from being reused in a connection pool [#2273](https://github.com/dotnet/SqlClient/pull/2273) + ## [Preview Release 5.2.0-preview5.24024.3] - 2024-01-24 This update brings the below changes over the previous release: diff --git a/NuGet.config b/NuGet.config new file mode 100644 index 0000000000..3233e60161 --- /dev/null +++ b/NuGet.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/RunPackageReferenceTests.cmd b/RunPackageReferenceTests.cmd index 037d5aa84c..fa503f905e 100644 --- a/RunPackageReferenceTests.cmd +++ b/RunPackageReferenceTests.cmd @@ -1,10 +1,10 @@ @echo off -:: .NET CORE + .NET STANDARD LIBRARY TEST CASES +:: .NET CORE TEST CASES echo Building .NET Core Tests call :pauseOnError msbuild -t:Clean -:: ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" AND "NETSTANDARDPACKAGE" REFERENCE TYPES *************** +:: ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" REFERENCE TYPE *************** :: THESE ARE NOT STAND ALONE TEST COMMANDS AND NEED A DEVELOPER'S SPECIAL ATTENTION TO WORK. ATTEMPTING TO RUN THE ENTIRE SET OF COMMANDS AS-IS IS LIKELY TO FAIL! :: CREATE A NUGET PACKAGE WITH BELOW COMMAND AND ADD TO LOCAL FOLDER + UPDATE NUGET CONFIG FILE TO READ FROM THAT LOCATION @@ -70,74 +70,6 @@ call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetFx -p:Targ call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj" -p:Platform="Win32" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" -p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-net48-functional-Win32.xml call :pauseOnError dotnet test "src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj" -p:Platform="Win32" -p:Configuration="Release" -p:TestTargetOS="Windowsnetfx" -p:TargetNetFxVersion=net48 --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" -p:ReferenceType=Package -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\package-net48-manual-Win32.xml -:: REFERENCE TYPE "NETSTANDARDPACKAGE" - -:: .NET - REFERENCE TYPE "NETSTANDARDPACKAGE" - -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-net6.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=net6.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net6.0-manual-anycpu.xml - -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:TargetNetCoreVersion=net8.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=net8.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net8.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=net8.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net8.0-manual-anycpu.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-net6.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=net6.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net6.0-manual-x64.xml - -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=x64 -p:TargetNetCoreVersion=net8.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=net8.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net8.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=net8.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net8.0-manual-x64.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-net6.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=net6.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net6.0-manual-win32.xml - -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandardPackage -p:Platform=Win32 -p:TargetNetCoreVersion=net8.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=net8.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net8.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=net8.0 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net8.0-manual-win32.xml - -:: .NET Framework - REFERENCE TYPE "NETSTANDARDPACKAGE" - -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 -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=net462 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net462-manual-anycpu.xml - -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetFx -p:ReferenceType=NetStandardPackage -p:TargetNetFxVersion=net48 -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: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 -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=net462 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net462-manual-x64.xml - -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetFx -p:ReferenceType=NetStandardPackage -p:Platform=x64 -p:TargetNetFxVersion=net48 -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: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 -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="Win32" -p:TargetNetFxVersion=net462 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net462-manual-win32.xml - -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetFx -p:ReferenceType=NetStandardPackage -p:Platform=Win32 -p:TargetNetFxVersion=net48 -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=net48 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-functional-win32.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="Win32" -p:TargetNetFxVersion=net48 -p:ReferenceType=NetStandardPackage -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandardpackage-net48-manual-win32.xml - -:: 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=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-net6.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=net6.0 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-net6.0-manual-anycpu.xml - -call :pauseOnError msbuild -p:Configuration="Release" -t:BuildTestsNetCore -p:ReferenceType=NetStandard -p:TargetNetCoreVersion=net8.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=net8.0 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-net8.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=net8.0 -p:ReferenceType=NetStandard -l:trx;LogFileName=..\..\..\..\..\artifacts\Results\netstandard-net8.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. - goto :eof :pauseOnError diff --git a/build.proj b/build.proj index d500f48886..89b46fb761 100644 --- a/build.proj +++ b/build.proj @@ -53,7 +53,6 @@ - @@ -62,7 +61,6 @@ - @@ -219,12 +217,6 @@ - - - - - - @@ -232,10 +224,4 @@ - - - - - - diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml index a19cff3c8a..7b0b19f031 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlCommand.xml @@ -1385,7 +1385,8 @@ The method is a st - Gets or sets a value indicating whether the command object should optimize parameter performance by disabling Output and InputOutput directions when submitting the command to the SQL Server. + Gets or sets a value indicating whether the command object should optimize parameter performance by disabling Output and InputOutput directions when submitting the command to the SQL Server.
+ This option is only used when the is Text otherwise it is ignored.
A value indicating whether the command object should optimize parameter performance by disabling Output and InputOuput parameter directions when submitting the command to the SQL Server. diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml index 7833db6f4a..8c4e2f4607 100644 --- a/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml +++ b/doc/snippets/Microsoft.Data.SqlClient/SqlConnection.xml @@ -51,7 +51,7 @@ using (SqlConnection connection = new SqlConnection(connectionString)) ## Examples - The following example creates a and a . The is opened and set as the for the . The example then calls . To accomplish this, the is passed a connection string and a query string that is a Transact-SQL INSERT statement. The connection is closed automatically when the code exits the using block. + The following example creates a and a . The is opened and set as the for the . The example then calls . To accomplish this, the is passed a SqlConnection and a query string that is a Transact-SQL INSERT statement. The connection is closed automatically when the code exits the using block. [!code-csharp[SqlCommand_ExecuteNonQuery Example#1](~/../sqlclient/doc/samples/SqlCommand_ExecuteNonQuery.cs#1)] diff --git a/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml b/doc/snippets/Microsoft.Data.SqlClient/SqlConnectionEncryptOption.xml index 35b8d24ab6..39111465a3 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 `null` convert to `true` and converts `false`. +Implicit conversions have been added to maintain backwards compatibility with boolean behavior 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`. ]]> @@ -49,13 +49,13 @@ Implicit conversions have been added to maintain backwards compatibility with bo The boolean value to be used for implicit comparison. - Enables implicit converstion of a boolean to a . A value of converts to . A value of converts to . + Enables implicit conversion of a boolean to a . A value of converts to . A value of converts to . The value to be used for implicit comparison. - Enables implicit converstion of a to a boolean. and convert to . converts to . + Enables implicit conversion of a to a boolean. and convert to . converts to . diff --git a/eng/pipelines/common/templates/jobs/build-signed-akv-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-akv-package-job.yml new file mode 100644 index 0000000000..617f61811f --- /dev/null +++ b/eng/pipelines/common/templates/jobs/build-signed-akv-package-job.yml @@ -0,0 +1,78 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: symbolsFolder + type: string + default: symbols + + - name: softwareFolder + type: string + default: software + + - name: publishSymbols + type: boolean + +jobs: +- job: build_signed_akv_package + pool: + type: windows # read more about custom job pool types at https://aka.ms/obpipelines/yaml/jobs + + variables: + - template: ../../../libraries/variables.yml@self + + steps: + - script: SET + displayName: 'Print Environment Variables' + + - template: ../steps/build-all-configurations-signed-dlls-step.yml@self + parameters: + product: AKV + nugetPackageRefVersion: $(MDS_PackageRef_Version) + AssemblyFileVersion: $(AKVAssemblyFileVersion) + + - template: ../steps/code-analyze-step.yml@self + parameters: + analyzeType: all + product: AKV + nugetPackageRefVersion: $(MDS_PackageRef_Version) + + - template: ../steps/esrp-code-signing-step.yml@self + parameters: + artifactType: dll + + - template: ../steps/generate-nuget-package-step.yml@self + parameters: + OutputDirectory: $(artifactDirectory) + nuspecPath: ${{variables.akvNuspecPath }} + NugetPackageVersion: ${{variables.AKVNuGetPackageVersion }} + referenceType: package + + - template: ../steps/esrp-code-signing-step.yml@self + parameters: + artifactType: pkg + + - template: ../steps/copy-dlls-for-test-step.yml@self + parameters: + product: AKV + referenceType: package + + # Publish symbols to private server + - template: ../steps/publish-symbols-step.yml@self + parameters: + SymAccount: $(PrivateSymAccount) + referenceType: package + symbolsVersion: ${{variables.AKVNuGetPackageVersion }} + product: AKV + publishSymbols: ${{ parameters['PublishSymbols'] }} + + # Publish symbols to public server + - template: ../steps/publish-symbols-step.yml@self + parameters: + SymAccount: $(PublicSymAccount) + referenceType: package + symbolsVersion: ${{variables.AKVNuGetPackageVersion }} + product: AKV + publishSymbols: ${{ parameters['PublishSymbols'] }} diff --git a/eng/pipelines/common/templates/jobs/build-signed-package-job.yml b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml new file mode 100644 index 0000000000..6a11dbadba --- /dev/null +++ b/eng/pipelines/common/templates/jobs/build-signed-package-job.yml @@ -0,0 +1,62 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: symbolsFolder + type: string + default: symbols + + - name: softwareFolder + type: string + default: software + + - name: publishSymbols + type: boolean + +jobs: +- job: build_signed_package + pool: + type: windows # read more about custom job pool types at https://aka.ms/obpipelines/yaml/jobs + + variables: + - template: ../../../libraries/variables.yml@self + + steps: + - script: SET + displayName: 'Print Environment Variables' + + - template: ../steps/build-all-configurations-signed-dlls-step.yml@self + + - template: ../steps/code-analyze-step.yml@self + parameters: + analyzeType: all + + - template: ../steps/esrp-code-signing-step.yml@self + parameters: + artifactType: dll + + - template: ../steps/generate-nuget-package-step.yml@self + parameters: + OutputDirectory: $(artifactDirectory) + + - template: ../steps/esrp-code-signing-step.yml@self + parameters: + artifactType: pkg + + - template: ../steps/copy-dlls-for-test-step.yml@self + parameters: + product: MDS + + # Publish symbols to private server + - template: ../steps/publish-symbols-step.yml@self + parameters: + SymAccount: $(PrivateSymAccount) + publishSymbols: ${{ parameters['PublishSymbols'] }} + + # Publish symbols to public server + - template: ../steps/publish-symbols-step.yml@self + parameters: + SymAccount: $(PublicSymAccount) + publishSymbols: ${{ parameters['PublishSymbols'] }} diff --git a/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml new file mode 100644 index 0000000000..f764a55201 --- /dev/null +++ b/eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml @@ -0,0 +1,58 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: downloadPackageStep + type: step + default: + script: echo + + - name: packageFolderName + type: string + default: drop_build_build_signed_package + + - name: dependsOn + type: string + default: empty + +jobs: +- job: run_tests_package_reference + ${{ if ne(parameters.dependsOn, 'empty')}}: + dependsOn: '${{parameters.dependsOn }}' + pool: + type: windows # read more about custom job pool types at https://aka.ms/obpipelines/yaml/jobs + isCustom: true + name: ADO-1ES-Pool + vmImage: 'ADO-MMS22-SQL19' + + variables: # More settings at https://aka.ms/obpipelines/yaml/jobs + - template: ../../../libraries/mds-validation-variables.yml@self + + steps: + - template: ../steps/pre-build-step.yml + + - ${{parameters.downloadPackageStep }} + + - template: ../steps/update-nuget-config-local-feed-step.yml + parameters: + downloadedNugetPath: $(Pipeline.Workspace)\${{parameters.packageFolderName }} + + - template: ../steps/update-config-file-step.yml + parameters: + TCPConnectionString: $(SQL_TCP_CONN_STRING) + NPConnectionString: $(SQL_NP_CONN_STRING) + SupportsIntegratedSecurity: false + + - template: ../steps/prepare-test-db-step.yml + +# build & test + - template: ../steps/build-and-run-tests-netfx-step.yml + parameters: + referenceType: Package + + - template: ../steps/build-and-run-tests-netcore-step.yml + parameters: + referenceType: Package + cleanFirst: true diff --git a/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml new file mode 100644 index 0000000000..379f6673f1 --- /dev/null +++ b/eng/pipelines/common/templates/jobs/validate-signed-package-job.yml @@ -0,0 +1,299 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: downloadPackageStep + type: step + default: + script: echo + + - name: packageFolderName + type: string + default: drop_build_build_signed_package + + - name: dependsOn + type: string + default: '' + + - name: packageType + type: string + default: both + values: + - dll + - pdb + - both + + - name: assembly_file_version_netfx + type: string + default: $(AssemblyFileVersion) + + - name: assembly_file_version_core + type: string + default: $(AssemblyFileVersion) + +jobs: +- job: validate_signed_package + ${{ if ne(parameters.dependsOn, '')}}: + dependsOn: '${{parameters.dependsOn }}' + pool: + type: windows # read more about custom job pool types at https://aka.ms/obpipelines/yaml/jobs + isCustom: true + name: ADO-1ES-Pool + vmImage: 'ADO-MMS22-SQL19' + + variables: # More settings at https://aka.ms/obpipelines/yaml/jobs + - template: ../../../libraries/mds-validation-variables.yml@self + + - name: pathToDownloadedNuget # path to the downloaded nuget files + value: $(Pipeline.Workspace)\${{parameters.packageFolderName }} + + steps: + - script: SET + displayName: 'Print Environment Variables' + + - task: NuGetToolInstaller@1 + displayName: 'Use NuGet ' + + - powershell: | + #Sets Variables for AssemblyFileVersion, AssemblyVersion and NugetPackageVersion + + [Xml] $versionprops = Get-Content -Path ".\tools\props\Versions.props" + Write-Host $versionprops.Project.PropertyGroup[0].AssemblyFileVersion + + $AssemblyVersion = $versionprops.Project.PropertyGroup[0].AssemblyVersion + + Write-Host "##vso[task.setvariable variable=ASSEMBLY_VERSION;]$AssemblyVersion" + displayName: 'Update assembly version property' + + - powershell: | + # Displays the paths of all the local cache directories + nuget locals all -List + + #Clears all files from all local cache directories + nuget locals all -Clear + displayName: 'Clear local cache' + + - ${{parameters.downloadPackageStep }} + + - powershell: | + # Install nuget package + Install-Package -Name "Microsoft.Data.SqlClient" -Destination "$(TempFolderName)" -Force -Source $(pathToDownloadedNuget) -SkipDependencies + + Write-Host "--------------------------------------------------" + Write-Host '$(TempFolderName)' + ls $(TempFolderName) + Write-Host "--------------------------------------------------" + displayName: 'Extract Nuget in temp folder' + + - powershell: | + # Artifact is stored in the Nuget folder + $packageType = '${{parameters.packageType}}' + + Write-Host "--------------------------------------------------" + Write-Host "This will verify the artifact signature" -ForegroundColor Green + Write-Host "--------------------------------------------------" + + if ($packageType -eq 'dll' -or $packageType -eq 'both') + { + nuget verify -All $(pathToDownloadedNuget)\*.nupkg + } + if ($packageType -eq 'pdb' -or $packageType -eq 'both') + { + nuget verify -All $(pathToDownloadedNuget)\*.snupkg + } + displayName: 'Verify nuget signature' + + - powershell: | + # Checks the expected folder names such as lib, ref, runtimes + Get-ChildItem -Path $(extractedNugetPath) -Directory | select Name | foreach { + if('$(expectedFolderNames)'.contains($_.Name)){ + Write-Host expected folder name verfied: $_.Name + } + } + displayName: 'Check expected folder names' + + - powershell: | + # Checks the version of DotNetFramework and DotNet + $countErr = 0 + $countPass = 0 + $excludNamesFromRuntimeFolder = 'lib','win','unix' + + Get-ChildItem -Path $(extractedNugetPath) -Directory | foreach { + $parentname=$_.Name + Write-Host $_.FullName -ForegroundColor yellow + + if($_.Name -ne 'runtimes') { + Get-ChildItem -Path $_.FullName -Directory | select Name | foreach { + if('$(expectedDotnetVersions)'.Contains($_.Name)){ + Write-Host "`tExpected version verified in $parentname": $_.Name -ForegroundColor green + $countPass += 1 + } + else{ + Write-Host "`tUnexpected version detected in $parentname": $_.Name + $countErr += 1 + } + } + } + + elseif ($_.Name -eq 'runtimes'){ + Get-ChildItem -Depth 3 -Path $_.FullName -Exclude $excludNamesFromRuntimeFolder -Directory | foreach{ + if('$(expectedDotnetVersions)'.Contains($_.Name)){ + Write-Host "`tExpected version verfied in $parentname": $_.Name + $countPass += 1 + } + else{ + Write-Host "`tUnexpected version detected": $_.Name -ForegroundColor Red + $countErr += 1 + } + } + } + else{ + Write-Host "`tUnknown folder " $_.Name -ForegroundColor Red + Exit -1 + } + } + + Write-Host "_______________" + Write-Host "Expected: $countPass" + Write-Host "Unexpected: $countErr" + Write-Host "_______________" + if ($countErr -ne 0) + { + Write-Host "Unexpected versions are detected!" -ForegroundColor Red + Exit -1 + } + displayName: 'Check Expected framework' + + - powershell: | + # list all the child items of created temp folder + + #Verify all DLLs unzipped match "expected" hierarchy + + foreach( $folderName in (Get-ChildItem -Path $(extractedNugetPath) -Directory).Name) + { + # List all Childerns of the Path + Get-ChildItem -Path $(extractedNugetPath)\$folderName -Recurse -File + $subFiles = Get-ChildItem -Path $(extractedNugetPath)\$folderName -Recurse -File + + foreach($file in $subFiles) + { + if($subFiles[0].Name -like "*.dll" ) + { + Write-Host $subFiles[0].Name -ForegroundColor Green + Write-Host $subFiles[1].Name -ForegroundColor Green + if(($folderName -eq 'lib') -or ($folderName -eq 'ref')) + { + if($subFiles[2].Name -like "*.dll") + { + Write-Host $subFiles[2].Name -ForegroundColor Green + } + else + { + $subFiles[2].Name + Write-Host "Expected file pattern for localization did not match to *.dll" -ForegroundColor Red + Exit -1 + } + } + } + else + { + $subFiles[0].Name + $subFiles[1].Name + Write-Host "Expected file pattern did not match to *.dll" -ForegroundColor Red + Exit -1 + } + } + } + displayName: 'Verify all DLLs unzipped match "expected" hierarchy' + + - powershell: | + # Verify all dlls status are Valid + + $dlls = Get-ChildItem -Path $(extractedNugetPath) -Recurse -Include *.dll + foreach ($status in $dlls | Get-AuthenticodeSignature) + { + if ($status.Status -eq "Valid") + { + Write-Host $status.Status $status.Path + } + else + { + Write-Host "dll status of '$status.Path' is not valid!" -ForegroundColor Red + $status + Exit -1 + } + } + displayName: 'Verify all dlls status are Valid' + + - powershell: | + # This will check for ProductVersion and FileVersion + # For NetFx we have a different FileVersion, but product versions are all the same some may have and extra numbering at the end. we only check for # first parts + + foreach ( $pVersion in Get-ChildItem *.dll -Path $(extractedNugetPath) -Recurse | ForEach-Object versioninfo ) + { + if ($pVersion.ProductVersion -Like '$(ProductVersion)*') + { + Write-Host Valid Product Version:"$pVersion.ProductVersion" $pVersion.ProductVersion detected for $pVersion.FileName -ForegroundColor Green + } + else + { + Write-Host "Wrong ProductVersion detected. Expected: '$(ProductVersion)', but Detected: "$pVersion.ProductVersion"" + Exit -1 + } + + if($pVersion.FileName -like '*lib\$(CurrentNetFxVersion)*'){ + + if($pVersion.FileVersion -eq '${{parameters.assembly_file_version_netfx }}') + { + Write-Host 'Correct File version Detected for net46,' $pVersion.FileVersion -ForegroundColor Green + } + else + { + Write-Host 'Wrong File version Detected for net46,' $pVersion.FileVersion -ForegroundColor Red + Exit -1 + } + } + else + { + + if($pVersion.FileVersion -eq '${{parameters.assembly_file_version_core}}') + { + Write-Host 'Correct File version Detected for netcore,' $pVersion.FileVersion -ForegroundColor Green + } + else + { + Write-Host 'Wrong File version Detected for netcore and ref folder,' $pVersion.FileVersion -ForegroundColor Red + Exit -1 + } + } + } + + Get-ChildItem *.dll -Path $(extractedNugetPath) -Recurse | ForEach-Object versioninfo + displayName: 'Verify "File Version" matches provided pipeline variable "ASSEMBLY_FILE_VERSION" for DLLs' + + - powershell: | + #Change TestMicrosoftDataSqlClientVersion + + [Xml] $versionprops = Get-Content -Path "tools/props/Versions.props" + $versionpropspath = "tools\props\Versions.props" + $versionprops.Project.PropertyGroup[$versionprops.Project.PropertyGroup.Count-1].TestMicrosoftDataSqlClientVersion ="$(NugetPackageVersion)" + Write-Host "Saving Test nuget version at $rootfolder\props ...." -ForegroundColor Green + $versionprops.Save($versionpropspath) + + displayName: 'Modify TestMicrosoftDataSqlClientVersion' + + - powershell: | + #Change TestMicrosoftDataSqlClientVersion + + [Xml] $versionprops = Get-Content -Path "tools/props/Versions.props" + $AssemblyFileVersion = $versionprops.Project.PropertyGroup[0].AssemblyFileVersion + $AssemblyVersion = $versionprops.Project.PropertyGroup[0].AssemblyVersion + + if($AssemblyFileVersion -eq $AssemblyVersion) + { + Write-Host AssemblyFileVersion: $AssemblyFileVersion should not be equal to: $AssemblyVersion + Exit -1 + } + displayName: 'Check "AssemblyFileVersion" is not same as "AssemblyVersion" in version.props' diff --git a/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml b/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml new file mode 100644 index 0000000000..5be79793fd --- /dev/null +++ b/eng/pipelines/common/templates/steps/build-all-configurations-signed-dlls-step.yml @@ -0,0 +1,54 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: AssemblyFileVersion + type: string + default: $(AssemblyFileVersion) + + - name: Configuration + type: string + default: '$(Configuration)' + + - name: nugetPackageRefVersion + type: string + default: '' + + - name: product + default: MDS + values: + - MDS + - AKV + - MSS + +steps: +- task: DownloadSecureFile@1 + displayName: 'Download Key Pair' + inputs: + secureFile: netfxKeypair.snk + retryCount: 5 + +- ${{ if eq(parameters.product, 'MDS') }}: + - task: MSBuild@1 + displayName: 'BuildAllConfigurations using build.proj' + inputs: + solution: '**/build.proj' + configuration: '${{parameters.Configuration }}' + msbuildArguments: '-p:AssemblyFileVersion=${{parameters.AssemblyFileVersion }} -t:BuildAllConfigurations -p:GenerateNuget=false -p:SignAssembly=true -p:AssemblyOriginatorKeyFile=$(Agent.TempDirectory)\netfxKeypair.snk' + +- ${{ if eq(parameters.product, 'AKV') }}: + - task: MSBuild@1 + displayName: 'BuildAKVNetFx using build.proj' + inputs: + solution: '**/build.proj' + configuration: '$(Configuration)' + msbuildArguments: '-p:AssemblyFileVersion=${{parameters.AssemblyFileVersion }} -t:BuildAKVNetFx -p:NugetPackageVersion=${{parameters.nugetPackageRefVersion }} -p:ReferenceType=Package -p:SignAssembly=true -p:AssemblyOriginatorKeyFile=$(Agent.TempDirectory)\netfxKeypair.snk' + + - task: MSBuild@1 + displayName: 'BuildAKVNetCoreAllOS using build.proj' + inputs: + solution: '**/build.proj' + configuration: '$(Configuration)' + msbuildArguments: '-p:AssemblyFileVersion=${{parameters.AssemblyFileVersion }} -t:BuildAKVNetCoreAllOS -p:NugetPackageVersion=${{parameters.nugetPackageRefVersion }} -p:ReferenceType=Package -p:SignAssembly=true -p:AssemblyOriginatorKeyFile=$(Agent.TempDirectory)\netfxKeypair.snk' diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml new file mode 100644 index 0000000000..f747fa57e6 --- /dev/null +++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netcore-step.yml @@ -0,0 +1,80 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: TargetNetCoreVersion + type: string + default: $(TargetNetCoreVersion) + + - name: configuration + type: string + default: $(Configuration) + + - name: referenceType + default: Project + values: + - Project + - Package + + - name: NugetPackageVersion + type: string + default: $(NugetPackageVersion) + + - name: platform + type: string + default: $(Platform) + + - name: cleanFirst + type: boolean + default: false + + - name: TestTargetOS + type: string + default: Windowsnetcoreapp + values: + - Windowsnetfx + - Windowsnetcoreapp + - Unixnetcoreapp + + - name: retryCountOnManualTests + type: number + default: 2 + +steps: +- ${{ if eq(parameters.cleanFirst, true)}}: + - task: MSBuild@1 + displayName: 'Clean artifacts folder' + inputs: + solution: build.proj + msbuildArguments: '-t:clean' + +- task: MSBuild@1 + displayName: 'Build AKV Provider .NET' + inputs: + solution: build.proj + msbuildArchitecture: x64 + msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetCore -p:ReferenceType=${{parameters.referenceType }} ' + +- task: MSBuild@1 + displayName: 'MSBuild Build Tests for ${{parameters.TargetNetCoreVersion }}' + inputs: + solution: build.proj + msbuildArchitecture: x64 + msbuildArguments: '-t:BuildTestsNetCore -p:ReferenceType=${{parameters.referenceType }} -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} -p:Configuration=${{parameters.configuration }}' + +- task: DotNetCoreCLI@2 + displayName: 'Run Functional Tests for ${{parameters.TargetNetCoreVersion }}' + inputs: + command: test + projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests"' + +- task: DotNetCoreCLI@2 + displayName: 'Run Manual Tests for ${{parameters.TargetNetCoreVersion }}' + inputs: + command: test + projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetCoreVersion=${{parameters.TargetNetCoreVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter category!=nonnetcoreapptests&category!=failing&category!=nonwindowstests --collect "Code Coverage"' + retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }} diff --git a/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml new file mode 100644 index 0000000000..ab77af3ee9 --- /dev/null +++ b/eng/pipelines/common/templates/steps/build-and-run-tests-netfx-step.yml @@ -0,0 +1,79 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: TargetNetFxVersion + type: string + default: $(TargetNetFxVersion) + + - name: configuration + type: string + default: $(Configuration) + + - name: referenceType + default: Project + values: + - Project + - Package + + - name: NugetPackageVersion + type: string + default: $(NugetPackageVersion) + + - name: platform + type: string + default: $(Platform) + + - name: cleanFirst + type: boolean + default: false + + - name: TestTargetOS + type: string + default: Windowsnetfx + values: + - Windowsnetfx + - Windowsnetcoreapp + - Unixnetcoreapp + + - name: retryCountOnManualTests + type: number + default: 2 + +steps: +- ${{ if eq(parameters.cleanFirst, true)}}: + - task: MSBuild@1 + displayName: 'Clean artifacts folder' + inputs: + solution: build.proj + msbuildArguments: '-t:clean' + +- task: MSBuild@1 + displayName: 'Build AKV Provider .NET Framework' + inputs: + solution: build.proj + msbuildArchitecture: x64 + msbuildArguments: '-p:Configuration=${{parameters.configuration }} -t:BuildAKVNetFx -p:ReferenceType=${{parameters.referenceType }} ' + +- task: MSBuild@1 + displayName: 'MSBuild Build Tests for ${{parameters.TargetNetFxVersion }}' + inputs: + solution: build.proj + msbuildArguments: ' -t:BuildTestsNetFx -p:ReferenceType=${{parameters.referenceType }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:Configuration=${{parameters.configuration }} -p:Platform=${{parameters.platform }}' + +- task: DotNetCoreCLI@2 + displayName: 'Run Functional Tests for ${{parameters.TargetNetFxVersion }}' + inputs: + command: test + projects: 'src\Microsoft.Data.SqlClient\tests\FunctionalTests\Microsoft.Data.SqlClient.Tests.csproj' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' + +- task: DotNetCoreCLI@2 + displayName: 'Run Manual Tests for ${{parameters.TargetNetFxVersion }}' + inputs: + command: test + projects: 'src\Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj' + arguments: '-p:Platform=${{parameters.platform }} -p:TestTargetOS="${{parameters.TestTargetOS }}" -p:TargetNetFxVersion=${{parameters.TargetNetFxVersion }} -p:ReferenceType=${{parameters.referenceType }} -p:Configuration=${{parameters.configuration }} -p:TestMicrosoftDataSqlClientVersion=${{parameters.NugetPackageVersion }} --no-build -v n --filter "category!=nonnetfxtests&category!=failing&category!=nonwindowstests" --collect "Code Coverage"' + retryCountOnTaskFailure: ${{parameters.retryCountOnManualTests }} diff --git a/eng/pipelines/common/templates/steps/code-analyze-step.yml b/eng/pipelines/common/templates/steps/code-analyze-step.yml new file mode 100644 index 0000000000..92be8eabf6 --- /dev/null +++ b/eng/pipelines/common/templates/steps/code-analyze-step.yml @@ -0,0 +1,51 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: analyzeType + values: + - roslyn + - inspect + - all + + - name: sourceRoot + type: string + default: $(REPOROOT) + + - name: nugetPackageRefVersion + type: string + default: '' + + - name: product + default: MDS + values: + - MDS + - AKV + - MSS + +steps: +- ${{ if or(eq(parameters.analyzeType, 'roslyn'), eq(parameters.analyzeType, 'all')) }}: + - ${{ if eq(parameters.product, 'MDS') }}: + - task: securedevelopmentteam.vss-secure-development-tools.build-task-roslynanalyzers.RoslynAnalyzers@3 + displayName: 'Guardian Dotnet Analyzers ' + inputs: + msBuildVersion: 17.0 + msBuildArchitecture: x64 + setupCommandlinePicker: vs2022 + msBuildCommandline: 'msbuild ${{parameters.sourceRoot}}\build.proj -p:configuration=Release -p:GenerateNuget=false -p:BuildTools=false' + - ${{ if eq(parameters.product, 'AKV') }}: + - task: securedevelopmentteam.vss-secure-development-tools.build-task-roslynanalyzers.RoslynAnalyzers@3 + displayName: 'Guardian Dotnet Analyzers ' + inputs: + msBuildVersion: 17.0 + msBuildArchitecture: x64 + setupCommandlinePicker: vs2022 + msBuildCommandline: 'msbuild ${{parameters.sourceRoot}}\build.proj -p:configuration=Release -p:GenerateNuget=false -p:BuildTools=false -p:NugetPackageVersion=${{parameters.nugetPackageRefVersion }} -p:ReferenceType=Package -t:BuildAKVNetCoreAllOS' + +- ${{ if or(eq(parameters.analyzeType, 'inspect'), eq(parameters.analyzeType, 'all')) }}: + - task: securedevelopmentteam.vss-secure-development-tools.build-task-codeinspector.CodeInspector@2 + displayName: 'Run Code Inspector' + inputs: + LogLevel: Error diff --git a/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml b/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml new file mode 100644 index 0000000000..faf54fc24d --- /dev/null +++ b/eng/pipelines/common/templates/steps/copy-dlls-for-test-step.yml @@ -0,0 +1,106 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: Configuration + type: string + default: '$(Configuration)' + + - name: symbolsFolder + type: string + default: symbols + + - name: softwareFolder + type: string + default: software + + - name: referenceType + default: project + values: + - project + - package + + - name: listOfTF + type: object + default: + - net462 + - net6.0 + - net8.0 + + - name: product + default: MDS + values: + - MDS + - AKV + - MSS + +steps: +- powershell: | + $software = '${{parameters.softwareFolder}}' + $symbols = '${{parameters.symbolsFolder}}' + + md $software + md $software\win + + md $symbols + md $symbols\win + displayName: 'Make base directories' + +- ${{ each targetFramework in parameters.listOfTF }}: + - ${{ if eq(parameters.product, 'MDS') }}: + - powershell: | + $software = '${{parameters.softwareFolder}}' + $tf = '${{ targetFramework }}' + md $software\win\$tf + + if ($tf.StartsWith('net4')) + { + Copy-Item "artifacts\${{parameters.referenceType }}\bin\Windows_NT\${{parameters.Configuration }}.AnyCPU\Microsoft.Data.SqlClient\netfx\$tf\Microsoft.Data.SqlClient.dll" "$software\win\$tf" -recurse + } + else + { + Copy-Item "artifacts\${{parameters.referenceType }}\bin\Windows_NT\${{parameters.Configuration }}.AnyCPU\Microsoft.Data.SqlClient\netcore\$tf\Microsoft.Data.SqlClient.dll" "$software\win\$tf" -recurse + } + + $symbols = '${{parameters.symbolsFolder}}' + md $symbols\win\$tf + + if ($tf.StartsWith('net4')) + { + Copy-Item "artifacts\Project\bin\Windows_NT\Release.AnyCPU\Microsoft.Data.SqlClient\netfx\$tf\Microsoft.Data.SqlClient.pdb" "$symbols\win\$tf" -recurse + } + else + { + Copy-Item "artifacts\Project\bin\Windows_NT\Release.AnyCPU\Microsoft.Data.SqlClient\netcore\$tf\Microsoft.Data.SqlClient.pdb" "$symbols\win\$tf" -recurse + } + + Write-Host "Artifacts fetched for testing" + Get-Location + displayName: 'Prepare ${{ targetFramework }} Arifacts for Testing' + + - ${{ if eq(parameters.product, 'AKV') }}: + - powershell: | + $software = '${{parameters.softwareFolder}}' + $tf = '${{ targetFramework }}' + md $software\win\$tf + + Copy-Item "artifacts\${{parameters.referenceType }}\bin\Windows_NT\${{parameters.Configuration }}.AnyCPU\AzureKeyVaultProvider\$tf\Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.dll" "$software\win\$tf" -recurse + + $symbols = '${{parameters.symbolsFolder}}' + md $symbols\win\$tf + + Copy-Item "artifacts\${{parameters.referenceType }}\bin\Windows_NT\${{parameters.Configuration }}.AnyCPU\AzureKeyVaultProvider\$tf\Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.pdb" "$symbols\win\$tf" -recurse + + Write-Host "Artifacts fetched for testing" + Get-Location + displayName: 'Prepare ${{ targetFramework }} Arifacts for Testing' + +- powershell: | + $software = '${{parameters.softwareFolder}}' + $symbols = '${{parameters.symbolsFolder}}' + + Get-ChildItem -recurse "$software\*.dll" + Get-ChildItem -recurse "$symbols\*.pdb" + displayName: 'List the prepared files' diff --git a/eng/pipelines/common/templates/steps/esrp-code-signing-step.yml b/eng/pipelines/common/templates/steps/esrp-code-signing-step.yml new file mode 100644 index 0000000000..02b9487cc3 --- /dev/null +++ b/eng/pipelines/common/templates/steps/esrp-code-signing-step.yml @@ -0,0 +1,106 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: artifactType + values: + - dll + - pkg + + - name: sourceRoot + type: string + default: $(REPOROOT) + + - name: artifactDirectory + type: string + default: $(artifactDirectory) + +steps: +- ${{ if eq(parameters.artifactType, 'dll') }}: + - task: SFP.build-tasks.custom-build-task-2.EsrpMalwareScanning@4 + displayName: 'ESRP MalwareScanning' + inputs: + ConnectedServiceName: 'SqlClient ESRP Malware Scanning' + FolderPath: '${{parameters.sourceRoot }}' + Pattern: '*.dll' + Region: US + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@4 + displayName: 'ESRP CodeSigning' + inputs: + ConnectedServiceName: 'SqlClient ESRP Code Signing' + FolderPath: '${{parameters.sourceRoot }}' + Pattern: '*.dll' + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolSign", + "parameters": [ + { + "parameterName": "OpusName", + "parameterValue": "Microsoft Data SqlClient Data Provider for SQL Server" + }, + { + "parameterName": "OpusInfo", + "parameterValue": "http://www.microsoft.com" + }, + { + "parameterName": "FileDigest", + "parameterValue": "/fd \"SHA256\"" + }, + { + "parameterName": "PageHash", + "parameterValue": "/NPH" + }, + { + "parameterName": "TimeStamp", + "parameterValue": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + ], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-230012", + "operationSetCode": "SigntoolVerify", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + +- ${{ if eq(parameters.artifactType, 'pkg') }}: + - task: SFP.build-tasks.custom-build-task-2.EsrpMalwareScanning@4 + displayName: 'ESRP MalwareScanning Nuget Package' + inputs: + ConnectedServiceName: 'SqlClient ESRP Malware Scanning' + FolderPath: '${{parameters.artifactDirectory }}' + Pattern: '*.*nupkg' + Region: US + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@4 + displayName: 'ESRP CodeSigning Nuget Package' + inputs: + ConnectedServiceName: 'SqlClient ESRP Code Signing' + FolderPath: '${{parameters.artifactDirectory }}' + Pattern: '*.*nupkg' + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetSign", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + }, + { + "keyCode": "CP-401405", + "operationSetCode": "NuGetVerify", + "parameters": [ ], + "toolName": "sign", + "toolVersion": "1.0" + } + ] diff --git a/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml new file mode 100644 index 0000000000..d97229089a --- /dev/null +++ b/eng/pipelines/common/templates/steps/generate-nuget-package-step.yml @@ -0,0 +1,42 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: nuspecPath + type: string + default: '$(nuspecPath)' + + - name: NugetPackageVersion + type: string + default: '$(NugetPackageVersion)' + + - name: OutputDirectory + type: string + default: '$(Build.SourcesDirectory)/packages' + + - name: Configuration + type: string + default: '$(Configuration)' + + - name: referenceType + default: project + values: + - project + - package + +steps: +- task: NuGetToolInstaller@1 + displayName: 'Install Latest Nuget' + inputs: + checkLatest: true +- powershell: | + $Commit=git rev-parse HEAD + Write-Host "##vso[task.setvariable variable=CommitHead;]$Commit" + displayName: CommitHead +- task: NuGetCommand@2 + displayName: 'NuGet pack with snupkg' + inputs: + command: custom + arguments: 'pack -Symbols -SymbolPackageFormat snupkg ${{parameters.nuspecPath}} -Version ${{parameters.NugetPackageVersion}} -OutputDirectory ${{parameters.OutputDirectory}} -properties "COMMITID=$(CommitHead);Configuration=${{parameters.Configuration}};ReferenceType=${{parameters.referenceType}}"' diff --git a/eng/pipelines/common/templates/steps/pre-build-step.yml b/eng/pipelines/common/templates/steps/pre-build-step.yml new file mode 100644 index 0000000000..327b5f21a5 --- /dev/null +++ b/eng/pipelines/common/templates/steps/pre-build-step.yml @@ -0,0 +1,20 @@ +################################################################################# +# 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. # +################################################################################# +steps: +- script: SET + displayName: 'Print Environment Variables' + +- powershell: | + # use sqlcmd to try to connect to localdb + $svc_name = "SQLBrowser" + Get-Service $svc_name | Select-Object -Property Name, StartType, Status + Set-Service -StartupType Automatic $svc_name + net start $svc_name + Get-Service $svc_name | Select-Object -Property Name, StartType, Status + displayName: 'Start SQLBrowser' + +- task: NuGetToolInstaller@1 + displayName: 'Use NuGet ' diff --git a/eng/pipelines/common/templates/steps/prepare-test-db-step.yml b/eng/pipelines/common/templates/steps/prepare-test-db-step.yml new file mode 100644 index 0000000000..8597a0c9e5 --- /dev/null +++ b/eng/pipelines/common/templates/steps/prepare-test-db-step.yml @@ -0,0 +1,26 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: databaseName + type: string + default: $(Database) + + - name: targetFramework + type: string + default: net6.0 + +steps: +- task: DotNetCoreCLI@2 + displayName: 'Build Ext Utilities' + inputs: + arguments: '-f ${{parameters.targetFramework }}' + workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities +- task: DotNetCoreCLI@2 + displayName: 'Create Test Database' + inputs: + command: run + arguments: '-f ${{parameters.targetFramework }} -- "CreateDatabase" ${{parameters.databaseName }} ' + workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities diff --git a/eng/pipelines/common/templates/steps/publish-symbols-step.yml b/eng/pipelines/common/templates/steps/publish-symbols-step.yml new file mode 100644 index 0000000000..5898fddd4a --- /dev/null +++ b/eng/pipelines/common/templates/steps/publish-symbols-step.yml @@ -0,0 +1,64 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: SymAccount + type: string + + - name: publishSymbols + type: string + default: '$(PublishSymbols)' + + - name: symbolsVersion + type: string + default: '$(NuGetPackageVersion)' + + - name: referenceType + default: project + values: + - project + - package + + - name: product + default: MDS + values: + - MDS + - AKV + - MSS + +steps: +- powershell: 'Write-Host "##vso[task.setvariable variable=ArtifactServices.Symbol.AccountName;]${{parameters.SymAccount}}"' + displayName: 'Update Symbol.AccountName ${{parameters.SymAccount}}' + condition: and(succeeded(), ${{ eq(parameters.publishSymbols, 'true') }}) + +- ${{ if eq(parameters.product, 'MDS') }}: + - task: PublishSymbols@2 + displayName: 'Publish symbols path' + inputs: + SymbolsFolder: '$(Build.SourcesDirectory)\artifacts\${{parameters.referenceType }}\bin' + SearchPattern: | + Windows_NT/$(Configuration).AnyCPU/**/Microsoft.Data.SqlClient.pdb + Unix/$(Configuration).AnyCPU/**/Microsoft.Data.SqlClient.pdb + IndexSources: false + SymbolServerType: TeamServices + SymbolsMaximumWaitTime: 60 + SymbolsProduct: Microsoft.Data.SqlClient + SymbolsVersion: '{{parameters.symbolsVersion }}' + condition: and(succeeded(), ${{ eq(parameters.publishSymbols, 'true') }}) + +- ${{ if eq(parameters.product, 'AKV') }}: + - task: PublishSymbols@2 + displayName: 'Publish symbols path' + inputs: + SymbolsFolder: '$(Build.SourcesDirectory)\artifacts\${{parameters.referenceType }}\bin' + SearchPattern: | + Windows_NT/$(Configuration).AnyCPU/AzureKeyVaultProvider/**/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.pdb + AnyOS/$(Configuration).AnyCPU/AzureKeyVaultProvider/**/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.pdb + IndexSources: false + SymbolServerType: TeamServices + SymbolsMaximumWaitTime: 60 + SymbolsProduct: Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider + SymbolsVersion: '{{parameters.symbolsVersion }}' + condition: and(succeeded(), ${{ eq(parameters.publishSymbols, 'true') }}) diff --git a/eng/pipelines/common/templates/steps/update-config-file-step.yml b/eng/pipelines/common/templates/steps/update-config-file-step.yml new file mode 100644 index 0000000000..2530f35d23 --- /dev/null +++ b/eng/pipelines/common/templates/steps/update-config-file-step.yml @@ -0,0 +1,35 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: TCPConnectionString + type: string + default: '' + + - name: NPConnectionString + type: string + default: '' + + - name: SupportsIntegratedSecurity + type: boolean + default: false + +steps: +# All properties should be added here, and this template should be used for any manipulation of the config.json file. +- powershell: | + $jdata = Get-Content -Raw "config.default.json" | ConvertFrom-Json + foreach ($p in $jdata) + { + if ("${{parameters.TCPConnectionString }}" -ne ""){ + $p.TCPConnectionString="${{parameters.TCPConnectionString }}"} + + if ("${{parameters.NPConnectionString }}" -ne ""){ + $p.NPConnectionString="${{parameters.NPConnectionString }}"} + + $p.SupportsIntegratedSecurity=[System.Convert]::ToBoolean("${{parameters.SupportsIntegratedSecurity }}") + } + $jdata | ConvertTo-Json | Set-Content "config.json" + workingDirectory: src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities + displayName: 'Update config.json' diff --git a/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml new file mode 100644 index 0000000000..5258a3941d --- /dev/null +++ b/eng/pipelines/common/templates/steps/update-nuget-config-local-feed-step.yml @@ -0,0 +1,78 @@ +################################################################################# +# 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. # +################################################################################# +parameters: + - name: downloadedNugetPath # path to the downloaded nuget files + type: string + + - name: nugetPackageVersion + type: string + default: $(NugetPackageVersion) + +steps: +- powershell: | + # Get a list of package sources available + Get-PackageSource + + #Current location + Get-Location + + # Register the local nuget folder to be used by nuget.config + Register-PackageSource -Name "Package Source" -Location ${{parameters.downloadedNugetPath }} -Force -ProviderName NuGet -Trusted + + # Get a list of package sources available after the change + Get-PackageSource + + #Set the Nuget.config file in the project to use extracted package + $rootFolder = Get-location + [Xml] $nugetConfig = Get-Content -Path "Nuget.config" + $Value = Resolve-Path ${{parameters.downloadedNugetPath }} + $newAdd = $nugetConfig.CreateElement("add") + $newAdd.SetAttribute("key","Package source") + $newAdd.SetAttribute("value", "$Value\" ) + $nugetConfig.configuration.packageSources.AppendChild($newAdd) + $nugetConfig.Save("$rootFolder\Nuget.config") + displayName: 'Update NuGet config file to read from Nuget folder' + +- task: MSBuild@1 + displayName: 'Restore nugets' + inputs: + solution: build.proj + msbuildArchitecture: x64 + msbuildArguments: '-t:restore' + +- powershell: | + $Doc = [xml](Get-Content ".\Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj") + $parent_xpath = '/Project/ItemGroup/ProjectReference' + $node = $Doc.SelectSingleNode($parent_xpath) + $parentNode = $node.ParentNode + while($node -ne $null) { + $node.ParentNode.RemoveChild($node) + $node = $Doc.SelectSingleNode($parent_xpath) + } + + $parent_xpath = '/Project/ItemGroup/PackageReference[@Include="Microsoft.Data.SqlClient"]' + $node = $Doc.SelectSingleNode($parent_xpath) + + if($node -ne $null){ + $node.Version="${{parameters.nugetPackageVersion }}" + } + else{ + $packagerefnode = $doc.createelement("packagereference") + $value = $doc.selectsinglenode('/project/itemgroup/projectreference') + $attrinclude = $doc.createattribute("include") + $attrinclude.value = "microsoft.data.sqlclient" + $attrversion = $doc.createattribute("version") + $attrversion.value = "${{parameters.nugetPackageVersion }}" + $packagerefnode.attributes.append($attrinclude) + $packagerefnode.attributes.append($attrversion) + $parentNode.AppendChild($packageRefNode) + } + + $currentFolder = Get-Location + $filePath = Join-Path $currentFolder "Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.csproj" + $Doc.Save($filePath) + workingDirectory: 'src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider' + displayName: 'Update AKV Project Ref to Package Ref (.NET Framework/Core)' diff --git a/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml b/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml new file mode 100644 index 0000000000..aa8d90d3e5 --- /dev/null +++ b/eng/pipelines/dotnet-sqlclient-signing-pipeline.yml @@ -0,0 +1,162 @@ +################################################################################# +# 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. # +################################################################################# + +name: $(Year:YY)$(DayOfYear)$(Rev:.rr) +trigger: + branches: + include: + - internal/main + paths: + include: + - src + - eng + - tools + - .config + - build.proj + - Nuget.config + - '*.cmd' + - '*.sh' + +schedules: +- cron: '30 4 * * Mon' + displayName: Weekly Sunday 9:30 PM (UTC - 7) Build + branches: + include: + - internal/main + always: true + +- cron: '30 3 * * Mon-Fri' + displayName: Mon-Fri 8:30 PM (UTC - 7) Build + branches: + include: + - internal/main + +parameters: # parameters are shown up in ADO UI in a build queue time +- name: 'debug' + displayName: 'Enable debug output' + type: boolean + default: true + +- name: publishSymbols + displayName: 'Publish symbols' + type: boolean + default: false +- name: MDS_PackageRef_Version + displayName: 'MDS package version of AKV Provider (build AKV)' + type: string + default: 5.1.5 +- name: CurrentNetFxVersion + displayName: 'Lowest supported .NET Framework version (MDS validation)' + type: string + default: 'net462' +- name: oneBranchType + displayName: 'Select OneBranch template' + default: Official + values: + - NonOfficial + - Official + +variables: + - template: /eng/pipelines/libraries/variables.yml@self + - name: packageFolderName + value: drop_buildMDS_build_signed_package + - name: PublishSymbols + value: ${{ parameters['publishSymbols'] }} + - name: MDS_PackageRef_Version + value: ${{ parameters['MDS_PackageRef_Version'] }} + - name: CurrentNetFxVersion + value: ${{ parameters['CurrentNetFxVersion'] }} + - name: ProductVersion #MDS product version (MDS validation) + value: $(NUGETPACKAGEVERSION) + +resources: + repositories: + - repository: templates + type: git + name: OneBranch.Pipelines/GovernedTemplates + ref: refs/heads/main + +extends: + template: v2/OneBranch.${{parameters.oneBranchType }}.CrossPlat.yml@templates # https://aka.ms/obpipelines/templates + parameters: + featureFlags: + WindowsHostVersion: 1ESWindows2022 + globalSdl: # https://aka.ms/obpipelines/sdl + apiscan: + enabled: true + softwareFolder: $(softwareFolder) + symbolsFolder: $(symbolsFolder) + softwarename: Microsoft.Data.SqlClient + versionNumber: $(AssemblyFileVersion) + tsa: + enabled: true # onebranch publish all sdl results to TSA. If TSA is disabled all SDL tools will forced into 'break' build mode. + codeql: + compiled: + enabled: true + sbom: + enabled: true + packageName: Microsoft.Data.SqlClient + packageVersion: $(NugetPackageVersion) + asyncSdl: + enabled: false + credscan: + enabled: true + suppressionsFile: $(REPOROOT)/.config/CredScanSuppressions.json + binskim: + enabled: true + policheck: + enabled: true + break: true # always break the build on policheck issues. You can disable it by setting to 'false' + exclusionsFile: $(REPOROOT)\.config\PolicheckExclusions.xml + armory: + enabled: true + break: true + eslint: # TypeScript and JavaScript + enabled: false + roslyn: + enabled: true + break: true + publishLogs: + enabled: true + tsaOptionsPath: $(REPOROOT)\.config\tsaoptions.json + disableLegacyManifest: true + stages: + - stage: buildAKV + jobs: + - template: eng/pipelines/common/templates/jobs/build-signed-akv-package-job.yml@self + parameters: + symbolsFolder: $(symbolsFolder) + softwareFolder: $(softwareFolder) + publishSymbols: ${{ parameters['publishSymbols'] }} + + - stage: buildMDS + jobs: + - template: eng/pipelines/common/templates/jobs/build-signed-package-job.yml@self + parameters: + symbolsFolder: $(symbolsFolder) + softwareFolder: $(softwareFolder) + publishSymbols: ${{ parameters['publishSymbols'] }} + + - stage: package_validation + dependsOn: buildMDS + jobs: + - template: eng/pipelines/common/templates/jobs/validate-signed-package-job.yml@self + parameters: + packageFolderName: $(packageFolderName) + downloadPackageStep: + download: current + artifact: $(packageFolderName) + patterns: '**/*.*nupkg' + displayName: 'Download NuGet Package' + + - template: eng/pipelines/common/templates/jobs/run-tests-package-reference-job.yml@self + parameters: + packageFolderName: $(packageFolderName) + downloadPackageStep: + download: current + artifact: $(packageFolderName) + patterns: '**/*.nupkg' + displayName: 'Download NuGet Package' diff --git a/eng/pipelines/libraries/akv-variables.yml b/eng/pipelines/libraries/akv-variables.yml new file mode 100644 index 0000000000..259ae19dba --- /dev/null +++ b/eng/pipelines/libraries/akv-variables.yml @@ -0,0 +1,15 @@ +################################################################################# +# 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. # +################################################################################# + +variables: + - group: AKV Release Variables + + - name: AKVNugetPackageVersion + value: $(AKVMajor).$(AKVMinor).$(AKVPatch) + - name: AKVAssemblyFileVersion + value: '$(AKVMajor).$(AKVMinor)$(AKVPatch).$(Build.BuildNumber)' + - name: akvNuspecPath + value: tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec diff --git a/eng/pipelines/libraries/build-variables.yml b/eng/pipelines/libraries/build-variables.yml new file mode 100644 index 0000000000..1c26f26a69 --- /dev/null +++ b/eng/pipelines/libraries/build-variables.yml @@ -0,0 +1,10 @@ +################################################################################# +# 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. # +################################################################################# + +variables: + - template: common-variables.yml@self + - template: akv-variables.yml@self + - template: mds-variables.yml@self diff --git a/eng/pipelines/libraries/common-variables.yml b/eng/pipelines/libraries/common-variables.yml new file mode 100644 index 0000000000..fb85f70d36 --- /dev/null +++ b/eng/pipelines/libraries/common-variables.yml @@ -0,0 +1,19 @@ +################################################################################# +# 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. # +################################################################################# + +variables: + - name: Configuration + value: Release + - name: CommitHead + value: '' # the value will be extracted from the repo's head + - name: REPOROOT + value: $(Build.SourcesDirectory) + - name: softwareFolder + value: $(REPOROOT)/software + - name: symbolsFolder + value: $(REPOROOT)/symbols + - name: artifactDirectory + value: '$(REPOROOT)/packages' diff --git a/eng/pipelines/libraries/mds-validation-variables.yml b/eng/pipelines/libraries/mds-validation-variables.yml new file mode 100644 index 0000000000..7aed06dd61 --- /dev/null +++ b/eng/pipelines/libraries/mds-validation-variables.yml @@ -0,0 +1,34 @@ +################################################################################# +# 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. # +################################################################################# + +variables: + - template: common-variables.yml@self + - template: mds-variables.yml@self + + - name: TempFolderName # extract the nuget package here + value: temp + - name: extractedNugetPath + value: $(Build.SourcesDirectory)\$(TempFolderName)\Microsoft.Data.SqlClient.$(NugetPackageVersion) + - name: expectedFolderNames + value: lib,ref,runtimes + - name: expectedDotnetVersions + value: net462,net6.0,net8.0 + - name: Database + value: Northwind + - name: platform + value: AnyCPU + - name: TargetNetFxVersion + value: net481 + - name: TargetNetCoreVersion + value: net8.0 + - name: SQLTarget + value: localhost + - name: encrypt + value: false + - name: SQL_NP_CONN_STRING + value: Data Source=np:$(SQLTarget);Initial Catalog=$(Database);Integrated Security=true;Encrypt=$(ENCRYPT);TrustServerCertificate=true; + - name: SQL_TCP_CONN_STRING + value: Data Source=tcp:$(SQLTarget);Initial Catalog=$(Database);Integrated Security=true;Encrypt=$(ENCRYPT);TrustServerCertificate=true; diff --git a/eng/pipelines/libraries/mds-variables.yml b/eng/pipelines/libraries/mds-variables.yml new file mode 100644 index 0000000000..3da3172fa3 --- /dev/null +++ b/eng/pipelines/libraries/mds-variables.yml @@ -0,0 +1,15 @@ +################################################################################# +# 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. # +################################################################################# + +variables: + - group: Release Variables + + - name: NugetPackageVersion + value: $(Major).$(Minor).$(Patch) + - name: AssemblyFileVersion + value: '$(Major).$(Minor)$(Patch).$(Build.BuildNumber)' + - name: nuspecPath + value: '$(REPOROOT)/tools/specs/Microsoft.Data.SqlClient.nuspec' diff --git a/eng/pipelines/libraries/variables.yml b/eng/pipelines/libraries/variables.yml new file mode 100644 index 0000000000..57894459d3 --- /dev/null +++ b/eng/pipelines/libraries/variables.yml @@ -0,0 +1,17 @@ +################################################################################# +# 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. # +################################################################################# + +variables: + - template: build-variables.yml@self + # onebranch template variables + - name: ob_outputDirectory + value: '$(artifactDirectory)' # this directory is uploaded to pipeline artifacts, reddog and cloudvault. More info at https://aka.ms/obpipelines/artifacts + - name: ob_sdl_binskim_break + value: true # https://aka.ms/obpipelines/sdl + - name: Packaging.EnableSBOMSigning + value: true + - name: WindowsContainerImage + value: 'onebranch.azurecr.io/windows/ltsc2022/vse2022:latest' # Docker image which is used to build the project https://aka.ms/obpipelines/containers diff --git a/release-notes/5.1/5.1.0.md b/release-notes/5.1/5.1.0.md index e7c4eae495..adbf449e63 100644 --- a/release-notes/5.1/5.1.0.md +++ b/release-notes/5.1/5.1.0.md @@ -79,7 +79,7 @@ The default value of the `ServerCertificate` connection setting is an empty stri #### .NET -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.7.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.JsonWebTokens 6.24.0 @@ -95,7 +95,7 @@ The default value of the `ServerCertificate` connection setting is an empty stri #### .NET Standard -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.7.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.Protocols.OpenIdConnect 6.24.0 diff --git a/release-notes/5.1/5.1.1.md b/release-notes/5.1/5.1.1.md index bf40701739..057466a565 100644 --- a/release-notes/5.1/5.1.1.md +++ b/release-notes/5.1/5.1.1.md @@ -37,7 +37,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.7.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.JsonWebTokens 6.24.0 @@ -53,7 +53,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET Standard -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.7.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.Protocols.OpenIdConnect 6.24.0 diff --git a/release-notes/5.1/5.1.2.md b/release-notes/5.1/5.1.2.md index 14c4b347ad..cb9ccc5992 100644 --- a/release-notes/5.1/5.1.2.md +++ b/release-notes/5.1/5.1.2.md @@ -45,7 +45,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET -- Microsoft.Data.SqlClient.SNI 5.1.1 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 - Azure.Identity 1.7.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.JsonWebTokens 6.24.0 @@ -61,7 +61,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET Standard -- Microsoft.Data.SqlClient.SNI 5.1.1 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 - Azure.Identity 1.7.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.Protocols.OpenIdConnect 6.24.0 diff --git a/release-notes/5.1/5.1.3.md b/release-notes/5.1/5.1.3.md index 75a3140a6d..7889bf61bb 100644 --- a/release-notes/5.1/5.1.3.md +++ b/release-notes/5.1/5.1.3.md @@ -34,7 +34,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET -- Microsoft.Data.SqlClient.SNI 5.1.1 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 - Azure.Identity 1.7.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.JsonWebTokens 6.24.0 @@ -50,7 +50,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET Standard -- Microsoft.Data.SqlClient.SNI 5.1.1 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 - Azure.Identity 1.7.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.Protocols.OpenIdConnect 6.24.0 diff --git a/release-notes/5.1/5.1.4.md b/release-notes/5.1/5.1.4.md index 3f4e784b75..c1638b1eee 100644 --- a/release-notes/5.1/5.1.4.md +++ b/release-notes/5.1/5.1.4.md @@ -37,7 +37,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET -- Microsoft.Data.SqlClient.SNI 5.1.1 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 - Azure.Identity 1.10.3 - Microsoft.Identity.Client 4.56.2 - Microsoft.IdentityModel.JsonWebTokens 6.24.0 @@ -53,7 +53,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET Standard -- Microsoft.Data.SqlClient.SNI 5.1.1 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 - Azure.Identity 1.10.3 - Microsoft.Identity.Client 4.56.2 - Microsoft.IdentityModel.Protocols.OpenIdConnect 6.24.0 diff --git a/release-notes/5.1/5.1.5.md b/release-notes/5.1/5.1.5.md index c25672a8d1..e05c26861f 100644 --- a/release-notes/5.1/5.1.5.md +++ b/release-notes/5.1/5.1.5.md @@ -39,7 +39,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET -- Microsoft.Data.SqlClient.SNI 5.1.1 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 - Azure.Identity 1.10.3 - Microsoft.Identity.Client 4.56.2 - Microsoft.IdentityModel.JsonWebTokens 6.35.0 @@ -55,7 +55,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET Standard -- Microsoft.Data.SqlClient.SNI 5.1.1 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.1 - Azure.Identity 1.10.3 - Microsoft.Identity.Client 4.56.2 - Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 diff --git a/release-notes/5.2/5.2.0-preview1.md b/release-notes/5.2/5.2.0-preview1.md index 84a4678452..152b3169b8 100644 --- a/release-notes/5.2/5.2.0-preview1.md +++ b/release-notes/5.2/5.2.0-preview1.md @@ -63,7 +63,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.8.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.JsonWebTokens 6.24.0 @@ -82,7 +82,7 @@ Thanks to the following public contributors. Their efforts toward this project a #### .NET Standard -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.6.0 - Microsoft.Identity.Client 4.47.2 - Microsoft.IdentityModel.Protocols.OpenIdConnect 6.24.0 diff --git a/release-notes/5.2/5.2.0-preview2.md b/release-notes/5.2/5.2.0-preview2.md index 6cfd799f69..360894b93a 100644 --- a/release-notes/5.2/5.2.0-preview2.md +++ b/release-notes/5.2/5.2.0-preview2.md @@ -84,7 +84,7 @@ Example usage: #### .NET -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.8.0 - Microsoft.Identity.Client 4.53.0 - Microsoft.IdentityModel.JsonWebTokens 6.24.0 @@ -103,7 +103,7 @@ Example usage: #### .NET Standard -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.6.0 - Microsoft.Identity.Client 4.53.0 - Microsoft.IdentityModel.Protocols.OpenIdConnect 6.24.0 diff --git a/release-notes/5.2/5.2.0-preview3.md b/release-notes/5.2/5.2.0-preview3.md index 0aa43912d2..82173a5744 100644 --- a/release-notes/5.2/5.2.0-preview3.md +++ b/release-notes/5.2/5.2.0-preview3.md @@ -81,7 +81,7 @@ Example usage: #### .NET -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.8.0 - Microsoft.Identity.Client 4.53.0 - Microsoft.IdentityModel.JsonWebTokens 6.24.0 @@ -100,7 +100,7 @@ Example usage: #### .NET Standard -- Microsoft.Data.SqlClient.SNI 5.1.0 +- Microsoft.Data.SqlClient.SNI.runtime 5.1.0 - Azure.Identity 1.6.0 - Microsoft.Identity.Client 4.53.0 - Microsoft.IdentityModel.Protocols.OpenIdConnect 6.24.0 diff --git a/release-notes/5.2/5.2.0.md b/release-notes/5.2/5.2.0.md index 498db81ac6..aef0863b6c 100644 --- a/release-notes/5.2/5.2.0.md +++ b/release-notes/5.2/5.2.0.md @@ -1,7 +1,277 @@ -| Release Date | Version | Notes | -| :-- | :-- | :--: | -| 2024/01/24 | 5.2.0-preview5.24024.3 | [release notes](5.2.0-preview5.md) | -| 2023/12/08 | 5.2.0-preview4.23342.2 | [release notes](5.2.0-preview4.md) | -| 2023/07/20 | 5.2.0-preview3.23201.1 | [release notes](5.2.0-preview3.md) | -| 2023/06/08 | 5.2.0-preview2.23159.1 | [release notes](5.2.0-preview2.md) | -| 2023/04/20 | 5.2.0-preview1.23109.1 | [release notes](5.2.0-preview1.md) | +# Release Notes + +## Microsoft.Data.SqlClient 5.2.0 released 28 February 2024 + +This update includes the following changes over the previous release: + +### Contributors +Thanks to the following public contributors. Their efforts toward this project are very much appreciated. + +- [Wraith2](https://github.com/Wraith2) +- [ErikEJ](https://github.com/ErikEJ) +- [kant2002](https://github.com/kant2002) +- [mattjohnsonpint](https://github.com/mattjohnsonpint) +- [azerios](https://github.com/azerios) +- [jinek](https://github.com/jinek) +- [christothes](https://github.com/christothes) +- [panoskj](https://github.com/panoskj) +- [saitama951](https://github.com/saitama951) +- [danielmarbach](https://github.com/danielmarbach) +- [wsugarman](https://github.com/wsugarman) +- [ViktorHofer](https://github.com/ViktorHofer) +- [emidah](https://github.com/emidah) + +### Added + +- Added a new `AccessTokenCallback` API to `SqlConnection`. [#1260](https://github.com/dotnet/SqlClient/pull/1260) [Read more](#added-new-property-accesstokencallback-to-sqlconnection) +- Added `SqlBatch` support on .NET 6+ [#1825](https://github.com/dotnet/SqlClient/pull/1825), [#2223](https://github.com/dotnet/SqlClient/pull/2223), [#2371](https://github.com/dotnet/SqlClient/pull/2371), [#2373](https://github.com/dotnet/SqlClient/pull/2373) [Read more](#added-new-property-sqlbatch-api) +- Added support of `SqlDiagnosticListener` on **.NET Standard**. [#1931](https://github.com/dotnet/SqlClient/pull/1931) +- Added new property `RowsCopied64` to `SqlBulkCopy`. [#2004](https://github.com/dotnet/SqlClient/pull/2004) [Read more](#added-new-property-rowscopied64-to-sqlbulkcopy) +- Added support for the `SuperSocketNetLib` registry option for Encrypt on .NET on Windows. [#2047](https://github.com/dotnet/SqlClient/pull/2047) +- Added the ability to generate debugging symbols in a separate package file [#2137](https://github.com/dotnet/SqlClient/pull/2137) +- Added Workload Identity authentication support [#2159](https://github.com/dotnet/SqlClient/pull/2159), [#2264](https://github.com/dotnet/SqlClient/pull/2264) +- Added support for Big Endian systems [#2170](https://github.com/dotnet/SqlClient/pull/2170) +- Added support for Georgian collation [#2194](https://github.com/dotnet/SqlClient/pull/2194) +- Added Localization support on .NET [#2210](https://github.com/dotnet/SqlClient/pull/2110) +- Added .NET 8 support [#2230](https://github.com/dotnet/SqlClient/pull/2230) +- Added explicit version for major .NET version dependencies on System.Runtime.Caching 8.0.0, System.Configuration.ConfigurationManager 8.0.0, and System.Diagnostics.DiagnosticSource 8.0.0 [#2303](https://github.com/dotnet/SqlClient/pull/2303) + +### Changed + +- Improved parsing buffered characters in `TdsParser`. [#1544](https://github.com/dotnet/SqlClient/pull/1544) +- Added Microsoft.SqlServer.Types to verify support for SqlHierarchyId and Spatial for .NET Core. [#1848](https://github.com/dotnet/SqlClient/pull/1848) +- Moved to new System.Data.SqlTypes APIs in **.NET 7** and upper. [#1934](https://github.com/dotnet/SqlClient/pull/1934) and [#1981](https://github.com/dotnet/SqlClient/pull/1981) +- Removed reference to Microsoft.Win32.Registry since it's shipped starting with .NET 6.0. [#1974](https://github.com/dotnet/SqlClient/pull/1974) +- Changed **[UseOneSecFloorInTimeoutCalculationDuringLogin](https://learn.microsoft.com/sql/connect/ado-net/appcontext-switches#enable-a-minimum-timeout-during-login)** App Context switch default to **true** and extended its effect to .NET and .NET Standard. [#2012](https://github.com/dotnet/SqlClient/pull/2012) +- Updated `Microsoft.Identity.Client` version from 4.47.2 to 4.53.0. [#2031](https://github.com/dotnet/SqlClient/pull/2031), [#2055](https://github.com/dotnet/SqlClient/pull/2055) +- Switched to the new .NET [NegotiateAuthentication](https://learn.microsoft.com/en-us/dotnet/api/system.net.security.negotiateauthentication?view=net-7.0) API on .NET 7.0 and above for SSPI token negotiation using Managed SNI. [#2063](https://github.com/dotnet/SqlClient/pull/2063) +- Removed `ignoreSniOpenTimeout` in open connection process on Windows. [#2067](https://github.com/dotnet/SqlClient/pull/2067) +- Enforce explicit ordinal for internal `StringComparison` operations. [#2068](https://github.com/dotnet/SqlClient/pull/2068) +- Improved error messages when validating server certificates in managed SNI (Linux/macOS) [#2060](https://github.com/dotnet/SqlClient/pull/2060) +- Improved CPU usage when `AppContext` switches are in use [#2227](https://github.com/dotnet/SqlClient/pull/2227) +- Upgraded `Azure.Identity` dependency version to [1.10.3](https://www.nuget.org/packages/Azure.Identity/1.10.3) to address [CVE-2023-36414](https://github.com/advisories/GHSA-5mfx-4wcx-rv27), [#2189](https://github.com/dotnet/SqlClient/pull/2189) +- Changed Microsoft.IdentityModel.JsonWebTokens and Microsoft.IdentityModel.Protocols.OpenIdConnect version 6.24.0 to 6.35.0 [#2290](https://github.com/dotnet/SqlClient/pull/2290) to address [CVE-2024-21319](https://www.cve.org/CVERecord?id=CVE-2024-21319) +- Updated `Microsoft.Data.SqlClient.SNI` (.NET Framework dependency) and `Microsoft.Data.SqlClient.SNI.runtime` (.NET/.NET Standard dependency) version to `v5.2.0`. [#2363](https://github.com/dotnet/SqlClient/pull/2363), which includes removing dead code and addressing static analysis warnings +- Code health improvements: [#1198](https://github.com/dotnet/SqlClient/pull/1198), [#1829](https://github.com/dotnet/SqlClient/pull/1829), [#1943](https://github.com/dotnet/SqlClient/pull/1943), [#1949](https://github.com/dotnet/SqlClient/pull/1949), [#1959](https://github.com/dotnet/SqlClient/pull/1959), [#1985](https://github.com/dotnet/SqlClient/pull/1985), [#2071](https://github.com/dotnet/SqlClient/pull/2071), [#2073](https://github.com/dotnet/SqlClient/pull/2073), [#2088](https://github.com/dotnet/SqlClient/pull/2088), [#2091](https://github.com/dotnet/SqlClient/pull/2091), [#2098](https://github.com/dotnet/SqlClient/pull/2098), [#2121](https://github.com/dotnet/SqlClient/pull/2121), [#2122](https://github.com/dotnet/SqlClient/pull/2122), [#2132](https://github.com/dotnet/SqlClient/pull/2132), [#2136](https://github.com/dotnet/SqlClient/pull/2136), [#2144](https://github.com/dotnet/SqlClient/pull/2144), [#2147](https://github.com/dotnet/SqlClient/pull/2147), [#2157](https://github.com/dotnet/SqlClient/pull/2157), [#2164](https://github.com/dotnet/SqlClient/pull/2164), [#2166](https://github.com/dotnet/SqlClient/pull/2166), [#2168](https://github.com/dotnet/SqlClient/pull/2168), [#2186](https://github.com/dotnet/SqlClient/pull/2186), [#2254](https://github.com/dotnet/SqlClient/pull/2254), [#2288](https://github.com/dotnet/SqlClient/pull/2288), [#2305](https://github.com/dotnet/SqlClient/pull/2305), [#2317](https://github.com/dotnet/SqlClient/pull/2317) + +### Fixed + +- Fixed Always Encrypted secure enclave retry logic for async queries. [#1988](https://github.com/dotnet/SqlClient/pull/1988) +- Fixed activity correlator to continue use of same GUID for connection activity. [#1997](https://github.com/dotnet/SqlClient/pull/1997) +- Fixed behavior when error class is greater than 20 on connection retry. [#1953](https://github.com/dotnet/SqlClient/pull/1953) +- Fixed error message when symmetric key decryption failed using Always Encrypted. [#1948](https://github.com/dotnet/SqlClient/pull/1948) +- Fixed TransactionScope connection issue when Enlist is enable, Pooling is disabled and network connection type is Redirect. [#1960](https://github.com/dotnet/SqlClient/pull/1960) +- Fixed TDS RPC error on large queries in SqlCommand.ExecuteReaderAsync. [#1936](https://github.com/dotnet/SqlClient/pull/1936) +- Fixed throttling of token requests by calling AcquireTokenSilent. [#1925](https://github.com/dotnet/SqlClient/pull/1925) +- Fixed Linux code coverage result in Build proj. [#1950](https://github.com/dotnet/SqlClient/pull/1950) +- Fixed NullReferenceException in GetBytesAsync. [#1906](https://github.com/dotnet/SqlClient/pull/1906) +- Fixed Transient fault handling issue with OpenAsync. [#1983](https://github.com/dotnet/SqlClient/pull/1983) +- Fixed invariant mode checks. [#1917](https://github.com/dotnet/SqlClient/pull/1917) +- Fixed GC behavior in TdsParser by adding array rental capability in TryReadPlpUnicodeChars. [#1866](https://github.com/dotnet/SqlClient/pull/1866) +- Fixed socket synchronization issue during connect in managed SNI. [#1029](https://github.com/dotnet/SqlClient/pull/1029) +- Fixed issue with `SqlConnectionStringBuilder` property indexer not supporting non-string values. [#2018](https://github.com/dotnet/SqlClient/pull/2018) +- Fixed `SqlDataAdapter.Fill` and configurable retry logic issue on .NET Framework. [#2084](https://github.com/dotnet/SqlClient/pull/2084) +- Fixed `SqlConnectionEncryptOption` type conversion by introducing the `SqlConnectionEncryptOptionConverter` attribute when using **appsettings.json** files. [#2057](https://github.com/dotnet/SqlClient/pull/2057) +- Fixed th-TH culture info issue on Managed SNI. [#2066](https://github.com/dotnet/SqlClient/pull/2066) +- Fixed an issue when using the Authentication option, but not encrypting on .NET Framework where the server certificate was being incorrectly validated [#2224](https://github.com/dotnet/SqlClient/pull/2224) +- Fixed a deadlock problem for distributed transactions when on .NET [#2161](https://github.com/dotnet/SqlClient/pull/2161) +- Fixed an issue with connecting to named instances on named pipes in managed SNI (Linux/macOS) [#2142](https://github.com/dotnet/SqlClient/pull/2142) +- Fixed LocalDb connection issue with an invalid source when using managed SNI [#2129](https://github.com/dotnet/SqlClient/pull/2129) +- Fixed an `AccessViolationException` when using a SQL Express user instance [#2101](https://github.com/dotnet/SqlClient/pull/2101) +- Fixed a metadata query issue when connecting to Azure SQL Edge [#2099](https://github.com/dotnet/SqlClient/pull/2099) +- Fixed file version information for .NET and .NET Standard binaries [#2093](https://github.com/dotnet/SqlClient/pull/2093) +- Fixed the SPN sent for a named instance when using Kerberos authentication on Linux/macOS [#2240](https://github.com/dotnet/SqlClient/pull/2240) +- Fixed connection to unsubscribe from transaction completion events before returning it to the connection pool [#2301](https://github.com/dotnet/SqlClient/pull/2301) +- Fixed InvalidCastException when reading an Always Encrypted date or time column [#2275](https://github.com/dotnet/SqlClient/pull/2275) +- Fixed token caching to prevent expired access tokens from being reused in a connection pool [#2273](https://github.com/dotnet/SqlClient/pull/2273) + +## New features + +### Added new property `SQLBatch API` + +```csharp +using Microsoft.Data.SqlClient; + +class Program +{ + static void Main() + { + string str = "Data Source=(local);Initial Catalog=Northwind;" + + "Integrated Security=SSPI;Encrypt=False"; + RunBatch(str); + } + + static void RunBatch(string connString) + { + using var connection = new SqlConnection(connString); + connection.Open(); + + var batch = new SqlBatch(connection); + + const int count = 10; + const string parameterName = "parameter"; + for (int i = 0; i < count; i++) + { + var batchCommand = new SqlBatchCommand($"SELECT @{parameterName} as value"); + batchCommand.Parameters.Add(new SqlParameter(parameterName, i)); + batch.BatchCommands.Add(batchCommand); + } + + // Optionally Prepare + batch.Prepare(); + + var results = new List(count); + using (SqlDataReader reader = batch.ExecuteReader()) + { + do + { + while (reader.Read()) + { + results.Add(reader.GetFieldValue(0)); + } + } while (reader.NextResult()); + } + Console.WriteLine(string.Join(", ", results)); + } +} +``` + +### Added new property `RowsCopied64` to SqlBulkCopy + +SqlBulkCopy has a new property `RowsCopied64` which supports `long` value types. + +**Note that the existing `SqlBulkCopy.RowsCopied` behavior is unchanged. When the value exceeds `int.MaxValue`, `RowsCopied` can return a negative number.** + +Example usage: + +```C# + using (SqlConnection srcConn = new SqlConnection(srcConstr)) + using (SqlCommand srcCmd = new SqlCommand("select top 5 * from employees", srcConn)) + { + srcConn.Open(); + using (DbDataReader reader = srcCmd.ExecuteReader()) + { + using (SqlBulkCopy bulkcopy = new SqlBulkCopy(dstConn)) + { + bulkcopy.DestinationTableName = dstTable; + SqlBulkCopyColumnMappingCollection ColumnMappings = bulkcopy.ColumnMappings; + + ColumnMappings.Add("EmployeeID", "col1"); + ColumnMappings.Add("LastName", "col2"); + ColumnMappings.Add("FirstName", "col3"); + + bulkcopy.WriteToServer(reader); + long rowsCopied = bulkcopy.RowsCopied64; + } + } + } +``` + +### Added new property `AccessTokenCallback` to SqlConnection + +SqlConnection supports `TokenCredential` authentication by introducing a new `AccessTokenCallback` property as a `Func>` delegate to return a federated authentication access token. + +Example usage: + +```C# + using Microsoft.Data.SqlClient; + using Azure.Identity; + + const string defaultScopeSuffix = "/.default"; + string connectionString = GetConnectionString(); + using SqlConnection connection = new SqlConnection(connectionString); + + connection.AccessTokenCallback = async (authParams, cancellationToken) => + { + var cred = new DefaultAzureCredential(); + string scope = authParams.Resource.EndsWith(defaultScopeSuffix) ? authParams.Resource : authParams.Resource + defaultScopeSuffix; + AccessToken token = await cred.GetTokenAsync(new TokenRequestContext(new[] { scope }), cancellationToken); + return new SqlAuthenticationToken(token.Token, token.ExpiresOn); + } + + connection.Open(); + Console.WriteLine("ServerVersion: {0}", connection.ServerVersion); + Console.WriteLine("State: {0}", connection.State); +``` + +## Target Platform Support + +- .NET Framework 4.6.2+ (Windows x86, Windows x64) +- .NET 6.0+ (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.2.0 +- Azure.Identity 1.10.3 +- Microsoft.Identity.Client 4.56.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Runtime.InteropServices.RuntimeInformation 4.3.0 +- System.Text.Encoding.Web 6.0.0 + +#### .NET 6 + +- Microsoft.Data.SqlClient.SNI.runtime 5.2.0 +- Azure.Identity 1.10.3 +- Microsoft.Identity.Client 4.56.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Diagnostics.DiagnosticSource 6.0.1 +- System.Runtime.Caching 6.0.0 + +#### .NET 8 + +- Microsoft.Data.SqlClient.SNI.runtime 5.2.0 +- Azure.Identity 1.10.3 +- Microsoft.Identity.Client 4.56.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- System.Configuration.ConfigurationManager 8.0.0 +- System.Diagnostics.DiagnosticSource 8.0.0 +- System.Runtime.Caching 8.0.0 + +#### .NET Standard 2.0 + +- Microsoft.Data.SqlClient.SNI.runtime 5.2.0 +- Azure.Identity 1.10.3 +- Microsoft.Identity.Client 4.56.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Buffers 4.5.1 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Diagnostics.DiagnosticSource 6.0.1 +- System.Runtime.Caching 6.0.0 +- System.Text.Encoding.CodePages 6.0.0 +- System.Text.Encodings.Web 6.0.0 +- System.Runtime.Loader 4.3.0 +- System.Security.Cryptography.Cng 5.0.0 +- System.Security.Principal.Windows 5.0.0 + +#### .NET Standard 2.1 + +- Microsoft.Data.SqlClient.SNI.runtime 5.2.0 +- Azure.Identity 1.10.3 +- Microsoft.Identity.Client 4.56.0 +- Microsoft.IdentityModel.Protocols.OpenIdConnect 6.35.0 +- Microsoft.IdentityModel.JsonWebTokens 6.35.0 +- Microsoft.SqlServer.Server 1.0.0 +- Microsoft.Win32.Registry 5.0.0 +- System.Configuration.ConfigurationManager 6.0.1 +- System.Diagnostics.DiagnosticSource 6.0.1 +- System.Runtime.Caching 6.0.0 +- System.Text.Encoding.CodePages 6.0.0 +- System.Text.Encodings.Web 6.0.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/5.2/5.2.md b/release-notes/5.2/5.2.md new file mode 100644 index 0000000000..8193904e37 --- /dev/null +++ b/release-notes/5.2/5.2.md @@ -0,0 +1,18 @@ +# Microsoft.Data.SqlClient 5.2 Releases + +The following Microsoft.Data.SqlClient 5.2 stable releases have been shipped: + +| Release Date | Version | Notes | +| :-- | :-- | :--: | +| 2024/02/28 | 5.2.0 | [release notes](5.2.0.md) | + +The following Microsoft.Data.SqlClient 5.2 preview releases have been shipped: + +| Release Date | Version | Notes | +| :-- | :-- | :--: | +| 2024/01/24 | 5.2.0-preview5.24024.3 | [release notes](5.2.0-preview5.md) | +| 2023/12/08 | 5.2.0-preview4.23342.2 | [release notes](5.2.0-preview4.md) | +| 2023/07/20 | 5.2.0-preview3.23201.1 | [release notes](5.2.0-preview3.md) | +| 2023/06/08 | 5.2.0-preview2.23159.1 | [release notes](5.2.0-preview2.md) | +| 2023/04/20 | 5.2.0-preview1.23109.1 | [release notes](5.2.0-preview1.md) | + diff --git a/release-notes/5.2/README.md b/release-notes/5.2/README.md index 8d4c031aea..a311f99484 100644 --- a/release-notes/5.2/README.md +++ b/release-notes/5.2/README.md @@ -1,5 +1,11 @@ # Microsoft.Data.SqlClient 5.2 Releases +The following Microsoft.Data.SqlClient 5.2 stable releases have been shipped: + +| Release Date | Version | Notes | +| :-- | :-- | :--: | +| 2024/02/28 | 5.2.0 | [release notes](5.2.0.md) | + The following Microsoft.Data.SqlClient 5.2 preview releases have been shipped: | Release Date | Version | Notes | diff --git a/release-notes/README.md b/release-notes/README.md index 94f7459695..8a23b21e3b 100644 --- a/release-notes/README.md +++ b/release-notes/README.md @@ -1,6 +1,6 @@ # Microsoft.Data.SqlClient Release Notes -The latest stable release is [Microsoft.Data.SqlClient 5.1](5.1). +The latest stable release is [Microsoft.Data.SqlClient 5.2](5.2). ## Release Information @@ -18,7 +18,7 @@ The latest stable release is [Microsoft.Data.SqlClient 5.1](5.1). # Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider Release Notes -The latest stable release is [Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider 3.0](add-ons/AzureKeyVaultProvider/3.0). +The latest stable release is [Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider 5.1](add-ons/AzureKeyVaultProvider/5.1). ## Release Information diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 27b5f364dd..1fa393eccb 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -15,10 +15,8 @@ "Project" => Build and run tests with Microsoft.Data.SqlClient as Project Reference "Package" => Build and run tests with Microsoft.Data.SqlClient as Package Reference with configured "TestMicrosoftDataSqlClientVersion" in "Versions.props" file. - "NetStandard" => Build and run tests with Microsoft.Data.SqlClient as Project Reference via .NET Standard Library - "NetStandardPackage" => Build and run tests with Microsoft.Data.SqlClient as Package Reference via .NET Standard Library - ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" AND "NETSTANDARDPACKAGE" REFERENCE TYPES *************** + ************** IMPORTANT NOTE BEFORE PROCEEDING WITH "PACKAGE" REFERENCE TYPE *************** CREATE A NUGET PACKAGE WITH BELOW COMMAND AND ADD TO LOCAL FOLDER + UPDATE NUGET CONFIG FILE TO READ FROM THAT LOCATION > msbuild -p:configuration=Release --> @@ -51,6 +49,7 @@ $(ManagedSourceCode)src\Resources\ $(ManagedSourceCode)add-ons\ $(RepoRoot)src\Microsoft.SqlServer.Server\ + $(RepoRoot)src\Microsoft.Data.SqlClient\src\ $(Artifacts)obj\ $(NetCoreSource)src\Common\src $(NetCoreSource)src\Common\tests @@ -95,5 +94,10 @@ - + + + + + false + diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index b09409f828..04668c8f81 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -78,6 +78,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.Sql", "Microsoft.Data.Sql", "{0CE216CE-8072-4985-B248-61F0D0BE9C2E}" ProjectSection(SolutionItems) = preProject ..\doc\snippets\Microsoft.Data.Sql\SqlNotificationRequest.xml = ..\doc\snippets\Microsoft.Data.Sql\SqlNotificationRequest.xml + ..\doc\snippets\Microsoft.Data.Sql\SqlDataSourceEnumerator.xml = ..\doc\snippets\Microsoft.Data.Sql\SqlDataSourceEnumerator.xml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlClient", "Microsoft.Data.SqlClient", "{C05F4FFE-6A14-4409-AA0A-10630BE4F1EE}" @@ -142,6 +143,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlClient", ..\doc\snippets\Microsoft.Data.SqlClient\SqlRowUpdatingEventArgs.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlRowUpdatingEventArgs.xml ..\doc\snippets\Microsoft.Data.SqlClient\SqlRowUpdatingEventHandler.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlRowUpdatingEventHandler.xml ..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlTransaction.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlBulkCopyColumnOrderHint.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlBulkCopyColumnOrderHint.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlBulkCopyColumnOrderHintCollection.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlBulkCopyColumnOrderHintCollection.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlConfigurableRetryFactory.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlConfigurableRetryFactory.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionIPAddressPreference.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionIPAddressPreference.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionOverrides.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlConnectionOverrides.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryingEventArgs.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryingEventArgs.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryIntervalBaseEnumerator.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryIntervalBaseEnumerator.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryLogicBase.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryLogicBase.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryLogicBaseProvider.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryLogicBaseProvider.xml + ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryLogicOption.xml = ..\doc\snippets\Microsoft.Data.SqlClient\SqlRetryLogicOption.xml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlClient.DataClassification", "Microsoft.Data.SqlClient.DataClassification", "{5D1F0032-7B0D-4FB6-A969-FCFB25C9EA1D}" @@ -151,22 +162,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlClient.Da ..\doc\snippets\Microsoft.Data.SqlClient.DataClassification\Label.xml = ..\doc\snippets\Microsoft.Data.SqlClient.DataClassification\Label.xml ..\doc\snippets\Microsoft.Data.SqlClient.DataClassification\SensitivityClassification.xml = ..\doc\snippets\Microsoft.Data.SqlClient.DataClassification\SensitivityClassification.xml ..\doc\snippets\Microsoft.Data.SqlClient.DataClassification\SensitivityProperty.xml = ..\doc\snippets\Microsoft.Data.SqlClient.DataClassification\SensitivityProperty.xml + ..\doc\snippets\Microsoft.Data.SqlClient.DataClassification\SensitivityRank.xml = ..\doc\snippets\Microsoft.Data.SqlClient.DataClassification\SensitivityRank.xml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlClient.Server", "Microsoft.Data.SqlClient.Server", "{650EB7FA-EB0D-4F8E-AB2C-161C3AD8E363}" ProjectSection(SolutionItems) = preProject - ..\doc\snippets\Microsoft.Data.SqlClient.Server\DataAccessKind.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\DataAccessKind.xml - ..\doc\snippets\Microsoft.Data.SqlClient.Server\Format.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\Format.xml - ..\doc\snippets\Microsoft.Data.SqlClient.Server\IBinarySerialize.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\IBinarySerialize.xml - ..\doc\snippets\Microsoft.Data.SqlClient.Server\InvalidUdtException.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\InvalidUdtException.xml ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlDataRecord.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlDataRecord.xml - ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlFacetAttribute.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlFacetAttribute.xml - ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlFunctionAttribute.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlFunctionAttribute.xml ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlMetaData.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlMetaData.xml - ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlMethodAttribute.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlMethodAttribute.xml - ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlUserDefinedAggregateAttribute.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlUserDefinedAggregateAttribute.xml - ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlUserDefinedTypeAttribute.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\SqlUserDefinedTypeAttribute.xml - ..\doc\snippets\Microsoft.Data.SqlClient.Server\SystemDataAccessKind.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\SystemDataAccessKind.xml ..\doc\snippets\Microsoft.Data.SqlClient.Server\TriggerAction.xml = ..\doc\snippets\Microsoft.Data.SqlClient.Server\TriggerAction.xml EndProjectSection EndProject @@ -177,12 +179,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.SqlTypes", " EndProject Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{F5DF2FDC-C860-4CB3-8B24-7C903C6FC076}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient.NSLibrary", "Microsoft.Data.SqlClient\tests\NSLibrary\Microsoft.Data.SqlClient.NSLibrary.csproj", "{E7336BFB-8521-423A-A140-3123F9065C5D}" - ProjectSection(ProjectDependencies) = postProject - {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} - {407890AC-9876-4FEF-A6F1-F36A876BAADE} = {407890AC-9876-4FEF-A6F1-F36A876BAADE} - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient.TestUtilities", "Microsoft.Data.SqlClient\tests\tools\Microsoft.Data.SqlClient.TestUtilities\Microsoft.Data.SqlClient.TestUtilities.csproj", "{89D6D382-9B36-43C9-A912-03802FDA8E36}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient.ExtUtilities", "Microsoft.Data.SqlClient\tests\tools\Microsoft.Data.SqlClient.ExtUtilities\Microsoft.Data.SqlClient.ExtUtilities.csproj", "{E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}" @@ -197,9 +193,29 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient.PerformanceTests", "Microsoft.Data.SqlClient\tests\PerformanceTests\Microsoft.Data.SqlClient.PerformanceTests.csproj", "{599A336B-2A5F-473D-8442-1223ED37C93E}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{4F3CD363-B1E6-4D6D-9466-97D78A56BE45}" + ProjectSection(SolutionItems) = preProject + Directory.Build.props = Directory.Build.props + NuGet.config = NuGet.config + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SqlServer.Server", "Microsoft.SqlServer.Server\Microsoft.SqlServer.Server.csproj", "{A314812A-7820-4565-A2A8-ABBE391C11E4}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.SqlServer.Server", "Microsoft.SqlServer.Server", "{869A9BCC-D303-4365-9BF7-958CD6387916}" + ProjectSection(SolutionItems) = preProject + ..\doc\snippets\Microsoft.SqlServer.Server\DataAccessKind.xml = ..\doc\snippets\Microsoft.SqlServer.Server\DataAccessKind.xml + ..\doc\snippets\Microsoft.SqlServer.Server\Format.xml = ..\doc\snippets\Microsoft.SqlServer.Server\Format.xml + ..\doc\snippets\Microsoft.SqlServer.Server\IBinarySerialize.xml = ..\doc\snippets\Microsoft.SqlServer.Server\IBinarySerialize.xml + ..\doc\snippets\Microsoft.SqlServer.Server\InvalidUdtException.xml = ..\doc\snippets\Microsoft.SqlServer.Server\InvalidUdtException.xml + ..\doc\snippets\Microsoft.SqlServer.Server\SqlFacetAttribute.xml = ..\doc\snippets\Microsoft.SqlServer.Server\SqlFacetAttribute.xml + ..\doc\snippets\Microsoft.SqlServer.Server\SqlFunctionAttribute.xml = ..\doc\snippets\Microsoft.SqlServer.Server\SqlFunctionAttribute.xml + ..\doc\snippets\Microsoft.SqlServer.Server\SqlMethodAttribute.xml = ..\doc\snippets\Microsoft.SqlServer.Server\SqlMethodAttribute.xml + ..\doc\snippets\Microsoft.SqlServer.Server\SqlUserDefinedAggregateAttribute.xml = ..\doc\snippets\Microsoft.SqlServer.Server\SqlUserDefinedAggregateAttribute.xml + ..\doc\snippets\Microsoft.SqlServer.Server\SqlUserDefinedTypeAttribute.xml = ..\doc\snippets\Microsoft.SqlServer.Server\SqlUserDefinedTypeAttribute.xml + ..\doc\snippets\Microsoft.SqlServer.Server\SystemDataAccessKind.xml = ..\doc\snippets\Microsoft.SqlServer.Server\SystemDataAccessKind.xml + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestClr", "TestClr", "{CDE508A5-F5D0-4A59-A4EF-978833830727}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -388,18 +404,6 @@ Global {F5DF2FDC-C860-4CB3-8B24-7C903C6FC076}.Release|x64.Build.0 = Release|Any CPU {F5DF2FDC-C860-4CB3-8B24-7C903C6FC076}.Release|x86.ActiveCfg = Release|Any CPU {F5DF2FDC-C860-4CB3-8B24-7C903C6FC076}.Release|x86.Build.0 = Release|Any CPU - {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|x64.ActiveCfg = Debug|x64 - {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|x64.Build.0 = Debug|x64 - {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|x86.ActiveCfg = Debug|x86 - {E7336BFB-8521-423A-A140-3123F9065C5D}.Debug|x86.Build.0 = Debug|x86 - {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|Any CPU.Build.0 = Release|Any CPU - {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|x64.ActiveCfg = Release|x64 - {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|x64.Build.0 = Release|x64 - {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|x86.ActiveCfg = Release|x86 - {E7336BFB-8521-423A-A140-3123F9065C5D}.Release|x86.Build.0 = Release|x86 {89D6D382-9B36-43C9-A912-03802FDA8E36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {89D6D382-9B36-43C9-A912-03802FDA8E36}.Debug|Any CPU.Build.0 = Debug|Any CPU {89D6D382-9B36-43C9-A912-03802FDA8E36}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -483,11 +487,7 @@ Global {8DC9D1A0-351B-47BC-A90F-B9DA542550E9} = {0CC4817A-12F3-4357-912C-09315FAAD008} {D2D1E2D1-B6E0-489F-A36D-1F3047AB87B9} = {0CC4817A-12F3-4357-912C-09315FAAD008} {37431336-5307-4184-9356-C4B7E47DC714} = {28E5EFE6-C9DD-4FF9-9FEC-532F72DFFA6E} - {D1392B54-998A-4F27-BC17-4CE149117BCC} = {0CC4817A-12F3-4357-912C-09315FAAD008} {45DB5F86-7AE3-45C6-870D-F9357B66BDB5} = {0CC4817A-12F3-4357-912C-09315FAAD008} - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F} = {0CC4817A-12F3-4357-912C-09315FAAD008} - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E} = {0CC4817A-12F3-4357-912C-09315FAAD008} - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E} = {0CC4817A-12F3-4357-912C-09315FAAD008} {A2E7E470-5EFF-4828-B55E-FCBA3650F51C} = {28E5EFE6-C9DD-4FF9-9FEC-532F72DFFA6E} {1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B} = {A2E7E470-5EFF-4828-B55E-FCBA3650F51C} {771F3F1E-7A68-4A9D-ADA8-A24F1D5BE71D} = {3FDD425C-FE01-4B56-863E-1FCDD0677CF5} @@ -500,13 +500,18 @@ Global {5D1F0032-7B0D-4FB6-A969-FCFB25C9EA1D} = {71F356DC-DFA3-4163-8BFE-D268722CE189} {650EB7FA-EB0D-4F8E-AB2C-161C3AD8E363} = {71F356DC-DFA3-4163-8BFE-D268722CE189} {5A7600BD-AED8-44AB-8F2A-7CB33A8D9C02} = {71F356DC-DFA3-4163-8BFE-D268722CE189} - {E7336BFB-8521-423A-A140-3123F9065C5D} = {0CC4817A-12F3-4357-912C-09315FAAD008} {89D6D382-9B36-43C9-A912-03802FDA8E36} = {0CC4817A-12F3-4357-912C-09315FAAD008} {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B} = {0CC4817A-12F3-4357-912C-09315FAAD008} {B499E477-C9B1-4087-A5CF-5C762D90E433} = {0CC4817A-12F3-4357-912C-09315FAAD008} {B93A3149-67E8-491E-A1E5-19D65F9D9E98} = {0CC4817A-12F3-4357-912C-09315FAAD008} {599A336B-2A5F-473D-8442-1223ED37C93E} = {0CC4817A-12F3-4357-912C-09315FAAD008} {A314812A-7820-4565-A2A8-ABBE391C11E4} = {4F3CD363-B1E6-4D6D-9466-97D78A56BE45} + {869A9BCC-D303-4365-9BF7-958CD6387916} = {71F356DC-DFA3-4163-8BFE-D268722CE189} + {CDE508A5-F5D0-4A59-A4EF-978833830727} = {0CC4817A-12F3-4357-912C-09315FAAD008} + {D1392B54-998A-4F27-BC17-4CE149117BCC} = {CDE508A5-F5D0-4A59-A4EF-978833830727} + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F} = {CDE508A5-F5D0-4A59-A4EF-978833830727} + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E} = {CDE508A5-F5D0-4A59-A4EF-978833830727} + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E} = {CDE508A5-F5D0-4A59-A4EF-978833830727} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {01D48116-37A2-4D33-B9EC-94793C702431} diff --git a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props index 3ec7e5a49c..4ec39ed694 100644 --- a/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props +++ b/src/Microsoft.Data.SqlClient/add-ons/Directory.Build.props @@ -17,7 +17,6 @@ net462 - netstandard2.0 net6.0 @@ -28,14 +27,13 @@ - $(TargetNetFxVersion);$(TargetNetCoreVersion);$(TargetNetStandardVersion) - $(TargetNetCoreVersion);$(TargetNetStandardVersion) + $(TargetNetCoreVersion);$(TargetNetFxVersion) + $(TargetNetCoreVersion) - netstandard2.0;netstandard2.1 net6.0;net8.0 net462 diff --git a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.NetStandard.cs deleted file mode 100644 index bdb2042b84..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.NetStandard.cs +++ /dev/null @@ -1,16 +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. -// ------------------------------------------------------------------------------ -// Changes to this file must follow the http://aka.ms/api-review process. -// ------------------------------------------------------------------------------ - -namespace Microsoft.Data.SqlClient -{ - /// - public sealed partial class ActiveDirectoryAuthenticationProvider : SqlAuthenticationProvider - { - /// - public void SetParentActivityOrWindowFunc(System.Func parentActivityOrWindowFunc) { } - } -} 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 ba7a1cd534..72203bb433 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.cs @@ -189,23 +189,23 @@ public class SqlAuthenticationParameters /// protected SqlAuthenticationParameters(Microsoft.Data.SqlClient.SqlAuthenticationMethod authenticationMethod, string serverName, string databaseName, string resource, string authority, string userId, string password, System.Guid connectionId, int connectionTimeout) { } /// - public Microsoft.Data.SqlClient.SqlAuthenticationMethod AuthenticationMethod { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public Microsoft.Data.SqlClient.SqlAuthenticationMethod AuthenticationMethod { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } /// - public string Authority { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public string Authority { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } /// - public System.Guid ConnectionId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public System.Guid ConnectionId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } /// - public string DatabaseName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public string DatabaseName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } /// - public string Password { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public string Password { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } /// - public string Resource { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public string Resource { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } /// - public string ServerName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public string ServerName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } /// - public string UserId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public string UserId { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } /// - public int ConnectionTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public int ConnectionTimeout { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } } /// public abstract partial class SqlAuthenticationProvider @@ -231,9 +231,9 @@ public partial class SqlAuthenticationToken /// public SqlAuthenticationToken(string accessToken, System.DateTimeOffset expiresOn) { } /// - public string AccessToken { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public string AccessToken { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } /// - public System.DateTimeOffset ExpiresOn { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } } + public System.DateTimeOffset ExpiresOn { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } } } /// public sealed partial class SqlBulkCopy : System.IDisposable @@ -427,6 +427,14 @@ internal SqlClientFactory() { } public override System.Data.Common.DbDataAdapter CreateDataAdapter() { throw null; } /// public override System.Data.Common.DbParameter CreateParameter() { throw null; } + /// + public override System.Data.Common.DbDataSourceEnumerator CreateDataSourceEnumerator() { throw null; } + /// + public override bool CanCreateBatch { get { throw null; } } + /// + public override System.Data.Common.DbBatch CreateBatch() { throw null; } + /// + public override System.Data.Common.DbBatchCommand CreateBatchCommand() { throw null; } } /// public partial class SqlClientLogger @@ -478,7 +486,7 @@ public static partial class SqlClientMetaDataCollectionNames /// public static readonly string StructuredTypeMembers; } -#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER +#if NET6_0_OR_GREATER /// public enum SqlConnectionAttestationProtocol { @@ -1017,7 +1025,7 @@ public SqlConnectionStringBuilder(string connectionString) { } [System.ComponentModel.DisplayNameAttribute("Data Source")] [System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.All)] public string DataSource { get { throw null; } set { } } -#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER +#if NET6_0_OR_GREATER /// [System.ComponentModel.DisplayNameAttribute("Attestation Protocol")] [System.ComponentModel.RefreshPropertiesAttribute(System.ComponentModel.RefreshProperties.All)] @@ -1444,7 +1452,7 @@ internal SqlException() { } public byte State { get { throw null; } } /// -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK [System.Security.Permissions.SecurityPermissionAttribute(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)] #endif #if NET8_0_OR_GREATER 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 9ab6b8d80f..498849102a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/ref/Microsoft.Data.SqlClient.csproj @@ -1,32 +1,23 @@  false - net8.0;net6.0;netstandard2.0;netstandard2.1 - netstandard2.1 + net6.0;net8.0 $(ObjFolder)$(Configuration)\$(AssemblyName)\ref\ $(BinFolder)$(Configuration)\$(AssemblyName)\ref\ $(OutputPath)\$(TargetFramework)\Microsoft.Data.SqlClient.xml Core $(BaseProduct) Debug;Release; netcoreapp - netstandard AnyCPU;x64;x86 - - - - - - - - + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.CloseHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.CloseHandle.cs index ff41f939f1..f133f10156 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.CloseHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/CoreLib/Interop/Windows/Kernel32/Interop.CloseHandle.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. +#if !NET8_0_OR_GREATER + using System; using System.Runtime.InteropServices; @@ -13,3 +15,5 @@ internal partial class Kernel32 internal static extern bool CloseHandle(IntPtr handle); } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/Interop.Libraries.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/Interop.Libraries.cs index c4f2f36493..7b74001a4f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/Interop.Libraries.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/Interop.Libraries.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. +#if !NET8_0_OR_GREATER + internal static partial class Interop { internal static partial class Libraries @@ -10,3 +12,5 @@ internal static partial class Libraries internal const string NetSecurityNative = "System.Net.Security.Native"; } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs index b08b41aeb2..34bc0b18dd 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssApiException.cs @@ -2,9 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Data; +#if !NET8_0_OR_GREATER + using System; using System.Runtime.InteropServices; +using Microsoft.Data; internal static partial class Interop { @@ -56,3 +58,5 @@ private static string GetGssApiDisplayStatus(Status status, bool isMinor) } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssBuffer.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssBuffer.cs index 0f479a8c62..112289bc7d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssBuffer.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.GssBuffer.cs @@ -2,10 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Data; +#if !NET8_0_OR_GREATER + using System; using System.Diagnostics; using System.Runtime.InteropServices; +using Microsoft.Data; internal static partial class Interop { @@ -74,3 +76,5 @@ static GssBuffer() } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs index 489d1cf8a9..f5e7d18f24 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Unix/System.Net.Security.Native/Interop.NetSecurityNative.cs @@ -2,8 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if !NET8_0_OR_GREATER + using System; -using System.Diagnostics; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; @@ -126,3 +127,5 @@ static NetSecurityNative() } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Crypt32/Interop.certificates.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Crypt32/Interop.certificates.cs index 2fb8e48a1d..6b8e616894 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Crypt32/Interop.certificates.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Crypt32/Interop.certificates.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. +#if !NET8_0_OR_GREATER + using System; using System.Runtime.InteropServices; @@ -24,3 +26,5 @@ internal static extern bool CertVerifyCertificateChainPolicy( [In, Out] ref CERT_CHAIN_POLICY_STATUS pPolicyStatus); } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Crypt32/Interop.certificates_types.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Crypt32/Interop.certificates_types.cs index cbf5c3309e..c120f1ba71 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Crypt32/Interop.certificates_types.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Crypt32/Interop.certificates_types.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. +#if !NET8_0_OR_GREATER + using System; using System.Runtime.InteropServices; @@ -125,3 +127,5 @@ internal unsafe struct CERT_CHAIN_POLICY_STATUS } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Interop.Libraries.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Interop.Libraries.cs index 40308195e7..f3c5526e0f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Interop.Libraries.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/Interop.Libraries.cs @@ -9,7 +9,7 @@ internal static partial class Libraries internal const string Crypt32 = "crypt32.dll"; internal const string Kernel32 = "kernel32.dll"; internal const string NtDll = "ntdll.dll"; -#if !NET7_0_OR_GREATER +#if !NET8_0_OR_GREATER internal const string SspiCli = "sspicli.dll"; #endif } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/SChannel/Interop.SECURITY_STATUS.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/SChannel/Interop.SECURITY_STATUS.cs index 435de74c59..dfd98621d6 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/SChannel/Interop.SECURITY_STATUS.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/SChannel/Interop.SECURITY_STATUS.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. +#if !NET8_0_OR_GREATER + internal static partial class Interop { internal enum SECURITY_STATUS @@ -358,3 +360,5 @@ internal static string MapSecurityStatus(uint statusCode) } #endif // TRACE_VERBOSE } + +#endif // !NET8_OR_GREATER diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/SChannel/SecPkgContext_ConnectionInfo.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/SChannel/SecPkgContext_ConnectionInfo.cs index 57b6eb3405..762c3ea146 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/SChannel/SecPkgContext_ConnectionInfo.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/SChannel/SecPkgContext_ConnectionInfo.cs @@ -2,7 +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.Diagnostics; +#if !NET8_0_OR_GREATER + using System.Runtime.InteropServices; namespace System.Net @@ -45,3 +46,5 @@ internal unsafe SecPkgContext_ConnectionInfo(byte[] nativeBuffer) } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/GlobalSSPI.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/GlobalSSPI.cs index 78571c5c96..6077ba5a77 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/GlobalSSPI.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/GlobalSSPI.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. +#if !NET8_0_OR_GREATER + namespace System.Net { internal static class GlobalSSPI @@ -10,3 +12,5 @@ internal static class GlobalSSPI internal static readonly SSPIInterface SSPISecureChannel = new SSPISecureChannelType(); } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/Interop.SSPI.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/Interop.SSPI.cs index 8ceed0e870..bb8d1ede6a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/Interop.SSPI.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/Interop.SSPI.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. +#if !NET8_0_OR_GREATER + using System; using System.Net.Security; using System.Runtime.InteropServices; @@ -388,3 +390,5 @@ internal static extern unsafe SECURITY_STATUS SspiEncodeStringsAsAuthIdentity( [Out] out SafeSspiAuthDataHandle authData); } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/NegotiationInfoClass.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/NegotiationInfoClass.cs index f5f7ab1b07..133c935174 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/NegotiationInfoClass.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/NegotiationInfoClass.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. +#if !NET8_0_OR_GREATER + using System.Runtime.InteropServices; namespace System.Net @@ -59,3 +61,5 @@ internal NegotiationInfoClass(SafeHandle safeHandle, int negotiationState) } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIAuthType.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIAuthType.cs index cdb3819605..4a86701ffd 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIAuthType.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIAuthType.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. +#if !NET8_0_OR_GREATER + using System.Net.Security; using System.Runtime.InteropServices; using Microsoft.Data; @@ -199,3 +201,5 @@ public int ApplyControlToken(ref SafeDeleteContext refContext, SecurityBuffer[] } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIInterface.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIInterface.cs index 655dcec07a..22e9a3c93d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIInterface.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIInterface.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. +#if !NET8_0_OR_GREATER + using System.Net.Security; using System.Runtime.InteropServices; @@ -30,3 +32,5 @@ internal interface SSPIInterface int ApplyControlToken(ref SafeDeleteContext refContext, SecurityBuffer[] inputBuffers); } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPISecureChannelType.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPISecureChannelType.cs index 4152a89a7d..e6c213d241 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPISecureChannelType.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPISecureChannelType.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. +#if !NET8_0_OR_GREATER + using System.Net.Security; using System.Runtime.InteropServices; using Microsoft.Data; @@ -155,3 +157,5 @@ public int ApplyControlToken(ref SafeDeleteContext refContext, SecurityBuffer[] } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIWrapper.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIWrapper.cs index f8231f9069..389cd83df3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIWrapper.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SSPIWrapper.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. +#if !NET8_0_OR_GREATER + using System.ComponentModel; using System.Globalization; using System.Net.Security; @@ -595,3 +597,5 @@ public static string ErrorDescription(int errorCode) } } // class SSPIWrapper } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SafeDeleteContext.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SafeDeleteContext.cs index cc9f80164f..7701689286 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SafeDeleteContext.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SafeDeleteContext.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Win32.SafeHandles; +#if !NET8_0_OR_GREATER -using System.Diagnostics; using System.Runtime.InteropServices; -using System.Security.Authentication.ExtendedProtection; namespace System.Net.Security { @@ -53,3 +51,5 @@ public override string ToString() #endif } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_Bindings.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_Bindings.cs index eb31544de1..f5bbb448eb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_Bindings.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_Bindings.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. +#if !NET8_0_OR_GREATER + using System.Runtime.InteropServices; namespace System.Net @@ -14,3 +16,5 @@ internal struct SecPkgContext_Bindings internal IntPtr Bindings; } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_NegotiationInfoW.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_NegotiationInfoW.cs index 4dc03b53a6..a5c71068eb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_NegotiationInfoW.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_NegotiationInfoW.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. +#if !NET8_0_OR_GREATER + using System.Runtime.InteropServices; namespace System.Net @@ -14,3 +16,5 @@ internal struct SecPkgContext_NegotiationInfoW internal uint NegotiationState; } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_Sizes.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_Sizes.cs index 48cdd54d2a..17fce36c6d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_Sizes.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_Sizes.cs @@ -2,7 +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.Diagnostics; +#if !NET8_0_OR_GREATER + using System.Runtime.InteropServices; namespace System.Net @@ -40,3 +41,5 @@ internal unsafe SecPkgContext_Sizes(byte[] memory) public static readonly int SizeOf = Marshal.SizeOf(); } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_StreamSizes.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_StreamSizes.cs index 519b607da7..98ec1a1d60 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_StreamSizes.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecPkgContext_StreamSizes.cs @@ -2,7 +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.Diagnostics; +#if !NET8_0_OR_GREATER + using System.Runtime.InteropServices; namespace System.Net @@ -42,3 +43,5 @@ internal unsafe SecPkgContext_StreamSizes(byte[] memory) public static readonly int SizeOf = Marshal.SizeOf(); } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecurityPackageInfo.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecurityPackageInfo.cs index 3ec3c7fda6..73e9c8635c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecurityPackageInfo.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecurityPackageInfo.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. +#if !NET8_0_OR_GREATER + using System.Runtime.InteropServices; namespace System.Net @@ -18,3 +20,5 @@ internal struct SecurityPackageInfo internal IntPtr Comment; } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecurityPackageInfoClass.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecurityPackageInfoClass.cs index 74fca62e89..433904171e 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecurityPackageInfoClass.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecurityPackageInfoClass.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. +#if !NET8_0_OR_GREATER + using System.Globalization; using System.Runtime.InteropServices; @@ -76,3 +78,5 @@ public override string ToString() } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecuritySafeHandles.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecuritySafeHandles.cs index f78b10697d..428e0e39eb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecuritySafeHandles.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Interop/Windows/sspicli/SecuritySafeHandles.cs @@ -2,12 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Win32.SafeHandles; +#if !NET8_0_OR_GREATER using System.Diagnostics; using System.Globalization; using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; +using Microsoft.Win32.SafeHandles; namespace System.Net.Security { @@ -1279,3 +1280,5 @@ protected override bool ReleaseHandle() } } } + +#endif // !NET8_OR_GREATER diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs deleted file mode 100644 index e7efdad252..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs +++ /dev/null @@ -1,263 +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.Diagnostics; -using System.Threading; - -namespace Microsoft.Data.ProviderBase -{ - internal abstract class DbReferenceCollection - { - private struct CollectionEntry - { - private int _tag; // information about the reference - private WeakReference _weak; // the reference itself. - - public void NewTarget(int tag, object target) - { - Debug.Assert(!TryGetTarget(out object _) , "Entry already has a valid target"); - Debug.Assert(tag != 0, "Bad tag"); - Debug.Assert(target != null, "Invalid target"); - - if (_weak == null) - { - _weak = new WeakReference(target, false); - } - else - { - _weak.SetTarget(target); - } - _tag = tag; - } - - public void RemoveTarget() - { - _tag = 0; - _weak.SetTarget(null); - } - - public int Tag => _tag; - - public bool TryGetTarget(out object target) - { - target = null; - return _tag != 0 && _weak.TryGetTarget(out target); - } - } - - private const int LockPollTime = 100; // Time to wait (in ms) between attempting to get the _itemLock - private const int DefaultCollectionSize = 20; // Default size for the collection, and the amount to grow every time the collection is full - private CollectionEntry[] _items; // The collection of items we are keeping track of - private readonly object _itemLock; // Used to synchronize access to the _items collection - private int _optimisticCount; // (#ItemsAdded - #ItemsRemoved) - This estimates the number of items that we *should* have (but doesn't take into account item targets being GC'd) - private int _lastItemIndex; // Location of the last item in _items - private volatile bool _isNotifying; // Indicates that the collection is currently being notified (and, therefore, about to be cleared) - - protected DbReferenceCollection() - { - _items = new CollectionEntry[DefaultCollectionSize]; - _itemLock = new object(); - _optimisticCount = 0; - _lastItemIndex = 0; - } - - abstract public void Add(object value, int tag); - - protected void AddItem(object value, int tag) - { - Debug.Assert(null != value && 0 != tag, "AddItem with null value or 0 tag"); - bool itemAdded = false; - - lock (_itemLock) - { - // Try to find a free spot - for (int i = 0; i <= _lastItemIndex; ++i) - { - if (_items[i].Tag == 0) - { - _items[i].NewTarget(tag, value); - Debug.Assert(_items[i].TryGetTarget(out object _), "missing expected target"); - itemAdded = true; - break; - } - } - - // No free spots, can we just add on to the end? - if ((!itemAdded) && (_lastItemIndex + 1 < _items.Length)) - { - _lastItemIndex++; - _items[_lastItemIndex].NewTarget(tag, value); - itemAdded = true; - } - - // If no free spots and no space at the end, try to find a dead item - if (!itemAdded) - { - for (int i = 0; i <= _lastItemIndex; ++i) - { - if (!_items[i].TryGetTarget(out object _)) - { - _items[i].NewTarget(tag, value); - Debug.Assert(_items[i].TryGetTarget(out object _), "missing expected target"); - itemAdded = true; - break; - } - } - } - - // If nothing was free, then resize and add to the end - if (!itemAdded) - { - Array.Resize(ref _items, _items.Length * 2); - _lastItemIndex++; - _items[_lastItemIndex].NewTarget(tag, value); - } - - _optimisticCount++; - } - } - - internal T FindItem(int tag, Func filterMethod) where T : class - { - bool lockObtained = false; - try - { - TryEnterItemLock(ref lockObtained); - if (lockObtained) - { - if (_optimisticCount > 0) - { - for (int counter = 0; counter <= _lastItemIndex; counter++) - { - // Check tag (should be easiest and quickest) - if (_items[counter].Tag == tag) - { - if (_items[counter].TryGetTarget(out object value)) - { - // Make sure the item has the correct type and passes the filtering - if (value is T tempItem && filterMethod(tempItem)) - { - return tempItem; - } - } - } - } - } - } - } - finally - { - ExitItemLockIfNeeded(lockObtained); - } - - // If we got to here, then no item was found, so return null - return null; - } - - public void Notify(int message) - { - bool lockObtained = false; - try - { - TryEnterItemLock(ref lockObtained); - if (lockObtained) - { - try - { - _isNotifying = true; - - // Loop through each live item and notify it - if (_optimisticCount > 0) - { - for (int index = 0; index <= _lastItemIndex; ++index) - { - if (_items[index].TryGetTarget(out object value)) - { - NotifyItem(message, _items[index].Tag, value); - _items[index].RemoveTarget(); - } - Debug.Assert(!_items[index].TryGetTarget(out object _), "Unexpected target after notifying"); - } - _optimisticCount = 0; - } - - // Shrink collection (if needed) - if (_items.Length > 100) - { - _lastItemIndex = 0; - _items = new CollectionEntry[DefaultCollectionSize]; - } - } - finally - { - _isNotifying = false; - } - } - } - finally - { - ExitItemLockIfNeeded(lockObtained); - } - } - - abstract protected void NotifyItem(int message, int tag, object value); - - abstract public void Remove(object value); - - protected void RemoveItem(object value) - { - Debug.Assert(null != value, "RemoveItem with null"); - - bool lockObtained = false; - try - { - TryEnterItemLock(ref lockObtained); - - if (lockObtained) - { - // Find the value, and then remove the target from our collection - if (_optimisticCount > 0) - { - for (int index = 0; index <= _lastItemIndex; ++index) - { - if (_items[index].TryGetTarget(out object target) && value == target) - { - _items[index].RemoveTarget(); - _optimisticCount--; - break; - } - } - } - } - } - finally - { - ExitItemLockIfNeeded(lockObtained); - } - } - - // This is polling lock that will abandon getting the lock if _isNotifying is set to true - private void TryEnterItemLock(ref bool lockObtained) - { - // Assume that we couldn't take the lock - lockObtained = false; - // Keep trying to take the lock until either we've taken it, or the collection is being notified - while ((!_isNotifying) && (!lockObtained)) - { - Monitor.TryEnter(_itemLock, LockPollTime, ref lockObtained); - } - } - - private void ExitItemLockIfNeeded(bool lockObtained) - { - if (lockObtained) - { - Monitor.Exit(_itemLock); - } - } - } -} - diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs index 6921ef6aba..6a5a8b17c8 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.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. +#if !NET8_0_OR_GREATER + using System; using System.Diagnostics; using System.Runtime.InteropServices; @@ -135,3 +137,5 @@ protected override bool ReleaseHandle() } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Collections/Generic/BidirectionalDictionary.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Collections/Generic/BidirectionalDictionary.cs index 32c4463433..2bf8459e1b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Collections/Generic/BidirectionalDictionary.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Collections/Generic/BidirectionalDictionary.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. +#if !NET8_0_OR_GREATER + using System.Diagnostics; namespace System.Collections.Generic @@ -59,3 +61,5 @@ IEnumerator IEnumerable.GetEnumerator() } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsAdapterPal.Unix.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsAdapterPal.Unix.cs index 599bd4ab7d..148e0bb76d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsAdapterPal.Unix.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsAdapterPal.Unix.cs @@ -2,7 +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; +#if !NET8_0_OR_GREATER namespace System.Net { @@ -84,3 +84,5 @@ internal static Interop.NetSecurityNative.GssFlags GetInteropFromContextFlagsPal } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsAdapterPal.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsAdapterPal.Windows.cs index 5ed6e347d8..036f24d4ed 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsAdapterPal.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsAdapterPal.Windows.cs @@ -2,7 +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; +#if !NET8_0_OR_GREATER namespace System.Net { @@ -75,3 +75,5 @@ internal static Interop.SspiCli.ContextFlags GetInteropFromContextFlagsPal(Conte } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsPal.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsPal.cs index d4df40b597..f0df3bd677 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsPal.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/ContextFlagsPal.cs @@ -2,7 +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; +#if !NET8_0_OR_GREATER namespace System.Net { @@ -33,3 +33,5 @@ internal enum ContextFlagsPal UnverifiedTargetName = 0x20000000, } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs index 1949341de2..a9d0965324 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugCriticalHandleMinusOneIsInvalid.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if DEBUG && !NET8_0_OR_GREATER + using Microsoft.Win32.SafeHandles; namespace System.Net { -#if DEBUG // // This is a helper class for debugging GC-ed handles that we define. // As a general rule normal code path should always destroy handles explicitly @@ -38,5 +39,6 @@ private void Trace() NetEventSource.Info(this, _trace); } } -#endif // DEBUG } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs index c28a7107b1..fcb485d568 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugCriticalHandleZeroOrMinusOneIsInvalid.cs @@ -2,11 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if DEBUG && !NET8_0_OR_GREATER + using Microsoft.Win32.SafeHandles; namespace System.Net { -#if DEBUG // // This is a helper class for debugging GC-ed handles that we define. // As a general rule normal code path should always destroy handles explicitly @@ -38,5 +39,6 @@ private void Trace() NetEventSource.Info(this, _trace); } } -#endif // DEBUG } + +#endif // !NET8_0_OR_GREATER diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugSafeHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugSafeHandle.cs index b0646f92e9..55d5bd8a6f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugSafeHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/DebugSafeHandle.cs @@ -2,17 +2,17 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Win32.SafeHandles; +#if DEBUG && !NET8_0_OR_GREATER using System.Net.NetworkInformation; using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; +using Microsoft.Win32.SafeHandles; namespace System.Net { -#if DEBUG // // This is a helper class for debugging GC-ed handles that we define. // As a general rule normal code path should always destroy handles explicitly @@ -47,5 +47,6 @@ private void Trace() NetEventSource.Info(this, _trace); } } -#endif // DEBUG } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Logging/DebugThreadTracking.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Logging/DebugThreadTracking.cs index 78d8d48ac6..cd66ff2287 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Logging/DebugThreadTracking.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Logging/DebugThreadTracking.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. +#if !NET8_0_OR_GREATER + using System.Collections.Generic; namespace System.Net @@ -162,3 +164,5 @@ internal enum ThreadKinds ThreadPool = CompletionPort | Worker, // Like Thread.CurrentThread.IsThreadPoolThread } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Logging/NetEventSource.Common.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Logging/NetEventSource.Common.cs index 5b908a3b8e..1e56818132 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Logging/NetEventSource.Common.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Logging/NetEventSource.Common.cs @@ -13,7 +13,7 @@ using System.Diagnostics.Tracing; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#if net462 +#if NETFRAMEWORK using System.Security; #endif @@ -45,7 +45,7 @@ namespace System.Net // method that takes an object and optionally provides a string representation of it, in case a particular library wants to customize further. /// Provides logging facilities for System.Net libraries. -#if net462 +#if NETFRAMEWORK [SecuritySafeCritical] #endif internal sealed partial class NetEventSource : EventSource diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/NegotiationInfoClass.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/NegotiationInfoClass.cs index 560098ef4c..d931c7c70d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/NegotiationInfoClass.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/NegotiationInfoClass.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. +#if !NET8_0_OR_GREATER + namespace System.Net { // This class is used to determine if NTLM or @@ -14,3 +16,5 @@ internal partial class NegotiationInfoClass internal const string Basic = "Basic"; } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs index 70c1a74377..f670a086cf 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NegotiateStreamPal.Unix.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. +#if !NET8_0_OR_GREATER + using System.ComponentModel; using System.Diagnostics; using Microsoft.Win32.SafeHandles; @@ -246,3 +248,5 @@ internal static SafeFreeCredentials AcquireCredentialsHandle(string package, boo } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NegotiateStreamPal.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NegotiateStreamPal.Windows.cs index fe56d8ed91..2ce87ac951 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NegotiateStreamPal.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NegotiateStreamPal.Windows.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. +#if !NET8_0_OR_GREATER + using System.Globalization; using System.ComponentModel; using Microsoft.Data; @@ -215,3 +217,5 @@ internal static int MakeSignature(SafeDeleteContext securityContext, byte[] buff } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NetEventSource.Security.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NetEventSource.Security.Windows.cs index f229b6845a..e28cc18296 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NetEventSource.Security.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NetEventSource.Security.Windows.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. +#if !NET8_0_OR_GREATER + using System.Diagnostics.Tracing; using System.Net.Security; @@ -88,3 +90,5 @@ public void SecurityContextInputBuffers(string context, int inputBuffersSize, in } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NetEventSource.Security.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NetEventSource.Security.cs index b003ce8b7e..e785fe016d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NetEventSource.Security.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/NetEventSource.Security.cs @@ -2,11 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if !NET8_0_OR_GREATER + using System.Diagnostics.Tracing; -using System.Globalization; -using System.Net.Security; -using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; namespace System.Net { @@ -34,3 +32,5 @@ public void SspiPackageNotFound(string packageName) } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityBuffer.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityBuffer.cs index b507449f1e..54c060a6e1 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityBuffer.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityBuffer.cs @@ -2,7 +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.Diagnostics; +#if !NET8_0_OR_GREATER + using System.Runtime.InteropServices; using System.Security.Authentication.ExtendedProtection; @@ -61,3 +62,5 @@ public SecurityBuffer(ChannelBinding binding) } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityBufferType.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityBufferType.cs index 51174938a1..ca29feac84 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityBufferType.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityBufferType.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. +#if !NET8_0_OR_GREATER + namespace System.Net.Security { // sspi.h @@ -26,3 +28,5 @@ internal enum SecurityBufferType SECBUFFER_READONLY_WITH_CHECKSUM = 0x10000000 } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityContextTokenHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityContextTokenHandle.cs index 00e5b3ac60..3d146e5bcc 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityContextTokenHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/SecurityContextTokenHandle.cs @@ -2,9 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Win32.SafeHandles; +#if !NET8_0_OR_GREATER using System.Threading; +using Microsoft.Win32.SafeHandles; namespace System.Net.Security { @@ -39,3 +40,5 @@ protected override bool ReleaseHandle() } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeDeleteContext.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeDeleteContext.cs index c3c75790b9..16636afd29 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeDeleteContext.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeDeleteContext.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. +#if !NET8_0_OR_GREATER + using System.Diagnostics; using System.Runtime.InteropServices; @@ -44,3 +46,5 @@ protected override bool ReleaseHandle() } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs index b98e9ac80b..53fe8e5ad9 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeDeleteNegoContext.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. +#if !NET8_0_OR_GREATER + using System.Diagnostics; using Microsoft.Win32.SafeHandles; @@ -75,3 +77,5 @@ protected override void Dispose(bool disposing) } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeFreeCredentials.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeFreeCredentials.cs index 51d6869a8d..254d9d127a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeFreeCredentials.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeFreeCredentials.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. +#if !NET8_0_OR_GREATER + using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; @@ -71,3 +73,5 @@ protected override bool ReleaseHandle() } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeFreeNegoCredentials.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeFreeNegoCredentials.cs index 217c787619..19ad2e2451 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeFreeNegoCredentials.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/Security/Unix/SafeFreeNegoCredentials.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. +#if !NET8_0_OR_GREATER + using System.Diagnostics; using Microsoft.Win32.SafeHandles; @@ -84,3 +86,5 @@ protected override bool ReleaseHandle() } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/SecurityStatusAdapterPal.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/SecurityStatusAdapterPal.Windows.cs index b7ce1e6b1e..c3b13d549f 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/SecurityStatusAdapterPal.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/SecurityStatusAdapterPal.Windows.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. +#if !NET8_0_OR_GREATER + using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -101,3 +103,5 @@ internal static Interop.SECURITY_STATUS GetInteropFromSecurityStatusPal(Security } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/SecurityStatusPal.cs b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/SecurityStatusPal.cs index 54b380e74f..5bbe78bd00 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/SecurityStatusPal.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Common/src/System/Net/SecurityStatusPal.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. +#if !NET8_0_OR_GREATER + namespace System.Net { internal readonly struct SecurityStatusPal @@ -71,3 +73,5 @@ internal enum SecurityStatusPalErrorCode ApplicationProtocolMismatch } } + +#endif 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 c8591a8c11..6f75be4e70 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Interop/SNINativeMethodWrapper.Windows.cs @@ -315,7 +315,7 @@ private static extern uint SNIOpenWrapper( [DllImport(SNI, CallingConvention = CallingConvention.Cdecl)] private static extern unsafe uint SNISecGenClientContextWrapper( [In] SNIHandle pConn, - [In, Out] byte[] pIn, + [In, Out] byte* pIn, uint cbIn, [In, Out] byte[] pOut, [In] ref uint pcbOut, @@ -471,15 +471,16 @@ internal static unsafe void SNIPacketSetData(SNIPacket packet, byte[] data, int } } - internal static unsafe uint SNISecGenClientContext(SNIHandle pConnectionObject, byte[] inBuff, uint receivedLength, byte[] OutBuff, ref uint sendLength, byte[] serverUserName) + internal static unsafe uint SNISecGenClientContext(SNIHandle pConnectionObject, ReadOnlySpan inBuff, byte[] OutBuff, ref uint sendLength, byte[] serverUserName) { fixed (byte* pin_serverUserName = &serverUserName[0]) + fixed (byte* pInBuff = inBuff) { bool local_fDone; return SNISecGenClientContextWrapper( pConnectionObject, - inBuff, - receivedLength, + pInBuff, + (uint)inBuff.Length, OutBuff, ref sendLength, out local_fDone, 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 7a3a8e208f..2cd3537ea7 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -1,8 +1,7 @@  Microsoft.Data.SqlClient - net8.0;net6.0;netstandard2.0;netstandard2.1 - netstandard2.1 + net8.0;net6.0 Microsoft.Data.SqlClient is not supported on this platform. $(OS) true @@ -10,7 +9,6 @@ false netcoreapp - netstandard Debug;Release; AnyCPU;x64;x86 $(ObjFolder)$(Configuration).$(Platform)\$(AssemblyName)\netcore\ @@ -30,609 +28,606 @@ - + + Common\CoreLib\System\Threading\Tasks\TaskToApm.cs + + + Common\Microsoft\Data\ProviderBase\DbConnectionClosed.cs + + + Common\Microsoft\Data\ProviderBase\DbConnectionFactory.cs + + + Common\Microsoft\Data\ProviderBase\DbConnectionInternal.cs + + + Common\System\Net\ContextFlagsPal.cs + + + Common\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs + + + Common\System\Net\DebugSafeHandle.cs + + + Common\System\Net\InternalException.cs + + + Common\System\Net\Logging\DebugThreadTracking.cs + + + Common\System\Net\Logging\NetEventSource.Common.cs + + + Common\System\Net\NegotiationInfoClass.cs + + + Common\System\Net\Security\SecurityBuffer.cs + + + Common\System\Net\Security\SecurityBufferType.cs + + + Common\System\Net\SecurityStatusPal.cs + + + Microsoft\Data\Common\ActivityCorrelator.cs - + Microsoft\Data\Common\AdapterUtil.cs - + Microsoft\Data\Common\BitConverterCompatible.cs - + Microsoft\Data\Common\DbConnectionOptions.Common.cs - + Microsoft\Data\Common\DbConnectionPoolKey.cs - + Microsoft\Data\Common\DbConnectionStringCommon.cs - + Microsoft\Data\Common\MultipartIdentifier.cs - + Microsoft\Data\Common\NameValuePair.cs - + Microsoft\Data\DataException.cs - + Microsoft\Data\OperationAbortedException.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolAuthenticationContext.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolAuthenticationContextKey.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolGroup.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolGroupProviderInfo.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolOptions.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolProviderInfo.cs - + Microsoft\Data\ProviderBase\DbMetaDataFactory.cs - + + Common\Microsoft\Data\ProviderBase\DbReferenceCollection.cs + + Microsoft\Data\ProviderBase\FieldNameLookup.cs - + Microsoft\Data\ProviderBase\TimeoutTimer.cs - + Microsoft\Data\Sql\SqlDataSourceEnumerator.cs - + Microsoft\Data\Sql\SqlDataSourceEnumeratorManagedHelper.cs - + Microsoft\Data\Sql\SqlDataSourceEnumeratorUtil.cs - + Microsoft\Data\Sql\SqlNotificationRequest.cs - + Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationProvider.cs - + Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationTimeoutRetryHelper.cs - + + Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs + + Microsoft\Data\SqlClient\ApplicationIntent.cs - + Microsoft\Data\SqlClient\AssemblyRef.cs - + + Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.cs + + Microsoft\Data\SqlClient\ColumnEncryptionKeyInfo.cs - + Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs - + Microsoft\Data\SqlClient\DisposableTemporaryOnStack.cs - + Microsoft\Data\SqlClient\EnclaveDelegate.cs - + + Microsoft\Data\SqlClient\EnclaveDelegate.Crypto.cs + + Microsoft\Data\SqlClient\EnclavePackage.cs - + + Microsoft\Data\SqlClient\EnclaveProviderBase.cs + + + Microsoft\Data\SqlClient\EnclaveSessionCache.cs + + Microsoft\Data\SqlClient\LocalAppContextSwitches.cs - + + Microsoft\Data\SqlClient\NoneAttestationEnclaveProvider.cs + + Microsoft\Data\SqlClient\OnChangedEventHandler.cs - + Microsoft\Data\SqlClient\ParameterPeekAheadValue.cs - + Microsoft\Data\SqlClient\PoolBlockingPeriod.cs - + Microsoft\Data\SqlClient\Reliability\AppConfigManager.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryingEventArgs.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryIntervalBaseEnumerator.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryLogic.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryLogicBase.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryLogicBaseProvider.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryLogicProvider.cs - + Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryFactory.cs - + Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicLoader.cs - + Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryIntervalEnumerators.cs - + Microsoft\Data\SqlClient\RowsCopiedEventArgs.cs - + Microsoft\Data\SqlClient\RowsCopiedEventHandler.cs - - Microsoft\Data\SqlClient\SqlSequentialTextReader.cs - - + Microsoft\Data\SqlClient\Server\ExtendedClrTypeCode.cs - + Microsoft\Data\SqlClient\Server\ITypedGetters.cs - + Microsoft\Data\SqlClient\Server\ITypedGettersV3.cs - + Microsoft\Data\SqlClient\Server\ITypedSetters.cs - + Microsoft\Data\SqlClient\Server\ITypedSettersV3.cs - + Microsoft\Data\SqlClient\Server\MemoryRecordBuffer.cs - + Microsoft\Data\SqlClient\Server\MetadataUtilsSmi.cs - + Microsoft\Data\SqlClient\Server\SmiEventSink.cs - + Microsoft\Data\SqlClient\Server\SmiEventSink_Default.Common.cs - + Microsoft\Data\SqlClient\Server\SmiGettersStream.cs - + Microsoft\Data\SqlClient\Server\SmiMetaData.cs - + Microsoft\Data\SqlClient\Server\SmiMetaDataProperty.cs - + Microsoft\Data\SqlClient\Server\SmiRecordBuffer.cs - + Microsoft\Data\SqlClient\Server\SmiSettersStream.cs - + Microsoft\Data\SqlClient\Server\SmiTypedGetterSetter.cs - + Microsoft\Data\SqlClient\Server\SmiXetterAccessMap.Common.cs - + Microsoft\Data\SqlClient\Server\SmiXetterTypeCode.cs - + Microsoft\Data\SqlClient\Server\SqlDataRecord.cs - + Microsoft\Data\SqlClient\Server\SqlDataRecord.netcore.cs - + Microsoft\Data\SqlClient\Server\SqlMetaData.cs - + Microsoft\Data\SqlClient\Server\SqlNormalizer.cs - + Microsoft\Data\SqlClient\Server\SqlRecordBuffer.cs - - Microsoft\Data\SqlClient\SqlTransaction.Common.cs + + Microsoft\Data\SqlClient\Server\SqlSer.cs - + Microsoft\Data\SqlClient\Server\ValueUtilsSmi.cs - + Microsoft\Data\SqlClient\SignatureVerificationCache.cs - + Microsoft\Data\SqlClient\SortOrder.cs - + Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Algorithm.cs - + Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256EncryptionKey.cs - + Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Factory.cs - + Microsoft\Data\SqlClient\SqlAuthenticationParameters.cs - + Microsoft\Data\SqlClient\SqlAuthenticationProvider.cs - - Microsoft\Data\SqlClient\SqlBuffer.cs - - + Microsoft\Data\SqlClient\SqlAuthenticationToken.cs - + Microsoft\Data\SqlClient\SqlBatch.cs - + Microsoft\Data\SqlClient\SqlBatchCommand.cs - + + Microsoft\Data\SqlClient\SqlBatchCommand.Net8OrGreater.cs + + Microsoft\Data\SqlClient\SqlBatchCommandCollection.cs - + + Microsoft\Data\SqlClient\SqlBuffer.cs + + Microsoft\Data\SqlClient\SqlBulkCopyColumnMapping.cs - + Microsoft\Data\SqlClient\SqlBulkCopyColumnMappingCollection.cs - + Microsoft\Data\SqlClient\SqlBulkCopyColumnOrderHint.cs - + Microsoft\Data\SqlClient\SqlBulkCopyColumnOrderHintCollection.cs - + Microsoft\Data\SqlClient\SqlBulkCopyOptions.cs - + Microsoft\Data\SqlClient\SqlCachedBuffer.cs - + Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithm.cs - + Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactory.cs - + Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactoryList.cs - + Microsoft\Data\SqlClient\SqlClientEncryptionType.cs - + Microsoft\Data\SqlClient\SqlClientEventSource.cs - + + Microsoft\Data\SqlClient\SqlClientFactory.cs + + Microsoft\Data\SqlClient\SqlClientLogger.cs - + Microsoft\Data\SqlClient\SqlClientMetaDataCollectionNames.cs - + Microsoft\Data\SqlClient\SqlClientSymmetricKey.cs - + Microsoft\Data\SqlClient\SqlCollation.cs - - Microsoft\Data\SqlClient\SqlColumnEncryptionKeyStoreProvider.cs - - + Microsoft\Data\SqlClient\SqlCommandBuilder.cs - + + Microsoft\Data\SqlClient\SqlColumnEncryptionKeyStoreProvider.cs + + Microsoft\Data\SqlClient\SqlCommandSet.cs - + Microsoft\Data\SqlClient\SqlConnectionEncryptOption.cs - + Microsoft\Data\SqlClient\SqlConnectionEncryptOptionConverter.cs - + Microsoft\Data\SqlClient\SqlConnectionPoolGroupProviderInfo.cs - + Microsoft\Data\SqlClient\SqlConnectionPoolKey.cs - + Microsoft\Data\SqlClient\SqlConnectionPoolProviderInfo.cs - + Microsoft\Data\SqlClient\SqlConnectionString.cs - + Microsoft\Data\SqlClient\SqlConnectionStringBuilder.cs - + Microsoft\Data\SqlClient\SqlConnectionTimeoutErrorInternal.cs - + Microsoft\Data\SqlClient\SqlCredential.cs - + Microsoft\Data\SqlClient\SqlDataAdapter.cs - + Microsoft\Data\SqlClient\SqlDependency.cs - + Microsoft\Data\SqlClient\SqlDependencyListener.cs - + Microsoft\Data\SqlClient\SqlDependencyUtils.cs - + Microsoft\Data\SqlClient\SqlDependencyUtils.AppDomain.cs - + + Microsoft\Data\SqlClient\SqlDependencyUtils.AssemblyLoadContext.cs + + + Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.Crypto.cs + + Microsoft\Data\SqlClient\SqlEnclaveSession.cs - + Microsoft\Data\SqlClient\SqlEnums.cs - + Microsoft\Data\SqlClient\SqlEnvChange.cs - + Microsoft\Data\SqlClient\SqlError.cs - + Microsoft\Data\SqlClient\SqlErrorCollection.cs - + Microsoft\Data\SqlClient\SqlException.cs - + Microsoft\Data\SqlClient\SQLFallbackDNSCache.cs - + Microsoft\Data\SqlClient\SqlInfoMessageEvent.cs - + Microsoft\Data\SqlClient\SqlInfoMessageEventHandler.cs - + Microsoft\Data\SqlClient\SqlInternalConnection.cs - + Microsoft\Data\SqlClient\SqlInternalTransaction.cs - + Microsoft\Data\SqlClient\SqlMetadataFactory.cs - + Microsoft\Data\SqlClient\SqlNotificationEventArgs.cs - + Microsoft\Data\SqlClient\SqlNotificationInfo.cs - + Microsoft\Data\SqlClient\SqlNotificationSource.cs - + Microsoft\Data\SqlClient\SqlNotificationType.cs - + Microsoft\Data\SqlClient\SqlObjectPool.cs - + Microsoft\Data\SqlClient\SqlParameter.cs - + Microsoft\Data\SqlClient\SqlParameterCollection.cs - + Microsoft\Data\SqlClient\SqlQueryMetadataCache.cs - + Microsoft\Data\SqlClient\SqlReferenceCollection.cs - + Microsoft\Data\SqlClient\SqlRowUpdatedEvent.cs - + Microsoft\Data\SqlClient\SqlRowUpdatedEventHandler.cs - + Microsoft\Data\SqlClient\SqlRowUpdatingEvent.cs - + Microsoft\Data\SqlClient\SqlRowUpdatingEventHandler.cs - + Microsoft\Data\SqlClient\SqlSecurityUtility.cs - + Microsoft\Data\SqlClient\SqlSequentialStream.cs - - Microsoft\Data\SqlClient\Server\SqlSer.cs + + Microsoft\Data\SqlClient\SqlSequentialTextReader.cs - + Microsoft\Data\SqlClient\SqlStatistics.cs - + + Microsoft\Data\SqlClient\SqlStream.cs + + Microsoft\Data\SqlClient\SqlSymmetricKeyCache.cs - + Microsoft\Data\SqlClient\SqlUdtInfo.cs - + Microsoft\Data\SqlClient\SqlUtil.cs - + + Microsoft\Data\SqlClient\SqlTransaction.Common.cs + + + Microsoft\Data\SqlClient\SSPI\ManagedSSPIContextProvider.cs + + + Microsoft\Data\SqlClient\SSPI\NegotiateSSPIContextProvider.cs + + + Microsoft\Data\SqlClient\SSPI\SSPIContextProvider.cs + + Microsoft\Data\SqlClient\TdsEnums.cs - + Microsoft\Data\SqlClient\TdsParameterSetter.cs - + + Microsoft\Data\SqlClient\TdsParser.cs + + Microsoft\Data\SqlClient\TdsParserStateObject.cs - + Microsoft\Data\SqlClient\TdsParserStaticMethods.cs - + Microsoft\Data\SqlClient\TdsRecordBufferSetter.cs - + Microsoft\Data\SqlClient\TdsParserSessionPool.cs - + Microsoft\Data\SqlClient\TdsValueSetter.cs - + + Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.cs + + + Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.cs + + Microsoft\Data\SQLTypes\SQLResource.cs - + Microsoft\Data\SqlTypes\SqlTypeWorkarounds.cs - - Microsoft\Data\SqlClient\SqlStream.cs - - + Resources\ResCategoryAttribute.cs - + Resources\ResDescriptionAttribute.cs - + Common\System\Diagnostics\CodeAnalysis.cs - - - - - - - Microsoft\Data\SqlClient\EnclaveDelegate.NotSupported.cs - - - Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.NotSupported.cs - - - - - - - - - - - - Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs - - - Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.cs - - - Microsoft\Data\SqlClient\EnclaveDelegate.Crypto.cs - - - Microsoft\Data\SqlClient\EnclaveProviderBase.cs - - - Microsoft\Data\SqlClient\EnclaveSessionCache.cs - - - Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.Crypto.cs - - - Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.cs - - - Microsoft\Data\SqlClient\NoneAttestationEnclaveProvider.cs - - - Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.cs - - - - - - - - - - - - - Microsoft\Data\SqlClient\SqlDependencyUtils.AssemblyLoadContext.cs - - - - - - - Resources\StringsHelper.cs - - - Resources\Strings.Designer.cs - True - True - Strings.resx - - - Resources\Strings.resx - Microsoft.Data.SqlClient.Resources.Strings.resources - ResXFileCodeGenerator - Strings.Designer.cs - System - - - Resources\%(RecursiveDir)%(Filename)%(Extension) - - - - - Common\CoreLib\System\Threading\Tasks\TaskToApm.cs - - - Common\Microsoft\Data\ProviderBase\DbConnectionClosed.cs - - - Common\Microsoft\Data\ProviderBase\DbConnectionFactory.cs - - - Common\Microsoft\Data\ProviderBase\DbConnectionInternal.cs - - - Common\Microsoft\Data\ProviderBase\DbReferenceCollection.cs - - + + + + @@ -642,16 +637,21 @@ + - + + + - + + + @@ -659,52 +659,22 @@ + + - - - + + - - - Microsoft\Data\Common\AdapterUtil.Windows.cs - - - Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs - - - Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs - - - - - - Microsoft\Data\SqlClient\TdsParserSafeHandles.Windows.cs - - - - - - Microsoft\Data\Common\AdapterUtil.Unix.cs - - - - - - - - - - Common\CoreLib\Interop\Windows\kernel32\Interop.FileTypes.cs @@ -712,15 +682,30 @@ Common\CoreLib\Interop\Windows\kernel32\Interop.GetFileType_SafeHandle.cs + + Common\CoreLib\Interop\Windows\Kernel32\Interop.CloseHandle.cs + Common\CoreLib\Interop\Windows\kernel32\Interop.SetThreadErrorMode.cs + + Common\CoreLib\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs + Common\CoreLib\System\IO\PathInternal.Windows.cs + + Common\Interop\Windows\Crypt32\Interop.certificates.cs + + + Common\Interop\Windows\Crypt32\Interop.certificates_types.cs + Common\Interop\Windows\Interop.Errors.cs + + Common\Interop\Windows\Interop.Libraries.cs + Common\Interop\Windows\Interop.UNICODE_STRING.cs @@ -730,12 +715,21 @@ Common\Interop\Windows\Kernel32\Interop.DeviceIoControl.cs + + Common\Interop\Windows\kernel32\Interop.FreeLibrary.cs + + + Common\Interop\Windows\kernel32\Interop.GetProcAddress.cs + Common\Interop\Windows\Kernel32\Interop.IoControlCodeAccess.cs Common\Interop\Windows\Kernel32\Interop.IoControlTransferType.cs + + Common\Interop\Windows\kernel32\Interop.LoadLibraryEx.cs + Common\Interop\Windows\NtDll\Interop.FILE_FULL_EA_INFORMATION.cs @@ -748,86 +742,6 @@ Common\Interop\Windows\NtDll\Interop.RtlNtStatusToDosError.cs - - - - - - - - - - - - - - - - - - - - - - Common\Interop\Windows\kernel32\Interop.LoadLibraryEx.cs - - - - - - - - - - - Common\CoreLib\Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs - - - Common\Interop\Windows\kernel32\Interop.FreeLibrary.cs - - - Common\Interop\Windows\kernel32\Interop.GetProcAddress.cs - - - - - - - Common\Interop\Windows\Interop.Libraries.cs - - - - - - Common\System\Net\InternalException.cs - - - Common\System\Net\Logging\NetEventSource.Common.cs - - - - - - - - - - - - - - - - - - Common\CoreLib\Interop\Windows\Kernel32\Interop.CloseHandle.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates.cs - - - Common\Interop\Windows\Crypt32\Interop.certificates_types.cs - Common\Interop\Windows\SChannel\Interop.SecPkgContext_ApplicationProtocol.cs @@ -837,30 +751,6 @@ Common\Interop\Windows\SChannel\SecPkgContext_ConnectionInfo.cs - - Common\System\Collections\Generic\BidirectionalDictionary.cs - - - Common\System\Net\ContextFlagsAdapterPal.Windows.cs - - - Common\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs - - - Common\System\Net\Security\SecurityContextTokenHandle.cs - - - Common\System\Net\SecurityStatusAdapterPal.Windows.cs - - - Common\System\Net\Security\NegotiateStreamPal.Windows.cs - - - Common\System\Net\Security\NetEventSource.Security.cs - - - Common\System\Net\Security\NetEventSource.Security.Windows.cs - Common\Interop\Windows\sspicli\GlobalSSPI.cs @@ -906,37 +796,65 @@ Common\Interop\Windows\sspicli\SSPIWrapper.cs - - - - - Common\System\Net\ContextFlagsPal.cs + + Common\System\Collections\Generic\BidirectionalDictionary.cs - - Common\System\Net\DebugCriticalHandleMinusOneIsInvalid.cs + + Common\System\Net\ContextFlagsAdapterPal.Windows.cs - - Common\System\Net\DebugSafeHandle.cs + + Common\System\Net\DebugCriticalHandleZeroOrMinusOneIsInvalid.cs - - Common\System\Net\Logging\DebugThreadTracking.cs + + Common\System\Net\Security\NegotiateStreamPal.Windows.cs - - Common\System\Net\NegotiationInfoClass.cs + + Common\System\Net\Security\NetEventSource.Security.cs - - Common\System\Net\Security\SecurityBuffer.cs + + Common\System\Net\Security\NetEventSource.Security.Windows.cs - - Common\System\Net\Security\SecurityBufferType.cs + + Common\System\Net\Security\SecurityContextTokenHandle.cs - - Common\System\Net\SecurityStatusPal.cs + + Common\System\Net\SecurityStatusAdapterPal.Windows.cs - + + + Microsoft\Data\Common\AdapterUtil.Windows.cs + + + Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs + + + Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs + + + Microsoft\Data\SqlClient\SSPI\NativeSSPIContextProvider.cs + + + Microsoft\Data\SqlClient\TdsParserSafeHandles.Windows.cs + + + + + + + + + + + + + + + + - - + + + Common\Interop\Unix\Interop.Libraries.cs @@ -970,37 +888,53 @@ Common\System\Net\Security\NegotiateStreamPal.Unix.cs - - - - - - - Microsoft\Data\SqlClient\SqlBatchCommand.Net8OrGreater.cs + + + Microsoft\Data\Common\AdapterUtil.Unix.cs + + + + + + + + + + + + + + - - - - + + + + Resources\StringsHelper.cs + + + Resources\Strings.Designer.cs + True + True + Strings.resx + + + Resources\Strings.resx + Microsoft.Data.SqlClient.Resources.Strings.resources + ResXFileCodeGenerator + Strings.Designer.cs + System + + + Resources\%(RecursiveDir)%(Filename)%(Extension) + Microsoft.Data.SqlClient.SqlMetaData.xml - - - - - - - - - - - - - + + @@ -1018,5 +952,5 @@ - + 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 c85d042b2a..4a59e0b858 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 @@ -2,14 +2,15 @@ // 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; +#if NET6_0_OR_GREATER + using System.Diagnostics; using Microsoft.Data.Common; using Microsoft.Data.SqlClient; namespace Microsoft.Data.ProviderBase { - sealed internal partial class DbConnectionPool + internal sealed partial class DbConnectionPool { private bool IsBlockingPeriodEnabled() { @@ -44,3 +45,5 @@ private bool IsBlockingPeriodEnabled() } } } + +#endif 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 7858adc93c..3bf8a9d561 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,7 @@ private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectio throw; } -#if NETCOREAPP +#if NET6_0_OR_GREATER if (!IsBlockingPeriodEnabled()) { throw; diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/LocalDBAPI.uap.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/LocalDBAPI.uap.cs deleted file mode 100644 index 9ed10f0fcc..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/LocalDBAPI.uap.cs +++ /dev/null @@ -1,14 +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; - -namespace System.Data -{ - internal static partial class LocalDBAPI - { - private static IntPtr LoadProcAddress() => - throw new PlatformNotSupportedException(Strings.LocalDBNotSupported); // No Registry support on UAP - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/LocalDB.uap.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/LocalDB.uap.cs deleted file mode 100644 index e764375802..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/LocalDB.uap.cs +++ /dev/null @@ -1,14 +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. - -namespace Microsoft.Data.SqlClient.SNI -{ - internal class LocalDB - { - internal static string GetLocalDBConnectionString(string localDbInstance) - { - throw new PlatformNotSupportedException(Strings.LocalDBNotSupported); // No Registry support on UAP - } - } -} 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 964d332ae4..f8f2facb59 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 @@ -138,196 +138,154 @@ internal class SNICommon internal const int LocalDBBadRuntime = 57; /// - /// We only validate Server name in Certificate to match with "targetServerName". + /// We either validate that the provided 'validationCert' matches the 'serverCert', or we validate that the server name in the 'serverCert' matches 'targetServerName'. /// Certificate validation and chain trust validations are done by SSLStream class [System.Net.Security.SecureChannel.VerifyRemoteCertificate method] /// This method is called as a result of callback for SSL Stream Certificate validation. /// + /// Connection ID/GUID for tracing /// Server that client is expecting to connect to - /// X.509 certificate + /// Optional hostname to use for server certificate validation + /// X.509 certificate from the server + /// Path to an X.509 certificate file from the application to compare with the serverCert /// Policy errors /// True if certificate is valid - internal static bool ValidateSslServerCertificate(string targetServerName, X509Certificate cert, SslPolicyErrors policyErrors) + internal static bool ValidateSslServerCertificate(Guid connectionId, string targetServerName, string hostNameInCertificate, X509Certificate serverCert, string validationCertFileName, SslPolicyErrors policyErrors) { using (TrySNIEventScope.Create("SNICommon.ValidateSslServerCertificate | SNI | SCOPE | INFO | Entering Scope {0} ")) { if (policyErrors == SslPolicyErrors.None) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "targetServerName {0}, SSL Server certificate not validated as PolicyErrors set to None.", args0: targetServerName); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, targetServerName {1}, SSL Server certificate not validated as PolicyErrors set to None.", args0: connectionId, args1: targetServerName); return true; } - // If we get to this point then there is a ssl policy flag. - StringBuilder messageBuilder = new(); - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors)) + string serverNameToValidate; + X509Certificate validationCertificate = null; + if (!string.IsNullOrEmpty(hostNameInCertificate)) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, SslPolicyError {1}, SSL Policy certificate chain has errors.", args0: targetServerName, args1: policyErrors); + serverNameToValidate = hostNameInCertificate; + } + else + { + serverNameToValidate = targetServerName; + } - // get the chain status from the certificate - X509Certificate2 cert2 = cert as X509Certificate2; - X509Chain chain = new(); - chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; - StringBuilder chainStatusInformation = new(); - bool chainIsValid = chain.Build(cert2); - Debug.Assert(!chainIsValid, "RemoteCertificateChainError flag is detected, but certificate chain is valid."); - if (!chainIsValid) + if (!string.IsNullOrEmpty(validationCertFileName)) + { + try { - foreach (X509ChainStatus chainStatus in chain.ChainStatus) - { - chainStatusInformation.Append($"{chainStatus.StatusInformation}, [Status: {chainStatus.Status}]"); - chainStatusInformation.AppendLine(); - } + validationCertificate = new X509Certificate(validationCertFileName); + } + catch (Exception e) + { + // if this fails, then fall back to the HostNameInCertificate or TargetServer validation. + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, Exception occurred loading specified ServerCertificate: {1}, treating it as if ServerCertificate has not been specified.", args0: connectionId, args1: e.Message); } - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, SslPolicyError {1}, SSL Policy certificate chain has errors. ChainStatus {2}", args0: targetServerName, args1: policyErrors, args2: chainStatusInformation); - messageBuilder.AppendFormat(Strings.SQL_RemoteCertificateChainErrors, chainStatusInformation); - messageBuilder.AppendLine(); } - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable)) + if (validationCertificate != null) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, SSL Policy invalidated certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNotAvailable); + if (serverCert.GetRawCertData().AsSpan().SequenceEqual(validationCertificate.GetRawCertData().AsSpan())) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, ServerCertificate matches the certificate provided by the server. Certificate validation passed.", args0: connectionId); + return true; + } + else + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, ServerCertificate doesn't match the certificate provided by the server. Certificate validation failed.", args0: connectionId); + throw ADP.SSLCertificateAuthenticationException(Strings.SQL_RemoteCertificateDoesNotMatchServerCertificate); + } } - - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch)) + else { -#if NET7_0_OR_GREATER - X509Certificate2 cert2 = cert as X509Certificate2; - if (!cert2.MatchesHostname(targetServerName)) + // If we get to this point then there is a ssl policy flag. + StringBuilder messageBuilder = new(); + if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable)) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name or HNIC does not match the Subject/SAN in Certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, targetServerName {1}, SSL Server certificate not validated as PolicyErrors set to RemoteCertificateNotAvailable.", args0: connectionId, args1: targetServerName); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNotAvailable); } -#else - // To Do: include certificate SAN (Subject Alternative Name) check. - string certServerName = cert.Subject.Substring(cert.Subject.IndexOf('=') + 1); - // Verify that target server name matches subject in the certificate - if (targetServerName.Length > certServerName.Length) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name is of greater length than Subject in Certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); - } - else if (targetServerName.Length == certServerName.Length) + if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors)) { - // Both strings have the same length, so targetServerName must be a FQDN - if (!targetServerName.Equals(certServerName, StringComparison.OrdinalIgnoreCase)) + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, targetServerName {0}, SslPolicyError {1}, SSL Policy certificate chain has errors.", args0: connectionId, args1: targetServerName, args2: policyErrors); + + // get the chain status from the certificate + X509Certificate2 cert2 = serverCert as X509Certificate2; + X509Chain chain = new(); + chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; + StringBuilder chainStatusInformation = new(); + bool chainIsValid = chain.Build(cert2); + Debug.Assert(!chainIsValid, "RemoteCertificateChainError flag is detected, but certificate chain is valid."); + if (!chainIsValid) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + foreach (X509ChainStatus chainStatus in chain.ChainStatus) + { + chainStatusInformation.Append($"{chainStatus.StatusInformation}, [Status: {chainStatus.Status}]"); + chainStatusInformation.AppendLine(); + } } + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, targetServerName {1}, SslPolicyError {2}, SSL Policy certificate chain has errors. ChainStatus {3}", args0: connectionId, args1: targetServerName, args2: policyErrors, args3: chainStatusInformation); + messageBuilder.AppendFormat(Strings.SQL_RemoteCertificateChainErrors, chainStatusInformation); + messageBuilder.AppendLine(); } - else + + if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch)) { - if (string.Compare(targetServerName, 0, certServerName, 0, targetServerName.Length, StringComparison.OrdinalIgnoreCase) != 0) +#if NET8_0_OR_GREATER + X509Certificate2 cert2 = serverCert as X509Certificate2; + if (!cert2.MatchesHostname(serverNameToValidate)) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name or HNIC does not match the Subject/SAN in Certificate.", args0: connectionId, args1: serverNameToValidate); messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); } +#else + // To Do: include certificate SAN (Subject Alternative Name) check. + string certServerName = serverCert.Subject.Substring(serverCert.Subject.IndexOf('=') + 1); - // Server name matches cert name for its whole length, so ensure that the - // character following the server name is a '.'. This will avoid - // having server name "ab" match "abc.corp.company.com" - // (Names have different lengths, so the target server can't be a FQDN.) - if (certServerName[targetServerName.Length] != '.') + // Verify that target server name matches subject in the certificate + if (serverNameToValidate.Length > certServerName.Length) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name is of greater length than Subject in Certificate.", args0: connectionId, args1: serverNameToValidate); messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); } - } -#endif - } - - if (messageBuilder.Length > 0) - { - throw ADP.SSLCertificateAuthenticationException(messageBuilder.ToString()); - } - - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, " Remote certificate with subject: {0}, validated successfully.", args0: cert.Subject); - return true; - } - } - - /// - /// We validate the provided certificate provided by the client with the one from the server to see if it matches. - /// Certificate validation and chain trust validations are done by SSLStream class [System.Net.Security.SecureChannel.VerifyRemoteCertificate method] - /// This method is called as a result of callback for SSL Stream Certificate validation. - /// - /// X.509 certificate provided by the client - /// X.509 certificate provided by the server - /// Policy errors - /// True if certificate is valid - internal static bool ValidateSslServerCertificate(X509Certificate clientCert, X509Certificate serverCert, SslPolicyErrors policyErrors) - { - using (TrySNIEventScope.Create("SNICommon.ValidateSslServerCertificate | SNI | SCOPE | INFO | Entering Scope {0} ")) - { - if (policyErrors == SslPolicyErrors.None) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "serverCert {0}, SSL Server certificate not validated as PolicyErrors set to None.", args0: clientCert.Subject); - return true; - } - - StringBuilder messageBuilder = new(); - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable)) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "serverCert {0}, SSL Server certificate not validated as PolicyErrors set to RemoteCertificateNotAvailable.", args0: clientCert.Subject); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNotAvailable); - } - - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors)) - { - // get the chain status from the server certificate - X509Certificate2 cert2 = serverCert as X509Certificate2; - X509Chain chain = new(); - chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; - StringBuilder chainStatusInformation = new(); - bool chainIsValid = chain.Build(cert2); - Debug.Assert(!chainIsValid, "RemoteCertificateChainError flag is detected, but certificate chain is valid."); - if (!chainIsValid) - { - foreach (X509ChainStatus chainStatus in chain.ChainStatus) + else if (serverNameToValidate.Length == certServerName.Length) { - chainStatusInformation.Append($"{chainStatus.StatusInformation}, [Status: {chainStatus.Status}]"); - chainStatusInformation.AppendLine(); + // Both strings have the same length, so serverNameToValidate must be a FQDN + if (!serverNameToValidate.Equals(certServerName, StringComparison.OrdinalIgnoreCase)) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name does not match Subject in Certificate.", args0: connectionId, args1: serverNameToValidate); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + } } - } - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "certificate subject from server is {0}, and does not match with the certificate provided client.", args0: cert2.SubjectName.Name); - messageBuilder.AppendFormat(Strings.SQL_RemoteCertificateChainErrors, chainStatusInformation); - messageBuilder.AppendLine(); - } - - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch)) - { -#if NET7_0_OR_GREATER - X509Certificate2 s_cert = serverCert as X509Certificate2; - X509Certificate2 c_cert = clientCert as X509Certificate2; - - if (!s_cert.MatchesHostname(c_cert.SubjectName.Name)) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "certificate from server does not match with the certificate provided client.", args0: s_cert.Subject); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); - } -#else - // Verify that subject name matches - if (serverCert.Subject != clientCert.Subject) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "certificate subject from server is {0}, and does not match with the certificate provided client.", args0: serverCert.Subject); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + else + { + if (string.Compare(serverNameToValidate, 0, certServerName, 0, serverNameToValidate.Length, StringComparison.OrdinalIgnoreCase) != 0) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name does not match Subject in Certificate.", args0: connectionId, args1: serverNameToValidate); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + } + + // Server name matches cert name for its whole length, so ensure that the + // character following the server name is a '.'. This will avoid + // having server name "ab" match "abc.corp.company.com" + // (Names have different lengths, so the target server can't be a FQDN.) + if (certServerName[serverNameToValidate.Length] != '.') + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name does not match Subject in Certificate.", args0: connectionId, args1: serverNameToValidate); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + } + } +#endif } - if (!serverCert.Equals(clientCert)) + if (messageBuilder.Length > 0) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "certificate from server does not match with the certificate provided client.", args0: serverCert.Subject); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + throw ADP.SSLCertificateAuthenticationException(messageBuilder.ToString()); } -#endif - } - - if (messageBuilder.Length > 0) - { - throw ADP.SSLCertificateAuthenticationException(messageBuilder.ToString()); } - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "certificate subject {0}, Client certificate validated successfully.", args0: clientCert.Subject); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, certificate with subject: {1}, validated successfully.", args0: connectionId, args1: serverCert.Subject); return true; } } 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 354ce3eff5..515686f6a3 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 @@ -19,7 +19,6 @@ internal abstract class SNIHandle { protected static readonly SslProtocols s_supportedProtocols = SslProtocols.None; -#if !NETSTANDARD2_0 protected static readonly List s_tdsProtocols = new List(1) { new(TdsEnums.TDS8_Protocol) }; protected static async Task AuthenticateAsClientAsync(SslStream sslStream, string serverNameIndication, X509CertificateCollection certificate, CancellationToken token) @@ -32,15 +31,10 @@ protected static async Task AuthenticateAsClientAsync(SslStream sslStream, strin }; await sslStream.AuthenticateAsClientAsync(sslClientOptions, token); } -#endif protected static void AuthenticateAsClient(SslStream sslStream, string serverNameIndication, X509CertificateCollection certificate) { -#if !NETSTANDARD2_0 AuthenticateAsClientAsync(sslStream, serverNameIndication, certificate, CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult(); -#else - throw new NotSupportedException(Strings.SQL_TDS8_NotSupported_Netstandard2_0); -#endif } /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 2889ce6bb4..8f8af57f58 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -24,6 +24,8 @@ internal sealed class SNINpHandle : SNIPhysicalHandle private readonly string _targetServer; private readonly object _sendSync; + private readonly string _hostNameInCertificate; + private readonly string _serverCertificateFilename; private readonly bool _tlsFirst; private Stream _stream; private NamedPipeClientStream _pipeStream; @@ -38,7 +40,7 @@ internal sealed class SNINpHandle : SNIPhysicalHandle private int _bufferSize = TdsEnums.DEFAULT_LOGIN_PACKET_SIZE; private readonly Guid _connectionId = Guid.NewGuid(); - public SNINpHandle(string serverName, string pipeName, TimeoutTimer timeout, bool tlsFirst) + public SNINpHandle(string serverName, string pipeName, TimeoutTimer timeout, bool tlsFirst, string hostNameInCertificate, string serverCertificateFilename) { using (TrySNIEventScope.Create(nameof(SNINpHandle))) { @@ -47,6 +49,8 @@ public SNINpHandle(string serverName, string pipeName, TimeoutTimer timeout, boo _sendSync = new object(); _targetServer = serverName; _tlsFirst = tlsFirst; + _hostNameInCertificate = hostNameInCertificate; + _serverCertificateFilename = serverCertificateFilename; try { _pipeStream = new NamedPipeClientStream( @@ -369,14 +373,14 @@ public override void DisableSsl() /// Validate server certificate /// /// Sender object - /// X.509 certificate + /// X.509 certificate /// X.509 chain /// Policy errors /// true if valid - private bool ValidateServerCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors) + private bool ValidateServerCertificate(object sender, X509Certificate serverCertificate, X509Chain chain, SslPolicyErrors policyErrors) { using (TrySNIEventScope.Create(nameof(SNINpHandle))) - { + { if (!_validateCert) { SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Certificate validation not requested.", args0: ConnectionId); @@ -384,8 +388,8 @@ private bool ValidateServerCertificate(object sender, X509Certificate cert, X509 } SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Proceeding to SSL certificate validation.", args0: ConnectionId); - return SNICommon.ValidateSslServerCertificate(_targetServer, cert, policyErrors); - } + return SNICommon.ValidateSslServerCertificate(_connectionId, _targetServer, _hostNameInCertificate, serverCertificate, _serverCertificateFilename, policyErrors); + } } /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs index d39f382bd6..0ee31e5f46 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Buffers; using System.Diagnostics; using System.IO; using System.Net; @@ -25,7 +26,7 @@ internal class SNIProxy private static readonly SNIProxy s_singleton = new SNIProxy(); internal static SNIProxy Instance => s_singleton; -#if !NET7_0_OR_GREATER +#if !NET8_0_OR_GREATER /// /// Generate SSPI context /// @@ -34,7 +35,21 @@ internal class SNIProxy /// Send buffer /// Service Principal Name buffer /// SNI error code - internal static void GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, byte[] receivedBuff, ref byte[] sendBuff, byte[][] serverName) + internal static void GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, ReadOnlyMemory receivedBuff, ref byte[] sendBuff, byte[][] serverName) + { + // TODO: this should use ReadOnlyMemory all the way through + byte[] array = null; + + if (!receivedBuff.IsEmpty) + { + array = new byte[receivedBuff.Length]; + receivedBuff.CopyTo(array); + } + + GenSspiClientContext(sspiClientContextStatus, array, ref sendBuff, serverName); + } + + private static void GenSspiClientContext(SspiClientContextStatus sspiClientContextStatus, byte[] receivedBuff, ref byte[] sendBuff, byte[][] serverName) { SafeDeleteContext securityContext = sspiClientContextStatus.SecurityContext; ContextFlagsPal contextFlags = sspiClientContextStatus.ContextFlags; @@ -189,9 +204,9 @@ internal static SNIHandle CreateConnectionHandle( case DataSource.Protocol.TCP: sniHandle = CreateTcpHandle(details, timeout, parallel, ipPreference, cachedFQDN, ref pendingDNSInfo, tlsFirst, hostNameInCertificate, serverCertificateFilename); - break; + break; case DataSource.Protocol.NP: - sniHandle = CreateNpHandle(details, timeout, parallel, tlsFirst); + sniHandle = CreateNpHandle(details, timeout, parallel, tlsFirst, hostNameInCertificate, serverCertificateFilename); break; default: Debug.Fail($"Unexpected connection protocol: {details._connectionProtocol}"); @@ -347,8 +362,10 @@ private static SNITCPHandle CreateTcpHandle( /// Timer expiration /// Should MultiSubnetFailover be used. Only returns an error for named pipes. /// + /// Host name in certificate + /// Used for the path to the Server Certificate /// SNINpHandle - private static SNINpHandle CreateNpHandle(DataSource details, TimeoutTimer timeout, bool parallel, bool tlsFirst) + private static SNINpHandle CreateNpHandle(DataSource details, TimeoutTimer timeout, bool parallel, bool tlsFirst, string hostNameInCertificate, string serverCertificateFilename) { if (parallel) { @@ -356,7 +373,7 @@ private static SNINpHandle CreateNpHandle(DataSource details, TimeoutTimer timeo SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.MultiSubnetFailoverWithNonTcpProtocol, Strings.SNI_ERROR_49); return null; } - return new SNINpHandle(details.PipeHostName, details.PipeName, timeout, tlsFirst); + return new SNINpHandle(details.PipeHostName, details.PipeName, timeout, tlsFirst, hostNameInCertificate, serverCertificateFilename); } /// @@ -653,10 +670,10 @@ private bool InferConnectionDetails() Port = port; } - // Instance Name Handling. - if (backSlashIndex > -1) + // Instance Name Handling. Only if we found a '\' and we did not find a port in the Data Source + else if (backSlashIndex > -1) { - // This means that there is a part separated by '\' + // This means that there will not be any part separated by comma. InstanceName = tokensByCommaAndSlash[1].Trim(); if (string.IsNullOrWhiteSpace(InstanceName)) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs deleted file mode 100644 index a1bf4a9e0e..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIStreams.Task.cs +++ /dev/null @@ -1,93 +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.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Data.SqlClient.SNI -{ - // NetCore2.1: - // DO NOT OVERRIDE ValueTask versions of ReadAsync and WriteAsync because the underlying SslStream implements them - // by calling the Task versions which are already overridden meaning that if a caller uses Task WriteAsync this would - // call ValueTask WriteAsync which then called TaskWriteAsync introducing a lock cycle and never return - - internal sealed partial class SNISslStream - { - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - await _readAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - return await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - } - catch (System.Exception e) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNISslStream), EventType.ERR, "Internal Exception occurred while reading data: {0}", args0: e?.Message); - throw; - } - finally - { - _readAsyncSemaphore.Release(); - } - } - - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - await _writeAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - await base.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - } - catch (System.Exception e) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNISslStream), EventType.ERR, "Internal Exception occurred while reading data: {0}", args0: e?.Message); - throw; - } - finally - { - _writeAsyncSemaphore.Release(); - } - } - } - - internal sealed partial class SNINetworkStream - { - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - await _readAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - return await base.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - } - catch (System.Exception e) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNISslStream), EventType.ERR, "Internal Exception occurred while reading data: {0}", args0: e?.Message); - throw; - } - finally - { - _readAsyncSemaphore.Release(); - } - } - - // Prevent the WriteAsync collisions by running the task in a Semaphore Slim - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - await _writeAsyncSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - await base.WriteAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); - } - catch (System.Exception e) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNISslStream), EventType.ERR, "Internal Exception occurred while reading data: {0}", args0: e?.Message); - throw; - } - finally - { - _writeAsyncSemaphore.Release(); - } - } - } -} 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 d12e91ad62..2791de17a4 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 @@ -644,7 +644,6 @@ public override uint EnableSsl(uint options) } else { - // TODO: Resolve whether to send _serverNameIndication or _targetServer. _serverNameIndication currently results in error. Why? _sslStream.AuthenticateAsClient(_targetServer, null, s_supportedProtocols, false); } if (_sslOverTdsStream is not null) @@ -698,33 +697,8 @@ private bool ValidateServerCertificate(object sender, X509Certificate serverCert return true; } - string serverNameToValidate; - if (!string.IsNullOrEmpty(_hostNameInCertificate)) - { - serverNameToValidate = _hostNameInCertificate; - } - else - { - serverNameToValidate = _targetServer; - } - - if (!string.IsNullOrEmpty(_serverCertificateFilename)) - { - X509Certificate clientCertificate = null; - try - { - clientCertificate = new X509Certificate(_serverCertificateFilename); - return SNICommon.ValidateSslServerCertificate(clientCertificate, serverCertificate, policyErrors); - } - catch (Exception e) - { - // if this fails, then fall back to the HostNameInCertificate or TargetServer validation. - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, IOException occurred: {1}", args0: _connectionId, args1: e.Message); - } - } - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, Certificate will be validated for Target Server name", args0: _connectionId); - return SNICommon.ValidateSslServerCertificate(serverNameToValidate, serverCertificate, policyErrors); + return SNICommon.ValidateSslServerCertificate(_connectionId, _targetServer, _hostNameInCertificate, serverCertificate, _serverCertificateFilename, policyErrors); } /// @@ -1008,7 +982,7 @@ public override void KillConnection() internal static void SetKeepAliveValues(ref Socket socket) { -#if NETCOREAPP +#if NET6_0_OR_GREATER socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 1); socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 30); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.NetStandard.cs deleted file mode 100644 index 60bb597974..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SslOverTdsStream.NetStandard.cs +++ /dev/null @@ -1,223 +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.Buffers; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Data.SqlClient.SNI -{ - internal sealed partial class SslOverTdsStream : Stream - { - public override int Read(byte[] buffer, int offset, int count) - { - using (TrySNIEventScope.Create(nameof(SslOverTdsStream))) - { - if (!_encapsulate) - { - return _stream.Read(buffer, offset, count); - } - - if (_packetBytes > 0) - { - // there are queued bytes from a previous packet available - // work out how many of the remaining bytes we can consume - int wantedCount = Math.Min(count, _packetBytes); - int readCount = _stream.Read(buffer, offset, wantedCount); - if (readCount == 0) - { - // 0 means the connection was closed, tell the caller - return 0; - } - _packetBytes -= readCount; - return readCount; - } - else - { - byte[] headerBytes = ArrayPool.Shared.Rent(TdsEnums.HEADER_LEN); - Array.Clear(headerBytes, 0, headerBytes.Length); - - // fetch the packet header to determine how long the packet is - int headerBytesRead = 0; - do - { - int headerBytesReadIteration = _stream.Read(headerBytes, headerBytesRead, (TdsEnums.HEADER_LEN - headerBytesRead)); - if (headerBytesReadIteration == 0) - { - // 0 means the connection was closed, cleanup the rented array and then tell the caller - ArrayPool.Shared.Return(headerBytes, clearArray: true); - return 0; - } - headerBytesRead += headerBytesReadIteration; - } while (headerBytesRead < TdsEnums.HEADER_LEN); - - // read the packet data size from the header and store it in case it is needed for a subsequent call - _packetBytes = ((headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8) | headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - TdsEnums.HEADER_LEN; - - ArrayPool.Shared.Return(headerBytes, clearArray: true); - - // read as much from the packet as the caller can accept - int packetBytesRead = _stream.Read(buffer, offset, Math.Min(count, _packetBytes)); - _packetBytes -= packetBytesRead; - return packetBytesRead; - } - } - } - - public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - using (TrySNIEventScope.Create(nameof(SslOverTdsStream))) - { - if (!_encapsulate) - { - return await _stream.ReadAsync(buffer, offset, count, cancellationToken); - } - - if (_packetBytes > 0) - { - // there are queued bytes from a previous packet available - // work out how many of the remaining bytes we can consume - int wantedCount = Math.Min(count, _packetBytes); - int readCount = await _stream.ReadAsync(buffer, offset, wantedCount, cancellationToken); - if (readCount == 0) - { - // 0 means the connection was closed, tell the caller - return 0; - } - _packetBytes -= readCount; - return readCount; - } - else - { - byte[] headerBytes = ArrayPool.Shared.Rent(TdsEnums.HEADER_LEN); - Array.Clear(headerBytes, 0, headerBytes.Length); - - // fetch the packet header to determine how long the packet is - int headerBytesRead = 0; - do - { - int headerBytesReadIteration = await _stream.ReadAsync(headerBytes, headerBytesRead, (TdsEnums.HEADER_LEN - headerBytesRead), cancellationToken); - if (headerBytesReadIteration == 0) - { - // 0 means the connection was closed, cleanup the rented array and then tell the caller - ArrayPool.Shared.Return(headerBytes, clearArray: true); - return 0; - } - headerBytesRead += headerBytesReadIteration; - } while (headerBytesRead < TdsEnums.HEADER_LEN); - - // read the packet data size from the header and store it in case it is needed for a subsequent call - _packetBytes = ((headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET] << 8) | headerBytes[TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - TdsEnums.HEADER_LEN; - - ArrayPool.Shared.Return(headerBytes, clearArray: true); - - // read as much from the packet as the caller can accept - int packetBytesRead = await _stream.ReadAsync(buffer, offset, Math.Min(count, _packetBytes), cancellationToken); - _packetBytes -= packetBytesRead; - return packetBytesRead; - } - } - } - - public override void Write(byte[] buffer, int offset, int count) - { - using (TrySNIEventScope.Create(nameof(SslOverTdsStream))) - { - // During the SSL negotiation phase, SSL is tunnelled over TDS packet type 0x12. After - // negotiation, the underlying socket only sees SSL frames. - if (!_encapsulate) - { - _stream.Write(buffer, offset, count); - _stream.Flush(); - return; - } - - int remainingBytes = count; - int dataOffset = offset; - byte[] packetBuffer = null; - while (remainingBytes > 0) - { - int dataLength = Math.Min(PACKET_SIZE_WITHOUT_HEADER, remainingBytes); - int packetLength = TdsEnums.HEADER_LEN + dataLength; - remainingBytes -= dataLength; - - if (packetBuffer == null) - { - packetBuffer = ArrayPool.Shared.Rent(packetLength); - } - else if (packetBuffer.Length < packetLength) - { - ArrayPool.Shared.Return(packetBuffer, clearArray: true); - packetBuffer = ArrayPool.Shared.Rent(packetLength); - } - - SetupPreLoginPacketHeader(packetBuffer, dataLength, remainingBytes); - - Array.Copy(buffer, dataOffset, packetBuffer, TdsEnums.HEADER_LEN, dataLength); - - _stream.Write(packetBuffer, 0, packetLength); - _stream.Flush(); - - dataOffset += dataLength; - } - if (packetBuffer != null) - { - ArrayPool.Shared.Return(packetBuffer, clearArray: true); - } - } - } - - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - using (TrySNIEventScope.Create(nameof(SslOverTdsStream))) - { - if (!_encapsulate) - { - await _stream.WriteAsync(buffer, offset, count).ConfigureAwait(false); - Task flushTask = _stream.FlushAsync(); - if (flushTask.Status == TaskStatus.RanToCompletion) - { - await flushTask.ConfigureAwait(false); - } - return; - } - - int remainingBytes = count; - int dataOffset = offset; - byte[] packetBuffer = null; - while (remainingBytes > 0) - { - int dataLength = Math.Min(PACKET_SIZE_WITHOUT_HEADER, remainingBytes); - int packetLength = TdsEnums.HEADER_LEN + dataLength; - remainingBytes -= dataLength; - - if (packetBuffer == null) - { - packetBuffer = ArrayPool.Shared.Rent(packetLength); - } - else if (packetBuffer.Length < packetLength) - { - ArrayPool.Shared.Return(packetBuffer, clearArray: true); - packetBuffer = ArrayPool.Shared.Rent(packetLength); - } - - SetupPreLoginPacketHeader(packetBuffer, dataLength, remainingBytes); - - Array.Copy(buffer, dataOffset, packetBuffer, TdsEnums.HEADER_LEN, dataLength); - - await _stream.WriteAsync(packetBuffer, 0, packetLength, cancellationToken).ConfigureAwait(false); - await _stream.FlushAsync().ConfigureAwait(false); - - dataOffset += dataLength; - } - if (packetBuffer != null) - { - ArrayPool.Shared.Return(packetBuffer, clearArray: true); - } - } - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SspiClientContextStatus.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SspiClientContextStatus.cs index b557bfa0be..d9aabab16b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SspiClientContextStatus.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SspiClientContextStatus.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. +#if !NET8_0_OR_GREATER + using System.Net; using System.Net.Security; @@ -28,3 +30,5 @@ public ContextFlagsPal ContextFlags } } } + +#endif diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.NetStandard.cs deleted file mode 100644 index 01a84342f8..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlAuthenticationProviderManager.NetStandard.cs +++ /dev/null @@ -1,15 +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. - -namespace Microsoft.Data.SqlClient -{ - internal partial class SqlAuthenticationProviderManager - { - static SqlAuthenticationProviderManager() - { - Instance = new SqlAuthenticationProviderManager(); - SetDefaultAuthProviders(Instance); - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs index 273394395a..92c6d0075c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs @@ -1640,14 +1640,12 @@ public void WriteToServer(DbDataReader reader) try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowSource = reader; _dbDataReaderRowSource = reader; _sqlDataReaderRowSource = reader as SqlDataReader; - - _dataTableSource = null; _rowSourceType = ValueSourceType.DbDataReader; - _isAsyncBulkCopy = false; WriteRowSourceToServerAsync(reader.FieldCount, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; } finally @@ -1673,12 +1671,11 @@ public void WriteToServer(IDataReader reader) try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowSource = reader; _sqlDataReaderRowSource = _rowSource as SqlDataReader; _dbDataReaderRowSource = _rowSource as DbDataReader; - _dataTableSource = null; _rowSourceType = ValueSourceType.IDataReader; - _isAsyncBulkCopy = false; WriteRowSourceToServerAsync(reader.FieldCount, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; } finally @@ -1707,13 +1704,12 @@ public void WriteToServer(DataTable table, DataRowState rowState) try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowStateToSkip = ((rowState == 0) || (rowState == DataRowState.Deleted)) ? DataRowState.Deleted : ~rowState | DataRowState.Deleted; _rowSource = table; _dataTableSource = table; - _sqlDataReaderRowSource = null; _rowSourceType = ValueSourceType.DataTable; _rowEnumerator = table.Rows.GetEnumerator(); - _isAsyncBulkCopy = false; WriteRowSourceToServerAsync(table.Columns.Count, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; } @@ -1746,16 +1742,14 @@ public void WriteToServer(DataRow[] rows) try { statistics = SqlStatistics.StartTimer(Statistics); - + ResetWriteToServerGlobalVariables(); DataTable table = rows[0].Table; Debug.Assert(null != table, "How can we have rows without a table?"); _rowStateToSkip = DataRowState.Deleted; // Don't allow deleted rows _rowSource = rows; _dataTableSource = table; - _sqlDataReaderRowSource = null; _rowSourceType = ValueSourceType.RowArray; _rowEnumerator = rows.GetEnumerator(); - _isAsyncBulkCopy = false; WriteRowSourceToServerAsync(table.Columns.Count, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; } @@ -1787,7 +1781,7 @@ public Task WriteToServerAsync(DataRow[] rows, CancellationToken cancellationTok try { statistics = SqlStatistics.StartTimer(Statistics); - + ResetWriteToServerGlobalVariables(); if (rows.Length == 0) { return cancellationToken.IsCancellationRequested ? @@ -1800,7 +1794,6 @@ public Task WriteToServerAsync(DataRow[] rows, CancellationToken cancellationTok _rowStateToSkip = DataRowState.Deleted; // Don't allow deleted rows _rowSource = rows; _dataTableSource = table; - _sqlDataReaderRowSource = null; _rowSourceType = ValueSourceType.RowArray; _rowEnumerator = rows.GetEnumerator(); _isAsyncBulkCopy = true; @@ -1834,10 +1827,10 @@ public Task WriteToServerAsync(DbDataReader reader, CancellationToken cancellati try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowSource = reader; _sqlDataReaderRowSource = reader as SqlDataReader; _dbDataReaderRowSource = reader; - _dataTableSource = null; _rowSourceType = ValueSourceType.DbDataReader; _isAsyncBulkCopy = true; resultTask = WriteRowSourceToServerAsync(reader.FieldCount, cancellationToken); // It returns Task since _isAsyncBulkCopy = true; @@ -1871,10 +1864,10 @@ public Task WriteToServerAsync(IDataReader reader, CancellationToken cancellatio try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowSource = reader; _sqlDataReaderRowSource = _rowSource as SqlDataReader; _dbDataReaderRowSource = _rowSource as DbDataReader; - _dataTableSource = null; _rowSourceType = ValueSourceType.IDataReader; _isAsyncBulkCopy = true; resultTask = WriteRowSourceToServerAsync(reader.FieldCount, cancellationToken); // It returns Task since _isAsyncBulkCopy = true; @@ -1914,9 +1907,9 @@ public Task WriteToServerAsync(DataTable table, DataRowState rowState, Cancellat try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowStateToSkip = ((rowState == 0) || (rowState == DataRowState.Deleted)) ? DataRowState.Deleted : ~rowState | DataRowState.Deleted; _rowSource = table; - _sqlDataReaderRowSource = null; _dataTableSource = table; _rowSourceType = ValueSourceType.DataTable; _rowEnumerator = table.Rows.GetEnumerator(); @@ -3093,5 +3086,17 @@ private Task WriteToServerInternalAsync(CancellationToken ctoken) } return resultTask; } + + private void ResetWriteToServerGlobalVariables() + { + _dataTableSource = null; + _dbDataReaderRowSource = null; + _isAsyncBulkCopy = false; + _rowEnumerator = null; + _rowSource = null; + _rowSourceType = ValueSourceType.Unspecified; + _sqlDataReaderRowSource = null; + _sqlDataReaderRowSource = null; + } } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientFactory.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientFactory.NetCoreApp.cs deleted file mode 100644 index 4b0d4a8b2d..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientFactory.NetCoreApp.cs +++ /dev/null @@ -1,20 +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.Data.Common; - -namespace Microsoft.Data.SqlClient -{ - public sealed partial class SqlClientFactory : DbProviderFactory - { - /// - public override bool CanCreateBatch => true; - - /// - public override DbBatch CreateBatch() => new SqlBatch(); - - /// - public override DbBatchCommand CreateBatchCommand() => new SqlBatchCommand(); - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientFactory.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientFactory.cs deleted file mode 100644 index 2dd3261fe6..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlClientFactory.cs +++ /dev/null @@ -1,55 +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.Data.Common; - -namespace Microsoft.Data.SqlClient -{ - /// - public sealed partial class SqlClientFactory : DbProviderFactory - { - /// - public static readonly SqlClientFactory Instance = new SqlClientFactory(); - - private SqlClientFactory() - { - } - - /// - public override DbCommand CreateCommand() - { - return new SqlCommand(); - } - - /// - public override DbCommandBuilder CreateCommandBuilder() - { - return new SqlCommandBuilder(); - } - - /// - public override DbConnection CreateConnection() - { - return new SqlConnection(); - } - - /// - public override DbConnectionStringBuilder CreateConnectionStringBuilder() - { - return new SqlConnectionStringBuilder(); - } - - /// - public override DbDataAdapter CreateDataAdapter() - { - return new SqlDataAdapter(); - } - - /// - public override DbParameter CreateParameter() - { - return new SqlParameter(); - } - } -} 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 39dbb917e0..94325d3c88 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 @@ -3994,7 +3994,7 @@ private SqlDataReader GetParameterEncryptionDataReader(out Task returnTask, Task SqlCommand command = (SqlCommand)state; bool processFinallyBlockAsync = true; bool decrementAsyncCountInFinallyBlockAsync = true; -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -4068,7 +4068,7 @@ private SqlDataReader GetParameterEncryptionDataReaderAsync(out Task returnTask, bool processFinallyBlockAsync = true; bool decrementAsyncCountInFinallyBlockAsync = true; -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -6776,7 +6776,7 @@ internal SqlBatchCommand GetCurrentBatchCommand() } else { - return _rpcArrayOf1[0].batchCommand; + return _rpcArrayOf1?[0].batchCommand; } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs index 4b4e7ccc43..1d044633ec 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnection.cs @@ -227,6 +227,7 @@ private SqlConnection(SqlConnection connection) } _accessToken = connection._accessToken; + _accessTokenCallback = connection._accessTokenCallback; CacheConnectionStringProperties(); } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionFactory.AssemblyLoadContext.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionFactory.AssemblyLoadContext.cs index 7338b8d4d2..230b7ae5fc 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionFactory.AssemblyLoadContext.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlConnectionFactory.AssemblyLoadContext.cs @@ -2,13 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if NET6_0_OR_GREATER + using System; using System.Reflection; using System.Runtime.Loader; namespace Microsoft.Data.SqlClient { - sealed internal partial class SqlConnectionFactory + internal sealed partial class SqlConnectionFactory { partial void SubscribeToAssemblyLoadContextUnload() { @@ -21,3 +23,5 @@ private void SqlConnectionFactoryAssemblyLoadContext_Unloading(AssemblyLoadConte } } } + +#endif 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 5eb7d7cdeb..c538483fc8 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 @@ -1353,7 +1353,7 @@ override public string GetName(int i) } /// -#if NET7_0_OR_GREATER +#if NET8_0_OR_GREATER [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] #endif override public Type GetProviderSpecificFieldType(int i) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.NetCoreApp.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.NetCoreApp.cs index c4655c4355..561f9bd6fb 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.NetCoreApp.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.NetCoreApp.cs @@ -7,7 +7,7 @@ namespace Microsoft.Data.SqlClient { - sealed internal partial class SqlDelegatedTransaction : IPromotableSinglePhaseNotification + internal sealed partial class SqlDelegatedTransaction : IPromotableSinglePhaseNotification { // Get the server-side Global Transaction Id from the PromotedDTCToken // Skip first 4 bytes since they contain the version diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.NetStandard.cs deleted file mode 100644 index cb97c4d677..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlDelegatedTransaction.NetStandard.cs +++ /dev/null @@ -1,22 +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.Transactions; - -namespace Microsoft.Data.SqlClient -{ - sealed internal partial class SqlDelegatedTransaction : IPromotableSinglePhaseNotification - { - // Get the server-side Global Transaction Id from the PromotedDTCToken - // Skip first 4 bytes since they contain the version - private Guid GetGlobalTxnIdentifierFromToken() - { - byte[] txnGuid = new byte[16]; - Array.Copy(_connection.PromotedDTCToken, _globalTransactionsTokenVersionSizeInBytes, // Skip the version - txnGuid, 0, txnGuid.Length); - return new Guid(txnGuid); - } - } -} 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 3ed756eef0..2f9e1e8e06 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,7 @@ 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 +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -146,7 +146,7 @@ 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 +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -256,7 +256,7 @@ 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 +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -343,7 +343,7 @@ 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 +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try 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 dd7043d629..5ef3d781ea 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 @@ -2300,7 +2300,7 @@ 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 +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.NetStandard.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.NetStandard.cs deleted file mode 100644 index 72c0b77b19..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.NetStandard.cs +++ /dev/null @@ -1,41 +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.Buffers; -using System.Diagnostics; - -namespace Microsoft.Data.SqlClient -{ - internal sealed partial class TdsParser - { - internal static void FillGuidBytes(Guid guid, Span buffer) - { - byte[] bytes = guid.ToByteArray(); - bytes.AsSpan().CopyTo(buffer); - } - - internal static void FillDoubleBytes(double value, Span buffer) - { - byte[] bytes = BitConverter.GetBytes(value); - bytes.AsSpan().CopyTo(buffer); - } - - internal static void FillFloatBytes(float value, Span buffer) - { - byte[] bytes = BitConverter.GetBytes(value); - bytes.AsSpan().CopyTo(buffer); - } - - internal static Guid ConstructGuid(ReadOnlySpan bytes) - { - Debug.Assert(bytes.Length >= 16, "not enough bytes to set guid"); - byte[] temp = ArrayPool.Shared.Rent(16); - bytes.CopyTo(temp.AsSpan()); - Guid retval = new Guid(temp); - ArrayPool.Shared.Return(temp); - return retval; - } - } -} diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs index f7a0363f27..7f15666951 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.Windows.cs @@ -10,8 +10,6 @@ namespace Microsoft.Data.SqlClient { internal sealed partial class TdsParser { - private static volatile bool s_fSSPILoaded = false; // bool to indicate whether library has been loaded - internal void PostReadAsyncForMars() { if (TdsParserStateObjectFactory.UseManagedSNI) @@ -43,37 +41,7 @@ internal void PostReadAsyncForMars() _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); ThrowExceptionAndWarning(_physicalStateObj); } - } - - private void LoadSSPILibrary() - { - if (TdsParserStateObjectFactory.UseManagedSNI) - return; - // Outer check so we don't acquire lock once it's loaded. - if (!s_fSSPILoaded) - { - lock (s_tdsParserLock) - { - // re-check inside lock - if (!s_fSSPILoaded) - { - // use local for ref param to defer setting s_maxSSPILength until we know the call succeeded. - uint maxLength = 0; - - if (0 != SNINativeMethodWrapper.SNISecInitPackage(ref maxLength)) - SSPIError(SQLMessage.SSPIInitializeError(), TdsEnums.INIT_SSPI_PACKAGE); - - s_maxSSPILength = maxLength; - s_fSSPILoaded = true; - } - } - } - - if (s_maxSSPILength > int.MaxValue) - { - throw SQL.InvalidSSPIPacketSize(); // SqlBu 332503 - } - } + } private void WaitForSSLHandShakeToComplete(ref uint error, ref int protocolVersion) { 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 7e04f6b9c5..8a5ed05abe 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 @@ -55,6 +55,8 @@ internal static void Assert(string message) private static int _objectTypeCount; // EventSource counter private readonly SqlClientLogger _logger = new SqlClientLogger(); + private SSPIContextProvider _authenticationProvider; + internal readonly int _objectID = Interlocked.Increment(ref _objectTypeCount); internal int ObjectID => _objectID; @@ -146,16 +148,9 @@ internal static void Assert(string message) // NIC address caching private static byte[] s_nicAddress; // cache the NIC address from the registry - // SSPI variables - - private volatile static uint s_maxSSPILength = 0; // variable to hold max SSPI data size, keep for token from server - // textptr sequence private static readonly byte[] s_longDataHeader = { 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - private static object s_tdsParserLock = new object(); - - // XML metadata substitute sequence private static readonly byte[] s_xmlMetadataSubstituteSequence = { 0xe7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -422,11 +417,12 @@ internal void Connect( } _sniSpnBuffer = null; + _authenticationProvider = null; // AD Integrated behaves like Windows integrated when connecting to a non-fedAuth server if (integratedSecurity || authType == SqlAuthenticationMethod.ActiveDirectoryIntegrated) { - LoadSSPILibrary(); + _authenticationProvider = _physicalStateObj.CreateSSPIContextProvider(); SqlClientEventSource.Log.TryTraceEvent("TdsParser.Connect | SEC | SSPI or Active Directory Authentication Library loaded for SQL Server based integrated authentication"); } @@ -472,6 +468,8 @@ internal void Connect( hostNameInCertificate, serverCertificateFilename); + _authenticationProvider?.Initialize(serverInfo, _physicalStateObj, this); + if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); @@ -569,6 +567,8 @@ internal void Connect( hostNameInCertificate, serverCertificateFilename); + _authenticationProvider?.Initialize(serverInfo, _physicalStateObj, this); + if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); @@ -1286,7 +1286,7 @@ private void FireInfoMessageEvent(SqlConnection connection, SqlCommand command, sqlErs.Add(error); - SqlException exc = SqlException.CreateException(sqlErs, serverVersion, _connHandler, innerException:null, batchCommand: command?.GetCurrentBatchCommand()); + SqlException exc = SqlException.CreateException(sqlErs, serverVersion, _connHandler, innerException: null, batchCommand: command?.GetCurrentBatchCommand()); bool notified; connection.OnInfoMessage(new SqlInfoMessageEventArgs(exc), out notified); @@ -1509,9 +1509,7 @@ internal SqlError ProcessSNIError(TdsParserStateObject stateObj) SqlClientEventSource.Log.TryAdvancedTraceEvent(" Empty error message received from SNI. Error Message = {0}", details.errorMessage); } - string sniContextEnumName = TdsEnums.GetSniContextEnumName(stateObj.SniContext); - - string sqlContextInfo = StringsHelper.GetResourceString(sniContextEnumName); + string sqlContextInfo = StringsHelper.GetResourceString(stateObj.SniContext.ToString()); string providerRid = string.Format("SNI_PN{0}", details.provider); string providerName = StringsHelper.GetResourceString(providerRid); Debug.Assert(!string.IsNullOrEmpty(providerName), $"invalid providerResourceId '{providerRid}'"); @@ -1776,7 +1774,7 @@ internal void WriteInt(int v, TdsParserStateObject stateObj) internal static void WriteInt(Span buffer, int value) { -#if NETCOREAPP +#if NET6_0_OR_GREATER BinaryPrimitives.TryWriteInt32LittleEndian(buffer, value); #else buffer[0] = (byte)(value & 0xff); @@ -2742,6 +2740,9 @@ private bool TryProcessEnvChange(int tokenLength, TdsParserStateObject stateObj, // to MARS initialization! int packetSize = int.Parse(env._newValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + SqlClientEventSource.Log.TryTraceEvent("{0}.{1} | Info | Server sent env packet size change of {2}, ClientConnectionID {3}", + nameof(TdsParser), nameof(TryProcessEnvChange), packetSize, _connHandler._clientConnectionId); + if (_physicalStateObj.SetPacketSize(packetSize)) { // If packet size changed, we need to release our SNIPackets since @@ -4001,7 +4002,7 @@ internal bool TryProcessError(byte token, TdsParserStateObject stateObj, SqlComm { batchIndex = command.GetCurrentBatchIndex(); } - error = new SqlError(number, state, errorClass, _server, message, procedure, line,exception: null, batchIndex: batchIndex); + error = new SqlError(number, state, errorClass, _server, message, procedure, line, exception: null, batchIndex: batchIndex); return true; } @@ -5744,7 +5745,7 @@ private bool TryReadSqlStringValue(SqlBuffer value, byte type, int length, Encod s = ""; } } - + if (buffIsRented) { // do not use clearArray:true on the rented array because it can be massively larger @@ -6146,7 +6147,7 @@ internal bool TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, int length, T } else { -#if NET7_0_OR_GREATER +#if NET8_0_OR_GREATER value.SqlBinary = SqlBinary.WrapBytes(b); #else value.SqlBinary = SqlTypeWorkarounds.SqlBinaryCtor(b, true); // doesn't copy the byte array @@ -6443,7 +6444,7 @@ internal bool TryReadSqlValueInternal(SqlBuffer value, byte tdsType, int length, { return false; } -#if NET7_0_OR_GREATER +#if NET8_0_OR_GREATER value.SqlBinary = SqlBinary.WrapBytes(b); #else value.SqlBinary = SqlTypeWorkarounds.SqlBinaryCtor(b, true); @@ -7315,7 +7316,7 @@ internal byte[] SerializeSqlDecimal(SqlDecimal d, TdsParserStateObject stateObj) Span data = stackalloc uint[4]; -#if NET7_0_OR_GREATER +#if NET8_0_OR_GREATER d.WriteTdsValue(data); #else SqlTypeWorkarounds.SqlDecimalExtractData(d, out data[0], out data[1], out data[2], out data[3]); @@ -7344,7 +7345,7 @@ internal void WriteSqlDecimal(SqlDecimal d, TdsParserStateObject stateObj) stateObj.WriteByte(0); Span data = stackalloc uint[4]; -#if NET7_0_OR_GREATER +#if NET8_0_OR_GREATER d.WriteTdsValue(data); #else SqlTypeWorkarounds.SqlDecimalExtractData(d, out data[0], out data[1], out data[2], out data[3]); @@ -7568,7 +7569,7 @@ private Task WriteEncodingChar(string s, Encoding encoding, TdsParserStateObject private byte[] SerializeEncodingChar(string s, int numChars, int offset, Encoding encoding) { -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK char[] charData; byte[] byteData = null; @@ -7605,7 +7606,7 @@ private Task WriteEncodingChar(string s, int numChars, int offset, Encoding enco } else { -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK char[] charData = s.ToCharArray(offset, numChars); byte[] byteData = encoding.GetBytes(charData, 0, numChars); Debug.Assert(byteData != null, "no data from encoding"); @@ -8108,165 +8109,6 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return len; } - internal void TdsLogin(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures, SessionData recoverySessionData, FederatedAuthenticationFeatureExtensionData fedAuthFeatureExtensionData, SqlConnectionEncryptOption encrypt) - { - _physicalStateObj.SetTimeoutSeconds(rec.timeout); - - Debug.Assert(recoverySessionData == null || (requestedFeatures & TdsEnums.FeatureExtension.SessionRecovery) != 0, "Recovery session data without session recovery feature request"); - Debug.Assert(TdsEnums.MAXLEN_HOSTNAME >= rec.hostName.Length, "_workstationId.Length exceeds the max length for this value"); - - Debug.Assert(!rec.useSSPI || (requestedFeatures & TdsEnums.FeatureExtension.FedAuth) == 0, "Cannot use both SSPI and FedAuth"); - Debug.Assert(fedAuthFeatureExtensionData == null || (requestedFeatures & TdsEnums.FeatureExtension.FedAuth) != 0, "fedAuthFeatureExtensionData provided without fed auth feature request"); - Debug.Assert(fedAuthFeatureExtensionData != null || (requestedFeatures & TdsEnums.FeatureExtension.FedAuth) == 0, "Fed Auth feature requested without specifying fedAuthFeatureExtensionData."); - - Debug.Assert(rec.userName == null || (rec.userName != null && TdsEnums.MAXLEN_CLIENTID >= rec.userName.Length), "_userID.Length exceeds the max length for this value"); - Debug.Assert(rec.credential == null || (rec.credential != null && TdsEnums.MAXLEN_CLIENTID >= rec.credential.UserId.Length), "_credential.UserId.Length exceeds the max length for this value"); - - Debug.Assert(rec.password == null || (rec.password != null && TdsEnums.MAXLEN_CLIENTSECRET >= rec.password.Length), "_password.Length exceeds the max length for this value"); - Debug.Assert(rec.credential == null || (rec.credential != null && TdsEnums.MAXLEN_CLIENTSECRET >= rec.credential.Password.Length), "_credential.Password.Length exceeds the max length for this value"); - - Debug.Assert(rec.credential != null || rec.userName != null || rec.password != null, "cannot mix the new secure password system and the connection string based password"); - Debug.Assert(rec.newSecurePassword != null || rec.newPassword != null, "cannot have both new secure change password and string based change password"); - Debug.Assert(TdsEnums.MAXLEN_APPNAME >= rec.applicationName.Length, "_applicationName.Length exceeds the max length for this value"); - Debug.Assert(TdsEnums.MAXLEN_SERVERNAME >= rec.serverName.Length, "_dataSource.Length exceeds the max length for this value"); - Debug.Assert(TdsEnums.MAXLEN_LANGUAGE >= rec.language.Length, "_currentLanguage .Length exceeds the max length for this value"); - Debug.Assert(TdsEnums.MAXLEN_DATABASE >= rec.database.Length, "_initialCatalog.Length exceeds the max length for this value"); - Debug.Assert(TdsEnums.MAXLEN_ATTACHDBFILE >= rec.attachDBFilename.Length, "_attachDBFileName.Length exceeds the max length for this value"); - - Debug.Assert(_connHandler != null, "SqlConnectionInternalTds handler can not be null at this point."); - _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.LoginBegin); - _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth); - - // get the password up front to use in sspi logic below - byte[] encryptedPassword = null; - byte[] encryptedChangePassword = null; - int encryptedPasswordLengthInBytes; - int encryptedChangePasswordLengthInBytes; - bool useFeatureExt = (requestedFeatures != TdsEnums.FeatureExtension.None); - - string userName; - - if (rec.credential != null) - { - userName = rec.credential.UserId; - encryptedPasswordLengthInBytes = rec.credential.Password.Length * 2; - } - else - { - userName = rec.userName; - encryptedPassword = TdsParserStaticMethods.ObfuscatePassword(rec.password); - encryptedPasswordLengthInBytes = encryptedPassword.Length; // password in clear text is already encrypted and its length is in byte - } - - if (rec.newSecurePassword != null) - { - encryptedChangePasswordLengthInBytes = rec.newSecurePassword.Length * 2; - } - else - { - encryptedChangePassword = TdsParserStaticMethods.ObfuscatePassword(rec.newPassword); - encryptedChangePasswordLengthInBytes = encryptedChangePassword.Length; - } - - // set the message type - _physicalStateObj._outputMessageType = TdsEnums.MT_LOGIN7; - - // length in bytes - int length = TdsEnums.SQL2005_LOG_REC_FIXED_LEN; - - string clientInterfaceName = TdsEnums.SQL_PROVIDER_NAME; - Debug.Assert(TdsEnums.MAXLEN_CLIENTINTERFACE >= clientInterfaceName.Length, "cchCltIntName can specify at most 128 unicode characters. See Tds spec"); - - // add up variable-len portions (multiply by 2 for byte len of char strings) - // - checked - { - length += (rec.hostName.Length + rec.applicationName.Length + - rec.serverName.Length + clientInterfaceName.Length + - rec.language.Length + rec.database.Length + - rec.attachDBFilename.Length) * 2; - if (useFeatureExt) - { - length += 4; - } - } - - // allocate memory for SSPI variables - byte[] rentedSSPIBuff = null; - byte[] outSSPIBuff = null; - uint outSSPILength = 0; - - // only add lengths of password and username if not using SSPI or requesting federated authentication info - if (!rec.useSSPI && !(_connHandler._federatedAuthenticationInfoRequested || _connHandler._federatedAuthenticationRequested)) - { - checked - { - length += (userName.Length * 2) + encryptedPasswordLengthInBytes - + encryptedChangePasswordLengthInBytes; - } - } - else - { - if (rec.useSSPI) - { - // now allocate proper length of buffer, and set length - rentedSSPIBuff = ArrayPool.Shared.Rent((int)s_maxSSPILength); - outSSPIBuff = rentedSSPIBuff; - outSSPILength = s_maxSSPILength; - - // Call helper function for SSPI data and actual length. - // Since we don't have SSPI data from the server, send null for the - // byte[] buffer and 0 for the int length. - Debug.Assert(SniContext.Snix_Login == _physicalStateObj.SniContext, $"Unexpected SniContext. Expecting Snix_Login, actual value is '{_physicalStateObj.SniContext}'"); - _physicalStateObj.SniContext = SniContext.Snix_LoginSspi; - - SSPIData(null, 0, ref outSSPIBuff, ref outSSPILength); - - if (outSSPILength > int.MaxValue) - { - throw SQL.InvalidSSPIPacketSize(); // SqlBu 332503 - } - _physicalStateObj.SniContext = SniContext.Snix_Login; - - checked - { - length += (int)outSSPILength; - } - } - } - - int feOffset = length; - // calculate and reserve the required bytes for the featureEx - length = ApplyFeatureExData(requestedFeatures, recoverySessionData, fedAuthFeatureExtensionData, useFeatureExt, length); - - WriteLoginData(rec, - requestedFeatures, - recoverySessionData, - fedAuthFeatureExtensionData, - encrypt, - encryptedPassword, - encryptedChangePassword, - encryptedPasswordLengthInBytes, - encryptedChangePasswordLengthInBytes, - useFeatureExt, - userName, - length, - feOffset, - clientInterfaceName, - outSSPIBuff, - outSSPILength); - - if (rentedSSPIBuff != null) - { - ArrayPool.Shared.Return(rentedSSPIBuff, clearArray: true); - } - - _physicalStateObj.WritePacket(TdsEnums.HARDFLUSH); - _physicalStateObj.ResetSecurePasswordsInformation(); - _physicalStateObj.HasPendingData = true; - _physicalStateObj._messageStatus = 0; - }// tdsLogin - private void WriteLoginData(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures, SessionData recoverySessionData, @@ -8617,81 +8459,6 @@ internal void SendFedAuthToken(SqlFedAuthToken fedAuthToken) _connHandler._federatedAuthenticationRequested = true; } - private void SSPIData(byte[] receivedBuff, uint receivedLength, ref byte[] sendBuff, ref uint sendLength) - { - if (TdsParserStateObjectFactory.UseManagedSNI) - { - try - { - _physicalStateObj.GenerateSspiClientContext(receivedBuff, receivedLength, ref sendBuff, ref sendLength, _sniSpnBuffer); - } - catch (Exception e) - { - SSPIError(e.Message + Environment.NewLine + e.StackTrace, TdsEnums.GEN_CLIENT_CONTEXT); - } - } - else - { - if (receivedBuff == null) - { - // if we do not have SSPI data coming from server, send over 0's for pointer and length - receivedLength = 0; - } - - // we need to respond to the server's message with SSPI data - if (0 != _physicalStateObj.GenerateSspiClientContext(receivedBuff, receivedLength, ref sendBuff, ref sendLength, _sniSpnBuffer)) - { - SSPIError(SQLMessage.SSPIGenerateError(), TdsEnums.GEN_CLIENT_CONTEXT); - } - } - } - - private void ProcessSSPI(int receivedLength) - { - SniContext outerContext = _physicalStateObj.SniContext; - _physicalStateObj.SniContext = SniContext.Snix_ProcessSspi; - // allocate received buffer based on length from SSPI message - byte[] receivedBuff = ArrayPool.Shared.Rent(receivedLength); - - // read SSPI data received from server - Debug.Assert(_physicalStateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); - bool result = _physicalStateObj.TryReadByteArray(receivedBuff, receivedLength); - if (!result) - { - throw SQL.SynchronousCallMayNotPend(); - } - - // allocate send buffer and initialize length - byte[] rentedSendBuff = ArrayPool.Shared.Rent((int)s_maxSSPILength); - byte[] sendBuff = rentedSendBuff; - uint sendLength = s_maxSSPILength; - - // make call for SSPI data - SSPIData(receivedBuff, (uint)receivedLength, ref sendBuff, ref sendLength); - - // DO NOT SEND LENGTH - TDS DOC INCORRECT! JUST SEND SSPI DATA! - _physicalStateObj.WriteByteArray(sendBuff, (int)sendLength, 0); - - ArrayPool.Shared.Return(rentedSendBuff, clearArray: true); - ArrayPool.Shared.Return(receivedBuff, clearArray: true); - - // set message type so server knows its a SSPI response - _physicalStateObj._outputMessageType = TdsEnums.MT_SSPI; - - // send to server - _physicalStateObj.WritePacket(TdsEnums.HARDFLUSH); - _physicalStateObj.SniContext = outerContext; - } - - private void SSPIError(string error, string procedure) - { - Debug.Assert(!string.IsNullOrEmpty(procedure), "TdsParser.SSPIError called with an empty or null procedure string"); - Debug.Assert(!string.IsNullOrEmpty(error), "TdsParser.SSPIError called with an empty or null error string"); - - _physicalStateObj.AddError(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, _server, error, procedure, 0)); - ThrowExceptionAndWarning(_physicalStateObj); - } - internal byte[] GetDTCAddress(int timeout, TdsParserStateObject stateObj) { // If this fails, the server will return a server error - Sameet Agarwal confirmed. @@ -9222,7 +8989,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, IList<_SqlRPC> rpcArray, int timeout int parametersLength = rpcext.userParamCount + rpcext.systemParamCount; bool isAdvancedTraceOn = SqlClientEventSource.Log.IsAdvancedTraceOn(); - bool enableOptimizedParameterBinding = cmd.EnableOptimizedParameterBinding; + bool enableOptimizedParameterBinding = cmd.EnableOptimizedParameterBinding && cmd.CommandType == CommandType.Text; for (int i = (ii == startRpc) ? startParam : 0; i < parametersLength; i++) { @@ -9240,7 +9007,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, IList<_SqlRPC> rpcArray, int timeout { // Throw an exception if ForceColumnEncryption is set on a parameter and the ColumnEncryption is not enabled on SqlConnection or SqlCommand if ( - !(cmd.ColumnEncryptionSetting == SqlCommandColumnEncryptionSetting.Enabled + !(cmd.ColumnEncryptionSetting == SqlCommandColumnEncryptionSetting.Enabled || (cmd.ColumnEncryptionSetting == SqlCommandColumnEncryptionSetting.UseConnectionSetting && cmd.Connection.IsColumnEncryptionSettingEnabled))) { diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs index 9a6ceb7054..d0431e1901 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserHelperClasses.cs @@ -764,13 +764,14 @@ private static string ToFriendlyName(this SslProtocols protocol) { name = "TLS 1.0"; } -#pragma warning disable CS0618 // Type or member is obsolete: SSL is depricated +// SSL 2.0 and 3.0 are only referenced to log a warning, not explicitly used for connections +#pragma warning disable CS0618, CA5397 else if ((protocol & SslProtocols.Ssl3) == SslProtocols.Ssl3) { name = "SSL 3.0"; } else if ((protocol & SslProtocols.Ssl2) == SslProtocols.Ssl2) -#pragma warning restore CS0618 // Type or member is obsolete: SSL is depricated +#pragma warning restore CS0618, CA5397 { name = "SSL 2.0"; } @@ -790,9 +791,10 @@ private static string ToFriendlyName(this SslProtocols protocol) public static string GetProtocolWarning(this SslProtocols protocol) { string message = string.Empty; -#pragma warning disable CS0618 // Type or member is obsolete : SSL is depricated +// SSL 2.0 and 3.0 are only referenced to log a warning, not explicitly used for connections +#pragma warning disable CS0618, CA5397 if ((protocol & (SslProtocols.Ssl2 | SslProtocols.Ssl3 | SslProtocols.Tls | SslProtocols.Tls11)) != SslProtocols.None) -#pragma warning restore CS0618 // Type or member is obsolete : SSL is depricated +#pragma warning restore CS0618, CA5397 { message = StringsHelper.Format(Strings.SEC_ProtocolWarning, protocol.ToFriendlyName()); } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs index b1bb4065c8..520367963d 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.netcore.cs @@ -62,7 +62,7 @@ internal TdsParserStateObject(TdsParser parser, TdsParserStateObject physicalCon AddError(parser.ProcessSNIError(this)); ThrowExceptionAndWarning(); } - + // we post a callback that represents the call to dispose; once the // object is disposed, the next callback will cause the GC Handle to // be released. @@ -75,6 +75,7 @@ internal TdsParserStateObject(TdsParser parser, TdsParserStateObject physicalCon //////////////// internal abstract uint DisableSsl(); + internal abstract SSPIContextProvider CreateSSPIContextProvider(); internal abstract uint EnableMars(ref uint info); @@ -83,6 +84,8 @@ internal abstract uint Status get; } + internal abstract Guid? SessionId { get; } + internal abstract SessionHandle SessionHandle { get; @@ -236,8 +239,6 @@ internal abstract void CreatePhysicalSNIHandle( protected abstract void RemovePacketFromPendingList(PacketHandle pointer); - internal abstract uint GenerateSspiClientContext(byte[] receivedBuff, uint receivedLength, ref byte[] sendBuff, ref uint sendLength, byte[][] _sniSpnBuffer); - internal int DecrementPendingCallbacks(bool release) { int remaining = Interlocked.Decrement(ref _pendingCallbacks); diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs index 1e0141dd58..b912ea9f09 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObjectManaged.cs @@ -21,11 +21,7 @@ internal sealed class TdsParserStateObjectManaged : TdsParserStateObject { private SNIMarsConnection? _marsConnection; private SNIHandle? _sessionHandle; -#if NET7_0_OR_GREATER - private NegotiateAuthentication? _negotiateAuth = null; -#else - private SspiClientContextStatus? _sspiClientContextStatus; -#endif + public TdsParserStateObjectManaged(TdsParser parser) : base(parser) { } internal TdsParserStateObjectManaged(TdsParser parser, TdsParserStateObject physicalConnection, bool async) : @@ -232,6 +228,8 @@ internal override PacketHandle ReadSyncOverAsync(int timeoutRemaining, out uint protected override PacketHandle EmptyReadPacket => PacketHandle.FromManagedPacket(null); + internal override Guid? SessionId => _sessionHandle?.ConnectionId; + internal override bool IsPacketEmpty(PacketHandle packet) => packet.ManagedPacket == null; internal override void ReleasePacket(PacketHandle syncReadPacket) @@ -389,30 +387,6 @@ internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) return TdsEnums.SNI_SUCCESS; } - internal override uint GenerateSspiClientContext(byte[] receivedBuff, - uint receivedLength, - ref byte[] sendBuff, - ref uint sendLength, - byte[][] _sniSpnBuffer) - { -#if NET7_0_OR_GREATER - _negotiateAuth ??= new(new NegotiateAuthenticationClientOptions { Package = "Negotiate", TargetName = Encoding.Unicode.GetString(_sniSpnBuffer[0]) }); - sendBuff = _negotiateAuth.GetOutgoingBlob(receivedBuff, out NegotiateAuthenticationStatusCode statusCode)!; - SqlClientEventSource.Log.TryTraceEvent("TdsParserStateObjectManaged.GenerateSspiClientContext | Info | Session Id {0}, StatusCode={1}", _sessionHandle?.ConnectionId, statusCode); - if (statusCode is not NegotiateAuthenticationStatusCode.Completed and not NegotiateAuthenticationStatusCode.ContinueNeeded) - { - throw new InvalidOperationException(SQLMessage.SSPIGenerateError() + Environment.NewLine + statusCode); - } -#else - _sspiClientContextStatus ??= new SspiClientContextStatus(); - - SNIProxy.GenSspiClientContext(_sspiClientContextStatus, receivedBuff, ref sendBuff, _sniSpnBuffer); - SqlClientEventSource.Log.TryTraceEvent("TdsParserStateObjectManaged.GenerateSspiClientContext | Info | Session Id {0}", _sessionHandle?.ConnectionId); -#endif - sendLength = (uint)(sendBuff != null ? sendBuff.Length : 0); - return 0; - } - internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) { protocolVersion = GetSessionSNIHandleHandleOrThrow().ProtocolVersion; @@ -432,5 +406,12 @@ private SNIHandle GetSessionSNIHandleHandleOrThrow() [DoesNotReturn] [MethodImpl(MethodImplOptions.NoInlining)] // this forces the exception throwing code not to be inlined for performance private void ThrowClosedConnection() => throw ADP.ClosedConnectionError(); + + internal override SSPIContextProvider CreateSSPIContextProvider() +#if NET8_0_OR_GREATER + => new NegotiateSSPIContextProvider(); +#else + => new ManagedSSPIContextProvider(); +#endif } } 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 59776956a1..611a003177 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 @@ -167,7 +167,7 @@ internal override void CreatePhysicalSNIHandle( byte[] srvSPN = Encoding.Unicode.GetBytes(serverSPN); Trace.Assert(srvSPN.Length <= SNINativeMethodWrapper.SniMaxComposedSpnLength, "Length of the provided SPN exceeded the buffer size."); spnBuffer[0] = srvSPN; - SqlClientEventSource.Log.TryTraceEvent("<{0}.{1}|SEC> Server SPN `{2}` from the connection string is used.",nameof(TdsParserStateObjectNative), nameof(CreatePhysicalSNIHandle), serverSPN); + SqlClientEventSource.Log.TryTraceEvent("<{0}.{1}|SEC> Server SPN `{2}` from the connection string is used.", nameof(TdsParserStateObjectNative), nameof(CreatePhysicalSNIHandle), serverSPN); } else { @@ -272,6 +272,8 @@ internal override PacketHandle ReadSyncOverAsync(int timeoutRemaining, out uint protected override PacketHandle EmptyReadPacket => PacketHandle.FromNativePointer(default); + internal override Guid? SessionId => default; + internal override bool IsPacketEmpty(PacketHandle readPacket) { Debug.Assert(readPacket.Type == PacketHandle.NativePointerType || readPacket.Type == 0, "unexpected packet type when requiring NativePointer"); @@ -398,9 +400,6 @@ internal override uint EnableSsl(ref uint info, bool tlsFirst, string serverCert internal override uint SetConnectionBufferSize(ref uint unsignedPacketSize) => SNINativeMethodWrapper.SNISetInfo(Handle, SNINativeMethodWrapper.QTypes.SNI_QUERY_CONN_BUFSIZE, ref unsignedPacketSize); - internal override uint GenerateSspiClientContext(byte[] receivedBuff, uint receivedLength, ref byte[] sendBuff, ref uint sendLength, byte[][] _sniSpnBuffer) - => SNINativeMethodWrapper.SNISecGenClientContext(Handle, receivedBuff, receivedLength, sendBuff, ref sendLength, _sniSpnBuffer[0]); - internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) { uint returnValue = SNINativeMethodWrapper.SNIWaitForSSLHandshakeToComplete(Handle, GetTimeoutRemaining(), out uint nativeProtocolVersion); @@ -410,7 +409,7 @@ internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) { protocolVersion = (int)SslProtocols.Tls12; } -#if NETCOREAPP +#if NET6_0_OR_GREATER 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 */ @@ -427,13 +426,14 @@ internal override uint WaitForSSLHandShakeToComplete(out int protocolVersion) } else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL3_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL3_SERVER)) { -#pragma warning disable CS0618 // Type or member is obsolete : SSL is depricated +// SSL 2.0 and 3.0 are only referenced to log a warning, not explicitly used for connections +#pragma warning disable CS0618, CA5397 protocolVersion = (int)SslProtocols.Ssl3; } else if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL2_CLIENT) || nativeProtocol.HasFlag(NativeProtocols.SP_PROT_SSL2_SERVER)) { protocolVersion = (int)SslProtocols.Ssl2; -#pragma warning restore CS0618 // Type or member is obsolete : SSL is depricated +#pragma warning restore CS0618, CA5397 } else //if (nativeProtocol.HasFlag(NativeProtocols.SP_PROT_NONE)) { @@ -451,6 +451,8 @@ internal override void DisposePacketCache() } } + internal override SSPIContextProvider CreateSSPIContextProvider() => new NativeSSPIContextProvider(); + internal sealed class WritePacketCache : IDisposable { private bool _disposed; 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 cfbd2139eb..319e0d0169 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,7 @@ public override void Flush() } /// -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK [HostProtection(ExternalThreading = true)] #endif public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) @@ -318,7 +318,7 @@ public override int EndRead(IAsyncResult asyncResult) } /// -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK [HostProtection(ExternalThreading = true)] #endif public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) @@ -693,11 +693,7 @@ static private string InitializeNtPath(string path) // Ensure we have validated and normalized the path before AssertPathFormat(path); string uniqueId = Guid.NewGuid().ToString("N"); -#if NETSTANDARD - return System.IO.PathInternal.IsDeviceUNC(path.AsSpan()) -#else return System.IO.PathInternal.IsDeviceUNC(path) -#endif ? string.Format(CultureInfo.InvariantCulture, @"{0}\{1}", path.Replace(@"\\.", @"\??"), uniqueId) : string.Format(CultureInfo.InvariantCulture, @"\??\UNC\{0}\{1}", path.Trim('\\'), uniqueId); } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/PinvokeAnalyzerExceptionList.analyzerdata.netstandard b/src/Microsoft.Data.SqlClient/netcore/src/PinvokeAnalyzerExceptionList.analyzerdata.netstandard deleted file mode 100644 index 5c0648966d..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/PinvokeAnalyzerExceptionList.analyzerdata.netstandard +++ /dev/null @@ -1,44 +0,0 @@ - -kernel32.dll!LoadLibraryExW -sni.dll!GetSniMaxComposedSpnLength -sni.dll!SNIAddProviderWrapper -sni.dll!SNICheckConnectionWrapper -sni.dll!SNICloseWrapper -sni.dll!SNIGetInfoWrapper -sni.dll!SNIGetLastError -sni.dll!SNIInitialize -sni.dll!SNIOpenSyncExWrapper -sni.dll!SNIOpenWrapper -sni.dll!SNIPacketAllocateWrapper -sni.dll!SNIPacketGetDataWrapper -sni.dll!SNIPacketRelease -sni.dll!SNIPacketResetWrapper -sni.dll!SNIPacketSetData -sni.dll!SNIQueryInfo -sni.dll!SNIReadAsyncWrapper -sni.dll!SNIReadSyncOverAsync -sni.dll!SNIRemoveProviderWrapper -sni.dll!SNISecGenClientContextWrapper -sni.dll!SNISecInitPackage -sni.dll!SNISetInfoWrapper -sni.dll!SNITerminate -sni.dll!SNIWaitForSSLHandshakeToCompleteWrapper -sni.dll!SNIWriteAsyncWrapper -sni.dll!SNIWriteSyncOverAsync -sni.dll!UnmanagedIsTokenRestricted -sspicli.dll!AcceptSecurityContext -sspicli.dll!AcquireCredentialsHandleW -sspicli.dll!ApplyControlToken -sspicli.dll!CompleteAuthToken -sspicli.dll!DecryptMessage -sspicli.dll!DeleteSecurityContext -sspicli.dll!EncryptMessage -sspicli.dll!EnumerateSecurityPackagesW -sspicli.dll!FreeContextBuffer -sspicli.dll!FreeCredentialsHandle -sspicli.dll!InitializeSecurityContextW -sspicli.dll!QueryContextAttributesW -sspicli.dll!QuerySecurityContextToken -sspicli.dll!SetContextAttributesW -sspicli.dll!SspiEncodeStringsAsAuthIdentity -sspicli.dll!SspiFreeAuthIdentity \ No newline at end of file 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 97feee8bef..e291206a4a 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -1,10 +1,8 @@ - - - + {407890AC-9876-4FEF-A6F1-F36A876BAADE} Microsoft.Data.SqlClient - v4.6.2 + net462 true Microsoft.Data.SqlClient AnyCPU @@ -17,6 +15,7 @@ True + false $(DefineConstants);NETFRAMEWORK; @@ -24,7 +23,7 @@ full - $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(GeneratedSourceFileName)')) + $([System.IO.Path]::Combine('$(IntermediateOutputPath)\$(TargetFramework)','$(GeneratedSourceFileName)')) @@ -94,522 +93,543 @@ - + Microsoft\Data\Common\ActivityCorrelator.cs - + Microsoft\Data\Common\AdapterUtil.cs - + Microsoft\Data\Common\AdapterUtil.Windows.cs - + Microsoft\Data\Common\BitConverterCompatible.cs - + Microsoft\Data\Common\DbConnectionStringCommon.cs - + Microsoft\Data\Common\DbConnectionOptions.Common.cs - + Microsoft\Data\Common\DbConnectionPoolKey.cs - + Microsoft\Data\Common\MultipartIdentifier.cs - + Microsoft\Data\Common\NameValuePair.cs - + Microsoft\Data\DataException.cs - + Microsoft\Data\OperationAbortedException.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolAuthenticationContext.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolAuthenticationContextKey.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolGroup.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolGroupProviderInfo.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolOptions.cs - + Microsoft\Data\ProviderBase\DbConnectionPoolProviderInfo.cs - + Microsoft\Data\ProviderBase\DbMetaDataFactory.cs - + Microsoft\Data\ProviderBase\FieldNameLookup.cs - + Microsoft\Data\ProviderBase\TimeoutTimer.cs - + + Microsoft\Data\SqlClient\SSPI\ManagedSSPIContextProvider.cs + + + Microsoft\Data\SqlClient\SSPI\NativeSSPIContextProvider.cs + + + Microsoft\Data\SqlClient\SSPI\NegotiateSSPIContextProvider.cs + + + Microsoft\Data\SqlClient\SSPI\SSPIContextProvider.cs + + + Microsoft\Data\SqlClient\TdsParser.cs + + Microsoft\Data\Sql\SqlDataSourceEnumerator.cs - + Microsoft\Data\Sql\SqlDataSourceEnumerator.Windows.cs - + Microsoft\Data\Sql\SqlDataSourceEnumeratorNativeHelper.cs - + Microsoft\Data\Sql\SqlDataSourceEnumeratorUtil.cs - + Microsoft\Data\Sql\SqlNotificationRequest.cs - + Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationTimeoutRetryHelper.cs - + Microsoft\Data\SqlClient\ApplicationIntent.cs - + Microsoft\Data\SqlClient\AssemblyRef.cs - + Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationProvider.cs - + Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs - + Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.cs - + Microsoft\Data\SqlClient\ColumnEncryptionKeyInfo.cs - + Microsoft\Data\SqlClient\DataClassification\SensitivityClassification.cs - + Microsoft\Data\SqlClient\DisposableTemporaryOnStack.cs - + Microsoft\Data\SqlClient\EnclaveDelegate.cs - + Microsoft\Data\SqlClient\EnclaveDelegate.Crypto.cs - + Microsoft\Data\SqlClient\EnclavePackage.cs - + Microsoft\Data\SqlClient\EnclaveProviderBase.cs - + Microsoft\Data\SqlClient\EnclaveSessionCache.cs - + Microsoft\Data\SqlClient\LocalAppContextSwitches.cs - + Microsoft\Data\SqlClient\NoneAttestationEnclaveProvider.cs - + Microsoft\Data\SqlClient\OnChangedEventHandler.cs - + Microsoft\Data\SqlClient\ParameterPeekAheadValue.cs - + Microsoft\Data\SqlClient\PoolBlockingPeriod.cs - + Microsoft\Data\SqlClient\Reliability\AppConfigManager.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryingEventArgs.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryIntervalBaseEnumerator.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryLogic.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryLogicBase.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryLogicBaseProvider.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryLogicProvider.cs - + Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryFactory.cs - + Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicLoader.cs - + Microsoft\Data\SqlClient\Reliability\SqlConfigurableRetryLogicManager.cs - + Microsoft\Data\SqlClient\Reliability\SqlRetryIntervalEnumerators.cs - + Microsoft\Data\SqlClient\RowsCopiedEventArgs.cs - + Microsoft\Data\SqlClient\RowsCopiedEventHandler.cs - + Microsoft\Data\SqlClient\Server\ExtendedClrTypeCode.cs - + Microsoft\Data\SqlClient\Server\ITypedGetters.cs - + Microsoft\Data\SqlClient\Server\ITypedGettersV3.cs - + Microsoft\Data\SqlClient\Server\ITypedSetters.cs - + Microsoft\Data\SqlClient\Server\ITypedSettersV3.cs - + Microsoft\Data\SqlClient\Server\MemoryRecordBuffer.cs - + Microsoft\Data\SqlClient\Server\MetadataUtilsSmi.cs - + Microsoft\Data\SqlClient\Server\SmiEventSink.cs - + Microsoft\Data\SqlClient\Server\SmiEventSink_Default.Common.cs - + Microsoft\Data\SqlClient\Server\SmiEventSink_Default.netfx.cs - + Microsoft\Data\SqlClient\Server\SmiGettersStream.cs - + Microsoft\Data\SqlClient\Server\SmiMetaData.cs - + Microsoft\Data\SqlClient\Server\SmiMetaDataProperty.cs - + Microsoft\Data\SqlClient\Server\SmiRecordBuffer.cs - + Microsoft\Data\SqlClient\Server\SmiSettersStream.cs - + Microsoft\Data\SqlClient\Server\SmiTypedGetterSetter.cs - + Microsoft\Data\SqlClient\Server\SmiXetterAccess.Common.cs - + Microsoft\Data\SqlClient\Server\SmiXetterTypeCode.cs - + Microsoft\Data\SqlClient\Server\SqlDataRecord.cs - + Microsoft\Data\SqlClient\Server\SqlDataRecord.netfx.cs - + Microsoft\Data\SqlClient\Server\SqlMetaData.cs - + Microsoft\Data\SqlClient\Server\SqlNormalizer.cs - + Microsoft\Data\SqlClient\Server\SqlRecordBuffer.cs - + Microsoft\Data\SqlClient\SqlTransaction.Common.cs - + Microsoft\Data\SqlClient\Server\ValueUtilsSmi.cs - + Microsoft\Data\SqlClient\Server\ValueUtilsSmi.netfx.cs - + Microsoft\Data\SqlClient\Server\SqlSer.cs - + Microsoft\Data\SqlClient\SignatureVerificationCache.cs - + Microsoft\Data\SqlClient\SortOrder.cs - + Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Algorithm.cs - + Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256EncryptionKey.cs - + Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Factory.cs - + Microsoft\Data\SqlClient\SqlAuthenticationParameters.cs - + Microsoft\Data\SqlClient\SqlAuthenticationProvider.cs - + Microsoft\Data\SqlClient\SqlBuffer.cs - + Microsoft\Data\SqlClient\SqlAuthenticationToken.cs - + Microsoft\Data\SqlClient\SqlBatchCommand.cs - + Microsoft\Data\SqlClient\SqlBulkCopyColumnMapping.cs - + Microsoft\Data\SqlClient\SqlBulkCopyColumnMappingCollection.cs - + Microsoft\Data\SqlClient\SqlBulkCopyColumnOrderHint.cs - + Microsoft\Data\SqlClient\SqlBulkCopyColumnOrderHintCollection.cs - + Microsoft\Data\SqlClient\SqlBulkCopyOptions.cs - + Microsoft\Data\SqlClient\SqlCachedBuffer.cs - + Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithm.cs - + Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactory.cs - + Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactoryList.cs - + Microsoft\Data\SqlClient\SqlClientEncryptionType.cs - + Microsoft\Data\SqlClient\SqlClientEventSource.cs - + + Microsoft\Data\SqlClient\SqlClientFactory.cs + + Microsoft\Data\SqlClient\SqlClientLogger.cs - + Microsoft\Data\SqlClient\SqlClientMetaDataCollectionNames.cs - + Microsoft\Data\SqlClient\SqlClientSymmetricKey.cs - + Microsoft\Data\SqlClient\SqlCollation.cs - + Microsoft\Data\SqlClient\SqlColumnEncryptionKeyStoreProvider.cs - + Microsoft\Data\SqlClient\SqlCommandBuilder.cs - + Microsoft\Data\SqlClient\SqlCommandSet.cs - + Microsoft\Data\SqlClient\SqlConnectionEncryptOption.cs - + Microsoft\Data\SqlClient\SqlConnectionEncryptOptionConverter.cs - + Microsoft\Data\SqlClient\SqlConnectionPoolGroupProviderInfo.cs - + Microsoft\Data\SqlClient\SqlConnectionPoolKey.cs - + Microsoft\Data\SqlClient\SqlConnectionPoolProviderInfo.cs - + Microsoft\Data\SqlClient\SqlConnectionString.cs - + Microsoft\Data\SqlClient\SqlConnectionStringBuilder.cs - + Microsoft\Data\SqlClient\SqlConnectionTimeoutErrorInternal.cs - + Microsoft\Data\SqlClient\SqlCredential.cs - + Microsoft\Data\SqlClient\SqlDataAdapter.cs - + Microsoft\Data\SqlClient\SqlDependency.cs - + Microsoft\Data\SqlClient\SqlDependencyListener.cs - + Microsoft\Data\SqlClient\SqlDependencyUtils.cs - + Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.Crypto.cs - + Microsoft\Data\SqlClient\SqlEnclaveSession.cs - + Microsoft\Data\SqlClient\SqlEnums.cs - + Microsoft\Data\SqlClient\SqlEnvChange.cs - + Microsoft\Data\SqlClient\SqlError.cs - + Microsoft\Data\SqlClient\SqlErrorCollection.cs - + Microsoft\Data\SqlClient\SqlException.cs - + Microsoft\Data\SqlClient\SQLFallbackDNSCache.cs - + Microsoft\Data\SqlClient\SqlInfoMessageEvent.cs - + Microsoft\Data\SqlClient\SqlInfoMessageEventHandler.cs - + Microsoft\Data\SqlClient\SqlInternalConnection.cs - + Microsoft\Data\SqlClient\SqlInternalTransaction.cs - + Microsoft\Data\SqlClient\SqlMetaDataFactory.cs - + Microsoft\Data\SqlClient\SqlNotificationEventArgs.cs - + Microsoft\Data\SqlClient\SqlNotificationInfo.cs - + Microsoft\Data\SqlClient\SqlNotificationSource.cs - + Microsoft\Data\SqlClient\SqlNotificationType.cs - + Microsoft\Data\SqlClient\SqlParameterCollection.cs - + Microsoft\Data\SqlClient\SqlParameter.cs - + Microsoft\Data\SqlClient\SqlQueryMetadataCache.cs - + Microsoft\Data\SqlClient\SqlReferenceCollection.cs - + Microsoft\Data\SqlClient\SqlRowUpdatedEvent.cs - + Microsoft\Data\SqlClient\SqlRowUpdatedEventHandler.cs - + Microsoft\Data\SqlClient\SqlRowUpdatingEvent.cs - + Microsoft\Data\SqlClient\SqlRowUpdatingEventHandler.cs - + Microsoft\Data\SqlClient\SqlSecurityUtility.cs - + Microsoft\Data\SqlClient\SqlSequentialStream.cs - + Microsoft\Data\SqlClient\SqlStream.cs - + Microsoft\Data\SqlClient\SqlStatistics.cs - + Microsoft\Data\SqlClient\SqlSequentialTextReader.cs - + Microsoft\Data\SqlClient\SqlSymmetricKeyCache.cs - + Microsoft\Data\SqlClient\SqlUdtInfo.cs - + Microsoft\Data\SqlClient\SqlUtil.cs - + Microsoft\Data\SqlClient\TdsEnums.cs - + Microsoft\Data\SqlClient\TdsParameterSetter.cs - + Microsoft\Data\SqlClient\TdsParserSafeHandles.Windows.cs - + Microsoft\Data\SqlClient\TdsParserStateObject.cs - + Microsoft\Data\SqlClient\TdsParserStaticMethods.cs - + Microsoft\Data\SqlClient\TdsRecordBufferSetter.cs - + Microsoft\Data\SqlClient\TdsParserSessionPool.cs - + Microsoft\Data\SqlClient\TdsValueSetter.cs - + Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.cs - + Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.cs - + Microsoft\Data\SqlTypes\SQLResource.cs - + Microsoft\Data\SqlTypes\SqlTypeWorkarounds.cs - + Resources\ResCategoryAttribute.cs - + Resources\ResDescriptionAttribute.cs + + Microsoft\Data\ProviderBase\DbReferenceCollection.cs + @@ -631,7 +651,6 @@ - @@ -652,7 +671,6 @@ - @@ -686,23 +704,23 @@ - + Resources\StringsHelper.cs - + Resources\Strings.Designer.cs True True Strings.resx - + Resources\Strings.resx Microsoft.Data.SqlClient.Resources.Strings.resources System ResXFileCodeGenerator Strings.Designer.cs - + Resources\%(RecursiveDir)%(Filename)%(Extension) @@ -746,8 +764,7 @@ $(SystemBuffersVersion) - - + 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 index 50552a3fb3..6e9bda11cd 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperARM64.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/Interop/SNINativeManagedWrapperARM64.cs @@ -116,7 +116,7 @@ internal static extern uint SNIOpenWrapper( [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISecGenClientContextWrapper")] internal static extern unsafe uint SNISecGenClientContextWrapper( [In] SNIHandle pConn, - [In, Out] byte[] pIn, + [In, Out] byte* pIn, uint cbIn, [In, Out] byte[] pOut, [In] ref uint pcbOut, 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 f4970e1cda..acb10c8c79 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 @@ -116,7 +116,7 @@ internal static extern uint SNIOpenWrapper( [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISecGenClientContextWrapper")] internal static extern unsafe uint SNISecGenClientContextWrapper( [In] SNIHandle pConn, - [In, Out] byte[] pIn, + [In, Out] byte* pIn, uint cbIn, [In, Out] byte[] pOut, [In] ref uint pcbOut, 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 6e1a0abf5f..c8bb7c0e93 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 @@ -116,7 +116,7 @@ internal static extern uint SNIOpenWrapper( [DllImport(SNI, CallingConvention = CallingConvention.Cdecl, EntryPoint = "SNISecGenClientContextWrapper")] internal static extern unsafe uint SNISecGenClientContextWrapper( [In] SNIHandle pConn, - [In, Out] byte[] pIn, + [In, Out] byte* pIn, uint cbIn, [In, Out] byte[] pOut, [In] ref uint pcbOut, 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 b9af5849c4..898fcc6866 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 @@ -889,8 +889,7 @@ private static unsafe void SNIPacketSetData(SNIPacket pPacket, [In] byte* pbBuf, private static unsafe uint SNISecGenClientContextWrapper( [In] SNIHandle pConn, - [In, Out] byte[] pIn, - uint cbIn, + [In, Out] ReadOnlySpan pIn, [In, Out] byte[] pOut, [In] ref uint pcbOut, [MarshalAsAttribute(UnmanagedType.Bool)] out bool pfDone, @@ -899,16 +898,19 @@ private static unsafe uint SNISecGenClientContextWrapper( [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszUserName, [MarshalAsAttribute(UnmanagedType.LPWStr)] string pwszPassword) { - switch (s_architecture) + fixed (byte* pInPtr = pIn) { - 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()); + switch (s_architecture) + { + case System.Runtime.InteropServices.Architecture.Arm64: + return SNINativeManagedWrapperARM64.SNISecGenClientContextWrapper(pConn, pInPtr, (uint)pIn.Length, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword); + case System.Runtime.InteropServices.Architecture.X64: + return SNINativeManagedWrapperX64.SNISecGenClientContextWrapper(pConn, pInPtr, (uint)pIn.Length, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword); + case System.Runtime.InteropServices.Architecture.X86: + return SNINativeManagedWrapperX86.SNISecGenClientContextWrapper(pConn, pInPtr, (uint)pIn.Length, pOut, ref pcbOut, out pfDone, szServerInfo, cbServerInfo, pwszUserName, pwszPassword); + default: + throw ADP.SNIPlatformNotSupported(s_architecture.ToString()); + } } } @@ -1378,7 +1380,7 @@ Int32[] passwordOffsets // Offset into data buffer where the password to be w } } - internal static unsafe uint SNISecGenClientContext(SNIHandle pConnectionObject, byte[] inBuff, uint receivedLength, byte[] OutBuff, ref uint sendLength, byte[] serverUserName) + internal static unsafe uint SNISecGenClientContext(SNIHandle pConnectionObject, ReadOnlySpan inBuff, byte[] OutBuff, ref uint sendLength, byte[] serverUserName) { fixed (byte* pin_serverUserName = &serverUserName[0]) { @@ -1386,7 +1388,6 @@ internal static unsafe uint SNISecGenClientContext(SNIHandle pConnectionObject, return SNISecGenClientContextWrapper( pConnectionObject, inBuff, - receivedLength, OutBuff, ref sendLength, out local_fDone, diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs index 6b65491499..54b03683b7 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs @@ -1689,6 +1689,7 @@ public void WriteToServer(DbDataReader reader) try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowSource = reader; _dbDataReaderRowSource = reader; _sqlDataReaderRowSource = reader as SqlDataReader; @@ -1697,10 +1698,8 @@ public void WriteToServer(DbDataReader reader) { _rowSourceIsSqlDataReaderSmi = _sqlDataReaderRowSource is SqlDataReaderSmi; } - _dataTableSource = null; _rowSourceType = ValueSourceType.DbDataReader; - _isAsyncBulkCopy = false; WriteRowSourceToServerAsync(reader.FieldCount, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; } finally @@ -1728,6 +1727,7 @@ public void WriteToServer(IDataReader reader) try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowSource = reader; _sqlDataReaderRowSource = _rowSource as SqlDataReader; if (_sqlDataReaderRowSource != null) @@ -1735,9 +1735,7 @@ public void WriteToServer(IDataReader reader) _rowSourceIsSqlDataReaderSmi = _sqlDataReaderRowSource is SqlDataReaderSmi; } _dbDataReaderRowSource = _rowSource as DbDataReader; - _dataTableSource = null; _rowSourceType = ValueSourceType.IDataReader; - _isAsyncBulkCopy = false; WriteRowSourceToServerAsync(reader.FieldCount, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; } finally @@ -1768,13 +1766,12 @@ public void WriteToServer(DataTable table, DataRowState rowState) try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowStateToSkip = ((rowState == 0) || (rowState == DataRowState.Deleted)) ? DataRowState.Deleted : ~rowState | DataRowState.Deleted; _rowSource = table; _dataTableSource = table; - _sqlDataReaderRowSource = null; _rowSourceType = ValueSourceType.DataTable; _rowEnumerator = table.Rows.GetEnumerator(); - _isAsyncBulkCopy = false; WriteRowSourceToServerAsync(table.Columns.Count, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; } @@ -1809,16 +1806,14 @@ public void WriteToServer(DataRow[] rows) try { statistics = SqlStatistics.StartTimer(Statistics); - + ResetWriteToServerGlobalVariables(); DataTable table = rows[0].Table; Debug.Assert(null != table, "How can we have rows without a table?"); _rowStateToSkip = DataRowState.Deleted; // Don't allow deleted rows _rowSource = rows; _dataTableSource = table; - _sqlDataReaderRowSource = null; _rowSourceType = ValueSourceType.RowArray; _rowEnumerator = rows.GetEnumerator(); - _isAsyncBulkCopy = false; WriteRowSourceToServerAsync(table.Columns.Count, CancellationToken.None); //It returns null since _isAsyncBulkCopy = false; } @@ -1851,7 +1846,7 @@ public Task WriteToServerAsync(DataRow[] rows, CancellationToken cancellationTok try { statistics = SqlStatistics.StartTimer(Statistics); - + ResetWriteToServerGlobalVariables(); if (rows.Length == 0) { TaskCompletionSource source = new TaskCompletionSource(); @@ -1872,7 +1867,6 @@ public Task WriteToServerAsync(DataRow[] rows, CancellationToken cancellationTok _rowStateToSkip = DataRowState.Deleted; // Don't allow deleted rows _rowSource = rows; _dataTableSource = table; - _sqlDataReaderRowSource = null; _rowSourceType = ValueSourceType.RowArray; _rowEnumerator = rows.GetEnumerator(); _isAsyncBulkCopy = true; @@ -1908,10 +1902,10 @@ public Task WriteToServerAsync(DbDataReader reader, CancellationToken cancellati try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowSource = reader; _sqlDataReaderRowSource = reader as SqlDataReader; _dbDataReaderRowSource = reader; - _dataTableSource = null; _rowSourceType = ValueSourceType.DbDataReader; _isAsyncBulkCopy = true; resultTask = WriteRowSourceToServerAsync(reader.FieldCount, cancellationToken); // It returns Task since _isAsyncBulkCopy = true; @@ -1946,10 +1940,10 @@ public Task WriteToServerAsync(IDataReader reader, CancellationToken cancellatio try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowSource = reader; _sqlDataReaderRowSource = _rowSource as SqlDataReader; _dbDataReaderRowSource = _rowSource as DbDataReader; - _dataTableSource = null; _rowSourceType = ValueSourceType.IDataReader; _isAsyncBulkCopy = true; resultTask = WriteRowSourceToServerAsync(reader.FieldCount, cancellationToken); // It returns Task since _isAsyncBulkCopy = true; @@ -1990,9 +1984,9 @@ public Task WriteToServerAsync(DataTable table, DataRowState rowState, Cancellat try { statistics = SqlStatistics.StartTimer(Statistics); + ResetWriteToServerGlobalVariables(); _rowStateToSkip = ((rowState == 0) || (rowState == DataRowState.Deleted)) ? DataRowState.Deleted : ~rowState | DataRowState.Deleted; _rowSource = table; - _sqlDataReaderRowSource = null; _dataTableSource = table; _rowSourceType = ValueSourceType.DataTable; _rowEnumerator = table.Rows.GetEnumerator(); @@ -3212,5 +3206,17 @@ private Task WriteToServerInternalAsync(CancellationToken ctoken) } return resultTask; } + + private void ResetWriteToServerGlobalVariables() + { + _dataTableSource = null; + _dbDataReaderRowSource = null; + _isAsyncBulkCopy = false; + _rowEnumerator = null; + _rowSource = null; + _rowSourceType = ValueSourceType.Unspecified; + _sqlDataReaderRowSource = null; + _sqlDataReaderRowSource = null; + } } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientFactory.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientFactory.cs deleted file mode 100644 index 3d44d202c0..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlClientFactory.cs +++ /dev/null @@ -1,98 +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.Common; -using System.Data.Sql; -using System.Security; -using System.Security.Permissions; -using Microsoft.Data.Common; - -namespace Microsoft.Data.SqlClient -{ - /// - public sealed class SqlClientFactory : DbProviderFactory, IServiceProvider - { - - /// - public static readonly SqlClientFactory Instance = new SqlClientFactory(); - - private SqlClientFactory() - { - } - - /// - public override bool CanCreateDataSourceEnumerator - { - get - { - return true; - } - } - - /// - public override DbCommand CreateCommand() - { - return new SqlCommand(); - } - - /// - public override DbCommandBuilder CreateCommandBuilder() - { - return new SqlCommandBuilder(); - } - - /// - public override DbConnection CreateConnection() - { - return new SqlConnection(); - } - - /// - public override DbConnectionStringBuilder CreateConnectionStringBuilder() - { - return new SqlConnectionStringBuilder(); - } - - /// - public override DbDataAdapter CreateDataAdapter() - { - return new SqlDataAdapter(); - } - - /// - public override DbParameter CreateParameter() - { - return new SqlParameter(); - } - - /// - public override CodeAccessPermission CreatePermission(PermissionState state) - { - return new SqlClientPermission(state); - } - - /// - public override DbDataSourceEnumerator CreateDataSourceEnumerator() - { - return SqlDataSourceEnumerator.Instance; - } - - /// - /// Extension mechanism for additional services; currently the only service - /// supported is the DbProviderServices - /// - /// requested service provider or null. - object IServiceProvider.GetService(Type serviceType) - { - object result = null; - if (serviceType == GreenMethods.SystemDataCommonDbProviderServices_Type) - { - result = GreenMethods.MicrosoftDataSqlClientSqlProviderServices_Instance(); - } - return result; - } - } -} - 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 0ac6ed775e..94cd927c1d 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 @@ -7487,7 +7487,7 @@ internal SqlBatchCommand GetCurrentBatchCommand() } else { - return _rpcArrayOf1[0].batchCommand; + return _rpcArrayOf1?[0].batchCommand; } } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs index b6104b9075..b9d2e32daa 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlConnection.cs @@ -429,6 +429,7 @@ private SqlConnection(SqlConnection connection) _credential = new SqlCredential(connection._credential.UserId, password); } _accessToken = connection._accessToken; + _accessTokenCallback = connection._accessTokenCallback; _serverCertificateValidationCallback = connection._serverCertificateValidationCallback; _clientCertificateRetrievalCallback = connection._clientCertificateRetrievalCallback; _originalNetworkAddressInfo = connection._originalNetworkAddressInfo; 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 7a9bbfdfd3..afa5220563 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 @@ -28,14 +28,15 @@ namespace Microsoft.Data.SqlClient { - // The TdsParser Object controls reading/writing to the netlib, parsing the tds, // and surfacing objects to the user. - sealed internal class TdsParser + sealed internal partial class TdsParser { private static int _objectTypeCount; // EventSource Counter private readonly SqlClientLogger _logger = new SqlClientLogger(); + private SSPIContextProvider _authenticationProvider; + internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); static Task completedTask; @@ -236,16 +237,9 @@ internal static void Assert(string message) // NIC address caching private static byte[] s_nicAddress; // cache the NIC address from the registry - // SSPI variables - private static bool s_fSSPILoaded = false; // bool to indicate whether library has been loaded - - private volatile static UInt32 s_maxSSPILength = 0; // variable to hold max SSPI data size, keep for token from server - // textptr sequence private static readonly byte[] s_longDataHeader = { 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - private static object s_tdsParserLock = new object(); - // Various other statics private const int ATTENTION_TIMEOUT = 5000; // internal attention timeout, in ticks @@ -549,7 +543,8 @@ internal void Connect(ServerInfo serverInfo, // AD Integrated behaves like Windows integrated when connecting to a non-fedAuth server if (integratedSecurity || authType == SqlAuthenticationMethod.ActiveDirectoryIntegrated) { - LoadSSPILibrary(); + _authenticationProvider = _physicalStateObj.CreateSSPIContextProvider(); + if (!string.IsNullOrEmpty(serverInfo.ServerSPN)) { // Native SNI requires the Unicode encoding and any other encoding like UTF8 breaks the code. @@ -567,7 +562,9 @@ internal void Connect(ServerInfo serverInfo, } else { + _authenticationProvider = null; _sniSpnBuffer = null; + switch (authType) { case SqlAuthenticationMethod.ActiveDirectoryPassword: @@ -655,6 +652,8 @@ internal void Connect(ServerInfo serverInfo, FQDNforDNSCache, hostNameInCertificate); + _authenticationProvider?.Initialize(serverInfo, _physicalStateObj, this); + if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); @@ -760,6 +759,8 @@ internal void Connect(ServerInfo serverInfo, serverInfo.ResolvedServerName, hostNameInCertificate); + _authenticationProvider?.Initialize(serverInfo, _physicalStateObj, this); + if (TdsEnums.SNI_SUCCESS != _physicalStateObj.Status) { _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); @@ -2547,7 +2548,7 @@ internal bool TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataRead (error.Class <= TdsEnums.MAX_USER_CORRECTABLE_ERROR_CLASS)) { // Fire SqlInfoMessage here - FireInfoMessageEvent(connection,cmdHandler, stateObj, error); + FireInfoMessageEvent(connection, cmdHandler, stateObj, error); } else { @@ -3181,6 +3182,9 @@ private bool TryProcessEnvChange(int tokenLength, TdsParserStateObject stateObj, // to MARS initialization! int packetSize = int.Parse(env._newValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + SqlClientEventSource.Log.TryTraceEvent("{0}.{1} | Info | Server sent env packet size change of {2}, ClientConnectionID {3}", + nameof(TdsParser), nameof(TryProcessEnvChange), packetSize, _connHandler._clientConnectionId); + if (_physicalStateObj.SetPacketSize(packetSize)) { // If packet size changed, we need to release our SNIPackets since @@ -8339,7 +8343,7 @@ private Task WriteEncodingChar(string s, Encoding encoding, TdsParserStateObject private byte[] SerializeEncodingChar(string s, int numChars, int offset, Encoding encoding) { -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK char[] charData; byte[] byteData = null; @@ -8376,7 +8380,7 @@ private Task WriteEncodingChar(string s, int numChars, int offset, Encoding enco } else { -#if NETFRAMEWORK || NETSTANDARD2_0 +#if NETFRAMEWORK var charData = s.ToCharArray(offset, numChars); var byteData = encoding.GetBytes(charData, 0, numChars); Debug.Assert(byteData != null, "no data from encoding"); @@ -8904,205 +8908,6 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return len; } - internal void TdsLogin(SqlLogin rec, - TdsEnums.FeatureExtension requestedFeatures, - SessionData recoverySessionData, - FederatedAuthenticationFeatureExtensionData fedAuthFeatureExtensionData, - SqlClientOriginalNetworkAddressInfo originalNetworkAddressInfo, - SqlConnectionEncryptOption encrypt) - { - _physicalStateObj.SetTimeoutSeconds(rec.timeout); - - Debug.Assert(recoverySessionData == null || (requestedFeatures & TdsEnums.FeatureExtension.SessionRecovery) != 0, "Recovery session data without session recovery feature request"); - Debug.Assert(TdsEnums.MAXLEN_HOSTNAME >= rec.hostName.Length, "_workstationId.Length exceeds the max length for this value"); - - Debug.Assert(!(rec.useSSPI && _connHandler._fedAuthRequired), "Cannot use SSPI when server has responded 0x01 for FedAuthRequired PreLogin Option."); - Debug.Assert(!rec.useSSPI || (requestedFeatures & TdsEnums.FeatureExtension.FedAuth) == 0, "Cannot use both SSPI and FedAuth"); - Debug.Assert(fedAuthFeatureExtensionData == null || (requestedFeatures & TdsEnums.FeatureExtension.FedAuth) != 0, "fedAuthFeatureExtensionData provided without fed auth feature request"); - Debug.Assert(fedAuthFeatureExtensionData != null || (requestedFeatures & TdsEnums.FeatureExtension.FedAuth) == 0, "Fed Auth feature requested without specifying fedAuthFeatureExtensionData."); - - Debug.Assert(rec.userName == null || (rec.userName != null && TdsEnums.MAXLEN_CLIENTID >= rec.userName.Length), "_userID.Length exceeds the max length for this value"); - Debug.Assert(rec.credential == null || (rec.credential != null && TdsEnums.MAXLEN_CLIENTID >= rec.credential.UserId.Length), "_credential.UserId.Length exceeds the max length for this value"); - - Debug.Assert(rec.password == null || (rec.password != null && TdsEnums.MAXLEN_CLIENTSECRET >= rec.password.Length), "_password.Length exceeds the max length for this value"); - Debug.Assert(rec.credential == null || (rec.credential != null && TdsEnums.MAXLEN_CLIENTSECRET >= rec.credential.Password.Length), "_credential.Password.Length exceeds the max length for this value"); - - Debug.Assert(rec.credential != null || rec.userName != null || rec.password != null, "cannot mix the new secure password system and the connection string based password"); - Debug.Assert(rec.newSecurePassword != null || rec.newPassword != null, "cannot have both new secure change password and string based change password"); - Debug.Assert(TdsEnums.MAXLEN_APPNAME >= rec.applicationName.Length, "_applicationName.Length exceeds the max length for this value"); - Debug.Assert(TdsEnums.MAXLEN_SERVERNAME >= rec.serverName.Length, "_dataSource.Length exceeds the max length for this value"); - Debug.Assert(TdsEnums.MAXLEN_LANGUAGE >= rec.language.Length, "_currentLanguage .Length exceeds the max length for this value"); - Debug.Assert(TdsEnums.MAXLEN_DATABASE >= rec.database.Length, "_initialCatalog.Length exceeds the max length for this value"); - Debug.Assert(TdsEnums.MAXLEN_ATTACHDBFILE >= rec.attachDBFilename.Length, "_attachDBFileName.Length exceeds the max length for this value"); - - Debug.Assert(_connHandler != null, "SqlConnectionInternalTds handler can not be null at this point."); - _connHandler.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.LoginBegin); - _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth); - - // Add CTAIP Provider - // - if (originalNetworkAddressInfo != null) - { - SNINativeMethodWrapper.CTAIPProviderInfo cauthInfo = new SNINativeMethodWrapper.CTAIPProviderInfo(); - cauthInfo.originalNetworkAddress = originalNetworkAddressInfo.Address.GetAddressBytes(); - cauthInfo.fromDataSecurityProxy = originalNetworkAddressInfo.IsFromDataSecurityProxy; - - UInt32 error = SNINativeMethodWrapper.SNIAddProvider(_physicalStateObj.Handle, SNINativeMethodWrapper.ProviderEnum.CTAIP_PROV, cauthInfo); - if (error != TdsEnums.SNI_SUCCESS) - { - _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); - ThrowExceptionAndWarning(_physicalStateObj); - } - - try - { } // EmptyTry/Finally to avoid FXCop violation - finally - { - _physicalStateObj.ClearAllWritePackets(); - } - } - - // get the password up front to use in sspi logic below - byte[] encryptedPassword = null; - byte[] encryptedChangePassword = null; - int encryptedPasswordLengthInBytes; - int encryptedChangePasswordLengthInBytes; - bool useFeatureExt = (requestedFeatures != TdsEnums.FeatureExtension.None); - - string userName; - - if (rec.credential != null) - { - userName = rec.credential.UserId; - encryptedPasswordLengthInBytes = rec.credential.Password.Length * 2; - } - else - { - userName = rec.userName; - encryptedPassword = TdsParserStaticMethods.ObfuscatePassword(rec.password); - encryptedPasswordLengthInBytes = encryptedPassword.Length; // password in clear text is already encrypted and its length is in byte - } - - if (rec.newSecurePassword != null) - { - encryptedChangePasswordLengthInBytes = rec.newSecurePassword.Length * 2; - } - else - { - encryptedChangePassword = TdsParserStaticMethods.ObfuscatePassword(rec.newPassword); - encryptedChangePasswordLengthInBytes = encryptedChangePassword.Length; - } - - - // set the message type - _physicalStateObj._outputMessageType = TdsEnums.MT_LOGIN7; - - // length in bytes - int length = TdsEnums.SQL2005_LOG_REC_FIXED_LEN; - - string clientInterfaceName = TdsEnums.SQL_PROVIDER_NAME; - Debug.Assert(TdsEnums.MAXLEN_CLIENTINTERFACE >= clientInterfaceName.Length, "cchCltIntName can specify at most 128 unicode characters. See Tds spec"); - - // add up variable-len portions (multiply by 2 for byte len of char strings) - // - checked - { - length += (rec.hostName.Length + rec.applicationName.Length + - rec.serverName.Length + clientInterfaceName.Length + - rec.language.Length + rec.database.Length + - rec.attachDBFilename.Length) * 2; - if (useFeatureExt) - { - length += 4; - } - } - - // allocate memory for SSPI variables - byte[] outSSPIBuff = null; - UInt32 outSSPILength = 0; - - // only add lengths of password and username if not using SSPI or requesting federated authentication info - if (!rec.useSSPI && !(_connHandler._federatedAuthenticationInfoRequested || _connHandler._federatedAuthenticationRequested)) - { - checked - { - length += (userName.Length * 2) + encryptedPasswordLengthInBytes - + encryptedChangePasswordLengthInBytes; - } - } - else - { - if (rec.useSSPI) - { - // now allocate proper length of buffer, and set length - outSSPIBuff = new byte[s_maxSSPILength]; - outSSPILength = s_maxSSPILength; - - // Call helper function for SSPI data and actual length. - // Since we don't have SSPI data from the server, send null for the - // byte[] buffer and 0 for the int length. - Debug.Assert(SniContext.Snix_Login == _physicalStateObj.SniContext, $"Unexpected SniContext. Expecting Snix_Login, actual value is '{_physicalStateObj.SniContext}'"); - _physicalStateObj.SniContext = SniContext.Snix_LoginSspi; - SSPIData(null, 0, outSSPIBuff, ref outSSPILength); - if (outSSPILength > int.MaxValue) - { - throw SQL.InvalidSSPIPacketSize(); // SqlBu 332503 - } - _physicalStateObj.SniContext = SniContext.Snix_Login; - - checked - { - length += (int)outSSPILength; - } - } - } - - int feOffset = length; - // calculate and reserve the required bytes for the featureEx - length = ApplyFeatureExData(requestedFeatures, recoverySessionData, fedAuthFeatureExtensionData, useFeatureExt, length); - - WriteLoginData(rec, - requestedFeatures, - recoverySessionData, - fedAuthFeatureExtensionData, - encrypt, - encryptedPassword, - encryptedChangePassword, - encryptedPasswordLengthInBytes, - encryptedChangePasswordLengthInBytes, - useFeatureExt, - userName, - length, - feOffset, - clientInterfaceName, - outSSPIBuff, - outSSPILength); - - _physicalStateObj.WritePacket(TdsEnums.HARDFLUSH); - _physicalStateObj.ResetSecurePasswordsInformation(); // Password information is needed only from Login process; done with writing login packet and should clear information - _physicalStateObj.HasPendingData = true; - _physicalStateObj._messageStatus = 0; - - // Remvove CTAIP Provider after login record is sent. - // - if (originalNetworkAddressInfo != null) - { - UInt32 error = SNINativeMethodWrapper.SNIRemoveProvider(_physicalStateObj.Handle, SNINativeMethodWrapper.ProviderEnum.CTAIP_PROV); - if (error != TdsEnums.SNI_SUCCESS) - { - _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); - ThrowExceptionAndWarning(_physicalStateObj); - } - - try - { } // EmptyTry/Finally to avoid FXCop violation - finally - { - _physicalStateObj.ClearAllWritePackets(); - } - } - }// tdsLogin - private void WriteLoginData(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures, SessionData recoverySessionData, @@ -9472,94 +9277,6 @@ internal void SendFedAuthToken(SqlFedAuthToken fedAuthToken) _connHandler._federatedAuthenticationRequested = true; } - private void SSPIData(byte[] receivedBuff, UInt32 receivedLength, byte[] sendBuff, ref UInt32 sendLength) - { - SNISSPIData(receivedBuff, receivedLength, sendBuff, ref sendLength); - } - - private void SNISSPIData(byte[] receivedBuff, UInt32 receivedLength, byte[] sendBuff, ref UInt32 sendLength) - { - if (receivedBuff == null) - { - // we do not have SSPI data coming from server, so send over 0's for pointer and length - receivedLength = 0; - } - // we need to respond to the server's message with SSPI data - if (0 != SNINativeMethodWrapper.SNISecGenClientContext(_physicalStateObj.Handle, receivedBuff, receivedLength, sendBuff, ref sendLength, _sniSpnBuffer)) - { - SSPIError(SQLMessage.SSPIGenerateError(), TdsEnums.GEN_CLIENT_CONTEXT); - } - } - - - private void ProcessSSPI(int receivedLength) - { - SniContext outerContext = _physicalStateObj.SniContext; - _physicalStateObj.SniContext = SniContext.Snix_ProcessSspi; - // allocate received buffer based on length from SSPI message - byte[] receivedBuff = new byte[receivedLength]; - - // read SSPI data received from server - Debug.Assert(_physicalStateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); - bool result = _physicalStateObj.TryReadByteArray(receivedBuff, receivedLength); - if (!result) - { throw SQL.SynchronousCallMayNotPend(); } - - // allocate send buffer and initialize length - byte[] sendBuff = new byte[s_maxSSPILength]; - UInt32 sendLength = s_maxSSPILength; - - // make call for SSPI data - SSPIData(receivedBuff, (UInt32)receivedLength, sendBuff, ref sendLength); - - // DO NOT SEND LENGTH - TDS DOC INCORRECT! JUST SEND SSPI DATA! - _physicalStateObj.WriteByteArray(sendBuff, (int)sendLength, 0); - - // set message type so server knows its a SSPI response - _physicalStateObj._outputMessageType = TdsEnums.MT_SSPI; - - // send to server - _physicalStateObj.WritePacket(TdsEnums.HARDFLUSH); - _physicalStateObj.SniContext = outerContext; - } - - private void SSPIError(string error, string procedure) - { - Debug.Assert(!ADP.IsEmpty(procedure), "TdsParser.SSPIError called with an empty or null procedure string"); - Debug.Assert(!ADP.IsEmpty(error), "TdsParser.SSPIError called with an empty or null error string"); - - _physicalStateObj.AddError(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, _server, error, procedure, 0)); - ThrowExceptionAndWarning(_physicalStateObj); - } - - private void LoadSSPILibrary() - { - // Outer check so we don't acquire lock once once it's loaded. - if (!s_fSSPILoaded) - { - lock (s_tdsParserLock) - { - // re-check inside lock - if (!s_fSSPILoaded) - { - // use local for ref param to defer setting s_maxSSPILength until we know the call succeeded. - UInt32 maxLength = 0; - if (0 != SNINativeMethodWrapper.SNISecInitPackage(ref maxLength)) - SSPIError(SQLMessage.SSPIInitializeError(), TdsEnums.INIT_SSPI_PACKAGE); - - s_maxSSPILength = maxLength; - s_fSSPILoaded = true; - - } - } - } - - if (s_maxSSPILength > Int32.MaxValue) - { - throw SQL.InvalidSSPIPacketSize(); // SqlBu 332503 - } - } - internal byte[] GetDTCAddress(int timeout, TdsParserStateObject stateObj) { // If this fails, the server will return a server error - Sameet Agarwal confirmed. @@ -10103,7 +9820,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, IList<_SqlRPC> rpcArray, int timeout int parametersLength = rpcext.userParamCount + rpcext.systemParamCount; bool isAdvancedTraceOn = SqlClientEventSource.Log.IsAdvancedTraceOn(); - bool enableOptimizedParameterBinding = cmd.EnableOptimizedParameterBinding; + bool enableOptimizedParameterBinding = cmd.EnableOptimizedParameterBinding && cmd.CommandType == CommandType.Text; for (int i = (ii == startRpc) ? startParam : 0; i < parametersLength; i++) { @@ -10123,7 +9840,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, IList<_SqlRPC> rpcArray, int timeout { // Throw an exception if ForceColumnEncryption is set on a parameter and the ColumnEncryption is not enabled on SqlConnection or SqlCommand if ( - !(cmd.ColumnEncryptionSetting == SqlCommandColumnEncryptionSetting.Enabled + !(cmd.ColumnEncryptionSetting == SqlCommandColumnEncryptionSetting.Enabled || (cmd.ColumnEncryptionSetting == SqlCommandColumnEncryptionSetting.UseConnectionSetting && cmd.Connection.IsColumnEncryptionSettingEnabled)) ) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.netfx.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.netfx.cs index 5d4a332665..9ce3c4ec11 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.netfx.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.netfx.cs @@ -100,6 +100,8 @@ internal TdsParserStateObject(TdsParser parser, SNIHandle physicalConnection, bo _lastSuccessfulIOTimer = parser._physicalStateObj._lastSuccessfulIOTimer; } + internal SSPIContextProvider CreateSSPIContextProvider() => new NativeSSPIContextProvider(); + //////////////// // Properties // //////////////// @@ -110,7 +112,7 @@ internal SNIHandle Handle return _sessionHandle; } } - + internal uint Status { get 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 abeadf86b7..6fbdfcb343 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 @@ -26,7 +26,7 @@ internal static partial class ADP [ResourceConsumption(ResourceScope.Machine)] internal static object LocalMachineRegistryValue(string subkey, string queryvalue) { // MDAC 77697 -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK (new RegistryPermission(RegistryPermissionAccess.Read, "HKEY_LOCAL_MACHINE\\" + subkey)).Assert(); // MDAC 62028 #endif try @@ -43,7 +43,7 @@ internal static object LocalMachineRegistryValue(string subkey, string queryvalu ADP.TraceExceptionWithoutRethrow(e); return null; } -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK finally { RegistryPermission.RevertAssert(); 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 1ded2eef3a..dcbb89a248 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/AdapterUtil.cs @@ -668,7 +668,7 @@ 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 +#if NETFRAMEWORK [EnvironmentPermission(SecurityAction.Assert, Read = "COMPUTERNAME")] #endif internal static string MachineName() => Environment.MachineName; diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs index 35aaf412a5..95a54538f9 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Common/DbConnectionStringCommon.cs @@ -1037,7 +1037,6 @@ internal static class DbConnectionStringKeywords internal const string OmitOracleConnectionName = "Omit Oracle Connection Name"; // SqlClient - internal const string TransparentNetworkIPResolution = "Transparent Network IP Resolution"; internal const string Certificate = "Certificate"; #endif // SqlClient @@ -1073,6 +1072,7 @@ internal static class DbConnectionStringKeywords internal const string IPAddressPreference = "IP Address Preference"; internal const string ServerSPN = "Server SPN"; internal const string FailoverPartnerSPN = "Failover Partner SPN"; + internal const string TransparentNetworkIPResolution = "Transparent Network IP Resolution"; // common keywords (OleDb, OracleClient, SqlClient) internal const string DataSource = "Data Source"; @@ -1092,10 +1092,9 @@ internal static class DbConnectionStringKeywords internal static class DbConnectionStringSynonyms { -#if NETFRAMEWORK //internal const string TransparentNetworkIPResolution = TRANSPARENTNETWORKIPRESOLUTION; internal const string TRANSPARENTNETWORKIPRESOLUTION = "transparentnetworkipresolution"; -#endif + //internal const string ApplicationName = APP; internal const string APP = "app"; 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 213f4b8b25..29ac7fee31 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,7 @@ internal bool LockToUpdate() /// /// Release the lock which was obtained through LockToUpdate. /// -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] #endif internal void ReleaseLockToUpdate() diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs similarity index 69% rename from src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs rename to src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs index 1e69bcaba9..35356bfa12 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs @@ -2,74 +2,90 @@ // 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.Diagnostics; +using System.Threading; + namespace Microsoft.Data.ProviderBase { - - using System; - using System.Diagnostics; - using System.Threading; - internal abstract class DbReferenceCollection { + #region Constants + // Time to wait (in ms) between attempting to get the _itemLock + private const int LockPollTime = 100; + + // Default size for the collection, and the amount to grow every time the collection is full + private const int DefaultCollectionSize = 20; + #endregion + + #region Fields + // The collection of items we are keeping track of + private CollectionEntry[] _items; + + // Used to synchronize access to the _items collection + private readonly object _itemLock; + + // (#ItemsAdded - #ItemsRemoved) - This estimates the number of items that we should have + // (but doesn't take into account item targets being GC'd) + private int _estimatedCount; + + // Location of the last item in _items + private int _lastItemIndex; + + // Indicates that the collection is currently being notified (and, therefore, about to be cleared) + private volatile bool _isNotifying; + #endregion private struct CollectionEntry { - private int _tag; // information about the reference - private WeakReference _weak; // the reference itself. + private int _refInfo; // information about the reference + private WeakReference _weakReference; // the reference itself. - public void NewTarget(int tag, object target) + public void SetNewTarget(int refInfo, object target) { Debug.Assert(!TryGetTarget(out object _), "Entry already has a valid target"); - Debug.Assert(tag != 0, "Bad tag"); + Debug.Assert(refInfo != 0, "Bad reference info"); Debug.Assert(target != null, "Invalid target"); - if (_weak == null) + if (_weakReference == null) { - _weak = new WeakReference(target, false); + _weakReference = new WeakReference(target, false); } else { - _weak.SetTarget(target); + _weakReference.SetTarget(target); } - _tag = tag; + _refInfo = refInfo; } public void RemoveTarget() { - _tag = 0; - _weak.SetTarget(null); + _refInfo = 0; + _weakReference.SetTarget(null); } - public int Tag => _tag; + public readonly int RefInfo => _refInfo; - public bool TryGetTarget(out object target) + public readonly bool TryGetTarget(out object target) { target = null; - return _tag != 0 && _weak.TryGetTarget(out target); + return _refInfo != 0 && _weakReference.TryGetTarget(out target); } } - private const int LockPollTime = 100; // Time to wait (in ms) between attempting to get the _itemLock - private const int DefaultCollectionSize = 20; // Default size for the collection, and the amount to grow every time the collection is full - private CollectionEntry[] _items; // The collection of items we are keeping track of - private readonly object _itemLock; // Used to synchronize access to the _items collection - private int _optimisticCount; // (#ItemsAdded - #ItemsRemoved) - This estimates the number of items that we *should* have (but doesn't take into account item targets being GC'd) - private int _lastItemIndex; // Location of the last item in _items - private volatile bool _isNotifying; // Indicates that the collection is currently being notified (and, therefore, about to be cleared) - protected DbReferenceCollection() { _items = new CollectionEntry[DefaultCollectionSize]; _itemLock = new object(); - _optimisticCount = 0; + _estimatedCount = 0; _lastItemIndex = 0; } - abstract public void Add(object value, int tag); + abstract public void Add(object value, int refInfo); - protected void AddItem(object value, int tag) + protected void AddItem(object value, int refInfo) { - Debug.Assert(null != value && 0 != tag, "AddItem with null value or 0 tag"); + Debug.Assert(value != null && 0 != refInfo, "AddItem with null value or 0 reference info"); bool itemAdded = false; lock (_itemLock) @@ -77,9 +93,9 @@ protected void AddItem(object value, int tag) // Try to find a free spot for (int i = 0; i <= _lastItemIndex; ++i) { - if (_items[i].Tag == 0) + if (_items[i].RefInfo == 0) { - _items[i].NewTarget(tag, value); + _items[i].SetNewTarget(refInfo, value); Debug.Assert(_items[i].TryGetTarget(out object _), "missing expected target"); itemAdded = true; break; @@ -90,7 +106,7 @@ protected void AddItem(object value, int tag) if ((!itemAdded) && (_lastItemIndex + 1 < _items.Length)) { _lastItemIndex++; - _items[_lastItemIndex].NewTarget(tag, value); + _items[_lastItemIndex].SetNewTarget(refInfo, value); itemAdded = true; } @@ -101,7 +117,7 @@ protected void AddItem(object value, int tag) { if (!_items[i].TryGetTarget(out object _)) { - _items[i].NewTarget(tag, value); + _items[i].SetNewTarget(refInfo, value); Debug.Assert(_items[i].TryGetTarget(out object _), "missing expected target"); itemAdded = true; break; @@ -114,14 +130,14 @@ protected void AddItem(object value, int tag) { Array.Resize(ref _items, _items.Length * 2); _lastItemIndex++; - _items[_lastItemIndex].NewTarget(tag, value); + _items[_lastItemIndex].SetNewTarget(refInfo, value); } - _optimisticCount++; + _estimatedCount++; } } - internal T FindItem(int tag, Func filterMethod) where T : class + internal T FindItem(int refInfo, Func filterMethod) where T : class { bool lockObtained = false; try @@ -129,13 +145,12 @@ internal T FindItem(int tag, Func filterMethod) where T : class TryEnterItemLock(ref lockObtained); if (lockObtained) { - if (_optimisticCount > 0) + if (_estimatedCount > 0) { - // Loop through the items for (int counter = 0; counter <= _lastItemIndex; counter++) { - // Check tag (should be easiest and quickest) - if (_items[counter].Tag == tag) + // Check reference info (should be easiest and quickest) + if (_items[counter].RefInfo == refInfo) { if (_items[counter].TryGetTarget(out object value)) { @@ -172,18 +187,18 @@ public void Notify(int message) _isNotifying = true; // Loop through each live item and notify it - if (_optimisticCount > 0) + if (_estimatedCount > 0) { for (int index = 0; index <= _lastItemIndex; ++index) { if (_items[index].TryGetTarget(out object value)) { - NotifyItem(message, _items[index].Tag, value); + NotifyItem(message, _items[index].RefInfo, value); _items[index].RemoveTarget(); } Debug.Assert(!_items[index].TryGetTarget(out object _), "Unexpected target after notifying"); } - _optimisticCount = 0; + _estimatedCount = 0; } // Shrink collection (if needed) @@ -205,7 +220,7 @@ public void Notify(int message) } } - abstract protected void NotifyItem(int message, int tag, object value); + abstract protected void NotifyItem(int message, int refInfo, object value); abstract public void Remove(object value); @@ -221,14 +236,14 @@ protected void RemoveItem(object value) if (lockObtained) { // Find the value, and then remove the target from our collection - if (_optimisticCount > 0) + if (_estimatedCount > 0) { for (int index = 0; index <= _lastItemIndex; ++index) { if (_items[index].TryGetTarget(out object target) && value == target) { _items[index].RemoveTarget(); - _optimisticCount--; + _estimatedCount--; break; } } @@ -262,4 +277,3 @@ private void ExitItemLockIfNeeded(bool lockObtained) } } } - diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs index 83ce5085e7..25caa8911b 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.Windows.cs @@ -7,7 +7,7 @@ namespace Microsoft.Data.Sql { - /// + /// public sealed partial class SqlDataSourceEnumerator : DbDataSourceEnumerator { private partial DataTable GetDataSourcesInternal() diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs index e8f7aac29c..496c887294 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/Sql/SqlDataSourceEnumerator.cs @@ -7,17 +7,17 @@ namespace Microsoft.Data.Sql { - /// + /// public sealed partial class SqlDataSourceEnumerator : DbDataSourceEnumerator { private static readonly Lazy s_singletonInstance = new(() => new SqlDataSourceEnumerator()); private SqlDataSourceEnumerator() : base(){} - /// + /// public static SqlDataSourceEnumerator Instance => s_singletonInstance.Value; - /// + /// override public DataTable GetDataSources() => GetDataSourcesInternal(); private partial DataTable GetDataSourcesInternal(); 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 9118e341af..a236d5645e 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,7 @@ internal static class SqlDataSourceEnumeratorNativeHelper /// internal static DataTable GetDataSources() { -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK (new NamedPermissionSet("FullTrust")).Demand(); // SQLBUDT 244304 #endif char[] buffer = null; @@ -37,13 +37,13 @@ internal static DataTable GetDataSources() bool more = true; bool failure = false; IntPtr handle = ADP.s_ptrZero; -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try { long s_timeoutTime = TdsParserStaticMethods.GetTimeoutSeconds(ADP.DefaultCommandTimeout); -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try 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 01f265cf50..d40f59c78b 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/ActiveDirectoryAuthenticationProvider.cs @@ -100,13 +100,6 @@ public override void BeforeUnload(SqlAuthenticationMethod authentication) _logger.LogInfo(_type, "BeforeUnload", $"being unloaded from SqlAuthProviders for {authentication}."); } -#if NETSTANDARD - private Func _parentActivityOrWindowFunc = null; - - /// - public void SetParentActivityOrWindowFunc(Func parentActivityOrWindowFunc) => this._parentActivityOrWindowFunc = parentActivityOrWindowFunc; -#endif - #if NETFRAMEWORK private Func _iWin32WindowFunc = null; @@ -214,7 +207,7 @@ public override async Task AcquireTokenAsync(SqlAuthenti */ string redirectUri = s_nativeClientRedirectUri; -#if NETCOREAPP +#if NET6_0_OR_GREATER if (parameters.AuthenticationMethod != SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow) { redirectUri = "http://localhost"; @@ -223,9 +216,6 @@ public override async Task AcquireTokenAsync(SqlAuthenti PublicClientAppKey pcaKey = new PublicClientAppKey(parameters.Authority, redirectUri, _applicationClientId #if NETFRAMEWORK , _iWin32WindowFunc -#endif -#if NETSTANDARD - , _parentActivityOrWindowFunc #endif ); @@ -371,7 +361,7 @@ private static async Task AcquireTokenInteractiveDeviceFlo if (authenticationMethod == SqlAuthenticationMethod.ActiveDirectoryInteractive) { CancellationTokenSource ctsInteractive = new CancellationTokenSource(); -#if NETCOREAPP +#if NET6_0_OR_GREATER /* * On .NET Core, MSAL will start the system browser as a separate process. MSAL does not have control over this browser, * but once the user finishes authentication, the web page is redirected in such a way that MSAL can intercept the Uri. @@ -491,18 +481,6 @@ private IPublicClientApplication CreateClientAppInstance(PublicClientAppKey publ { IPublicClientApplication publicClientApplication; -#if NETSTANDARD - if (_parentActivityOrWindowFunc != null) - { - publicClientApplication = PublicClientApplicationBuilder.Create(publicClientAppKey._applicationClientId) - .WithAuthority(publicClientAppKey._authority) - .WithClientName(Common.DbConnectionStringDefaults.ApplicationName) - .WithClientVersion(Common.ADP.GetAssemblyVersion().ToString()) - .WithRedirectUri(publicClientAppKey._redirectUri) - .WithParentActivityOrWindow(_parentActivityOrWindowFunc) - .Build(); - } -#endif #if NETFRAMEWORK if (_iWin32WindowFunc != null) { @@ -514,8 +492,6 @@ private IPublicClientApplication CreateClientAppInstance(PublicClientAppKey publ .WithParentActivityOrWindow(_iWin32WindowFunc) .Build(); } -#endif -#if !NETCOREAPP else #endif { @@ -538,16 +514,10 @@ internal class PublicClientAppKey #if NETFRAMEWORK public readonly Func _iWin32WindowFunc; #endif -#if NETSTANDARD - public readonly Func _parentActivityOrWindowFunc; -#endif public PublicClientAppKey(string authority, string redirectUri, string applicationClientId #if NETFRAMEWORK , Func iWin32WindowFunc -#endif -#if NETSTANDARD - , Func parentActivityOrWindowFunc #endif ) { @@ -556,9 +526,6 @@ public PublicClientAppKey(string authority, string redirectUri, string applicati _applicationClientId = applicationClientId; #if NETFRAMEWORK _iWin32WindowFunc = iWin32WindowFunc; -#endif -#if NETSTANDARD - _parentActivityOrWindowFunc = parentActivityOrWindowFunc; #endif } @@ -571,9 +538,6 @@ public override bool Equals(object obj) && string.CompareOrdinal(_applicationClientId, pcaKey._applicationClientId) == 0 #if NETFRAMEWORK && pcaKey._iWin32WindowFunc == _iWin32WindowFunc -#endif -#if NETSTANDARD - && pcaKey._parentActivityOrWindowFunc == _parentActivityOrWindowFunc #endif ); } @@ -583,9 +547,6 @@ public override bool Equals(object obj) public override int GetHashCode() => Tuple.Create(_authority, _redirectUri, _applicationClientId #if NETFRAMEWORK , _iWin32WindowFunc -#endif -#if NETSTANDARD - , _parentActivityOrWindowFunc #endif ).GetHashCode(); } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.NotSupported.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.NotSupported.cs deleted file mode 100644 index 461bfdf6d7..0000000000 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveDelegate.NotSupported.cs +++ /dev/null @@ -1,56 +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.Concurrent; -using System.Collections.Generic; - -namespace Microsoft.Data.SqlClient -{ - internal sealed partial class EnclaveDelegate - { - internal byte[] GetSerializedAttestationParameters( - SqlEnclaveAttestationParameters sqlEnclaveAttestationParameters, string enclaveType) - { - throw new PlatformNotSupportedException(); - } - - /// - /// Create a new enclave session - /// - /// attestation protocol - /// enclave type - /// The set of parameters required for enclave session. - /// attestation info from SQL Server - /// attestation parameters - /// A set of extra data needed for attesting the enclave. - /// The length of the extra data needed for attesting the enclave. - /// Indicates if this is a retry from a failed call. - internal void CreateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, EnclaveSessionParameters enclaveSessionParameters, - byte[] attestationInfo, SqlEnclaveAttestationParameters attestationParameters, byte[] customData, int customDataLength, bool isRetry) - { - throw new PlatformNotSupportedException(); - } - - internal void GetEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, EnclaveSessionParameters enclaveSessionParameters, bool generateCustomData, bool isRetry, out SqlEnclaveSession sqlEnclaveSession, out byte[] customData, out int customDataLength) - { - throw new PlatformNotSupportedException(); - } - - internal EnclavePackage GenerateEnclavePackage(SqlConnectionAttestationProtocol attestationProtocol, ConcurrentDictionary keysTobeSentToEnclave, string queryText, string enclaveType, EnclaveSessionParameters enclaveSessionParameters, SqlConnection connection, SqlCommand command) - { - throw new PlatformNotSupportedException(); - } - - internal void InvalidateEnclaveSession(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, EnclaveSessionParameters enclaveSessionParameters, SqlEnclaveSession enclaveSession) - { - throw new PlatformNotSupportedException(); - } - - internal SqlEnclaveAttestationParameters GetAttestationParameters(SqlConnectionAttestationProtocol attestationProtocol, string enclaveType, string attestationUrl, byte[] customData, int customDataLength) - { - throw new PlatformNotSupportedException(); - } - } -} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs index f76191fec8..2cc34eeeb5 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/EnclaveSessionCache.cs @@ -12,7 +12,7 @@ namespace Microsoft.Data.SqlClient internal class EnclaveSessionCache { private readonly MemoryCache enclaveMemoryCache = new MemoryCache("EnclaveMemoryCache"); - private readonly Object enclaveCacheLock = new Object(); + private readonly object enclaveCacheLock = new object(); // Nonce for each message sent by the client to the server to prevent replay attacks by the server, // given that for Always Encrypted scenarios, the server is considered an "untrusted" man-in-the-middle. @@ -37,8 +37,7 @@ internal void InvalidateSession(EnclaveSessionParameters enclaveSessionParameter lock (enclaveCacheLock) { - long counter; - SqlEnclaveSession enclaveSession = GetEnclaveSession(enclaveSessionParameters, out counter); + SqlEnclaveSession enclaveSession = GetEnclaveSession(enclaveSessionParameters, out _); if (enclaveSession != null && enclaveSession.SessionId == enclaveSessionToInvalidate.SessionId) { 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 ed2c4aedf7..5d35159d60 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/LocalAppContextSwitches.cs @@ -26,7 +26,7 @@ private enum Tristate : byte private static Tristate s_makeReadAsyncBlocking; private static Tristate s_useMinimumLoginTimeout; -#if !NETFRAMEWORK +#if NET6_0_OR_GREATER static LocalAppContextSwitches() { IAppContextSwitchOverridesSection appContextSwitch = AppConfigManager.FetchConfigurationSection(AppContextSwitchOverridesSection.Name); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Reliability/SqlConfigurableRetryLogicLoader.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Reliability/SqlConfigurableRetryLogicLoader.cs index a4d197d5e2..ab69ed288f 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Reliability/SqlConfigurableRetryLogicLoader.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Reliability/SqlConfigurableRetryLogicLoader.cs @@ -43,7 +43,7 @@ public SqlConfigurableRetryLogicLoader(ISqlConfigurableRetryConnectionSection co string cnnSectionName = SqlConfigurableRetryConnectionSection.Name, string cmdSectionName = SqlConfigurableRetryCommandSection.Name) { -#if !NETFRAMEWORK +#if NET6_0_OR_GREATER // Just only one subscription to this event is required. // This class isn't supposed to be called more than one time; // SqlConfigurableRetryLogicManager manages a single instance of this class. diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/ManagedSSPIContextProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/ManagedSSPIContextProvider.cs new file mode 100644 index 0000000000..546ee11366 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/ManagedSSPIContextProvider.cs @@ -0,0 +1,24 @@ +#if NET6_0 + +using System; +using Microsoft.Data.SqlClient.SNI; + +#nullable enable + +namespace Microsoft.Data.SqlClient +{ + internal sealed class ManagedSSPIContextProvider : SSPIContextProvider + { + private SspiClientContextStatus? _sspiClientContextStatus; + + internal override void GenerateSspiClientContext(ReadOnlyMemory received, ref byte[] sendBuff, ref uint sendLength, byte[][] _sniSpnBuffer) + { + _sspiClientContextStatus ??= new SspiClientContextStatus(); + + SNIProxy.GenSspiClientContext(_sspiClientContextStatus, received, ref sendBuff, _sniSpnBuffer); + SqlClientEventSource.Log.TryTraceEvent("TdsParserStateObjectManaged.GenerateSspiClientContext | Info | Session Id {0}", _physicalStateObj.SessionId); + sendLength = (uint)(sendBuff != null ? sendBuff.Length : 0); + } + } +} +#endif diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/NativeSSPIContextProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/NativeSSPIContextProvider.cs new file mode 100644 index 0000000000..067682a617 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/NativeSSPIContextProvider.cs @@ -0,0 +1,68 @@ +using System; +using System.Diagnostics; + +#nullable enable + +namespace Microsoft.Data.SqlClient +{ + internal sealed class NativeSSPIContextProvider : SSPIContextProvider + { + private static readonly object s_tdsParserLock = new(); + + // bool to indicate whether library has been loaded + private static bool s_fSSPILoaded; + + // variable to hold max SSPI data size, keep for token from server + private volatile static uint s_maxSSPILength; + + internal override uint MaxSSPILength => s_maxSSPILength; + + private protected override void Initialize() + { + LoadSSPILibrary(); + } + + private void LoadSSPILibrary() + { + // Outer check so we don't acquire lock once it's loaded. + if (!s_fSSPILoaded) + { + lock (s_tdsParserLock) + { + // re-check inside lock + if (!s_fSSPILoaded) + { + // use local for ref param to defer setting s_maxSSPILength until we know the call succeeded. + uint maxLength = 0; + + if (0 != SNINativeMethodWrapper.SNISecInitPackage(ref maxLength)) + SSPIError(SQLMessage.SSPIInitializeError(), TdsEnums.INIT_SSPI_PACKAGE); + + s_maxSSPILength = maxLength; + s_fSSPILoaded = true; + } + } + } + + if (s_maxSSPILength > int.MaxValue) + { + throw SQL.InvalidSSPIPacketSize(); // SqlBu 332503 + } + } + + internal override void GenerateSspiClientContext(ReadOnlyMemory receivedBuff, ref byte[] sendBuff, ref uint sendLength, byte[][] _sniSpnBuffer) + { +#if NETFRAMEWORK + SNIHandle handle = _physicalStateObj.Handle; +#else + Debug.Assert(_physicalStateObj.SessionHandle.Type == SessionHandle.NativeHandleType); + SNIHandle handle = _physicalStateObj.SessionHandle.NativeHandle; +#endif + if (0 != SNINativeMethodWrapper.SNISecGenClientContext(handle, receivedBuff.Span, sendBuff, ref sendLength, _sniSpnBuffer[0])) + { + throw new InvalidOperationException(SQLMessage.SSPIGenerateError()); + } + } + } +} + diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/NegotiateSSPIContextProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/NegotiateSSPIContextProvider.cs new file mode 100644 index 0000000000..2c68839e3f --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/NegotiateSSPIContextProvider.cs @@ -0,0 +1,28 @@ +#if NET8_0_OR_GREATER + +using System; +using System.Text; +using System.Net.Security; + +#nullable enable + +namespace Microsoft.Data.SqlClient +{ + internal sealed class NegotiateSSPIContextProvider : SSPIContextProvider + { + private NegotiateAuthentication? _negotiateAuth = null; + + internal override void GenerateSspiClientContext(ReadOnlyMemory received, ref byte[] sendBuff, ref uint sendLength, byte[][] _sniSpnBuffer) + { + _negotiateAuth ??= new(new NegotiateAuthenticationClientOptions { Package = "Negotiate", TargetName = Encoding.Unicode.GetString(_sniSpnBuffer[0]) }); + sendBuff = _negotiateAuth.GetOutgoingBlob(received.Span, out NegotiateAuthenticationStatusCode statusCode)!; + SqlClientEventSource.Log.TryTraceEvent("TdsParserStateObjectManaged.GenerateSspiClientContext | Info | Session Id {0}, StatusCode={1}", _physicalStateObj.SessionId, statusCode); + if (statusCode is not NegotiateAuthenticationStatusCode.Completed and not NegotiateAuthenticationStatusCode.ContinueNeeded) + { + throw new InvalidOperationException(SQLMessage.SSPIGenerateError() + Environment.NewLine + statusCode); + } + sendLength = (uint)(sendBuff != null ? sendBuff.Length : 0); + } + } +} +#endif diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/SSPIContextProvider.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/SSPIContextProvider.cs new file mode 100644 index 0000000000..256818660e --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SSPI/SSPIContextProvider.cs @@ -0,0 +1,56 @@ +using System; +using System.Diagnostics; +using Microsoft.Data.Common; + +#nullable enable + +namespace Microsoft.Data.SqlClient +{ + internal abstract class SSPIContextProvider + { + private TdsParser _parser = null!; + private ServerInfo _serverInfo = null!; + private protected TdsParserStateObject _physicalStateObj = null!; + + internal virtual uint MaxSSPILength => 4096; // TODO: what is a good default here? + + internal void Initialize(ServerInfo serverInfo, TdsParserStateObject physicalStateObj, TdsParser parser) + { + _parser = parser; + _physicalStateObj = physicalStateObj; + _serverInfo = serverInfo; + + Initialize(); + } + + private protected virtual void Initialize() + { + } + + internal abstract void GenerateSspiClientContext(ReadOnlyMemory input, ref byte[] sendBuff, ref uint sendLength, byte[][] _sniSpnBuffer); + + internal void SSPIData(ReadOnlyMemory receivedBuff, ref byte[] sendBuff, ref UInt32 sendLength, byte[] sniSpnBuffer) + => SSPIData(receivedBuff, ref sendBuff, ref sendLength, new[] { sniSpnBuffer }); + + internal void SSPIData(ReadOnlyMemory receivedBuff, ref byte[] sendBuff, ref UInt32 sendLength, byte[][] sniSpnBuffer) + { + try + { + GenerateSspiClientContext(receivedBuff, ref sendBuff, ref sendLength, sniSpnBuffer); + } + catch (Exception e) + { + SSPIError(e.Message + Environment.NewLine + e.StackTrace, TdsEnums.GEN_CLIENT_CONTEXT); + } + } + + protected void SSPIError(string error, string procedure) + { + Debug.Assert(!ADP.IsEmpty(procedure), "TdsParser.SSPIError called with an empty or null procedure string"); + Debug.Assert(!ADP.IsEmpty(error), "TdsParser.SSPIError called with an empty or null error string"); + + _physicalStateObj.AddError(new SqlError(0, (byte)0x00, (byte)TdsEnums.MIN_ERROR_CLASS, _serverInfo.ResolvedServerName, error, procedure, 0)); + _parser.ThrowExceptionAndWarning(_physicalStateObj); + } + } +} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ExtendedClrTypeCode.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ExtendedClrTypeCode.cs index 28818a16f1..953a5d5e55 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ExtendedClrTypeCode.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ExtendedClrTypeCode.cs @@ -49,6 +49,10 @@ internal enum ExtendedClrTypeCode IEnumerableOfSqlDataRecord, // System.Collections.Generic.IEnumerable TimeSpan, // System.TimeSpan DateTimeOffset, // System.DateTimeOffset +#if NET6_0_OR_GREATER + DateOnly, // System.DateOnly + TimeOnly, // System.TimeOnly +#endif Stream, // System.IO.Stream TextReader, // System.IO.TextReader XmlReader, // System.Xml.XmlReader diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/MetadataUtilsSmi.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/MetadataUtilsSmi.cs index 590429222a..d3c01546ce 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/MetadataUtilsSmi.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/MetadataUtilsSmi.cs @@ -75,6 +75,10 @@ internal class MetaDataUtilsSmi SqlDbType.Structured, // System.Collections.Generic.IEnumerable SqlDbType.Time, // System.TimeSpan SqlDbType.DateTimeOffset, // System.DateTimeOffset +#if NET6_0_OR_GREATER + SqlDbType.Date, // System.DateOnly + SqlDbType.Time, // System.TimeOnly +#endif }; @@ -86,7 +90,11 @@ internal class MetaDataUtilsSmi private static Dictionary CreateTypeToExtendedTypeCodeMap() { +#if NET6_0_OR_GREATER + int Count = 44; +#else int Count = 42; +#endif // Keep this initialization list in the same order as ExtendedClrTypeCode for ease in validating! var dictionary = new Dictionary(Count) { @@ -132,6 +140,10 @@ private static Dictionary CreateTypeToExtendedTypeCod { typeof(IEnumerable), ExtendedClrTypeCode.IEnumerableOfSqlDataRecord }, { typeof(TimeSpan), ExtendedClrTypeCode.TimeSpan }, { typeof(DateTimeOffset), ExtendedClrTypeCode.DateTimeOffset }, +#if NET6_0_OR_GREATER + { typeof(DateOnly), ExtendedClrTypeCode.DateOnly }, + { typeof(TimeOnly), ExtendedClrTypeCode.TimeOnly }, +#endif }; return dictionary; } @@ -244,6 +256,16 @@ Type udtType extendedCode = ExtendedClrTypeCode.Char; break; case SqlDbType.Date: +#if NET6_0_OR_GREATER + if (value.GetType() == typeof(DateOnly)) + extendedCode = ExtendedClrTypeCode.DateOnly; + else if (value.GetType() == typeof(DateTime)) + extendedCode = ExtendedClrTypeCode.DateTime; + else if (value.GetType() == typeof(SqlDateTime)) + extendedCode = ExtendedClrTypeCode.SqlDateTime; + + break; +#endif case SqlDbType.DateTime2: #if NETFRAMEWORK if (smiVersion >= SmiContextFactory.Sql2008Version) @@ -330,6 +352,14 @@ Type udtType extendedCode = ExtendedClrTypeCode.Invalid; } break; +#if NET6_0_OR_GREATER + case SqlDbType.Time: + if (value.GetType() == typeof(TimeOnly)) + extendedCode = ExtendedClrTypeCode.TimeOnly; + else if (value.GetType() == typeof(TimeSpan)) + extendedCode = ExtendedClrTypeCode.TimeSpan; + break; +#else case SqlDbType.Time: if (value.GetType() == typeof(TimeSpan) #if NETFRAMEWORK @@ -338,6 +368,7 @@ Type udtType ) extendedCode = ExtendedClrTypeCode.TimeSpan; break; +#endif case SqlDbType.DateTimeOffset: if (value.GetType() == typeof(DateTimeOffset) #if NETFRAMEWORK @@ -500,11 +531,7 @@ internal static SmiExtendedMetaData SqlMetaDataToSmiExtendedMetaData(SqlMetaData source.Scale, source.LocaleId, source.CompareOptions, -#if NETFRAMEWORK source.Type, -#else - null, -#endif source.Name, typeSpecificNamePart1, typeSpecificNamePart2, diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs index 61bcec417f..7dd4abd7c1 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/Server/ValueUtilsSmi.cs @@ -15,7 +15,7 @@ using Microsoft.Data.Common; using Microsoft.Data.SqlTypes; -#if !NETFRAMEWORK +#if NET6_0_OR_GREATER using SmiContext = System.Object; #endif @@ -1542,6 +1542,14 @@ value is DataFeed SetCompatibleValue(sink, setters, ordinal, metaData, charsValue, ExtendedClrTypeCode.CharArray, 0); break; } +#if NET6_0_OR_GREATER + case ExtendedClrTypeCode.DateOnly: + SetDateTime_Checked(sink, setters, ordinal, metaData, ((DateOnly)value).ToDateTime(new TimeOnly(0, 0))); + break; + case ExtendedClrTypeCode.TimeOnly: + SetTimeSpan_Checked(sink, (SmiTypedGetterSetter)setters, ordinal, metaData, ((TimeOnly)value).ToTimeSpan()); + break; +#endif case ExtendedClrTypeCode.DateTime: SetDateTime_Checked(sink, setters, ordinal, metaData, (DateTime)value); break; @@ -2899,6 +2907,10 @@ int length /*EnSDR*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X, _ , _ , _ , _ , },/*IEnurerable*/ /*TmSpn*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeSpan*/ /*DTOst*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , X , },/*DateTimeOffset*/ +#if NET6_0_OR_GREATER +/*DOnly*/{ _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, X , _ , X , _ , },/*DateOnly*/ +/*TOnly*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeOnly*/ +#endif /*Strm */{ _ , X , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , X , _, _ , _ , _ , _ , },/*Stream*/ /*TxRdr*/{ _ , _ , _ , X , _ , _ , _ , _ , _ , _ , X , X , X , _ , _ , _ , _ , _ , X , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*TextReader*/ /*XmlRd*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*XmlReader*/ @@ -2951,6 +2963,10 @@ int length /*EnSDR*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X, _ , _ , _ , _ , },/*IEnurerable*/ /*TmSpn*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeSpan*/ /*DTOst*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , X , },/*DateTimeOffset*/ +#if NET6_0_OR_GREATER +/*DOnly*/{ _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _ , X , _ , _ , _ , _ , _ , _ , _, X , _ , X , _ , },/*DateOnly*/ +/*TOnly*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , X , _ , _ , },/*TimeOnly*/ +#endif /*Strm */{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*Stream*/ /*TxRdr*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*TextReader*/ /*XmlRd*/{ _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _ , _, _ , _ , _ , _ , },/*XmlReader*/ @@ -3158,7 +3174,7 @@ private static SqlMoney GetSqlMoney_Unchecked(SmiEventSink_Default sink, ITypedG long temp = getters.GetInt64(sink, ordinal); sink.ProcessMessagesAndThrow(); -#if NETCOREAPP && NET7_0_OR_GREATER +#if NET8_0_OR_GREATER return SqlMoney.FromTdsValue(temp); #else return SqlTypeWorkarounds.SqlMoneyCtor(temp, 1 /* ignored */ ); @@ -3642,7 +3658,7 @@ private static void SetSqlMoney_Unchecked(SmiEventSink_Default sink, ITypedSette sink.ProcessMessagesAndThrow(); } -#if NET7_0_OR_GREATER +#if NET8_0_OR_GREATER setters.SetInt64(sink, ordinal, value.GetTdsValue()); #else setters.SetInt64(sink, ordinal, SqlTypeWorkarounds.SqlMoneyToSqlInternalRepresentation(value)); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBatchCommand.Net8OrGreater.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBatchCommand.Net8OrGreater.cs index d31480afc7..d81a378ecf 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBatchCommand.Net8OrGreater.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBatchCommand.Net8OrGreater.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. +#if NET8_0_OR_GREATER + using System.Data.Common; namespace Microsoft.Data.SqlClient @@ -15,3 +17,5 @@ public partial class SqlBatchCommand public override bool CanCreateParameter => true; } } + +#endif 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 9cfc077da4..f28bf6033b 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBuffer.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBuffer.cs @@ -811,7 +811,7 @@ internal SqlGuid SqlGuid { if (StorageType.Guid == _type) { - return new SqlGuid(_value._guid); + return IsNull ? SqlGuid.Null : new SqlGuid(_value._guid); } else if (StorageType.SqlGuid == _type) { @@ -886,7 +886,7 @@ internal SqlMoney SqlMoney { return SqlMoney.Null; } -#if NETCOREAPP && NET7_0_OR_GREATER +#if NET8_0_OR_GREATER return SqlMoney.FromTdsValue(_value._int64); #else return SqlTypeWorkarounds.SqlMoneyCtor(_value._int64, 1/*ignored*/); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientFactory.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientFactory.cs new file mode 100644 index 0000000000..eacf4d6e55 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlClientFactory.cs @@ -0,0 +1,108 @@ +// 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 Microsoft.Data.Sql; +using System; +using System.Data.Common; +using System.Security.Permissions; +using System.Security; +using Microsoft.Data.Common; + +namespace Microsoft.Data.SqlClient +{ + /// + public sealed class SqlClientFactory : DbProviderFactory +#if NETFRAMEWORK + , IServiceProvider +#endif + { + + /// + public static readonly SqlClientFactory Instance = new SqlClientFactory(); + + private SqlClientFactory() + { + } + + /// + public override bool CanCreateDataSourceEnumerator => true; + + /// + public override DbCommand CreateCommand() + { + return new SqlCommand(); + } + + /// + public override DbCommandBuilder CreateCommandBuilder() + { + return new SqlCommandBuilder(); + } + + /// + public override DbConnection CreateConnection() + { + return new SqlConnection(); + } + + /// + public override DbConnectionStringBuilder CreateConnectionStringBuilder() + { + return new SqlConnectionStringBuilder(); + } + + /// + public override DbDataAdapter CreateDataAdapter() + { + return new SqlDataAdapter(); + } + + /// + public override DbParameter CreateParameter() + { + return new SqlParameter(); + } + +#if NETFRAMEWORK + /// + public override CodeAccessPermission CreatePermission(PermissionState state) + { + return new SqlClientPermission(state); + } + + /// + /// Extension mechanism for additional services; currently the only service + /// supported is the DbProviderServices + /// + /// requested service provider or null. + object IServiceProvider.GetService(Type serviceType) + { + object result = null; + if (serviceType == GreenMethods.SystemDataCommonDbProviderServices_Type) + { + result = GreenMethods.MicrosoftDataSqlClientSqlProviderServices_Instance(); + } + return result; + } +#endif + + /// + public override DbDataSourceEnumerator CreateDataSourceEnumerator() + { + return SqlDataSourceEnumerator.Instance; + } + +#if NET6_0_OR_GREATER + /// + public override bool CanCreateBatch => true; + + /// + public override DbBatch CreateBatch() => new SqlBatch(); + + /// + public override DbBatchCommand CreateBatchCommand() => new SqlBatchCommand(); +#endif + + } +} 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 90546993a6..e256dde95c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlCommandBuilder.cs @@ -256,8 +256,6 @@ public static void DeriveParameters(SqlCommand command) } #if NETFRAMEWORK TdsParser bestEffortCleanupTarget = null; -#endif -#if !NET6_0_OR_GREATER RuntimeHelpers.PrepareConstrainedRegions(); #endif try diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs index 690a4e810a..243efb3db1 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionString.cs @@ -233,7 +233,6 @@ internal static class TRANSACTIONBINDING internal const int SynonymCount = 33; #else internal const int SynonymCount = 30; - internal const int DeprecatedSynonymCount = 2; #endif // NETFRAMEWORK private static Dictionary s_sqlClientSynonyms; @@ -836,8 +835,8 @@ internal static Dictionary GetParseSynonyms() { int count = SqlConnectionStringBuilder.KeywordsCount + SynonymCount; -#if !NETFRAMEWORK - count += SqlConnectionStringBuilder.DeprecatedKeywordsCount + DeprecatedSynonymCount; +#if NET6_0_OR_GREATER + count += SqlConnectionStringBuilder.DeprecatedKeywordsCount; #endif synonyms = new Dictionary(count, StringComparer.OrdinalIgnoreCase) { @@ -1024,7 +1023,7 @@ internal ApplicationIntent ConvertValueToApplicationIntent() // ArgumentException and other types are raised as is (no wrapping) } -#if NETCOREAPP || NETSTANDARD +#if NET6_0_OR_GREATER internal void ThrowUnsupportedIfKeywordSet(string keyword) { if (ContainsKey(keyword)) 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 c9f9fd2912..de8319c526 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlConnectionStringBuilder.cs @@ -139,7 +139,7 @@ private enum Keywords private string _certificate = DbConnectionStringDefaults.Certificate; #endif #else - internal const int DeprecatedKeywordsCount = 3; + internal const int DeprecatedKeywordsCount = 5; #endif #endregion //Fields @@ -363,7 +363,6 @@ private object GetAt(Keywords index) return MinPoolSize; case Keywords.MultiSubnetFailover: return MultiSubnetFailover; - // case Keywords.NamedConnection: return NamedConnection; case Keywords.PacketSize: return PacketSize; case Keywords.Password: @@ -638,7 +637,7 @@ private void SetPoolBlockingPeriodValue(PoolBlockingPeriod value) private Exception UnsupportedKeyword(string keyword) { -#if !NETFRAMEWORK +#if NET6_0_OR_GREATER for (int index = 0; index < s_notSupportedKeywords.Length; index++) { if (string.Equals(keyword, s_notSupportedKeywords[index], StringComparison.OrdinalIgnoreCase)) @@ -912,17 +911,19 @@ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContex } } #else - private static readonly string[] s_notSupportedKeywords = new string[DeprecatedKeywordsCount] { + private static readonly string[] s_notSupportedKeywords = { DbConnectionStringKeywords.ConnectionReset, DbConnectionStringKeywords.ContextConnection, DbConnectionStringKeywords.TransactionBinding, + DbConnectionStringKeywords.TransparentNetworkIPResolution, + DbConnectionStringSynonyms.TRANSPARENTNETWORKIPRESOLUTION, }; - private static readonly string[] s_notSupportedNetworkLibraryKeywords = new string[] { + private static readonly string[] s_notSupportedNetworkLibraryKeywords = { DbConnectionStringKeywords.NetworkLibrary, DbConnectionStringSynonyms.NET, - DbConnectionStringSynonyms.NETWORK + DbConnectionStringSynonyms.NETWORK, }; #endif #endregion //Private Methods 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 401cde2fa2..0b882bc02c 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependency.cs @@ -629,7 +629,7 @@ internal static bool Start(string connectionString, string queue, bool useDefaul string database = null; string service = null; bool appDomainStart = false; -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try @@ -775,7 +775,7 @@ internal static bool Stop(string connectionString, string queue, bool useDefault if (useDefaults) { bool appDomainStop = false; -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.AssemblyLoadContext.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.AssemblyLoadContext.cs index 47f62fc5ac..34052c3a9d 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.AssemblyLoadContext.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.AssemblyLoadContext.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. +#if NET6_0_OR_GREATER + using System; using System.Reflection; using System.Runtime.Loader; @@ -24,3 +26,5 @@ private void SqlDependencyPerAppDomainDispatcher_Unloading(AssemblyLoadContext o } } } + +#endif 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 506b45faac..c3a0bb1492 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDependencyUtils.cs @@ -107,7 +107,7 @@ private SqlDependencyPerAppDomainDispatcher() } } -#if NETCOREAPP || NETSTANDARD +#if NET6_0_OR_GREATER partial void SubscribeToAppDomainUnload(); partial void SubscribeToAssemblyLoadContextUnload(); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnclaveAttestationParameters.NotSupported.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnclaveAttestationParameters.NotSupported.cs deleted file mode 100644 index 0ae67d4a94..0000000000 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnclaveAttestationParameters.NotSupported.cs +++ /dev/null @@ -1,19 +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. - -namespace Microsoft.Data.SqlClient -{ - /// - internal partial class SqlEnclaveAttestationParameters - { - /// - internal int Protocol { get; } - - /// - internal byte[] GetInput() - { - return null; - } - } -} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs index e6faafc405..401815cf94 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlInternalConnection.cs @@ -27,7 +27,7 @@ internal abstract class SqlInternalConnection : DbConnectionInternal private bool _isGlobalTransactionEnabledForServer; // Whether Global Transactions are enabled for this Azure SQL DB Server 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 +#if NET6_0_OR_GREATER internal SqlCommand.ExecuteReaderAsyncCallContext CachedCommandExecuteReaderAsyncContext; internal SqlCommand.ExecuteNonQueryAsyncCallContext CachedCommandExecuteNonQueryAsyncContext; internal SqlCommand.ExecuteXmlReaderAsyncCallContext CachedCommandExecuteXmlReaderAsyncContext; 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 ee3a09c17a..a7c7fa58e1 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs @@ -844,7 +844,7 @@ public override string SourceColumn /// [ResCategory("DataCategory_Update")] -#if !NETFRAMEWORK +#if NET6_0_OR_GREATER [ResDescription(StringsHelper.ResourceNames.SqlParameter_SourceColumnNullMapping)] #endif public override bool SourceColumnNullMapping diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlSequentialTextReader.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlSequentialTextReader.cs index 9ea820000e..a563d0dfc6 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlSequentialTextReader.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlSequentialTextReader.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Buffers; using System.Buffers.Binary; using System.Diagnostics; using System.Text; @@ -18,7 +19,8 @@ sealed internal class SqlSequentialTextReader : System.IO.TextReader private readonly int _columnIndex; // The index of out column in the table private readonly Encoding _encoding; // Encoding for this character stream private readonly Decoder _decoder; // Decoder based on the encoding (NOTE: Decoders are stateful as they are designed to process streams of data) - private byte[] _leftOverBytes; // Bytes leftover from the last Read() operation - this can be null if there were no bytes leftover (Possible optimization: re-use the same array?) + private byte[] _leftOverBytes; // Bytes leftover from the last Read() operation - this can be null if there were no bytes leftover + private int _leftOverByteBufferUsed; //Number of bytes used from _leftOverBytes buffer - will be zero in case of null buffer private int _peekedChar; // The last character that we peeked at (or -1 if we haven't peeked at anything) private Task _currentTask; // The current async task private readonly CancellationTokenSource _disposalTokenSource; // Used to indicate that a cancellation is requested due to disposal @@ -357,23 +359,18 @@ private byte[] PrepareByteBuffer(int numberOfChars, out int byteBufferUsed) if (_leftOverBytes != null) { - // If we have more leftover bytes than we need for this conversion, then just re-use the leftover buffer - if (_leftOverBytes.Length > byteBufferSize) - { - byteBuffer = _leftOverBytes; - byteBufferUsed = byteBuffer.Length; - } - else - { - // Otherwise, copy over the leftover buffer - byteBuffer = new byte[byteBufferSize]; - Buffer.BlockCopy(_leftOverBytes, 0, byteBuffer, 0, _leftOverBytes.Length); - byteBufferUsed = _leftOverBytes.Length; - } + // Copy over the leftover buffer + byteBuffer = ArrayPool.Shared.Rent(byteBufferSize); + Buffer.BlockCopy(_leftOverBytes, 0, byteBuffer, 0, _leftOverByteBufferUsed); + byteBufferUsed = _leftOverByteBufferUsed; + //return _leftOverBytes and clean _leftOverBytes reference + ArrayPool.Shared.Return(_leftOverBytes); + _leftOverBytes = null; + _leftOverByteBufferUsed = 0; } else { - byteBuffer = new byte[byteBufferSize]; + byteBuffer = ArrayPool.Shared.Rent(byteBufferSize); byteBufferUsed = 0; } } @@ -402,14 +399,26 @@ private int DecodeBytesToChars(byte[] inBuffer, int inBufferCount, char[] outBuf // completed may be false and there is no spare bytes if the Decoder has stored bytes to use later if ((!completed) && (bytesUsed < inBufferCount)) { - _leftOverBytes = new byte[inBufferCount - bytesUsed]; - Buffer.BlockCopy(inBuffer, bytesUsed, _leftOverBytes, 0, _leftOverBytes.Length); + _leftOverByteBufferUsed = inBufferCount - bytesUsed; + _leftOverBytes = ArrayPool.Shared.Rent(_leftOverByteBufferUsed); + + Buffer.BlockCopy(inBuffer, bytesUsed, _leftOverBytes, 0, _leftOverByteBufferUsed); } else { // If Convert() sets completed to true, then it must have used all of the bytes we gave it Debug.Assert(bytesUsed >= inBufferCount, "Converted completed, but not all bytes were used"); - _leftOverBytes = null; + if (_leftOverBytes != null) + { + ArrayPool.Shared.Return(_leftOverBytes); + _leftOverBytes = null; + _leftOverByteBufferUsed = 0; + } + } + + if (inBuffer.Length > 0) + { + ArrayPool.Shared.Return(inBuffer); } Debug.Assert(((_reader == null) || (_reader.ColumnDataBytesRemaining() > 0) || (!completed) || (_leftOverBytes == null)), "Stream has run out of data and the decoder finished, but there are leftover bytes"); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs index c483d8a0f8..8c7119a695 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -3,11 +3,7 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using System.ComponentModel; using System.Data; -using System.Diagnostics; -using Microsoft.Data.Common; namespace Microsoft.Data.SqlClient { @@ -998,47 +994,6 @@ internal enum FedAuthInfoId : byte internal const byte DATA_CLASSIFICATION_VERSION_WITHOUT_RANK_SUPPORT = 0x01; internal const byte DATA_CLASSIFICATION_VERSION_MAX_SUPPORTED = 0x02; - // Needed for UapAot, since we cannot use Enum.GetName() on SniContext. - // Enum.GetName() uses reflection, which is blocked on UapAot for internal types - // like SniContext. - internal static string GetSniContextEnumName(SniContext sniContext) - { - switch (sniContext) - { - case SniContext.Undefined: - return "Undefined"; - case SniContext.Snix_Connect: - return "Snix_Connect"; - case SniContext.Snix_PreLoginBeforeSuccessfulWrite: - return "Snix_PreLoginBeforeSuccessfulWrite"; - case SniContext.Snix_PreLogin: - return "Snix_PreLogin"; - case SniContext.Snix_LoginSspi: - return "Snix_LoginSspi"; - case SniContext.Snix_ProcessSspi: - return "Snix_ProcessSspi"; - case SniContext.Snix_Login: - return "Snix_Login"; - case SniContext.Snix_EnableMars: - return "Snix_EnableMars"; - case SniContext.Snix_AutoEnlist: - return "Snix_AutoEnlist"; - case SniContext.Snix_GetMarsSession: - return "Snix_GetMarsSession"; - case SniContext.Snix_Execute: - return "Snix_Execute"; - case SniContext.Snix_Read: - return "Snix_Read"; - case SniContext.Snix_Close: - return "Snix_Close"; - case SniContext.Snix_SendRows: - return "Snix_SendRows"; - default: - Debug.Fail($"Received unknown SniContext enum. Value: {sniContext}"); - return null; - } - } - // TCE Related constants internal const byte MAX_SUPPORTED_TCE_VERSION = 0x03; // max version internal const byte MIN_TCE_VERSION_WITH_ENCLAVE_SUPPORT = 0x02; // min version with enclave support diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs new file mode 100644 index 0000000000..8e0569b44b --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -0,0 +1,265 @@ +using System; +using System.Buffers; +using System.Diagnostics; + +#nullable enable + +namespace Microsoft.Data.SqlClient +{ + internal partial class TdsParser + { + internal void ProcessSSPI(int receivedLength) + { + Debug.Assert(_authenticationProvider is not null); + + SniContext outerContext = _physicalStateObj.SniContext; + _physicalStateObj.SniContext = SniContext.Snix_ProcessSspi; + // allocate received buffer based on length from SSPI message + byte[] receivedBuff = ArrayPool.Shared.Rent(receivedLength); + + // read SSPI data received from server + Debug.Assert(_physicalStateObj._syncOverAsync, "Should not attempt pends in a synchronous call"); + bool result = _physicalStateObj.TryReadByteArray(receivedBuff, receivedLength); + if (!result) + { + throw SQL.SynchronousCallMayNotPend(); + } + + // allocate send buffer and initialize length + byte[] rentedSendBuff = ArrayPool.Shared.Rent((int)_authenticationProvider!.MaxSSPILength); + byte[] sendBuff = rentedSendBuff; // need to track these separately in case someone updates the ref parameter + uint sendLength = _authenticationProvider.MaxSSPILength; + + // make call for SSPI data + _authenticationProvider.SSPIData(receivedBuff.AsMemory(0, receivedLength), ref sendBuff, ref sendLength, _sniSpnBuffer); + + // DO NOT SEND LENGTH - TDS DOC INCORRECT! JUST SEND SSPI DATA! + _physicalStateObj.WriteByteArray(sendBuff, (int)sendLength, 0); + + ArrayPool.Shared.Return(rentedSendBuff, clearArray: true); + ArrayPool.Shared.Return(receivedBuff, clearArray: true); + + // set message type so server knows its a SSPI response + _physicalStateObj._outputMessageType = TdsEnums.MT_SSPI; + + // send to server + _physicalStateObj.WritePacket(TdsEnums.HARDFLUSH); + _physicalStateObj.SniContext = outerContext; + } + +#nullable disable + + internal void TdsLogin( + SqlLogin rec, + TdsEnums.FeatureExtension requestedFeatures, + SessionData recoverySessionData, + FederatedAuthenticationFeatureExtensionData fedAuthFeatureExtensionData, +#if NETFRAMEWORK + SqlClientOriginalNetworkAddressInfo originalNetworkAddressInfo, +#endif + SqlConnectionEncryptOption encrypt) + { + _physicalStateObj.SetTimeoutSeconds(rec.timeout); + + Debug.Assert(recoverySessionData == null || (requestedFeatures & TdsEnums.FeatureExtension.SessionRecovery) != 0, "Recovery session data without session recovery feature request"); + Debug.Assert(TdsEnums.MAXLEN_HOSTNAME >= rec.hostName.Length, "_workstationId.Length exceeds the max length for this value"); + + Debug.Assert(!(rec.useSSPI && _connHandler._fedAuthRequired), "Cannot use SSPI when server has responded 0x01 for FedAuthRequired PreLogin Option."); + Debug.Assert(!rec.useSSPI || (requestedFeatures & TdsEnums.FeatureExtension.FedAuth) == 0, "Cannot use both SSPI and FedAuth"); + Debug.Assert(fedAuthFeatureExtensionData == null || (requestedFeatures & TdsEnums.FeatureExtension.FedAuth) != 0, "fedAuthFeatureExtensionData provided without fed auth feature request"); + Debug.Assert(fedAuthFeatureExtensionData != null || (requestedFeatures & TdsEnums.FeatureExtension.FedAuth) == 0, "Fed Auth feature requested without specifying fedAuthFeatureExtensionData."); + + Debug.Assert(rec.userName == null || (rec.userName != null && TdsEnums.MAXLEN_CLIENTID >= rec.userName.Length), "_userID.Length exceeds the max length for this value"); + Debug.Assert(rec.credential == null || (rec.credential != null && TdsEnums.MAXLEN_CLIENTID >= rec.credential.UserId.Length), "_credential.UserId.Length exceeds the max length for this value"); + + Debug.Assert(rec.password == null || (rec.password != null && TdsEnums.MAXLEN_CLIENTSECRET >= rec.password.Length), "_password.Length exceeds the max length for this value"); + Debug.Assert(rec.credential == null || (rec.credential != null && TdsEnums.MAXLEN_CLIENTSECRET >= rec.credential.Password.Length), "_credential.Password.Length exceeds the max length for this value"); + + Debug.Assert(rec.credential != null || rec.userName != null || rec.password != null, "cannot mix the new secure password system and the connection string based password"); + Debug.Assert(rec.newSecurePassword != null || rec.newPassword != null, "cannot have both new secure change password and string based change password"); + Debug.Assert(TdsEnums.MAXLEN_APPNAME >= rec.applicationName.Length, "_applicationName.Length exceeds the max length for this value"); + Debug.Assert(TdsEnums.MAXLEN_SERVERNAME >= rec.serverName.Length, "_dataSource.Length exceeds the max length for this value"); + Debug.Assert(TdsEnums.MAXLEN_LANGUAGE >= rec.language.Length, "_currentLanguage .Length exceeds the max length for this value"); + Debug.Assert(TdsEnums.MAXLEN_DATABASE >= rec.database.Length, "_initialCatalog.Length exceeds the max length for this value"); + Debug.Assert(TdsEnums.MAXLEN_ATTACHDBFILE >= rec.attachDBFilename.Length, "_attachDBFileName.Length exceeds the max length for this value"); + + Debug.Assert(_connHandler != null, "SqlConnectionInternalTds handler can not be null at this point."); + _connHandler!.TimeoutErrorInternal.EndPhase(SqlConnectionTimeoutErrorPhase.LoginBegin); + _connHandler.TimeoutErrorInternal.SetAndBeginPhase(SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth); + +#if NETFRAMEWORK + // Add CTAIP Provider + // + if (originalNetworkAddressInfo != null) + { + SNINativeMethodWrapper.CTAIPProviderInfo cauthInfo = new SNINativeMethodWrapper.CTAIPProviderInfo(); + cauthInfo.originalNetworkAddress = originalNetworkAddressInfo.Address.GetAddressBytes(); + cauthInfo.fromDataSecurityProxy = originalNetworkAddressInfo.IsFromDataSecurityProxy; + + UInt32 error = SNINativeMethodWrapper.SNIAddProvider(_physicalStateObj.Handle, SNINativeMethodWrapper.ProviderEnum.CTAIP_PROV, cauthInfo); + if (error != TdsEnums.SNI_SUCCESS) + { + _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); + ThrowExceptionAndWarning(_physicalStateObj); + } + + try + { } // EmptyTry/Finally to avoid FXCop violation + finally + { + _physicalStateObj.ClearAllWritePackets(); + } + } +#endif + + // get the password up front to use in sspi logic below + byte[] encryptedPassword = null; + byte[] encryptedChangePassword = null; + int encryptedPasswordLengthInBytes; + int encryptedChangePasswordLengthInBytes; + bool useFeatureExt = (requestedFeatures != TdsEnums.FeatureExtension.None); + + string userName; + + if (rec.credential != null) + { + userName = rec.credential.UserId; + encryptedPasswordLengthInBytes = rec.credential.Password.Length * 2; + } + else + { + userName = rec.userName; + encryptedPassword = TdsParserStaticMethods.ObfuscatePassword(rec.password); + encryptedPasswordLengthInBytes = encryptedPassword.Length; // password in clear text is already encrypted and its length is in byte + } + + if (rec.newSecurePassword != null) + { + encryptedChangePasswordLengthInBytes = rec.newSecurePassword.Length * 2; + } + else + { + encryptedChangePassword = TdsParserStaticMethods.ObfuscatePassword(rec.newPassword); + encryptedChangePasswordLengthInBytes = encryptedChangePassword.Length; + } + + // set the message type + _physicalStateObj._outputMessageType = TdsEnums.MT_LOGIN7; + + // length in bytes + int length = TdsEnums.SQL2005_LOG_REC_FIXED_LEN; + + string clientInterfaceName = TdsEnums.SQL_PROVIDER_NAME; + Debug.Assert(TdsEnums.MAXLEN_CLIENTINTERFACE >= clientInterfaceName.Length, "cchCltIntName can specify at most 128 unicode characters. See Tds spec"); + + // add up variable-len portions (multiply by 2 for byte len of char strings) + // + checked + { + length += (rec.hostName.Length + rec.applicationName.Length + + rec.serverName.Length + clientInterfaceName.Length + + rec.language.Length + rec.database.Length + + rec.attachDBFilename.Length) * 2; + if (useFeatureExt) + { + length += 4; + } + } + + // allocate memory for SSPI variables + byte[] rentedSSPIBuff = null; + byte[] outSSPIBuff = null; // track the rented buffer as a separate variable in case it is updated via the ref parameter + uint outSSPILength = 0; + + // only add lengths of password and username if not using SSPI or requesting federated authentication info + if (!rec.useSSPI && !(_connHandler._federatedAuthenticationInfoRequested || _connHandler._federatedAuthenticationRequested)) + { + checked + { + length += (userName.Length * 2) + encryptedPasswordLengthInBytes + + encryptedChangePasswordLengthInBytes; + } + } + else + { + if (rec.useSSPI) + { + // now allocate proper length of buffer, and set length + outSSPILength = _authenticationProvider.MaxSSPILength; + rentedSSPIBuff = ArrayPool.Shared.Rent((int)outSSPILength); + outSSPIBuff = rentedSSPIBuff; + + // Call helper function for SSPI data and actual length. + // Since we don't have SSPI data from the server, send null for the + // byte[] buffer and 0 for the int length. + Debug.Assert(SniContext.Snix_Login == _physicalStateObj.SniContext, $"Unexpected SniContext. Expecting Snix_Login, actual value is '{_physicalStateObj.SniContext}'"); + _physicalStateObj.SniContext = SniContext.Snix_LoginSspi; + _authenticationProvider.SSPIData(ReadOnlyMemory.Empty, ref outSSPIBuff, ref outSSPILength, _sniSpnBuffer); + + if (outSSPILength > int.MaxValue) + { + throw SQL.InvalidSSPIPacketSize(); // SqlBu 332503 + } + _physicalStateObj.SniContext = SniContext.Snix_Login; + + checked + { + length += (int)outSSPILength; + } + } + } + + int feOffset = length; + // calculate and reserve the required bytes for the featureEx + length = ApplyFeatureExData(requestedFeatures, recoverySessionData, fedAuthFeatureExtensionData, useFeatureExt, length); + + WriteLoginData(rec, + requestedFeatures, + recoverySessionData, + fedAuthFeatureExtensionData, + encrypt, + encryptedPassword, + encryptedChangePassword, + encryptedPasswordLengthInBytes, + encryptedChangePasswordLengthInBytes, + useFeatureExt, + userName, + length, + feOffset, + clientInterfaceName, + outSSPIBuff, + outSSPILength); + + if (rentedSSPIBuff != null) + { + ArrayPool.Shared.Return(rentedSSPIBuff, clearArray: true); + } + + _physicalStateObj.WritePacket(TdsEnums.HARDFLUSH); + _physicalStateObj.ResetSecurePasswordsInformation(); // Password information is needed only from Login process; done with writing login packet and should clear information + _physicalStateObj.HasPendingData = true; + _physicalStateObj._messageStatus = 0; + +#if NETFRAMEWORK + // Remvove CTAIP Provider after login record is sent. + // + if (originalNetworkAddressInfo != null) + { + UInt32 error = SNINativeMethodWrapper.SNIRemoveProvider(_physicalStateObj.Handle, SNINativeMethodWrapper.ProviderEnum.CTAIP_PROV); + if (error != TdsEnums.SNI_SUCCESS) + { + _physicalStateObj.AddError(ProcessSNIError(_physicalStateObj)); + ThrowExceptionAndWarning(_physicalStateObj); + } + + try + { } // EmptyTry/Finally to avoid FXCop violation + finally + { + _physicalStateObj.ClearAllWritePackets(); + } + } +#endif + }// tdsLogin + } +} 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 8d276cd285..dba1ec788c 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 @@ -164,7 +164,7 @@ internal SNIHandle( string hostNameInCertificate) : base(IntPtr.Zero, true) { -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK RuntimeHelpers.PrepareConstrainedRegions(); #endif try diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index 17729a4cc9..4347d0f2e0 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -976,7 +976,7 @@ internal bool TryProcessHeader() _inBuff[_inBytesUsed + TdsEnums.HEADER_LEN_FIELD_OFFSET + 1]) - _inputHeaderLen; _spid = _inBuff[_inBytesUsed + TdsEnums.SPID_OFFSET] << 8 | _inBuff[_inBytesUsed + TdsEnums.SPID_OFFSET + 1]; -#if !NETFRAMEWORK +#if NET6_0_OR_GREATER SqlClientEventSource.Log.TryAdvancedTraceEvent("TdsParserStateObject.TryProcessHeader | ADV | State Object Id {0}, Client Connection Id {1}, Server process Id (SPID) {2}", _objectID, _parser?.Connection?.ClientConnectionId, _spid); #endif _inBytesUsed += _inputHeaderLen; @@ -1097,6 +1097,9 @@ internal bool SetPacketSize(int size) (_outBytesUsed == _outputHeaderLen && _outputPacketNumber == 1), "SetPacketSize called with data in the buffer!"); + SqlClientEventSource.Log.TryTraceEvent("{0}.{1} | Info | State Object Id {2}, Setting packet size to {3}", + nameof(TdsParserStateObject), nameof(SetPacketSize), _objectID, size); + if (_inBuff == null || _inBuff.Length != size) { // We only check _inBuff, since two buffers should be consistent. // Allocate or re-allocate _inBuff. diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsValueSetter.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsValueSetter.cs index f2c33824a2..6b05698972 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsValueSetter.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsValueSetter.cs @@ -587,7 +587,7 @@ internal void SetDateTime(DateTime value) if (SqlDbType.DateTime2 == _metaData.SqlDbType) { long time = value.TimeOfDay.Ticks / TdsEnums.TICKS_FROM_SCALE[_metaData.Scale]; -#if NETCOREAPP +#if NET6_0_OR_GREATER Span result_time = stackalloc byte[8]; BinaryPrimitives.WriteInt64LittleEndian(result_time, time); _stateObj.WriteByteSpan(result_time.Slice(0, (int)_metaData.MaxLength - 3)); @@ -595,7 +595,7 @@ internal void SetDateTime(DateTime value) _stateObj.WriteByteArray(BitConverter.GetBytes(time), (int)_metaData.MaxLength - 3, 0); #endif } -#if NETCOREAPP +#if NET6_0_OR_GREATER Span result_date = stackalloc byte[4]; BinaryPrimitives.WriteInt32LittleEndian(result_date, days); _stateObj.WriteByteSpan(result_date.Slice(0, 3)); @@ -612,7 +612,7 @@ internal void SetGuid(Guid value) Debug.Assert( SmiXetterAccessMap.IsSetterAccessValid(_metaData, SmiXetterTypeCode.XetGuid)); -#if NETCOREAPP +#if NET6_0_OR_GREATER Span bytes = stackalloc byte[16]; value.TryWriteBytes(bytes); @@ -631,7 +631,7 @@ internal void SetGuid(Guid value) _stateObj.WriteByte((byte)_metaData.MaxLength); } -#if NETCOREAPP +#if NET6_0_OR_GREATER _stateObj.WriteByteSpan(bytes); #else _stateObj.WriteByteArray(bytes, bytes.Length, 0); @@ -659,7 +659,7 @@ internal void SetTimeSpan(TimeSpan value) _stateObj.WriteByte(length); } long time = value.Ticks / TdsEnums.TICKS_FROM_SCALE[scale]; -#if NETCOREAPP +#if NET6_0_OR_GREATER Span result_time = stackalloc byte[8]; BinaryPrimitives.WriteInt64LittleEndian(result_time, time); _stateObj.WriteByteSpan(result_time.Slice(0, length)); @@ -696,11 +696,35 @@ internal void SetDateTimeOffset(DateTimeOffset value) int days = utcDateTime.Subtract(DateTime.MinValue).Days; short offset = (short)value.Offset.TotalMinutes; -#if NETCOREAPP - Span result = stackalloc byte[9]; +#if NET6_0_OR_GREATER + // In TDS protocol: + // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-tds/786f5b8a-f87d-4980-9070-b9b7274c681d + // + // date is represented as one 3 - byte unsigned integer that represents the number of days since January 1, year 1. + // + // time(n) is represented as one unsigned integer that represents the number of 10^-n, + // (10 to the power of negative n), second increments since 12 AM within a day. + // The length, in bytes, of that integer depends on the scale n as follows: + // 3 bytes if 0 <= n < = 2. + // 4 bytes if 3 <= n < = 4. + // 5 bytes if 5 <= n < = 7. + // For example: + // DateTimeOffset dateTimeOffset = new DateTimeOffset(2024, 1, 1, 23, 59, 59, TimeSpan.Zero); // using scale of 0 + // time = 23:59:59, scale is 1, is represented as 863990 in 3 bytes or { 246, 46, 13, 0, 0, 0, 0, 0 } in bytes array + + Span result = stackalloc byte[8]; + + // https://learn.microsoft.com/en-us/dotnet/api/system.buffers.binary.binaryprimitives.writeint64bigendian?view=net-8.0 + // WriteInt64LittleEndian requires 8 bytes to write the value. BinaryPrimitives.WriteInt64LittleEndian(result, time); - BinaryPrimitives.WriteInt32LittleEndian(result.Slice(5), days); - _stateObj.WriteByteSpan(result.Slice(0, 8)); + // The DateTimeOffset length is variable depending on the scale, 1 to 7, used. + // If length = 8, 8 - 5 = 3 bytes is used for time. + // If length = 10, 10 - 5 = 5 bytes is used for time. + _stateObj.WriteByteSpan(result.Slice(0, length - 5)); // this writes the time value to the state object using dynamic length based on the scale. + + // Date is represented as 3 bytes. So, 3 bytes are written to the state object. + BinaryPrimitives.WriteInt32LittleEndian(result, days); + _stateObj.WriteByteSpan(result.Slice(0, 3)); #else _stateObj.WriteByteArray(BitConverter.GetBytes(time), length - 5, 0); // time _stateObj.WriteByteArray(BitConverter.GetBytes(days), 3, 0); // date diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs index eba8b856a2..cfbe531e82 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/VirtualSecureModeEnclaveProviderBase.cs @@ -252,7 +252,13 @@ private bool VerifyHealthReportAgainstRootCertificate(X509Certificate2Collection chain.ChainPolicy.ExtraStore.Add(cert); } + // An Always Encrypted-enabled driver doesn't verify an expiration date or a certificate authority chain. + // A certificate is simply used as a key pair consisting of a public and private key. This is by design. + + #pragma warning disable IA5352 + // CodeQL [SM00395] By design. Always Encrypted certificates should not be checked. chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; + #pragma warning restore IA5352 if (!chain.Build(healthReportCert)) { diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs b/src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs index a99e5d0303..a685787e9e 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs @@ -10215,6 +10215,15 @@ internal static string SQL_RemoteCertificateChainErrors { } } + /// + /// Looks up a localized string similar to The certificate provided by the server does not match the certificate provided by the ServerCertificate option.. + /// + internal static string SQL_RemoteCertificateDoesNotMatchServerCertificate { + get { + return ResourceManager.GetString("SQL_RemoteCertificateDoesNotMatchServerCertificate", resourceCulture); + } + } + /// /// Looks up a localized string similar to Certificate name mismatch. The provided 'DataSource' or 'HostNameInCertificate' does not match the name in the certificate.. /// @@ -10503,15 +10512,6 @@ internal static string SQL_StreamWriteNotSupported { } } - /// - /// Looks up a localized string similar to Not supported in .Net Standard 2.0.. - /// - internal static string SQL_TDS8_NotSupported_Netstandard2_0 { - get { - return ResourceManager.GetString("SQL_TDS8_NotSupported_Netstandard2_0", resourceCulture); - } - } - /// /// Looks up a localized string similar to Processing of results from SQL Server failed because of an invalid multipart name. /// diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.de.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.de.resx index ac803efe71..4a6d349fd8 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.de.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.de.resx @@ -4680,9 +4680,6 @@ Socket hat den erwarteten "{0}" nicht ausgelöst. Fehlercode: "{1}". - - Wird in .NET Standard 2.0 nicht unterstützt. - Der Server versucht, ein Feature zu verwenden, das auf dieser Plattform nicht unterstützt wird. diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.es.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.es.resx index 821f8f1aa5..ff71f45c02 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.es.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.es.resx @@ -4680,9 +4680,6 @@ El socket no produjo el esperado '{0}' con el código de error '{1}'. - - No se admite en .NET Standard 2.0. - El servidor está intentando usar una característica que no se admite en esta plataforma. diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.fr.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.fr.resx index d7e42c70c7..8b426074c2 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.fr.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.fr.resx @@ -4680,9 +4680,6 @@ Le socket n’a pas levé le '{0}' attendu avec le code d’erreur '{1}'. - - Non pris en charge dans .Net Standard 2.0. - Le serveur tente d’utiliser une fonctionnalité qui n’est pas prise en charge sur cette plateforme. diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.it.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.it.resx index add941c9ce..b5cbd33bdd 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.it.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.it.resx @@ -4680,9 +4680,6 @@ Il socket non ha generato '{0}' previsto con codice errore '{1}'. - - Non supportato in .NET Standard 2.0. - Il server sta tentando di usare una funzionalità non supportata in questa piattaforma. diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.ja.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.ja.resx index 8b5b367a9f..de5a1c1830 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.ja.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.ja.resx @@ -4680,9 +4680,6 @@ ソケットは予期された '{0}' をスローしませんでした。エラー コード '{1}'。 - - .Net Standard 2.0 ではサポートされていません。 - サーバーは、このプラットフォームでサポートされていない機能を使用しようとしています。 diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.ko.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.ko.resx index d3d62df164..20db99df33 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.ko.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.ko.resx @@ -4680,9 +4680,6 @@ 소켓이 오류 코드 '{1}'과(와) 예상되는 '{0}'을(를) throw하지 않았습니다. - - .Net Standard 2.0에서는 지원되지 않습니다. - 서버가 이 플랫폼에서 지원되지 않는 기능을 사용하려고 합니다. diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.pt-BR.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.pt-BR.resx index 3cb1ae77ec..911334848e 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.pt-BR.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.pt-BR.resx @@ -4680,9 +4680,6 @@ O soquete não lançou o esperado '{0}' com código de erro '{1}'. - - Sem suporte no .Net Standard 2.0. - O servidor está tentando usar um recurso que não é suportado nesta plataforma. diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx index 3712ece88f..c2dd68b867 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx @@ -4680,9 +4680,6 @@ Socket did not throw expected '{0}' with error code '{1}'. - - Not supported in .Net Standard 2.0. - The server is attempting to use a feature that is not supported on this platform. @@ -4740,4 +4737,7 @@ Certificate not available while validating the certificate. - \ No newline at end of file + + The certificate provided by the server does not match the certificate provided by the ServerCertificate option. + + diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.ru.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.ru.resx index 24fb60a6e4..cae6234541 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.ru.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.ru.resx @@ -4680,9 +4680,6 @@ Сокет не вызвал ожидаемый "{0}" с кодом ошибки "{1}". - - Не поддерживается в .NET Standard 2.0. - Сервер пытается использовать функцию, которая не поддерживается этой платформой. diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.zh-Hans.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.zh-Hans.resx index e2d34132a8..2b866bd6ed 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.zh-Hans.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.zh-Hans.resx @@ -4680,9 +4680,6 @@ 套接字未引发预期的“{0}”,错误代码为“{1}”。 - - .Net Standard 2.0 不支持。 - 服务器正在尝试使用此平台不支持的功能。 diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.zh-Hant.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.zh-Hant.resx index d345373858..404f048cf6 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.zh-Hant.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.zh-Hant.resx @@ -4680,9 +4680,6 @@ 通訊端未擲出預期的 '{0}',錯誤碼為 '{1}'。 - - .NET Standard 2.0 中不支援。 - 伺服器正嘗試使用此平台上不支援的功能。 diff --git a/src/Microsoft.Data.SqlClient/src/Resources/StringsHelper.cs b/src/Microsoft.Data.SqlClient/src/Resources/StringsHelper.cs index 3f003c081c..d1b736f595 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/StringsHelper.cs +++ b/src/Microsoft.Data.SqlClient/src/Resources/StringsHelper.cs @@ -63,7 +63,7 @@ public static string GetString(string res, params object[] args) } } -#if !NETFRAMEWORK +#if NET6_0_OR_GREATER // This method is used to decide if we need to append the exception message parameters to the message when calling Strings.Format. // by default it returns false. // Native code generators can replace the value this returns based on user input at the time of native code generation. diff --git a/src/Microsoft.Data.SqlClient/src/System/Diagnostics/CodeAnalysis.cs b/src/Microsoft.Data.SqlClient/src/System/Diagnostics/CodeAnalysis.cs index e62544d06d..aaca20a34d 100644 --- a/src/Microsoft.Data.SqlClient/src/System/Diagnostics/CodeAnalysis.cs +++ b/src/Microsoft.Data.SqlClient/src/System/Diagnostics/CodeAnalysis.cs @@ -4,62 +4,8 @@ namespace System.Diagnostics.CodeAnalysis { -#if NETSTANDARD2_0 - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property)] - internal sealed class AllowNullAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property)] - internal sealed class DisallowNullAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Method)] - internal sealed class DoesNotReturnAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Parameter)] - internal sealed class DoesNotReturnIfAttribute : Attribute - { - public DoesNotReturnIfAttribute(bool parameterValue) => ParameterValue = parameterValue; - public bool ParameterValue { get; } - } - - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)] - internal sealed class MaybeNullAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Parameter)] - internal sealed class MaybeNullWhenAttribute : Attribute - { - public MaybeNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; - public bool ReturnValue { get; } - } - - [AttributeUsage(AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue)] - internal sealed class NotNullAttribute : Attribute - { - } - - [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.ReturnValue, AllowMultiple = true)] - internal sealed class NotNullIfNotNullAttribute : Attribute - { - public NotNullIfNotNullAttribute(string parameterName) => ParameterName = parameterName; - public string ParameterName { get; } - } - - [AttributeUsage(AttributeTargets.Parameter)] - internal sealed class NotNullWhenAttribute : Attribute - { - public NotNullWhenAttribute(bool returnValue) => ReturnValue = returnValue; - public bool ReturnValue { get; } - } -#endif -#if !NET6_0_OR_GREATER +#if NETFRAMEWORK [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = true, Inherited = false)] internal sealed class MemberNotNullAttribute : Attribute { diff --git a/src/Microsoft.Data.SqlClient/tests/CustomConfigurableRetryLogic/CustomRetryLogicProvider.csproj b/src/Microsoft.Data.SqlClient/tests/CustomConfigurableRetryLogic/CustomRetryLogicProvider.csproj index 4c4d66ca94..8a076d1e52 100644 --- a/src/Microsoft.Data.SqlClient/tests/CustomConfigurableRetryLogic/CustomRetryLogicProvider.csproj +++ b/src/Microsoft.Data.SqlClient/tests/CustomConfigurableRetryLogic/CustomRetryLogicProvider.csproj @@ -13,7 +13,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props index 7e412a3375..12c7957a23 100644 --- a/src/Microsoft.Data.SqlClient/tests/Directory.Build.props +++ b/src/Microsoft.Data.SqlClient/tests/Directory.Build.props @@ -24,7 +24,7 @@ - $(TargetNetFxVersion);$(TargetNetCoreVersion); + $(TargetNetCoreVersion);$(TargetNetFxVersion) $(TargetNetCoreVersion); diff --git a/src/Microsoft.Data.SqlClient/tests/Docker/DockerLinuxTest/Dockerfile b/src/Microsoft.Data.SqlClient/tests/Docker/DockerLinuxTest/Dockerfile index 04640c06a5..4d48876e33 100644 --- a/src/Microsoft.Data.SqlClient/tests/Docker/DockerLinuxTest/Dockerfile +++ b/src/Microsoft.Data.SqlClient/tests/Docker/DockerLinuxTest/Dockerfile @@ -1,9 +1,9 @@ #See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. -FROM mcr.microsoft.com/dotnet/runtime:8.0@sha256:bb9e61f07f93945ab97391b1dcbcc41136b03310583f36e52b3ec2815111e58a AS base +FROM mcr.microsoft.com/dotnet/runtime:8.0@sha256:113324d7d68c23885ee6ce61f192f5cd2bed7a42d80a2038f26538b5653a1250 AS base WORKDIR /app -FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:8e77ad6fb7c33c17f026424d3bef05ea2ee15d1621e28f312adeab4dc1005866 AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0.101@sha256:1b99a629b4f55a496db835d9c3347737aa4a1d995d43ffe5ab92d04bee69adeb AS build WORKDIR /sqlclient COPY . . diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs index 31c3504d84..79956e78d5 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/AlwaysEncryptedTests/SqlColumnEncryptionCertificateStoreProviderShould.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.Security.Principal; using System.Text; @@ -495,22 +496,24 @@ public override IEnumerable GetData(MethodInfo testMethod) { yield return new object[2] { StoreLocation.CurrentUser, CurrentUserMyPathPrefix }; // use localmachine cert path only when current user is Admin. - if (CertificateFixture.IsAdmin) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && CertificateFixture.IsAdmin) { yield return new object[2] { StoreLocation.LocalMachine, LocalMachineMyPathPrefix }; } } } + public class ValidCertificatePathsParameters : DataAttribute { + public override IEnumerable GetData(MethodInfo testMethod) { yield return new object[2] { CurrentUserMyPathPrefix, StoreLocation.CurrentUser }; yield return new object[2] { MyPathPrefix, null }; yield return new object[2] { @"", null }; // use localmachine cert path only when current user is Admin. - if (CertificateFixture.IsAdmin) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && CertificateFixture.IsAdmin) { yield return new object[2] { LocalMachineMyPathPrefix, StoreLocation.LocalMachine }; } @@ -653,7 +656,7 @@ public CertificateFixture() AddCertificateToStore(certificate1, StoreLocation.CurrentUser); AddCertificateToStore(certificate2, StoreLocation.CurrentUser); AddCertificateToStore(certificate3, StoreLocation.CurrentUser); - if (IsAdmin) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && IsAdmin) { AddCertificateToStore(certificate3, StoreLocation.LocalMachine); } diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/BaseProviderAsyncTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/BaseProviderAsyncTest.cs index 0d13ad5f77..92acc68092 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/BaseProviderAsyncTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/BaseProviderAsyncTest.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; using Xunit; -namespace Microsoft.Data.SqlClient.ManualTesting.Tests +namespace Microsoft.Data.SqlClient.Tests { public static class BaseProviderAsyncTest { diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockCommand.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockCommand.cs index eef8d13700..ce77e22db8 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockCommand.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockCommand.cs @@ -9,7 +9,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Data.SqlClient.ManualTesting.Tests +namespace Microsoft.Data.SqlClient.Tests { public class MockCommand : DbCommand { diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockConnection.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockConnection.cs index 77c84e9f26..96f6922eb6 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockConnection.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockConnection.cs @@ -7,7 +7,7 @@ using System.Data.Common; using System.Threading; -namespace Microsoft.Data.SqlClient.ManualTesting.Tests +namespace Microsoft.Data.SqlClient.Tests { public class MockConnection : DbConnection { diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockDataReader.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockDataReader.cs index 5914f9825a..b4e6875ddc 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockDataReader.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/BaseProviderAsyncTest/MockDataReader.cs @@ -7,7 +7,7 @@ using System.Data.Common; using System.Threading; -namespace Microsoft.Data.SqlClient.ManualTesting.Tests +namespace Microsoft.Data.SqlClient.Tests { internal class MockDataReader : DbDataReader { diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/CloneTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/CloneTests.cs index f5deb6c62c..1c8efc4456 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/CloneTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/CloneTests.cs @@ -4,6 +4,7 @@ using System; using System.Data; +using System.Threading.Tasks; using Xunit; namespace Microsoft.Data.SqlClient.Tests @@ -18,10 +19,19 @@ public void CloneSqlConnection() builder.ConnectTimeout = 1; builder.InitialCatalog = "northwinddb"; SqlConnection connection = new SqlConnection(builder.ConnectionString); + connection.AccessToken = Guid.NewGuid().ToString(); SqlConnection clonedConnection = (connection as ICloneable).Clone() as SqlConnection; Assert.Equal(connection.ConnectionString, clonedConnection.ConnectionString); Assert.Equal(connection.ConnectionTimeout, clonedConnection.ConnectionTimeout); + Assert.Equal(connection.AccessToken, clonedConnection.AccessToken); + Assert.NotEqual(connection, clonedConnection); + + connection = new SqlConnection(builder.ConnectionString); + connection.AccessTokenCallback = (ctx, token) => + Task.FromResult(new SqlAuthenticationToken(Guid.NewGuid().ToString(), DateTimeOffset.MaxValue)); + clonedConnection = (connection as ICloneable).Clone() as SqlConnection; + Assert.Equal(connection.AccessTokenCallback, clonedConnection.AccessTokenCallback); Assert.NotEqual(connection, clonedConnection); } 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 7724f4c58e..b5ac559337 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 @@ -8,9 +8,9 @@ win-$(Platform) $(DefineConstants);NETFRAMEWORK $(DefineConstants);NETCOREAPP - NETSTANDARDREFERNCE $(ObjFolder)$(Configuration).$(Platform).$(AssemblyName) $(BinFolder)$(Configuration).$(Platform).$(AssemblyName) + true @@ -32,6 +32,7 @@ + @@ -91,9 +92,10 @@ - + + @@ -114,15 +116,19 @@ TDS - + - - + + PreserveNewest + %(Filename)%(Extension) + + + diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlBufferTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlBufferTests.cs new file mode 100644 index 0000000000..21169fba96 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlBufferTests.cs @@ -0,0 +1,253 @@ +// 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.Data.SqlTypes; +using System.Linq; +using System.Reflection; +using Xunit; + +namespace Microsoft.Data.SqlClient.Tests +{ + public sealed class SqlBufferTests + { + static SqlBufferTests() + { + const string sqlBufferTypeFullName = "Microsoft.Data.SqlClient.SqlBuffer"; + const string storageTypeName = nameof(SqlBufferProxy.StorageType); + + var assembly = typeof(SqlClientFactory).Assembly; + _sqlBufferType = assembly.GetType(sqlBufferTypeFullName) + ?? throw new Exception($"Type not found [{sqlBufferTypeFullName}]"); + _storageTypeType = _sqlBufferType.GetNestedTypes(BindingFlags.NonPublic) + .FirstOrDefault(x => x.Name == storageTypeName) + ?? throw new Exception($"Type not found [{sqlBufferTypeFullName}+{storageTypeName}]"); + } + + private static readonly Type _sqlBufferType; + private static readonly Type _storageTypeType; + private readonly SqlBufferProxy _target = new(); + + public static IEnumerable GetStorageTypeValues() + { +#if NET6_0_OR_GREATER + return Enum.GetValues() + .Select(x => new object[] { x }); +#else + return Enum.GetValues(typeof(SqlBufferProxy.StorageType)) + .OfType() + .Select(x => new object[] { x }); +#endif + } + + [Theory] + [MemberData(nameof(GetStorageTypeValues))] + public void StorageTypeInProxyShouldHaveTheSameValueAsOriginal(SqlBufferProxy.StorageType expected) + { + var originalEnumName = Enum.GetName(_storageTypeType, (int)expected); + + Assert.Equal(expected.ToString(), originalEnumName); + } + + [Fact] + public void GuidShouldThrowWhenSqlGuidNullIsSet() + { + _target.SqlGuid = SqlGuid.Null; + + Assert.Throws(() => _target.Guid); + } + + [Theory] + [InlineData(SqlBufferProxy.StorageType.Guid)] + [InlineData(SqlBufferProxy.StorageType.SqlGuid)] + public void GuidShouldThrowWhenSetToNullOfTypeIsCalled(SqlBufferProxy.StorageType storageType) + { + _target.SetToNullOfType(storageType); + + Assert.Throws(() => _target.Guid); + } + + [Fact] + public void GuidShouldReturnWhenGuidIsSet() + { + var expected = Guid.NewGuid(); + _target.Guid = expected; + + Assert.Equal(expected, _target.Guid); + } + + [Fact] + public void GuidShouldReturnExpectedWhenSqlGuidIsSet() + { + var expected = Guid.NewGuid(); + _target.SqlGuid = expected; + + Assert.Equal(expected, _target.Guid); + } + + [Theory] + [InlineData(SqlBufferProxy.StorageType.Guid)] + [InlineData(SqlBufferProxy.StorageType.SqlGuid)] + public void SqlGuidShouldReturnSqlNullWhenSetToNullOfTypeIsCalled(SqlBufferProxy.StorageType storageType) + { + _target.SetToNullOfType(storageType); + + Assert.Equal(SqlGuid.Null, _target.SqlGuid); + } + + [Fact] + public void SqlGuidShouldReturnSqlGuidNullWhenSqlGuidNullIsSet() + { + _target.SqlGuid = SqlGuid.Null; + + Assert.Equal(SqlGuid.Null, _target.SqlGuid); + } + + [Fact] + public void SqlGuidShouldReturnExpectedWhenGuidIsSet() + { + var guid = Guid.NewGuid(); + SqlGuid expected = guid; + _target.Guid = guid; + + Assert.Equal(expected, _target.SqlGuid); + } + + [Fact] + public void SqlGuidShouldReturnExpectedWhenSqlGuidIsSet() + { + SqlGuid expected = Guid.NewGuid(); + _target.SqlGuid = expected; + + Assert.Equal(expected, _target.SqlGuid); + } + + [Fact] + public void SqlValueShouldReturnExpectedWhenGuidIsSet() + { + var guid = Guid.NewGuid(); + SqlGuid expected = guid; + _target.Guid = guid; + + Assert.Equal(expected, _target.SqlValue); + } + + [Fact] + public void SqlValueShouldReturnExpectedWhenSqlGuidIsSet() + { + SqlGuid expected = Guid.NewGuid(); + _target.SqlGuid = expected; + + Assert.Equal(expected, _target.SqlValue); + } + + public sealed class SqlBufferProxy + { + public enum StorageType + { + Empty = 0, + Boolean, + Byte, + DateTime, + Decimal, + Double, + Int16, + Int32, + Int64, + Guid, + Money, + Single, + String, + SqlBinary, + SqlCachedBuffer, + SqlGuid, + SqlXml, + Date, + DateTime2, + DateTimeOffset, + Time, + } + + private static readonly PropertyInfo _guidProperty; + private static readonly PropertyInfo _sqlGuidProperty; + private static readonly PropertyInfo _sqlValueProperty; + private static readonly MethodInfo _setToNullOfTypeMethod; + private readonly object _instance; + + static SqlBufferProxy() + { + var flags = BindingFlags.NonPublic | BindingFlags.Instance; + _guidProperty = _sqlBufferType.GetProperty(nameof(Guid), flags); + _sqlGuidProperty = _sqlBufferType.GetProperty(nameof(SqlGuid), flags); + _sqlValueProperty = _sqlBufferType.GetProperty(nameof(SqlValue), flags); + _setToNullOfTypeMethod = _sqlBufferType.GetMethod(nameof(SetToNullOfType), flags); + } + + public SqlBufferProxy() + { + _instance = Activator.CreateInstance(_sqlBufferType, true); + } + + public Guid Guid + { + get => GetPropertyValue(_guidProperty); + set => SetPropertyValue(_guidProperty, value); + } + + public SqlGuid SqlGuid + { + get => GetPropertyValue(_sqlGuidProperty); + set => SetPropertyValue(_sqlGuidProperty, value); + } + + public object SqlValue + { + get => GetPropertyValue(_sqlValueProperty); + } + + public void SetToNullOfType(StorageType storageType) + { +#if NET6_0_OR_GREATER + _setToNullOfTypeMethod + .Invoke(_instance, BindingFlags.DoNotWrapExceptions, null, new object[] { (int)storageType }, null); +#else + _setToNullOfTypeMethod.Invoke(_instance, new object[] { (int)storageType }); +#endif + } + + private T GetPropertyValue(PropertyInfo property) + { +#if NET6_0_OR_GREATER + return (T)property.GetValue(_instance, BindingFlags.DoNotWrapExceptions, null, null, null); +#else + try + { + return (T)property.GetValue(_instance); + } + catch (TargetInvocationException e) + { + throw e.InnerException!; + } +#endif + } + + private void SetPropertyValue(PropertyInfo property, object value) + { +#if NET6_0_OR_GREATER + property.SetValue(_instance, value, BindingFlags.DoNotWrapExceptions, null, null, null); +#else + try + { + property.SetValue(_instance, value); + } + catch (TargetInvocationException e) + { + throw e.InnerException!; + } +#endif + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientFactoryTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientFactoryTest.cs index f0e8d39173..b88ae0a260 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientFactoryTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlClientFactoryTest.cs @@ -21,40 +21,34 @@ public void InstanceTest() public static readonly object[][] FactoryMethodTestData = { - new object[] { new Func(SqlClientFactory.Instance.CreateCommand), typeof(SqlCommand) }, - new object[] { new Func(SqlClientFactory.Instance.CreateCommandBuilder), typeof(SqlCommandBuilder) }, - new object[] { new Func(SqlClientFactory.Instance.CreateConnection), typeof(SqlConnection) }, - new object[] { new Func(SqlClientFactory.Instance.CreateConnectionStringBuilder), typeof(SqlConnectionStringBuilder) }, - new object[] { new Func(SqlClientFactory.Instance.CreateDataAdapter), typeof(SqlDataAdapter) }, - new object[] { new Func(SqlClientFactory.Instance.CreateParameter), typeof(SqlParameter) }, + new object[] { new Func(SqlClientFactory.Instance.CreateCommand), typeof(SqlCommand), false }, + new object[] { new Func(SqlClientFactory.Instance.CreateCommandBuilder), typeof(SqlCommandBuilder), false }, + new object[] { new Func(SqlClientFactory.Instance.CreateConnection), typeof(SqlConnection), false }, + new object[] { new Func(SqlClientFactory.Instance.CreateConnectionStringBuilder), typeof(SqlConnectionStringBuilder), false }, + new object[] { new Func(SqlClientFactory.Instance.CreateDataAdapter), typeof(SqlDataAdapter), false }, + new object[] { new Func(SqlClientFactory.Instance.CreateParameter), typeof(SqlParameter), false }, + new object[] { new Func(SqlClientFactory.Instance.CreateDataSourceEnumerator), typeof(Microsoft.Data.Sql.SqlDataSourceEnumerator), true }, }; [Theory] [MemberData(nameof(FactoryMethodTestData))] - public void FactoryMethodTest(Func factory, Type expectedType) + public void FactoryMethodTest(Func factory, Type expectedType, bool singleton) { object value1 = factory(); Assert.NotNull(value1); Assert.IsType(expectedType, value1); - object value2 = factory(); - Assert.NotNull(value2); - Assert.IsType(expectedType, value2); + if (!singleton) + { + object value2 = factory(); + Assert.NotNull(value2); + Assert.IsType(expectedType, value2); - Assert.NotSame(value1, value2); + Assert.NotSame(value1, value2); + } } #if NETFRAMEWORK - [Fact] - public void FactoryCreateDataSourceEnumerator() - { - // Unable to cover the in the FactoryMethodTest because the SqlDataSourceEnumerator is a singleton so, it's always the same. - object instance = SqlClientFactory.Instance.CreateDataSourceEnumerator(); - // SqlDataSourceEnumerator is not available for .NET core 3.1 and above, so the type check is only for .NET Framework. - Assert.IsType(instance); - Assert.NotNull(instance); - } - [Fact] public void FactoryGetService() { diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandTest.cs index 0a1a8e9ef5..c5e3b000dc 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlCommandTest.cs @@ -125,7 +125,7 @@ public void Constructor3() Assert.Null(cmd.Container); Assert.True(cmd.DesignTimeVisible); Assert.Null(cmd.Notification); -#if NETFRAMEWORK && !NETSTANDARDREFERNCE +#if NETFRAMEWORK // see https://github.com/dotnet/SqlClient/issues/17 Assert.True(cmd.NotificationAutoEnlist); #endif @@ -166,7 +166,7 @@ public void Constructor4() Assert.Null(cmd.Container); Assert.True(cmd.DesignTimeVisible); Assert.Null(cmd.Notification); -#if NETFRAMEWORK && !NETSTANDARDREFERNCE +#if NETFRAMEWORK // see https://github.com/dotnet/SqlClient/issues/17 Assert.True(cmd.NotificationAutoEnlist); #endif @@ -184,7 +184,7 @@ public void Constructor4() Assert.Null(cmd.Container); Assert.True(cmd.DesignTimeVisible); Assert.Null(cmd.Notification); -#if NETFRAMEWORK && !NETSTANDARDREFERNCE +#if NETFRAMEWORK // see https://github.com/dotnet/SqlClient/issues/17 Assert.True(cmd.NotificationAutoEnlist); #endif @@ -202,7 +202,7 @@ public void Constructor4() Assert.Null(cmd.Container); Assert.True(cmd.DesignTimeVisible); Assert.Null(cmd.Notification); -#if NETFRAMEWORK && !NETSTANDARDREFERNCE +#if NETFRAMEWORK // see https://github.com/dotnet/SqlClient/issues/17 Assert.True(cmd.NotificationAutoEnlist); #endif @@ -224,7 +224,7 @@ public void Clone() cmd.CommandType = CommandType.StoredProcedure; cmd.DesignTimeVisible = false; cmd.Notification = notificationReq; -#if NETFRAMEWORK && !NETSTANDARDREFERNCE +#if NETFRAMEWORK // see https://github.com/dotnet/SqlClient/issues/17 Assert.True(cmd.NotificationAutoEnlist); #endif @@ -240,7 +240,7 @@ public void Clone() Assert.Null(cmd.Connection); Assert.False(cmd.DesignTimeVisible); Assert.Same(notificationReq, cmd.Notification); -#if NETFRAMEWORK && !NETSTANDARDREFERNCE +#if NETFRAMEWORK // see https://github.com/dotnet/SqlClient/issues/17 Assert.True(cmd.NotificationAutoEnlist); #endif diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs index 8f16c09aa3..a164149a60 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs @@ -12,6 +12,7 @@ using System.Security; using System.Threading; using System.Threading.Tasks; +using Microsoft.SqlServer.TDS.PreLogin; using Microsoft.SqlServer.TDS.Servers; using Xunit; diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs index d1c3fd2d34..05b3ca5b48 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionStringBuilderTest.cs @@ -107,19 +107,34 @@ public void ConnectionStringTests(string connectionString) ExecuteConnectionStringTests(connectionString); } + public static readonly IEnumerable ConnectionStringTestsNetFx_TestCases = new[] + { + new object[] { "Connection Reset = false" }, + new object[] { "Context Connection = false" }, + new object[] { "Network Library = dbmssocn" }, + new object[] { "Network = dbnmpntw" }, + new object[] { "Net = dbmsrpcn" }, + new object[] { "TransparentNetworkIPResolution = false" }, + new object[] { "Transparent Network IP Resolution = true" }, + }; + [Theory] - [InlineData("Connection Reset = false")] - [InlineData("Context Connection = false")] - [InlineData("Network Library = dbmssocn")] - [InlineData("Network = dbnmpntw")] - [InlineData("Net = dbmsrpcn")] - [InlineData("TransparentNetworkIPResolution = false")] - [InlineData("Transparent Network IP Resolution = true")] - [SkipOnTargetFramework(~TargetFrameworkMonikers.NetFramework)] - public void ConnectionStringTestsNetFx(string connectionString) + [MemberData(nameof(ConnectionStringTestsNetFx_TestCases))] + #if NETFRAMEWORK + public void ConnectionStringTestsNetFx_OnNetFx_Success(string connectionString) { ExecuteConnectionStringTests(connectionString); } + #else + public void ConnectionStringTestsNetFx_OnNetCore_Throws(string connectionString) + { + // Act + Action action = () => _ = new SqlConnectionStringBuilder(connectionString); + + // Assert + Assert.Throws(action); + } + #endif [Fact] public void SetInvalidApplicationIntent_Throws() diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataRecordTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataRecordTest.cs index 87f6c167ec..0e748c5d74 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataRecordTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlDataRecordTest.cs @@ -8,6 +8,7 @@ using System.Data; using System.Data.SqlTypes; using Microsoft.Data.SqlClient.Server; +using Microsoft.SqlServer.Types; using Xunit; namespace Microsoft.Data.SqlClient.Tests @@ -318,6 +319,19 @@ public void GetChar_ThrowsNotSupported() Assert.Throws(() => record.GetChar(0)); } + [Theory] + [ClassData(typeof(GetUdtTypeTestData))] + public void GetUdt_ReturnsValue(Type udtType, object value, string serverTypeName) + { + SqlMetaData[] metadata = new SqlMetaData[] { new SqlMetaData(nameof(udtType.Name), SqlDbType.Udt, udtType, serverTypeName) }; + + SqlDataRecord record = new SqlDataRecord(metadata); + + record.SetValue(0, value); + + Assert.Equal(value.ToString(), record.GetValue(0).ToString()); + } + [Theory] [ClassData(typeof(GetXXXBadTypeTestData))] public void GetXXX_ThrowsIfBadType(Func getXXX) @@ -342,8 +356,8 @@ public void GetXXX_ReturnValue(SqlDbType dbType, object value, Func + { + public IEnumerator GetEnumerator() + { + yield return new object[] { typeof(SqlGeography), SqlGeography.Point(43, -81, 4326), "Geography" }; + yield return new object[] { typeof(SqlGeometry), SqlGeometry.Point(43, -81, 4326), "Geometry" }; + yield return new object[] { typeof(SqlHierarchyId), SqlHierarchyId.Parse("/"), "HierarchyId" }; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } + public class GetXXXCheckValueTestData : IEnumerable { public IEnumerator GetEnumerator() @@ -383,6 +412,10 @@ public IEnumerator GetEnumerator() yield return new object[] { SqlDbType.DateTime, DateTime.Now, new Func(r => r.GetDateTime(0)) }; yield return new object[] { SqlDbType.DateTimeOffset, new DateTimeOffset(DateTime.Now), new Func(r => r.GetDateTimeOffset(0)) }; yield return new object[] { SqlDbType.Time, TimeSpan.FromHours(1), new Func(r => r.GetTimeSpan(0)) }; + yield return new object[] { SqlDbType.Date, DateTime.Now.Date, new Func(r => r.GetDateTime(0)) }; + yield return new object[] { SqlDbType.Bit, bool.Parse(bool.TrueString), new Func(r => r.GetBoolean(0)) }; + yield return new object[] { SqlDbType.SmallDateTime, DateTime.Now, new Func(r => r.GetDateTime(0)) }; + yield return new object[] { SqlDbType.TinyInt, (byte)1, new Func(r => r.GetByte(0)) }; } IEnumerator IEnumerable.GetEnumerator() diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs index bce79cb6d1..ee05379870 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlErrorTest.cs @@ -16,7 +16,7 @@ public class SqlErrorTest "Connecting to a mirrored SQL Server instance using the MultiSubnetFailover connection option is not supported."; private const byte FATAL_ERROR_CLASS = 20; -#if !NET50_OR_LATER +#if NETFRAMEWORK [Fact] public static void SqlErrorSerializationTest() { diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlExceptionTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlExceptionTest.cs index 204ab379c1..85d3a02fb1 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 !NET6_0_OR_GREATER +#if NETFRAMEWORK [Fact] [ActiveIssue("12161", TestPlatforms.AnyUnix)] public static void SqlExcpetionSerializationTest() diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlMetaDataTest.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlMetaDataTest.cs index a9123e1582..dd6c228fd2 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlMetaDataTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlMetaDataTest.cs @@ -870,7 +870,7 @@ public void XmlConstructorWithNullObjectName_Throws() new object[] {SqlDbType.Bit, new SqlBinary(new byte[] { 1 })}, new object[] {SqlDbType.Decimal, new SqlBytes()}, new object[] {SqlDbType.Char, new TimeSpan(0, 0, 1)}, - new object[] {SqlDbType.UniqueIdentifier, new DateTimeOffset(new DateTime(0))}, + new object[] {SqlDbType.UniqueIdentifier, new DateTimeOffset(new DateTime(0), TimeSpan.Zero)}, new object[] {SqlDbType.DateTimeOffset, SqlGuid.Null}, new object[] {SqlDbType.Date, new SqlDateTime(DateTime.UtcNow)}, new object[] {SqlDbType.Bit, SqlXml.Null }, @@ -963,7 +963,7 @@ public void XmlConstructorWithNullObjectName_Throws() new object[] {SqlDbType.Image, new SqlBinary(new byte[] { 1 })}, new object[] {SqlDbType.Image, new SqlBytes(new byte[] { 1 })}, new object[] {SqlDbType.Time, new TimeSpan(0, 0, 1)}, - new object[] {SqlDbType.DateTimeOffset, new DateTimeOffset(new DateTime(0))}, + new object[] {SqlDbType.DateTimeOffset, new DateTimeOffset(new DateTime(0), TimeSpan.Zero)}, new object[] {SqlDbType.UniqueIdentifier, SqlGuid.Null}, new object[] {SqlDbType.UniqueIdentifier, Guid.Empty}, }; @@ -1019,7 +1019,7 @@ public void XmlConstructorWithNullObjectName_Throws() new object[] {SqlDbType.VarBinary, new byte[8001]}, new object[] {SqlDbType.Time, new TimeSpan(0, 0, 1)}, new object[] {SqlDbType.Time, new TimeSpan(TimeSpan.TicksPerDay - 1)}, - new object[] {SqlDbType.DateTimeOffset, new DateTimeOffset(new DateTime(0))}, + new object[] {SqlDbType.DateTimeOffset, new DateTimeOffset(new DateTime(0), TimeSpan.Zero)}, new object[] {SqlDbType.DateTimeOffset, new DateTimeOffset(DateTime.Now)}, new object[] {SqlDbType.UniqueIdentifier, SqlGuid.Null}, new object[] {SqlDbType.UniqueIdentifier, Guid.Empty}, diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs index 1ead74f58d..ef45bdbc7a 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs @@ -65,6 +65,5 @@ public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool ena public void Dispose() => _endpoint?.Stop(); public string ConnectionString { get; private set; } - } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/AKVUnitTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/AKVUnitTests.cs index 85192076fc..9374b3783c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/AKVUnitTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/AKVUnitTests.cs @@ -3,12 +3,10 @@ // See the LICENSE file in the project root for more information. using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; -using Azure.Identity; using Xunit; using Azure.Security.KeyVault.Keys; using System.Reflection; using System; -using System.Linq; using System.Collections.Generic; using System.Threading; using System.Diagnostics.Tracing; @@ -86,8 +84,7 @@ public static void TokenCredentialTest() Guid activityId = Trace.CorrelationManager.ActivityId = Guid.NewGuid(); using DataTestUtility.AKVEventListener AKVListener = new(); - ClientSecretCredential clientSecretCredential = new ClientSecretCredential(DataTestUtility.AKVTenantId, DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); - SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(clientSecretCredential); + SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(DataTestUtility.GetTokenCredential()); byte[] encryptedCek = akvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCek = akvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCek); @@ -104,8 +101,7 @@ public static void TokenCredentialRotationTest() // SqlClientCustomTokenCredential implements a legacy authentication callback to request the access token from the client-side. SqlColumnEncryptionAzureKeyVaultProvider oldAkvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new SqlClientCustomTokenCredential()); - ClientSecretCredential clientSecretCredential = new ClientSecretCredential(DataTestUtility.AKVTenantId, DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); - SqlColumnEncryptionAzureKeyVaultProvider newAkvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(clientSecretCredential); + SqlColumnEncryptionAzureKeyVaultProvider newAkvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(DataTestUtility.GetTokenCredential()); byte[] encryptedCekWithNewProvider = newAkvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCekWithOldProvider = oldAkvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCekWithNewProvider); @@ -129,15 +125,14 @@ public static void ReturnSpecifiedVersionOfKeyWhenItIsNotTheMostRecentVersion() { string keyName = keyPathUri.Segments[2]; string keyVersion = keyPathUri.Segments[3]; - ClientSecretCredential clientSecretCredential = new ClientSecretCredential(DataTestUtility.AKVTenantId, DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); - KeyClient keyClient = new KeyClient(vaultUri, clientSecretCredential); + KeyClient keyClient = new KeyClient(vaultUri, DataTestUtility.GetTokenCredential()); KeyVaultKey currentVersionKey = keyClient.GetKey(keyName); KeyVaultKey specifiedVersionKey = keyClient.GetKey(keyName, keyVersion); //If specified versioned key is the most recent version of the key then we cannot test. if (!KeyIsLatestVersion(specifiedVersionKey, currentVersionKey)) { - SqlColumnEncryptionAzureKeyVaultProvider azureKeyProvider = new SqlColumnEncryptionAzureKeyVaultProvider(clientSecretCredential); + SqlColumnEncryptionAzureKeyVaultProvider azureKeyProvider = new SqlColumnEncryptionAzureKeyVaultProvider(DataTestUtility.GetTokenCredential()); // Perform an operation to initialize the internal caches azureKeyProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVOriginalUrl, EncryptionAlgorithm, s_columnEncryptionKey); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtility.cs index 1c054f3769..3d3c717b31 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/TestFixtures/Setup/CertificateUtility.cs @@ -141,8 +141,7 @@ internal static X509Certificate2 CreateCertificate() private static async Task SetupAKVKeysAsync() { - ClientSecretCredential clientSecretCredential = new ClientSecretCredential(DataTestUtility.AKVTenantId, DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); - KeyClient keyClient = new KeyClient(DataTestUtility.AKVBaseUri, clientSecretCredential); + KeyClient keyClient = new KeyClient(DataTestUtility.AKVBaseUri, DataTestUtility.GetTokenCredential()); AsyncPageable keys = keyClient.GetPropertiesOfKeysAsync(); IAsyncEnumerator enumerator = keys.GetAsyncEnumerator(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/AADUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/AADUtility.cs index 6733b49b31..55ab5744e6 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/AADUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/AADUtility.cs @@ -7,25 +7,11 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using Microsoft.IdentityModel.Clients.ActiveDirectory; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { public static class AADUtility { - public static async Task AzureActiveDirectoryAuthenticationCallback(string authority, string resource, string scope) - { - var authContext = new AuthenticationContext(authority); - ClientCredential clientCred = new ClientCredential(DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); - AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred); - if (result == null) - { - throw new Exception($"Failed to retrieve an access token for {resource}"); - } - - return result.AccessToken; - } - public static async Task GetManagedIdentityToken(string clientId = null) => await new MockManagedIdentityTokenProvider().AcquireTokenAsync(clientId).ConfigureAwait(false); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs new file mode 100644 index 0000000000..4b6e7b087b --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.SqlServer.TDS.PreLogin; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests.DataCommon +{ + public class ConnectionTestParameters + { + private SqlConnectionEncryptOption _encryptionOption; + private TDSPreLoginTokenEncryptionType _encryptionType; + private string _hnic; + private string _cert; + private bool _result; + private bool _trustServerCert; + + public SqlConnectionEncryptOption Encrypt => _encryptionOption; + public bool TrustServerCertificate => _trustServerCert; + public string Certificate => _cert; + public string HostNameInCertificate => _hnic; + public bool TestResult => _result; + public TDSPreLoginTokenEncryptionType TdsEncryptionType => _encryptionType; + + public ConnectionTestParameters(TDSPreLoginTokenEncryptionType tdsEncryptionType, SqlConnectionEncryptOption encryptOption, bool trustServerCert, string cert, string hnic, bool result) + { + _encryptionOption = encryptOption; + _trustServerCert = trustServerCert; + _cert = cert; + _hnic = hnic; + _result = result; + _encryptionType = tdsEncryptionType; + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs new file mode 100644 index 0000000000..5a2e01a77c --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -0,0 +1,85 @@ +// 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.Collections.Generic; +using System.IO; +using Microsoft.SqlServer.TDS.PreLogin; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests.DataCommon +{ + public class ConnectionTestParametersData + { + private const int CASES = 30; + private string _empty = string.Empty; + // It was advised to store the client certificate in its own folder. + private static readonly string s_fullPathToCer = Path.Combine(Directory.GetCurrentDirectory(), "clientcert", "localhostcert.cer"); + private static readonly string s_mismatchedcert = Path.Combine(Directory.GetCurrentDirectory(), "clientcert", "mismatchedcert.cer"); + + private static readonly string s_hostName = System.Net.Dns.GetHostName(); + public static ConnectionTestParametersData Data { get; } = new ConnectionTestParametersData(); + public List ConnectionTestParametersList { get; set; } + + public static IEnumerable GetConnectionTestParameters() + { + for (int i = 0; i < CASES; i++) + { + yield return new object[] { Data.ConnectionTestParametersList[i] }; + } + } + + public ConnectionTestParametersData() + { + // Test cases possible field values for connection parameters: + // These combinations are based on the possible values of Encrypt, TrustServerCertificate, Certificate, HostNameInCertificate + /* + * TDSEncryption | Encrypt | TrustServerCertificate | Certificate | HNIC | TestResults + * ---------------------------------------------------------------------------------------------- + * Off | Optional | true | valid | valid name | true + * On | Mandatory | false | mismatched | empty | false + * Required | | x | ChainError? | wrong name? | + */ + ConnectionTestParametersList = new List + { + // TDSPreLoginTokenEncryptionType.Off + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Optional, false, _empty, _empty, true), + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Mandatory, false, _empty, _empty, false), + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Optional, true, _empty, _empty, true), + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Mandatory, true, _empty, _empty, true), + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Mandatory, false, s_fullPathToCer, _empty, true), + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Mandatory, true, s_fullPathToCer, _empty, true), + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Mandatory, false, _empty, s_hostName, false), + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Mandatory, true, _empty, s_hostName, true), + + // TDSPreLoginTokenEncryptionType.On + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Optional, false, _empty, _empty, false), + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Mandatory, false, _empty, _empty, false), + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Optional, true, _empty, _empty, true), + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Mandatory, true, _empty, _empty, true), + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Mandatory, false, s_fullPathToCer, _empty, true), + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Mandatory, true, s_fullPathToCer, _empty, true), + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Mandatory, false, _empty, s_hostName, false), + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Mandatory, true, _empty, s_hostName, true), + + // TDSPreLoginTokenEncryptionType.Required + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Optional, false, _empty, _empty, false), + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Mandatory, false, _empty, _empty, false), + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Optional, true, _empty, _empty, true), + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Mandatory, true, _empty, _empty, true), + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Mandatory, false, s_fullPathToCer, _empty, true), + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Mandatory, true, s_fullPathToCer, _empty, true), + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Mandatory, false, _empty, s_hostName, false), + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Mandatory, true, _empty, s_hostName, true), + + // Mismatched certificate test + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Mandatory, false, s_mismatchedcert, _empty, false), + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Mandatory, true, s_mismatchedcert, _empty, false), + new(TDSPreLoginTokenEncryptionType.Off, SqlConnectionEncryptOption.Mandatory, true, s_mismatchedcert, _empty, true), + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Mandatory, false, s_mismatchedcert, _empty, false), + new(TDSPreLoginTokenEncryptionType.On, SqlConnectionEncryptOption.Mandatory, true, s_mismatchedcert, _empty, true), + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Mandatory, false, s_mismatchedcert, _empty, false), + new(TDSPreLoginTokenEncryptionType.Required, SqlConnectionEncryptOption.Mandatory, true, s_mismatchedcert, _empty, true), + }; + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index d588761bdb..34fbacb218 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -11,17 +11,19 @@ using System.IO; using System.Linq; using System.Net; +using System.Net.NetworkInformation; using System.Net.Sockets; +using System.Runtime.InteropServices; using System.Security; +using System.Security.Principal; +using System.Text; using System.Threading; using System.Threading.Tasks; +using Azure.Core; +using Azure.Identity; using Microsoft.Data.SqlClient.TestUtilities; using Microsoft.Identity.Client; using Xunit; -using System.Net.NetworkInformation; -using System.Text; -using System.Security.Principal; -using System.Runtime.InteropServices; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { @@ -30,7 +32,6 @@ public static class DataTestUtility public static readonly string NPConnectionString = null; public static readonly string TCPConnectionString = null; public static readonly string TCPConnectionStringHGSVBS = null; - public static readonly string TCPConnectionStringAASVBS = null; public static readonly string TCPConnectionStringNoneVBS = null; public static readonly string TCPConnectionStringAASSGX = null; public static readonly string AADAuthorityURL = null; @@ -41,8 +42,6 @@ public static class DataTestUtility public static readonly string AKVUrl = null; public static readonly string AKVOriginalUrl = null; public static readonly string AKVTenantId = null; - public static readonly string AKVClientId = null; - public static readonly string AKVClientSecret = null; public static readonly string LocalDbAppName = null; public static readonly string LocalDbSharedInstanceName = null; public static List AEConnStrings = new List(); @@ -78,10 +77,6 @@ public static class DataTestUtility public const string AKVEventSourceName = "Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.EventSource"; private const string ManagedNetworkingAppContextSwitch = "Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows"; - // uap constant - const long APPMODEL_ERROR_NO_PACKAGE = 15700L; - public static readonly bool IsRunningAsUWPApp = RunningAsUWPApp(); - private static Dictionary AvailableDatabases; private static BaseEventListener TraceListener; @@ -144,7 +139,6 @@ static DataTestUtility() NPConnectionString = c.NPConnectionString; TCPConnectionString = c.TCPConnectionString; TCPConnectionStringHGSVBS = c.TCPConnectionStringHGSVBS; - TCPConnectionStringAASVBS = c.TCPConnectionStringAASVBS; TCPConnectionStringNoneVBS = c.TCPConnectionStringNoneVBS; TCPConnectionStringAASSGX = c.TCPConnectionStringAASSGX; AADAuthorityURL = c.AADAuthorityURL; @@ -194,8 +188,6 @@ static DataTestUtility() } AKVTenantId = c.AzureKeyVaultTenantId; - AKVClientId = c.AzureKeyVaultClientId; - AKVClientSecret = c.AzureKeyVaultClientSecret; if (EnclaveEnabled) { @@ -205,11 +197,6 @@ static DataTestUtility() AEConnStringsSetup.Add(TCPConnectionStringHGSVBS); } - if (!string.IsNullOrEmpty(TCPConnectionStringAASVBS)) - { - AEConnStrings.Add(TCPConnectionStringAASVBS); - } - if (!string.IsNullOrEmpty(TCPConnectionStringNoneVBS)) { AEConnStrings.Add(TCPConnectionStringNoneVBS); @@ -458,7 +445,14 @@ public static bool IsNotAzureServer() // Ref: https://feedback.azure.com/forums/307516-azure-synapse-analytics/suggestions/17858869-support-always-encrypted-in-sql-data-warehouse public static bool IsAKVSetupAvailable() { - return !string.IsNullOrEmpty(AKVUrl) && !string.IsNullOrEmpty(AKVClientId) && !string.IsNullOrEmpty(AKVClientSecret) && !string.IsNullOrEmpty(AKVTenantId) && IsNotAzureSynapse(); + return !string.IsNullOrEmpty(AKVUrl) && !string.IsNullOrEmpty(UserManagedIdentityClientId) && !string.IsNullOrEmpty(AKVTenantId) && IsNotAzureSynapse(); + } + + private static readonly DefaultAzureCredential s_defaultCredential = new(new DefaultAzureCredentialOptions { ManagedIdentityClientId = UserManagedIdentityClientId }); + + public static TokenCredential GetTokenCredential() + { + return s_defaultCredential; } public static bool IsTargetReadyForAeWithKeyStore() @@ -473,7 +467,7 @@ public static bool IsTargetReadyForAeWithKeyStore() public static bool IsSupportingDistributedTransactions() { -#if NET7_0_OR_GREATER +#if NET8_0_OR_GREATER return OperatingSystem.IsWindows() && System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture != System.Runtime.InteropServices.Architecture.X86 && IsNotAzureServer(); #elif NETFRAMEWORK return IsNotAzureServer(); @@ -487,8 +481,8 @@ public static bool IsSupportingDistributedTransactions() public static bool IsNotUsingManagedSNIOnWindows() => !UseManagedSNIOnWindows; public static bool IsUsingNativeSNI() => -#if !NETFRAMEWORK - DataTestUtility.IsNotUsingManagedSNIOnWindows(); +#if NET6_0_OR_GREATER + IsNotUsingManagedSNIOnWindows(); #else true; #endif @@ -678,10 +672,6 @@ public static string GetUserIdentityAccessToken() public static bool IsAccessTokenSetup() => !string.IsNullOrEmpty(GetAccessToken()); - public static bool IsSystemIdentityTokenSetup() => !string.IsNullOrEmpty(GetSystemIdentityAccessToken()); - - public static bool IsUserIdentityTokenSetup() => !string.IsNullOrEmpty(GetUserIdentityAccessToken()); - public static bool IsFileStreamSetup() => !string.IsNullOrEmpty(FileStreamDirectory) && IsNotAzureServer() && IsNotAzureSynapse(); private static bool CheckException(Exception ex, string exceptionMessage, bool innerExceptionMustBeNull) where TException : Exception @@ -782,58 +772,6 @@ public static TException ExpectFailure(Action actionThatFails, strin } } - public static TException ExpectFailure(Action actionThatFails, string exceptionMessage = null, string innerExceptionMessage = null, bool innerInnerExceptionMustBeNull = false) where TException : Exception where TInnerException : Exception - { - try - { - actionThatFails(); - Assert.Fail("ERROR: Did not get expected exception"); - return null; - } - catch (Exception ex) - { - if ((CheckException(ex, exceptionMessage, false)) && (CheckException(ex.InnerException, innerExceptionMessage, innerInnerExceptionMustBeNull))) - { - return (ex as TException); - } - else - { - throw; - } - } - } - - public static TException ExpectFailure(Action actionThatFails, string exceptionMessage = null, string innerExceptionMessage = null, string innerInnerExceptionMessage = null, bool innerInnerInnerExceptionMustBeNull = false) where TException : Exception where TInnerException : Exception where TInnerInnerException : Exception - { - try - { - actionThatFails(); - Assert.Fail("ERROR: Did not get expected exception"); - return null; - } - catch (Exception ex) - { - if ((CheckException(ex, exceptionMessage, false)) && (CheckException(ex.InnerException, innerExceptionMessage, false)) && (CheckException(ex.InnerException.InnerException, innerInnerExceptionMessage, innerInnerInnerExceptionMustBeNull))) - { - return (ex as TException); - } - else - { - throw; - } - } - } - - public static void ExpectAsyncFailure(Func actionThatFails, string exceptionMessage = null, bool innerExceptionMustBeNull = false) where TException : Exception - { - ExpectFailure(() => actionThatFails().Wait(), null, exceptionMessage, innerExceptionMustBeNull); - } - - public static void ExpectAsyncFailure(Func actionThatFails, string exceptionMessage = null, string innerExceptionMessage = null, bool innerInnerExceptionMustBeNull = false) where TException : Exception where TInnerException : Exception - { - ExpectFailure(() => actionThatFails().Wait(), null, exceptionMessage, innerExceptionMessage, innerInnerExceptionMustBeNull); - } - public static string GenerateObjectName() { return string.Format("TEST_{0}{1}{2}", Environment.GetEnvironmentVariable("ComputerName"), Environment.TickCount, Guid.NewGuid()).Replace('-', '_'); @@ -1095,44 +1033,5 @@ public static string GetMachineFQDN(string hostname) } return fqdn.ToString(); } - - public static bool IsNotLocalhost() - { - // get the tcp connection string - SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); - - string hostname = ""; - - // parse the datasource - ParseDataSource(builder.DataSource, out hostname, out _, out _); - - // hostname must not be localhost, ., 127.0.0.1 nor ::1 - return !(new string[] { "localhost", ".", "127.0.0.1", "::1" }).Contains(hostname.ToLowerInvariant()); - - } - - private static bool RunningAsUWPApp() - { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return false; - } - else - { - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName); - - { - int length = 0; - StringBuilder sb = new(0); - _ = GetCurrentPackageFullName(ref length, sb); - - sb = new StringBuilder(length); - int result = GetCurrentPackageFullName(ref length, sb); - - return result != APPMODEL_ERROR_NO_PACKAGE; - } - } - } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/SqlClientCustomTokenCredential.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/SqlClientCustomTokenCredential.cs index c83883fca1..fa57a93697 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/SqlClientCustomTokenCredential.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/SqlClientCustomTokenCredential.cs @@ -3,20 +3,20 @@ // See the LICENSE file in the project root for more information. using System; -using System.IdentityModel.Tokens.Jwt; +using System.Collections.Concurrent; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Azure.Core; -using Microsoft.IdentityModel.Clients.ActiveDirectory; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; +using Azure.Identity; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { public class SqlClientCustomTokenCredential : TokenCredential { + private const string DEFAULT_PREFIX = "/.default"; + string _authority = ""; string _resource = ""; string _akvUrl = ""; @@ -70,40 +70,8 @@ private async Task AcquireTokenAsync() _akvUrl = DataTestUtility.AKVUrl; } - string strAccessToken = await AzureActiveDirectoryAuthenticationCallback(_authority, _resource); - DateTime expiryTime = InterceptAccessTokenForExpiry(strAccessToken); - return new AccessToken(strAccessToken, new DateTimeOffset(expiryTime)); - } - - private DateTime InterceptAccessTokenForExpiry(string accessToken) - { - if (null == accessToken) - { - throw new ArgumentNullException(accessToken); - } - - var jwtHandler = new JwtSecurityTokenHandler(); - var jwtOutput = string.Empty; - - // Check Token Format - if (!jwtHandler.CanReadToken(accessToken)) - throw new FormatException(accessToken); - - JwtSecurityToken token = jwtHandler.ReadJwtToken(accessToken); - - // Re-serialize the Token Headers to just Key and Values - var jwtHeader = JsonConvert.SerializeObject(token.Header.Select(h => new { h.Key, h.Value })); - jwtOutput = $"{{\r\n\"Header\":\r\n{JToken.Parse(jwtHeader)},"; - - // Re-serialize the Token Claims to just Type and Values - var jwtPayload = JsonConvert.SerializeObject(token.Claims.Select(c => new { c.Type, c.Value })); - jwtOutput += $"\r\n\"Payload\":\r\n{JToken.Parse(jwtPayload)}\r\n}}"; - - // Output the whole thing to pretty JSON object formatted. - string jToken = JToken.Parse(jwtOutput).ToString(Formatting.Indented); - JToken payload = JObject.Parse(jToken).GetValue("Payload"); - - return new DateTime(1970, 1, 1).AddSeconds((long)payload[4]["Value"]); + AccessToken accessToken = await AzureActiveDirectoryAuthenticationCallback(_authority, _resource); + return accessToken; } private static string ValidateChallenge(string challenge) @@ -127,16 +95,18 @@ private static string ValidateChallenge(string challenge) /// Authorization URL /// Resource /// - public static async Task AzureActiveDirectoryAuthenticationCallback(string authority, string resource) + public static async Task AzureActiveDirectoryAuthenticationCallback(string authority, string resource) { - var authContext = new AuthenticationContext(authority); - ClientCredential clientCred = new ClientCredential(DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); - AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred); - if (result == null) - { - throw new InvalidOperationException($"Failed to retrieve an access token for {resource}"); - } - return result.AccessToken; + using CancellationTokenSource cts = new(); + cts.CancelAfter(30000); // Hard coded for tests + string[] scopes = new string[] { resource + DEFAULT_PREFIX }; + TokenRequestContext tokenRequestContext = new(scopes); + int separatorIndex = authority.LastIndexOf('/'); + string authorityHost = authority.Remove(separatorIndex + 1); + string audience = authority.Substring(separatorIndex + 1); + TokenCredentialOptions tokenCredentialOptions = new TokenCredentialOptions() { AuthorityHost = new Uri(authorityHost) }; + AccessToken accessToken = await DataTestUtility.GetTokenCredential().GetTokenAsync(tokenRequestContext, cts.Token).ConfigureAwait(false); + return accessToken; } } } 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 da3f55dfc1..8962d5ab15 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 @@ -12,8 +12,9 @@ $(DefineConstants);NETFRAMEWORK $(ObjFolder)$(Configuration).$(Platform).$(AssemblyName) $(BinFolder)$(Configuration).$(Platform).$(AssemblyName) + true - + @@ -29,7 +30,7 @@ TCECryptoNativeBaselineRsa.txt - + @@ -163,6 +164,7 @@ + @@ -202,6 +204,7 @@ + @@ -254,7 +257,7 @@ - + @@ -267,6 +270,8 @@ + + @@ -284,6 +289,7 @@ + @@ -307,7 +313,6 @@ - @@ -332,26 +337,35 @@ - - - - + + PreserveNewest + %(Filename)%(Extension) + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + Always diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTest.cs index fc358acb05..d8a402236e 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTest.cs @@ -32,7 +32,7 @@ public class CertificateTest : IDisposable // InstanceName will get replaced with an instance name in the connection string private static string InstanceName = "MSSQLSERVER"; - // InstanceNamePrefix will get replaced with MSSQL$ is there is an instance name in connection string + // s_instanceNamePrefix will get replaced with MSSQL$ is there is an instance name in connection string private static string InstanceNamePrefix = ""; // SlashInstance is used to override IPV4 and IPV6 defined about so it includes an instance name diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs new file mode 100644 index 0000000000..9cfc1c71bb --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -0,0 +1,269 @@ +// 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.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; +using System.Security.Principal; +using System.ServiceProcess; +using System.Text; +using Microsoft.Data.SqlClient.ManualTesting.Tests.DataCommon; +using Microsoft.Win32; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public class CertificateTestWithTdsServer : IDisposable + { + private static readonly string s_fullPathToPowershellScript = Path.Combine(Directory.GetCurrentDirectory(), "makepfxcert.ps1"); + private static readonly string s_fullPathToCleanupPowershellScript = Path.Combine(Directory.GetCurrentDirectory(), "removecert.ps1"); + private static readonly string s_fullPathToPfx = Path.Combine(Directory.GetCurrentDirectory(), "localhostcert.pfx"); + private static readonly string s_fullPathTothumbprint = Path.Combine(Directory.GetCurrentDirectory(), "thumbprint.txt"); + private static readonly string s_fullPathToClientCert = Path.Combine(Directory.GetCurrentDirectory(), "clientcert"); + private static bool s_windowsAdmin = true; + private static string s_instanceName = "MSSQLSERVER"; + // s_instanceNamePrefix will get replaced with MSSQL$ is there is an instance name in the connection string + private static string s_instanceNamePrefix = ""; + private const string LocalHost = "localhost"; + + public CertificateTestWithTdsServer() + { + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); + Assert.True(DataTestUtility.ParseDataSource(builder.DataSource, out string hostname, out _, out string instanceName)); + + if (!string.IsNullOrEmpty(instanceName)) + { + s_instanceName = instanceName; + s_instanceNamePrefix = "MSSQL$"; + } + + // Confirm that user has elevated access on Windows + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + using WindowsIdentity identity = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new(identity); + if (principal.IsInRole(WindowsBuiltInRole.Administrator)) + s_windowsAdmin = true; + else + s_windowsAdmin = false; + } + + if (!Directory.Exists(s_fullPathToClientCert)) + { + Directory.CreateDirectory(s_fullPathToClientCert); + } + + RunPowershellScript(s_fullPathToPowershellScript); + } + + private static bool IsLocalHost() + { + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); + Assert.True(DataTestUtility.ParseDataSource(builder.DataSource, out string hostname, out _, out _)); + return LocalHost.Equals(hostname, StringComparison.OrdinalIgnoreCase); + } + + private static bool AreConnStringsSetup() => DataTestUtility.AreConnStringsSetup(); + private static bool IsNotAzureServer() => DataTestUtility.IsNotAzureServer(); + private static bool UseManagedSNIOnWindows() => DataTestUtility.UseManagedSNIOnWindows; + + private static string ForceEncryptionRegistryPath + { + get + { + if (DataTestUtility.IsSQL2022()) + { + return $@"SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL16.{s_instanceName}\MSSQLSERVER\SuperSocketNetLib"; + } + if (DataTestUtility.IsSQL2019()) + { + return $@"SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL15.{s_instanceName}\MSSQLSERVER\SuperSocketNetLib"; + } + if (DataTestUtility.IsSQL2016()) + { + return $@"SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL14.{s_instanceName}\MSSQLSERVER\SuperSocketNetLib"; + } + return string.Empty; + } + } + + [ConditionalTheory(nameof(AreConnStringsSetup), nameof(IsNotAzureServer), nameof(IsLocalHost))] + [MemberData(nameof(ConnectionTestParametersData.GetConnectionTestParameters), MemberType = typeof(ConnectionTestParametersData))] + [PlatformSpecific(TestPlatforms.Windows)] + public void BeginWindowsConnectionTest(ConnectionTestParameters connectionTestParameters) + { + if (!s_windowsAdmin) + { + Assert.Fail("User needs to have elevated access for these set of tests"); + } + + ConnectionTest(connectionTestParameters); + } + + [ConditionalTheory(nameof(AreConnStringsSetup), nameof(IsNotAzureServer), nameof(IsLocalHost))] + [MemberData(nameof(ConnectionTestParametersData.GetConnectionTestParameters), MemberType = typeof(ConnectionTestParametersData))] + [PlatformSpecific(TestPlatforms.Linux)] + public void BeginLinuxConnectionTest(ConnectionTestParameters connectionTestParameters) + { + ConnectionTest(connectionTestParameters); + } + + private void ConnectionTest(ConnectionTestParameters connectionTestParameters) + { + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); + + // The TestTdsServer does not validate the user name and password, so we can use any value if they are not defined. + string userId = string.IsNullOrWhiteSpace(builder.UserID) ? "user" : builder.UserID; + string password = string.IsNullOrWhiteSpace(builder.Password) ? "password" : builder.Password; + + using TestTdsServer server = TestTdsServer.StartTestServer(enableFedAuth: false, enableLog: false, connectionTimeout: 15, + methodName: "", new X509Certificate2(s_fullPathToPfx, "nopassword", X509KeyStorageFlags.UserKeySet), + encryptionType: connectionTestParameters.TdsEncryptionType); + + builder = new(server.ConnectionString) + { + UserID = userId, + Password = password, + TrustServerCertificate = connectionTestParameters.TrustServerCertificate, + Encrypt = connectionTestParameters.Encrypt, + }; + + if (!string.IsNullOrEmpty(connectionTestParameters.Certificate)) + { + builder.ServerCertificate = connectionTestParameters.Certificate; + } + + if (!string.IsNullOrEmpty(connectionTestParameters.HostNameInCertificate)) + { + builder.HostNameInCertificate = connectionTestParameters.HostNameInCertificate; + } + + using SqlConnection connection = new(builder.ConnectionString); + try + { + connection.Open(); + Assert.Equal(connectionTestParameters.TestResult, (connection.State == ConnectionState.Open)); + } + catch (Exception) + { + Assert.False(connectionTestParameters.TestResult); + } + } + + private static void RunPowershellScript(string script) + { + string currentDirectory = Directory.GetCurrentDirectory(); + string powerShellCommand = "powershell.exe"; + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + powerShellCommand = "pwsh"; + } + + if (File.Exists(script)) + { + StringBuilder output = new(); + Process proc = new() + { + StartInfo = + { + FileName = powerShellCommand, + RedirectStandardError = true, + RedirectStandardOutput = true, + UseShellExecute = false, + Arguments = $"{script} -OutDir {currentDirectory} > result.txt", + CreateNoWindow = false, + Verb = "runas" + } + }; + + proc.EnableRaisingEvents = true; + + proc.OutputDataReceived += new DataReceivedEventHandler((sender, e) => + { + if (e.Data != null) + { + output.AppendLine(e.Data); + } + }); + + proc.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => + { + if (e.Data != null) + { + output.AppendLine(e.Data); + } + }); + + proc.Start(); + + proc.BeginOutputReadLine(); + proc.BeginErrorReadLine(); + + if (!proc.WaitForExit(60000)) + { + proc.Kill(); + proc.WaitForExit(2000); + throw new Exception($"Could not generate certificate. Error output: {output}"); + } + } + else + { + throw new Exception($"Could not find makepfxcert.ps1"); + } + } + + private void RemoveCertificate() + { + string thumbprint = File.ReadAllText(s_fullPathTothumbprint); + using X509Store certStore = new(StoreName.Root, StoreLocation.LocalMachine); + certStore.Open(OpenFlags.ReadWrite); + X509Certificate2Collection certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false); + if (certCollection.Count > 0) + { + certStore.Remove(certCollection[0]); + } + certStore.Close(); + + File.Delete(s_fullPathTothumbprint); + Directory.Delete(s_fullPathToClientCert, true); + } + + private static void RemoveForceEncryptionFromRegistryPath(string registryPath) + { + RegistryKey key = Registry.LocalMachine.OpenSubKey(registryPath, true); + key?.SetValue("ForceEncryption", 0, RegistryValueKind.DWord); + key?.SetValue("Certificate", "", RegistryValueKind.String); + ServiceController sc = new($"{s_instanceNamePrefix}{s_instanceName}"); + sc.Stop(); + sc.WaitForStatus(ServiceControllerStatus.Stopped); + sc.Start(); + sc.WaitForStatus(ServiceControllerStatus.Running); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (disposing && !string.IsNullOrEmpty(s_fullPathTothumbprint)) + { + RemoveCertificate(); + RemoveForceEncryptionFromRegistryPath(ForceEncryptionRegistryPath); + } + } + else + { + RunPowershellScript(s_fullPathToCleanupPowershellScript); + } + } + } +} 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 60260fe79f..bf26f84018 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectivityTests/ConnectivityTest.cs @@ -474,5 +474,29 @@ public static void SqlPasswordConnectionTest() using SqlConnection sqlConnection = new(b.ConnectionString); sqlConnection.Open(); } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] + public static void ConnectionFireInfoMessageEventOnUserErrorsShouldSucceed() + { + using (var connection = new SqlConnection(DataTestUtility.TCPConnectionString)) + { + string command = "print"; + string commandParam = "OK"; + + connection.FireInfoMessageEventOnUserErrors = true; + + connection.InfoMessage += (sender, args) => + { + Assert.Equal(commandParam, args.Message); + }; + + connection.Open(); + + using SqlCommand cmd = connection.CreateCommand(); + cmd.CommandType = System.Data.CommandType.Text; + cmd.CommandText = $"{command} '{commandParam}'"; + cmd.ExecuteNonQuery(); + } + } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderStreamsTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderStreamsTest.cs index 3f16a3a138..3902f812fc 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderStreamsTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderStreamsTest.cs @@ -472,7 +472,7 @@ public static void InvalidCastExceptionStream(CommandBehavior behavior, Accessor } } -#if NETCOREAPP +#if NET6_0_OR_GREATER [ConditionalFact(typeof(DataTestUtility),nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] public static async void ReadAsyncContentsCompletes() { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs index 9b8e7476e4..b1ba557562 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ExceptionTest/ConnectionExceptionTest.cs @@ -176,25 +176,6 @@ public void NamedPipeInvalidConnStringTest() OpenBadConnection(builder.ConnectionString, invalidConnStringError); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsRunningAsUWPApp))] - public static void LocalDBNotSupportedOnUapTest() - { - SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(@$"server=(localdb)\{DataTestUtility.LocalDbAppName}") - { - IntegratedSecurity = true, - ConnectTimeout = 2 - }; - - Assert.Throws(() => - { - using (SqlConnection conn = new SqlConnection(builder.ConnectionString)) - { - conn.Open(); - } - }); - } - - private void GenerateConnectionException(string connectionString) { using (SqlConnection sqlConnection = new SqlConnection(connectionString)) 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 205b9d33f1..61474ece7f 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/InstanceNameTest/InstanceNameTest.cs @@ -86,7 +86,8 @@ public static void ConnectManagedWithInstanceNameTest(bool useMultiSubnetFailove } } -#if NETCOREAPP +#if NET6_0_OR_GREATER + [ActiveIssue("27824")] // When specifying instance name and port number, this method call always returns false [ConditionalFact(nameof(IsSPNPortNumberTestForTCP))] public static void PortNumberInSPNTestForTCP() { 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 3b71cbf851..378a32c07c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/ParametersTest.cs @@ -9,6 +9,9 @@ using System.Data.SqlTypes; using System.Threading; using Xunit; +#if NET6_0_OR_GREATER +using Microsoft.Data.SqlClient.Server; +#endif namespace Microsoft.Data.SqlClient.ManualTesting.Tests { @@ -306,6 +309,56 @@ public static void TestParametersWithDatatablesTVPInsert() } } +#if NET6_0_OR_GREATER + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] + public static void TestDateOnlyTVPDataTable_CommandSP() + { + string tableTypeName = "[dbo]." + DataTestUtility.GetUniqueNameForSqlServer("UDTTTestDateOnlyTVP"); + string spName = DataTestUtility.GetUniqueNameForSqlServer("spTestDateOnlyTVP"); + SqlConnection connection = new(s_connString); + try + { + connection.Open(); + using (SqlCommand cmd = connection.CreateCommand()) + { + cmd.CommandType = CommandType.Text; + cmd.CommandText = $"CREATE TYPE {tableTypeName} AS TABLE ([DateColumn] date NULL, [TimeColumn] time NULL)"; + cmd.ExecuteNonQuery(); + cmd.CommandText = $"CREATE PROCEDURE {spName} (@dates {tableTypeName} READONLY) AS SELECT COUNT(*) FROM @dates"; + cmd.ExecuteNonQuery(); + } + using (SqlCommand cmd = connection.CreateCommand()) + { + cmd.CommandText = spName; + cmd.CommandType = CommandType.StoredProcedure; + + DataTable dtTest = new(); + dtTest.Columns.Add(new DataColumn("DateColumn", typeof(DateOnly))); + dtTest.Columns.Add(new DataColumn("TimeColumn", typeof(TimeOnly))); + var dataRow = dtTest.NewRow(); + dataRow["DateColumn"] = new DateOnly(2023, 11, 15); + dataRow["TimeColumn"] = new TimeOnly(12, 30, 45); + dtTest.Rows.Add(dataRow); + + cmd.Parameters.Add(new SqlParameter + { + ParameterName = "@dates", + SqlDbType = SqlDbType.Structured, + TypeName = tableTypeName, + Value = dtTest, + }); + + cmd.ExecuteNonQuery(); + } + } + finally + { + DataTestUtility.DropStoredProcedure(connection, spName); + DataTestUtility.DropUserDefinedType(connection, tableTypeName); + } + } +#endif + #region Scaled Decimal Parameter & TVP Test [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] [InlineData("CAST(1.0 as decimal(38, 37))", "1.0000000000000000000000000000")] diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/RetryLogicConfigHelper.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/RetryLogicConfigHelper.cs index 7162c4dcaa..21370c08e7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/RetryLogicConfigHelper.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/RetryLogic/RetryLogicConfigHelper.cs @@ -73,7 +73,7 @@ public static object CreateLoader(RetryLogicConfigs cnnConfig, RetryLogicConfigs public static void ApplyContextSwitchByManager(string name, bool value) { -#if NETCOREAPP +#if NET6_0_OR_GREATER var appCtxType = s_sqlClientAssembly.GetType(AppCtxCfgTypeName); var appCtxObj = Activator.CreateInstance(appCtxType); SetValue(appCtxObj, appCtxType, "Value", string.Concat(name, "=", value)); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/WriteToServerTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/WriteToServerTest.cs new file mode 100644 index 0000000000..343a7bcfe2 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/SqlBulkCopyTest/WriteToServerTest.cs @@ -0,0 +1,138 @@ +// 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.Threading.Tasks; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public class WriteToServerTest + { + private readonly string _connectionString = null; + private readonly string _tableName1 = DataTestUtility.GetUniqueName("Bulk1"); + private readonly string _tableName2 = DataTestUtility.GetUniqueName("Bulk2"); + + public WriteToServerTest() + { + _connectionString = (new SqlConnectionStringBuilder(DataTestUtility.TCPConnectionString) { MultipleActiveResultSets = true }).ConnectionString; + } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse))] + public async Task WriteToServerWithDbReaderFollowedByWriteToServerWithDataRowsShouldSucceed() + { + try + { + SetupTestTables(); + + DataRow[] dataRows = WriteToServerTest.CreateDataRows(); + Assert.Equal(4, dataRows.Length); // Verify the number of rows created + + DoBulkCopy(dataRows); + await DoBulkCopyAsync(dataRows); + } + finally + { + RemoveTestTables(); + } + } + + private void SetupTestTables() + { + // Create the source table and insert some data + using SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString); + connection.Open(); + + DataTestUtility.DropTable(connection, _tableName1); + DataTestUtility.DropTable(connection, _tableName2); + + using SqlCommand command = connection.CreateCommand(); + + Helpers.TryExecute(command, $"create table {_tableName1} (Id int identity primary key, FirstName nvarchar(50), LastName nvarchar(50))"); + Helpers.TryExecute(command, $"create table {_tableName2} (Id int identity primary key, FirstName nvarchar(50), LastName nvarchar(50))"); + + Helpers.TryExecute(command, $"insert into {_tableName1} (Firstname, LastName) values ('John', 'Doe')"); + Helpers.TryExecute(command, $"insert into {_tableName1} (Firstname, LastName) values ('Johnny', 'Smith')"); + Helpers.TryExecute(command, $"insert into {_tableName1} (Firstname, LastName) values ('Jenny', 'Doe')"); + Helpers.TryExecute(command, $"insert into {_tableName1} (Firstname, LastName) values ('Jane', 'Smith')"); + } + + private static DataRow[] CreateDataRows() + { + DataTable table = new DataTable(); + table.Columns.Add("Id", typeof(int)); + table.Columns.Add("FirstName", typeof(string)); + table.Columns.Add("LastName", typeof(string)); + + table.Rows.Add(null, "Aaron", "Washington"); + table.Rows.Add(null, "Barry", "Mannilow"); + table.Rows.Add(null, "Charles", "Babage"); + table.Rows.Add(null, "Dean", "Snipes"); + + return table.Select(); + } + + private void RemoveTestTables() + { + // Simplify the using statement in a small block of code + using SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString); + connection.Open(); + + DataTestUtility.DropTable(connection, _tableName1); + DataTestUtility.DropTable(connection, _tableName2); + } + + private void DoBulkCopy(DataRow[] dataRows) + { + using SqlConnection connection = new SqlConnection(_connectionString); + connection.Open(); + + using SqlCommand command = connection.CreateCommand(); + command.CommandText = $"select * from {_tableName1}"; + + using IDataReader reader = command.ExecuteReader(); + + using SqlBulkCopy bulkCopy = new SqlBulkCopy(connection); + + bulkCopy.DestinationTableName = _tableName2; + + BulkCopy(bulkCopy, reader, dataRows); + } + + private async Task DoBulkCopyAsync(DataRow[] dataRows) + { + // Test should be run with MARS enabled + using SqlConnection connection = new SqlConnection(_connectionString); + await connection.OpenAsync(); + + using SqlCommand command = connection.CreateCommand(); + command.CommandText = $"select * from {_tableName1}"; + + using IDataReader reader = await command.ExecuteReaderAsync(); + + using SqlBulkCopy bulkCopy = new SqlBulkCopy(connection); + + bulkCopy.DestinationTableName = _tableName2; + + await BulkCopyAsync(bulkCopy, reader, dataRows); + } + + private static void BulkCopy(SqlBulkCopy bulkCopy, IDataReader reader, DataRow[] dataRows) + { + bulkCopy.WriteToServer(reader); + Assert.Equal(dataRows.Length, bulkCopy.RowsCopied); // Verify the number of rows copied from the reader + bulkCopy.WriteToServer(dataRows); + Assert.Equal(dataRows.Length, bulkCopy.RowsCopied); // Verify the number of rows copied from the reader + } + + private static async Task BulkCopyAsync(SqlBulkCopy bulkCopy, IDataReader reader, DataRow[] dataRows) + { + await bulkCopy.WriteToServerAsync(reader); + Assert.Equal(dataRows.Length, bulkCopy.RowsCopied); // Verify the number of rows copied from the reader + await bulkCopy.WriteToServerAsync(dataRows); + Assert.Equal(dataRows.Length, bulkCopy.RowsCopied); // Verify the number of rows copied from the reader + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/TransactionTest/DistributedTransactionTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/TransactionTest/DistributedTransactionTest.cs index dc04ea56ae..658104e193 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/TransactionTest/DistributedTransactionTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/TransactionTest/DistributedTransactionTest.cs @@ -8,7 +8,7 @@ using System.Transactions; using Xunit; -#if NET7_0_OR_GREATER +#if NET8_0_OR_GREATER namespace Microsoft.Data.SqlClient.ManualTesting.Tests { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj index e525bdeda3..941b08588c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Address/Address.csproj @@ -11,7 +11,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Circle/Circle.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Circle/Circle.csproj index 750ae10973..93137d1883 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Circle/Circle.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Circle/Circle.csproj @@ -11,7 +11,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Shapes/Shapes.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Shapes/Shapes.csproj index d2b894a83d..596f7ffe74 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Shapes/Shapes.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Shapes/Shapes.csproj @@ -11,7 +11,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Utf8String/Utf8String.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Utf8String/Utf8String.csproj index 4b520c0286..ec1229e0e7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Utf8String/Utf8String.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UDTs/Utf8String/Utf8String.csproj @@ -11,7 +11,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UdtDateTimeOffsetTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UdtDateTimeOffsetTest.cs new file mode 100644 index 0000000000..a09d00895c --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/UdtTest/UdtDateTimeOffsetTest.cs @@ -0,0 +1,143 @@ +// 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 Microsoft.Data.SqlClient.Server; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public class DateTimeOffsetList : SqlDataRecord + { + public DateTimeOffsetList(DateTimeOffset dateTimeOffset) + : base(new SqlMetaData("dateTimeOffset", SqlDbType.DateTimeOffset, 0, 1)) // this is using scale 1 + { + this.SetValues(dateTimeOffset); + } + } + + public class DateTimeOffsetVariableScale : SqlDataRecord + { + public DateTimeOffsetVariableScale(DateTimeOffset dateTimeOffset, int scale) + : base(new SqlMetaData("dateTimeOffset", SqlDbType.DateTimeOffset, 0, (byte)scale)) // this is using variable scale + { + this.SetValues(dateTimeOffset); + } + } + + public class UdtDateTimeOffsetTest + { + private readonly string _connectionString = null; + private readonly string _udtTableType = DataTestUtility.GetUniqueNameForSqlServer("DataTimeOffsetTableType"); + + public UdtDateTimeOffsetTest() + { + _connectionString = DataTestUtility.TCPConnectionString; + } + + // This unit test is for the reported issue #2423 using a specific scale of 1 + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse))] + public void SelectFromSqlParameterShouldSucceed() + { + using SqlConnection connection = new(_connectionString); + connection.Open(); + SetupUserDefinedTableType(connection, _udtTableType); + + try + { + DateTimeOffset dateTimeOffset = new DateTimeOffset(2024, 1, 1, 23, 59, 59, 500, TimeSpan.Zero); + var param = new SqlParameter + { + ParameterName = "@params", + SqlDbType = SqlDbType.Structured, + TypeName = $"dbo.{_udtTableType}", + Value = new DateTimeOffsetList[] { new DateTimeOffsetList(dateTimeOffset) } + }; + + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "SELECT * FROM @params"; + cmd.Parameters.Add(param); + var result = cmd.ExecuteScalar(); + Assert.Equal(dateTimeOffset, result); + } + } + finally + { + DataTestUtility.DropUserDefinedType(connection, _udtTableType); + } + } + + // This unit test is to ensure that time in DateTimeOffset with all scales are working as expected + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse))] + public void DateTimeOffsetAllScalesTestShouldSucceed() + { + string tvpTypeName = DataTestUtility.GetUniqueNameForSqlServer("tvpType"); + + using SqlConnection connection = new(_connectionString); + connection.Open(); + + try + { + // Use different scale for each test: 0 to 7 + int fromScale = 0; + int toScale = 7; + + for (int scale = fromScale; scale <= toScale; scale++) + { + DateTimeOffset dateTimeOffset = new DateTimeOffset(2024, 1, 1, 23, 59, 59, TimeSpan.Zero); + + // Add sub-second offset corresponding to the scale being tested + TimeSpan subSeconds = TimeSpan.FromTicks((long)(TimeSpan.TicksPerSecond / Math.Pow(10, scale))); + dateTimeOffset = dateTimeOffset.Add(subSeconds); + + DataTestUtility.DropUserDefinedType(connection, tvpTypeName); + SetupDateTimeOffsetTableType(connection, tvpTypeName, scale); + + var param = new SqlParameter + { + ParameterName = "@params", + SqlDbType = SqlDbType.Structured, + Scale = (byte)scale, + TypeName = $"dbo.{tvpTypeName}", + Value = new DateTimeOffsetVariableScale[] { new DateTimeOffsetVariableScale(dateTimeOffset, scale) } + }; + + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "SELECT * FROM @params"; + cmd.Parameters.Add(param); + var result = cmd.ExecuteScalar(); + Assert.Equal(dateTimeOffset, result); + } + } + } + finally + { + DataTestUtility.DropUserDefinedType(connection, tvpTypeName); + } + } + + private static void SetupUserDefinedTableType(SqlConnection connection, string tableTypeName) + { + using (SqlCommand cmd = connection.CreateCommand()) + { + cmd.CommandType = CommandType.Text; + cmd.CommandText = $"CREATE TYPE {tableTypeName} AS TABLE ([Value] DATETIMEOFFSET(1) NOT NULL) "; + cmd.ExecuteNonQuery(); + } + } + + private static void SetupDateTimeOffsetTableType(SqlConnection connection, string tableTypeName, int scale) + { + using (SqlCommand cmd = connection.CreateCommand()) + { + cmd.CommandType = CommandType.Text; + cmd.CommandText = $"CREATE TYPE {tableTypeName} AS TABLE ([Value] DATETIMEOFFSET({scale}) NOT NULL) "; + cmd.ExecuteNonQuery(); + } + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs index 6aff5c727f..5d5c9d5ec7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/DiagnosticTest.cs @@ -25,9 +25,8 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests public class DiagnosticTest { private const string BadConnectionString = "data source = bad; initial catalog = bad; integrated security = true; connection timeout = 1;"; - private static readonly string s_tcpConnStr = DataTestUtility.TCPConnectionString ?? string.Empty; - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteScalarTest() { RemoteExecutor.Invoke(() => @@ -41,14 +40,14 @@ public void ExecuteScalarTest() cmd.CommandText = "SELECT [name], [state] FROM [sys].[databases] WHERE [name] = db_name();"; conn.Open(); - var output = cmd.ExecuteScalar(); + cmd.ExecuteScalar(); } }); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteScalarErrorTest() { RemoteExecutor.Invoke(() => @@ -59,19 +58,17 @@ public void ExecuteScalarErrorTest() using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "select 1 / 0;"; + cmd.CommandText = "SELECT 1 / 0;"; conn.Open(); - try - { var output = cmd.ExecuteScalar(); } - catch { } + Assert.Throws(() => cmd.ExecuteScalar()); } }); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteNonQueryTest() { RemoteExecutor.Invoke(() => @@ -85,14 +82,14 @@ public void ExecuteNonQueryTest() cmd.CommandText = "SELECT [name], [state] FROM [sys].[databases] WHERE [name] = db_name();"; conn.Open(); - var output = cmd.ExecuteNonQuery(); + cmd.ExecuteNonQuery(); } }); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteNonQueryErrorTest() { RemoteExecutor.Invoke(() => @@ -100,29 +97,23 @@ public void ExecuteNonQueryErrorTest() CollectStatisticsDiagnostics(connectionString => { using (SqlConnection conn = new SqlConnection(connectionString)) + using (SqlCommand cmd = new SqlCommand()) { - using (SqlCommand cmd = new SqlCommand()) - { - cmd.Connection = conn; - cmd.CommandText = "select 1 / 0;"; + cmd.Connection = conn; + cmd.CommandText = "SELECT 1 / 0;"; - // Limiting the command timeout to 3 seconds. This should be lower than the Process timeout. - cmd.CommandTimeout = 3; - conn.Open(); - Console.WriteLine("SqlClient.DiagnosticTest.ExecuteNonQueryErrorTest Connection Open Successful"); + // Limiting the command timeout to 3 seconds. This should be lower than the Process timeout. + cmd.CommandTimeout = 3; + conn.Open(); - SqlException ex = Assert.Throws(() => cmd.ExecuteNonQuery()); - Console.WriteLine("SqlClient.DiagnosticTest.ExecuteNonQueryErrorTest Command Executed"); - } - Console.WriteLine("SqlClient.DiagnosticTest.ExecuteNonQueryErrorTest Command Disposed"); + Assert.Throws(() => cmd.ExecuteNonQuery()); } - Console.WriteLine("SqlClient.DiagnosticTest.ExecuteNonQueryErrorTest Connection Disposed"); }); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteReaderTest() { RemoteExecutor.Invoke(() => @@ -138,14 +129,16 @@ public void ExecuteReaderTest() conn.Open(); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) - { } + { + // Read until end. + } } }); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteReaderErrorTest() { RemoteExecutor.Invoke(() => @@ -156,22 +149,18 @@ public void ExecuteReaderErrorTest() using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "select 1 / 0;"; + cmd.CommandText = "SELECT 1 / 0;"; - try - { - SqlDataReader reader = cmd.ExecuteReader(); - while (reader.Read()) - { } - } - catch { } + conn.Open(); + // @TODO: TestTdsServer should not throw on ExecuteReader, it should throw on reader.Read + Assert.Throws(() => cmd.ExecuteReader()); } }); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteReaderWithCommandBehaviorTest() { RemoteExecutor.Invoke(() => @@ -187,7 +176,9 @@ public void ExecuteReaderWithCommandBehaviorTest() conn.Open(); SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default); while (reader.Read()) - { } + { + // Read to end + } } }); return RemoteExecutor.SuccessExitCode; @@ -198,24 +189,27 @@ public void ExecuteReaderWithCommandBehaviorTest() [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] public void ExecuteXmlReaderTest() { - RemoteExecutor.Invoke(cs => + RemoteExecutor.Invoke(() => { CollectStatisticsDiagnostics(_ => { - using (SqlConnection conn = new SqlConnection(cs)) + // @TODO: Test TDS server doesn't support ExecuteXmlReader, so connect to real server as workaround + using (SqlConnection conn = new SqlConnection(DataTestUtility.TCPConnectionString)) using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "select top 10 * from sys.objects for xml auto, xmldata;"; + cmd.CommandText = "SELECT TOP 10 * FROM sys.objects FOR xml auto, xmldata;"; conn.Open(); XmlReader reader = cmd.ExecuteXmlReader(); while (reader.Read()) - { } + { + // Read to end + } } }); return RemoteExecutor.SuccessExitCode; - }, s_tcpConnStr).Dispose(); + }).Dispose(); } [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] @@ -229,119 +223,110 @@ public void ExecuteXmlReaderErrorTest() using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "select *, baddata = 1 / 0 from sys.objects for xml auto, xmldata;"; + cmd.CommandText = "SELECT *, baddata = 1 / 0 FROM sys.objects FOR xml auto, xmldata;"; - try - { - XmlReader reader = cmd.ExecuteXmlReader(); - while (reader.Read()) - { } - } - catch { } + conn.Open(); + // @TODO: TestTdsServer should not throw on ExecuteXmlReader, should throw on reader.Read + Assert.Throws(() => cmd.ExecuteXmlReader()); } }); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteScalarAsyncTest() { RemoteExecutor.Invoke(() => { CollectStatisticsDiagnosticsAsync(async connectionString => { - using (SqlConnection conn = new SqlConnection(connectionString)) - using (SqlCommand cmd = new SqlCommand()) + await using (SqlConnection conn = new SqlConnection(connectionString)) + await using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandText = "SELECT [name], [state] FROM [sys].[databases] WHERE [name] = db_name();"; conn.Open(); - var output = await cmd.ExecuteScalarAsync(); + await cmd.ExecuteScalarAsync(); } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteScalarAsyncErrorTest() { RemoteExecutor.Invoke(() => { CollectStatisticsDiagnosticsAsync(async connectionString => { - using (SqlConnection conn = new SqlConnection(connectionString)) - using (SqlCommand cmd = new SqlCommand()) + await using (SqlConnection conn = new SqlConnection(connectionString)) + await using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "select 1 / 0;"; + cmd.CommandText = "SELECT 1 / 0;"; conn.Open(); - - try - { var output = await cmd.ExecuteScalarAsync(); } - catch { } + await Assert.ThrowsAsync(() => cmd.ExecuteScalarAsync()); } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteNonQueryAsyncTest() { RemoteExecutor.Invoke(() => { CollectStatisticsDiagnosticsAsync(async connectionString => { - using (SqlConnection conn = new SqlConnection(connectionString)) - using (SqlCommand cmd = new SqlCommand()) + await using (SqlConnection conn = new SqlConnection(connectionString)) + await using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandText = "SELECT [name], [state] FROM [sys].[databases] WHERE [name] = db_name();"; conn.Open(); - var output = await cmd.ExecuteNonQueryAsync(); + await cmd.ExecuteNonQueryAsync(); } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteNonQueryAsyncErrorTest() { RemoteExecutor.Invoke(() => { CollectStatisticsDiagnosticsAsync(async connectionString => { - using (SqlConnection conn = new SqlConnection(connectionString)) - using (SqlCommand cmd = new SqlCommand()) + await using (SqlConnection conn = new SqlConnection(connectionString)) + await using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "select 1 / 0;"; + cmd.CommandText = "SELECT 1 / 0;"; conn.Open(); - try - { var output = await cmd.ExecuteNonQueryAsync(); } - catch { } + await Assert.ThrowsAsync(() => cmd.ExecuteNonQueryAsync()); } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteReaderAsyncTest() { RemoteExecutor.Invoke(() => { CollectStatisticsDiagnosticsAsync(async connectionString => { - using (SqlConnection conn = new SqlConnection(connectionString)) - using (SqlCommand cmd = new SqlCommand()) + await using (SqlConnection conn = new SqlConnection(connectionString)) + await using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandText = "SELECT [name], [state] FROM [sys].[databases] WHERE [name] = db_name();"; @@ -349,35 +334,33 @@ public void ExecuteReaderAsyncTest() conn.Open(); SqlDataReader reader = await cmd.ExecuteReaderAsync(); while (reader.Read()) - { } + { + // Read to end + } } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteReaderAsyncErrorTest() { RemoteExecutor.Invoke(() => { CollectStatisticsDiagnosticsAsync(async connectionString => { - using (SqlConnection conn = new SqlConnection(connectionString)) - using (SqlCommand cmd = new SqlCommand()) + await using (SqlConnection conn = new SqlConnection(connectionString)) + await using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "select 1 / 0;"; + cmd.CommandText = "SELECT 1 / 0;"; - try - { - SqlDataReader reader = await cmd.ExecuteReaderAsync(); - while (reader.Read()) - { } - } - catch { } + conn.Open(); + // @TODO: TestTdsServer should not throw on ExecuteReader, should throw on reader.Read + await Assert.ThrowsAsync(() => cmd.ExecuteReaderAsync()); } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; }).Dispose(); } @@ -386,53 +369,57 @@ public void ExecuteReaderAsyncErrorTest() [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureSynapse))] public void ExecuteXmlReaderAsyncTest() { - RemoteExecutor.Invoke(cs => + // @TODO: TestTdsServer does not handle xml reader, so connect to a real server as a workaround + RemoteExecutor.Invoke(() => { CollectStatisticsDiagnosticsAsync(async _ => { - using (SqlConnection conn = new SqlConnection(cs)) - using (SqlCommand cmd = new SqlCommand()) + await using (SqlConnection conn = new SqlConnection(DataTestUtility.TCPConnectionString)) + await using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; - cmd.CommandText = "select TOP 10 * from sys.objects for xml auto, xmldata;"; + cmd.CommandText = "SELECT TOP 10 * FROM sys.objects FOR xml auto, xmldata;"; conn.Open(); XmlReader reader = await cmd.ExecuteXmlReaderAsync(); while (reader.Read()) - { } + { + // Read to end + } } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; - }, s_tcpConnStr).Dispose(); + }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ExecuteXmlReaderAsyncErrorTest() { - RemoteExecutor.Invoke(cs => + // @TODO: TestTdsServer does not handle xml reader, so connect to a real server as a workaround + RemoteExecutor.Invoke(() => { + CollectStatisticsDiagnosticsAsync(async _ => { - using (SqlConnection conn = new SqlConnection(cs)) - using (SqlCommand cmd = new SqlCommand()) + await using (SqlConnection conn = new SqlConnection(DataTestUtility.TCPConnectionString)) + await using (SqlCommand cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandText = "select *, baddata = 1 / 0 from sys.objects for xml auto, xmldata;"; - try - { - XmlReader reader = await cmd.ExecuteXmlReaderAsync(); - while (reader.Read()) - { } - } - catch { } + // @TODO: Since this test uses a real database connection, the exception is + // thrown during reader.Read. (ie, TestTdsServer does not obey proper + // exception behavior) + await conn.OpenAsync(); + XmlReader reader = await cmd.ExecuteXmlReaderAsync(); + await Assert.ThrowsAsync(() => reader.ReadAsync()); } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; - }, s_tcpConnStr).Dispose(); + }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ConnectionOpenTest() { RemoteExecutor.Invoke(() => @@ -442,17 +429,13 @@ public void ConnectionOpenTest() using (SqlConnection sqlConnection = new SqlConnection(connectionString)) { sqlConnection.Open(); - Console.WriteLine("SqlClient.DiagnosticsTest.ConnectionOpenTest:: Connection Opened "); } - Console.WriteLine("SqlClient.DiagnosticsTest.ConnectionOpenTest:: Connection Should Be Disposed"); }, true); - - Console.WriteLine("SqlClient.DiagnosticsTest.ConnectionOpenTest:: Done with Diagnostics collection"); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ConnectionOpenErrorTest() { RemoteExecutor.Invoke(() => @@ -461,45 +444,41 @@ public void ConnectionOpenErrorTest() { using (SqlConnection sqlConnection = new SqlConnection(BadConnectionString)) { - try - { sqlConnection.Open(); } - catch { } + Assert.Throws(() => sqlConnection.Open()); } }); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ConnectionOpenAsyncTest() { RemoteExecutor.Invoke(() => { CollectStatisticsDiagnosticsAsync(async connectionString => { - using (SqlConnection sqlConnection = new SqlConnection(connectionString)) + await using (SqlConnection sqlConnection = new SqlConnection(connectionString)) { await sqlConnection.OpenAsync(); } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; }).Dispose(); } - [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup))] + [Fact] public void ConnectionOpenAsyncErrorTest() { RemoteExecutor.Invoke(() => { CollectStatisticsDiagnosticsAsync(async _ => { - using (SqlConnection sqlConnection = new SqlConnection(BadConnectionString)) + await using (SqlConnection sqlConnection = new SqlConnection(BadConnectionString)) { - try - { await sqlConnection.OpenAsync(); } - catch { } + await Assert.ThrowsAsync(() => sqlConnection.OpenAsync()); } - }).GetAwaiter().GetResult(); + }).Wait(); return RemoteExecutor.SuccessExitCode; }).Dispose(); } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs index 3552204886..a4557d72b6 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs @@ -3,27 +3,35 @@ // See the LICENSE file in the project root for more information. using System; +using System.Linq; using System.Net; +using System.Net.Sockets; using System.Runtime.CompilerServices; +using System.Security.Cryptography.X509Certificates; using Microsoft.SqlServer.TDS.EndPoint; +using Microsoft.SqlServer.TDS.PreLogin; using Microsoft.SqlServer.TDS.Servers; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { internal class TestTdsServer : GenericTDSServer, IDisposable { + private const int DefaultConnectionTimeout = 5; + private TDSServerEndPoint _endpoint = null; - private SqlConnectionStringBuilder connectionStringBuilder; + private SqlConnectionStringBuilder _connectionStringBuilder; public TestTdsServer(TDSServerArguments args) : base(args) { } public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) { - this.Engine = engine; + Engine = engine; } - public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, [CallerMemberName] string methodName = "") + public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, + int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.NotSupported) { TDSServerArguments args = new TDSServerArguments() { @@ -32,10 +40,18 @@ public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool if (enableFedAuth) { - args.FedAuthRequiredPreLoginOption = Microsoft.SqlServer.TDS.PreLogin.TdsPreLoginFedAuthRequiredOption.FedAuthRequired; + args.FedAuthRequiredPreLoginOption = SqlServer.TDS.PreLogin.TdsPreLoginFedAuthRequiredOption.FedAuthRequired; + } + + if (encryptionCertificate != null) + { + args.EncryptionCertificate = encryptionCertificate; } + args.Encryption = encryptionType; + TestTdsServer server = engine == null ? new TestTdsServer(args) : new TestTdsServer(engine, args); + server._endpoint = new TDSServerEndPoint(server) { ServerEndPoint = new IPEndPoint(IPAddress.Any, 0) }; server._endpoint.EndpointName = methodName; // The server EventLog should be enabled as it logs the exceptions. @@ -43,19 +59,37 @@ public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool server._endpoint.Start(); int port = server._endpoint.ServerEndPoint.Port; - server.connectionStringBuilder = new SqlConnectionStringBuilder() { DataSource = "localhost," + port, ConnectTimeout = 5, Encrypt = SqlConnectionEncryptOption.Optional }; - server.ConnectionString = server.connectionStringBuilder.ConnectionString; + + server._connectionStringBuilder = new SqlConnectionStringBuilder() + { + DataSource = "localhost," + port, + ConnectTimeout = connectionTimeout, + }; + + if (encryptionType == TDSPreLoginTokenEncryptionType.Off || + encryptionType == TDSPreLoginTokenEncryptionType.None || + encryptionType == TDSPreLoginTokenEncryptionType.NotSupported) + { + server._connectionStringBuilder.Encrypt = SqlConnectionEncryptOption.Optional; + } + else + { + server._connectionStringBuilder.Encrypt = SqlConnectionEncryptOption.Mandatory; + } + + server.ConnectionString = server._connectionStringBuilder.ConnectionString; return server; } - public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool enableLog = false, [CallerMemberName] string methodName = "") + public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool enableLog = false, + int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.NotSupported) { - return StartServerWithQueryEngine(null, false, false, methodName); + return StartServerWithQueryEngine(null, enableFedAuth, enableLog, connectionTimeout, methodName, encryptionCertificate, encryptionType); } public void Dispose() => _endpoint?.Stop(); public string ConnectionString { get; private set; } - } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 new file mode 100644 index 0000000000..02d558d77b --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -0,0 +1,158 @@ +# 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. +# Script: Invoke-SqlServerCertificateCommand# +# Author: SqlClient Team +# Date: March 20, 2024 +# Comments: This scripts creates SSL Self-Signed Certificate for TestTdsServer in pfx format. +# This script is not intended to be used in any production environments. + +param ($OutDir) + +function Invoke-SqlServerCertificateCommand { + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [string] $certificateName = "localhostcert.cer", + [string] $myCertStoreLocation = "Cert:\LocalMachine\My", + [string] $rootCertStoreLocation = "Cert:\LocalMachine\Root", + [string] $sqlAliasName = "SQLAliasName", + [string] $localhost = "localhost", + [string] $LoopBackIPV4 = "127.0.0.1", + [string] $LoopBackIPV6 = "::1" + ) + Write-Output "Certificate generation started..." + + # Change directory to where the tests are + Write-Output "Change directory to $OutDir ..." + cd $OutDir + pwd + + try { + # Get FQDN of the machine + Write-Output "Get FQDN of the machine..." + $fqdn = [System.Net.Dns]::GetHostByName(($env:computerName)).HostName + Write-Output "FQDN = $fqdn" + + $OS = [System.Environment]::OSVersion.Platform + Write-Output "Operating System is $OS" + + # Create a self-signed certificate + if ($OS -eq "Unix") { + chmod 777 $OutDir + # Install OpenSSL module + Install-Module -Name OpenSSL -Repository PSGallery -Force + # Show version of OpenSSL just to make sure it is installed + openssl version + + # Create self signed certificate using openssl + Write-Output "Creating certificate for linux..." + if ($fqdn.length -gt 64) { + $machineId = $fqdn.Substring(0,15) + openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$machineId" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" + } + else { + openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" + } + chmod 777 $OutDir/localhostcert.key $OutDir/localhostcert.cer + # Copy the certificate to the clientcert folder + cp $OutDir/localhostcert.cer $OutDir/clientcert/ + # Export the certificate to pfx + Write-Output "Exporting certificate to pfx..." + openssl pkcs12 -export -in $OutDir/localhostcert.cer -inkey $OutDir/localhostcert.key -out $OutDir/localhostcert.pfx -password pass:nopassword + chmod 777 $OutDir/localhostcert.pfx + + Write-Output "Converting certificate to pem..." + # Create pem from cer + cp $OutDir/localhostcert.cer $OutDir/localhostcert.pem + chmod 777 $OutDir/localhostcert.pem + + # Add trust to the pem certificate + Write-Output "Adding trust to pem certificate..." + openssl x509 -trustout -addtrust "serverAuth" -in $OutDir/localhostcert.pem + + # Import the certificate to the Root store ------------------------------------------------------------------------------ + # NOTE: The process must have root privileges to add the certificate to the Root store. If not, then use + # "chmod 777 /usr/local/share/ca-certificates" to give read, write and execute privileges to anyone on that folder + # Copy the certificate to /usr/local/share/ca-certificates folder while changing the extension to "crt". + # Only certificates with extension "crt" gets added for some reason. + Write-Output "Copy the pem certificate to /usr/local/share/ca-certificates folder..." + cp $OutDir/localhostcert.pem /usr/local/share/ca-certificates/localhostcert.crt + + # Add trust to the mismatched certificate as well + $ openssl x509 -in $OutDir/mismatchedcert.cer -inform der -out $OutDir/mismatchedcert.pem + # Copy the mismatched certificate to the clientcert folder + cp $OutDir/mismatchedcert.cer $OutDir/clientcert/ + openssl x509 -trustout -addtrust "serverAuth" -in $OutDir/mismatchedcert.pem + cp $OutDir/mismatchedcert.pem /usr/local/share/ca-certificates/mismatchedcert.crt + + # enable certificate as CA certificate + dpkg-reconfigure ca-certificates -f noninteractive -p critical + + # Update the certificates store + Write-Output "Updating the certificates store..." + update-ca-certificates -v + } else { + Write-Output "Creating a self-signed certificate..." + $params = @{ + Type = "SSLServerAuthentication" + Subject = "CN=$fqdn" + KeyAlgorithm = "RSA" + KeyLength = 4096 + HashAlgorithm = "SHA256" + TextExtension = "2.5.29.37={text}1.3.6.1.5.5.7.3.1", "2.5.29.17={text}DNS=$fqdn&DNS=$localhost&IPAddress=$LoopBackIPV4&DNS=$sqlAliasName&IPAddress=$LoopBackIPV6" + NotAfter = (Get-Date).AddMonths(36) + KeySpec = "KeyExchange" + Provider = "Microsoft RSA SChannel Cryptographic Provider" + CertStoreLocation = $myCertStoreLocation + FriendlyName = "TestTDSServerCertificate" + } + + $certificate = New-SelfSignedCertificate @params + Write-Output "Certificate created successfully" + Write-Output "Certificate Thumbprint: $($certificate.Thumbprint)" + + # Export the certificate to a file + Write-Output "Exporting the certificate to a file..." + Export-Certificate -Cert $certificate -FilePath "$OutDir/$certificateName" -Type CERT + + # Copy the certificate to the clientcert folder + copy $OutDir/$certificateName $OutDir/clientcert/ + copy $OutDir/mismatchedcert.cer $OutDir/clientcert/ + + # Import the certificate to the Root store + Write-Output "Importing the certificate to the Root store..." + $params = @{ + FilePath = "$OutDir/$certificateName" + CertStoreLocation = $rootCertStoreLocation + } + Import-Certificate @params + + Write-Output "Converting certificate to pfx..." + Write-Output "Cert:\LocalMachine\my\$($certificate.Thumbprint)" + + $pwd = ConvertTo-SecureString -String 'nopassword' -Force -AsPlainText + # Export the certificate to a pfx format + Export-PfxCertificate -Password $pwd -FilePath "$OutDir\localhostcert.pfx" -Cert "Cert:\LocalMachine\my\$($certificate.Thumbprint)" + + # Write the certificate thumbprint to a file + echo $certificate.Thumbprint | Out-File -FilePath "$OutDir\thumbprint.txt" -Encoding ascii + } + + Write-Output "Done creating pfx certificate..." + } + catch { + $e = $_.Exception + $msg = $e.Message + while ($e.InnerException) { + $e = $e.InnerException + $msg += "`n" + $e.Message + } + + Write-Output "Certificate generation was not successfull. $msg" + } + + Write-Output "Certificate generation task completed." +} + +Invoke-SqlServerCertificateCommand diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/mismatchedcert.cer b/src/Microsoft.Data.SqlClient/tests/ManualTests/mismatchedcert.cer new file mode 100644 index 0000000000..6b35e97a55 Binary files /dev/null and b/src/Microsoft.Data.SqlClient/tests/ManualTests/mismatchedcert.cer differ diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/removecert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/removecert.ps1 new file mode 100644 index 0000000000..14b944de80 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/removecert.ps1 @@ -0,0 +1,21 @@ +# 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. +# Script: removecert.ps1 +# Author: SqlClient Team +# Date: May 24, 2024 +# Comments: This script deletes the SSL Self-Signed Certificate from Linux certificate store. +# This script is not intended to be used in any production environments. + +param ($OutDir) + +# Delete all certificates +rm $OutDir/clientcer/*.cer +rm $OutDir/localhostcert.pem +rm $OutDir/mismatchedcert.pem +rm /usr/local/share/ca-certificates/localhostcert.crt +rm /usr/local/share/ca-certificates/mismatchedcert.crt + +# Update the certificates store +Write-Output "Updating the certificates store..." +update-ca-certificates -v diff --git a/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj b/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj deleted file mode 100644 index c7658cb0a5..0000000000 --- a/src/Microsoft.Data.SqlClient/tests/NSLibrary/Microsoft.Data.SqlClient.NSLibrary.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - netstandard2.0;netstandard2.1 - netstandard2.1 - $(ObjFolder)$(Configuration).$(Platform)\$(AssemblyName) - $(BinFolder)$(Configuration).$(Platform)\$(AssemblyName) - - - - - - diff --git a/src/Microsoft.Data.SqlClient/tests/NuGet.config b/src/Microsoft.Data.SqlClient/tests/NuGet.config deleted file mode 100644 index 366141ab39..0000000000 --- a/src/Microsoft.Data.SqlClient/tests/NuGet.config +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs index 6a936ac5a1..52bf5c30f4 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.ExtUtilities/SqlDbManager.cs @@ -24,7 +24,6 @@ public static class SqlDbManager private const string TCPConnectionString = "TCPConnectionString"; private const string NPConnectionString = "NPConnectionString"; private const string TCPConnectionStringAASSGX = "TCPConnectionStringAASSGX"; - private const string TCPConnectionStringAASVBS = "TCPConnectionStringAASVBS"; private const string TCPConnectionStringHGSVBS = "TCPConnectionStringHGSVBS"; /// @@ -124,10 +123,6 @@ private static void LoadActiveConnectionStrings() { s_activeConnectionStrings.Add(TCPConnectionStringAASSGX, s_configJson.TCPConnectionStringAASSGX); } - if (!string.IsNullOrEmpty(s_configJson.TCPConnectionStringAASVBS)) - { - s_activeConnectionStrings.Add(TCPConnectionStringAASVBS, s_configJson.TCPConnectionStringAASVBS); - } if (!string.IsNullOrEmpty(s_configJson.TCPConnectionStringHGSVBS)) { s_activeConnectionStrings.Add(TCPConnectionStringHGSVBS, s_configJson.TCPConnectionStringHGSVBS); @@ -148,9 +143,6 @@ private static void UpdateConfig(string key, SqlConnectionStringBuilder builder) case TCPConnectionStringAASSGX: s_configJson.TCPConnectionStringAASSGX = builder.ConnectionString; break; - case TCPConnectionStringAASVBS: - s_configJson.TCPConnectionStringAASVBS = builder.ConnectionString; - break; case TCPConnectionStringHGSVBS: s_configJson.TCPConnectionStringHGSVBS = builder.ConnectionString; break; 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 49c368c790..3fbe8313ee 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 @@ -13,7 +13,6 @@ public class Config public string TCPConnectionString = null; public string NPConnectionString = null; public string TCPConnectionStringHGSVBS = null; - public string TCPConnectionStringAASVBS = null; public string TCPConnectionStringNoneVBS = null; public string TCPConnectionStringAASSGX = null; public string AADAuthorityURL = null; @@ -22,8 +21,6 @@ public class Config public string AADServicePrincipalSecret = null; public string AzureKeyVaultURL = null; public string AzureKeyVaultTenantId = null; - public string AzureKeyVaultClientId = null; - public string AzureKeyVaultClientSecret = null; public string LocalDbAppName = null; public string LocalDbSharedInstanceName = null; public bool EnclaveEnabled = false; 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 411f4ad88f..d159b7628d 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 @@ -2,7 +2,6 @@ "TCPConnectionString": "Data Source=tcp:localhost;Database=Northwind;Integrated Security=true;Encrypt=false;", "NPConnectionString": "Data Source=np:localhost;Database=Northwind;Integrated Security=true;Encrypt=false;", "TCPConnectionStringHGSVBS": "", - "TCPConnectionStringAASVBS": "", "TCPConnectionStringNoneVBS": "", "TCPConnectionStringAASSGX": "", "EnclaveEnabled": false, @@ -13,8 +12,6 @@ "AADServicePrincipalSecret": "", "AzureKeyVaultURL": "", "AzureKeyVaultTenantId": "", - "AzureKeyVaultClientId": "", - "AzureKeyVaultClientSecret": "", "SupportsIntegratedSecurity": true, "LocalDbAppName": "", "LocalDbSharedInstanceName": "", diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs index 94abbf5818..80d8633501 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs @@ -264,6 +264,10 @@ public override int Read(byte[] buffer, int offset, int count) // Calculate how much data can be read until the end of the packet is reached long packetDataAvailable = IncomingPacketHeader.Length - IncomingPacketPosition; + // Set count to actual size of data to be read from the buffer so this loop can exit + if (packetDataAvailable < count) + count = (int)packetDataAvailable; + // Check how much data we should give back in the current iteration int packetDataToRead = Math.Min((int)packetDataAvailable, count - bufferReadPosition); diff --git a/src/NuGet.config b/src/NuGet.config deleted file mode 100644 index 5832a9da27..0000000000 --- a/src/NuGet.config +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/tools/props/Versions.props b/tools/props/Versions.props index 80db684225..29d1201137 100644 --- a/tools/props/Versions.props +++ b/tools/props/Versions.props @@ -1,14 +1,14 @@ - 5.2.0 + 6.0.0 0 $(MdsVersionDefault).$(BuildNumber) $(AssemblyFileVersion) - 5.0.0.0 + 6.0.0.0 $(MdsVersionDefault)-dev $(NugetPackageVersion) @@ -27,17 +27,16 @@ - 1.10.3 - 4.56.0 - 6.35.0 - 6.35.0 + 1.11.3 + 4.60.3 + 7.5.0 + 7.5.0 4.5.1 6.0.0 8.0.0 - 5.0.0 5.2.0 6.0.1 1.0.0 @@ -48,28 +47,21 @@ 5.0.0 6.0.0 - - - 4.3.0 - 6.0.1 - - [1.35.0,2.0.0) - [4.4.0,5.0.0) + [1.38.0,2.0.0) + [4.5.0,5.0.0) 6.0.1 - 9.0.0-beta.23613.3 + 8.0.0-beta.24123.1 3.1.6 - 5.2.9 17.8.0 13.0.1 4.3.0 6.0.1 - 6.35.0 - 2.6.3 + 2.4.2 2.5.5 1.0.3 7.0.0-beta.22316.1 @@ -80,6 +72,7 @@ 0.13.2 6.0.0 6.0.1 + 5.0.0 $(NugetPackageVersion) diff --git a/tools/props/VersionsNet8OrLater.props b/tools/props/VersionsNet8OrLater.props index a5e1f52bb4..2c203223bd 100644 --- a/tools/props/VersionsNet8OrLater.props +++ b/tools/props/VersionsNet8OrLater.props @@ -5,5 +5,7 @@ 8.0.0 8.0.0 8.0.0 + 9.0.0-beta.24157.1 + 2.6.3 diff --git a/tools/specs/Microsoft.Data.SqlClient.nuspec b/tools/specs/Microsoft.Data.SqlClient.nuspec index 57fff91307..6bbc961ac7 100644 --- a/tools/specs/Microsoft.Data.SqlClient.nuspec +++ b/tools/specs/Microsoft.Data.SqlClient.nuspec @@ -29,10 +29,10 @@ When using NuGet 3.x this package requires at least version 3.4. - - - - + + + + @@ -40,59 +40,24 @@ When using NuGet 3.x this package requires at least version 3.4. - - - - + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -111,14 +76,6 @@ When using NuGet 3.x this package requires at least version 3.4. - - - - - - - - @@ -135,36 +92,29 @@ When using NuGet 3.x this package requires at least version 3.4. - - - - - - - - - - - - - - - - - + + + + + + + + + + - - - + + + - + @@ -175,7 +125,7 @@ When using NuGet 3.x this package requires at least version 3.4. - + @@ -194,44 +144,9 @@ When using NuGet 3.x this package requires at least version 3.4. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -244,16 +159,5 @@ 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 6c2ea69cbf..5c89d24276 100644 --- a/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec +++ b/tools/specs/add-ons/Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider.nuspec @@ -26,25 +26,19 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyStoreProvider.SqlColumnEncrypti - + - + - - - - - - - + @@ -58,42 +52,31 @@ Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyStoreProvider.SqlColumnEncrypti - - - - - + + + + + - - - + + + - - - + + + - + - - - - - - - + + + - - - - - - + + + - - - - - - + + diff --git a/tools/testsql/createUdtTestDb.sql b/tools/testsql/createUdtTestDb.sql index 5511f5a680..2f573faeb9 100644 Binary files a/tools/testsql/createUdtTestDb.sql and b/tools/testsql/createUdtTestDb.sql differ