LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonpath_gram.y (source / functions) Hit Total Coverage
Test: PostgreSQL 15beta1 Lines: 198 198 100.0 %
Date: 2022-05-18 02:09:37 Functions: 13 13 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : %{
       2             : /*-------------------------------------------------------------------------
       3             :  *
       4             :  * jsonpath_gram.y
       5             :  *   Grammar definitions for jsonpath datatype
       6             :  *
       7             :  * Transforms tokenized jsonpath into tree of JsonPathParseItem structs.
       8             :  *
       9             :  * Copyright (c) 2019-2022, PostgreSQL Global Development Group
      10             :  *
      11             :  * IDENTIFICATION
      12             :  *  src/backend/utils/adt/jsonpath_gram.y
      13             :  *
      14             :  *-------------------------------------------------------------------------
      15             :  */
      16             : 
      17             : #include "postgres.h"
      18             : 
      19             : #include "catalog/pg_collation.h"
      20             : #include "fmgr.h"
      21             : #include "miscadmin.h"
      22             : #include "nodes/pg_list.h"
      23             : #include "regex/regex.h"
      24             : #include "utils/builtins.h"
      25             : #include "utils/jsonpath.h"
      26             : 
      27             : /* struct JsonPathString is shared between scan and gram */
      28             : typedef struct JsonPathString
      29             : {
      30             :     char       *val;
      31             :     int         len;
      32             :     int         total;
      33             : }           JsonPathString;
      34             : 
      35             : union YYSTYPE;
      36             : 
      37             : /* flex 2.5.4 doesn't bother with a decl for this */
      38             : int jsonpath_yylex(union YYSTYPE *yylval_param);
      39             : int jsonpath_yyparse(JsonPathParseResult **result);
      40             : void jsonpath_yyerror(JsonPathParseResult **result, const char *message);
      41             : 
      42             : static JsonPathParseItem *makeItemType(JsonPathItemType type);
      43             : static JsonPathParseItem *makeItemString(JsonPathString *s);
      44             : static JsonPathParseItem *makeItemVariable(JsonPathString *s);
      45             : static JsonPathParseItem *makeItemKey(JsonPathString *s);
      46             : static JsonPathParseItem *makeItemNumeric(JsonPathString *s);
      47             : static JsonPathParseItem *makeItemBool(bool val);
      48             : static JsonPathParseItem *makeItemBinary(JsonPathItemType type,
      49             :                                          JsonPathParseItem *la,
      50             :                                          JsonPathParseItem *ra);
      51             : static JsonPathParseItem *makeItemUnary(JsonPathItemType type,
      52             :                                         JsonPathParseItem *a);
      53             : static JsonPathParseItem *makeItemList(List *list);
      54             : static JsonPathParseItem *makeIndexArray(List *list);
      55             : static JsonPathParseItem *makeAny(int first, int last);
      56             : static JsonPathParseItem *makeItemLikeRegex(JsonPathParseItem *expr,
      57             :                                             JsonPathString *pattern,
      58             :                                             JsonPathString *flags);
      59             : 
      60             : /*
      61             :  * Bison doesn't allocate anything that needs to live across parser calls,
      62             :  * so we can easily have it use palloc instead of malloc.  This prevents
      63             :  * memory leaks if we error out during parsing.  Note this only works with
      64             :  * bison >= 2.0.  However, in bison 1.875 the default is to use alloca()
      65             :  * if possible, so there's not really much problem anyhow, at least if
      66             :  * you're building with gcc.
      67             :  */
      68             : #define YYMALLOC palloc
      69             : #define YYFREE   pfree
      70             : 
      71             : %}
      72             : 
      73             : /* BISON Declarations */
      74             : %pure-parser
      75             : %expect 0
      76             : %name-prefix="jsonpath_yy"
      77             : %error-verbose
      78             : %parse-param {JsonPathParseResult **result}
      79             : 
      80             : %union
      81             : {
      82             :     JsonPathString      str;
      83             :     List               *elems;  /* list of JsonPathParseItem */
      84             :     List               *indexs; /* list of integers */
      85             :     JsonPathParseItem  *value;
      86             :     JsonPathParseResult *result;
      87             :     JsonPathItemType    optype;
      88             :     bool                boolean;
      89             :     int                 integer;
      90             : }
      91             : 
      92             : %token  <str>     TO_P NULL_P TRUE_P FALSE_P IS_P UNKNOWN_P EXISTS_P
      93             : %token  <str>     IDENT_P STRING_P NUMERIC_P INT_P VARIABLE_P
      94             : %token  <str>     OR_P AND_P NOT_P
      95             : %token  <str>     LESS_P LESSEQUAL_P EQUAL_P NOTEQUAL_P GREATEREQUAL_P GREATER_P
      96             : %token  <str>     ANY_P STRICT_P LAX_P LAST_P STARTS_P WITH_P LIKE_REGEX_P FLAG_P
      97             : %token  <str>     ABS_P SIZE_P TYPE_P FLOOR_P DOUBLE_P CEILING_P KEYVALUE_P
      98             : %token  <str>     DATETIME_P
      99             : 
     100             : %type   <result>  result
     101             : 
     102             : %type   <value>       scalar_value path_primary expr array_accessor
     103             :                     any_path accessor_op key predicate delimited_predicate
     104             :                     index_elem starts_with_initial expr_or_predicate
     105             :                     datetime_template opt_datetime_template
     106             : 
     107             : %type   <elems>       accessor_expr
     108             : 
     109             : %type   <indexs>  index_list
     110             : 
     111             : %type   <optype>  comp_op method
     112             : 
     113             : %type   <boolean> mode
     114             : 
     115             : %type   <str>     key_name
     116             : 
     117             : %type   <integer> any_level
     118             : 
     119             : %left   OR_P
     120             : %left   AND_P
     121             : %right  NOT_P
     122             : %left   '+' '-'
     123             : %left   '*' '/' '%'
     124             : %left   UMINUS
     125             : %nonassoc '(' ')'
     126             : 
     127             : /* Grammar follows */
     128             : %%
     129             : 
     130             : result:
     131             :     mode expr_or_predicate          {
     132        6636 :                                         *result = palloc(sizeof(JsonPathParseResult));
     133        6636 :                                         (*result)->expr = $2;
     134        6636 :                                         (*result)->lax = $1;
     135             :                                     }
     136           6 :     | /* EMPTY */                   { *result = NULL; }
     137             :     ;
     138             : 
     139             : expr_or_predicate:
     140        6216 :     expr                            { $$ = $1; }
     141         420 :     | predicate                     { $$ = $1; }
     142             :     ;
     143             : 
     144             : mode:
     145         684 :     STRICT_P                        { $$ = false; }
     146         594 :     | LAX_P                         { $$ = true; }
     147        5436 :     | /* EMPTY */                   { $$ = true; }
     148             :     ;
     149             : 
     150             : scalar_value:
     151         516 :     STRING_P                        { $$ = makeItemString(&$1); }
     152         114 :     | NULL_P                        { $$ = makeItemString(NULL); }
     153         138 :     | TRUE_P                        { $$ = makeItemBool(true); }
     154          18 :     | FALSE_P                       { $$ = makeItemBool(false); }
     155         510 :     | NUMERIC_P                     { $$ = makeItemNumeric(&$1); }
     156        1284 :     | INT_P                         { $$ = makeItemNumeric(&$1); }
     157         486 :     | VARIABLE_P                    { $$ = makeItemVariable(&$1); }
     158             :     ;
     159             : 
     160             : comp_op:
     161         894 :     EQUAL_P                         { $$ = jpiEqual; }
     162          12 :     | NOTEQUAL_P                    { $$ = jpiNotEqual; }
     163         564 :     | LESS_P                        { $$ = jpiLess; }
     164         426 :     | GREATER_P                     { $$ = jpiGreater; }
     165          30 :     | LESSEQUAL_P                   { $$ = jpiLessOrEqual; }
     166         138 :     | GREATEREQUAL_P                { $$ = jpiGreaterOrEqual; }
     167             :     ;
     168             : 
     169             : delimited_predicate:
     170          72 :     '(' predicate ')'               { $$ = $2; }
     171         264 :     | EXISTS_P '(' expr ')'         { $$ = makeItemUnary(jpiExists, $3); }
     172             :     ;
     173             : 
     174             : predicate:
     175         312 :     delimited_predicate             { $$ = $1; }
     176        2064 :     | expr comp_op expr             { $$ = makeItemBinary($2, $1, $3); }
     177         186 :     | predicate AND_P predicate     { $$ = makeItemBinary(jpiAnd, $1, $3); }
     178         108 :     | predicate OR_P predicate      { $$ = makeItemBinary(jpiOr, $1, $3); }
     179          24 :     | NOT_P delimited_predicate     { $$ = makeItemUnary(jpiNot, $2); }
     180             :     | '(' predicate ')' IS_P UNKNOWN_P
     181          72 :                                     { $$ = makeItemUnary(jpiIsUnknown, $2); }
     182             :     | expr STARTS_P WITH_P starts_with_initial
     183          60 :                                     { $$ = makeItemBinary(jpiStartsWith, $1, $4); }
     184          18 :     | expr LIKE_REGEX_P STRING_P    { $$ = makeItemLikeRegex($1, &$3, NULL); }
     185             :     | expr LIKE_REGEX_P STRING_P FLAG_P STRING_P
     186         108 :                                     { $$ = makeItemLikeRegex($1, &$3, &$5); }
     187             :     ;
     188             : 
     189             : starts_with_initial:
     190          54 :     STRING_P                        { $$ = makeItemString(&$1); }
     191           6 :     | VARIABLE_P                    { $$ = makeItemVariable(&$1); }
     192             :     ;
     193             : 
     194             : path_primary:
     195        3066 :     scalar_value                    { $$ = $1; }
     196        6474 :     | '$'                           { $$ = makeItemType(jpiRoot); }
     197        2046 :     | '@'                           { $$ = makeItemType(jpiCurrent); }
     198          90 :     | LAST_P                        { $$ = makeItemType(jpiLast); }
     199             :     ;
     200             : 
     201             : accessor_expr:
     202       11676 :     path_primary                    { $$ = list_make1($1); }
     203          90 :     | '(' expr ')' accessor_op      { $$ = list_make2($2, $4); }
     204          30 :     | '(' predicate ')' accessor_op { $$ = list_make2($2, $4); }
     205        8742 :     | accessor_expr accessor_op     { $$ = lappend($1, $2); }
     206             :     ;
     207             : 
     208             : expr:
     209       11724 :     accessor_expr                   { $$ = makeItemList($1); }
     210          72 :     | '(' expr ')'                  { $$ = $2; }
     211         174 :     | '+' expr %prec UMINUS         { $$ = makeItemUnary(jpiPlus, $2); }
     212         246 :     | '-' expr %prec UMINUS         { $$ = makeItemUnary(jpiMinus, $2); }
     213         150 :     | expr '+' expr                 { $$ = makeItemBinary(jpiAdd, $1, $3); }
     214          60 :     | expr '-' expr                 { $$ = makeItemBinary(jpiSub, $1, $3); }
     215          48 :     | expr '*' expr                 { $$ = makeItemBinary(jpiMul, $1, $3); }
     216          36 :     | expr '/' expr                 { $$ = makeItemBinary(jpiDiv, $1, $3); }
     217          18 :     | expr '%' expr                 { $$ = makeItemBinary(jpiMod, $1, $3); }
     218             :     ;
     219             : 
     220             : index_elem:
     221         432 :     expr                            { $$ = makeItemBinary(jpiSubscript, $1, NULL); }
     222          48 :     | expr TO_P expr                { $$ = makeItemBinary(jpiSubscript, $1, $3); }
     223             :     ;
     224             : 
     225             : index_list:
     226         432 :     index_elem                      { $$ = list_make1($1); }
     227          48 :     | index_list ',' index_elem     { $$ = lappend($1, $3); }
     228             :     ;
     229             : 
     230             : array_accessor:
     231        1512 :     '[' '*' ']'                     { $$ = makeItemType(jpiAnyArray); }
     232         432 :     | '[' index_list ']'            { $$ = makeIndexArray($2); }
     233             :     ;
     234             : 
     235             : any_level:
     236         282 :     INT_P                           { $$ = pg_strtoint32($1.val); }
     237          96 :     | LAST_P                        { $$ = -1; }
     238             :     ;
     239             : 
     240             : any_path:
     241         114 :     ANY_P                           { $$ = makeAny(0, -1); }
     242         102 :     | ANY_P '{' any_level '}'       { $$ = makeAny($3, $3); }
     243             :     | ANY_P '{' any_level TO_P any_level '}'
     244         138 :                                     { $$ = makeAny($3, $5); }
     245             :     ;
     246             : 
     247             : accessor_op:
     248        3306 :     '.' key                         { $$ = $2; }
     249         114 :     | '.' '*'                       { $$ = makeItemType(jpiAnyKey); }
     250        1944 :     | array_accessor                { $$ = $1; }
     251         354 :     | '.' any_path                  { $$ = $2; }
     252         516 :     | '.' method '(' ')'            { $$ = makeItemType($2); }
     253             :     | '.' DATETIME_P '(' opt_datetime_template ')'
     254         876 :                                     { $$ = makeItemUnary(jpiDatetime, $4); }
     255        1752 :     | '?' '(' predicate ')'         { $$ = makeItemUnary(jpiFilter, $3); }
     256             :     ;
     257             : 
     258             : datetime_template:
     259         480 :     STRING_P                        { $$ = makeItemString(&$1); }
     260             :     ;
     261             : 
     262             : opt_datetime_template:
     263         480 :     datetime_template               { $$ = $1; }
     264         396 :     | /* EMPTY */                   { $$ = NULL; }
     265             :     ;
     266             : 
     267             : key:
     268        3306 :     key_name                        { $$ = makeItemKey(&$1); }
     269             :     ;
     270             : 
     271             : key_name:
     272             :     IDENT_P
     273             :     | STRING_P
     274             :     | TO_P
     275             :     | NULL_P
     276             :     | TRUE_P
     277             :     | FALSE_P
     278             :     | IS_P
     279             :     | UNKNOWN_P
     280             :     | EXISTS_P
     281             :     | STRICT_P
     282             :     | LAX_P
     283             :     | ABS_P
     284             :     | SIZE_P
     285             :     | TYPE_P
     286             :     | FLOOR_P
     287             :     | DOUBLE_P
     288             :     | CEILING_P
     289             :     | DATETIME_P
     290             :     | KEYVALUE_P
     291             :     | LAST_P
     292             :     | STARTS_P
     293             :     | WITH_P
     294             :     | LIKE_REGEX_P
     295             :     | FLAG_P
     296             :     ;
     297             : 
     298             : method:
     299          42 :     ABS_P                           { $$ = jpiAbs; }
     300          30 :     | SIZE_P                        { $$ = jpiSize; }
     301         192 :     | TYPE_P                        { $$ = jpiType; }
     302          30 :     | FLOOR_P                       { $$ = jpiFloor; }
     303         120 :     | DOUBLE_P                      { $$ = jpiDouble; }
     304          36 :     | CEILING_P                     { $$ = jpiCeiling; }
     305          66 :     | KEYVALUE_P                    { $$ = jpiKeyValue; }
     306             :     ;
     307             : %%
     308             : 
     309             : /*
     310             :  * The helper functions below allocate and fill JsonPathParseItem's of various
     311             :  * types.
     312             :  */
     313             : 
     314             : static JsonPathParseItem *
     315       25074 : makeItemType(JsonPathItemType type)
     316             : {
     317       25074 :     JsonPathParseItem *v = palloc(sizeof(*v));
     318             : 
     319       25074 :     CHECK_FOR_INTERRUPTS();
     320             : 
     321       25074 :     v->type = type;
     322       25074 :     v->next = NULL;
     323             : 
     324       25074 :     return v;
     325             : }
     326             : 
     327             : static JsonPathParseItem *
     328        4470 : makeItemString(JsonPathString *s)
     329             : {
     330             :     JsonPathParseItem *v;
     331             : 
     332        4470 :     if (s == NULL)
     333             :     {
     334         114 :         v = makeItemType(jpiNull);
     335             :     }
     336             :     else
     337             :     {
     338        4356 :         v = makeItemType(jpiString);
     339        4356 :         v->value.string.val = s->val;
     340        4356 :         v->value.string.len = s->len;
     341             :     }
     342             : 
     343        4470 :     return v;
     344             : }
     345             : 
     346             : static JsonPathParseItem *
     347         492 : makeItemVariable(JsonPathString *s)
     348             : {
     349             :     JsonPathParseItem *v;
     350             : 
     351         492 :     v = makeItemType(jpiVariable);
     352         492 :     v->value.string.val = s->val;
     353         492 :     v->value.string.len = s->len;
     354             : 
     355         492 :     return v;
     356             : }
     357             : 
     358             : static JsonPathParseItem *
     359        3306 : makeItemKey(JsonPathString *s)
     360             : {
     361             :     JsonPathParseItem *v;
     362             : 
     363        3306 :     v = makeItemString(s);
     364        3306 :     v->type = jpiKey;
     365             : 
     366        3306 :     return v;
     367             : }
     368             : 
     369             : static JsonPathParseItem *
     370        1794 : makeItemNumeric(JsonPathString *s)
     371             : {
     372             :     JsonPathParseItem *v;
     373             : 
     374        1794 :     v = makeItemType(jpiNumeric);
     375        1794 :     v->value.numeric =
     376        1794 :         DatumGetNumeric(DirectFunctionCall3(numeric_in,
     377             :                                             CStringGetDatum(s->val),
     378             :                                             ObjectIdGetDatum(InvalidOid),
     379             :                                             Int32GetDatum(-1)));
     380             : 
     381        1794 :     return v;
     382             : }
     383             : 
     384             : static JsonPathParseItem *
     385         156 : makeItemBool(bool val)
     386             : {
     387         156 :     JsonPathParseItem *v = makeItemType(jpiBool);
     388             : 
     389         156 :     v->value.boolean = val;
     390             : 
     391         156 :     return v;
     392             : }
     393             : 
     394             : static JsonPathParseItem *
     395        3210 : makeItemBinary(JsonPathItemType type, JsonPathParseItem *la, JsonPathParseItem *ra)
     396             : {
     397        3210 :     JsonPathParseItem *v = makeItemType(type);
     398             : 
     399        3210 :     v->value.args.left = la;
     400        3210 :     v->value.args.right = ra;
     401             : 
     402        3210 :     return v;
     403             : }
     404             : 
     405             : static JsonPathParseItem *
     406        3408 : makeItemUnary(JsonPathItemType type, JsonPathParseItem *a)
     407             : {
     408             :     JsonPathParseItem *v;
     409             : 
     410        3408 :     if (type == jpiPlus && a->type == jpiNumeric && !a->next)
     411         120 :         return a;
     412             : 
     413        3288 :     if (type == jpiMinus && a->type == jpiNumeric && !a->next)
     414             :     {
     415         138 :         v = makeItemType(jpiNumeric);
     416         138 :         v->value.numeric =
     417         138 :             DatumGetNumeric(DirectFunctionCall1(numeric_uminus,
     418             :                                                 NumericGetDatum(a->value.numeric)));
     419         138 :         return v;
     420             :     }
     421             : 
     422        3150 :     v = makeItemType(type);
     423             : 
     424        3150 :     v->value.arg = a;
     425             : 
     426        3150 :     return v;
     427             : }
     428             : 
     429             : static JsonPathParseItem *
     430       11724 : makeItemList(List *list)
     431             : {
     432             :     JsonPathParseItem *head,
     433             :                *end;
     434             :     ListCell   *cell;
     435             : 
     436       11724 :     head = end = (JsonPathParseItem *) linitial(list);
     437             : 
     438       11724 :     if (list_length(list) == 1)
     439        5394 :         return head;
     440             : 
     441             :     /* append items to the end of already existing list */
     442        6342 :     while (end->next)
     443          12 :         end = end->next;
     444             : 
     445       15192 :     for_each_from(cell, list, 1)
     446             :     {
     447        8862 :         JsonPathParseItem *c = (JsonPathParseItem *) lfirst(cell);
     448             : 
     449        8862 :         end->next = c;
     450        8862 :         end = c;
     451             :     }
     452             : 
     453        6330 :     return head;
     454             : }
     455             : 
     456             : static JsonPathParseItem *
     457         432 : makeIndexArray(List *list)
     458             : {
     459         432 :     JsonPathParseItem *v = makeItemType(jpiIndexArray);
     460             :     ListCell   *cell;
     461         432 :     int         i = 0;
     462             : 
     463             :     Assert(list_length(list) > 0);
     464         432 :     v->value.array.nelems = list_length(list);
     465             : 
     466         864 :     v->value.array.elems = palloc(sizeof(v->value.array.elems[0]) *
     467         432 :                                   v->value.array.nelems);
     468             : 
     469         912 :     foreach(cell, list)
     470             :     {
     471         480 :         JsonPathParseItem *jpi = lfirst(cell);
     472             : 
     473             :         Assert(jpi->type == jpiSubscript);
     474             : 
     475         480 :         v->value.array.elems[i].from = jpi->value.args.left;
     476         480 :         v->value.array.elems[i++].to = jpi->value.args.right;
     477             :     }
     478             : 
     479         432 :     return v;
     480             : }
     481             : 
     482             : static JsonPathParseItem *
     483         354 : makeAny(int first, int last)
     484             : {
     485         354 :     JsonPathParseItem *v = makeItemType(jpiAny);
     486             : 
     487         354 :     v->value.anybounds.first = (first >= 0) ? first : PG_UINT32_MAX;
     488         354 :     v->value.anybounds.last = (last >= 0) ? last : PG_UINT32_MAX;
     489             : 
     490         354 :     return v;
     491             : }
     492             : 
     493             : static JsonPathParseItem *
     494         126 : makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern,
     495             :                   JsonPathString *flags)
     496             : {
     497         126 :     JsonPathParseItem *v = makeItemType(jpiLikeRegex);
     498             :     int         i;
     499             :     int         cflags;
     500             : 
     501         126 :     v->value.like_regex.expr = expr;
     502         126 :     v->value.like_regex.pattern = pattern->val;
     503         126 :     v->value.like_regex.patternlen = pattern->len;
     504             : 
     505             :     /* Parse the flags string, convert to bitmask.  Duplicate flags are OK. */
     506         126 :     v->value.like_regex.flags = 0;
     507         288 :     for (i = 0; flags && i < flags->len; i++)
     508             :     {
     509         168 :         switch (flags->val[i])
     510             :         {
     511          48 :             case 'i':
     512          48 :                 v->value.like_regex.flags |= JSP_REGEX_ICASE;
     513          48 :                 break;
     514          36 :             case 's':
     515          36 :                 v->value.like_regex.flags |= JSP_REGEX_DOTALL;
     516          36 :                 break;
     517          24 :             case 'm':
     518          24 :                 v->value.like_regex.flags |= JSP_REGEX_MLINE;
     519          24 :                 break;
     520          12 :             case 'x':
     521          12 :                 v->value.like_regex.flags |= JSP_REGEX_WSPACE;
     522          12 :                 break;
     523          42 :             case 'q':
     524          42 :                 v->value.like_regex.flags |= JSP_REGEX_QUOTE;
     525          42 :                 break;
     526           6 :             default:
     527           6 :                 ereport(ERROR,
     528             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     529             :                          errmsg("invalid input syntax for type %s", "jsonpath"),
     530             :                          errdetail("unrecognized flag character \"%.*s\" in LIKE_REGEX predicate",
     531             :                                    pg_mblen(flags->val + i), flags->val + i)));
     532             :                 break;
     533             :         }
     534             :     }
     535             : 
     536             :     /* Convert flags to what RE_compile_and_cache needs */
     537         120 :     cflags = jspConvertRegexFlags(v->value.like_regex.flags);
     538             : 
     539             :     /* check regex validity */
     540         114 :     (void) RE_compile_and_cache(cstring_to_text_with_len(pattern->val,
     541             :                                                          pattern->len),
     542             :                                 cflags, DEFAULT_COLLATION_OID);
     543             : 
     544         108 :     return v;
     545             : }
     546             : 
     547             : /*
     548             :  * Convert from XQuery regex flags to those recognized by our regex library.
     549             :  */
     550             : int
     551         396 : jspConvertRegexFlags(uint32 xflags)
     552             : {
     553             :     /* By default, XQuery is very nearly the same as Spencer's AREs */
     554         396 :     int         cflags = REG_ADVANCED;
     555             : 
     556             :     /* Ignore-case means the same thing, too, modulo locale issues */
     557         396 :     if (xflags & JSP_REGEX_ICASE)
     558         102 :         cflags |= REG_ICASE;
     559             : 
     560             :     /* Per XQuery spec, if 'q' is specified then 'm', 's', 'x' are ignored */
     561         396 :     if (xflags & JSP_REGEX_QUOTE)
     562             :     {
     563         114 :         cflags &= ~REG_ADVANCED;
     564         114 :         cflags |= REG_QUOTE;
     565             :     }
     566             :     else
     567             :     {
     568             :         /* Note that dotall mode is the default in POSIX */
     569         282 :         if (!(xflags & JSP_REGEX_DOTALL))
     570         216 :             cflags |= REG_NLSTOP;
     571         282 :         if (xflags & JSP_REGEX_MLINE)
     572          60 :             cflags |= REG_NLANCH;
     573             : 
     574             :         /*
     575             :          * XQuery's 'x' mode is related to Spencer's expanded mode, but it's
     576             :          * not really enough alike to justify treating JSP_REGEX_WSPACE as
     577             :          * REG_EXPANDED.  For now we treat 'x' as unimplemented; perhaps in
     578             :          * future we'll modify the regex library to have an option for
     579             :          * XQuery-style ignore-whitespace mode.
     580             :          */
     581         282 :         if (xflags & JSP_REGEX_WSPACE)
     582           6 :             ereport(ERROR,
     583             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     584             :                      errmsg("XQuery \"x\" flag (expanded regular expressions) is not implemented")));
     585             :     }
     586             : 
     587             :     /*
     588             :      * We'll never need sub-match details at execution.  While
     589             :      * RE_compile_and_execute would set this flag anyway, force it on here to
     590             :      * ensure that the regex cache entries created by makeItemLikeRegex are
     591             :      * useful.
     592             :      */
     593         390 :     cflags |= REG_NOSUB;
     594             : 
     595         390 :     return cflags;
     596             : }
     597             : 
     598             : /*
     599             :  * jsonpath_scan.l is compiled as part of jsonpath_gram.y.  Currently, this is
     600             :  * unavoidable because jsonpath_gram does not create a .h file to export its
     601             :  * token symbols.  If these files ever grow large enough to be worth compiling
     602             :  * separately, that could be fixed; but for now it seems like useless
     603             :  * complication.
     604             :  */
     605             : 
     606             : #include "jsonpath_scan.c"

Generated by: LCOV version 1.14