Skip to content

Commit ad3daa1

Browse files
author
Keerat Singh
authored
Merge pull request dotnet/corefx#30917 from keeratsingh/utf8-feature-extension
Add support for UTF8 Feature Extension Commit migrated from dotnet/corefx@06b5dab
2 parents dace483 + b861956 commit ad3daa1

File tree

5 files changed

+134
-32
lines changed

5 files changed

+134
-32
lines changed

src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/SqlInternalConnectionTds.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,8 +1157,8 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword,
11571157
_federatedAuthenticationRequested = true;
11581158
}
11591159

1160-
// The GLOBALTRANSACTIONS feature is implicitly requested
1161-
requestedFeatures |= TdsEnums.FeatureExtension.GlobalTransactions;
1160+
// The GLOBALTRANSACTIONS and UTF8 support features are implicitly requested
1161+
requestedFeatures |= TdsEnums.FeatureExtension.GlobalTransactions | TdsEnums.FeatureExtension.UTF8Support;
11621162
_parser.TdsLogin(login, requestedFeatures, _recoverySessionData, _fedAuthFeatureExtensionData);
11631163
}
11641164

@@ -1959,6 +1959,14 @@ internal void OnFeatureExtAck(int featureId, byte[] data)
19591959
break;
19601960
}
19611961

1962+
case TdsEnums.FEATUREEXT_UTF8SUPPORT:
1963+
{
1964+
if (data.Length < 1)
1965+
{
1966+
throw SQL.ParsingError();
1967+
}
1968+
break;
1969+
}
19621970
default:
19631971
{
19641972
// Unknown feature ack

src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsEnums.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,18 +201,22 @@ public enum EnvChangeType : byte
201201
// Feature Extension
202202
public const byte FEATUREEXT_TERMINATOR = 0xFF;
203203
public const byte FEATUREEXT_SRECOVERY = 0x01;
204-
public const byte FEATUREEXT_GLOBALTRANSACTIONS = 0x05;
205204
public const byte FEATUREEXT_FEDAUTH = 0x02;
205+
public const byte FEATUREEXT_GLOBALTRANSACTIONS = 0x05;
206+
public const byte FEATUREEXT_UTF8SUPPORT = 0x0A;
206207

207208
[Flags]
208209
public enum FeatureExtension : uint
209210
{
210211
None = 0,
211212
SessionRecovery = 1,
212213
FedAuth = 2,
213-
GlobalTransactions = 8,
214+
GlobalTransactions = 16,
215+
UTF8Support = 512,
214216
}
215217

218+
public const uint UTF8_IN_TDSCOLLATION = 0x4000000;
219+
216220
public const byte FEDAUTHLIB_LIVEID = 0X00;
217221
public const byte FEDAUTHLIB_SECURITYTOKEN = 0x01;
218222
public const byte FEDAUTHLIB_ADAL = 0x02;

src/libraries/System.Data.SqlClient/src/System/Data/SqlClient/TdsParser.cs

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2281,14 +2281,23 @@ private bool TryProcessEnvChange(int tokenLength, TdsParserStateObject stateObj,
22812281
{
22822282
return false;
22832283
}
2284-
2285-
// give the parser the new collation values in case parameters don't specify one
2284+
2285+
// Give the parser the new collation values in case parameters don't specify one
22862286
_defaultCollation = env.newCollation;
2287-
int newCodePage = GetCodePage(env.newCollation, stateObj);
2288-
if (newCodePage != _defaultCodePage)
2287+
2288+
// UTF8 collation
2289+
if ((env.newCollation.info & TdsEnums.UTF8_IN_TDSCOLLATION) == TdsEnums.UTF8_IN_TDSCOLLATION)
22892290
{
2290-
_defaultCodePage = newCodePage;
2291-
_defaultEncoding = System.Text.Encoding.GetEncoding(_defaultCodePage);
2291+
_defaultEncoding = Encoding.UTF8;
2292+
}
2293+
else
2294+
{
2295+
int newCodePage = GetCodePage(env.newCollation, stateObj);
2296+
if (newCodePage != _defaultCodePage)
2297+
{
2298+
_defaultCodePage = newCodePage;
2299+
_defaultEncoding = System.Text.Encoding.GetEncoding(_defaultCodePage);
2300+
}
22922301
}
22932302
_defaultLCID = env.newCollation.LCID;
22942303
}
@@ -3245,18 +3254,26 @@ internal bool TryProcessReturnValue(int length, TdsParserStateObject stateObj, o
32453254
return false;
32463255
}
32473256

3248-
int codePage = GetCodePage(rec.collation, stateObj);
3249-
3250-
// if the column lcid is the same as the default, use the default encoder
3251-
if (codePage == _defaultCodePage)
3257+
// UTF8 collation
3258+
if ((rec.collation.info & TdsEnums.UTF8_IN_TDSCOLLATION) == TdsEnums.UTF8_IN_TDSCOLLATION)
32523259
{
3253-
rec.codePage = _defaultCodePage;
3254-
rec.encoding = _defaultEncoding;
3260+
rec.encoding = Encoding.UTF8;
32553261
}
32563262
else
32573263
{
3258-
rec.codePage = codePage;
3259-
rec.encoding = System.Text.Encoding.GetEncoding(rec.codePage);
3264+
int codePage = GetCodePage(rec.collation, stateObj);
3265+
3266+
// If the column lcid is the same as the default, use the default encoder
3267+
if (codePage == _defaultCodePage)
3268+
{
3269+
rec.codePage = _defaultCodePage;
3270+
rec.encoding = _defaultEncoding;
3271+
}
3272+
else
3273+
{
3274+
rec.codePage = codePage;
3275+
rec.encoding = System.Text.Encoding.GetEncoding(rec.codePage);
3276+
}
32603277
}
32613278
}
32623279

