LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - jsonpath.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 92.3 % 508 469 9 7 15 8 9 178 62 220 21 209 1 33
Current Date: 2023-04-08 15:15:32 Functions: 90.9 % 22 20 2 18 2 2 20
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * jsonpath.c
       4                 :  *   Input/output and supporting routines for jsonpath
       5                 :  *
       6                 :  * jsonpath expression is a chain of path items.  First path item is $, $var,
       7                 :  * literal or arithmetic expression.  Subsequent path items are accessors
       8                 :  * (.key, .*, [subscripts], [*]), filters (? (predicate)) and methods (.type(),
       9                 :  * .size() etc).
      10                 :  *
      11                 :  * For instance, structure of path items for simple expression:
      12                 :  *
      13                 :  *      $.a[*].type()
      14                 :  *
      15                 :  * is pretty evident:
      16                 :  *
      17                 :  *      $ => .a => [*] => .type()
      18                 :  *
      19                 :  * Some path items such as arithmetic operations, predicates or array
      20                 :  * subscripts may comprise subtrees.  For instance, more complex expression
      21                 :  *
      22                 :  *      ($.a + $[1 to 5, 7] ? (@ > 3).double()).type()
      23                 :  *
      24                 :  * have following structure of path items:
      25                 :  *
      26                 :  *            +  =>  .type()
      27                 :  *        ___/ \___
      28                 :  *       /         \
      29                 :  *      $ => .a  $  =>  []  => ?  =>  .double()
      30                 :  *                        _||_      |
      31                 :  *                       /    \     >
      32                 :  *                      to    to   / \
      33                 :  *                     / \    /   @   3
      34                 :  *                    1   5  7
      35                 :  *
      36                 :  * Binary encoding of jsonpath constitutes a sequence of 4-bytes aligned
      37                 :  * variable-length path items connected by links.  Every item has a header
      38                 :  * consisting of item type (enum JsonPathItemType) and offset of next item
      39                 :  * (zero means no next item).  After the header, item may have payload
      40                 :  * depending on item type.  For instance, payload of '.key' accessor item is
      41                 :  * length of key name and key name itself.  Payload of '>' arithmetic operator
      42                 :  * item is offsets of right and left operands.
      43                 :  *
      44                 :  * So, binary representation of sample expression above is:
      45                 :  * (bottom arrows are next links, top lines are argument links)
      46                 :  *
      47                 :  *                                _____
      48                 :  *       _____                ___/____ \                __
      49                 :  *    _ /_    \         _____/__/____ \ \      __    _ /_ \
      50                 :  *   / /  \    \       /    /  /     \ \ \    /  \  / /  \ \
      51                 :  * +(LR)  $ .a  $  [](* to *, * to *) 1 5 7 ?(A)  >(LR)   @ 3 .double() .type()
      52                 :  * |      |  ^  |  ^|                        ^|                   ^        ^
      53                 :  * |      |__|  |__||________________________||___________________|        |
      54                 :  * |_______________________________________________________________________|
      55                 :  *
      56                 :  * Copyright (c) 2019-2023, PostgreSQL Global Development Group
      57                 :  *
      58                 :  * IDENTIFICATION
      59                 :  *  src/backend/utils/adt/jsonpath.c
      60                 :  *
      61                 :  *-------------------------------------------------------------------------
      62                 :  */
      63                 : 
      64                 : #include "postgres.h"
      65                 : 
      66                 : #include "funcapi.h"
      67                 : #include "lib/stringinfo.h"
      68                 : #include "libpq/pqformat.h"
      69                 : #include "nodes/miscnodes.h"
      70                 : #include "miscadmin.h"
      71                 : #include "utils/builtins.h"
      72                 : #include "utils/json.h"
      73                 : #include "utils/jsonpath.h"
      74                 : 
      75                 : 
      76                 : static Datum jsonPathFromCstring(char *in, int len, struct Node *escontext);
      77                 : static char *jsonPathToCstring(StringInfo out, JsonPath *in,
      78                 :                                int estimated_len);
      79                 : static bool flattenJsonPathParseItem(StringInfo buf, int *result,
      80                 :                                      struct Node *escontext,
      81                 :                                      JsonPathParseItem *item,
      82                 :                                      int nestingLevel, bool insideArraySubscript);
      83                 : static void alignStringInfoInt(StringInfo buf);
      84                 : static int32 reserveSpaceForItemPointer(StringInfo buf);
      85                 : static void printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
      86                 :                               bool printBracketes);
      87                 : static int  operationPriority(JsonPathItemType op);
      88                 : 
      89                 : 
      90                 : /**************************** INPUT/OUTPUT ********************************/
      91                 : 
      92                 : /*
      93                 :  * jsonpath type input function
      94                 :  */
      95                 : Datum
      96 GIC        2280 : jsonpath_in(PG_FUNCTION_ARGS)
      97                 : {
      98            2280 :     char       *in = PG_GETARG_CSTRING(0);
      99 CBC        2280 :     int         len = strlen(in);
     100                 : 
     101 GNC        2280 :     return jsonPathFromCstring(in, len, fcinfo->context);
     102 ECB             : }
     103                 : 
     104                 : /*
     105                 :  * jsonpath type recv function
     106                 :  *
     107                 :  * The type is sent as text in binary mode, so this is almost the same
     108                 :  * as the input function, but it's prefixed with a version number so we
     109                 :  * can change the binary format sent in future if necessary. For now,
     110                 :  * only version 1 is supported.
     111                 :  */
     112                 : Datum
     113 UIC           0 : jsonpath_recv(PG_FUNCTION_ARGS)
     114                 : {
     115               0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     116 UBC           0 :     int         version = pq_getmsgint(buf, 1);
     117                 :     char       *str;
     118 EUB             :     int         nbytes;
     119                 : 
     120 UIC           0 :     if (version == JSONPATH_VERSION)
     121               0 :         str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
     122                 :     else
     123 UBC           0 :         elog(ERROR, "unsupported jsonpath version number: %d", version);
     124 EUB             : 
     125 UNC           0 :     return jsonPathFromCstring(str, nbytes, NULL);
     126 EUB             : }
     127                 : 
     128                 : /*
     129                 :  * jsonpath type output function
     130                 :  */
     131                 : Datum
     132 GIC         586 : jsonpath_out(PG_FUNCTION_ARGS)
     133                 : {
     134             586 :     JsonPath   *in = PG_GETARG_JSONPATH_P(0);
     135 ECB             : 
     136 GIC         586 :     PG_RETURN_CSTRING(jsonPathToCstring(NULL, in, VARSIZE(in)));
     137 ECB             : }
     138                 : 
     139                 : /*
     140                 :  * jsonpath type send function
     141                 :  *
     142                 :  * Just send jsonpath as a version number, then a string of text
     143                 :  */
     144                 : Datum
     145 UIC           0 : jsonpath_send(PG_FUNCTION_ARGS)
     146                 : {
     147               0 :     JsonPath   *in = PG_GETARG_JSONPATH_P(0);
     148 EUB             :     StringInfoData buf;
     149                 :     StringInfoData jtext;
     150 UBC           0 :     int         version = JSONPATH_VERSION;
     151                 : 
     152 UIC           0 :     initStringInfo(&jtext);
     153 UBC           0 :     (void) jsonPathToCstring(&jtext, in, VARSIZE(in));
     154                 : 
     155               0 :     pq_begintypsend(&buf);
     156               0 :     pq_sendint8(&buf, version);
     157 UIC           0 :     pq_sendtext(&buf, jtext.data, jtext.len);
     158 UBC           0 :     pfree(jtext.data);
     159 EUB             : 
     160 UBC           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     161 EUB             : }
     162                 : 
     163                 : /*
     164                 :  * Converts C-string to a jsonpath value.
     165                 :  *
     166                 :  * Uses jsonpath parser to turn string into an AST, then
     167                 :  * flattenJsonPathParseItem() does second pass turning AST into binary
     168                 :  * representation of jsonpath.
     169                 :  */
     170                 : static Datum
     171 GNC        2280 : jsonPathFromCstring(char *in, int len, struct Node *escontext)
     172                 : {
     173            2280 :     JsonPathParseResult *jsonpath = parsejsonpath(in, len, escontext);
     174 ECB             :     JsonPath   *res;
     175                 :     StringInfoData buf;
     176                 : 
     177 GNC        2130 :     if (SOFT_ERROR_OCCURRED(escontext))
     178              18 :         return (Datum) 0;
     179                 : 
     180            2112 :     if (!jsonpath)
     181               3 :         ereturn(escontext, (Datum) 0,
     182                 :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
     183                 :                  errmsg("invalid input syntax for type %s: \"%s\"", "jsonpath",
     184                 :                         in)));
     185                 : 
     186 GIC        2109 :     initStringInfo(&buf);
     187            2109 :     enlargeStringInfo(&buf, 4 * len /* estimation */ );
     188                 : 
     189 CBC        2109 :     appendStringInfoSpaces(&buf, JSONPATH_HDRSZ);
     190 ECB             : 
     191 GNC        2109 :     if (!flattenJsonPathParseItem(&buf, NULL, escontext,
     192                 :                                   jsonpath->expr, 0, false))
     193               6 :         return (Datum) 0;
     194 ECB             : 
     195 CBC        2094 :     res = (JsonPath *) buf.data;
     196 GIC        2094 :     SET_VARSIZE(res, buf.len);
     197 CBC        2094 :     res->header = JSONPATH_VERSION;
     198 GIC        2094 :     if (jsonpath->lax)
     199 CBC        1917 :         res->header |= JSONPATH_LAX;
     200                 : 
     201            2094 :     PG_RETURN_JSONPATH_P(res);
     202                 : }
     203 ECB             : 
     204                 : /*
     205                 :  * Converts jsonpath value to a C-string.
     206                 :  *
     207                 :  * If 'out' argument is non-null, the resulting C-string is stored inside the
     208                 :  * StringBuffer.  The resulting string is always returned.
     209                 :  */
     210                 : static char *
     211 GIC         586 : jsonPathToCstring(StringInfo out, JsonPath *in, int estimated_len)
     212                 : {
     213                 :     StringInfoData buf;
     214                 :     JsonPathItem v;
     215                 : 
     216             586 :     if (!out)
     217                 :     {
     218             586 :         out = &buf;
     219 CBC         586 :         initStringInfo(out);
     220                 :     }
     221 GIC         586 :     enlargeStringInfo(out, estimated_len);
     222                 : 
     223             586 :     if (!(in->header & JSONPATH_LAX))
     224 GNC           3 :         appendStringInfoString(out, "strict ");
     225                 : 
     226 CBC         586 :     jspInit(&v, in);
     227             586 :     printJsonPathItem(out, &v, false, true);
     228                 : 
     229             586 :     return out->data;
     230                 : }
     231 ECB             : 
     232                 : /*
     233                 :  * Recursive function converting given jsonpath parse item and all its
     234                 :  * children into a binary representation.
     235                 :  */
     236                 : static bool
     237 GNC        9843 : flattenJsonPathParseItem(StringInfo buf,  int *result, struct Node *escontext,
     238                 :                          JsonPathParseItem *item, int nestingLevel,
     239                 :                          bool insideArraySubscript)
     240                 : {
     241                 :     /* position from beginning of jsonpath data */
     242 GIC        9843 :     int32       pos = buf->len - JSONPATH_HDRSZ;
     243                 :     int32       chld;
     244                 :     int32       next;
     245            9843 :     int         argNestingLevel = 0;
     246 ECB             : 
     247 GIC        9843 :     check_stack_depth();
     248            9843 :     CHECK_FOR_INTERRUPTS();
     249                 : 
     250            9843 :     appendStringInfoChar(buf, (char) (item->type));
     251 ECB             : 
     252                 :     /*
     253                 :      * We align buffer to int32 because a series of int32 values often goes
     254                 :      * after the header, and we want to read them directly by dereferencing
     255                 :      * int32 pointer (see jspInitByBuffer()).
     256                 :      */
     257 CBC        9843 :     alignStringInfoInt(buf);
     258                 : 
     259 ECB             :     /*
     260                 :      * Reserve space for next item pointer.  Actual value will be recorded
     261                 :      * later, after next and children items processing.
     262                 :      */
     263 GIC        9843 :     next = reserveSpaceForItemPointer(buf);
     264                 : 
     265            9843 :     switch (item->type)
     266 ECB             :     {
     267 GIC        1947 :         case jpiString:
     268                 :         case jpiVariable:
     269                 :         case jpiKey:
     270 GNC        1947 :             appendBinaryStringInfo(buf, &item->value.string.len,
     271                 :                                    sizeof(item->value.string.len));
     272 CBC        1947 :             appendBinaryStringInfo(buf, item->value.string.val,
     273 GIC        1947 :                                    item->value.string.len);
     274 CBC        1947 :             appendStringInfoChar(buf, '\0');
     275 GIC        1947 :             break;
     276 CBC         870 :         case jpiNumeric:
     277 GNC         870 :             appendBinaryStringInfo(buf, item->value.numeric,
     278 GIC         870 :                                    VARSIZE(item->value.numeric));
     279 CBC         870 :             break;
     280 GIC          90 :         case jpiBool:
     281 GNC          90 :             appendBinaryStringInfo(buf, &item->value.boolean,
     282 ECB             :                                    sizeof(item->value.boolean));
     283 CBC          90 :             break;
     284            1272 :         case jpiAnd:
     285 ECB             :         case jpiOr:
     286                 :         case jpiEqual:
     287                 :         case jpiNotEqual:
     288                 :         case jpiLess:
     289                 :         case jpiGreater:
     290                 :         case jpiLessOrEqual:
     291                 :         case jpiGreaterOrEqual:
     292                 :         case jpiAdd:
     293                 :         case jpiSub:
     294                 :         case jpiMul:
     295                 :         case jpiDiv:
     296                 :         case jpiMod:
     297                 :         case jpiStartsWith:
     298                 :             {
     299                 :                 /*
     300                 :                  * First, reserve place for left/right arg's positions, then
     301                 :                  * record both args and sets actual position in reserved
     302                 :                  * places.
     303                 :                  */
     304 GIC        1272 :                 int32       left = reserveSpaceForItemPointer(buf);
     305            1272 :                 int32       right = reserveSpaceForItemPointer(buf);
     306                 : 
     307 GNC        1272 :                 if (!item->value.args.left)
     308 UNC           0 :                     chld = pos;
     309 GNC        1272 :                 else if (! flattenJsonPathParseItem(buf, &chld, escontext,
     310                 :                                                     item->value.args.left,
     311                 :                                                     nestingLevel + argNestingLevel,
     312                 :                                                     insideArraySubscript))
     313               6 :                     return false;
     314 GIC        1260 :                 *(int32 *) (buf->data + left) = chld - pos;
     315                 : 
     316 GNC        1260 :                 if (!item->value.args.right)
     317 UNC           0 :                     chld = pos;
     318 GNC        1260 :                 else if (! flattenJsonPathParseItem(buf, &chld, escontext,
     319                 :                                                     item->value.args.right,
     320                 :                                                     nestingLevel + argNestingLevel,
     321                 :                                                     insideArraySubscript))
     322 UNC           0 :                     return false;
     323 GBC        1260 :                 *(int32 *) (buf->data + right) = chld - pos;
     324 ECB             :             }
     325 GIC        1260 :             break;
     326              60 :         case jpiLikeRegex:
     327                 :             {
     328 ECB             :                 int32       offs;
     329                 : 
     330 GIC          60 :                 appendBinaryStringInfo(buf,
     331 GNC          60 :                                        &item->value.like_regex.flags,
     332 EUB             :                                        sizeof(item->value.like_regex.flags));
     333 CBC          60 :                 offs = reserveSpaceForItemPointer(buf);
     334 GIC          60 :                 appendBinaryStringInfo(buf,
     335 GNC          60 :                                        &item->value.like_regex.patternlen,
     336                 :                                        sizeof(item->value.like_regex.patternlen));
     337 GBC          60 :                 appendBinaryStringInfo(buf, item->value.like_regex.pattern,
     338 CBC          60 :                                        item->value.like_regex.patternlen);
     339 GIC          60 :                 appendStringInfoChar(buf, '\0');
     340 ECB             : 
     341 GNC          60 :                 if (! flattenJsonPathParseItem(buf, &chld, escontext,
     342                 :                                                item->value.like_regex.expr,
     343                 :                                                nestingLevel,
     344                 :                                                insideArraySubscript))
     345 UNC           0 :                     return false;
     346 GIC          60 :                 *(int32 *) (buf->data + offs) = chld - pos;
     347 ECB             :             }
     348 CBC          60 :             break;
     349 GIC         819 :         case jpiFilter:
     350 CBC         819 :             argNestingLevel++;
     351 ECB             :             /* FALLTHROUGH */
     352 CBC        1455 :         case jpiIsUnknown:
     353                 :         case jpiNot:
     354 ECB             :         case jpiPlus:
     355                 :         case jpiMinus:
     356                 :         case jpiExists:
     357                 :         case jpiDatetime:
     358                 :             {
     359 GIC        1455 :                 int32       arg = reserveSpaceForItemPointer(buf);
     360                 : 
     361 GNC        1455 :                 if (!item->value.arg)
     362             168 :                     chld = pos;
     363            1287 :                 else if (! flattenJsonPathParseItem(buf, &chld, escontext,
     364                 :                                                     item->value.arg,
     365                 :                                                     nestingLevel + argNestingLevel,
     366                 :                                                     insideArraySubscript))
     367 UNC           0 :                     return false;
     368 CBC        1452 :                 *(int32 *) (buf->data + arg) = chld - pos;
     369 ECB             :             }
     370 CBC        1452 :             break;
     371 GIC          57 :         case jpiNull:
     372 CBC          57 :             break;
     373 GIC        1929 :         case jpiRoot:
     374            1929 :             break;
     375             561 :         case jpiAnyArray:
     376                 :         case jpiAnyKey:
     377             561 :             break;
     378             954 :         case jpiCurrent:
     379 CBC         954 :             if (nestingLevel <= 0)
     380 GNC           9 :                 ereturn(escontext, false,
     381 ECB             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     382                 :                          errmsg("@ is not allowed in root expressions")));
     383 CBC         945 :             break;
     384 GIC          45 :         case jpiLast:
     385              45 :             if (!insideArraySubscript)
     386 GNC           6 :                 ereturn(escontext, false,
     387 EUB             :                         (errcode(ERRCODE_SYNTAX_ERROR),
     388 ECB             :                          errmsg("LAST is allowed only in array subscripts")));
     389 GIC          39 :             break;
     390 CBC         168 :         case jpiIndexArray:
     391 ECB             :             {
     392 CBC         168 :                 int32       nelems = item->value.array.nelems;
     393 ECB             :                 int         offset;
     394                 :                 int         i;
     395                 : 
     396 GNC         168 :                 appendBinaryStringInfo(buf, &nelems, sizeof(nelems));
     397 ECB             : 
     398 CBC         168 :                 offset = buf->len;
     399 ECB             : 
     400 CBC         168 :                 appendStringInfoSpaces(buf, sizeof(int32) * 2 * nelems);
     401                 : 
     402 GIC         351 :                 for (i = 0; i < nelems; i++)
     403 ECB             :                 {
     404                 :                     int32      *ppos;
     405                 :                     int32       topos;
     406                 :                     int32       frompos;
     407                 : 
     408 GNC         183 :                     if (! flattenJsonPathParseItem(buf, &frompos, escontext,
     409             183 :                                                    item->value.array.elems[i].from,
     410                 :                                                    nestingLevel, true))
     411 UNC           0 :                         return false;
     412 GNC         183 :                     frompos -= pos;
     413 ECB             : 
     414 GIC         183 :                     if (item->value.array.elems[i].to)
     415                 :                     {
     416 GNC          21 :                         if (! flattenJsonPathParseItem(buf, &topos, escontext,
     417              21 :                                                        item->value.array.elems[i].to,
     418                 :                                                        nestingLevel, true))
     419 UNC           0 :                             return false;
     420 GNC          21 :                         topos -= pos;
     421                 :                     }
     422                 :                     else
     423 CBC         162 :                         topos = 0;
     424                 : 
     425             183 :                     ppos = (int32 *) &buf->data[offset + i * 2 * sizeof(int32)];
     426                 : 
     427             183 :                     ppos[0] = frompos;
     428 GIC         183 :                     ppos[1] = topos;
     429 ECB             :                 }
     430                 :             }
     431 GIC         168 :             break;
     432             177 :         case jpiAny:
     433             177 :             appendBinaryStringInfo(buf,
     434 GNC         177 :                                    &item->value.anybounds.first,
     435 ECB             :                                    sizeof(item->value.anybounds.first));
     436 CBC         177 :             appendBinaryStringInfo(buf,
     437 GNC         177 :                                    &item->value.anybounds.last,
     438 EUB             :                                    sizeof(item->value.anybounds.last));
     439 CBC         177 :             break;
     440 GIC         258 :         case jpiType:
     441 ECB             :         case jpiSize:
     442                 :         case jpiAbs:
     443                 :         case jpiFloor:
     444                 :         case jpiCeiling:
     445                 :         case jpiDouble:
     446 EUB             :         case jpiKeyValue:
     447 CBC         258 :             break;
     448 UIC           0 :         default:
     449               0 :             elog(ERROR, "unrecognized jsonpath item type: %d", item->type);
     450 ECB             :     }
     451                 : 
     452 CBC        9813 :     if (item->next)
     453                 :     {
     454 GNC        3651 :         if (! flattenJsonPathParseItem(buf, &chld, escontext,
     455                 :                                        item->next, nestingLevel,
     456                 :                                        insideArraySubscript))
     457 UNC           0 :             return false;
     458 GNC        3648 :         chld -= pos;
     459 GIC        3648 :         *(int32 *) (buf->data + next) = chld;
     460                 :     }
     461 ECB             : 
     462 GNC        9810 :     if (result)
     463            7716 :         *result = pos;
     464            9810 :     return true;
     465 ECB             : }
     466                 : 
     467                 : /*
     468                 :  * Align StringInfo to int by adding zero padding bytes
     469                 :  */
     470                 : static void
     471 CBC        9843 : alignStringInfoInt(StringInfo buf)
     472 ECB             : {
     473 GIC        9843 :     switch (INTALIGN(buf->len) - buf->len)
     474                 :     {
     475            8649 :         case 3:
     476            8649 :             appendStringInfoCharMacro(buf, 0);
     477                 :             /* FALLTHROUGH */
     478                 :         case 2:
     479 CBC        8817 :             appendStringInfoCharMacro(buf, 0);
     480 EUB             :             /* FALLTHROUGH */
     481                 :         case 1:
     482 GIC        9747 :             appendStringInfoCharMacro(buf, 0);
     483                 :             /* FALLTHROUGH */
     484 ECB             :         default:
     485 GIC        9843 :             break;
     486 ECB             :     }
     487 GIC        9843 : }
     488                 : 
     489 EUB             : /*
     490 ECB             :  * Reserve space for int32 JsonPathItem pointer.  Now zero pointer is written,
     491                 :  * actual value will be recorded at '(int32 *) &buf->data[pos]' later.
     492                 :  */
     493                 : static int32
     494 CBC       13902 : reserveSpaceForItemPointer(StringInfo buf)
     495 ECB             : {
     496 CBC       13902 :     int32       pos = buf->len;
     497 GIC       13902 :     int32       ptr = 0;
     498                 : 
     499 GNC       13902 :     appendBinaryStringInfo(buf, &ptr, sizeof(ptr));
     500                 : 
     501 GIC       13902 :     return pos;
     502                 : }
     503 ECB             : 
     504                 : /*
     505                 :  * Prints text representation of given jsonpath item and all its children.
     506                 :  */
     507                 : static void
     508 CBC        2623 : printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
     509                 :                   bool printBracketes)
     510                 : {
     511 ECB             :     JsonPathItem elem;
     512                 :     int         i;
     513                 : 
     514 CBC        2623 :     check_stack_depth();
     515 GIC        2623 :     CHECK_FOR_INTERRUPTS();
     516                 : 
     517 CBC        2623 :     switch (v->type)
     518                 :     {
     519              21 :         case jpiNull:
     520 GIC          21 :             appendStringInfoString(buf, "null");
     521              21 :             break;
     522             532 :         case jpiKey:
     523             532 :             if (inKey)
     524             532 :                 appendStringInfoChar(buf, '.');
     525             532 :             escape_json(buf, jspGetString(v, NULL));
     526 CBC         532 :             break;
     527 GIC          42 :         case jpiString:
     528 CBC          42 :             escape_json(buf, jspGetString(v, NULL));
     529              42 :             break;
     530 GIC          24 :         case jpiVariable:
     531 CBC          24 :             appendStringInfoChar(buf, '$');
     532 GIC          24 :             escape_json(buf, jspGetString(v, NULL));
     533 CBC          24 :             break;
     534 GIC         442 :         case jpiNumeric:
     535             442 :             if (jspHasNext(v))
     536              42 :                 appendStringInfoChar(buf, '(');
     537             442 :             appendStringInfoString(buf,
     538             442 :                                    DatumGetCString(DirectFunctionCall1(numeric_out,
     539                 :                                                                        NumericGetDatum(jspGetNumeric(v)))));
     540 CBC         442 :             if (jspHasNext(v))
     541 GIC          42 :                 appendStringInfoChar(buf, ')');
     542             442 :             break;
     543               6 :         case jpiBool:
     544               6 :             if (jspGetBool(v))
     545 GNC           3 :                 appendStringInfoString(buf, "true");
     546 ECB             :             else
     547 GNC           3 :                 appendStringInfoString(buf, "false");
     548 GIC           6 :             break;
     549 CBC         370 :         case jpiAnd:
     550                 :         case jpiOr:
     551 ECB             :         case jpiEqual:
     552                 :         case jpiNotEqual:
     553                 :         case jpiLess:
     554                 :         case jpiGreater:
     555                 :         case jpiLessOrEqual:
     556                 :         case jpiGreaterOrEqual:
     557                 :         case jpiAdd:
     558                 :         case jpiSub:
     559                 :         case jpiMul:
     560                 :         case jpiDiv:
     561                 :         case jpiMod:
     562                 :         case jpiStartsWith:
     563 CBC         370 :             if (printBracketes)
     564              57 :                 appendStringInfoChar(buf, '(');
     565             370 :             jspGetLeftArg(v, &elem);
     566             370 :             printJsonPathItem(buf, &elem, false,
     567             370 :                               operationPriority(elem.type) <=
     568             370 :                               operationPriority(v->type));
     569             370 :             appendStringInfoChar(buf, ' ');
     570             370 :             appendStringInfoString(buf, jspOperationName(v->type));
     571 GIC         370 :             appendStringInfoChar(buf, ' ');
     572 CBC         370 :             jspGetRightArg(v, &elem);
     573             370 :             printJsonPathItem(buf, &elem, false,
     574             370 :                               operationPriority(elem.type) <=
     575             370 :                               operationPriority(v->type));
     576             370 :             if (printBracketes)
     577              57 :                 appendStringInfoChar(buf, ')');
     578 GIC         370 :             break;
     579 CBC          24 :         case jpiLikeRegex:
     580              24 :             if (printBracketes)
     581 LBC           0 :                 appendStringInfoChar(buf, '(');
     582                 : 
     583 GIC          24 :             jspInitByBuffer(&elem, v->base, v->content.like_regex.expr);
     584              24 :             printJsonPathItem(buf, &elem, false,
     585              24 :                               operationPriority(elem.type) <=
     586              24 :                               operationPriority(v->type));
     587                 : 
     588 GNC          24 :             appendStringInfoString(buf, " like_regex ");
     589                 : 
     590 GIC          24 :             escape_json(buf, v->content.like_regex.pattern);
     591                 : 
     592              24 :             if (v->content.like_regex.flags)
     593                 :             {
     594 GNC          18 :                 appendStringInfoString(buf, " flag \"");
     595 ECB             : 
     596 CBC          18 :                 if (v->content.like_regex.flags & JSP_REGEX_ICASE)
     597              15 :                     appendStringInfoChar(buf, 'i');
     598              18 :                 if (v->content.like_regex.flags & JSP_REGEX_DOTALL)
     599               9 :                     appendStringInfoChar(buf, 's');
     600              18 :                 if (v->content.like_regex.flags & JSP_REGEX_MLINE)
     601               6 :                     appendStringInfoChar(buf, 'm');
     602              18 :                 if (v->content.like_regex.flags & JSP_REGEX_WSPACE)
     603               3 :                     appendStringInfoChar(buf, 'x');
     604              18 :                 if (v->content.like_regex.flags & JSP_REGEX_QUOTE)
     605               9 :                     appendStringInfoChar(buf, 'q');
     606 ECB             : 
     607 CBC          18 :                 appendStringInfoChar(buf, '"');
     608 ECB             :             }
     609                 : 
     610 CBC          24 :             if (printBracketes)
     611 LBC           0 :                 appendStringInfoChar(buf, ')');
     612 CBC          24 :             break;
     613 GBC          24 :         case jpiPlus:
     614                 :         case jpiMinus:
     615 CBC          24 :             if (printBracketes)
     616               9 :                 appendStringInfoChar(buf, '(');
     617              24 :             appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-');
     618              24 :             jspGetArg(v, &elem);
     619 GIC          24 :             printJsonPathItem(buf, &elem, false,
     620 CBC          24 :                               operationPriority(elem.type) <=
     621 GIC          24 :                               operationPriority(v->type));
     622 CBC          24 :             if (printBracketes)
     623 GIC           9 :                 appendStringInfoChar(buf, ')');
     624 CBC          24 :             break;
     625 GIC         253 :         case jpiFilter:
     626 GNC         253 :             appendStringInfoString(buf, "?(");
     627 GIC         253 :             jspGetArg(v, &elem);
     628 CBC         253 :             printJsonPathItem(buf, &elem, false, false);
     629             253 :             appendStringInfoChar(buf, ')');
     630             253 :             break;
     631               6 :         case jpiNot:
     632 GNC           6 :             appendStringInfoString(buf, "!(");
     633 CBC           6 :             jspGetArg(v, &elem);
     634               6 :             printJsonPathItem(buf, &elem, false, false);
     635               6 :             appendStringInfoChar(buf, ')');
     636               6 :             break;
     637               3 :         case jpiIsUnknown:
     638 GIC           3 :             appendStringInfoChar(buf, '(');
     639 CBC           3 :             jspGetArg(v, &elem);
     640 GIC           3 :             printJsonPathItem(buf, &elem, false, false);
     641 GNC           3 :             appendStringInfoString(buf, ") is unknown");
     642 CBC           3 :             break;
     643 GBC          12 :         case jpiExists:
     644 GNC          12 :             appendStringInfoString(buf, "exists (");
     645 CBC          12 :             jspGetArg(v, &elem);
     646 GIC          12 :             printJsonPathItem(buf, &elem, false, false);
     647 CBC          12 :             appendStringInfoChar(buf, ')');
     648              12 :             break;
     649             289 :         case jpiCurrent:
     650             289 :             Assert(!inKey);
     651             289 :             appendStringInfoChar(buf, '@');
     652             289 :             break;
     653             427 :         case jpiRoot:
     654             427 :             Assert(!inKey);
     655             427 :             appendStringInfoChar(buf, '$');
     656             427 :             break;
     657               6 :         case jpiLast:
     658 GNC           6 :             appendStringInfoString(buf, "last");
     659 CBC           6 :             break;
     660              43 :         case jpiAnyArray:
     661 GNC          43 :             appendStringInfoString(buf, "[*]");
     662 CBC          43 :             break;
     663               6 :         case jpiAnyKey:
     664               6 :             if (inKey)
     665               6 :                 appendStringInfoChar(buf, '.');
     666               6 :             appendStringInfoChar(buf, '*');
     667               6 :             break;
     668              30 :         case jpiIndexArray:
     669              30 :             appendStringInfoChar(buf, '[');
     670              69 :             for (i = 0; i < v->content.array.nelems; i++)
     671 ECB             :             {
     672                 :                 JsonPathItem from;
     673                 :                 JsonPathItem to;
     674 CBC          39 :                 bool        range = jspGetArraySubscript(v, &from, &to, i);
     675 ECB             : 
     676 CBC          39 :                 if (i)
     677               9 :                     appendStringInfoChar(buf, ',');
     678 ECB             : 
     679 CBC          39 :                 printJsonPathItem(buf, &from, false, false);
     680 ECB             : 
     681 CBC          39 :                 if (range)
     682 ECB             :                 {
     683 GNC           6 :                     appendStringInfoString(buf, " to ");
     684 CBC           6 :                     printJsonPathItem(buf, &to, false, false);
     685 ECB             :                 }
     686                 :             }
     687 CBC          30 :             appendStringInfoChar(buf, ']');
     688              30 :             break;
     689              24 :         case jpiAny:
     690              24 :             if (inKey)
     691              24 :                 appendStringInfoChar(buf, '.');
     692 ECB             : 
     693 CBC          24 :             if (v->content.anybounds.first == 0 &&
     694               6 :                 v->content.anybounds.last == PG_UINT32_MAX)
     695 GNC           3 :                 appendStringInfoString(buf, "**");
     696 CBC          21 :             else if (v->content.anybounds.first == v->content.anybounds.last)
     697 ECB             :             {
     698 CBC           9 :                 if (v->content.anybounds.first == PG_UINT32_MAX)
     699               3 :                     appendStringInfoString(buf, "**{last}");
     700 ECB             :                 else
     701 CBC           6 :                     appendStringInfo(buf, "**{%u}",
     702 ECB             :                                      v->content.anybounds.first);
     703                 :             }
     704 GIC          12 :             else if (v->content.anybounds.first == PG_UINT32_MAX)
     705               3 :                 appendStringInfo(buf, "**{last to %u}",
     706 ECB             :                                  v->content.anybounds.last);
     707 GIC           9 :             else if (v->content.anybounds.last == PG_UINT32_MAX)
     708 CBC           3 :                 appendStringInfo(buf, "**{%u to last}",
     709 ECB             :                                  v->content.anybounds.first);
     710                 :             else
     711 CBC           6 :                 appendStringInfo(buf, "**{%u to %u}",
     712                 :                                  v->content.anybounds.first,
     713 ECB             :                                  v->content.anybounds.last);
     714 GIC          24 :             break;
     715 CBC          15 :         case jpiType:
     716 GNC          15 :             appendStringInfoString(buf, ".type()");
     717 GIC          15 :             break;
     718               3 :         case jpiSize:
     719 GNC           3 :             appendStringInfoString(buf, ".size()");
     720 CBC           3 :             break;
     721               3 :         case jpiAbs:
     722 GNC           3 :             appendStringInfoString(buf, ".abs()");
     723 CBC           3 :             break;
     724 GIC           3 :         case jpiFloor:
     725 GNC           3 :             appendStringInfoString(buf, ".floor()");
     726 CBC           3 :             break;
     727               3 :         case jpiCeiling:
     728 GNC           3 :             appendStringInfoString(buf, ".ceiling()");
     729 GIC           3 :             break;
     730 CBC           3 :         case jpiDouble:
     731 GNC           3 :             appendStringInfoString(buf, ".double()");
     732 GIC           3 :             break;
     733 CBC           6 :         case jpiDatetime:
     734 GNC           6 :             appendStringInfoString(buf, ".datetime(");
     735 GIC           6 :             if (v->content.arg)
     736 ECB             :             {
     737 CBC           3 :                 jspGetArg(v, &elem);
     738 GIC           3 :                 printJsonPathItem(buf, &elem, false, false);
     739 ECB             :             }
     740 CBC           6 :             appendStringInfoChar(buf, ')');
     741 GIC           6 :             break;
     742               3 :         case jpiKeyValue:
     743 GNC           3 :             appendStringInfoString(buf, ".keyvalue()");
     744 GIC           3 :             break;
     745 UIC           0 :         default:
     746 LBC           0 :             elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
     747 ECB             :     }
     748                 : 
     749 CBC        2623 :     if (jspGetNext(v, &elem))
     750             927 :         printJsonPathItem(buf, &elem, true, true);
     751            2623 : }
     752 ECB             : 
     753                 : const char *
     754 CBC         451 : jspOperationName(JsonPathItemType type)
     755 ECB             : {
     756 CBC         451 :     switch (type)
     757 ECB             :     {
     758 CBC          15 :         case jpiAnd:
     759              15 :             return "&&";
     760              27 :         case jpiOr:
     761              27 :             return "||";
     762              81 :         case jpiEqual:
     763              81 :             return "==";
     764               3 :         case jpiNotEqual:
     765               3 :             return "!=";
     766             150 :         case jpiLess:
     767             150 :             return "<";
     768 GIC          19 :         case jpiGreater:
     769 CBC          19 :             return ">";
     770               3 :         case jpiLessOrEqual:
     771 GIC           3 :             return "<=";
     772 CBC          15 :         case jpiGreaterOrEqual:
     773              15 :             return ">=";
     774              36 :         case jpiPlus:
     775 ECB             :         case jpiAdd:
     776 CBC          36 :             return "+";
     777 GBC          12 :         case jpiMinus:
     778 EUB             :         case jpiSub:
     779 GIC          12 :             return "-";
     780              12 :         case jpiMul:
     781 CBC          12 :             return "*";
     782               3 :         case jpiDiv:
     783               3 :             return "/";
     784 GIC           3 :         case jpiMod:
     785               3 :             return "%";
     786 CBC           6 :         case jpiStartsWith:
     787 GIC           6 :             return "starts with";
     788 LBC           0 :         case jpiLikeRegex:
     789 UIC           0 :             return "like_regex";
     790 LBC           0 :         case jpiType:
     791               0 :             return "type";
     792 CBC           3 :         case jpiSize:
     793               3 :             return "size";
     794               9 :         case jpiKeyValue:
     795               9 :             return "keyvalue";
     796              30 :         case jpiDouble:
     797              30 :             return "double";
     798               3 :         case jpiAbs:
     799               3 :             return "abs";
     800               3 :         case jpiFloor:
     801               3 :             return "floor";
     802               3 :         case jpiCeiling:
     803               3 :             return "ceiling";
     804              15 :         case jpiDatetime:
     805              15 :             return "datetime";
     806 LBC           0 :         default:
     807 UIC           0 :             elog(ERROR, "unrecognized jsonpath item type: %d", type);
     808 ECB             :             return NULL;
     809                 :     }
     810                 : }
     811                 : 
     812                 : static int
     813 CBC        1576 : operationPriority(JsonPathItemType op)
     814 ECB             : {
     815 CBC        1576 :     switch (op)
     816 ECB             :     {
     817 CBC          57 :         case jpiOr:
     818              57 :             return 0;
     819              39 :         case jpiAnd:
     820 GBC          39 :             return 1;
     821             617 :         case jpiEqual:
     822 EUB             :         case jpiNotEqual:
     823                 :         case jpiLess:
     824 ECB             :         case jpiGreater:
     825                 :         case jpiLessOrEqual:
     826                 :         case jpiGreaterOrEqual:
     827                 :         case jpiStartsWith:
     828 CBC         617 :             return 2;
     829              90 :         case jpiAdd:
     830 ECB             :         case jpiSub:
     831 CBC          90 :             return 3;
     832              33 :         case jpiMul:
     833 ECB             :         case jpiDiv:
     834                 :         case jpiMod:
     835 CBC          33 :             return 4;
     836              42 :         case jpiPlus:
     837 ECB             :         case jpiMinus:
     838 GBC          42 :             return 5;
     839             698 :         default:
     840 GIC         698 :             return 6;
     841                 :     }
     842                 : }
     843                 : 
     844                 : /******************* Support functions for JsonPath *************************/
     845 ECB             : 
     846                 : /*
     847                 :  * Support macros to read stored values
     848                 :  */
     849                 : 
     850                 : #define read_byte(v, b, p) do {         \
     851                 :     (v) = *(uint8*)((b) + (p));         \
     852                 :     (p) += 1;                           \
     853                 : } while(0)                              \
     854                 : 
     855                 : #define read_int32(v, b, p) do {        \
     856                 :     (v) = *(uint32*)((b) + (p));        \
     857                 :     (p) += sizeof(int32);               \
     858                 : } while(0)                              \
     859                 : 
     860                 : #define read_int32_n(v, b, p, n) do {   \
     861                 :     (v) = (void *)((b) + (p));          \
     862                 :     (p) += sizeof(int32) * (n);         \
     863                 : } while(0)                              \
     864                 : 
     865                 : /*
     866                 :  * Read root node and fill root node representation
     867                 :  */
     868                 : void
     869 GIC       96016 : jspInit(JsonPathItem *v, JsonPath *js)
     870 ECB             : {
     871 CBC       96016 :     Assert((js->header & ~JSONPATH_LAX) == JSONPATH_VERSION);
     872           96016 :     jspInitByBuffer(v, js->data, 0);
     873 GIC       96016 : }
     874                 : 
     875                 : /*
     876                 :  * Read node from buffer and fill its representation
     877                 :  */
     878                 : void
     879          324031 : jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
     880                 : {
     881          324031 :     v->base = base + pos;
     882                 : 
     883          324031 :     read_byte(v->type, base, pos);
     884          324031 :     pos = INTALIGN((uintptr_t) (base + pos)) - (uintptr_t) base;
     885          324031 :     read_int32(v->nextPos, base, pos);
     886                 : 
     887          324031 :     switch (v->type)
     888                 :     {
     889          117153 :         case jpiNull:
     890                 :         case jpiRoot:
     891                 :         case jpiCurrent:
     892                 :         case jpiAnyArray:
     893                 :         case jpiAnyKey:
     894                 :         case jpiType:
     895                 :         case jpiSize:
     896                 :         case jpiAbs:
     897                 :         case jpiFloor:
     898                 :         case jpiCeiling:
     899                 :         case jpiDouble:
     900                 :         case jpiKeyValue:
     901 ECB             :         case jpiLast:
     902 GIC      117153 :             break;
     903 CBC       97906 :         case jpiKey:
     904 ECB             :         case jpiString:
     905                 :         case jpiVariable:
     906 GIC       97906 :             read_int32(v->content.value.datalen, base, pos);
     907                 :             /* FALLTHROUGH */
     908          108830 :         case jpiNumeric:
     909                 :         case jpiBool:
     910          108830 :             v->content.value.data = base + pos;
     911 CBC      108830 :             break;
     912 GIC       47371 :         case jpiAnd:
     913 ECB             :         case jpiOr:
     914                 :         case jpiAdd:
     915                 :         case jpiSub:
     916                 :         case jpiMul:
     917                 :         case jpiDiv:
     918                 :         case jpiMod:
     919                 :         case jpiEqual:
     920                 :         case jpiNotEqual:
     921                 :         case jpiLess:
     922                 :         case jpiGreater:
     923                 :         case jpiLessOrEqual:
     924                 :         case jpiGreaterOrEqual:
     925                 :         case jpiStartsWith:
     926 GIC       47371 :             read_int32(v->content.args.left, base, pos);
     927           47371 :             read_int32(v->content.args.right, base, pos);
     928           47371 :             break;
     929             222 :         case jpiLikeRegex:
     930             222 :             read_int32(v->content.like_regex.flags, base, pos);
     931             222 :             read_int32(v->content.like_regex.expr, base, pos);
     932             222 :             read_int32(v->content.like_regex.patternlen, base, pos);
     933             222 :             v->content.like_regex.pattern = base + pos;
     934 CBC         222 :             break;
     935           50104 :         case jpiNot:
     936                 :         case jpiExists:
     937                 :         case jpiIsUnknown:
     938 ECB             :         case jpiPlus:
     939                 :         case jpiMinus:
     940                 :         case jpiFilter:
     941                 :         case jpiDatetime:
     942 CBC       50104 :             read_int32(v->content.arg, base, pos);
     943           50104 :             break;
     944             174 :         case jpiIndexArray:
     945 GIC         174 :             read_int32(v->content.array.nelems, base, pos);
     946             174 :             read_int32_n(v->content.array.elems, base, pos,
     947                 :                          v->content.array.nelems * 2);
     948             174 :             break;
     949             177 :         case jpiAny:
     950             177 :             read_int32(v->content.anybounds.first, base, pos);
     951             177 :             read_int32(v->content.anybounds.last, base, pos);
     952             177 :             break;
     953 UIC           0 :         default:
     954               0 :             elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
     955                 :     }
     956 GIC      324031 : }
     957                 : 
     958 ECB             : void
     959 CBC       50470 : jspGetArg(JsonPathItem *v, JsonPathItem *a)
     960 ECB             : {
     961 CBC       50470 :     Assert(v->type == jpiFilter ||
     962 ECB             :            v->type == jpiNot ||
     963                 :            v->type == jpiIsUnknown ||
     964                 :            v->type == jpiExists ||
     965                 :            v->type == jpiPlus ||
     966                 :            v->type == jpiMinus ||
     967                 :            v->type == jpiDatetime);
     968                 : 
     969 GIC       50470 :     jspInitByBuffer(a, v->base, v->content.arg);
     970           50470 : }
     971                 : 
     972                 : bool
     973          210505 : jspGetNext(JsonPathItem *v, JsonPathItem *a)
     974 ECB             : {
     975 CBC      210505 :     if (jspHasNext(v))
     976 ECB             :     {
     977 CBC       94860 :         Assert(v->type == jpiString ||
     978 ECB             :                v->type == jpiNumeric ||
     979                 :                v->type == jpiBool ||
     980                 :                v->type == jpiNull ||
     981                 :                v->type == jpiKey ||
     982                 :                v->type == jpiAny ||
     983                 :                v->type == jpiAnyArray ||
     984                 :                v->type == jpiAnyKey ||
     985 EUB             :                v->type == jpiIndexArray ||
     986                 :                v->type == jpiFilter ||
     987                 :                v->type == jpiCurrent ||
     988 ECB             :                v->type == jpiExists ||
     989                 :                v->type == jpiRoot ||
     990                 :                v->type == jpiVariable ||
     991                 :                v->type == jpiLast ||
     992                 :                v->type == jpiAdd ||
     993                 :                v->type == jpiSub ||
     994                 :                v->type == jpiMul ||
     995                 :                v->type == jpiDiv ||
     996                 :                v->type == jpiMod ||
     997                 :                v->type == jpiPlus ||
     998                 :                v->type == jpiMinus ||
     999                 :                v->type == jpiEqual ||
    1000                 :                v->type == jpiNotEqual ||
    1001                 :                v->type == jpiGreater ||
    1002                 :                v->type == jpiGreaterOrEqual ||
    1003                 :                v->type == jpiLess ||
    1004                 :                v->type == jpiLessOrEqual ||
    1005                 :                v->type == jpiAnd ||
    1006                 :                v->type == jpiOr ||
    1007                 :                v->type == jpiNot ||
    1008                 :                v->type == jpiIsUnknown ||
    1009                 :                v->type == jpiType ||
    1010                 :                v->type == jpiSize ||
    1011                 :                v->type == jpiAbs ||
    1012                 :                v->type == jpiFloor ||
    1013                 :                v->type == jpiCeiling ||
    1014                 :                v->type == jpiDouble ||
    1015                 :                v->type == jpiDatetime ||
    1016                 :                v->type == jpiKeyValue ||
    1017                 :                v->type == jpiStartsWith);
    1018                 : 
    1019 GIC       94860 :         if (a)
    1020           94860 :             jspInitByBuffer(a, v->base, v->nextPos);
    1021           94860 :         return true;
    1022                 :     }
    1023                 : 
    1024          115645 :     return false;
    1025                 : }
    1026                 : 
    1027                 : void
    1028           47371 : jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
    1029                 : {
    1030           47371 :     Assert(v->type == jpiAnd ||
    1031                 :            v->type == jpiOr ||
    1032                 :            v->type == jpiEqual ||
    1033                 :            v->type == jpiNotEqual ||
    1034                 :            v->type == jpiLess ||
    1035                 :            v->type == jpiGreater ||
    1036                 :            v->type == jpiLessOrEqual ||
    1037                 :            v->type == jpiGreaterOrEqual ||
    1038                 :            v->type == jpiAdd ||
    1039                 :            v->type == jpiSub ||
    1040                 :            v->type == jpiMul ||
    1041                 :            v->type == jpiDiv ||
    1042                 :            v->type == jpiMod ||
    1043                 :            v->type == jpiStartsWith);
    1044                 : 
    1045           47371 :     jspInitByBuffer(a, v->base, v->content.args.left);
    1046           47371 : }
    1047                 : 
    1048                 : void
    1049           34888 : jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
    1050                 : {
    1051 CBC       34888 :     Assert(v->type == jpiAnd ||
    1052 ECB             :            v->type == jpiOr ||
    1053                 :            v->type == jpiEqual ||
    1054                 :            v->type == jpiNotEqual ||
    1055                 :            v->type == jpiLess ||
    1056                 :            v->type == jpiGreater ||
    1057                 :            v->type == jpiLessOrEqual ||
    1058                 :            v->type == jpiGreaterOrEqual ||
    1059                 :            v->type == jpiAdd ||
    1060                 :            v->type == jpiSub ||
    1061                 :            v->type == jpiMul ||
    1062                 :            v->type == jpiDiv ||
    1063                 :            v->type == jpiMod ||
    1064                 :            v->type == jpiStartsWith);
    1065                 : 
    1066 GIC       34888 :     jspInitByBuffer(a, v->base, v->content.args.right);
    1067           34888 : }
    1068                 : 
    1069                 : bool
    1070             717 : jspGetBool(JsonPathItem *v)
    1071                 : {
    1072             717 :     Assert(v->type == jpiBool);
    1073                 : 
    1074             717 :     return (bool) *v->content.value.data;
    1075                 : }
    1076                 : 
    1077 ECB             : Numeric
    1078 CBC       10120 : jspGetNumeric(JsonPathItem *v)
    1079                 : {
    1080 GIC       10120 :     Assert(v->type == jpiNumeric);
    1081 ECB             : 
    1082 GIC       10120 :     return (Numeric) v->content.value.data;
    1083 ECB             : }
    1084                 : 
    1085                 : char *
    1086 GIC       97846 : jspGetString(JsonPathItem *v, int32 *len)
    1087                 : {
    1088           97846 :     Assert(v->type == jpiKey ||
    1089                 :            v->type == jpiString ||
    1090                 :            v->type == jpiVariable);
    1091                 : 
    1092           97846 :     if (len)
    1093           97248 :         *len = v->content.value.datalen;
    1094           97846 :     return v->content.value.data;
    1095                 : }
    1096                 : 
    1097                 : bool
    1098 CBC         183 : jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to,
    1099 ECB             :                      int i)
    1100                 : {
    1101 GIC         183 :     Assert(v->type == jpiIndexArray);
    1102 ECB             : 
    1103 GIC         183 :     jspInitByBuffer(from, v->base, v->content.array.elems[i].from);
    1104 ECB             : 
    1105 GIC         183 :     if (!v->content.array.elems[i].to)
    1106 CBC         162 :         return false;
    1107                 : 
    1108 GIC          21 :     jspInitByBuffer(to, v->base, v->content.array.elems[i].to);
    1109                 : 
    1110 CBC          21 :     return true;
    1111                 : }
        

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