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 2fd15a0def..ed28bdcfb7 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
@@ -3054,19 +3054,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)
{
diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
index 4b43a3ae8c..c75beda615 100644
--- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
+++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs
@@ -358,16 +358,23 @@ public static string GetUniqueName(string prefix, bool withBracket = true)
return uniqueName;
}
- // SQL Server supports long names (up to 128 characters), add extra info for troubleshooting
- public static string GetUniqueNameForSqlServer(string prefix)
+ ///
+ /// Uses environment values `UserName` and `MachineName` in addition to the specified `prefix` and current date
+ /// to generate a unique name to use in Sql Server;
+ /// SQL Server supports long names (up to 128 characters), add extra info for troubleshooting.
+ ///
+ /// Add the prefix to the generate string.
+ /// Database name must be pass with brackets by default.
+ /// Unique name by considering the Sql Server naming rules.
+ public static string GetUniqueNameForSqlServer(string prefix, bool withBracket = true)
{
string extendedPrefix = string.Format(
- "{0}_{1}@{2}",
+ "{0}_{1}_{2}@{3}",
prefix,
Environment.UserName,
Environment.MachineName,
DateTime.Now.ToString("yyyy_MM_dd", CultureInfo.InvariantCulture));
- string name = GetUniqueName(extendedPrefix);
+ string name = GetUniqueName(extendedPrefix, withBracket);
if (name.Length > 128)
{
throw new ArgumentOutOfRangeException("the name is too long - SQL Server names are limited to 128");
@@ -399,6 +406,30 @@ public static void DropStoredProcedure(SqlConnection sqlConnection, string spNam
}
}
+ private static void ResurrectConnection(SqlConnection sqlConnection, int counter = 2)
+ {
+ if (sqlConnection.State == ConnectionState.Closed)
+ {
+ sqlConnection.Open();
+ }
+ while (counter-- > 0 && sqlConnection.State == ConnectionState.Connecting)
+ {
+ Thread.Sleep(80);
+ }
+ }
+
+ ///
+ /// Drops specified database on provided connection.
+ ///
+ /// Open connection to be used.
+ /// Database name without brackets.
+ public static void DropDatabase(SqlConnection sqlConnection, string dbName)
+ {
+ ResurrectConnection(sqlConnection);
+ using SqlCommand cmd = new(string.Format("IF (EXISTS(SELECT 1 FROM sys.databases WHERE name = '{0}')) \nBEGIN \n ALTER DATABASE [{0}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE \n DROP DATABASE [{0}] \nEND", dbName), sqlConnection);
+ cmd.ExecuteNonQuery();
+ }
+
public static bool IsLocalDBInstalled() => SupportsLocalDb;
public static bool IsIntegratedSecuritySetup() => SupportsIntegratedSecurity;
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..e59711f287 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.Threading;
using Xunit;
namespace Microsoft.Data.SqlClient.ManualTesting.Tests
@@ -29,6 +31,76 @@ 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.
+ int count = 3;
+ while(count-- > 0)
+ {
+ try
+ {
+ cnnTest.Open();
+ break;
+ }
+ catch
+ {
+ if (count == 0) throw;
+
+ Thread.Sleep(200);
+ }
+ }
+
+ 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();
+ }
}
}