From a9c5f7f211bb237c69d01f1ef56ced0a4389e12e Mon Sep 17 00:00:00 2001 From: Lawrence LCI Date: Fri, 3 Mar 2023 17:03:18 -0500 Subject: [PATCH 1/2] Port changes from netcore to netfx where the enclaveinfo is writen once per rpc request instead of once per parameter within the same rpc for async and add test to validate --- src/Microsoft.Data.SqlClient.sln | 48 ++++++ .../src/Microsoft/Data/SqlClient/TdsParser.cs | 6 +- .../ManualTests/AlwaysEncrypted/ApiShould.cs | 138 ++++++++++++++++++ 3 files changed, 189 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index a03e196464..e2ed615b45 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -1128,6 +1128,54 @@ Global {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x64.Build.0 = Release|Any CPU {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x86.ActiveCfg = Release|Any CPU {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x86.Build.0 = Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x64.ActiveCfg = Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x64.Build.0 = Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x86.ActiveCfg = Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x86.Build.0 = Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|Any CPU.ActiveCfg = net461-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|Any CPU.Build.0 = net461-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x64.ActiveCfg = net461-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x64.Build.0 = net461-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x86.ActiveCfg = net461-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x86.Build.0 = net461-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|Any CPU.ActiveCfg = net461-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|Any CPU.Build.0 = net461-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x64.ActiveCfg = net461-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x64.Build.0 = net461-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x86.ActiveCfg = net461-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x86.Build.0 = net461-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|Any CPU.ActiveCfg = netcoreapp2.1-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|Any CPU.Build.0 = netcoreapp2.1-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x64.ActiveCfg = netcoreapp2.1-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x64.Build.0 = netcoreapp2.1-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x86.ActiveCfg = netcoreapp2.1-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x86.Build.0 = netcoreapp2.1-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|Any CPU.ActiveCfg = netcoreapp2.1-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|Any CPU.Build.0 = netcoreapp2.1-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x64.ActiveCfg = netcoreapp2.1-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x64.Build.0 = netcoreapp2.1-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x86.ActiveCfg = netcoreapp2.1-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x86.Build.0 = netcoreapp2.1-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|Any CPU.ActiveCfg = netcoreapp3.1-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|Any CPU.Build.0 = netcoreapp3.1-Debug|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x64.ActiveCfg = netcoreapp3.1-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x64.Build.0 = netcoreapp3.1-Debug|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x86.ActiveCfg = netcoreapp3.1-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x86.Build.0 = netcoreapp3.1-Debug|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|Any CPU.ActiveCfg = netcoreapp3.1-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|Any CPU.Build.0 = netcoreapp3.1-Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x64.ActiveCfg = netcoreapp3.1-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x64.Build.0 = netcoreapp3.1-Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x86.ActiveCfg = netcoreapp3.1-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x86.Build.0 = netcoreapp3.1-Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|Any CPU.Build.0 = Release|Any CPU + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x64.ActiveCfg = Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x64.Build.0 = Release|x64 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x86.ActiveCfg = Release|x86 + {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE 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 31a44e3221..58cfc9af79 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 @@ -9860,10 +9860,10 @@ internal Task TdsExecuteRPC(SqlCommand cmd, _SqlRPC[] rpcArray, int timeout, boo // Options WriteShort((short)rpcext.options, stateObj); - } - byte[] enclavePackage = cmd.enclavePackage != null ? cmd.enclavePackage.EnclavePackageBytes : null; - WriteEnclaveInfo(stateObj, enclavePackage); + byte[] enclavePackage = cmd.enclavePackage != null ? cmd.enclavePackage.EnclavePackageBytes : null; + WriteEnclaveInfo(stateObj, enclavePackage); + } // Stream out parameters SqlParameter[] parameters = rpcext.parameters; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs index 136bd36b42..fadf2ed254 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/ApiShould.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; @@ -753,6 +754,55 @@ public void TestExecuteReader(string connection) }); } + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringSetupForAE))] + [ClassData(typeof(AEConnectionStringProvider))] + public async void TestExecuteReaderAsyncWithLargeQuery(string connection) + { + string tableName = "VeryLong_01234567890123456789012345678901234567890123456789_TestTableName"; + int columnsCount = 50; + + // Arrange - drops the table with long name and re-creates it with 52 columns (ID, name, ColumnName0..49) + try + { + DropTableIfExists(connection, tableName); + CreateTable(connection, tableName, columnsCount); + string name = "nobody"; + + using (SqlConnection sqlConnection = new SqlConnection(connection)) + { + await sqlConnection.OpenAsync(); + // This creates a "select top 100" query that has over 40k characters + using (SqlCommand sqlCommand = new SqlCommand(GenerateSelectQuery(tableName, columnsCount, 10, "WHERE Name = @FirstName AND ID = @CustomerId"), + sqlConnection, + transaction: null, + columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled)) + { + sqlCommand.Parameters.Add(@"CustomerId", SqlDbType.Int); + sqlCommand.Parameters.Add(@"FirstName", SqlDbType.VarChar, name.Length); + + sqlCommand.Parameters[0].Value = 0; + sqlCommand.Parameters[1].Value = name; + + // Act and Assert + // Test that execute reader async does not throw an exception. + // The table is empty so there should be no results; however, the bug previously found is that it causes a TDS RPC exception on enclave. + using (SqlDataReader sqlDataReader = await sqlCommand.ExecuteReaderAsync()) + { + Assert.False(sqlDataReader.HasRows, "The table should be empty"); + } + } + } + } + catch (Exception ex) + { + Assert.False(true, $"The following exception was thrown: {ex.Message}"); + } + finally + { + DropTableIfExists(connection, tableName); + } + } + [ConditionalTheory(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringSetupForAE))] [ClassData(typeof(AEConnectionStringProviderWithCommandBehaviorSet1))] public void TestExecuteReaderWithCommandBehavior(string connection, CommandBehavior commandBehavior) @@ -2820,6 +2870,94 @@ private void CleanUpTable(string connString, string tableName) } } + + /// + /// Creates a table with the specified number of bit columns. + /// + /// The connection string to the database + /// The table name + /// The number of bit columns + private void CreateTable(string connString, string tableName, int columnsCount) + { + using (var sqlConnection = new SqlConnection(connString)) + { + sqlConnection.Open(); + + SqlCommand cmd = new SqlCommand(GenerateCreateQuery(tableName, columnsCount), sqlConnection); + cmd.ExecuteNonQuery(); + } + } + + /// + /// Drops the table if the specified table exists + /// + /// The connection string to the database + /// The name of the table to be dropped + private void DropTableIfExists(string connString, string tableName) + { + using (var sqlConnection = new SqlConnection(connString)) + { + sqlConnection.Open(); + SqlCommand cmd = new SqlCommand($"DROP TABLE IF EXISTS {tableName};", sqlConnection); + cmd.ExecuteNonQuery(); + } + } + + /// + /// Generates the query for creating a table with the number of bit columns specified. + /// + /// The name of the table + /// The number of columns for the table + /// + private string GenerateCreateQuery(string tableName, int columnsCount) + { + StringBuilder builder = new StringBuilder(); + builder.Append(string.Format("CREATE TABLE [dbo].[{0}]", tableName)); + builder.Append('('); + builder.AppendLine("[ID][bigint] NOT NULL,"); + builder.AppendLine("[Name] [varchar] (200) NOT NULL"); + for (int i = 0; i < columnsCount; i++) + { + builder.Append(','); + builder.Append($"[ColumnName{i}][bit] NULL"); + } + builder.Append(");"); + + return builder.ToString(); + } + + /// + /// Generates the large query with the select top 100 of all the columns repeated multiple times. + /// + /// The name of the table + /// The number of columns to be explicitly included + /// The number of times the select query is repeated + /// A where clause for additional filters + /// + private string GenerateSelectQuery(string tableName, int columnsCount, int repeat = 10, string where = "") + { + StringBuilder builder = new StringBuilder(); + builder.AppendLine($"SELECT TOP 100"); + builder.AppendLine($"[{tableName}].[ID],"); + builder.AppendLine($"[{tableName}].[Name]"); + for (int i = 0; i < columnsCount; i++) + { + builder.Append(","); + builder.AppendLine($"[{tableName}].[ColumnName{i}]"); + } + + string extra = string.IsNullOrEmpty(where) ? $"(NOLOCK) [{tableName}]" : where; + builder.AppendLine($"FROM [{tableName}] {extra};"); + + StringBuilder builder2 = new StringBuilder(); + for (int i = 0; i < repeat; i++) + { + builder2.AppendLine(builder.ToString()); + } + + return builder2.ToString(); + } + /// /// An helper method to test the cancellation of the command using cancellationToken to async SqlCommand APIs. /// From 4f284ef1be8dd0e7ee40a1cacc4b235c10cf6cf6 Mon Sep 17 00:00:00 2001 From: Lawrence LCI Date: Thu, 9 Mar 2023 14:01:47 -0500 Subject: [PATCH 2/2] Revert the sln --- src/Microsoft.Data.SqlClient.sln | 48 -------------------------------- 1 file changed, 48 deletions(-) diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index e2ed615b45..a03e196464 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -1128,54 +1128,6 @@ Global {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x64.Build.0 = Release|Any CPU {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x86.ActiveCfg = Release|Any CPU {E4C08DCE-DC29-4FEB-B655-1E7287DB5A2B}.Release|x86.Build.0 = Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x64.ActiveCfg = Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x64.Build.0 = Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x86.ActiveCfg = Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Debug|x86.Build.0 = Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|Any CPU.ActiveCfg = net461-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|Any CPU.Build.0 = net461-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x64.ActiveCfg = net461-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x64.Build.0 = net461-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x86.ActiveCfg = net461-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Debug|x86.Build.0 = net461-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|Any CPU.ActiveCfg = net461-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|Any CPU.Build.0 = net461-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x64.ActiveCfg = net461-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x64.Build.0 = net461-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x86.ActiveCfg = net461-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.net461-Release|x86.Build.0 = net461-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|Any CPU.ActiveCfg = netcoreapp2.1-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|Any CPU.Build.0 = netcoreapp2.1-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x64.ActiveCfg = netcoreapp2.1-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x64.Build.0 = netcoreapp2.1-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x86.ActiveCfg = netcoreapp2.1-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Debug|x86.Build.0 = netcoreapp2.1-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|Any CPU.ActiveCfg = netcoreapp2.1-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|Any CPU.Build.0 = netcoreapp2.1-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x64.ActiveCfg = netcoreapp2.1-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x64.Build.0 = netcoreapp2.1-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x86.ActiveCfg = netcoreapp2.1-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp2.1-Release|x86.Build.0 = netcoreapp2.1-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|Any CPU.ActiveCfg = netcoreapp3.1-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|Any CPU.Build.0 = netcoreapp3.1-Debug|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x64.ActiveCfg = netcoreapp3.1-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x64.Build.0 = netcoreapp3.1-Debug|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x86.ActiveCfg = netcoreapp3.1-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Debug|x86.Build.0 = netcoreapp3.1-Debug|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|Any CPU.ActiveCfg = netcoreapp3.1-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|Any CPU.Build.0 = netcoreapp3.1-Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x64.ActiveCfg = netcoreapp3.1-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x64.Build.0 = netcoreapp3.1-Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x86.ActiveCfg = netcoreapp3.1-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.netcoreapp3.1-Release|x86.Build.0 = netcoreapp3.1-Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|Any CPU.Build.0 = Release|Any CPU - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x64.ActiveCfg = Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x64.Build.0 = Release|x64 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x86.ActiveCfg = Release|x86 - {B499E477-C9B1-4087-A5CF-5C762D90E433}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE