Skip to content

Commit f243072

Browse files
committed
Fix the fastpath rule for jsonb_concat with an empty operand.
To prevent perverse results, we now only return the other operand if it's not scalar, and if both operands are of the same kind (array or object). Original bug complaint and patch from Oskari Saarenmaa, extended by me to cover the cases of different kinds of jsonb. Backpatch to 9.5 where jsonb_concat was introduced.
1 parent 63c0f5b commit f243072

File tree

4 files changed

+90
-5
lines changed

4 files changed

+90
-5
lines changed

src/backend/utils/adt/jsonfuncs.c

+11-5
Original file line numberDiff line numberDiff line change
@@ -3359,12 +3359,18 @@ jsonb_concat(PG_FUNCTION_ARGS)
33593359
*it2;
33603360

33613361
/*
3362-
* If one of the jsonb is empty, just return other.
3362+
* If one of the jsonb is empty, just return the other if it's not
3363+
* scalar and both are of the same kind. If it's a scalar or they are
3364+
* of different kinds we need to perform the concatenation even if one is
3365+
* empty.
33633366
*/
3364-
if (JB_ROOT_COUNT(jb1) == 0)
3365-
PG_RETURN_JSONB(jb2);
3366-
else if (JB_ROOT_COUNT(jb2) == 0)
3367-
PG_RETURN_JSONB(jb1);
3367+
if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
3368+
{
3369+
if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
3370+
PG_RETURN_JSONB(jb2);
3371+
else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
3372+
PG_RETURN_JSONB(jb1);
3373+
}
33683374

33693375
it1 = JsonbIteratorInit(&jb1->root);
33703376
it2 = JsonbIteratorInit(&jb2->root);

src/test/regress/expected/jsonb.out

+36
Original file line numberDiff line numberDiff line change
@@ -2912,6 +2912,42 @@ select '"c"' || '["a", "b"]'::jsonb;
29122912
["c", "a", "b"]
29132913
(1 row)
29142914

2915+
select '[]'::jsonb || '["a"]'::jsonb;
2916+
?column?
2917+
----------
2918+
["a"]
2919+
(1 row)
2920+
2921+
select '[]'::jsonb || '"a"'::jsonb;
2922+
?column?
2923+
----------
2924+
["a"]
2925+
(1 row)
2926+
2927+
select '"b"'::jsonb || '"a"'::jsonb;
2928+
?column?
2929+
------------
2930+
["b", "a"]
2931+
(1 row)
2932+
2933+
select '{}'::jsonb || '{"a":"b"}'::jsonb;
2934+
?column?
2935+
------------
2936+
{"a": "b"}
2937+
(1 row)
2938+
2939+
select '[]'::jsonb || '{"a":"b"}'::jsonb;
2940+
?column?
2941+
--------------
2942+
[{"a": "b"}]
2943+
(1 row)
2944+
2945+
select '{"a":"b"}'::jsonb || '[]'::jsonb;
2946+
?column?
2947+
--------------
2948+
[{"a": "b"}]
2949+
(1 row)
2950+
29152951
select '"a"'::jsonb || '{"a":1}';
29162952
ERROR: invalid concatenation of jsonb objects
29172953
select '{"a":1}' || '"a"'::jsonb;

src/test/regress/expected/jsonb_1.out

+36
Original file line numberDiff line numberDiff line change
@@ -2912,6 +2912,42 @@ select '"c"' || '["a", "b"]'::jsonb;
29122912
["c", "a", "b"]
29132913
(1 row)
29142914

2915+
select '[]'::jsonb || '["a"]'::jsonb;
2916+
?column?
2917+
----------
2918+
["a"]
2919+
(1 row)
2920+
2921+
select '[]'::jsonb || '"a"'::jsonb;
2922+
?column?
2923+
----------
2924+
["a"]
2925+
(1 row)
2926+
2927+
select '"b"'::jsonb || '"a"'::jsonb;
2928+
?column?
2929+
------------
2930+
["b", "a"]
2931+
(1 row)
2932+
2933+
select '{}'::jsonb || '{"a":"b"}'::jsonb;
2934+
?column?
2935+
------------
2936+
{"a": "b"}
2937+
(1 row)
2938+
2939+
select '[]'::jsonb || '{"a":"b"}'::jsonb;
2940+
?column?
2941+
--------------
2942+
[{"a": "b"}]
2943+
(1 row)
2944+
2945+
select '{"a":"b"}'::jsonb || '[]'::jsonb;
2946+
?column?
2947+
--------------
2948+
[{"a": "b"}]
2949+
(1 row)
2950+
29152951
select '"a"'::jsonb || '{"a":1}';
29162952
ERROR: invalid concatenation of jsonb objects
29172953
select '{"a":1}' || '"a"'::jsonb;

src/test/regress/sql/jsonb.sql

+7
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,13 @@ select '["c"]' || '["a", "b"]'::jsonb;
718718
select '["a", "b"]'::jsonb || '"c"';
719719
select '"c"' || '["a", "b"]'::jsonb;
720720

721+
select '[]'::jsonb || '["a"]'::jsonb;
722+
select '[]'::jsonb || '"a"'::jsonb;
723+
select '"b"'::jsonb || '"a"'::jsonb;
724+
select '{}'::jsonb || '{"a":"b"}'::jsonb;
725+
select '[]'::jsonb || '{"a":"b"}'::jsonb;
726+
select '{"a":"b"}'::jsonb || '[]'::jsonb;
727+
721728
select '"a"'::jsonb || '{"a":1}';
722729
select '{"a":1}' || '"a"'::jsonb;
723730

0 commit comments

Comments
 (0)