HiveBrain v1.2.0
Get Started
← Back to all entries
debugsqlMinor

Why does this throw a JSON parsing error and why can't I trap it?

Submitted by: @import:stackexchange-dba··
0
Viewed 0 times
thiswhyerrorcanandjsontrapparsingdoesthrow

Problem

Consider the below function which returns a portion of a well-formatted JSON object. It will return "Bad JSON" when the JSON is not well-formatted. Importantly, it will not error when the JSON is not well-formatted.

CREATE OR ALTER FUNCTION TestJSONParse
(
    @nv nvarchar(max)
)
RETURNS TABLE 
AS
RETURN 
(
    SELECT
        v3 = isNull(t2.v2,t1.v1)
    FROM        (
                    SELECT
                        v1 = 'Bad JSON'
                ) AS t1
    LEFT JOIN   (
                    SELECT
                        v2 = JSON_VALUE(@nv,'$.prop')
                    WHERE ISJSON(@nv) <> 0
                ) AS t2
    ON          1 = 1
);
GO

SELECT * FROM TestJSONParse('{"prop": "Good JSON"}');
SELECT * FROM TestJSONParse('zzzz');
GO


Results:

v3
Good JSON

v3
Bad JSON


So far, so good.

Now I want to use this function in a procedure and feed it the same bad JSON:

CREATE OR ALTER PROCEDURE TestJSONParseProc
(
    @nv nvarchar(max)
)
AS
BEGIN
    BEGIN TRY
        DECLARE @v nvarchar(max);
        SELECT
            @v = v3
        FROM        TestJSONParse(@nv);
    END TRY
    BEGIN CATCH
        SELECT
            Result = N'I have caught an error.';
    END CATCH
END
GO

EXEC TestJSONParseProc
    @nv = N'zzzz';
GO


Results:

Msg 13609, Level 16, State 2, Procedure TestJSONParseProc, Line 10 [Batch Start Line 45]
JSON text is not properly formatted. Unexpected character 'z' is found at position 0.


-
Why does this error occur? The evaluation of JSON_VALUE should not take place because ISJSON should be 0 and therefore the row is filtered from the results.

-
Why isn't this error caught by the BEGIN TRY?

I found a suggestion online that this was some sort of a compilation error. Some support for that conclusion is provided by the behavior when the first call of the procedure after creation is with valid JSON:

```
CREATE OR ALTER PROCEDURE TestJSONParseProc
(
@nv nvarchar(max)
)
AS
BEGIN
BEGIN TRY
DECLARE

Solution

You need to use the ISJSON() function to verify the column is valid JSON in the SELECT clause regardless of the WHERE clause. The reasoning for this is because contrary to popular belief, sometimes the SQL Engine generates an execution plan where it finds it more efficient to evaluate the SELECT clause before the WHERE clause is applied. That results in these odd cases where an exception is thrown unbeknownst to the average developer why.

So inside your TestJSONParse() function you'll need to change the line of code v2 = JSON_VALUE(@nv,'$.prop') to v2 = CASE WHEN ISJSON(@nv) = 1 THEN JSON_VALUE(@nv,'$.prop') ELSE NULL, for example.

Context

StackExchange Database Administrators Q#290588, answer score: 3

Revisions (0)

No revisions yet.