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

Implement read and write functionality for JSON #2829

Merged
merged 6 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
24 changes: 24 additions & 0 deletions doc/snippets/Microsoft.Data/SqlDbTypeExtensions.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0"?>
<docs>
<members name="SqlDbTypeExtensions">
<SqlDbTypeExtensions>
<summary>Extensions for SqlDbType.</summary>
<remarks>
<format type="text/markdown">
<![CDATA[

## Remarks
The <xref:Microsoft.Data.SqlDbTypeExtensions> class provides <xref:System.Data.SqlDbType> enums which will be added. These are meant to be used by applications which cannot leverage the enums in <xref:System.Data.SqlDbType> available in newer .NET runtime versions.

]]>
</format>
</remarks>
</SqlDbTypeExtensions>
<SqlJson name="default">
<summary>Gets the <see cref="T:System.Data.SqlDbType" /> enum value for JSON datatype.</summary>
deepaksa1 marked this conversation as resolved.
Show resolved Hide resolved
<returns>
<see cref="T:System.Data.SqlDbType" /> enum value for JSON datatype.
</returns>
</SqlJson>
</members>
</docs>
1 change: 1 addition & 0 deletions src/Microsoft.Data.SqlClient.sln
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data", "Microsoft.Data", "{908C7DD3-C999-40A6-9433-9F5ACA7C36F5}"
ProjectSection(SolutionItems) = preProject
..\doc\snippets\Microsoft.Data\OperationAbortedException.xml = ..\doc\snippets\Microsoft.Data\OperationAbortedException.xml
..\doc\snippets\Microsoft.Data\SqlDbTypeExtensions.xml = ..\doc\snippets\Microsoft.Data\SqlDbTypeExtensions.xml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.Data.Sql", "Microsoft.Data.Sql", "{0CE216CE-8072-4985-B248-61F0D0BE9C2E}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
// NOTE: The current Microsoft.VSDesigner editor attributes are implemented for System.Data.SqlClient, and are not publicly available.
// New attributes that are designed to work with Microsoft.Data.SqlClient and are publicly documented should be included in future.

using System;

[assembly: System.CLSCompliant(true)]
namespace Microsoft.Data
{
Expand All @@ -15,7 +13,15 @@ public sealed partial class OperationAbortedException : System.SystemException
{
internal OperationAbortedException() { }
}

/// <include file='../../../../doc/snippets/Microsoft.Data/SqlDbTypeExtensions.xml' path='docs/members[@name="SqlDbTypeExtensions"]/SqlDbTypeExtensions/*' />
public static class SqlDbTypeExtensions
{
/// <include file='../../../../doc/snippets/Microsoft.Data/SqlDbTypeExtensions.xml' path='docs/members[@name="SqlDbTypeExtensions"]/SqlJson[@name="default"]' />
public const System.Data.SqlDbType Json = (System.Data.SqlDbType)35;
}
}

namespace Microsoft.Data.Sql
{
/// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlNotificationRequest.xml' path='docs/members[@name="SqlNotificationRequest"]/SqlNotificationRequest/*' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Data.SqlClient.SNI.runtime" Version="$(MicrosoftDataSqlClientSNIRuntimeVersion)" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryVersion)" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryVersion)" />
<!-- Enable the project reference for debugging purposes. -->
<!-- <ProjectReference Include="$(SqlServerSourceCode)\Microsoft.SqlServer.Server.csproj" /> -->
<PackageReference Include="Microsoft.SqlServer.Server" Version="$(MicrosoftSqlServerServerVersion)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6466,7 +6466,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) ");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5174,7 +5174,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)
Expand Down Expand Up @@ -5952,6 +5952,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)
Expand Down Expand Up @@ -6420,6 +6421,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)
{
Expand Down Expand Up @@ -7957,6 +7959,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");
Expand Down Expand Up @@ -9817,7 +9820,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))
Expand Down Expand Up @@ -9857,53 +9860,56 @@ 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)
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;
Expand Down Expand Up @@ -11478,10 +11484,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. For more details see https://github.com/dotnet/SqlClient/issues/2852
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);
Expand Down Expand Up @@ -12128,6 +12142,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");
Expand All @@ -12149,7 +12164,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);
Expand Down Expand Up @@ -12655,7 +12677,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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,15 @@ internal OperationAbortedException() { }
private OperationAbortedException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }

}

/// <include file='../../../../doc/snippets/Microsoft.Data/SqlDbTypeExtensions.xml' path='docs/members[@name="SqlDbTypeExtensions"]/SqlDbTypeExtensions/*' />
public static class SqlDbTypeExtensions
{
/// <include file='../../../../doc/snippets/Microsoft.Data/SqlDbTypeExtensions.xml' path='docs/members[@name="SqlDbTypeExtensions"]/SqlJson[@name="default"]' />
public const System.Data.SqlDbType Json = (System.Data.SqlDbType)35;
}
}

namespace Microsoft.Data.Sql
{
/// <include file='../../../../doc/snippets/Microsoft.Data.Sql/SqlNotificationRequest.xml' path='docs/members[@name="SqlNotificationRequest"]/SqlNotificationRequest/*' />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@
</COMReference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryVersion)" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(MicrosoftExtensionsCachingMemoryVersion)" />
<PackageReference Include="System.Text.Encodings.Web">
<Version>$(SystemTextEncodingsWebVersion)</Version>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7173,7 +7173,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) ");
}
Expand Down
Loading
Loading