diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index 5ef3d781ea..7f9f74577c 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -201,6 +201,9 @@ internal bool IsDNSCachingBeforeRedirectSupported internal SQLDNSInfo pendingSQLDNSObject = null; + // Json Support Flag + internal bool IsJsonSupportEnabled = false; + // TCE flags internal byte _tceVersionSupported; @@ -1365,6 +1368,8 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword, // The SQLDNSCaching feature is implicitly set requestedFeatures |= TdsEnums.FeatureExtension.SQLDNSCaching; + requestedFeatures |= TdsEnums.FeatureExtension.JsonSupport; + _parser.TdsLogin(login, requestedFeatures, _recoverySessionData, _fedAuthFeatureExtensionData, encrypt); } @@ -2812,6 +2817,24 @@ internal void OnFeatureExtAck(int featureId, byte[] data) break; } + case TdsEnums.FEATUREEXT_JSONSUPPORT: + { + SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Received feature extension acknowledgement for JSONSUPPORT", ObjectID); + if (data.Length != 1) + { + SqlClientEventSource.Log.TryTraceEvent(" {0}, Unknown token for JSONSUPPORT", ObjectID); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); + } + byte jsonSupportVersion = data[0]; + if (jsonSupportVersion == 0 || jsonSupportVersion > 1) + { + SqlClientEventSource.Log.TryTraceEvent(" {0}, Invalid version number for JSONSUPPORT", ObjectID); + throw SQL.ParsingError(); + } + IsJsonSupportEnabled = true; + break; + } + default: { // Unknown feature ack diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs index 6af6ae7734..e43bc94952 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParser.cs @@ -8115,6 +8115,21 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return len; } + internal int WriteJsonSupportFeatureRequest(bool write /* if false just calculates the length */) + { + int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version + + if (write) + { + // Write Feature ID + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_JSONSUPPORT); + WriteInt(1, _physicalStateObj); + _physicalStateObj.WriteByte(1); + } + + return len; + } + private void WriteLoginData(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures, SessionData recoverySessionData, @@ -8425,6 +8440,11 @@ private int ApplyFeatureExData(TdsEnums.FeatureExtension requestedFeatures, length += WriteSQLDNSCachingFeatureRequest(write); } + if ((requestedFeatures & TdsEnums.FeatureExtension.JsonSupport) != 0) + { + length += WriteJsonSupportFeatureRequest(write); + } + length++; // for terminator if (write) { diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs index cc80af6767..672eafe472 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlInternalConnectionTds.cs @@ -212,6 +212,9 @@ internal bool IsDNSCachingBeforeRedirectSupported internal SQLDNSInfo pendingSQLDNSObject = null; + // Json Support Flag + internal bool IsJsonSupportEnabled = false; + // TCE flags internal byte _tceVersionSupported; @@ -1638,6 +1641,8 @@ private void Login(ServerInfo server, TimeoutTimer timeout, string newPassword, // The SQLDNSCaching feature is implicitly set requestedFeatures |= TdsEnums.FeatureExtension.SQLDNSCaching; + requestedFeatures |= TdsEnums.FeatureExtension.JsonSupport; + _parser.TdsLogin(login, requestedFeatures, _recoverySessionData, _fedAuthFeatureExtensionData, _originalNetworkAddressInfo, encrypt); } @@ -3239,6 +3244,24 @@ internal void OnFeatureExtAck(int featureId, byte[] data) break; } + case TdsEnums.FEATUREEXT_JSONSUPPORT: + { + SqlClientEventSource.Log.TryAdvancedTraceEvent(" {0}, Received feature extension acknowledgement for JSONSUPPORT", ObjectID); + if (data.Length != 1) + { + SqlClientEventSource.Log.TryTraceEvent(" {0}, Unknown token for JSONSUPPORT", ObjectID); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); + } + byte jsonSupportVersion = data[0]; + if (jsonSupportVersion == 0 || jsonSupportVersion > 1) + { + SqlClientEventSource.Log.TryTraceEvent(" {0}, Invalid version number for JSONSUPPORT", ObjectID); + throw SQL.ParsingError(ParsingErrorState.CorruptedTdsStream); + } + IsJsonSupportEnabled = true; + break; + } + default: { // Unknown feature ack 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 0c74f8f61b..639e6f5a98 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 @@ -8914,6 +8914,21 @@ internal int WriteFedAuthFeatureRequest(FederatedAuthenticationFeatureExtensionD return len; } + internal int WriteJsonSupportFeatureRequest(bool write /* if false just calculates the length */) + { + int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version + + if (write) + { + // Write Feature ID + _physicalStateObj.WriteByte(TdsEnums.FEATUREEXT_JSONSUPPORT); + WriteInt(1, _physicalStateObj); + _physicalStateObj.WriteByte(1); + } + + return len; + } + private void WriteLoginData(SqlLogin rec, TdsEnums.FeatureExtension requestedFeatures, SessionData recoverySessionData, @@ -9241,6 +9256,11 @@ private int ApplyFeatureExData(TdsEnums.FeatureExtension requestedFeatures, length += WriteSQLDNSCachingFeatureRequest(write); } + if ((requestedFeatures & TdsEnums.FeatureExtension.JsonSupport) != 0) + { + length += WriteJsonSupportFeatureRequest(write); + } + length++; // for terminator if (write) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs index 8c7119a695..f8b320be1a 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -238,6 +238,7 @@ public enum EnvChangeType : byte public const byte FEATUREEXT_DATACLASSIFICATION = 0x09; public const byte FEATUREEXT_UTF8SUPPORT = 0x0A; public const byte FEATUREEXT_SQLDNSCACHING = 0x0B; + public const byte FEATUREEXT_JSONSUPPORT = 0x0D; [Flags] public enum FeatureExtension : uint @@ -250,7 +251,8 @@ public enum FeatureExtension : uint AzureSQLSupport = 1 << (TdsEnums.FEATUREEXT_AZURESQLSUPPORT - 1), DataClassification = 1 << (TdsEnums.FEATUREEXT_DATACLASSIFICATION - 1), UTF8Support = 1 << (TdsEnums.FEATUREEXT_UTF8SUPPORT - 1), - SQLDNSCaching = 1 << (TdsEnums.FEATUREEXT_SQLDNSCACHING - 1) + SQLDNSCaching = 1 << (TdsEnums.FEATUREEXT_SQLDNSCACHING - 1), + JsonSupport = 1 << (TdsEnums.FEATUREEXT_JSONSUPPORT - 1) } public const uint UTF8_IN_TDSCOLLATION = 0x4000000; diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/ITDSServerSession.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/ITDSServerSession.cs index 0c9320f512..bbe039d426 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/ITDSServerSession.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/ITDSServerSession.cs @@ -77,5 +77,10 @@ public interface ITDSServerSession /// Indicates whether this session supports transport-level recovery /// bool IsSessionRecoveryEnabled { get; set; } + + /// + /// Indicates whether the client supports Json column type + /// + bool IsJsonSupportEnabled { get; set; } } } diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServer.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServer.cs index 535304964d..1a6e60fd08 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServer.cs @@ -230,6 +230,12 @@ public virtual TDSMessageCollection OnLogin7Request(ITDSServerSession session, T // Save the fed auth library to be used (session as GenericTDSServerSession).FederatedAuthenticationLibrary = federatedAuthenticationOption.Library; + break; + } + case TDSFeatureID.JsonSupport: + { + // Enable Json Support + session.IsJsonSupportEnabled = true; break; } default: @@ -544,6 +550,32 @@ protected virtual TDSMessageCollection OnAuthenticationCompleted(ITDSServerSessi responseMessage.Add(featureExtActToken); } + // Check if Json is supported + if (session.IsJsonSupportEnabled) + { + // Create ack data (1 byte: Version number) + byte[] data = new byte[1]; + data[0] = (byte)1; + + // Create Json support as a generic feature extension option + TDSFeatureExtAckGenericOption jsonSupportOption = new TDSFeatureExtAckGenericOption(TDSFeatureID.JsonSupport, (uint)data.Length, data); + + // Look for feature extension token + TDSFeatureExtAckToken featureExtAckToken = (TDSFeatureExtAckToken)responseMessage.Where(t => t is TDSFeatureExtAckToken).FirstOrDefault(); + + if (featureExtAckToken == null) + { + // Create feature extension ack token + featureExtAckToken = new TDSFeatureExtAckToken(jsonSupportOption); + responseMessage.Add(featureExtAckToken); + } + else + { + // Update the existing token + featureExtAckToken.Options.Add(jsonSupportOption); + } + } + // Create DONE token TDSDoneToken doneToken = new TDSDoneToken(TDSDoneTokenStatusType.Final); diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServerSession.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServerSession.cs index 4c1de9f986..3272036e15 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServerSession.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/GenericTDSServerSession.cs @@ -108,6 +108,11 @@ public class GenericTDSServerSession : ITDSServerSession /// public bool IsSessionRecoveryEnabled { get; set; } + /// + /// Indicates whether this session supports Json column type + /// + public bool IsJsonSupportEnabled { get; set; } + #region Session Options /// diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSFeatureID.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSFeatureID.cs index bac86b591c..eb84a631d0 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSFeatureID.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSFeatureID.cs @@ -19,6 +19,11 @@ public enum TDSFeatureID : byte /// FederatedAuthentication = 0x02, + /// + /// JSON Support + /// + JsonSupport = 0x0D, + /// /// End of the list ///