@@ -3755,17 +3772,25 @@ private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaDat
37553772
return false;
37563773
}
37573774

3758-
int codePage = GetCodePage(col.collation, stateObj);
3759-
3760-
if (codePage == _defaultCodePage)
3775+
// UTF8 collation
3776+
if ((col.collation.info & TdsEnums.UTF8_IN_TDSCOLLATION) == TdsEnums.UTF8_IN_TDSCOLLATION)
37613777
{
3762-
col.codePage = _defaultCodePage;
3763-
col.encoding = _defaultEncoding;
3778+
col.encoding = Encoding.UTF8;
37643779
}
37653780
else
37663781
{
3767-
col.codePage = codePage;
3768-
col.encoding = System.Text.Encoding.GetEncoding(col.codePage);
3782+
int codePage = GetCodePage(col.collation, stateObj);
3783+
3784+
if (codePage == _defaultCodePage)
3785+
{
3786+
col.codePage = _defaultCodePage;
3787+
col.encoding = _defaultEncoding;
3788+
}
3789+
else
3790+
{
3791+
col.codePage = codePage;
3792+
col.encoding = System.Text.Encoding.GetEncoding(col.codePage);
3793+
}
37693794
}
37703795
}
37713796

@@ -6067,6 +6092,19 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD
60676092

60686093
return len;
60696094
}
6095+
internal int WriteUTF8SupportFeatureRequest(bool write /* if false just calculates the length */)
6096+
{
6097+
int len = 5; // 1byte = featureID, 4bytes = featureData length, sizeof(DWORD)
6098+
6099+
if (write)
6100+
{
6101+
// Write Feature ID
6102+
_physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_UTF8SUPPORT);
6103+
WriteInt(0, _physicalStateObj); // we don't send any data
6104+
}
6105+
6106+
return len;
6107+
}
60706108

