Re: jsonb_concat: make sure we always return a non-scalar value

From: Andrew Dunstan <andrew(at)dunslane(dot)net>
To: Oskari Saarenmaa <os(at)ohmu(dot)fi>, pgsql-hackers(at)postgresql(dot)org
Cc: Дмитрий Долгов <9erthalion6(at)gmail(dot)com>
Subject: Re: jsonb_concat: make sure we always return a non-scalar value
Date: 2015-09-11 23:11:33
Message-ID: 55F35FA5.7070904@dunslane.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 09/09/2015 01:03 PM, Oskari Saarenmaa wrote:
> 09.09.2015, 18:53, Andrew Dunstan kirjoitti:
>> On 09/08/2015 09:54 AM, Andrew Dunstan wrote:
>>> On 09/05/2015 02:47 AM, Oskari Saarenmaa wrote:
>>>> There was a long thread about concatenating jsonb objects to each
>>>> other, but that discussion didn't touch concatenating other types.
>>>> Currently jsonb_concat always just returns the other argument if one
>>>> of arguments is considered empty. This causes surprising behavior
>>>> when concatenating scalar values to empty arrays:
>>>>
>>>> os=# select '[]'::jsonb || '1'::jsonb;
>>>> 1
>>>>
>>>> os=# select '[]'::jsonb || '[1]'::jsonb;
>>>> [1]
>>>>
>>>> os=# select '[]'::jsonb || '1'::jsonb || '2'::jsonb;
>>>> [1, 2]
>>>>
>>>> os=# select '0'::jsonb || '1'::jsonb;
>>>> [0, 1]
>>>>
>>>> os=# select '{"x": "y"}'::jsonb || '[1]'::jsonb;
>>>> [{"x": "y"}, 1]
>>>>
>>>> os=# select '{"x": "y"}'::jsonb || '1'::jsonb;
>>>> ERROR: invalid concatenation of jsonb objects
>>>>
>>>> Attached a patch to fix and test this. Also added a test case for
>>>> concatenating two scalar values which currently produces an array..
>>>> I'm not sure that behavior makes sense, but didn't want to change
>>>> that in this patch as I guess someone could consider that feature
>>>> useful.
>>>
>>>
>>>
>>> This looks correct. Barring objection I'll apply this shortly.
>>
>>
>> Actually, I'm not sure the test is sufficient here. It looks to me like
>> we should only be taking this fast path if one operand is an empty array
>> and the other is a non-scalar array.
>>
>> Otherwise we get things like this (second case is wrong, I think):
>>
>> andrew=# select '[]'::jsonb || '"a"';
>> ?column?
>> ----------
>> ["a"]
>>
>> andrew=# select '[]'::jsonb || '{"a":"b"}';
>> ?column?
>> ------------
>> {"a": "b"}
>>
>> andrew=# select '[1]'::jsonb || '{"a":"b"}';
>> ?column?
>> -----------------
>> [1, {"a": "b"}]
>
> It looks wrong, but I'm not sure what's right in that case. I think
> it'd make sense to just restrict concatenation to object || object,
> array || array and array || scalar and document that. I doubt many
> people expect their objects to turn into arrays if they accidentally
> concatenate an array into it. Alternatively the behavior could depend
> on the order of arguments for concatenation, array || anything ->
> array, object || array -> error.
>
>

I don't think I want to change the semantics in general at this stage. A
simple minimal fix to handle the case of the fastpath where one of other
operand is empty, making it entirely consistent with the case where it's
not empty, is attached.

cheers

andrew

Attachment Content-Type Size
jsonbconcatfix.patch application/x-patch 3.5 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Thom Brown 2015-09-12 00:04:58 Re: [PROPOSAL] VACUUM Progress Checker.
Previous Message Alvaro Herrera 2015-09-11 21:34:51 Re: [PROPOSAL] VACUUM Progress Checker.