Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.1.2] Backport: Fix | Default UTF8 collation conflict #1910

Merged
merged 1 commit into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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();
}
}
}