From 1edd4ec831458e10b524d1473a7de5791aa8753e Mon Sep 17 00:00:00 2001 From: Andrew Dunstan Date: Sun, 4 Oct 2015 13:28:16 -0400 Subject: [PATCH] Disallow invalid path elements in jsonb_set Null path elements and, where the object is an array, invalid integer elements now cause an error. Incorrect behaviour noted by Thom Brown, patch from Dmitry Dolgov. Backpatch to 9.5 where jsonb_set was introduced --- src/backend/utils/adt/jsonfuncs.c | 5 ++++- src/test/regress/expected/jsonb.out | 24 +++++++++--------------- src/test/regress/expected/jsonb_1.out | 24 +++++++++--------------- src/test/regress/sql/jsonb.sql | 3 +++ 4 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index 154a8837e1..01b6bb0a48 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -3724,6 +3724,9 @@ setPath(JsonbIterator **it, Datum *path_elems, JsonbValue *res = NULL; int r; + if (path_nulls[level]) + elog(ERROR, "path element at the position %d is NULL", level + 1); + r = JsonbIteratorNext(it, &v, false); switch (r) @@ -3875,7 +3878,7 @@ setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, lindex = strtol(c, &badp, 10); if (errno != 0 || badp == c || *badp != '\0' || lindex > INT_MAX || lindex < INT_MIN) - idx = nelems; + elog(ERROR, "path element at the position %d is not an integer", level + 1); else idx = lindex; } diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out index 82d1b69bfa..6da5a151d7 100644 --- a/src/test/regress/expected/jsonb.out +++ b/src/test/regress/expected/jsonb.out @@ -3127,11 +3127,7 @@ select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::j (1 row) select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{d,NULL,0}', '[1,2,3]'); - jsonb_set ---------------------------------------------------------------------- - {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null} -(1 row) - +ERROR: path element at the position 2 is NULL select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{n}', '{"1": 2}'); jsonb_set ------------------------------------------------------------------------- @@ -3151,11 +3147,7 @@ select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::j (1 row) select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{d,NULL,0}', '{"1": 2}'); - jsonb_set ---------------------------------------------------------------------- - {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null} -(1 row) - +ERROR: path element at the position 2 is NULL select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{b,-1}', '"test"'); jsonb_set -------------------------------------------------------------------------- @@ -3199,11 +3191,7 @@ select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{ (1 row) select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{b,-1e}'; -- invalid array subscript - ?column? ---------------------------------------------------------------------- - {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null} -(1 row) - +ERROR: path element at the position 2 is not an integer select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{d,1,0}'; ?column? ------------------------------------------------------------------ @@ -3331,3 +3319,9 @@ select jsonb_set('[]','{-99}','{"foo":123}'); [{"foo": 123}] (1 row) +select jsonb_set('{"a": [1, 2, 3]}', '{a, non_integer}', '"new_value"'); +ERROR: path element at the position 2 is not an integer +select jsonb_set('{"a": {"b": [1, 2, 3]}}', '{a, b, non_integer}', '"new_value"'); +ERROR: path element at the position 3 is not an integer +select jsonb_set('{"a": {"b": [1, 2, 3]}}', '{a, b, NULL}', '"new_value"'); +ERROR: path element at the position 3 is NULL diff --git a/src/test/regress/expected/jsonb_1.out b/src/test/regress/expected/jsonb_1.out index 2cbc0c79bb..39e7b1ff57 100644 --- a/src/test/regress/expected/jsonb_1.out +++ b/src/test/regress/expected/jsonb_1.out @@ -3127,11 +3127,7 @@ select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::j (1 row) select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{d,NULL,0}', '[1,2,3]'); - jsonb_set ---------------------------------------------------------------------- - {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null} -(1 row) - +ERROR: path element at the position 2 is NULL select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{n}', '{"1": 2}'); jsonb_set ------------------------------------------------------------------------- @@ -3151,11 +3147,7 @@ select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::j (1 row) select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{d,NULL,0}', '{"1": 2}'); - jsonb_set ---------------------------------------------------------------------- - {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null} -(1 row) - +ERROR: path element at the position 2 is NULL select jsonb_set('{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb, '{b,-1}', '"test"'); jsonb_set -------------------------------------------------------------------------- @@ -3199,11 +3191,7 @@ select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{ (1 row) select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{b,-1e}'; -- invalid array subscript - ?column? ---------------------------------------------------------------------- - {"a": 1, "b": [1, 2], "c": {"1": 2}, "d": {"1": [2, 3]}, "n": null} -(1 row) - +ERROR: path element at the position 2 is not an integer select '{"n":null, "a":1, "b":[1,2], "c":{"1":2}, "d":{"1":[2,3]}}'::jsonb #- '{d,1,0}'; ?column? ------------------------------------------------------------------ @@ -3331,3 +3319,9 @@ select jsonb_set('[]','{-99}','{"foo":123}'); [{"foo": 123}] (1 row) +select jsonb_set('{"a": [1, 2, 3]}', '{a, non_integer}', '"new_value"'); +ERROR: path element at the position 2 is not an integer +select jsonb_set('{"a": {"b": [1, 2, 3]}}', '{a, b, non_integer}', '"new_value"'); +ERROR: path element at the position 3 is not an integer +select jsonb_set('{"a": {"b": [1, 2, 3]}}', '{a, b, NULL}', '"new_value"'); +ERROR: path element at the position 3 is NULL diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql index cb03ada173..b1a0764cfa 100644 --- a/src/test/regress/sql/jsonb.sql +++ b/src/test/regress/sql/jsonb.sql @@ -816,3 +816,6 @@ select jsonb_set('{}','{x}','{"foo":123}'); select jsonb_set('[]','{0}','{"foo":123}'); select jsonb_set('[]','{99}','{"foo":123}'); select jsonb_set('[]','{-99}','{"foo":123}'); +select jsonb_set('{"a": [1, 2, 3]}', '{a, non_integer}', '"new_value"'); +select jsonb_set('{"a": {"b": [1, 2, 3]}}', '{a, b, non_integer}', '"new_value"'); +select jsonb_set('{"a": {"b": [1, 2, 3]}}', '{a, b, NULL}', '"new_value"'); -- 2.39.5