diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2022-12-12 16:17:49 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2022-12-12 16:17:49 -0500 |
commit | d79b76b10ed55ceb25377c0623f2a159ad6117b4 (patch) | |
tree | 9584a3d3687cac04d724c7658d5e0519d7228f7c /src/backend/utils/adt/jsonb_op.c | |
parent | 8b5ba2f3f40a9c82623a19b551bc5790a84275a2 (diff) | |
download | postgresql-d79b76b10ed55ceb25377c0623f2a159ad6117b4.tar.gz postgresql-d79b76b10ed55ceb25377c0623f2a159ad6117b4.zip |
Fix jsonb subscripting to cope with toasted subscript values.
jsonb_get_element() was incautious enough to use VARDATA() and
VARSIZE() directly on an arbitrary text Datum. That of course
fails if the Datum is short-header, compressed, or out-of-line.
The typical result would be failing to match any element of a
jsonb object, though matching the wrong one seems possible as well.
setPathObject() was slightly brighter, in that it used VARDATA_ANY
and VARSIZE_ANY_EXHDR, but that only kept it out of trouble for
short-header Datums. push_path() had the same issue. This could
result in faulty subscripted insertions, though keys long enough to
cause a problem are likely rare in the wild.
Having seen these, I looked around for unsafe usages in the rest
of the adt/json* files. There are a couple of places where it's not
immediately obvious that the Datum can't be compressed or out-of-line,
so I added pg_detoast_datum_packed() to cope if it is. Also, remove
some other usages of VARDATA/VARSIZE on Datums we just extracted from
a text array. Those aren't actively broken, but they will become so
if we ever start allowing short-header array elements, which does not
seem like a terribly unreasonable thing to do. In any case they are
not great coding examples, and they could also do with comments
pointing out that we're assuming we don't need pg_detoast_datum_packed.
Per report from exe-dealer@yandex.ru. Patch by me, but thanks to
David Johnston for initial investigation. Back-patch to v14 where
jsonb subscripting was introduced.
Discussion: https://postgr.es/m/205321670615953@mail.yandex.ru
Diffstat (limited to 'src/backend/utils/adt/jsonb_op.c')
-rw-r--r-- | src/backend/utils/adt/jsonb_op.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/src/backend/utils/adt/jsonb_op.c b/src/backend/utils/adt/jsonb_op.c index ed37252e7f8..9270520d1d4 100644 --- a/src/backend/utils/adt/jsonb_op.c +++ b/src/backend/utils/adt/jsonb_op.c @@ -64,8 +64,9 @@ jsonb_exists_any(PG_FUNCTION_ARGS) continue; strVal.type = jbvString; - strVal.val.string.val = VARDATA(key_datums[i]); - strVal.val.string.len = VARSIZE(key_datums[i]) - VARHDRSZ; + /* We rely on the array elements not being toasted */ + strVal.val.string.val = VARDATA_ANY(key_datums[i]); + strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]); if (findJsonbValueFromContainer(&jb->root, JB_FOBJECT | JB_FARRAY, @@ -97,8 +98,9 @@ jsonb_exists_all(PG_FUNCTION_ARGS) continue; strVal.type = jbvString; - strVal.val.string.val = VARDATA(key_datums[i]); - strVal.val.string.len = VARSIZE(key_datums[i]) - VARHDRSZ; + /* We rely on the array elements not being toasted */ + strVal.val.string.val = VARDATA_ANY(key_datums[i]); + strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]); if (findJsonbValueFromContainer(&jb->root, JB_FOBJECT | JB_FARRAY, |