From 6e95e72aea25a0c727f7f5d666676778c14de90f Mon Sep 17 00:00:00 2001 From: Apoorv Deshmukh Date: Thu, 25 Jul 2024 17:02:51 +0530 Subject: [PATCH 1/4] Implement read functionality for JSON col --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 3 ++- .../netcore/src/Microsoft/Data/SqlClient/SqlJson.cs | 10 ++++++++++ .../netcore/src/Microsoft/Data/SqlClient/TdsParser.cs | 7 +++++-- .../netfx/src/Microsoft.Data.SqlClient.csproj | 3 ++- .../netfx/src/Microsoft/Data/SqlClient/SqlJson.cs | 10 ++++++++++ .../netfx/src/Microsoft/Data/SqlClient/TdsParser.cs | 5 ++++- .../src/Microsoft/Data/SqlClient/SqlEnums.cs | 5 +++++ .../src/Microsoft/Data/SqlClient/TdsEnums.cs | 3 +++ 8 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlJson.cs create mode 100644 src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlJson.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 9c7cf50ee5..0b150666b2 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -936,6 +936,7 @@ True Strings.resx + Resources\Strings.resx Microsoft.Data.SqlClient.Resources.Strings.resources @@ -958,7 +959,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlJson.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlJson.cs new file mode 100644 index 0000000000..5a7f7b62d4 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlJson.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Data.SqlClient +{ + internal class SqlJson + { + } +} \ No newline at end of file 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 c3291e4e5d..cc7e4851e2 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 @@ -5178,7 +5178,7 @@ private TdsOperationStatus TryProcessTypeInfo(TdsParserStateObject stateObj, Sql } // read the collation for 7.x servers - if (col.metaType.IsCharType && (tdsType != TdsEnums.SQLXMLTYPE)) + if (col.metaType.IsCharType && (tdsType != TdsEnums.SQLXMLTYPE) && ((tdsType != TdsEnums.SQLJSON))) { result = TryProcessCollation(stateObj, out col.collation); if (result != TdsOperationStatus.Done) @@ -5958,6 +5958,7 @@ private TdsOperationStatus TryReadSqlStringValue(SqlBuffer value, byte type, int case TdsEnums.SQLVARCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: + case TdsEnums.SQLJSON: // If bigvarchar(max), we only read the first chunk here, // expecting the caller to read the rest if (encoding == null) @@ -6427,6 +6428,7 @@ internal TdsOperationStatus TryReadSqlValue(SqlBuffer value, SqlMetaDataPriv md, case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: + case TdsEnums.SQLJSON: result = TryReadSqlStringValue(value, tdsType, length, md.encoding, isPlp, stateObj); if (result != TdsOperationStatus.Done) { @@ -7964,6 +7966,7 @@ internal TdsOperationStatus TryGetDataLength(SqlMetaDataPriv colmeta, TdsParserS colmeta.tdsType == TdsEnums.SQLBIGVARCHAR || colmeta.tdsType == TdsEnums.SQLBIGVARBINARY || colmeta.tdsType == TdsEnums.SQLNVARCHAR || + colmeta.tdsType == TdsEnums.SQLJSON || // Large UDTs is WinFS-only colmeta.tdsType == TdsEnums.SQLUDT, "GetDataLength:Invalid streaming datatype"); @@ -9905,7 +9908,7 @@ private Task TDSExecuteRPCAddParameter(TdsParserStateObject stateObj, SqlParamet stateObj.WriteByte(0); // No schema } } - else if (mt.IsCharType) + else if (mt.IsCharType && mt.SqlDbType != SqlDbTypeExtensions.Json) { // if it is not supplied, simply write out our default collation, otherwise, write out the one attached to the parameter SqlCollation outCollation = (param.Collation != null) ? param.Collation : _defaultCollation; diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 840f5b6520..a07ede0711 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -704,6 +704,7 @@ + @@ -756,7 +757,7 @@ - + $(SystemTextEncodingsWebVersion) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlJson.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlJson.cs new file mode 100644 index 0000000000..6e1d1bca06 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlJson.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Data.SqlClient +{ + internal class SqlJson + { + } +} 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 459b230be6..1c4f20e931 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 @@ -5876,7 +5876,7 @@ private TdsOperationStatus TryProcessTypeInfo(TdsParserStateObject stateObj, Sql } // read the collation for 7.x servers - if (_is2000 && col.metaType.IsCharType && (tdsType != TdsEnums.SQLXMLTYPE)) + if (_is2000 && col.metaType.IsCharType && (tdsType != TdsEnums.SQLXMLTYPE) && (tdsType != TdsEnums.SQLJSON)) { result = TryProcessCollation(stateObj, out col.collation); if (result != TdsOperationStatus.Done) @@ -6805,6 +6805,7 @@ private TdsOperationStatus TryReadSqlStringValue(SqlBuffer value, byte type, int case TdsEnums.SQLVARCHAR: case TdsEnums.SQLBIGVARCHAR: case TdsEnums.SQLTEXT: + case TdsEnums.SQLJSON: // If bigvarchar(max), we only read the first chunk here, // expecting the caller to read the rest if (encoding == null) @@ -7255,6 +7256,7 @@ internal TdsOperationStatus TryReadSqlValue(SqlBuffer value, case TdsEnums.SQLNCHAR: case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: + case TdsEnums.SQLJSON: result = TryReadSqlStringValue(value, tdsType, length, md.encoding, isPlp, stateObj); if (result != TdsOperationStatus.Done) { @@ -8777,6 +8779,7 @@ internal TdsOperationStatus TryGetDataLength(SqlMetaDataPriv colmeta, TdsParserS colmeta.tdsType == TdsEnums.SQLBIGVARCHAR || colmeta.tdsType == TdsEnums.SQLBIGVARBINARY || colmeta.tdsType == TdsEnums.SQLNVARCHAR || + colmeta.tdsType == TdsEnums.SQLJSON || // Large UDTs is WinFS-only colmeta.tdsType == TdsEnums.SQLUDT, "GetDataLength:Invalid streaming datatype"); diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs index 3fbd9b112a..1f4ec71be5 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs @@ -862,6 +862,8 @@ internal static MetaType GetSqlDataType(int tdsType, uint userType, int length) return s_metaDateTime2; case TdsEnums.SQLDATETIMEOFFSET: return MetaDateTimeOffset; + case TdsEnums.SQLJSON: + return s_MetaJson; case TdsEnums.SQLVOID: default: @@ -968,6 +970,8 @@ internal static string GetStringFromXml(XmlReader xmlreader) internal static readonly MetaType MetaDateTimeOffset = new(255, 7, -1, false, false, false, TdsEnums.SQLDATETIMEOFFSET, TdsEnums.SQLDATETIMEOFFSET, MetaTypeName.DATETIMEOFFSET, typeof(System.DateTimeOffset), typeof(System.DateTimeOffset), SqlDbType.DateTimeOffset, DbType.DateTimeOffset, 1); + internal static readonly MetaType s_MetaJson = new(255, 255, -1, false, true, true, TdsEnums.SQLJSON, TdsEnums.SQLJSON, MetaTypeName.JSON, typeof(string), typeof(SqlJson), SqlDbTypeExtensions.Json, DbType.String, 0); + public static TdsDateTime FromDateTime(DateTime dateTime, byte cb) { SqlDateTime sqlDateTime; @@ -1054,6 +1058,7 @@ private static class MetaTypeName public const string TIME = "time"; public const string DATETIME2 = "datetime2"; public const string DATETIMEOFFSET = "datetimeoffset"; + public const string JSON = "json"; } } 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 f8b320be1a..9f5d532832 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -490,6 +490,9 @@ public enum ActiveDirectoryWorkflow : byte public const int SQLDATETIME2 = 0x2a; public const int SQLDATETIMEOFFSET = 0x2b; + // New datatypes + public const int SQLJSON = 0xF4; + public const int DEFAULT_VARTIME_SCALE = 7; //Partially length prefixed datatypes constants. These apply to XMLTYPE, BIGVARCHRTYPE, From b83b3e5ff2fd99bff0ff7262a83600ac5a67d50b Mon Sep 17 00:00:00 2001 From: Apoorv Deshmukh Date: Fri, 26 Jul 2024 23:06:12 +0530 Subject: [PATCH 2/4] Remove SqlJson class --- .../netcore/src/Microsoft.Data.SqlClient.csproj | 1 - .../netcore/src/Microsoft/Data/SqlClient/SqlJson.cs | 10 ---------- .../netfx/src/Microsoft.Data.SqlClient.csproj | 1 - .../netfx/src/Microsoft/Data/SqlClient/SqlJson.cs | 10 ---------- .../src/Microsoft/Data/SqlClient/SqlEnums.cs | 2 +- 5 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlJson.cs delete mode 100644 src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlJson.cs diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj index 0b150666b2..dc5fc9dd51 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft.Data.SqlClient.csproj @@ -936,7 +936,6 @@ True Strings.resx - Resources\Strings.resx Microsoft.Data.SqlClient.Resources.Strings.resources diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlJson.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlJson.cs deleted file mode 100644 index 5a7f7b62d4..0000000000 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlJson.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Data.SqlClient -{ - internal class SqlJson - { - } -} \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index a07ede0711..9e4fffdfa1 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -704,7 +704,6 @@ - diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlJson.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlJson.cs deleted file mode 100644 index 6e1d1bca06..0000000000 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlJson.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Data.SqlClient -{ - internal class SqlJson - { - } -} diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs index 1f4ec71be5..f61fceb1b2 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs @@ -970,7 +970,7 @@ internal static string GetStringFromXml(XmlReader xmlreader) internal static readonly MetaType MetaDateTimeOffset = new(255, 7, -1, false, false, false, TdsEnums.SQLDATETIMEOFFSET, TdsEnums.SQLDATETIMEOFFSET, MetaTypeName.DATETIMEOFFSET, typeof(System.DateTimeOffset), typeof(System.DateTimeOffset), SqlDbType.DateTimeOffset, DbType.DateTimeOffset, 1); - internal static readonly MetaType s_MetaJson = new(255, 255, -1, false, true, true, TdsEnums.SQLJSON, TdsEnums.SQLJSON, MetaTypeName.JSON, typeof(string), typeof(SqlJson), SqlDbTypeExtensions.Json, DbType.String, 0); + internal static readonly MetaType s_MetaJson = new(255, 255, -1, false, true, true, TdsEnums.SQLJSON, TdsEnums.SQLJSON, MetaTypeName.JSON, typeof(string), typeof(string), SqlDbTypeExtensions.Json, DbType.String, 0); public static TdsDateTime FromDateTime(DateTime dateTime, byte cb) { From 5297458af5374f58ee9194b46e1fc9429643fb8a Mon Sep 17 00:00:00 2001 From: Deepak Saini Date: Fri, 26 Jul 2024 23:08:41 +0530 Subject: [PATCH 3/4] json write changes --- .../Microsoft/Data/SqlClient/SqlCommand.cs | 2 +- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 97 ++++++++++------- .../Microsoft/Data/SqlClient/SqlCommand.cs | 2 +- .../src/Microsoft/Data/SqlClient/TdsParser.cs | 101 +++++++++++------- .../src/Microsoft/Data/SqlClient/SqlEnums.cs | 2 + .../Microsoft/Data/SqlClient/SqlParameter.cs | 1 + 6 files changed, 123 insertions(+), 82 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs index 015fb6c1fe..d811c3f021 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -6471,7 +6471,7 @@ internal string BuildParamList(TdsParser parser, SqlParameterCollection paramete paramList.Append(size); paramList.Append(')'); } - else if (mt.IsPlp && (mt.SqlDbType != SqlDbType.Xml) && (mt.SqlDbType != SqlDbType.Udt)) + else if (mt.IsPlp && (mt.SqlDbType != SqlDbType.Xml) && (mt.SqlDbType != SqlDbType.Udt) && (mt.SqlDbType != SqlDbTypeExtensions.Json)) { paramList.Append("(max) "); } 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 cc7e4851e2..f8865b5540 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 @@ -9822,7 +9822,7 @@ private Task TDSExecuteRPCAddParameter(TdsParserStateObject stateObj, SqlParamet } else if (mt.IsPlp) { - if (mt.SqlDbType != SqlDbType.Xml) + if (mt.SqlDbType != SqlDbType.Xml && mt.SqlDbType != SqlDbTypeExtensions.Json) WriteShort(TdsEnums.SQL_USHORTVARMAXLEN, stateObj); } else if ((!mt.IsVarTime) && (mt.SqlDbType != SqlDbType.Date)) @@ -9862,51 +9862,54 @@ private Task TDSExecuteRPCAddParameter(TdsParserStateObject stateObj, SqlParamet // write out collation or xml metadata - if (_is2005 && (mt.SqlDbType == SqlDbType.Xml)) + if ((mt.SqlDbType == SqlDbType.Xml || mt.SqlDbType == SqlDbTypeExtensions.Json)) { - if (!string.IsNullOrEmpty(param.XmlSchemaCollectionDatabase) || - !string.IsNullOrEmpty(param.XmlSchemaCollectionOwningSchema) || - !string.IsNullOrEmpty(param.XmlSchemaCollectionName)) + if (mt.SqlDbType == SqlDbType.Xml) { - stateObj.WriteByte(1); //Schema present flag - - if (!string.IsNullOrEmpty(param.XmlSchemaCollectionDatabase)) + if (!string.IsNullOrEmpty(param.XmlSchemaCollectionDatabase) || + !string.IsNullOrEmpty(param.XmlSchemaCollectionOwningSchema) || + !string.IsNullOrEmpty(param.XmlSchemaCollectionName)) { - tempLen = (param.XmlSchemaCollectionDatabase).Length; - stateObj.WriteByte((byte)(tempLen)); - WriteString(param.XmlSchemaCollectionDatabase, tempLen, 0, stateObj); - } - else - { - stateObj.WriteByte(0); // No dbname - } + stateObj.WriteByte(1); //Schema present flag - if (!string.IsNullOrEmpty(param.XmlSchemaCollectionOwningSchema)) - { - tempLen = (param.XmlSchemaCollectionOwningSchema).Length; - stateObj.WriteByte((byte)(tempLen)); - WriteString(param.XmlSchemaCollectionOwningSchema, tempLen, 0, stateObj); - } - else - { - stateObj.WriteByte(0); // no xml schema name - } + if (!string.IsNullOrEmpty(param.XmlSchemaCollectionDatabase)) + { + tempLen = (param.XmlSchemaCollectionDatabase).Length; + stateObj.WriteByte((byte)(tempLen)); + WriteString(param.XmlSchemaCollectionDatabase, tempLen, 0, stateObj); + } + else + { + stateObj.WriteByte(0); // No dbname + } + + if (!string.IsNullOrEmpty(param.XmlSchemaCollectionOwningSchema)) + { + tempLen = (param.XmlSchemaCollectionOwningSchema).Length; + stateObj.WriteByte((byte)(tempLen)); + WriteString(param.XmlSchemaCollectionOwningSchema, tempLen, 0, stateObj); + } + else + { + stateObj.WriteByte(0); // no xml schema name + } + if (!string.IsNullOrEmpty(param.XmlSchemaCollectionName)) + { + tempLen = (param.XmlSchemaCollectionName).Length; + WriteShort((short)(tempLen), stateObj); + WriteString(param.XmlSchemaCollectionName, tempLen, 0, stateObj); + } + else + { + WriteShort(0, stateObj); // No xml schema collection name + } - if (!string.IsNullOrEmpty(param.XmlSchemaCollectionName)) - { - tempLen = (param.XmlSchemaCollectionName).Length; - WriteShort((short)(tempLen), stateObj); - WriteString(param.XmlSchemaCollectionName, tempLen, 0, stateObj); } else { - WriteShort(0, stateObj); // No xml schema collection name + stateObj.WriteByte(0); // No schema } } - else - { - stateObj.WriteByte(0); // No schema - } } else if (mt.IsCharType && mt.SqlDbType != SqlDbTypeExtensions.Json) { @@ -11488,10 +11491,18 @@ private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLe case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: case TdsEnums.SQLXMLTYPE: + case TdsEnums.SQLJSON: if (type.IsPlp) { - if (IsBOMNeeded(type, value)) + if (type.NullableType == TdsEnums.SQLJSON) + { + // TODO : Performance and BOM check. Saurabh + byte[] jsonAsBytes = Encoding.UTF8.GetBytes(value.ToString()); + WriteInt(jsonAsBytes.Length, stateObj); + return stateObj.WriteByteArray(jsonAsBytes, jsonAsBytes.Length, 0, canAccumulate: false); + } + else if (IsBOMNeeded(type, value)) { WriteInt(actualLength + 2, stateObj); // chunk length WriteShort(TdsEnums.XMLUNICODEBOM, stateObj); @@ -12138,6 +12149,7 @@ private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: case TdsEnums.SQLXMLTYPE: + case TdsEnums.SQLJSON: { Debug.Assert(!isDataFeed || (value is TextDataFeed || value is XmlDataFeed), "Value must be a TextReader or XmlReader"); Debug.Assert(isDataFeed || (value is string || value is byte[]), "Value is a byte array or string"); @@ -12159,7 +12171,14 @@ private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int { if (type.IsPlp) { - if (IsBOMNeeded(type, value)) + if (type.NullableType == TdsEnums.SQLJSON) + { + // TODO : Performance and BOM check. Saurabh + byte[] jsonAsBytes = Encoding.UTF8.GetBytes((string)value); + WriteInt(jsonAsBytes.Length, stateObj); + return stateObj.WriteByteArray(jsonAsBytes, jsonAsBytes.Length, 0, canAccumulate: false); + } + else if (IsBOMNeeded(type, value)) { WriteInt(actualLength + 2, stateObj); // chunk length WriteShort(TdsEnums.XMLUNICODEBOM, stateObj); @@ -12665,7 +12684,7 @@ internal void WriteParameterVarLen(MetaType type, int size, bool isNull, TdsPars WriteInt(unchecked((int)TdsEnums.VARLONGNULL), stateObj); } } - else if (type.NullableType == TdsEnums.SQLXMLTYPE || unknownLength) + else if (type.NullableType is TdsEnums.SQLXMLTYPE or TdsEnums.SQLJSON || unknownLength) { WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, stateObj); } diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs index 00b17a0213..fcb8aaf58c 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/SqlCommand.cs @@ -7180,7 +7180,7 @@ internal string BuildParamList(TdsParser parser, SqlParameterCollection paramete paramList.Append(size); paramList.Append(')'); } - else if (mt.IsPlp && (mt.SqlDbType != SqlDbType.Xml) && (mt.SqlDbType != SqlDbType.Udt)) + else if (mt.IsPlp && (mt.SqlDbType != SqlDbType.Xml) && (mt.SqlDbType != SqlDbType.Udt) && (mt.SqlDbType != SqlDbTypeExtensions.Json)) { paramList.Append("(max) "); } 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 1c4f20e931..cc91798a0c 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 @@ -10573,7 +10573,7 @@ internal Task TdsExecuteRPC(SqlCommand cmd, IList<_SqlRPC> rpcArray, int timeout } else if (mt.IsPlp) { - if (mt.SqlDbType != SqlDbType.Xml) + if (mt.SqlDbType != SqlDbType.Xml && mt.SqlDbType != SqlDbTypeExtensions.Json) WriteShort(TdsEnums.SQL_USHORTVARMAXLEN, stateObj); } else if ((!mt.IsVarTime) && (mt.SqlDbType != SqlDbType.Date)) @@ -10614,53 +10614,56 @@ internal Task TdsExecuteRPC(SqlCommand cmd, IList<_SqlRPC> rpcArray, int timeout // write out collation or xml metadata - if (_is2005 && (mt.SqlDbType == SqlDbType.Xml)) + if ((mt.SqlDbType == SqlDbType.Xml || mt.SqlDbType == SqlDbTypeExtensions.Json)) { - if (!string.IsNullOrEmpty(param.XmlSchemaCollectionDatabase) || - !string.IsNullOrEmpty(param.XmlSchemaCollectionOwningSchema) || - !string.IsNullOrEmpty(param.XmlSchemaCollectionName)) + if (mt.SqlDbType == SqlDbType.Xml) { - stateObj.WriteByte(1); //Schema present flag - - if (!string.IsNullOrEmpty(param.XmlSchemaCollectionDatabase)) + if (!string.IsNullOrEmpty(param.XmlSchemaCollectionDatabase) || + !string.IsNullOrEmpty(param.XmlSchemaCollectionOwningSchema) || + !string.IsNullOrEmpty(param.XmlSchemaCollectionName)) { - tempLen = (param.XmlSchemaCollectionDatabase).Length; - stateObj.WriteByte((byte)(tempLen)); - WriteString(param.XmlSchemaCollectionDatabase, tempLen, 0, stateObj); - } - else - { - stateObj.WriteByte(0); // No dbname - } + stateObj.WriteByte(1); //Schema present flag + + if (!string.IsNullOrEmpty(param.XmlSchemaCollectionDatabase)) + { + tempLen = (param.XmlSchemaCollectionDatabase).Length; + stateObj.WriteByte((byte)(tempLen)); + WriteString(param.XmlSchemaCollectionDatabase, tempLen, 0, stateObj); + } + else + { + stateObj.WriteByte(0); // No dbname + } + + if (!string.IsNullOrEmpty(param.XmlSchemaCollectionOwningSchema)) + { + tempLen = (param.XmlSchemaCollectionOwningSchema).Length; + stateObj.WriteByte((byte)(tempLen)); + WriteString(param.XmlSchemaCollectionOwningSchema, tempLen, 0, stateObj); + } + else + { + stateObj.WriteByte(0); // no xml schema name + } + if (!string.IsNullOrEmpty(param.XmlSchemaCollectionName)) + { + tempLen = (param.XmlSchemaCollectionName).Length; + WriteShort((short)(tempLen), stateObj); + WriteString(param.XmlSchemaCollectionName, tempLen, 0, stateObj); + } + else + { + WriteShort(0, stateObj); // No xml schema collection name + } - if (!string.IsNullOrEmpty(param.XmlSchemaCollectionOwningSchema)) - { - tempLen = (param.XmlSchemaCollectionOwningSchema).Length; - stateObj.WriteByte((byte)(tempLen)); - WriteString(param.XmlSchemaCollectionOwningSchema, tempLen, 0, stateObj); - } - else - { - stateObj.WriteByte(0); // no xml schema name - } - if (!string.IsNullOrEmpty(param.XmlSchemaCollectionName)) - { - tempLen = (param.XmlSchemaCollectionName).Length; - WriteShort((short)(tempLen), stateObj); - WriteString(param.XmlSchemaCollectionName, tempLen, 0, stateObj); } else { - WriteShort(0, stateObj); // No xml schema collection name + stateObj.WriteByte(0); // No schema } - - } - else - { - stateObj.WriteByte(0); // No schema } } - else if (_is2000 && mt.IsCharType) + else if (mt.IsCharType && mt.SqlDbType != SqlDbTypeExtensions.Json) { // if it is not supplied, simply write out our default collation, otherwise, write out the one attached to the parameter SqlCollation outCollation = (param.Collation != null) ? param.Collation : _defaultCollation; @@ -12435,10 +12438,18 @@ private Task WriteUnterminatedSqlValue(object value, MetaType type, int actualLe case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: case TdsEnums.SQLXMLTYPE: + case TdsEnums.SQLJSON: if (type.IsPlp) { - if (IsBOMNeeded(type, value)) + if (type.NullableType == TdsEnums.SQLJSON) + { + // TODO : Performance and BOM check. Saurabh + byte[] jsonAsBytes = Encoding.UTF8.GetBytes(value.ToString()); + WriteInt(jsonAsBytes.Length, stateObj); + return stateObj.WriteByteArray(jsonAsBytes, jsonAsBytes.Length, 0, canAccumulate: false); + } + else if (IsBOMNeeded(type, value)) { WriteInt(actualLength + 2, stateObj); // chunk length WriteShort(TdsEnums.XMLUNICODEBOM, stateObj); @@ -13127,6 +13138,7 @@ private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int case TdsEnums.SQLNVARCHAR: case TdsEnums.SQLNTEXT: case TdsEnums.SQLXMLTYPE: + case TdsEnums.SQLJSON: { Debug.Assert(!isDataFeed || (value is TextDataFeed || value is XmlDataFeed), "Value must be a TextReader or XmlReader"); Debug.Assert(isDataFeed || (value is string || value is byte[]), "Value is a byte array or string"); @@ -13148,7 +13160,14 @@ private Task WriteUnterminatedValue(object value, MetaType type, byte scale, int { if (type.IsPlp) { - if (IsBOMNeeded(type, value)) + if (type.NullableType == TdsEnums.SQLJSON) + { + // TODO : Performance and BOM check. Saurabh + byte[] jsonAsBytes = Encoding.UTF8.GetBytes((string)value); + WriteInt(jsonAsBytes.Length, stateObj); + return stateObj.WriteByteArray(jsonAsBytes, jsonAsBytes.Length, 0, canAccumulate: false); + } + else if (IsBOMNeeded(type, value)) { WriteInt(actualLength + 2, stateObj); // chunk length WriteShort(TdsEnums.XMLUNICODEBOM, stateObj); @@ -13655,7 +13674,7 @@ internal void WriteParameterVarLen(MetaType type, int size, bool isNull, TdsPars WriteInt(unchecked((int)TdsEnums.VARLONGNULL), stateObj); } } - else if (type.NullableType == TdsEnums.SQLXMLTYPE || unknownLength) + else if (type.NullableType is TdsEnums.SQLXMLTYPE or TdsEnums.SQLJSON || unknownLength) { WriteUnsignedLong(TdsEnums.SQL_PLP_UNKNOWNLEN, stateObj); } diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs index f61fceb1b2..fe7bfc7f9a 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlEnums.cs @@ -226,6 +226,8 @@ internal static MetaType GetMetaTypeFromSqlDbType(SqlDbType target, bool isMulti return MetaXml; case SqlDbType.Udt: return MetaUdt; + case SqlDbTypeExtensions.Json: + return s_MetaJson; case SqlDbType.Structured: if (isMultiValued) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs index a7c7fa58e1..65cd5d1e9b 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs @@ -1563,6 +1563,7 @@ internal int GetActualSize() case SqlDbType.NVarChar: case SqlDbType.NText: case SqlDbType.Xml: + case SqlDbTypeExtensions.Json: { coercedSize = ((!HasFlag(SqlParameterFlags.IsNull)) && (!HasFlag(SqlParameterFlags.CoercedValueIsDataFeed))) ? StringSize(val, HasFlag(SqlParameterFlags.CoercedValueIsSqlType)) : 0; _actualSize = (ShouldSerializeSize() ? Size : 0); From 74e37b9a60068ff97a65d25d1247d6d4e498d9d0 Mon Sep 17 00:00:00 2001 From: Apoorv Deshmukh Date: Tue, 30 Jul 2024 22:23:03 +0530 Subject: [PATCH 4/4] Remove code comment for new datatypes --- .../src/Microsoft/Data/SqlClient/TdsEnums.cs | 1 - 1 file changed, 1 deletion(-) 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 9f5d532832..058bf51dc5 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsEnums.cs @@ -490,7 +490,6 @@ public enum ActiveDirectoryWorkflow : byte public const int SQLDATETIME2 = 0x2a; public const int SQLDATETIMEOFFSET = 0x2b; - // New datatypes public const int SQLJSON = 0xF4; public const int DEFAULT_VARTIME_SCALE = 7;