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
This commit is contained in:
Tom Lane 2022-12-12 16:17:49 -05:00
parent 8b5ba2f3f4
commit d79b76b10e
5 changed files with 90 additions and 18 deletions

View File

@ -896,9 +896,10 @@ gin_extract_jsonb_query(PG_FUNCTION_ARGS)
/* Nulls in the array are ignored */ /* Nulls in the array are ignored */
if (key_nulls[i]) if (key_nulls[i])
continue; continue;
/* We rely on the array elements not being toasted */
entries[j++] = make_text_key(JGINFLAG_KEY, entries[j++] = make_text_key(JGINFLAG_KEY,
VARDATA(key_datums[i]), VARDATA_ANY(key_datums[i]),
VARSIZE(key_datums[i]) - VARHDRSZ); VARSIZE_ANY_EXHDR(key_datums[i]));
} }
*nentries = j; *nentries = j;

View File

@ -64,8 +64,9 @@ jsonb_exists_any(PG_FUNCTION_ARGS)
continue; continue;
strVal.type = jbvString; strVal.type = jbvString;
strVal.val.string.val = VARDATA(key_datums[i]); /* We rely on the array elements not being toasted */
strVal.val.string.len = VARSIZE(key_datums[i]) - VARHDRSZ; strVal.val.string.val = VARDATA_ANY(key_datums[i]);
strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
if (findJsonbValueFromContainer(&jb->root, if (findJsonbValueFromContainer(&jb->root,
JB_FOBJECT | JB_FARRAY, JB_FOBJECT | JB_FARRAY,
@ -97,8 +98,9 @@ jsonb_exists_all(PG_FUNCTION_ARGS)
continue; continue;
strVal.type = jbvString; strVal.type = jbvString;
strVal.val.string.val = VARDATA(key_datums[i]); /* We rely on the array elements not being toasted */
strVal.val.string.len = VARSIZE(key_datums[i]) - VARHDRSZ; strVal.val.string.val = VARDATA_ANY(key_datums[i]);
strVal.val.string.len = VARSIZE_ANY_EXHDR(key_datums[i]);
if (findJsonbValueFromContainer(&jb->root, if (findJsonbValueFromContainer(&jb->root,
JB_FOBJECT | JB_FARRAY, JB_FOBJECT | JB_FARRAY,

View File

@ -516,6 +516,12 @@ pg_parse_json_or_ereport(JsonLexContext *lex, JsonSemAction *sem)
JsonLexContext * JsonLexContext *
makeJsonLexContext(text *json, bool need_escapes) makeJsonLexContext(text *json, bool need_escapes)
{ {
/*
* Most callers pass a detoasted datum, but it's not clear that they all
* do. pg_detoast_datum_packed() is cheap insurance.
*/
json = pg_detoast_datum_packed(json);
return makeJsonLexContextCstringLen(VARDATA_ANY(json), return makeJsonLexContextCstringLen(VARDATA_ANY(json),
VARSIZE_ANY_EXHDR(json), VARSIZE_ANY_EXHDR(json),
GetDatabaseEncoding(), GetDatabaseEncoding(),
@ -1518,9 +1524,11 @@ jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
{ {
if (have_object) if (have_object)
{ {
text *subscr = DatumGetTextPP(path[i]);
jbvp = getKeyJsonValueFromContainer(container, jbvp = getKeyJsonValueFromContainer(container,
VARDATA(path[i]), VARDATA_ANY(subscr),
VARSIZE(path[i]) - VARHDRSZ, VARSIZE_ANY_EXHDR(subscr),
NULL); NULL);
} }
else if (have_array) else if (have_array)
@ -1693,8 +1701,8 @@ push_path(JsonbParseState **st, int level, Datum *path_elems,
{ {
/* text, an object is expected */ /* text, an object is expected */
newkey.type = jbvString; newkey.type = jbvString;
newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[i]); newkey.val.string.val = c;
newkey.val.string.val = VARDATA_ANY(path_elems[i]); newkey.val.string.len = strlen(c);
(void) pushJsonbValue(st, WJB_BEGIN_OBJECT, NULL); (void) pushJsonbValue(st, WJB_BEGIN_OBJECT, NULL);
(void) pushJsonbValue(st, WJB_KEY, &newkey); (void) pushJsonbValue(st, WJB_KEY, &newkey);
@ -4349,6 +4357,7 @@ jsonb_delete_array(PG_FUNCTION_ARGS)
if (keys_nulls[i]) if (keys_nulls[i])
continue; continue;
/* We rely on the array elements not being toasted */
keyptr = VARDATA_ANY(keys_elems[i]); keyptr = VARDATA_ANY(keys_elems[i]);
keylen = VARSIZE_ANY_EXHDR(keys_elems[i]); keylen = VARSIZE_ANY_EXHDR(keys_elems[i]);
if (keylen == v.val.string.len && if (keylen == v.val.string.len &&
@ -4873,6 +4882,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
int path_len, JsonbParseState **st, int level, int path_len, JsonbParseState **st, int level,
JsonbValue *newval, uint32 npairs, int op_type) JsonbValue *newval, uint32 npairs, int op_type)
{ {
text *pathelem = NULL;
int i; int i;
JsonbValue k, JsonbValue k,
v; v;
@ -4880,6 +4890,11 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
if (level >= path_len || path_nulls[level]) if (level >= path_len || path_nulls[level])
done = true; done = true;
else
{
/* The path Datum could be toasted, in which case we must detoast it */
pathelem = DatumGetTextPP(path_elems[level]);
}
/* empty object is a special case for create */ /* empty object is a special case for create */
if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) && if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
@ -4888,8 +4903,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
JsonbValue newkey; JsonbValue newkey;
newkey.type = jbvString; newkey.type = jbvString;
newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]); newkey.val.string.val = VARDATA_ANY(pathelem);
newkey.val.string.val = VARDATA_ANY(path_elems[level]); newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
(void) pushJsonbValue(st, WJB_KEY, &newkey); (void) pushJsonbValue(st, WJB_KEY, &newkey);
(void) pushJsonbValue(st, WJB_VALUE, newval); (void) pushJsonbValue(st, WJB_VALUE, newval);
@ -4902,8 +4917,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
Assert(r == WJB_KEY); Assert(r == WJB_KEY);
if (!done && if (!done &&
k.val.string.len == VARSIZE_ANY_EXHDR(path_elems[level]) && k.val.string.len == VARSIZE_ANY_EXHDR(pathelem) &&
memcmp(k.val.string.val, VARDATA_ANY(path_elems[level]), memcmp(k.val.string.val, VARDATA_ANY(pathelem),
k.val.string.len) == 0) k.val.string.len) == 0)
{ {
done = true; done = true;
@ -4943,8 +4958,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
JsonbValue newkey; JsonbValue newkey;
newkey.type = jbvString; newkey.type = jbvString;
newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]); newkey.val.string.val = VARDATA_ANY(pathelem);
newkey.val.string.val = VARDATA_ANY(path_elems[level]); newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
(void) pushJsonbValue(st, WJB_KEY, &newkey); (void) pushJsonbValue(st, WJB_KEY, &newkey);
(void) pushJsonbValue(st, WJB_VALUE, newval); (void) pushJsonbValue(st, WJB_VALUE, newval);
@ -4987,8 +5002,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
JsonbValue newkey; JsonbValue newkey;
newkey.type = jbvString; newkey.type = jbvString;
newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]); newkey.val.string.val = VARDATA_ANY(pathelem);
newkey.val.string.val = VARDATA_ANY(path_elems[level]); newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
(void) pushJsonbValue(st, WJB_KEY, &newkey); (void) pushJsonbValue(st, WJB_KEY, &newkey);
(void) push_path(st, level, path_elems, path_nulls, (void) push_path(st, level, path_elems, path_nulls,
@ -5397,6 +5412,8 @@ transform_jsonb_string_values(Jsonb *jsonb, void *action_state,
if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString) if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
{ {
out = transform_action(action_state, v.val.string.val, v.val.string.len); out = transform_action(action_state, v.val.string.val, v.val.string.len);
/* out is probably not toasted, but let's be sure */
out = pg_detoast_datum_packed(out);
v.val.string.val = VARDATA_ANY(out); v.val.string.val = VARDATA_ANY(out);
v.val.string.len = VARSIZE_ANY_EXHDR(out); v.val.string.len = VARSIZE_ANY_EXHDR(out);
res = pushJsonbValue(&st, type, type < WJB_BEGIN_ARRAY ? &v : NULL); res = pushJsonbValue(&st, type, type < WJB_BEGIN_ARRAY ? &v : NULL);

View File

@ -5199,6 +5199,40 @@ DETAIL: The path assumes key is a composite object, but it is a scalar value.
update test_jsonb_subscript set test_json[0][0] = '1'; update test_jsonb_subscript set test_json[0][0] = '1';
ERROR: cannot replace existing key ERROR: cannot replace existing key
DETAIL: The path assumes key is a composite object, but it is a scalar value. DETAIL: The path assumes key is a composite object, but it is a scalar value.
-- try some things with short-header and toasted subscript values
drop table test_jsonb_subscript;
create temp table test_jsonb_subscript (
id text,
test_json jsonb
);
insert into test_jsonb_subscript values('foo', '{"foo": "bar"}');
insert into test_jsonb_subscript
select s, ('{"' || s || '": "bar"}')::jsonb from repeat('xyzzy', 500) s;
select length(id), test_json[id] from test_jsonb_subscript;
length | test_json
--------+-----------
3 | "bar"
2500 | "bar"
(2 rows)
update test_jsonb_subscript set test_json[id] = '"baz"';
select length(id), test_json[id] from test_jsonb_subscript;
length | test_json
--------+-----------
3 | "baz"
2500 | "baz"
(2 rows)
\x
table test_jsonb_subscript;
-[ RECORD 1 ]--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | foo
test_json | {"foo": "baz"}
-[ RECORD 2 ]--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | xyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzy
test_json | {"xyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzyxyzzy": "baz"}
\x
-- jsonb to tsvector -- jsonb to tsvector
select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb); select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);
to_tsvector to_tsvector

View File

@ -1415,6 +1415,24 @@ insert into test_jsonb_subscript values (1, 'null');
update test_jsonb_subscript set test_json[0] = '1'; update test_jsonb_subscript set test_json[0] = '1';
update test_jsonb_subscript set test_json[0][0] = '1'; update test_jsonb_subscript set test_json[0][0] = '1';
-- try some things with short-header and toasted subscript values
drop table test_jsonb_subscript;
create temp table test_jsonb_subscript (
id text,
test_json jsonb
);
insert into test_jsonb_subscript values('foo', '{"foo": "bar"}');
insert into test_jsonb_subscript
select s, ('{"' || s || '": "bar"}')::jsonb from repeat('xyzzy', 500) s;
select length(id), test_json[id] from test_jsonb_subscript;
update test_jsonb_subscript set test_json[id] = '"baz"';
select length(id), test_json[id] from test_jsonb_subscript;
\x
table test_jsonb_subscript;
\x
-- jsonb to tsvector -- jsonb to tsvector
select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb); select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);