Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitff5d561

Browse files
committed
Remove "invalid concatenation of jsonb objects" error case.
The jsonb || jsonb operator arbitrarily rejected certain combinationsof scalar and non-scalar inputs, while being willing to concatenateother combinations. This was of course quite undocumented. Ratherthan trying to document it, let's just remove the restriction,creating a uniform rule that unless we are handling an object-to-objectconcatenation, non-array inputs are converted to one-element arrays,resulting in an array-to-array concatenation. (This does not changethe behavior for any case that didn't throw an error before.)Per complaint from Joel Jacobson. Back-patch to all supported branches.Discussion:https://postgr.es/m/163099.1608312033@sss.pgh.pa.us
1 parent86b7cca commitff5d561

File tree

4 files changed

+94
-40
lines changed

4 files changed

+94
-40
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14715,8 +14715,12 @@ table2-mapping
1471514715
</para>
1471614716
<para>
1471714717
Concatenates two <type>jsonb</type> values.
14718-
Concatenating two objects generates an object with the union of their
14718+
Concatenating two arrays generates an array containing all the
14719+
elements of each input. Concatenating two objects generates an
14720+
object containing the union of their
1471914721
keys, taking the second object's value when there are duplicate keys.
14722+
All other cases are treated by converting a non-array input into a
14723+
single-element array, and then proceeding as for two arrays.
1472014724
Does not operate recursively: only the top-level array or object
1472114725
structure is merged.
1472214726
</para>
@@ -14727,6 +14731,22 @@ table2-mapping
1472714731
<para>
1472814732
<literal>'{"a": "b"}'::jsonb || '{"c": "d"}'::jsonb</literal>
1472914733
<returnvalue>{"a": "b", "c": "d"}</returnvalue>
14734+
</para>
14735+
<para>
14736+
<literal>'[1, 2]'::jsonb || '3'::jsonb</literal>
14737+
<returnvalue>[1, 2, 3]</returnvalue>
14738+
</para>
14739+
<para>
14740+
<literal>'{"a": "b"}'::jsonb || '42'::jsonb</literal>
14741+
<returnvalue>[{"a": "b"}, 42]</returnvalue>
14742+
</para>
14743+
<para>
14744+
To append an array to another array as a single entry, wrap it
14745+
in an additional layer of array, for example:
14746+
</para>
14747+
<para>
14748+
<literal>'[1, 2]'::jsonb || jsonb_build_array('[3, 4]'::jsonb)</literal>
14749+
<returnvalue>[1, 2, [3, 4]]</returnvalue>
1473014750
</para></entry>
1473114751
</row>
1473214752

‎src/backend/utils/adt/jsonfuncs.c

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4690,11 +4690,14 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
46904690
rk2=JsonbIteratorNext(it2,&v2, false);
46914691

