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 bb9008f017..d171aa292a 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 @@ -4368,7 +4368,7 @@ internal TdsOperationStatus TryProcessReturnValue(int length, TdsParserStateObje } } } - else if (rec.metaType.IsCharType) + else if (rec.metaType.IsCharType && rec.metaType.SqlDbType != SqlDbTypeExtensions.Json) { // read the collation for 8.x servers result = TryProcessCollation(stateObj, out rec.collation); 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 03889347ae..3d3bddda9c 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 @@ -4837,7 +4837,7 @@ internal TdsOperationStatus TryProcessReturnValue(int length, } } } - else if (_is2000 && rec.metaType.IsCharType) + else if (_is2000 && rec.metaType.IsCharType && rec.metaType.SqlDbType != SqlDbTypeExtensions.Json) { // read the collation for 8.x servers result = TryProcessCollation(stateObj, out rec.collation); 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 1eaf878851..91530e5de6 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlParameter.cs @@ -1993,7 +1993,7 @@ internal void Validate(int index, bool isCommandProc) (SqlDbType != SqlDbType.Udt) && // BUG: (VSTFDevDiv - 479609): Output parameter with size 0 throws for XML, TEXT, NTEXT, IMAGE. // NOTE: (VSTFDevDiv - 479609): Not Fixed for TEXT, NTEXT, IMAGE as these are deprecated LOB types. - (SqlDbType != SqlDbType.Xml) && + (SqlDbType != SqlDbType.Xml && SqlDbType != SqlDbTypeExtensions.Json) && !metaType.IsVarTime ) { diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 54058a9218..dfdf1f8443 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -603,6 +603,17 @@ public static void CreateTable(SqlConnection sqlConnection, string tableName, st } } + public static void CreateSP(SqlConnection sqlConnection, string spName, string spBody) + { + DropStoredProcedure(sqlConnection, spName); + string spCreate = "CREATE PROCEDURE " + spName + spBody; + using (SqlCommand command = sqlConnection.CreateCommand()) + { + command.CommandText = spCreate; + command.ExecuteNonQuery(); + } + } + public static void DropTable(SqlConnection sqlConnection, string tableName) { ResurrectConnection(sqlConnection); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonTest.cs index cc8b43f1a6..ccf0c00919 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/JsonTest/JsonTest.cs @@ -10,6 +10,7 @@ using Xunit; using Xunit.Abstractions; using System.Text.Json; +using Microsoft.Data.SqlTypes; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { @@ -124,6 +125,12 @@ public void TestJsonWrite() ValidateRowsAffected(rowsAffected3); } + //Test 4 + // Write json value using a parameterized query with SqlJson type + parameter.Value = new SqlJson(JsonDataString); + int rowsAffected4 = command.ExecuteNonQuery(); + ValidateRowsAffected(rowsAffected4); + DataTestUtility.DropTable(connection, tableName); DataTestUtility.DropStoredProcedure(connection, spName); } @@ -182,6 +189,12 @@ public async Task TestJsonWriteAsync() ValidateRowsAffected(rowsAffected3); } + //Test 4 + // Write json value using a parameterized query with SqlJson type + parameter.Value = new SqlJson(JsonDataString); + int rowsAffected4 = await command.ExecuteNonQueryAsync(); + ValidateRowsAffected(rowsAffected4); + DataTestUtility.DropTable(connection, tableName); DataTestUtility.DropStoredProcedure(connection, spName); } @@ -354,7 +367,7 @@ public void TestJsonAPIs() // Create Table DataTestUtility.CreateTable(connection, tableName, "(Data json)"); - // Insert Null value + //Insert command.CommandText = tableInsert; var parameter = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json); parameter.Value = JsonDataString; @@ -373,6 +386,7 @@ public void TestJsonAPIs() Assert.Equal(JsonDataString, jsonDocument.RootElement.ToString()); Assert.Equal("json", reader.GetDataTypeName(0)); Assert.Equal("System.String", reader.GetFieldType(0).ToString()); + Assert.Equal(JsonDataString, reader.GetSqlJson(0).Value); } } } @@ -439,5 +453,57 @@ public void TestJsonWithMARS() } } } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsJsonSupported))] + public void TestJsonSPParams() + { + string tableName = DataTestUtility.GenerateObjectName(); + string procName = DataTestUtility.GenerateObjectName(); + string tableInsert = $"INSERT INTO {tableName} VALUES (@id, @jsonData)"; + string tableRead = $"SELECT * FROM {tableName}"; + + using (SqlConnection connection = new SqlConnection(DataTestUtility.TCPConnectionString)) + { + connection.Open(); + try + { + // Create Table + DataTestUtility.CreateTable(connection, tableName, "(Id int, Data json)"); + + // Create Stored Procedure + string createSP = $@" + @id int, + @jsonData json OUTPUT + AS + BEGIN + SELECT @jsonData = (SELECT Data FROM {tableName} WHERE Id = @id) + END;"; + DataTestUtility.CreateSP(connection, procName, createSP); + + // Insert Data + using (SqlCommand command = new SqlCommand(tableInsert, connection)) + { + command.Parameters.Add(new SqlParameter("@id", SqlDbType.Int) { Value = 1 }); + command.Parameters.Add(new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Value = JsonDataString }); + command.ExecuteNonQuery(); + } + + // Execute Stored Procedure + using (SqlCommand spCommand = new SqlCommand(procName, connection)) + { + spCommand.CommandType = CommandType.StoredProcedure; + spCommand.Parameters.Add(new SqlParameter("@id", SqlDbType.Int) { Direction = ParameterDirection.Input, Value = 1 }); + SqlParameter outputParam = new SqlParameter("@jsonData", SqlDbTypeExtensions.Json) { Direction = ParameterDirection.Output }; + spCommand.Parameters.Add(outputParam); + spCommand.ExecuteNonQuery(); + Assert.Equal(JsonDataString, (string)outputParam.Value); + } + } + finally + { + DataTestUtility.DropTable(connection, tableName); + } + } + } } }