60716109
internal void TdsLogin(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures, SessionData recoverySessionData, FederatedAuthenticationFeatureExtensionData? fedAuthFeatureExtensionData)
60726110
{
@@ -6201,15 +6239,20 @@ internal void TdsLogin(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures
62016239
{
62026240
length += WriteSessionRecoveryFeatureRequest(recoverySessionData, false);
62036241
}
6242+
if ((requestedFeatures & TdsEnums.FeatureExtension.FedAuth) != 0)
6243+
{
6244+
Debug.Assert(fedAuthFeatureExtensionData != null, "fedAuthFeatureExtensionData should not null.");
6245+
length += WriteFedAuthFeatureRequest(fedAuthFeatureExtensionData.Value, write: false);
6246+
}
62046247
if ((requestedFeatures & TdsEnums.FeatureExtension.GlobalTransactions) != 0)
62056248
{
62066249
length += WriteGlobalTransactionsFeatureRequest(false);
62076250
}
6208-
if ((requestedFeatures & TdsEnums.FeatureExtension.FedAuth) != 0)
6251+
if ((requestedFeatures & TdsEnums.FeatureExtension.UTF8Support) != 0)
62096252
{
6210-
Debug.Assert(fedAuthFeatureExtensionData != null, "fedAuthFeatureExtensionData should not null.");
6211-
length += WriteFedAuthFeatureRequest(fedAuthFeatureExtensionData.Value, write: false);
6253+
length += WriteUTF8SupportFeatureRequest(false);
62126254
}
6255+
62136256
length++; // for terminator
62146257
}
62156258

@@ -6443,15 +6486,20 @@ internal void TdsLogin(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures
64436486
{
64446487
length += WriteSessionRecoveryFeatureRequest(recoverySessionData, true);
64456488
}
6489+
if ((requestedFeatures & TdsEnums.FeatureExtension.FedAuth) != 0)
6490+
{
6491+
Debug.Assert(fedAuthFeatureExtensionData != null, "fedAuthFeatureExtensionData should not null.");
6492+
WriteFedAuthFeatureRequest(fedAuthFeatureExtensionData.Value, write: true);
6493+
}
64466494
if ((requestedFeatures & TdsEnums.FeatureExtension.GlobalTransactions) != 0)
64476495
{
64486496
WriteGlobalTransactionsFeatureRequest(true);
64496497
}
6450-
if ((requestedFeatures & TdsEnums.FeatureExtension.FedAuth) != 0)
6498+
if ((requestedFeatures & TdsEnums.FeatureExtension.UTF8Support) != 0)
64516499
{
6452-
Debug.Assert(fedAuthFeatureExtensionData != null, "fedAuthFeatureExtensionData should not null.");
6453-
WriteFedAuthFeatureRequest(fedAuthFeatureExtensionData.Value, write: true);
6454-
};
6500+
WriteUTF8SupportFeatureRequest(true);
6501+
}
6502+
64556503
_physicalStateObj.WriteByte(0xFF); // terminator
64566504
}
64576505
}
@@ -8127,6 +8175,12 @@ internal Task WriteBulkCopyValue(object value, SqlMetaDataPriv metadata, TdsPars
81278175
}
81288176
if (metadata.collation != null)
81298177
{
8178+
// Replace encoding if it is UTF8
8179+
if ((metadata.collation.info & TdsEnums.UTF8_IN_TDSCOLLATION) == TdsEnums.UTF8_IN_TDSCOLLATION)
8180+
{
8181+
_defaultEncoding = Encoding.UTF8;
8182+
}
8183+
81308184
_defaultCollation = metadata.collation;
81318185
_defaultLCID = _defaultCollation.LCID;
81328186
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Xunit;
2+
3+
namespace System.Data.SqlClient.ManualTesting.Tests
4+
{
5+
public static class Utf8SupportTest
6+
{
7+
[CheckConnStrSetupFact]
8+
public static void CheckSupportUtf8ConnectionProperty()
9+
{
10+
using (SqlConnection connection = new SqlConnection(DataTestUtility.TcpConnStr))
11+
using (SqlCommand command = new SqlCommand())
12+
{
13+
command.Connection = connection;
14+
command.CommandText = "SELECT CONNECTIONPROPERTY('SUPPORT_UTF8')";
15+
connection.Open();
16+
17+
using (SqlDataReader reader = command.ExecuteReader())
18+
{
19+
while (reader.Read())
20+
{
21+
// CONNECTIONPROPERTY('SUPPORT_UTF8') returns NULL in SQLServer versions that don't support UTF-8.
22+
if (!reader.IsDBNull(0))
23+
{
24+
Assert.Equal(1, reader.GetInt32(0));
25+
}
26+
else
27+
{
28+
Console.WriteLine("CONNECTIONPROPERTY('SUPPORT_UTF8') is not supported on this SQLServer");
29+
}
30+
}
31+
}
32+
}
33+
}
34+
}
35+
}

src/libraries/System.Data.SqlClient/tests/ManualTests/System.Data.SqlClient.ManualTesting.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
<Compile Include="SQL\UdtTest\UdtTest.cs" />
122122
<Compile Include="SQL\UdtTest\UdtTest2.cs" />
123123
<Compile Include="SQL\UdtTest\UdtTestHelpers.cs" />
124+
<Compile Include="SQL\Utf8SupportTest\Utf8SupportTest.cs" />
124125
<Compile Include="SQL\WeakRefTest\WeakRefTest.cs" />
125126
<Compile Include="SQL\WeakRefTestYukonSpecific\WeakRefTestYukonSpecific.cs" />
126127
<Compile Include="XUnitAssemblyAttributes.cs" />

0 commit comments

Comments
 (0)