BUG #19454: PL/pgSQL mishandling jsonb attribute reference

Started by PG Bug reporting form2 days ago3 messagesbugs
Jump to latest
#1PG Bug reporting form
noreply@postgresql.org

The following bug has been logged on the website:

Bug reference: 19454
Logged by: CN Liou
Email address: ma.sao@msa.hinet.net
PostgreSQL version: 18.3
Operating system: Linux Debian Bookworm
Description:

It appears the PL/pgSQL assignment operator := fails to maintain the
stability of a jsonb attribute reference (from a function result) during a
self-concatenation operation, whereas a SELECT wrapper forces correct
materialization.

DO $$
DECLARE
v_payload JSONB := '[]'::jsonb;
tj JSONB;
BEGIN
tj := '{"delta": [["1221", "1221", "TWD", 577.82, {"tags":
[]}]]}'::jsonb;
RAISE NOTICE 'Before: %, Delta is Null: %', (v_payload IS NULL),
(tj->'delta' IS NULL);
v_payload := v_payload || tj->'delta'; -- The problematic line
--v_payload := (SELECT v_payload || (tj->'delta')); --This avoids
the issue.
RAISE NOTICE 'After: %', (v_payload IS NULL);
END $$;

#2David G. Johnston
david.g.johnston@gmail.com
In reply to: PG Bug reporting form (#1)
Re: BUG #19454: PL/pgSQL mishandling jsonb attribute reference

On Sunday, April 12, 2026, PG Bug reporting form <noreply@postgresql.org>
wrote:

The following bug has been logged on the website:

Bug reference: 19454
Logged by: CN Liou
Email address: ma.sao@msa.hinet.net
PostgreSQL version: 18.3
Operating system: Linux Debian Bookworm
Description:

v_payload := v_payload || tj->'delta'; -- The problematic line
--v_payload := (SELECT v_payload || (tj->'delta')); --This avoids
the issue.

I’m not following. The problematic line above is indeed annoying but it’s
not a bug. Operator precedence is behaving as documented. The second line
(wrapping tj->’delta’ with parentheses) is simply the necessary way to
write many expressions involving the “->”-like json[b] operators.

David J.

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: PG Bug reporting form (#1)
Re: BUG #19454: PL/pgSQL mishandling jsonb attribute reference

PG Bug reporting form <noreply@postgresql.org> writes:

It appears the PL/pgSQL assignment operator := fails to maintain the
stability of a jsonb attribute reference (from a function result) during a
self-concatenation operation, whereas a SELECT wrapper forces correct
materialization.

Your problem is operator precedence:

v_payload := v_payload || tj->'delta'; -- The problematic line
v_payload := (SELECT v_payload || (tj->'delta')); --This avoids the issue.

The second formulation works because of the "extra" parentheses;
that is,
v_payload || tj->'delta'
is parsed as
(v_payload || tj)->'delta'
but what you need is
v_payload || (tj->'delta')

Yeah, this isn't super intuitive, but all our non-SQL-standard
operators have the same precedence [1]https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-PRECEDENCE, so || and -> associate
left-to-right by default.

regards, tom lane

[1]: https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-PRECEDENCE