LCOV - code coverage report
Current view: top level - src/backend/utils/adt - jsonpath_gram.y (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 98.8 % 246 243
Test Date: 2026-07-22 12:15:41 Functions: 100.0 % 13 13
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 84.6 % 78 66

             Branch data     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-2026, 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                 :             : %parse-param {yyscan_t yyscanner}
      64                 :             : %lex-param {JsonPathParseResult **result}
      65                 :             : %lex-param {struct Node *escontext}
      66                 :             : %lex-param {yyscan_t yyscanner}
      67                 :             : 
      68                 :             : %union
      69                 :             : {
      70                 :             :     JsonPathString      str;
      71                 :             :     List               *elems;  /* list of JsonPathParseItem */
      72                 :             :     List               *indexs; /* list of integers */
      73                 :             :     JsonPathParseItem  *value;
      74                 :             :     JsonPathParseResult *result;
      75                 :             :     JsonPathItemType    optype;
      76                 :             :     bool                boolean;
      77                 :             :     int                 integer;
      78                 :             : }
      79                 :             : 
      80                 :             : %token  <str>     TO_P NULL_P TRUE_P FALSE_P IS_P UNKNOWN_P EXISTS_P
      81                 :             : %token  <str>     IDENT_P STRING_P NUMERIC_P INT_P VARIABLE_P
      82                 :             : %token  <str>     OR_P AND_P NOT_P
      83                 :             : %token  <str>     LESS_P LESSEQUAL_P EQUAL_P NOTEQUAL_P GREATEREQUAL_P GREATER_P
      84                 :             : %token  <str>     ANY_P STRICT_P LAX_P LAST_P STARTS_P WITH_P LIKE_REGEX_P FLAG_P
      85                 :             : %token  <str>     ABS_P SIZE_P TYPE_P FLOOR_P DOUBLE_P CEILING_P KEYVALUE_P
      86                 :             : %token  <str>     DATETIME_P
      87                 :             : %token  <str>     BIGINT_P BOOLEAN_P DATE_P DECIMAL_P INTEGER_P NUMBER_P
      88                 :             : %token  <str>     STRINGFUNC_P TIME_P TIME_TZ_P TIMESTAMP_P TIMESTAMP_TZ_P
      89                 :             : %token  <str>     STR_REPLACE_P STR_LOWER_P STR_UPPER_P STR_LTRIM_P STR_RTRIM_P STR_BTRIM_P
      90                 :             :                     STR_INITCAP_P STR_SPLIT_PART_P
      91                 :             : 
      92                 :             : %type   <result>  result
      93                 :             : 
      94                 :             : %type   <value>       scalar_value path_primary expr array_accessor
      95                 :             :                     any_path accessor_op key predicate delimited_predicate
      96                 :             :                     index_elem starts_with_initial expr_or_predicate
      97                 :             :                     str_elem opt_str_arg int_elem
      98                 :             :                     uint_elem opt_uint_arg
      99                 :             : 
     100                 :             : %type   <elems>       accessor_expr int_list opt_int_list str_int_args str_str_args
     101                 :             : 
     102                 :             : %type   <indexs>  index_list
     103                 :             : 
     104                 :             : %type   <optype>  comp_op method
     105                 :             : 
     106                 :             : %type   <boolean> mode
     107                 :             : 
     108                 :             : %type   <str>     key_name
     109                 :             : 
     110                 :             : %type   <integer> any_level
     111                 :             : 
     112                 :             : %left   OR_P
     113                 :             : %left   AND_P
     114                 :             : %right  NOT_P
     115                 :             : %left   '+' '-'
     116                 :             : %left   '*' '/' '%'
     117                 :             : %left   UMINUS
     118                 :             : %nonassoc '(' ')'
     119                 :             : 
     120                 :             : /* Grammar follows */
     121                 :             : %%
     122                 :             : 
     123                 :             : result:
     124                 :             :     mode expr_or_predicate          {
     125                 :        8102 :                                         *result = palloc_object(JsonPathParseResult);
     126                 :        8102 :                                         (*result)->expr = $2;
     127                 :        8102 :                                         (*result)->lax = $1;
     128                 :             :                                         (void) yynerrs;
     129                 :             :                                     }
     130                 :          20 :     | /* EMPTY */                   { *result = NULL; }
     131                 :             :     ;
     132                 :             : 
     133                 :             : expr_or_predicate:
     134                 :        7802 :     expr                            { $$ = $1; }
     135                 :         300 :     | predicate                     { $$ = $1; }
     136                 :             :     ;
     137                 :             : 
     138                 :             : mode:
     139                 :         644 :     STRICT_P                        { $$ = false; }
     140                 :         500 :     | LAX_P                         { $$ = true; }
     141                 :        7158 :     | /* EMPTY */                   { $$ = true; }
     142                 :             :     ;
     143                 :             : 
     144                 :             : scalar_value:
     145                 :         556 :     STRING_P                        { $$ = makeItemString(&$1); }
     146                 :          76 :     | NULL_P                        { $$ = makeItemString(NULL); }
     147                 :          92 :     | TRUE_P                        { $$ = makeItemBool(true); }
     148                 :          28 :     | FALSE_P                       { $$ = makeItemBool(false); }
     149                 :         356 :     | NUMERIC_P                     { $$ = makeItemNumeric(&$1); }
     150                 :        1032 :     | INT_P                         { $$ = makeItemNumeric(&$1); }
     151                 :         472 :     | VARIABLE_P                    { $$ = makeItemVariable(&$1); }
     152                 :             :     ;
     153                 :             : 
     154                 :             : comp_op:
     155                 :         668 :     EQUAL_P                         { $$ = jpiEqual; }
     156                 :           8 :     | NOTEQUAL_P                    { $$ = jpiNotEqual; }
     157                 :         504 :     | LESS_P                        { $$ = jpiLess; }
     158                 :         296 :     | GREATER_P                     { $$ = jpiGreater; }
     159                 :          28 :     | LESSEQUAL_P                   { $$ = jpiLessOrEqual; }
     160                 :         224 :     | GREATEREQUAL_P                { $$ = jpiGreaterOrEqual; }
     161                 :             :     ;
     162                 :             : 
     163                 :             : delimited_predicate:
     164                 :          48 :     '(' predicate ')'               { $$ = $2; }
     165                 :         176 :     | EXISTS_P '(' expr ')'         { $$ = makeItemUnary(jpiExists, $3); }
     166                 :             :     ;
     167                 :             : 
     168                 :             : predicate:
     169                 :         208 :     delimited_predicate             { $$ = $1; }
     170                 :        1728 :     | expr comp_op expr             { $$ = makeItemBinary($2, $1, $3); }
     171                 :         124 :     | predicate AND_P predicate     { $$ = makeItemBinary(jpiAnd, $1, $3); }
     172                 :          72 :     | predicate OR_P predicate      { $$ = makeItemBinary(jpiOr, $1, $3); }
     173                 :          16 :     | NOT_P delimited_predicate     { $$ = makeItemUnary(jpiNot, $2); }
     174                 :             :     | '(' predicate ')' IS_P UNKNOWN_P
     175                 :          48 :                                     { $$ = makeItemUnary(jpiIsUnknown, $2); }
     176                 :             :     | expr STARTS_P WITH_P starts_with_initial
     177                 :          52 :                                     { $$ = makeItemBinary(jpiStartsWith, $1, $4); }
     178                 :             :     | expr LIKE_REGEX_P STRING_P
     179                 :             :     {
     180                 :             :         JsonPathParseItem *jppitem;
     181         [ -  + ]:          12 :         if (! makeItemLikeRegex($1, &$3, NULL, &jppitem, escontext))
     182                 :           0 :             YYABORT;
     183                 :           8 :         $$ = jppitem;
     184                 :             :     }
     185                 :             :     | expr LIKE_REGEX_P STRING_P FLAG_P STRING_P
     186                 :             :     {
     187                 :             :         JsonPathParseItem *jppitem;
     188         [ +  + ]:          88 :         if (! makeItemLikeRegex($1, &$3, &$5, &jppitem, escontext))
     189                 :           8 :             YYABORT;
     190                 :          72 :         $$ = jppitem;
     191                 :             :     }
     192                 :             :     ;
     193                 :             : 
     194                 :             : starts_with_initial:
     195                 :          48 :     STRING_P                        { $$ = makeItemString(&$1); }
     196                 :           4 :     | VARIABLE_P                    { $$ = makeItemVariable(&$1); }
     197                 :             :     ;
     198                 :             : 
     199                 :             : path_primary:
     200                 :        2612 :     scalar_value                    { $$ = $1; }
     201                 :        8014 :     | '$'                           { $$ = makeItemType(jpiRoot); }
     202                 :        1732 :     | '@'                           { $$ = makeItemType(jpiCurrent); }
     203                 :          60 :     | LAST_P                        { $$ = makeItemType(jpiLast); }
     204                 :             :     ;
     205                 :             : 
     206                 :             : accessor_expr:
     207                 :       12418 :     path_primary                    { $$ = list_make1($1); }
     208                 :          60 :     | '(' expr ')' accessor_op      { $$ = list_make2($2, $4); }
     209                 :          20 :     | '(' predicate ')' accessor_op { $$ = list_make2($2, $4); }
     210                 :       10078 :     | accessor_expr accessor_op     { $$ = lappend($1, $2); }
     211                 :             :     ;
     212                 :             : 
     213                 :             : expr:
     214                 :       12350 :     accessor_expr                   { $$ = makeItemList($1); }
     215                 :         108 :     | '(' expr ')'                  { $$ = $2; }
     216                 :         116 :     | '+' expr %prec UMINUS         { $$ = makeItemUnary(jpiPlus, $2); }
     217                 :         164 :     | '-' expr %prec UMINUS         { $$ = makeItemUnary(jpiMinus, $2); }
     218                 :         140 :     | expr '+' expr                 { $$ = makeItemBinary(jpiAdd, $1, $3); }
     219                 :          68 :     | expr '-' expr                 { $$ = makeItemBinary(jpiSub, $1, $3); }
     220                 :          48 :     | expr '*' expr                 { $$ = makeItemBinary(jpiMul, $1, $3); }
     221                 :          24 :     | expr '/' expr                 { $$ = makeItemBinary(jpiDiv, $1, $3); }
     222                 :          12 :     | expr '%' expr                 { $$ = makeItemBinary(jpiMod, $1, $3); }
     223                 :             :     ;
     224                 :             : 
     225                 :             : index_elem:
     226                 :         348 :     expr                            { $$ = makeItemBinary(jpiSubscript, $1, NULL); }
     227                 :          32 :     | expr TO_P expr                { $$ = makeItemBinary(jpiSubscript, $1, $3); }
     228                 :             :     ;
     229                 :             : 
     230                 :             : index_list:
     231                 :         348 :     index_elem                      { $$ = list_make1($1); }
     232                 :          32 :     | index_list ',' index_elem     { $$ = lappend($1, $3); }
     233                 :             :     ;
     234                 :             : 
     235                 :             : array_accessor:
     236                 :        1608 :     '[' '*' ']'                     { $$ = makeItemType(jpiAnyArray); }
     237                 :         348 :     | '[' index_list ']'            { $$ = makeIndexArray($2); }
     238                 :             :     ;
     239                 :             : 
     240                 :             : any_level:
     241                 :         188 :     INT_P                           { $$ = pg_strtoint32($1.val); }
     242                 :          64 :     | LAST_P                        { $$ = -1; }
     243                 :             :     ;
     244                 :             : 
     245                 :             : any_path:
     246                 :          76 :     ANY_P                           { $$ = makeAny(0, -1); }
     247                 :          68 :     | ANY_P '{' any_level '}'       { $$ = makeAny($3, $3); }
     248                 :             :     | ANY_P '{' any_level TO_P any_level '}'
     249                 :          92 :                                     { $$ = makeAny($3, $5); }
     250                 :             :     ;
     251                 :             : 
     252                 :             : accessor_op:
     253                 :        2858 :     '.' key                         { $$ = $2; }
     254                 :         116 :     | '.' '*'                       { $$ = makeItemType(jpiAnyKey); }
     255                 :        1956 :     | array_accessor                { $$ = $1; }
     256                 :         236 :     | '.' any_path                  { $$ = $2; }
     257                 :        1472 :     | '.' method '(' ')'            { $$ = makeItemType($2); }
     258                 :        1520 :     | '?' '(' predicate ')'         { $$ = makeItemUnary(jpiFilter, $3); }
     259                 :             :     | '.' DECIMAL_P '(' opt_int_list ')'
     260                 :             :         {
     261         [ +  + ]:         208 :             if (list_length($4) == 0)
     262                 :         112 :                 $$ = makeItemBinary(jpiDecimal, NULL, NULL);
     263         [ +  + ]:          96 :             else if (list_length($4) == 1)
     264                 :           4 :                 $$ = makeItemBinary(jpiDecimal, linitial($4), NULL);
     265         [ +  - ]:          92 :             else if (list_length($4) == 2)
     266                 :          92 :                 $$ = makeItemBinary(jpiDecimal, linitial($4), lsecond($4));
     267                 :             :             else
     268         [ #  # ]:           0 :                 ereturn(escontext, false,
     269                 :             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     270                 :             :                          errmsg("invalid input syntax for type %s", "jsonpath"),
     271                 :             :                          errdetail(".decimal() can only have an optional precision[,scale].")));
     272                 :             :         }
     273                 :             :     | '.' DATETIME_P '(' opt_str_arg ')'
     274                 :         688 :         { $$ = makeItemUnary(jpiDatetime, $4); }
     275                 :             :     | '.' TIME_P '(' opt_uint_arg ')'
     276                 :         216 :         { $$ = makeItemUnary(jpiTime, $4); }
     277                 :             :     | '.' TIME_TZ_P '(' opt_uint_arg ')'
     278                 :         196 :         { $$ = makeItemUnary(jpiTimeTz, $4); }
     279                 :             :     | '.' TIMESTAMP_P '(' opt_uint_arg ')'
     280                 :         224 :         { $$ = makeItemUnary(jpiTimestamp, $4); }
     281                 :             :     | '.' TIMESTAMP_TZ_P '(' opt_uint_arg ')'
     282                 :         228 :         { $$ = makeItemUnary(jpiTimestampTz, $4); }
     283                 :             :     | '.' STR_REPLACE_P '(' str_str_args ')'
     284                 :          68 :         { $$ = makeItemBinary(jpiStrReplace, linitial($4), lsecond($4)); }
     285                 :             :     | '.' STR_SPLIT_PART_P '(' str_int_args ')'
     286                 :          32 :         { $$ = makeItemBinary(jpiStrSplitPart, linitial($4), lsecond($4)); }
     287                 :             :     | '.' STR_LTRIM_P '(' opt_str_arg ')'
     288                 :          88 :         { $$ = makeItemUnary(jpiStrLtrim, $4); }
     289                 :             :     | '.' STR_RTRIM_P '(' opt_str_arg ')'
     290                 :          24 :         { $$ = makeItemUnary(jpiStrRtrim, $4); }
     291                 :             :     | '.' STR_BTRIM_P '(' opt_str_arg ')'
     292                 :          28 :         { $$ = makeItemUnary(jpiStrBtrim, $4); }
     293                 :             :     ;
     294                 :             : 
     295                 :             : int_elem:
     296                 :             :     INT_P
     297                 :         168 :         { $$ = makeItemNumeric(&$1); }
     298                 :             :     | '+' INT_P %prec UMINUS
     299                 :          24 :         { $$ = makeItemUnary(jpiPlus, makeItemNumeric(&$2)); }
     300                 :             :     | '-' INT_P %prec UMINUS
     301                 :          32 :         { $$ = makeItemUnary(jpiMinus, makeItemNumeric(&$2)); }
     302                 :             :     ;
     303                 :             : 
     304                 :             : int_list:
     305                 :          96 :     int_elem                        { $$ = list_make1($1); }
     306                 :          92 :     | int_list ',' int_elem         { $$ = lappend($1, $3); }
     307                 :             :     ;
     308                 :             : 
     309                 :             : opt_int_list:
     310                 :          96 :     int_list                        { $$ = $1; }
     311                 :         112 :     | /* EMPTY */                   { $$ = NULL; }
     312                 :             :     ;
     313                 :             : 
     314                 :             : uint_elem:
     315                 :         184 :     INT_P                           { $$ = makeItemNumeric(&$1); }
     316                 :             :     ;
     317                 :             : 
     318                 :             : opt_uint_arg:
     319                 :         184 :     uint_elem                       { $$ = $1; }
     320                 :         712 :     | /* EMPTY */                   { $$ = NULL; }
     321                 :             :     ;
     322                 :             : 
     323                 :             : str_elem:
     324                 :         580 :     STRING_P                        { $$ = makeItemString(&$1); }
     325                 :             :     ;
     326                 :             : 
     327                 :             : opt_str_arg:
     328                 :         388 :     str_elem                        { $$ = $1; }
     329                 :         456 :     | /* EMPTY */                   { $$ = NULL; }
     330                 :             :     ;
     331                 :             : 
     332                 :             : str_int_args:
     333                 :          36 :     str_elem ',' int_elem           { $$ = list_make2($1, $3); }
     334                 :             :     ;
     335                 :             : 
     336                 :             : str_str_args:
     337                 :          72 :     str_elem ',' str_elem           { $$ = list_make2($1, $3); }
     338                 :             :     ;
     339                 :             : 
     340                 :             : key:
     341                 :        2858 :     key_name                        { $$ = makeItemKey(&$1); }
     342                 :             :     ;
     343                 :             : 
     344                 :             : key_name:
     345                 :             :     IDENT_P
     346                 :             :     | STRING_P
     347                 :             :     | TO_P
     348                 :             :     | NULL_P
     349                 :             :     | TRUE_P
     350                 :             :     | FALSE_P
     351                 :             :     | IS_P
     352                 :             :     | UNKNOWN_P
     353                 :             :     | EXISTS_P
     354                 :             :     | STRICT_P
     355                 :             :     | LAX_P
     356                 :             :     | ABS_P
     357                 :             :     | SIZE_P
     358                 :             :     | TYPE_P
     359                 :             :     | FLOOR_P
     360                 :             :     | DOUBLE_P
     361                 :             :     | CEILING_P
     362                 :             :     | DATETIME_P
     363                 :             :     | KEYVALUE_P
     364                 :             :     | LAST_P
     365                 :             :     | STARTS_P
     366                 :             :     | WITH_P
     367                 :             :     | LIKE_REGEX_P
     368                 :             :     | FLAG_P
     369                 :             :     | BIGINT_P
     370                 :             :     | BOOLEAN_P
     371                 :             :     | DATE_P
     372                 :             :     | DECIMAL_P
     373                 :             :     | INTEGER_P
     374                 :             :     | NUMBER_P
     375                 :             :     | STRINGFUNC_P
     376                 :             :     | TIME_P
     377                 :             :     | TIME_TZ_P
     378                 :             :     | TIMESTAMP_P
     379                 :             :     | TIMESTAMP_TZ_P
     380                 :             :     | STR_LOWER_P
     381                 :             :     | STR_UPPER_P
     382                 :             :     | STR_INITCAP_P
     383                 :             :     | STR_REPLACE_P
     384                 :             :     | STR_SPLIT_PART_P
     385                 :             :     | STR_LTRIM_P
     386                 :             :     | STR_RTRIM_P
     387                 :             :     | STR_BTRIM_P
     388                 :             :     ;
     389                 :             : 
     390                 :             : method:
     391                 :          28 :     ABS_P                           { $$ = jpiAbs; }
     392                 :          20 :     | SIZE_P                        { $$ = jpiSize; }
     393                 :         196 :     | TYPE_P                        { $$ = jpiType; }
     394                 :          20 :     | FLOOR_P                       { $$ = jpiFloor; }
     395                 :          80 :     | DOUBLE_P                      { $$ = jpiDouble; }
     396                 :          24 :     | CEILING_P                     { $$ = jpiCeiling; }
     397                 :          44 :     | KEYVALUE_P                    { $$ = jpiKeyValue; }
     398                 :         124 :     | BIGINT_P                      { $$ = jpiBigint; }
     399                 :         164 :     | BOOLEAN_P                     { $$ = jpiBoolean; }
     400                 :         156 :     | DATE_P                        { $$ = jpiDate; }
     401                 :         116 :     | INTEGER_P                     { $$ = jpiInteger; }
     402                 :         112 :     | NUMBER_P                      { $$ = jpiNumber; }
     403                 :         116 :     | STRINGFUNC_P                  { $$ = jpiStringFunc; }
     404                 :         112 :     | STR_LOWER_P                   { $$ = jpiStrLower; }
     405                 :         104 :     | STR_UPPER_P                   { $$ = jpiStrUpper; }
     406                 :          72 :     | STR_INITCAP_P                 { $$ = jpiStrInitcap; }
     407                 :             :     ;
     408                 :             : %%
     409                 :             : 
     410                 :             : /*
     411                 :             :  * The helper functions below allocate and fill JsonPathParseItem's of various
     412                 :             :  * types.
     413                 :             :  */
     414                 :             : 
     415                 :             : static JsonPathParseItem *
     416                 :       26836 : makeItemType(JsonPathItemType type)
     417                 :             : {
     418                 :       26836 :     JsonPathParseItem *v = palloc_object(JsonPathParseItem);
     419                 :             : 
     420         [ -  + ]:       26836 :     CHECK_FOR_INTERRUPTS();
     421                 :             : 
     422                 :       26836 :     v->type = type;
     423                 :       26836 :     v->next = NULL;
     424                 :             : 
     425                 :       26836 :     return v;
     426                 :             : }
     427                 :             : 
     428                 :             : static JsonPathParseItem *
     429                 :        4118 : makeItemString(JsonPathString *s)
     430                 :             : {
     431                 :             :     JsonPathParseItem *v;
     432                 :             : 
     433         [ +  + ]:        4118 :     if (s == NULL)
     434                 :             :     {
     435                 :          76 :         v = makeItemType(jpiNull);
     436                 :             :     }
     437                 :             :     else
     438                 :             :     {
     439                 :        4042 :         v = makeItemType(jpiString);
     440                 :        4042 :         v->value.string.val = s->val;
     441                 :        4042 :         v->value.string.len = s->len;
     442                 :             :     }
     443                 :             : 
     444                 :        4118 :     return v;
     445                 :             : }
     446                 :             : 
     447                 :             : static JsonPathParseItem *
     448                 :         476 : makeItemVariable(JsonPathString *s)
     449                 :             : {
     450                 :             :     JsonPathParseItem *v;
     451                 :             : 
     452                 :         476 :     v = makeItemType(jpiVariable);
     453                 :         476 :     v->value.string.val = s->val;
     454                 :         476 :     v->value.string.len = s->len;
     455                 :             : 
     456                 :         476 :     return v;
     457                 :             : }
     458                 :             : 
     459                 :             : static JsonPathParseItem *
     460                 :        2858 : makeItemKey(JsonPathString *s)
     461                 :             : {
     462                 :             :     JsonPathParseItem *v;
     463                 :             : 
     464                 :        2858 :     v = makeItemString(s);
     465                 :        2858 :     v->type = jpiKey;
     466                 :             : 
     467                 :        2858 :     return v;
     468                 :             : }
     469                 :             : 
     470                 :             : static JsonPathParseItem *
     471                 :        1796 : makeItemNumeric(JsonPathString *s)
     472                 :             : {
     473                 :             :     JsonPathParseItem *v;
     474                 :             : 
     475                 :        1796 :     v = makeItemType(jpiNumeric);
     476                 :        1796 :     v->value.numeric =
     477                 :        1796 :         DatumGetNumeric(DirectFunctionCall3(numeric_in,
     478                 :             :                                             CStringGetDatum(s->val),
     479                 :             :                                             ObjectIdGetDatum(InvalidOid),
     480                 :             :                                             Int32GetDatum(-1)));
     481                 :             : 
     482                 :        1796 :     return v;
     483                 :             : }
     484                 :             : 
     485                 :             : static JsonPathParseItem *
     486                 :         120 : makeItemBool(bool val)
     487                 :             : {
     488                 :         120 :     JsonPathParseItem *v = makeItemType(jpiBool);
     489                 :             : 
     490                 :         120 :     v->value.boolean = val;
     491                 :             : 
     492                 :         120 :     return v;
     493                 :             : }
     494                 :             : 
     495                 :             : static JsonPathParseItem *
     496                 :        2956 : makeItemBinary(JsonPathItemType type, JsonPathParseItem *la, JsonPathParseItem *ra)
     497                 :             : {
     498                 :        2956 :     JsonPathParseItem *v = makeItemType(type);
     499                 :             : 
     500                 :        2956 :     v->value.args.left = la;
     501                 :        2956 :     v->value.args.right = ra;
     502                 :             : 
     503                 :        2956 :     return v;
     504                 :             : }
     505                 :             : 
     506                 :             : static JsonPathParseItem *
     507                 :        3788 : makeItemUnary(JsonPathItemType type, JsonPathParseItem *a)
     508                 :             : {
     509                 :             :     JsonPathParseItem *v;
     510                 :             : 
     511   [ +  +  +  +  :        3788 :     if (type == jpiPlus && a->type == jpiNumeric && !a->next)
                   +  - ]
     512                 :         104 :         return a;
     513                 :             : 
     514   [ +  +  +  +  :        3684 :     if (type == jpiMinus && a->type == jpiNumeric && !a->next)
                   +  - ]
     515                 :             :     {
     516                 :         124 :         v = makeItemType(jpiNumeric);
     517                 :         124 :         v->value.numeric =
     518                 :         124 :             DatumGetNumeric(DirectFunctionCall1(numeric_uminus,
     519                 :             :                                                 NumericGetDatum(a->value.numeric)));
     520                 :         124 :         return v;
     521                 :             :     }
     522                 :             : 
     523                 :        3560 :     v = makeItemType(type);
     524                 :             : 
     525                 :        3560 :     v->value.arg = a;
     526                 :             : 
     527                 :        3560 :     return v;
     528                 :             : }
     529                 :             : 
     530                 :             : static JsonPathParseItem *
     531                 :       12350 : makeItemList(List *list)
     532                 :             : {
     533                 :             :     JsonPathParseItem *head,
     534                 :             :                *end;
     535                 :             :     ListCell   *cell;
     536                 :             : 
     537                 :       12350 :     head = end = (JsonPathParseItem *) linitial(list);
     538                 :             : 
     539         [ +  + ]:       12350 :     if (list_length(list) == 1)
     540                 :        4872 :         return head;
     541                 :             : 
     542                 :             :     /* append items to the end of already existing list */
     543         [ +  + ]:        7486 :     while (end->next)
     544                 :           8 :         end = end->next;
     545                 :             : 
     546   [ +  -  +  +  :       17636 :     for_each_from(cell, list, 1)
                   +  + ]
     547                 :             :     {
     548                 :       10158 :         JsonPathParseItem *c = (JsonPathParseItem *) lfirst(cell);
     549                 :             : 
     550                 :       10158 :         end->next = c;
     551                 :       10158 :         end = c;
     552                 :             :     }
     553                 :             : 
     554                 :        7478 :     return head;
     555                 :             : }
     556                 :             : 
     557                 :             : static JsonPathParseItem *
     558                 :         348 : makeIndexArray(List *list)
     559                 :             : {
     560                 :         348 :     JsonPathParseItem *v = makeItemType(jpiIndexArray);
     561                 :             :     ListCell   *cell;
     562                 :         348 :     int         i = 0;
     563                 :             : 
     564                 :             :     Assert(list != NIL);
     565                 :         348 :     v->value.array.nelems = list_length(list);
     566                 :             : 
     567                 :         696 :     v->value.array.elems = palloc(sizeof(v->value.array.elems[0]) *
     568                 :         348 :                                   v->value.array.nelems);
     569                 :             : 
     570   [ +  -  +  +  :         728 :     foreach(cell, list)
                   +  + ]
     571                 :             :     {
     572                 :         380 :         JsonPathParseItem *jpi = lfirst(cell);
     573                 :             : 
     574                 :             :         Assert(jpi->type == jpiSubscript);
     575                 :             : 
     576                 :         380 :         v->value.array.elems[i].from = jpi->value.args.left;
     577                 :         380 :         v->value.array.elems[i++].to = jpi->value.args.right;
     578                 :             :     }
     579                 :             : 
     580                 :         348 :     return v;
     581                 :             : }
     582                 :             : 
     583                 :             : static JsonPathParseItem *
     584                 :         236 : makeAny(int first, int last)
     585                 :             : {
     586                 :         236 :     JsonPathParseItem *v = makeItemType(jpiAny);
     587                 :             : 
     588         [ +  + ]:         236 :     v->value.anybounds.first = (first >= 0) ? first : PG_UINT32_MAX;
     589         [ +  + ]:         236 :     v->value.anybounds.last = (last >= 0) ? last : PG_UINT32_MAX;
     590                 :             : 
     591                 :         236 :     return v;
     592                 :             : }
     593                 :             : 
     594                 :             : static bool
     595                 :         100 : makeItemLikeRegex(JsonPathParseItem *expr, JsonPathString *pattern,
     596                 :             :                   JsonPathString *flags, JsonPathParseItem **result,
     597                 :             :                   struct Node *escontext)
     598                 :             : {
     599                 :         100 :     JsonPathParseItem *v = makeItemType(jpiLikeRegex);
     600                 :             :     int         i;
     601                 :             :     int         cflags;
     602                 :             : 
     603                 :         100 :     v->value.like_regex.expr = expr;
     604                 :         100 :     v->value.like_regex.pattern = pattern->val;
     605                 :         100 :     v->value.like_regex.patternlen = pattern->len;
     606                 :             : 
     607                 :             :     /* Parse the flags string, convert to bitmask.  Duplicate flags are OK. */
     608                 :         100 :     v->value.like_regex.flags = 0;
     609   [ +  +  +  + ]:         248 :     for (i = 0; flags && i < flags->len; i++)
     610                 :             :     {
     611   [ +  +  +  +  :         160 :         switch (flags->val[i])
                   +  + ]
     612                 :             :         {
     613                 :          40 :             case 'i':
     614                 :          40 :                 v->value.like_regex.flags |= JSP_REGEX_ICASE;
     615                 :          40 :                 break;
     616                 :          32 :             case 's':
     617                 :          32 :                 v->value.like_regex.flags |= JSP_REGEX_DOTALL;
     618                 :          32 :                 break;
     619                 :          24 :             case 'm':
     620                 :          24 :                 v->value.like_regex.flags |= JSP_REGEX_MLINE;
     621                 :          24 :                 break;
     622                 :          16 :             case 'x':
     623                 :          16 :                 v->value.like_regex.flags |= JSP_REGEX_WSPACE;
     624                 :          16 :                 break;
     625                 :          36 :             case 'q':
     626                 :          36 :                 v->value.like_regex.flags |= JSP_REGEX_QUOTE;
     627                 :          36 :                 break;
     628                 :          12 :             default:
     629         [ +  + ]:          12 :                 ereturn(escontext, false,
     630                 :             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     631                 :             :                          errmsg("invalid input syntax for type %s", "jsonpath"),
     632                 :             :                          errdetail("Unrecognized flag character \"%.*s\" in LIKE_REGEX predicate.",
     633                 :             :                                    pg_mblen_range(flags->val + i, flags->val + flags->len),
     634                 :             :                                    flags->val + i)));
     635                 :             :                 break;
     636                 :             :         }
     637                 :             :     }
     638                 :             : 
     639                 :             :     /* Convert flags to what pg_regcomp needs */
     640         [ -  + ]:          88 :     if (!jspConvertRegexFlags(v->value.like_regex.flags, &cflags, escontext))
     641                 :           0 :         return false;
     642                 :             : 
     643                 :             :     /* check regex validity */
     644                 :             :     {
     645                 :             :         regex_t     re_tmp;
     646                 :             :         pg_wchar   *wpattern;
     647                 :             :         int         wpattern_len;
     648                 :             :         int         re_result;
     649                 :             : 
     650                 :          84 :         wpattern = (pg_wchar *) palloc((pattern->len + 1) * sizeof(pg_wchar));
     651                 :          84 :         wpattern_len = pg_mb2wchar_with_len(pattern->val,
     652                 :             :                                             wpattern,
     653                 :             :                                             pattern->len);
     654                 :             : 
     655         [ +  + ]:          84 :         if ((re_result = pg_regcomp(&re_tmp, wpattern, wpattern_len, cflags,
     656                 :             :                                     DEFAULT_COLLATION_OID)) != REG_OKAY)
     657                 :             :         {
     658                 :             :             char        errMsg[100];
     659                 :             : 
     660                 :           4 :             pg_regerror(re_result, &re_tmp, errMsg, sizeof(errMsg));
     661         [ +  - ]:           4 :             ereturn(escontext, false,
     662                 :             :                     (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
     663                 :             :                      errmsg("invalid regular expression: %s", errMsg)));
     664                 :             :         }
     665                 :             : 
     666                 :          80 :         pg_regfree(&re_tmp);
     667                 :             :     }
     668                 :             : 
     669                 :          80 :     *result = v;
     670                 :             : 
     671                 :          80 :     return true;
     672                 :             : }
     673                 :             : 
     674                 :             : /*
     675                 :             :  * Convert from XQuery regex flags to those recognized by our regex library.
     676                 :             :  */
     677                 :             : bool
     678                 :         272 : jspConvertRegexFlags(uint32 xflags, int *result, struct Node *escontext)
     679                 :             : {
     680                 :             :     /* By default, XQuery is very nearly the same as Spencer's AREs */
     681                 :         272 :     int         cflags = REG_ADVANCED;
     682                 :             : 
     683                 :             :     /* Ignore-case means the same thing, too, modulo locale issues */
     684         [ +  + ]:         272 :     if (xflags & JSP_REGEX_ICASE)
     685                 :          76 :         cflags |= REG_ICASE;
     686                 :             : 
     687                 :             :     /* Per XQuery spec, if 'q' is specified then 'm', 's', 'x' are ignored */
     688         [ +  + ]:         272 :     if (xflags & JSP_REGEX_QUOTE)
     689                 :             :     {
     690                 :          84 :         cflags &= ~REG_ADVANCED;
     691                 :          84 :         cflags |= REG_QUOTE;
     692                 :             :     }
     693                 :             :     else
     694                 :             :     {
     695                 :             :         /* Note that dotall mode is the default in POSIX */
     696         [ +  + ]:         188 :         if (!(xflags & JSP_REGEX_DOTALL))
     697                 :         144 :             cflags |= REG_NLSTOP;
     698         [ +  + ]:         188 :         if (xflags & JSP_REGEX_MLINE)
     699                 :          40 :             cflags |= REG_NLANCH;
     700                 :             : 
     701                 :             :         /*
     702                 :             :          * XQuery's 'x' mode is related to Spencer's expanded mode, but it's
     703                 :             :          * not really enough alike to justify treating JSP_REGEX_WSPACE as
     704                 :             :          * REG_EXPANDED.  For now we treat 'x' as unimplemented; perhaps in
     705                 :             :          * future we'll modify the regex library to have an option for
     706                 :             :          * XQuery-style ignore-whitespace mode.
     707                 :             :          */
     708         [ +  + ]:         188 :         if (xflags & JSP_REGEX_WSPACE)
     709         [ +  - ]:           4 :             ereturn(escontext, false,
     710                 :             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     711                 :             :                      errmsg("XQuery \"x\" flag (expanded regular expressions) is not implemented")));
     712                 :             :     }
     713                 :             : 
     714                 :         268 :     *result = cflags;
     715                 :             : 
     716                 :         268 :     return true;
     717                 :             : }
        

Generated by: LCOV version 2.0-1