46924692
/*
4693-
* Both elements are objects.
4693+
* JsonbIteratorNext reports raw scalars as if they were single-element
4694+
* arrays; hence we only need consider "object" and "array" cases here.
46944695
*/
46954696
if (rk1==WJB_BEGIN_OBJECT&&rk2==WJB_BEGIN_OBJECT)
46964697
{
46974698
/*
4699+
* Both inputs are objects.
4700+
*
46984701
* Append all the tokens from v1 to res, except last WJB_END_OBJECT
46994702
* (because res will not be finished yet).
47004703
*/
@@ -4703,18 +4706,18 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
47034706
pushJsonbValue(state,r1,&v1);
47044707

47054708
/*
4706-
* Append all the tokens from v2 to res, include last WJB_END_OBJECT
4707-
* (the concatenation will be completed).
4709+
* Append all the tokens from v2 to res, including last WJB_END_OBJECT
4710+
* (the concatenation will be completed). Any duplicate keys will
4711+
* automatically override the value from the first object.
47084712
*/
47094713
while ((r2=JsonbIteratorNext(it2,&v2, true))!=WJB_DONE)
47104714
res=pushJsonbValue(state,r2,r2!=WJB_END_OBJECT ?&v2 :NULL);
47114715
}
4712-
4713-
/*
4714-
* Both elements are arrays (either can be scalar).
4715-
*/
47164716
elseif (rk1==WJB_BEGIN_ARRAY&&rk2==WJB_BEGIN_ARRAY)
47174717
{
4718+
/*
4719+
* Both inputs are arrays.
4720+
*/
47184721
pushJsonbValue(state,rk1,NULL);
47194722

47204723
while ((r1=JsonbIteratorNext(it1,&v1, true))!=WJB_END_ARRAY)
@@ -4731,46 +4734,40 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
47314734

47324735
res=pushJsonbValue(state,WJB_END_ARRAY,NULL/* signal to sort */ );
47334736
}
4734-
/* have we got array || object or object || array? */
4735-
elseif (((rk1==WJB_BEGIN_ARRAY&& !(*it1)->isScalar)&&rk2==WJB_BEGIN_OBJECT)||
4736-
(rk1==WJB_BEGIN_OBJECT&& (rk2==WJB_BEGIN_ARRAY&& !(*it2)->isScalar)))
4737+
elseif (rk1==WJB_BEGIN_OBJECT)
47374738
{
4738-
JsonbIterator**it_array=rk1==WJB_BEGIN_ARRAY ?it1 :it2;
4739-
JsonbIterator**it_object=rk1==WJB_BEGIN_OBJECT ?it1 :it2;
4740-
boolprepend= (rk1==WJB_BEGIN_OBJECT);
4739+
/*
4740+
* We have object || array.
4741+
*/
4742+
Assert(rk2==WJB_BEGIN_ARRAY);
47414743

47424744
pushJsonbValue(state,WJB_BEGIN_ARRAY,NULL);
47434745

4744-
if (prepend)
4745-
{
4746-
pushJsonbValue(state,WJB_BEGIN_OBJECT,NULL);
4747-
while ((r1=JsonbIteratorNext(it_object,&v1, true))!=WJB_DONE)
4748-
pushJsonbValue(state,r1,r1!=WJB_END_OBJECT ?&v1 :NULL);
4749-
4750-
while ((r2=JsonbIteratorNext(it_array,&v2, true))!=WJB_DONE)
4751-
res=pushJsonbValue(state,r2,r2!=WJB_END_ARRAY ?&v2 :NULL);
4752-
}
4753-
else
4754-
{
4755-
while ((r1=JsonbIteratorNext(it_array,&v1, true))!=WJB_END_ARRAY)
4756-
pushJsonbValue(state,r1,&v1);
4757-
4758-
pushJsonbValue(state,WJB_BEGIN_OBJECT,NULL);
4759-
while ((r2=JsonbIteratorNext(it_object,&v2, true))!=WJB_DONE)
4760-
pushJsonbValue(state,r2,r2!=WJB_END_OBJECT ?&v2 :NULL);
4746+
pushJsonbValue(state,WJB_BEGIN_OBJECT,NULL);
4747+
while ((r1=JsonbIteratorNext(it1,&v1, true))!=WJB_DONE)
4748+
pushJsonbValue(state,r1,r1!=WJB_END_OBJECT ?&v1 :NULL);
47614749

4762-
res=pushJsonbValue(state,WJB_END_ARRAY,NULL);
4763-
}
4750+
while ((r2=JsonbIteratorNext(it2,&v2, true))!=WJB_DONE)
4751+
res=pushJsonbValue(state,r2,r2!=WJB_END_ARRAY ?&v2 :NULL);
47644752
}
47654753
else
47664754
{
47674755
/*
4768-
* This must be scalar || object or object || scalar, as that's all
4769-
* that's left. Both of these make no sense, so error out.
4756+
* We have array || object.
47704757
*/
4771-
ereport(ERROR,
4772-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4773-
errmsg("invalid concatenation of jsonb objects")));
4758+
Assert(rk1==WJB_BEGIN_ARRAY);
4759+
Assert(rk2==WJB_BEGIN_OBJECT);
4760+
4761+
pushJsonbValue(state,WJB_BEGIN_ARRAY,NULL);
4762+
4763+
while ((r1=JsonbIteratorNext(it1,&v1, true))!=WJB_END_ARRAY)
4764+
pushJsonbValue(state,r1,&v1);
4765+
4766+
pushJsonbValue(state,WJB_BEGIN_OBJECT,NULL);
4767+
while ((r2=JsonbIteratorNext(it2,&v2, true))!=WJB_DONE)
4768+
pushJsonbValue(state,r2,r2!=WJB_END_OBJECT ?&v2 :NULL);
4769+
4770+
res=pushJsonbValue(state,WJB_END_ARRAY,NULL);
47744771
}
47754772

47764773
returnres;

‎src/test/regress/expected/jsonb.out

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4111,9 +4111,41 @@ select '{"a":"b"}'::jsonb || '[]'::jsonb;
41114111
(1 row)
41124112

41134113
select '"a"'::jsonb || '{"a":1}';
4114-
ERROR: invalid concatenation of jsonb objects
4114+
?column?
4115+
-----------------
4116+
["a", {"a": 1}]
4117+
(1 row)
4118+
41154119
select '{"a":1}' || '"a"'::jsonb;
4116-
ERROR: invalid concatenation of jsonb objects
4120+
?column?
4121+
-----------------
4122+
[{"a": 1}, "a"]
4123+
(1 row)
4124+
4125+
select '[3]'::jsonb || '{}'::jsonb;
4126+
?column?
4127+
----------
4128+
[3, {}]
4129+
(1 row)
4130+
4131+
select '3'::jsonb || '[]'::jsonb;
4132+
?column?
4133+
----------
4134+
[3]
4135+
(1 row)
4136+
4137+
select '3'::jsonb || '4'::jsonb;
4138+
?column?
4139+
----------
4140+
[3, 4]
4141+
(1 row)
4142+
4143+
select '3'::jsonb || '{}'::jsonb;
4144+
?column?
4145+
----------
4146+
[3, {}]
4147+
(1 row)
4148+
41174149
select '["a", "b"]'::jsonb || '{"c":1}';
41184150
?column?
41194151
----------------------

‎src/test/regress/sql/jsonb.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,11 @@ select '{"a":"b"}'::jsonb || '[]'::jsonb;
10561056
select'"a"'::jsonb||'{"a":1}';
10571057
select'{"a":1}'||'"a"'::jsonb;
10581058

1059+
select'[3]'::jsonb||'{}'::jsonb;
1060+
select'3'::jsonb||'[]'::jsonb;
1061+
select'3'::jsonb||'4'::jsonb;
1062+
select'3'::jsonb||'{}'::jsonb;
1063+
10591064
select'["a", "b"]'::jsonb||'{"c":1}';
10601065
select'{"c": 1}'::jsonb||'["a", "b"]';
10611066

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp