Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1WjI2f-0003Al-1O for pgsql-hackers@arkaria.postgresql.org; Sun, 11 May 2014 00:55:01 +0000 Received: from localhost ([127.0.0.1] helo=postgresql.org) by malur.postgresql.org with smtp (Exim 4.80) (envelope-from ) id 1WjI2e-0000cc-Ak for pgsql-hackers@arkaria.postgresql.org; Sun, 11 May 2014 00:55:00 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1WjI2c-0000cT-I0 for pgsql-hackers@postgresql.org; Sun, 11 May 2014 00:54:58 +0000 Received: from sss.pgh.pa.us ([66.207.139.130]) by magus.postgresql.org with esmtp (Exim 4.80) (envelope-from ) id 1WjI2Y-0002B5-FY for pgsql-hackers@postgresql.org; Sun, 11 May 2014 00:54:58 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.14.4/8.14.4) with ESMTP id s4B0sXvt004987; Sat, 10 May 2014 20:54:33 -0400 From: Tom Lane To: Peter Geoghegan cc: Heikki Linnakangas , Greg Stark , Bruce Momjian , Gavin Flower , "David E. Wheeler" , Robert Haas , Andrew Dunstan , "pgsql-hackers@postgresql.org" Subject: Re: default opclass for jsonb (was Re: Call for GIST/GIN/SP-GIST opclass documentation) In-reply-to: References: <16769.1399407530@sss.pgh.pa.us> <20140506212020.GK30817@momjian.us> <57E8AA44-F816-45F2-BB61-5A854FFB0A97@justatheory.com> <28554.1399414853@sss.pgh.pa.us> <20140508134701.GO30817@momjian.us> <5819.1399558614@sss.pgh.pa.us> <1888.1399588751@sss.pgh.pa.us> <20140509033405.GA23254@momjian.us> <536C550F.50108@archidevsys.co.nz> <18360.1399633457@sss.pgh.pa.us> <20140509135336.GC23254@momjian.us> <28961.1399668272@sss.pgh.pa.us> <536E8F3A.40706@vmware.com> Comments: In-reply-to Peter Geoghegan message dated "Sat, 10 May 2014 17:25:49 -0700" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <4960.1399769595.0@sss.pgh.pa.us> Date: Sat, 10 May 2014 20:54:33 -0400 Message-ID: <4986.1399769673@sss.pgh.pa.us> X-Pg-Spam-Score: -2.6 (--) List-Archive: List-Help: List-ID: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-Mailing-List: pgsql-hackers Precedence: bulk Sender: pgsql-hackers-owner@postgresql.org ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <4960.1399769595.1@sss.pgh.pa.us> Peter Geoghegan writes: > Now, I'm not all that worried about this, because this is surely an > odd-ball use case, particularly for jsonb_hash_ops where no keys are > separately indexed (separately from *primitive* elements/values). > However, it is worth noting in the documentation in my view. I attach > a doc patch that adds this. Agreed, we'd better mention that somewhere. I'm not sure whether we have consensus to rename jsonb_hash_ops to jsonb_path_ops, but since time is so short I went ahead and made a draft patch to do so (attached). Probably the most interesting part of this is the new text in json.sgml explaining the difference between the two opclasses. I also added a paragraph about the empty-query hazard that Peter mentions. Do people think this discussion is correct and useful? regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="rename-jsonb_hash_ops.patch"; charset="us-ascii" Content-ID: <4960.1399769595.2@sss.pgh.pa.us> Content-Description: rename-jsonb_hash_ops.patch Content-Transfer-Encoding: quoted-printable diff --git a/doc/src/sgml/gin.sgml b/doc/src/sgml/gin.sgml index 0b3d6ee..1cbc73c 100644 *** a/doc/src/sgml/gin.sgml --- b/doc/src/sgml/gin.sgml *************** *** 395,401 **** ! jsonb_hash_ops jsonb @> --- 395,401 ---- ! jsonb_path_ops jsonb @> *************** *** 415,421 **** =20=20 Of the two operator classes for type jsonb, jsonb_ops= ! is the default. jsonb_hash_ops supports fewer operators but offers better performance for those operators. See for details. --- 415,421 ---- =20=20 Of the two operator classes for type jsonb, jsonb_ops= ! is the default. jsonb_path_ops supports fewer operators but offers better performance for those operators. See for details. diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml index 518fe63..52ad882 100644 *** a/doc/src/sgml/json.sgml --- b/doc/src/sgml/json.sgml *************** *** 156,162 **** =20=20 ! <type>jsonb</> Input and Output Syntax The input/output syntax for the JSON data types is as specified in RFC 7159. --- 156,162 ---- =20=20 ! JSON Input and Output Syntax The input/output syntax for the JSON data types is as specified in RFC 7159. *************** SELECT '"foo"'::jsonb ? 'foo'; *** 366,376 **** CREATE INDEX idxgin ON api USING gin (jdoc); ! The non-default GIN operator class jsonb_hash_ops supports indexing the @> operator only. An example of creating an index with this operator class is: ! CREATE INDEX idxginh ON api USING gin (jdoc jsonb_hash_ops); =20=20 --- 366,376 ---- CREATE INDEX idxgin ON api USING gin (jdoc); ! The non-default GIN operator class jsonb_path_ops supports indexing the @> operator only. An example of creating an index with this operator class is: ! CREATE INDEX idxginh ON api USING gin (jdoc jsonb_path_ops); =20=20 *************** SELECT jdoc->'guid', jdoc->'name'=20 *** 444,453 **** =20=20 ! Although the jsonb_hash_ops operator class supports only queries with the @> operator, it has notable performance advantages over the default operator ! class jsonb_ops. A jsonb_hash_ops index is usually much smaller than a jsonb_ops index over the same data, and the specificity of searches is better, particularly when queries contain keys that appear frequently in the --- 444,453 ---- =20=20 ! Although the jsonb_path_ops operator class supports only queries with the @> operator, it has notable performance advantages over the default operator ! class jsonb_ops. A jsonb_path_ops index is usually much smaller than a jsonb_ops index over the same data, and the specificity of searches is better, particularly when queries contain keys that appear frequently in the *************** SELECT jdoc->'guid', jdoc->'name'=20 *** 456,461 **** --- 456,493 ---- =20=20 + The technical difference between a jsonb_ops + and a jsonb_path_ops GIN index is that the former + creates independent index items for each key and value in the data, + while the latter creates index items only for each value in the data. + But in jsonb_path_ops, each index item is a hash + of both the value and the key(s) leading to it; for example to index + {"foo": {"bar": "baz"}}, a single index item would + be created incorporating all three of foo, bar, + and baz into the hash value. Thus a containment query + looking for this structure would result in an extremely specific index + search; but there is no way at all to find out whether foo + appears as a key. On the other hand, a jsonb_ops + index would create three index items representing foo, + bar, and baz separately; then to do the + containment query, it would look for rows containing all three of + these keys. While GIN indexes can perform such an AND search fairly + efficiently, it will still be less specific and slower than the + equivalent jsonb_path_ops search, especially if + there are a very large number of rows containing any single one of the + three keys. + +=20 + + A disadvantage of the jsonb_path_ops approach is + that it produces no index entries for JSON structures not containing + any values, such as {"a": {}}. If a search for + documents containing such a structure is requested, it will require a + full-index scan, which is quite slow. jsonb_path_ops is + therefore ill-suited for applications that perform such searches. + +=20 + jsonb also supports btree and hash indexes. These are usually useful only if it's important to check equality of complete JSON documents. diff --git a/src/backend/utils/adt/jsonb_gin.c b/src/backend/utils/adt/json= b_gin.c index 57a0b2c..069ee03 100644 *** a/src/backend/utils/adt/jsonb_gin.c --- b/src/backend/utils/adt/jsonb_gin.c *************** gin_triconsistent_jsonb(PG_FUNCTION_ARGS *** 315,323 **** =20=20 /* * ! * jsonb_hash_ops GIN opclass support functions * ! * In a jsonb_hash_ops index, the GIN keys are uint32 hashes, one per JSON * value; but the JSON key(s) leading to each value are also included in = its * hash computation. This means we can only support containment queries, * but the index can distinguish, for example, {"foo": 42} from {"bar": 4= 2} --- 315,323 ---- =20=20 /* * ! * jsonb_path_ops GIN opclass support functions * ! * In a jsonb_path_ops index, the GIN keys are uint32 hashes, one per JSON * value; but the JSON key(s) leading to each value are also included in = its * hash computation. This means we can only support containment queries, * but the index can distinguish, for example, {"foo": 42} from {"bar": 4= 2} *************** gin_triconsistent_jsonb(PG_FUNCTION_ARGS *** 326,332 **** */ =20=20 Datum ! gin_extract_jsonb_hash(PG_FUNCTION_ARGS) { Jsonb *jb =3D PG_GETARG_JSONB(0); int32 *nentries =3D (int32 *) PG_GETARG_POINTER(1); --- 326,332 ---- */ =20=20 Datum ! gin_extract_jsonb_path(PG_FUNCTION_ARGS) { Jsonb *jb =3D PG_GETARG_JSONB(0); int32 *nentries =3D (int32 *) PG_GETARG_POINTER(1); *************** gin_extract_jsonb_hash(PG_FUNCTION_ARGS) *** 349,355 **** /* Otherwise, use 2 * root count as initial estimate of result size */ entries =3D (Datum *) palloc(sizeof(Datum) * total); =20=20 ! /* We keep a stack of hashes corresponding to parent key levels */ tail.parent =3D NULL; tail.hash =3D 0; stack =3D &tail; --- 349,355 ---- /* Otherwise, use 2 * root count as initial estimate of result size */ entries =3D (Datum *) palloc(sizeof(Datum) * total); =20=20 ! /* We keep a stack of partial hashes corresponding to parent key levels = */ tail.parent =3D NULL; tail.hash =3D 0; stack =3D &tail; *************** gin_extract_jsonb_hash(PG_FUNCTION_ARGS) *** 439,445 **** } =20=20 Datum ! gin_extract_jsonb_query_hash(PG_FUNCTION_ARGS) { int32 *nentries =3D (int32 *) PG_GETARG_POINTER(1); StrategyNumber strategy =3D PG_GETARG_UINT16(2); --- 439,445 ---- } =20=20 Datum ! gin_extract_jsonb_query_path(PG_FUNCTION_ARGS) { int32 *nentries =3D (int32 *) PG_GETARG_POINTER(1); StrategyNumber strategy =3D PG_GETARG_UINT16(2); *************** gin_extract_jsonb_query_hash(PG_FUNCTION *** 449,457 **** if (strategy !=3D JsonbContainsStrategyNumber) elog(ERROR, "unrecognized strategy number: %d", strategy); =20=20 ! /* Query is a jsonb, so just apply gin_extract_jsonb_hash ... */ entries =3D (Datum *) ! DatumGetPointer(DirectFunctionCall2(gin_extract_jsonb_hash, PG_GETARG_DATUM(0), PointerGetDatum(nentries))); =20=20 --- 449,457 ---- if (strategy !=3D JsonbContainsStrategyNumber) elog(ERROR, "unrecognized strategy number: %d", strategy); =20=20 ! /* Query is a jsonb, so just apply gin_extract_jsonb_path ... */ entries =3D (Datum *) ! DatumGetPointer(DirectFunctionCall2(gin_extract_jsonb_path, PG_GETARG_DATUM(0), PointerGetDatum(nentries))); =20=20 *************** gin_extract_jsonb_query_hash(PG_FUNCTION *** 463,469 **** } =20=20 Datum ! gin_consistent_jsonb_hash(PG_FUNCTION_ARGS) { bool *check =3D (bool *) PG_GETARG_POINTER(0); StrategyNumber strategy =3D PG_GETARG_UINT16(1); --- 463,469 ---- } =20=20 Datum ! gin_consistent_jsonb_path(PG_FUNCTION_ARGS) { bool *check =3D (bool *) PG_GETARG_POINTER(0); StrategyNumber strategy =3D PG_GETARG_UINT16(1); *************** gin_consistent_jsonb_hash(PG_FUNCTION_AR *** 480,492 **** elog(ERROR, "unrecognized strategy number: %d", strategy); =20=20 /* ! * jsonb_hash_ops is necessarily lossy, not only because of hash * collisions but also because it doesn't preserve complete information * about the structure of the JSON object. Besides, there are some ! * special rules around the containment of raw scalar arrays and regular ! * arrays that are not handled here. So we must always recheck a match. ! * However, if not all of the keys are present, the tuple certainly ! * doesn't match. */ *recheck =3D true; for (i =3D 0; i < nkeys; i++) --- 480,491 ---- elog(ERROR, "unrecognized strategy number: %d", strategy); =20=20 /* ! * jsonb_path_ops is necessarily lossy, not only because of hash * collisions but also because it doesn't preserve complete information * about the structure of the JSON object. Besides, there are some ! * special rules around the containment of raw scalars in arrays that are ! * not handled here. So we must always recheck a match. However, if not ! * all of the keys are present, the tuple certainly doesn't match. */ *recheck =3D true; for (i =3D 0; i < nkeys; i++) *************** gin_consistent_jsonb_hash(PG_FUNCTION_AR *** 502,508 **** } =20=20 Datum ! gin_triconsistent_jsonb_hash(PG_FUNCTION_ARGS) { GinTernaryValue *check =3D (GinTernaryValue *) PG_GETARG_POINTER(0); StrategyNumber strategy =3D PG_GETARG_UINT16(1); --- 501,507 ---- } =20=20 Datum ! gin_triconsistent_jsonb_path(PG_FUNCTION_ARGS) { GinTernaryValue *check =3D (GinTernaryValue *) PG_GETARG_POINTER(0); StrategyNumber strategy =3D PG_GETARG_UINT16(1); diff --git a/src/include/catalog/pg_amop.h b/src/include/catalog/pg_amop.h index 8efd3be..264059f 100644 *** a/src/include/catalog/pg_amop.h --- b/src/include/catalog/pg_amop.h *************** DATA(insert ( 4033 3802 3802 4 s 3245=20 *** 787,798 **** DATA(insert ( 4033 3802 3802 5 s 3243 403 0 )); =20=20 /* ! * hash jsonb ops */ DATA(insert ( 4034 3802 3802 1 s 3240 405 0 )); =20=20 /* ! * GIN jsonb ops */ DATA(insert ( 4036 3802 3802 7 s 3246 2742 0 )); DATA(insert ( 4036 3802 25 9 s 3247 2742 0 )); --- 787,798 ---- DATA(insert ( 4033 3802 3802 5 s 3243 403 0 )); =20=20 /* ! * hash jsonb_ops */ DATA(insert ( 4034 3802 3802 1 s 3240 405 0 )); =20=20 /* ! * GIN jsonb_ops */ DATA(insert ( 4036 3802 3802 7 s 3246 2742 0 )); DATA(insert ( 4036 3802 25 9 s 3247 2742 0 )); *************** DATA(insert ( 4036 3802 1009 10 s 3248 *** 800,806 **** DATA(insert ( 4036 3802 1009 11 s 3249 2742 0 )); =20=20 /* ! * GIN jsonb hash ops */ DATA(insert ( 4037 3802 3802 7 s 3246 2742 0 )); =20=20 --- 800,806 ---- DATA(insert ( 4036 3802 1009 11 s 3249 2742 0 )); =20=20 /* ! * GIN jsonb_path_ops */ DATA(insert ( 4037 3802 3802 7 s 3246 2742 0 )); =20=20 diff --git a/src/include/catalog/pg_opclass.h b/src/include/catalog/pg_opcl= ass.h index ecf7063..3698886 100644 *** a/src/include/catalog/pg_opclass.h --- b/src/include/catalog/pg_opclass.h *************** DATA(insert ( 4000 text_ops PGNSP PGUI *** 232,237 **** DATA(insert ( 403 jsonb_ops PGNSP PGUID 4033 3802 t 0 )); DATA(insert ( 405 jsonb_ops PGNSP PGUID 4034 3802 t 0 )); DATA(insert ( 2742 jsonb_ops PGNSP PGUID 4036 3802 t 25 )); ! DATA(insert ( 2742 jsonb_hash_ops PGNSP PGUID 4037 3802 f 23 )); =20=20 #endif /* PG_OPCLASS_H */ --- 232,237 ---- DATA(insert ( 403 jsonb_ops PGNSP PGUID 4033 3802 t 0 )); DATA(insert ( 405 jsonb_ops PGNSP PGUID 4034 3802 t 0 )); DATA(insert ( 2742 jsonb_ops PGNSP PGUID 4036 3802 t 25 )); ! DATA(insert ( 2742 jsonb_path_ops PGNSP PGUID 4037 3802 f 23 )); =20=20 #endif /* PG_OPCLASS_H */ diff --git a/src/include/catalog/pg_opfamily.h b/src/include/catalog/pg_opf= amily.h index 9e8f4ac..c83ac8c 100644 *** a/src/include/catalog/pg_opfamily.h --- b/src/include/catalog/pg_opfamily.h *************** DATA(insert OID =3D 3474 ( 4000 range_ops=09 *** 148,158 **** DATA(insert OID =3D 4015 ( 4000 quad_point_ops PGNSP PGUID )); DATA(insert OID =3D 4016 ( 4000 kd_point_ops PGNSP PGUID )); DATA(insert OID =3D 4017 ( 4000 text_ops PGNSP PGUID )); DATA(insert OID =3D 4033 ( 403 jsonb_ops PGNSP PGUID )); DATA(insert OID =3D 4034 ( 405 jsonb_ops PGNSP PGUID )); DATA(insert OID =3D 4035 ( 783 jsonb_ops PGNSP PGUID )); DATA(insert OID =3D 4036 ( 2742 jsonb_ops PGNSP PGUID )); ! DATA(insert OID =3D 4037 ( 2742 jsonb_hash_ops PGNSP PGUID )); ! #define TEXT_SPGIST_FAM_OID 4017 =20=20 #endif /* PG_OPFAMILY_H */ --- 148,158 ---- DATA(insert OID =3D 4015 ( 4000 quad_point_ops PGNSP PGUID )); DATA(insert OID =3D 4016 ( 4000 kd_point_ops PGNSP PGUID )); DATA(insert OID =3D 4017 ( 4000 text_ops PGNSP PGUID )); + #define TEXT_SPGIST_FAM_OID 4017 DATA(insert OID =3D 4033 ( 403 jsonb_ops PGNSP PGUID )); DATA(insert OID =3D 4034 ( 405 jsonb_ops PGNSP PGUID )); DATA(insert OID =3D 4035 ( 783 jsonb_ops PGNSP PGUID )); DATA(insert OID =3D 4036 ( 2742 jsonb_ops PGNSP PGUID )); ! DATA(insert OID =3D 4037 ( 2742 jsonb_path_ops PGNSP PGUID )); =20=20 #endif /* PG_OPFAMILY_H */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index e601ccd..72170af 100644 *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** DATA(insert OID =3D 3484 ( gin_consistent *** 4645,4657 **** DESCR("GIN support"); DATA(insert OID =3D 3488 ( gin_triconsistent_jsonb PGNSP PGUID 12 1 0 0 = 0 f f f f t f i 7 0 16 "2281 21 2277 23 2281 2281 2281" _null_ _null_ _null= _ _null_ gin_triconsistent_jsonb _null_ _null_ _null_ )); DESCR("GIN support"); ! DATA(insert OID =3D 3485 ( gin_extract_jsonb_hash PGNSP PGUID 12 1 0 0 = 0 f f f f t f i 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ gin_e= xtract_jsonb_hash _null_ _null_ _null_ )); DESCR("GIN support"); ! DATA(insert OID =3D 3486 ( gin_extract_jsonb_query_hash PGNSP PGUID 12 1= 0 0 0 f f f f t f i 7 0 2281 "2277 2281 21 2281 2281 2281 2281" _null_ _nu= ll_ _null_ _null_ gin_extract_jsonb_query_hash _null_ _null_ _null_ )); DESCR("GIN support"); ! DATA(insert OID =3D 3487 ( gin_consistent_jsonb_hash PGNSP PGUID 12 1 0= 0 0 f f f f t f i 8 0 16 "2281 21 2277 23 2281 2281 2281 2281" _null_ _nul= l_ _null_ _null_ gin_consistent_jsonb_hash _null_ _null_ _null_ )); DESCR("GIN support"); ! DATA(insert OID =3D 3489 ( gin_triconsistent_jsonb_hash PGNSP PGUID 12 1= 0 0 0 f f f f t f i 7 0 16 "2281 21 2277 23 2281 2281 2281" _null_ _null_ = _null_ _null_ gin_triconsistent_jsonb_hash _null_ _null_ _null_ )); DESCR("GIN support"); =20=20 /* txid */ --- 4645,4657 ---- DESCR("GIN support"); DATA(insert OID =3D 3488 ( gin_triconsistent_jsonb PGNSP PGUID 12 1 0 0 = 0 f f f f t f i 7 0 16 "2281 21 2277 23 2281 2281 2281" _null_ _null_ _null= _ _null_ gin_triconsistent_jsonb _null_ _null_ _null_ )); DESCR("GIN support"); ! DATA(insert OID =3D 3485 ( gin_extract_jsonb_path PGNSP PGUID 12 1 0 0 = 0 f f f f t f i 3 0 2281 "2281 2281 2281" _null_ _null_ _null_ _null_ gin_e= xtract_jsonb_path _null_ _null_ _null_ )); DESCR("GIN support"); ! DATA(insert OID =3D 3486 ( gin_extract_jsonb_query_path PGNSP PGUID 12 1= 0 0 0 f f f f t f i 7 0 2281 "2277 2281 21 2281 2281 2281 2281" _null_ _nu= ll_ _null_ _null_ gin_extract_jsonb_query_path _null_ _null_ _null_ )); DESCR("GIN support"); ! DATA(insert OID =3D 3487 ( gin_consistent_jsonb_path PGNSP PGUID 12 1 0= 0 0 f f f f t f i 8 0 16 "2281 21 2277 23 2281 2281 2281 2281" _null_ _nul= l_ _null_ _null_ gin_consistent_jsonb_path _null_ _null_ _null_ )); DESCR("GIN support"); ! DATA(insert OID =3D 3489 ( gin_triconsistent_jsonb_path PGNSP PGUID 12 1= 0 0 0 f f f f t f i 7 0 16 "2281 21 2277 23 2281 2281 2281" _null_ _null_ = _null_ _null_ gin_triconsistent_jsonb_path _null_ _null_ _null_ )); DESCR("GIN support"); =20=20 /* txid */ diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h index bb8c380..add7628 100644 *** a/src/include/utils/jsonb.h --- b/src/include/utils/jsonb.h *************** extern Datum jsonb_eq(PG_FUNCTION_ARGS); *** 332,349 **** extern Datum jsonb_cmp(PG_FUNCTION_ARGS); extern Datum jsonb_hash(PG_FUNCTION_ARGS); =20=20 ! /* GIN support functions */ extern Datum gin_compare_jsonb(PG_FUNCTION_ARGS); extern Datum gin_extract_jsonb(PG_FUNCTION_ARGS); extern Datum gin_extract_jsonb_query(PG_FUNCTION_ARGS); extern Datum gin_consistent_jsonb(PG_FUNCTION_ARGS); extern Datum gin_triconsistent_jsonb(PG_FUNCTION_ARGS); =20=20 ! /* GIN hash opclass functions */ ! extern Datum gin_extract_jsonb_hash(PG_FUNCTION_ARGS); ! extern Datum gin_extract_jsonb_query_hash(PG_FUNCTION_ARGS); ! extern Datum gin_consistent_jsonb_hash(PG_FUNCTION_ARGS); ! extern Datum gin_triconsistent_jsonb_hash(PG_FUNCTION_ARGS); =20=20 /* Support functions */ extern int compareJsonbContainers(JsonbContainer *a, JsonbContainer *b); --- 332,349 ---- extern Datum jsonb_cmp(PG_FUNCTION_ARGS); extern Datum jsonb_hash(PG_FUNCTION_ARGS); =20=20 ! /* GIN support functions for jsonb_ops */ extern Datum gin_compare_jsonb(PG_FUNCTION_ARGS); extern Datum gin_extract_jsonb(PG_FUNCTION_ARGS); extern Datum gin_extract_jsonb_query(PG_FUNCTION_ARGS); extern Datum gin_consistent_jsonb(PG_FUNCTION_ARGS); extern Datum gin_triconsistent_jsonb(PG_FUNCTION_ARGS); =20=20 ! /* GIN support functions for jsonb_path_ops */ ! extern Datum gin_extract_jsonb_path(PG_FUNCTION_ARGS); ! extern Datum gin_extract_jsonb_query_path(PG_FUNCTION_ARGS); ! extern Datum gin_consistent_jsonb_path(PG_FUNCTION_ARGS); ! extern Datum gin_triconsistent_jsonb_path(PG_FUNCTION_ARGS); =20=20 /* Support functions */ extern int compareJsonbContainers(JsonbContainer *a, JsonbContainer *b); diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expecte= d/jsonb.out index c5a7d64..ae7c506 100644 *** a/src/test/regress/expected/jsonb.out --- b/src/test/regress/expected/jsonb.out *************** SELECT count(*) FROM testjsonb WHERE j =3D *** 1685,1693 **** 1 (1 row) =20=20 ! --gin hash DROP INDEX jidx; ! CREATE INDEX jidx ON testjsonb USING gin (j jsonb_hash_ops); SET enable_seqscan =3D off; SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}'; count=20 --- 1685,1693 ---- 1 (1 row) =20=20 ! --gin path opclass DROP INDEX jidx; ! CREATE INDEX jidx ON testjsonb USING gin (j jsonb_path_ops); SET enable_seqscan =3D off; SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}'; count=20 diff --git a/src/test/regress/expected/jsonb_1.out b/src/test/regress/expec= ted/jsonb_1.out index 0e3ebd1..38a95b4 100644 *** a/src/test/regress/expected/jsonb_1.out --- b/src/test/regress/expected/jsonb_1.out *************** SELECT count(*) FROM testjsonb WHERE j =3D *** 1685,1693 **** 1 (1 row) =20=20 ! --gin hash DROP INDEX jidx; ! CREATE INDEX jidx ON testjsonb USING gin (j jsonb_hash_ops); SET enable_seqscan =3D off; SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}'; count=20 --- 1685,1693 ---- 1 (1 row) =20=20 ! --gin path opclass DROP INDEX jidx; ! CREATE INDEX jidx ON testjsonb USING gin (j jsonb_path_ops); SET enable_seqscan =3D off; SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}'; count=20 diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql index 3e90489..7527925 100644 *** a/src/test/regress/sql/jsonb.sql --- b/src/test/regress/sql/jsonb.sql *************** SET enable_seqscan =3D off; *** 391,399 **** SELECT count(*) FROM testjsonb WHERE j > '{"p":1}'; SELECT count(*) FROM testjsonb WHERE j =3D '{"pos":98, "line":371, "node"= :"CBA", "indexed":true}'; =20=20 ! --gin hash DROP INDEX jidx; ! CREATE INDEX jidx ON testjsonb USING gin (j jsonb_hash_ops); SET enable_seqscan =3D off; =20=20 SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}'; --- 391,399 ---- SELECT count(*) FROM testjsonb WHERE j > '{"p":1}'; SELECT count(*) FROM testjsonb WHERE j =3D '{"pos":98, "line":371, "node"= :"CBA", "indexed":true}'; =20=20 ! --gin path opclass DROP INDEX jidx; ! CREATE INDEX jidx ON testjsonb USING gin (j jsonb_path_ops); SET enable_seqscan =3D off; =20=20 SELECT count(*) FROM testjsonb WHERE j @> '{"wait":null}'; ------- =_aaaaaaaaaa0 Content-Type: text/plain Content-Disposition: inline Content-Transfer-Encoding: 8bit MIME-Version: 1.0 -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers ------- =_aaaaaaaaaa0--