From ec3e20d3a6863416b77c0cec3150b3cb6500f665 Mon Sep 17 00:00:00 2001 From: Parminder Kaur Date: Mon, 30 Jan 2023 17:33:49 -0800 Subject: [PATCH] Bacporting Fix | Default UTF8 collation conflict --- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 9 +-- .../SQL/Utf8SupportTest/Utf8SupportTest.cs | 62 ++++++++++++++++++- 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParser.cs index ccea8f1886..31a44e3221 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 @@ -3063,20 +3063,13 @@ private bool TryProcessEnvChange(int tokenLength, TdsParserStateObject stateObj, _defaultCollation = env.newCollation; _defaultLCID = env.newCollation.LCID; - int newCodePage = GetCodePage(env.newCollation, stateObj); - if ((env.newCollation.info & TdsEnums.UTF8_IN_TDSCOLLATION) == TdsEnums.UTF8_IN_TDSCOLLATION) { // UTF8 collation _defaultEncoding = Encoding.UTF8; - - if (newCodePage != _defaultCodePage) - { - _defaultCodePage = newCodePage; - } } else { - + int newCodePage = GetCodePage(env.newCollation, stateObj); if (newCodePage != _defaultCodePage) { _defaultCodePage = newCodePage; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Utf8SupportTest/Utf8SupportTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Utf8SupportTest/Utf8SupportTest.cs index c6bc56d9f4..7f88155c59 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Utf8SupportTest/Utf8SupportTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/Utf8SupportTest/Utf8SupportTest.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Text; +using System; using Xunit; namespace Microsoft.Data.SqlClient.ManualTesting.Tests @@ -29,6 +31,64 @@ public static void CheckSupportUtf8ConnectionProperty() } } - // TODO: Write tests using UTF8 collations + // skip creating database on Azure + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.AreConnStringsSetup), nameof(DataTestUtility.IsNotAzureServer), nameof(DataTestUtility.IsNotAzureSynapse))] + public static void UTF8databaseTest() + { + const string letters = @"!\#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u007f€\u0081‚ƒ„…†‡ˆ‰Š‹Œ\u008dŽ\u008f\u0090‘’“”•–—˜™š›œ\u009džŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ"; + string dbName = DataTestUtility.GetUniqueNameForSqlServer("UTF8databaseTest", false); + string tblName = "Table1"; + + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); + builder.InitialCatalog = "master"; + + using SqlConnection cn = new(builder.ConnectionString); + cn.Open(); + + try + { + PrepareDatabaseUTF8(cn, dbName, tblName, letters); + + builder.InitialCatalog = dbName; + using SqlConnection cnnTest = new(builder.ConnectionString); + // creating a databse is a time consumer action and could be retried. + SqlRetryLogicOption retryOption = new() { NumberOfTries = 3, DeltaTime = TimeSpan.FromMilliseconds(200) }; + cnnTest.RetryLogicProvider = SqlConfigurableRetryFactory.CreateIncrementalRetryProvider(retryOption); + cnnTest.Open(); + + using SqlCommand cmd = cnnTest.CreateCommand(); + cmd.CommandText = $"SELECT * FROM {tblName}"; + + using SqlDataReader reader = cmd.ExecuteReader(); + + Assert.True(reader.Read(), "The test table should have a row!"); + object[] data = new object[1]; + reader.GetSqlValues(data); + Assert.Equal(letters, data[0].ToString()); + reader.Close(); + cnnTest.Close(); + } + finally + { + DataTestUtility.DropDatabase(cn, dbName); + } + } + + private static void PrepareDatabaseUTF8(SqlConnection cnn, string dbName, string tblName, string letters) + { + StringBuilder sb = new(); + + using SqlCommand cmd = cnn.CreateCommand(); + + cmd.CommandText = $"CREATE DATABASE [{dbName}] COLLATE Latin1_General_100_CI_AS_SC_UTF8;"; + cmd.ExecuteNonQuery(); + + sb.AppendLine($"CREATE TABLE [{dbName}].dbo.[{tblName}] (col VARCHAR(7633) COLLATE Latin1_General_100_CI_AS_SC);"); + sb.AppendLine($"INSERT INTO [{dbName}].dbo.[{tblName}] VALUES (@letters);"); + + cmd.Parameters.Add(new SqlParameter("letters", letters)); + cmd.CommandText = sb.ToString(); + cmd.ExecuteNonQuery(); + } } }