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 17:13:01 Functions: 90.9 % 22 20 2 18 2 2 20
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 87.7 % 73 64 9 2 61 1 1
Legend: Lines: hit not hit (240..) days: 93.1 % 435 405 7 15 8 9 176 1 219 21 194
Function coverage date bins:
(60,120] days: 100.0 % 2 2 2
(240..) days: 45.0 % 40 18 2 18 2 18

 Age         Owner                  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
 1485 akorotkov                  96 GIC        2280 : jsonpath_in(PG_FUNCTION_ARGS)
                                 97                 : {
                                 98            2280 :     char       *in = PG_GETARG_CSTRING(0);
 1485 akorotkov                  99 CBC        2280 :     int         len = strlen(in);
                                100                 : 
  106 andrew                    101 GNC        2280 :     return jsonPathFromCstring(in, len, fcinfo->context);
 1485 akorotkov                 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
 1485 akorotkov                 113 UIC           0 : jsonpath_recv(PG_FUNCTION_ARGS)
                                114                 : {
                                115               0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
 1485 akorotkov                 116 UBC           0 :     int         version = pq_getmsgint(buf, 1);
                                117                 :     char       *str;
 1485 akorotkov                 118 EUB             :     int         nbytes;
                                119                 : 
 1485 akorotkov                 120 UIC           0 :     if (version == JSONPATH_VERSION)
                                121               0 :         str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
                                122                 :     else
 1485 akorotkov                 123 UBC           0 :         elog(ERROR, "unsupported jsonpath version number: %d", version);
 1485 akorotkov                 124 EUB             : 
  106 andrew                    125 UNC           0 :     return jsonPathFromCstring(str, nbytes, NULL);
 1485 akorotkov                 126 EUB             : }
                                127                 : 
                                128                 : /*
                                129                 :  * jsonpath type output function
                                130                 :  */
                                131                 : Datum
 1485 akorotkov                 132 GIC         586 : jsonpath_out(PG_FUNCTION_ARGS)
                                133                 : {
                                134             586 :     JsonPath   *in = PG_GETARG_JSONPATH_P(0);
 1485 akorotkov                 135 ECB             : 
 1485 akorotkov                 136 GIC         586 :     PG_RETURN_CSTRING(jsonPathToCstring(NULL, in, VARSIZE(in)));
 1485 akorotkov                 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
 1485 akorotkov                 145 UIC           0 : jsonpath_send(PG_FUNCTION_ARGS)
                                146                 : {
                                147               0 :     JsonPath   *in = PG_GETARG_JSONPATH_P(0);
 1485 akorotkov                 148 EUB             :     StringInfoData buf;
                                149                 :     StringInfoData jtext;
 1485 akorotkov                 150 UBC           0 :     int         version = JSONPATH_VERSION;
                                151                 : 
 1485 akorotkov                 152 UIC           0 :     initStringInfo(&jtext);
 1485 akorotkov                 153 UBC           0 :     (void) jsonPathToCstring(&jtext, in, VARSIZE(in));
                                154                 : 
                                155               0 :     pq_begintypsend(&buf);
                                156               0 :     pq_sendint8(&buf, version);
 1485 akorotkov                 157 UIC           0 :     pq_sendtext(&buf, jtext.data, jtext.len);
 1485 akorotkov                 158 UBC           0 :     pfree(jtext.data);
 1485 akorotkov                 159 EUB             : 
 1485 akorotkov                 160 UBC           0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 1485 akorotkov                 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
  106 andrew                    171 GNC        2280 : jsonPathFromCstring(char *in, int len, struct Node *escontext)
                                172                 : {
                                173            2280 :     JsonPathParseResult *jsonpath = parsejsonpath(in, len, escontext);
 1485 akorotkov                 174 ECB             :     JsonPath   *res;
                                175                 :     StringInfoData buf;
                                176                 : 
  106 andrew                    177 GNC        2130 :     if (SOFT_ERROR_OCCURRED(escontext))
                                178              18 :         return (Datum) 0;
                                179                 : 
 1485 akorotkov                 180            2112 :     if (!jsonpath)
  106 andrew                    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                 : 
  106 andrew                    186 GIC        2109 :     initStringInfo(&buf);
                                187            2109 :     enlargeStringInfo(&buf, 4 * len /* estimation */ );
                                188                 : 
  106 andrew                    189 CBC        2109 :     appendStringInfoSpaces(&buf, JSONPATH_HDRSZ);
  106 andrew                    190 ECB             : 
  106 andrew                    191 GNC        2109 :     if (!flattenJsonPathParseItem(&buf, NULL, escontext,
                                192                 :                                   jsonpath->expr, 0, false))
                                193               6 :         return (Datum) 0;
 1485 akorotkov                 194 ECB             : 
 1485 akorotkov                 195 CBC        2094 :     res = (JsonPath *) buf.data;
 1485 akorotkov                 196 GIC        2094 :     SET_VARSIZE(res, buf.len);
 1485 akorotkov                 197 CBC        2094 :     res->header = JSONPATH_VERSION;
 1485 akorotkov                 198 GIC        2094 :     if (jsonpath->lax)
 1485 akorotkov                 199 CBC        1917 :         res->header |= JSONPATH_LAX;
                                200                 : 
                                201            2094 :     PG_RETURN_JSONPATH_P(res);
                                202                 : }
 1485 akorotkov                 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 *
 1485 akorotkov                 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;
 1485 akorotkov                 219 CBC         586 :         initStringInfo(out);
                                220                 :     }
 1485 akorotkov                 221 GIC         586 :     enlargeStringInfo(out, estimated_len);
                                222                 : 
                                223             586 :     if (!(in->header & JSONPATH_LAX))
  100 peter                     224 GNC           3 :         appendStringInfoString(out, "strict ");
                                225                 : 
 1485 akorotkov                 226 CBC         586 :     jspInit(&v, in);
                                227             586 :     printJsonPathItem(out, &v, false, true);
                                228                 : 
                                229             586 :     return out->data;
                                230                 : }
 1485 akorotkov                 231 ECB             : 
                                232                 : /*
                                233                 :  * Recursive function converting given jsonpath parse item and all its
                                234                 :  * children into a binary representation.
                                235                 :  */
                                236                 : static bool
  106 andrew                    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 */
 1485 akorotkov                 242 GIC        9843 :     int32       pos = buf->len - JSONPATH_HDRSZ;
                                243                 :     int32       chld;
                                244                 :     int32       next;
                                245            9843 :     int         argNestingLevel = 0;
 1485 akorotkov                 246 ECB             : 
 1485 akorotkov                 247 GIC        9843 :     check_stack_depth();
                                248            9843 :     CHECK_FOR_INTERRUPTS();
                                249                 : 
                                250            9843 :     appendStringInfoChar(buf, (char) (item->type));
 1485 akorotkov                 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                 :      */
 1485 akorotkov                 257 CBC        9843 :     alignStringInfoInt(buf);
                                258                 : 
 1485 akorotkov                 259 ECB             :     /*
                                260                 :      * Reserve space for next item pointer.  Actual value will be recorded
                                261                 :      * later, after next and children items processing.
                                262                 :      */
 1485 akorotkov                 263 GIC        9843 :     next = reserveSpaceForItemPointer(buf);
                                264                 : 
                                265            9843 :     switch (item->type)
 1485 akorotkov                 266 ECB             :     {
 1485 akorotkov                 267 GIC        1947 :         case jpiString:
                                268                 :         case jpiVariable:
                                269                 :         case jpiKey:
  100 peter                     270 GNC        1947 :             appendBinaryStringInfo(buf, &item->value.string.len,
                                271                 :                                    sizeof(item->value.string.len));
 1485 akorotkov                 272 CBC        1947 :             appendBinaryStringInfo(buf, item->value.string.val,
 1485 akorotkov                 273 GIC        1947 :                                    item->value.string.len);
 1485 akorotkov                 274 CBC        1947 :             appendStringInfoChar(buf, '\0');
 1485 akorotkov                 275 GIC        1947 :             break;
 1485 akorotkov                 276 CBC         870 :         case jpiNumeric:
  100 peter                     277 GNC         870 :             appendBinaryStringInfo(buf, item->value.numeric,
 1485 akorotkov                 278 GIC         870 :                                    VARSIZE(item->value.numeric));
 1485 akorotkov                 279 CBC         870 :             break;
 1485 akorotkov                 280 GIC          90 :         case jpiBool:
  100 peter                     281 GNC          90 :             appendBinaryStringInfo(buf, &item->value.boolean,
 1485 akorotkov                 282 ECB             :                                    sizeof(item->value.boolean));
 1485 akorotkov                 283 CBC          90 :             break;
                                284            1272 :         case jpiAnd:
 1485 akorotkov                 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                 :                  */
 1485 akorotkov                 304 GIC        1272 :                 int32       left = reserveSpaceForItemPointer(buf);
                                305            1272 :                 int32       right = reserveSpaceForItemPointer(buf);
                                306                 : 
  106 andrew                    307 GNC        1272 :                 if (!item->value.args.left)
  106 andrew                    308 UNC           0 :                     chld = pos;
  106 andrew                    309 GNC        1272 :                 else if (! flattenJsonPathParseItem(buf, &chld, escontext,
                                310                 :                                                     item->value.args.left,
                                311                 :                                                     nestingLevel + argNestingLevel,
                                312                 :                                                     insideArraySubscript))
                                313               6 :                     return false;
 1485 akorotkov                 314 GIC        1260 :                 *(int32 *) (buf->data + left) = chld - pos;
                                315                 : 
  106 andrew                    316 GNC        1260 :                 if (!item->value.args.right)
  106 andrew                    317 UNC           0 :                     chld = pos;
  106 andrew                    318 GNC        1260 :                 else if (! flattenJsonPathParseItem(buf, &chld, escontext,
                                319                 :                                                     item->value.args.right,
                                320                 :                                                     nestingLevel + argNestingLevel,
                                321                 :                                                     insideArraySubscript))
  106 andrew                    322 UNC           0 :                     return false;
 1485 akorotkov                 323 GBC        1260 :                 *(int32 *) (buf->data + right) = chld - pos;
 1485 akorotkov                 324 ECB             :             }
 1485 akorotkov                 325 GIC        1260 :             break;
                                326              60 :         case jpiLikeRegex:
                                327                 :             {
 1485 akorotkov                 328 ECB             :                 int32       offs;
                                329                 : 
 1485 akorotkov                 330 GIC          60 :                 appendBinaryStringInfo(buf,
  100 peter                     331 GNC          60 :                                        &item->value.like_regex.flags,
 1485 akorotkov                 332 EUB             :                                        sizeof(item->value.like_regex.flags));
 1485 akorotkov                 333 CBC          60 :                 offs = reserveSpaceForItemPointer(buf);
 1485 akorotkov                 334 GIC          60 :                 appendBinaryStringInfo(buf,
  100 peter                     335 GNC          60 :                                        &item->value.like_regex.patternlen,
                                336                 :                                        sizeof(item->value.like_regex.patternlen));
 1485 akorotkov                 337 GBC          60 :                 appendBinaryStringInfo(buf, item->value.like_regex.pattern,
 1485 akorotkov                 338 CBC          60 :                                        item->value.like_regex.patternlen);
 1485 akorotkov                 339 GIC          60 :                 appendStringInfoChar(buf, '\0');
 1485 akorotkov                 340 ECB             : 
  106 andrew                    341 GNC          60 :                 if (! flattenJsonPathParseItem(buf, &chld, escontext,
                                342                 :                                                item->value.like_regex.expr,
                                343                 :                                                nestingLevel,
                                344                 :                                                insideArraySubscript))
  106 andrew                    345 UNC           0 :                     return false;
 1485 akorotkov                 346 GIC          60 :                 *(int32 *) (buf->data + offs) = chld - pos;
 1485 akorotkov                 347 ECB             :             }
 1485 akorotkov                 348 CBC          60 :             break;
 1485 akorotkov                 349 GIC         819 :         case jpiFilter:
 1485 akorotkov                 350 CBC         819 :             argNestingLevel++;
 1485 tgl                       351 ECB             :             /* FALLTHROUGH */
 1485 akorotkov                 352 CBC        1455 :         case jpiIsUnknown:
                                353                 :         case jpiNot:
 1485 akorotkov                 354 ECB             :         case jpiPlus:
                                355                 :         case jpiMinus:
                                356                 :         case jpiExists:
                                357                 :         case jpiDatetime:
                                358                 :             {
 1485 akorotkov                 359 GIC        1455 :                 int32       arg = reserveSpaceForItemPointer(buf);
                                360                 : 
  106 andrew                    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))
  106 andrew                    367 UNC           0 :                     return false;
 1485 akorotkov                 368 CBC        1452 :                 *(int32 *) (buf->data + arg) = chld - pos;
 1485 akorotkov                 369 ECB             :             }
 1485 akorotkov                 370 CBC        1452 :             break;
 1485 akorotkov                 371 GIC          57 :         case jpiNull:
 1485 akorotkov                 372 CBC          57 :             break;
 1485 akorotkov                 373 GIC        1929 :         case jpiRoot:
                                374            1929 :             break;
                                375             561 :         case jpiAnyArray:
                                376                 :         case jpiAnyKey:
                                377             561 :             break;
                                378             954 :         case jpiCurrent:
 1485 akorotkov                 379 CBC         954 :             if (nestingLevel <= 0)
  106 andrew                    380 GNC           9 :                 ereturn(escontext, false,
 1485 akorotkov                 381 ECB             :                         (errcode(ERRCODE_SYNTAX_ERROR),
                                382                 :                          errmsg("@ is not allowed in root expressions")));
 1485 akorotkov                 383 CBC         945 :             break;
 1485 akorotkov                 384 GIC          45 :         case jpiLast:
                                385              45 :             if (!insideArraySubscript)
  106 andrew                    386 GNC           6 :                 ereturn(escontext, false,
 1485 akorotkov                 387 EUB             :                         (errcode(ERRCODE_SYNTAX_ERROR),
 1485 akorotkov                 388 ECB             :                          errmsg("LAST is allowed only in array subscripts")));
 1485 akorotkov                 389 GIC          39 :             break;
 1485 akorotkov                 390 CBC         168 :         case jpiIndexArray:
 1485 akorotkov                 391 ECB             :             {
 1485 akorotkov                 392 CBC         168 :                 int32       nelems = item->value.array.nelems;
 1485 akorotkov                 393 ECB             :                 int         offset;
                                394                 :                 int         i;
                                395                 : 
  100 peter                     396 GNC         168 :                 appendBinaryStringInfo(buf, &nelems, sizeof(nelems));
 1485 akorotkov                 397 ECB             : 
 1485 akorotkov                 398 CBC         168 :                 offset = buf->len;
 1485 akorotkov                 399 ECB             : 
 1485 akorotkov                 400 CBC         168 :                 appendStringInfoSpaces(buf, sizeof(int32) * 2 * nelems);
                                401                 : 
 1485 akorotkov                 402 GIC         351 :                 for (i = 0; i < nelems; i++)
 1485 akorotkov                 403 ECB             :                 {
                                404                 :                     int32      *ppos;
                                405                 :                     int32       topos;
                                406                 :                     int32       frompos;
                                407                 : 
  106 andrew                    408 GNC         183 :                     if (! flattenJsonPathParseItem(buf, &frompos, escontext,
                                409             183 :                                                    item->value.array.elems[i].from,
                                410                 :                                                    nestingLevel, true))
  106 andrew                    411 UNC           0 :                         return false;
  106 andrew                    412 GNC         183 :                     frompos -= pos;
 1485 akorotkov                 413 ECB             : 
 1485 akorotkov                 414 GIC         183 :                     if (item->value.array.elems[i].to)
                                415                 :                     {
  106 andrew                    416 GNC          21 :                         if (! flattenJsonPathParseItem(buf, &topos, escontext,
                                417              21 :                                                        item->value.array.elems[i].to,
                                418                 :                                                        nestingLevel, true))
  106 andrew                    419 UNC           0 :                             return false;
  106 andrew                    420 GNC          21 :                         topos -= pos;
                                421                 :                     }
                                422                 :                     else
 1485 akorotkov                 423 CBC         162 :                         topos = 0;
                                424                 : 
                                425             183 :                     ppos = (int32 *) &buf->data[offset + i * 2 * sizeof(int32)];
                                426                 : 
                                427             183 :                     ppos[0] = frompos;
 1485 akorotkov                 428 GIC         183 :                     ppos[1] = topos;
 1485 akorotkov                 429 ECB             :                 }
                                430                 :             }
 1485 akorotkov                 431 GIC         168 :             break;
                                432             177 :         case jpiAny:
                                433             177 :             appendBinaryStringInfo(buf,
  100 peter                     434 GNC         177 :                                    &item->value.anybounds.first,
 1485 akorotkov                 435 ECB             :                                    sizeof(item->value.anybounds.first));
 1485 akorotkov                 436 CBC         177 :             appendBinaryStringInfo(buf,
  100 peter                     437 GNC         177 :                                    &item->value.anybounds.last,
 1485 akorotkov                 438 EUB             :                                    sizeof(item->value.anybounds.last));
 1485 akorotkov                 439 CBC         177 :             break;
 1485 akorotkov                 440 GIC         258 :         case jpiType:
 1485 akorotkov                 441 ECB             :         case jpiSize:
                                442                 :         case jpiAbs:
                                443                 :         case jpiFloor:
                                444                 :         case jpiCeiling:
                                445                 :         case jpiDouble:
 1485 akorotkov                 446 EUB             :         case jpiKeyValue:
 1485 akorotkov                 447 CBC         258 :             break;
 1485 akorotkov                 448 UIC           0 :         default:
                                449               0 :             elog(ERROR, "unrecognized jsonpath item type: %d", item->type);
 1485 akorotkov                 450 ECB             :     }
                                451                 : 
 1485 akorotkov                 452 CBC        9813 :     if (item->next)
                                453                 :     {
  106 andrew                    454 GNC        3651 :         if (! flattenJsonPathParseItem(buf, &chld, escontext,
                                455                 :                                        item->next, nestingLevel,
                                456                 :                                        insideArraySubscript))
  106 andrew                    457 UNC           0 :             return false;
  106 andrew                    458 GNC        3648 :         chld -= pos;
 1485 akorotkov                 459 GIC        3648 :         *(int32 *) (buf->data + next) = chld;
                                460                 :     }
 1485 akorotkov                 461 ECB             : 
  106 andrew                    462 GNC        9810 :     if (result)
                                463            7716 :         *result = pos;
                                464            9810 :     return true;
 1485 akorotkov                 465 ECB             : }
                                466                 : 
                                467                 : /*
                                468                 :  * Align StringInfo to int by adding zero padding bytes
                                469                 :  */
                                470                 : static void
 1485 akorotkov                 471 CBC        9843 : alignStringInfoInt(StringInfo buf)
 1485 akorotkov                 472 ECB             : {
 1485 akorotkov                 473 GIC        9843 :     switch (INTALIGN(buf->len) - buf->len)
                                474                 :     {
                                475            8649 :         case 3:
                                476            8649 :             appendStringInfoCharMacro(buf, 0);
                                477                 :             /* FALLTHROUGH */
                                478                 :         case 2:
 1485 akorotkov                 479 CBC        8817 :             appendStringInfoCharMacro(buf, 0);
 1485 tgl                       480 EUB             :             /* FALLTHROUGH */
      akorotkov                 481                 :         case 1:
 1485 akorotkov                 482 GIC        9747 :             appendStringInfoCharMacro(buf, 0);
                                483                 :             /* FALLTHROUGH */
 1485 akorotkov                 484 ECB             :         default:
 1485 akorotkov                 485 GIC        9843 :             break;
 1485 akorotkov                 486 ECB             :     }
 1485 akorotkov                 487 GIC        9843 : }
                                488                 : 
 1485 akorotkov                 489 EUB             : /*
 1485 akorotkov                 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
 1485 akorotkov                 494 CBC       13902 : reserveSpaceForItemPointer(StringInfo buf)
 1485 akorotkov                 495 ECB             : {
 1485 akorotkov                 496 CBC       13902 :     int32       pos = buf->len;
 1485 akorotkov                 497 GIC       13902 :     int32       ptr = 0;
                                498                 : 
  100 peter                     499 GNC       13902 :     appendBinaryStringInfo(buf, &ptr, sizeof(ptr));
                                500                 : 
 1485 akorotkov                 501 GIC       13902 :     return pos;
                                502                 : }
 1485 akorotkov                 503 ECB             : 
                                504                 : /*
                                505                 :  * Prints text representation of given jsonpath item and all its children.
                                506                 :  */
                                507                 : static void
 1485 akorotkov                 508 CBC        2623 : printJsonPathItem(StringInfo buf, JsonPathItem *v, bool inKey,
                                509                 :                   bool printBracketes)
                                510                 : {
 1485 akorotkov                 511 ECB             :     JsonPathItem elem;
                                512                 :     int         i;
                                513                 : 
 1485 akorotkov                 514 CBC        2623 :     check_stack_depth();
 1485 akorotkov                 515 GIC        2623 :     CHECK_FOR_INTERRUPTS();
                                516                 : 
 1485 akorotkov                 517 CBC        2623 :     switch (v->type)
                                518                 :     {
                                519              21 :         case jpiNull:
 1485 akorotkov                 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));
 1485 akorotkov                 526 CBC         532 :             break;
 1485 akorotkov                 527 GIC          42 :         case jpiString:
 1485 akorotkov                 528 CBC          42 :             escape_json(buf, jspGetString(v, NULL));
                                529              42 :             break;
 1485 akorotkov                 530 GIC          24 :         case jpiVariable:
 1485 akorotkov                 531 CBC          24 :             appendStringInfoChar(buf, '$');
 1485 akorotkov                 532 GIC          24 :             escape_json(buf, jspGetString(v, NULL));
 1485 akorotkov                 533 CBC          24 :             break;
 1485 akorotkov                 534 GIC         442 :         case jpiNumeric:
  377 peter                     535             442 :             if (jspHasNext(v))
                                536              42 :                 appendStringInfoChar(buf, '(');
 1485 akorotkov                 537             442 :             appendStringInfoString(buf,
                                538             442 :                                    DatumGetCString(DirectFunctionCall1(numeric_out,
                                539                 :                                                                        NumericGetDatum(jspGetNumeric(v)))));
  377 peter                     540 CBC         442 :             if (jspHasNext(v))
  377 peter                     541 GIC          42 :                 appendStringInfoChar(buf, ')');
 1485 akorotkov                 542             442 :             break;
                                543               6 :         case jpiBool:
                                544               6 :             if (jspGetBool(v))
  100 peter                     545 GNC           3 :                 appendStringInfoString(buf, "true");
 1485 akorotkov                 546 ECB             :             else
  100 peter                     547 GNC           3 :                 appendStringInfoString(buf, "false");
 1485 akorotkov                 548 GIC           6 :             break;
 1485 akorotkov                 549 CBC         370 :         case jpiAnd:
                                550                 :         case jpiOr:
 1485 akorotkov                 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:
 1485 akorotkov                 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));
 1485 akorotkov                 571 GIC         370 :             appendStringInfoChar(buf, ' ');
 1485 akorotkov                 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, ')');
 1485 akorotkov                 578 GIC         370 :             break;
 1485 akorotkov                 579 CBC          24 :         case jpiLikeRegex:
                                580              24 :             if (printBracketes)
 1485 akorotkov                 581 LBC           0 :                 appendStringInfoChar(buf, '(');
                                582                 : 
 1485 akorotkov                 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                 : 
  100 peter                     588 GNC          24 :             appendStringInfoString(buf, " like_regex ");
                                589                 : 
 1485 akorotkov                 590 GIC          24 :             escape_json(buf, v->content.like_regex.pattern);
                                591                 : 
                                592              24 :             if (v->content.like_regex.flags)
                                593                 :             {
  100 peter                     594 GNC          18 :                 appendStringInfoString(buf, " flag \"");
 1485 akorotkov                 595 ECB             : 
 1485 akorotkov                 596 CBC          18 :                 if (v->content.like_regex.flags & JSP_REGEX_ICASE)
                                597              15 :                     appendStringInfoChar(buf, 'i');
 1300 tgl                       598              18 :                 if (v->content.like_regex.flags & JSP_REGEX_DOTALL)
 1485 akorotkov                 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');
 1390                           604              18 :                 if (v->content.like_regex.flags & JSP_REGEX_QUOTE)
                                605               9 :                     appendStringInfoChar(buf, 'q');
 1485 akorotkov                 606 ECB             : 
 1485 akorotkov                 607 CBC          18 :                 appendStringInfoChar(buf, '"');
 1485 akorotkov                 608 ECB             :             }
                                609                 : 
 1485 akorotkov                 610 CBC          24 :             if (printBracketes)
 1485 akorotkov                 611 LBC           0 :                 appendStringInfoChar(buf, ')');
 1485 akorotkov                 612 CBC          24 :             break;
 1485 akorotkov                 613 GBC          24 :         case jpiPlus:
                                614                 :         case jpiMinus:
 1485 akorotkov                 615 CBC          24 :             if (printBracketes)
                                616               9 :                 appendStringInfoChar(buf, '(');
                                617              24 :             appendStringInfoChar(buf, v->type == jpiPlus ? '+' : '-');
                                618              24 :             jspGetArg(v, &elem);
 1485 akorotkov                 619 GIC          24 :             printJsonPathItem(buf, &elem, false,
 1485 akorotkov                 620 CBC          24 :                               operationPriority(elem.type) <=
 1485 akorotkov                 621 GIC          24 :                               operationPriority(v->type));
 1485 akorotkov                 622 CBC          24 :             if (printBracketes)
 1485 akorotkov                 623 GIC           9 :                 appendStringInfoChar(buf, ')');
 1485 akorotkov                 624 CBC          24 :             break;
 1485 akorotkov                 625 GIC         253 :         case jpiFilter:
  100 peter                     626 GNC         253 :             appendStringInfoString(buf, "?(");
 1485 akorotkov                 627 GIC         253 :             jspGetArg(v, &elem);
 1485 akorotkov                 628 CBC         253 :             printJsonPathItem(buf, &elem, false, false);
                                629             253 :             appendStringInfoChar(buf, ')');
                                630             253 :             break;
                                631               6 :         case jpiNot:
  100 peter                     632 GNC           6 :             appendStringInfoString(buf, "!(");
 1485 akorotkov                 633 CBC           6 :             jspGetArg(v, &elem);
                                634               6 :             printJsonPathItem(buf, &elem, false, false);
                                635               6 :             appendStringInfoChar(buf, ')');
                                636               6 :             break;
                                637               3 :         case jpiIsUnknown:
 1485 akorotkov                 638 GIC           3 :             appendStringInfoChar(buf, '(');
 1485 akorotkov                 639 CBC           3 :             jspGetArg(v, &elem);
 1485 akorotkov                 640 GIC           3 :             printJsonPathItem(buf, &elem, false, false);
  100 peter                     641 GNC           3 :             appendStringInfoString(buf, ") is unknown");
 1485 akorotkov                 642 CBC           3 :             break;
 1485 akorotkov                 643 GBC          12 :         case jpiExists:
  100 peter                     644 GNC          12 :             appendStringInfoString(buf, "exists (");
 1485 akorotkov                 645 CBC          12 :             jspGetArg(v, &elem);
 1485 akorotkov                 646 GIC          12 :             printJsonPathItem(buf, &elem, false, false);
 1485 akorotkov                 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:
  100 peter                     658 GNC           6 :             appendStringInfoString(buf, "last");
 1485 akorotkov                 659 CBC           6 :             break;
                                660              43 :         case jpiAnyArray:
  100 peter                     661 GNC          43 :             appendStringInfoString(buf, "[*]");
 1485 akorotkov                 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++)
 1485 akorotkov                 671 ECB             :             {
                                672                 :                 JsonPathItem from;
                                673                 :                 JsonPathItem to;
 1485 akorotkov                 674 CBC          39 :                 bool        range = jspGetArraySubscript(v, &from, &to, i);
 1485 akorotkov                 675 ECB             : 
 1485 akorotkov                 676 CBC          39 :                 if (i)
                                677               9 :                     appendStringInfoChar(buf, ',');
 1485 akorotkov                 678 ECB             : 
 1485 akorotkov                 679 CBC          39 :                 printJsonPathItem(buf, &from, false, false);
 1485 akorotkov                 680 ECB             : 
 1485 akorotkov                 681 CBC          39 :                 if (range)
 1485 akorotkov                 682 ECB             :                 {
  100 peter                     683 GNC           6 :                     appendStringInfoString(buf, " to ");
 1485 akorotkov                 684 CBC           6 :                     printJsonPathItem(buf, &to, false, false);
 1485 akorotkov                 685 ECB             :                 }
                                686                 :             }
 1485 akorotkov                 687 CBC          30 :             appendStringInfoChar(buf, ']');
                                688              30 :             break;
                                689              24 :         case jpiAny:
                                690              24 :             if (inKey)
                                691              24 :                 appendStringInfoChar(buf, '.');
 1485 akorotkov                 692 ECB             : 
 1485 akorotkov                 693 CBC          24 :             if (v->content.anybounds.first == 0 &&
                                694               6 :                 v->content.anybounds.last == PG_UINT32_MAX)
  100 peter                     695 GNC           3 :                 appendStringInfoString(buf, "**");
 1485 akorotkov                 696 CBC          21 :             else if (v->content.anybounds.first == v->content.anybounds.last)
 1485 akorotkov                 697 ECB             :             {
 1485 akorotkov                 698 CBC           9 :                 if (v->content.anybounds.first == PG_UINT32_MAX)
  906 drowley                   699               3 :                     appendStringInfoString(buf, "**{last}");
 1485 akorotkov                 700 ECB             :                 else
 1485 akorotkov                 701 CBC           6 :                     appendStringInfo(buf, "**{%u}",
 1485 akorotkov                 702 ECB             :                                      v->content.anybounds.first);
                                703                 :             }
 1485 akorotkov                 704 GIC          12 :             else if (v->content.anybounds.first == PG_UINT32_MAX)
                                705               3 :                 appendStringInfo(buf, "**{last to %u}",
 1485 akorotkov                 706 ECB             :                                  v->content.anybounds.last);
 1485 akorotkov                 707 GIC           9 :             else if (v->content.anybounds.last == PG_UINT32_MAX)
 1485 akorotkov                 708 CBC           3 :                 appendStringInfo(buf, "**{%u to last}",
 1485 akorotkov                 709 ECB             :                                  v->content.anybounds.first);
                                710                 :             else
 1485 akorotkov                 711 CBC           6 :                 appendStringInfo(buf, "**{%u to %u}",
                                712                 :                                  v->content.anybounds.first,
 1485 akorotkov                 713 ECB             :                                  v->content.anybounds.last);
 1485 akorotkov                 714 GIC          24 :             break;
 1485 akorotkov                 715 CBC          15 :         case jpiType:
  100 peter                     716 GNC          15 :             appendStringInfoString(buf, ".type()");
 1485 akorotkov                 717 GIC          15 :             break;
                                718               3 :         case jpiSize:
  100 peter                     719 GNC           3 :             appendStringInfoString(buf, ".size()");
 1485 akorotkov                 720 CBC           3 :             break;
                                721               3 :         case jpiAbs:
  100 peter                     722 GNC           3 :             appendStringInfoString(buf, ".abs()");
 1485 akorotkov                 723 CBC           3 :             break;
 1485 akorotkov                 724 GIC           3 :         case jpiFloor:
  100 peter                     725 GNC           3 :             appendStringInfoString(buf, ".floor()");
 1485 akorotkov                 726 CBC           3 :             break;
                                727               3 :         case jpiCeiling:
  100 peter                     728 GNC           3 :             appendStringInfoString(buf, ".ceiling()");
 1485 akorotkov                 729 GIC           3 :             break;
 1485 akorotkov                 730 CBC           3 :         case jpiDouble:
  100 peter                     731 GNC           3 :             appendStringInfoString(buf, ".double()");
 1485 akorotkov                 732 GIC           3 :             break;
 1292 akorotkov                 733 CBC           6 :         case jpiDatetime:
  100 peter                     734 GNC           6 :             appendStringInfoString(buf, ".datetime(");
 1292 akorotkov                 735 GIC           6 :             if (v->content.arg)
 1292 akorotkov                 736 ECB             :             {
 1292 akorotkov                 737 CBC           3 :                 jspGetArg(v, &elem);
 1292 akorotkov                 738 GIC           3 :                 printJsonPathItem(buf, &elem, false, false);
 1292 akorotkov                 739 ECB             :             }
 1292 akorotkov                 740 CBC           6 :             appendStringInfoChar(buf, ')');
 1292 akorotkov                 741 GIC           6 :             break;
 1485                           742               3 :         case jpiKeyValue:
  100 peter                     743 GNC           3 :             appendStringInfoString(buf, ".keyvalue()");
 1485 akorotkov                 744 GIC           3 :             break;
 1485 akorotkov                 745 UIC           0 :         default:
 1485 akorotkov                 746 LBC           0 :             elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
 1485 akorotkov                 747 ECB             :     }
                                748                 : 
 1485 akorotkov                 749 CBC        2623 :     if (jspGetNext(v, &elem))
                                750             927 :         printJsonPathItem(buf, &elem, true, true);
                                751            2623 : }
 1485 akorotkov                 752 ECB             : 
                                753                 : const char *
 1485 akorotkov                 754 CBC         451 : jspOperationName(JsonPathItemType type)
 1485 akorotkov                 755 ECB             : {
 1485 akorotkov                 756 CBC         451 :     switch (type)
 1485 akorotkov                 757 ECB             :     {
 1485 akorotkov                 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 "<";
 1485 akorotkov                 768 GIC          19 :         case jpiGreater:
 1485 akorotkov                 769 CBC          19 :             return ">";
                                770               3 :         case jpiLessOrEqual:
 1485 akorotkov                 771 GIC           3 :             return "<=";
 1485 akorotkov                 772 CBC          15 :         case jpiGreaterOrEqual:
                                773              15 :             return ">=";
                                774              36 :         case jpiPlus:
 1485 akorotkov                 775 ECB             :         case jpiAdd:
 1485 akorotkov                 776 CBC          36 :             return "+";
 1485 akorotkov                 777 GBC          12 :         case jpiMinus:
 1485 akorotkov                 778 EUB             :         case jpiSub:
 1485 akorotkov                 779 GIC          12 :             return "-";
                                780              12 :         case jpiMul:
 1485 akorotkov                 781 CBC          12 :             return "*";
                                782               3 :         case jpiDiv:
                                783               3 :             return "/";
 1485 akorotkov                 784 GIC           3 :         case jpiMod:
                                785               3 :             return "%";
 1485 akorotkov                 786 CBC           6 :         case jpiStartsWith:
 1485 akorotkov                 787 GIC           6 :             return "starts with";
 1485 akorotkov                 788 LBC           0 :         case jpiLikeRegex:
 1485 akorotkov                 789 UIC           0 :             return "like_regex";
 1485 akorotkov                 790 LBC           0 :         case jpiType:
                                791               0 :             return "type";
 1485 akorotkov                 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";
 1292                           804              15 :         case jpiDatetime:
                                805              15 :             return "datetime";
 1485 akorotkov                 806 LBC           0 :         default:
 1485 akorotkov                 807 UIC           0 :             elog(ERROR, "unrecognized jsonpath item type: %d", type);
 1485 akorotkov                 808 ECB             :             return NULL;
                                809                 :     }
                                810                 : }
                                811                 : 
                                812                 : static int
 1485 akorotkov                 813 CBC        1576 : operationPriority(JsonPathItemType op)
 1485 akorotkov                 814 ECB             : {
 1485 akorotkov                 815 CBC        1576 :     switch (op)
 1485 akorotkov                 816 ECB             :     {
 1485 akorotkov                 817 CBC          57 :         case jpiOr:
                                818              57 :             return 0;
                                819              39 :         case jpiAnd:
 1485 akorotkov                 820 GBC          39 :             return 1;
                                821             617 :         case jpiEqual:
 1485 akorotkov                 822 EUB             :         case jpiNotEqual:
                                823                 :         case jpiLess:
 1485 akorotkov                 824 ECB             :         case jpiGreater:
                                825                 :         case jpiLessOrEqual:
                                826                 :         case jpiGreaterOrEqual:
                                827                 :         case jpiStartsWith:
 1485 akorotkov                 828 CBC         617 :             return 2;
                                829              90 :         case jpiAdd:
 1485 akorotkov                 830 ECB             :         case jpiSub:
 1485 akorotkov                 831 CBC          90 :             return 3;
                                832              33 :         case jpiMul:
 1485 akorotkov                 833 ECB             :         case jpiDiv:
                                834                 :         case jpiMod:
 1485 akorotkov                 835 CBC          33 :             return 4;
                                836              42 :         case jpiPlus:
 1485 akorotkov                 837 ECB             :         case jpiMinus:
 1485 akorotkov                 838 GBC          42 :             return 5;
                                839             698 :         default:
 1485 akorotkov                 840 GIC         698 :             return 6;
                                841                 :     }
                                842                 : }
                                843                 : 
                                844                 : /******************* Support functions for JsonPath *************************/
 1485 akorotkov                 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
 1485 akorotkov                 869 GIC       96016 : jspInit(JsonPathItem *v, JsonPath *js)
 1485 akorotkov                 870 ECB             : {
 1485 akorotkov                 871 CBC       96016 :     Assert((js->header & ~JSONPATH_LAX) == JSONPATH_VERSION);
                                872           96016 :     jspInitByBuffer(v, js->data, 0);
 1485 akorotkov                 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:
 1485 akorotkov                 901 ECB             :         case jpiLast:
 1485 akorotkov                 902 GIC      117153 :             break;
 1485 akorotkov                 903 CBC       97906 :         case jpiKey:
 1485 akorotkov                 904 ECB             :         case jpiString:
                                905                 :         case jpiVariable:
 1485 akorotkov                 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;
 1485 akorotkov                 911 CBC      108830 :             break;
 1485 akorotkov                 912 GIC       47371 :         case jpiAnd:
 1485 akorotkov                 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:
 1485 akorotkov                 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;
 1485 akorotkov                 934 CBC         222 :             break;
                                935           50104 :         case jpiNot:
                                936                 :         case jpiExists:
                                937                 :         case jpiIsUnknown:
 1485 akorotkov                 938 ECB             :         case jpiPlus:
                                939                 :         case jpiMinus:
                                940                 :         case jpiFilter:
                                941                 :         case jpiDatetime:
 1485 akorotkov                 942 CBC       50104 :             read_int32(v->content.arg, base, pos);
                                943           50104 :             break;
                                944             174 :         case jpiIndexArray:
 1485 akorotkov                 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;
 1485 akorotkov                 953 UIC           0 :         default:
                                954               0 :             elog(ERROR, "unrecognized jsonpath item type: %d", v->type);
                                955                 :     }
 1485 akorotkov                 956 GIC      324031 : }
                                957                 : 
 1485 akorotkov                 958 ECB             : void
 1485 akorotkov                 959 CBC       50470 : jspGetArg(JsonPathItem *v, JsonPathItem *a)
 1485 akorotkov                 960 ECB             : {
 1485 akorotkov                 961 CBC       50470 :     Assert(v->type == jpiFilter ||
 1485 akorotkov                 962 ECB             :            v->type == jpiNot ||
                                963                 :            v->type == jpiIsUnknown ||
                                964                 :            v->type == jpiExists ||
                                965                 :            v->type == jpiPlus ||
 1292                           966                 :            v->type == jpiMinus ||
                                967                 :            v->type == jpiDatetime);
                                968                 : 
 1485 akorotkov                 969 GIC       50470 :     jspInitByBuffer(a, v->base, v->content.arg);
                                970           50470 : }
                                971                 : 
                                972                 : bool
                                973          210505 : jspGetNext(JsonPathItem *v, JsonPathItem *a)
 1485 akorotkov                 974 ECB             : {
 1485 akorotkov                 975 CBC      210505 :     if (jspHasNext(v))
 1485 akorotkov                 976 ECB             :     {
 1485 akorotkov                 977 CBC       94860 :         Assert(v->type == jpiString ||
 1485 akorotkov                 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 ||
 1485 akorotkov                 985 EUB             :                v->type == jpiIndexArray ||
                                986                 :                v->type == jpiFilter ||
                                987                 :                v->type == jpiCurrent ||
 1485 akorotkov                 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                 : 
 1485 akorotkov                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                 : {
 1485 akorotkov                1051 CBC       34888 :     Assert(v->type == jpiAnd ||
 1485 akorotkov                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                 : 
 1485 akorotkov                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                 : 
 1485 akorotkov                1077 ECB             : Numeric
 1485 akorotkov                1078 CBC       10120 : jspGetNumeric(JsonPathItem *v)
                               1079                 : {
 1485 akorotkov                1080 GIC       10120 :     Assert(v->type == jpiNumeric);
 1485 akorotkov                1081 ECB             : 
 1485 akorotkov                1082 GIC       10120 :     return (Numeric) v->content.value.data;
 1485 akorotkov                1083 ECB             : }
                               1084                 : 
                               1085                 : char *
 1485 akorotkov                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
 1485 akorotkov                1098 CBC         183 : jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to,
 1485 akorotkov                1099 ECB             :                      int i)
                               1100                 : {
 1485 akorotkov                1101 GIC         183 :     Assert(v->type == jpiIndexArray);
 1485 akorotkov                1102 ECB             : 
 1485 akorotkov                1103 GIC         183 :     jspInitByBuffer(from, v->base, v->content.array.elems[i].from);
 1485 akorotkov                1104 ECB             : 
 1485 akorotkov                1105 GIC         183 :     if (!v->content.array.elems[i].to)
 1485 akorotkov                1106 CBC         162 :         return false;
                               1107                 : 
 1485 akorotkov                1108 GIC          21 :     jspInitByBuffer(to, v->base, v->content.array.elems[i].to);
                               1109                 : 
 1485 akorotkov                1110 CBC          21 :     return true;
                               1111                 : }
        

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