]> granicus.if.org Git - postgresql/commitdiff
Support 'q' flag in jsonpath 'like_regex' predicate
authorAlexander Korotkov <akorotkov@postgresql.org>
Wed, 19 Jun 2019 19:40:58 +0000 (22:40 +0300)
committerAlexander Korotkov <akorotkov@postgresql.org>
Wed, 19 Jun 2019 19:41:57 +0000 (22:41 +0300)
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

src/backend/utils/adt/jsonpath.c
src/backend/utils/adt/jsonpath_exec.c
src/backend/utils/adt/jsonpath_gram.y
src/include/utils/jsonpath.h
src/test/regress/expected/jsonb_jsonpath.out
src/test/regress/expected/jsonpath.out
src/test/regress/sql/jsonb_jsonpath.sql
src/test/regress/sql/jsonpath.sql

index d5da1558670d334b225b1e58e9a55a283bce22a1..87ae60e490f6232bf211276e50f7fb9ed6ee8784 100644 (file)
@@ -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, '"');
                        }
index 873d64b630465fe2b4a576262e2f084412efd690..6bf4dcaec33360c04077302b3d11c71abaa4dd30 100644 (file)
@@ -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,
index 22c2089f78fd62deca78534c3ccc348f376c943b..a0a930ccf0cb679976338ee5ea7ecb324636165d 100644 (file)
@@ -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),
index 3e9d60cb760a0a4a642f5098f4d2911c07cd3322..40ad5fda928c1ebba0c4dc0fe0bd8d5c6477422a 100644 (file)
@@ -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.
index b486fb602a3e4f8f40b7bb87d74a2549fc9cd451..31a871af0289a8891ae6d58fadbeb8f284ad1aa3 100644 (file)
@@ -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 
index 0f9cd17e2e9dc915284ced397e4e5425cc7d4412..ecdd453942b2ca48a6082152652c3cb49cc2fbef 100644 (file)
@@ -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;
index 464ff94be3774f4f5e5daab37613f112e5e94651..733fbd4e0d032fd7123a86819fd2a8ef69372f14 100644 (file)
@@ -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
 
index 9171ddbc6cd8a8d87d3b9e8ecb5c1efa6d6a5e63..29ea77a4858094e9f9ed485dd33ce8f739ee092c 100644 (file)
@@ -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;