diff --git a/Makefile b/Makefile index b11a9b1..540bee1 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,8 @@ ifdef USE_ASSERT_CHECKING override CFLAGS += -DUSE_ASSERT_CHECKING endif +override CPPFLAGS += $(CPPFLAGS) -I$(srcdir)/include + jsquery_gram.o: jsquery_scan.c jsquery_gram.c: BISONFLAGS += -d diff --git a/README.md b/README.md index 7b15ae0..eb8fb22 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ examples. Same rules apply when you search inside objects and branchy structures. Type checking operators and "every" placeholders are useful for document -schema validation. JsQuery matchig operator `@@` is immutable and can be used +schema validation. JsQuery matching operator `@@` is immutable and can be used in CHECK constraint. See following example. ```sql @@ -220,13 +220,14 @@ for more examples. GIN indexes ----------- -JsQuery extension contains two operator classes (opclasses) for GIN which +JsQuery extension contains three operator classes (opclasses) for GIN which provide different kinds of query optimization. - * jsonb\_path\_value\_ops - * jsonb\_value\_path\_ops + * `jsonb_path_value_ops` + * `jsonb_laxpath_value_ops` + * `jsonb_value_path_ops` -In each of two GIN opclasses jsonb documents are decomposed into entries. Each +In each of GIN opclasses jsonb documents are decomposed into entries. Each entry is associated with particular value and it's path. Difference between opclasses is in the entry representation, comparison and usage for search optimization. @@ -235,11 +236,11 @@ For example, jsonb document `{"a": [{"b": "xyz", "c": true}, 10], "d": {"e": [7, false]}}` would be decomposed into following entries: - * "a".#."b"."xyz" - * "a".#."c".true - * "a".#.10 - * "d"."e".#.7 - * "d"."e".#.false + * `"a".#."b"."xyz"` + * `"a".#."c".true` + * `"a".#.10` + * `"d"."e".#.7` + * `"d"."e".#.false` Since JsQuery doesn't support search in particular array index, we consider all array elements to be equivalent. Thus, each array element is marked with @@ -247,12 +248,12 @@ same `#` sign in the path. Major problem in the entries representation is its size. In the given example key "a" is presented three times. In the large branchy documents with long -keys size of naive entries representation becomes unreasonable. Both opclasses +keys size of naive entries representation becomes unreasonable. All opclasses address this issue but in a slightly different way. -### jsonb\_path\_value\_ops +### `jsonb_path_value_ops` -jsonb\_path\_value\_ops represents entry as pair of path hash and value. +`jsonb_path_value_ops` represents entry as pair of path hash and value. Following pseudocode illustrates it. (hash(path_item_1.path_item_2. ... .path_item_n); value) @@ -263,9 +264,25 @@ is hashed and it is higher part of entry we need to know the full path to the value in order to use it for search. However, once path is specified we can use both exact and range searches very efficiently. -### jsonb\_value\_path\_ops +### `jsonb_laxpath_value_ops` -jsonb\_value\_path\_ops represents entry as pair of value and bloom filter +`jsonb_laxpath_value_ops` differs from the `jsonb_path_value_ops` only in +that it skips array path items from the hashing. So, the jsonb document above +would be decomposed into following entries: + + * `(hash("a", "b"); "xyz")` + * `(hash("a", "c"); true)` + * `(hash("a"); 10)` + * `(hash("d", "e"); 7)` + * `(hash("d", "e"); false)` + +Skipping array items greatly simplifies extraction of lax JSON path queries – +there is no need to extract all possible unwrapped paths (see example for +`gin_debug_jsonpath_path_value()` below). + +### `jsonb_value_path_ops` + +`jsonb_value_path_ops` represents entry as pair of value and bloom filter of path. (value; bloom(path_item_1) | bloom(path_item_2) | ... | bloom(path_item_n)) @@ -286,8 +303,15 @@ Unfortunately, opclasses aren't allowed to do any custom output to the EXPLAIN. That's why JsQuery provides following functions which allows to see how particular opclass optimizes given query. - * gin\_debug\_query\_path\_value(jsquery) – for jsonb\_path\_value\_ops - * gin\_debug\_query\_value\_path(jsquery) – for jsonb\_value\_path\_ops + * `jsonb_path_value_ops`: + - `gin_debug_query_path_value(jsquery)` + - `gin_debug_jsonpath_path_value(jsonpath)` + * `jsonb_laxpath_value_ops`: + - `gin_debug_query_laxpath_value(jsquery)` + - `gin_debug_jsonpath_laxpath_value(jsonpath)` + * `jsonb_value_path_ops`: + - `gin_debug_query_value_path(jsquery)` + - `gin_debug_jsonpath_value_path(jsonpath)` Result of these functions is a textual representation of query tree which leafs are GIN search entries. Following examples show different results of @@ -307,17 +331,42 @@ query optimization by different opclasses. *.y = 1 , entry 1 + y = 2 , entry 2 + +Examples for nearly equivalent JSON path query: + + # SELECT gin_debug_jsonpath_value_path('$.x == 1 && ($.**.y == 1 || $.y == 2)'); + gin_debug_jsonpath_value_path + ------------------------------- + AND + + OR + + *.y = 1 , entry 0 + + y = 2 , entry 1 + + x = 1 , entry 2 + + + # SELECT gin_debug_jsonpath_path_value('$.x == 1 && ($.**.y == 1 || $.y == 2)'); + gin_debug_jsonpath_path_value + ------------------------------- + OR + + #.x = 1 , entry 0 + + #.x.# = 1 , entry 1 + + x = 1 , entry 2 + + x.# = 1 , entry 3 + + + # SELECT gin_debug_jsonpath_laxpath_value('$.x == 1 && ($.**.y == 1 || $.y == 2)'); + gin_debug_jsonpath_laxpath_value + ---------------------------------- + x = 1 , entry 0 + + Unfortunately, jsonb have no statistics yet. That's why JsQuery optimizer has to do imperative decision while selecting conditions to be evaluated using -index. This decision is made by assumtion that some condition types are less +index. This decision is made by assumption that some condition types are less selective than others. Optimizer divides conditions into following selectivity class (listed by descending of selectivity). - 1. Equality (x = c) - 2. Range (c1 < x < c2) - 3. Inequality (x > c) - 4. Is (x is type) - 5. Any (x = \*) + 1. Equality (`x = c`) + 2. Range (`c1 < x < c2`) + 3. Inequality (`x > c`) + 4. Is (`x is type`) + 5. Any (`x = *`) Optimizer evades index evaluation of less selective conditions when possible. For example, in the `x = 1 AND y > 0` query `x = 1` is assumed to be more diff --git a/data/test_jsquery.data b/data/test_jsquery.data index 01d8660..add7fb5 100644 --- a/data/test_jsquery.data +++ b/data/test_jsquery.data @@ -1015,6 +1015,8 @@ {"t": "a"} {"t": true} {"t": false} +{} +[] [1, 2, 3] ["a", "b", "c"] 1 diff --git a/expected/jsquery.out b/expected/jsquery.out index 7a06abb..4880f43 100644 --- a/expected/jsquery.out +++ b/expected/jsquery.out @@ -530,325 +530,325 @@ select 'a.b.#10203.* > 4'::jsquery; "a"."b".#10203.* > 4 (1 row) -select '{"a": {"b": null}}'::jsonb @@ 'a.b = 1'; +select '{"a": {"b": null}}'::jsonb @@ 'a.b = 1'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": null}}'::jsonb @@ 'a.b = null'; +select '{"a": {"b": null}}'::jsonb @@ 'a.b = null'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": null}}'::jsonb @@ 'a.b = false'; +select '{"a": {"b": null}}'::jsonb @@ 'a.b = false'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": false}}'::jsonb @@ 'a.b = false'; +select '{"a": {"b": false}}'::jsonb @@ 'a.b = false'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": false}}'::jsonb @@ 'a.b = true'; +select '{"a": {"b": false}}'::jsonb @@ 'a.b = true'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": true}}'::jsonb @@ 'a.b = true'; +select '{"a": {"b": true}}'::jsonb @@ 'a.b = true'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 1'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 1'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 1'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 1'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 1'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 1'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 1'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 1'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 1'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 1'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 2'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 2'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 2'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 2'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 2'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 2'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 2'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 2'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 2'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 2'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 0'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 0'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 0'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 0'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 0'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 0'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 0'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 0'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 0'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 0'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ '*.b > 0'; +select '{"a": {"b": 1}}'::jsonb @@ '*.b > 0'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ '*.b > 0'; +select '{"a": {"b": 1}}'::jsonb @@ '*.b > 0'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.* > 0'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.* > 0'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1}}'::jsonb @@ 'a.* > 0'; +select '{"a": {"b": 1}}'::jsonb @@ 'a.* > 0'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 1 ]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 1 ]'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b @> [ 1 ]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b @> [ 1 ]'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b <@ [ 1 ]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b <@ [ 1 ]'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b @> [ 1,2,3,4 ]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b @> [ 1,2,3,4 ]'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b <@ [ 1,2,3,4 ]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b <@ [ 1,2,3,4 ]'::jsquery; ?column? ---------- t (1 row) -select '[{"a": 2}, {"a": 3}]'::jsonb @@ '*.a = 4'; +select '[{"a": 2}, {"a": 3}]'::jsonb @@ '*.a = 4'::jsquery; ?column? ---------- f (1 row) -select '[{"a": 2}, {"a": 3}]'::jsonb @@ '*.a = 3'; +select '[{"a": 2}, {"a": 3}]'::jsonb @@ '*.a = 3'::jsquery; ?column? ---------- t (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.a = 4'; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.a = 4'::jsquery; ?column? ---------- f (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.a = 4'; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.a = 4'::jsquery; ?column? ---------- t (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 1 OR a=3)'; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 1 OR a=3)'::jsquery; ?column? ---------- t (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 OR a=1)'; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 OR a=1)'::jsquery; ?column? ---------- t (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 and a=1)'; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 and a=1)'::jsquery; ?column? ---------- f (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 and a=2)' as "false"; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 and a=2)'::jsquery as "false"; false ------- f (1 row) -select '[{"a": 2, "b":3}, {"a": 3, "b": 1}]'::jsonb @@ '#(b = 1 and a=3)'; +select '[{"a": 2, "b":3}, {"a": 3, "b": 1}]'::jsonb @@ '#(b = 1 and a=3)'::jsquery; ?column? ---------- t (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.a.a = 4'; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.a.a = 4'::jsquery; ?column? ---------- t (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.a.a = 4'; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.a.a = 4'::jsquery; ?column? ---------- t (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.#.a.a = 4'; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.#.a.a = 4'::jsquery; ?column? ---------- t (1 row) -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.*.a.a = 4'; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.*.a.a = 4'::jsquery; ?column? ---------- t (1 row) -select '{"a": 1}'::jsonb @@ 'a in (0,1,2)'; +select '{"a": 1}'::jsonb @@ 'a in (0,1,2)'::jsquery; ?column? ---------- t (1 row) -select '{"a": 1}'::jsonb @@ 'a in (0,2)'; +select '{"a": 1}'::jsonb @@ 'a in (0,2)'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#=2'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#=2'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 5 ]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 5 ]'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a=*'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a=*'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b=*'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b=*'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.c=*'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.c=*'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b = [1,2,3]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b = [1,2,3]'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.# = [1,2,3]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.# = [1,2,3]'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b && [1,2,3]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b && [1,2,3]'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.# && [1,2,3]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.# && [1,2,3]'::jsquery; ?column? ---------- f @@ -890,175 +890,175 @@ select '{"x":[0,1,1,2]}'::jsonb @@ 'x @> [1,0,3]'::jsquery; f (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 2 ]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 2 ]'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b($ && [ 2 ])'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b($ && [ 2 ])'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.$.b && [ 2 ]'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.$.b && [ 2 ]'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.$.b ($ && [ 2 ])'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.$.b ($ && [ 2 ])'::jsquery; ?column? ---------- t (1 row) -select '[1,2,3]'::jsonb @@ '# && [2]'; +select '[1,2,3]'::jsonb @@ '# && [2]'::jsquery; ?column? ---------- f (1 row) -select '[1,2,3]'::jsonb @@ '#($ && [2])'; +select '[1,2,3]'::jsonb @@ '#($ && [2])'::jsquery; ?column? ---------- f (1 row) -select '[1,2,3]'::jsonb @@ '$ && [2]'; +select '[1,2,3]'::jsonb @@ '$ && [2]'::jsquery; ?column? ---------- t (1 row) -select '[1,2,3]'::jsonb @@ '$ ($ && [2])'; +select '[1,2,3]'::jsonb @@ '$ ($ && [2])'::jsquery; ?column? ---------- t (1 row) -select '[1,2,3]'::jsonb @@ '$ = 2'; +select '[1,2,3]'::jsonb @@ '$ = 2'::jsquery; ?column? ---------- f (1 row) -select '[1,2,3]'::jsonb @@ '# = 2'; +select '[1,2,3]'::jsonb @@ '# = 2'::jsquery; ?column? ---------- t (1 row) -select '[1,2,3]'::jsonb @@ '#.$ = 2'; +select '[1,2,3]'::jsonb @@ '#.$ = 2'::jsquery; ?column? ---------- t (1 row) -select '[1,2,3]'::jsonb @@ '#($ = 2)'; +select '[1,2,3]'::jsonb @@ '#($ = 2)'::jsquery; ?column? ---------- t (1 row) -select '[3,4]'::jsonb @@ '#($ > 2 and $ < 5)'; +select '[3,4]'::jsonb @@ '#($ > 2 and $ < 5)'::jsquery; ?column? ---------- t (1 row) -select '[3,4]'::jsonb @@ '# > 2 and # < 5'; +select '[3,4]'::jsonb @@ '# > 2 and # < 5'::jsquery; ?column? ---------- t (1 row) -select '[1,6]'::jsonb @@ '#($ > 2 and $ < 5)'; +select '[1,6]'::jsonb @@ '#($ > 2 and $ < 5)'::jsquery; ?column? ---------- f (1 row) -select '[1,6]'::jsonb @@ '# > 2 and # < 5'; +select '[1,6]'::jsonb @@ '# > 2 and # < 5'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%.b=3'; +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%.b=3'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ 'a.%=3'; +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ 'a.%=3'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%.%="hey"'; +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%.%="hey"'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%="hey"'; +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%="hey"'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%=[5,6]'; +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%=[5,6]'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#1 = 2'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#1 = 2'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#2 = 2'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#2 = 2'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#3 = 2'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#3 = 2'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#1.x = 2'; +select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#1.x = 2'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#2.x = 2'; +select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#2.x = 2'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#3.x = 2'; +select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#3.x = 2'::jsquery; ?column? ---------- f (1 row) -select '"XXX"'::jsonb @@ '$="XXX"'; +select '"XXX"'::jsonb @@ '$="XXX"'::jsquery; ?column? ---------- t (1 row) -select '"XXX"'::jsonb @@ '#.$="XXX"'; +select '"XXX"'::jsonb @@ '#.$="XXX"'::jsquery; ?column? ---------- f @@ -1071,19 +1071,19 @@ select 'a\t = "dollar \u0024 character"'::jsquery; "a\t" = "dollar $ character" (1 row) -select '{ "a": "dollar \u0024 character" }'::jsonb @@ '* = "dollar \u0024 character"'; +select '{ "a": "dollar \u0024 character" }'::jsonb @@ '* = "dollar \u0024 character"'::jsquery; ?column? ---------- t (1 row) -select '{ "a": "dollar \u0024 character" }'::jsonb @@ '* = "dollar $ character"'; +select '{ "a": "dollar \u0024 character" }'::jsonb @@ '* = "dollar $ character"'::jsquery; ?column? ---------- t (1 row) -select '{ "a": "dollar $ character" }'::jsonb @@ '* = "dollar \u0024 character"'; +select '{ "a": "dollar $ character" }'::jsonb @@ '* = "dollar \u0024 character"'::jsquery; ?column? ---------- t @@ -1471,31 +1471,31 @@ select 'a.$.? (b>0 and x.*= 0 ).c.k'::jsquery; "a".$. ?(("b" > 0 AND "x".* = 0)) ."c"."k" (1 row) -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a < 0) (b=20)'; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a < 0) (b=20)'::jsquery; ?column? ---------- f (1 row) -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 0) (b=20)'; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 0) (b=20)'::jsquery; ?column? ---------- t (1 row) -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 1) (b=20)'; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 1) (b=20)'::jsquery; ?column? ---------- t (1 row) -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 2) (b=20)'; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 2) (b=20)'::jsquery; ?column? ---------- f (1 row) -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 3) (b=20)'; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 3) (b=20)'::jsquery; ?column? ---------- f @@ -1856,49 +1856,49 @@ select '[16]' @@ '(@# > 0 and #: = 16)'::jsquery; t (1 row) -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.b or b.d'; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.b or b.d'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c or b.d'; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c or b.d'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g or b.d'; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g or b.d'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g or b.c'; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g or b.c'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.b and b.d'; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.b and b.d'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c and b.d'; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c and b.d'::jsquery; ?column? ---------- t (1 row) -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c and b.b'; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c and b.b'::jsquery; ?column? ---------- f (1 row) -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g and b.d'; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g and b.d'::jsquery; ?column? ---------- f @@ -2161,7 +2161,7 @@ SELECT gin_debug_query_path_value('#:(NOT x=1) AND %:(NOT y=1) AND *:(NOT z=1)') SELECT gin_debug_query_path_value('NOT #:(NOT x=1) AND NOT %:(NOT y=1) AND NOT *:(NOT z=1)'); gin_debug_query_path_value ---------------------------- - #.x = 1 , entry 0 + + NULL + (1 row) @@ -2188,6 +2188,205 @@ SELECT gin_debug_query_path_value('similar_product_ids . ? (# = "B0002W4TL2") . (1 row) +SELECT gin_debug_query_laxpath_value('NOT NOT NOT x(y(NOT (a=1) and NOT (b=2)) OR NOT NOT (c=3)) and z = 5'); + gin_debug_query_laxpath_value +------------------------------- + AND + + z = 5 , entry 0 + + OR + + x.y.a = 1 , entry 1 + + x.y.b = 2 , entry 2 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('NOT #(x=1) and NOT *(y=1) and NOT %(z=1) '); + gin_debug_query_laxpath_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_query_laxpath_value('#(NOT x=1) and *(NOT y=1) and %(NOT z=1) '); + gin_debug_query_laxpath_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_query_laxpath_value('NOT #(NOT x=1) and NOT *(NOT y=1) and NOT %(NOT z=1) '); + gin_debug_query_laxpath_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_query_laxpath_value('#(x = "a" and y > 0 and y < 1 and z > 0)'); + gin_debug_query_laxpath_value +------------------------------- + #.x = "a" , entry 0 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('#(x = "a" and y /*-- index */ >= 0 and y < 1 and z > 0)'); + gin_debug_query_laxpath_value +------------------------------- + AND + + #.x = "a" , entry 0 + + #.y >= 0 , < 1 , entry 1 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('#(x /*-- noindex */ = "a" and y > 0 and y <= 1 and z /*-- index */ > 0)'); + gin_debug_query_laxpath_value +------------------------------- + AND + + #.y > 0 , <= 1 , entry 0 + + #.z > 0 , entry 1 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x = 1 and (y /*-- index */ > 0 and y < 1 OR z > 0)'); + gin_debug_query_laxpath_value +------------------------------- + AND + + x = 1 , entry 0 + + OR + + y > 0 , < 1 , entry 1 + + z > 0 , entry 2 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('%.x = 1'); + gin_debug_query_laxpath_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_query_laxpath_value('*.x = "b"'); + gin_debug_query_laxpath_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x && [1,2,3]'); + gin_debug_query_laxpath_value +------------------------------- + OR + + x.# = 1 , entry 0 + + x.# = 2 , entry 1 + + x.# = 3 , entry 2 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x @> [1,2,3]'); + gin_debug_query_laxpath_value +------------------------------- + AND + + x.# = 1 , entry 0 + + x.# = 2 , entry 1 + + x.# = 3 , entry 2 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x <@ [1,2,3]'); + gin_debug_query_laxpath_value +------------------------------- + OR + + x = [] , entry 0 + + x.# = 1 , entry 1 + + x.# = 2 , entry 2 + + x.# = 3 , entry 3 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x = *'); + gin_debug_query_laxpath_value +------------------------------- + x = * , entry 0 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x is boolean'); + gin_debug_query_laxpath_value +------------------------------- + x IS boolean , entry 0 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x is string'); + gin_debug_query_laxpath_value +------------------------------- + x IS string , entry 0 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x is numeric'); + gin_debug_query_laxpath_value +------------------------------- + x IS numeric , entry 0 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x is array'); + gin_debug_query_laxpath_value +------------------------------- + x IS array , entry 0 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('x is object'); + gin_debug_query_laxpath_value +------------------------------- + x IS object , entry 0 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('#:(x=1) AND %:(y=1) AND *:(z=1)'); + gin_debug_query_laxpath_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_query_laxpath_value('#:(NOT x=1) AND %:(NOT y=1) AND *:(NOT z=1)'); + gin_debug_query_laxpath_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_query_laxpath_value('NOT #:(NOT x=1) AND NOT %:(NOT y=1) AND NOT *:(NOT z=1)'); + gin_debug_query_laxpath_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_query_laxpath_value('$ = true'); + gin_debug_query_laxpath_value +------------------------------- + $ = true , entry 0 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('$ . ? (review_votes > 10) . review_rating < 7'); + gin_debug_query_laxpath_value +-------------------------------- + AND + + review_rating < 7 , entry 0 + + review_votes > 10 , entry 1 + + +(1 row) + +SELECT gin_debug_query_laxpath_value('similar_product_ids . ? (# = "B0002W4TL2") . $'); + gin_debug_query_laxpath_value +------------------------------------------------- + similar_product_ids.# = "B0002W4TL2" , entry 0 + + +(1 row) + SELECT gin_debug_query_value_path('NOT NOT NOT x(y(NOT (a=1) and NOT (b=2)) OR NOT NOT (c=3)) and z = 5'); gin_debug_query_value_path ---------------------------- @@ -2370,10 +2569,7 @@ SELECT gin_debug_query_value_path('#:(NOT x=1) AND %:(NOT y=1) AND *:(NOT z=1)') SELECT gin_debug_query_value_path('NOT #:(NOT x=1) AND NOT %:(NOT y=1) AND NOT *:(NOT z=1)'); gin_debug_query_value_path ---------------------------- - AND + - #.x = 1 , entry 0 + - %.y = 1 , entry 1 + - *.z = 1 , entry 2 + + *.z = 1 , entry 0 + (1 row) @@ -2384,330 +2580,3240 @@ SELECT gin_debug_query_value_path('(@# > 0 and #: = 16)'); (1 row) -SELECT gin_debug_query_value_path('*.@# ($ = 4 or $ = 2)'); - gin_debug_query_value_path ----------------------------- - NULL + - +SELECT gin_debug_query_value_path('*.@# ($ = 4 or $ = 2)'); + gin_debug_query_value_path +---------------------------- + NULL + + +(1 row) + +SELECT gin_debug_query_value_path('tags.#.term. ? ( # = "NYC").x > 0'); + gin_debug_query_value_path +---------------------------------- + tags.#.term.# = "NYC" , entry 0 + + +(1 row) + +SELECT gin_debug_query_value_path('$ = true'); + gin_debug_query_value_path +---------------------------- + $ = true , entry 0 + + +(1 row) + +SELECT gin_debug_query_value_path('$ . ? (review_votes > 10) . review_rating < 7'); + gin_debug_query_value_path +-------------------------------- + AND + + review_rating < 7 , entry 0 + + review_votes > 10 , entry 1 + + +(1 row) + +SELECT gin_debug_query_value_path('similar_product_ids . ? (# = "B0002W4TL2") . $'); + gin_debug_query_value_path +------------------------------------------------- + similar_product_ids.# = "B0002W4TL2" , entry 0 + + +(1 row) + +-- -extract jsonpath entries for index scan +SELECT gin_debug_jsonpath_value_path('lax $'); + gin_debug_jsonpath_value_path +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict $'); + gin_debug_jsonpath_value_path +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax $.a'); + gin_debug_jsonpath_value_path +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict $.a'); + gin_debug_jsonpath_value_path +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax exists($)'); + gin_debug_jsonpath_value_path +------------------------------- + $ = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict exists($)'); + gin_debug_jsonpath_value_path +------------------------------- + $ = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax exists($.a)'); + gin_debug_jsonpath_value_path +------------------------------- + a = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict exists($.a)'); + gin_debug_jsonpath_value_path +------------------------------- + a = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax exists($.a.b)'); + gin_debug_jsonpath_value_path +------------------------------- + a.b = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict exists($.a.b)'); + gin_debug_jsonpath_value_path +------------------------------- + a.b = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax exists($ ? (@.b == 3).c.d)'); + gin_debug_jsonpath_value_path +------------------------------- + b = 3 , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict exists($ ? (@.b == 3).c.d)'); + gin_debug_jsonpath_value_path +------------------------------- + b = 3 , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); + gin_debug_jsonpath_value_path +------------------------------- + AND + + OR + + a.c.d.e = "aa" , entry 0 + + a.c.d = 1 , entry 1 + + a.b = 3 , entry 2 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); + gin_debug_jsonpath_value_path +------------------------------- + AND + + a.b = 3 , entry 0 + + OR + + a.c.d.e = "aa" , entry 1 + + a.c.d = 1 , entry 2 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax $.a ? (@.b == "foo").c == 1'); + gin_debug_jsonpath_value_path +------------------------------- + AND + + a.b = "foo" , entry 0 + + a.c = 1 , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict $.a ? (@.b == "foo").c == 1'); + gin_debug_jsonpath_value_path +------------------------------- + AND + + a.b = "foo" , entry 0 + + a.c = 1 , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax $.a ? (@.b == "foo") == 1'); + gin_debug_jsonpath_value_path +------------------------------- + AND + + a = 1 , entry 0 + + a.b = "foo" , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict $.a ? (@.b == "foo") == 1'); + gin_debug_jsonpath_value_path +------------------------------- + AND + + a = 1 , entry 0 + + a.b = "foo" , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax $.a ? (@.b == "foo")'); + gin_debug_jsonpath_value_path +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict $.a ? (@.b == "foo")'); + gin_debug_jsonpath_value_path +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax exists($.a ? (@.b == "foo"))'); + gin_debug_jsonpath_value_path +------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict exists($.a ? (@.b == "foo"))'); + gin_debug_jsonpath_value_path +------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax exists($.a ? (@.b == "foo").c)'); + gin_debug_jsonpath_value_path +------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict exists($.a ? (@.b == "foo").c)'); + gin_debug_jsonpath_value_path +------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +select gin_debug_jsonpath_value_path('lax exists($.a.b ? (@.c.d == 1))'); + gin_debug_jsonpath_value_path +------------------------------- + a.b.c.d = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_value_path('strict exists($.a.b ? (@.c.d == 1))'); + gin_debug_jsonpath_value_path +------------------------------- + a.b.c.d = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_value_path('$.a > 1'); + gin_debug_jsonpath_value_path +------------------------------- + a > 1 , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('lax $.a == $.b'); + gin_debug_jsonpath_value_path +------------------------------- + AND + + a = * , entry 0 + + b = * , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_value_path('strict $.a == $.b'); + gin_debug_jsonpath_value_path +------------------------------- + AND + + a = * , entry 0 + + b = * , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax $'); + gin_debug_jsonpath_path_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict $'); + gin_debug_jsonpath_path_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax $.a'); + gin_debug_jsonpath_path_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict $.a'); + gin_debug_jsonpath_path_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax exists($)'); + gin_debug_jsonpath_path_value +------------------------------- + $ = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict exists($)'); + gin_debug_jsonpath_path_value +------------------------------- + $ = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax exists($.a)'); + gin_debug_jsonpath_path_value +------------------------------- + OR + + #.a = * , entry 0 + + a = * , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict exists($.a)'); + gin_debug_jsonpath_path_value +------------------------------- + a = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax exists($.a.b)'); + gin_debug_jsonpath_path_value +------------------------------- + OR + + #.a.#.b = * , entry 0 + + #.a.b = * , entry 1 + + a.#.b = * , entry 2 + + a.b = * , entry 3 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict exists($.a.b)'); + gin_debug_jsonpath_path_value +------------------------------- + a.b = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax exists($ ? (@.b == 3).c.d)'); + gin_debug_jsonpath_path_value +------------------------------- + OR + + OR + + #.#.b = 3 , entry 12 + + #.#.b.# = 3 , entry 13 + + #.b = 3 , entry 14 + + #.b.# = 3 , entry 15 + + OR + + #.#.b = 3 , entry 12 + + #.#.b.# = 3 , entry 13 + + #.b = 3 , entry 14 + + #.b.# = 3 , entry 15 + + OR + + #.#.b = 3 , entry 12 + + #.#.b.# = 3 , entry 13 + + #.b = 3 , entry 14 + + #.b.# = 3 , entry 15 + + OR + + #.#.b = 3 , entry 12 + + #.#.b.# = 3 , entry 13 + + #.b = 3 , entry 14 + + #.b.# = 3 , entry 15 + + OR + + #.b = 3 , entry 28 + + #.b.# = 3 , entry 29 + + b = 3 , entry 30 + + b.# = 3 , entry 31 + + OR + + #.b = 3 , entry 28 + + #.b.# = 3 , entry 29 + + b = 3 , entry 30 + + b.# = 3 , entry 31 + + OR + + #.b = 3 , entry 28 + + #.b.# = 3 , entry 29 + + b = 3 , entry 30 + + b.# = 3 , entry 31 + + OR + + #.b = 3 , entry 28 + + #.b.# = 3 , entry 29 + + b = 3 , entry 30 + + b.# = 3 , entry 31 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict exists($ ? (@.b == 3).c.d)'); + gin_debug_jsonpath_path_value +------------------------------- + b = 3 , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); + gin_debug_jsonpath_path_value +----------------------------------------------- + OR + + AND + + OR + + #.a.#.#.b = 3 , entry 70 + + #.a.#.#.b.# = 3 , entry 71 + + #.a.#.b = 3 , entry 72 + + #.a.#.b.# = 3 , entry 73 + + OR + + #.a.#.#.c.#.d.#.#.e = "aa" , entry 4 + + #.a.#.#.c.#.d.#.#.e.# = "aa" , entry 5 + + #.a.#.#.c.#.d.#.e = "aa" , entry 6 + + #.a.#.#.c.#.d.#.e.# = "aa" , entry 7 + + #.a.#.#.c.#.d.# = 1 , entry 8 + + #.a.#.#.c.#.d.#.# = 1 , entry 9 + + AND + + OR + + #.a.#.#.b = 3 , entry 70 + + #.a.#.#.b.# = 3 , entry 71 + + #.a.#.b = 3 , entry 72 + + #.a.#.b.# = 3 , entry 73 + + OR + + #.a.#.#.c.#.d.#.e = "aa" , entry 14 + + #.a.#.#.c.#.d.#.e.# = "aa" , entry 15 + + #.a.#.#.c.#.d.e = "aa" , entry 16 + + #.a.#.#.c.#.d.e.# = "aa" , entry 17 + + #.a.#.#.c.#.d = 1 , entry 18 + + #.a.#.#.c.#.d.# = 1 , entry 19 + + AND + + OR + + #.a.#.#.b = 3 , entry 70 + + #.a.#.#.b.# = 3 , entry 71 + + #.a.#.b = 3 , entry 72 + + #.a.#.b.# = 3 , entry 73 + + OR + + #.a.#.#.c.d.#.#.e = "aa" , entry 24 + + #.a.#.#.c.d.#.#.e.# = "aa" , entry 25 + + #.a.#.#.c.d.#.e = "aa" , entry 26 + + #.a.#.#.c.d.#.e.# = "aa" , entry 27 + + #.a.#.#.c.d.# = 1 , entry 28 + + #.a.#.#.c.d.#.# = 1 , entry 29 + + AND + + OR + + #.a.#.#.b = 3 , entry 70 + + #.a.#.#.b.# = 3 , entry 71 + + #.a.#.b = 3 , entry 72 + + #.a.#.b.# = 3 , entry 73 + + OR + + #.a.#.#.c.d.#.e = "aa" , entry 34 + + #.a.#.#.c.d.#.e.# = "aa" , entry 35 + + #.a.#.#.c.d.e = "aa" , entry 36 + + #.a.#.#.c.d.e.# = "aa" , entry 37 + + #.a.#.#.c.d = 1 , entry 38 + + #.a.#.#.c.d.# = 1 , entry 39 + + AND + + OR + + #.a.#.#.b = 3 , entry 70 + + #.a.#.#.b.# = 3 , entry 71 + + #.a.#.b = 3 , entry 72 + + #.a.#.b.# = 3 , entry 73 + + OR + + #.a.#.c.#.d.#.#.e = "aa" , entry 44 + + #.a.#.c.#.d.#.#.e.# = "aa" , entry 45 + + #.a.#.c.#.d.#.e = "aa" , entry 46 + + #.a.#.c.#.d.#.e.# = "aa" , entry 47 + + #.a.#.c.#.d.# = 1 , entry 48 + + #.a.#.c.#.d.#.# = 1 , entry 49 + + AND + + OR + + #.a.#.#.b = 3 , entry 70 + + #.a.#.#.b.# = 3 , entry 71 + + #.a.#.b = 3 , entry 72 + + #.a.#.b.# = 3 , entry 73 + + OR + + #.a.#.c.#.d.#.e = "aa" , entry 54 + + #.a.#.c.#.d.#.e.# = "aa" , entry 55 + + #.a.#.c.#.d.e = "aa" , entry 56 + + #.a.#.c.#.d.e.# = "aa" , entry 57 + + #.a.#.c.#.d = 1 , entry 58 + + #.a.#.c.#.d.# = 1 , entry 59 + + AND + + OR + + #.a.#.#.b = 3 , entry 70 + + #.a.#.#.b.# = 3 , entry 71 + + #.a.#.b = 3 , entry 72 + + #.a.#.b.# = 3 , entry 73 + + OR + + #.a.#.c.d.#.#.e = "aa" , entry 64 + + #.a.#.c.d.#.#.e.# = "aa" , entry 65 + + #.a.#.c.d.#.e = "aa" , entry 66 + + #.a.#.c.d.#.e.# = "aa" , entry 67 + + #.a.#.c.d.# = 1 , entry 68 + + #.a.#.c.d.#.# = 1 , entry 69 + + AND + + OR + + #.a.#.#.b = 3 , entry 70 + + #.a.#.#.b.# = 3 , entry 71 + + #.a.#.b = 3 , entry 72 + + #.a.#.b.# = 3 , entry 73 + + OR + + #.a.#.c.d.#.e = "aa" , entry 74 + + #.a.#.c.d.#.e.# = "aa" , entry 75 + + #.a.#.c.d.e = "aa" , entry 76 + + #.a.#.c.d.e.# = "aa" , entry 77 + + #.a.#.c.d = 1 , entry 78 + + #.a.#.c.d.# = 1 , entry 79 + + AND + + OR + + #.a.#.b = 3 , entry 150 + + #.a.#.b.# = 3 , entry 151 + + #.a.b = 3 , entry 152 + + #.a.b.# = 3 , entry 153 + + OR + + #.a.#.c.#.d.#.#.e = "aa" , entry 84 + + #.a.#.c.#.d.#.#.e.# = "aa" , entry 85 + + #.a.#.c.#.d.#.e = "aa" , entry 86 + + #.a.#.c.#.d.#.e.# = "aa" , entry 87 + + #.a.#.c.#.d.# = 1 , entry 88 + + #.a.#.c.#.d.#.# = 1 , entry 89 + + AND + + OR + + #.a.#.b = 3 , entry 150 + + #.a.#.b.# = 3 , entry 151 + + #.a.b = 3 , entry 152 + + #.a.b.# = 3 , entry 153 + + OR + + #.a.#.c.#.d.#.e = "aa" , entry 94 + + #.a.#.c.#.d.#.e.# = "aa" , entry 95 + + #.a.#.c.#.d.e = "aa" , entry 96 + + #.a.#.c.#.d.e.# = "aa" , entry 97 + + #.a.#.c.#.d = 1 , entry 98 + + #.a.#.c.#.d.# = 1 , entry 99 + + AND + + OR + + #.a.#.b = 3 , entry 150 + + #.a.#.b.# = 3 , entry 151 + + #.a.b = 3 , entry 152 + + #.a.b.# = 3 , entry 153 + + OR + + #.a.#.c.d.#.#.e = "aa" , entry 104 + + #.a.#.c.d.#.#.e.# = "aa" , entry 105 + + #.a.#.c.d.#.e = "aa" , entry 106 + + #.a.#.c.d.#.e.# = "aa" , entry 107 + + #.a.#.c.d.# = 1 , entry 108 + + #.a.#.c.d.#.# = 1 , entry 109 + + AND + + OR + + #.a.#.b = 3 , entry 150 + + #.a.#.b.# = 3 , entry 151 + + #.a.b = 3 , entry 152 + + #.a.b.# = 3 , entry 153 + + OR + + #.a.#.c.d.#.e = "aa" , entry 114 + + #.a.#.c.d.#.e.# = "aa" , entry 115 + + #.a.#.c.d.e = "aa" , entry 116 + + #.a.#.c.d.e.# = "aa" , entry 117 + + #.a.#.c.d = 1 , entry 118 + + #.a.#.c.d.# = 1 , entry 119 + + AND + + OR + + #.a.#.b = 3 , entry 150 + + #.a.#.b.# = 3 , entry 151 + + #.a.b = 3 , entry 152 + + #.a.b.# = 3 , entry 153 + + OR + + #.a.c.#.d.#.#.e = "aa" , entry 124 + + #.a.c.#.d.#.#.e.# = "aa" , entry 125 + + #.a.c.#.d.#.e = "aa" , entry 126 + + #.a.c.#.d.#.e.# = "aa" , entry 127 + + #.a.c.#.d.# = 1 , entry 128 + + #.a.c.#.d.#.# = 1 , entry 129 + + AND + + OR + + #.a.#.b = 3 , entry 150 + + #.a.#.b.# = 3 , entry 151 + + #.a.b = 3 , entry 152 + + #.a.b.# = 3 , entry 153 + + OR + + #.a.c.#.d.#.e = "aa" , entry 134 + + #.a.c.#.d.#.e.# = "aa" , entry 135 + + #.a.c.#.d.e = "aa" , entry 136 + + #.a.c.#.d.e.# = "aa" , entry 137 + + #.a.c.#.d = 1 , entry 138 + + #.a.c.#.d.# = 1 , entry 139 + + AND + + OR + + #.a.#.b = 3 , entry 150 + + #.a.#.b.# = 3 , entry 151 + + #.a.b = 3 , entry 152 + + #.a.b.# = 3 , entry 153 + + OR + + #.a.c.d.#.#.e = "aa" , entry 144 + + #.a.c.d.#.#.e.# = "aa" , entry 145 + + #.a.c.d.#.e = "aa" , entry 146 + + #.a.c.d.#.e.# = "aa" , entry 147 + + #.a.c.d.# = 1 , entry 148 + + #.a.c.d.#.# = 1 , entry 149 + + AND + + OR + + #.a.#.b = 3 , entry 150 + + #.a.#.b.# = 3 , entry 151 + + #.a.b = 3 , entry 152 + + #.a.b.# = 3 , entry 153 + + OR + + #.a.c.d.#.e = "aa" , entry 154 + + #.a.c.d.#.e.# = "aa" , entry 155 + + #.a.c.d.e = "aa" , entry 156 + + #.a.c.d.e.# = "aa" , entry 157 + + #.a.c.d = 1 , entry 158 + + #.a.c.d.# = 1 , entry 159 + + AND + + OR + + a.#.#.b = 3 , entry 230 + + a.#.#.b.# = 3 , entry 231 + + a.#.b = 3 , entry 232 + + a.#.b.# = 3 , entry 233 + + OR + + a.#.#.c.#.d.#.#.e = "aa" , entry 164 + + a.#.#.c.#.d.#.#.e.# = "aa" , entry 165 + + a.#.#.c.#.d.#.e = "aa" , entry 166 + + a.#.#.c.#.d.#.e.# = "aa" , entry 167 + + a.#.#.c.#.d.# = 1 , entry 168 + + a.#.#.c.#.d.#.# = 1 , entry 169 + + AND + + OR + + a.#.#.b = 3 , entry 230 + + a.#.#.b.# = 3 , entry 231 + + a.#.b = 3 , entry 232 + + a.#.b.# = 3 , entry 233 + + OR + + a.#.#.c.#.d.#.e = "aa" , entry 174 + + a.#.#.c.#.d.#.e.# = "aa" , entry 175 + + a.#.#.c.#.d.e = "aa" , entry 176 + + a.#.#.c.#.d.e.# = "aa" , entry 177 + + a.#.#.c.#.d = 1 , entry 178 + + a.#.#.c.#.d.# = 1 , entry 179 + + AND + + OR + + a.#.#.b = 3 , entry 230 + + a.#.#.b.# = 3 , entry 231 + + a.#.b = 3 , entry 232 + + a.#.b.# = 3 , entry 233 + + OR + + a.#.#.c.d.#.#.e = "aa" , entry 184 + + a.#.#.c.d.#.#.e.# = "aa" , entry 185 + + a.#.#.c.d.#.e = "aa" , entry 186 + + a.#.#.c.d.#.e.# = "aa" , entry 187 + + a.#.#.c.d.# = 1 , entry 188 + + a.#.#.c.d.#.# = 1 , entry 189 + + AND + + OR + + a.#.#.b = 3 , entry 230 + + a.#.#.b.# = 3 , entry 231 + + a.#.b = 3 , entry 232 + + a.#.b.# = 3 , entry 233 + + OR + + a.#.#.c.d.#.e = "aa" , entry 194 + + a.#.#.c.d.#.e.# = "aa" , entry 195 + + a.#.#.c.d.e = "aa" , entry 196 + + a.#.#.c.d.e.# = "aa" , entry 197 + + a.#.#.c.d = 1 , entry 198 + + a.#.#.c.d.# = 1 , entry 199 + + AND + + OR + + a.#.#.b = 3 , entry 230 + + a.#.#.b.# = 3 , entry 231 + + a.#.b = 3 , entry 232 + + a.#.b.# = 3 , entry 233 + + OR + + a.#.c.#.d.#.#.e = "aa" , entry 204 + + a.#.c.#.d.#.#.e.# = "aa" , entry 205 + + a.#.c.#.d.#.e = "aa" , entry 206 + + a.#.c.#.d.#.e.# = "aa" , entry 207 + + a.#.c.#.d.# = 1 , entry 208 + + a.#.c.#.d.#.# = 1 , entry 209 + + AND + + OR + + a.#.#.b = 3 , entry 230 + + a.#.#.b.# = 3 , entry 231 + + a.#.b = 3 , entry 232 + + a.#.b.# = 3 , entry 233 + + OR + + a.#.c.#.d.#.e = "aa" , entry 214 + + a.#.c.#.d.#.e.# = "aa" , entry 215 + + a.#.c.#.d.e = "aa" , entry 216 + + a.#.c.#.d.e.# = "aa" , entry 217 + + a.#.c.#.d = 1 , entry 218 + + a.#.c.#.d.# = 1 , entry 219 + + AND + + OR + + a.#.#.b = 3 , entry 230 + + a.#.#.b.# = 3 , entry 231 + + a.#.b = 3 , entry 232 + + a.#.b.# = 3 , entry 233 + + OR + + a.#.c.d.#.#.e = "aa" , entry 224 + + a.#.c.d.#.#.e.# = "aa" , entry 225 + + a.#.c.d.#.e = "aa" , entry 226 + + a.#.c.d.#.e.# = "aa" , entry 227 + + a.#.c.d.# = 1 , entry 228 + + a.#.c.d.#.# = 1 , entry 229 + + AND + + OR + + a.#.#.b = 3 , entry 230 + + a.#.#.b.# = 3 , entry 231 + + a.#.b = 3 , entry 232 + + a.#.b.# = 3 , entry 233 + + OR + + a.#.c.d.#.e = "aa" , entry 234 + + a.#.c.d.#.e.# = "aa" , entry 235 + + a.#.c.d.e = "aa" , entry 236 + + a.#.c.d.e.# = "aa" , entry 237 + + a.#.c.d = 1 , entry 238 + + a.#.c.d.# = 1 , entry 239 + + AND + + OR + + a.#.b = 3 , entry 310 + + a.#.b.# = 3 , entry 311 + + a.b = 3 , entry 312 + + a.b.# = 3 , entry 313 + + OR + + a.#.c.#.d.#.#.e = "aa" , entry 244 + + a.#.c.#.d.#.#.e.# = "aa" , entry 245 + + a.#.c.#.d.#.e = "aa" , entry 246 + + a.#.c.#.d.#.e.# = "aa" , entry 247 + + a.#.c.#.d.# = 1 , entry 248 + + a.#.c.#.d.#.# = 1 , entry 249 + + AND + + OR + + a.#.b = 3 , entry 310 + + a.#.b.# = 3 , entry 311 + + a.b = 3 , entry 312 + + a.b.# = 3 , entry 313 + + OR + + a.#.c.#.d.#.e = "aa" , entry 254 + + a.#.c.#.d.#.e.# = "aa" , entry 255 + + a.#.c.#.d.e = "aa" , entry 256 + + a.#.c.#.d.e.# = "aa" , entry 257 + + a.#.c.#.d = 1 , entry 258 + + a.#.c.#.d.# = 1 , entry 259 + + AND + + OR + + a.#.b = 3 , entry 310 + + a.#.b.# = 3 , entry 311 + + a.b = 3 , entry 312 + + a.b.# = 3 , entry 313 + + OR + + a.#.c.d.#.#.e = "aa" , entry 264 + + a.#.c.d.#.#.e.# = "aa" , entry 265 + + a.#.c.d.#.e = "aa" , entry 266 + + a.#.c.d.#.e.# = "aa" , entry 267 + + a.#.c.d.# = 1 , entry 268 + + a.#.c.d.#.# = 1 , entry 269 + + AND + + OR + + a.#.b = 3 , entry 310 + + a.#.b.# = 3 , entry 311 + + a.b = 3 , entry 312 + + a.b.# = 3 , entry 313 + + OR + + a.#.c.d.#.e = "aa" , entry 274 + + a.#.c.d.#.e.# = "aa" , entry 275 + + a.#.c.d.e = "aa" , entry 276 + + a.#.c.d.e.# = "aa" , entry 277 + + a.#.c.d = 1 , entry 278 + + a.#.c.d.# = 1 , entry 279 + + AND + + OR + + a.#.b = 3 , entry 310 + + a.#.b.# = 3 , entry 311 + + a.b = 3 , entry 312 + + a.b.# = 3 , entry 313 + + OR + + a.c.#.d.#.#.e = "aa" , entry 284 + + a.c.#.d.#.#.e.# = "aa" , entry 285 + + a.c.#.d.#.e = "aa" , entry 286 + + a.c.#.d.#.e.# = "aa" , entry 287 + + a.c.#.d.# = 1 , entry 288 + + a.c.#.d.#.# = 1 , entry 289 + + AND + + OR + + a.#.b = 3 , entry 310 + + a.#.b.# = 3 , entry 311 + + a.b = 3 , entry 312 + + a.b.# = 3 , entry 313 + + OR + + a.c.#.d.#.e = "aa" , entry 294 + + a.c.#.d.#.e.# = "aa" , entry 295 + + a.c.#.d.e = "aa" , entry 296 + + a.c.#.d.e.# = "aa" , entry 297 + + a.c.#.d = 1 , entry 298 + + a.c.#.d.# = 1 , entry 299 + + AND + + OR + + a.#.b = 3 , entry 310 + + a.#.b.# = 3 , entry 311 + + a.b = 3 , entry 312 + + a.b.# = 3 , entry 313 + + OR + + a.c.d.#.#.e = "aa" , entry 304 + + a.c.d.#.#.e.# = "aa" , entry 305 + + a.c.d.#.e = "aa" , entry 306 + + a.c.d.#.e.# = "aa" , entry 307 + + a.c.d.# = 1 , entry 308 + + a.c.d.#.# = 1 , entry 309 + + AND + + OR + + a.#.b = 3 , entry 310 + + a.#.b.# = 3 , entry 311 + + a.b = 3 , entry 312 + + a.b.# = 3 , entry 313 + + OR + + a.c.d.#.e = "aa" , entry 314 + + a.c.d.#.e.# = "aa" , entry 315 + + a.c.d.e = "aa" , entry 316 + + a.c.d.e.# = "aa" , entry 317 + + a.c.d = 1 , entry 318 + + a.c.d.# = 1 , entry 319 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); + gin_debug_jsonpath_path_value +------------------------------- + AND + + a.b = 3 , entry 0 + + OR + + a.c.d.e = "aa" , entry 1 + + a.c.d = 1 , entry 2 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax $.a ? (@.b == "foo").c == 1'); + gin_debug_jsonpath_path_value +--------------------------------------- + OR + + AND + + OR + + #.a.#.#.b = "foo" , entry 15 + + #.a.#.#.b.# = "foo" , entry 16 + + #.a.#.b = "foo" , entry 17 + + #.a.#.b.# = "foo" , entry 18 + + #.a.#.#.c = 1 , entry 4 + + AND + + OR + + #.a.#.#.b = "foo" , entry 15 + + #.a.#.#.b.# = "foo" , entry 16 + + #.a.#.b = "foo" , entry 17 + + #.a.#.b.# = "foo" , entry 18 + + #.a.#.#.c.# = 1 , entry 9 + + AND + + OR + + #.a.#.#.b = "foo" , entry 15 + + #.a.#.#.b.# = "foo" , entry 16 + + #.a.#.b = "foo" , entry 17 + + #.a.#.b.# = "foo" , entry 18 + + #.a.#.c = 1 , entry 14 + + AND + + OR + + #.a.#.#.b = "foo" , entry 15 + + #.a.#.#.b.# = "foo" , entry 16 + + #.a.#.b = "foo" , entry 17 + + #.a.#.b.# = "foo" , entry 18 + + #.a.#.c.# = 1 , entry 19 + + AND + + OR + + #.a.#.b = "foo" , entry 35 + + #.a.#.b.# = "foo" , entry 36 + + #.a.b = "foo" , entry 37 + + #.a.b.# = "foo" , entry 38 + + #.a.#.c = 1 , entry 24 + + AND + + OR + + #.a.#.b = "foo" , entry 35 + + #.a.#.b.# = "foo" , entry 36 + + #.a.b = "foo" , entry 37 + + #.a.b.# = "foo" , entry 38 + + #.a.#.c.# = 1 , entry 29 + + AND + + OR + + #.a.#.b = "foo" , entry 35 + + #.a.#.b.# = "foo" , entry 36 + + #.a.b = "foo" , entry 37 + + #.a.b.# = "foo" , entry 38 + + #.a.c = 1 , entry 34 + + AND + + OR + + #.a.#.b = "foo" , entry 35 + + #.a.#.b.# = "foo" , entry 36 + + #.a.b = "foo" , entry 37 + + #.a.b.# = "foo" , entry 38 + + #.a.c.# = 1 , entry 39 + + AND + + OR + + a.#.#.b = "foo" , entry 55 + + a.#.#.b.# = "foo" , entry 56 + + a.#.b = "foo" , entry 57 + + a.#.b.# = "foo" , entry 58 + + a.#.#.c = 1 , entry 44 + + AND + + OR + + a.#.#.b = "foo" , entry 55 + + a.#.#.b.# = "foo" , entry 56 + + a.#.b = "foo" , entry 57 + + a.#.b.# = "foo" , entry 58 + + a.#.#.c.# = 1 , entry 49 + + AND + + OR + + a.#.#.b = "foo" , entry 55 + + a.#.#.b.# = "foo" , entry 56 + + a.#.b = "foo" , entry 57 + + a.#.b.# = "foo" , entry 58 + + a.#.c = 1 , entry 54 + + AND + + OR + + a.#.#.b = "foo" , entry 55 + + a.#.#.b.# = "foo" , entry 56 + + a.#.b = "foo" , entry 57 + + a.#.b.# = "foo" , entry 58 + + a.#.c.# = 1 , entry 59 + + AND + + OR + + a.#.b = "foo" , entry 75 + + a.#.b.# = "foo" , entry 76 + + a.b = "foo" , entry 77 + + a.b.# = "foo" , entry 78 + + a.#.c = 1 , entry 64 + + AND + + OR + + a.#.b = "foo" , entry 75 + + a.#.b.# = "foo" , entry 76 + + a.b = "foo" , entry 77 + + a.b.# = "foo" , entry 78 + + a.#.c.# = 1 , entry 69 + + AND + + a.c = 1 , entry 70 + + OR + + a.#.b = "foo" , entry 75 + + a.#.b.# = "foo" , entry 76 + + a.b = "foo" , entry 77 + + a.b.# = "foo" , entry 78 + + AND + + OR + + a.#.b = "foo" , entry 75 + + a.#.b.# = "foo" , entry 76 + + a.b = "foo" , entry 77 + + a.b.# = "foo" , entry 78 + + a.c.# = 1 , entry 79 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict $.a ? (@.b == "foo").c == 1'); + gin_debug_jsonpath_path_value +------------------------------- + AND + + a.b = "foo" , entry 0 + + a.c = 1 , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax $.a ? (@.b == "foo") == 1'); + gin_debug_jsonpath_path_value +-------------------------------------- + OR + + AND + + OR + + #.a.#.#.b = "foo" , entry 5 + + #.a.#.#.b.# = "foo" , entry 6 + + #.a.#.b = "foo" , entry 7 + + #.a.#.b.# = "foo" , entry 8 + + #.a.# = 1 , entry 4 + + AND + + OR + + #.a.#.#.b = "foo" , entry 5 + + #.a.#.#.b.# = "foo" , entry 6 + + #.a.#.b = "foo" , entry 7 + + #.a.#.b.# = "foo" , entry 8 + + #.a.#.# = 1 , entry 9 + + AND + + OR + + #.a.#.b = "foo" , entry 15 + + #.a.#.b.# = "foo" , entry 16 + + #.a.b = "foo" , entry 17 + + #.a.b.# = "foo" , entry 18 + + #.a = 1 , entry 14 + + AND + + OR + + #.a.#.b = "foo" , entry 15 + + #.a.#.b.# = "foo" , entry 16 + + #.a.b = "foo" , entry 17 + + #.a.b.# = "foo" , entry 18 + + #.a.# = 1 , entry 19 + + AND + + OR + + a.#.#.b = "foo" , entry 25 + + a.#.#.b.# = "foo" , entry 26 + + a.#.b = "foo" , entry 27 + + a.#.b.# = "foo" , entry 28 + + a.# = 1 , entry 24 + + AND + + OR + + a.#.#.b = "foo" , entry 25 + + a.#.#.b.# = "foo" , entry 26 + + a.#.b = "foo" , entry 27 + + a.#.b.# = "foo" , entry 28 + + a.#.# = 1 , entry 29 + + AND + + a = 1 , entry 30 + + OR + + a.#.b = "foo" , entry 35 + + a.#.b.# = "foo" , entry 36 + + a.b = "foo" , entry 37 + + a.b.# = "foo" , entry 38 + + AND + + OR + + a.#.b = "foo" , entry 35 + + a.#.b.# = "foo" , entry 36 + + a.b = "foo" , entry 37 + + a.b.# = "foo" , entry 38 + + a.# = 1 , entry 39 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict $.a ? (@.b == "foo") == 1'); + gin_debug_jsonpath_path_value +------------------------------- + AND + + a = 1 , entry 0 + + a.b = "foo" , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax $.a ? (@.b == "foo")'); + gin_debug_jsonpath_path_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict $.a ? (@.b == "foo")'); + gin_debug_jsonpath_path_value +------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax exists($.a ? (@.b == "foo"))'); + gin_debug_jsonpath_path_value +------------------------------------ + OR + + OR + + #.a.#.#.b = "foo" , entry 0 + + #.a.#.#.b.# = "foo" , entry 1 + + #.a.#.b = "foo" , entry 2 + + #.a.#.b.# = "foo" , entry 3 + + OR + + #.a.#.b = "foo" , entry 4 + + #.a.#.b.# = "foo" , entry 5 + + #.a.b = "foo" , entry 6 + + #.a.b.# = "foo" , entry 7 + + OR + + a.#.#.b = "foo" , entry 8 + + a.#.#.b.# = "foo" , entry 9 + + a.#.b = "foo" , entry 10 + + a.#.b.# = "foo" , entry 11 + + OR + + a.#.b = "foo" , entry 12 + + a.#.b.# = "foo" , entry 13 + + a.b = "foo" , entry 14 + + a.b.# = "foo" , entry 15 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict exists($.a ? (@.b == "foo"))'); + gin_debug_jsonpath_path_value +------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax exists($.a ? (@.b == "foo").c)'); + gin_debug_jsonpath_path_value +------------------------------------ + OR + + OR + + #.a.#.#.b = "foo" , entry 4 + + #.a.#.#.b.# = "foo" , entry 5 + + #.a.#.b = "foo" , entry 6 + + #.a.#.b.# = "foo" , entry 7 + + OR + + #.a.#.#.b = "foo" , entry 4 + + #.a.#.#.b.# = "foo" , entry 5 + + #.a.#.b = "foo" , entry 6 + + #.a.#.b.# = "foo" , entry 7 + + OR + + #.a.#.b = "foo" , entry 12 + + #.a.#.b.# = "foo" , entry 13 + + #.a.b = "foo" , entry 14 + + #.a.b.# = "foo" , entry 15 + + OR + + #.a.#.b = "foo" , entry 12 + + #.a.#.b.# = "foo" , entry 13 + + #.a.b = "foo" , entry 14 + + #.a.b.# = "foo" , entry 15 + + OR + + a.#.#.b = "foo" , entry 20 + + a.#.#.b.# = "foo" , entry 21 + + a.#.b = "foo" , entry 22 + + a.#.b.# = "foo" , entry 23 + + OR + + a.#.#.b = "foo" , entry 20 + + a.#.#.b.# = "foo" , entry 21 + + a.#.b = "foo" , entry 22 + + a.#.b.# = "foo" , entry 23 + + OR + + a.#.b = "foo" , entry 28 + + a.#.b.# = "foo" , entry 29 + + a.b = "foo" , entry 30 + + a.b.# = "foo" , entry 31 + + OR + + a.#.b = "foo" , entry 28 + + a.#.b.# = "foo" , entry 29 + + a.b = "foo" , entry 30 + + a.b.# = "foo" , entry 31 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict exists($.a ? (@.b == "foo").c)'); + gin_debug_jsonpath_path_value +------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +select gin_debug_jsonpath_path_value('strict exists($.a.b ? (@.c.d == 1))'); + gin_debug_jsonpath_path_value +------------------------------- + a.b.c.d = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_path_value('lax exists($.a.b ? (@.c.d == 1))'); + gin_debug_jsonpath_path_value +---------------------------------------- + OR + + OR + + #.a.#.b.#.#.c.#.d = 1 , entry 0 + + #.a.#.b.#.#.c.#.d.# = 1 , entry 1 + + #.a.#.b.#.#.c.d = 1 , entry 2 + + #.a.#.b.#.#.c.d.# = 1 , entry 3 + + #.a.#.b.#.c.#.d = 1 , entry 4 + + #.a.#.b.#.c.#.d.# = 1 , entry 5 + + #.a.#.b.#.c.d = 1 , entry 6 + + #.a.#.b.#.c.d.# = 1 , entry 7 + + OR + + #.a.#.b.#.c.#.d = 1 , entry 8 + + #.a.#.b.#.c.#.d.# = 1 , entry 9 + + #.a.#.b.#.c.d = 1 , entry 10 + + #.a.#.b.#.c.d.# = 1 , entry 11 + + #.a.#.b.c.#.d = 1 , entry 12 + + #.a.#.b.c.#.d.# = 1 , entry 13 + + #.a.#.b.c.d = 1 , entry 14 + + #.a.#.b.c.d.# = 1 , entry 15 + + OR + + #.a.b.#.#.c.#.d = 1 , entry 16 + + #.a.b.#.#.c.#.d.# = 1 , entry 17 + + #.a.b.#.#.c.d = 1 , entry 18 + + #.a.b.#.#.c.d.# = 1 , entry 19 + + #.a.b.#.c.#.d = 1 , entry 20 + + #.a.b.#.c.#.d.# = 1 , entry 21 + + #.a.b.#.c.d = 1 , entry 22 + + #.a.b.#.c.d.# = 1 , entry 23 + + OR + + #.a.b.#.c.#.d = 1 , entry 24 + + #.a.b.#.c.#.d.# = 1 , entry 25 + + #.a.b.#.c.d = 1 , entry 26 + + #.a.b.#.c.d.# = 1 , entry 27 + + #.a.b.c.#.d = 1 , entry 28 + + #.a.b.c.#.d.# = 1 , entry 29 + + #.a.b.c.d = 1 , entry 30 + + #.a.b.c.d.# = 1 , entry 31 + + OR + + a.#.b.#.#.c.#.d = 1 , entry 32 + + a.#.b.#.#.c.#.d.# = 1 , entry 33 + + a.#.b.#.#.c.d = 1 , entry 34 + + a.#.b.#.#.c.d.# = 1 , entry 35 + + a.#.b.#.c.#.d = 1 , entry 36 + + a.#.b.#.c.#.d.# = 1 , entry 37 + + a.#.b.#.c.d = 1 , entry 38 + + a.#.b.#.c.d.# = 1 , entry 39 + + OR + + a.#.b.#.c.#.d = 1 , entry 40 + + a.#.b.#.c.#.d.# = 1 , entry 41 + + a.#.b.#.c.d = 1 , entry 42 + + a.#.b.#.c.d.# = 1 , entry 43 + + a.#.b.c.#.d = 1 , entry 44 + + a.#.b.c.#.d.# = 1 , entry 45 + + a.#.b.c.d = 1 , entry 46 + + a.#.b.c.d.# = 1 , entry 47 + + OR + + a.b.#.#.c.#.d = 1 , entry 48 + + a.b.#.#.c.#.d.# = 1 , entry 49 + + a.b.#.#.c.d = 1 , entry 50 + + a.b.#.#.c.d.# = 1 , entry 51 + + a.b.#.c.#.d = 1 , entry 52 + + a.b.#.c.#.d.# = 1 , entry 53 + + a.b.#.c.d = 1 , entry 54 + + a.b.#.c.d.# = 1 , entry 55 + + OR + + a.b.#.c.#.d = 1 , entry 56 + + a.b.#.c.#.d.# = 1 , entry 57 + + a.b.#.c.d = 1 , entry 58 + + a.b.#.c.d.# = 1 , entry 59 + + a.b.c.#.d = 1 , entry 60 + + a.b.c.#.d.# = 1 , entry 61 + + a.b.c.d = 1 , entry 62 + + a.b.c.d.# = 1 , entry 63 + + +(1 row) + +select gin_debug_jsonpath_path_value('strict $.a.b == 1'); + gin_debug_jsonpath_path_value +------------------------------- + a.b = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_path_value('lax $.a.b == 1'); + gin_debug_jsonpath_path_value +------------------------------- + OR + + #.a.#.b = 1 , entry 0 + + #.a.#.b.# = 1 , entry 1 + + #.a.b = 1 , entry 2 + + #.a.b.# = 1 , entry 3 + + a.#.b = 1 , entry 4 + + a.#.b.# = 1 , entry 5 + + a.b = 1 , entry 6 + + a.b.# = 1 , entry 7 + + +(1 row) + +select gin_debug_jsonpath_path_value('strict $.a.b[*] == 1'); + gin_debug_jsonpath_path_value +------------------------------- + a.b.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_path_value('lax $.a.b[*] == 1'); + gin_debug_jsonpath_path_value +------------------------------- + OR + + #.a.#.b = 1 , entry 0 + + #.a.#.b.# = 1 , entry 1 + + #.a.#.b.#.# = 1 , entry 2 + + #.a.b = 1 , entry 3 + + #.a.b.# = 1 , entry 4 + + #.a.b.#.# = 1 , entry 5 + + a.#.b = 1 , entry 6 + + a.#.b.# = 1 , entry 7 + + a.#.b.#.# = 1 , entry 8 + + a.b = 1 , entry 9 + + a.b.# = 1 , entry 10 + + a.b.#.# = 1 , entry 11 + + +(1 row) + +select gin_debug_jsonpath_path_value('strict $.a[*].b[*] == 1'); + gin_debug_jsonpath_path_value +------------------------------- + a.#.b.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_path_value('lax $.a[*].b[*] == 1'); + gin_debug_jsonpath_path_value +-------------------------------- + OR + + #.a.b = 1 , entry 0 + + #.a.b.# = 1 , entry 1 + + #.a.b.#.# = 1 , entry 2 + + #.a.#.#.b = 1 , entry 3 + + #.a.#.#.b.# = 1 , entry 4 + + #.a.#.#.b.#.# = 1 , entry 5 + + #.a.#.b = 1 , entry 6 + + #.a.#.b.# = 1 , entry 7 + + #.a.#.b.#.# = 1 , entry 8 + + a.b = 1 , entry 9 + + a.b.# = 1 , entry 10 + + a.b.#.# = 1 , entry 11 + + a.#.#.b = 1 , entry 12 + + a.#.#.b.# = 1 , entry 13 + + a.#.#.b.#.# = 1 , entry 14 + + a.#.b = 1 , entry 15 + + a.#.b.# = 1 , entry 16 + + a.#.b.#.# = 1 , entry 17 + + +(1 row) + +select gin_debug_jsonpath_path_value('strict $.a.b[*][*] == 1'); + gin_debug_jsonpath_path_value +------------------------------- + a.b.#.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_path_value('lax $.a.b[*][*] == 1'); + gin_debug_jsonpath_path_value +-------------------------------- + OR + + #.a.#.b = 1 , entry 0 + + #.a.#.b.# = 1 , entry 1 + + #.a.#.b.#.# = 1 , entry 2 + + #.a.#.b.# = 1 , entry 3 + + #.a.#.b.#.# = 1 , entry 4 + + #.a.#.b.#.#.# = 1 , entry 5 + + #.a.b = 1 , entry 6 + + #.a.b.# = 1 , entry 7 + + #.a.b.#.# = 1 , entry 8 + + #.a.b.# = 1 , entry 9 + + #.a.b.#.# = 1 , entry 10 + + #.a.b.#.#.# = 1 , entry 11 + + a.#.b = 1 , entry 12 + + a.#.b.# = 1 , entry 13 + + a.#.b.#.# = 1 , entry 14 + + a.#.b.# = 1 , entry 15 + + a.#.b.#.# = 1 , entry 16 + + a.#.b.#.#.# = 1 , entry 17 + + a.b = 1 , entry 18 + + a.b.# = 1 , entry 19 + + a.b.#.# = 1 , entry 20 + + a.b.# = 1 , entry 21 + + a.b.#.# = 1 , entry 22 + + a.b.#.#.# = 1 , entry 23 + + +(1 row) + +select gin_debug_jsonpath_path_value('strict $.a[*].b[*] == 1'); + gin_debug_jsonpath_path_value +------------------------------- + a.#.b.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_path_value('lax $.a[*].b[*] == 1'); + gin_debug_jsonpath_path_value +-------------------------------- + OR + + #.a.b = 1 , entry 0 + + #.a.b.# = 1 , entry 1 + + #.a.b.#.# = 1 , entry 2 + + #.a.#.#.b = 1 , entry 3 + + #.a.#.#.b.# = 1 , entry 4 + + #.a.#.#.b.#.# = 1 , entry 5 + + #.a.#.b = 1 , entry 6 + + #.a.#.b.# = 1 , entry 7 + + #.a.#.b.#.# = 1 , entry 8 + + a.b = 1 , entry 9 + + a.b.# = 1 , entry 10 + + a.b.#.# = 1 , entry 11 + + a.#.#.b = 1 , entry 12 + + a.#.#.b.# = 1 , entry 13 + + a.#.#.b.#.# = 1 , entry 14 + + a.#.b = 1 , entry 15 + + a.#.b.# = 1 , entry 16 + + a.#.b.#.# = 1 , entry 17 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax $.a > 1 && $.a < 2 && $.b >= 3 && $.c <= "aaa"'); + gin_debug_jsonpath_path_value +------------------------------- + AND + + OR + + #.a > 1 , entry 0 + + #.a.# > 1 , entry 1 + + a > 1 , entry 2 + + a.# > 1 , entry 3 + + OR + + #.a < 2 , entry 4 + + #.a.# < 2 , entry 5 + + a < 2 , entry 6 + + a.# < 2 , entry 7 + + OR + + #.b >= 3 , entry 8 + + #.b.# >= 3 , entry 9 + + b >= 3 , entry 10 + + b.# >= 3 , entry 11 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict $.a > 1 && $.a < 2 && $.b >= 3 && $.c <= "aaa"'); + gin_debug_jsonpath_path_value +------------------------------- + a > 1 , < 2 , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('lax $.a == $.b'); + gin_debug_jsonpath_path_value +------------------------------- + AND + + OR + + #.a = * , entry 0 + + #.a.# = * , entry 1 + + a = * , entry 2 + + a.# = * , entry 3 + + OR + + #.b = * , entry 4 + + #.b.# = * , entry 5 + + b = * , entry 6 + + b.# = * , entry 7 + + +(1 row) + +SELECT gin_debug_jsonpath_path_value('strict $.a == $.b'); + gin_debug_jsonpath_path_value +------------------------------- + AND + + a = * , entry 0 + + b = * , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax $'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict $'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax $.a'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict $.a'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax exists($)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + $ = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict exists($)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + $ = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a.b)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a.b)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b = * , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax exists($ ? (@.b == 3).c.d)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + b = 3 , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict exists($ ? (@.b == 3).c.d)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + b = 3 , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + AND + + OR + + a.c.d.e = "aa" , entry 0 + + a.c.d = 1 , entry 1 + + a.b = 3 , entry 2 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + AND + + a.b = 3 , entry 0 + + OR + + a.c.d.e = "aa" , entry 1 + + a.c.d = 1 , entry 2 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax $.a ? (@.b == "foo").c == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + AND + + a.b = "foo" , entry 0 + + a.c = 1 , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict $.a ? (@.b == "foo").c == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + AND + + a.b = "foo" , entry 0 + + a.c = 1 , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax $.a ? (@.b == "foo") == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + AND + + a = 1 , entry 0 + + a.b = "foo" , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict $.a ? (@.b == "foo") == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + AND + + a = 1 , entry 0 + + a.b = "foo" , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax $.a ? (@.b == "foo")'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict $.a ? (@.b == "foo")'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + NULL + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a ? (@.b == "foo"))'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a ? (@.b == "foo"))'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a ? (@.b == "foo").c)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a ? (@.b == "foo").c)'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b = "foo" , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('exists($.a.b ? (@.c.d == 1))'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b.c.d = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('strict $.a.b == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('lax $.a.b == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('strict $.a.b[*] == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('lax $.a.b[*] == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('strict $.a[*].b[*] == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.#.b.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('lax $.a[*].b[*] == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.#.b.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('strict $.a.b[*][*] == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b.#.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('lax $.a.b[*][*] == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.b.#.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('strict $.a[*].b[*] == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.#.b.# = 1 , entry 0 + + +(1 row) + +select gin_debug_jsonpath_laxpath_value('lax $.a[*].b[*] == 1'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a.#.b.# = 1 , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax $.a > 1 && $.a < 2 && $.b >= 3 && $.c <= "aaa"'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + AND + + a > 1 , entry 0 + + a < 2 , entry 1 + + b >= 3 , entry 2 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict $.a > 1 && $.a < 2 && $.b >= 3 && $.c <= "aaa"'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + a > 1 , < 2 , entry 0 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('lax $.a == $.b'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + AND + + a = * , entry 0 + + b = * , entry 1 + + +(1 row) + +SELECT gin_debug_jsonpath_laxpath_value('strict $.a == $.b'); + gin_debug_jsonpath_laxpath_value +---------------------------------- + AND + + a = * , entry 0 + + b = * , entry 1 + + +(1 row) + +---table and index +select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 0; + count +------- + 654 +(1 row) + +select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 19; + count +------- + 13 +(1 row) + +select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 < 19; + count +------- + 985 +(1 row) + +select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 >= 19; + count +------- + 16 +(1 row) + +select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 <= 19; + count +------- + 988 +(1 row) + +select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 = 19; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 16 AND + (v->>'review_helpful_votes')::int4 < 20; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; + count +------- + 654 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'::jsquery; + count +------- + 13 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'::jsquery; + count +------- + 985 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'::jsquery; + count +------- + 16 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'::jsquery; + count +------- + 988 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16'::jsquery AND + v @@ 'review_helpful_votes < 20'::jsquery; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'::jsquery; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'::jsquery; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'::jsquery; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '::jsquery; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '::jsquery; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'::jsquery; + count +------- + 4 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; + count +------- + 54 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ 'customer_id = null'::jsquery; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_votes = true'::jsquery; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ 'product_group = false'::jsquery; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ 't = *'::jsquery; + count +------- + 10 +(1 row) + +select count(*) from test_jsquery where v @@ 't is boolean'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is string'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is numeric'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is array'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is object'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is boolean'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is string'::jsquery; + count +------- + 4 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is numeric'::jsquery; + count +------- + 5 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is array'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is object'::jsquery; + count +------- + 1018 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'::jsquery; + count +------- + 51 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'::jsquery; + count +------- + 1001 +(1 row) + +select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsquery; + count +------- + 42 +(1 row) + +select count(*) from test_jsquery where v @@ '$ > 2'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$ = false'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't'::jsquery; + count +------- + 10 +(1 row) + +select count(*) from test_jsquery where v @@ '$'::jsquery; + count +------- + 1036 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids.#'::jsquery; + count +------- + 950 +(1 row) + +select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'::jsquery; + count +------- + 79 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'::jsquery; + count +------- + 3 +(1 row) + +select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; + v +------------------- + {"array": [2]} + {"array": [2, 3]} +(2 rows) + +select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; + v +---------------------- + {"array": [2]} + {"array": [2, 3]} + {"array": [1, 2, 3]} + {"array": [2, 3, 4]} + {"array": [3, 4, 5]} +(5 rows) + +select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; + v +---------------------- + {"array": [2, 3]} + {"array": [1, 2, 3]} + {"array": [2, 3, 4]} +(3 rows) + +select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + v +------------------- + {"array": [2, 3]} +(1 row) + +create index t_idx on test_jsquery using gin (v jsonb_value_path_ops); +set enable_seqscan = off; +explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; + QUERY PLAN +------------------------------------------------------------------------ + Aggregate + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"review_helpful_votes" > 0'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"review_helpful_votes" > 0'::jsquery) +(5 rows) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; + count +------- + 654 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'::jsquery; + count +------- + 13 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'::jsquery; + count +------- + 985 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'::jsquery; + count +------- + 16 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'::jsquery; + count +------- + 988 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16'::jsquery AND + v @@ 'review_helpful_votes < 20'::jsquery; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'::jsquery; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'::jsquery; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'::jsquery; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '::jsquery; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '::jsquery; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'::jsquery; + count +------- + 4 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; + count +------- + 54 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ 'customer_id = null'::jsquery; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_votes = true'::jsquery; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ 'product_group = false'::jsquery; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ 't = *'::jsquery; + count +------- + 10 +(1 row) + +select count(*) from test_jsquery where v @@ 't is boolean'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is string'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is numeric'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is array'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is object'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is boolean'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is string'::jsquery; + count +------- + 4 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is numeric'::jsquery; + count +------- + 5 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is array'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is object'::jsquery; + count +------- + 1018 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'::jsquery; + count +------- + 51 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'::jsquery; + count +------- + 1001 +(1 row) + +select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsquery; + count +------- + 42 +(1 row) + +select count(*) from test_jsquery where v @@ '$ > 2'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$ = false'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't'::jsquery; + count +------- + 10 +(1 row) + +select count(*) from test_jsquery where v @@ '$'::jsquery; + count +------- + 1036 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids.#'::jsquery; + count +------- + 950 +(1 row) + +select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'::jsquery; + count +------- + 79 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'::jsquery; + count +------- + 3 +(1 row) + +explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; + QUERY PLAN +--------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"array" <@ [2, 3]'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"array" <@ [2, 3]'::jsquery) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; + QUERY PLAN +--------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"array" && [2, 3]'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"array" && [2, 3]'::jsquery) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; + QUERY PLAN +--------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"array" @> [2, 3]'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"array" @> [2, 3]'::jsquery) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + QUERY PLAN +-------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"array" = [2, 3]'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"array" = [2, 3]'::jsquery) +(6 rows) + +select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; + v +------------------- + {"array": [2]} + {"array": [2, 3]} +(2 rows) + +select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; + v +---------------------- + {"array": [2]} + {"array": [2, 3]} + {"array": [1, 2, 3]} + {"array": [2, 3, 4]} + {"array": [3, 4, 5]} +(5 rows) + +select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; + v +---------------------- + {"array": [2, 3]} + {"array": [1, 2, 3]} + {"array": [2, 3, 4]} +(3 rows) + +select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + v +------------------- + {"array": [2, 3]} +(1 row) + +explain (costs off) select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; + QUERY PLAN +----------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '($."review_helpful_votes" > 0)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '($."review_helpful_votes" > 0)'::jsonpath) +(5 rows) + +explain (costs off) select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 0)'::jsonpath; + QUERY PLAN +------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @? '$."review_helpful_votes"?(@ > 0)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @? '$."review_helpful_votes"?(@ > 0)'::jsonpath) +(5 rows) + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; + count +------- + 654 +(1 row) + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 19'::jsonpath; + count +------- + 13 +(1 row) + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes < 19'::jsonpath; + count +------- + 985 +(1 row) + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes >= 19'::jsonpath; + count +------- + 16 +(1 row) + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes <= 19'::jsonpath; + count +------- + 988 +(1 row) + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes == 19'::jsonpath; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16'::jsonpath AND + v @@ '$.review_helpful_votes < 20'::jsonpath; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16 && $.review_helpful_votes < 20'::jsonpath; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 16 && @ < 20)'::jsonpath; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295"'::jsonpath; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "0440180295")'::jsonpath; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @? '$.similar_product_ids[*] ? (@ == "0440180295")'::jsonpath; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295" && $.product_sales_rank > 300000'::jsonpath; + count +------- + 4 +(1 row) + +--select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @? 'strict $.similar_product_ids ? (@[*] == "B000002H2H" && @[*] == "B000002H6C")'::jsonpath; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$.customer_id == null'::jsonpath; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ '$.review_votes == true'::jsonpath; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ '$.product_group == false'::jsonpath; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @? '$.t'::jsonpath; + count +------- + 10 +(1 row) + +select count(*) from test_jsquery where v @@ '$.t.type() == "boolean"'::jsonpath; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ '$.t.type() == "string"'::jsonpath; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ '$.t.type() == "number"'::jsonpath; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ '$.t.type() == "array"'::jsonpath; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ '$.t.type() == "object"'::jsonpath; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ '$.type() == "boolean"'::jsonpath; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$.type() == "string"'::jsonpath; + count +------- + 4 +(1 row) + +select count(*) from test_jsquery where v @@ '$.type() == "number"'::jsonpath; + count +------- + 5 +(1 row) + +select count(*) from test_jsquery where v @@ '$.type() == "array"'::jsonpath; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$.type() == "object"'::jsonpath; + count +------- + 1018 +(1 row) + +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is numeric)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is string)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @@ 'strict $ > 2'::jsonpath; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$ == false'::jsonpath; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @? '$.t'::jsonpath; + count +------- + 10 +(1 row) + +select count(*) from test_jsquery where v @? '$'::jsonpath; + count +------- + 1036 +(1 row) + +select count(*) from test_jsquery where v @? '$.similar_product_ids[*]'::jsonpath; + count +------- + 950 +(1 row) + +select count(*) from test_jsquery where v @@ '$ ? (@.review_votes > 10) . review_rating < 7'::jsonpath; + count +------- + 79 +(1 row) + +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "B0002W4TL2") '::jsonpath; + count +------- + 3 +(1 row) + +--explain (costs off) select v from test_jsquery where v @@ '$.array <@ [2,3]'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; + QUERY PLAN +------------------------------------------------------------------------------ + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @? '$."array"[*]?(@ == 2 || @ == 3)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @? '$."array"[*]?(@ == 2 || @ == 3)'::jsonpath) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; + QUERY PLAN +--------------------------------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '($."array"[*] == 2 && $."array"[*] == 3)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '($."array"[*] == 2 && $."array"[*] == 3)'::jsonpath) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '(($."array"[0] == 2 && $."array"[1] == 3) && $."array".size() == 2)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '(($."array"[0] == 2 && $."array"[1] == 3) && $."array".size() == 2)'::jsonpath) +(6 rows) + +--select v from test_jsquery where v @@ 'array <@ [2,3]'::jsonpath order by v; +select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; + v +---------------------- + {"array": [2]} + {"array": [2, 3]} + {"array": [1, 2, 3]} + {"array": [2, 3, 4]} + {"array": [3, 4, 5]} +(5 rows) + +select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; + v +---------------------- + {"array": [2, 3]} + {"array": [1, 2, 3]} + {"array": [2, 3, 4]} +(3 rows) + +select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; + v +------------------- + {"array": [2, 3]} +(1 row) + +drop index t_idx; +create index t_idx on test_jsquery using gin (v jsonb_path_value_ops); +set enable_seqscan = off; +explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; + QUERY PLAN +------------------------------------------------------------------------ + Aggregate + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"review_helpful_votes" > 0'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"review_helpful_votes" > 0'::jsquery) +(5 rows) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; + count +------- + 654 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'::jsquery; + count +------- + 13 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'::jsquery; + count +------- + 985 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'::jsquery; + count +------- + 16 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'::jsquery; + count +------- + 988 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16'::jsquery AND + v @@ 'review_helpful_votes < 20'::jsquery; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'::jsquery; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'::jsquery; + count +------- + 8 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'::jsquery; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '::jsquery; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '::jsquery; + count +------- + 7 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'::jsquery; + count +------- + 4 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; + count +------- + 54 +(1 row) + +select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ 'customer_id = null'::jsquery; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ 'review_votes = true'::jsquery; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ 'product_group = false'::jsquery; + count +------- + 1 +(1 row) + +select count(*) from test_jsquery where v @@ 't = *'::jsquery; + count +------- + 10 +(1 row) + +select count(*) from test_jsquery where v @@ 't is boolean'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is string'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is numeric'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is array'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ 't is object'::jsquery; + count +------- + 2 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is boolean'::jsquery; + count +------- + 3 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is string'::jsquery; + count +------- + 4 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is numeric'::jsquery; + count +------- + 5 +(1 row) + +select count(*) from test_jsquery where v @@ '$ is array'::jsquery; + count +------- + 3 (1 row) -SELECT gin_debug_query_value_path('tags.#.term. ? ( # = "NYC").x > 0'); - gin_debug_query_value_path ----------------------------------- - tags.#.term.# = "NYC" , entry 0 + - +select count(*) from test_jsquery where v @@ '$ is object'::jsquery; + count +------- + 1018 (1 row) -SELECT gin_debug_query_value_path('$ = true'); - gin_debug_query_value_path ----------------------------- - $ = true , entry 0 + - +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'::jsquery; + count +------- + 51 (1 row) -SELECT gin_debug_query_value_path('$ . ? (review_votes > 10) . review_rating < 7'); - gin_debug_query_value_path --------------------------------- - AND + - review_rating < 7 , entry 0 + - review_votes > 10 , entry 1 + - +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'::jsquery; + count +------- + 1001 (1 row) -SELECT gin_debug_query_value_path('similar_product_ids . ? (# = "B0002W4TL2") . $'); - gin_debug_query_value_path -------------------------------------------------- - similar_product_ids.# = "B0002W4TL2" , entry 0 + - +select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsquery; + count +------- + 42 (1 row) ----table and index -select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 0; +select count(*) from test_jsquery where v @@ '$ > 2'::jsquery; count ------- - 654 + 3 (1 row) -select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 19; +select count(*) from test_jsquery where v @@ '$ = false'::jsquery; count ------- - 13 + 2 (1 row) -select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 < 19; +select count(*) from test_jsquery where v @@ 't'::jsquery; count ------- - 985 + 10 (1 row) -select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 >= 19; +select count(*) from test_jsquery where v @@ '$'::jsquery; count ------- - 16 + 1036 (1 row) -select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 <= 19; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#'::jsquery; count ------- - 988 + 950 (1 row) -select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 = 19; +select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'::jsquery; count ------- - 3 + 79 (1 row) -select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 16 AND - (v->>'review_helpful_votes')::int4 < 20; +select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'::jsquery; count ------- - 8 + 3 +(1 row) + +explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; + QUERY PLAN +--------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"array" <@ [2, 3]'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"array" <@ [2, 3]'::jsquery) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; + QUERY PLAN +--------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"array" && [2, 3]'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"array" && [2, 3]'::jsquery) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; + QUERY PLAN +--------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"array" @> [2, 3]'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"array" @> [2, 3]'::jsquery) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + QUERY PLAN +-------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '"array" = [2, 3]'::jsquery) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '"array" = [2, 3]'::jsquery) +(6 rows) + +select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; + v +------------------- + {"array": [2]} + {"array": [2, 3]} +(2 rows) + +select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; + v +---------------------- + {"array": [2]} + {"array": [2, 3]} + {"array": [1, 2, 3]} + {"array": [2, 3, 4]} + {"array": [3, 4, 5]} +(5 rows) + +select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; + v +---------------------- + {"array": [2, 3]} + {"array": [1, 2, 3]} + {"array": [2, 3, 4]} +(3 rows) + +select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + v +------------------- + {"array": [2, 3]} (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; +explain (costs off) select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; + QUERY PLAN +----------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '($."review_helpful_votes" > 0)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '($."review_helpful_votes" > 0)'::jsonpath) +(5 rows) + +explain (costs off) select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 0)'::jsonpath; + QUERY PLAN +------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @? '$."review_helpful_votes"?(@ > 0)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @? '$."review_helpful_votes"?(@ > 0)'::jsonpath) +(5 rows) + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; count ------- 654 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 19'::jsonpath; count ------- 13 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes < 19'::jsonpath; count ------- 985 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes >= 19'::jsonpath; count ------- 16 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes <= 19'::jsonpath; count ------- 988 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes == 19'::jsonpath; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16' AND - v @@ 'review_helpful_votes < 20'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16'::jsonpath AND + v @@ '$.review_helpful_votes < 20'::jsonpath; count ------- 8 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16 && $.review_helpful_votes < 20'::jsonpath; count ------- 8 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'; +select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 16 && @ < 20)'::jsonpath; count ------- 8 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295"'::jsonpath; count ------- 7 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "0440180295")'::jsonpath; count ------- 7 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*] ? (@ == "0440180295")'::jsonpath; count ------- 7 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295" && $.product_sales_rank > 300000'::jsonpath; count ------- 4 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'; - count -------- - 54 -(1 row) - -select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'; +--select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @? 'strict $.similar_product_ids ? (@[*] == "B000002H2H" && @[*] == "B000002H6C")'::jsonpath; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ 'customer_id = null'; +select count(*) from test_jsquery where v @@ '$.customer_id == null'::jsonpath; count ------- 1 (1 row) -select count(*) from test_jsquery where v @@ 'review_votes = true'; +select count(*) from test_jsquery where v @@ '$.review_votes == true'::jsonpath; count ------- 1 (1 row) -select count(*) from test_jsquery where v @@ 'product_group = false'; +select count(*) from test_jsquery where v @@ '$.product_group == false'::jsonpath; count ------- 1 (1 row) -select count(*) from test_jsquery where v @@ 't = *'; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; count ------- 10 (1 row) -select count(*) from test_jsquery where v @@ 't is boolean'; +select count(*) from test_jsquery where v @@ '$.t.type() == "boolean"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is string'; +select count(*) from test_jsquery where v @@ '$.t.type() == "string"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is numeric'; +select count(*) from test_jsquery where v @@ '$.t.type() == "number"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is array'; +select count(*) from test_jsquery where v @@ '$.t.type() == "array"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is object'; +select count(*) from test_jsquery where v @@ '$.t.type() == "object"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ '$ is boolean'; +select count(*) from test_jsquery where v @@ '$.type() == "boolean"'::jsonpath; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ '$ is string'; +select count(*) from test_jsquery where v @@ '$.type() == "string"'::jsonpath; count ------- 4 (1 row) -select count(*) from test_jsquery where v @@ '$ is numeric'; +select count(*) from test_jsquery where v @@ '$.type() == "number"'::jsonpath; count ------- 5 (1 row) -select count(*) from test_jsquery where v @@ '$ is array'; - count -------- - 2 -(1 row) - -select count(*) from test_jsquery where v @@ '$ is object'; - count -------- - 1017 -(1 row) - -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'; - count -------- - 51 -(1 row) - -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'; +select count(*) from test_jsquery where v @@ '$.type() == "array"'::jsonpath; count ------- - 1001 + 3 (1 row) -select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'; +select count(*) from test_jsquery where v @@ '$.type() == "object"'::jsonpath; count ------- - 40 + 1018 (1 row) -select count(*) from test_jsquery where v @@ '$ > 2'; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is numeric)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is string)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @@ 'strict $ > 2'::jsonpath; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ '$ = false'; +select count(*) from test_jsquery where v @@ '$ == false'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't'; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; count ------- 10 (1 row) -select count(*) from test_jsquery where v @@ '$'; +select count(*) from test_jsquery where v @? '$'::jsonpath; count ------- - 1034 + 1036 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids.#'; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*]'::jsonpath; count ------- - 1001 + 950 (1 row) -select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'; +select count(*) from test_jsquery where v @@ '$ ? (@.review_votes > 10) . review_rating < 7'::jsonpath; count ------- 79 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "B0002W4TL2") '::jsonpath; count ------- 3 (1 row) -select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; - v -------------------- - {"array": [2]} - {"array": [2, 3]} -(2 rows) +--explain (costs off) select v from test_jsquery where v @@ '$.array <@ [2,3]'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; + QUERY PLAN +------------------------------------------------------------------------------ + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @? '$."array"[*]?(@ == 2 || @ == 3)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @? '$."array"[*]?(@ == 2 || @ == 3)'::jsonpath) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; + QUERY PLAN +--------------------------------------------------------------------------------------- + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '($."array"[*] == 2 && $."array"[*] == 3)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '($."array"[*] == 2 && $."array"[*] == 3)'::jsonpath) +(6 rows) + +explain (costs off) select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ + Sort + Sort Key: v + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @@ '(($."array"[0] == 2 && $."array"[1] == 3) && $."array".size() == 2)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @@ '(($."array"[0] == 2 && $."array"[1] == 3) && $."array".size() == 2)'::jsonpath) +(6 rows) -select v from test_jsquery where v @@ 'array && [2,3]' order by v; +--select v from test_jsquery where v @@ 'array <@ [2,3]'::jsonpath order by v; +select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; v ---------------------- {"array": [2]} @@ -2717,7 +5823,7 @@ select v from test_jsquery where v @@ 'array && [2,3]' order by v; {"array": [3, 4, 5]} (5 rows) -select v from test_jsquery where v @@ 'array @> [2,3]' order by v; +select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; v ---------------------- {"array": [2, 3]} @@ -2725,15 +5831,16 @@ select v from test_jsquery where v @@ 'array @> [2,3]' order by v; {"array": [2, 3, 4]} (3 rows) -select v from test_jsquery where v @@ 'array = [2,3]' order by v; +select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; v ------------------- {"array": [2, 3]} (1 row) -create index t_idx on test_jsquery using gin (v jsonb_value_path_ops); +drop index t_idx; +create index t_idx on test_jsquery using gin (v jsonb_laxpath_value_ops); set enable_seqscan = off; -explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; +explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; QUERY PLAN ------------------------------------------------------------------------ Aggregate @@ -2743,242 +5850,242 @@ explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful Index Cond: (v @@ '"review_helpful_votes" > 0'::jsquery) (5 rows) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; count ------- 654 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'::jsquery; count ------- 13 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'; +select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'::jsquery; count ------- 985 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'; +select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'::jsquery; count ------- 16 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'; +select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'::jsquery; count ------- 988 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'; +select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'::jsquery; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16' AND - v @@ 'review_helpful_votes < 20'; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16'::jsquery AND + v @@ 'review_helpful_votes < 20'::jsquery; count ------- 8 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'::jsquery; count ------- 8 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'; +select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'::jsquery; count ------- 8 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'::jsquery; count ------- 7 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '; +select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '::jsquery; count ------- 7 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '::jsquery; count ------- 7 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'::jsquery; count ------- 4 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'; +select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; count ------- 54 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'; +select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'::jsquery; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ 'customer_id = null'; +select count(*) from test_jsquery where v @@ 'customer_id = null'::jsquery; count ------- 1 (1 row) -select count(*) from test_jsquery where v @@ 'review_votes = true'; +select count(*) from test_jsquery where v @@ 'review_votes = true'::jsquery; count ------- 1 (1 row) -select count(*) from test_jsquery where v @@ 'product_group = false'; +select count(*) from test_jsquery where v @@ 'product_group = false'::jsquery; count ------- 1 (1 row) -select count(*) from test_jsquery where v @@ 't = *'; +select count(*) from test_jsquery where v @@ 't = *'::jsquery; count ------- 10 (1 row) -select count(*) from test_jsquery where v @@ 't is boolean'; +select count(*) from test_jsquery where v @@ 't is boolean'::jsquery; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is string'; +select count(*) from test_jsquery where v @@ 't is string'::jsquery; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is numeric'; +select count(*) from test_jsquery where v @@ 't is numeric'::jsquery; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is array'; +select count(*) from test_jsquery where v @@ 't is array'::jsquery; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is object'; +select count(*) from test_jsquery where v @@ 't is object'::jsquery; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ '$ is boolean'; +select count(*) from test_jsquery where v @@ '$ is boolean'::jsquery; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ '$ is string'; +select count(*) from test_jsquery where v @@ '$ is string'::jsquery; count ------- 4 (1 row) -select count(*) from test_jsquery where v @@ '$ is numeric'; +select count(*) from test_jsquery where v @@ '$ is numeric'::jsquery; count ------- 5 (1 row) -select count(*) from test_jsquery where v @@ '$ is array'; +select count(*) from test_jsquery where v @@ '$ is array'::jsquery; count ------- - 2 + 3 (1 row) -select count(*) from test_jsquery where v @@ '$ is object'; +select count(*) from test_jsquery where v @@ '$ is object'::jsquery; count ------- - 1017 + 1018 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'::jsquery; count ------- 51 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'::jsquery; count ------- 1001 (1 row) -select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'; +select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsquery; count ------- - 7 + 42 (1 row) -select count(*) from test_jsquery where v @@ '$ > 2'; +select count(*) from test_jsquery where v @@ '$ > 2'::jsquery; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ '$ = false'; +select count(*) from test_jsquery where v @@ '$ = false'::jsquery; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't'; +select count(*) from test_jsquery where v @@ 't'::jsquery; count ------- 10 (1 row) -select count(*) from test_jsquery where v @@ '$'; +select count(*) from test_jsquery where v @@ '$'::jsquery; count ------- - 1034 + 1036 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids.#'; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#'::jsquery; count ------- - 1001 + 950 (1 row) -select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'; +select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'::jsquery; count ------- 79 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'; +select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'::jsquery; count ------- 3 (1 row) -explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; +explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; QUERY PLAN --------------------------------------------------------------- Sort @@ -2989,7 +6096,7 @@ explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]' order Index Cond: (v @@ '"array" <@ [2, 3]'::jsquery) (6 rows) -explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]' order by v; +explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; QUERY PLAN --------------------------------------------------------------- Sort @@ -3000,7 +6107,7 @@ explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]' order Index Cond: (v @@ '"array" && [2, 3]'::jsquery) (6 rows) -explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]' order by v; +explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; QUERY PLAN --------------------------------------------------------------- Sort @@ -3011,7 +6118,7 @@ explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]' order Index Cond: (v @@ '"array" @> [2, 3]'::jsquery) (6 rows) -explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]' order by v; +explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; QUERY PLAN -------------------------------------------------------------- Sort @@ -3022,14 +6129,14 @@ explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]' order Index Cond: (v @@ '"array" = [2, 3]'::jsquery) (6 rows) -select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; +select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; v ------------------- {"array": [2]} {"array": [2, 3]} (2 rows) -select v from test_jsquery where v @@ 'array && [2,3]' order by v; +select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; v ---------------------- {"array": [2]} @@ -3039,7 +6146,7 @@ select v from test_jsquery where v @@ 'array && [2,3]' order by v; {"array": [3, 4, 5]} (5 rows) -select v from test_jsquery where v @@ 'array @> [2,3]' order by v; +select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; v ---------------------- {"array": [2, 3]} @@ -3047,312 +6154,283 @@ select v from test_jsquery where v @@ 'array @> [2,3]' order by v; {"array": [2, 3, 4]} (3 rows) -select v from test_jsquery where v @@ 'array = [2,3]' order by v; +select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; v ------------------- {"array": [2, 3]} (1 row) -drop index t_idx; -create index t_idx on test_jsquery using gin (v jsonb_path_value_ops); -set enable_seqscan = off; -explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; - QUERY PLAN ------------------------------------------------------------------------- +explain (costs off) select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; + QUERY PLAN +----------------------------------------------------------------------------- Aggregate -> Bitmap Heap Scan on test_jsquery - Recheck Cond: (v @@ '"review_helpful_votes" > 0'::jsquery) + Recheck Cond: (v @@ '($."review_helpful_votes" > 0)'::jsonpath) -> Bitmap Index Scan on t_idx - Index Cond: (v @@ '"review_helpful_votes" > 0'::jsquery) + Index Cond: (v @@ '($."review_helpful_votes" > 0)'::jsonpath) +(5 rows) + +explain (costs off) select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 0)'::jsonpath; + QUERY PLAN +------------------------------------------------------------------------------- + Aggregate + -> Bitmap Heap Scan on test_jsquery + Recheck Cond: (v @? '$."review_helpful_votes"?(@ > 0)'::jsonpath) + -> Bitmap Index Scan on t_idx + Index Cond: (v @? '$."review_helpful_votes"?(@ > 0)'::jsonpath) (5 rows) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; count ------- 654 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 19'::jsonpath; count ------- 13 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes < 19'::jsonpath; count ------- 985 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes >= 19'::jsonpath; count ------- 16 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes <= 19'::jsonpath; count ------- 988 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes == 19'::jsonpath; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16' AND - v @@ 'review_helpful_votes < 20'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16'::jsonpath AND + v @@ '$.review_helpful_votes < 20'::jsonpath; count ------- 8 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16 && $.review_helpful_votes < 20'::jsonpath; count ------- 8 (1 row) -select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'; +select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 16 && @ < 20)'::jsonpath; count ------- 8 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295"'::jsonpath; count ------- 7 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "0440180295")'::jsonpath; count ------- 7 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*] ? (@ == "0440180295")'::jsonpath; count ------- 7 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295" && $.product_sales_rank > 300000'::jsonpath; count ------- 4 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'; - count -------- - 54 -(1 row) - -select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'; +--select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @? 'strict $.similar_product_ids ? (@[*] == "B000002H2H" && @[*] == "B000002H6C")'::jsonpath; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ 'customer_id = null'; +select count(*) from test_jsquery where v @@ '$.customer_id == null'::jsonpath; count ------- 1 (1 row) -select count(*) from test_jsquery where v @@ 'review_votes = true'; +select count(*) from test_jsquery where v @@ '$.review_votes == true'::jsonpath; count ------- 1 (1 row) -select count(*) from test_jsquery where v @@ 'product_group = false'; +select count(*) from test_jsquery where v @@ '$.product_group == false'::jsonpath; count ------- 1 (1 row) -select count(*) from test_jsquery where v @@ 't = *'; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; count ------- 10 (1 row) -select count(*) from test_jsquery where v @@ 't is boolean'; +select count(*) from test_jsquery where v @@ '$.t.type() == "boolean"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is string'; +select count(*) from test_jsquery where v @@ '$.t.type() == "string"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is numeric'; +select count(*) from test_jsquery where v @@ '$.t.type() == "number"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is array'; +select count(*) from test_jsquery where v @@ '$.t.type() == "array"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't is object'; +select count(*) from test_jsquery where v @@ '$.t.type() == "object"'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ '$ is boolean'; +select count(*) from test_jsquery where v @@ '$.type() == "boolean"'::jsonpath; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ '$ is string'; +select count(*) from test_jsquery where v @@ '$.type() == "string"'::jsonpath; count ------- 4 (1 row) -select count(*) from test_jsquery where v @@ '$ is numeric'; +select count(*) from test_jsquery where v @@ '$.type() == "number"'::jsonpath; count ------- 5 (1 row) -select count(*) from test_jsquery where v @@ '$ is array'; - count -------- - 2 -(1 row) - -select count(*) from test_jsquery where v @@ '$ is object'; - count -------- - 1017 -(1 row) - -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'; - count -------- - 51 -(1 row) - -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'; +select count(*) from test_jsquery where v @@ '$.type() == "array"'::jsonpath; count ------- - 1001 + 3 (1 row) -select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'; +select count(*) from test_jsquery where v @@ '$.type() == "object"'::jsonpath; count ------- - 7 + 1018 (1 row) -select count(*) from test_jsquery where v @@ '$ > 2'; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is numeric)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is string)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @@ 'strict $ > 2'::jsonpath; count ------- 3 (1 row) -select count(*) from test_jsquery where v @@ '$ = false'; +select count(*) from test_jsquery where v @@ '$ == false'::jsonpath; count ------- 2 (1 row) -select count(*) from test_jsquery where v @@ 't'; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; count ------- 10 (1 row) -select count(*) from test_jsquery where v @@ '$'; +select count(*) from test_jsquery where v @? '$'::jsonpath; count ------- - 1034 + 1036 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids.#'; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*]'::jsonpath; count ------- 950 (1 row) -select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'; +select count(*) from test_jsquery where v @@ '$ ? (@.review_votes > 10) . review_rating < 7'::jsonpath; count ------- 79 (1 row) -select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "B0002W4TL2") '::jsonpath; count ------- 3 (1 row) -explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; - QUERY PLAN ---------------------------------------------------------------- - Sort - Sort Key: v - -> Bitmap Heap Scan on test_jsquery - Recheck Cond: (v @@ '"array" <@ [2, 3]'::jsquery) - -> Bitmap Index Scan on t_idx - Index Cond: (v @@ '"array" <@ [2, 3]'::jsquery) -(6 rows) - -explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]' order by v; - QUERY PLAN ---------------------------------------------------------------- +--explain (costs off) select v from test_jsquery where v @@ '$.array <@ [2,3]'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; + QUERY PLAN +------------------------------------------------------------------------------ Sort Sort Key: v -> Bitmap Heap Scan on test_jsquery - Recheck Cond: (v @@ '"array" && [2, 3]'::jsquery) + Recheck Cond: (v @? '$."array"[*]?(@ == 2 || @ == 3)'::jsonpath) -> Bitmap Index Scan on t_idx - Index Cond: (v @@ '"array" && [2, 3]'::jsquery) + Index Cond: (v @? '$."array"[*]?(@ == 2 || @ == 3)'::jsonpath) (6 rows) -explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]' order by v; - QUERY PLAN ---------------------------------------------------------------- +explain (costs off) select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; + QUERY PLAN +--------------------------------------------------------------------------------------- Sort Sort Key: v -> Bitmap Heap Scan on test_jsquery - Recheck Cond: (v @@ '"array" @> [2, 3]'::jsquery) + Recheck Cond: (v @@ '($."array"[*] == 2 && $."array"[*] == 3)'::jsonpath) -> Bitmap Index Scan on t_idx - Index Cond: (v @@ '"array" @> [2, 3]'::jsquery) + Index Cond: (v @@ '($."array"[*] == 2 && $."array"[*] == 3)'::jsonpath) (6 rows) -explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]' order by v; - QUERY PLAN --------------------------------------------------------------- +explain (costs off) select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------ Sort Sort Key: v -> Bitmap Heap Scan on test_jsquery - Recheck Cond: (v @@ '"array" = [2, 3]'::jsquery) + Recheck Cond: (v @@ '(($."array"[0] == 2 && $."array"[1] == 3) && $."array".size() == 2)'::jsonpath) -> Bitmap Index Scan on t_idx - Index Cond: (v @@ '"array" = [2, 3]'::jsquery) + Index Cond: (v @@ '(($."array"[0] == 2 && $."array"[1] == 3) && $."array".size() == 2)'::jsonpath) (6 rows) -select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; - v -------------------- - {"array": [2]} - {"array": [2, 3]} -(2 rows) - -select v from test_jsquery where v @@ 'array && [2,3]' order by v; +--select v from test_jsquery where v @@ 'array <@ [2,3]'::jsonpath order by v; +select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; v ---------------------- {"array": [2]} @@ -3362,7 +6440,7 @@ select v from test_jsquery where v @@ 'array && [2,3]' order by v; {"array": [3, 4, 5]} (5 rows) -select v from test_jsquery where v @@ 'array @> [2,3]' order by v; +select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; v ---------------------- {"array": [2, 3]} @@ -3370,7 +6448,7 @@ select v from test_jsquery where v @@ 'array @> [2,3]' order by v; {"array": [2, 3, 4]} (3 rows) -select v from test_jsquery where v @@ 'array = [2,3]' order by v; +select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; v ------------------- {"array": [2, 3]} diff --git a/include/utils/jsonpath.h b/include/utils/jsonpath.h new file mode 100644 index 0000000..98bd3d1 --- /dev/null +++ b/include/utils/jsonpath.h @@ -0,0 +1 @@ +#define NO_JSONPATH 1 diff --git a/jsonb_gin_ops.c b/jsonb_gin_ops.c index a9bc22c..45b4753 100644 --- a/jsonb_gin_ops.c +++ b/jsonb_gin_ops.c @@ -21,9 +21,14 @@ #include "miscadmin.h" #include "utils/builtins.h" #include "utils/jsonb.h" +#include "utils/jsonpath.h" #include "jsquery.h" +#ifdef PG_GETARG_JSONB_P +#define PG_GETARG_JSONB PG_GETARG_JSONB_P +#endif + typedef struct PathHashStack { uint32 hash; @@ -55,6 +60,8 @@ typedef struct #define BLOOM_BITS 2 #define JsonbNestedContainsStrategyNumber 13 #define JsQueryMatchStrategyNumber 14 +#define JsonpathExistsStrategyNumber 15 +#define JsonpathMatchStrategyNumber 16 typedef struct { @@ -65,6 +72,12 @@ typedef struct int count, total; } Entries; +typedef struct PathValueExtra +{ + Entries *entries; + bool lax; +} PathValueExtra; + typedef struct { ExtractedNode *root; @@ -91,6 +104,7 @@ PG_FUNCTION_INFO_V1(gin_extract_jsonb_query_value_path); PG_FUNCTION_INFO_V1(gin_consistent_jsonb_value_path); PG_FUNCTION_INFO_V1(gin_triconsistent_jsonb_value_path); PG_FUNCTION_INFO_V1(gin_debug_query_value_path); +PG_FUNCTION_INFO_V1(gin_debug_jsonpath_value_path); Datum gin_compare_jsonb_value_path(PG_FUNCTION_ARGS); Datum gin_compare_partial_jsonb_value_path(PG_FUNCTION_ARGS); @@ -99,22 +113,33 @@ Datum gin_extract_jsonb_query_value_path(PG_FUNCTION_ARGS); Datum gin_consistent_jsonb_value_path(PG_FUNCTION_ARGS); Datum gin_triconsistent_jsonb_value_path(PG_FUNCTION_ARGS); Datum gin_debug_query_value_path(PG_FUNCTION_ARGS); +Datum gin_debug_jsonpath_value_path(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(gin_compare_jsonb_path_value); PG_FUNCTION_INFO_V1(gin_compare_partial_jsonb_path_value); PG_FUNCTION_INFO_V1(gin_extract_jsonb_path_value); +PG_FUNCTION_INFO_V1(gin_extract_jsonb_laxpath_value); PG_FUNCTION_INFO_V1(gin_extract_jsonb_query_path_value); +PG_FUNCTION_INFO_V1(gin_extract_jsonb_query_laxpath_value); PG_FUNCTION_INFO_V1(gin_consistent_jsonb_path_value); PG_FUNCTION_INFO_V1(gin_triconsistent_jsonb_path_value); PG_FUNCTION_INFO_V1(gin_debug_query_path_value); +PG_FUNCTION_INFO_V1(gin_debug_query_laxpath_value); +PG_FUNCTION_INFO_V1(gin_debug_jsonpath_path_value); +PG_FUNCTION_INFO_V1(gin_debug_jsonpath_laxpath_value); Datum gin_compare_jsonb_path_value(PG_FUNCTION_ARGS); Datum gin_compare_partial_jsonb_path_value(PG_FUNCTION_ARGS); Datum gin_extract_jsonb_path_value(PG_FUNCTION_ARGS); +Datum gin_extract_jsonb_laxpath_value(PG_FUNCTION_ARGS); Datum gin_extract_jsonb_query_path_value(PG_FUNCTION_ARGS); +Datum gin_extract_jsonb_query_laxpath_value(PG_FUNCTION_ARGS); Datum gin_consistent_jsonb_path_value(PG_FUNCTION_ARGS); Datum gin_triconsistent_jsonb_path_value(PG_FUNCTION_ARGS); Datum gin_debug_query_path_value(PG_FUNCTION_ARGS); +Datum gin_debug_query_laxpath_value(PG_FUNCTION_ARGS); +Datum gin_debug_jsonpath_path_value(PG_FUNCTION_ARGS); +Datum gin_debug_jsonpath_laxpath_value(PG_FUNCTION_ARGS); static int add_entry(Entries *e, Datum key, Pointer extra, bool pmatch) @@ -568,7 +593,9 @@ gin_compare_partial_jsonb_value_path(PG_FUNCTION_ARGS) StrategyNumber strategy = PG_GETARG_UINT16(2); int32 result; - if (strategy == JsQueryMatchStrategyNumber) + if (strategy == JsQueryMatchStrategyNumber || + strategy == JsonpathExistsStrategyNumber || + strategy == JsonpathMatchStrategyNumber) { KeyExtra *extra = (KeyExtra *)PG_GETARG_POINTER(3); ExtractedNode *node = extra->node; @@ -656,10 +683,7 @@ gin_extract_jsonb_value_path_internal(Jsonb *jb, int32 *nentries, uint32 **bloom uint32 hash; if (total == 0) - { - *nentries = 0; - return NULL; - } + total = 2; /* single entry for empty object/array */ entries = (Datum *) palloc(sizeof(Datum) * total); if (bloom) @@ -741,18 +765,78 @@ gin_extract_jsonb_value_path(PG_FUNCTION_ARGS) PG_RETURN_POINTER(gin_extract_jsonb_value_path_internal(jb, nentries, NULL)); } +static text * +gin_debug_query_internal(FunctionCallInfo fcinfo, + MakeEntryHandler makeHandler, + CheckEntryHandler checkHandler, Pointer extra) +{ + JsQuery *jq = PG_GETARG_JSQUERY(0); + ExtractedNode *root; + char *s; + int optimize = 0; + + if (PG_GETARG_BOOL(1)) + optimize |= optFlatten; + if (PG_GETARG_BOOL(2)) + optimize |= optSimplify; + if (PG_GETARG_BOOL(3)) + optimize |= optSelectivity; + + root = extractJsQuery(jq, optimize, makeHandler, checkHandler, extra); + s = debugExtractedQuery(root); + + return cstring_to_text(s); +} + Datum gin_debug_query_value_path(PG_FUNCTION_ARGS) { - JsQuery *jq; Entries e = {0}; + + PG_RETURN_TEXT_P(gin_debug_query_internal(fcinfo, + make_value_path_entry_handler, + check_value_path_entry_handler, + (Pointer) &e)); +} + +#ifndef NO_JSONPATH +static text * +gin_debug_jsonpath_internal(FunctionCallInfo fcinfo, + bool arrayPathItems, + MakeEntryHandler makeHandler, + CheckEntryHandler checkHandler, Pointer extra) +{ + JsonPath *jp = PG_GETARG_JSONPATH_P(0); + ExtractedNode *root; char *s; + int optimize = 0; + bool exists = PG_GETARG_BOOL(1); + + if (PG_GETARG_BOOL(2)) + optimize |= optFlatten; + if (PG_GETARG_BOOL(3)) + optimize |= optSimplify; + if (PG_GETARG_BOOL(4)) + optimize |= optSelectivity; - jq = PG_GETARG_JSQUERY(0); - s = debugJsQuery(jq, make_value_path_entry_handler, - check_value_path_entry_handler, (Pointer)&e); - PG_RETURN_TEXT_P(cstring_to_text(s)); + root = extractJsonPathQuery(jp, exists, arrayPathItems, optimize, + makeHandler, checkHandler, extra); + s = debugExtractedQuery(root); + + return cstring_to_text(s); +} + +Datum +gin_debug_jsonpath_value_path(PG_FUNCTION_ARGS) +{ + Entries e = {0}; + + PG_RETURN_TEXT_P(gin_debug_jsonpath_internal(fcinfo, false, + make_value_path_entry_handler, + check_value_path_entry_handler, + (Pointer) &e)); } +#endif Datum gin_extract_jsonb_query_value_path(PG_FUNCTION_ARGS) @@ -767,7 +851,6 @@ gin_extract_jsonb_query_value_path(PG_FUNCTION_ARGS) int i, n; uint32 *bloom; Entries e = {0}; - JsQuery *jq; ExtractedNode *root; switch(strategy) @@ -792,9 +875,25 @@ gin_extract_jsonb_query_value_path(PG_FUNCTION_ARGS) break; case JsQueryMatchStrategyNumber: - jq = PG_GETARG_JSQUERY(0); - root = extractJsQuery(jq, make_value_path_entry_handler, - check_value_path_entry_handler, (Pointer)&e); +#ifndef NO_JSONPATH + case JsonpathExistsStrategyNumber: + case JsonpathMatchStrategyNumber: + if (strategy != JsQueryMatchStrategyNumber) + root = extractJsonPathQuery(PG_GETARG_JSONPATH_P(0), + strategy == JsonpathExistsStrategyNumber, + false, + optAll, + make_value_path_entry_handler, + check_value_path_entry_handler, + (Pointer) &e); + else +#endif + root = extractJsQuery(PG_GETARG_JSQUERY(0), + optAll, + make_value_path_entry_handler, + check_value_path_entry_handler, + (Pointer)&e); + if (root) { *nentries = e.count; @@ -851,6 +950,8 @@ gin_consistent_jsonb_value_path(PG_FUNCTION_ARGS) break; case JsQueryMatchStrategyNumber: + case JsonpathExistsStrategyNumber: + case JsonpathMatchStrategyNumber: if (nkeys == 0) res = true; else @@ -912,6 +1013,8 @@ gin_triconsistent_jsonb_value_path(PG_FUNCTION_ARGS) break; case JsQueryMatchStrategyNumber: + case JsonpathExistsStrategyNumber: + case JsonpathMatchStrategyNumber: if (nkeys == 0) res = GIN_MAYBE; else @@ -931,14 +1034,14 @@ gin_triconsistent_jsonb_value_path(PG_FUNCTION_ARGS) } static bool -get_query_path_hash(PathItem *pathItem, uint32 *hash) +get_query_path_hash(PathItem *pathItem, uint32 *hash, bool lax) { check_stack_depth(); if (!pathItem) return true; - if (!get_query_path_hash(pathItem->parent, hash)) + if (!get_query_path_hash(pathItem->parent, hash, lax)) { return false; } @@ -955,7 +1058,7 @@ get_query_path_hash(PathItem *pathItem, uint32 *hash) *hash = (*hash << 1) | (*hash >> 31); *hash ^= hash_any((unsigned char *)pathItem->s, pathItem->len); } - else if (pathItem->type == iAnyArray || pathItem->type == iIndexArray) + else if (!lax && (pathItem->type == iAnyArray || pathItem->type == iIndexArray)) { *hash = (*hash << 1) | (*hash >> 31); *hash ^= JB_FARRAY; @@ -968,9 +1071,10 @@ get_query_path_hash(PathItem *pathItem, uint32 *hash) static bool check_path_value_entry_handler(ExtractedNode *node, Pointer extra) { + PathValueExtra *pvextra = (PathValueExtra *) extra; uint32 hash; hash = 0; - if (!get_query_path_hash(node->path, &hash)) + if (!get_query_path_hash(node->path, &hash, pvextra->lax)) return false; return true; } @@ -978,7 +1082,8 @@ check_path_value_entry_handler(ExtractedNode *node, Pointer extra) static int make_path_value_entry_handler(ExtractedNode *node, Pointer extra) { - Entries *e = (Entries *)extra; + PathValueExtra *pvextra = (PathValueExtra *) extra; + Entries *e = pvextra->entries; uint32 hash; GINKey *key; KeyExtra *keyExtra; @@ -988,7 +1093,7 @@ make_path_value_entry_handler(ExtractedNode *node, Pointer extra) Assert(!isLogicalNodeType(node->type)); hash = 0; - if (!get_query_path_hash(node->path, &hash)) + if (!get_query_path_hash(node->path, &hash, pvextra->lax)) return -1; keyExtra = (KeyExtra *)palloc(sizeof(KeyExtra)); @@ -1032,7 +1137,9 @@ gin_compare_partial_jsonb_path_value(PG_FUNCTION_ARGS) { result = (key->hash > partial_key->hash) ? 1 : -1; } - else if (strategy == JsQueryMatchStrategyNumber) + else if (strategy == JsQueryMatchStrategyNumber || + strategy == JsonpathExistsStrategyNumber || + strategy == JsonpathMatchStrategyNumber) { KeyExtra *extra = (KeyExtra *)PG_GETARG_POINTER(3); ExtractedNode *node = extra->node; @@ -1081,7 +1188,7 @@ gin_compare_partial_jsonb_path_value(PG_FUNCTION_ARGS) } static Datum * -gin_extract_jsonb_path_value_internal(Jsonb *jb, int32 *nentries) +gin_extract_jsonb_path_value_internal(Jsonb *jb, int32 *nentries, bool lax) { int total = 2 * JB_ROOT_COUNT(jb); JsonbIterator *it; @@ -1093,10 +1200,7 @@ gin_extract_jsonb_path_value_internal(Jsonb *jb, int32 *nentries) Datum *entries = NULL; if (total == 0) - { - *nentries = 0; - return NULL; - } + total = 2; /* single entry for empty object/array */ entries = (Datum *) palloc(sizeof(Datum) * total); @@ -1125,6 +1229,8 @@ gin_extract_jsonb_path_value_internal(Jsonb *jb, int32 *nentries) if (v.val.array.rawScalar) break; entries[i++] = PointerGetDatum(make_gin_key(&v, stack->hash)); + if (lax) + break; tmp = stack; stack = (PathHashStack *) palloc(sizeof(PathHashStack)); stack->parent = tmp; @@ -1152,7 +1258,7 @@ gin_extract_jsonb_path_value_internal(Jsonb *jb, int32 *nentries) entries[i++] = PointerGetDatum(make_gin_key(&v, stack->hash)); break; case WJB_END_ARRAY: - if (!stack->parent) + if (!stack->parent || lax) break; /* raw scalar array */ /* fall through */ case WJB_END_OBJECT: @@ -1177,25 +1283,76 @@ gin_extract_jsonb_path_value(PG_FUNCTION_ARGS) Jsonb *jb = PG_GETARG_JSONB_P(0); int32 *nentries = (int32 *) PG_GETARG_POINTER(1); - PG_RETURN_POINTER(gin_extract_jsonb_path_value_internal(jb, nentries)); + PG_RETURN_POINTER(gin_extract_jsonb_path_value_internal(jb, nentries, false)); +} + +Datum +gin_extract_jsonb_laxpath_value(PG_FUNCTION_ARGS) +{ + Jsonb *jb = PG_GETARG_JSONB_P(0); + int32 *nentries = (int32 *) PG_GETARG_POINTER(1); + + PG_RETURN_POINTER(gin_extract_jsonb_path_value_internal(jb, nentries, true)); +} + +static Datum +gin_debug_query_path_value_internal(FunctionCallInfo fcinfo, bool lax) +{ + Entries e = {0}; + PathValueExtra extra; + + extra.entries = &e; + extra.lax = lax; + + PG_RETURN_TEXT_P(gin_debug_query_internal(fcinfo, + make_path_value_entry_handler, + check_path_value_entry_handler, + (Pointer) &extra)); } Datum gin_debug_query_path_value(PG_FUNCTION_ARGS) { - JsQuery *jq; + PG_RETURN_DATUM(gin_debug_query_path_value_internal(fcinfo, false)); +} + +Datum +gin_debug_query_laxpath_value(PG_FUNCTION_ARGS) +{ + PG_RETURN_DATUM(gin_debug_query_path_value_internal(fcinfo, true)); +} + +#ifndef NO_JSONPATH +static text * +gin_debug_jsonpath_path_value_internal(FunctionCallInfo fcinfo, bool lax) +{ Entries e = {0}; - char *s; + PathValueExtra extra; + extra.entries = &e; + extra.lax = lax; - jq = PG_GETARG_JSQUERY(0); - s = debugJsQuery(jq, make_path_value_entry_handler, - check_path_value_entry_handler, (Pointer)&e); - PG_RETURN_TEXT_P(cstring_to_text(s)); + return gin_debug_jsonpath_internal(fcinfo, !lax, + make_path_value_entry_handler, + check_path_value_entry_handler, + (Pointer) &extra); } Datum -gin_extract_jsonb_query_path_value(PG_FUNCTION_ARGS) +gin_debug_jsonpath_path_value(PG_FUNCTION_ARGS) +{ + PG_RETURN_TEXT_P(gin_debug_jsonpath_path_value_internal(fcinfo, false)); +} + +Datum +gin_debug_jsonpath_laxpath_value(PG_FUNCTION_ARGS) +{ + PG_RETURN_TEXT_P(gin_debug_jsonpath_path_value_internal(fcinfo, true)); +} +#endif + +static Datum +gin_extract_jsonb_query_path_value_internal(FunctionCallInfo fcinfo, bool lax) { Jsonb *jb; int32 *nentries = (int32 *) PG_GETARG_POINTER(1); @@ -1206,20 +1363,39 @@ gin_extract_jsonb_query_path_value(PG_FUNCTION_ARGS) Datum *entries = NULL; int i; Entries e = {0}; - JsQuery *jq; + PathValueExtra extra; ExtractedNode *root; + extra.entries = &e; + extra.lax = lax; + switch(strategy) { case JsonbContainsStrategyNumber: jb = PG_GETARG_JSONB_P(0); - entries = gin_extract_jsonb_path_value_internal(jb, nentries); + entries = gin_extract_jsonb_path_value_internal(jb, nentries, lax); break; case JsQueryMatchStrategyNumber: - jq = PG_GETARG_JSQUERY(0); - root = extractJsQuery(jq, make_path_value_entry_handler, - check_path_value_entry_handler, (Pointer)&e); +#ifndef NO_JSONPATH + case JsonpathExistsStrategyNumber: + case JsonpathMatchStrategyNumber: + if (strategy != JsQueryMatchStrategyNumber) + root = extractJsonPathQuery(PG_GETARG_JSONPATH_P(0), + strategy == JsonpathExistsStrategyNumber, + !lax, + optAll, + make_path_value_entry_handler, + check_path_value_entry_handler, + (Pointer) &extra); + else +#endif + root = extractJsQuery(PG_GETARG_JSQUERY(0), + optAll, + make_path_value_entry_handler, + check_path_value_entry_handler, + (Pointer) &extra); + if (root) { *nentries = e.count; @@ -1248,6 +1424,18 @@ gin_extract_jsonb_query_path_value(PG_FUNCTION_ARGS) PG_RETURN_POINTER(entries); } +Datum +gin_extract_jsonb_query_path_value(PG_FUNCTION_ARGS) +{ + return gin_extract_jsonb_query_path_value_internal(fcinfo, false); +} + +Datum +gin_extract_jsonb_query_laxpath_value(PG_FUNCTION_ARGS) +{ + return gin_extract_jsonb_query_path_value_internal(fcinfo, true); +} + Datum gin_consistent_jsonb_path_value(PG_FUNCTION_ARGS) { @@ -1275,6 +1463,8 @@ gin_consistent_jsonb_path_value(PG_FUNCTION_ARGS) break; case JsQueryMatchStrategyNumber: + case JsonpathExistsStrategyNumber: + case JsonpathMatchStrategyNumber: if (nkeys == 0) res = true; else @@ -1336,6 +1526,8 @@ gin_triconsistent_jsonb_path_value(PG_FUNCTION_ARGS) break; case JsQueryMatchStrategyNumber: + case JsonpathExistsStrategyNumber: + case JsonpathMatchStrategyNumber: if (nkeys == 0) res = GIN_MAYBE; else diff --git a/jsquery--1.1.sql b/jsquery--1.1.sql index d10076a..fcd9c30 100644 --- a/jsquery--1.1.sql +++ b/jsquery--1.1.sql @@ -293,12 +293,84 @@ CREATE OPERATOR CLASS jsonb_path_value_ops FUNCTION 6 gin_triconsistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal), STORAGE bytea; -CREATE OR REPLACE FUNCTION gin_debug_query_value_path(jsquery) +CREATE OR REPLACE FUNCTION gin_extract_jsonb_laxpath_value(internal, internal, internal) + RETURNS internal + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_extract_jsonb_query_laxpath_value(anyarray, internal, smallint, internal, internal, internal, internal) + RETURNS internal + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +CREATE OPERATOR CLASS jsonb_laxpath_value_ops + FOR TYPE jsonb USING gin AS + OPERATOR 7 @>, + OPERATOR 14 @@ (jsonb, jsquery), + FUNCTION 1 gin_compare_jsonb_path_value(bytea, bytea), + FUNCTION 2 gin_extract_jsonb_laxpath_value(internal, internal, internal), + FUNCTION 3 gin_extract_jsonb_query_laxpath_value(anyarray, internal, smallint, internal, internal, internal, internal), + FUNCTION 4 gin_consistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal, internal), + FUNCTION 5 gin_compare_partial_jsonb_path_value(bytea, bytea, smallint, internal), + FUNCTION 6 gin_triconsistent_jsonb_path_value(internal, smallint, anyarray, integer, internal, internal, internal), + STORAGE bytea; + +CREATE OR REPLACE FUNCTION gin_debug_query_value_path(jsquery, flatten bool = true, simplify bool = true, selectivity bool = true) RETURNS text AS 'MODULE_PATHNAME' LANGUAGE C STRICT IMMUTABLE; -CREATE OR REPLACE FUNCTION gin_debug_query_path_value(jsquery) +CREATE OR REPLACE FUNCTION gin_debug_query_path_value(jsquery, flatten bool = true, simplify bool = true, selectivity bool = true) RETURNS text AS 'MODULE_PATHNAME' LANGUAGE C STRICT IMMUTABLE; + +CREATE OR REPLACE FUNCTION gin_debug_query_laxpath_value(jsquery, flatten bool = true, simplify bool = true, selectivity bool = true) + RETURNS text + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + +-- add support for operators @?, @@ (jsonb, jsonpath) if type jsonpath exists in catalog +DO LANGUAGE plpgsql +$$ +BEGIN + PERFORM + FROM + pg_type t, + pg_namespace ns + WHERE + t.typname = 'jsonpath' AND + t.typnamespace = ns.oid AND + ns.nspname = 'pg_catalog'; + + IF FOUND THEN + ALTER OPERATOR FAMILY jsonb_path_value_ops USING gin + ADD OPERATOR 15 @? (jsonb, jsonpath); + ALTER OPERATOR FAMILY jsonb_path_value_ops USING gin + ADD OPERATOR 16 @@ (jsonb, jsonpath); + ALTER OPERATOR FAMILY jsonb_laxpath_value_ops USING gin + ADD OPERATOR 15 @? (jsonb, jsonpath); + ALTER OPERATOR FAMILY jsonb_laxpath_value_ops USING gin + ADD OPERATOR 16 @@ (jsonb, jsonpath); + ALTER OPERATOR FAMILY jsonb_value_path_ops USING gin + ADD OPERATOR 15 @? (jsonb, jsonpath); + ALTER OPERATOR FAMILY jsonb_value_path_ops USING gin + ADD OPERATOR 16 @@ (jsonb, jsonpath); + + CREATE OR REPLACE FUNCTION gin_debug_jsonpath_value_path(jsonpath, is_exists bool = false, flatten bool = true, simplify bool = true, selectivity bool = true) + RETURNS text + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + + CREATE OR REPLACE FUNCTION gin_debug_jsonpath_path_value(jsonpath, is_exists bool = false, flatten bool = true, simplify bool = true, selectivity bool = true) + RETURNS text + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + + CREATE OR REPLACE FUNCTION gin_debug_jsonpath_laxpath_value(jsonpath, is_exists bool = false, flatten bool = true, simplify bool = true, selectivity bool = true) + RETURNS text + AS 'MODULE_PATHNAME' + LANGUAGE C STRICT IMMUTABLE; + END IF; +END +$$; diff --git a/jsquery.h b/jsquery.h index 9563944..0a6a955 100644 --- a/jsquery.h +++ b/jsquery.h @@ -19,6 +19,7 @@ #include "fmgr.h" #include "utils/numeric.h" #include "utils/jsonb.h" +#include "utils/jsonpath.h" typedef struct { @@ -241,10 +242,23 @@ typedef int (*MakeEntryHandler)(ExtractedNode *node, Pointer extra); typedef bool (*CheckEntryHandler)(ExtractedNode *node, Pointer extra); bool isLogicalNodeType(ExtractedNodeType type); -ExtractedNode *extractJsQuery(JsQuery *jq, MakeEntryHandler makeHandler, - CheckEntryHandler checkHandler, Pointer extra); -char *debugJsQuery(JsQuery *jq, MakeEntryHandler makeHandler, +typedef enum +{ + optFlatten = 0x01, + optSimplify = 0x02, + optSelectivity = 0x04, + optAll = 0x07 +} JsQueryOptFlags; + +ExtractedNode *extractJsQuery(JsQuery *jq, int optimize, + MakeEntryHandler makeHandler, CheckEntryHandler checkHandler, Pointer extra); +#ifndef NO_JSONPATH +ExtractedNode *extractJsonPathQuery(JsonPath *jp, bool exists, bool arrayPathItems, + int optimize, MakeEntryHandler makeHandler, + CheckEntryHandler checkHandler, Pointer extra); +#endif +char *debugExtractedQuery(ExtractedNode *root); bool queryNeedRecheck(ExtractedNode *node); bool execRecursive(ExtractedNode *node, bool *check); bool execRecursiveTristate(ExtractedNode *node, GinTernaryValue *check); diff --git a/jsquery_extract.c b/jsquery_extract.c index 1b61267..6194268 100644 --- a/jsquery_extract.c +++ b/jsquery_extract.c @@ -17,12 +17,16 @@ #include "access/gin.h" #include "utils/builtins.h" #include "utils/jsonb.h" +#include "utils/jsonpath.h" #include "miscadmin.h" #include "jsquery.h" static ExtractedNode *recursiveExtract(JsQueryItem *jsq, bool not, bool indirect, PathItem *path); static ExtractedNode *makeAnyNode(bool not, bool indirect, PathItem *path); +static ExtractedNode *makeBinaryNode(ExtractedNodeType type, PathItem *path, + bool indirect, ExtractedNode *leftNode, ExtractedNode *rightNode); +static ExtractedNode *makeEmptyArrayNode(PathItem *path, JsQueryHint hint); static int coundChildren(ExtractedNode *node, ExtractedNodeType type, bool first, bool *found); static void fillChildren(ExtractedNode *node, ExtractedNodeType type, bool first, ExtractedNode **items, int *i); static void flatternTree(ExtractedNode *node); @@ -32,7 +36,7 @@ static int compareJsQueryItem(JsQueryItem *v1, JsQueryItem *v2); static void processGroup(ExtractedNode *node, int start, int end); static void simplifyRecursive(ExtractedNode *node); static SelectivityClass getScalarSelectivityClass(ExtractedNode *node); -static ExtractedNode *makeEntries(ExtractedNode *node, MakeEntryHandler handler, Pointer extra); +static ExtractedNode *makeEntries(ExtractedNode *node, bool skipNonSelective, MakeEntryHandler handler, Pointer extra); static void setSelectivityClass(ExtractedNode *node, CheckEntryHandler checkHandler, Pointer extra); static void debugPath(StringInfo buf, PathItem *path); static void debugValue(StringInfo buf, JsQueryItem *v); @@ -92,15 +96,7 @@ recursiveExtract(JsQueryItem *jsq, bool not, bool indirect, PathItem *path) } } - result = (ExtractedNode *)palloc(sizeof(ExtractedNode)); - result->type = type; - result->path = path; - result->indirect = indirect; - result->args.items = (ExtractedNode **)palloc(2 * sizeof(ExtractedNode *)); - result->args.items[0] = leftNode; - result->args.items[1] = rightNode; - result->args.count = 2; - return result; + return makeBinaryNode(type, path, indirect, leftNode, rightNode); case jqiNot: jsqGetArg(jsq, &elem); return recursiveExtract(&elem, !not, indirect, path); @@ -114,6 +110,7 @@ recursiveExtract(JsQueryItem *jsq, bool not, bool indirect, PathItem *path) return recursiveExtract(&elem, not, indirect, pathItem); case jqiAny: case jqiAll: + /* 'NOT *: (predicate)' is equivalent to '*: (NOT predicate)' */ if ((not && jsq->type == jqiAny) || (!not && jsq->type == jqiAll)) return NULL; pathItem = (PathItem *)palloc(sizeof(PathItem)); @@ -130,9 +127,11 @@ recursiveExtract(JsQueryItem *jsq, bool not, bool indirect, PathItem *path) if (!jsqGetNext(jsq, &elem)) return makeAnyNode(not, indirect, pathItem); return recursiveExtract(&elem, not, true, pathItem); - case jqiAnyArray: case jqiAllArray: - if ((not && jsq->type == jqiAnyArray) || (!not && jsq->type == jqiAllArray)) + /* 'NOT #: (predicate)' is not equivalent to '#: (NOT predicate)' */ + return NULL; + case jqiAnyArray: + if (not) return NULL; pathItem = (PathItem *)palloc(sizeof(PathItem)); pathItem->type = iAnyArray; @@ -140,9 +139,11 @@ recursiveExtract(JsQueryItem *jsq, bool not, bool indirect, PathItem *path) if (!jsqGetNext(jsq, &elem)) return makeAnyNode(not, indirect, pathItem); return recursiveExtract(&elem, not, true, pathItem); - case jqiAnyKey: case jqiAllKey: - if ((not && jsq->type == jqiAnyKey) || (!not && jsq->type == jqiAllKey)) + /* 'NOT %: (predicate)' is not equivalent to '%: (NOT predicate)' */ + return NULL; + case jqiAnyKey: + if (not) return NULL; pathItem = (PathItem *)palloc(sizeof(PathItem)); pathItem->type = iAnyKey; @@ -208,13 +209,7 @@ recursiveExtract(JsQueryItem *jsq, bool not, bool indirect, PathItem *path) if (jsq->type == jqiContained || (jsq->type == jqiEqual && elem.array.nelems == 0)) { - ExtractedNode *item = (ExtractedNode *)palloc(sizeof(ExtractedNode)); - - item->hint = e.hint; - item->type = eEmptyArray; - item->path = pathItem->parent; - item->indirect = false; - item->hint = jsq->hint; + ExtractedNode *item = makeEmptyArrayNode(pathItem->parent, jsq->hint); /* XXX e.hint */ result->args.items[result->args.count] = item; result->args.count++; @@ -284,6 +279,508 @@ recursiveExtract(JsQueryItem *jsq, bool not, bool indirect, PathItem *path) return NULL; } +#ifndef NO_JSONPATH +static PathItem * +makePathItem(PathItemType type, PathItem *parent) +{ + PathItem *item = (PathItem *) palloc(sizeof(PathItem)); + + item->type = type; + item->parent = parent; + + return item; +} + +typedef struct ExtractedJsonPath +{ + PathItem *path; + List *filters; + bool indirect; + bool type; +} ExtractedJsonPath; + +typedef enum +{ + efLax = 0x01, + efArrays = 0x02, + efLaxWithArrays = efLax | efArrays +} JsonPathExtractionFlags; + +static ExtractedNode * +extractJsonPathExpr(JsonPathItem *jpi, int flags, bool not, bool indirect, + PathItem *path); + +static bool +extractJsonPathRec(JsonPathItem *jpi, + int flags, bool indirect, bool unwrap, bool preunwrap, + PathItem *parent, List **paths, List *filters) +{ + JsonPathItem next; + PathItem *path; + + check_stack_depth(); + + switch (jpi->type) + { + case jpiRoot: + Assert(!parent); + path = NULL; + indirect = parent != NULL; + break; + + case jpiCurrent: + path = parent; + indirect = false; + break; + + case jpiKey: + if (flags == efLaxWithArrays && preunwrap && + !extractJsonPathRec(jpi, flags, true, unwrap, false, + makePathItem(iAnyArray, parent), + paths, filters)) + return false; + + path = makePathItem(iKey, parent); + path->s = jspGetString(jpi, &path->len); + break; + + case jpiAny: + path = makePathItem(iAny, parent); + indirect = true; + break; + + case jpiAnyArray: + case jpiIndexArray: + if (flags == efLaxWithArrays) + { + /* try to skip [*] path item */ + JsonPathItem next; + + if (!jspGetNext(jpi, &next)) + { + ExtractedJsonPath *ejp = palloc(sizeof(*ejp)); + + ejp->path = parent; + ejp->filters = list_copy(filters); + ejp->indirect = indirect; + ejp->type = false; + + *paths = lappend(*paths, ejp); + } + else if (!extractJsonPathRec(&next, flags, indirect, unwrap, + false, parent, paths, filters)) + return false; + } + + indirect = true; +#if 0 + if (jpi->content.array.nelems == 1) + { + JsonPathItem from; + JsonPathItem to; + + if (!jspGetArraySubscript(jpi, &from, &to, 0) && + from->type == jpiNumeric) + { + path = makePathItem(iIndexArray, parent); + path->arrayIndex = -1; + break; + } + } +#endif + path = makePathItem(iAnyArray, parent); + break; + + case jpiAnyKey: + /* add implicit [*] path item in lax mode */ + if (flags == efLaxWithArrays && preunwrap && + !extractJsonPathRec(jpi, flags, true, unwrap, false, + makePathItem(iAnyArray, parent), + paths, filters)) + return false; + + path = makePathItem(iAnyKey, parent); + indirect = true; + break; + + case jpiFilter: + { + JsonPathItem arg; + ExtractedNode *expr; + + /* add implicit [*] path item in lax mode */ + if (flags == efLaxWithArrays && preunwrap && + !extractJsonPathRec(jpi, flags, true, unwrap, false, + makePathItem(iAnyArray, parent), + paths, filters)) + return false; + + jspGetArg(jpi, &arg); + expr = extractJsonPathExpr(&arg, flags, false, false, parent); + + if (expr) + filters = lappend(list_copy(filters), expr); + + path = parent; + break; + } + + default: + /* elog(ERROR,"Wrong state: %d", jpi->type); */ + return false; + } + + if (!jspGetNext(jpi, &next) || + (next.type == jpiType && !jspHasNext(&next))) + { + ExtractedJsonPath *ejp = palloc(sizeof(*ejp)); + + ejp->path = path; + ejp->filters = list_copy(filters); + ejp->indirect = flags == efLax ? path != NULL : indirect; + ejp->type = jspHasNext(jpi) && next.type == jpiType; + + *paths = lappend(*paths, ejp); + + if (flags == efLaxWithArrays && unwrap && + !(jspHasNext(jpi) && next.type == jpiType)) + { + ejp = palloc(sizeof(*ejp)); + + ejp->path = makePathItem(iAnyArray, path); + ejp->filters = list_copy(filters); + ejp->indirect = true; + ejp->type = false; + + *paths = lappend(*paths, ejp); + } + + return true; + } + + return extractJsonPathRec(&next, flags, indirect, unwrap, true, path, paths, filters); +} + +static List * +extractJsonPath(JsonPathItem *jpi, int flags, bool unwrap, PathItem *parent) +{ + List *paths = NIL; + + return extractJsonPathRec(jpi, flags, false, unwrap, false, parent, + &paths, NIL) ? paths : NIL; +} + +static inline JsQueryItem * +jspConstToJsQueryItem(JsonPathItem *jpi) +{ + JsQueryItem *jqi = palloc(sizeof(*jqi)); + + switch (jpi->type) + { + case jpiNull: + jqi->type = jqiNull; + break; + + case jpiBool: + jqi->type = jqiBool; + jqi->value.data = jpi->content.value.data; + break; + + case jpiNumeric: + jqi->type = jqiNumeric; + jqi->value.data = jpi->content.value.data; + break; + + case jpiString: + jqi->type = jqiString; + jqi->value.data = jpi->content.value.data; + jqi->value.datalen = jpi->content.value.datalen; + break; + + default: + elog(ERROR, "invalid JsonPathItem literal type: %d", jpi->type); + return NULL; + } + + return jqi; +} + +static ExtractedNode * +appendJsonPathExprNode(ExtractedNode *result, ExtractedNode *node, PathItem *path, + List *filters) +{ + ExtractedNode *orNode; + + if (filters) + { + ListCell *flc; + + foreach(flc, filters) + { + ExtractedNode *filter = lfirst(flc); + ExtractedNode *andNode = palloc(sizeof(ExtractedNode)); + + andNode->type = eAnd; + andNode->hint = jsqIndexDefault; + andNode->path = path; + andNode->indirect = false; + andNode->args.items = palloc(2 * sizeof(ExtractedNode *)); + andNode->args.items[0] = node; + andNode->args.items[1] = filter; + andNode->args.count = 2; + + node = andNode; + } + } + + if (!result) + return node; + + orNode = palloc(sizeof(ExtractedNode)); + + orNode->type = eOr; + orNode->hint = jsqIndexDefault; + orNode->path = path; + orNode->indirect = false; + orNode->args.items = palloc(2 * sizeof(ExtractedNode *)); + orNode->args.items[0] = result; + orNode->args.items[1] = node; + orNode->args.count = 2; + + return orNode; +} + +static ExtractedNode * +extractJsonPathExists(JsonPathItem *jpi, int flags, bool indirect, bool unwrap, + PathItem *path) +{ + List *paths; + ListCell *lc; + ExtractedNode *result; + + if (!(paths = extractJsonPath(jpi, flags, unwrap, path))) + return NULL; + + result = NULL; + + foreach(lc, paths) + { + ExtractedJsonPath *ejp = lfirst(lc); + ExtractedNode *node = makeAnyNode(false, ejp->indirect, ejp->path); + + result = appendJsonPathExprNode(result, node, path, ejp->filters); + } + + return result; +} + +static JsQueryItem * +extractJsonPathConst(JsonPathItem *jpi, bool equal) +{ + if (jpi->type == jpiNumeric || + (equal && + (jpi->type == jpiNull || + jpi->type == jpiBool || + jpi->type == jpiString))) + return jspConstToJsQueryItem(jpi); + + return NULL; +} + +static ExtractedNode * +extractJsonPathExpr(JsonPathItem *jpi, int flags, bool not, bool indirect, + PathItem *path) +{ + ExtractedNode *result; + JsonPathItem elem; + + check_stack_depth(); + + switch (jpi->type) + { + case jpiAnd: + case jpiOr: + { + ExtractedNode *leftNode; + ExtractedNode *rightNode; + ExtractedNodeType type; + + type = ((jpi->type == jpiAnd) == not) ? eOr : eAnd; + + jspGetLeftArg(jpi, &elem); + leftNode = extractJsonPathExpr(&elem, flags, not, indirect, path); + + jspGetRightArg(jpi, &elem); + rightNode = extractJsonPathExpr(&elem, flags, not, indirect, path); + + if (leftNode && rightNode) + return makeBinaryNode(type, path, indirect, leftNode, rightNode); + else if (type == eOr) + return NULL; + else if (leftNode) + { + leftNode->indirect |= indirect; + return leftNode; + } + else if (rightNode) + { + rightNode->indirect |= indirect; + return rightNode; + } + else + return NULL; + } + + case jpiNot: + jspGetArg(jpi, &elem); + return extractJsonPathExpr(&elem, flags, !not, indirect, path); + + case jpiEqual: + case jpiLess: + case jpiGreater: + case jpiLessOrEqual: + case jpiGreaterOrEqual: + { + bool equal = jpi->type == jpiEqual; + bool greater = jpi->type == jpiGreater || + jpi->type == jpiGreaterOrEqual; + bool inclusive = jpi->type == jpiLessOrEqual || + jpi->type == jpiGreaterOrEqual; + List *paths = NIL; + ListCell *lc; + JsQueryItem *bound; + JsonPathItem *patharg; + JsonPathItem larg; + JsonPathItem rarg; + + if (not) + return NULL; + + jspGetLeftArg(jpi, &larg); + jspGetRightArg(jpi, &rarg); + + if ((bound = extractJsonPathConst(&rarg, equal))) + { + patharg = &larg; + } + else if ((bound = extractJsonPathConst(&larg, equal))) + { + patharg = &rarg; + greater = !greater; + } + else + { + ExtractedNode *lnode; + ExtractedNode *rnode; + + lnode = extractJsonPathExists(&larg, flags, indirect, true, path); + rnode = extractJsonPathExists(&rarg, flags, indirect, true, path); + + if (lnode && rnode) + return makeBinaryNode(eAnd, path, indirect, lnode, rnode); + else if (lnode) + return lnode; + else + return rnode; + } + + if (!(paths = extractJsonPath(patharg, flags, true, path))) + return NULL; + + result = NULL; + + foreach(lc, paths) + { + ExtractedJsonPath *ejp = lfirst(lc); + ExtractedNode *node = palloc(sizeof(ExtractedNode)); + + node->hint = jsqIndexDefault; + node->path = ejp->path; + node->indirect = ejp->indirect; + + if (equal) + { + if (ejp->type) + { + if (bound->type != jqiString) + return NULL; /* FIXME always false */ + + node->type = eIs; + + if (!strncmp("null", bound->value.data, + bound->value.datalen)) + node->isType = jbvNull; + else if (!strncmp("boolean", bound->value.data, + bound->value.datalen)) + node->isType = jbvBool; + else if (!strncmp("number", bound->value.data, + bound->value.datalen)) + node->isType = jbvNumeric; + else if (!strncmp("string", bound->value.data, + bound->value.datalen)) + node->isType = jbvString; + else if (!strncmp("object", bound->value.data, + bound->value.datalen)) + node->isType = jbvObject; + else if (!strncmp("array", bound->value.data, + bound->value.datalen)) + node->isType = jbvArray; + else + return NULL; /* FIXME always false */ + } + else + { + node->type = eExactValue; + node->exactValue = bound; + } + } + else + { + if (ejp->type) + return NULL; + + node->type = eInequality; + + if (greater) + { + node->bounds.leftInclusive = inclusive; + node->bounds.rightBound = NULL; + node->bounds.leftBound = bound; + } + else + { + node->bounds.rightInclusive = inclusive; + node->bounds.leftBound = NULL; + node->bounds.rightBound = bound; + } + } + + result = appendJsonPathExprNode(result, node, path, + ejp->filters); + } + + return result; + } + + case jpiExists: + { + if (not) + return NULL; + + jspGetArg(jpi, &elem); + + return extractJsonPathExists(&elem, flags, indirect, false, path); + } + + default: + /* elog(ERROR,"Wrong state: %d", jpi->type); */ + return NULL; + } + + return NULL; +} +#endif + /* * Make node for checking existence of path. */ @@ -303,6 +800,36 @@ makeAnyNode(bool not, bool indirect, PathItem *path) return result; } +static ExtractedNode * +makeBinaryNode(ExtractedNodeType type, PathItem *path, bool indirect, + ExtractedNode *leftNode, ExtractedNode *rightNode) +{ + ExtractedNode *result = (ExtractedNode *) palloc(sizeof(ExtractedNode)); + + result->type = type; + result->path = path; + result->indirect = indirect; + result->args.items = (ExtractedNode **)palloc(2 * sizeof(ExtractedNode *)); + result->args.items[0] = leftNode; + result->args.items[1] = rightNode; + result->args.count = 2; + + return result; +} + +static ExtractedNode * +makeEmptyArrayNode(PathItem *path, JsQueryHint hint) +{ + ExtractedNode *result = (ExtractedNode *) palloc(sizeof(ExtractedNode)); + + result->type = eEmptyArray; + result->path = path; + result->indirect = false; + result->hint = hint; + + return result; +} + /* * Count number of children connected with nodes of same type. */ @@ -692,7 +1219,8 @@ getScalarSelectivityClass(ExtractedNode *node) * Make entries for all leaf tree nodes using user-provided handler. */ static ExtractedNode * -makeEntries(ExtractedNode *node, MakeEntryHandler handler, Pointer extra) +makeEntries(ExtractedNode *node, bool skipNonSelective, + MakeEntryHandler handler, Pointer extra) { if (node->type == eAnd || node->type == eOr) { @@ -704,11 +1232,12 @@ makeEntries(ExtractedNode *node, MakeEntryHandler handler, Pointer extra) if (!child) continue; /* Skip non-selective AND children */ - if (child->sClass > node->sClass && + if (skipNonSelective && + child->sClass > node->sClass && node->type == eAnd && !child->forceIndex) continue; - child = makeEntries(child, handler, extra); + child = makeEntries(child, skipNonSelective, handler, extra); if (child) { node->args.items[j] = child; @@ -807,27 +1336,64 @@ setSelectivityClass(ExtractedNode *node, CheckEntryHandler checkHandler, } } +static ExtractedNode * +emitExtractedQuery(ExtractedNode *root, int optimize, + MakeEntryHandler makeHandler, + CheckEntryHandler checkHandler, + Pointer extra) +{ + if (!root) + return NULL; + + if (optimize & optFlatten) + flatternTree(root); + + if (optimize & optSimplify) + simplifyRecursive(root); + + setSelectivityClass(root, checkHandler, extra); + + return makeEntries(root, (optimize & optSelectivity) != 0, makeHandler, extra); +} + /* * Turn jsquery into tree of entries using user-provided handler. */ ExtractedNode * -extractJsQuery(JsQuery *jq, MakeEntryHandler makeHandler, - CheckEntryHandler checkHandler, Pointer extra) +extractJsQuery(JsQuery *jq, int optimize, MakeEntryHandler makeHandler, + CheckEntryHandler checkHandler, Pointer extra) { ExtractedNode *root; JsQueryItem jsq; jsqInit(&jsq, jq); root = recursiveExtract(&jsq, false, false, NULL); - if (root) - { - flatternTree(root); - simplifyRecursive(root); - setSelectivityClass(root, checkHandler, extra); - root = makeEntries(root, makeHandler, extra); - } - return root; + + return emitExtractedQuery(root, optimize, makeHandler, checkHandler, extra); +} + +#ifndef NO_JSONPATH +/* + * Turn jsonpath into tree of entries using user-provided handler. + */ +ExtractedNode * +extractJsonPathQuery(JsonPath *jp, bool exists, bool arrayPathItems, int optimize, + MakeEntryHandler makeHandler, + CheckEntryHandler checkHandler, Pointer extra) +{ + ExtractedNode *root; + JsonPathItem jsp; + bool lax = (jp->header & JSONPATH_LAX) != 0; + int flags = (lax ? efLax : 0) | (arrayPathItems ? efArrays : 0); + + jspInit(&jsp, jp); + root = exists + ? extractJsonPathExists(&jsp, flags, false, false, NULL) + : extractJsonPathExpr(&jsp, flags, false, false, NULL); + + return emitExtractedQuery(root, optimize, makeHandler, checkHandler, extra); } +#endif /* * Evaluate previously extracted tree. @@ -1051,13 +1617,10 @@ debugRecursive(StringInfo buf, ExtractedNode *node, int shift) * Debug print of query processing. */ char * -debugJsQuery(JsQuery *jq, MakeEntryHandler makeHandler, - CheckEntryHandler checkHandler, Pointer extra) +debugExtractedQuery(ExtractedNode *root) { - ExtractedNode *root; StringInfoData buf; - root = extractJsQuery(jq, makeHandler, checkHandler, extra); if (!root) return "NULL\n"; diff --git a/jsquery_gram.y b/jsquery_gram.y index 2d6d531..3943abb 100644 --- a/jsquery_gram.y +++ b/jsquery_gram.y @@ -255,6 +255,7 @@ result: array: '[' value_list ']' { $$ = makeItemArray($2); } + | '[' ']' { $$ = makeItemArray(NIL); } ; scalar_value: diff --git a/jsquery_op.c b/jsquery_op.c index e848421..3ecf3fd 100644 --- a/jsquery_op.c +++ b/jsquery_op.c @@ -29,6 +29,10 @@ #include "jsquery.h" +#ifdef PG_GETARG_JSONB_P +#define PG_GETARG_JSONB PG_GETARG_JSONB_P +#endif + typedef struct ResultAccum { StringInfo buf; bool missAppend; @@ -600,7 +604,9 @@ recursiveExecute(JsQueryItem *jsq, JsonbValue *jb, JsQueryItem *jsqLeftArg, if (hasNext == false) { - res = true; + if (jsq->type == jqiAllArray || + JsonContainerSize(jb->val.binary.data) > 0) + res = true; while(ra && (r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE) if (r == WJB_ELEM) diff --git a/jsquery_support.c b/jsquery_support.c index 08a805d..278e561 100644 --- a/jsquery_support.c +++ b/jsquery_support.c @@ -209,7 +209,7 @@ jsqGetNumeric(JsQueryItem *v) int32 jsqGetIsType(JsQueryItem *v) { - Assert(v->type = jqiIs); + Assert(v->type == jqiIs); return (int32)*v->value.data; } diff --git a/sql/jsquery.sql b/sql/jsquery.sql index fb501b6..2c14d72 100644 --- a/sql/jsquery.sql +++ b/sql/jsquery.sql @@ -105,74 +105,74 @@ select 'is.not < 1'::jsquery; select 'a.b.#4 > 4'::jsquery; select 'a.b.#10203.* > 4'::jsquery; -select '{"a": {"b": null}}'::jsonb @@ 'a.b = 1'; -select '{"a": {"b": null}}'::jsonb @@ 'a.b = null'; -select '{"a": {"b": null}}'::jsonb @@ 'a.b = false'; -select '{"a": {"b": false}}'::jsonb @@ 'a.b = false'; -select '{"a": {"b": false}}'::jsonb @@ 'a.b = true'; -select '{"a": {"b": true}}'::jsonb @@ 'a.b = true'; - - -select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 1'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 1'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 1'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 1'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 1'; - -select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 2'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 2'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 2'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 2'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 2'; - -select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 0'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 0'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 0'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 0'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 0'; - -select '{"a": {"b": 1}}'::jsonb @@ '*.b > 0'; -select '{"a": {"b": 1}}'::jsonb @@ '*.b > 0'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.* > 0'; -select '{"a": {"b": 1}}'::jsonb @@ 'a.* > 0'; - -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 1 ]'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b @> [ 1 ]'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b <@ [ 1 ]'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b @> [ 1,2,3,4 ]'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b <@ [ 1,2,3,4 ]'; - -select '[{"a": 2}, {"a": 3}]'::jsonb @@ '*.a = 4'; -select '[{"a": 2}, {"a": 3}]'::jsonb @@ '*.a = 3'; - -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.a = 4'; -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.a = 4'; - -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 1 OR a=3)'; -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 OR a=1)'; -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 and a=1)'; -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 and a=2)' as "false"; -select '[{"a": 2, "b":3}, {"a": 3, "b": 1}]'::jsonb @@ '#(b = 1 and a=3)'; - -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.a.a = 4'; -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.a.a = 4'; -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.#.a.a = 4'; -select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.*.a.a = 4'; - -select '{"a": 1}'::jsonb @@ 'a in (0,1,2)'; -select '{"a": 1}'::jsonb @@ 'a in (0,2)'; - -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#=2'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 5 ]'; - -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a=*'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b=*'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.c=*'; - -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b = [1,2,3]'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.# = [1,2,3]'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b && [1,2,3]'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.# && [1,2,3]'; +select '{"a": {"b": null}}'::jsonb @@ 'a.b = 1'::jsquery; +select '{"a": {"b": null}}'::jsonb @@ 'a.b = null'::jsquery; +select '{"a": {"b": null}}'::jsonb @@ 'a.b = false'::jsquery; +select '{"a": {"b": false}}'::jsonb @@ 'a.b = false'::jsquery; +select '{"a": {"b": false}}'::jsonb @@ 'a.b = true'::jsquery; +select '{"a": {"b": true}}'::jsonb @@ 'a.b = true'::jsquery; + + +select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 1'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 1'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 1'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 1'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 1'::jsquery; + +select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 2'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 2'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 2'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 2'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 2'::jsquery; + +select '{"a": {"b": 1}}'::jsonb @@ 'a.b = 0'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b < 0'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b <= 0'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b >= 0'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.b > 0'::jsquery; + +select '{"a": {"b": 1}}'::jsonb @@ '*.b > 0'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ '*.b > 0'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.* > 0'::jsquery; +select '{"a": {"b": 1}}'::jsonb @@ 'a.* > 0'::jsquery; + +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 1 ]'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b @> [ 1 ]'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b <@ [ 1 ]'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b @> [ 1,2,3,4 ]'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b <@ [ 1,2,3,4 ]'::jsquery; + +select '[{"a": 2}, {"a": 3}]'::jsonb @@ '*.a = 4'::jsquery; +select '[{"a": 2}, {"a": 3}]'::jsonb @@ '*.a = 3'::jsquery; + +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.a = 4'::jsquery; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.a = 4'::jsquery; + +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 1 OR a=3)'::jsquery; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 OR a=1)'::jsquery; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 and a=1)'::jsquery; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#(a = 3 and a=2)'::jsquery as "false"; +select '[{"a": 2, "b":3}, {"a": 3, "b": 1}]'::jsonb @@ '#(b = 1 and a=3)'::jsquery; + +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.a.a = 4'::jsquery; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.a.a = 4'::jsquery; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '*.#.a.a = 4'::jsquery; +select '[{"a": 2}, {"a": 3}, {"a": {"a":4}}]'::jsonb @@ '#.*.a.a = 4'::jsquery; + +select '{"a": 1}'::jsonb @@ 'a in (0,1,2)'::jsquery; +select '{"a": 1}'::jsonb @@ 'a in (0,2)'::jsquery; + +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#=2'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 5 ]'::jsquery; + +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a=*'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b=*'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.c=*'::jsquery; + +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b = [1,2,3]'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.# = [1,2,3]'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b && [1,2,3]'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.# && [1,2,3]'::jsquery; select 'asd.# = 3'::jsquery & 'zzz = true' | 'xxx.# = zero'; select !'asd.# = 3'::jsquery & 'zzz = true' | !'xxx.# = zero'; @@ -182,47 +182,47 @@ select '{"x":[0,1,1,2]}'::jsonb @@ 'x @> [1,0]'::jsquery; select '{"x":[0,1,1,2]}'::jsonb @@ 'x @> [1,0,1]'::jsquery; select '{"x":[0,1,1,2]}'::jsonb @@ 'x @> [1,0,3]'::jsquery; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 2 ]'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b($ && [ 2 ])'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.$.b && [ 2 ]'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.$.b ($ && [ 2 ])'; - -select '[1,2,3]'::jsonb @@ '# && [2]'; -select '[1,2,3]'::jsonb @@ '#($ && [2])'; -select '[1,2,3]'::jsonb @@ '$ && [2]'; -select '[1,2,3]'::jsonb @@ '$ ($ && [2])'; -select '[1,2,3]'::jsonb @@ '$ = 2'; -select '[1,2,3]'::jsonb @@ '# = 2'; -select '[1,2,3]'::jsonb @@ '#.$ = 2'; -select '[1,2,3]'::jsonb @@ '#($ = 2)'; - -select '[3,4]'::jsonb @@ '#($ > 2 and $ < 5)'; -select '[3,4]'::jsonb @@ '# > 2 and # < 5'; -select '[1,6]'::jsonb @@ '#($ > 2 and $ < 5)'; -select '[1,6]'::jsonb @@ '# > 2 and # < 5'; - -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%.b=3'; -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ 'a.%=3'; -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%.%="hey"'; -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%="hey"'; -select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%=[5,6]'; - -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#1 = 2'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#2 = 2'; -select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#3 = 2'; -select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#1.x = 2'; -select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#2.x = 2'; -select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#3.x = 2'; - -select '"XXX"'::jsonb @@ '$="XXX"'; -select '"XXX"'::jsonb @@ '#.$="XXX"'; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b && [ 2 ]'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ '*.b($ && [ 2 ])'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.$.b && [ 2 ]'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.$.b ($ && [ 2 ])'::jsquery; + +select '[1,2,3]'::jsonb @@ '# && [2]'::jsquery; +select '[1,2,3]'::jsonb @@ '#($ && [2])'::jsquery; +select '[1,2,3]'::jsonb @@ '$ && [2]'::jsquery; +select '[1,2,3]'::jsonb @@ '$ ($ && [2])'::jsquery; +select '[1,2,3]'::jsonb @@ '$ = 2'::jsquery; +select '[1,2,3]'::jsonb @@ '# = 2'::jsquery; +select '[1,2,3]'::jsonb @@ '#.$ = 2'::jsquery; +select '[1,2,3]'::jsonb @@ '#($ = 2)'::jsquery; + +select '[3,4]'::jsonb @@ '#($ > 2 and $ < 5)'::jsquery; +select '[3,4]'::jsonb @@ '# > 2 and # < 5'::jsquery; +select '[1,6]'::jsonb @@ '#($ > 2 and $ < 5)'::jsquery; +select '[1,6]'::jsonb @@ '# > 2 and # < 5'::jsquery; + +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%.b=3'::jsquery; +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ 'a.%=3'::jsquery; +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%.%="hey"'::jsquery; +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%="hey"'::jsquery; +select '{"a": {"b": 3, "c": "hey"}, "x": [5,6]}'::jsonb @@ '%=[5,6]'::jsquery; + +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#1 = 2'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#2 = 2'::jsquery; +select '{"a": {"b": [1,2,3]}}'::jsonb @@ 'a.b.#3 = 2'::jsquery; +select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#1.x = 2'::jsquery; +select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#2.x = 2'::jsquery; +select '{"a": {"b": [{"x":1},{"x":2},{"x":3}]}}'::jsonb @@ 'a.b.#3.x = 2'::jsquery; + +select '"XXX"'::jsonb @@ '$="XXX"'::jsquery; +select '"XXX"'::jsonb @@ '#.$="XXX"'::jsquery; --Unicode select 'a\t = "dollar \u0024 character"'::jsquery; -select '{ "a": "dollar \u0024 character" }'::jsonb @@ '* = "dollar \u0024 character"'; -select '{ "a": "dollar \u0024 character" }'::jsonb @@ '* = "dollar $ character"'; -select '{ "a": "dollar $ character" }'::jsonb @@ '* = "dollar \u0024 character"'; +select '{ "a": "dollar \u0024 character" }'::jsonb @@ '* = "dollar \u0024 character"'::jsquery; +select '{ "a": "dollar \u0024 character" }'::jsonb @@ '* = "dollar $ character"'::jsquery; +select '{ "a": "dollar $ character" }'::jsonb @@ '* = "dollar \u0024 character"'::jsquery; select 'a\r = "\n\""'::jsquery; select 'a\r = "\u0000"'::jsquery; select 'a\r = \u0000'::jsquery; @@ -301,11 +301,11 @@ select '?( not b>0). x'::jsquery; select 'a.?(b>0 and x= 0 ) .c'::jsquery; select 'a.$. ?(b>0 and x= 0 ) . c.k'::jsquery; select 'a.$.? (b>0 and x.*= 0 ).c.k'::jsquery; -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a < 0) (b=20)'; -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 0) (b=20)'; -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 1) (b=20)'; -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 2) (b=20)'; -select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 3) (b=20)'; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a < 0) (b=20)'::jsquery; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 0) (b=20)'::jsquery; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 1) (b=20)'::jsquery; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 2) (b=20)'::jsquery; +select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb @@ '#. ?(a > 3) (b=20)'::jsquery; select '[{"a":1, "b":10}, {"a":2, "b":20}]'::jsonb ~~ '#.a'; select '[{"a":1, "b":10}, {"a":2, "b":20}]'::jsonb ~~ '#. ?(a > 1). b'; select '[{"a":1, "b":10}, {"a":2, "b":20}, {"a":3, "b":30}]'::jsonb ~~ '# . ?(a > 1)'; @@ -369,14 +369,14 @@ SELECT 'test.# IN (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,2 select '[]' @@ '(@# > 0 and #: = 16)'::jsquery; select '[16]' @@ '(@# > 0 and #: = 16)'::jsquery; -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.b or b.d'; -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c or b.d'; -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g or b.d'; -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g or b.c'; -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.b and b.d'; -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c and b.d'; -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c and b.b'; -select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g and b.d'; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.b or b.d'::jsquery; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c or b.d'::jsquery; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g or b.d'::jsquery; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g or b.c'::jsquery; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.b and b.d'::jsquery; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c and b.d'::jsquery; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.c and b.b'::jsquery; +select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb @@ 'a.g and b.d'::jsquery; select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb ~~ 'a.b and b.d'; select '{"a": {"b": 1, "c": 2}, "b": {"d":3}}'::jsonb ~~ 'a.b and b.c'; @@ -421,6 +421,32 @@ SELECT gin_debug_query_path_value('$ = true'); SELECT gin_debug_query_path_value('$ . ? (review_votes > 10) . review_rating < 7'); SELECT gin_debug_query_path_value('similar_product_ids . ? (# = "B0002W4TL2") . $'); +SELECT gin_debug_query_laxpath_value('NOT NOT NOT x(y(NOT (a=1) and NOT (b=2)) OR NOT NOT (c=3)) and z = 5'); +SELECT gin_debug_query_laxpath_value('NOT #(x=1) and NOT *(y=1) and NOT %(z=1) '); +SELECT gin_debug_query_laxpath_value('#(NOT x=1) and *(NOT y=1) and %(NOT z=1) '); +SELECT gin_debug_query_laxpath_value('NOT #(NOT x=1) and NOT *(NOT y=1) and NOT %(NOT z=1) '); +SELECT gin_debug_query_laxpath_value('#(x = "a" and y > 0 and y < 1 and z > 0)'); +SELECT gin_debug_query_laxpath_value('#(x = "a" and y /*-- index */ >= 0 and y < 1 and z > 0)'); +SELECT gin_debug_query_laxpath_value('#(x /*-- noindex */ = "a" and y > 0 and y <= 1 and z /*-- index */ > 0)'); +SELECT gin_debug_query_laxpath_value('x = 1 and (y /*-- index */ > 0 and y < 1 OR z > 0)'); +SELECT gin_debug_query_laxpath_value('%.x = 1'); +SELECT gin_debug_query_laxpath_value('*.x = "b"'); +SELECT gin_debug_query_laxpath_value('x && [1,2,3]'); +SELECT gin_debug_query_laxpath_value('x @> [1,2,3]'); +SELECT gin_debug_query_laxpath_value('x <@ [1,2,3]'); +SELECT gin_debug_query_laxpath_value('x = *'); +SELECT gin_debug_query_laxpath_value('x is boolean'); +SELECT gin_debug_query_laxpath_value('x is string'); +SELECT gin_debug_query_laxpath_value('x is numeric'); +SELECT gin_debug_query_laxpath_value('x is array'); +SELECT gin_debug_query_laxpath_value('x is object'); +SELECT gin_debug_query_laxpath_value('#:(x=1) AND %:(y=1) AND *:(z=1)'); +SELECT gin_debug_query_laxpath_value('#:(NOT x=1) AND %:(NOT y=1) AND *:(NOT z=1)'); +SELECT gin_debug_query_laxpath_value('NOT #:(NOT x=1) AND NOT %:(NOT y=1) AND NOT *:(NOT z=1)'); +SELECT gin_debug_query_laxpath_value('$ = true'); +SELECT gin_debug_query_laxpath_value('$ . ? (review_votes > 10) . review_rating < 7'); +SELECT gin_debug_query_laxpath_value('similar_product_ids . ? (# = "B0002W4TL2") . $'); + SELECT gin_debug_query_value_path('NOT NOT NOT x(y(NOT (a=1) and NOT (b=2)) OR NOT NOT (c=3)) and z = 5'); SELECT gin_debug_query_value_path('NOT #(x=1) and NOT *(y=1) and NOT %(z=1) '); SELECT gin_debug_query_value_path('#(NOT x=1) and *(NOT y=1) and %(NOT z=1) '); @@ -451,6 +477,133 @@ SELECT gin_debug_query_value_path('$ = true'); SELECT gin_debug_query_value_path('$ . ? (review_votes > 10) . review_rating < 7'); SELECT gin_debug_query_value_path('similar_product_ids . ? (# = "B0002W4TL2") . $'); +-- -extract jsonpath entries for index scan + +SELECT gin_debug_jsonpath_value_path('lax $'); +SELECT gin_debug_jsonpath_value_path('strict $'); +SELECT gin_debug_jsonpath_value_path('lax $.a'); +SELECT gin_debug_jsonpath_value_path('strict $.a'); +SELECT gin_debug_jsonpath_value_path('lax exists($)'); +SELECT gin_debug_jsonpath_value_path('strict exists($)'); +SELECT gin_debug_jsonpath_value_path('lax exists($.a)'); +SELECT gin_debug_jsonpath_value_path('strict exists($.a)'); +SELECT gin_debug_jsonpath_value_path('lax exists($.a.b)'); +SELECT gin_debug_jsonpath_value_path('strict exists($.a.b)'); + +SELECT gin_debug_jsonpath_value_path('lax exists($ ? (@.b == 3).c.d)'); +SELECT gin_debug_jsonpath_value_path('strict exists($ ? (@.b == 3).c.d)'); +SELECT gin_debug_jsonpath_value_path('lax exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); +SELECT gin_debug_jsonpath_value_path('strict exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); + +SELECT gin_debug_jsonpath_value_path('lax $.a ? (@.b == "foo").c == 1'); +SELECT gin_debug_jsonpath_value_path('strict $.a ? (@.b == "foo").c == 1'); +SELECT gin_debug_jsonpath_value_path('lax $.a ? (@.b == "foo") == 1'); +SELECT gin_debug_jsonpath_value_path('strict $.a ? (@.b == "foo") == 1'); +SELECT gin_debug_jsonpath_value_path('lax $.a ? (@.b == "foo")'); +SELECT gin_debug_jsonpath_value_path('strict $.a ? (@.b == "foo")'); +SELECT gin_debug_jsonpath_value_path('lax exists($.a ? (@.b == "foo"))'); +SELECT gin_debug_jsonpath_value_path('strict exists($.a ? (@.b == "foo"))'); +SELECT gin_debug_jsonpath_value_path('lax exists($.a ? (@.b == "foo").c)'); +SELECT gin_debug_jsonpath_value_path('strict exists($.a ? (@.b == "foo").c)'); +select gin_debug_jsonpath_value_path('lax exists($.a.b ? (@.c.d == 1))'); +select gin_debug_jsonpath_value_path('strict exists($.a.b ? (@.c.d == 1))'); + +select gin_debug_jsonpath_value_path('$.a > 1'); + +SELECT gin_debug_jsonpath_value_path('lax $.a == $.b'); +SELECT gin_debug_jsonpath_value_path('strict $.a == $.b'); + +SELECT gin_debug_jsonpath_path_value('lax $'); +SELECT gin_debug_jsonpath_path_value('strict $'); +SELECT gin_debug_jsonpath_path_value('lax $.a'); +SELECT gin_debug_jsonpath_path_value('strict $.a'); +SELECT gin_debug_jsonpath_path_value('lax exists($)'); +SELECT gin_debug_jsonpath_path_value('strict exists($)'); +SELECT gin_debug_jsonpath_path_value('lax exists($.a)'); +SELECT gin_debug_jsonpath_path_value('strict exists($.a)'); +SELECT gin_debug_jsonpath_path_value('lax exists($.a.b)'); +SELECT gin_debug_jsonpath_path_value('strict exists($.a.b)'); + +SELECT gin_debug_jsonpath_path_value('lax exists($ ? (@.b == 3).c.d)'); +SELECT gin_debug_jsonpath_path_value('strict exists($ ? (@.b == 3).c.d)'); +SELECT gin_debug_jsonpath_path_value('lax exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); +SELECT gin_debug_jsonpath_path_value('strict exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); + +SELECT gin_debug_jsonpath_path_value('lax $.a ? (@.b == "foo").c == 1'); +SELECT gin_debug_jsonpath_path_value('strict $.a ? (@.b == "foo").c == 1'); +SELECT gin_debug_jsonpath_path_value('lax $.a ? (@.b == "foo") == 1'); +SELECT gin_debug_jsonpath_path_value('strict $.a ? (@.b == "foo") == 1'); +SELECT gin_debug_jsonpath_path_value('lax $.a ? (@.b == "foo")'); +SELECT gin_debug_jsonpath_path_value('strict $.a ? (@.b == "foo")'); +SELECT gin_debug_jsonpath_path_value('lax exists($.a ? (@.b == "foo"))'); +SELECT gin_debug_jsonpath_path_value('strict exists($.a ? (@.b == "foo"))'); +SELECT gin_debug_jsonpath_path_value('lax exists($.a ? (@.b == "foo").c)'); +SELECT gin_debug_jsonpath_path_value('strict exists($.a ? (@.b == "foo").c)'); +select gin_debug_jsonpath_path_value('strict exists($.a.b ? (@.c.d == 1))'); +select gin_debug_jsonpath_path_value('lax exists($.a.b ? (@.c.d == 1))'); + +select gin_debug_jsonpath_path_value('strict $.a.b == 1'); +select gin_debug_jsonpath_path_value('lax $.a.b == 1'); +select gin_debug_jsonpath_path_value('strict $.a.b[*] == 1'); +select gin_debug_jsonpath_path_value('lax $.a.b[*] == 1'); +select gin_debug_jsonpath_path_value('strict $.a[*].b[*] == 1'); +select gin_debug_jsonpath_path_value('lax $.a[*].b[*] == 1'); +select gin_debug_jsonpath_path_value('strict $.a.b[*][*] == 1'); +select gin_debug_jsonpath_path_value('lax $.a.b[*][*] == 1'); +select gin_debug_jsonpath_path_value('strict $.a[*].b[*] == 1'); +select gin_debug_jsonpath_path_value('lax $.a[*].b[*] == 1'); + +SELECT gin_debug_jsonpath_path_value('lax $.a > 1 && $.a < 2 && $.b >= 3 && $.c <= "aaa"'); +SELECT gin_debug_jsonpath_path_value('strict $.a > 1 && $.a < 2 && $.b >= 3 && $.c <= "aaa"'); + +SELECT gin_debug_jsonpath_path_value('lax $.a == $.b'); +SELECT gin_debug_jsonpath_path_value('strict $.a == $.b'); + +SELECT gin_debug_jsonpath_laxpath_value('lax $'); +SELECT gin_debug_jsonpath_laxpath_value('strict $'); +SELECT gin_debug_jsonpath_laxpath_value('lax $.a'); +SELECT gin_debug_jsonpath_laxpath_value('strict $.a'); +SELECT gin_debug_jsonpath_laxpath_value('lax exists($)'); +SELECT gin_debug_jsonpath_laxpath_value('strict exists($)'); +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a)'); +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a)'); +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a.b)'); +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a.b)'); + +SELECT gin_debug_jsonpath_laxpath_value('lax exists($ ? (@.b == 3).c.d)'); +SELECT gin_debug_jsonpath_laxpath_value('strict exists($ ? (@.b == 3).c.d)'); +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a ? (@.b == 3).c.d ? (@.e == "aa" || @ == 1))'); + +SELECT gin_debug_jsonpath_laxpath_value('lax $.a ? (@.b == "foo").c == 1'); +SELECT gin_debug_jsonpath_laxpath_value('strict $.a ? (@.b == "foo").c == 1'); +SELECT gin_debug_jsonpath_laxpath_value('lax $.a ? (@.b == "foo") == 1'); +SELECT gin_debug_jsonpath_laxpath_value('strict $.a ? (@.b == "foo") == 1'); +SELECT gin_debug_jsonpath_laxpath_value('lax $.a ? (@.b == "foo")'); +SELECT gin_debug_jsonpath_laxpath_value('strict $.a ? (@.b == "foo")'); +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a ? (@.b == "foo"))'); +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a ? (@.b == "foo"))'); +SELECT gin_debug_jsonpath_laxpath_value('lax exists($.a ? (@.b == "foo").c)'); +SELECT gin_debug_jsonpath_laxpath_value('strict exists($.a ? (@.b == "foo").c)'); +select gin_debug_jsonpath_laxpath_value('exists($.a.b ? (@.c.d == 1))'); + +select gin_debug_jsonpath_laxpath_value('strict $.a.b == 1'); +select gin_debug_jsonpath_laxpath_value('lax $.a.b == 1'); +select gin_debug_jsonpath_laxpath_value('strict $.a.b[*] == 1'); +select gin_debug_jsonpath_laxpath_value('lax $.a.b[*] == 1'); +select gin_debug_jsonpath_laxpath_value('strict $.a[*].b[*] == 1'); +select gin_debug_jsonpath_laxpath_value('lax $.a[*].b[*] == 1'); +select gin_debug_jsonpath_laxpath_value('strict $.a.b[*][*] == 1'); +select gin_debug_jsonpath_laxpath_value('lax $.a.b[*][*] == 1'); +select gin_debug_jsonpath_laxpath_value('strict $.a[*].b[*] == 1'); +select gin_debug_jsonpath_laxpath_value('lax $.a[*].b[*] == 1'); + +SELECT gin_debug_jsonpath_laxpath_value('lax $.a > 1 && $.a < 2 && $.b >= 3 && $.c <= "aaa"'); +SELECT gin_debug_jsonpath_laxpath_value('strict $.a > 1 && $.a < 2 && $.b >= 3 && $.c <= "aaa"'); + +SELECT gin_debug_jsonpath_laxpath_value('lax $.a == $.b'); +SELECT gin_debug_jsonpath_laxpath_value('strict $.a == $.b'); + ---table and index select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 0; @@ -463,164 +616,385 @@ select count(*) from test_jsquery where (v->>'review_helpful_votes')::int4 > 16 (v->>'review_helpful_votes')::int4 < 20; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16' AND - v @@ 'review_helpful_votes < 20'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'; -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'; -select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '; -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'; -select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'; -select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'; -select count(*) from test_jsquery where v @@ 'customer_id = null'; -select count(*) from test_jsquery where v @@ 'review_votes = true'; -select count(*) from test_jsquery where v @@ 'product_group = false'; -select count(*) from test_jsquery where v @@ 't = *'; -select count(*) from test_jsquery where v @@ 't is boolean'; -select count(*) from test_jsquery where v @@ 't is string'; -select count(*) from test_jsquery where v @@ 't is numeric'; -select count(*) from test_jsquery where v @@ 't is array'; -select count(*) from test_jsquery where v @@ 't is object'; -select count(*) from test_jsquery where v @@ '$ is boolean'; -select count(*) from test_jsquery where v @@ '$ is string'; -select count(*) from test_jsquery where v @@ '$ is numeric'; -select count(*) from test_jsquery where v @@ '$ is array'; -select count(*) from test_jsquery where v @@ '$ is object'; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'; -select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'; -select count(*) from test_jsquery where v @@ '$ > 2'; -select count(*) from test_jsquery where v @@ '$ = false'; -select count(*) from test_jsquery where v @@ 't'; -select count(*) from test_jsquery where v @@ '$'; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#'; -select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'; -select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'; - -select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; -select v from test_jsquery where v @@ 'array && [2,3]' order by v; -select v from test_jsquery where v @@ 'array @> [2,3]' order by v; -select v from test_jsquery where v @@ 'array = [2,3]' order by v; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16'::jsquery AND + v @@ 'review_helpful_votes < 20'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'::jsquery; +select count(*) from test_jsquery where v @@ 'customer_id = null'::jsquery; +select count(*) from test_jsquery where v @@ 'review_votes = true'::jsquery; +select count(*) from test_jsquery where v @@ 'product_group = false'::jsquery; +select count(*) from test_jsquery where v @@ 't = *'::jsquery; +select count(*) from test_jsquery where v @@ 't is boolean'::jsquery; +select count(*) from test_jsquery where v @@ 't is string'::jsquery; +select count(*) from test_jsquery where v @@ 't is numeric'::jsquery; +select count(*) from test_jsquery where v @@ 't is array'::jsquery; +select count(*) from test_jsquery where v @@ 't is object'::jsquery; +select count(*) from test_jsquery where v @@ '$ is boolean'::jsquery; +select count(*) from test_jsquery where v @@ '$ is string'::jsquery; +select count(*) from test_jsquery where v @@ '$ is numeric'::jsquery; +select count(*) from test_jsquery where v @@ '$ is array'::jsquery; +select count(*) from test_jsquery where v @@ '$ is object'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'::jsquery; +select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsquery; +select count(*) from test_jsquery where v @@ '$ > 2'::jsquery; +select count(*) from test_jsquery where v @@ '$ = false'::jsquery; +select count(*) from test_jsquery where v @@ 't'::jsquery; +select count(*) from test_jsquery where v @@ '$'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#'::jsquery; +select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'::jsquery; + +select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; create index t_idx on test_jsquery using gin (v jsonb_value_path_ops); set enable_seqscan = off; -explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; - -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16' AND - v @@ 'review_helpful_votes < 20'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'; -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'; -select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '; -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'; -select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'; -select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'; -select count(*) from test_jsquery where v @@ 'customer_id = null'; -select count(*) from test_jsquery where v @@ 'review_votes = true'; -select count(*) from test_jsquery where v @@ 'product_group = false'; -select count(*) from test_jsquery where v @@ 't = *'; -select count(*) from test_jsquery where v @@ 't is boolean'; -select count(*) from test_jsquery where v @@ 't is string'; -select count(*) from test_jsquery where v @@ 't is numeric'; -select count(*) from test_jsquery where v @@ 't is array'; -select count(*) from test_jsquery where v @@ 't is object'; -select count(*) from test_jsquery where v @@ '$ is boolean'; -select count(*) from test_jsquery where v @@ '$ is string'; -select count(*) from test_jsquery where v @@ '$ is numeric'; -select count(*) from test_jsquery where v @@ '$ is array'; -select count(*) from test_jsquery where v @@ '$ is object'; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'; -select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'; -select count(*) from test_jsquery where v @@ '$ > 2'; -select count(*) from test_jsquery where v @@ '$ = false'; -select count(*) from test_jsquery where v @@ 't'; -select count(*) from test_jsquery where v @@ '$'; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#'; -select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'; -select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'; - -explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; -explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]' order by v; -explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]' order by v; -explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]' order by v; - -select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; -select v from test_jsquery where v @@ 'array && [2,3]' order by v; -select v from test_jsquery where v @@ 'array @> [2,3]' order by v; -select v from test_jsquery where v @@ 'array = [2,3]' order by v; +explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16'::jsquery AND + v @@ 'review_helpful_votes < 20'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'::jsquery; +select count(*) from test_jsquery where v @@ 'customer_id = null'::jsquery; +select count(*) from test_jsquery where v @@ 'review_votes = true'::jsquery; +select count(*) from test_jsquery where v @@ 'product_group = false'::jsquery; +select count(*) from test_jsquery where v @@ 't = *'::jsquery; +select count(*) from test_jsquery where v @@ 't is boolean'::jsquery; +select count(*) from test_jsquery where v @@ 't is string'::jsquery; +select count(*) from test_jsquery where v @@ 't is numeric'::jsquery; +select count(*) from test_jsquery where v @@ 't is array'::jsquery; +select count(*) from test_jsquery where v @@ 't is object'::jsquery; +select count(*) from test_jsquery where v @@ '$ is boolean'::jsquery; +select count(*) from test_jsquery where v @@ '$ is string'::jsquery; +select count(*) from test_jsquery where v @@ '$ is numeric'::jsquery; +select count(*) from test_jsquery where v @@ '$ is array'::jsquery; +select count(*) from test_jsquery where v @@ '$ is object'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'::jsquery; +select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsquery; +select count(*) from test_jsquery where v @@ '$ > 2'::jsquery; +select count(*) from test_jsquery where v @@ '$ = false'::jsquery; +select count(*) from test_jsquery where v @@ 't'::jsquery; +select count(*) from test_jsquery where v @@ '$'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#'::jsquery; +select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'::jsquery; + +explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; +explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; +explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; +explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + +select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + +explain (costs off) select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; +explain (costs off) select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 0)'::jsonpath; + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes < 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes >= 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes <= 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes == 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16'::jsonpath AND + v @@ '$.review_helpful_votes < 20'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16 && $.review_helpful_votes < 20'::jsonpath; +select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 16 && @ < 20)'::jsonpath; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295"'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*] ? (@ == "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295" && $.product_sales_rank > 300000'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @? 'strict $.similar_product_ids ? (@[*] == "B000002H2H" && @[*] == "B000002H6C")'::jsonpath; +select count(*) from test_jsquery where v @@ '$.customer_id == null'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_votes == true'::jsonpath; +select count(*) from test_jsquery where v @@ '$.product_group == false'::jsonpath; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "boolean"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "string"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "number"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "array"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "object"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "boolean"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "string"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "number"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "array"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "object"'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is numeric)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is string)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @@ 'strict $ > 2'::jsonpath; +select count(*) from test_jsquery where v @@ '$ == false'::jsonpath; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; +select count(*) from test_jsquery where v @? '$'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*]'::jsonpath; +select count(*) from test_jsquery where v @@ '$ ? (@.review_votes > 10) . review_rating < 7'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "B0002W4TL2") '::jsonpath; + +--explain (costs off) select v from test_jsquery where v @@ '$.array <@ [2,3]'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; + +--select v from test_jsquery where v @@ 'array <@ [2,3]'::jsonpath order by v; +select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; +select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; +select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; drop index t_idx; create index t_idx on test_jsquery using gin (v jsonb_path_value_ops); set enable_seqscan = off; -explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; - -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16' AND - v @@ 'review_helpful_votes < 20'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'; -select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'; -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'; -select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '; -select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'; -select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'; -select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'; -select count(*) from test_jsquery where v @@ 'customer_id = null'; -select count(*) from test_jsquery where v @@ 'review_votes = true'; -select count(*) from test_jsquery where v @@ 'product_group = false'; -select count(*) from test_jsquery where v @@ 't = *'; -select count(*) from test_jsquery where v @@ 't is boolean'; -select count(*) from test_jsquery where v @@ 't is string'; -select count(*) from test_jsquery where v @@ 't is numeric'; -select count(*) from test_jsquery where v @@ 't is array'; -select count(*) from test_jsquery where v @@ 't is object'; -select count(*) from test_jsquery where v @@ '$ is boolean'; -select count(*) from test_jsquery where v @@ '$ is string'; -select count(*) from test_jsquery where v @@ '$ is numeric'; -select count(*) from test_jsquery where v @@ '$ is array'; -select count(*) from test_jsquery where v @@ '$ is object'; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'; -select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'; -select count(*) from test_jsquery where v @@ '$ > 2'; -select count(*) from test_jsquery where v @@ '$ = false'; -select count(*) from test_jsquery where v @@ 't'; -select count(*) from test_jsquery where v @@ '$'; -select count(*) from test_jsquery where v @@ 'similar_product_ids.#'; -select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'; -select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'; - -explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; -explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]' order by v; -explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]' order by v; -explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]' order by v; - -select v from test_jsquery where v @@ 'array <@ [2,3]' order by v; -select v from test_jsquery where v @@ 'array && [2,3]' order by v; -select v from test_jsquery where v @@ 'array @> [2,3]' order by v; -select v from test_jsquery where v @@ 'array = [2,3]' order by v; +explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16'::jsquery AND + v @@ 'review_helpful_votes < 20'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'::jsquery; +select count(*) from test_jsquery where v @@ 'customer_id = null'::jsquery; +select count(*) from test_jsquery where v @@ 'review_votes = true'::jsquery; +select count(*) from test_jsquery where v @@ 'product_group = false'::jsquery; +select count(*) from test_jsquery where v @@ 't = *'::jsquery; +select count(*) from test_jsquery where v @@ 't is boolean'::jsquery; +select count(*) from test_jsquery where v @@ 't is string'::jsquery; +select count(*) from test_jsquery where v @@ 't is numeric'::jsquery; +select count(*) from test_jsquery where v @@ 't is array'::jsquery; +select count(*) from test_jsquery where v @@ 't is object'::jsquery; +select count(*) from test_jsquery where v @@ '$ is boolean'::jsquery; +select count(*) from test_jsquery where v @@ '$ is string'::jsquery; +select count(*) from test_jsquery where v @@ '$ is numeric'::jsquery; +select count(*) from test_jsquery where v @@ '$ is array'::jsquery; +select count(*) from test_jsquery where v @@ '$ is object'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'::jsquery; +select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsquery; +select count(*) from test_jsquery where v @@ '$ > 2'::jsquery; +select count(*) from test_jsquery where v @@ '$ = false'::jsquery; +select count(*) from test_jsquery where v @@ 't'::jsquery; +select count(*) from test_jsquery where v @@ '$'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#'::jsquery; +select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'::jsquery; + +explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; +explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; +explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; +explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + +select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + +explain (costs off) select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; +explain (costs off) select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 0)'::jsonpath; + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes < 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes >= 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes <= 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes == 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16'::jsonpath AND + v @@ '$.review_helpful_votes < 20'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16 && $.review_helpful_votes < 20'::jsonpath; +select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 16 && @ < 20)'::jsonpath; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295"'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*] ? (@ == "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295" && $.product_sales_rank > 300000'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @? 'strict $.similar_product_ids ? (@[*] == "B000002H2H" && @[*] == "B000002H6C")'::jsonpath; +select count(*) from test_jsquery where v @@ '$.customer_id == null'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_votes == true'::jsonpath; +select count(*) from test_jsquery where v @@ '$.product_group == false'::jsonpath; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "boolean"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "string"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "number"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "array"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "object"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "boolean"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "string"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "number"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "array"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "object"'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is numeric)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is string)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @@ 'strict $ > 2'::jsonpath; +select count(*) from test_jsquery where v @@ '$ == false'::jsonpath; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; +select count(*) from test_jsquery where v @? '$'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*]'::jsonpath; +select count(*) from test_jsquery where v @@ '$ ? (@.review_votes > 10) . review_rating < 7'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "B0002W4TL2") '::jsonpath; + +--explain (costs off) select v from test_jsquery where v @@ '$.array <@ [2,3]'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; + +--select v from test_jsquery where v @@ 'array <@ [2,3]'::jsonpath order by v; +select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; +select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; +select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; + +drop index t_idx; + +create index t_idx on test_jsquery using gin (v jsonb_laxpath_value_ops); +set enable_seqscan = off; + +explain (costs off) select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; + +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 0'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes < 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes >= 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes <= 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes = 19'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16'::jsquery AND + v @@ 'review_helpful_votes < 20'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes > 16 and review_helpful_votes < 20'::jsquery; +select count(*) from test_jsquery where v @@ 'review_helpful_votes ($ > 16 and $ < 20)'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"]'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids(# = "0440180295") '::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#($ = "0440180295") '::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids && ["0440180295"] and product_sales_rank > 300000'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids @> ["B000002H2H", "B000002H6C"]'::jsquery; +select count(*) from test_jsquery where v @@ 'customer_id = null'::jsquery; +select count(*) from test_jsquery where v @@ 'review_votes = true'::jsquery; +select count(*) from test_jsquery where v @@ 'product_group = false'::jsquery; +select count(*) from test_jsquery where v @@ 't = *'::jsquery; +select count(*) from test_jsquery where v @@ 't is boolean'::jsquery; +select count(*) from test_jsquery where v @@ 't is string'::jsquery; +select count(*) from test_jsquery where v @@ 't is numeric'::jsquery; +select count(*) from test_jsquery where v @@ 't is array'::jsquery; +select count(*) from test_jsquery where v @@ 't is object'::jsquery; +select count(*) from test_jsquery where v @@ '$ is boolean'::jsquery; +select count(*) from test_jsquery where v @@ '$ is string'::jsquery; +select count(*) from test_jsquery where v @@ '$ is numeric'::jsquery; +select count(*) from test_jsquery where v @@ '$ is array'::jsquery; +select count(*) from test_jsquery where v @@ '$ is object'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is numeric'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#: is string'::jsquery; +select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsquery; +select count(*) from test_jsquery where v @@ '$ > 2'::jsquery; +select count(*) from test_jsquery where v @@ '$ = false'::jsquery; +select count(*) from test_jsquery where v @@ 't'::jsquery; +select count(*) from test_jsquery where v @@ '$'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids.#'::jsquery; +select count(*) from test_jsquery where v @@ '$ . ? (review_votes > 10) . review_rating < 7'::jsquery; +select count(*) from test_jsquery where v @@ 'similar_product_ids . ? (# = "B0002W4TL2") . $'::jsquery; + +explain (costs off) select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; +explain (costs off) select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; +explain (costs off) select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; +explain (costs off) select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + +select v from test_jsquery where v @@ 'array <@ [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array && [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array @> [2,3]'::jsquery order by v; +select v from test_jsquery where v @@ 'array = [2,3]'::jsquery order by v; + + +explain (costs off) select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; +explain (costs off) select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 0)'::jsonpath; + +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 0'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes < 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes >= 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes <= 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes == 19'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16'::jsonpath AND + v @@ '$.review_helpful_votes < 20'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_helpful_votes > 16 && $.review_helpful_votes < 20'::jsonpath; +select count(*) from test_jsquery where v @? '$.review_helpful_votes ? (@ > 16 && @ < 20)'::jsonpath; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295"'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*] ? (@ == "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @@ '$.similar_product_ids[*] == "0440180295" && $.product_sales_rank > 300000'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids <@ ["B00000DG0U", "B00004SQXU", "B0001XAM18", "B00000FDBU", "B00000FDBV", "B000002H2H", "B000002H6C", "B000002H5E", "B000002H97", "B000002HMH"]'::jsquery; +select count(*) from test_jsquery where v @? 'strict $.similar_product_ids ? (@[*] == "B000002H2H" && @[*] == "B000002H6C")'::jsonpath; +select count(*) from test_jsquery where v @@ '$.customer_id == null'::jsonpath; +select count(*) from test_jsquery where v @@ '$.review_votes == true'::jsonpath; +select count(*) from test_jsquery where v @@ '$.product_group == false'::jsonpath; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "boolean"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "string"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "number"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "array"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.t.type() == "object"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "boolean"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "string"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "number"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "array"'::jsonpath; +select count(*) from test_jsquery where v @@ '$.type() == "object"'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is numeric)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'similar_product_ids.#: ($ is string)'::jsonpath; +--select count(*) from test_jsquery where v @@ 'NOT similar_product_ids.#: (NOT $ = "0440180295")'::jsonpath; +select count(*) from test_jsquery where v @@ 'strict $ > 2'::jsonpath; +select count(*) from test_jsquery where v @@ '$ == false'::jsonpath; +select count(*) from test_jsquery where v @? '$.t'::jsonpath; +select count(*) from test_jsquery where v @? '$'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids[*]'::jsonpath; +select count(*) from test_jsquery where v @@ '$ ? (@.review_votes > 10) . review_rating < 7'::jsonpath; +select count(*) from test_jsquery where v @? '$.similar_product_ids ? (@[*] == "B0002W4TL2") '::jsonpath; + +--explain (costs off) select v from test_jsquery where v @@ '$.array <@ [2,3]'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; +explain (costs off) select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; + +--select v from test_jsquery where v @@ 'array <@ [2,3]'::jsonpath order by v; +select v from test_jsquery where v @? '$.array[*] ? (@ == 2 || @ == 3)'::jsonpath order by v; +select v from test_jsquery where v @@ '$.array[*] == 2 && $.array[*] == 3'::jsonpath order by v; +select v from test_jsquery where v @@ '$.array[0] == 2 && $.array[1] == 3 && $.array.size() == 2'::jsonpath order by v; RESET enable_seqscan;