LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonpath_gram.y (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 197 197 100.0 %
Date: 2020-06-03 09:06:53 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-2020, 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             :     JsonPathString      str;
      82             :     List               *elems;  /* list of JsonPathParseItem */
      83             :     List               *indexs; /* list of integers */
      84             :     JsonPathParseItem  *value;
      85             :     JsonPathParseResult *result;
      86             :     JsonPathItemType    optype;
      87             :     bool                boolean;
      88             :     int                 integer;
      89             : }
      90             : 
      91             : %token  <str>     TO_P NULL_P TRUE_P FALSE_P IS_P UNKNOWN_P EXISTS_P
      92             : %token  <str>     IDENT_P STRING_P NUMERIC_P INT_P VARIABLE_P
      93             : %token  <str>     OR_P AND_P NOT_P
      94             : %token  <str>     LESS_P LESSEQUAL_P EQUAL_P NOTEQUAL_P GREATEREQUAL_P GREATER_P
      95             : %token  <str>     ANY_P STRICT_P LAX_P LAST_P STARTS_P WITH_P LIKE_REGEX_P FLAG_P
      96             : %token  <str>     ABS_P SIZE_P TYPE_P FLOOR_P DOUBLE_P CEILING_P KEYVALUE_P
      97             : %token  <str>     DATETIME_P
      98             : 
      99             : %type   <result>  result
     100             : 
     101             : %type   <value>       scalar_value path_primary expr array_accessor
     102             :                     any_path accessor_op key predicate delimited_predicate
     103             :                     index_elem starts_with_initial expr_or_predicate
     104             :                     datetime_template opt_datetime_template
     105             : 
     106             : %type   <elems>       accessor_expr
     107             : 
     108             : %type   <indexs>  index_list
     109             : 
     110             : %type   <optype>  comp_op method
     111             : 
     112             : %type   <boolean> mode
     113             : 
     114             : %type   <str>     key_name
     115             : 
     116             : %type   <integer> any_level
     117             : 
     118             : %left   OR_P
     119             : %left   AND_P
     120             : %right  NOT_P
     121             : %left   '+' '-'
     122             : %left   '*' '/' '%'
     123             : %left   UMINUS
     124             : %nonassoc '(' ')'
     125             : 
     126             : /* Grammar follows */
     127             : %%
     128             : 
     129             : result:
     130             :     mode expr_or_predicate          {
     131        2604 :                                         *result = palloc(sizeof(JsonPathParseResult));
     132        2604 :                                         (*result)->expr = $2;
     133        2604 :                                         (*result)->lax = $1;
     134             :                                     }
     135           4 :     | /* EMPTY */                   { *result = NULL; }
     136             :     ;
     137             : 
     138             : expr_or_predicate:
     139        2348 :     expr                            { $$ = $1; }
     140         256 :     | predicate                     { $$ = $1; }
     141             :     ;
     142             : 
     143             : mode:
     144         236 :     STRICT_P                        { $$ = false; }
     145         304 :     | LAX_P                         { $$ = true; }
     146        2180 :     | /* EMPTY */                   { $$ = true; }
     147             :     ;
     148             : 
     149             : scalar_value:
     150         344 :     STRING_P                        { $$ = makeItemString(&$1); }
     151          76 :     | NULL_P                        { $$ = makeItemString(NULL); }
     152          92 :     | TRUE_P                        { $$ = makeItemBool(true); }
     153          12 :     | FALSE_P                       { $$ = makeItemBool(false); }
     154         248 :     | NUMERIC_P                     { $$ = makeItemNumeric(&$1); }
     155         800 :     | INT_P                         { $$ = makeItemNumeric(&$1); }
     156         196 :     | VARIABLE_P                    { $$ = makeItemVariable(&$1); }
     157             :     ;
     158             : 
     159             : comp_op:
     160         576 :     EQUAL_P                         { $$ = jpiEqual; }
     161           8 :     | NOTEQUAL_P                    { $$ = jpiNotEqual; }
     162         316 :     | LESS_P                        { $$ = jpiLess; }
     163         248 :     | GREATER_P                     { $$ = jpiGreater; }
     164          16 :     | LESSEQUAL_P                   { $$ = jpiLessOrEqual; }
     165          84 :     | GREATEREQUAL_P                { $$ = jpiGreaterOrEqual; }
     166             :     ;
     167             : 
     168             : delimited_predicate:
     169          48 :     '(' predicate ')'               { $$ = $2; }
     170         176 :     | EXISTS_P '(' expr ')'         { $$ = makeItemUnary(jpiExists, $3); }
     171             :     ;
     172             : 
     173             : predicate:
     174         208 :     delimited_predicate             { $$ = $1; }
     175        1200 :     | expr comp_op expr             { $$ = makeItemBinary($2, $1, $3); }
     176         112 :     | predicate AND_P predicate     { $$ = makeItemBinary(jpiAnd, $1, $3); }
     177          72 :     | predicate OR_P predicate      { $$ = makeItemBinary(jpiOr, $1, $3); }
     178          16 :     | NOT_P delimited_predicate     { $$ = makeItemUnary(jpiNot, $2); }
     179             :     | '(' predicate ')' IS_P UNKNOWN_P
     180          48 :                                     { $$ = makeItemUnary(jpiIsUnknown, $2); }
     181             :     | expr STARTS_P WITH_P starts_with_initial
     182          40 :                                     { $$ = makeItemBinary(jpiStartsWith, $1, $4); }
     183          12 :     | expr LIKE_REGEX_P STRING_P    { $$ = makeItemLikeRegex($1, &$3, NULL); }
     184             :     | expr LIKE_REGEX_P STRING_P FLAG_P STRING_P
     185          72 :                                     { $$ = makeItemLikeRegex($1, &$3, &$5); }
     186             :     ;
     187             : 
     188             : starts_with_initial:
     189          36 :     STRING_P                        { $$ = makeItemString(&$1); }
     190           4 :     | VARIABLE_P                    { $$ = makeItemVariable(&$1); }
     191             :     ;
     192             : 
     193             : path_primary:
     194        1768 :     scalar_value                    { $$ = $1; }
     195        2576 :     | '$'                           { $$ = makeItemType(jpiRoot); }
     196        1264 :     | '@'                           { $$ = makeItemType(jpiCurrent); }
     197          60 :     | LAST_P                        { $$ = makeItemType(jpiLast); }
     198             :     ;
     199             : 
     200             : accessor_expr:
     201        5668 :     path_primary                    { $$ = list_make1($1); }
     202          52 :     | '(' expr ')' accessor_op      { $$ = list_make2($2, $4); }
     203          20 :     | '(' predicate ')' accessor_op { $$ = list_make2($2, $4); }
     204        4696 :     | accessor_expr accessor_op     { $$ = lappend($1, $2); }
     205             :     ;
     206             : 
     207             : expr:
     208        5628 :     accessor_expr                   { $$ = makeItemList($1); }
     209          48 :     | '(' expr ')'                  { $$ = $2; }
     210         100 :     | '+' expr %prec UMINUS         { $$ = makeItemUnary(jpiPlus, $2); }
     211         148 :     | '-' expr %prec UMINUS         { $$ = makeItemUnary(jpiMinus, $2); }
     212         100 :     | expr '+' expr                 { $$ = makeItemBinary(jpiAdd, $1, $3); }
     213          40 :     | expr '-' expr                 { $$ = makeItemBinary(jpiSub, $1, $3); }
     214          32 :     | expr '*' expr                 { $$ = makeItemBinary(jpiMul, $1, $3); }
     215          24 :     | expr '/' expr                 { $$ = makeItemBinary(jpiDiv, $1, $3); }
     216          12 :     | expr '%' expr                 { $$ = makeItemBinary(jpiMod, $1, $3); }
     217             :     ;
     218             : 
     219             : index_elem:
     220         216 :     expr                            { $$ = makeItemBinary(jpiSubscript, $1, NULL); }
     221          28 :     | expr TO_P expr                { $$ = makeItemBinary(jpiSubscript, $1, $3); }
     222             :     ;
     223             : 
     224             : index_list:
     225         224 :     index_elem                      { $$ = list_make1($1); }
     226          20 :     | index_list ',' index_elem     { $$ = lappend($1, $3); }
     227             :     ;
     228             : 
     229             : array_accessor:
     230         680 :     '[' '*' ']'                     { $$ = makeItemType(jpiAnyArray); }
     231         224 :     | '[' index_list ']'            { $$ = makeIndexArray($2); }
     232             :     ;
     233             : 
     234             : any_level:
     235         188 :     INT_P                           { $$ = pg_atoi($1.val, 4, 0); }
     236          64 :     | LAST_P                        { $$ = -1; }
     237             :     ;
     238             : 
     239             : any_path:
     240          76 :     ANY_P                           { $$ = makeAny(0, -1); }
     241          68 :     | ANY_P '{' any_level '}'       { $$ = makeAny($3, $3); }
     242             :     | ANY_P '{' any_level TO_P any_level '}'
     243          92 :                                     { $$ = makeAny($3, $5); }
     244             :     ;
     245             : 
     246             : accessor_op:
     247        1720 :     '.' key                         { $$ = $2; }
     248          56 :     | '.' '*'                       { $$ = makeItemType(jpiAnyKey); }
     249         904 :     | array_accessor                { $$ = $1; }
     250         236 :     | '.' any_path                  { $$ = $2; }
     251         344 :     | '.' method '(' ')'            { $$ = makeItemType($2); }
     252             :     | '.' DATETIME_P '(' opt_datetime_template ')'
     253         480 :                                     { $$ = makeItemUnary(jpiDatetime, $4); }
     254        1028 :     | '?' '(' predicate ')'         { $$ = makeItemUnary(jpiFilter, $3); }
     255             :     ;
     256             : 
     257             : datetime_template:
     258         264 :     STRING_P                        { $$ = makeItemString(&$1); }
     259             :     ;
     260             : 
     261             : opt_datetime_template:
     262         264 :     datetime_template               { $$ = $1; }
     263         216 :     | /* EMPTY */                   { $$ = NULL; }
     264             :     ;
     265             : 
     266             : key:
     267        1720 :     key_name                        { $$ = makeItemKey(&$1); }
     268             :     ;
     269             : 
     270             : key_name:
     271             :     IDENT_P
     272             :     | STRING_P
     273             :     | TO_P
     274             :     | NULL_P
     275             :     | TRUE_P
     276             :     | FALSE_P
     277             :     | IS_P
     278             :     | UNKNOWN_P
     279             :     | EXISTS_P
     280             :     | STRICT_P
     281             :     | LAX_P
     282             :     | ABS_P
     283             :     | SIZE_P
     284             :     | TYPE_P
     285             :     | FLOOR_P
     286             :     | DOUBLE_P
     287             :     | CEILING_P
     288             :     | DATETIME_P
     289             :     | KEYVALUE_P
     290             :     | LAST_P
     291             :     | STARTS_P
     292             :     | WITH_P
     293             :     | LIKE_REGEX_P
     294             :     | FLAG_P
     295             :     ;
     296             : 
     297             : method:
     298          28 :     ABS_P                           { $$ = jpiAbs; }
     299          20 :     | SIZE_P                        { $$ = jpiSize; }
     300         132 :     | TYPE_P                        { $$ = jpiType; }
     301          20 :     | FLOOR_P                       { $$ = jpiFloor; }
     302          76 :     | DOUBLE_P                      { $$ = jpiDouble; }
     303          24 :     | CEILING_P                     { $$ = jpiCeiling; }
     304          44 :     | KEYVALUE_P                    { $$ = jpiKeyValue; }
     305             :     ;
     306             : %%
     307             : 
     308             : /*
     309             :  * The helper functions below allocate and fill JsonPathParseItem's of various
     310             :  * types.
     311             :  */
     312             : 
     313             : static JsonPathParseItem *
     314       13124 : makeItemType(JsonPathItemType type)
     315             : {
     316       13124 :     JsonPathParseItem  *v = palloc(sizeof(*v));
     317             : 
     318       13124 :     CHECK_FOR_INTERRUPTS();
     319             : 
     320       13124 :     v->type = type;
     321       13124 :     v->next = NULL;
     322             : 
     323       13124 :     return v;
     324             : }
     325             : 
     326             : static JsonPathParseItem *
     327        2440 : makeItemString(JsonPathString *s)
     328             : {
     329             :     JsonPathParseItem  *v;
     330             : 
     331        2440 :     if (s == NULL)
     332             :     {
     333          76 :         v = makeItemType(jpiNull);
     334             :     }
     335             :     else
     336             :     {
     337        2364 :         v = makeItemType(jpiString);
     338        2364 :         v->value.string.val = s->val;
     339        2364 :         v->value.string.len = s->len;
     340             :     }
     341             : 
     342        2440 :     return v;
     343             : }
     344             : 
     345             : static JsonPathParseItem *
     346         200 : makeItemVariable(JsonPathString *s)
     347             : {
     348             :     JsonPathParseItem  *v;
     349             : 
     350         200 :     v = makeItemType(jpiVariable);
     351         200 :     v->value.string.val = s->val;
     352         200 :     v->value.string.len = s->len;
     353             : 
     354         200 :     return v;
     355             : }
     356             : 
     357             : static JsonPathParseItem *
     358        1720 : makeItemKey(JsonPathString *s)
     359             : {
     360             :     JsonPathParseItem  *v;
     361             : 
     362        1720 :     v = makeItemString(s);
     363        1720 :     v->type = jpiKey;
     364             : 
     365        1720 :     return v;
     366             : }
     367             : 
     368             : static JsonPathParseItem *
     369        1048 : makeItemNumeric(JsonPathString *s)
     370             : {
     371             :     JsonPathParseItem  *v;
     372             : 
     373        1048 :     v = makeItemType(jpiNumeric);
     374        1048 :     v->value.numeric =
     375        1048 :         DatumGetNumeric(DirectFunctionCall3(numeric_in,
     376             :                                             CStringGetDatum(s->val),
     377             :                                             ObjectIdGetDatum(InvalidOid),
     378             :                                             Int32GetDatum(-1)));
     379             : 
     380        1048 :     return v;
     381             : }
     382             : 
     383             : static JsonPathParseItem *
     384         104 : makeItemBool(bool val)
     385             : {
     386         104 :     JsonPathParseItem  *v = makeItemType(jpiBool);
     387             : 
     388         104 :     v->value.boolean = val;
     389             : 
     390         104 :     return v;
     391             : }
     392             : 
     393             : static JsonPathParseItem *
     394        1876 : makeItemBinary(JsonPathItemType type, JsonPathParseItem *la, JsonPathParseItem *ra)
     395             : {
     396        1876 :     JsonPathParseItem  *v = makeItemType(type);
     397             : 
     398        1876 :     v->value.args.left = la;
     399        1876 :     v->value.args.right = ra;
     400             : 
     401        1876 :     return v;
     402             : }
     403             : 
     404             : static JsonPathParseItem *
     405        1996 : makeItemUnary(JsonPathItemType type, JsonPathParseItem *a)
     406             : {
     407             :     JsonPathParseItem  *v;
     408             : 
     409        1996 :     if (type == jpiPlus && a->type == jpiNumeric && !a->next)
     410          64 :         return a;
     411             : 
     412        1932 :     if (type == jpiMinus && a->type == jpiNumeric && !a->next)
     413             :     {
     414          76 :         v = makeItemType(jpiNumeric);
     415          76 :         v->value.numeric =
     416          76 :             DatumGetNumeric(DirectFunctionCall1(numeric_uminus,
     417             :                                                 NumericGetDatum(a->value.numeric)));
     418          76 :         return v;
     419             :     }
     420             : 
     421        1856 :     v = makeItemType(type);
     422             : 
     423        1856 :     v->value.arg = a;
     424             : 
     425        1856 :     return v;
     426             : }
     427             : 
     428             : static JsonPathParseItem *
     429        5628 : makeItemList(List *list)
     430             : {
     431             :     JsonPathParseItem  *head,
     432             :                        *end;
     433             :     ListCell           *cell;
     434             : 
     435        5628 :     head = end = (JsonPathParseItem *) linitial(list);
     436             : 
     437        5628 :     if (list_length(list) == 1)
     438        2364 :         return head;
     439             : 
     440             :     /* append items to the end of already existing list */
     441        3272 :     while (end->next)
     442           8 :         end = end->next;
     443             : 
     444        8032 :     for_each_cell(cell, list, list_second_cell(list))
     445             :     {
     446        4768 :         JsonPathParseItem *c = (JsonPathParseItem *) lfirst(cell);
     447             : 
     448        4768 :         end->next = c;
     449        4768 :         end = c;
     450             :     }
     451             : 
     452        3264 :     return head;
     453             : }
     454             : 
     455             : static JsonPathParseItem *
     456         224 : makeIndexArray(List *list)
     457             : {
     458         224 :     JsonPathParseItem  *v = makeItemType(jpiIndexArray);
     459             :     ListCell           *cell;
     460         224 :     int                 i = 0;
     461             : 
     462             :     Assert(list_length(list) > 0);
     463         224 :     v->value.array.nelems = list_length(list);
     464             : 
     465         448 :     v->value.array.elems = palloc(sizeof(v->value.array.elems[0]) *
     466         224 :                                   v->value.array.nelems);
     467             : 
     468         468 :     foreach(cell, list)
     469             :     {
     470         244 :         JsonPathParseItem  *jpi = lfirst(cell);
     471             : 
     472             :         Assert(jpi->type == jpiSubscript);
     473             : 
     474         244 :         v->value.array.elems[i].from = jpi->value.args.left;
     475         244 :         v->value.array.elems[i++].to = jpi->value.args.right;
     476             :     }
     477             : 
     478         224 :     return v;
     479             : }
     480             : 
     481             : static JsonPathParseItem *
     482         236 : makeAny(int first, int last)
     483             : {
     484         236 :     JsonPathParseItem  *v = makeItemType(jpiAny);
     485             : 
     486         236 :     v->value.anybounds.first = (first >= 0) ? first : PG_UINT32_MAX;
     487         236 :     v->value.anybounds.last = (last >= 0) ? last : PG_UINT32_MAX;
     488             : 
     489         236 :     return v;
     490             : }
     491             : 
     492             : static JsonPathParseItem *
     493          84 : makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern,
     494             :                   JsonPathString *flags)
     495             : {
     496          84 :     JsonPathParseItem  *v = makeItemType(jpiLikeRegex);
     497             :     int                 i;
     498             :     int                 cflags;
     499             : 
     500          84 :     v->value.like_regex.expr = expr;
     501          84 :     v->value.like_regex.pattern = pattern->val;
     502          84 :     v->value.like_regex.patternlen = pattern->len;
     503             : 
     504             :     /* Parse the flags string, convert to bitmask.  Duplicate flags are OK. */
     505          84 :     v->value.like_regex.flags = 0;
     506         192 :     for (i = 0; flags && i < flags->len; i++)
     507             :     {
     508         112 :         switch (flags->val[i])
     509             :         {
     510          32 :             case 'i':
     511          32 :                 v->value.like_regex.flags |= JSP_REGEX_ICASE;
     512          32 :                 break;
     513          24 :             case 's':
     514          24 :                 v->value.like_regex.flags |= JSP_REGEX_DOTALL;
     515          24 :                 break;
     516          16 :             case 'm':
     517          16 :                 v->value.like_regex.flags |= JSP_REGEX_MLINE;
     518          16 :                 break;
     519           8 :             case 'x':
     520           8 :                 v->value.like_regex.flags |= JSP_REGEX_WSPACE;
     521           8 :                 break;
     522          28 :             case 'q':
     523          28 :                 v->value.like_regex.flags |= JSP_REGEX_QUOTE;
     524          28 :                 break;
     525           4 :             default:
     526           4 :                 ereport(ERROR,
     527             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     528             :                          errmsg("invalid input syntax for type %s", "jsonpath"),
     529             :                          errdetail("unrecognized flag character \"%c\" in LIKE_REGEX predicate",
     530             :                                    flags->val[i])));
     531             :                 break;
     532             :         }
     533             :     }
     534             : 
     535             :     /* Convert flags to what RE_compile_and_cache needs */
     536          80 :     cflags = jspConvertRegexFlags(v->value.like_regex.flags);
     537             : 
     538             :     /* check regex validity */
     539          76 :     (void) RE_compile_and_cache(cstring_to_text_with_len(pattern->val,
     540             :                                                          pattern->len),
     541             :                                 cflags, DEFAULT_COLLATION_OID);
     542             : 
     543          72 :     return v;
     544             : }
     545             : 
     546             : /*
     547             :  * Convert from XQuery regex flags to those recognized by our regex library.
     548             :  */
     549             : int
     550         264 : jspConvertRegexFlags(uint32 xflags)
     551             : {
     552             :     /* By default, XQuery is very nearly the same as Spencer's AREs */
     553         264 :     int         cflags = REG_ADVANCED;
     554             : 
     555             :     /* Ignore-case means the same thing, too, modulo locale issues */
     556         264 :     if (xflags & JSP_REGEX_ICASE)
     557          68 :         cflags |= REG_ICASE;
     558             : 
     559             :     /* Per XQuery spec, if 'q' is specified then 'm', 's', 'x' are ignored */
     560         264 :     if (xflags & JSP_REGEX_QUOTE)
     561             :     {
     562          76 :         cflags &= ~REG_ADVANCED;
     563          76 :         cflags |= REG_QUOTE;
     564             :     }
     565             :     else
     566             :     {
     567             :         /* Note that dotall mode is the default in POSIX */
     568         188 :         if (!(xflags & JSP_REGEX_DOTALL))
     569         144 :             cflags |= REG_NLSTOP;
     570         188 :         if (xflags & JSP_REGEX_MLINE)
     571          40 :             cflags |= REG_NLANCH;
     572             : 
     573             :         /*
     574             :          * XQuery's 'x' mode is related to Spencer's expanded mode, but it's
     575             :          * not really enough alike to justify treating JSP_REGEX_WSPACE as
     576             :          * REG_EXPANDED.  For now we treat 'x' as unimplemented; perhaps in
     577             :          * future we'll modify the regex library to have an option for
     578             :          * XQuery-style ignore-whitespace mode.
     579             :          */
     580         188 :         if (xflags & JSP_REGEX_WSPACE)
     581           4 :             ereport(ERROR,
     582             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     583             :                      errmsg("XQuery \"x\" flag (expanded regular expressions) is not implemented")));
     584             :     }
     585             : 
     586         260 :     return cflags;
     587             : }
     588             : 
     589             : /*
     590             :  * jsonpath_scan.l is compiled as part of jsonpath_gram.y.  Currently, this is
     591             :  * unavoidable because jsonpath_gram does not create a .h file to export its
     592             :  * token symbols.  If these files ever grow large enough to be worth compiling
     593             :  * separately, that could be fixed; but for now it seems like useless
     594             :  * complication.
     595             :  */
     596             : 
     597             : #include "jsonpath_scan.c"

Generated by: LCOV version 1.13