8000 Fix json_to_record() bug with nested objects. · postgres/postgres@a9d199f · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit a9d199f

Browse files
committed
Fix json_to_record() bug with nested objects.
A thinko concerning nesting depth caused json_to_record() to produce bogus output if a field of its input object contained a sub-object with a field name matching one of the requested output column names. Per bug #13996 from Johann Visagie. I added a regression test case based on his example, plus parallel tests for json_to_recordset, jsonb_to_record, jsonb_to_recordset. The latter three do not exhibit the same bug (which suggests that we may be missing some opportunities to share code...) but testing seems like a good idea in any case. Back-patch to 9.4 where these functions were introduced.
1 parent eb43e85 commit a9d199f

File tree

5 files changed

+48
-1
lines changed
  • test/regress
  • 5 files changed

    +48
    -1
    lines changed

    src/backend/utils/adt/jsonfuncs.c

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -2438,7 +2438,7 @@ hash_object_field_end(void *state, char *fname, bool isnull)
    24382438
    /*
    24392439
    * Ignore nested fields.
    24402440
    */
    2441-
    if (_state->lex->lex_level > 2)
    2441+
    if (_state->lex->lex_level > 1)
    24422442
    return;
    24432443

    24442444
    /*

    src/test/regress/expected/json.out

    Lines changed: 16 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1599,6 +1599,22 @@ select * from json_to_recordset('[{"a":1,"b":{"d":"foo"},"c":true},{"a":2,"c":fa
    15991599
    2 | {"d":"bar"} | f
    16001600
    (2 rows)
    16011601

    1602+
    select *, c is null as c_is_null
    1603+
    from json_to_record('{"a":1, "b":{"c":16, "d":2}, "x":8}'::json)
    1604+
    as t(a int, b json, c text, x int);
    1605+
    a | b | c | x | c_is_null
    1606+
    ---+-----------------+---+---+-----------
    1607+
    1 | {"c":16, "d":2} | | 8 | t
    1608+
    (1 row)
    1609+
    1610+
    select *, c is null as c_is_null
    1611+
    from json_to_recordset('[{"a":1, "b":{"c":16, "d":2}, "x":8}]'::json)
    1612+
    as t(a int, b json, c text, x int);
    1613+
    a | b | c | x | c_is_null
    1614+
    ---+-----------------+---+---+-----------
    1615+
    1 | {"c":16, "d":2} | | 8 | t
    1616+
    (1 row)
    1617+
    16021618
    -- json_strip_nulls
    16031619
    select json_strip_nulls(null);
    16041620
    json_strip_nulls

    src/test/regress/expected/jsonb.out

    Lines changed: 16 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -2001,6 +2001,22 @@ select * from jsonb_to_recordset('[{"a":1,"b":"foo","d":false},{"a":2,"b":"bar",
    20012001
    2 | bar | t
    20022002
    (2 rows)
    20032003

    2004+
    select *, c is null as c_is_null
    2005+
    from jsonb_to_record('{"a":1, "b":{"c":16, "d":2}, "x":8}'::jsonb)
    2006+
    as t(a int, b jsonb, c text, x int);
    2007+
    a | b | c | x | c_is_null
    2008+
    ---+-------------------+---+---+-----------
    2009+
    1 | {"c": 16, "d": 2} | | 8 | t
    2010+
    (1 row)
    2011+
    2012+
    select *, c is null as c_is_null
    2013+
    from jsonb_to_recordset('[{"a":1, "b":{"c":16, "d":2}, "x":8}]'::jsonb)
    2014+
    as t(a int, b jsonb, c text, x int);
    2015+
    a | b | c | x | c_is_null
    2016+
    ---+-------------------+---+---+-----------
    2017+
    1 | {"c": 16, "d": 2} | | 8 | t
    2018+
    (1 row)
    2019+
    20042020
    -- indexing
    20052021
    SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}';
    20062022
    count

    src/test/regress/sql/json.sql

    Lines changed: 7 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -519,6 +519,13 @@ select * from json_to_recordset('[{"a":1,"b":"foo","d":false},{"a":2,"b":"bar","
    519519
    select * from json_to_recordset('[{"a":1,"b":{"d":"foo"},"c":true},{"a":2,"c":false,"b":{"d":"bar"}}]')
    520520
    as x(a int, b json, c boolean);
    521521

    522+
    select *, c is null as c_is_null
    523+
    from json_to_record('{"a":1, "b":{"c":16, "d":2}, "x":8}'::json)
    524+
    as t(a int, b json, c text, x int);
    525+
    526+
    select *, c is null as c_is_null
    527+
    from json_to_recordset('[{"a":1, "b":{"c":16, "d":2}, "x":8}]'::json)
    528+
    as t(a int, b json, c text, x int);
    522529

    523530
    -- json_strip_nulls
    524531

    src/test/regress/sql/jsonb.sql

    Lines changed: 8 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -508,6 +508,14 @@ select * from jsonb_to_record('{"a":1,"b":"foo","c":"bar"}')
    508508
    select * from jsonb_to_recordset('[{"a":1,"b":"foo","d":false},{"a":2,"b":"bar","c":true}]')
    509509
    as x(a int, b text, c boolean);
    510510

    511+
    select *, c is null as c_is_null
    512+
    from jsonb_to_record('{"a":1, "b":{"c":16, "d":2}, "x":8}'::jsonb)
    513+
    as t(a int, b jsonb, c text, x int);
    514+
    515+
    select *, c is null as c_is_null
    516+
    from jsonb_to_recordset('[{"a":1, "b":{"c":16, "d":2}, "x":8}]'::jsonb)
    517+
    as t(a int, b jsonb, c text, x int);
    518+
    511519
    -- indexing
    512520
    SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}';
    513521
    SELECT count(*) FROM testjsonb WHERE j @> '{"wait":"CC"}';

    0 commit comments

    Comments
     (0)
    0