Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions src/Core/Models/SqlTypeConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public static class SqlTypeConstants
{ "time", true }, // SqlDbType.Time
{ "datetime2", true }, // SqlDbType.DateTime2
{ "datetimeoffset", true }, // SqlDbType.DateTimeOffset
{ "json", true }, // SqlDbType.Json (SQL Server 2025+) treated as string
{ "", false }, // SqlDbType.Udt and SqlDbType.Structured provided by SQL as empty strings (unsupported)
{ "numeric", true}, // Not present in SqlDbType, however can be returned by sql functions like LAG and should map to decimal.
{ "vector", true } // SqlDbType.Vector
Expand Down
8 changes: 6 additions & 2 deletions src/Core/Resolvers/MsSqlDbExceptionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ public MsSqlDbExceptionParser(RuntimeConfigProvider configProvider) : base(confi
"4435", "4436", "4437", "4438", "4439", "4440", "4441",
"4442", "4443", "4444", "4445", "4446", "4447", "4448",
"4450", "4451", "4452", "4453", "4454", "4455", "4456",
"4457", "4933", "4934", "4936", "4988", "8102"
"4457", "4933", "4934", "4936", "4988", "8102",
// JSON data type validation errors (SQL Server 2025+). Invalid JSON
// supplied for a json column is a client error, mapped to HTTP 400.
"13608", "13609", "13610", "13611", "13612", "13613", "13614"
Comment thread
souvikghosh04 marked this conversation as resolved.
});

TransientExceptionCodes.UnionWith(new List<string>
Expand Down Expand Up @@ -92,8 +95,9 @@ public override DataApiBuilderException.SubStatusCodes GetResultSubStatusCodeFor
{
int errorCode = ((SqlException)e).Number;
// MSSQL 201 - Procedure or function '%.*ls' expects parameter '%.*ls', which was not supplied.
// SQL Server 2025+ JSON validation errors are also client input errors.
// Pending revisions of error code classifications, this is a temporary fix to determine substatus code.
if (errorCode == 201)
if (errorCode is 201 or 13608 or 13609 or 13610 or 13611 or 13612 or 13613 or 13614)
{
return DataApiBuilderException.SubStatusCodes.DatabaseInputError;
}
Expand Down
1 change: 1 addition & 0 deletions src/Core/Services/TypeHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public static class TypeHelper
[SqlDbType.Float] = typeof(double),
[SqlDbType.Image] = typeof(byte[]),
[SqlDbType.Int] = typeof(int),
[SqlDbType.Json] = typeof(string),
[SqlDbType.Money] = typeof(decimal),
[SqlDbType.NChar] = typeof(char),
[SqlDbType.NText] = typeof(string),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,17 @@ public void ResolveUnderlyingTypeForNullableValueType(Type nullableType)
Assert.AreNotEqual(notExpected: JsonDataType.Undefined, actual: TypeHelper.GetJsonDataTypeFromSystemType(nullableType));
Assert.IsNotNull(TypeHelper.GetDbTypeFromSystemType(nullableType));
}

/// <summary>
/// Validates that the SQL Server 2025+ 'json' data type literal resolves to the
/// CLR string type and maps to JsonDataType.String, i.e. DAB treats a JSON column
/// just like a string column.
/// </summary>
[TestMethod]
public void JsonSqlDbTypeResolvesToString()
{
Type resolvedType = TypeHelper.GetSystemTypeFromSqlDbType("json");
Assert.AreEqual(typeof(string), resolvedType);
Assert.AreEqual(JsonDataType.String, TypeHelper.GetJsonDataTypeFromSystemType(resolvedType));
}
}
44 changes: 44 additions & 0 deletions src/Service.Tests/UnitTests/DbExceptionParserUnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Azure.DataApiBuilder.Config.ObjectModel;
using Azure.DataApiBuilder.Core.Configurations;
using Azure.DataApiBuilder.Core.Resolvers;
using Azure.DataApiBuilder.Service.Exceptions;
using Azure.DataApiBuilder.Service.Tests.SqlTests;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
Expand Down Expand Up @@ -94,5 +95,48 @@ public void TestIsTransientExceptionMethod(bool expected, int number)

Assert.AreEqual(expected, dbExceptionParser.IsTransientException(SqlTestHelper.CreateSqlException(number)));
}

/// <summary>
/// Validates that JSON data type validation error codes raised by SQL Server 2025+
/// when invalid JSON is supplied for a json column are mapped to HTTP 400 Bad Request
/// and are classified as client input errors.
/// </summary>
/// <param name="number">SQL error code populated in SqlException.Number.</param>
[DataTestMethod]
[DataRow(13608, DisplayName = "JSON validation error code 13608 maps to 400")]
[DataRow(13609, DisplayName = "JSON validation error code 13609 maps to 400")]
[DataRow(13610, DisplayName = "JSON validation error code 13610 maps to 400")]
[DataRow(13611, DisplayName = "JSON validation error code 13611 maps to 400")]
[DataRow(13612, DisplayName = "JSON validation error code 13612 maps to 400")]
[DataRow(13613, DisplayName = "JSON validation error code 13613 maps to 400")]
[DataRow(13614, DisplayName = "JSON validation error code 13614 maps to 400")]
public void TestJsonValidationErrorsMapToBadRequest(int number)
{
RuntimeConfig mockConfig = new(
Schema: "",
DataSource: new(DatabaseType.MSSQL, "", new()),
Runtime: new(
Rest: new(),
GraphQL: new(),
Mcp: new(),
Host: new(null, null, HostMode.Development)
),
Entities: new(new Dictionary<string, Entity>())
);
MockFileSystem fileSystem = new();
fileSystem.AddFile(FileSystemRuntimeConfigLoader.DEFAULT_CONFIG_FILE_NAME, new MockFileData(mockConfig.ToJson()));
FileSystemRuntimeConfigLoader loader = new(fileSystem);
RuntimeConfigProvider provider = new(loader);
DbExceptionParser dbExceptionParser = new MsSqlDbExceptionParser(provider);

DbException sqlException = SqlTestHelper.CreateSqlException(number);

Assert.AreEqual(
System.Net.HttpStatusCode.BadRequest,
dbExceptionParser.GetHttpStatusCodeForException(sqlException));
Assert.AreEqual(
DataApiBuilderException.SubStatusCodes.DatabaseInputError,
dbExceptionParser.GetResultSubStatusCodeForException(sqlException));
}
Comment thread
souvikghosh04 marked this conversation as resolved.
}
}