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

Commit38bef9e

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 parentdef510c commit38bef9e

File tree

4 files changed

+85
-50
lines changed

4 files changed

+85
-50
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11925,10 +11925,13 @@ table2-mapping
1192511925

1192611926
<note>
1192711927
<para>
11928-
The <literal>||</literal> operator concatenates the elements at the top level of
11929-
each of its operands. It does not operate recursively. For example, if
11930-
both operands are objects with a common key field name, the value of the
11931-
field in the result will just be the value from the right hand operand.
11928+
The <literal>||</literal> operator concatenates two JSON objects by
11929+
generating an object containing the union of their keys, taking the
11930+
second object's value when there are duplicate keys. All other cases
11931+
produce a JSON array: first, any non-array input is converted into a
11932+
single-element array, and then the two arrays are concatenated.
11933+
It does not operate recursively; only the top-level array or object
11934+
structure is merged.
1193211935
</para>
1193311936
</note>
1193411937

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

Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4583,36 +4583,39 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
45834583
rk1,
45844584
rk2;
45854585

4586-
r1=rk1=JsonbIteratorNext(it1,&v1, false);
4587-
r2=rk2=JsonbIteratorNext(it2,&v2, false);
4586+
rk1=JsonbIteratorNext(it1,&v1, false);
4587+
rk2=JsonbIteratorNext(it2,&v2, false);
45884588

45894589
/*
4590-
* Both elements are objects.
4590+
* JsonbIteratorNext reports raw scalars as if they were single-element
4591+
* arrays; hence we only need consider "object" and "array" cases here.
45914592
*/
45924593
if (rk1==WJB_BEGIN_OBJECT&&rk2==WJB_BEGIN_OBJECT)
45934594
{
45944595
/*
4595-
* Append the all tokens from v1 to res, except last WJB_END_OBJECT
4596+
* Both inputs are objects.
4597+
*
4598+
* Append all the tokens from v1 to res, except last WJB_END_OBJECT
45964599
* (because res will not be finished yet).
45974600
*/
4598-
pushJsonbValue(state,r1,NULL);
4601+
pushJsonbValue(state,rk1,NULL);
45994602
while ((r1=JsonbIteratorNext(it1,&v1, true))!=WJB_END_OBJECT)
46004603
pushJsonbValue(state,r1,&v1);
46014604

46024605
/*
4603-
* Append the all tokens from v2 to res, include last WJB_END_OBJECT
4604-
* (the concatenation will be completed).
4606+
* Append all the tokens from v2 to res, including last WJB_END_OBJECT
4607+
* (the concatenation will be completed). Any duplicate keys will
4608+
* automatically override the value from the first object.
46054609
*/
46064610
while ((r2=JsonbIteratorNext(it2,&v2, true))!=WJB_DONE)
46074611
res=pushJsonbValue(state,r2,r2!=WJB_END_OBJECT ?&v2 :NULL);
46084612
}
4609-
4610-
/*
4611-
* Both elements are arrays (either can be scalar).
4612-
*/
46134613
elseif (rk1==WJB_BEGIN_ARRAY&&rk2==WJB_BEGIN_ARRAY)
46144614
{
4615-
pushJsonbValue(state,r1,NULL);
4615+
/*
4616+
* Both inputs are arrays.
4617+
*/
4618+
pushJsonbValue(state,rk1,NULL);
46164619

46174620
while ((r1=JsonbIteratorNext(it1,&v1, true))!=WJB_END_ARRAY)
46184621
{
@@ -4628,48 +4631,40 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2,
46284631

46294632
res=pushJsonbValue(state,WJB_END_ARRAY,NULL/* signal to sort */ );
46304633
}
4631-
/* have we got array || object or object || array? */
4632-
elseif (((rk1==WJB_BEGIN_ARRAY&& !(*it1)->isScalar)&&rk2==WJB_BEGIN_OBJECT)||
4633-
(rk1==WJB_BEGIN_OBJECT&& (rk2==WJB_BEGIN_ARRAY&& !(*it2)->isScalar)))
4634+
elseif (rk1==WJB_BEGIN_OBJECT)
46344635
{
4635-
4636-
JsonbIterator**it_array=rk1==WJB_BEGIN_ARRAY ?it1 :it2;
4637-
JsonbIterator**it_object=rk1==WJB_BEGIN_OBJECT ?it1 :it2;
4638-
4639-
boolprepend= (rk1==WJB_BEGIN_OBJECT);
4636+
/*
4637+
* We have object || array.
4638+
*/
4639+
Assert(rk2==WJB_BEGIN_ARRAY);
46404640

46414641
pushJsonbValue(state,WJB_BEGIN_ARRAY,NULL);
46424642

4643-
if (prepend)
4644-
{
4645-
pushJsonbValue(state,WJB_BEGIN_OBJECT,NULL);
4646-
while ((r1=JsonbIteratorNext(it_object,&v1, true))!=WJB_DONE)
4647-
pushJsonbValue(state,r1,r1!=WJB_END_OBJECT ?&v1 :NULL);
4648-
4649-
while ((r2=JsonbIteratorNext(it_array,&v2, true))!=WJB_DONE)
4650-
res=pushJsonbValue(state,r2,r2!=WJB_END_ARRAY ?&v2 :NULL);
4651-
}
4652-
else
4653-
{
4654-
while ((r1=JsonbIteratorNext(it_array,&v1, true))!=WJB_END_ARRAY)
4655-
pushJsonbValue(state,r1,&v1);
4643+
pushJsonbValue(state,WJB_BEGIN_OBJECT,NULL);
4644+
while ((r1=JsonbIteratorNext(it1,&v1, true))!=WJB_DONE)
4645+
pushJsonbValue(state,r1,r1!=WJB_END_OBJECT ?&v1 :NULL);
46564646

4657-
pushJsonbValue(state,WJB_BEGIN_OBJECT,NULL);
4658-
while ((r2=JsonbIteratorNext(it_object,&v2, true))!=WJB_DONE)
4659-
pushJsonbValue(state,r2,r2!=WJB_END_OBJECT ?&v2 :NULL);
4660-
4661-
res=pushJsonbValue(state,WJB_END_ARRAY,NULL);
4662-
}
4647+
while ((r2=JsonbIteratorNext(it2,&v2, true))!=WJB_DONE)
4648+
res=pushJsonbValue(state,r2,r2!=WJB_END_ARRAY ?&v2 :NULL);
46634649
}
46644650
else
46654651
{
46664652
/*
4667-
* This must be scalar || object or object || scalar, as that's all
4668-
* that's left. Both of these make no sense, so error out.
4653+
* We have array || object.
46694654
*/
4670-
ereport(ERROR,
4671-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4672-
errmsg("invalid concatenation of jsonb objects")));
4655+
Assert(rk1==WJB_BEGIN_ARRAY);
4656+
Assert(rk2==WJB_BEGIN_OBJECT);
4657+
4658+
pushJsonbValue(state,WJB_BEGIN_ARRAY,NULL);
4659+
4660+
while ((r1=JsonbIteratorNext(it1,&v1, true))!=WJB_END_ARRAY)
4661+
pushJsonbValue(state,r1,&v1);
4662+
4663+
pushJsonbValue(state,WJB_BEGIN_OBJECT,NULL);
4664+
while ((r2=JsonbIteratorNext(it2,&v2, true))!=WJB_DONE)
4665+
pushJsonbValue(state,r2,r2!=WJB_END_OBJECT ?&v2 :NULL);
4666+
4667+
res=pushJsonbValue(state,WJB_END_ARRAY,NULL);
46734668
}
46744669

