Fix jsonb subscripting to cope with toasted subscript values.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 12 Dec 2022 21:17:49 +0000 (16:17 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 12 Dec 2022 21:17:54 +0000 (16:17 -0500)
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

src/backend/utils/adt/jsonb_gin.c
src/backend/utils/adt/jsonb_op.c
src/backend/utils/adt/jsonfuncs.c
src/test/regress/expected/jsonb.out
src/test/regress/sql/jsonb.sql

index 731eb018d4e434846384db62f814cc230260e6b4..1778386aac9c429f4fe2cbf666fddcbb7eafc400 100644 (file)
@@ -894,9 +894,10 @@ gin_extract_jsonb_query(PG_FUNCTION_ARGS)
            /* Nulls in the array are ignored */
            if (key_nulls[i])
                continue;
+           /* We rely on the array elements not being toasted */
            entries[j++] = make_text_key(JGINFLAG_KEY,
-                                        VARDATA(key_datums[i]),
-                                        VARSIZE(key_datums[i]) - VARHDRSZ);
+                                        VARDATA_ANY(key_datums[i]),
+                                        VARSIZE_ANY_EXHDR(key_datums[i]));
        }
 
        *nentries = j;
index 202367e9964c1d876e7fc3b62c77378ca9fa5553..27e960e5043ad24c02d84a536f39b5ed684b1107 100644 (file)
@@ -63,8 +63,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,
@@ -95,8 +96,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,
index 376a9b7ab8215304f58ff977539f1f000d1a545a..2d293da18efeb86b2786dfd04f079c1f271fc29d 100644 (file)
@@ -527,6 +527,12 @@ pg_parse_json_or_errsave(JsonLexContext *lex, JsonSemAction *sem,
 JsonLexContext *
 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),
                                        VARSIZE_ANY_EXHDR(json),
                                        GetDatabaseEncoding(),
@@ -1559,9 +1565,11 @@ jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text)
    {
        if (have_object)
        {
+           text       *subscr = DatumGetTextPP(path[i]);
+
            jbvp = getKeyJsonValueFromContainer(container,
-                                               VARDATA(path[i]),
-                                               VARSIZE(path[i]) - VARHDRSZ,
+                                               VARDATA_ANY(subscr),
+                                               VARSIZE_ANY_EXHDR(subscr),
                                                NULL);
        }
        else if (have_array)
@@ -1734,8 +1742,8 @@ push_path(JsonbParseState **st, int level, Datum *path_elems,
        {
            /* text, an object is expected */
            newkey.type = jbvString;
-           newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[i]);
-           newkey.val.string.val = VARDATA_ANY(path_elems[i]);
+           newkey.val.string.val = c;
+           newkey.val.string.len = strlen(c);
 
            (void) pushJsonbValue(st, WJB_BEGIN_OBJECT, NULL);
            (void) pushJsonbValue(st, WJB_KEY, &newkey);
@@ -4456,6 +4464,7 @@ jsonb_delete_array(PG_FUNCTION_ARGS)
                if (keys_nulls[i])
                    continue;
 
+               /* We rely on the array elements not being toasted */
                keyptr = VARDATA_ANY(keys_elems[i]);
                keylen = VARSIZE_ANY_EXHDR(keys_elems[i]);
                if (keylen == v.val.string.len &&
@@ -4977,6 +4986,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
              int path_len, JsonbParseState **st, int level,
              JsonbValue *newval, uint32 npairs, int op_type)
 {
+   text       *pathelem = NULL;
    int         i;
    JsonbValue  k,
                v;
@@ -4984,6 +4994,11 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
 
    if (level >= path_len || path_nulls[level])
        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 */
    if ((npairs == 0) && (op_type & JB_PATH_CREATE_OR_INSERT) &&
@@ -4992,8 +5007,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
        JsonbValue  newkey;
 
        newkey.type = jbvString;
-       newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]);
-       newkey.val.string.val = VARDATA_ANY(path_elems[level]);
+       newkey.val.string.val = VARDATA_ANY(pathelem);
+       newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
 
        (void) pushJsonbValue(st, WJB_KEY, &newkey);
        (void) pushJsonbValue(st, WJB_VALUE, newval);
@@ -5006,8 +5021,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
        Assert(r == WJB_KEY);
 
        if (!done &&
-           k.val.string.len == VARSIZE_ANY_EXHDR(path_elems[level]) &&
-           memcmp(k.val.string.val, VARDATA_ANY(path_elems[level]),
+           k.val.string.len == VARSIZE_ANY_EXHDR(pathelem) &&
+           memcmp(k.val.string.val, VARDATA_ANY(pathelem),
                   k.val.string.len) == 0)
        {
            done = true;
@@ -5047,8 +5062,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
                JsonbValue  newkey;
 
                newkey.type = jbvString;
-               newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]);
-               newkey.val.string.val = VARDATA_ANY(path_elems[level]);
+               newkey.val.string.val = VARDATA_ANY(pathelem);
+               newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
 
                (void) pushJsonbValue(st, WJB_KEY, &newkey);
                (void) pushJsonbValue(st, WJB_VALUE, newval);
@@ -5091,8 +5106,8 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls,
        JsonbValue  newkey;
 
        newkey.type = jbvString;
-       newkey.val.string.len = VARSIZE_ANY_EXHDR(path_elems[level]);
-       newkey.val.string.val = VARDATA_ANY(path_elems[level]);
+       newkey.val.string.val = VARDATA_ANY(pathelem);
+       newkey.val.string.len = VARSIZE_ANY_EXHDR(pathelem);
 
        (void) pushJsonbValue(st, WJB_KEY, &newkey);
        (void) push_path(st, level, path_elems, path_nulls,
@@ -5505,6 +5520,8 @@ transform_jsonb_string_values(Jsonb *jsonb, void *action_state,
        if ((type == WJB_VALUE || type == WJB_ELEM) && v.type == jbvString)
        {
            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.len = VARSIZE_ANY_EXHDR(out);
            res = pushJsonbValue(&st, type, type < WJB_BEGIN_ARRAY ? &v : NULL);
index be85676b5b93024b0e9f562e9ef0677f63af0d83..d3248aa0fd9c1a1b7cd739af405b7d4c9ea771b4 100644 (file)
@@ -5224,6 +5224,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';
 ERROR:  cannot replace existing key
 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
 select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);
                                 to_tsvector                                
index bc44ad1518f633308fd9d04759e94bd55066e7a4..9f67f4c71d6f9624a54ce6d943e3df8f5be9616c 100644 (file)
@@ -1421,6 +1421,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][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
 select to_tsvector('{"a": "aaa bbb ddd ccc", "b": ["eee fff ggg"], "c": {"d": "hhh iii"}}'::jsonb);