diff options
Diffstat (limited to 'src/backend/utils/adt')
-rw-r--r-- | src/backend/utils/adt/jsonpath.c | 2 | ||||
-rw-r--r-- | src/backend/utils/adt/jsonpath_exec.c | 26 | ||||
-rw-r--r-- | src/backend/utils/adt/jsonpath_gram.y | 64 |
3 files changed, 52 insertions, 40 deletions
diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c index 87ae60e490f..7f322485e7b 100644 --- a/src/backend/utils/adt/jsonpath.c +++ b/src/backend/utils/adt/jsonpath.c @@ -557,7 +557,7 @@ printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey, if (v->content.like_regex.flags & JSP_REGEX_ICASE) appendStringInfoChar(buf, 'i'); - if (v->content.like_regex.flags & JSP_REGEX_SLINE) + if (v->content.like_regex.flags & JSP_REGEX_DOTALL) appendStringInfoChar(buf, 's'); if (v->content.like_regex.flags & JSP_REGEX_MLINE) appendStringInfoChar(buf, 'm'); diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 22ec578d778..fbb8392fe96 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -1645,34 +1645,10 @@ executeLikeRegex(JsonPathItem *jsp, JsonbValue *str, JsonbValue *rarg, /* Cache regex text and converted flags. */ if (!cxt->regex) { - uint32 flags = jsp->content.like_regex.flags; - cxt->regex = cstring_to_text_with_len(jsp->content.like_regex.pattern, jsp->content.like_regex.patternlen); - - /* Convert regex flags. */ - cxt->cflags = REG_ADVANCED; - - if (flags & JSP_REGEX_ICASE) - cxt->cflags |= REG_ICASE; - if (flags & JSP_REGEX_MLINE) - cxt->cflags |= REG_NEWLINE; - if (flags & JSP_REGEX_SLINE) - 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; - } + cxt->cflags = jspConvertRegexFlags(jsp->content.like_regex.flags); } 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 a0a930ccf0c..4681f1f0d00 100644 --- a/src/backend/utils/adt/jsonpath_gram.y +++ b/src/backend/utils/adt/jsonpath_gram.y @@ -481,42 +481,32 @@ makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern, { JsonPathParseItem *v = makeItemType(jpiLikeRegex); int i; - int cflags = REG_ADVANCED; + int cflags; v->value.like_regex.expr = expr; v->value.like_regex.pattern = pattern->val; v->value.like_regex.patternlen = pattern->len; - v->value.like_regex.flags = 0; + /* Parse the flags string, convert to bitmask. Duplicate flags are OK. */ + v->value.like_regex.flags = 0; for (i = 0; flags && i < flags->len; i++) { switch (flags->val[i]) { case 'i': v->value.like_regex.flags |= JSP_REGEX_ICASE; - cflags |= REG_ICASE; break; case 's': - v->value.like_regex.flags &= ~JSP_REGEX_MLINE; - v->value.like_regex.flags |= JSP_REGEX_SLINE; - cflags |= REG_NEWLINE; + v->value.like_regex.flags |= JSP_REGEX_DOTALL; break; case 'm': - v->value.like_regex.flags &= ~JSP_REGEX_SLINE; v->value.like_regex.flags |= JSP_REGEX_MLINE; - cflags &= ~REG_NEWLINE; break; case 'x': 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, @@ -528,6 +518,9 @@ makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern, } } + /* Convert flags to what RE_compile_and_cache needs */ + cflags = jspConvertRegexFlags(v->value.like_regex.flags); + /* check regex validity */ (void) RE_compile_and_cache(cstring_to_text_with_len(pattern->val, pattern->len), @@ -537,6 +530,49 @@ makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern, } /* + * Convert from XQuery regex flags to those recognized by our regex library. + */ +int +jspConvertRegexFlags(uint32 xflags) +{ + /* By default, XQuery is very nearly the same as Spencer's AREs */ + int cflags = REG_ADVANCED; + + /* Ignore-case means the same thing, too, modulo locale issues */ + if (xflags & JSP_REGEX_ICASE) + cflags |= REG_ICASE; + + /* Per XQuery spec, if 'q' is specified then 'm', 's', 'x' are ignored */ + if (xflags & JSP_REGEX_QUOTE) + { + cflags &= ~REG_ADVANCED; + cflags |= REG_QUOTE; + } + else + { + /* Note that dotall mode is the default in POSIX */ + if (!(xflags & JSP_REGEX_DOTALL)) + cflags |= REG_NLSTOP; + if (xflags & JSP_REGEX_MLINE) + cflags |= REG_NLANCH; + + /* + * XQuery's 'x' mode is related to Spencer's expanded mode, but it's + * not really enough alike to justify treating JSP_REGEX_WSPACE as + * REG_EXPANDED. For now we treat 'x' as unimplemented; perhaps in + * future we'll modify the regex library to have an option for + * XQuery-style ignore-whitespace mode. + */ + if (xflags & JSP_REGEX_WSPACE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("XQuery \"x\" flag (expanded regular expressions) is not implemented"))); + } + + return cflags; +} + +/* * jsonpath_scan.l is compiled as part of jsonpath_gram.y. Currently, this is * unavoidable because jsonpath_gram does not create a .h file to export its * token symbols. If these files ever grow large enough to be worth compiling |