LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - jsonpath_gram.y (source / functions) Coverage Total Hit UNC GBC GIC GNC CBC ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 99.1 % 211 209 2 1 92 20 96 103 1 10
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 13 13 12 1 13
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a