LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - jsonpath_exec.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 92.9 % 1037 963 29 36 9 11 543 13 396 54 530 8
Current Date: 2023-04-08 15:15:32 Functions: 93.8 % 64 60 4 60 4 59 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * jsonpath_exec.c
       4                 :  *   Routines for SQL/JSON path execution.
       5                 :  *
       6                 :  * Jsonpath is executed in the global context stored in JsonPathExecContext,
       7                 :  * which is passed to almost every function involved into execution.  Entry
       8                 :  * point for jsonpath execution is executeJsonPath() function, which
       9                 :  * initializes execution context including initial JsonPathItem and JsonbValue,
      10                 :  * flags, stack for calculation of @ in filters.
      11                 :  *
      12                 :  * The result of jsonpath query execution is enum JsonPathExecResult and
      13                 :  * if succeeded sequence of JsonbValue, written to JsonValueList *found, which
      14                 :  * is passed through the jsonpath items.  When found == NULL, we're inside
      15                 :  * exists-query and we're interested only in whether result is empty.  In this
      16                 :  * case execution is stopped once first result item is found, and the only
      17                 :  * execution result is JsonPathExecResult.  The values of JsonPathExecResult
      18                 :  * are following:
      19                 :  * - jperOk         -- result sequence is not empty
      20                 :  * - jperNotFound   -- result sequence is empty
      21                 :  * - jperError      -- error occurred during execution
      22                 :  *
      23                 :  * Jsonpath is executed recursively (see executeItem()) starting form the
      24                 :  * first path item (which in turn might be, for instance, an arithmetic
      25                 :  * expression evaluated separately).  On each step single JsonbValue obtained
      26                 :  * from previous path item is processed.  The result of processing is a
      27                 :  * sequence of JsonbValue (probably empty), which is passed to the next path
      28                 :  * item one by one.  When there is no next path item, then JsonbValue is added
      29                 :  * to the 'found' list.  When found == NULL, then execution functions just
      30                 :  * return jperOk (see executeNextItem()).
      31                 :  *
      32                 :  * Many of jsonpath operations require automatic unwrapping of arrays in lax
      33                 :  * mode.  So, if input value is array, then corresponding operation is
      34                 :  * processed not on array itself, but on all of its members one by one.
      35                 :  * executeItemOptUnwrapTarget() function have 'unwrap' argument, which indicates
      36                 :  * whether unwrapping of array is needed.  When unwrap == true, each of array
      37                 :  * members is passed to executeItemOptUnwrapTarget() again but with unwrap == false
      38                 :  * in order to avoid subsequent array unwrapping.
      39                 :  *
      40                 :  * All boolean expressions (predicates) are evaluated by executeBoolItem()
      41                 :  * function, which returns tri-state JsonPathBool.  When error is occurred
      42                 :  * during predicate execution, it returns jpbUnknown.  According to standard
      43                 :  * predicates can be only inside filters.  But we support their usage as
      44                 :  * jsonpath expression.  This helps us to implement @@ operator.  In this case
      45                 :  * resulting JsonPathBool is transformed into jsonb bool or null.
      46                 :  *
      47                 :  * Arithmetic and boolean expression are evaluated recursively from expression
      48                 :  * tree top down to the leaves.  Therefore, for binary arithmetic expressions
      49                 :  * we calculate operands first.  Then we check that results are numeric
      50                 :  * singleton lists, calculate the result and pass it to the next path item.
      51                 :  *
      52                 :  * Copyright (c) 2019-2023, PostgreSQL Global Development Group
      53                 :  *
      54                 :  * IDENTIFICATION
      55                 :  *  src/backend/utils/adt/jsonpath_exec.c
      56                 :  *
      57                 :  *-------------------------------------------------------------------------
      58                 :  */
      59                 : 
      60                 : #include "postgres.h"
      61                 : 
      62                 : #include "catalog/pg_collation.h"
      63                 : #include "catalog/pg_type.h"
      64                 : #include "funcapi.h"
      65                 : #include "lib/stringinfo.h"
      66                 : #include "miscadmin.h"
      67                 : #include "nodes/miscnodes.h"
      68                 : #include "regex/regex.h"
      69                 : #include "utils/builtins.h"
      70                 : #include "utils/date.h"
      71                 : #include "utils/datetime.h"
      72                 : #include "utils/datum.h"
      73                 : #include "utils/float.h"
      74                 : #include "utils/formatting.h"
      75                 : #include "utils/guc.h"
      76                 : #include "utils/json.h"
      77                 : #include "utils/jsonpath.h"
      78                 : #include "utils/timestamp.h"
      79                 : #include "utils/varlena.h"
      80                 : 
      81                 : /*
      82                 :  * Represents "base object" and it's "id" for .keyvalue() evaluation.
      83                 :  */
      84                 : typedef struct JsonBaseObjectInfo
      85                 : {
      86                 :     JsonbContainer *jbc;
      87                 :     int         id;
      88                 : } JsonBaseObjectInfo;
      89                 : 
      90                 : /*
      91                 :  * Context of jsonpath execution.
      92                 :  */
      93                 : typedef struct JsonPathExecContext
      94                 : {
      95                 :     Jsonb      *vars;           /* variables to substitute into jsonpath */
      96                 :     JsonbValue *root;           /* for $ evaluation */
      97                 :     JsonbValue *current;        /* for @ evaluation */
      98                 :     JsonBaseObjectInfo baseObject;  /* "base object" for .keyvalue()
      99                 :                                      * evaluation */
     100                 :     int         lastGeneratedObjectId;  /* "id" counter for .keyvalue()
     101                 :                                          * evaluation */
     102                 :     int         innermostArraySize; /* for LAST array index evaluation */
     103                 :     bool        laxMode;        /* true for "lax" mode, false for "strict"
     104                 :                                  * mode */
     105                 :     bool        ignoreStructuralErrors; /* with "true" structural errors such
     106                 :                                          * as absence of required json item or
     107                 :                                          * unexpected json item type are
     108                 :                                          * ignored */
     109                 :     bool        throwErrors;    /* with "false" all suppressible errors are
     110                 :                                  * suppressed */
     111                 :     bool        useTz;
     112                 : } JsonPathExecContext;
     113                 : 
     114                 : /* Context for LIKE_REGEX execution. */
     115                 : typedef struct JsonLikeRegexContext
     116                 : {
     117                 :     text       *regex;
     118                 :     int         cflags;
     119                 : } JsonLikeRegexContext;
     120                 : 
     121                 : /* Result of jsonpath predicate evaluation */
     122                 : typedef enum JsonPathBool
     123                 : {
     124                 :     jpbFalse = 0,
     125                 :     jpbTrue = 1,
     126                 :     jpbUnknown = 2
     127                 : } JsonPathBool;
     128                 : 
     129                 : /* Result of jsonpath expression evaluation */
     130                 : typedef enum JsonPathExecResult
     131                 : {
     132                 :     jperOk = 0,
     133                 :     jperNotFound = 1,
     134                 :     jperError = 2
     135                 : } JsonPathExecResult;
     136                 : 
     137                 : #define jperIsError(jper)           ((jper) == jperError)
     138                 : 
     139                 : /*
     140                 :  * List of jsonb values with shortcut for single-value list.
     141                 :  */
     142                 : typedef struct JsonValueList
     143                 : {
     144                 :     JsonbValue *singleton;
     145                 :     List       *list;
     146                 : } JsonValueList;
     147                 : 
     148                 : typedef struct JsonValueListIterator
     149                 : {
     150                 :     JsonbValue *value;
     151                 :     List       *list;
     152                 :     ListCell   *next;
     153                 : } JsonValueListIterator;
     154                 : 
     155                 : /* strict/lax flags is decomposed into four [un]wrap/error flags */
     156                 : #define jspStrictAbsenseOfErrors(cxt)   (!(cxt)->laxMode)
     157                 : #define jspAutoUnwrap(cxt)              ((cxt)->laxMode)
     158                 : #define jspAutoWrap(cxt)                ((cxt)->laxMode)
     159                 : #define jspIgnoreStructuralErrors(cxt)  ((cxt)->ignoreStructuralErrors)
     160                 : #define jspThrowErrors(cxt)             ((cxt)->throwErrors)
     161                 : 
     162                 : /* Convenience macro: return or throw error depending on context */
     163                 : #define RETURN_ERROR(throw_error) \
     164                 : do { \
     165                 :     if (jspThrowErrors(cxt)) \
     166                 :         throw_error; \
     167                 :     else \
     168                 :         return jperError; \
     169                 : } while (0)
     170                 : 
     171                 : typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
     172                 :                                                    JsonbValue *larg,
     173                 :                                                    JsonbValue *rarg,
     174                 :                                                    void *param);
     175                 : typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
     176                 : 
     177                 : static JsonPathExecResult executeJsonPath(JsonPath *path, Jsonb *vars,
     178                 :                                           Jsonb *json, bool throwErrors,
     179                 :                                           JsonValueList *result, bool useTz);
     180                 : static JsonPathExecResult executeItem(JsonPathExecContext *cxt,
     181                 :                                       JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found);
     182                 : static JsonPathExecResult executeItemOptUnwrapTarget(JsonPathExecContext *cxt,
     183                 :                                                      JsonPathItem *jsp, JsonbValue *jb,
     184                 :                                                      JsonValueList *found, bool unwrap);
     185                 : static JsonPathExecResult executeItemUnwrapTargetArray(JsonPathExecContext *cxt,
     186                 :                                                        JsonPathItem *jsp, JsonbValue *jb,
     187                 :                                                        JsonValueList *found, bool unwrapElements);
     188                 : static JsonPathExecResult executeNextItem(JsonPathExecContext *cxt,
     189                 :                                           JsonPathItem *cur, JsonPathItem *next,
     190                 :                                           JsonbValue *v, JsonValueList *found, bool copy);
     191                 : static JsonPathExecResult executeItemOptUnwrapResult(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
     192                 :                                                      bool unwrap, JsonValueList *found);
     193                 : static JsonPathExecResult executeItemOptUnwrapResultNoThrow(JsonPathExecContext *cxt, JsonPathItem *jsp,
     194                 :                                                             JsonbValue *jb, bool unwrap, JsonValueList *found);
     195                 : static JsonPathBool executeBoolItem(JsonPathExecContext *cxt,
     196                 :                                     JsonPathItem *jsp, JsonbValue *jb, bool canHaveNext);
     197                 : static JsonPathBool executeNestedBoolItem(JsonPathExecContext *cxt,
     198                 :                                           JsonPathItem *jsp, JsonbValue *jb);
     199                 : static JsonPathExecResult executeAnyItem(JsonPathExecContext *cxt,
     200                 :                                          JsonPathItem *jsp, JsonbContainer *jbc, JsonValueList *found,
     201                 :                                          uint32 level, uint32 first, uint32 last,
     202                 :                                          bool ignoreStructuralErrors, bool unwrapNext);
     203                 : static JsonPathBool executePredicate(JsonPathExecContext *cxt,
     204                 :                                      JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg,
     205                 :                                      JsonbValue *jb, bool unwrapRightArg,
     206                 :                                      JsonPathPredicateCallback exec, void *param);
     207                 : static JsonPathExecResult executeBinaryArithmExpr(JsonPathExecContext *cxt,
     208                 :                                                   JsonPathItem *jsp, JsonbValue *jb,
     209                 :                                                   BinaryArithmFunc func, JsonValueList *found);
     210                 : static JsonPathExecResult executeUnaryArithmExpr(JsonPathExecContext *cxt,
     211                 :                                                  JsonPathItem *jsp, JsonbValue *jb, PGFunction func,
     212                 :                                                  JsonValueList *found);
     213                 : static JsonPathBool executeStartsWith(JsonPathItem *jsp,
     214                 :                                       JsonbValue *whole, JsonbValue *initial, void *param);
     215                 : static JsonPathBool executeLikeRegex(JsonPathItem *jsp, JsonbValue *str,
     216                 :                                      JsonbValue *rarg, void *param);
     217                 : static JsonPathExecResult executeNumericItemMethod(JsonPathExecContext *cxt,
     218                 :                                                    JsonPathItem *jsp, JsonbValue *jb, bool unwrap, PGFunction func,
     219                 :                                                    JsonValueList *found);
     220                 : static JsonPathExecResult executeDateTimeMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
     221                 :                                                 JsonbValue *jb, JsonValueList *found);
     222                 : static JsonPathExecResult executeKeyValueMethod(JsonPathExecContext *cxt,
     223                 :                                                 JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found);
     224                 : static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt,
     225                 :                                            JsonPathItem *jsp, JsonValueList *found, JsonPathBool res);
     226                 : static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
     227                 :                             JsonbValue *value);
     228                 : static void getJsonPathVariable(JsonPathExecContext *cxt,
     229                 :                                 JsonPathItem *variable, Jsonb *vars, JsonbValue *value);
     230                 : static int  JsonbArraySize(JsonbValue *jb);
     231                 : static JsonPathBool executeComparison(JsonPathItem *cmp, JsonbValue *lv,
     232                 :                                       JsonbValue *rv, void *p);
     233                 : static JsonPathBool compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2,
     234                 :                                  bool useTz);
     235                 : static int  compareNumeric(Numeric a, Numeric b);
     236                 : static JsonbValue *copyJsonbValue(JsonbValue *src);
     237                 : static JsonPathExecResult getArrayIndex(JsonPathExecContext *cxt,
     238                 :                                         JsonPathItem *jsp, JsonbValue *jb, int32 *index);
     239                 : static JsonBaseObjectInfo setBaseObject(JsonPathExecContext *cxt,
     240                 :                                         JsonbValue *jbv, int32 id);
     241                 : static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv);
     242                 : static int  JsonValueListLength(const JsonValueList *jvl);
     243                 : static bool JsonValueListIsEmpty(JsonValueList *jvl);
     244                 : static JsonbValue *JsonValueListHead(JsonValueList *jvl);
     245                 : static List *JsonValueListGetList(JsonValueList *jvl);
     246                 : static void JsonValueListInitIterator(const JsonValueList *jvl,
     247                 :                                       JsonValueListIterator *it);
     248                 : static JsonbValue *JsonValueListNext(const JsonValueList *jvl,
     249                 :                                      JsonValueListIterator *it);
     250                 : static int  JsonbType(JsonbValue *jb);
     251                 : static JsonbValue *JsonbInitBinary(JsonbValue *jbv, Jsonb *jb);
     252                 : static int  JsonbType(JsonbValue *jb);
     253                 : static JsonbValue *getScalar(JsonbValue *scalar, enum jbvType type);
     254                 : static JsonbValue *wrapItemsInArray(const JsonValueList *items);
     255                 : static int  compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
     256                 :                             bool useTz, bool *cast_error);
     257                 : 
     258                 : /****************** User interface to JsonPath executor ********************/
     259                 : 
     260                 : /*
     261                 :  * jsonb_path_exists
     262                 :  *      Returns true if jsonpath returns at least one item for the specified
     263                 :  *      jsonb value.  This function and jsonb_path_match() are used to
     264                 :  *      implement @? and @@ operators, which in turn are intended to have an
     265                 :  *      index support.  Thus, it's desirable to make it easier to achieve
     266                 :  *      consistency between index scan results and sequential scan results.
     267                 :  *      So, we throw as few errors as possible.  Regarding this function,
     268                 :  *      such behavior also matches behavior of JSON_EXISTS() clause of
     269                 :  *      SQL/JSON.  Regarding jsonb_path_match(), this function doesn't have
     270                 :  *      an analogy in SQL/JSON, so we define its behavior on our own.
     271                 :  */
     272                 : static Datum
     273 GIC       43005 : jsonb_path_exists_internal(FunctionCallInfo fcinfo, bool tz)
     274 ECB             : {
     275 GIC       43005 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     276 CBC       43005 :     JsonPath   *jp = PG_GETARG_JSONPATH_P(1);
     277 ECB             :     JsonPathExecResult res;
     278 GIC       43005 :     Jsonb      *vars = NULL;
     279 CBC       43005 :     bool        silent = true;
     280 ECB             : 
     281 GIC       43005 :     if (PG_NARGS() == 4)
     282 ECB             :     {
     283 GIC          27 :         vars = PG_GETARG_JSONB_P(2);
     284 CBC          27 :         silent = PG_GETARG_BOOL(3);
     285 ECB             :     }
     286                 : 
     287 GIC       43005 :     res = executeJsonPath(jp, vars, jb, !silent, NULL, tz);
     288 ECB             : 
     289 GIC       42999 :     PG_FREE_IF_COPY(jb, 0);
     290 CBC       42999 :     PG_FREE_IF_COPY(jp, 1);
     291 ECB             : 
     292 GIC       42999 :     if (jperIsError(res))
     293 CBC          27 :         PG_RETURN_NULL();
     294 ECB             : 
     295 GIC       42972 :     PG_RETURN_BOOL(res == jperOk);
     296 ECB             : }
     297                 : 
     298                 : Datum
     299 GIC          27 : jsonb_path_exists(PG_FUNCTION_ARGS)
     300 ECB             : {
     301 GIC          27 :     return jsonb_path_exists_internal(fcinfo, false);
     302 ECB             : }
     303                 : 
     304                 : Datum
     305 UIC           0 : jsonb_path_exists_tz(PG_FUNCTION_ARGS)
     306 EUB             : {
     307 UIC           0 :     return jsonb_path_exists_internal(fcinfo, true);
     308 EUB             : }
     309                 : 
     310                 : /*
     311                 :  * jsonb_path_exists_opr
     312                 :  *      Implementation of operator "jsonb @? jsonpath" (2-argument version of
     313                 :  *      jsonb_path_exists()).
     314                 :  */
     315                 : Datum
     316 GIC       42978 : jsonb_path_exists_opr(PG_FUNCTION_ARGS)
     317 ECB             : {
     318                 :     /* just call the other one -- it can handle both cases */
     319 GIC       42978 :     return jsonb_path_exists_internal(fcinfo, false);
     320 ECB             : }
     321                 : 
     322                 : /*
     323                 :  * jsonb_path_match
     324                 :  *      Returns jsonpath predicate result item for the specified jsonb value.
     325                 :  *      See jsonb_path_exists() comment for details regarding error handling.
     326                 :  */
     327                 : static Datum
     328 GIC       48957 : jsonb_path_match_internal(FunctionCallInfo fcinfo, bool tz)
     329 ECB             : {
     330 GIC       48957 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     331 CBC       48957 :     JsonPath   *jp = PG_GETARG_JSONPATH_P(1);
     332           48957 :     JsonValueList found = {0};
     333           48957 :     Jsonb      *vars = NULL;
     334           48957 :     bool        silent = true;
     335 ECB             : 
     336 GIC       48957 :     if (PG_NARGS() == 4)
     337 ECB             :     {
     338 GIC          63 :         vars = PG_GETARG_JSONB_P(2);
     339 CBC          63 :         silent = PG_GETARG_BOOL(3);
     340 ECB             :     }
     341                 : 
     342 GIC       48957 :     (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
     343 ECB             : 
     344 GIC       48951 :     PG_FREE_IF_COPY(jb, 0);
     345 CBC       48951 :     PG_FREE_IF_COPY(jp, 1);
     346 ECB             : 
     347 GIC       48951 :     if (JsonValueListLength(&found) == 1)
     348 ECB             :     {
     349 GIC       48936 :         JsonbValue *jbv = JsonValueListHead(&found);
     350 ECB             : 
     351 GIC       48936 :         if (jbv->type == jbvBool)
     352 CBC       48900 :             PG_RETURN_BOOL(jbv->val.boolean);
     353 ECB             : 
     354 GIC          36 :         if (jbv->type == jbvNull)
     355 CBC          12 :             PG_RETURN_NULL();
     356 ECB             :     }
     357                 : 
     358 GIC          39 :     if (!silent)
     359 CBC          18 :         ereport(ERROR,
     360 ECB             :                 (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
     361                 :                  errmsg("single boolean result is expected")));
     362                 : 
     363 GIC          21 :     PG_RETURN_NULL();
     364 ECB             : }
     365                 : 
     366                 : Datum
     367 GIC          63 : jsonb_path_match(PG_FUNCTION_ARGS)
     368 ECB             : {
     369 GIC          63 :     return jsonb_path_match_internal(fcinfo, false);
     370 ECB             : }
     371                 : 
     372                 : Datum
     373 UIC           0 : jsonb_path_match_tz(PG_FUNCTION_ARGS)
     374 EUB             : {
     375 UIC           0 :     return jsonb_path_match_internal(fcinfo, true);
     376 EUB             : }
     377                 : 
     378                 : /*
     379                 :  * jsonb_path_match_opr
     380                 :  *      Implementation of operator "jsonb @@ jsonpath" (2-argument version of
     381                 :  *      jsonb_path_match()).
     382                 :  */
     383                 : Datum
     384 GIC       48894 : jsonb_path_match_opr(PG_FUNCTION_ARGS)
     385 ECB             : {
     386                 :     /* just call the other one -- it can handle both cases */
     387 GIC       48894 :     return jsonb_path_match_internal(fcinfo, false);
     388 ECB             : }
     389                 : 
     390                 : /*
     391                 :  * jsonb_path_query
     392                 :  *      Executes jsonpath for given jsonb document and returns result as
     393                 :  *      rowset.
     394                 :  */
     395                 : static Datum
     396 GIC        1809 : jsonb_path_query_internal(FunctionCallInfo fcinfo, bool tz)
     397 ECB             : {
     398                 :     FuncCallContext *funcctx;
     399                 :     List       *found;
     400                 :     JsonbValue *v;
     401                 :     ListCell   *c;
     402                 : 
     403 GIC        1809 :     if (SRF_IS_FIRSTCALL())
     404 ECB             :     {
     405                 :         JsonPath   *jp;
     406                 :         Jsonb      *jb;
     407                 :         MemoryContext oldcontext;
     408                 :         Jsonb      *vars;
     409                 :         bool        silent;
     410 GIC         936 :         JsonValueList found = {0};
     411 ECB             : 
     412 GIC         936 :         funcctx = SRF_FIRSTCALL_INIT();
     413 CBC         936 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
     414 ECB             : 
     415 GIC         936 :         jb = PG_GETARG_JSONB_P_COPY(0);
     416 CBC         936 :         jp = PG_GETARG_JSONPATH_P_COPY(1);
     417             936 :         vars = PG_GETARG_JSONB_P_COPY(2);
     418             936 :         silent = PG_GETARG_BOOL(3);
     419 ECB             : 
     420 GIC         936 :         (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
     421 ECB             : 
     422 GIC         708 :         funcctx->user_fctx = JsonValueListGetList(&found);
     423 ECB             : 
     424 GIC         708 :         MemoryContextSwitchTo(oldcontext);
     425 ECB             :     }
     426                 : 
     427 GIC        1581 :     funcctx = SRF_PERCALL_SETUP();
     428 CBC        1581 :     found = funcctx->user_fctx;
     429 ECB             : 
     430 GIC        1581 :     c = list_head(found);
     431 ECB             : 
     432 GIC        1581 :     if (c == NULL)
     433 CBC         708 :         SRF_RETURN_DONE(funcctx);
     434 ECB             : 
     435 GIC         873 :     v = lfirst(c);
     436 CBC         873 :     funcctx->user_fctx = list_delete_first(found);
     437 ECB             : 
     438 GIC         873 :     SRF_RETURN_NEXT(funcctx, JsonbPGetDatum(JsonbValueToJsonb(v)));
     439 ECB             : }
     440                 : 
     441                 : Datum
     442 GIC        1617 : jsonb_path_query(PG_FUNCTION_ARGS)
     443 ECB             : {
     444 GIC        1617 :     return jsonb_path_query_internal(fcinfo, false);
     445 ECB             : }
     446                 : 
     447                 : Datum
     448 GIC         192 : jsonb_path_query_tz(PG_FUNCTION_ARGS)
     449 ECB             : {
     450 GIC         192 :     return jsonb_path_query_internal(fcinfo, true);
     451 ECB             : }
     452                 : 
     453                 : /*
     454                 :  * jsonb_path_query_array
     455                 :  *      Executes jsonpath for given jsonb document and returns result as
     456                 :  *      jsonb array.
     457                 :  */
     458                 : static Datum
     459 GIC          24 : jsonb_path_query_array_internal(FunctionCallInfo fcinfo, bool tz)
     460 ECB             : {
     461 GIC          24 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     462 CBC          24 :     JsonPath   *jp = PG_GETARG_JSONPATH_P(1);
     463              24 :     JsonValueList found = {0};
     464              24 :     Jsonb      *vars = PG_GETARG_JSONB_P(2);
     465              24 :     bool        silent = PG_GETARG_BOOL(3);
     466 ECB             : 
     467 GIC          24 :     (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
     468 ECB             : 
     469 GIC          21 :     PG_RETURN_JSONB_P(JsonbValueToJsonb(wrapItemsInArray(&found)));
     470 ECB             : }
     471                 : 
     472                 : Datum
     473 GIC          24 : jsonb_path_query_array(PG_FUNCTION_ARGS)
     474 ECB             : {
     475 GIC          24 :     return jsonb_path_query_array_internal(fcinfo, false);
     476 ECB             : }
     477                 : 
     478                 : Datum
     479 UIC           0 : jsonb_path_query_array_tz(PG_FUNCTION_ARGS)
     480 EUB             : {
     481 UIC           0 :     return jsonb_path_query_array_internal(fcinfo, true);
     482 EUB             : }
     483                 : 
     484                 : /*
     485                 :  * jsonb_path_query_first
     486                 :  *      Executes jsonpath for given jsonb document and returns first result
     487                 :  *      item.  If there are no items, NULL returned.
     488                 :  */
     489                 : static Datum
     490 GIC        2187 : jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz)
     491 ECB             : {
     492 GIC        2187 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
     493 CBC        2187 :     JsonPath   *jp = PG_GETARG_JSONPATH_P(1);
     494            2187 :     JsonValueList found = {0};
     495            2187 :     Jsonb      *vars = PG_GETARG_JSONB_P(2);
     496            2187 :     bool        silent = PG_GETARG_BOOL(3);
     497 ECB             : 
     498 GIC        2187 :     (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
     499 ECB             : 
     500 GIC        2181 :     if (JsonValueListLength(&found) >= 1)
     501 CBC        2175 :         PG_RETURN_JSONB_P(JsonbValueToJsonb(JsonValueListHead(&found)));
     502 ECB             :     else
     503 GIC           6 :         PG_RETURN_NULL();
     504 ECB             : }
     505                 : 
     506                 : Datum
     507 GIC        2187 : jsonb_path_query_first(PG_FUNCTION_ARGS)
     508 ECB             : {
     509 GIC        2187 :     return jsonb_path_query_first_internal(fcinfo, false);
     510 ECB             : }
     511                 : 
     512                 : Datum
     513 UIC           0 : jsonb_path_query_first_tz(PG_FUNCTION_ARGS)
     514 EUB             : {
     515 UIC           0 :     return jsonb_path_query_first_internal(fcinfo, true);
     516 EUB             : }
     517                 : 
     518                 : /********************Execute functions for JsonPath**************************/
     519                 : 
     520                 : /*
     521                 :  * Interface to jsonpath executor
     522                 :  *
     523                 :  * 'path' - jsonpath to be executed
     524                 :  * 'vars' - variables to be substituted to jsonpath
     525                 :  * 'json' - target document for jsonpath evaluation
     526                 :  * 'throwErrors' - whether we should throw suppressible errors
     527                 :  * 'result' - list to store result items into
     528                 :  *
     529                 :  * Returns an error if a recoverable error happens during processing, or NULL
     530                 :  * on no error.
     531                 :  *
     532                 :  * Note, jsonb and jsonpath values should be available and untoasted during
     533                 :  * work because JsonPathItem, JsonbValue and result item could have pointers
     534                 :  * into input values.  If caller needs to just check if document matches
     535                 :  * jsonpath, then it doesn't provide a result arg.  In this case executor
     536                 :  * works till first positive result and does not check the rest if possible.
     537                 :  * In other case it tries to find all the satisfied result items.
     538                 :  */
     539                 : static JsonPathExecResult
     540 GIC       95109 : executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
     541 ECB             :                 JsonValueList *result, bool useTz)
     542                 : {
     543                 :     JsonPathExecContext cxt;
     544                 :     JsonPathExecResult res;
     545                 :     JsonPathItem jsp;
     546                 :     JsonbValue  jbv;
     547                 : 
     548 GIC       95109 :     jspInit(&jsp, path);
     549 ECB             : 
     550 GIC       95109 :     if (!JsonbExtractScalar(&json->root, &jbv))
     551 CBC       94761 :         JsonbInitBinary(&jbv, json);
     552 ECB             : 
     553 GIC       95109 :     if (vars && !JsonContainerIsObject(&vars->root))
     554 ECB             :     {
     555 GIC           6 :         ereport(ERROR,
     556 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     557                 :                  errmsg("\"vars\" argument is not an object"),
     558                 :                  errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
     559                 :     }
     560                 : 
     561 GIC       95103 :     cxt.vars = vars;
     562 CBC       95103 :     cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
     563           95103 :     cxt.ignoreStructuralErrors = cxt.laxMode;
     564           95103 :     cxt.root = &jbv;
     565           95103 :     cxt.current = &jbv;
     566           95103 :     cxt.baseObject.jbc = NULL;
     567           95103 :     cxt.baseObject.id = 0;
     568           95103 :     cxt.lastGeneratedObjectId = vars ? 2 : 1;
     569           95103 :     cxt.innermostArraySize = -1;
     570           95103 :     cxt.throwErrors = throwErrors;
     571           95103 :     cxt.useTz = useTz;
     572 ECB             : 
     573 GIC       95103 :     if (jspStrictAbsenseOfErrors(&cxt) && !result)
     574 ECB             :     {
     575                 :         /*
     576                 :          * In strict mode we must get a complete list of values to check that
     577                 :          * there are no errors at all.
     578                 :          */
     579 GIC          27 :         JsonValueList vals = {0};
     580 ECB             : 
     581 GIC          27 :         res = executeItem(&cxt, &jsp, &jbv, &vals);
     582 ECB             : 
     583 GIC          24 :         if (jperIsError(res))
     584 CBC          21 :             return res;
     585 ECB             : 
     586 GIC           3 :         return JsonValueListIsEmpty(&vals) ? jperNotFound : jperOk;
     587 ECB             :     }
     588                 : 
     589 GIC       95076 :     res = executeItem(&cxt, &jsp, &jbv, result);
     590 ECB             : 
     591 GIC       94836 :     Assert(!throwErrors || !jperIsError(res));
     592 ECB             : 
     593 GIC       94836 :     return res;
     594 ECB             : }
     595                 : 
     596                 : /*
     597                 :  * Execute jsonpath with automatic unwrapping of current item in lax mode.
     598                 :  */
     599                 : static JsonPathExecResult
     600 GIC      282933 : executeItem(JsonPathExecContext *cxt, JsonPathItem *jsp,
     601 ECB             :             JsonbValue *jb, JsonValueList *found)
     602                 : {
     603 GIC      282933 :     return executeItemOptUnwrapTarget(cxt, jsp, jb, found, jspAutoUnwrap(cxt));
     604 ECB             : }
     605                 : 
     606                 : /*
     607                 :  * Main jsonpath executor function: walks on jsonpath structure, finds
     608                 :  * relevant parts of jsonb and evaluates expressions over them.
     609                 :  * When 'unwrap' is true current SQL/JSON item is unwrapped if it is an array.
     610                 :  */
     611                 : static JsonPathExecResult
     612 GIC      284925 : executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
     613 ECB             :                            JsonbValue *jb, JsonValueList *found, bool unwrap)
     614                 : {
     615                 :     JsonPathItem elem;
     616 GIC      284925 :     JsonPathExecResult res = jperNotFound;
     617 ECB             :     JsonBaseObjectInfo baseObject;
     618                 : 
     619 GIC      284925 :     check_stack_depth();
     620 CBC      284925 :     CHECK_FOR_INTERRUPTS();
     621 ECB             : 
     622 GIC      284925 :     switch (jsp->type)
     623 ECB             :     {
     624                 :             /* all boolean item types: */
     625 GIC       51081 :         case jpiAnd:
     626 ECB             :         case jpiOr:
     627                 :         case jpiNot:
     628                 :         case jpiIsUnknown:
     629                 :         case jpiEqual:
     630                 :         case jpiNotEqual:
     631                 :         case jpiLess:
     632                 :         case jpiGreater:
     633                 :         case jpiLessOrEqual:
     634                 :         case jpiGreaterOrEqual:
     635                 :         case jpiExists:
     636                 :         case jpiStartsWith:
     637                 :         case jpiLikeRegex:
     638                 :             {
     639 GIC       51081 :                 JsonPathBool st = executeBoolItem(cxt, jsp, jb, true);
     640 ECB             : 
     641 GIC       51081 :                 res = appendBoolResult(cxt, jsp, found, st);
     642 CBC       51081 :                 break;
     643 ECB             :             }
     644                 : 
     645 GIC       82614 :         case jpiKey:
     646 CBC       82614 :             if (JsonbType(jb) == jbvObject)
     647 ECB             :             {
     648                 :                 JsonbValue *v;
     649                 :                 JsonbValue  key;
     650                 : 
     651 GIC       82488 :                 key.type = jbvString;
     652 CBC       82488 :                 key.val.string.val = jspGetString(jsp, &key.val.string.len);
     653 ECB             : 
     654 GIC       82488 :                 v = findJsonbValueFromContainer(jb->val.binary.data,
     655 ECB             :                                                 JB_FOBJECT, &key);
     656                 : 
     657 GIC       82488 :                 if (v != NULL)
     658 ECB             :                 {
     659 GIC       13074 :                     res = executeNextItem(cxt, jsp, NULL,
     660 ECB             :                                           v, found, false);
     661                 : 
     662                 :                     /* free value if it was not added to found list */
     663 GIC       13074 :                     if (jspHasNext(jsp) || !found)
     664 CBC        8052 :                         pfree(v);
     665 ECB             :                 }
     666 GIC       69414 :                 else if (!jspIgnoreStructuralErrors(cxt))
     667 ECB             :                 {
     668 GIC          36 :                     Assert(found);
     669 ECB             : 
     670 GIC          36 :                     if (!jspThrowErrors(cxt))
     671 CBC          24 :                         return jperError;
     672 ECB             : 
     673 GIC          12 :                     ereport(ERROR,
     674 ECB             :                             (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND), \
     675                 :                              errmsg("JSON object does not contain key \"%s\"",
     676                 :                                     pnstrdup(key.val.string.val,
     677                 :                                              key.val.string.len))));
     678                 :                 }
     679                 :             }
     680 GIC         126 :             else if (unwrap && JsonbType(jb) == jbvArray)
     681 CBC           3 :                 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
     682             123 :             else if (!jspIgnoreStructuralErrors(cxt))
     683 ECB             :             {
     684 GIC          33 :                 Assert(found);
     685 CBC          33 :                 RETURN_ERROR(ereport(ERROR,
     686 ECB             :                                      (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND),
     687                 :                                       errmsg("jsonpath member accessor can only be applied to an object"))));
     688                 :             }
     689 GIC       82542 :             break;
     690 ECB             : 
     691 GIC      101205 :         case jpiRoot:
     692 CBC      101205 :             jb = cxt->root;
     693          101205 :             baseObject = setBaseObject(cxt, jb, 0);
     694          101205 :             res = executeNextItem(cxt, jsp, NULL, jb, found, true);
     695          100998 :             cxt->baseObject = baseObject;
     696          100998 :             break;
     697 ECB             : 
     698 GIC        9678 :         case jpiCurrent:
     699 CBC        9678 :             res = executeNextItem(cxt, jsp, NULL, cxt->current,
     700 ECB             :                                   found, true);
     701 GIC        9678 :             break;
     702 ECB             : 
     703 GIC         663 :         case jpiAnyArray:
     704 CBC         663 :             if (JsonbType(jb) == jbvArray)
     705 ECB             :             {
     706 GIC         570 :                 bool        hasNext = jspGetNext(jsp, &elem);
     707 ECB             : 
     708 GIC         570 :                 res = executeItemUnwrapTargetArray(cxt, hasNext ? &elem : NULL,
     709 CBC         570 :                                                    jb, found, jspAutoUnwrap(cxt));
     710 ECB             :             }
     711 GIC          93 :             else if (jspAutoWrap(cxt))
     712 CBC          87 :                 res = executeNextItem(cxt, jsp, NULL, jb, found, true);
     713               6 :             else if (!jspIgnoreStructuralErrors(cxt))
     714               6 :                 RETURN_ERROR(ereport(ERROR,
     715 ECB             :                                      (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
     716                 :                                       errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
     717 GIC         594 :             break;
     718 ECB             : 
     719 GIC         144 :         case jpiIndexArray:
     720 CBC         144 :             if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
     721              87 :             {
     722             138 :                 int         innermostArraySize = cxt->innermostArraySize;
     723 ECB             :                 int         i;
     724 GIC         138 :                 int         size = JsonbArraySize(jb);
     725 CBC         138 :                 bool        singleton = size < 0;
     726             138 :                 bool        hasNext = jspGetNext(jsp, &elem);
     727 ECB             : 
     728 GIC         138 :                 if (singleton)
     729 CBC           3 :                     size = 1;
     730 ECB             : 
     731 GIC         138 :                 cxt->innermostArraySize = size; /* for LAST evaluation */
     732 ECB             : 
     733 GIC         216 :                 for (i = 0; i < jsp->content.array.nelems; i++)
     734 ECB             :                 {
     735                 :                     JsonPathItem from;
     736                 :                     JsonPathItem to;
     737                 :                     int32       index;
     738                 :                     int32       index_from;
     739                 :                     int32       index_to;
     740 GIC         144 :                     bool        range = jspGetArraySubscript(jsp, &from,
     741 ECB             :                                                              &to, i);
     742                 : 
     743 GIC         144 :                     res = getArrayIndex(cxt, &from, jb, &index_from);
     744 ECB             : 
     745 GIC         132 :                     if (jperIsError(res))
     746 CBC          15 :                         break;
     747 ECB             : 
     748 GIC         120 :                     if (range)
     749 ECB             :                     {
     750 GIC          15 :                         res = getArrayIndex(cxt, &to, jb, &index_to);
     751 ECB             : 
     752 GIC          12 :                         if (jperIsError(res))
     753 LBC           0 :                             break;
     754 EUB             :                     }
     755                 :                     else
     756 GIC         105 :                         index_to = index_from;
     757 ECB             : 
     758 GIC         117 :                     if (!jspIgnoreStructuralErrors(cxt) &&
     759 CBC          42 :                         (index_from < 0 ||
     760              36 :                          index_from > index_to ||
     761              36 :                          index_to >= size))
     762              36 :                         RETURN_ERROR(ereport(ERROR,
     763 ECB             :                                              (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
     764                 :                                               errmsg("jsonpath array subscript is out of bounds"))));
     765                 : 
     766 GIC          93 :                     if (index_from < 0)
     767 CBC           6 :                         index_from = 0;
     768 ECB             : 
     769 GIC          93 :                     if (index_to >= size)
     770 CBC           9 :                         index_to = size - 1;
     771 ECB             : 
     772 GIC          93 :                     res = jperNotFound;
     773 ECB             : 
     774 GIC         180 :                     for (index = index_from; index <= index_to; index++)
     775 ECB             :                     {
     776                 :                         JsonbValue *v;
     777                 :                         bool        copy;
     778                 : 
     779 GIC         102 :                         if (singleton)
     780 ECB             :                         {
     781 GIC           3 :                             v = jb;
     782 CBC           3 :                             copy = true;
     783 ECB             :                         }
     784                 :                         else
     785                 :                         {
     786 GIC          99 :                             v = getIthJsonbValueFromContainer(jb->val.binary.data,
     787 ECB             :                                                               (uint32) index);
     788                 : 
     789 GIC          99 :                             if (v == NULL)
     790 LBC           0 :                                 continue;
     791 EUB             : 
     792 GIC          99 :                             copy = false;
     793 ECB             :                         }
     794                 : 
     795 GIC         102 :                         if (!hasNext && !found)
     796 CBC          12 :                             return jperOk;
     797 ECB             : 
     798 GIC          90 :                         res = executeNextItem(cxt, jsp, &elem, v, found,
     799 ECB             :                                               copy);
     800                 : 
     801 GIC          90 :                         if (jperIsError(res))
     802 LBC           0 :                             break;
     803 EUB             : 
     804 GIC          90 :                         if (res == jperOk && !found)
     805 CBC           3 :                             break;
     806 ECB             :                     }
     807                 : 
     808 GIC          81 :                     if (jperIsError(res))
     809 LBC           0 :                         break;
     810 EUB             : 
     811 GIC          81 :                     if (res == jperOk && !found)
     812 CBC           3 :                         break;
     813 ECB             :                 }
     814                 : 
     815 GIC          87 :                 cxt->innermostArraySize = innermostArraySize;
     816 ECB             :             }
     817 GIC           6 :             else if (!jspIgnoreStructuralErrors(cxt))
     818 ECB             :             {
     819 GIC           6 :                 RETURN_ERROR(ereport(ERROR,
     820 ECB             :                                      (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
     821                 :                                       errmsg("jsonpath array accessor can only be applied to an array"))));
     822                 :             }
     823 GIC          87 :             break;
     824 ECB             : 
     825 GIC          33 :         case jpiLast:
     826 ECB             :             {
     827                 :                 JsonbValue  tmpjbv;
     828                 :                 JsonbValue *lastjbv;
     829                 :                 int         last;
     830 GIC          33 :                 bool        hasNext = jspGetNext(jsp, &elem);
     831 ECB             : 
     832 GIC          33 :                 if (cxt->innermostArraySize < 0)
     833 LBC           0 :                     elog(ERROR, "evaluating jsonpath LAST outside of array subscript");
     834 EUB             : 
     835 GIC          33 :                 if (!hasNext && !found)
     836 ECB             :                 {
     837 GIC           3 :                     res = jperOk;
     838 CBC           3 :                     break;
     839 ECB             :                 }
     840                 : 
     841 GIC          30 :                 last = cxt->innermostArraySize - 1;
     842 ECB             : 
     843 GIC          30 :                 lastjbv = hasNext ? &tmpjbv : palloc(sizeof(*lastjbv));
     844 ECB             : 
     845 GIC          30 :                 lastjbv->type = jbvNumeric;
     846 CBC          30 :                 lastjbv->val.numeric = int64_to_numeric(last);
     847 ECB             : 
     848 GIC          30 :                 res = executeNextItem(cxt, jsp, &elem,
     849 ECB             :                                       lastjbv, found, hasNext);
     850                 :             }
     851 GIC          30 :             break;
     852 ECB             : 
     853 GIC          42 :         case jpiAnyKey:
     854 CBC          42 :             if (JsonbType(jb) == jbvObject)
     855 ECB             :             {
     856 GIC          33 :                 bool        hasNext = jspGetNext(jsp, &elem);
     857 ECB             : 
     858 GIC          33 :                 if (jb->type != jbvBinary)
     859 LBC           0 :                     elog(ERROR, "invalid jsonb object type: %d", jb->type);
     860 EUB             : 
     861 GIC          33 :                 return executeAnyItem
     862 ECB             :                     (cxt, hasNext ? &elem : NULL,
     863                 :                      jb->val.binary.data, found, 1, 1, 1,
     864 GIC          33 :                      false, jspAutoUnwrap(cxt));
     865 ECB             :             }
     866 GIC           9 :             else if (unwrap && JsonbType(jb) == jbvArray)
     867 LBC           0 :                 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
     868 GBC           9 :             else if (!jspIgnoreStructuralErrors(cxt))
     869 ECB             :             {
     870 GIC           6 :                 Assert(found);
     871 CBC           6 :                 RETURN_ERROR(ereport(ERROR,
     872 ECB             :                                      (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
     873                 :                                       errmsg("jsonpath wildcard member accessor can only be applied to an object"))));
     874                 :             }
     875 GIC           3 :             break;
     876 ECB             : 
     877 GIC          84 :         case jpiAdd:
     878 CBC          84 :             return executeBinaryArithmExpr(cxt, jsp, jb,
     879 ECB             :                                            numeric_add_opt_error, found);
     880                 : 
     881 GIC          30 :         case jpiSub:
     882 CBC          30 :             return executeBinaryArithmExpr(cxt, jsp, jb,
     883 ECB             :                                            numeric_sub_opt_error, found);
     884                 : 
     885 GIC          18 :         case jpiMul:
     886 CBC          18 :             return executeBinaryArithmExpr(cxt, jsp, jb,
     887 ECB             :                                            numeric_mul_opt_error, found);
     888                 : 
     889 GIC          33 :         case jpiDiv:
     890 CBC          33 :             return executeBinaryArithmExpr(cxt, jsp, jb,
     891 ECB             :                                            numeric_div_opt_error, found);
     892                 : 
     893 GIC           6 :         case jpiMod:
     894 CBC           6 :             return executeBinaryArithmExpr(cxt, jsp, jb,
     895 ECB             :                                            numeric_mod_opt_error, found);
     896                 : 
     897 GIC          30 :         case jpiPlus:
     898 CBC          30 :             return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
     899 ECB             : 
     900 GIC          63 :         case jpiMinus:
     901 CBC          63 :             return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus,
     902 ECB             :                                           found);
     903                 : 
     904 GIC        9291 :         case jpiFilter:
     905 ECB             :             {
     906                 :                 JsonPathBool st;
     907                 : 
     908 GIC        9291 :                 if (unwrap && JsonbType(jb) == jbvArray)
     909 CBC          63 :                     return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
     910 ECB             :                                                         false);
     911                 : 
     912 GIC        9228 :                 jspGetArg(jsp, &elem);
     913 CBC        9228 :                 st = executeNestedBoolItem(cxt, &elem, jb);
     914            9180 :                 if (st != jpbTrue)
     915            8241 :                     res = jperNotFound;
     916 ECB             :                 else
     917 GIC         939 :                     res = executeNextItem(cxt, jsp, NULL,
     918 ECB             :                                           jb, found, true);
     919 GIC        9180 :                 break;
     920 ECB             :             }
     921                 : 
     922 GIC         153 :         case jpiAny:
     923 ECB             :             {
     924 GIC         153 :                 bool        hasNext = jspGetNext(jsp, &elem);
     925 ECB             : 
     926                 :                 /* first try without any intermediate steps */
     927 GIC         153 :                 if (jsp->content.anybounds.first == 0)
     928 ECB             :                 {
     929                 :                     bool        savedIgnoreStructuralErrors;
     930                 : 
     931 GIC          84 :                     savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
     932 CBC          84 :                     cxt->ignoreStructuralErrors = true;
     933              84 :                     res = executeNextItem(cxt, jsp, &elem,
     934 ECB             :                                           jb, found, true);
     935 GIC          84 :                     cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
     936 ECB             : 
     937 GIC          84 :                     if (res == jperOk && !found)
     938 CBC           3 :                         break;
     939 ECB             :                 }
     940                 : 
     941 GIC         150 :                 if (jb->type == jbvBinary)
     942 CBC         150 :                     res = executeAnyItem
     943 ECB             :                         (cxt, hasNext ? &elem : NULL,
     944                 :                          jb->val.binary.data, found,
     945                 :                          1,
     946                 :                          jsp->content.anybounds.first,
     947                 :                          jsp->content.anybounds.last,
     948 GIC         150 :                          true, jspAutoUnwrap(cxt));
     949 CBC         150 :                 break;
     950 ECB             :             }
     951                 : 
     952 GIC       27774 :         case jpiNull:
     953 ECB             :         case jpiBool:
     954                 :         case jpiNumeric:
     955                 :         case jpiString:
     956                 :         case jpiVariable:
     957                 :             {
     958                 :                 JsonbValue  vbuf;
     959                 :                 JsonbValue *v;
     960 GIC       27774 :                 bool        hasNext = jspGetNext(jsp, &elem);
     961 ECB             : 
     962 GIC       27774 :                 if (!hasNext && !found && jsp->type != jpiVariable)
     963 ECB             :                 {
     964                 :                     /*
     965                 :                      * Skip evaluation, but not for variables.  We must
     966                 :                      * trigger an error for the missing variable.
     967                 :                      */
     968 GIC           6 :                     res = jperOk;
     969 CBC           6 :                     break;
     970 ECB             :                 }
     971                 : 
     972 GIC       27768 :                 v = hasNext ? &vbuf : palloc(sizeof(*v));
     973 ECB             : 
     974 GIC       27768 :                 baseObject = cxt->baseObject;
     975 CBC       27768 :                 getJsonPathItem(cxt, jsp, v);
     976 ECB             : 
     977 GIC       27753 :                 res = executeNextItem(cxt, jsp, &elem,
     978 ECB             :                                       v, found, hasNext);
     979 GIC       27753 :                 cxt->baseObject = baseObject;
     980 ECB             :             }
     981 GIC       27753 :             break;
     982 ECB             : 
     983 GIC         105 :         case jpiType:
     984 ECB             :             {
     985 GIC         105 :                 JsonbValue *jbv = palloc(sizeof(*jbv));
     986 ECB             : 
     987 GIC         105 :                 jbv->type = jbvString;
     988 CBC         105 :                 jbv->val.string.val = pstrdup(JsonbTypeName(jb));
     989             105 :                 jbv->val.string.len = strlen(jbv->val.string.val);
     990 ECB             : 
     991 GIC         105 :                 res = executeNextItem(cxt, jsp, NULL, jbv,
     992 ECB             :                                       found, false);
     993                 :             }
     994 GIC         105 :             break;
     995 ECB             : 
     996 GIC          36 :         case jpiSize:
     997 ECB             :             {
     998 GIC          36 :                 int         size = JsonbArraySize(jb);
     999 ECB             : 
    1000 GIC          36 :                 if (size < 0)
    1001 ECB             :                 {
    1002 GIC          24 :                     if (!jspAutoWrap(cxt))
    1003 ECB             :                     {
    1004 GIC           6 :                         if (!jspIgnoreStructuralErrors(cxt))
    1005 CBC           6 :                             RETURN_ERROR(ereport(ERROR,
    1006 ECB             :                                                  (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
    1007                 :                                                   errmsg("jsonpath item method .%s() can only be applied to an array",
    1008                 :                                                          jspOperationName(jsp->type)))));
    1009 UIC           0 :                         break;
    1010 EUB             :                     }
    1011                 : 
    1012 GIC          18 :                     size = 1;
    1013 ECB             :                 }
    1014                 : 
    1015 GIC          30 :                 jb = palloc(sizeof(*jb));
    1016 ECB             : 
    1017 GIC          30 :                 jb->type = jbvNumeric;
    1018 CBC          30 :                 jb->val.numeric = int64_to_numeric(size);
    1019 ECB             : 
    1020 GIC          30 :                 res = executeNextItem(cxt, jsp, NULL, jb, found, false);
    1021 ECB             :             }
    1022 GIC          30 :             break;
    1023 ECB             : 
    1024 GIC          54 :         case jpiAbs:
    1025 CBC          54 :             return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_abs,
    1026 ECB             :                                             found);
    1027                 : 
    1028 GIC          24 :         case jpiFloor:
    1029 CBC          24 :             return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_floor,
    1030 ECB             :                                             found);
    1031                 : 
    1032 GIC          51 :         case jpiCeiling:
    1033 CBC          51 :             return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_ceil,
    1034 ECB             :                                             found);
    1035                 : 
    1036 GIC          57 :         case jpiDouble:
    1037 ECB             :             {
    1038                 :                 JsonbValue  jbv;
    1039                 : 
    1040 GIC          57 :                 if (unwrap && JsonbType(jb) == jbvArray)
    1041 CBC          21 :                     return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
    1042 ECB             :                                                         false);
    1043                 : 
    1044 GIC          54 :                 if (jb->type == jbvNumeric)
    1045 ECB             :                 {
    1046 GIC           6 :                     char       *tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
    1047 ECB             :                                                                           NumericGetDatum(jb->val.numeric)));
    1048                 :                     double      val;
    1049 GNC           6 :                     ErrorSaveContext escontext = {T_ErrorSaveContext};
    1050 ECB             : 
    1051 GNC           6 :                     val = float8in_internal(tmp,
    1052                 :                                             NULL,
    1053                 :                                             "double precision",
    1054                 :                                             tmp,
    1055                 :                                             (Node *) &escontext);
    1056                 : 
    1057               6 :                     if (escontext.error_occurred || isinf(val) || isnan(val))
    1058 CBC           3 :                         RETURN_ERROR(ereport(ERROR,
    1059 ECB             :                                              (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
    1060                 :                                               errmsg("numeric argument of jsonpath item method .%s() is out of range for type double precision",
    1061                 :                                                      jspOperationName(jsp->type)))));
    1062 GIC           3 :                     res = jperOk;
    1063 ECB             :                 }
    1064 GIC          48 :                 else if (jb->type == jbvString)
    1065 ECB             :                 {
    1066                 :                     /* cast string as double */
    1067                 :                     double      val;
    1068 GIC          24 :                     char       *tmp = pnstrdup(jb->val.string.val,
    1069 CBC          24 :                                                jb->val.string.len);
    1070 GNC          24 :                     ErrorSaveContext escontext = {T_ErrorSaveContext};
    1071 ECB             : 
    1072 GNC          24 :                     val = float8in_internal(tmp,
    1073                 :                                             NULL,
    1074                 :                                             "double precision",
    1075                 :                                             tmp,
    1076                 :                                             (Node *) &escontext);
    1077                 : 
    1078              24 :                     if (escontext.error_occurred || isinf(val) || isnan(val))
    1079 CBC          21 :                         RETURN_ERROR(ereport(ERROR,
    1080 ECB             :                                              (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
    1081                 :                                               errmsg("string argument of jsonpath item method .%s() is not a valid representation of a double precision number",
    1082                 :                                                      jspOperationName(jsp->type)))));
    1083                 : 
    1084 GIC           3 :                     jb = &jbv;
    1085 CBC           3 :                     jb->type = jbvNumeric;
    1086               3 :                     jb->val.numeric = DatumGetNumeric(DirectFunctionCall1(float8_numeric,
    1087 ECB             :                                                                           Float8GetDatum(val)));
    1088 GIC           3 :                     res = jperOk;
    1089 ECB             :                 }
    1090                 : 
    1091 GIC          30 :                 if (res == jperNotFound)
    1092 CBC          24 :                     RETURN_ERROR(ereport(ERROR,
    1093 ECB             :                                          (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
    1094                 :                                           errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
    1095                 :                                                  jspOperationName(jsp->type)))));
    1096                 : 
    1097 GIC           6 :                 res = executeNextItem(cxt, jsp, NULL, jb, found, true);
    1098 ECB             :             }
    1099 GIC           6 :             break;
    1100 ECB             : 
    1101 GIC        1611 :         case jpiDatetime:
    1102 CBC        1611 :             if (unwrap && JsonbType(jb) == jbvArray)
    1103               3 :                 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
    1104 ECB             : 
    1105 GIC        1608 :             return executeDateTimeMethod(cxt, jsp, jb, found);
    1106 ECB             : 
    1107 GIC          45 :         case jpiKeyValue:
    1108 CBC          45 :             if (unwrap && JsonbType(jb) == jbvArray)
    1109               3 :                 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
    1110 ECB             : 
    1111 GIC          42 :             return executeKeyValueMethod(cxt, jsp, jb, found);
    1112 ECB             : 
    1113 UIC           0 :         default:
    1114 UBC           0 :             elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
    1115 EUB             :     }
    1116                 : 
    1117 GIC      282249 :     return res;
    1118 ECB             : }
    1119                 : 
    1120                 : /*
    1121                 :  * Unwrap current array item and execute jsonpath for each of its elements.
    1122                 :  */
    1123                 : static JsonPathExecResult
    1124 GIC         672 : executeItemUnwrapTargetArray(JsonPathExecContext *cxt, JsonPathItem *jsp,
    1125 ECB             :                              JsonbValue *jb, JsonValueList *found,
    1126                 :                              bool unwrapElements)
    1127                 : {
    1128 GIC         672 :     if (jb->type != jbvBinary)
    1129 ECB             :     {
    1130 UIC           0 :         Assert(jb->type != jbvArray);
    1131 UBC           0 :         elog(ERROR, "invalid jsonb array value type: %d", jb->type);
    1132 EUB             :     }
    1133                 : 
    1134 GIC         672 :     return executeAnyItem
    1135 ECB             :         (cxt, jsp, jb->val.binary.data, found, 1, 1, 1,
    1136                 :          false, unwrapElements);
    1137                 : }
    1138                 : 
    1139                 : /*
    1140                 :  * Execute next jsonpath item if exists.  Otherwise put "v" to the "found"
    1141                 :  * list if provided.
    1142                 :  */
    1143                 : static JsonPathExecResult
    1144 GIC      206007 : executeNextItem(JsonPathExecContext *cxt,
    1145 ECB             :                 JsonPathItem *cur, JsonPathItem *next,
    1146                 :                 JsonbValue *v, JsonValueList *found, bool copy)
    1147                 : {
    1148                 :     JsonPathItem elem;
    1149                 :     bool        hasNext;
    1150                 : 
    1151 GIC      206007 :     if (!cur)
    1152 LBC           0 :         hasNext = next != NULL;
    1153 GBC      206007 :     else if (next)
    1154 CBC       80883 :         hasNext = jspHasNext(cur);
    1155 ECB             :     else
    1156                 :     {
    1157 GIC      125124 :         next = &elem;
    1158 CBC      125124 :         hasNext = jspGetNext(cur, next);
    1159 ECB             :     }
    1160                 : 
    1161 GIC      206007 :     if (hasNext)
    1162 CBC       92898 :         return executeItem(cxt, next, v, found);
    1163 ECB             : 
    1164 GIC      113109 :     if (found)
    1165 CBC       88089 :         JsonValueListAppend(found, copy ? copyJsonbValue(v) : v);
    1166 ECB             : 
    1167 GIC      113109 :     return jperOk;
    1168 ECB             : }
    1169                 : 
    1170                 : /*
    1171                 :  * Same as executeItem(), but when "unwrap == true" automatically unwraps
    1172                 :  * each array item from the resulting sequence in lax mode.
    1173                 :  */
    1174                 : static JsonPathExecResult
    1175 GIC       94773 : executeItemOptUnwrapResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
    1176 ECB             :                            JsonbValue *jb, bool unwrap,
    1177                 :                            JsonValueList *found)
    1178                 : {
    1179 GIC       94773 :     if (unwrap && jspAutoUnwrap(cxt))
    1180 ECB             :     {
    1181 GIC       55080 :         JsonValueList seq = {0};
    1182 ECB             :         JsonValueListIterator it;
    1183 GIC       55080 :         JsonPathExecResult res = executeItem(cxt, jsp, jb, &seq);
    1184 ECB             :         JsonbValue *item;
    1185                 : 
    1186 GIC       55068 :         if (jperIsError(res))
    1187 CBC          33 :             return res;
    1188 ECB             : 
    1189 GIC       55035 :         JsonValueListInitIterator(&seq, &it);
    1190 CBC       91149 :         while ((item = JsonValueListNext(&seq, &it)))
    1191 ECB             :         {
    1192 GIC       36114 :             Assert(item->type != jbvArray);
    1193 ECB             : 
    1194 GIC       36114 :             if (JsonbType(item) == jbvArray)
    1195 CBC          27 :                 executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
    1196 ECB             :             else
    1197 GIC       36087 :                 JsonValueListAppend(found, item);
    1198 ECB             :         }
    1199                 : 
    1200 GIC       55035 :         return jperOk;
    1201 ECB             :     }
    1202                 : 
    1203 GIC       39693 :     return executeItem(cxt, jsp, jb, found);
    1204 ECB             : }
    1205                 : 
    1206                 : /*
    1207                 :  * Same as executeItemOptUnwrapResult(), but with error suppression.
    1208                 :  */
    1209                 : static JsonPathExecResult
    1210 GIC       94341 : executeItemOptUnwrapResultNoThrow(JsonPathExecContext *cxt,
    1211 ECB             :                                   JsonPathItem *jsp,
    1212                 :                                   JsonbValue *jb, bool unwrap,
    1213                 :                                   JsonValueList *found)
    1214                 : {
    1215                 :     JsonPathExecResult res;
    1216 GIC       94341 :     bool        throwErrors = cxt->throwErrors;
    1217 ECB             : 
    1218 GIC       94341 :     cxt->throwErrors = false;
    1219 CBC       94341 :     res = executeItemOptUnwrapResult(cxt, jsp, jb, unwrap, found);
    1220           94338 :     cxt->throwErrors = throwErrors;
    1221 ECB             : 
    1222 GIC       94338 :     return res;
    1223 ECB             : }
    1224                 : 
    1225                 : /* Execute boolean-valued jsonpath expression. */
    1226                 : static JsonPathBool
    1227 GIC       86472 : executeBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp,
    1228 ECB             :                 JsonbValue *jb, bool canHaveNext)
    1229                 : {
    1230                 :     JsonPathItem larg;
    1231                 :     JsonPathItem rarg;
    1232                 :     JsonPathBool res;
    1233                 :     JsonPathBool res2;
    1234                 : 
    1235 GIC       86472 :     if (!canHaveNext && jspHasNext(jsp))
    1236 LBC           0 :         elog(ERROR, "boolean jsonpath item cannot have next item");
    1237 EUB             : 
    1238 GIC       86472 :     switch (jsp->type)
    1239 ECB             :     {
    1240 GIC       12765 :         case jpiAnd:
    1241 CBC       12765 :             jspGetLeftArg(jsp, &larg);
    1242           12765 :             res = executeBoolItem(cxt, &larg, jb, false);
    1243 ECB             : 
    1244 GIC       12765 :             if (res == jpbFalse)
    1245 CBC       11235 :                 return jpbFalse;
    1246 ECB             : 
    1247                 :             /*
    1248                 :              * SQL/JSON says that we should check second arg in case of
    1249                 :              * jperError
    1250                 :              */
    1251                 : 
    1252 GIC        1530 :             jspGetRightArg(jsp, &rarg);
    1253 CBC        1530 :             res2 = executeBoolItem(cxt, &rarg, jb, false);
    1254 ECB             : 
    1255 GIC        1530 :             return res2 == jpbTrue ? res : res2;
    1256 ECB             : 
    1257 GIC        6477 :         case jpiOr:
    1258 CBC        6477 :             jspGetLeftArg(jsp, &larg);
    1259            6477 :             res = executeBoolItem(cxt, &larg, jb, false);
    1260 ECB             : 
    1261 GIC        6477 :             if (res == jpbTrue)
    1262 CBC        1245 :                 return jpbTrue;
    1263 ECB             : 
    1264 GIC        5232 :             jspGetRightArg(jsp, &rarg);
    1265 CBC        5232 :             res2 = executeBoolItem(cxt, &rarg, jb, false);
    1266 ECB             : 
    1267 GIC        5232 :             return res2 == jpbFalse ? res : res2;
    1268 ECB             : 
    1269 GIC          54 :         case jpiNot:
    1270 CBC          54 :             jspGetArg(jsp, &larg);
    1271 ECB             : 
    1272 GIC          54 :             res = executeBoolItem(cxt, &larg, jb, false);
    1273 ECB             : 
    1274 GIC          54 :             if (res == jpbUnknown)
    1275 CBC          18 :                 return jpbUnknown;
    1276 ECB             : 
    1277 GIC          36 :             return res == jpbTrue ? jpbFalse : jpbTrue;
    1278 ECB             : 
    1279 GIC         105 :         case jpiIsUnknown:
    1280 CBC         105 :             jspGetArg(jsp, &larg);
    1281             105 :             res = executeBoolItem(cxt, &larg, jb, false);
    1282             105 :             return res == jpbUnknown ? jpbTrue : jpbFalse;
    1283 ECB             : 
    1284 GIC       27237 :         case jpiEqual:
    1285 ECB             :         case jpiNotEqual:
    1286                 :         case jpiLess:
    1287                 :         case jpiGreater:
    1288                 :         case jpiLessOrEqual:
    1289                 :         case jpiGreaterOrEqual:
    1290 GIC       27237 :             jspGetLeftArg(jsp, &larg);
    1291 CBC       27237 :             jspGetRightArg(jsp, &rarg);
    1292           27237 :             return executePredicate(cxt, jsp, &larg, &rarg, jb, true,
    1293 ECB             :                                     executeComparison, cxt);
    1294                 : 
    1295 GIC          42 :         case jpiStartsWith:     /* 'whole STARTS WITH initial' */
    1296 CBC          42 :             jspGetLeftArg(jsp, &larg);  /* 'whole' */
    1297              42 :             jspGetRightArg(jsp, &rarg); /* 'initial' */
    1298              42 :             return executePredicate(cxt, jsp, &larg, &rarg, jb, false,
    1299 ECB             :                                     executeStartsWith, NULL);
    1300                 : 
    1301 GIC         198 :         case jpiLikeRegex:      /* 'expr LIKE_REGEX pattern FLAGS flags' */
    1302 ECB             :             {
    1303                 :                 /*
    1304                 :                  * 'expr' is a sequence-returning expression.  'pattern' is a
    1305                 :                  * regex string literal.  SQL/JSON standard requires XQuery
    1306                 :                  * regexes, but we use Postgres regexes here.  'flags' is a
    1307                 :                  * string literal converted to integer flags at compile-time.
    1308                 :                  */
    1309 GIC         198 :                 JsonLikeRegexContext lrcxt = {0};
    1310 ECB             : 
    1311 GIC         198 :                 jspInitByBuffer(&larg, jsp->base,
    1312 ECB             :                                 jsp->content.like_regex.expr);
    1313                 : 
    1314 GIC         198 :                 return executePredicate(cxt, jsp, &larg, NULL, jb, false,
    1315 ECB             :                                         executeLikeRegex, &lrcxt);
    1316                 :             }
    1317                 : 
    1318 GIC       39594 :         case jpiExists:
    1319 CBC       39594 :             jspGetArg(jsp, &larg);
    1320 ECB             : 
    1321 GIC       39594 :             if (jspStrictAbsenseOfErrors(cxt))
    1322 ECB             :             {
    1323                 :                 /*
    1324                 :                  * In strict mode we must get a complete list of values to
    1325                 :                  * check that there are no errors at all.
    1326                 :                  */
    1327 GIC          24 :                 JsonValueList vals = {0};
    1328 ECB             :                 JsonPathExecResult res =
    1329 GIC          24 :                 executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
    1330 ECB             :                                                   false, &vals);
    1331                 : 
    1332 GIC          24 :                 if (jperIsError(res))
    1333 CBC          18 :                     return jpbUnknown;
    1334 ECB             : 
    1335 GIC           6 :                 return JsonValueListIsEmpty(&vals) ? jpbFalse : jpbTrue;
    1336 ECB             :             }
    1337                 :             else
    1338                 :             {
    1339                 :                 JsonPathExecResult res =
    1340 GIC       39570 :                 executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
    1341 ECB             :                                                   false, NULL);
    1342                 : 
    1343 GIC       39570 :                 if (jperIsError(res))
    1344 CBC          12 :                     return jpbUnknown;
    1345 ECB             : 
    1346 GIC       39558 :                 return res == jperOk ? jpbTrue : jpbFalse;
    1347 ECB             :             }
    1348                 : 
    1349 UIC           0 :         default:
    1350 UBC           0 :             elog(ERROR, "invalid boolean jsonpath item type: %d", jsp->type);
    1351 EUB             :             return jpbUnknown;
    1352                 :     }
    1353                 : }
    1354                 : 
    1355                 : /*
    1356                 :  * Execute nested (filters etc.) boolean expression pushing current SQL/JSON
    1357                 :  * item onto the stack.
    1358                 :  */
    1359                 : static JsonPathBool
    1360 GIC        9228 : executeNestedBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp,
    1361 ECB             :                       JsonbValue *jb)
    1362                 : {
    1363                 :     JsonbValue *prev;
    1364                 :     JsonPathBool res;
    1365                 : 
    1366 GIC        9228 :     prev = cxt->current;
    1367 CBC        9228 :     cxt->current = jb;
    1368            9228 :     res = executeBoolItem(cxt, jsp, jb, false);
    1369            9180 :     cxt->current = prev;
    1370 ECB             : 
    1371 GIC        9180 :     return res;
    1372 ECB             : }
    1373                 : 
    1374                 : /*
    1375                 :  * Implementation of several jsonpath nodes:
    1376                 :  *  - jpiAny (.** accessor),
    1377                 :  *  - jpiAnyKey (.* accessor),
    1378                 :  *  - jpiAnyArray ([*] accessor)
    1379                 :  */
    1380                 : static JsonPathExecResult
    1381 GIC         948 : executeAnyItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbContainer *jbc,
    1382 ECB             :                JsonValueList *found, uint32 level, uint32 first, uint32 last,
    1383                 :                bool ignoreStructuralErrors, bool unwrapNext)
    1384                 : {
    1385 GIC         948 :     JsonPathExecResult res = jperNotFound;
    1386 ECB             :     JsonbIterator *it;
    1387                 :     int32       r;
    1388                 :     JsonbValue  v;
    1389                 : 
    1390 GIC         948 :     check_stack_depth();
    1391 ECB             : 
    1392 GIC         948 :     if (level > last)
    1393 CBC          15 :         return res;
    1394 ECB             : 
    1395 GIC         933 :     it = JsonbIteratorInit(jbc);
    1396 ECB             : 
    1397                 :     /*
    1398                 :      * Recursively iterate over jsonb objects/arrays
    1399                 :      */
    1400 GIC        4815 :     while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
    1401 ECB             :     {
    1402 GIC        4170 :         if (r == WJB_KEY)
    1403 ECB             :         {
    1404 GIC         276 :             r = JsonbIteratorNext(&it, &v, true);
    1405 CBC         276 :             Assert(r == WJB_VALUE);
    1406 ECB             :         }
    1407                 : 
    1408 GIC        4170 :         if (r == WJB_VALUE || r == WJB_ELEM)
    1409 ECB             :         {
    1410                 : 
    1411 GIC        2592 :             if (level >= first ||
    1412 CBC           6 :                 (first == PG_UINT32_MAX && last == PG_UINT32_MAX &&
    1413               6 :                  v.type != jbvBinary))  /* leaves only requested */
    1414 ECB             :             {
    1415                 :                 /* check expression */
    1416 GIC        2562 :                 if (jsp)
    1417 ECB             :                 {
    1418 GIC        1992 :                     if (ignoreStructuralErrors)
    1419 ECB             :                     {
    1420                 :                         bool        savedIgnoreStructuralErrors;
    1421                 : 
    1422 GIC         174 :                         savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
    1423 CBC         174 :                         cxt->ignoreStructuralErrors = true;
    1424             174 :                         res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
    1425             174 :                         cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
    1426 ECB             :                     }
    1427                 :                     else
    1428 GIC        1818 :                         res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
    1429 ECB             : 
    1430 GIC        1929 :                     if (jperIsError(res))
    1431 CBC          33 :                         break;
    1432 ECB             : 
    1433 GIC        1896 :                     if (res == jperOk && !found)
    1434 CBC         162 :                         break;
    1435 ECB             :                 }
    1436 GIC         570 :                 else if (found)
    1437 CBC         558 :                     JsonValueListAppend(found, copyJsonbValue(&v));
    1438 ECB             :                 else
    1439 GIC          12 :                     return jperOk;
    1440 ECB             :             }
    1441                 : 
    1442 GIC        2322 :             if (level < last && v.type == jbvBinary)
    1443 ECB             :             {
    1444 GIC          93 :                 res = executeAnyItem
    1445 ECB             :                     (cxt, jsp, v.val.binary.data, found,
    1446                 :                      level + 1, first, last,
    1447                 :                      ignoreStructuralErrors, unwrapNext);
    1448                 : 
    1449 GIC          93 :                 if (jperIsError(res))
    1450 LBC           0 :                     break;
    1451 EUB             : 
    1452 GIC          93 :                 if (res == jperOk && found == NULL)
    1453 CBC          18 :                     break;
    1454 ECB             :             }
    1455                 :         }
    1456                 :     }
    1457                 : 
    1458 GIC         858 :     return res;
    1459 ECB             : }
    1460                 : 
    1461                 : /*
    1462                 :  * Execute unary or binary predicate.
    1463                 :  *
    1464                 :  * Predicates have existence semantics, because their operands are item
    1465                 :  * sequences.  Pairs of items from the left and right operand's sequences are
    1466                 :  * checked.  TRUE returned only if any pair satisfying the condition is found.
    1467                 :  * In strict mode, even if the desired pair has already been found, all pairs
    1468                 :  * still need to be examined to check the absence of errors.  If any error
    1469                 :  * occurs, UNKNOWN (analogous to SQL NULL) is returned.
    1470                 :  */
    1471                 : static JsonPathBool
    1472 GIC       27477 : executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred,
    1473 ECB             :                  JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb,
    1474                 :                  bool unwrapRightArg, JsonPathPredicateCallback exec,
    1475                 :                  void *param)
    1476                 : {
    1477                 :     JsonPathExecResult res;
    1478                 :     JsonValueListIterator lseqit;
    1479 GIC       27477 :     JsonValueList lseq = {0};
    1480 CBC       27477 :     JsonValueList rseq = {0};
    1481 ECB             :     JsonbValue *lval;
    1482 GIC       27477 :     bool        error = false;
    1483 CBC       27477 :     bool        found = false;
    1484 ECB             : 
    1485                 :     /* Left argument is always auto-unwrapped. */
    1486 GIC       27477 :     res = executeItemOptUnwrapResultNoThrow(cxt, larg, jb, true, &lseq);
    1487 CBC       27477 :     if (jperIsError(res))
    1488               9 :         return jpbUnknown;
    1489 ECB             : 
    1490 GIC       27468 :     if (rarg)
    1491 ECB             :     {
    1492                 :         /* Right argument is conditionally auto-unwrapped. */
    1493 GIC       27270 :         res = executeItemOptUnwrapResultNoThrow(cxt, rarg, jb,
    1494 ECB             :                                                 unwrapRightArg, &rseq);
    1495 GIC       27267 :         if (jperIsError(res))
    1496 CBC          27 :             return jpbUnknown;
    1497 ECB             :     }
    1498                 : 
    1499 GIC       27438 :     JsonValueListInitIterator(&lseq, &lseqit);
    1500 CBC       36021 :     while ((lval = JsonValueListNext(&lseq, &lseqit)))
    1501 ECB             :     {
    1502                 :         JsonValueListIterator rseqit;
    1503                 :         JsonbValue *rval;
    1504 GIC       11037 :         bool        first = true;
    1505 ECB             : 
    1506 GIC       11037 :         JsonValueListInitIterator(&rseq, &rseqit);
    1507 CBC       11037 :         if (rarg)
    1508           10839 :             rval = JsonValueListNext(&rseq, &rseqit);
    1509 ECB             :         else
    1510 GIC         198 :             rval = NULL;
    1511 ECB             : 
    1512                 :         /* Loop over right arg sequence or do single pass otherwise */
    1513 GIC       17148 :         while (rarg ? (rval != NULL) : first)
    1514 ECB             :         {
    1515 GIC        8565 :             JsonPathBool res = exec(pred, lval, rval, param);
    1516 ECB             : 
    1517 GIC        8520 :             if (res == jpbUnknown)
    1518 ECB             :             {
    1519 GIC         339 :                 if (jspStrictAbsenseOfErrors(cxt))
    1520 CBC        2409 :                     return jpbUnknown;
    1521 ECB             : 
    1522 GIC         327 :                 error = true;
    1523 ECB             :             }
    1524 GIC        8181 :             else if (res == jpbTrue)
    1525 ECB             :             {
    1526 GIC        2421 :                 if (!jspStrictAbsenseOfErrors(cxt))
    1527 CBC        2397 :                     return jpbTrue;
    1528 ECB             : 
    1529 GIC          24 :                 found = true;
    1530 ECB             :             }
    1531                 : 
    1532 GIC        6111 :             first = false;
    1533 CBC        6111 :             if (rarg)
    1534            5964 :                 rval = JsonValueListNext(&rseq, &rseqit);
    1535 ECB             :         }
    1536                 :     }
    1537                 : 
    1538 GIC       24984 :     if (found)                  /* possible only in strict mode */
    1539 CBC           9 :         return jpbTrue;
    1540 ECB             : 
    1541 GIC       24975 :     if (error)                  /* possible only in lax mode */
    1542 CBC         312 :         return jpbUnknown;
    1543 ECB             : 
    1544 GIC       24663 :     return jpbFalse;
    1545 ECB             : }
    1546                 : 
    1547                 : /*
    1548                 :  * Execute binary arithmetic expression on singleton numeric operands.
    1549                 :  * Array operands are automatically unwrapped in lax mode.
    1550                 :  */
    1551                 : static JsonPathExecResult
    1552 GIC         171 : executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
    1553 ECB             :                         JsonbValue *jb, BinaryArithmFunc func,
    1554                 :                         JsonValueList *found)
    1555                 : {
    1556                 :     JsonPathExecResult jper;
    1557                 :     JsonPathItem elem;
    1558 GIC         171 :     JsonValueList lseq = {0};
    1559 CBC         171 :     JsonValueList rseq = {0};
    1560 ECB             :     JsonbValue *lval;
    1561                 :     JsonbValue *rval;
    1562                 :     Numeric     res;
    1563                 : 
    1564 GIC         171 :     jspGetLeftArg(jsp, &elem);
    1565 ECB             : 
    1566                 :     /*
    1567                 :      * XXX: By standard only operands of multiplicative expressions are
    1568                 :      * unwrapped.  We extend it to other binary arithmetic expressions too.
    1569                 :      */
    1570 GIC         171 :     jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &lseq);
    1571 CBC         168 :     if (jperIsError(jper))
    1572 LBC           0 :         return jper;
    1573 EUB             : 
    1574 GIC         168 :     jspGetRightArg(jsp, &elem);
    1575 ECB             : 
    1576 GIC         168 :     jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &rseq);
    1577 CBC         165 :     if (jperIsError(jper))
    1578 LBC           0 :         return jper;
    1579 EUB             : 
    1580 GIC         297 :     if (JsonValueListLength(&lseq) != 1 ||
    1581 CBC         132 :         !(lval = getScalar(JsonValueListHead(&lseq), jbvNumeric)))
    1582              33 :         RETURN_ERROR(ereport(ERROR,
    1583 ECB             :                              (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
    1584                 :                               errmsg("left operand of jsonpath operator %s is not a single numeric value",
    1585                 :                                      jspOperationName(jsp->type)))));
    1586                 : 
    1587 GIC         249 :     if (JsonValueListLength(&rseq) != 1 ||
    1588 CBC         117 :         !(rval = getScalar(JsonValueListHead(&rseq), jbvNumeric)))
    1589              27 :         RETURN_ERROR(ereport(ERROR,
    1590 ECB             :                              (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
    1591                 :                               errmsg("right operand of jsonpath operator %s is not a single numeric value",
    1592                 :                                      jspOperationName(jsp->type)))));
    1593                 : 
    1594 GIC         105 :     if (jspThrowErrors(cxt))
    1595 ECB             :     {
    1596 GIC          39 :         res = func(lval->val.numeric, rval->val.numeric, NULL);
    1597 ECB             :     }
    1598                 :     else
    1599                 :     {
    1600 GIC          66 :         bool        error = false;
    1601 ECB             : 
    1602 GIC          66 :         res = func(lval->val.numeric, rval->val.numeric, &error);
    1603 ECB             : 
    1604 GIC          66 :         if (error)
    1605 CBC           6 :             return jperError;
    1606 ECB             :     }
    1607                 : 
    1608 GIC          87 :     if (!jspGetNext(jsp, &elem) && !found)
    1609 CBC           3 :         return jperOk;
    1610 ECB             : 
    1611 GIC          84 :     lval = palloc(sizeof(*lval));
    1612 CBC          84 :     lval->type = jbvNumeric;
    1613              84 :     lval->val.numeric = res;
    1614 ECB             : 
    1615 GIC          84 :     return executeNextItem(cxt, jsp, &elem, lval, found, false);
    1616 ECB             : }
    1617                 : 
    1618                 : /*
    1619                 :  * Execute unary arithmetic expression for each numeric item in its operand's
    1620                 :  * sequence.  Array operand is automatically unwrapped in lax mode.
    1621                 :  */
    1622                 : static JsonPathExecResult
    1623 GIC          93 : executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
    1624 ECB             :                        JsonbValue *jb, PGFunction func, JsonValueList *found)
    1625                 : {
    1626                 :     JsonPathExecResult jper;
    1627                 :     JsonPathExecResult jper2;
    1628                 :     JsonPathItem elem;
    1629 GIC          93 :     JsonValueList seq = {0};
    1630 ECB             :     JsonValueListIterator it;
    1631                 :     JsonbValue *val;
    1632                 :     bool        hasNext;
    1633                 : 
    1634 GIC          93 :     jspGetArg(jsp, &elem);
    1635 CBC          93 :     jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &seq);
    1636 ECB             : 
    1637 GIC          90 :     if (jperIsError(jper))
    1638 LBC           0 :         return jper;
    1639 EUB             : 
    1640 GIC          90 :     jper = jperNotFound;
    1641 ECB             : 
    1642 GIC          90 :     hasNext = jspGetNext(jsp, &elem);
    1643 ECB             : 
    1644 GIC          90 :     JsonValueListInitIterator(&seq, &it);
    1645 CBC         162 :     while ((val = JsonValueListNext(&seq, &it)))
    1646 ECB             :     {
    1647 GIC          96 :         if ((val = getScalar(val, jbvNumeric)))
    1648 ECB             :         {
    1649 GIC          75 :             if (!found && !hasNext)
    1650 CBC           6 :                 return jperOk;
    1651 ECB             :         }
    1652                 :         else
    1653                 :         {
    1654 GIC          21 :             if (!found && !hasNext)
    1655 CBC           3 :                 continue;       /* skip non-numerics processing */
    1656 ECB             : 
    1657 GIC          18 :             RETURN_ERROR(ereport(ERROR,
    1658 ECB             :                                  (errcode(ERRCODE_SQL_JSON_NUMBER_NOT_FOUND),
    1659                 :                                   errmsg("operand of unary jsonpath operator %s is not a numeric value",
    1660                 :                                          jspOperationName(jsp->type)))));
    1661                 :         }
    1662                 : 
    1663 GIC          69 :         if (func)
    1664 CBC          42 :             val->val.numeric =
    1665              42 :                 DatumGetNumeric(DirectFunctionCall1(func,
    1666 ECB             :                                                     NumericGetDatum(val->val.numeric)));
    1667                 : 
    1668 GIC          69 :         jper2 = executeNextItem(cxt, jsp, &elem, val, found, false);
    1669 ECB             : 
    1670 GIC          69 :         if (jperIsError(jper2))
    1671 LBC           0 :             return jper2;
    1672 EUB             : 
    1673 GIC          69 :         if (jper2 == jperOk)
    1674 ECB             :         {
    1675 GIC          69 :             if (!found)
    1676 LBC           0 :                 return jperOk;
    1677 GBC          69 :             jper = jperOk;
    1678 ECB             :         }
    1679                 :     }
    1680                 : 
    1681 GIC          66 :     return jper;
    1682 ECB             : }
    1683                 : 
    1684                 : /*
    1685                 :  * STARTS_WITH predicate callback.
    1686                 :  *
    1687                 :  * Check if the 'whole' string starts from 'initial' string.
    1688                 :  */
    1689                 : static JsonPathBool
    1690 GIC          87 : executeStartsWith(JsonPathItem *jsp, JsonbValue *whole, JsonbValue *initial,
    1691 ECB             :                   void *param)
    1692                 : {
    1693 GIC          87 :     if (!(whole = getScalar(whole, jbvString)))
    1694 CBC          24 :         return jpbUnknown;      /* error */
    1695 ECB             : 
    1696 GIC          63 :     if (!(initial = getScalar(initial, jbvString)))
    1697 LBC           0 :         return jpbUnknown;      /* error */
    1698 EUB             : 
    1699 GIC          63 :     if (whole->val.string.len >= initial->val.string.len &&
    1700 CBC          45 :         !memcmp(whole->val.string.val,
    1701              45 :                 initial->val.string.val,
    1702              45 :                 initial->val.string.len))
    1703              27 :         return jpbTrue;
    1704 ECB             : 
    1705 GIC          36 :     return jpbFalse;
    1706 ECB             : }
    1707                 : 
    1708                 : /*
    1709                 :  * LIKE_REGEX predicate callback.
    1710                 :  *
    1711                 :  * Check if the string matches regex pattern.
    1712                 :  */
    1713                 : static JsonPathBool
    1714 GIC         198 : executeLikeRegex(JsonPathItem *jsp, JsonbValue *str, JsonbValue *rarg,
    1715 ECB             :                  void *param)
    1716                 : {
    1717 GIC         198 :     JsonLikeRegexContext *cxt = param;
    1718 ECB             : 
    1719 GIC         198 :     if (!(str = getScalar(str, jbvString)))
    1720 CBC          60 :         return jpbUnknown;
    1721 ECB             : 
    1722                 :     /* Cache regex text and converted flags. */
    1723 GIC         138 :     if (!cxt->regex)
    1724 ECB             :     {
    1725 GIC         138 :         cxt->regex =
    1726 CBC         138 :             cstring_to_text_with_len(jsp->content.like_regex.pattern,
    1727 ECB             :                                      jsp->content.like_regex.patternlen);
    1728 GNC         138 :         (void) jspConvertRegexFlags(jsp->content.like_regex.flags,
    1729                 :                                     &(cxt->cflags), NULL);
    1730 ECB             :     }
    1731                 : 
    1732 GIC         138 :     if (RE_compile_and_execute(cxt->regex, str->val.string.val,
    1733                 :                                str->val.string.len,
    1734 ECB             :                                cxt->cflags, DEFAULT_COLLATION_OID, 0, NULL))
    1735 GIC          51 :         return jpbTrue;
    1736                 : 
    1737 CBC          87 :     return jpbFalse;
    1738                 : }
    1739 ECB             : 
    1740                 : /*
    1741                 :  * Execute numeric item methods (.abs(), .floor(), .ceil()) using the specified
    1742                 :  * user function 'func'.
    1743                 :  */
    1744                 : static JsonPathExecResult
    1745 GIC         129 : executeNumericItemMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
    1746                 :                          JsonbValue *jb, bool unwrap, PGFunction func,
    1747 ECB             :                          JsonValueList *found)
    1748                 : {
    1749                 :     JsonPathItem next;
    1750                 :     Datum       datum;
    1751                 : 
    1752 GIC         129 :     if (unwrap && JsonbType(jb) == jbvArray)
    1753 UIC           0 :         return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
    1754 ECB             : 
    1755 GBC         129 :     if (!(jb = getScalar(jb, jbvNumeric)))
    1756 GIC          18 :         RETURN_ERROR(ereport(ERROR,
    1757 ECB             :                              (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
    1758                 :                               errmsg("jsonpath item method .%s() can only be applied to a numeric value",
    1759                 :                                      jspOperationName(jsp->type)))));
    1760                 : 
    1761 GIC         111 :     datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
    1762                 : 
    1763 CBC         111 :     if (!jspGetNext(jsp, &next) && !found)
    1764 UIC           0 :         return jperOk;
    1765 ECB             : 
    1766 GBC         111 :     jb = palloc(sizeof(*jb));
    1767 GIC         111 :     jb->type = jbvNumeric;
    1768 CBC         111 :     jb->val.numeric = DatumGetNumeric(datum);
    1769 ECB             : 
    1770 CBC         111 :     return executeNextItem(cxt, jsp, &next, jb, found, false);
    1771                 : }
    1772 ECB             : 
    1773                 : /*
    1774                 :  * Implementation of the .datetime() method.
    1775                 :  *
    1776                 :  * Converts a string into a date/time value. The actual type is determined at run time.
    1777                 :  * If an argument is provided, this argument is used as a template string.
    1778                 :  * Otherwise, the first fitting ISO format is selected.
    1779                 :  */
    1780                 : static JsonPathExecResult
    1781 GIC        1608 : executeDateTimeMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
    1782                 :                       JsonbValue *jb, JsonValueList *found)
    1783 ECB             : {
    1784                 :     JsonbValue  jbvbuf;
    1785                 :     Datum       value;
    1786                 :     text       *datetime;
    1787                 :     Oid         collid;
    1788                 :     Oid         typid;
    1789 GIC        1608 :     int32       typmod = -1;
    1790            1608 :     int         tz = 0;
    1791 ECB             :     bool        hasNext;
    1792 CBC        1608 :     JsonPathExecResult res = jperNotFound;
    1793                 :     JsonPathItem elem;
    1794 ECB             : 
    1795 GIC        1608 :     if (!(jb = getScalar(jb, jbvString)))
    1796              15 :         RETURN_ERROR(ereport(ERROR,
    1797 ECB             :                              (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
    1798                 :                               errmsg("jsonpath item method .%s() can only be applied to a string",
    1799                 :                                      jspOperationName(jsp->type)))));
    1800                 : 
    1801 GIC        1593 :     datetime = cstring_to_text_with_len(jb->val.string.val,
    1802                 :                                         jb->val.string.len);
    1803 ECB             : 
    1804                 :     /*
    1805                 :      * At some point we might wish to have callers supply the collation to
    1806                 :      * use, but right now it's unclear that they'd be able to do better than
    1807                 :      * DEFAULT_COLLATION_OID anyway.
    1808                 :      */
    1809 GIC        1593 :     collid = DEFAULT_COLLATION_OID;
    1810                 : 
    1811 CBC        1593 :     if (jsp->content.arg)
    1812                 :     {
    1813 ECB             :         text       *template;
    1814                 :         char       *template_str;
    1815                 :         int         template_len;
    1816 GNC         825 :         ErrorSaveContext escontext = {T_ErrorSaveContext};
    1817                 : 
    1818 CBC         825 :         jspGetArg(jsp, &elem);
    1819                 : 
    1820             825 :         if (elem.type != jpiString)
    1821 UIC           0 :             elog(ERROR, "invalid jsonpath item type for .datetime() argument");
    1822 ECB             : 
    1823 GBC         825 :         template_str = jspGetString(&elem, &template_len);
    1824                 : 
    1825 CBC         825 :         template = cstring_to_text_with_len(template_str,
    1826                 :                                             template_len);
    1827 ECB             : 
    1828 GIC         825 :         value = parse_datetime(datetime, template, collid, true,
    1829                 :                                &typid, &typmod, &tz,
    1830 GNC         825 :                                jspThrowErrors(cxt) ? NULL : (Node *) &escontext);
    1831                 : 
    1832             795 :         if (escontext.error_occurred)
    1833 UIC           0 :             res = jperError;
    1834 ECB             :         else
    1835 GBC         795 :             res = jperOk;
    1836                 :     }
    1837 ECB             :     else
    1838                 :     {
    1839                 :         /*
    1840                 :          * According to SQL/JSON standard enumerate ISO formats for: date,
    1841                 :          * timetz, time, timestamptz, timestamp.
    1842                 :          *
    1843                 :          * We also support ISO 8601 for timestamps, because to_json[b]()
    1844                 :          * functions use this format.
    1845                 :          */
    1846                 :         static const char *fmt_str[] =
    1847                 :         {
    1848                 :             "yyyy-mm-dd",
    1849                 :             "HH24:MI:SSTZH:TZM",
    1850                 :             "HH24:MI:SSTZH",
    1851                 :             "HH24:MI:SS",
    1852                 :             "yyyy-mm-dd HH24:MI:SSTZH:TZM",
    1853                 :             "yyyy-mm-dd HH24:MI:SSTZH",
    1854                 :             "yyyy-mm-dd HH24:MI:SS",
    1855                 :             "yyyy-mm-dd\"T\"HH24:MI:SSTZH:TZM",
    1856                 :             "yyyy-mm-dd\"T\"HH24:MI:SSTZH",
    1857                 :             "yyyy-mm-dd\"T\"HH24:MI:SS"
    1858                 :         };
    1859                 : 
    1860                 :         /* cache for format texts */
    1861                 :         static text *fmt_txt[lengthof(fmt_str)] = {0};
    1862                 :         int         i;
    1863                 : 
    1864                 :         /* loop until datetime format fits */
    1865 GIC        3414 :         for (i = 0; i < lengthof(fmt_str); i++)
    1866                 :         {
    1867 GNC        3408 :             ErrorSaveContext escontext = {T_ErrorSaveContext};
    1868                 : 
    1869 CBC        3408 :             if (!fmt_txt[i])
    1870                 :             {
    1871 ECB             :                 MemoryContext oldcxt =
    1872 GIC          30 :                 MemoryContextSwitchTo(TopMemoryContext);
    1873                 : 
    1874 CBC          30 :                 fmt_txt[i] = cstring_to_text(fmt_str[i]);
    1875 GIC          30 :                 MemoryContextSwitchTo(oldcxt);
    1876 ECB             :             }
    1877                 : 
    1878 GIC        3408 :             value = parse_datetime(datetime, fmt_txt[i], collid, true,
    1879                 :                                    &typid, &typmod, &tz,
    1880                 :                                    (Node *) &escontext);
    1881                 : 
    1882 GNC        3408 :             if (!escontext.error_occurred)
    1883                 :             {
    1884 CBC         762 :                 res = jperOk;
    1885 GIC         762 :                 break;
    1886 ECB             :             }
    1887                 :         }
    1888                 : 
    1889 GIC         768 :         if (res == jperNotFound)
    1890               6 :             RETURN_ERROR(ereport(ERROR,
    1891 ECB             :                                  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
    1892                 :                                   errmsg("datetime format is not recognized: \"%s\"",
    1893                 :                                          text_to_cstring(datetime)),
    1894                 :                                   errhint("Use a datetime template argument to specify the input data format."))));
    1895                 :     }
    1896                 : 
    1897 GIC        1557 :     pfree(datetime);
    1898                 : 
    1899 CBC        1557 :     if (jperIsError(res))
    1900 UIC           0 :         return res;
    1901 ECB             : 
    1902 GBC        1557 :     hasNext = jspGetNext(jsp, &elem);
    1903                 : 
    1904 CBC        1557 :     if (!hasNext && !found)
    1905 GIC           3 :         return res;
    1906 ECB             : 
    1907 CBC        1554 :     jb = hasNext ? &jbvbuf : palloc(sizeof(*jb));
    1908                 : 
    1909            1554 :     jb->type = jbvDatetime;
    1910 GIC        1554 :     jb->val.datetime.value = value;
    1911 CBC        1554 :     jb->val.datetime.typid = typid;
    1912            1554 :     jb->val.datetime.typmod = typmod;
    1913            1554 :     jb->val.datetime.tz = tz;
    1914 ECB             : 
    1915 CBC        1554 :     return executeNextItem(cxt, jsp, &elem, jb, found, hasNext);
    1916                 : }
    1917 ECB             : 
    1918                 : /*
    1919                 :  * Implementation of .keyvalue() method.
    1920                 :  *
    1921                 :  * .keyvalue() method returns a sequence of object's key-value pairs in the
    1922                 :  * following format: '{ "key": key, "value": value, "id": id }'.
    1923                 :  *
    1924                 :  * "id" field is an object identifier which is constructed from the two parts:
    1925                 :  * base object id and its binary offset in base object's jsonb:
    1926                 :  * id = 10000000000 * base_object_id + obj_offset_in_base_object
    1927                 :  *
    1928                 :  * 10000000000 (10^10) -- is a first round decimal number greater than 2^32
    1929                 :  * (maximal offset in jsonb).  Decimal multiplier is used here to improve the
    1930                 :  * readability of identifiers.
    1931                 :  *
    1932                 :  * Base object is usually a root object of the path: context item '$' or path
    1933                 :  * variable '$var', literals can't produce objects for now.  But if the path
    1934                 :  * contains generated objects (.keyvalue() itself, for example), then they
    1935                 :  * become base object for the subsequent .keyvalue().
    1936                 :  *
    1937                 :  * Id of '$' is 0. Id of '$var' is its ordinal (positive) number in the list
    1938                 :  * of variables (see getJsonPathVariable()).  Ids for generated objects
    1939                 :  * are assigned using global counter JsonPathExecContext.lastGeneratedObjectId.
    1940                 :  */
    1941                 : static JsonPathExecResult
    1942 GIC          42 : executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
    1943                 :                       JsonbValue *jb, JsonValueList *found)
    1944 ECB             : {
    1945 GIC          42 :     JsonPathExecResult res = jperNotFound;
    1946                 :     JsonPathItem next;
    1947 ECB             :     JsonbContainer *jbc;
    1948                 :     JsonbValue  key;
    1949                 :     JsonbValue  val;
    1950                 :     JsonbValue  idval;
    1951                 :     JsonbValue  keystr;
    1952                 :     JsonbValue  valstr;
    1953                 :     JsonbValue  idstr;
    1954                 :     JsonbIterator *it;
    1955                 :     JsonbIteratorToken tok;
    1956                 :     int64       id;
    1957                 :     bool        hasNext;
    1958                 : 
    1959 GIC          42 :     if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
    1960              12 :         RETURN_ERROR(ereport(ERROR,
    1961 ECB             :                              (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
    1962                 :                               errmsg("jsonpath item method .%s() can only be applied to an object",
    1963                 :                                      jspOperationName(jsp->type)))));
    1964                 : 
    1965 GIC          30 :     jbc = jb->val.binary.data;
    1966                 : 
    1967 CBC          30 :     if (!JsonContainerSize(jbc))
    1968 GIC           9 :         return jperNotFound;    /* no key-value pairs */
    1969 ECB             : 
    1970 CBC          21 :     hasNext = jspGetNext(jsp, &next);
    1971                 : 
    1972              21 :     keystr.type = jbvString;
    1973 GIC          21 :     keystr.val.string.val = "key";
    1974 CBC          21 :     keystr.val.string.len = 3;
    1975 ECB             : 
    1976 CBC          21 :     valstr.type = jbvString;
    1977 GIC          21 :     valstr.val.string.val = "value";
    1978 CBC          21 :     valstr.val.string.len = 5;
    1979 ECB             : 
    1980 CBC          21 :     idstr.type = jbvString;
    1981 GIC          21 :     idstr.val.string.val = "id";
    1982 CBC          21 :     idstr.val.string.len = 2;
    1983 ECB             : 
    1984                 :     /* construct object id from its base object and offset inside that */
    1985 GIC          21 :     id = jb->type != jbvBinary ? 0 :
    1986              21 :         (int64) ((char *) jbc - (char *) cxt->baseObject.jbc);
    1987 CBC          21 :     id += (int64) cxt->baseObject.id * INT64CONST(10000000000);
    1988 ECB             : 
    1989 CBC          21 :     idval.type = jbvNumeric;
    1990 GIC          21 :     idval.val.numeric = int64_to_numeric(id);
    1991 ECB             : 
    1992 CBC          21 :     it = JsonbIteratorInit(jbc);
    1993                 : 
    1994              84 :     while ((tok = JsonbIteratorNext(&it, &key, true)) != WJB_DONE)
    1995                 :     {
    1996 ECB             :         JsonBaseObjectInfo baseObject;
    1997                 :         JsonbValue  obj;
    1998                 :         JsonbParseState *ps;
    1999                 :         JsonbValue *keyval;
    2000                 :         Jsonb      *jsonb;
    2001                 : 
    2002 GIC          69 :         if (tok != WJB_KEY)
    2003              36 :             continue;
    2004 ECB             : 
    2005 CBC          33 :         res = jperOk;
    2006                 : 
    2007              33 :         if (!hasNext && !found)
    2008 GIC           6 :             break;
    2009 ECB             : 
    2010 CBC          30 :         tok = JsonbIteratorNext(&it, &val, true);
    2011 GIC          30 :         Assert(tok == WJB_VALUE);
    2012 ECB             : 
    2013 CBC          30 :         ps = NULL;
    2014 GIC          30 :         pushJsonbValue(&ps, WJB_BEGIN_OBJECT, NULL);
    2015 ECB             : 
    2016 CBC          30 :         pushJsonbValue(&ps, WJB_KEY, &keystr);
    2017 GIC          30 :         pushJsonbValue(&ps, WJB_VALUE, &key);
    2018 ECB             : 
    2019 CBC          30 :         pushJsonbValue(&ps, WJB_KEY, &valstr);
    2020 GIC          30 :         pushJsonbValue(&ps, WJB_VALUE, &val);
    2021 ECB             : 
    2022 CBC          30 :         pushJsonbValue(&ps, WJB_KEY, &idstr);
    2023 GIC          30 :         pushJsonbValue(&ps, WJB_VALUE, &idval);
    2024 ECB             : 
    2025 CBC          30 :         keyval = pushJsonbValue(&ps, WJB_END_OBJECT, NULL);
    2026                 : 
    2027              30 :         jsonb = JsonbValueToJsonb(keyval);
    2028                 : 
    2029              30 :         JsonbInitBinary(&obj, jsonb);
    2030                 : 
    2031              30 :         baseObject = setBaseObject(cxt, &obj, cxt->lastGeneratedObjectId++);
    2032                 : 
    2033              30 :         res = executeNextItem(cxt, jsp, &next, &obj, found, true);
    2034                 : 
    2035              30 :         cxt->baseObject = baseObject;
    2036                 : 
    2037              30 :         if (jperIsError(res))
    2038 UIC           0 :             return res;
    2039 ECB             : 
    2040 GBC          30 :         if (res == jperOk && !found)
    2041 GIC           3 :             break;
    2042 ECB             :     }
    2043                 : 
    2044 GIC          21 :     return res;
    2045                 : }
    2046 ECB             : 
    2047                 : /*
    2048                 :  * Convert boolean execution status 'res' to a boolean JSON item and execute
    2049                 :  * next jsonpath.
    2050                 :  */
    2051                 : static JsonPathExecResult
    2052 GIC       51081 : appendBoolResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
    2053                 :                  JsonValueList *found, JsonPathBool res)
    2054 ECB             : {
    2055                 :     JsonPathItem next;
    2056                 :     JsonbValue  jbv;
    2057                 : 
    2058 GIC       51081 :     if (!jspGetNext(jsp, &next) && !found)
    2059               3 :         return jperOk;          /* found singleton boolean value */
    2060 ECB             : 
    2061 CBC       51078 :     if (res == jpbUnknown)
    2062                 :     {
    2063              15 :         jbv.type = jbvNull;
    2064                 :     }
    2065 ECB             :     else
    2066                 :     {
    2067 GIC       51063 :         jbv.type = jbvBool;
    2068           51063 :         jbv.val.boolean = res == jpbTrue;
    2069 ECB             :     }
    2070                 : 
    2071 GIC       51078 :     return executeNextItem(cxt, jsp, &next, &jbv, found, true);
    2072                 : }
    2073 ECB             : 
    2074                 : /*
    2075                 :  * Convert jsonpath's scalar or variable node to actual jsonb value.
    2076                 :  *
    2077                 :  * If node is a variable then its id returned, otherwise 0 returned.
    2078                 :  */
    2079                 : static void
    2080 GIC       27768 : getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
    2081                 :                 JsonbValue *value)
    2082 ECB             : {
    2083 GIC       27768 :     switch (item->type)
    2084                 :     {
    2085 CBC        3777 :         case jpiNull:
    2086 GIC        3777 :             value->type = jbvNull;
    2087 CBC        3777 :             break;
    2088             711 :         case jpiBool:
    2089             711 :             value->type = jbvBool;
    2090             711 :             value->val.boolean = jspGetBool(item);
    2091             711 :             break;
    2092            9678 :         case jpiNumeric:
    2093            9678 :             value->type = jbvNumeric;
    2094            9678 :             value->val.numeric = jspGetNumeric(item);
    2095            9678 :             break;
    2096           10977 :         case jpiString:
    2097           10977 :             value->type = jbvString;
    2098           21954 :             value->val.string.val = jspGetString(item,
    2099           10977 :                                                  &value->val.string.len);
    2100           10977 :             break;
    2101            2625 :         case jpiVariable:
    2102            2625 :             getJsonPathVariable(cxt, item, cxt->vars, value);
    2103            2610 :             return;
    2104 LBC           0 :         default:
    2105               0 :             elog(ERROR, "unexpected jsonpath item type");
    2106 EUB             :     }
    2107                 : }
    2108                 : 
    2109                 : /*
    2110                 :  * Get the value of variable passed to jsonpath executor
    2111                 :  */
    2112                 : static void
    2113 GIC        2625 : getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
    2114                 :                     Jsonb *vars, JsonbValue *value)
    2115 ECB             : {
    2116                 :     char       *varName;
    2117                 :     int         varNameLength;
    2118                 :     JsonbValue  tmp;
    2119                 :     JsonbValue *v;
    2120                 : 
    2121 GIC        2625 :     if (!vars)
    2122                 :     {
    2123 LBC           0 :         value->type = jbvNull;
    2124 UIC           0 :         return;
    2125 EUB             :     }
    2126                 : 
    2127 GIC        2625 :     Assert(variable->type == jpiVariable);
    2128            2625 :     varName = jspGetString(variable, &varNameLength);
    2129 CBC        2625 :     tmp.type = jbvString;
    2130            2625 :     tmp.val.string.val = varName;
    2131            2625 :     tmp.val.string.len = varNameLength;
    2132 ECB             : 
    2133 CBC        2625 :     v = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
    2134                 : 
    2135            2625 :     if (v)
    2136                 :     {
    2137            2610 :         *value = *v;
    2138 GIC        2610 :         pfree(v);
    2139 ECB             :     }
    2140                 :     else
    2141                 :     {
    2142 GIC          15 :         ereport(ERROR,
    2143                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    2144 ECB             :                  errmsg("could not find jsonpath variable \"%s\"",
    2145                 :                         pnstrdup(varName, varNameLength))));
    2146                 :     }
    2147                 : 
    2148 GIC        2610 :     JsonbInitBinary(&tmp, vars);
    2149            2610 :     setBaseObject(cxt, &tmp, 1);
    2150 ECB             : }
    2151                 : 
    2152                 : /**************** Support functions for JsonPath execution *****************/
    2153                 : 
    2154                 : /*
    2155                 :  * Returns the size of an array item, or -1 if item is not an array.
    2156                 :  */
    2157                 : static int
    2158 GIC         174 : JsonbArraySize(JsonbValue *jb)
    2159                 : {
    2160 CBC         174 :     Assert(jb->type != jbvArray);
    2161                 : 
    2162             174 :     if (jb->type == jbvBinary)
    2163                 :     {
    2164             153 :         JsonbContainer *jbc = jb->val.binary.data;
    2165                 : 
    2166             153 :         if (JsonContainerIsArray(jbc) && !JsonContainerIsScalar(jbc))
    2167 GIC         147 :             return JsonContainerSize(jbc);
    2168 ECB             :     }
    2169                 : 
    2170 GIC          27 :     return -1;
    2171                 : }
    2172 ECB             : 
    2173                 : /* Comparison predicate callback. */
    2174                 : static JsonPathBool
    2175 GIC        8280 : executeComparison(JsonPathItem *cmp, JsonbValue *lv, JsonbValue *rv, void *p)
    2176                 : {
    2177 CBC        8280 :     JsonPathExecContext *cxt = (JsonPathExecContext *) p;
    2178                 : 
    2179            8280 :     return compareItems(cmp->type, lv, rv, cxt->useTz);
    2180                 : }
    2181 ECB             : 
    2182                 : /*
    2183                 :  * Perform per-byte comparison of two strings.
    2184                 :  */
    2185                 : static int
    2186 GIC        1728 : binaryCompareStrings(const char *s1, int len1,
    2187                 :                      const char *s2, int len2)
    2188 ECB             : {
    2189                 :     int         cmp;
    2190                 : 
    2191 GIC        1728 :     cmp = memcmp(s1, s2, Min(len1, len2));
    2192                 : 
    2193 CBC        1728 :     if (cmp != 0)
    2194 GIC         984 :         return cmp;
    2195 ECB             : 
    2196 CBC         744 :     if (len1 == len2)
    2197 GIC         144 :         return 0;
    2198 ECB             : 
    2199 CBC         600 :     return len1 < len2 ? -1 : 1;
    2200                 : }
    2201 ECB             : 
    2202                 : /*
    2203                 :  * Compare two strings in the current server encoding using Unicode codepoint
    2204                 :  * collation.
    2205                 :  */
    2206                 : static int
    2207 GIC        1728 : compareStrings(const char *mbstr1, int mblen1,
    2208                 :                const char *mbstr2, int mblen2)
    2209 ECB             : {
    2210 GIC        3456 :     if (GetDatabaseEncoding() == PG_SQL_ASCII ||
    2211            1728 :         GetDatabaseEncoding() == PG_UTF8)
    2212 ECB             :     {
    2213                 :         /*
    2214                 :          * It's known property of UTF-8 strings that their per-byte comparison
    2215                 :          * result matches codepoints comparison result.  ASCII can be
    2216                 :          * considered as special case of UTF-8.
    2217                 :          */
    2218 GIC        1728 :         return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
    2219                 :     }
    2220 ECB             :     else
    2221                 :     {
    2222                 :         char       *utf8str1,
    2223                 :                    *utf8str2;
    2224                 :         int         cmp,
    2225                 :                     utf8len1,
    2226                 :                     utf8len2;
    2227                 : 
    2228                 :         /*
    2229                 :          * We have to convert other encodings to UTF-8 first, then compare.
    2230                 :          * Input strings may be not null-terminated and pg_server_to_any() may
    2231                 :          * return them "as is".  So, use strlen() only if there is real
    2232                 :          * conversion.
    2233                 :          */
    2234 UIC           0 :         utf8str1 = pg_server_to_any(mbstr1, mblen1, PG_UTF8);
    2235               0 :         utf8str2 = pg_server_to_any(mbstr2, mblen2, PG_UTF8);
    2236 UBC           0 :         utf8len1 = (mbstr1 == utf8str1) ? mblen1 : strlen(utf8str1);
    2237               0 :         utf8len2 = (mbstr2 == utf8str2) ? mblen2 : strlen(utf8str2);
    2238 EUB             : 
    2239 UBC           0 :         cmp = binaryCompareStrings(utf8str1, utf8len1, utf8str2, utf8len2);
    2240                 : 
    2241 EUB             :         /*
    2242                 :          * If pg_server_to_any() did no real conversion, then we actually
    2243                 :          * compared original strings.  So, we already done.
    2244                 :          */
    2245 UIC           0 :         if (mbstr1 == utf8str1 && mbstr2 == utf8str2)
    2246               0 :             return cmp;
    2247 EUB             : 
    2248                 :         /* Free memory if needed */
    2249 UIC           0 :         if (mbstr1 != utf8str1)
    2250               0 :             pfree(utf8str1);
    2251 UBC           0 :         if (mbstr2 != utf8str2)
    2252               0 :             pfree(utf8str2);
    2253 EUB             : 
    2254                 :         /*
    2255                 :          * When all Unicode codepoints are equal, return result of binary
    2256                 :          * comparison.  In some edge cases, same characters may have different
    2257                 :          * representations in encoding.  Then our behavior could diverge from
    2258                 :          * standard.  However, that allow us to do simple binary comparison
    2259                 :          * for "==" operator, which is performance critical in typical cases.
    2260                 :          * In future to implement strict standard conformance, we can do
    2261                 :          * normalization of input JSON strings.
    2262                 :          */
    2263 UIC           0 :         if (cmp == 0)
    2264               0 :             return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
    2265 EUB             :         else
    2266 UBC           0 :             return cmp;
    2267                 :     }
    2268 EUB             : }
    2269                 : 
    2270                 : /*
    2271                 :  * Compare two SQL/JSON items using comparison operation 'op'.
    2272                 :  */
    2273                 : static JsonPathBool
    2274 GIC        8280 : compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2, bool useTz)
    2275                 : {
    2276 ECB             :     int         cmp;
    2277                 :     bool        res;
    2278                 : 
    2279 GIC        8280 :     if (jb1->type != jb2->type)
    2280                 :     {
    2281 CBC        1485 :         if (jb1->type == jbvNull || jb2->type == jbvNull)
    2282                 : 
    2283 ECB             :             /*
    2284                 :              * Equality and order comparison of nulls to non-nulls returns
    2285                 :              * always false, but inequality comparison returns true.
    2286                 :              */
    2287 GIC        1362 :             return op == jpiNotEqual ? jpbTrue : jpbFalse;
    2288                 : 
    2289 ECB             :         /* Non-null items of different types are not comparable. */
    2290 GIC         123 :         return jpbUnknown;
    2291                 :     }
    2292 ECB             : 
    2293 GIC        6795 :     switch (jb1->type)
    2294                 :     {
    2295 CBC          93 :         case jbvNull:
    2296 GIC          93 :             cmp = 0;
    2297 CBC          93 :             break;
    2298             435 :         case jbvBool:
    2299             633 :             cmp = jb1->val.boolean == jb2->val.boolean ? 0 :
    2300             198 :                 jb1->val.boolean ? 1 : -1;
    2301             435 :             break;
    2302             582 :         case jbvNumeric:
    2303             582 :             cmp = compareNumeric(jb1->val.numeric, jb2->val.numeric);
    2304             582 :             break;
    2305            4965 :         case jbvString:
    2306            4965 :             if (op == jpiEqual)
    2307            3237 :                 return jb1->val.string.len != jb2->val.string.len ||
    2308            1791 :                     memcmp(jb1->val.string.val,
    2309            1791 :                            jb2->val.string.val,
    2310            3237 :                            jb1->val.string.len) ? jpbFalse : jpbTrue;
    2311 ECB             : 
    2312 CBC        1728 :             cmp = compareStrings(jb1->val.string.val, jb1->val.string.len,
    2313 GIC        1728 :                                  jb2->val.string.val, jb2->val.string.len);
    2314 CBC        1728 :             break;
    2315             714 :         case jbvDatetime:
    2316 ECB             :             {
    2317                 :                 bool        cast_error;
    2318                 : 
    2319 GIC         714 :                 cmp = compareDatetime(jb1->val.datetime.value,
    2320                 :                                       jb1->val.datetime.typid,
    2321 ECB             :                                       jb2->val.datetime.value,
    2322                 :                                       jb2->val.datetime.typid,
    2323                 :                                       useTz,
    2324                 :                                       &cast_error);
    2325                 : 
    2326 GIC         669 :                 if (cast_error)
    2327             126 :                     return jpbUnknown;
    2328 ECB             :             }
    2329 CBC         543 :             break;
    2330                 : 
    2331               6 :         case jbvBinary:
    2332                 :         case jbvArray:
    2333 ECB             :         case jbvObject:
    2334 GIC           6 :             return jpbUnknown;  /* non-scalars are not comparable */
    2335                 : 
    2336 LBC           0 :         default:
    2337 UIC           0 :             elog(ERROR, "invalid jsonb value type %d", jb1->type);
    2338 EUB             :     }
    2339                 : 
    2340 GIC        3381 :     switch (op)
    2341                 :     {
    2342 CBC         843 :         case jpiEqual:
    2343 GIC         843 :             res = (cmp == 0);
    2344 CBC         843 :             break;
    2345               3 :         case jpiNotEqual:
    2346               3 :             res = (cmp != 0);
    2347               3 :             break;
    2348             708 :         case jpiLess:
    2349             708 :             res = (cmp < 0);
    2350             708 :             break;
    2351             717 :         case jpiGreater:
    2352             717 :             res = (cmp > 0);
    2353             717 :             break;
    2354             438 :         case jpiLessOrEqual:
    2355             438 :             res = (cmp <= 0);
    2356             438 :             break;
    2357             672 :         case jpiGreaterOrEqual:
    2358             672 :             res = (cmp >= 0);
    2359             672 :             break;
    2360 LBC           0 :         default:
    2361               0 :             elog(ERROR, "unrecognized jsonpath operation: %d", op);
    2362 EUB             :             return jpbUnknown;
    2363                 :     }
    2364                 : 
    2365 GIC        3381 :     return res ? jpbTrue : jpbFalse;
    2366                 : }
    2367 ECB             : 
    2368                 : /* Compare two numerics */
    2369                 : static int
    2370 GIC         582 : compareNumeric(Numeric a, Numeric b)
    2371                 : {
    2372 CBC         582 :     return DatumGetInt32(DirectFunctionCall2(numeric_cmp,
    2373                 :                                              NumericGetDatum(a),
    2374 ECB             :                                              NumericGetDatum(b)));
    2375                 : }
    2376                 : 
    2377                 : static JsonbValue *
    2378 GIC       55389 : copyJsonbValue(JsonbValue *src)
    2379                 : {
    2380 CBC       55389 :     JsonbValue *dst = palloc(sizeof(*dst));
    2381                 : 
    2382           55389 :     *dst = *src;
    2383                 : 
    2384           55389 :     return dst;
    2385                 : }
    2386 ECB             : 
    2387                 : /*
    2388                 :  * Execute array subscript expression and convert resulting numeric item to
    2389                 :  * the integer type with truncation.
    2390                 :  */
    2391                 : static JsonPathExecResult
    2392 GIC         159 : getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
    2393                 :               int32 *index)
    2394 ECB             : {
    2395                 :     JsonbValue *jbv;
    2396 GIC         159 :     JsonValueList found = {0};
    2397             159 :     JsonPathExecResult res = executeItem(cxt, jsp, jb, &found);
    2398 ECB             :     Datum       numeric_index;
    2399 CBC         156 :     bool        have_error = false;
    2400                 : 
    2401             156 :     if (jperIsError(res))
    2402 UIC           0 :         return res;
    2403 ECB             : 
    2404 GBC         306 :     if (JsonValueListLength(&found) != 1 ||
    2405 GIC         150 :         !(jbv = getScalar(JsonValueListHead(&found), jbvNumeric)))
    2406 CBC          12 :         RETURN_ERROR(ereport(ERROR,
    2407 ECB             :                              (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
    2408                 :                               errmsg("jsonpath array subscript is not a single numeric value"))));
    2409                 : 
    2410 GIC         144 :     numeric_index = DirectFunctionCall2(numeric_trunc,
    2411                 :                                         NumericGetDatum(jbv->val.numeric),
    2412 ECB             :                                         Int32GetDatum(0));
    2413                 : 
    2414 GIC         144 :     *index = numeric_int4_opt_error(DatumGetNumeric(numeric_index),
    2415                 :                                     &have_error);
    2416 ECB             : 
    2417 GIC         144 :     if (have_error)
    2418              12 :         RETURN_ERROR(ereport(ERROR,
    2419 ECB             :                              (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
    2420                 :                               errmsg("jsonpath array subscript is out of integer range"))));
    2421                 : 
    2422 GIC         132 :     return jperOk;
    2423                 : }
    2424 ECB             : 
    2425                 : /* Save base object and its id needed for the execution of .keyvalue(). */
    2426                 : static JsonBaseObjectInfo
    2427 GIC      103845 : setBaseObject(JsonPathExecContext *cxt, JsonbValue *jbv, int32 id)
    2428                 : {
    2429 CBC      103845 :     JsonBaseObjectInfo baseObject = cxt->baseObject;
    2430                 : 
    2431          103845 :     cxt->baseObject.jbc = jbv->type != jbvBinary ? NULL :
    2432                 :         (JsonbContainer *) jbv->val.binary.data;
    2433          103845 :     cxt->baseObject.id = id;
    2434                 : 
    2435          103845 :     return baseObject;
    2436                 : }
    2437 ECB             : 
    2438                 : static void
    2439 GIC      124734 : JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv)
    2440                 : {
    2441 CBC      124734 :     if (jvl->singleton)
    2442                 :     {
    2443             492 :         jvl->list = list_make2(jvl->singleton, jbv);
    2444 GIC         492 :         jvl->singleton = NULL;
    2445 ECB             :     }
    2446 CBC      124242 :     else if (!jvl->list)
    2447 GIC      123792 :         jvl->singleton = jbv;
    2448 ECB             :     else
    2449 CBC         450 :         jvl->list = lappend(jvl->list, jbv);
    2450 GIC      124734 : }
    2451 ECB             : 
    2452                 : static int
    2453 GIC       51585 : JsonValueListLength(const JsonValueList *jvl)
    2454                 : {
    2455 CBC       51585 :     return jvl->singleton ? 1 : list_length(jvl->list);
    2456                 : }
    2457 ECB             : 
    2458                 : static bool
    2459 GIC           9 : JsonValueListIsEmpty(JsonValueList *jvl)
    2460                 : {
    2461 GNC           9 :     return !jvl->singleton && (jvl->list == NIL);
    2462                 : }
    2463 ECB             : 
    2464                 : static JsonbValue *
    2465 GIC       51510 : JsonValueListHead(JsonValueList *jvl)
    2466                 : {
    2467 CBC       51510 :     return jvl->singleton ? jvl->singleton : linitial(jvl->list);
    2468                 : }
    2469 ECB             : 
    2470                 : static List *
    2471 GIC         708 : JsonValueListGetList(JsonValueList *jvl)
    2472                 : {
    2473 CBC         708 :     if (jvl->singleton)
    2474 GIC         417 :         return list_make1(jvl->singleton);
    2475 ECB             : 
    2476 CBC         291 :     return jvl->list;
    2477                 : }
    2478 ECB             : 
    2479                 : static void
    2480 GIC       93621 : JsonValueListInitIterator(const JsonValueList *jvl, JsonValueListIterator *it)
    2481                 : {
    2482 CBC       93621 :     if (jvl->singleton)
    2483                 :     {
    2484           54891 :         it->value = jvl->singleton;
    2485 GIC       54891 :         it->list = NIL;
    2486 CBC       54891 :         it->next = NULL;
    2487 ECB             :     }
    2488 CBC       38730 :     else if (jvl->list != NIL)
    2489                 :     {
    2490             309 :         it->value = (JsonbValue *) linitial(jvl->list);
    2491 GIC         309 :         it->list = jvl->list;
    2492 CBC         309 :         it->next = list_second_cell(jvl->list);
    2493 ECB             :     }
    2494                 :     else
    2495                 :     {
    2496 GIC       38421 :         it->value = NULL;
    2497           38421 :         it->list = NIL;
    2498 CBC       38421 :         it->next = NULL;
    2499 ECB             :     }
    2500 CBC       93621 : }
    2501                 : 
    2502 ECB             : /*
    2503                 :  * Get the next item from the sequence advancing iterator.
    2504                 :  */
    2505                 : static JsonbValue *
    2506 GIC      144177 : JsonValueListNext(const JsonValueList *jvl, JsonValueListIterator *it)
    2507                 : {
    2508 CBC      144177 :     JsonbValue *result = it->value;
    2509                 : 
    2510          144177 :     if (it->next)
    2511                 :     {
    2512             534 :         it->value = lfirst(it->next);
    2513 GIC         534 :         it->next = lnext(it->list, it->next);
    2514 ECB             :     }
    2515                 :     else
    2516                 :     {
    2517 GIC      143643 :         it->value = NULL;
    2518                 :     }
    2519 ECB             : 
    2520 GIC      144177 :     return result;
    2521                 : }
    2522 ECB             : 
    2523                 : /*
    2524                 :  * Initialize a binary JsonbValue with the given jsonb container.
    2525                 :  */
    2526                 : static JsonbValue *
    2527 GIC       97401 : JsonbInitBinary(JsonbValue *jbv, Jsonb *jb)
    2528                 : {
    2529 CBC       97401 :     jbv->type = jbvBinary;
    2530 GIC       97401 :     jbv->val.binary.data = &jb->root;
    2531 CBC       97401 :     jbv->val.binary.len = VARSIZE_ANY_EXHDR(jb);
    2532 ECB             : 
    2533 CBC       97401 :     return jbv;
    2534                 : }
    2535 ECB             : 
    2536                 : /*
    2537                 :  * Returns jbv* type of JsonbValue. Note, it never returns jbvBinary as is.
    2538                 :  */
    2539                 : static int
    2540 GIC      130671 : JsonbType(JsonbValue *jb)
    2541                 : {
    2542 CBC      130671 :     int         type = jb->type;
    2543                 : 
    2544          130671 :     if (jb->type == jbvBinary)
    2545                 :     {
    2546           89724 :         JsonbContainer *jbc = (void *) jb->val.binary.data;
    2547                 : 
    2548 ECB             :         /* Scalars should be always extracted during jsonpath execution. */
    2549 GIC       89724 :         Assert(!JsonContainerIsScalar(jbc));
    2550                 : 
    2551 CBC       89724 :         if (JsonContainerIsObject(jbc))
    2552 GIC       88902 :             type = jbvObject;
    2553 CBC         822 :         else if (JsonContainerIsArray(jbc))
    2554             822 :             type = jbvArray;
    2555 ECB             :         else
    2556 LBC           0 :             elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
    2557                 :     }
    2558 EUB             : 
    2559 GIC      130671 :     return type;
    2560                 : }
    2561 ECB             : 
    2562                 : /* Get scalar of given type or NULL on type mismatch */
    2563                 : static JsonbValue *
    2564 GIC        2580 : getScalar(JsonbValue *scalar, enum jbvType type)
    2565                 : {
    2566 ECB             :     /* Scalars should be always extracted during jsonpath execution. */
    2567 GIC        2580 :     Assert(scalar->type != jbvBinary ||
    2568                 :            !JsonContainerIsScalar(scalar->val.binary.data));
    2569 ECB             : 
    2570 GIC        2580 :     return scalar->type == type ? scalar : NULL;
    2571                 : }
    2572 ECB             : 
    2573                 : /* Construct a JSON array from the item list */
    2574                 : static JsonbValue *
    2575 GIC          21 : wrapItemsInArray(const JsonValueList *items)
    2576                 : {
    2577 CBC          21 :     JsonbParseState *ps = NULL;
    2578                 :     JsonValueListIterator it;
    2579 ECB             :     JsonbValue *jbv;
    2580                 : 
    2581 GIC          21 :     pushJsonbValue(&ps, WJB_BEGIN_ARRAY, NULL);
    2582                 : 
    2583 CBC          21 :     JsonValueListInitIterator(items, &it);
    2584 GIC          42 :     while ((jbv = JsonValueListNext(items, &it)))
    2585 CBC          21 :         pushJsonbValue(&ps, WJB_ELEM, jbv);
    2586 ECB             : 
    2587 CBC          21 :     return pushJsonbValue(&ps, WJB_END_ARRAY, NULL);
    2588                 : }
    2589 ECB             : 
    2590                 : /* Check if the timezone required for casting from type1 to type2 is used */
    2591                 : static void
    2592 GIC         189 : checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
    2593                 : {
    2594 CBC         189 :     if (!useTz)
    2595 GIC          45 :         ereport(ERROR,
    2596 ECB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    2597                 :                  errmsg("cannot convert value from %s to %s without time zone usage",
    2598                 :                         type1, type2),
    2599                 :                  errhint("Use *_tz() function for time zone support.")));
    2600 GIC         144 : }
    2601                 : 
    2602 ECB             : /* Convert time datum to timetz datum */
    2603                 : static Datum
    2604 GIC          72 : castTimeToTimeTz(Datum time, bool useTz)
    2605                 : {
    2606 CBC          72 :     checkTimezoneIsUsedForCast(useTz, "time", "timetz");
    2607                 : 
    2608              54 :     return DirectFunctionCall1(time_timetz, time);
    2609                 : }
    2610 ECB             : 
    2611                 : /*
    2612                 :  * Compare date to timestamp.
    2613                 :  * Note that this doesn't involve any timezone considerations.
    2614                 :  */
    2615                 : static int
    2616 GIC          57 : cmpDateToTimestamp(DateADT date1, Timestamp ts2, bool useTz)
    2617                 : {
    2618 CBC          57 :     return date_cmp_timestamp_internal(date1, ts2);
    2619                 : }
    2620 ECB             : 
    2621                 : /*
    2622                 :  * Compare date to timestamptz.
    2623                 :  */
    2624                 : static int
    2625 GIC          45 : cmpDateToTimestampTz(DateADT date1, TimestampTz tstz2, bool useTz)
    2626                 : {
    2627 CBC          45 :     checkTimezoneIsUsedForCast(useTz, "date", "timestamptz");
    2628                 : 
    2629              36 :     return date_cmp_timestamptz_internal(date1, tstz2);
    2630                 : }
    2631 ECB             : 
    2632                 : /*
    2633                 :  * Compare timestamp to timestamptz.
    2634                 :  */
    2635                 : static int
    2636 GIC          72 : cmpTimestampToTimestampTz(Timestamp ts1, TimestampTz tstz2, bool useTz)
    2637                 : {
    2638 CBC          72 :     checkTimezoneIsUsedForCast(useTz, "timestamp", "timestamptz");
    2639                 : 
    2640              54 :     return timestamp_cmp_timestamptz_internal(ts1, tstz2);
    2641                 : }
    2642 ECB             : 
    2643                 : /*
    2644                 :  * Cross-type comparison of two datetime SQL/JSON items.  If items are
    2645                 :  * uncomparable *cast_error flag is set, otherwise *cast_error is unset.
    2646                 :  * If the cast requires timezone and it is not used, then explicit error is thrown.
    2647                 :  */
    2648                 : static int
    2649 GIC         714 : compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
    2650                 :                 bool useTz, bool *cast_error)
    2651 ECB             : {
    2652                 :     PGFunction  cmpfunc;
    2653                 : 
    2654 GIC         714 :     *cast_error = false;
    2655                 : 
    2656 CBC         714 :     switch (typid1)
    2657                 :     {
    2658             111 :         case DATEOID:
    2659                 :             switch (typid2)
    2660 ECB             :             {
    2661 GIC          54 :                 case DATEOID:
    2662              54 :                     cmpfunc = date_cmp;
    2663 ECB             : 
    2664 CBC          54 :                     break;
    2665                 : 
    2666              21 :                 case TIMESTAMPOID:
    2667 GIC          21 :                     return cmpDateToTimestamp(DatumGetDateADT(val1),
    2668 ECB             :                                               DatumGetTimestamp(val2),
    2669                 :                                               useTz);
    2670                 : 
    2671 GIC          18 :                 case TIMESTAMPTZOID:
    2672              18 :                     return cmpDateToTimestampTz(DatumGetDateADT(val1),
    2673 ECB             :                                                 DatumGetTimestampTz(val2),
    2674                 :                                                 useTz);
    2675                 : 
    2676 GIC          18 :                 case TIMEOID:
    2677                 :                 case TIMETZOID:
    2678 CBC          18 :                     *cast_error = true; /* uncomparable types */
    2679 GIC          18 :                     return 0;
    2680 ECB             : 
    2681 LBC           0 :                 default:
    2682 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
    2683 EUB             :                          typid2);
    2684                 :             }
    2685 GIC          54 :             break;
    2686                 : 
    2687 CBC         126 :         case TIMEOID:
    2688                 :             switch (typid2)
    2689 ECB             :             {
    2690 GIC          54 :                 case TIMEOID:
    2691              54 :                     cmpfunc = time_cmp;
    2692 ECB             : 
    2693 CBC          54 :                     break;
    2694                 : 
    2695              36 :                 case TIMETZOID:
    2696 GIC          36 :                     val1 = castTimeToTimeTz(val1, useTz);
    2697 CBC          27 :                     cmpfunc = timetz_cmp;
    2698 ECB             : 
    2699 CBC          27 :                     break;
    2700                 : 
    2701              36 :                 case DATEOID:
    2702                 :                 case TIMESTAMPOID:
    2703 ECB             :                 case TIMESTAMPTZOID:
    2704 GIC          36 :                     *cast_error = true; /* uncomparable types */
    2705              36 :                     return 0;
    2706 ECB             : 
    2707 LBC           0 :                 default:
    2708 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
    2709 EUB             :                          typid2);
    2710                 :             }
    2711 GIC          81 :             break;
    2712                 : 
    2713 CBC         162 :         case TIMETZOID:
    2714                 :             switch (typid2)
    2715 ECB             :             {
    2716 GIC          36 :                 case TIMEOID:
    2717              36 :                     val2 = castTimeToTimeTz(val2, useTz);
    2718 CBC          27 :                     cmpfunc = timetz_cmp;
    2719 ECB             : 
    2720 CBC          27 :                     break;
    2721                 : 
    2722              90 :                 case TIMETZOID:
    2723 GIC          90 :                     cmpfunc = timetz_cmp;
    2724 ECB             : 
    2725 CBC          90 :                     break;
    2726                 : 
    2727              36 :                 case DATEOID:
    2728                 :                 case TIMESTAMPOID:
    2729 ECB             :                 case TIMESTAMPTZOID:
    2730 GIC          36 :                     *cast_error = true; /* uncomparable types */
    2731              36 :                     return 0;
    2732 ECB             : 
    2733 LBC           0 :                 default:
    2734 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
    2735 EUB             :                          typid2);
    2736                 :             }
    2737 GIC         117 :             break;
    2738                 : 
    2739 CBC         144 :         case TIMESTAMPOID:
    2740                 :             switch (typid2)
    2741 ECB             :             {
    2742 GIC          36 :                 case DATEOID:
    2743              36 :                     return -cmpDateToTimestamp(DatumGetDateADT(val2),
    2744 ECB             :                                                DatumGetTimestamp(val1),
    2745                 :                                                useTz);
    2746                 : 
    2747 GIC          54 :                 case TIMESTAMPOID:
    2748              54 :                     cmpfunc = timestamp_cmp;
    2749 ECB             : 
    2750 CBC          54 :                     break;
    2751                 : 
    2752              36 :                 case TIMESTAMPTZOID:
    2753 GIC          36 :                     return cmpTimestampToTimestampTz(DatumGetTimestamp(val1),
    2754 ECB             :                                                      DatumGetTimestampTz(val2),
    2755                 :                                                      useTz);
    2756                 : 
    2757 GIC          18 :                 case TIMEOID:
    2758                 :                 case TIMETZOID:
    2759 CBC          18 :                     *cast_error = true; /* uncomparable types */
    2760 GIC          18 :                     return 0;
    2761 ECB             : 
    2762 LBC           0 :                 default:
    2763 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
    2764 EUB             :                          typid2);
    2765                 :             }
    2766 GIC          54 :             break;
    2767                 : 
    2768 CBC         171 :         case TIMESTAMPTZOID:
    2769                 :             switch (typid2)
    2770 ECB             :             {
    2771 GIC          27 :                 case DATEOID:
    2772              27 :                     return -cmpDateToTimestampTz(DatumGetDateADT(val2),
    2773 ECB             :                                                  DatumGetTimestampTz(val1),
    2774                 :                                                  useTz);
    2775                 : 
    2776 GIC          36 :                 case TIMESTAMPOID:
    2777              36 :                     return -cmpTimestampToTimestampTz(DatumGetTimestamp(val2),
    2778 ECB             :                                                       DatumGetTimestampTz(val1),
    2779                 :                                                       useTz);
    2780                 : 
    2781 GIC          90 :                 case TIMESTAMPTZOID:
    2782              90 :                     cmpfunc = timestamp_cmp;
    2783 ECB             : 
    2784 CBC          90 :                     break;
    2785                 : 
    2786              18 :                 case TIMEOID:
    2787                 :                 case TIMETZOID:
    2788              18 :                     *cast_error = true; /* uncomparable types */
    2789 GIC          18 :                     return 0;
    2790 ECB             : 
    2791 LBC           0 :                 default:
    2792 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
    2793 EUB             :                          typid2);
    2794                 :             }
    2795 GIC          90 :             break;
    2796                 : 
    2797 LBC           0 :         default:
    2798 UIC           0 :             elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u", typid1);
    2799 EUB             :     }
    2800                 : 
    2801 GIC         396 :     if (*cast_error)
    2802 UIC           0 :         return 0;               /* cast error */
    2803 ECB             : 
    2804 GBC         396 :     return DatumGetInt32(DirectFunctionCall2(cmpfunc, val1, val2));
    2805                 : }
        

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