46754670
returnres;

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

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

41094109
select '"a"'::jsonb || '{"a":1}';
4110-
ERROR: invalid concatenation of jsonb objects
4110+
?column?
4111+
-----------------
4112+
["a", {"a": 1}]
4113+
(1 row)
4114+
41114115
select '{"a":1}' || '"a"'::jsonb;
4112-
ERROR: invalid concatenation of jsonb objects
4116+
?column?
4117+
-----------------
4118+
[{"a": 1}, "a"]
4119+
(1 row)
4120+
4121+
select '[3]'::jsonb || '{}'::jsonb;
4122+
?column?
4123+
----------
4124+
[3, {}]
4125+
(1 row)
4126+
4127+
select '3'::jsonb || '[]'::jsonb;
4128+
?column?
4129+
----------
4130+
[3]
4131+
(1 row)
4132+
4133+
select '3'::jsonb || '4'::jsonb;
4134+
?column?
4135+
----------
4136+
[3, 4]
4137+
(1 row)
4138+
4139+
select '3'::jsonb || '{}'::jsonb;
4140+
?column?
4141+
----------
4142+
[3, {}]
4143+
(1 row)
4144+
41134145
select '["a", "b"]'::jsonb || '{"c":1}';
41144146
?column?
41154147
----------------------

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

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

1055+
select'[3]'::jsonb||'{}'::jsonb;
1056+
select'3'::jsonb||'[]'::jsonb;
1057+
select'3'::jsonb||'4'::jsonb;
1058+
select'3'::jsonb||'{}'::jsonb;
1059+
10551060
select'["a", "b"]'::jsonb||'{"c":1}';
10561061
select'{"c": 1}'::jsonb||'["a", "b"]';
10571062

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp