SQL/JSON path issues/questions

Started by Thom Brownover 6 years ago36 messages
#1Thom Brown
thom@linux.com

Hi,

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

? operator
==========
The first mention of '?' is in section 9.15, where it says:

"Suppose you would like to retrieve all heart rate values higher than
130. You can achieve this using the following expression:
'$.track.segments[*].HR ? (@ > 130)'"

So what is the ? operator doing here? Sure, there's the regular ?
operator, which is given as an example further down the page:

'{"a":1, "b":2}'::jsonb ? 'b'

But this doesn't appear to have the same purpose.

like_regex
==========
Then there's like_regex, which shows an example that uses the keyword
"flag", but that is the only instance of that keyword being mentioned,
and the flags available to this expression aren't anywhere to be seen.

is unknown
==========
"is unknown" suggests a boolean output, but the example shows an
output of "infinity". While I understand what it does, this appears
inconsistent with all other "is..." functions (e.g. is_valid(lsn),
pg_is_other_temp_schema(oid), pg_opclass_is_visible(opclass_oid),
pg_is_in_backup() etc.).

$varname
==========
The jsonpath variable, $varname, has an incomplete description: "A
named variable. Its value must be set in the PASSING clause of an
SQL/JSON query function. for details."

Binary operation error
==========
I get an error when I run this query:

postgres=# SELECT jsonb_path_query('[2]', '2 + $[1]');
psql: ERROR: right operand of jsonpath operator + is not a single numeric value

While I know it's correct to get an error in this scenario as there is
no element beyond 0, the message I get is confusing. I'd expect this
if it encountered another array in that position, but not for
exceeding the upper bound of the array.

Cryptic error
==========
postgres=# SELECT jsonb_path_query('[1, "2",
{},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].type()');
psql: ERROR: syntax error, unexpected ANY_P at or near "**" of jsonpath input
LINE 1: ...},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].typ...
^
Again, I expect an error, but the message produced doesn't help me.
I'll remove the ANY_P if I can find it.

Can't use nested arrays with jsonpath
==========

I encounter an error in this scenario:

postgres=# select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == [1,2])');
psql: ERROR: syntax error, unexpected '[' at or near "[" of jsonpath input
LINE 1: select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == ...

So these filter operators only work with scalars?

Thanks

Thom

#2Kyotaro Horiguchi
horikyota.ntt@gmail.com
In reply to: Thom Brown (#1)
3 attachment(s)
Re: SQL/JSON path issues/questions

Hi, Thom.

At Thu, 13 Jun 2019 14:59:51 +0100, Thom Brown <thom@linux.com> wrote
in <CAA-aLv4VVX=b9RK5hkfPXJczqaiTdqO04teW9i0wiQVhdKcqzw@mail.gmail.com>

Hi,

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

? operator
==========
The first mention of '?' is in section 9.15, where it says:

"Suppose you would like to retrieve all heart rate values higher than
130. You can achieve this using the following expression:
'$.track.segments[*].HR ? (@ > 130)'"

So what is the ? operator doing here? Sure, there's the regular ?

It is described just above as:

| Each filter expression must be enclosed in parentheses and
| preceded by a question mark.

operator, which is given as an example further down the page:

'{"a":1, "b":2}'::jsonb ? 'b'

But this doesn't appear to have the same purpose.

The section is mentioning path expressions and the '?' is a jsonb
operator. It's somewhat confusing but not so much comparing with
around..

like_regex
==========
Then there's like_regex, which shows an example that uses the keyword
"flag", but that is the only instance of that keyword being mentioned,
and the flags available to this expression aren't anywhere to be seen.

It is described as POSIX regular expressions. So '9.7.3 POSIX
Regular Expressions' is that. But linking it would
helpful. (attached 0001)

is unknown
==========
"is unknown" suggests a boolean output, but the example shows an
output of "infinity". While I understand what it does, this appears
inconsistent with all other "is..." functions (e.g. is_valid(lsn),
pg_is_other_temp_schema(oid), pg_opclass_is_visible(opclass_oid),
pg_is_in_backup() etc.).

It's the right behavior. Among them, only "infinity" gives
"unknown' for the test (@ > 0). -1 gives false, 2 and 3 true.

$varname
==========
The jsonpath variable, $varname, has an incomplete description: "A
named variable. Its value must be set in the PASSING clause of an
SQL/JSON query function. for details."

Yeah, it is apparently chopped amid. In the sgml source, the
missing part is "<!-- TBD: See <xref
linkend="sqljson-input-clause"/> -->", and the PASSING clause is
not implemented yet. On the other hand a similar stuff is
currently implemented as vas parameter in some jsonb
functions. Linking it to there might be helpful (Attached 0002).

Binary operation error
==========
I get an error when I run this query:

postgres=# SELECT jsonb_path_query('[2]', '2 + $[1]');
psql: ERROR: right operand of jsonpath operator + is not a single numeric value

While I know it's correct to get an error in this scenario as there is
no element beyond 0, the message I get is confusing. I'd expect this
if it encountered another array in that position, but not for
exceeding the upper bound of the array.

Something like attached makes it clerer? (Attached 0003)

| ERROR: right operand of jsonpath operator + is not a single numeric value
| DETAIL: It was an array with 0 elements.

Cryptic error
==========
postgres=# SELECT jsonb_path_query('[1, "2",
{},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].type()');
psql: ERROR: syntax error, unexpected ANY_P at or near "**" of jsonpath input
LINE 1: ...},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].typ...
^
Again, I expect an error, but the message produced doesn't help me.
I'll remove the ANY_P if I can find it.

Yeah, I had a similar error:

=# select jsonb_path_query('[-1,2,7, "infinity"]', '$[*] ? (($hoge) is
unknown)', '{"hoge": (@ > 0)}');
ERROR: syntax error, unexpected IS_P at or near " " of jsonpath input

When the errors are issued, the caller side is commented as:

jsonpath_scan.l:481

jsonpath_yyerror(NULL, "bogus input"); /* shouldn't happen */

The error message is reasonable if it were really shouldn't
happen, but it quite easily happen. I don't have an idea of how
to fix it for the present..

Can't use nested arrays with jsonpath
==========

I encounter an error in this scenario:

postgres=# select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == [1,2])');
psql: ERROR: syntax error, unexpected '[' at or near "[" of jsonpath input
LINE 1: select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == ...

So these filter operators only work with scalars?

Perhaps true. It seems that SQL/JSON is saying so. Array is not
comparable with anything. (See 6.13.5 Comparison predicates in
[1]: http://standards.iso.org/ittf/PubliclyAvailableStandards/c067367_ISO_IEC_TR_19075-6_2017.zip

[1]: http://standards.iso.org/ittf/PubliclyAvailableStandards/c067367_ISO_IEC_TR_19075-6_2017.zip

regards.

Attachments:

0001-Add-link-to-description-for-like_regex.patchapplication/octet-stream; name=0001-Add-link-to-description-for-like_regex.patchDownload
From fd2a2c5876c003f36a08ad34fa299594d257e6c5 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Fri, 14 Jun 2019 15:52:04 +0900
Subject: [PATCH 1/3] Add link to description for like_regex.

The description for JSON like regex refers POSIX regular expressions
but it is not linked. Doing that is useful for users.
---
 doc/src/sgml/func.sgml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index a072b97616..487f752aa4 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12048,7 +12048,7 @@ table2-mapping
        </row>
        <row>
         <entry><literal>like_regex</literal></entry>
-        <entry>Tests pattern matching with POSIX regular expressions</entry>
+        <entry>Tests pattern matching with POSIX regular expressions (<xref linkend="functions-posix-regexp"/>)</entry>
         <entry><literal>["abc", "abd", "aBdC", "abdacb", "babc"]</literal></entry>
         <entry><literal>$[*] ? (@ like_regex "^ab.*c" flag "i")</literal></entry>
         <entry><literal>"abc", "aBdC", "abdacb"</literal></entry>
-- 
2.16.3

0002-Fix-description-for-varname-of-jsonpath-variable.patchapplication/octet-stream; name=0002-Fix-description-for-varname-of-jsonpath-variable.patchDownload
From 8661da3608488d40eb4245f2f57ccd2320c22db9 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Fri, 14 Jun 2019 15:21:17 +0900
Subject: [PATCH 2/3] Fix description for $varname of jsonpath variable.

The description is ended part way and PASSING is not impletented
yet. But the variable is impletemented in several jsonpath
functions. So complete the description based on the current
implementation, leaving the TBD.
---
 doc/src/sgml/func.sgml |  2 +-
 doc/src/sgml/json.sgml | 12 ++++++++----
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 487f752aa4..0070ef4913 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -13170,7 +13170,7 @@ table2-mapping
    </para>
    <para>
     When <literal>vars</literal> argument is specified, it constitutes an object
-    contained variables to be substituted into <literal>jsonpath</literal>
+    contained named variables to be substituted into <literal>jsonpath</literal>
     expression.
    </para>
    <para>
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index b8246badda..47cb16cdb4 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -733,10 +733,14 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
      </row>
      <row>
       <entry><literal>$varname</literal></entry>
-      <entry>A named variable. Its value must be set in the
-      <command>PASSING</command> clause of an SQL/JSON query function.
- <!-- TBD: See <xref linkend="sqljson-input-clause"/> -->
-      for details.
+      <entry>A named variable. Its value can be set by the
+        parameter <parameter>vars</parameter> of several JSON processing
+        functions. See <xref linkend="functions-json-processing-table"/> and
+        its notes
+        <!-- TBD: Its value must be set by the <command>PASSING</command>
+             clause of an SQL/JSON query function. See
+             <xref linkend="sqljson-input-clause"/> -->
+        for details.
       </entry>
      </row>
      <row>
-- 
2.16.3

0003-Separate-two-distinctive-json-errors.patchapplication/octet-stream; name=0003-Separate-two-distinctive-json-errors.patchDownload
From 5c2a0ca449465548107af2daf597dfe1e8b70f29 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Fri, 14 Jun 2019 15:11:24 +0900
Subject: [PATCH 3/3] Separate two distinctive json errors.

The error message "right/left operand of jsonpath operator %s is not a
single numeric value" is not user-friendly since the two different
causes are not easy to identify for users. Differenciate the two cases
for users's convenience.
---
 src/backend/utils/adt/jsonpath_exec.c | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 873d64b630..4afc4b517f 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -1484,6 +1484,7 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
 	JsonValueList rseq = {0};
 	JsonbValue *lval;
 	JsonbValue *rval;
+	int			llen;
 	Numeric		res;
 
 	jspGetLeftArg(jsp, &elem);
@@ -1502,19 +1503,27 @@ executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
 	if (jperIsError(jper))
 		return jper;
 
-	if (JsonValueListLength(&lseq) != 1 ||
+	llen = JsonValueListLength(&lseq);
+	if (llen != 1 ||
 		!(lval = getScalar(JsonValueListHead(&lseq), jbvNumeric)))
 		RETURN_ERROR(ereport(ERROR,
 							 (errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
 							  errmsg("left operand of jsonpath operator %s is not a single numeric value",
-									 jspOperationName(jsp->type)))));
+									 jspOperationName(jsp->type)),
+							  (llen != 1 ?
+							   errdetail("It was an array with %d elements.", llen):
+							   errdetail("The only element was not a numeric.")))));
 
-	if (JsonValueListLength(&rseq) != 1 ||
+	llen = JsonValueListLength(&rseq);
+	if (llen != 1 ||
 		!(rval = getScalar(JsonValueListHead(&rseq), jbvNumeric)))
 		RETURN_ERROR(ereport(ERROR,
 							 (errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
 							  errmsg("right operand of jsonpath operator %s is not a single numeric value",
-									 jspOperationName(jsp->type)))));
+									 jspOperationName(jsp->type)),
+							  (llen != 1 ?
+							   errdetail("It was an array with %d elements.", llen):
+							   errdetail("The only element was not a numeric.")))));
 
 	if (jspThrowErrors(cxt))
 	{
-- 
2.16.3

#3Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Kyotaro Horiguchi (#2)
1 attachment(s)
Re: SQL/JSON path issues/questions

Hi!

On Fri, Jun 14, 2019 at 10:16 AM Kyotaro Horiguchi
<horikyota.ntt@gmail.com> wrote:

At Thu, 13 Jun 2019 14:59:51 +0100, Thom Brown <thom@linux.com> wrote
in <CAA-aLv4VVX=b9RK5hkfPXJczqaiTdqO04teW9i0wiQVhdKcqzw@mail.gmail.com>

Hi,

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

? operator
==========
The first mention of '?' is in section 9.15, where it says:

"Suppose you would like to retrieve all heart rate values higher than
130. You can achieve this using the following expression:
'$.track.segments[*].HR ? (@ > 130)'"

So what is the ? operator doing here? Sure, there's the regular ?

It is described just above as:

| Each filter expression must be enclosed in parentheses and
| preceded by a question mark.

+1

operator, which is given as an example further down the page:

'{"a":1, "b":2}'::jsonb ? 'b'

But this doesn't appear to have the same purpose.

The section is mentioning path expressions and the '?' is a jsonb
operator. It's somewhat confusing but not so much comparing with
around..

+1

like_regex
==========
Then there's like_regex, which shows an example that uses the keyword
"flag", but that is the only instance of that keyword being mentioned,
and the flags available to this expression aren't anywhere to be seen.

It is described as POSIX regular expressions. So '9.7.3 POSIX
Regular Expressions' is that. But linking it would
helpful. (attached 0001)

Actually, standard requires supporting the same regex flags as
XQuery/XPath does [1]. Perhaps, we found that we miss support for 'q'
flag, while it's trivial. Attached patch fixes that. Documentation
should contain description of flags. That will be posted as separate
patch.

is unknown
==========
"is unknown" suggests a boolean output, but the example shows an
output of "infinity". While I understand what it does, this appears
inconsistent with all other "is..." functions (e.g. is_valid(lsn),
pg_is_other_temp_schema(oid), pg_opclass_is_visible(opclass_oid),
pg_is_in_backup() etc.).

It's the right behavior. Among them, only "infinity" gives
"unknown' for the test (@ > 0). -1 gives false, 2 and 3 true.

+1
We follow here SQL standard for jsonpath language. There is no direct
analogy with our SQL-level functions.

$varname
==========
The jsonpath variable, $varname, has an incomplete description: "A
named variable. Its value must be set in the PASSING clause of an
SQL/JSON query function. for details."

Yeah, it is apparently chopped amid. In the sgml source, the
missing part is "<!-- TBD: See <xref
linkend="sqljson-input-clause"/> -->", and the PASSING clause is
not implemented yet. On the other hand a similar stuff is
currently implemented as vas parameter in some jsonb
functions. Linking it to there might be helpful (Attached 0002).

Binary operation error
==========
I get an error when I run this query:

postgres=# SELECT jsonb_path_query('[2]', '2 + $[1]');
psql: ERROR: right operand of jsonpath operator + is not a single numeric value

While I know it's correct to get an error in this scenario as there is
no element beyond 0, the message I get is confusing. I'd expect this
if it encountered another array in that position, but not for
exceeding the upper bound of the array.

Something like attached makes it clerer? (Attached 0003)

Thank you. Will review these two and commit.

| ERROR: right operand of jsonpath operator + is not a single numeric value
| DETAIL: It was an array with 0 elements.

Cryptic error
==========
postgres=# SELECT jsonb_path_query('[1, "2",
{},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].type()');
psql: ERROR: syntax error, unexpected ANY_P at or near "**" of jsonpath input
LINE 1: ...},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].typ...
^
Again, I expect an error, but the message produced doesn't help me.
I'll remove the ANY_P if I can find it.

Yeah, I had a similar error:

=# select jsonb_path_query('[-1,2,7, "infinity"]', '$[*] ? (($hoge) is
unknown)', '{"hoge": (@ > 0)}');
ERROR: syntax error, unexpected IS_P at or near " " of jsonpath input

When the errors are issued, the caller side is commented as:

jsonpath_scan.l:481

jsonpath_yyerror(NULL, "bogus input"); /* shouldn't happen */

The error message is reasonable if it were really shouldn't
happen, but it quite easily happen. I don't have an idea of how
to fix it for the present..

I'm also not sure. Need further thinking about it.

Can't use nested arrays with jsonpath
==========

I encounter an error in this scenario:

postgres=# select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == [1,2])');
psql: ERROR: syntax error, unexpected '[' at or near "[" of jsonpath input
LINE 1: select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == ...

So these filter operators only work with scalars?

Perhaps true. It seems that SQL/JSON is saying so. Array is not
comparable with anything. (See 6.13.5 Comparison predicates in
[1])

That's true. But we may we extended version of jsonpath having more
features than standard defined. We can pick proposal [2] to evade
possible incompatibility with future standard updates.

Links.

1. https://www.w3.org/TR/xpath-functions/#func-matches
2. /messages/by-id/5CF28EA0.80902@anastigmatix.net

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

0001-Implement-like_regex-flag-q-in-jsonpath.patchapplication/x-patch; name=0001-Implement-like_regex-flag-q-in-jsonpath.patchDownload
From 16375595a67f1816cb753a3644198ba9b27cc823 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Fri, 14 Jun 2019 15:24:54 +0300
Subject: [PATCH] Implement like_regex flag 'q' in jsonpath

---
 src/backend/utils/adt/jsonpath.c             |  2 ++
 src/backend/utils/adt/jsonpath_exec.c        |  6 +++++
 src/backend/utils/adt/jsonpath_gram.y        |  8 +++++++
 src/include/utils/jsonpath.h                 |  1 +
 src/test/regress/expected/jsonb_jsonpath.out | 36 ++++++++++++++++++++++++++++
 src/test/regress/expected/jsonpath.out       | 18 ++++++++++++++
 src/test/regress/sql/jsonb_jsonpath.sql      |  6 +++++
 src/test/regress/sql/jsonpath.sql            |  3 +++
 8 files changed, 80 insertions(+)

diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c
index d5da155..87ae60e 100644
--- a/src/backend/utils/adt/jsonpath.c
+++ b/src/backend/utils/adt/jsonpath.c
@@ -563,6 +563,8 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
 					appendStringInfoChar(buf, 'm');
 				if (v->content.like_regex.flags & JSP_REGEX_WSPACE)
 					appendStringInfoChar(buf, 'x');
+				if (v->content.like_regex.flags & JSP_REGEX_QUOTE)
+					appendStringInfoChar(buf, 'q');
 
 				appendStringInfoChar(buf, '"');
 			}
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 873d64b..bef9112 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -1664,6 +1664,12 @@ executeLikeRegex(JsonPathItem *jsp, JsonbValue *str, JsonbValue *rarg,
 			cxt->cflags &= ~REG_NEWLINE;
 		if (flags & JSP_REGEX_WSPACE)
 			cxt->cflags |= REG_EXPANDED;
+		if ((flags & JSP_REGEX_QUOTE) &&
+			!(flags & (JSP_REGEX_MLINE | JSP_REGEX_SLINE | JSP_REGEX_WSPACE)))
+		{
+			cxt->cflags &= ~REG_ADVANCED;
+			cxt->cflags |= REG_QUOTE;
+		}
 	}
 
 	if (RE_compile_and_execute(cxt->regex, str->val.string.val,
diff --git a/src/backend/utils/adt/jsonpath_gram.y b/src/backend/utils/adt/jsonpath_gram.y
index 22c2089..a0a930c 100644
--- a/src/backend/utils/adt/jsonpath_gram.y
+++ b/src/backend/utils/adt/jsonpath_gram.y
@@ -510,6 +510,14 @@ makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern,
 				v->value.like_regex.flags |= JSP_REGEX_WSPACE;
 				cflags |= REG_EXPANDED;
 				break;
+			case 'q':
+				v->value.like_regex.flags |= JSP_REGEX_QUOTE;
+				if (!(v->value.like_regex.flags & (JSP_REGEX_MLINE | JSP_REGEX_SLINE | JSP_REGEX_WSPACE)))
+				{
+					cflags &= ~REG_ADVANCED;
+					cflags |= REG_QUOTE;
+				}
+				break;
 			default:
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h
index 3e9d60c..40ad5fd 100644
--- a/src/include/utils/jsonpath.h
+++ b/src/include/utils/jsonpath.h
@@ -91,6 +91,7 @@ typedef enum JsonPathItemType
 #define JSP_REGEX_SLINE		0x02	/* s flag, single-line mode */
 #define JSP_REGEX_MLINE		0x04	/* m flag, multi-line mode */
 #define JSP_REGEX_WSPACE	0x08	/* x flag, expanded syntax */
+#define JSP_REGEX_QUOTE		0x10	/* q flag, no special characters */
 
 /*
  * Support functions to parse/construct binary value.
diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out
index b486fb6..31a871a 100644
--- a/src/test/regress/expected/jsonb_jsonpath.out
+++ b/src/test/regress/expected/jsonb_jsonpath.out
@@ -1622,6 +1622,42 @@ select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "
  "abdacb"
 (2 rows)
 
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "a\\b" flag "q")');
+ jsonb_path_query 
+------------------
+ "a\\b"
+ "^a\\b$"
+(2 rows)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "a\\b" flag "")');
+ jsonb_path_query 
+------------------
+ "a\b"
+(1 row)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\b$" flag "q")');
+ jsonb_path_query 
+------------------
+ "^a\\b$"
+(1 row)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\B$" flag "q")');
+ jsonb_path_query 
+------------------
+(0 rows)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\B$" flag "iq")');
+ jsonb_path_query 
+------------------
+ "^a\\b$"
+(1 row)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\b$" flag "")');
+ jsonb_path_query 
+------------------
+ "a\b"
+(1 row)
+
 -- jsonpath operators
 SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*]');
  jsonb_path_query 
diff --git a/src/test/regress/expected/jsonpath.out b/src/test/regress/expected/jsonpath.out
index 0f9cd17..ecdd453 100644
--- a/src/test/regress/expected/jsonpath.out
+++ b/src/test/regress/expected/jsonpath.out
@@ -453,6 +453,24 @@ select '$ ? (@ like_regex "pattern" flag "xsms")'::jsonpath;
  $?(@ like_regex "pattern" flag "sx")
 (1 row)
 
+select '$ ? (@ like_regex "pattern" flag "q")'::jsonpath;
+              jsonpath               
+-------------------------------------
+ $?(@ like_regex "pattern" flag "q")
+(1 row)
+
+select '$ ? (@ like_regex "pattern" flag "iq")'::jsonpath;
+               jsonpath               
+--------------------------------------
+ $?(@ like_regex "pattern" flag "iq")
+(1 row)
+
+select '$ ? (@ like_regex "pattern" flag "smixq")'::jsonpath;
+                jsonpath                
+----------------------------------------
+ $?(@ like_regex "pattern" flag "imxq")
+(1 row)
+
 select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
 ERROR:  invalid input syntax for type jsonpath
 LINE 1: select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql
index 464ff94..733fbd4 100644
--- a/src/test/regress/sql/jsonb_jsonpath.sql
+++ b/src/test/regress/sql/jsonb_jsonpath.sql
@@ -339,6 +339,12 @@ select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "
 select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "babc"]', 'lax $[*] ? (@ like_regex "^a  b.*  c " flag "ix")');
 select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "babc"]', 'lax $[*] ? (@ like_regex "^ab.*c" flag "m")');
 select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "babc"]', 'lax $[*] ? (@ like_regex "^ab.*c" flag "s")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "a\\b" flag "q")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "a\\b" flag "")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\b$" flag "q")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\B$" flag "q")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\B$" flag "iq")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\b$" flag "")');
 
 -- jsonpath operators
 
diff --git a/src/test/regress/sql/jsonpath.sql b/src/test/regress/sql/jsonpath.sql
index 9171ddb..29ea77a 100644
--- a/src/test/regress/sql/jsonpath.sql
+++ b/src/test/regress/sql/jsonpath.sql
@@ -83,6 +83,9 @@ select '$ ? (@ like_regex "pattern" flag "i")'::jsonpath;
 select '$ ? (@ like_regex "pattern" flag "is")'::jsonpath;
 select '$ ? (@ like_regex "pattern" flag "isim")'::jsonpath;
 select '$ ? (@ like_regex "pattern" flag "xsms")'::jsonpath;
+select '$ ? (@ like_regex "pattern" flag "q")'::jsonpath;
+select '$ ? (@ like_regex "pattern" flag "iq")'::jsonpath;
+select '$ ? (@ like_regex "pattern" flag "smixq")'::jsonpath;
 select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
 
 select '$ < 1'::jsonpath;
-- 
2.7.4

#4Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Thom Brown (#1)
Re: SQL/JSON path issues/questions

On Thu, Jun 13, 2019 at 5:00 PM Thom Brown <thom@linux.com> wrote:

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

BTW, I've some general idea about jsonpath documentation structure.
Right now definition of jsonpath language is spread between sections
"JSON Types" [1] and "JSON Functions, Operators, and Expressions" [2].
Thank might be confusing. I think it would be more readable if whole
jsonpath language definition would be given in a single place. I
propose to move whole definition of jsonpath to section [1] leaving
section [2] just with SQL-level functions. Any thoughts?

Links.

1. https://www.postgresql.org/docs/devel/datatype-json.html#DATATYPE-JSONPATH
2. https://www.postgresql.org/docs/devel/functions-json.html#FUNCTIONS-SQLJSON-PATH

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#5Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Alexander Korotkov (#3)
3 attachment(s)
Re: SQL/JSON path issues/questions

I'm going to push attached 3 patches if no objections.

Regarding 0003-Separate-two-distinctive-json-errors.patch, I think it
requires more thoughts.

        RETURN_ERROR(ereport(ERROR,
                             (errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
                              errmsg("left operand of jsonpath
operator %s is not a single numeric value",
-                                    jspOperationName(jsp->type)))));
+                                    jspOperationName(jsp->type)),
+                             (llen != 1 ?
+                              errdetail("It was an array with %d
elements.", llen):
+                              errdetail("The only element was not a
numeric.")))));

When we have more than 1 value, it's no exactly array. Jsonpath can
extract values from various parts of json document, which never
constitute and array. Should we say something like "There are %d
values"? Also, probably we should display the type of single element
if it's not numeric. jsonb_path_match() also throws
ERRCODE_SINGLETON_JSON_ITEM_REQUIRED, should we add similar
errdetail() there?

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

0001-implement-like_regex-flag-q-in-jsonpath-2.patchapplication/octet-stream; name=0001-implement-like_regex-flag-q-in-jsonpath-2.patchDownload
commit d107fa166bd4c79208555f50e005e20fb468995a
Author: Alexander Korotkov <akorotkov@postgresql.org>
Date:   Sun Jun 16 20:50:45 2019 +0300

    Support 'q' flag in jsonpath 'like_regex' predicate
    
    SQL/JSON standard defines that jsonpath 'like_regex' predicate should support
    the same set of flags as XQuery/XPath.  It appears that implementation of 'q'
    flag was missed.  This commit fixes that.
    
    Discussion: https://postgr.es/m/CAPpHfdtyfPsxLYiTjp5Ov8T5xGsB5t3CwE5%2B3PS%3DLLwA%2BxTJog%40mail.gmail.com
    Author: Nikita Glukhov, Alexander Korotkov

diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c
index d5da1558670..87ae60e490f 100644
--- a/src/backend/utils/adt/jsonpath.c
+++ b/src/backend/utils/adt/jsonpath.c
@@ -563,6 +563,8 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
 					appendStringInfoChar(buf, 'm');
 				if (v->content.like_regex.flags & JSP_REGEX_WSPACE)
 					appendStringInfoChar(buf, 'x');
+				if (v->content.like_regex.flags & JSP_REGEX_QUOTE)
+					appendStringInfoChar(buf, 'q');
 
 				appendStringInfoChar(buf, '"');
 			}
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 873d64b6304..6bf4dcaec33 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -1664,6 +1664,17 @@ executeLikeRegex(JsonPathItem *jsp, JsonbValue *str, JsonbValue *rarg,
 			cxt->cflags &= ~REG_NEWLINE;
 		if (flags & JSP_REGEX_WSPACE)
 			cxt->cflags |= REG_EXPANDED;
+
+		/*
+		 * 'q' flag can work together only with 'i'.  When other is specified,
+		 * then 'q' has no effect.
+		 */
+		if ((flags & JSP_REGEX_QUOTE) &&
+			!(flags & (JSP_REGEX_MLINE | JSP_REGEX_SLINE | JSP_REGEX_WSPACE)))
+		{
+			cxt->cflags &= ~REG_ADVANCED;
+			cxt->cflags |= REG_QUOTE;
+		}
 	}
 
 	if (RE_compile_and_execute(cxt->regex, str->val.string.val,
diff --git a/src/backend/utils/adt/jsonpath_gram.y b/src/backend/utils/adt/jsonpath_gram.y
index 22c2089f78f..a0a930ccf0c 100644
--- a/src/backend/utils/adt/jsonpath_gram.y
+++ b/src/backend/utils/adt/jsonpath_gram.y
@@ -510,6 +510,14 @@ makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern,
 				v->value.like_regex.flags |= JSP_REGEX_WSPACE;
 				cflags |= REG_EXPANDED;
 				break;
+			case 'q':
+				v->value.like_regex.flags |= JSP_REGEX_QUOTE;
+				if (!(v->value.like_regex.flags & (JSP_REGEX_MLINE | JSP_REGEX_SLINE | JSP_REGEX_WSPACE)))
+				{
+					cflags &= ~REG_ADVANCED;
+					cflags |= REG_QUOTE;
+				}
+				break;
 			default:
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/include/utils/jsonpath.h b/src/include/utils/jsonpath.h
index 3e9d60cb760..40ad5fda928 100644
--- a/src/include/utils/jsonpath.h
+++ b/src/include/utils/jsonpath.h
@@ -91,6 +91,7 @@ typedef enum JsonPathItemType
 #define JSP_REGEX_SLINE		0x02	/* s flag, single-line mode */
 #define JSP_REGEX_MLINE		0x04	/* m flag, multi-line mode */
 #define JSP_REGEX_WSPACE	0x08	/* x flag, expanded syntax */
+#define JSP_REGEX_QUOTE		0x10	/* q flag, no special characters */
 
 /*
  * Support functions to parse/construct binary value.
diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out
index b486fb602a3..31a871af028 100644
--- a/src/test/regress/expected/jsonb_jsonpath.out
+++ b/src/test/regress/expected/jsonb_jsonpath.out
@@ -1622,6 +1622,42 @@ select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "
  "abdacb"
 (2 rows)
 
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "a\\b" flag "q")');
+ jsonb_path_query 
+------------------
+ "a\\b"
+ "^a\\b$"
+(2 rows)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "a\\b" flag "")');
+ jsonb_path_query 
+------------------
+ "a\b"
+(1 row)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\b$" flag "q")');
+ jsonb_path_query 
+------------------
+ "^a\\b$"
+(1 row)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\B$" flag "q")');
+ jsonb_path_query 
+------------------
+(0 rows)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\B$" flag "iq")');
+ jsonb_path_query 
+------------------
+ "^a\\b$"
+(1 row)
+
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\b$" flag "")');
+ jsonb_path_query 
+------------------
+ "a\b"
+(1 row)
+
 -- jsonpath operators
 SELECT jsonb_path_query('[{"a": 1}, {"a": 2}]', '$[*]');
  jsonb_path_query 
diff --git a/src/test/regress/expected/jsonpath.out b/src/test/regress/expected/jsonpath.out
index 0f9cd17e2e9..ecdd453942b 100644
--- a/src/test/regress/expected/jsonpath.out
+++ b/src/test/regress/expected/jsonpath.out
@@ -453,6 +453,24 @@ select '$ ? (@ like_regex "pattern" flag "xsms")'::jsonpath;
  $?(@ like_regex "pattern" flag "sx")
 (1 row)
 
+select '$ ? (@ like_regex "pattern" flag "q")'::jsonpath;
+              jsonpath               
+-------------------------------------
+ $?(@ like_regex "pattern" flag "q")
+(1 row)
+
+select '$ ? (@ like_regex "pattern" flag "iq")'::jsonpath;
+               jsonpath               
+--------------------------------------
+ $?(@ like_regex "pattern" flag "iq")
+(1 row)
+
+select '$ ? (@ like_regex "pattern" flag "smixq")'::jsonpath;
+                jsonpath                
+----------------------------------------
+ $?(@ like_regex "pattern" flag "imxq")
+(1 row)
+
 select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
 ERROR:  invalid input syntax for type jsonpath
 LINE 1: select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql
index 464ff94be37..733fbd4e0d0 100644
--- a/src/test/regress/sql/jsonb_jsonpath.sql
+++ b/src/test/regress/sql/jsonb_jsonpath.sql
@@ -339,6 +339,12 @@ select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "
 select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "babc"]', 'lax $[*] ? (@ like_regex "^a  b.*  c " flag "ix")');
 select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "babc"]', 'lax $[*] ? (@ like_regex "^ab.*c" flag "m")');
 select jsonb_path_query('[null, 1, "abc", "abd", "aBdC", "abdacb", "adc\nabc", "babc"]', 'lax $[*] ? (@ like_regex "^ab.*c" flag "s")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "a\\b" flag "q")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "a\\b" flag "")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\b$" flag "q")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\B$" flag "q")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\B$" flag "iq")');
+select jsonb_path_query('[null, 1, "a\b", "a\\b", "^a\\b$"]', 'lax $[*] ? (@ like_regex "^a\\b$" flag "")');
 
 -- jsonpath operators
 
diff --git a/src/test/regress/sql/jsonpath.sql b/src/test/regress/sql/jsonpath.sql
index 9171ddbc6cd..29ea77a4858 100644
--- a/src/test/regress/sql/jsonpath.sql
+++ b/src/test/regress/sql/jsonpath.sql
@@ -83,6 +83,9 @@ select '$ ? (@ like_regex "pattern" flag "i")'::jsonpath;
 select '$ ? (@ like_regex "pattern" flag "is")'::jsonpath;
 select '$ ? (@ like_regex "pattern" flag "isim")'::jsonpath;
 select '$ ? (@ like_regex "pattern" flag "xsms")'::jsonpath;
+select '$ ? (@ like_regex "pattern" flag "q")'::jsonpath;
+select '$ ? (@ like_regex "pattern" flag "iq")'::jsonpath;
+select '$ ? (@ like_regex "pattern" flag "smixq")'::jsonpath;
 select '$ ? (@ like_regex "pattern" flag "a")'::jsonpath;
 
 select '$ < 1'::jsonpath;
0002-improve-jsonpath-like_regex-documentation-2.patchapplication/octet-stream; name=0002-improve-jsonpath-like_regex-documentation-2.patchDownload
commit 6d440378490a1feb7fe7406322925558b77d5c53
Author: Alexander Korotkov <akorotkov@postgresql.org>
Date:   Sun Jun 16 21:20:16 2019 +0300

    Improve documentation for jsonpath like_regex predicate
    
    Reference posix regex documentation section and list supported flags.
    
    Discussion: https://postgr.es/m/CAKPRHz%2BxOuQSSvkuB1mCQjedd%2BB2B1Vnkrq0E-pLmoXyTO%2Bz9Q%40mail.gmail.com
    Author: Kyotaro Horiguchi, Alexander Korotkov

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index e9181338742..3a8581d2050 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12048,7 +12048,11 @@ table2-mapping
        </row>
        <row>
         <entry><literal>like_regex</literal></entry>
-        <entry>Tests pattern matching with POSIX regular expressions</entry>
+        <entry>
+          Tests pattern matching with POSIX regular expressions
+          (<xref linkend="functions-posix-regexp"/>).  Supported flags
+          are <literal>i</literal>, <literal>s</literal>, <literal>m</literal>,
+          <literal>x</literal> and <literal>q</literal>.</entry>
         <entry><literal>["abc", "abd", "aBdC", "abdacb", "babc"]</literal></entry>
         <entry><literal>$[*] ? (@ like_regex "^ab.*c" flag "i")</literal></entry>
         <entry><literal>"abc", "aBdC", "abdacb"</literal></entry>
0003-fix-jsonpath-varname-description-2.patchapplication/octet-stream; name=0003-fix-jsonpath-varname-description-2.patchDownload
commit 95c53c8bc6505e948a3d840f142a5020665ceec5
Author: Alexander Korotkov <akorotkov@postgresql.org>
Date:   Sun Jun 16 23:35:44 2019 +0300

    Fix description for $varname jsonpath variable
    
    The description is ended part way and PASSING clause is not implemented yet.
    But the variables might be passed as parameters to several jsonpath functions.
    So, complete the description based on the current implementation, leaving
    description of PASSING clause in TODO.
    
    Discussion: https://postgr.es/m/CAKPRHz%2BxOuQSSvkuB1mCQjedd%2BB2B1Vnkrq0E-pLmoXyTO%2Bz9Q%40mail.gmail.com
    Author: Kyotaro Horiguchi, Alexander Korotkov

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 3a8581d2050..059eaa4397a 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -13174,7 +13174,7 @@ table2-mapping
    </para>
    <para>
     When <literal>vars</literal> argument is specified, it constitutes an object
-    contained variables to be substituted into <literal>jsonpath</literal>
+    contained named variables to be substituted into <literal>jsonpath</literal>
     expression.
    </para>
    <para>
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index b8246badda9..daebb4f3410 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -733,10 +733,12 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
      </row>
      <row>
       <entry><literal>$varname</literal></entry>
-      <entry>A named variable. Its value must be set in the
-      <command>PASSING</command> clause of an SQL/JSON query function.
- <!-- TBD: See <xref linkend="sqljson-input-clause"/> -->
-      for details.
+      <entry>
+        A named variable. Its value can be set by the parameter
+        <parameter>vars</parameter> of several JSON processing functions.
+        See <xref linkend="functions-json-processing-table"/> and
+        its notes for details.
+        <!-- TODO: describe PASSING clause once implemented !-->
       </entry>
      </row>
      <row>
#6Liudmila Mantrova
l.mantrova@postgrespro.ru
In reply to: Alexander Korotkov (#5)
2 attachment(s)
Re: SQL/JSON path issues/questions

On 6/17/19 11:36 AM, Alexander Korotkov wrote:

I'm going to push attached 3 patches if no objections.

Regarding 0003-Separate-two-distinctive-json-errors.patch, I think it
requires more thoughts.

RETURN_ERROR(ereport(ERROR,
(errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
errmsg("left operand of jsonpath
operator %s is not a single numeric value",
-                                    jspOperationName(jsp->type)))));
+                                    jspOperationName(jsp->type)),
+                             (llen != 1 ?
+                              errdetail("It was an array with %d
elements.", llen):
+                              errdetail("The only element was not a
numeric.")))));

When we have more than 1 value, it's no exactly array. Jsonpath can
extract values from various parts of json document, which never
constitute and array. Should we say something like "There are %d
values"? Also, probably we should display the type of single element
if it's not numeric. jsonb_path_match() also throws
ERRCODE_SINGLETON_JSON_ITEM_REQUIRED, should we add similar
errdetail() there?

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Hi Alexander,

While I have no objections to the proposed fixes, I think we can further
improve patch 0003 and the text it refers to.
In attempt to clarify jsonpath docs and address the concern that ? is
hard to trace in the current text, I'd also like to propose patch 0004.
Please see both of them attached.

--
Liudmila Mantrova
Technical writer at Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

0003-fix-jsonpath-varname-description-3.patchtext/x-patch; name=0003-fix-jsonpath-varname-description-3.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index e918133..39ba18d 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -12281,7 +12281,7 @@ table2-mapping
        <row>
         <entry><literal>@?</literal></entry>
         <entry><type>jsonpath</type></entry>
-        <entry>Does JSON path returns any item for the specified JSON value?</entry>
+        <entry>Does JSON path return any item for the specified JSON value?</entry>
         <entry><literal>'{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)'</literal></entry>
        </row>
        <row>
@@ -12309,8 +12309,8 @@ table2-mapping
   <note>
    <para>
     The <literal>@?</literal> and <literal>@@</literal> operators suppress
-    errors including: lacking object field or array element, unexpected JSON
-    item type and numeric errors.
+    the following errors: lacking object field or array element, unexpected
+    JSON item type, and numeric errors.
     This behavior might be helpful while searching over JSON document
     collections of varying structure.
    </para>
@@ -13166,26 +13166,25 @@ table2-mapping
     <literal>jsonb_path_query</literal>, <literal>jsonb_path_query_array</literal> and
     <literal>jsonb_path_query_first</literal>
     functions have optional <literal>vars</literal> and <literal>silent</literal>
-    argument.
+    arguments.
    </para>
    <para>
-    When <literal>vars</literal> argument is specified, it constitutes an object
-    contained variables to be substituted into <literal>jsonpath</literal>
-    expression.
+    If the <literal>vars</literal> argument is specified, it provides an
+    object containing named variables to be substituted into a
+    <literal>jsonpath</literal> expression.
    </para>
    <para>
-    When <literal>silent</literal> argument is specified and has
-    <literal>true</literal> value, the same errors are suppressed as it is in
-    the <literal>@?</literal> and <literal>@@</literal> operators.
+    If the <literal>silent</literal> argument is specified and has the
+    <literal>true</literal> value, these functions suppress the same errors
+    as the <literal>@?</literal> and <literal>@@</literal> operators.
    </para>
   </note>
 
   <para>
-    See also <xref linkend="functions-aggregate"/> for the aggregate
-    function <function>json_agg</function> which aggregates record
-    values as JSON, and the aggregate function
-    <function>json_object_agg</function> which aggregates pairs of values
-    into a JSON object, and their <type>jsonb</type> equivalents,
+    See also <xref linkend="functions-aggregate"/> for details on
+    <function>json_agg</function> function that aggregates record
+    values as JSON, <function>json_object_agg</function> function
+    that aggregates pairs of values into a JSON object, and their <type>jsonb</type> equivalents,
     <function>jsonb_agg</function> and <function>jsonb_object_agg</function>.
   </para>
 
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index b8246ba..daebb4f 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -733,10 +733,12 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
      </row>
      <row>
       <entry><literal>$varname</literal></entry>
-      <entry>A named variable. Its value must be set in the
-      <command>PASSING</command> clause of an SQL/JSON query function.
- <!-- TBD: See <xref linkend="sqljson-input-clause"/> -->
-      for details.
+      <entry>
+        A named variable. Its value can be set by the parameter
+        <parameter>vars</parameter> of several JSON processing functions.
+        See <xref linkend="functions-json-processing-table"/> and
+        its notes for details.
+        <!-- TODO: describe PASSING clause once implemented !-->
       </entry>
      </row>
      <row>
0004-clarify-jsonpath-docs-1.patchtext/x-patch; name=0004-clarify-jsonpath-docs-1.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 39ba18d..fa5afc1 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -11638,10 +11638,17 @@ table2-mapping
   <para>
    When defining the path, you can also use one or more
    <firstterm>filter expressions</firstterm>, which work similar to
-   the <literal>WHERE</literal> clause in SQL. Each filter expression
-   can provide one or more filtering conditions that are applied
-   to the result of the path evaluation. Each filter expression must
-   be enclosed in parentheses and preceded by a question mark.
+   the <literal>WHERE</literal> clause in SQL. A filter expression must
+   be enclosed in parentheses and preceded by a question mark:
+
+    <programlisting>
+? (@ <replaceable>filter</replaceable> ...)
+    </programlisting>
+  </para>
+
+  <para>
+   Each filter expression can provide one or more filters
+   that are applied to the result of the path evaluation.
    Filter expressions are evaluated from left to right and can be nested.
    The <literal>@</literal> variable denotes the current path evaluation
    result to be filtered, and can be followed by one or more accessor
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index daebb4f..55286a6 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -815,21 +815,18 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
         <literal>.**{<replaceable>level</replaceable>}</literal>
        </para>
        <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        <replaceable>upper_level</replaceable>}</literal>
-       </para>
-       <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        last}</literal>
+        <literal>.**{<replaceable>start_level</replaceable> to
+        <replaceable>end_level</replaceable>}</literal>
        </para>
       </entry>
       <entry>
        <para>
-        Same as <literal>.**</literal>, but with filter over nesting
-        level of JSON hierarchy.  Levels are specified as integers.
-        Zero level corresponds to current object.  This is a
-        <productname>PostgreSQL</productname> extension of the SQL/JSON
-        standard.
+        Same as <literal>.**</literal>, but with a filter over nesting
+        levels of JSON hierarchy. Nesting levels are specified as integers.
+        Zero level corresponds to the current object. To access the lowest
+        nesting level, you can use the <literal>last</literal> keyword.
+        This is a <productname>PostgreSQL</productname> extension of
+        the SQL/JSON standard.
        </para>
       </entry>
      </row>
@@ -841,19 +838,22 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
       </entry>
       <entry>
        <para>
-        Array element accessor.  <literal><replaceable>subscript</replaceable></literal>
-        might be given in two forms: <literal><replaceable>expr</replaceable></literal>
-        or <literal><replaceable>lower_expr</replaceable> to <replaceable>upper_expr</replaceable></literal>.
-        The first form specifies single array element by its index.  The second
-        form specified array slice by the range of indexes.  Zero index
-        corresponds to the first array element.
+        Array element accessor.
+        <literal><replaceable>subscript</replaceable></literal> can be
+        given in two forms: <literal><replaceable>index</replaceable></literal>
+        or <literal><replaceable>start_index</replaceable> to <replaceable>end_index</replaceable></literal>.
+        The first form returns a single array element by its index. The second
+        form returns an array slice by the range of indexes, including the
+        elements that correspond to the provided
+        <replaceable>start_index</replaceable> and <replaceable>end_index</replaceable>.
        </para>
        <para>
-        Expression inside subscript may consititue an integer,
-        numeric expression or any other <literal>jsonpath</literal> expression
-        returning single numeric value.  The <literal>last</literal> keyword
-        can be used in the expression denoting the last subscript in an array.
-        That's helpful for handling arrays of unknown length.
+        The specified <replaceable>index</replaceable> can be an integer,
+        as well as a numeric or <literal>jsonpath</literal> expression that
+        returns a single integer value. Zero index corresponds to the first
+        array element. To access the last element in an array, you can use
+        the <literal>last</literal> keyword, which is useful for handling
+        arrays of unknown length.
        </para>
       </entry>
      </row>
#7Thom Brown
thom@linux.com
In reply to: Kyotaro Horiguchi (#2)
Re: SQL/JSON path issues/questions

On Fri, 14 Jun 2019 at 08:16, Kyotaro Horiguchi <horikyota.ntt@gmail.com> wrote:

Hi, Thom.

At Thu, 13 Jun 2019 14:59:51 +0100, Thom Brown <thom@linux.com> wrote
in <CAA-aLv4VVX=b9RK5hkfPXJczqaiTdqO04teW9i0wiQVhdKcqzw@mail.gmail.com>

Hi,

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

? operator
==========
The first mention of '?' is in section 9.15, where it says:

"Suppose you would like to retrieve all heart rate values higher than
130. You can achieve this using the following expression:
'$.track.segments[*].HR ? (@ > 130)'"

So what is the ? operator doing here? Sure, there's the regular ?

It is described just above as:

| Each filter expression must be enclosed in parentheses and
| preceded by a question mark.

Can I suggest that, rather than using "question mark", we use the "?"
symbol, or provide a syntax structure which shows something like:

<path expression> ? <filter expression>

This not only makes this key information clearer and more prominent,
but it also makes the "?" symbol searchable in a browser for anyone
wanting to find out what that symbol is doing.

operator, which is given as an example further down the page:

'{"a":1, "b":2}'::jsonb ? 'b'

But this doesn't appear to have the same purpose.

The section is mentioning path expressions and the '?' is a jsonb
operator. It's somewhat confusing but not so much comparing with
around..

like_regex
==========
Then there's like_regex, which shows an example that uses the keyword
"flag", but that is the only instance of that keyword being mentioned,
and the flags available to this expression aren't anywhere to be seen.

It is described as POSIX regular expressions. So '9.7.3 POSIX
Regular Expressions' is that. But linking it would
helpful. (attached 0001)

is unknown
==========
"is unknown" suggests a boolean output, but the example shows an
output of "infinity". While I understand what it does, this appears
inconsistent with all other "is..." functions (e.g. is_valid(lsn),
pg_is_other_temp_schema(oid), pg_opclass_is_visible(opclass_oid),
pg_is_in_backup() etc.).

It's the right behavior. Among them, only "infinity" gives
"unknown' for the test (@ > 0). -1 gives false, 2 and 3 true.

I still find it counter-intuitive.

$varname
==========
The jsonpath variable, $varname, has an incomplete description: "A
named variable. Its value must be set in the PASSING clause of an
SQL/JSON query function. for details."

Yeah, it is apparently chopped amid. In the sgml source, the
missing part is "<!-- TBD: See <xref
linkend="sqljson-input-clause"/> -->", and the PASSING clause is
not implemented yet. On the other hand a similar stuff is
currently implemented as vas parameter in some jsonb
functions. Linking it to there might be helpful (Attached 0002).

Binary operation error
==========
I get an error when I run this query:

postgres=# SELECT jsonb_path_query('[2]', '2 + $[1]');
psql: ERROR: right operand of jsonpath operator + is not a single numeric value

While I know it's correct to get an error in this scenario as there is
no element beyond 0, the message I get is confusing. I'd expect this
if it encountered another array in that position, but not for
exceeding the upper bound of the array.

Something like attached makes it clerer? (Attached 0003)

| ERROR: right operand of jsonpath operator + is not a single numeric value
| DETAIL: It was an array with 0 elements.

My first thought upon seeing this error message would be, "I don't see
an array with 0 elements."

Show quoted text

Cryptic error
==========
postgres=# SELECT jsonb_path_query('[1, "2",
{},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].type()');
psql: ERROR: syntax error, unexpected ANY_P at or near "**" of jsonpath input
LINE 1: ...},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].typ...
^
Again, I expect an error, but the message produced doesn't help me.
I'll remove the ANY_P if I can find it.

Yeah, I had a similar error:

=# select jsonb_path_query('[-1,2,7, "infinity"]', '$[*] ? (($hoge) is
unknown)', '{"hoge": (@ > 0)}');
ERROR: syntax error, unexpected IS_P at or near " " of jsonpath input

When the errors are issued, the caller side is commented as:

jsonpath_scan.l:481

jsonpath_yyerror(NULL, "bogus input"); /* shouldn't happen */

The error message is reasonable if it were really shouldn't
happen, but it quite easily happen. I don't have an idea of how
to fix it for the present..

Can't use nested arrays with jsonpath
==========

I encounter an error in this scenario:

postgres=# select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == [1,2])');
psql: ERROR: syntax error, unexpected '[' at or near "[" of jsonpath input
LINE 1: select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == ...

So these filter operators only work with scalars?

Perhaps true. It seems that SQL/JSON is saying so. Array is not
comparable with anything. (See 6.13.5 Comparison predicates in
[1])

[1] http://standards.iso.org/ittf/PubliclyAvailableStandards/c067367_ISO_IEC_TR_19075-6_2017.zip

regards.

#8Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Thom Brown (#7)
Re: SQL/JSON path issues/questions

On Mon, Jun 17, 2019 at 8:40 PM Thom Brown <thom@linux.com> wrote:

On Fri, 14 Jun 2019 at 08:16, Kyotaro Horiguchi <horikyota.ntt@gmail.com> wrote:

Hi, Thom.

At Thu, 13 Jun 2019 14:59:51 +0100, Thom Brown <thom@linux.com> wrote
in <CAA-aLv4VVX=b9RK5hkfPXJczqaiTdqO04teW9i0wiQVhdKcqzw@mail.gmail.com>

Hi,

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

? operator
==========
The first mention of '?' is in section 9.15, where it says:

"Suppose you would like to retrieve all heart rate values higher than
130. You can achieve this using the following expression:
'$.track.segments[*].HR ? (@ > 130)'"

So what is the ? operator doing here? Sure, there's the regular ?

It is described just above as:

| Each filter expression must be enclosed in parentheses and
| preceded by a question mark.

Can I suggest that, rather than using "question mark", we use the "?"
symbol, or provide a syntax structure which shows something like:

<path expression> ? <filter expression>

This not only makes this key information clearer and more prominent,
but it also makes the "?" symbol searchable in a browser for anyone
wanting to find out what that symbol is doing.

Sounds like a good point for me.

operator, which is given as an example further down the page:

'{"a":1, "b":2}'::jsonb ? 'b'

But this doesn't appear to have the same purpose.

The section is mentioning path expressions and the '?' is a jsonb
operator. It's somewhat confusing but not so much comparing with
around..

like_regex
==========
Then there's like_regex, which shows an example that uses the keyword
"flag", but that is the only instance of that keyword being mentioned,
and the flags available to this expression aren't anywhere to be seen.

It is described as POSIX regular expressions. So '9.7.3 POSIX
Regular Expressions' is that. But linking it would
helpful. (attached 0001)

is unknown
==========
"is unknown" suggests a boolean output, but the example shows an
output of "infinity". While I understand what it does, this appears
inconsistent with all other "is..." functions (e.g. is_valid(lsn),
pg_is_other_temp_schema(oid), pg_opclass_is_visible(opclass_oid),
pg_is_in_backup() etc.).

It's the right behavior. Among them, only "infinity" gives
"unknown' for the test (@ > 0). -1 gives false, 2 and 3 true.

I still find it counter-intuitive.

It might be so. But it's defined do in SQL Standard 2016. Following
an SQL standard was always a project priority. We unlikely going to
say: "We don't want to follow a standard, because it doesn't looks
similar to our home brew functions."

$varname
==========
The jsonpath variable, $varname, has an incomplete description: "A
named variable. Its value must be set in the PASSING clause of an
SQL/JSON query function. for details."

Yeah, it is apparently chopped amid. In the sgml source, the
missing part is "<!-- TBD: See <xref
linkend="sqljson-input-clause"/> -->", and the PASSING clause is
not implemented yet. On the other hand a similar stuff is
currently implemented as vas parameter in some jsonb
functions. Linking it to there might be helpful (Attached 0002).

Binary operation error
==========
I get an error when I run this query:

postgres=# SELECT jsonb_path_query('[2]', '2 + $[1]');
psql: ERROR: right operand of jsonpath operator + is not a single numeric value

While I know it's correct to get an error in this scenario as there is
no element beyond 0, the message I get is confusing. I'd expect this
if it encountered another array in that position, but not for
exceeding the upper bound of the array.

Something like attached makes it clerer? (Attached 0003)

| ERROR: right operand of jsonpath operator + is not a single numeric value
| DETAIL: It was an array with 0 elements.

My first thought upon seeing this error message would be, "I don't see
an array with 0 elements."

Yes, it looks counter-intuitive for me too. There is really no array
with 0 elements. Actually, jsonpath subexpression selects no items.
We probably should adjust the message accordingly.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#9Chapman Flack
chap@anastigmatix.net
In reply to: Alexander Korotkov (#8)
Re: SQL/JSON path issues/questions

On 6/17/19 4:13 PM, Alexander Korotkov wrote:

On Mon, Jun 17, 2019 at 8:40 PM Thom Brown <thom@linux.com> wrote:

"is unknown" suggests a boolean output, but the example shows an
output of "infinity". While I understand what it does, this appears
inconsistent with all other "is..." functions (e.g. is_valid(lsn),
pg_is_other_temp_schema(oid), pg_opclass_is_visible(opclass_oid),
pg_is_in_backup() etc.).

It's the right behavior. Among them, only "infinity" gives
"unknown' for the test (@ > 0). -1 gives false, 2 and 3 true.

I still find it counter-intuitive.

It might be so. But it's defined do in SQL Standard 2016.

IIUC, this comes about simply because the JSON data model for numeric
values does not have any infinity or NaN.

So the example given in our doc is sort of a trick example that does
double duty: it demonstrates that (@ > 0) is Unknown when @ is a string,
because numbers and strings are incomparable, and it *also* sort of
slyly reminds the reader that JSON numbers have no infinity, and
therefore "infinity" is nothing but a run-of-the-mill string.

But maybe it is just too brow-furrowingly clever to ask one example
to make both of those points. Maybe it would be clearer to use some
string other than "infinity" to make the first point:

[-1, 2, 7, "some string"] | $[*] ? ((@ > 0) is unknown) | "some string"

... and then if the reminder about infinity is worth making, repeat
the example:

[-1, 2, 7, "infinity"] | $[*] ? ((@ > 0) is unknown) | "infinity"

with a note that it's a trick example as a reminder that JSON numbers
don't have infinity or NaN and so it is no different from any other
string.

Regards,
-Chap

#10Thom Brown
thom@linux.com
In reply to: Thom Brown (#1)
Re: SQL/JSON path issues/questions

On Thu, 13 Jun 2019 at 14:59, Thom Brown <thom@linux.com> wrote:

Hi,

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

? operator
==========
The first mention of '?' is in section 9.15, where it says:

"Suppose you would like to retrieve all heart rate values higher than
130. You can achieve this using the following expression:
'$.track.segments[*].HR ? (@ > 130)'"

So what is the ? operator doing here? Sure, there's the regular ?
operator, which is given as an example further down the page:

'{"a":1, "b":2}'::jsonb ? 'b'

But this doesn't appear to have the same purpose.

like_regex
==========
Then there's like_regex, which shows an example that uses the keyword
"flag", but that is the only instance of that keyword being mentioned,
and the flags available to this expression aren't anywhere to be seen.

is unknown
==========
"is unknown" suggests a boolean output, but the example shows an
output of "infinity". While I understand what it does, this appears
inconsistent with all other "is..." functions (e.g. is_valid(lsn),
pg_is_other_temp_schema(oid), pg_opclass_is_visible(opclass_oid),
pg_is_in_backup() etc.).

$varname
==========
The jsonpath variable, $varname, has an incomplete description: "A
named variable. Its value must be set in the PASSING clause of an
SQL/JSON query function. for details."

Binary operation error
==========
I get an error when I run this query:

postgres=# SELECT jsonb_path_query('[2]', '2 + $[1]');
psql: ERROR: right operand of jsonpath operator + is not a single numeric value

While I know it's correct to get an error in this scenario as there is
no element beyond 0, the message I get is confusing. I'd expect this
if it encountered another array in that position, but not for
exceeding the upper bound of the array.

Cryptic error
==========
postgres=# SELECT jsonb_path_query('[1, "2",
{},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].type()');
psql: ERROR: syntax error, unexpected ANY_P at or near "**" of jsonpath input
LINE 1: ...},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].typ...
^
Again, I expect an error, but the message produced doesn't help me.
I'll remove the ANY_P if I can find it.

Can't use nested arrays with jsonpath
==========

I encounter an error in this scenario:

postgres=# select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == [1,2])');
psql: ERROR: syntax error, unexpected '[' at or near "[" of jsonpath input
LINE 1: select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == ...

So these filter operators only work with scalars?

Another observation about the documentation is that the examples given
in 9.15. JSON Functions, Operators, and Expressions aren't all
functional. Some example JSON is provided, followed by example
jsonpath queries which could be used against it. These will produce
results for the reader wishing to test them out until this example:

'$.track.segments[*].HR ? (@ > 130)'

This is because there is no HR value greater than 130. May I propose
setting this and all similar examples to (@ > 120) instead?

Also, this example doesn't work:

'$.track ? (@.segments[*] ? (@.HR > 130)).segments.size()'

This gives me:

psql: ERROR: syntax error, unexpected $end at end of jsonpath input
LINE 13: }','$.track ? (@.segments[*]');
^

Thanks

Thom

#11Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Thom Brown (#7)
Re: SQL/JSON path issues/questions

On Mon, Jun 17, 2019 at 8:40 PM Thom Brown <thom@linux.com> wrote:

On Fri, 14 Jun 2019 at 08:16, Kyotaro Horiguchi <horikyota.ntt@gmail.com> wrote:

Hi, Thom.

At Thu, 13 Jun 2019 14:59:51 +0100, Thom Brown <thom@linux.com> wrote
in <CAA-aLv4VVX=b9RK5hkfPXJczqaiTdqO04teW9i0wiQVhdKcqzw@mail.gmail.com>

Hi,

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

? operator
==========
The first mention of '?' is in section 9.15, where it says:

"Suppose you would like to retrieve all heart rate values higher than
130. You can achieve this using the following expression:
'$.track.segments[*].HR ? (@ > 130)'"

So what is the ? operator doing here? Sure, there's the regular ?

It is described just above as:

| Each filter expression must be enclosed in parentheses and
| preceded by a question mark.

Can I suggest that, rather than using "question mark", we use the "?"
symbol, or provide a syntax structure which shows something like:

<path expression> ? <filter expression>

This not only makes this key information clearer and more prominent,
but it also makes the "?" symbol searchable in a browser for anyone
wanting to find out what that symbol is doing.

Sounds good for me.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#12Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Thom Brown (#10)
Re: SQL/JSON path issues/questions

On Wed, Jun 19, 2019 at 7:07 PM Thom Brown <thom@linux.com> wrote:

On Thu, 13 Jun 2019 at 14:59, Thom Brown <thom@linux.com> wrote:

Hi,

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

? operator
==========
The first mention of '?' is in section 9.15, where it says:

"Suppose you would like to retrieve all heart rate values higher than
130. You can achieve this using the following expression:
'$.track.segments[*].HR ? (@ > 130)'"

So what is the ? operator doing here? Sure, there's the regular ?
operator, which is given as an example further down the page:

'{"a":1, "b":2}'::jsonb ? 'b'

But this doesn't appear to have the same purpose.

like_regex
==========
Then there's like_regex, which shows an example that uses the keyword
"flag", but that is the only instance of that keyword being mentioned,
and the flags available to this expression aren't anywhere to be seen.

is unknown
==========
"is unknown" suggests a boolean output, but the example shows an
output of "infinity". While I understand what it does, this appears
inconsistent with all other "is..." functions (e.g. is_valid(lsn),
pg_is_other_temp_schema(oid), pg_opclass_is_visible(opclass_oid),
pg_is_in_backup() etc.).

$varname
==========
The jsonpath variable, $varname, has an incomplete description: "A
named variable. Its value must be set in the PASSING clause of an
SQL/JSON query function. for details."

Binary operation error
==========
I get an error when I run this query:

postgres=# SELECT jsonb_path_query('[2]', '2 + $[1]');
psql: ERROR: right operand of jsonpath operator + is not a single numeric value

While I know it's correct to get an error in this scenario as there is
no element beyond 0, the message I get is confusing. I'd expect this
if it encountered another array in that position, but not for
exceeding the upper bound of the array.

Cryptic error
==========
postgres=# SELECT jsonb_path_query('[1, "2",
{},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].type()');
psql: ERROR: syntax error, unexpected ANY_P at or near "**" of jsonpath input
LINE 1: ...},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].typ...
^
Again, I expect an error, but the message produced doesn't help me.
I'll remove the ANY_P if I can find it.

Can't use nested arrays with jsonpath
==========

I encounter an error in this scenario:

postgres=# select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == [1,2])');
psql: ERROR: syntax error, unexpected '[' at or near "[" of jsonpath input
LINE 1: select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == ...

So these filter operators only work with scalars?

Another observation about the documentation is that the examples given
in 9.15. JSON Functions, Operators, and Expressions aren't all
functional. Some example JSON is provided, followed by example
jsonpath queries which could be used against it. These will produce
results for the reader wishing to test them out until this example:

'$.track.segments[*].HR ? (@ > 130)'

This is because there is no HR value greater than 130. May I propose
setting this and all similar examples to (@ > 120) instead?

Makes sense to me.

Also, this example doesn't work:

'$.track ? (@.segments[*] ? (@.HR > 130)).segments.size()'

This gives me:

psql: ERROR: syntax error, unexpected $end at end of jsonpath input
LINE 13: }','$.track ? (@.segments[*]');
^

Perhaps it should be following:

'$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()'

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#13Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Liudmila Mantrova (#6)
Re: SQL/JSON path issues/questions

Hi, Liudmila!

While I have no objections to the proposed fixes, I think we can further
improve patch 0003 and the text it refers to.
In attempt to clarify jsonpath docs and address the concern that ? is
hard to trace in the current text, I'd also like to propose patch 0004.
Please see both of them attached.

Thank you for your editing. I'm going to commit them as well.

But I'm going to commit your changes separately from 0003 I've posted
before. Because 0003 fixes factual error, while you're proposing set
of grammar/style fixes.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#14Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Alexander Korotkov (#13)
Re: SQL/JSON path issues/questions

On Wed, Jun 19, 2019 at 10:14 PM Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

While I have no objections to the proposed fixes, I think we can further
improve patch 0003 and the text it refers to.
In attempt to clarify jsonpath docs and address the concern that ? is
hard to trace in the current text, I'd also like to propose patch 0004.
Please see both of them attached.

Thank you for your editing. I'm going to commit them as well.

But I'm going to commit your changes separately from 0003 I've posted
before. Because 0003 fixes factual error, while you're proposing set
of grammar/style fixes.

I made some review of these patches. My notes are following:

   <para>
-    See also <xref linkend="functions-aggregate"/> for the aggregate
-    function <function>json_agg</function> which aggregates record
-    values as JSON, and the aggregate function
-    <function>json_object_agg</function> which aggregates pairs of values
-    into a JSON object, and their <type>jsonb</type> equivalents,
+    See also <xref linkend="functions-aggregate"/> for details on
+    <function>json_agg</function> function that aggregates record
+    values as JSON, <function>json_object_agg</function> function
+    that aggregates pairs of values into a JSON object, and their
<type>jsonb</type> equivalents,
     <function>jsonb_agg</function> and <function>jsonb_object_agg</function>.
   </para>

This part is not directly related to jsonpath, and it has been there
for a long time. I'd like some native english speaker to review this
change before committing this.

        <para>
-        Expression inside subscript may consititue an integer,
-        numeric expression or any other <literal>jsonpath</literal> expression
-        returning single numeric value.  The <literal>last</literal> keyword
-        can be used in the expression denoting the last subscript in an array.
-        That's helpful for handling arrays of unknown length.
+        The specified <replaceable>index</replaceable> can be an integer,
+        as well as a numeric or <literal>jsonpath</literal> expression that
+        returns a single integer value. Zero index corresponds to the first
+        array element. To access the last element in an array, you can use
+        the <literal>last</literal> keyword, which is useful for handling
+        arrays of unknown length.
        </para>

I think this part requires more work. Let's see what cases do we have
with examples:

1) Integer: '$.ar[1]'
2) Numeric: '$.ar[1.5]' (converted to integer)
3) Some numeric expression: '$.ar[last - 1]'
4) Arbitrary jsonpath expression: '$.ar[$.ar2.size() + $.num - 2]'

In principle, it not necessary to divide 3 and 4, or divide 1 and 2.
Or we may don't describe cases at all, but just say it's a jsonpath
expression returning numeric, which is converted to integer.

Also, note that we do not necessary *access* last array element with
"last" keyword. "last" keyword denotes index of last element in
expression. But completely different element might be actually
accessed.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#15Liudmila Mantrova
l.mantrova@postgrespro.ru
In reply to: Alexander Korotkov (#14)
1 attachment(s)
Re: SQL/JSON path issues/questions

On 6/21/19 8:04 PM, Alexander Korotkov wrote:

On Wed, Jun 19, 2019 at 10:14 PM Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

While I have no objections to the proposed fixes, I think we can further
improve patch 0003 and the text it refers to.
In attempt to clarify jsonpath docs and address the concern that ? is
hard to trace in the current text, I'd also like to propose patch 0004.
Please see both of them attached.

Thank you for your editing. I'm going to commit them as well.

But I'm going to commit your changes separately from 0003 I've posted
before. Because 0003 fixes factual error, while you're proposing set
of grammar/style fixes.

I made some review of these patches. My notes are following:

<para>
-    See also <xref linkend="functions-aggregate"/> for the aggregate
-    function <function>json_agg</function> which aggregates record
-    values as JSON, and the aggregate function
-    <function>json_object_agg</function> which aggregates pairs of values
-    into a JSON object, and their <type>jsonb</type> equivalents,
+    See also <xref linkend="functions-aggregate"/> for details on
+    <function>json_agg</function> function that aggregates record
+    values as JSON, <function>json_object_agg</function> function
+    that aggregates pairs of values into a JSON object, and their
<type>jsonb</type> equivalents,
<function>jsonb_agg</function> and <function>jsonb_object_agg</function>.
</para>

This part is not directly related to jsonpath, and it has been there
for a long time. I'd like some native english speaker to review this
change before committing this.

<para>
-        Expression inside subscript may consititue an integer,
-        numeric expression or any other <literal>jsonpath</literal> expression
-        returning single numeric value.  The <literal>last</literal> keyword
-        can be used in the expression denoting the last subscript in an array.
-        That's helpful for handling arrays of unknown length.
+        The specified <replaceable>index</replaceable> can be an integer,
+        as well as a numeric or <literal>jsonpath</literal> expression that
+        returns a single integer value. Zero index corresponds to the first
+        array element. To access the last element in an array, you can use
+        the <literal>last</literal> keyword, which is useful for handling
+        arrays of unknown length.
</para>

I think this part requires more work. Let's see what cases do we have
with examples:

1) Integer: '$.ar[1]'
2) Numeric: '$.ar[1.5]' (converted to integer)
3) Some numeric expression: '$.ar[last - 1]'
4) Arbitrary jsonpath expression: '$.ar[$.ar2.size() + $.num - 2]'

In principle, it not necessary to divide 3 and 4, or divide 1 and 2.
Or we may don't describe cases at all, but just say it's a jsonpath
expression returning numeric, which is converted to integer.

Also, note that we do not necessary *access* last array element with
"last" keyword. "last" keyword denotes index of last element in
expression. But completely different element might be actually
accessed.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Hi Alexander,

Thank you for the catch! Please see the modified version of patch 0004
attached.

As for your comment on patch 0003, since I'm not a native speaker, I can
only refer to a recent discussion in pgsql-docs mailing list that seems
to support my view on a similar issue:

/messages/by-id/9484.1558050957@sss.pgh.pa.us

--
Liudmila Mantrova
Technical writer at Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

0004-clarify-jsonpath-docs-2.patchtext/x-patch; name=0004-clarify-jsonpath-docs-2.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 39ba18d..fa5afc1 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -11638,10 +11638,17 @@ table2-mapping
   <para>
    When defining the path, you can also use one or more
    <firstterm>filter expressions</firstterm>, which work similar to
-   the <literal>WHERE</literal> clause in SQL. Each filter expression
-   can provide one or more filtering conditions that are applied
-   to the result of the path evaluation. Each filter expression must
-   be enclosed in parentheses and preceded by a question mark.
+   the <literal>WHERE</literal> clause in SQL. A filter expression must
+   be enclosed in parentheses and preceded by a question mark:
+
+    <programlisting>
+? (@ <replaceable>filter</replaceable> ...)
+    </programlisting>
+  </para>
+
+  <para>
+   Each filter expression can provide one or more filters
+   that are applied to the result of the path evaluation.
    Filter expressions are evaluated from left to right and can be nested.
    The <literal>@</literal> variable denotes the current path evaluation
    result to be filtered, and can be followed by one or more accessor
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index daebb4f..0d8e2c6 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -815,21 +815,18 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
         <literal>.**{<replaceable>level</replaceable>}</literal>
        </para>
        <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        <replaceable>upper_level</replaceable>}</literal>
-       </para>
-       <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        last}</literal>
+        <literal>.**{<replaceable>start_level</replaceable> to
+        <replaceable>end_level</replaceable>}</literal>
        </para>
       </entry>
       <entry>
        <para>
-        Same as <literal>.**</literal>, but with filter over nesting
-        level of JSON hierarchy.  Levels are specified as integers.
-        Zero level corresponds to current object.  This is a
-        <productname>PostgreSQL</productname> extension of the SQL/JSON
-        standard.
+        Same as <literal>.**</literal>, but with a filter over nesting
+        levels of JSON hierarchy. Nesting levels are specified as integers.
+        Zero level corresponds to the current object. To access the lowest
+        nesting level, you can use the <literal>last</literal> keyword.
+        This is a <productname>PostgreSQL</productname> extension of
+        the SQL/JSON standard.
        </para>
       </entry>
      </row>
@@ -841,19 +838,22 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
       </entry>
       <entry>
        <para>
-        Array element accessor.  <literal><replaceable>subscript</replaceable></literal>
-        might be given in two forms: <literal><replaceable>expr</replaceable></literal>
-        or <literal><replaceable>lower_expr</replaceable> to <replaceable>upper_expr</replaceable></literal>.
-        The first form specifies single array element by its index.  The second
-        form specified array slice by the range of indexes.  Zero index
-        corresponds to the first array element.
+        Array element accessor.
+        <literal><replaceable>subscript</replaceable></literal> can be
+        given in two forms: <literal><replaceable>index</replaceable></literal>
+        or <literal><replaceable>start_index</replaceable> to <replaceable>end_index</replaceable></literal>.
+        The first form returns a single array element by its index. The second
+        form returns an array slice by the range of indexes, including the
+        elements that correspond to the provided
+        <replaceable>start_index</replaceable> and <replaceable>end_index</replaceable>.
        </para>
        <para>
-        Expression inside subscript may consititue an integer,
-        numeric expression or any other <literal>jsonpath</literal> expression
-        returning single numeric value.  The <literal>last</literal> keyword
-        can be used in the expression denoting the last subscript in an array.
-        That's helpful for handling arrays of unknown length.
+        The specified <replaceable>index</replaceable> can be an integer, as
+        well as an expression returning a single numeric value, which is
+        automatically cast to integer. Zero index corresponds to the first
+        array element. You can also use the <literal>last</literal> keyword
+        to denote the last array element, which is useful for handling arrays
+        of unknown length.
        </para>
       </entry>
      </row>
#16Thom Brown
thom@linux.com
In reply to: Alexander Korotkov (#12)
Re: SQL/JSON path issues/questions

On Wed, 19 Jun 2019 at 20:04, Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Wed, Jun 19, 2019 at 7:07 PM Thom Brown <thom@linux.com> wrote:

On Thu, 13 Jun 2019 at 14:59, Thom Brown <thom@linux.com> wrote:

Hi,

I've been reading through the documentation regarding jsonpath and
jsonb_path_query etc., and I have found it lacking explanation for
some functionality, and I've also had some confusion when using the
feature.

? operator
==========
The first mention of '?' is in section 9.15, where it says:

"Suppose you would like to retrieve all heart rate values higher than
130. You can achieve this using the following expression:
'$.track.segments[*].HR ? (@ > 130)'"

So what is the ? operator doing here? Sure, there's the regular ?
operator, which is given as an example further down the page:

'{"a":1, "b":2}'::jsonb ? 'b'

But this doesn't appear to have the same purpose.

like_regex
==========
Then there's like_regex, which shows an example that uses the keyword
"flag", but that is the only instance of that keyword being mentioned,
and the flags available to this expression aren't anywhere to be seen.

is unknown
==========
"is unknown" suggests a boolean output, but the example shows an
output of "infinity". While I understand what it does, this appears
inconsistent with all other "is..." functions (e.g. is_valid(lsn),
pg_is_other_temp_schema(oid), pg_opclass_is_visible(opclass_oid),
pg_is_in_backup() etc.).

$varname
==========
The jsonpath variable, $varname, has an incomplete description: "A
named variable. Its value must be set in the PASSING clause of an
SQL/JSON query function. for details."

Binary operation error
==========
I get an error when I run this query:

postgres=# SELECT jsonb_path_query('[2]', '2 + $[1]');
psql: ERROR: right operand of jsonpath operator + is not a single numeric value

While I know it's correct to get an error in this scenario as there is
no element beyond 0, the message I get is confusing. I'd expect this
if it encountered another array in that position, but not for
exceeding the upper bound of the array.

Cryptic error
==========
postgres=# SELECT jsonb_path_query('[1, "2",
{},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].type()');
psql: ERROR: syntax error, unexpected ANY_P at or near "**" of jsonpath input
LINE 1: ...},[{"a":2}],2.3,null,"2019-06-05T13:25:43.511Z"]','$[**].typ...
^
Again, I expect an error, but the message produced doesn't help me.
I'll remove the ANY_P if I can find it.

Can't use nested arrays with jsonpath
==========

I encounter an error in this scenario:

postgres=# select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == [1,2])');
psql: ERROR: syntax error, unexpected '[' at or near "[" of jsonpath input
LINE 1: select jsonb_path_query('[1, 2, 1, [1,2], 3]','$[*] ? (@ == ...

So these filter operators only work with scalars?

Another observation about the documentation is that the examples given
in 9.15. JSON Functions, Operators, and Expressions aren't all
functional. Some example JSON is provided, followed by example
jsonpath queries which could be used against it. These will produce
results for the reader wishing to test them out until this example:

'$.track.segments[*].HR ? (@ > 130)'

This is because there is no HR value greater than 130. May I propose
setting this and all similar examples to (@ > 120) instead?

Makes sense to me.

Also, this example doesn't work:

'$.track ? (@.segments[*] ? (@.HR > 130)).segments.size()'

This gives me:

psql: ERROR: syntax error, unexpected $end at end of jsonpath input
LINE 13: }','$.track ? (@.segments[*]');
^

Perhaps it should be following:

'$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()'

I'm not clear on why the original example doesn't work here.

Thom

#17Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Thom Brown (#16)
Re: SQL/JSON path issues/questions

On Thu, Jun 27, 2019 at 4:57 PM Thom Brown <thom@linux.com> wrote:

On Wed, 19 Jun 2019 at 20:04, Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Wed, Jun 19, 2019 at 7:07 PM Thom Brown <thom@linux.com> wrote:

On Thu, 13 Jun 2019 at 14:59, Thom Brown <thom@linux.com> wrote:
Also, this example doesn't work:

'$.track ? (@.segments[*] ? (@.HR > 130)).segments.size()'

This gives me:

psql: ERROR: syntax error, unexpected $end at end of jsonpath input
LINE 13: }','$.track ? (@.segments[*]');
^

Perhaps it should be following:

'$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()'

I'm not clear on why the original example doesn't work here.

It doesn't work because filter expression should be predicate, i.e.
always return bool. In the original example filter expression selects
some json elements. My original idea was that it was accidentally
come from some of our extensions where we've allowed that. But it
appears to be just plain wrong example, which never worked. Sorry for
that.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#18Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Liudmila Mantrova (#15)
Re: SQL/JSON path issues/questions

On Tue, Jun 25, 2019 at 6:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you for the catch! Please see the modified version of patch 0004
attached.

I tried to review and revise the part related to filters, but I failed
because I don't understand the notions used in the documentation.

What is the difference between filter expression and filter condition?
I can guess that filter expression contains question mark,
parentheses and filter condition inside. But this sentence is in
contradiction with my guess: "A filter expression must be enclosed in
parentheses and preceded by a question mark". So, filter expression
is inside the parentheses. Then what is filter condition? The same?

Each filter expression can provide one or more filters
that are applied to the result of the path evaluation.

So additionally to filter condition and filter expression we introduce
the notion of just filter. What is it? Could we make it without
introduction of new notion?

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#19Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Alexander Korotkov (#18)
Re: SQL/JSON path issues/questions

On 2019-Jun-28, Alexander Korotkov wrote:

On Tue, Jun 25, 2019 at 6:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you for the catch! Please see the modified version of patch 0004
attached.

I tried to review and revise the part related to filters, but I failed
because I don't understand the notions used in the documentation.

What is the difference between filter expression and filter condition?
I can guess that filter expression contains question mark,
parentheses and filter condition inside. But this sentence is in
contradiction with my guess: "A filter expression must be enclosed in
parentheses and preceded by a question mark". So, filter expression
is inside the parentheses. Then what is filter condition? The same?

The SQL standard defines "JSON filter expressions" (in 9.39 of the 2016
edition). It does not use either term "filter condition" nor bare
"filter"; it uses "JSON path predicate" which is the part of the JSON
filter expression that is preceded by the question mark and enclosed by
parens.

Maybe we should stick with the standard terminology ...

--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#20Oleg Bartunov
obartunov@postgrespro.ru
In reply to: Alvaro Herrera (#19)
Re: SQL/JSON path issues/questions

On Fri, Jun 28, 2019 at 8:10 AM Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

On 2019-Jun-28, Alexander Korotkov wrote:

On Tue, Jun 25, 2019 at 6:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you for the catch! Please see the modified version of patch 0004
attached.

I tried to review and revise the part related to filters, but I failed
because I don't understand the notions used in the documentation.

What is the difference between filter expression and filter condition?
I can guess that filter expression contains question mark,
parentheses and filter condition inside. But this sentence is in
contradiction with my guess: "A filter expression must be enclosed in
parentheses and preceded by a question mark". So, filter expression
is inside the parentheses. Then what is filter condition? The same?

The SQL standard defines "JSON filter expressions" (in 9.39 of the 2016
edition). It does not use either term "filter condition" nor bare
"filter"; it uses "JSON path predicate" which is the part of the JSON
filter expression that is preceded by the question mark and enclosed by
parens.

Yes, this is what I used in my talk
http://www.sai.msu.su/~megera/postgres/talks/jsonpath-ibiza-2019.pdf

Maybe we should stick with the standard terminology ...

Sure.

As for the jsonpath documentation, I think we should remember, that
jsonpath is a part of SQL/JSON, and in the following releases we will
expand documentation to include SQL/JSON functions, so I suggest to
have one chapter SQL/JSON with following structure:
1. Introduction
1.1 SQL/JSON data model
1.2 SQL/JSON path language
1.3 <SQL/JSON functions> -- to be added
2. PostgreSQL implementation
2.1 jsonpath data type -- link from json data types
2.2 jsonpath functions and operators -- link from functions
2.3 Indexing

I plan to work on a separate chapter "JSON handling in PostgreSQL" for
PG13, which includes
JSON(b) data types, functions, indexing and SQL/JSON.

--
Álvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#21Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Oleg Bartunov (#20)
Re: SQL/JSON path issues/questions

On Fri, Jun 28, 2019 at 9:01 AM Oleg Bartunov <obartunov@postgrespro.ru> wrote:

On Fri, Jun 28, 2019 at 8:10 AM Alvaro Herrera <alvherre@2ndquadrant.com> wrote:

On 2019-Jun-28, Alexander Korotkov wrote:

On Tue, Jun 25, 2019 at 6:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you for the catch! Please see the modified version of patch 0004
attached.

I tried to review and revise the part related to filters, but I failed
because I don't understand the notions used in the documentation.

What is the difference between filter expression and filter condition?
I can guess that filter expression contains question mark,
parentheses and filter condition inside. But this sentence is in
contradiction with my guess: "A filter expression must be enclosed in
parentheses and preceded by a question mark". So, filter expression
is inside the parentheses. Then what is filter condition? The same?

The SQL standard defines "JSON filter expressions" (in 9.39 of the 2016
edition). It does not use either term "filter condition" nor bare
"filter"; it uses "JSON path predicate" which is the part of the JSON
filter expression that is preceded by the question mark and enclosed by
parens.

Yes, this is what I used in my talk
http://www.sai.msu.su/~megera/postgres/talks/jsonpath-ibiza-2019.pdf

Maybe we should stick with the standard terminology ...

Sure.

+1

As for the jsonpath documentation, I think we should remember, that
jsonpath is a part of SQL/JSON, and in the following releases we will
expand documentation to include SQL/JSON functions, so I suggest to
have one chapter SQL/JSON with following structure:
1. Introduction
1.1 SQL/JSON data model
1.2 SQL/JSON path language
1.3 <SQL/JSON functions> -- to be added
2. PostgreSQL implementation
2.1 jsonpath data type -- link from json data types
2.2 jsonpath functions and operators -- link from functions
2.3 Indexing

I plan to work on a separate chapter "JSON handling in PostgreSQL" for
PG13, which includes
JSON(b) data types, functions, indexing and SQL/JSON.

It would be great if you manage to do this.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#22Liudmila Mantrova
l.mantrova@postgrespro.ru
In reply to: Alexander Korotkov (#18)
1 attachment(s)
Re: SQL/JSON path issues/questions

On 6/28/19 6:47 AM, Alexander Korotkov wrote:

On Tue, Jun 25, 2019 at 6:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you for the catch! Please see the modified version of patch 0004
attached.

I tried to review and revise the part related to filters, but I failed
because I don't understand the notions used in the documentation.

What is the difference between filter expression and filter condition?
I can guess that filter expression contains question mark,
parentheses and filter condition inside. But this sentence is in
contradiction with my guess: "A filter expression must be enclosed in
parentheses and preceded by a question mark". So, filter expression
is inside the parentheses. Then what is filter condition? The same?

Each filter expression can provide one or more filters
that are applied to the result of the path evaluation.

So additionally to filter condition and filter expression we introduce
the notion of just filter. What is it? Could we make it without
introduction of new notion?

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Hi,

I have rechecked the standard and I agree that we should use "filter
expression" whenever possible.
"A filter expression must be enclosed in parentheses..." looks like an
oversight, so I fixed it. As for what's actually enclosed, I believe we
can still use the word "condition" here as it's easy to understand and
is already used in our docs, e.g. in description of the WHERE clause
that serves a similar purpose.
The new version of the patch fixes the terminology, tweaks the examples,
and provides some grammar and style fixes in the jsonpath-related chapters.

--
Liudmila Mantrova
Technical writer at Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

0004-clarify-jsonpath-docs-3.patchtext/x-patch; name=0004-clarify-jsonpath-docs-3.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 3a8581d..b0de624 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -11538,7 +11538,8 @@ table2-mapping
    from the JSON data, similar to XPath expressions used
    for SQL access to XML. In <productname>PostgreSQL</productname>,
    path expressions are implemented as the <type>jsonpath</type>
-   data type, described in <xref linkend="datatype-jsonpath"/>.
+   data type and can use any elements described in
+   <xref linkend="datatype-jsonpath"/>.
   </para>
 
   <para>JSON query functions and operators
@@ -11585,7 +11586,7 @@ table2-mapping
       },
       { "location":   [ 47.706, 13.2635 ],
         "start time": "2018-10-14 10:39:21",
-        "HR": 130
+        "HR": 135
       } ]
   }
 }
@@ -11637,23 +11638,33 @@ table2-mapping
 
   <para>
    When defining the path, you can also use one or more
-   <firstterm>filter expressions</firstterm>, which work similar to
-   the <literal>WHERE</literal> clause in SQL. Each filter expression
-   can provide one or more filtering conditions that are applied
-   to the result of the path evaluation. Each filter expression must
-   be enclosed in parentheses and preceded by a question mark.
-   Filter expressions are evaluated from left to right and can be nested.
-   The <literal>@</literal> variable denotes the current path evaluation
-   result to be filtered, and can be followed by one or more accessor
-   operators to define the JSON element by which to filter the result.
-   Functions and operators that can be used in the filtering condition
-   are listed in <xref linkend="functions-sqljson-filter-ex-table"/>.
-   SQL/JSON defines three-valued logic, so the result of the filter
-   expression may be <literal>true</literal>, <literal>false</literal>,
+   <firstterm>filter expressions</firstterm> that work similar to the
+   <literal>WHERE</literal> clause in SQL. A filter expression begins with
+   a question mark and provides a condition in parentheses:
+
+    <programlisting>
+? (<replaceable>condition</replaceable>)
+    </programlisting>
+  </para>
+
+  <para>
+   Filter expressions must be specified right after the path evaluation step
+   to which they are applied. The result of this step is filtered to include
+   only those items that satisfy the provided condition. SQL/JSON defines
+   three-valued logic, so the condition can be <literal>true</literal>, <literal>false</literal>,
    or <literal>unknown</literal>. The <literal>unknown</literal> value
-   plays the same role as SQL <literal>NULL</literal>. Further path
+   plays the same role as SQL <literal>NULL</literal> and can be tested
+   for with the <literal>is unknown</literal> predicate. Further path
    evaluation steps use only those items for which filter expressions
-   return true.
+   return <literal>true</literal>.
+  </para>
+
+  <para>
+   Functions and operators that can be used in filter expressions are listed
+   in <xref linkend="functions-sqljson-filter-ex-table"/>. The path
+   evaluation result to be filtered is denoted by the <literal>@</literal>
+   variable. It can be followed by one or more accessor operators to define
+   the JSON element on a lower nesting level by which to filter the result.
   </para>
 
   <para>
@@ -11667,8 +11678,8 @@ table2-mapping
   <para>
    To get the start time of segments with such values instead, you have to
    filter out irrelevant segments before returning the start time, so the
-   filter is applied to the previous step and the path in the filtering
-   condition is different:
+   filter expression is applied to the previous step, and the path used
+   in the condition is different:
 <programlisting>
 '$.track.segments[*] ? (@.HR &gt; 130)."start time"'
 </programlisting>
@@ -11693,9 +11704,9 @@ table2-mapping
   </para>
 
   <para>
-   You can also nest filters within each other:
+   You can also nest filter expressions within each other:
 <programlisting>
-'$.track ? (@.segments[*] ? (@.HR &gt; 130)).segments.size()'
+'$.track ? (exists(@.segments[*] ? (@.HR &gt; 130))).segments.size()'
 </programlisting>
    This expression returns the size of the track if it contains any
    segments with high heart rate values, or an empty sequence otherwise.
@@ -12285,7 +12296,7 @@ table2-mapping
        <row>
         <entry><literal>@?</literal></entry>
         <entry><type>jsonpath</type></entry>
-        <entry>Does JSON path returns any item for the specified JSON value?</entry>
+        <entry>Does JSON path return any item for the specified JSON value?</entry>
         <entry><literal>'{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)'</literal></entry>
        </row>
        <row>
@@ -12313,8 +12324,8 @@ table2-mapping
   <note>
    <para>
     The <literal>@?</literal> and <literal>@@</literal> operators suppress
-    errors including: lacking object field or array element, unexpected JSON
-    item type and numeric errors.
+    the following errors: lacking object field or array element, unexpected
+    JSON item type, and numeric errors.
     This behavior might be helpful while searching over JSON document
     collections of varying structure.
    </para>
@@ -13170,17 +13181,17 @@ table2-mapping
     <literal>jsonb_path_query</literal>, <literal>jsonb_path_query_array</literal> and
     <literal>jsonb_path_query_first</literal>
     functions have optional <literal>vars</literal> and <literal>silent</literal>
-    argument.
+    arguments.
    </para>
    <para>
-    When <literal>vars</literal> argument is specified, it constitutes an object
-    contained variables to be substituted into <literal>jsonpath</literal>
-    expression.
+    If the <literal>vars</literal> argument is specified, it provides an
+    object containing named variables to be substituted into a
+    <literal>jsonpath</literal> expression.
    </para>
    <para>
-    When <literal>silent</literal> argument is specified and has
-    <literal>true</literal> value, the same errors are suppressed as it is in
-    the <literal>@?</literal> and <literal>@@</literal> operators.
+    If the <literal>silent</literal> argument is specified and has the
+    <literal>true</literal> value, these functions suppress the same errors
+    as the <literal>@?</literal> and <literal>@@</literal> operators.
    </para>
   </note>
 
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index daebb4f..0d8e2c6 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -815,21 +815,18 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
         <literal>.**{<replaceable>level</replaceable>}</literal>
        </para>
        <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        <replaceable>upper_level</replaceable>}</literal>
-       </para>
-       <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        last}</literal>
+        <literal>.**{<replaceable>start_level</replaceable> to
+        <replaceable>end_level</replaceable>}</literal>
        </para>
       </entry>
       <entry>
        <para>
-        Same as <literal>.**</literal>, but with filter over nesting
-        level of JSON hierarchy.  Levels are specified as integers.
-        Zero level corresponds to current object.  This is a
-        <productname>PostgreSQL</productname> extension of the SQL/JSON
-        standard.
+        Same as <literal>.**</literal>, but with a filter over nesting
+        levels of JSON hierarchy. Nesting levels are specified as integers.
+        Zero level corresponds to the current object. To access the lowest
+        nesting level, you can use the <literal>last</literal> keyword.
+        This is a <productname>PostgreSQL</productname> extension of
+        the SQL/JSON standard.
        </para>
       </entry>
      </row>
@@ -841,19 +838,22 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
       </entry>
       <entry>
        <para>
-        Array element accessor.  <literal><replaceable>subscript</replaceable></literal>
-        might be given in two forms: <literal><replaceable>expr</replaceable></literal>
-        or <literal><replaceable>lower_expr</replaceable> to <replaceable>upper_expr</replaceable></literal>.
-        The first form specifies single array element by its index.  The second
-        form specified array slice by the range of indexes.  Zero index
-        corresponds to the first array element.
+        Array element accessor.
+        <literal><replaceable>subscript</replaceable></literal> can be
+        given in two forms: <literal><replaceable>index</replaceable></literal>
+        or <literal><replaceable>start_index</replaceable> to <replaceable>end_index</replaceable></literal>.
+        The first form returns a single array element by its index. The second
+        form returns an array slice by the range of indexes, including the
+        elements that correspond to the provided
+        <replaceable>start_index</replaceable> and <replaceable>end_index</replaceable>.
        </para>
        <para>
-        Expression inside subscript may consititue an integer,
-        numeric expression or any other <literal>jsonpath</literal> expression
-        returning single numeric value.  The <literal>last</literal> keyword
-        can be used in the expression denoting the last subscript in an array.
-        That's helpful for handling arrays of unknown length.
+        The specified <replaceable>index</replaceable> can be an integer, as
+        well as an expression returning a single numeric value, which is
+        automatically cast to integer. Zero index corresponds to the first
+        array element. You can also use the <literal>last</literal> keyword
+        to denote the last array element, which is useful for handling arrays
+        of unknown length.
        </para>
       </entry>
      </row>
#23Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Liudmila Mantrova (#22)
Re: SQL/JSON path issues/questions

Hi!

On Wed, Jul 3, 2019 at 5:27 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

I have rechecked the standard and I agree that we should use "filter
expression" whenever possible.
"A filter expression must be enclosed in parentheses..." looks like an
oversight, so I fixed it. As for what's actually enclosed, I believe we
can still use the word "condition" here as it's easy to understand and
is already used in our docs, e.g. in description of the WHERE clause
that serves a similar purpose.
The new version of the patch fixes the terminology, tweaks the examples,
and provides some grammar and style fixes in the jsonpath-related chapters.

It looks good to me. But this sentence looks a bit too complicated.

"It can be followed by one or more accessor operators to define the
JSON element on a lower nesting level by which to filter the result."

Could we phrase this as following?

"In order to filter the result by values lying on lower nesting level,
@ operator can be followed by one or more accessor operators."

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#24Liudmila Mantrova
l.mantrova@postgrespro.ru
In reply to: Alexander Korotkov (#23)
1 attachment(s)
Re: SQL/JSON path issues/questions

On 7/3/19 11:59 PM, Alexander Korotkov wrote:

Hi!

On Wed, Jul 3, 2019 at 5:27 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

I have rechecked the standard and I agree that we should use "filter
expression" whenever possible.
"A filter expression must be enclosed in parentheses..." looks like an
oversight, so I fixed it. As for what's actually enclosed, I believe we
can still use the word "condition" here as it's easy to understand and
is already used in our docs, e.g. in description of the WHERE clause
that serves a similar purpose.
The new version of the patch fixes the terminology, tweaks the examples,
and provides some grammar and style fixes in the jsonpath-related chapters.

It looks good to me. But this sentence looks a bit too complicated.

"It can be followed by one or more accessor operators to define the
JSON element on a lower nesting level by which to filter the result."

Could we phrase this as following?

"In order to filter the result by values lying on lower nesting level,
@ operator can be followed by one or more accessor operators."

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Thank  you!

I think we can make this sentence even shorter, the fix is attached:

"To refer to a JSON element stored at a lower nesting level, add one or
more accessor operators after <literal>@</literal>."

--
Liudmila Mantrova
Technical writer at Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

0004-clarify-jsonpath-docs-4.patchtext/x-patch; name=0004-clarify-jsonpath-docs-4.patchDownload
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 3a8581d..6d2aefb 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -11538,7 +11538,8 @@ table2-mapping
    from the JSON data, similar to XPath expressions used
    for SQL access to XML. In <productname>PostgreSQL</productname>,
    path expressions are implemented as the <type>jsonpath</type>
-   data type, described in <xref linkend="datatype-jsonpath"/>.
+   data type and can use any elements described in
+   <xref linkend="datatype-jsonpath"/>.
   </para>
 
   <para>JSON query functions and operators
@@ -11585,7 +11586,7 @@ table2-mapping
       },
       { "location":   [ 47.706, 13.2635 ],
         "start time": "2018-10-14 10:39:21",
-        "HR": 130
+        "HR": 135
       } ]
   }
 }
@@ -11637,23 +11638,33 @@ table2-mapping
 
   <para>
    When defining the path, you can also use one or more
-   <firstterm>filter expressions</firstterm>, which work similar to
-   the <literal>WHERE</literal> clause in SQL. Each filter expression
-   can provide one or more filtering conditions that are applied
-   to the result of the path evaluation. Each filter expression must
-   be enclosed in parentheses and preceded by a question mark.
-   Filter expressions are evaluated from left to right and can be nested.
-   The <literal>@</literal> variable denotes the current path evaluation
-   result to be filtered, and can be followed by one or more accessor
-   operators to define the JSON element by which to filter the result.
-   Functions and operators that can be used in the filtering condition
-   are listed in <xref linkend="functions-sqljson-filter-ex-table"/>.
-   SQL/JSON defines three-valued logic, so the result of the filter
-   expression may be <literal>true</literal>, <literal>false</literal>,
+   <firstterm>filter expressions</firstterm> that work similar to the
+   <literal>WHERE</literal> clause in SQL. A filter expression begins with
+   a question mark and provides a condition in parentheses:
+
+    <programlisting>
+? (<replaceable>condition</replaceable>)
+    </programlisting>
+  </para>
+
+  <para>
+   Filter expressions must be specified right after the path evaluation step
+   to which they are applied. The result of this step is filtered to include
+   only those items that satisfy the provided condition. SQL/JSON defines
+   three-valued logic, so the condition can be <literal>true</literal>, <literal>false</literal>,
    or <literal>unknown</literal>. The <literal>unknown</literal> value
-   plays the same role as SQL <literal>NULL</literal>. Further path
+   plays the same role as SQL <literal>NULL</literal> and can be tested
+   for with the <literal>is unknown</literal> predicate. Further path
    evaluation steps use only those items for which filter expressions
-   return true.
+   return <literal>true</literal>.
+  </para>
+
+  <para>
+   Functions and operators that can be used in filter expressions are listed
+   in <xref linkend="functions-sqljson-filter-ex-table"/>. The path
+   evaluation result to be filtered is denoted by the <literal>@</literal>
+   variable. To refer to a JSON element stored at a lower nesting level,
+   add one or more accessor operators after <literal>@</literal>.
   </para>
 
   <para>
@@ -11667,8 +11678,8 @@ table2-mapping
   <para>
    To get the start time of segments with such values instead, you have to
    filter out irrelevant segments before returning the start time, so the
-   filter is applied to the previous step and the path in the filtering
-   condition is different:
+   filter expression is applied to the previous step, and the path used
+   in the condition is different:
 <programlisting>
 '$.track.segments[*] ? (@.HR &gt; 130)."start time"'
 </programlisting>
@@ -11693,9 +11704,9 @@ table2-mapping
   </para>
 
   <para>
-   You can also nest filters within each other:
+   You can also nest filter expressions within each other:
 <programlisting>
-'$.track ? (@.segments[*] ? (@.HR &gt; 130)).segments.size()'
+'$.track ? (exists(@.segments[*] ? (@.HR &gt; 130))).segments.size()'
 </programlisting>
    This expression returns the size of the track if it contains any
    segments with high heart rate values, or an empty sequence otherwise.
@@ -12285,7 +12296,7 @@ table2-mapping
        <row>
         <entry><literal>@?</literal></entry>
         <entry><type>jsonpath</type></entry>
-        <entry>Does JSON path returns any item for the specified JSON value?</entry>
+        <entry>Does JSON path return any item for the specified JSON value?</entry>
         <entry><literal>'{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)'</literal></entry>
        </row>
        <row>
@@ -12313,8 +12324,8 @@ table2-mapping
   <note>
    <para>
     The <literal>@?</literal> and <literal>@@</literal> operators suppress
-    errors including: lacking object field or array element, unexpected JSON
-    item type and numeric errors.
+    the following errors: lacking object field or array element, unexpected
+    JSON item type, and numeric errors.
     This behavior might be helpful while searching over JSON document
     collections of varying structure.
    </para>
@@ -13170,17 +13181,17 @@ table2-mapping
     <literal>jsonb_path_query</literal>, <literal>jsonb_path_query_array</literal> and
     <literal>jsonb_path_query_first</literal>
     functions have optional <literal>vars</literal> and <literal>silent</literal>
-    argument.
+    arguments.
    </para>
    <para>
-    When <literal>vars</literal> argument is specified, it constitutes an object
-    contained variables to be substituted into <literal>jsonpath</literal>
-    expression.
+    If the <literal>vars</literal> argument is specified, it provides an
+    object containing named variables to be substituted into a
+    <literal>jsonpath</literal> expression.
    </para>
    <para>
-    When <literal>silent</literal> argument is specified and has
-    <literal>true</literal> value, the same errors are suppressed as it is in
-    the <literal>@?</literal> and <literal>@@</literal> operators.
+    If the <literal>silent</literal> argument is specified and has the
+    <literal>true</literal> value, these functions suppress the same errors
+    as the <literal>@?</literal> and <literal>@@</literal> operators.
    </para>
   </note>
 
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index daebb4f..0d8e2c6 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -815,21 +815,18 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
         <literal>.**{<replaceable>level</replaceable>}</literal>
        </para>
        <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        <replaceable>upper_level</replaceable>}</literal>
-       </para>
-       <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        last}</literal>
+        <literal>.**{<replaceable>start_level</replaceable> to
+        <replaceable>end_level</replaceable>}</literal>
        </para>
       </entry>
       <entry>
        <para>
-        Same as <literal>.**</literal>, but with filter over nesting
-        level of JSON hierarchy.  Levels are specified as integers.
-        Zero level corresponds to current object.  This is a
-        <productname>PostgreSQL</productname> extension of the SQL/JSON
-        standard.
+        Same as <literal>.**</literal>, but with a filter over nesting
+        levels of JSON hierarchy. Nesting levels are specified as integers.
+        Zero level corresponds to the current object. To access the lowest
+        nesting level, you can use the <literal>last</literal> keyword.
+        This is a <productname>PostgreSQL</productname> extension of
+        the SQL/JSON standard.
        </para>
       </entry>
      </row>
@@ -841,19 +838,22 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
       </entry>
       <entry>
        <para>
-        Array element accessor.  <literal><replaceable>subscript</replaceable></literal>
-        might be given in two forms: <literal><replaceable>expr</replaceable></literal>
-        or <literal><replaceable>lower_expr</replaceable> to <replaceable>upper_expr</replaceable></literal>.
-        The first form specifies single array element by its index.  The second
-        form specified array slice by the range of indexes.  Zero index
-        corresponds to the first array element.
+        Array element accessor.
+        <literal><replaceable>subscript</replaceable></literal> can be
+        given in two forms: <literal><replaceable>index</replaceable></literal>
+        or <literal><replaceable>start_index</replaceable> to <replaceable>end_index</replaceable></literal>.
+        The first form returns a single array element by its index. The second
+        form returns an array slice by the range of indexes, including the
+        elements that correspond to the provided
+        <replaceable>start_index</replaceable> and <replaceable>end_index</replaceable>.
        </para>
        <para>
-        Expression inside subscript may consititue an integer,
-        numeric expression or any other <literal>jsonpath</literal> expression
-        returning single numeric value.  The <literal>last</literal> keyword
-        can be used in the expression denoting the last subscript in an array.
-        That's helpful for handling arrays of unknown length.
+        The specified <replaceable>index</replaceable> can be an integer, as
+        well as an expression returning a single numeric value, which is
+        automatically cast to integer. Zero index corresponds to the first
+        array element. You can also use the <literal>last</literal> keyword
+        to denote the last array element, which is useful for handling arrays
+        of unknown length.
        </para>
       </entry>
      </row>
#25Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Liudmila Mantrova (#24)
1 attachment(s)
Re: SQL/JSON path issues/questions

On Thu, Jul 4, 2019 at 4:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you!

I think we can make this sentence even shorter, the fix is attached:

"To refer to a JSON element stored at a lower nesting level, add one or
more accessor operators after <literal>@</literal>."

Thanks, looks good to me. Attached revision of patch contains commit
message. I'm going to commit this on no objections.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

Attachments:

0004-clarify-jsonpath-docs-5.patchapplication/octet-stream; name=0004-clarify-jsonpath-docs-5.patchDownload
commit 49af175c43c86fa9c268674138d589e207f380c3
Author: Alexander Korotkov <akorotkov@postgresql.org>
Date:   Mon Jul 8 00:22:59 2019 +0300

    Assorted fixes for jsonpath documentation
    
    This commit contains assorted fixes for jsonpath documentation including:
    grammar fixes, incorrect examples fixes as well as wording improvements.
    
    Discussion: https://postgr.es/m/CAA-aLv4VVX%3Db9RK5hkfPXJczqaiTdqO04teW9i0wiQVhdKcqzw%40mail.gmail.com
    Author: Liudmila Mantrova
    Reviewed-by: Alexander Korotkov
    Reported-by: Thom Brown

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index eeb3c46316a..7a80acecffa 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -11514,7 +11514,8 @@ table2-mapping
    from the JSON data, similar to XPath expressions used
    for SQL access to XML. In <productname>PostgreSQL</productname>,
    path expressions are implemented as the <type>jsonpath</type>
-   data type, described in <xref linkend="datatype-jsonpath"/>.
+   data type and can use any elements described in
+   <xref linkend="datatype-jsonpath"/>.
   </para>
 
   <para>JSON query functions and operators
@@ -11561,7 +11562,7 @@ table2-mapping
       },
       { "location":   [ 47.706, 13.2635 ],
         "start time": "2018-10-14 10:39:21",
-        "HR": 130
+        "HR": 135
       } ]
   }
 }
@@ -11613,23 +11614,33 @@ table2-mapping
 
   <para>
    When defining the path, you can also use one or more
-   <firstterm>filter expressions</firstterm>, which work similar to
-   the <literal>WHERE</literal> clause in SQL. Each filter expression
-   can provide one or more filtering conditions that are applied
-   to the result of the path evaluation. Each filter expression must
-   be enclosed in parentheses and preceded by a question mark.
-   Filter expressions are evaluated from left to right and can be nested.
-   The <literal>@</literal> variable denotes the current path evaluation
-   result to be filtered, and can be followed by one or more accessor
-   operators to define the JSON element by which to filter the result.
-   Functions and operators that can be used in the filtering condition
-   are listed in <xref linkend="functions-sqljson-filter-ex-table"/>.
-   SQL/JSON defines three-valued logic, so the result of the filter
-   expression may be <literal>true</literal>, <literal>false</literal>,
+   <firstterm>filter expressions</firstterm> that work similar to the
+   <literal>WHERE</literal> clause in SQL. A filter expression begins with
+   a question mark and provides a condition in parentheses:
+
+    <programlisting>
+? (<replaceable>condition</replaceable>)
+    </programlisting>
+  </para>
+
+  <para>
+   Filter expressions must be specified right after the path evaluation step
+   to which they are applied. The result of this step is filtered to include
+   only those items that satisfy the provided condition. SQL/JSON defines
+   three-valued logic, so the condition can be <literal>true</literal>, <literal>false</literal>,
    or <literal>unknown</literal>. The <literal>unknown</literal> value
-   plays the same role as SQL <literal>NULL</literal>. Further path
+   plays the same role as SQL <literal>NULL</literal> and can be tested
+   for with the <literal>is unknown</literal> predicate. Further path
    evaluation steps use only those items for which filter expressions
-   return true.
+   return <literal>true</literal>.
+  </para>
+
+  <para>
+   Functions and operators that can be used in filter expressions are listed
+   in <xref linkend="functions-sqljson-filter-ex-table"/>. The path
+   evaluation result to be filtered is denoted by the <literal>@</literal>
+   variable. To refer to a JSON element stored at a lower nesting level,
+   add one or more accessor operators after <literal>@</literal>.
   </para>
 
   <para>
@@ -11643,8 +11654,8 @@ table2-mapping
   <para>
    To get the start time of segments with such values instead, you have to
    filter out irrelevant segments before returning the start time, so the
-   filter is applied to the previous step and the path in the filtering
-   condition is different:
+   filter expression is applied to the previous step, and the path used
+   in the condition is different:
 <programlisting>
 '$.track.segments[*] ? (@.HR &gt; 130)."start time"'
 </programlisting>
@@ -11669,9 +11680,9 @@ table2-mapping
   </para>
 
   <para>
-   You can also nest filters within each other:
+   You can also nest filter expressions within each other:
 <programlisting>
-'$.track ? (@.segments[*] ? (@.HR &gt; 130)).segments.size()'
+'$.track ? (exists(@.segments[*] ? (@.HR &gt; 130))).segments.size()'
 </programlisting>
    This expression returns the size of the track if it contains any
    segments with high heart rate values, or an empty sequence otherwise.
@@ -12261,7 +12272,7 @@ table2-mapping
        <row>
         <entry><literal>@?</literal></entry>
         <entry><type>jsonpath</type></entry>
-        <entry>Does JSON path returns any item for the specified JSON value?</entry>
+        <entry>Does JSON path return any item for the specified JSON value?</entry>
         <entry><literal>'{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)'</literal></entry>
        </row>
        <row>
@@ -12289,8 +12300,8 @@ table2-mapping
   <note>
    <para>
     The <literal>@?</literal> and <literal>@@</literal> operators suppress
-    errors including: lacking object field or array element, unexpected JSON
-    item type and numeric errors.
+    the following errors: lacking object field or array element, unexpected
+    JSON item type, and numeric errors.
     This behavior might be helpful while searching over JSON document
     collections of varying structure.
    </para>
@@ -13146,17 +13157,17 @@ table2-mapping
     <literal>jsonb_path_query</literal>, <literal>jsonb_path_query_array</literal> and
     <literal>jsonb_path_query_first</literal>
     functions have optional <literal>vars</literal> and <literal>silent</literal>
-    argument.
+    arguments.
    </para>
    <para>
-    When <literal>vars</literal> argument is specified, it constitutes an object
-    contained variables to be substituted into <literal>jsonpath</literal>
-    expression.
+    If the <literal>vars</literal> argument is specified, it provides an
+    object containing named variables to be substituted into a
+    <literal>jsonpath</literal> expression.
    </para>
    <para>
-    When <literal>silent</literal> argument is specified and has
-    <literal>true</literal> value, the same errors are suppressed as it is in
-    the <literal>@?</literal> and <literal>@@</literal> operators.
+    If the <literal>silent</literal> argument is specified and has the
+    <literal>true</literal> value, these functions suppress the same errors
+    as the <literal>@?</literal> and <literal>@@</literal> operators.
    </para>
   </note>
 
diff --git a/doc/src/sgml/json.sgml b/doc/src/sgml/json.sgml
index 2aa98024ae9..0d8e2c6de4b 100644
--- a/doc/src/sgml/json.sgml
+++ b/doc/src/sgml/json.sgml
@@ -815,21 +815,18 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
         <literal>.**{<replaceable>level</replaceable>}</literal>
        </para>
        <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        <replaceable>upper_level</replaceable>}</literal>
-       </para>
-       <para>
-        <literal>.**{<replaceable>lower_level</replaceable> to
-        last}</literal>
+        <literal>.**{<replaceable>start_level</replaceable> to
+        <replaceable>end_level</replaceable>}</literal>
        </para>
       </entry>
       <entry>
        <para>
-        Same as <literal>.**</literal>, but with filter over nesting
-        level of JSON hierarchy.  Levels are specified as integers.
-        Zero level corresponds to current object.  This is a
-        <productname>PostgreSQL</productname> extension of the SQL/JSON
-        standard.
+        Same as <literal>.**</literal>, but with a filter over nesting
+        levels of JSON hierarchy. Nesting levels are specified as integers.
+        Zero level corresponds to the current object. To access the lowest
+        nesting level, you can use the <literal>last</literal> keyword.
+        This is a <productname>PostgreSQL</productname> extension of
+        the SQL/JSON standard.
        </para>
       </entry>
      </row>
@@ -841,19 +838,22 @@ SELECT jdoc-&gt;'guid', jdoc-&gt;'name' FROM api WHERE jdoc @&gt; '{"tags": ["qu
       </entry>
       <entry>
        <para>
-        Array element accessor.  <literal><replaceable>subscript</replaceable></literal>
-        might be given in two forms: <literal><replaceable>expr</replaceable></literal>
-        or <literal><replaceable>lower_expr</replaceable> to <replaceable>upper_expr</replaceable></literal>.
-        The first form specifies single array element by its index.  The second
-        form specified array slice by the range of indexes.  Zero index
-        corresponds to the first array element.
+        Array element accessor.
+        <literal><replaceable>subscript</replaceable></literal> can be
+        given in two forms: <literal><replaceable>index</replaceable></literal>
+        or <literal><replaceable>start_index</replaceable> to <replaceable>end_index</replaceable></literal>.
+        The first form returns a single array element by its index. The second
+        form returns an array slice by the range of indexes, including the
+        elements that correspond to the provided
+        <replaceable>start_index</replaceable> and <replaceable>end_index</replaceable>.
        </para>
        <para>
-        An expression in the subscript may be an integer,
-        numeric expression, or any other <literal>jsonpath</literal> expression
-        returning single numeric value.  The <literal>last</literal> keyword
-        can be used in the expression denoting the last subscript in an array.
-        That's helpful for handling arrays of unknown length.
+        The specified <replaceable>index</replaceable> can be an integer, as
+        well as an expression returning a single numeric value, which is
+        automatically cast to integer. Zero index corresponds to the first
+        array element. You can also use the <literal>last</literal> keyword
+        to denote the last array element, which is useful for handling arrays
+        of unknown length.
        </para>
       </entry>
      </row>
#26Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Alexander Korotkov (#25)
Re: SQL/JSON path issues/questions

On Mon, Jul 8, 2019 at 12:30 AM Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Thu, Jul 4, 2019 at 4:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you!

I think we can make this sentence even shorter, the fix is attached:

"To refer to a JSON element stored at a lower nesting level, add one or
more accessor operators after <literal>@</literal>."

Thanks, looks good to me. Attached revision of patch contains commit
message. I'm going to commit this on no objections.

So, pushed!

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#27Thom Brown
thom@linux.com
In reply to: Alexander Korotkov (#26)
Re: SQL/JSON path issues/questions

On Wed, 10 Jul 2019 at 05:58, Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Mon, Jul 8, 2019 at 12:30 AM Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Thu, Jul 4, 2019 at 4:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you!

I think we can make this sentence even shorter, the fix is attached:

"To refer to a JSON element stored at a lower nesting level, add one or
more accessor operators after <literal>@</literal>."

Thanks, looks good to me. Attached revision of patch contains commit
message. I'm going to commit this on no objections.

So, pushed!

I've just noticed the >= operator shows up as just > in the "jsonpath
Filter Expression Elements" table, and the <= example only shows <.

Thom

#28Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Thom Brown (#27)
Re: SQL/JSON path issues/questions

On Thu, Jul 11, 2019 at 5:10 PM Thom Brown <thom@linux.com> wrote:

On Wed, 10 Jul 2019 at 05:58, Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Mon, Jul 8, 2019 at 12:30 AM Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Thu, Jul 4, 2019 at 4:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you!

I think we can make this sentence even shorter, the fix is attached:

"To refer to a JSON element stored at a lower nesting level, add one or
more accessor operators after <literal>@</literal>."

Thanks, looks good to me. Attached revision of patch contains commit
message. I'm going to commit this on no objections.

So, pushed!

I've just noticed the >= operator shows up as just > in the "jsonpath
Filter Expression Elements" table, and the <= example only shows <.

Thank you for catching this! Fix just pushed.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#29Thom Brown
thom@linux.com
In reply to: Alexander Korotkov (#28)
Re: SQL/JSON path issues/questions

On Thu, 11 Jul 2019 at 16:23, Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Thu, Jul 11, 2019 at 5:10 PM Thom Brown <thom@linux.com> wrote:

On Wed, 10 Jul 2019 at 05:58, Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Mon, Jul 8, 2019 at 12:30 AM Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Thu, Jul 4, 2019 at 4:38 PM Liudmila Mantrova
<l.mantrova@postgrespro.ru> wrote:

Thank you!

I think we can make this sentence even shorter, the fix is attached:

"To refer to a JSON element stored at a lower nesting level, add one or
more accessor operators after <literal>@</literal>."

Thanks, looks good to me. Attached revision of patch contains commit
message. I'm going to commit this on no objections.

So, pushed!

I've just noticed the >= operator shows up as just > in the "jsonpath
Filter Expression Elements" table, and the <= example only shows <.

Thank you for catching this! Fix just pushed.

Thanks.

Now I'm looking at the @? and @@ operators, and getting a bit
confused. This following query returns true, but I can't determine
why:

# SELECT '{"a":[1,2,3,4,5]}'::jsonb @? '$.b == "hello"'::jsonpath;
?column?
----------
t
(1 row)

"b" is not a valid item, so there should be no match. Perhaps it's my
misunderstanding of how these operators are supposed to work, but the
documentation is quite terse on the behaviour.

Thom

#30Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Thom Brown (#29)
Re: SQL/JSON path issues/questions

On Tue, Jul 16, 2019 at 9:22 PM Thom Brown <thom@linux.com> wrote:

Now I'm looking at the @? and @@ operators, and getting a bit
confused. This following query returns true, but I can't determine
why:

# SELECT '{"a":[1,2,3,4,5]}'::jsonb @? '$.b == "hello"'::jsonpath;
?column?
----------
t
(1 row)

"b" is not a valid item, so there should be no match. Perhaps it's my
misunderstanding of how these operators are supposed to work, but the
documentation is quite terse on the behaviour.

So, the result of jsonpath evaluation is single value "false".

# SELECT jsonb_path_query_array('{"a":[1,2,3,4,5]}'::jsonb, '$.b == "hello"');
jsonb_path_query_array
------------------------
[false]
(1 row)

@@ operator checks that result is "true". This is why it returns "false".

@? operator checks if result is not empty. So, it's single "false"
value, not empty list. This is why it returns "true".

Perhaps, we need to clarify this in docs providing more explanation.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#31Thom Brown
thom@linux.com
In reply to: Alexander Korotkov (#30)
Re: SQL/JSON path issues/questions

On Tue, 16 Jul 2019 at 19:44, Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Tue, Jul 16, 2019 at 9:22 PM Thom Brown <thom@linux.com> wrote:

Now I'm looking at the @? and @@ operators, and getting a bit
confused. This following query returns true, but I can't determine
why:

# SELECT '{"a":[1,2,3,4,5]}'::jsonb @? '$.b == "hello"'::jsonpath;
?column?
----------
t
(1 row)

"b" is not a valid item, so there should be no match. Perhaps it's my
misunderstanding of how these operators are supposed to work, but the
documentation is quite terse on the behaviour.

So, the result of jsonpath evaluation is single value "false".

# SELECT jsonb_path_query_array('{"a":[1,2,3,4,5]}'::jsonb, '$.b == "hello"');
jsonb_path_query_array
------------------------
[false]
(1 row)

@@ operator checks that result is "true". This is why it returns "false".

@? operator checks if result is not empty. So, it's single "false"
value, not empty list. This is why it returns "true".

Perhaps, we need to clarify this in docs providing more explanation.

Understood. Thanks.

Also, is there a reason why jsonb_path_query doesn't have an operator analog?

Thom

#32Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Thom Brown (#31)
Re: SQL/JSON path issues/questions

On Thu, Jul 18, 2019 at 5:08 PM Thom Brown <thom@linux.com> wrote:

On Tue, 16 Jul 2019 at 19:44, Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Tue, Jul 16, 2019 at 9:22 PM Thom Brown <thom@linux.com> wrote:

Now I'm looking at the @? and @@ operators, and getting a bit
confused. This following query returns true, but I can't determine
why:

# SELECT '{"a":[1,2,3,4,5]}'::jsonb @? '$.b == "hello"'::jsonpath;
?column?
----------
t
(1 row)

"b" is not a valid item, so there should be no match. Perhaps it's my
misunderstanding of how these operators are supposed to work, but the
documentation is quite terse on the behaviour.

So, the result of jsonpath evaluation is single value "false".

# SELECT jsonb_path_query_array('{"a":[1,2,3,4,5]}'::jsonb, '$.b == "hello"');
jsonb_path_query_array
------------------------
[false]
(1 row)

@@ operator checks that result is "true". This is why it returns "false".

@? operator checks if result is not empty. So, it's single "false"
value, not empty list. This is why it returns "true".

Perhaps, we need to clarify this in docs providing more explanation.

Understood. Thanks.

Also, is there a reason why jsonb_path_query doesn't have an operator analog?

The point of existing operator analogues is index support. We
introduced operators for searches we can accelerate using GIN indexes.

jsonb_path_query() doesn't return bool. So, even if we have an
operator for that, it wouldn't get index support.

However, we can discuss introduction of operator analogues for other
functions as syntax sugar.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#33Steven Pousty
steve.pousty@gmail.com
In reply to: Alexander Korotkov (#32)
Re: SQL/JSON path issues/questions

I would like to help review this documentation. Can you please point me in
the right direction?
Thanks
Steve

On Fri, Jul 19, 2019 at 2:02 AM Alexander Korotkov <
a.korotkov@postgrespro.ru> wrote:

Show quoted text

On Thu, Jul 18, 2019 at 5:08 PM Thom Brown <thom@linux.com> wrote:

On Tue, 16 Jul 2019 at 19:44, Alexander Korotkov
<a.korotkov@postgrespro.ru> wrote:

On Tue, Jul 16, 2019 at 9:22 PM Thom Brown <thom@linux.com> wrote:

Now I'm looking at the @? and @@ operators, and getting a bit
confused. This following query returns true, but I can't determine
why:

# SELECT '{"a":[1,2,3,4,5]}'::jsonb @? '$.b == "hello"'::jsonpath;
?column?
----------
t
(1 row)

"b" is not a valid item, so there should be no match. Perhaps it's

my

misunderstanding of how these operators are supposed to work, but the
documentation is quite terse on the behaviour.

So, the result of jsonpath evaluation is single value "false".

# SELECT jsonb_path_query_array('{"a":[1,2,3,4,5]}'::jsonb, '$.b ==

"hello"');

jsonb_path_query_array
------------------------
[false]
(1 row)

@@ operator checks that result is "true". This is why it returns

"false".

@? operator checks if result is not empty. So, it's single "false"
value, not empty list. This is why it returns "true".

Perhaps, we need to clarify this in docs providing more explanation.

Understood. Thanks.

Also, is there a reason why jsonb_path_query doesn't have an operator

analog?

The point of existing operator analogues is index support. We
introduced operators for searches we can accelerate using GIN indexes.

jsonb_path_query() doesn't return bool. So, even if we have an
operator for that, it wouldn't get index support.

However, we can discuss introduction of operator analogues for other
functions as syntax sugar.

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#34Alexander Korotkov
a.korotkov@postgrespro.ru
In reply to: Steven Pousty (#33)
Re: SQL/JSON path issues/questions

Hi Steven,

On Fri, Jul 19, 2019 at 9:53 PM Steven Pousty <steve.pousty@gmail.com> wrote:

I would like to help review this documentation. Can you please point me in the right direction?

Thank you for your interest. You're welcome to do review.

Please take a look at instruction for reviewing a patch [1] and
working with git [2]. Also, in order to build a doc you will need to
setup a toolset first [3].

Links

1. https://wiki.postgresql.org/wiki/Reviewing_a_Patch
2. https://wiki.postgresql.org/wiki/Working_with_git#Testing_a_patch
3. https://www.postgresql.org/docs/devel/docguide-toolsets.html

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#35Steven Pousty
steve.pousty@gmail.com
In reply to: Alexander Korotkov (#34)
Re: SQL/JSON path issues/questions

Thanks so much, hope to get to it over this weekend.

On Sat, Jul 20, 2019, 11:48 AM Alexander Korotkov <a.korotkov@postgrespro.ru>
wrote:

Show quoted text

Hi Steven,

On Fri, Jul 19, 2019 at 9:53 PM Steven Pousty <steve.pousty@gmail.com>
wrote:

I would like to help review this documentation. Can you please point me

in the right direction?

Thank you for your interest. You're welcome to do review.

Please take a look at instruction for reviewing a patch [1] and
working with git [2]. Also, in order to build a doc you will need to
setup a toolset first [3].

Links

1. https://wiki.postgresql.org/wiki/Reviewing_a_Patch
2. https://wiki.postgresql.org/wiki/Working_with_git#Testing_a_patch
3. https://www.postgresql.org/docs/devel/docguide-toolsets.html

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company

#36Steven Pousty
steve.pousty@gmail.com
In reply to: Alexander Korotkov (#34)
Re: SQL/JSON path issues/questions

Ok I have the toolset.
Where do I find the PR for the doc on this work. I only feel qualified to
review the doc.
Thanks
Steve

On Sat, Jul 20, 2019 at 11:48 AM Alexander Korotkov <
a.korotkov@postgrespro.ru> wrote:

Show quoted text

Hi Steven,

On Fri, Jul 19, 2019 at 9:53 PM Steven Pousty <steve.pousty@gmail.com>
wrote:

I would like to help review this documentation. Can you please point me

in the right direction?

Thank you for your interest. You're welcome to do review.

Please take a look at instruction for reviewing a patch [1] and
working with git [2]. Also, in order to build a doc you will need to
setup a toolset first [3].

Links

1. https://wiki.postgresql.org/wiki/Reviewing_a_Patch
2. https://wiki.postgresql.org/wiki/Working_with_git#Testing_a_patch
3. https://www.postgresql.org/docs/devel/docguide-toolsets.html

------
Alexander Korotkov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company