Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6f5e4fe

Browse files
author
Peter Geoghegan
committed
Fix contains operator in jsonb GIN support routine
Have gin_extract_jsonb() flag boths keys and elements as keys. I believe this is safe, but additional review would be useful. Add some regression testing for this. The same bug exists for GiST, and that isn't fixed here, so the failing regression test adding for the analogous GiST bug earlier continues to fail.
1 parent b88a365 commit 6f5e4fe

File tree

3 files changed

+31
-10
lines changed

3 files changed

+31
-10
lines changed

src/backend/utils/adt/jsonb_gin.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,17 @@ gin_extract_jsonb(PG_FUNCTION_ARGS)
6464
switch (r)
6565
{
6666
case WJB_KEY:
67+
/*
68+
* An element of an array is serialized as a key for our
69+
* purposes. This is necessary because array elements are also
70+
* keys.
71+
*/
72+
case WJB_ELEM:
6773
entries[i++] = PointerGetDatum(makeitemFromValue(&v, KEYFLAG));
6874
break;
6975
case WJB_VALUE:
7076
entries[i++] = PointerGetDatum(makeitemFromValue(&v, VALFLAG));
7177
break;
72-
case WJB_ELEM:
73-
entries[i++] = PointerGetDatum(makeitemFromValue(&v, ELEMFLAG));
74-
break;
7578
default:
7679
break;
7780
}
@@ -409,6 +412,11 @@ makeitem(char *str, int len, char flag)
409412
return item;
410413
}
411414

415+
/*
416+
* Create a textual representation of a jsonbValue for GIN storage.
417+
*
418+
* N.B: This should only be called where the recheck flag will be set.
419+
*/
412420
static text *
413421
makeitemFromValue(JsonbValue * v, char flag)
414422
{
@@ -424,11 +432,10 @@ makeitemFromValue(JsonbValue * v, char flag)
424432
item = makeitem((v->boolean) ? " t" : " f", 2, flag);
425433
break;
426434
case jbvNumeric:
427-
428435
/*
429436
* A textual, locale and precision independent representation of
430-
* numeric is required. Use the standard hash_numeric for this.
431-
* This is sufficient because the recheck flag will be set anyway.
437+
* numeric is required. Use the standard hash_numeric to build
438+
* one.
432439
*/
433440
cstr = palloc(8 /* hex numbers */ + 1 /* \0 */ );
434441
snprintf(cstr, 9, "%08x", DatumGetInt32(DirectFunctionCall1(hash_numeric,

src/test/regress/expected/jsonb.out

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,7 +1431,7 @@ SELECT count(*) FROM testjsonb WHERE j ?& ARRAY['public','disabled'];
14311431
42
14321432
(1 row)
14331433

1434-
-- array exists - array elements should behave as keys (for index scans too)
1434+
-- array exists - array elements should behave as keys (for GiST index scans too)
14351435
CREATE INDEX jidx_array ON testjsonb USING gist((j->'array'));
14361436
SELECT 1 from testjsonb WHERE j->'array' ? 'bar';
14371437
?column?
@@ -1492,6 +1492,14 @@ SELECT count(*) FROM testjsonb WHERE j ?& ARRAY['public','disabled'];
14921492
42
14931493
(1 row)
14941494

1495+
-- array exists - array elements should behave as keys (for GIN index scans too)
1496+
CREATE INDEX jidx_array ON testjsonb USING gin((j->'array'));
1497+
SELECT 1 from testjsonb WHERE j->'array' ? 'bar';
1498+
?column?
1499+
----------
1500+
1
1501+
(1 row)
1502+
14951503
RESET enable_seqscan;
14961504
SELECT count(*) FROM (SELECT (jsonb_each(j)).key FROM testjsonb) AS wow;
14971505
count
@@ -1559,8 +1567,9 @@ SELECT distinct * FROM (values (jsonb '{}' || ''),('{}')) v(j);
15591567
SET enable_sort = on;
15601568
RESET enable_hashagg;
15611569
RESET enable_sort;
1562-
-- btree
15631570
DROP INDEX jidx;
1571+
DROP INDEX jidx_array;
1572+
-- btree
15641573
CREATE INDEX jidx ON testjsonb USING btree (j);
15651574
SET enable_seqscan = off;
15661575
SELECT count(*) FROM testjsonb WHERE j > '{"p":1}';

src/test/regress/sql/jsonb.sql

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ SELECT count(*) FROM testjsonb WHERE j @> '{"age":25.0}';
319319
SELECT count(*) FROM testjsonb WHERE j ? 'public';
320320
SELECT count(*) FROM testjsonb WHERE j ?| ARRAY['public','disabled'];
321321
SELECT count(*) FROM testjsonb WHERE j ?& ARRAY['public','disabled'];
322-
-- array exists - array elements should behave as keys (for index scans too)
322+
-- array exists - array elements should behave as keys (for GiST index scans too)
323323
CREATE INDEX jidx_array ON testjsonb USING gist((j->'array'));
324324
SELECT 1 from testjsonb WHERE j->'array' ? 'bar';
325325

@@ -339,6 +339,10 @@ SELECT count(*) FROM testjsonb WHERE j ? 'public';
339339
SELECT count(*) FROM testjsonb WHERE j ?| ARRAY['public','disabled'];
340340
SELECT count(*) FROM testjsonb WHERE j ?& ARRAY['public','disabled'];
341341

342+
-- array exists - array elements should behave as keys (for GIN index scans too)
343+
CREATE INDEX jidx_array ON testjsonb USING gin((j->'array'));
344+
SELECT 1 from testjsonb WHERE j->'array' ? 'bar';
345+
342346
RESET enable_seqscan;
343347

344348
SELECT count(*) FROM (SELECT (jsonb_each(j)).key FROM testjsonb) AS wow;
@@ -357,8 +361,9 @@ SET enable_sort = on;
357361
RESET enable_hashagg;
358362
RESET enable_sort;
359363

360-
-- btree
361364
DROP INDEX jidx;
365+
DROP INDEX jidx_array;
366+
-- btree
362367
CREATE INDEX jidx ON testjsonb USING btree (j);
363368
SET enable_seqscan = off;
364369

0 commit comments

Comments
 (0)