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 17:13:01 Functions: 93.8 % 64 60 4 60 4 59 1
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 3 3 2 1
Legend: Lines: hit not hit (120,180] days: 100.0 % 11 11 11
(180,240] days: 90.9 % 22 20 1 1 15 1 4 6
(240..) days: 92.8 % 1001 929 28 35 9 11 526 392 54 523
Function coverage date bins:
(180,240] days: 50.0 % 2 1 1 1
(240..) days: 47.2 % 125 59 4 59 4 58

 Age         Owner                  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
 1292 akorotkov                 273 GIC       43005 : jsonb_path_exists_internal(FunctionCallInfo fcinfo, bool tz)
 1485 akorotkov                 274 ECB             : {
 1485 akorotkov                 275 GIC       43005 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
 1485 akorotkov                 276 CBC       43005 :     JsonPath   *jp = PG_GETARG_JSONPATH_P(1);
 1485 akorotkov                 277 ECB             :     JsonPathExecResult res;
 1485 akorotkov                 278 GIC       43005 :     Jsonb      *vars = NULL;
 1485 akorotkov                 279 CBC       43005 :     bool        silent = true;
 1485 akorotkov                 280 ECB             : 
 1485 akorotkov                 281 GIC       43005 :     if (PG_NARGS() == 4)
 1485 akorotkov                 282 ECB             :     {
 1485 akorotkov                 283 GIC          27 :         vars = PG_GETARG_JSONB_P(2);
 1485 akorotkov                 284 CBC          27 :         silent = PG_GETARG_BOOL(3);
 1485 akorotkov                 285 ECB             :     }
                                286                 : 
  220 andrew                    287 GIC       43005 :     res = executeJsonPath(jp, vars, jb, !silent, NULL, tz);
 1485 akorotkov                 288 ECB             : 
 1485 akorotkov                 289 GIC       42999 :     PG_FREE_IF_COPY(jb, 0);
 1485 akorotkov                 290 CBC       42999 :     PG_FREE_IF_COPY(jp, 1);
 1485 akorotkov                 291 ECB             : 
 1485 akorotkov                 292 GIC       42999 :     if (jperIsError(res))
 1485 akorotkov                 293 CBC          27 :         PG_RETURN_NULL();
 1485 akorotkov                 294 ECB             : 
 1485 akorotkov                 295 GIC       42972 :     PG_RETURN_BOOL(res == jperOk);
 1485 akorotkov                 296 ECB             : }
                                297                 : 
                                298                 : Datum
 1292 akorotkov                 299 GIC          27 : jsonb_path_exists(PG_FUNCTION_ARGS)
 1292 akorotkov                 300 ECB             : {
 1292 akorotkov                 301 GIC          27 :     return jsonb_path_exists_internal(fcinfo, false);
 1292 akorotkov                 302 ECB             : }
                                303                 : 
                                304                 : Datum
 1292 akorotkov                 305 UIC           0 : jsonb_path_exists_tz(PG_FUNCTION_ARGS)
 1292 akorotkov                 306 EUB             : {
 1292 akorotkov                 307 UIC           0 :     return jsonb_path_exists_internal(fcinfo, true);
 1292 akorotkov                 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
 1485 akorotkov                 316 GIC       42978 : jsonb_path_exists_opr(PG_FUNCTION_ARGS)
 1485 akorotkov                 317 ECB             : {
                                318                 :     /* just call the other one -- it can handle both cases */
 1292 akorotkov                 319 GIC       42978 :     return jsonb_path_exists_internal(fcinfo, false);
 1485 akorotkov                 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
 1292 akorotkov                 328 GIC       48957 : jsonb_path_match_internal(FunctionCallInfo fcinfo, bool tz)
 1485 akorotkov                 329 ECB             : {
 1485 akorotkov                 330 GIC       48957 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
 1485 akorotkov                 331 CBC       48957 :     JsonPath   *jp = PG_GETARG_JSONPATH_P(1);
 1483                           332           48957 :     JsonValueList found = {0};
 1485                           333           48957 :     Jsonb      *vars = NULL;
                                334           48957 :     bool        silent = true;
 1485 akorotkov                 335 ECB             : 
 1485 akorotkov                 336 GIC       48957 :     if (PG_NARGS() == 4)
 1485 akorotkov                 337 ECB             :     {
 1485 akorotkov                 338 GIC          63 :         vars = PG_GETARG_JSONB_P(2);
 1485 akorotkov                 339 CBC          63 :         silent = PG_GETARG_BOOL(3);
 1485 akorotkov                 340 ECB             :     }
                                341                 : 
  220 andrew                    342 GIC       48957 :     (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
 1485 akorotkov                 343 ECB             : 
 1485 akorotkov                 344 GIC       48951 :     PG_FREE_IF_COPY(jb, 0);
 1485 akorotkov                 345 CBC       48951 :     PG_FREE_IF_COPY(jp, 1);
 1485 akorotkov                 346 ECB             : 
 1469 akorotkov                 347 GIC       48951 :     if (JsonValueListLength(&found) == 1)
 1469 akorotkov                 348 ECB             :     {
 1469 akorotkov                 349 GIC       48936 :         JsonbValue *jbv = JsonValueListHead(&found);
 1469 akorotkov                 350 ECB             : 
 1469 akorotkov                 351 GIC       48936 :         if (jbv->type == jbvBool)
 1469 akorotkov                 352 CBC       48900 :             PG_RETURN_BOOL(jbv->val.boolean);
 1469 akorotkov                 353 ECB             : 
 1469 akorotkov                 354 GIC          36 :         if (jbv->type == jbvNull)
 1469 akorotkov                 355 CBC          12 :             PG_RETURN_NULL();
 1469 akorotkov                 356 ECB             :     }
                                357                 : 
 1469 akorotkov                 358 GIC          39 :     if (!silent)
 1469 akorotkov                 359 CBC          18 :         ereport(ERROR,
 1326 peter                     360 ECB             :                 (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
                                361                 :                  errmsg("single boolean result is expected")));
                                362                 : 
 1469 akorotkov                 363 GIC          21 :     PG_RETURN_NULL();
 1485 akorotkov                 364 ECB             : }
                                365                 : 
                                366                 : Datum
 1292 akorotkov                 367 GIC          63 : jsonb_path_match(PG_FUNCTION_ARGS)
 1292 akorotkov                 368 ECB             : {
 1292 akorotkov                 369 GIC          63 :     return jsonb_path_match_internal(fcinfo, false);
 1292 akorotkov                 370 ECB             : }
                                371                 : 
                                372                 : Datum
 1292 akorotkov                 373 UIC           0 : jsonb_path_match_tz(PG_FUNCTION_ARGS)
 1292 akorotkov                 374 EUB             : {
 1292 akorotkov                 375 UIC           0 :     return jsonb_path_match_internal(fcinfo, true);
 1292 akorotkov                 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
 1485 akorotkov                 384 GIC       48894 : jsonb_path_match_opr(PG_FUNCTION_ARGS)
 1485 akorotkov                 385 ECB             : {
                                386                 :     /* just call the other one -- it can handle both cases */
 1292 akorotkov                 387 GIC       48894 :     return jsonb_path_match_internal(fcinfo, false);
 1485 akorotkov                 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
 1292 akorotkov                 396 GIC        1809 : jsonb_path_query_internal(FunctionCallInfo fcinfo, bool tz)
 1485 akorotkov                 397 ECB             : {
                                398                 :     FuncCallContext *funcctx;
                                399                 :     List       *found;
                                400                 :     JsonbValue *v;
                                401                 :     ListCell   *c;
                                402                 : 
 1485 akorotkov                 403 GIC        1809 :     if (SRF_IS_FIRSTCALL())
 1485 akorotkov                 404 ECB             :     {
                                405                 :         JsonPath   *jp;
                                406                 :         Jsonb      *jb;
                                407                 :         MemoryContext oldcontext;
                                408                 :         Jsonb      *vars;
                                409                 :         bool        silent;
 1483 akorotkov                 410 GIC         936 :         JsonValueList found = {0};
 1485 akorotkov                 411 ECB             : 
 1485 akorotkov                 412 GIC         936 :         funcctx = SRF_FIRSTCALL_INIT();
 1485 akorotkov                 413 CBC         936 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
 1485 akorotkov                 414 ECB             : 
 1485 akorotkov                 415 GIC         936 :         jb = PG_GETARG_JSONB_P_COPY(0);
 1485 akorotkov                 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);
 1485 akorotkov                 419 ECB             : 
  220 andrew                    420 GIC         936 :         (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
 1485 akorotkov                 421 ECB             : 
 1485 akorotkov                 422 GIC         708 :         funcctx->user_fctx = JsonValueListGetList(&found);
 1485 akorotkov                 423 ECB             : 
 1485 akorotkov                 424 GIC         708 :         MemoryContextSwitchTo(oldcontext);
 1485 akorotkov                 425 ECB             :     }
                                426                 : 
 1485 akorotkov                 427 GIC        1581 :     funcctx = SRF_PERCALL_SETUP();
 1485 akorotkov                 428 CBC        1581 :     found = funcctx->user_fctx;
 1485 akorotkov                 429 ECB             : 
 1485 akorotkov                 430 GIC        1581 :     c = list_head(found);
 1485 akorotkov                 431 ECB             : 
 1485 akorotkov                 432 GIC        1581 :     if (c == NULL)
 1485 akorotkov                 433 CBC         708 :         SRF_RETURN_DONE(funcctx);
 1485 akorotkov                 434 ECB             : 
 1485 akorotkov                 435 GIC         873 :     v = lfirst(c);
 1485 akorotkov                 436 CBC         873 :     funcctx->user_fctx = list_delete_first(found);
 1485 akorotkov                 437 ECB             : 
 1485 akorotkov                 438 GIC         873 :     SRF_RETURN_NEXT(funcctx, JsonbPGetDatum(JsonbValueToJsonb(v)));
 1485 akorotkov                 439 ECB             : }
                                440                 : 
                                441                 : Datum
 1292 akorotkov                 442 GIC        1617 : jsonb_path_query(PG_FUNCTION_ARGS)
 1292 akorotkov                 443 ECB             : {
 1292 akorotkov                 444 GIC        1617 :     return jsonb_path_query_internal(fcinfo, false);
 1292 akorotkov                 445 ECB             : }
                                446                 : 
                                447                 : Datum
 1292 akorotkov                 448 GIC         192 : jsonb_path_query_tz(PG_FUNCTION_ARGS)
 1292 akorotkov                 449 ECB             : {
 1292 akorotkov                 450 GIC         192 :     return jsonb_path_query_internal(fcinfo, true);
 1292 akorotkov                 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
 1292 akorotkov                 459 GIC          24 : jsonb_path_query_array_internal(FunctionCallInfo fcinfo, bool tz)
 1485 akorotkov                 460 ECB             : {
 1485 akorotkov                 461 GIC          24 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
 1485 akorotkov                 462 CBC          24 :     JsonPath   *jp = PG_GETARG_JSONPATH_P(1);
 1483                           463              24 :     JsonValueList found = {0};
 1485                           464              24 :     Jsonb      *vars = PG_GETARG_JSONB_P(2);
                                465              24 :     bool        silent = PG_GETARG_BOOL(3);
 1485 akorotkov                 466 ECB             : 
  220 andrew                    467 GIC          24 :     (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
 1485 akorotkov                 468 ECB             : 
 1485 akorotkov                 469 GIC          21 :     PG_RETURN_JSONB_P(JsonbValueToJsonb(wrapItemsInArray(&found)));
 1485 akorotkov                 470 ECB             : }
                                471                 : 
                                472                 : Datum
 1292 akorotkov                 473 GIC          24 : jsonb_path_query_array(PG_FUNCTION_ARGS)
 1292 akorotkov                 474 ECB             : {
 1292 akorotkov                 475 GIC          24 :     return jsonb_path_query_array_internal(fcinfo, false);
 1292 akorotkov                 476 ECB             : }
                                477                 : 
                                478                 : Datum
 1292 akorotkov                 479 UIC           0 : jsonb_path_query_array_tz(PG_FUNCTION_ARGS)
 1292 akorotkov                 480 EUB             : {
 1292 akorotkov                 481 UIC           0 :     return jsonb_path_query_array_internal(fcinfo, true);
 1292 akorotkov                 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
 1292 akorotkov                 490 GIC        2187 : jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz)
 1485 akorotkov                 491 ECB             : {
 1485 akorotkov                 492 GIC        2187 :     Jsonb      *jb = PG_GETARG_JSONB_P(0);
 1485 akorotkov                 493 CBC        2187 :     JsonPath   *jp = PG_GETARG_JSONPATH_P(1);
 1483                           494            2187 :     JsonValueList found = {0};
 1485                           495            2187 :     Jsonb      *vars = PG_GETARG_JSONB_P(2);
                                496            2187 :     bool        silent = PG_GETARG_BOOL(3);
 1485 akorotkov                 497 ECB             : 
  220 andrew                    498 GIC        2187 :     (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
 1485 akorotkov                 499 ECB             : 
 1485 akorotkov                 500 GIC        2181 :     if (JsonValueListLength(&found) >= 1)
 1485 akorotkov                 501 CBC        2175 :         PG_RETURN_JSONB_P(JsonbValueToJsonb(JsonValueListHead(&found)));
 1485 akorotkov                 502 ECB             :     else
 1485 akorotkov                 503 GIC           6 :         PG_RETURN_NULL();
 1485 akorotkov                 504 ECB             : }
                                505                 : 
                                506                 : Datum
 1292 akorotkov                 507 GIC        2187 : jsonb_path_query_first(PG_FUNCTION_ARGS)
 1292 akorotkov                 508 ECB             : {
 1292 akorotkov                 509 GIC        2187 :     return jsonb_path_query_first_internal(fcinfo, false);
 1292 akorotkov                 510 ECB             : }
                                511                 : 
                                512                 : Datum
 1292 akorotkov                 513 UIC           0 : jsonb_path_query_first_tz(PG_FUNCTION_ARGS)
 1292 akorotkov                 514 EUB             : {
 1292 akorotkov                 515 UIC           0 :     return jsonb_path_query_first_internal(fcinfo, true);
 1292 akorotkov                 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
  220 andrew                    540 GIC       95109 : executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
  220 andrew                    541 ECB             :                 JsonValueList *result, bool useTz)
                                542                 : {
                                543                 :     JsonPathExecContext cxt;
                                544                 :     JsonPathExecResult res;
                                545                 :     JsonPathItem jsp;
                                546                 :     JsonbValue  jbv;
                                547                 : 
 1485 akorotkov                 548 GIC       95109 :     jspInit(&jsp, path);
 1485 akorotkov                 549 ECB             : 
 1485 akorotkov                 550 GIC       95109 :     if (!JsonbExtractScalar(&json->root, &jbv))
 1485 akorotkov                 551 CBC       94761 :         JsonbInitBinary(&jbv, json);
 1485 akorotkov                 552 ECB             : 
  220 andrew                    553 GIC       95109 :     if (vars && !JsonContainerIsObject(&vars->root))
  220 andrew                    554 ECB             :     {
  220 andrew                    555 GIC           6 :         ereport(ERROR,
  220 andrew                    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                 : 
 1485 akorotkov                 561 GIC       95103 :     cxt.vars = vars;
 1485 akorotkov                 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;
  220 andrew                    568           95103 :     cxt.lastGeneratedObjectId = vars ? 2 : 1;
 1485 akorotkov                 569           95103 :     cxt.innermostArraySize = -1;
                                570           95103 :     cxt.throwErrors = throwErrors;
 1292                           571           95103 :     cxt.useTz = useTz;
 1485 akorotkov                 572 ECB             : 
 1485 akorotkov                 573 GIC       95103 :     if (jspStrictAbsenseOfErrors(&cxt) && !result)
 1485 akorotkov                 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                 :          */
 1483 akorotkov                 579 GIC          27 :         JsonValueList vals = {0};
 1485 akorotkov                 580 ECB             : 
 1485 akorotkov                 581 GIC          27 :         res = executeItem(&cxt, &jsp, &jbv, &vals);
 1485 akorotkov                 582 ECB             : 
 1485 akorotkov                 583 GIC          24 :         if (jperIsError(res))
 1485 akorotkov                 584 CBC          21 :             return res;
 1485 akorotkov                 585 ECB             : 
 1485 akorotkov                 586 GIC           3 :         return JsonValueListIsEmpty(&vals) ? jperNotFound : jperOk;
 1485 akorotkov                 587 ECB             :     }
                                588                 : 
 1485 akorotkov                 589 GIC       95076 :     res = executeItem(&cxt, &jsp, &jbv, result);
 1485 akorotkov                 590 ECB             : 
 1485 akorotkov                 591 GIC       94836 :     Assert(!throwErrors || !jperIsError(res));
 1485 akorotkov                 592 ECB             : 
 1485 akorotkov                 593 GIC       94836 :     return res;
 1485 akorotkov                 594 ECB             : }
                                595                 : 
                                596                 : /*
                                597                 :  * Execute jsonpath with automatic unwrapping of current item in lax mode.
                                598                 :  */
                                599                 : static JsonPathExecResult
 1485 akorotkov                 600 GIC      282933 : executeItem(JsonPathExecContext *cxt, JsonPathItem *jsp,
 1485 akorotkov                 601 ECB             :             JsonbValue *jb, JsonValueList *found)
                                602                 : {
 1485 akorotkov                 603 GIC      282933 :     return executeItemOptUnwrapTarget(cxt, jsp, jb, found, jspAutoUnwrap(cxt));
 1485 akorotkov                 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
 1485 akorotkov                 612 GIC      284925 : executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp,
 1485 akorotkov                 613 ECB             :                            JsonbValue *jb, JsonValueList *found, bool unwrap)
                                614                 : {
                                615                 :     JsonPathItem elem;
 1485 akorotkov                 616 GIC      284925 :     JsonPathExecResult res = jperNotFound;
 1485 akorotkov                 617 ECB             :     JsonBaseObjectInfo baseObject;
                                618                 : 
 1485 akorotkov                 619 GIC      284925 :     check_stack_depth();
 1485 akorotkov                 620 CBC      284925 :     CHECK_FOR_INTERRUPTS();
 1485 akorotkov                 621 ECB             : 
 1485 akorotkov                 622 GIC      284925 :     switch (jsp->type)
 1485 akorotkov                 623 ECB             :     {
                                624                 :             /* all boolean item types: */
 1485 akorotkov                 625 GIC       51081 :         case jpiAnd:
 1485 akorotkov                 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                 :             {
 1485 akorotkov                 639 GIC       51081 :                 JsonPathBool st = executeBoolItem(cxt, jsp, jb, true);
 1485 akorotkov                 640 ECB             : 
 1485 akorotkov                 641 GIC       51081 :                 res = appendBoolResult(cxt, jsp, found, st);
 1485 akorotkov                 642 CBC       51081 :                 break;
 1485 akorotkov                 643 ECB             :             }
                                644                 : 
 1485 akorotkov                 645 GIC       82614 :         case jpiKey:
 1485 akorotkov                 646 CBC       82614 :             if (JsonbType(jb) == jbvObject)
 1485 akorotkov                 647 ECB             :             {
                                648                 :                 JsonbValue *v;
                                649                 :                 JsonbValue  key;
                                650                 : 
 1485 akorotkov                 651 GIC       82488 :                 key.type = jbvString;
 1485 akorotkov                 652 CBC       82488 :                 key.val.string.val = jspGetString(jsp, &key.val.string.len);
 1485 akorotkov                 653 ECB             : 
 1485 akorotkov                 654 GIC       82488 :                 v = findJsonbValueFromContainer(jb->val.binary.data,
 1485 akorotkov                 655 ECB             :                                                 JB_FOBJECT, &key);
                                656                 : 
 1485 akorotkov                 657 GIC       82488 :                 if (v != NULL)
 1485 akorotkov                 658 ECB             :                 {
 1485 akorotkov                 659 GIC       13074 :                     res = executeNextItem(cxt, jsp, NULL,
 1485 akorotkov                 660 ECB             :                                           v, found, false);
                                661                 : 
                                662                 :                     /* free value if it was not added to found list */
 1485 akorotkov                 663 GIC       13074 :                     if (jspHasNext(jsp) || !found)
 1485 akorotkov                 664 CBC        8052 :                         pfree(v);
 1485 akorotkov                 665 ECB             :                 }
 1485 akorotkov                 666 GIC       69414 :                 else if (!jspIgnoreStructuralErrors(cxt))
 1485 akorotkov                 667 ECB             :                 {
 1485 akorotkov                 668 GIC          36 :                     Assert(found);
 1485 akorotkov                 669 ECB             : 
 1485 akorotkov                 670 GIC          36 :                     if (!jspThrowErrors(cxt))
 1485 akorotkov                 671 CBC          24 :                         return jperError;
 1485 akorotkov                 672 ECB             : 
 1485 akorotkov                 673 GIC          12 :                     ereport(ERROR,
 1326 peter                     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                 :             }
 1485 akorotkov                 680 GIC         126 :             else if (unwrap && JsonbType(jb) == jbvArray)
 1485 akorotkov                 681 CBC           3 :                 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
                                682             123 :             else if (!jspIgnoreStructuralErrors(cxt))
 1485 akorotkov                 683 ECB             :             {
 1485 akorotkov                 684 GIC          33 :                 Assert(found);
 1485 akorotkov                 685 CBC          33 :                 RETURN_ERROR(ereport(ERROR,
 1326 peter                     686 ECB             :                                      (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND),
                                687                 :                                       errmsg("jsonpath member accessor can only be applied to an object"))));
                                688                 :             }
 1485 akorotkov                 689 GIC       82542 :             break;
 1485 akorotkov                 690 ECB             : 
 1485 akorotkov                 691 GIC      101205 :         case jpiRoot:
 1485 akorotkov                 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;
 1485 akorotkov                 697 ECB             : 
 1485 akorotkov                 698 GIC        9678 :         case jpiCurrent:
 1485 akorotkov                 699 CBC        9678 :             res = executeNextItem(cxt, jsp, NULL, cxt->current,
 1485 akorotkov                 700 ECB             :                                   found, true);
 1485 akorotkov                 701 GIC        9678 :             break;
 1485 akorotkov                 702 ECB             : 
 1485 akorotkov                 703 GIC         663 :         case jpiAnyArray:
 1485 akorotkov                 704 CBC         663 :             if (JsonbType(jb) == jbvArray)
 1485 akorotkov                 705 ECB             :             {
 1485 akorotkov                 706 GIC         570 :                 bool        hasNext = jspGetNext(jsp, &elem);
 1485 akorotkov                 707 ECB             : 
 1485 akorotkov                 708 GIC         570 :                 res = executeItemUnwrapTargetArray(cxt, hasNext ? &elem : NULL,
 1485 akorotkov                 709 CBC         570 :                                                    jb, found, jspAutoUnwrap(cxt));
 1485 akorotkov                 710 ECB             :             }
 1485 akorotkov                 711 GIC          93 :             else if (jspAutoWrap(cxt))
 1485 akorotkov                 712 CBC          87 :                 res = executeNextItem(cxt, jsp, NULL, jb, found, true);
                                713               6 :             else if (!jspIgnoreStructuralErrors(cxt))
                                714               6 :                 RETURN_ERROR(ereport(ERROR,
 1326 peter                     715 ECB             :                                      (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
                                716                 :                                       errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
 1485 akorotkov                 717 GIC         594 :             break;
 1485 akorotkov                 718 ECB             : 
 1485 akorotkov                 719 GIC         144 :         case jpiIndexArray:
 1485 akorotkov                 720 CBC         144 :             if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
                                721              87 :             {
                                722             138 :                 int         innermostArraySize = cxt->innermostArraySize;
 1485 akorotkov                 723 ECB             :                 int         i;
 1485 akorotkov                 724 GIC         138 :                 int         size = JsonbArraySize(jb);
 1485 akorotkov                 725 CBC         138 :                 bool        singleton = size < 0;
                                726             138 :                 bool        hasNext = jspGetNext(jsp, &elem);
 1485 akorotkov                 727 ECB             : 
 1485 akorotkov                 728 GIC         138 :                 if (singleton)
 1485 akorotkov                 729 CBC           3 :                     size = 1;
 1485 akorotkov                 730 ECB             : 
 1485 akorotkov                 731 GIC         138 :                 cxt->innermostArraySize = size; /* for LAST evaluation */
 1485 akorotkov                 732 ECB             : 
 1485 akorotkov                 733 GIC         216 :                 for (i = 0; i < jsp->content.array.nelems; i++)
 1485 akorotkov                 734 ECB             :                 {
                                735                 :                     JsonPathItem from;
                                736                 :                     JsonPathItem to;
                                737                 :                     int32       index;
                                738                 :                     int32       index_from;
                                739                 :                     int32       index_to;
 1485 akorotkov                 740 GIC         144 :                     bool        range = jspGetArraySubscript(jsp, &from,
 1485 akorotkov                 741 ECB             :                                                              &to, i);
                                742                 : 
 1485 akorotkov                 743 GIC         144 :                     res = getArrayIndex(cxt, &from, jb, &index_from);
 1485 akorotkov                 744 ECB             : 
 1485 akorotkov                 745 GIC         132 :                     if (jperIsError(res))
 1485 akorotkov                 746 CBC          15 :                         break;
 1485 akorotkov                 747 ECB             : 
 1485 akorotkov                 748 GIC         120 :                     if (range)
 1485 akorotkov                 749 ECB             :                     {
 1485 akorotkov                 750 GIC          15 :                         res = getArrayIndex(cxt, &to, jb, &index_to);
 1485 akorotkov                 751 ECB             : 
 1485 akorotkov                 752 GIC          12 :                         if (jperIsError(res))
 1485 akorotkov                 753 LBC           0 :                             break;
 1485 akorotkov                 754 EUB             :                     }
                                755                 :                     else
 1485 akorotkov                 756 GIC         105 :                         index_to = index_from;
 1485 akorotkov                 757 ECB             : 
 1485 akorotkov                 758 GIC         117 :                     if (!jspIgnoreStructuralErrors(cxt) &&
 1485 akorotkov                 759 CBC          42 :                         (index_from < 0 ||
                                760              36 :                          index_from > index_to ||
                                761              36 :                          index_to >= size))
                                762              36 :                         RETURN_ERROR(ereport(ERROR,
 1326 peter                     763 ECB             :                                              (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
                                764                 :                                               errmsg("jsonpath array subscript is out of bounds"))));
                                765                 : 
 1485 akorotkov                 766 GIC          93 :                     if (index_from < 0)
 1485 akorotkov                 767 CBC           6 :                         index_from = 0;
 1485 akorotkov                 768 ECB             : 
 1485 akorotkov                 769 GIC          93 :                     if (index_to >= size)
 1485 akorotkov                 770 CBC           9 :                         index_to = size - 1;
 1485 akorotkov                 771 ECB             : 
 1485 akorotkov                 772 GIC          93 :                     res = jperNotFound;
 1485 akorotkov                 773 ECB             : 
 1485 akorotkov                 774 GIC         180 :                     for (index = index_from; index <= index_to; index++)
 1485 akorotkov                 775 ECB             :                     {
                                776                 :                         JsonbValue *v;
                                777                 :                         bool        copy;
                                778                 : 
 1485 akorotkov                 779 GIC         102 :                         if (singleton)
 1485 akorotkov                 780 ECB             :                         {
 1485 akorotkov                 781 GIC           3 :                             v = jb;
 1485 akorotkov                 782 CBC           3 :                             copy = true;
 1485 akorotkov                 783 ECB             :                         }
                                784                 :                         else
                                785                 :                         {
 1485 akorotkov                 786 GIC          99 :                             v = getIthJsonbValueFromContainer(jb->val.binary.data,
 1485 akorotkov                 787 ECB             :                                                               (uint32) index);
                                788                 : 
 1485 akorotkov                 789 GIC          99 :                             if (v == NULL)
 1485 akorotkov                 790 LBC           0 :                                 continue;
 1485 akorotkov                 791 EUB             : 
 1485 akorotkov                 792 GIC          99 :                             copy = false;
 1485 akorotkov                 793 ECB             :                         }
                                794                 : 
 1485 akorotkov                 795 GIC         102 :                         if (!hasNext && !found)
 1485 akorotkov                 796 CBC          12 :                             return jperOk;
 1485 akorotkov                 797 ECB             : 
 1485 akorotkov                 798 GIC          90 :                         res = executeNextItem(cxt, jsp, &elem, v, found,
 1485 akorotkov                 799 ECB             :                                               copy);
                                800                 : 
 1485 akorotkov                 801 GIC          90 :                         if (jperIsError(res))
 1485 akorotkov                 802 LBC           0 :                             break;
 1485 akorotkov                 803 EUB             : 
 1485 akorotkov                 804 GIC          90 :                         if (res == jperOk && !found)
 1485 akorotkov                 805 CBC           3 :                             break;
 1485 akorotkov                 806 ECB             :                     }
                                807                 : 
 1485 akorotkov                 808 GIC          81 :                     if (jperIsError(res))
 1485 akorotkov                 809 LBC           0 :                         break;
 1485 akorotkov                 810 EUB             : 
 1485 akorotkov                 811 GIC          81 :                     if (res == jperOk && !found)
 1485 akorotkov                 812 CBC           3 :                         break;
 1485 akorotkov                 813 ECB             :                 }
                                814                 : 
 1485 akorotkov                 815 GIC          87 :                 cxt->innermostArraySize = innermostArraySize;
 1485 akorotkov                 816 ECB             :             }
 1485 akorotkov                 817 GIC           6 :             else if (!jspIgnoreStructuralErrors(cxt))
 1485 akorotkov                 818 ECB             :             {
 1485 akorotkov                 819 GIC           6 :                 RETURN_ERROR(ereport(ERROR,
 1326 peter                     820 ECB             :                                      (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
                                821                 :                                       errmsg("jsonpath array accessor can only be applied to an array"))));
                                822                 :             }
 1485 akorotkov                 823 GIC          87 :             break;
 1485 akorotkov                 824 ECB             : 
 1485 akorotkov                 825 GIC          33 :         case jpiLast:
 1485 akorotkov                 826 ECB             :             {
                                827                 :                 JsonbValue  tmpjbv;
                                828                 :                 JsonbValue *lastjbv;
                                829                 :                 int         last;
 1485 akorotkov                 830 GIC          33 :                 bool        hasNext = jspGetNext(jsp, &elem);
 1485 akorotkov                 831 ECB             : 
 1485 akorotkov                 832 GIC          33 :                 if (cxt->innermostArraySize < 0)
 1447 akorotkov                 833 LBC           0 :                     elog(ERROR, "evaluating jsonpath LAST outside of array subscript");
 1485 akorotkov                 834 EUB             : 
 1485 akorotkov                 835 GIC          33 :                 if (!hasNext && !found)
 1485 akorotkov                 836 ECB             :                 {
 1485 akorotkov                 837 GIC           3 :                     res = jperOk;
 1485 akorotkov                 838 CBC           3 :                     break;
 1485 akorotkov                 839 ECB             :                 }
                                840                 : 
 1485 akorotkov                 841 GIC          30 :                 last = cxt->innermostArraySize - 1;
 1485 akorotkov                 842 ECB             : 
 1485 akorotkov                 843 GIC          30 :                 lastjbv = hasNext ? &tmpjbv : palloc(sizeof(*lastjbv));
 1485 akorotkov                 844 ECB             : 
 1485 akorotkov                 845 GIC          30 :                 lastjbv->type = jbvNumeric;
  942 peter                     846 CBC          30 :                 lastjbv->val.numeric = int64_to_numeric(last);
 1485 akorotkov                 847 ECB             : 
 1485 akorotkov                 848 GIC          30 :                 res = executeNextItem(cxt, jsp, &elem,
 1485 akorotkov                 849 ECB             :                                       lastjbv, found, hasNext);
                                850                 :             }
 1485 akorotkov                 851 GIC          30 :             break;
 1485 akorotkov                 852 ECB             : 
 1485 akorotkov                 853 GIC          42 :         case jpiAnyKey:
 1485 akorotkov                 854 CBC          42 :             if (JsonbType(jb) == jbvObject)
 1485 akorotkov                 855 ECB             :             {
 1485 akorotkov                 856 GIC          33 :                 bool        hasNext = jspGetNext(jsp, &elem);
 1485 akorotkov                 857 ECB             : 
 1485 akorotkov                 858 GIC          33 :                 if (jb->type != jbvBinary)
 1485 akorotkov                 859 LBC           0 :                     elog(ERROR, "invalid jsonb object type: %d", jb->type);
 1485 akorotkov                 860 EUB             : 
 1485 akorotkov                 861 GIC          33 :                 return executeAnyItem
 1485 akorotkov                 862 ECB             :                     (cxt, hasNext ? &elem : NULL,
                                863                 :                      jb->val.binary.data, found, 1, 1, 1,
 1485 akorotkov                 864 GIC          33 :                      false, jspAutoUnwrap(cxt));
 1485 akorotkov                 865 ECB             :             }
 1485 akorotkov                 866 GIC           9 :             else if (unwrap && JsonbType(jb) == jbvArray)
 1485 akorotkov                 867 LBC           0 :                 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
 1485 akorotkov                 868 GBC           9 :             else if (!jspIgnoreStructuralErrors(cxt))
 1485 akorotkov                 869 ECB             :             {
 1485 akorotkov                 870 GIC           6 :                 Assert(found);
 1485 akorotkov                 871 CBC           6 :                 RETURN_ERROR(ereport(ERROR,
 1326 peter                     872 ECB             :                                      (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
                                873                 :                                       errmsg("jsonpath wildcard member accessor can only be applied to an object"))));
                                874                 :             }
 1485 akorotkov                 875 GIC           3 :             break;
 1485 akorotkov                 876 ECB             : 
 1485 akorotkov                 877 GIC          84 :         case jpiAdd:
 1485 akorotkov                 878 CBC          84 :             return executeBinaryArithmExpr(cxt, jsp, jb,
 1485 akorotkov                 879 ECB             :                                            numeric_add_opt_error, found);
                                880                 : 
 1485 akorotkov                 881 GIC          30 :         case jpiSub:
 1485 akorotkov                 882 CBC          30 :             return executeBinaryArithmExpr(cxt, jsp, jb,
 1485 akorotkov                 883 ECB             :                                            numeric_sub_opt_error, found);
                                884                 : 
 1485 akorotkov                 885 GIC          18 :         case jpiMul:
 1485 akorotkov                 886 CBC          18 :             return executeBinaryArithmExpr(cxt, jsp, jb,
 1485 akorotkov                 887 ECB             :                                            numeric_mul_opt_error, found);
                                888                 : 
 1485 akorotkov                 889 GIC          33 :         case jpiDiv:
 1485 akorotkov                 890 CBC          33 :             return executeBinaryArithmExpr(cxt, jsp, jb,
 1485 akorotkov                 891 ECB             :                                            numeric_div_opt_error, found);
                                892                 : 
 1485 akorotkov                 893 GIC           6 :         case jpiMod:
 1485 akorotkov                 894 CBC           6 :             return executeBinaryArithmExpr(cxt, jsp, jb,
 1485 akorotkov                 895 ECB             :                                            numeric_mod_opt_error, found);
                                896                 : 
 1485 akorotkov                 897 GIC          30 :         case jpiPlus:
 1485 akorotkov                 898 CBC          30 :             return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
 1485 akorotkov                 899 ECB             : 
 1485 akorotkov                 900 GIC          63 :         case jpiMinus:
 1485 akorotkov                 901 CBC          63 :             return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus,
 1485 akorotkov                 902 ECB             :                                           found);
                                903                 : 
 1485 akorotkov                 904 GIC        9291 :         case jpiFilter:
 1485 akorotkov                 905 ECB             :             {
                                906                 :                 JsonPathBool st;
                                907                 : 
 1485 akorotkov                 908 GIC        9291 :                 if (unwrap && JsonbType(jb) == jbvArray)
 1485 akorotkov                 909 CBC          63 :                     return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
 1485 akorotkov                 910 ECB             :                                                         false);
                                911                 : 
 1485 akorotkov                 912 GIC        9228 :                 jspGetArg(jsp, &elem);
 1485 akorotkov                 913 CBC        9228 :                 st = executeNestedBoolItem(cxt, &elem, jb);
                                914            9180 :                 if (st != jpbTrue)
                                915            8241 :                     res = jperNotFound;
 1485 akorotkov                 916 ECB             :                 else
 1485 akorotkov                 917 GIC         939 :                     res = executeNextItem(cxt, jsp, NULL,
 1485 akorotkov                 918 ECB             :                                           jb, found, true);
 1485 akorotkov                 919 GIC        9180 :                 break;
 1485 akorotkov                 920 ECB             :             }
                                921                 : 
 1485 akorotkov                 922 GIC         153 :         case jpiAny:
 1485 akorotkov                 923 ECB             :             {
 1485 akorotkov                 924 GIC         153 :                 bool        hasNext = jspGetNext(jsp, &elem);
 1485 akorotkov                 925 ECB             : 
                                926                 :                 /* first try without any intermediate steps */
 1485 akorotkov                 927 GIC         153 :                 if (jsp->content.anybounds.first == 0)
 1485 akorotkov                 928 ECB             :                 {
                                929                 :                     bool        savedIgnoreStructuralErrors;
                                930                 : 
 1485 akorotkov                 931 GIC          84 :                     savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
 1485 akorotkov                 932 CBC          84 :                     cxt->ignoreStructuralErrors = true;
                                933              84 :                     res = executeNextItem(cxt, jsp, &elem,
 1485 akorotkov                 934 ECB             :                                           jb, found, true);
 1485 akorotkov                 935 GIC          84 :                     cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
 1485 akorotkov                 936 ECB             : 
 1485 akorotkov                 937 GIC          84 :                     if (res == jperOk && !found)
 1485 akorotkov                 938 CBC           3 :                         break;
 1485 akorotkov                 939 ECB             :                 }
                                940                 : 
 1485 akorotkov                 941 GIC         150 :                 if (jb->type == jbvBinary)
 1485 akorotkov                 942 CBC         150 :                     res = executeAnyItem
 1485 akorotkov                 943 ECB             :                         (cxt, hasNext ? &elem : NULL,
                                944                 :                          jb->val.binary.data, found,
                                945                 :                          1,
                                946                 :                          jsp->content.anybounds.first,
                                947                 :                          jsp->content.anybounds.last,
 1485 akorotkov                 948 GIC         150 :                          true, jspAutoUnwrap(cxt));
 1485 akorotkov                 949 CBC         150 :                 break;
 1485 akorotkov                 950 ECB             :             }
                                951                 : 
 1485 akorotkov                 952 GIC       27774 :         case jpiNull:
 1485 akorotkov                 953 ECB             :         case jpiBool:
                                954                 :         case jpiNumeric:
                                955                 :         case jpiString:
                                956                 :         case jpiVariable:
                                957                 :             {
                                958                 :                 JsonbValue  vbuf;
                                959                 :                 JsonbValue *v;
 1485 akorotkov                 960 GIC       27774 :                 bool        hasNext = jspGetNext(jsp, &elem);
 1485 akorotkov                 961 ECB             : 
   87 akorotkov                 962 GIC       27774 :                 if (!hasNext && !found && jsp->type != jpiVariable)
 1485 akorotkov                 963 ECB             :                 {
                                964                 :                     /*
                                965                 :                      * Skip evaluation, but not for variables.  We must
                                966                 :                      * trigger an error for the missing variable.
                                967                 :                      */
   87 akorotkov                 968 GIC           6 :                     res = jperOk;
 1485 akorotkov                 969 CBC           6 :                     break;
 1485 akorotkov                 970 ECB             :                 }
                                971                 : 
 1485 akorotkov                 972 GIC       27768 :                 v = hasNext ? &vbuf : palloc(sizeof(*v));
 1485 akorotkov                 973 ECB             : 
 1485 akorotkov                 974 GIC       27768 :                 baseObject = cxt->baseObject;
 1485 akorotkov                 975 CBC       27768 :                 getJsonPathItem(cxt, jsp, v);
 1485 akorotkov                 976 ECB             : 
 1485 akorotkov                 977 GIC       27753 :                 res = executeNextItem(cxt, jsp, &elem,
 1485 akorotkov                 978 ECB             :                                       v, found, hasNext);
 1485 akorotkov                 979 GIC       27753 :                 cxt->baseObject = baseObject;
 1485 akorotkov                 980 ECB             :             }
 1485 akorotkov                 981 GIC       27753 :             break;
 1485 akorotkov                 982 ECB             : 
 1485 akorotkov                 983 GIC         105 :         case jpiType:
 1485 akorotkov                 984 ECB             :             {
 1485 akorotkov                 985 GIC         105 :                 JsonbValue *jbv = palloc(sizeof(*jbv));
 1485 akorotkov                 986 ECB             : 
 1485 akorotkov                 987 GIC         105 :                 jbv->type = jbvString;
 1485 akorotkov                 988 CBC         105 :                 jbv->val.string.val = pstrdup(JsonbTypeName(jb));
                                989             105 :                 jbv->val.string.len = strlen(jbv->val.string.val);
 1485 akorotkov                 990 ECB             : 
 1485 akorotkov                 991 GIC         105 :                 res = executeNextItem(cxt, jsp, NULL, jbv,
 1485 akorotkov                 992 ECB             :                                       found, false);
                                993                 :             }
 1485 akorotkov                 994 GIC         105 :             break;
 1485 akorotkov                 995 ECB             : 
 1485 akorotkov                 996 GIC          36 :         case jpiSize:
 1485 akorotkov                 997 ECB             :             {
 1485 akorotkov                 998 GIC          36 :                 int         size = JsonbArraySize(jb);
 1485 akorotkov                 999 ECB             : 
 1485 akorotkov                1000 GIC          36 :                 if (size < 0)
 1485 akorotkov                1001 ECB             :                 {
 1485 akorotkov                1002 GIC          24 :                     if (!jspAutoWrap(cxt))
 1485 akorotkov                1003 ECB             :                     {
 1485 akorotkov                1004 GIC           6 :                         if (!jspIgnoreStructuralErrors(cxt))
 1485 akorotkov                1005 CBC           6 :                             RETURN_ERROR(ereport(ERROR,
 1326 peter                    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)))));
 1485 akorotkov                1009 UIC           0 :                         break;
 1485 akorotkov                1010 EUB             :                     }
                               1011                 : 
 1485 akorotkov                1012 GIC          18 :                     size = 1;
 1485 akorotkov                1013 ECB             :                 }
                               1014                 : 
 1485 akorotkov                1015 GIC          30 :                 jb = palloc(sizeof(*jb));
 1485 akorotkov                1016 ECB             : 
 1485 akorotkov                1017 GIC          30 :                 jb->type = jbvNumeric;
  942 peter                    1018 CBC          30 :                 jb->val.numeric = int64_to_numeric(size);
 1485 akorotkov                1019 ECB             : 
 1485 akorotkov                1020 GIC          30 :                 res = executeNextItem(cxt, jsp, NULL, jb, found, false);
 1485 akorotkov                1021 ECB             :             }
 1485 akorotkov                1022 GIC          30 :             break;
 1485 akorotkov                1023 ECB             : 
 1485 akorotkov                1024 GIC          54 :         case jpiAbs:
 1485 akorotkov                1025 CBC          54 :             return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_abs,
 1485 akorotkov                1026 ECB             :                                             found);
                               1027                 : 
 1485 akorotkov                1028 GIC          24 :         case jpiFloor:
 1485 akorotkov                1029 CBC          24 :             return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_floor,
 1485 akorotkov                1030 ECB             :                                             found);
                               1031                 : 
 1485 akorotkov                1032 GIC          51 :         case jpiCeiling:
 1485 akorotkov                1033 CBC          51 :             return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_ceil,
 1485 akorotkov                1034 ECB             :                                             found);
                               1035                 : 
 1485 akorotkov                1036 GIC          57 :         case jpiDouble:
 1485 akorotkov                1037 ECB             :             {
                               1038                 :                 JsonbValue  jbv;
                               1039                 : 
 1485 akorotkov                1040 GIC          57 :                 if (unwrap && JsonbType(jb) == jbvArray)
 1485 akorotkov                1041 CBC          21 :                     return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
 1485 akorotkov                1042 ECB             :                                                         false);
                               1043                 : 
 1485 akorotkov                1044 GIC          54 :                 if (jb->type == jbvNumeric)
 1485 akorotkov                1045 ECB             :                 {
 1485 akorotkov                1046 GIC           6 :                     char       *tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
 1485 akorotkov                1047 ECB             :                                                                           NumericGetDatum(jb->val.numeric)));
                               1048                 :                     double      val;
  121 tgl                      1049 GNC           6 :                     ErrorSaveContext escontext = {T_ErrorSaveContext};
 1485 akorotkov                1050 ECB             : 
  121 tgl                      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))
 1485 akorotkov                1058 CBC           3 :                         RETURN_ERROR(ereport(ERROR,
 1326 peter                    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)))));
 1485 akorotkov                1062 GIC           3 :                     res = jperOk;
 1485 akorotkov                1063 ECB             :                 }
 1485 akorotkov                1064 GIC          48 :                 else if (jb->type == jbvString)
 1485 akorotkov                1065 ECB             :                 {
                               1066                 :                     /* cast string as double */
                               1067                 :                     double      val;
 1485 akorotkov                1068 GIC          24 :                     char       *tmp = pnstrdup(jb->val.string.val,
 1485 akorotkov                1069 CBC          24 :                                                jb->val.string.len);
  121 tgl                      1070 GNC          24 :                     ErrorSaveContext escontext = {T_ErrorSaveContext};
 1485 akorotkov                1071 ECB             : 
  121 tgl                      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))
 1485 akorotkov                1079 CBC          21 :                         RETURN_ERROR(ereport(ERROR,
 1326 peter                    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                 : 
 1485 akorotkov                1084 GIC           3 :                     jb = &jbv;
 1485 akorotkov                1085 CBC           3 :                     jb->type = jbvNumeric;
                               1086               3 :                     jb->val.numeric = DatumGetNumeric(DirectFunctionCall1(float8_numeric,
 1485 akorotkov                1087 ECB             :                                                                           Float8GetDatum(val)));
 1485 akorotkov                1088 GIC           3 :                     res = jperOk;
 1485 akorotkov                1089 ECB             :                 }
                               1090                 : 
 1485 akorotkov                1091 GIC          30 :                 if (res == jperNotFound)
 1485 akorotkov                1092 CBC          24 :                     RETURN_ERROR(ereport(ERROR,
 1326 peter                    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                 : 
 1485 akorotkov                1097 GIC           6 :                 res = executeNextItem(cxt, jsp, NULL, jb, found, true);
 1485 akorotkov                1098 ECB             :             }
 1485 akorotkov                1099 GIC           6 :             break;
 1485 akorotkov                1100 ECB             : 
 1292 akorotkov                1101 GIC        1611 :         case jpiDatetime:
 1292 akorotkov                1102 CBC        1611 :             if (unwrap && JsonbType(jb) == jbvArray)
                               1103               3 :                 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
 1292 akorotkov                1104 ECB             : 
 1292 akorotkov                1105 GIC        1608 :             return executeDateTimeMethod(cxt, jsp, jb, found);
 1292 akorotkov                1106 ECB             : 
 1485 akorotkov                1107 GIC          45 :         case jpiKeyValue:
 1485 akorotkov                1108 CBC          45 :             if (unwrap && JsonbType(jb) == jbvArray)
                               1109               3 :                 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
 1485 akorotkov                1110 ECB             : 
 1485 akorotkov                1111 GIC          42 :             return executeKeyValueMethod(cxt, jsp, jb, found);
 1485 akorotkov                1112 ECB             : 
 1485 akorotkov                1113 UIC           0 :         default:
 1485 akorotkov                1114 UBC           0 :             elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
 1485 akorotkov                1115 EUB             :     }
                               1116                 : 
 1485 akorotkov                1117 GIC      282249 :     return res;
 1485 akorotkov                1118 ECB             : }
                               1119                 : 
                               1120                 : /*
                               1121                 :  * Unwrap current array item and execute jsonpath for each of its elements.
                               1122                 :  */
                               1123                 : static JsonPathExecResult
 1485 akorotkov                1124 GIC         672 : executeItemUnwrapTargetArray(JsonPathExecContext *cxt, JsonPathItem *jsp,
 1485 akorotkov                1125 ECB             :                              JsonbValue *jb, JsonValueList *found,
                               1126                 :                              bool unwrapElements)
                               1127                 : {
 1485 akorotkov                1128 GIC         672 :     if (jb->type != jbvBinary)
 1485 akorotkov                1129 ECB             :     {
 1485 akorotkov                1130 UIC           0 :         Assert(jb->type != jbvArray);
 1485 akorotkov                1131 UBC           0 :         elog(ERROR, "invalid jsonb array value type: %d", jb->type);
 1485 akorotkov                1132 EUB             :     }
                               1133                 : 
 1485 akorotkov                1134 GIC         672 :     return executeAnyItem
 1485 akorotkov                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
 1485 akorotkov                1144 GIC      206007 : executeNextItem(JsonPathExecContext *cxt,
 1485 akorotkov                1145 ECB             :                 JsonPathItem *cur, JsonPathItem *next,
                               1146                 :                 JsonbValue *v, JsonValueList *found, bool copy)
                               1147                 : {
                               1148                 :     JsonPathItem elem;
                               1149                 :     bool        hasNext;
                               1150                 : 
 1485 akorotkov                1151 GIC      206007 :     if (!cur)
 1485 akorotkov                1152 LBC           0 :         hasNext = next != NULL;
 1485 akorotkov                1153 GBC      206007 :     else if (next)
 1485 akorotkov                1154 CBC       80883 :         hasNext = jspHasNext(cur);
 1485 akorotkov                1155 ECB             :     else
                               1156                 :     {
 1485 akorotkov                1157 GIC      125124 :         next = &elem;
 1485 akorotkov                1158 CBC      125124 :         hasNext = jspGetNext(cur, next);
 1485 akorotkov                1159 ECB             :     }
                               1160                 : 
 1485 akorotkov                1161 GIC      206007 :     if (hasNext)
 1485 akorotkov                1162 CBC       92898 :         return executeItem(cxt, next, v, found);
 1485 akorotkov                1163 ECB             : 
 1485 akorotkov                1164 GIC      113109 :     if (found)
 1485 akorotkov                1165 CBC       88089 :         JsonValueListAppend(found, copy ? copyJsonbValue(v) : v);
 1485 akorotkov                1166 ECB             : 
 1485 akorotkov                1167 GIC      113109 :     return jperOk;
 1485 akorotkov                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
 1485 akorotkov                1175 GIC       94773 : executeItemOptUnwrapResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
 1485 akorotkov                1176 ECB             :                            JsonbValue *jb, bool unwrap,
                               1177                 :                            JsonValueList *found)
                               1178                 : {
 1485 akorotkov                1179 GIC       94773 :     if (unwrap && jspAutoUnwrap(cxt))
 1485 akorotkov                1180 ECB             :     {
 1483 akorotkov                1181 GIC       55080 :         JsonValueList seq = {0};
 1485 akorotkov                1182 ECB             :         JsonValueListIterator it;
 1485 akorotkov                1183 GIC       55080 :         JsonPathExecResult res = executeItem(cxt, jsp, jb, &seq);
 1485 akorotkov                1184 ECB             :         JsonbValue *item;
                               1185                 : 
 1485 akorotkov                1186 GIC       55068 :         if (jperIsError(res))
 1485 akorotkov                1187 CBC          33 :             return res;
 1485 akorotkov                1188 ECB             : 
 1485 akorotkov                1189 GIC       55035 :         JsonValueListInitIterator(&seq, &it);
 1485 akorotkov                1190 CBC       91149 :         while ((item = JsonValueListNext(&seq, &it)))
 1485 akorotkov                1191 ECB             :         {
 1485 akorotkov                1192 GIC       36114 :             Assert(item->type != jbvArray);
 1485 akorotkov                1193 ECB             : 
 1485 akorotkov                1194 GIC       36114 :             if (JsonbType(item) == jbvArray)
 1485 akorotkov                1195 CBC          27 :                 executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
 1485 akorotkov                1196 ECB             :             else
 1485 akorotkov                1197 GIC       36087 :                 JsonValueListAppend(found, item);
 1485 akorotkov                1198 ECB             :         }
                               1199                 : 
 1485 akorotkov                1200 GIC       55035 :         return jperOk;
 1485 akorotkov                1201 ECB             :     }
                               1202                 : 
 1485 akorotkov                1203 GIC       39693 :     return executeItem(cxt, jsp, jb, found);
 1485 akorotkov                1204 ECB             : }
                               1205                 : 
                               1206                 : /*
                               1207                 :  * Same as executeItemOptUnwrapResult(), but with error suppression.
                               1208                 :  */
                               1209                 : static JsonPathExecResult
 1485 akorotkov                1210 GIC       94341 : executeItemOptUnwrapResultNoThrow(JsonPathExecContext *cxt,
 1485 akorotkov                1211 ECB             :                                   JsonPathItem *jsp,
                               1212                 :                                   JsonbValue *jb, bool unwrap,
                               1213                 :                                   JsonValueList *found)
                               1214                 : {
                               1215                 :     JsonPathExecResult res;
 1485 akorotkov                1216 GIC       94341 :     bool        throwErrors = cxt->throwErrors;
 1485 akorotkov                1217 ECB             : 
 1485 akorotkov                1218 GIC       94341 :     cxt->throwErrors = false;
 1485 akorotkov                1219 CBC       94341 :     res = executeItemOptUnwrapResult(cxt, jsp, jb, unwrap, found);
                               1220           94338 :     cxt->throwErrors = throwErrors;
 1485 akorotkov                1221 ECB             : 
 1485 akorotkov                1222 GIC       94338 :     return res;
 1485 akorotkov                1223 ECB             : }
                               1224                 : 
                               1225                 : /* Execute boolean-valued jsonpath expression. */
                               1226                 : static JsonPathBool
 1485 akorotkov                1227 GIC       86472 : executeBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp,
 1485 akorotkov                1228 ECB             :                 JsonbValue *jb, bool canHaveNext)
                               1229                 : {
                               1230                 :     JsonPathItem larg;
                               1231                 :     JsonPathItem rarg;
                               1232                 :     JsonPathBool res;
                               1233                 :     JsonPathBool res2;
                               1234                 : 
 1485 akorotkov                1235 GIC       86472 :     if (!canHaveNext && jspHasNext(jsp))
 1485 akorotkov                1236 LBC           0 :         elog(ERROR, "boolean jsonpath item cannot have next item");
 1485 akorotkov                1237 EUB             : 
 1485 akorotkov                1238 GIC       86472 :     switch (jsp->type)
 1485 akorotkov                1239 ECB             :     {
 1485 akorotkov                1240 GIC       12765 :         case jpiAnd:
 1485 akorotkov                1241 CBC       12765 :             jspGetLeftArg(jsp, &larg);
                               1242           12765 :             res = executeBoolItem(cxt, &larg, jb, false);
 1485 akorotkov                1243 ECB             : 
 1485 akorotkov                1244 GIC       12765 :             if (res == jpbFalse)
 1485 akorotkov                1245 CBC       11235 :                 return jpbFalse;
 1485 akorotkov                1246 ECB             : 
                               1247                 :             /*
                               1248                 :              * SQL/JSON says that we should check second arg in case of
                               1249                 :              * jperError
                               1250                 :              */
                               1251                 : 
 1485 akorotkov                1252 GIC        1530 :             jspGetRightArg(jsp, &rarg);
 1485 akorotkov                1253 CBC        1530 :             res2 = executeBoolItem(cxt, &rarg, jb, false);
 1485 akorotkov                1254 ECB             : 
 1485 akorotkov                1255 GIC        1530 :             return res2 == jpbTrue ? res : res2;
 1485 akorotkov                1256 ECB             : 
 1485 akorotkov                1257 GIC        6477 :         case jpiOr:
 1485 akorotkov                1258 CBC        6477 :             jspGetLeftArg(jsp, &larg);
                               1259            6477 :             res = executeBoolItem(cxt, &larg, jb, false);
 1485 akorotkov                1260 ECB             : 
 1485 akorotkov                1261 GIC        6477 :             if (res == jpbTrue)
 1485 akorotkov                1262 CBC        1245 :                 return jpbTrue;
 1485 akorotkov                1263 ECB             : 
 1485 akorotkov                1264 GIC        5232 :             jspGetRightArg(jsp, &rarg);
 1485 akorotkov                1265 CBC        5232 :             res2 = executeBoolItem(cxt, &rarg, jb, false);
 1485 akorotkov                1266 ECB             : 
 1485 akorotkov                1267 GIC        5232 :             return res2 == jpbFalse ? res : res2;
 1485 akorotkov                1268 ECB             : 
 1485 akorotkov                1269 GIC          54 :         case jpiNot:
 1485 akorotkov                1270 CBC          54 :             jspGetArg(jsp, &larg);
 1485 akorotkov                1271 ECB             : 
 1485 akorotkov                1272 GIC          54 :             res = executeBoolItem(cxt, &larg, jb, false);
 1485 akorotkov                1273 ECB             : 
 1485 akorotkov                1274 GIC          54 :             if (res == jpbUnknown)
 1485 akorotkov                1275 CBC          18 :                 return jpbUnknown;
 1485 akorotkov                1276 ECB             : 
 1485 akorotkov                1277 GIC          36 :             return res == jpbTrue ? jpbFalse : jpbTrue;
 1485 akorotkov                1278 ECB             : 
 1485 akorotkov                1279 GIC         105 :         case jpiIsUnknown:
 1485 akorotkov                1280 CBC         105 :             jspGetArg(jsp, &larg);
                               1281             105 :             res = executeBoolItem(cxt, &larg, jb, false);
                               1282             105 :             return res == jpbUnknown ? jpbTrue : jpbFalse;
 1485 akorotkov                1283 ECB             : 
 1485 akorotkov                1284 GIC       27237 :         case jpiEqual:
 1485 akorotkov                1285 ECB             :         case jpiNotEqual:
                               1286                 :         case jpiLess:
                               1287                 :         case jpiGreater:
                               1288                 :         case jpiLessOrEqual:
                               1289                 :         case jpiGreaterOrEqual:
 1485 akorotkov                1290 GIC       27237 :             jspGetLeftArg(jsp, &larg);
 1485 akorotkov                1291 CBC       27237 :             jspGetRightArg(jsp, &rarg);
                               1292           27237 :             return executePredicate(cxt, jsp, &larg, &rarg, jb, true,
 1292 akorotkov                1293 ECB             :                                     executeComparison, cxt);
                               1294                 : 
 1485 akorotkov                1295 GIC          42 :         case jpiStartsWith:     /* 'whole STARTS WITH initial' */
 1485 akorotkov                1296 CBC          42 :             jspGetLeftArg(jsp, &larg);  /* 'whole' */
                               1297              42 :             jspGetRightArg(jsp, &rarg); /* 'initial' */
                               1298              42 :             return executePredicate(cxt, jsp, &larg, &rarg, jb, false,
 1485 akorotkov                1299 ECB             :                                     executeStartsWith, NULL);
                               1300                 : 
 1485 akorotkov                1301 GIC         198 :         case jpiLikeRegex:      /* 'expr LIKE_REGEX pattern FLAGS flags' */
 1485 akorotkov                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                 :                  */
 1483 akorotkov                1309 GIC         198 :                 JsonLikeRegexContext lrcxt = {0};
 1485 akorotkov                1310 ECB             : 
 1485 akorotkov                1311 GIC         198 :                 jspInitByBuffer(&larg, jsp->base,
 1485 akorotkov                1312 ECB             :                                 jsp->content.like_regex.expr);
                               1313                 : 
 1485 akorotkov                1314 GIC         198 :                 return executePredicate(cxt, jsp, &larg, NULL, jb, false,
 1485 akorotkov                1315 ECB             :                                         executeLikeRegex, &lrcxt);
                               1316                 :             }
                               1317                 : 
 1485 akorotkov                1318 GIC       39594 :         case jpiExists:
 1485 akorotkov                1319 CBC       39594 :             jspGetArg(jsp, &larg);
 1485 akorotkov                1320 ECB             : 
 1485 akorotkov                1321 GIC       39594 :             if (jspStrictAbsenseOfErrors(cxt))
 1485 akorotkov                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                 :                  */
 1483 akorotkov                1327 GIC          24 :                 JsonValueList vals = {0};
 1485 akorotkov                1328 ECB             :                 JsonPathExecResult res =
 1485 akorotkov                1329 GIC          24 :                 executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
 1485 akorotkov                1330 ECB             :                                                   false, &vals);
                               1331                 : 
 1485 akorotkov                1332 GIC          24 :                 if (jperIsError(res))
 1485 akorotkov                1333 CBC          18 :                     return jpbUnknown;
 1485 akorotkov                1334 ECB             : 
 1485 akorotkov                1335 GIC           6 :                 return JsonValueListIsEmpty(&vals) ? jpbFalse : jpbTrue;
 1485 akorotkov                1336 ECB             :             }
                               1337                 :             else
                               1338                 :             {
                               1339                 :                 JsonPathExecResult res =
 1485 akorotkov                1340 GIC       39570 :                 executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
 1485 akorotkov                1341 ECB             :                                                   false, NULL);
                               1342                 : 
 1485 akorotkov                1343 GIC       39570 :                 if (jperIsError(res))
 1485 akorotkov                1344 CBC          12 :                     return jpbUnknown;
 1485 akorotkov                1345 ECB             : 
 1485 akorotkov                1346 GIC       39558 :                 return res == jperOk ? jpbTrue : jpbFalse;
 1485 akorotkov                1347 ECB             :             }
                               1348                 : 
 1485 akorotkov                1349 UIC           0 :         default:
 1485 akorotkov                1350 UBC           0 :             elog(ERROR, "invalid boolean jsonpath item type: %d", jsp->type);
 1485 akorotkov                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
 1485 akorotkov                1360 GIC        9228 : executeNestedBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp,
 1485 akorotkov                1361 ECB             :                       JsonbValue *jb)
                               1362                 : {
                               1363                 :     JsonbValue *prev;
                               1364                 :     JsonPathBool res;
                               1365                 : 
 1485 akorotkov                1366 GIC        9228 :     prev = cxt->current;
 1485 akorotkov                1367 CBC        9228 :     cxt->current = jb;
                               1368            9228 :     res = executeBoolItem(cxt, jsp, jb, false);
                               1369            9180 :     cxt->current = prev;
 1485 akorotkov                1370 ECB             : 
 1485 akorotkov                1371 GIC        9180 :     return res;
 1485 akorotkov                1372 ECB             : }
                               1373                 : 
                               1374                 : /*
                               1375                 :  * Implementation of several jsonpath nodes:
                               1376                 :  *  - jpiAny (.** accessor),
                               1377                 :  *  - jpiAnyKey (.* accessor),
                               1378                 :  *  - jpiAnyArray ([*] accessor)
                               1379                 :  */
                               1380                 : static JsonPathExecResult
 1485 akorotkov                1381 GIC         948 : executeAnyItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbContainer *jbc,
 1485 akorotkov                1382 ECB             :                JsonValueList *found, uint32 level, uint32 first, uint32 last,
                               1383                 :                bool ignoreStructuralErrors, bool unwrapNext)
                               1384                 : {
 1485 akorotkov                1385 GIC         948 :     JsonPathExecResult res = jperNotFound;
 1485 akorotkov                1386 ECB             :     JsonbIterator *it;
                               1387                 :     int32       r;
                               1388                 :     JsonbValue  v;
                               1389                 : 
 1485 akorotkov                1390 GIC         948 :     check_stack_depth();
 1485 akorotkov                1391 ECB             : 
 1485 akorotkov                1392 GIC         948 :     if (level > last)
 1485 akorotkov                1393 CBC          15 :         return res;
 1485 akorotkov                1394 ECB             : 
 1485 akorotkov                1395 GIC         933 :     it = JsonbIteratorInit(jbc);
 1485 akorotkov                1396 ECB             : 
                               1397                 :     /*
                               1398                 :      * Recursively iterate over jsonb objects/arrays
                               1399                 :      */
 1485 akorotkov                1400 GIC        4815 :     while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
 1485 akorotkov                1401 ECB             :     {
 1485 akorotkov                1402 GIC        4170 :         if (r == WJB_KEY)
 1485 akorotkov                1403 ECB             :         {
 1485 akorotkov                1404 GIC         276 :             r = JsonbIteratorNext(&it, &v, true);
 1485 akorotkov                1405 CBC         276 :             Assert(r == WJB_VALUE);
 1485 akorotkov                1406 ECB             :         }
                               1407                 : 
 1485 akorotkov                1408 GIC        4170 :         if (r == WJB_VALUE || r == WJB_ELEM)
 1485 akorotkov                1409 ECB             :         {
                               1410                 : 
 1485 akorotkov                1411 GIC        2592 :             if (level >= first ||
 1485 akorotkov                1412 CBC           6 :                 (first == PG_UINT32_MAX && last == PG_UINT32_MAX &&
                               1413               6 :                  v.type != jbvBinary))  /* leaves only requested */
 1485 akorotkov                1414 ECB             :             {
                               1415                 :                 /* check expression */
 1485 akorotkov                1416 GIC        2562 :                 if (jsp)
 1485 akorotkov                1417 ECB             :                 {
 1485 akorotkov                1418 GIC        1992 :                     if (ignoreStructuralErrors)
 1485 akorotkov                1419 ECB             :                     {
                               1420                 :                         bool        savedIgnoreStructuralErrors;
                               1421                 : 
 1485 akorotkov                1422 GIC         174 :                         savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
 1485 akorotkov                1423 CBC         174 :                         cxt->ignoreStructuralErrors = true;
                               1424             174 :                         res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
                               1425             174 :                         cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
 1485 akorotkov                1426 ECB             :                     }
                               1427                 :                     else
 1485 akorotkov                1428 GIC        1818 :                         res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
 1485 akorotkov                1429 ECB             : 
 1485 akorotkov                1430 GIC        1929 :                     if (jperIsError(res))
 1485 akorotkov                1431 CBC          33 :                         break;
 1485 akorotkov                1432 ECB             : 
 1485 akorotkov                1433 GIC        1896 :                     if (res == jperOk && !found)
 1485 akorotkov                1434 CBC         162 :                         break;
 1485 akorotkov                1435 ECB             :                 }
 1485 akorotkov                1436 GIC         570 :                 else if (found)
 1485 akorotkov                1437 CBC         558 :                     JsonValueListAppend(found, copyJsonbValue(&v));
 1485 akorotkov                1438 ECB             :                 else
 1485 akorotkov                1439 GIC          12 :                     return jperOk;
 1485 akorotkov                1440 ECB             :             }
                               1441                 : 
 1485 akorotkov                1442 GIC        2322 :             if (level < last && v.type == jbvBinary)
 1485 akorotkov                1443 ECB             :             {
 1485 akorotkov                1444 GIC          93 :                 res = executeAnyItem
 1485 akorotkov                1445 ECB             :                     (cxt, jsp, v.val.binary.data, found,
                               1446                 :                      level + 1, first, last,
                               1447                 :                      ignoreStructuralErrors, unwrapNext);
                               1448                 : 
 1485 akorotkov                1449 GIC          93 :                 if (jperIsError(res))
 1485 akorotkov                1450 LBC           0 :                     break;
 1485 akorotkov                1451 EUB             : 
 1485 akorotkov                1452 GIC          93 :                 if (res == jperOk && found == NULL)
 1485 akorotkov                1453 CBC          18 :                     break;
 1485 akorotkov                1454 ECB             :             }
                               1455                 :         }
                               1456                 :     }
                               1457                 : 
 1485 akorotkov                1458 GIC         858 :     return res;
 1485 akorotkov                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
 1485 akorotkov                1472 GIC       27477 : executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred,
 1485 akorotkov                1473 ECB             :                  JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb,
                               1474                 :                  bool unwrapRightArg, JsonPathPredicateCallback exec,
                               1475                 :                  void *param)
                               1476                 : {
                               1477                 :     JsonPathExecResult res;
                               1478                 :     JsonValueListIterator lseqit;
 1483 akorotkov                1479 GIC       27477 :     JsonValueList lseq = {0};
 1483 akorotkov                1480 CBC       27477 :     JsonValueList rseq = {0};
 1485 akorotkov                1481 ECB             :     JsonbValue *lval;
 1485 akorotkov                1482 GIC       27477 :     bool        error = false;
 1485 akorotkov                1483 CBC       27477 :     bool        found = false;
 1485 akorotkov                1484 ECB             : 
                               1485                 :     /* Left argument is always auto-unwrapped. */
 1485 akorotkov                1486 GIC       27477 :     res = executeItemOptUnwrapResultNoThrow(cxt, larg, jb, true, &lseq);
 1485 akorotkov                1487 CBC       27477 :     if (jperIsError(res))
                               1488               9 :         return jpbUnknown;
 1485 akorotkov                1489 ECB             : 
 1485 akorotkov                1490 GIC       27468 :     if (rarg)
 1485 akorotkov                1491 ECB             :     {
                               1492                 :         /* Right argument is conditionally auto-unwrapped. */
 1485 akorotkov                1493 GIC       27270 :         res = executeItemOptUnwrapResultNoThrow(cxt, rarg, jb,
 1485 akorotkov                1494 ECB             :                                                 unwrapRightArg, &rseq);
 1485 akorotkov                1495 GIC       27267 :         if (jperIsError(res))
 1485 akorotkov                1496 CBC          27 :             return jpbUnknown;
 1485 akorotkov                1497 ECB             :     }
                               1498                 : 
 1485 akorotkov                1499 GIC       27438 :     JsonValueListInitIterator(&lseq, &lseqit);
 1485 akorotkov                1500 CBC       36021 :     while ((lval = JsonValueListNext(&lseq, &lseqit)))
 1485 akorotkov                1501 ECB             :     {
                               1502                 :         JsonValueListIterator rseqit;
                               1503                 :         JsonbValue *rval;
 1485 akorotkov                1504 GIC       11037 :         bool        first = true;
 1485 akorotkov                1505 ECB             : 
 1484 akorotkov                1506 GIC       11037 :         JsonValueListInitIterator(&rseq, &rseqit);
 1485 akorotkov                1507 CBC       11037 :         if (rarg)
                               1508           10839 :             rval = JsonValueListNext(&rseq, &rseqit);
 1485 akorotkov                1509 ECB             :         else
 1485 akorotkov                1510 GIC         198 :             rval = NULL;
 1485 akorotkov                1511 ECB             : 
                               1512                 :         /* Loop over right arg sequence or do single pass otherwise */
 1485 akorotkov                1513 GIC       17148 :         while (rarg ? (rval != NULL) : first)
 1485 akorotkov                1514 ECB             :         {
 1485 akorotkov                1515 GIC        8565 :             JsonPathBool res = exec(pred, lval, rval, param);
 1485 akorotkov                1516 ECB             : 
 1485 akorotkov                1517 GIC        8520 :             if (res == jpbUnknown)
 1485 akorotkov                1518 ECB             :             {
 1485 akorotkov                1519 GIC         339 :                 if (jspStrictAbsenseOfErrors(cxt))
 1485 akorotkov                1520 CBC        2409 :                     return jpbUnknown;
 1485 akorotkov                1521 ECB             : 
 1485 akorotkov                1522 GIC         327 :                 error = true;
 1485 akorotkov                1523 ECB             :             }
 1485 akorotkov                1524 GIC        8181 :             else if (res == jpbTrue)
 1485 akorotkov                1525 ECB             :             {
 1485 akorotkov                1526 GIC        2421 :                 if (!jspStrictAbsenseOfErrors(cxt))
 1485 akorotkov                1527 CBC        2397 :                     return jpbTrue;
 1485 akorotkov                1528 ECB             : 
 1485 akorotkov                1529 GIC          24 :                 found = true;
 1485 akorotkov                1530 ECB             :             }
                               1531                 : 
 1485 akorotkov                1532 GIC        6111 :             first = false;
 1485 akorotkov                1533 CBC        6111 :             if (rarg)
                               1534            5964 :                 rval = JsonValueListNext(&rseq, &rseqit);
 1485 akorotkov                1535 ECB             :         }
                               1536                 :     }
                               1537                 : 
 1485 akorotkov                1538 GIC       24984 :     if (found)                  /* possible only in strict mode */
 1485 akorotkov                1539 CBC           9 :         return jpbTrue;
 1485 akorotkov                1540 ECB             : 
 1485 akorotkov                1541 GIC       24975 :     if (error)                  /* possible only in lax mode */
 1485 akorotkov                1542 CBC         312 :         return jpbUnknown;
 1485 akorotkov                1543 ECB             : 
 1485 akorotkov                1544 GIC       24663 :     return jpbFalse;
 1485 akorotkov                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
 1485 akorotkov                1552 GIC         171 : executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
 1485 akorotkov                1553 ECB             :                         JsonbValue *jb, BinaryArithmFunc func,
                               1554                 :                         JsonValueList *found)
                               1555                 : {
                               1556                 :     JsonPathExecResult jper;
                               1557                 :     JsonPathItem elem;
 1483 akorotkov                1558 GIC         171 :     JsonValueList lseq = {0};
 1483 akorotkov                1559 CBC         171 :     JsonValueList rseq = {0};
 1485 akorotkov                1560 ECB             :     JsonbValue *lval;
                               1561                 :     JsonbValue *rval;
                               1562                 :     Numeric     res;
                               1563                 : 
 1485 akorotkov                1564 GIC         171 :     jspGetLeftArg(jsp, &elem);
 1485 akorotkov                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                 :      */
 1485 akorotkov                1570 GIC         171 :     jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &lseq);
 1485 akorotkov                1571 CBC         168 :     if (jperIsError(jper))
 1485 akorotkov                1572 LBC           0 :         return jper;
 1485 akorotkov                1573 EUB             : 
 1485 akorotkov                1574 GIC         168 :     jspGetRightArg(jsp, &elem);
 1485 akorotkov                1575 ECB             : 
 1485 akorotkov                1576 GIC         168 :     jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &rseq);
 1485 akorotkov                1577 CBC         165 :     if (jperIsError(jper))
 1485 akorotkov                1578 LBC           0 :         return jper;
 1485 akorotkov                1579 EUB             : 
 1485 akorotkov                1580 GIC         297 :     if (JsonValueListLength(&lseq) != 1 ||
 1485 akorotkov                1581 CBC         132 :         !(lval = getScalar(JsonValueListHead(&lseq), jbvNumeric)))
                               1582              33 :         RETURN_ERROR(ereport(ERROR,
 1326 peter                    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                 : 
 1485 akorotkov                1587 GIC         249 :     if (JsonValueListLength(&rseq) != 1 ||
 1485 akorotkov                1588 CBC         117 :         !(rval = getScalar(JsonValueListHead(&rseq), jbvNumeric)))
                               1589              27 :         RETURN_ERROR(ereport(ERROR,
 1326 peter                    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                 : 
 1485 akorotkov                1594 GIC         105 :     if (jspThrowErrors(cxt))
 1485 akorotkov                1595 ECB             :     {
 1485 akorotkov                1596 GIC          39 :         res = func(lval->val.numeric, rval->val.numeric, NULL);
 1485 akorotkov                1597 ECB             :     }
                               1598                 :     else
                               1599                 :     {
 1485 akorotkov                1600 GIC          66 :         bool        error = false;
 1485 akorotkov                1601 ECB             : 
 1485 akorotkov                1602 GIC          66 :         res = func(lval->val.numeric, rval->val.numeric, &error);
 1485 akorotkov                1603 ECB             : 
 1485 akorotkov                1604 GIC          66 :         if (error)
 1485 akorotkov                1605 CBC           6 :             return jperError;
 1485 akorotkov                1606 ECB             :     }
                               1607                 : 
 1485 akorotkov                1608 GIC          87 :     if (!jspGetNext(jsp, &elem) && !found)
 1485 akorotkov                1609 CBC           3 :         return jperOk;
 1485 akorotkov                1610 ECB             : 
 1485 akorotkov                1611 GIC          84 :     lval = palloc(sizeof(*lval));
 1485 akorotkov                1612 CBC          84 :     lval->type = jbvNumeric;
                               1613              84 :     lval->val.numeric = res;
 1485 akorotkov                1614 ECB             : 
 1485 akorotkov                1615 GIC          84 :     return executeNextItem(cxt, jsp, &elem, lval, found, false);
 1485 akorotkov                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
 1485 akorotkov                1623 GIC          93 : executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp,
 1485 akorotkov                1624 ECB             :                        JsonbValue *jb, PGFunction func, JsonValueList *found)
                               1625                 : {
                               1626                 :     JsonPathExecResult jper;
                               1627                 :     JsonPathExecResult jper2;
                               1628                 :     JsonPathItem elem;
 1483 akorotkov                1629 GIC          93 :     JsonValueList seq = {0};
 1485 akorotkov                1630 ECB             :     JsonValueListIterator it;
                               1631                 :     JsonbValue *val;
                               1632                 :     bool        hasNext;
                               1633                 : 
 1485 akorotkov                1634 GIC          93 :     jspGetArg(jsp, &elem);
 1485 akorotkov                1635 CBC          93 :     jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &seq);
 1485 akorotkov                1636 ECB             : 
 1485 akorotkov                1637 GIC          90 :     if (jperIsError(jper))
 1485 akorotkov                1638 LBC           0 :         return jper;
 1485 akorotkov                1639 EUB             : 
 1485 akorotkov                1640 GIC          90 :     jper = jperNotFound;
 1485 akorotkov                1641 ECB             : 
 1485 akorotkov                1642 GIC          90 :     hasNext = jspGetNext(jsp, &elem);
 1485 akorotkov                1643 ECB             : 
 1485 akorotkov                1644 GIC          90 :     JsonValueListInitIterator(&seq, &it);
 1485 akorotkov                1645 CBC         162 :     while ((val = JsonValueListNext(&seq, &it)))
 1485 akorotkov                1646 ECB             :     {
 1485 akorotkov                1647 GIC          96 :         if ((val = getScalar(val, jbvNumeric)))
 1485 akorotkov                1648 ECB             :         {
 1485 akorotkov                1649 GIC          75 :             if (!found && !hasNext)
 1485 akorotkov                1650 CBC           6 :                 return jperOk;
 1485 akorotkov                1651 ECB             :         }
                               1652                 :         else
                               1653                 :         {
 1485 akorotkov                1654 GIC          21 :             if (!found && !hasNext)
 1485 akorotkov                1655 CBC           3 :                 continue;       /* skip non-numerics processing */
 1485 akorotkov                1656 ECB             : 
 1485 akorotkov                1657 GIC          18 :             RETURN_ERROR(ereport(ERROR,
 1326 peter                    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                 : 
 1485 akorotkov                1663 GIC          69 :         if (func)
 1485 akorotkov                1664 CBC          42 :             val->val.numeric =
                               1665              42 :                 DatumGetNumeric(DirectFunctionCall1(func,
 1485 akorotkov                1666 ECB             :                                                     NumericGetDatum(val->val.numeric)));
                               1667                 : 
 1485 akorotkov                1668 GIC          69 :         jper2 = executeNextItem(cxt, jsp, &elem, val, found, false);
 1485 akorotkov                1669 ECB             : 
 1485 akorotkov                1670 GIC          69 :         if (jperIsError(jper2))
 1485 akorotkov                1671 LBC           0 :             return jper2;
 1485 akorotkov                1672 EUB             : 
 1485 akorotkov                1673 GIC          69 :         if (jper2 == jperOk)
 1485 akorotkov                1674 ECB             :         {
 1485 akorotkov                1675 GIC          69 :             if (!found)
 1485 akorotkov                1676 LBC           0 :                 return jperOk;
 1485 akorotkov                1677 GBC          69 :             jper = jperOk;
 1485 akorotkov                1678 ECB             :         }
                               1679                 :     }
                               1680                 : 
 1485 akorotkov                1681 GIC          66 :     return jper;
 1485 akorotkov                1682 ECB             : }
                               1683                 : 
                               1684                 : /*
                               1685                 :  * STARTS_WITH predicate callback.
                               1686                 :  *
                               1687                 :  * Check if the 'whole' string starts from 'initial' string.
                               1688                 :  */
                               1689                 : static JsonPathBool
 1485 akorotkov                1690 GIC          87 : executeStartsWith(JsonPathItem *jsp, JsonbValue *whole, JsonbValue *initial,
 1485 akorotkov                1691 ECB             :                   void *param)
                               1692                 : {
 1485 akorotkov                1693 GIC          87 :     if (!(whole = getScalar(whole, jbvString)))
 1485 akorotkov                1694 CBC          24 :         return jpbUnknown;      /* error */
 1485 akorotkov                1695 ECB             : 
 1485 akorotkov                1696 GIC          63 :     if (!(initial = getScalar(initial, jbvString)))
 1485 akorotkov                1697 LBC           0 :         return jpbUnknown;      /* error */
 1485 akorotkov                1698 EUB             : 
 1485 akorotkov                1699 GIC          63 :     if (whole->val.string.len >= initial->val.string.len &&
 1485 akorotkov                1700 CBC          45 :         !memcmp(whole->val.string.val,
                               1701              45 :                 initial->val.string.val,
                               1702              45 :                 initial->val.string.len))
                               1703              27 :         return jpbTrue;
 1485 akorotkov                1704 ECB             : 
 1485 akorotkov                1705 GIC          36 :     return jpbFalse;
 1485 akorotkov                1706 ECB             : }
                               1707                 : 
                               1708                 : /*
                               1709                 :  * LIKE_REGEX predicate callback.
                               1710                 :  *
                               1711                 :  * Check if the string matches regex pattern.
                               1712                 :  */
                               1713                 : static JsonPathBool
 1485 akorotkov                1714 GIC         198 : executeLikeRegex(JsonPathItem *jsp, JsonbValue *str, JsonbValue *rarg,
 1485 akorotkov                1715 ECB             :                  void *param)
                               1716                 : {
 1485 akorotkov                1717 GIC         198 :     JsonLikeRegexContext *cxt = param;
 1485 akorotkov                1718 ECB             : 
 1485 akorotkov                1719 GIC         198 :     if (!(str = getScalar(str, jbvString)))
 1485 akorotkov                1720 CBC          60 :         return jpbUnknown;
 1485 akorotkov                1721 ECB             : 
                               1722                 :     /* Cache regex text and converted flags. */
 1485 akorotkov                1723 GIC         138 :     if (!cxt->regex)
 1485 akorotkov                1724 ECB             :     {
 1485 akorotkov                1725 GIC         138 :         cxt->regex =
 1485 akorotkov                1726 CBC         138 :             cstring_to_text_with_len(jsp->content.like_regex.pattern,
 1485 akorotkov                1727 ECB             :                                      jsp->content.like_regex.patternlen);
  106 andrew                   1728 GNC         138 :         (void) jspConvertRegexFlags(jsp->content.like_regex.flags,
                               1729                 :                                     &(cxt->cflags), NULL);
 1485 akorotkov                1730 ECB             :     }
                               1731                 : 
 1485 akorotkov                1732 GIC         138 :     if (RE_compile_and_execute(cxt->regex, str->val.string.val,
                               1733                 :                                str->val.string.len,
 1485 akorotkov                1734 ECB             :                                cxt->cflags, DEFAULT_COLLATION_OID, 0, NULL))
 1485 akorotkov                1735 GIC          51 :         return jpbTrue;
                               1736                 : 
 1485 akorotkov                1737 CBC          87 :     return jpbFalse;
                               1738                 : }
 1485 akorotkov                1739 ECB             : 
                               1740                 : /*
                               1741                 :  * Execute numeric item methods (.abs(), .floor(), .ceil()) using the specified
                               1742                 :  * user function 'func'.
                               1743                 :  */
                               1744                 : static JsonPathExecResult
 1485 akorotkov                1745 GIC         129 : executeNumericItemMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
                               1746                 :                          JsonbValue *jb, bool unwrap, PGFunction func,
 1485 akorotkov                1747 ECB             :                          JsonValueList *found)
                               1748                 : {
                               1749                 :     JsonPathItem next;
                               1750                 :     Datum       datum;
                               1751                 : 
 1485 akorotkov                1752 GIC         129 :     if (unwrap && JsonbType(jb) == jbvArray)
 1485 akorotkov                1753 UIC           0 :         return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
 1485 akorotkov                1754 ECB             : 
 1485 akorotkov                1755 GBC         129 :     if (!(jb = getScalar(jb, jbvNumeric)))
 1485 akorotkov                1756 GIC          18 :         RETURN_ERROR(ereport(ERROR,
 1326 peter                    1757 ECB             :                              (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
 1447 akorotkov                1758                 :                               errmsg("jsonpath item method .%s() can only be applied to a numeric value",
                               1759                 :                                      jspOperationName(jsp->type)))));
                               1760                 : 
 1442 tgl                      1761 GIC         111 :     datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
                               1762                 : 
 1485 akorotkov                1763 CBC         111 :     if (!jspGetNext(jsp, &next) && !found)
 1485 akorotkov                1764 UIC           0 :         return jperOk;
 1485 akorotkov                1765 ECB             : 
 1485 akorotkov                1766 GBC         111 :     jb = palloc(sizeof(*jb));
 1485 akorotkov                1767 GIC         111 :     jb->type = jbvNumeric;
 1485 akorotkov                1768 CBC         111 :     jb->val.numeric = DatumGetNumeric(datum);
 1485 akorotkov                1769 ECB             : 
 1485 akorotkov                1770 CBC         111 :     return executeNextItem(cxt, jsp, &next, jb, found, false);
                               1771                 : }
 1485 akorotkov                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
 1292 akorotkov                1781 GIC        1608 : executeDateTimeMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
                               1782                 :                       JsonbValue *jb, JsonValueList *found)
 1292 akorotkov                1783 ECB             : {
                               1784                 :     JsonbValue  jbvbuf;
                               1785                 :     Datum       value;
                               1786                 :     text       *datetime;
                               1787                 :     Oid         collid;
                               1788                 :     Oid         typid;
 1292 akorotkov                1789 GIC        1608 :     int32       typmod = -1;
                               1790            1608 :     int         tz = 0;
 1292 akorotkov                1791 ECB             :     bool        hasNext;
 1292 akorotkov                1792 CBC        1608 :     JsonPathExecResult res = jperNotFound;
                               1793                 :     JsonPathItem elem;
 1292 akorotkov                1794 ECB             : 
 1292 akorotkov                1795 GIC        1608 :     if (!(jb = getScalar(jb, jbvString)))
                               1796              15 :         RETURN_ERROR(ereport(ERROR,
 1074 peter                    1797 ECB             :                              (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
 1292 akorotkov                1798                 :                               errmsg("jsonpath item method .%s() can only be applied to a string",
                               1799                 :                                      jspOperationName(jsp->type)))));
                               1800                 : 
 1292 akorotkov                1801 GIC        1593 :     datetime = cstring_to_text_with_len(jb->val.string.val,
                               1802                 :                                         jb->val.string.len);
 1292 akorotkov                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                 :      */
 1132 tgl                      1809 GIC        1593 :     collid = DEFAULT_COLLATION_OID;
                               1810                 : 
 1292 akorotkov                1811 CBC        1593 :     if (jsp->content.arg)
                               1812                 :     {
 1292 akorotkov                1813 ECB             :         text       *template;
                               1814                 :         char       *template_str;
                               1815                 :         int         template_len;
  121 tgl                      1816 GNC         825 :         ErrorSaveContext escontext = {T_ErrorSaveContext};
                               1817                 : 
 1292 akorotkov                1818 CBC         825 :         jspGetArg(jsp, &elem);
                               1819                 : 
                               1820             825 :         if (elem.type != jpiString)
 1292 akorotkov                1821 UIC           0 :             elog(ERROR, "invalid jsonpath item type for .datetime() argument");
 1292 akorotkov                1822 ECB             : 
 1292 akorotkov                1823 GBC         825 :         template_str = jspGetString(&elem, &template_len);
                               1824                 : 
 1292 akorotkov                1825 CBC         825 :         template = cstring_to_text_with_len(template_str,
                               1826                 :                                             template_len);
 1292 akorotkov                1827 ECB             : 
 1132 tgl                      1828 GIC         825 :         value = parse_datetime(datetime, template, collid, true,
                               1829                 :                                &typid, &typmod, &tz,
  121 tgl                      1830 GNC         825 :                                jspThrowErrors(cxt) ? NULL : (Node *) &escontext);
                               1831                 : 
                               1832             795 :         if (escontext.error_occurred)
 1292 akorotkov                1833 UIC           0 :             res = jperError;
 1292 akorotkov                1834 ECB             :         else
 1292 akorotkov                1835 GBC         795 :             res = jperOk;
                               1836                 :     }
 1292 akorotkov                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 */
 1292 akorotkov                1865 GIC        3414 :         for (i = 0; i < lengthof(fmt_str); i++)
                               1866                 :         {
  121 tgl                      1867 GNC        3408 :             ErrorSaveContext escontext = {T_ErrorSaveContext};
                               1868                 : 
 1292 akorotkov                1869 CBC        3408 :             if (!fmt_txt[i])
                               1870                 :             {
 1292 akorotkov                1871 ECB             :                 MemoryContext oldcxt =
 1292 akorotkov                1872 GIC          30 :                 MemoryContextSwitchTo(TopMemoryContext);
                               1873                 : 
 1292 akorotkov                1874 CBC          30 :                 fmt_txt[i] = cstring_to_text(fmt_str[i]);
 1292 akorotkov                1875 GIC          30 :                 MemoryContextSwitchTo(oldcxt);
 1292 akorotkov                1876 ECB             :             }
                               1877                 : 
 1132 tgl                      1878 GIC        3408 :             value = parse_datetime(datetime, fmt_txt[i], collid, true,
                               1879                 :                                    &typid, &typmod, &tz,
                               1880                 :                                    (Node *) &escontext);
                               1881                 : 
  121 tgl                      1882 GNC        3408 :             if (!escontext.error_occurred)
                               1883                 :             {
 1292 akorotkov                1884 CBC         762 :                 res = jperOk;
 1292 akorotkov                1885 GIC         762 :                 break;
 1292 akorotkov                1886 ECB             :             }
                               1887                 :         }
                               1888                 : 
 1292 akorotkov                1889 GIC         768 :         if (res == jperNotFound)
                               1890               6 :             RETURN_ERROR(ereport(ERROR,
 1074 peter                    1891 ECB             :                                  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
 1132 tgl                      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                 : 
 1292 akorotkov                1897 GIC        1557 :     pfree(datetime);
                               1898                 : 
 1292 akorotkov                1899 CBC        1557 :     if (jperIsError(res))
 1292 akorotkov                1900 UIC           0 :         return res;
 1292 akorotkov                1901 ECB             : 
 1292 akorotkov                1902 GBC        1557 :     hasNext = jspGetNext(jsp, &elem);
                               1903                 : 
 1292 akorotkov                1904 CBC        1557 :     if (!hasNext && !found)
 1292 akorotkov                1905 GIC           3 :         return res;
 1292 akorotkov                1906 ECB             : 
 1292 akorotkov                1907 CBC        1554 :     jb = hasNext ? &jbvbuf : palloc(sizeof(*jb));
                               1908                 : 
                               1909            1554 :     jb->type = jbvDatetime;
 1292 akorotkov                1910 GIC        1554 :     jb->val.datetime.value = value;
 1292 akorotkov                1911 CBC        1554 :     jb->val.datetime.typid = typid;
                               1912            1554 :     jb->val.datetime.typmod = typmod;
                               1913            1554 :     jb->val.datetime.tz = tz;
 1292 akorotkov                1914 ECB             : 
 1292 akorotkov                1915 CBC        1554 :     return executeNextItem(cxt, jsp, &elem, jb, found, hasNext);
                               1916                 : }
 1292 akorotkov                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
 1485 akorotkov                1942 GIC          42 : executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp,
                               1943                 :                       JsonbValue *jb, JsonValueList *found)
 1485 akorotkov                1944 ECB             : {
 1485 akorotkov                1945 GIC          42 :     JsonPathExecResult res = jperNotFound;
                               1946                 :     JsonPathItem next;
 1485 akorotkov                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                 : 
 1485 akorotkov                1959 GIC          42 :     if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
                               1960              12 :         RETURN_ERROR(ereport(ERROR,
 1326 peter                    1961 ECB             :                              (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
 1447 akorotkov                1962                 :                               errmsg("jsonpath item method .%s() can only be applied to an object",
                               1963                 :                                      jspOperationName(jsp->type)))));
                               1964                 : 
 1485 akorotkov                1965 GIC          30 :     jbc = jb->val.binary.data;
                               1966                 : 
 1485 akorotkov                1967 CBC          30 :     if (!JsonContainerSize(jbc))
 1485 akorotkov                1968 GIC           9 :         return jperNotFound;    /* no key-value pairs */
 1485 akorotkov                1969 ECB             : 
 1485 akorotkov                1970 CBC          21 :     hasNext = jspGetNext(jsp, &next);
                               1971                 : 
                               1972              21 :     keystr.type = jbvString;
 1485 akorotkov                1973 GIC          21 :     keystr.val.string.val = "key";
 1485 akorotkov                1974 CBC          21 :     keystr.val.string.len = 3;
 1485 akorotkov                1975 ECB             : 
 1485 akorotkov                1976 CBC          21 :     valstr.type = jbvString;
 1485 akorotkov                1977 GIC          21 :     valstr.val.string.val = "value";
 1485 akorotkov                1978 CBC          21 :     valstr.val.string.len = 5;
 1485 akorotkov                1979 ECB             : 
 1485 akorotkov                1980 CBC          21 :     idstr.type = jbvString;
 1485 akorotkov                1981 GIC          21 :     idstr.val.string.val = "id";
 1485 akorotkov                1982 CBC          21 :     idstr.val.string.len = 2;
 1485 akorotkov                1983 ECB             : 
                               1984                 :     /* construct object id from its base object and offset inside that */
 1485 akorotkov                1985 GIC          21 :     id = jb->type != jbvBinary ? 0 :
                               1986              21 :         (int64) ((char *) jbc - (char *) cxt->baseObject.jbc);
 1485 akorotkov                1987 CBC          21 :     id += (int64) cxt->baseObject.id * INT64CONST(10000000000);
 1485 akorotkov                1988 ECB             : 
 1485 akorotkov                1989 CBC          21 :     idval.type = jbvNumeric;
  942 peter                    1990 GIC          21 :     idval.val.numeric = int64_to_numeric(id);
 1485 akorotkov                1991 ECB             : 
 1485 akorotkov                1992 CBC          21 :     it = JsonbIteratorInit(jbc);
                               1993                 : 
                               1994              84 :     while ((tok = JsonbIteratorNext(&it, &key, true)) != WJB_DONE)
                               1995                 :     {
 1485 akorotkov                1996 ECB             :         JsonBaseObjectInfo baseObject;
                               1997                 :         JsonbValue  obj;
                               1998                 :         JsonbParseState *ps;
                               1999                 :         JsonbValue *keyval;
                               2000                 :         Jsonb      *jsonb;
                               2001                 : 
 1485 akorotkov                2002 GIC          69 :         if (tok != WJB_KEY)
                               2003              36 :             continue;
 1485 akorotkov                2004 ECB             : 
 1485 akorotkov                2005 CBC          33 :         res = jperOk;
                               2006                 : 
                               2007              33 :         if (!hasNext && !found)
 1485 akorotkov                2008 GIC           6 :             break;
 1485 akorotkov                2009 ECB             : 
 1485 akorotkov                2010 CBC          30 :         tok = JsonbIteratorNext(&it, &val, true);
 1485 akorotkov                2011 GIC          30 :         Assert(tok == WJB_VALUE);
 1485 akorotkov                2012 ECB             : 
 1485 akorotkov                2013 CBC          30 :         ps = NULL;
 1485 akorotkov                2014 GIC          30 :         pushJsonbValue(&ps, WJB_BEGIN_OBJECT, NULL);
 1485 akorotkov                2015 ECB             : 
 1485 akorotkov                2016 CBC          30 :         pushJsonbValue(&ps, WJB_KEY, &keystr);
 1485 akorotkov                2017 GIC          30 :         pushJsonbValue(&ps, WJB_VALUE, &key);
 1485 akorotkov                2018 ECB             : 
 1485 akorotkov                2019 CBC          30 :         pushJsonbValue(&ps, WJB_KEY, &valstr);
 1485 akorotkov                2020 GIC          30 :         pushJsonbValue(&ps, WJB_VALUE, &val);
 1485 akorotkov                2021 ECB             : 
 1485 akorotkov                2022 CBC          30 :         pushJsonbValue(&ps, WJB_KEY, &idstr);
 1485 akorotkov                2023 GIC          30 :         pushJsonbValue(&ps, WJB_VALUE, &idval);
 1485 akorotkov                2024 ECB             : 
 1485 akorotkov                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))
 1485 akorotkov                2038 UIC           0 :             return res;
 1485 akorotkov                2039 ECB             : 
 1485 akorotkov                2040 GBC          30 :         if (res == jperOk && !found)
 1485 akorotkov                2041 GIC           3 :             break;
 1485 akorotkov                2042 ECB             :     }
                               2043                 : 
 1485 akorotkov                2044 GIC          21 :     return res;
                               2045                 : }
 1485 akorotkov                2046 ECB             : 
                               2047                 : /*
                               2048                 :  * Convert boolean execution status 'res' to a boolean JSON item and execute
                               2049                 :  * next jsonpath.
                               2050                 :  */
                               2051                 : static JsonPathExecResult
 1485 akorotkov                2052 GIC       51081 : appendBoolResult(JsonPathExecContext *cxt, JsonPathItem *jsp,
                               2053                 :                  JsonValueList *found, JsonPathBool res)
 1485 akorotkov                2054 ECB             : {
                               2055                 :     JsonPathItem next;
                               2056                 :     JsonbValue  jbv;
                               2057                 : 
 1485 akorotkov                2058 GIC       51081 :     if (!jspGetNext(jsp, &next) && !found)
                               2059               3 :         return jperOk;          /* found singleton boolean value */
 1485 akorotkov                2060 ECB             : 
 1485 akorotkov                2061 CBC       51078 :     if (res == jpbUnknown)
                               2062                 :     {
                               2063              15 :         jbv.type = jbvNull;
                               2064                 :     }
 1485 akorotkov                2065 ECB             :     else
                               2066                 :     {
 1485 akorotkov                2067 GIC       51063 :         jbv.type = jbvBool;
                               2068           51063 :         jbv.val.boolean = res == jpbTrue;
 1485 akorotkov                2069 ECB             :     }
                               2070                 : 
 1485 akorotkov                2071 GIC       51078 :     return executeNextItem(cxt, jsp, &next, &jbv, found, true);
                               2072                 : }
 1485 akorotkov                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
 1485 akorotkov                2080 GIC       27768 : getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
                               2081                 :                 JsonbValue *value)
 1485 akorotkov                2082 ECB             : {
 1485 akorotkov                2083 GIC       27768 :     switch (item->type)
                               2084                 :     {
 1485 akorotkov                2085 CBC        3777 :         case jpiNull:
 1485 akorotkov                2086 GIC        3777 :             value->type = jbvNull;
 1485 akorotkov                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:
  220 andrew                   2102            2625 :             getJsonPathVariable(cxt, item, cxt->vars, value);
 1485 akorotkov                2103            2610 :             return;
 1485 akorotkov                2104 LBC           0 :         default:
                               2105               0 :             elog(ERROR, "unexpected jsonpath item type");
 1485 akorotkov                2106 EUB             :     }
                               2107                 : }
                               2108                 : 
                               2109                 : /*
                               2110                 :  * Get the value of variable passed to jsonpath executor
                               2111                 :  */
                               2112                 : static void
 1485 akorotkov                2113 GIC        2625 : getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
                               2114                 :                     Jsonb *vars, JsonbValue *value)
 1485 akorotkov                2115 ECB             : {
                               2116                 :     char       *varName;
                               2117                 :     int         varNameLength;
                               2118                 :     JsonbValue  tmp;
                               2119                 :     JsonbValue *v;
                               2120                 : 
  220 andrew                   2121 GIC        2625 :     if (!vars)
                               2122                 :     {
  220 andrew                   2123 LBC           0 :         value->type = jbvNull;
  220 andrew                   2124 UIC           0 :         return;
 1485 akorotkov                2125 EUB             :     }
                               2126                 : 
  220 andrew                   2127 GIC        2625 :     Assert(variable->type == jpiVariable);
                               2128            2625 :     varName = jspGetString(variable, &varNameLength);
 1485 akorotkov                2129 CBC        2625 :     tmp.type = jbvString;
                               2130            2625 :     tmp.val.string.val = varName;
                               2131            2625 :     tmp.val.string.len = varNameLength;
 1485 akorotkov                2132 ECB             : 
 1485 akorotkov                2133 CBC        2625 :     v = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
                               2134                 : 
  220 andrew                   2135            2625 :     if (v)
                               2136                 :     {
                               2137            2610 :         *value = *v;
  220 andrew                   2138 GIC        2610 :         pfree(v);
  220 andrew                   2139 ECB             :     }
                               2140                 :     else
                               2141                 :     {
  220 andrew                   2142 GIC          15 :         ereport(ERROR,
                               2143                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
  220 andrew                   2144 ECB             :                  errmsg("could not find jsonpath variable \"%s\"",
                               2145                 :                         pnstrdup(varName, varNameLength))));
                               2146                 :     }
                               2147                 : 
  220 andrew                   2148 GIC        2610 :     JsonbInitBinary(&tmp, vars);
                               2149            2610 :     setBaseObject(cxt, &tmp, 1);
 1485 akorotkov                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
 1485 akorotkov                2158 GIC         174 : JsonbArraySize(JsonbValue *jb)
                               2159                 : {
 1485 akorotkov                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))
 1485 akorotkov                2167 GIC         147 :             return JsonContainerSize(jbc);
 1485 akorotkov                2168 ECB             :     }
                               2169                 : 
 1485 akorotkov                2170 GIC          27 :     return -1;
                               2171                 : }
 1485 akorotkov                2172 ECB             : 
                               2173                 : /* Comparison predicate callback. */
                               2174                 : static JsonPathBool
 1485 akorotkov                2175 GIC        8280 : executeComparison(JsonPathItem *cmp, JsonbValue *lv, JsonbValue *rv, void *p)
                               2176                 : {
 1292 akorotkov                2177 CBC        8280 :     JsonPathExecContext *cxt = (JsonPathExecContext *) p;
                               2178                 : 
                               2179            8280 :     return compareItems(cmp->type, lv, rv, cxt->useTz);
                               2180                 : }
 1485 akorotkov                2181 ECB             : 
                               2182                 : /*
                               2183                 :  * Perform per-byte comparison of two strings.
                               2184                 :  */
                               2185                 : static int
 1337 akorotkov                2186 GIC        1728 : binaryCompareStrings(const char *s1, int len1,
                               2187                 :                      const char *s2, int len2)
 1337 akorotkov                2188 ECB             : {
                               2189                 :     int         cmp;
                               2190                 : 
 1337 akorotkov                2191 GIC        1728 :     cmp = memcmp(s1, s2, Min(len1, len2));
                               2192                 : 
 1337 akorotkov                2193 CBC        1728 :     if (cmp != 0)
 1337 akorotkov                2194 GIC         984 :         return cmp;
 1337 akorotkov                2195 ECB             : 
 1337 akorotkov                2196 CBC         744 :     if (len1 == len2)
 1337 akorotkov                2197 GIC         144 :         return 0;
 1337 akorotkov                2198 ECB             : 
 1337 akorotkov                2199 CBC         600 :     return len1 < len2 ? -1 : 1;
                               2200                 : }
 1337 akorotkov                2201 ECB             : 
                               2202                 : /*
                               2203                 :  * Compare two strings in the current server encoding using Unicode codepoint
                               2204                 :  * collation.
                               2205                 :  */
                               2206                 : static int
 1337 akorotkov                2207 GIC        1728 : compareStrings(const char *mbstr1, int mblen1,
                               2208                 :                const char *mbstr2, int mblen2)
 1337 akorotkov                2209 ECB             : {
 1337 akorotkov                2210 GIC        3456 :     if (GetDatabaseEncoding() == PG_SQL_ASCII ||
                               2211            1728 :         GetDatabaseEncoding() == PG_UTF8)
 1337 akorotkov                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                 :          */
 1337 akorotkov                2218 GIC        1728 :         return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
                               2219                 :     }
 1337 akorotkov                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                 :          */
 1336 akorotkov                2234 UIC           0 :         utf8str1 = pg_server_to_any(mbstr1, mblen1, PG_UTF8);
                               2235               0 :         utf8str2 = pg_server_to_any(mbstr2, mblen2, PG_UTF8);
 1336 akorotkov                2236 UBC           0 :         utf8len1 = (mbstr1 == utf8str1) ? mblen1 : strlen(utf8str1);
                               2237               0 :         utf8len2 = (mbstr2 == utf8str2) ? mblen2 : strlen(utf8str2);
 1336 akorotkov                2238 EUB             : 
 1336 akorotkov                2239 UBC           0 :         cmp = binaryCompareStrings(utf8str1, utf8len1, utf8str2, utf8len2);
                               2240                 : 
 1336 akorotkov                2241 EUB             :         /*
                               2242                 :          * If pg_server_to_any() did no real conversion, then we actually
                               2243                 :          * compared original strings.  So, we already done.
                               2244                 :          */
 1336 akorotkov                2245 UIC           0 :         if (mbstr1 == utf8str1 && mbstr2 == utf8str2)
                               2246               0 :             return cmp;
 1336 akorotkov                2247 EUB             : 
                               2248                 :         /* Free memory if needed */
 1336 akorotkov                2249 UIC           0 :         if (mbstr1 != utf8str1)
                               2250               0 :             pfree(utf8str1);
 1336 akorotkov                2251 UBC           0 :         if (mbstr2 != utf8str2)
                               2252               0 :             pfree(utf8str2);
 1337 akorotkov                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                 :          */
 1337 akorotkov                2263 UIC           0 :         if (cmp == 0)
                               2264               0 :             return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
 1337 akorotkov                2265 EUB             :         else
 1337 akorotkov                2266 UBC           0 :             return cmp;
                               2267                 :     }
 1337 akorotkov                2268 EUB             : }
                               2269                 : 
                               2270                 : /*
                               2271                 :  * Compare two SQL/JSON items using comparison operation 'op'.
                               2272                 :  */
                               2273                 : static JsonPathBool
 1292 akorotkov                2274 GIC        8280 : compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2, bool useTz)
                               2275                 : {
 1485 akorotkov                2276 ECB             :     int         cmp;
                               2277                 :     bool        res;
                               2278                 : 
 1485 akorotkov                2279 GIC        8280 :     if (jb1->type != jb2->type)
                               2280                 :     {
 1485 akorotkov                2281 CBC        1485 :         if (jb1->type == jbvNull || jb2->type == jbvNull)
                               2282                 : 
 1485 akorotkov                2283 ECB             :             /*
                               2284                 :              * Equality and order comparison of nulls to non-nulls returns
                               2285                 :              * always false, but inequality comparison returns true.
                               2286                 :              */
 1485 akorotkov                2287 GIC        1362 :             return op == jpiNotEqual ? jpbTrue : jpbFalse;
                               2288                 : 
 1485 akorotkov                2289 ECB             :         /* Non-null items of different types are not comparable. */
 1485 akorotkov                2290 GIC         123 :         return jpbUnknown;
                               2291                 :     }
 1485 akorotkov                2292 ECB             : 
 1485 akorotkov                2293 GIC        6795 :     switch (jb1->type)
                               2294                 :     {
 1485 akorotkov                2295 CBC          93 :         case jbvNull:
 1485 akorotkov                2296 GIC          93 :             cmp = 0;
 1485 akorotkov                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;
 1485 akorotkov                2311 ECB             : 
 1337 akorotkov                2312 CBC        1728 :             cmp = compareStrings(jb1->val.string.val, jb1->val.string.len,
 1337 akorotkov                2313 GIC        1728 :                                  jb2->val.string.val, jb2->val.string.len);
 1485 akorotkov                2314 CBC        1728 :             break;
 1292                          2315             714 :         case jbvDatetime:
 1292 akorotkov                2316 ECB             :             {
 1266                          2317                 :                 bool        cast_error;
                               2318                 : 
 1292 akorotkov                2319 GIC         714 :                 cmp = compareDatetime(jb1->val.datetime.value,
                               2320                 :                                       jb1->val.datetime.typid,
 1292 akorotkov                2321 ECB             :                                       jb2->val.datetime.value,
                               2322                 :                                       jb2->val.datetime.typid,
                               2323                 :                                       useTz,
                               2324                 :                                       &cast_error);
                               2325                 : 
 1266 akorotkov                2326 GIC         669 :                 if (cast_error)
 1292                          2327             126 :                     return jpbUnknown;
 1292 akorotkov                2328 ECB             :             }
 1292 akorotkov                2329 CBC         543 :             break;
                               2330                 : 
 1485                          2331               6 :         case jbvBinary:
                               2332                 :         case jbvArray:
 1485 akorotkov                2333 ECB             :         case jbvObject:
 1485 akorotkov                2334 GIC           6 :             return jpbUnknown;  /* non-scalars are not comparable */
                               2335                 : 
 1485 akorotkov                2336 LBC           0 :         default:
 1485 akorotkov                2337 UIC           0 :             elog(ERROR, "invalid jsonb value type %d", jb1->type);
 1485 akorotkov                2338 EUB             :     }
                               2339                 : 
 1485 akorotkov                2340 GIC        3381 :     switch (op)
                               2341                 :     {
 1485 akorotkov                2342 CBC         843 :         case jpiEqual:
 1485 akorotkov                2343 GIC         843 :             res = (cmp == 0);
 1485 akorotkov                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;
 1485 akorotkov                2360 LBC           0 :         default:
                               2361               0 :             elog(ERROR, "unrecognized jsonpath operation: %d", op);
 1485 akorotkov                2362 EUB             :             return jpbUnknown;
                               2363                 :     }
                               2364                 : 
 1485 akorotkov                2365 GIC        3381 :     return res ? jpbTrue : jpbFalse;
                               2366                 : }
 1485 akorotkov                2367 ECB             : 
                               2368                 : /* Compare two numerics */
                               2369                 : static int
 1485 akorotkov                2370 GIC         582 : compareNumeric(Numeric a, Numeric b)
                               2371                 : {
 1485 akorotkov                2372 CBC         582 :     return DatumGetInt32(DirectFunctionCall2(numeric_cmp,
                               2373                 :                                              NumericGetDatum(a),
 1442 tgl                      2374 ECB             :                                              NumericGetDatum(b)));
                               2375                 : }
                               2376                 : 
                               2377                 : static JsonbValue *
 1485 akorotkov                2378 GIC       55389 : copyJsonbValue(JsonbValue *src)
                               2379                 : {
 1485 akorotkov                2380 CBC       55389 :     JsonbValue *dst = palloc(sizeof(*dst));
                               2381                 : 
                               2382           55389 :     *dst = *src;
                               2383                 : 
                               2384           55389 :     return dst;
                               2385                 : }
 1485 akorotkov                2386 ECB             : 
                               2387                 : /*
                               2388                 :  * Execute array subscript expression and convert resulting numeric item to
                               2389                 :  * the integer type with truncation.
                               2390                 :  */
                               2391                 : static JsonPathExecResult
 1485 akorotkov                2392 GIC         159 : getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb,
                               2393                 :               int32 *index)
 1485 akorotkov                2394 ECB             : {
                               2395                 :     JsonbValue *jbv;
 1483 akorotkov                2396 GIC         159 :     JsonValueList found = {0};
 1485                          2397             159 :     JsonPathExecResult res = executeItem(cxt, jsp, jb, &found);
 1485 akorotkov                2398 ECB             :     Datum       numeric_index;
 1485 akorotkov                2399 CBC         156 :     bool        have_error = false;
                               2400                 : 
                               2401             156 :     if (jperIsError(res))
 1485 akorotkov                2402 UIC           0 :         return res;
 1485 akorotkov                2403 ECB             : 
 1485 akorotkov                2404 GBC         306 :     if (JsonValueListLength(&found) != 1 ||
 1485 akorotkov                2405 GIC         150 :         !(jbv = getScalar(JsonValueListHead(&found), jbvNumeric)))
 1485 akorotkov                2406 CBC          12 :         RETURN_ERROR(ereport(ERROR,
 1326 peter                    2407 ECB             :                              (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
 1447 akorotkov                2408                 :                               errmsg("jsonpath array subscript is not a single numeric value"))));
                               2409                 : 
 1485 akorotkov                2410 GIC         144 :     numeric_index = DirectFunctionCall2(numeric_trunc,
                               2411                 :                                         NumericGetDatum(jbv->val.numeric),
 1485 akorotkov                2412 ECB             :                                         Int32GetDatum(0));
                               2413                 : 
 1485 akorotkov                2414 GIC         144 :     *index = numeric_int4_opt_error(DatumGetNumeric(numeric_index),
                               2415                 :                                     &have_error);
 1485 akorotkov                2416 ECB             : 
 1485 akorotkov                2417 GIC         144 :     if (have_error)
                               2418              12 :         RETURN_ERROR(ereport(ERROR,
 1326 peter                    2419 ECB             :                              (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
 1447 akorotkov                2420                 :                               errmsg("jsonpath array subscript is out of integer range"))));
                               2421                 : 
 1485 akorotkov                2422 GIC         132 :     return jperOk;
                               2423                 : }
 1485 akorotkov                2424 ECB             : 
                               2425                 : /* Save base object and its id needed for the execution of .keyvalue(). */
                               2426                 : static JsonBaseObjectInfo
 1485 akorotkov                2427 GIC      103845 : setBaseObject(JsonPathExecContext *cxt, JsonbValue *jbv, int32 id)
                               2428                 : {
 1485 akorotkov                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                 : }
 1485 akorotkov                2437 ECB             : 
                               2438                 : static void
 1485 akorotkov                2439 GIC      124734 : JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv)
                               2440                 : {
 1485 akorotkov                2441 CBC      124734 :     if (jvl->singleton)
                               2442                 :     {
                               2443             492 :         jvl->list = list_make2(jvl->singleton, jbv);
 1485 akorotkov                2444 GIC         492 :         jvl->singleton = NULL;
 1485 akorotkov                2445 ECB             :     }
 1485 akorotkov                2446 CBC      124242 :     else if (!jvl->list)
 1485 akorotkov                2447 GIC      123792 :         jvl->singleton = jbv;
 1485 akorotkov                2448 ECB             :     else
 1485 akorotkov                2449 CBC         450 :         jvl->list = lappend(jvl->list, jbv);
 1485 akorotkov                2450 GIC      124734 : }
 1485 akorotkov                2451 ECB             : 
                               2452                 : static int
 1485 akorotkov                2453 GIC       51585 : JsonValueListLength(const JsonValueList *jvl)
                               2454                 : {
 1485 akorotkov                2455 CBC       51585 :     return jvl->singleton ? 1 : list_length(jvl->list);
                               2456                 : }
 1485 akorotkov                2457 ECB             : 
                               2458                 : static bool
 1485 akorotkov                2459 GIC           9 : JsonValueListIsEmpty(JsonValueList *jvl)
                               2460                 : {
  235 tgl                      2461 GNC           9 :     return !jvl->singleton && (jvl->list == NIL);
                               2462                 : }
 1485 akorotkov                2463 ECB             : 
                               2464                 : static JsonbValue *
 1485 akorotkov                2465 GIC       51510 : JsonValueListHead(JsonValueList *jvl)
                               2466                 : {
 1485 akorotkov                2467 CBC       51510 :     return jvl->singleton ? jvl->singleton : linitial(jvl->list);
                               2468                 : }
 1485 akorotkov                2469 ECB             : 
                               2470                 : static List *
 1485 akorotkov                2471 GIC         708 : JsonValueListGetList(JsonValueList *jvl)
                               2472                 : {
 1485 akorotkov                2473 CBC         708 :     if (jvl->singleton)
 1485 akorotkov                2474 GIC         417 :         return list_make1(jvl->singleton);
 1485 akorotkov                2475 ECB             : 
 1485 akorotkov                2476 CBC         291 :     return jvl->list;
                               2477                 : }
 1485 akorotkov                2478 ECB             : 
                               2479                 : static void
 1485 akorotkov                2480 GIC       93621 : JsonValueListInitIterator(const JsonValueList *jvl, JsonValueListIterator *it)
                               2481                 : {
 1485 akorotkov                2482 CBC       93621 :     if (jvl->singleton)
                               2483                 :     {
                               2484           54891 :         it->value = jvl->singleton;
 1364 tgl                      2485 GIC       54891 :         it->list = NIL;
 1485 akorotkov                2486 CBC       54891 :         it->next = NULL;
 1485 akorotkov                2487 ECB             :     }
 1364 tgl                      2488 CBC       38730 :     else if (jvl->list != NIL)
                               2489                 :     {
 1485 akorotkov                2490             309 :         it->value = (JsonbValue *) linitial(jvl->list);
 1364 tgl                      2491 GIC         309 :         it->list = jvl->list;
 1364 tgl                      2492 CBC         309 :         it->next = list_second_cell(jvl->list);
 1485 akorotkov                2493 ECB             :     }
                               2494                 :     else
                               2495                 :     {
 1485 akorotkov                2496 GIC       38421 :         it->value = NULL;
 1364 tgl                      2497           38421 :         it->list = NIL;
 1485 akorotkov                2498 CBC       38421 :         it->next = NULL;
 1485 akorotkov                2499 ECB             :     }
 1485 akorotkov                2500 CBC       93621 : }
                               2501                 : 
 1485 akorotkov                2502 ECB             : /*
                               2503                 :  * Get the next item from the sequence advancing iterator.
                               2504                 :  */
                               2505                 : static JsonbValue *
 1485 akorotkov                2506 GIC      144177 : JsonValueListNext(const JsonValueList *jvl, JsonValueListIterator *it)
                               2507                 : {
 1485 akorotkov                2508 CBC      144177 :     JsonbValue *result = it->value;
                               2509                 : 
                               2510          144177 :     if (it->next)
                               2511                 :     {
                               2512             534 :         it->value = lfirst(it->next);
 1364 tgl                      2513 GIC         534 :         it->next = lnext(it->list, it->next);
 1485 akorotkov                2514 ECB             :     }
                               2515                 :     else
                               2516                 :     {
 1485 akorotkov                2517 GIC      143643 :         it->value = NULL;
                               2518                 :     }
 1485 akorotkov                2519 ECB             : 
 1485 akorotkov                2520 GIC      144177 :     return result;
                               2521                 : }
 1485 akorotkov                2522 ECB             : 
                               2523                 : /*
                               2524                 :  * Initialize a binary JsonbValue with the given jsonb container.
                               2525                 :  */
                               2526                 : static JsonbValue *
 1485 akorotkov                2527 GIC       97401 : JsonbInitBinary(JsonbValue *jbv, Jsonb *jb)
                               2528                 : {
 1485 akorotkov                2529 CBC       97401 :     jbv->type = jbvBinary;
 1485 akorotkov                2530 GIC       97401 :     jbv->val.binary.data = &jb->root;
 1485 akorotkov                2531 CBC       97401 :     jbv->val.binary.len = VARSIZE_ANY_EXHDR(jb);
 1485 akorotkov                2532 ECB             : 
 1485 akorotkov                2533 CBC       97401 :     return jbv;
                               2534                 : }
 1485 akorotkov                2535 ECB             : 
                               2536                 : /*
                               2537                 :  * Returns jbv* type of JsonbValue. Note, it never returns jbvBinary as is.
                               2538                 :  */
                               2539                 : static int
 1485 akorotkov                2540 GIC      130671 : JsonbType(JsonbValue *jb)
                               2541                 : {
 1485 akorotkov                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                 : 
 1485 akorotkov                2548 ECB             :         /* Scalars should be always extracted during jsonpath execution. */
 1485 akorotkov                2549 GIC       89724 :         Assert(!JsonContainerIsScalar(jbc));
                               2550                 : 
 1485 akorotkov                2551 CBC       89724 :         if (JsonContainerIsObject(jbc))
 1485 akorotkov                2552 GIC       88902 :             type = jbvObject;
 1485 akorotkov                2553 CBC         822 :         else if (JsonContainerIsArray(jbc))
                               2554             822 :             type = jbvArray;
 1485 akorotkov                2555 ECB             :         else
 1485 akorotkov                2556 LBC           0 :             elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
                               2557                 :     }
 1485 akorotkov                2558 EUB             : 
 1485 akorotkov                2559 GIC      130671 :     return type;
                               2560                 : }
 1485 akorotkov                2561 ECB             : 
                               2562                 : /* Get scalar of given type or NULL on type mismatch */
                               2563                 : static JsonbValue *
 1485 akorotkov                2564 GIC        2580 : getScalar(JsonbValue *scalar, enum jbvType type)
                               2565                 : {
 1485 akorotkov                2566 ECB             :     /* Scalars should be always extracted during jsonpath execution. */
 1485 akorotkov                2567 GIC        2580 :     Assert(scalar->type != jbvBinary ||
                               2568                 :            !JsonContainerIsScalar(scalar->val.binary.data));
 1485 akorotkov                2569 ECB             : 
 1485 akorotkov                2570 GIC        2580 :     return scalar->type == type ? scalar : NULL;
                               2571                 : }
 1485 akorotkov                2572 ECB             : 
                               2573                 : /* Construct a JSON array from the item list */
                               2574                 : static JsonbValue *
 1485 akorotkov                2575 GIC          21 : wrapItemsInArray(const JsonValueList *items)
                               2576                 : {
 1485 akorotkov                2577 CBC          21 :     JsonbParseState *ps = NULL;
                               2578                 :     JsonValueListIterator it;
 1485 akorotkov                2579 ECB             :     JsonbValue *jbv;
                               2580                 : 
 1485 akorotkov                2581 GIC          21 :     pushJsonbValue(&ps, WJB_BEGIN_ARRAY, NULL);
                               2582                 : 
 1485 akorotkov                2583 CBC          21 :     JsonValueListInitIterator(items, &it);
 1485 akorotkov                2584 GIC          42 :     while ((jbv = JsonValueListNext(items, &it)))
 1485 akorotkov                2585 CBC          21 :         pushJsonbValue(&ps, WJB_ELEM, jbv);
 1485 akorotkov                2586 ECB             : 
 1485 akorotkov                2587 CBC          21 :     return pushJsonbValue(&ps, WJB_END_ARRAY, NULL);
                               2588                 : }
 1292 akorotkov                2589 ECB             : 
                               2590                 : /* Check if the timezone required for casting from type1 to type2 is used */
                               2591                 : static void
 1266 akorotkov                2592 GIC         189 : checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
                               2593                 : {
 1266 akorotkov                2594 CBC         189 :     if (!useTz)
 1266 akorotkov                2595 GIC          45 :         ereport(ERROR,
 1266 akorotkov                2596 ECB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  937 peter                    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.")));
 1266 akorotkov                2600 GIC         144 : }
                               2601                 : 
 1266 akorotkov                2602 ECB             : /* Convert time datum to timetz datum */
                               2603                 : static Datum
 1266 akorotkov                2604 GIC          72 : castTimeToTimeTz(Datum time, bool useTz)
                               2605                 : {
 1266 akorotkov                2606 CBC          72 :     checkTimezoneIsUsedForCast(useTz, "time", "timetz");
                               2607                 : 
                               2608              54 :     return DirectFunctionCall1(time_timetz, time);
                               2609                 : }
 1266 akorotkov                2610 ECB             : 
                               2611                 : /*
                               2612                 :  * Compare date to timestamp.
                               2613                 :  * Note that this doesn't involve any timezone considerations.
                               2614                 :  */
                               2615                 : static int
 1266 akorotkov                2616 GIC          57 : cmpDateToTimestamp(DateADT date1, Timestamp ts2, bool useTz)
                               2617                 : {
  914 tgl                      2618 CBC          57 :     return date_cmp_timestamp_internal(date1, ts2);
                               2619                 : }
 1266 akorotkov                2620 ECB             : 
                               2621                 : /*
                               2622                 :  * Compare date to timestamptz.
                               2623                 :  */
                               2624                 : static int
 1266 akorotkov                2625 GIC          45 : cmpDateToTimestampTz(DateADT date1, TimestampTz tstz2, bool useTz)
                               2626                 : {
 1266 akorotkov                2627 CBC          45 :     checkTimezoneIsUsedForCast(useTz, "date", "timestamptz");
                               2628                 : 
  914 tgl                      2629              36 :     return date_cmp_timestamptz_internal(date1, tstz2);
                               2630                 : }
 1266 akorotkov                2631 ECB             : 
                               2632                 : /*
                               2633                 :  * Compare timestamp to timestamptz.
                               2634                 :  */
                               2635                 : static int
 1266 akorotkov                2636 GIC          72 : cmpTimestampToTimestampTz(Timestamp ts1, TimestampTz tstz2, bool useTz)
                               2637                 : {
 1266 akorotkov                2638 CBC          72 :     checkTimezoneIsUsedForCast(useTz, "timestamp", "timestamptz");
                               2639                 : 
  914 tgl                      2640              54 :     return timestamp_cmp_timestamptz_internal(ts1, tstz2);
                               2641                 : }
 1266 akorotkov                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
 1292 akorotkov                2649 GIC         714 : compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
                               2650                 :                 bool useTz, bool *cast_error)
 1292 akorotkov                2651 ECB             : {
                               2652                 :     PGFunction  cmpfunc;
                               2653                 : 
 1266 akorotkov                2654 GIC         714 :     *cast_error = false;
                               2655                 : 
 1292 akorotkov                2656 CBC         714 :     switch (typid1)
                               2657                 :     {
                               2658             111 :         case DATEOID:
                               2659                 :             switch (typid2)
 1292 akorotkov                2660 ECB             :             {
 1292 akorotkov                2661 GIC          54 :                 case DATEOID:
                               2662              54 :                     cmpfunc = date_cmp;
 1292 akorotkov                2663 ECB             : 
 1292 akorotkov                2664 CBC          54 :                     break;
                               2665                 : 
                               2666              21 :                 case TIMESTAMPOID:
 1266 akorotkov                2667 GIC          21 :                     return cmpDateToTimestamp(DatumGetDateADT(val1),
 1266 akorotkov                2668 ECB             :                                               DatumGetTimestamp(val2),
                               2669                 :                                               useTz);
                               2670                 : 
 1292 akorotkov                2671 GIC          18 :                 case TIMESTAMPTZOID:
 1266                          2672              18 :                     return cmpDateToTimestampTz(DatumGetDateADT(val1),
 1266 akorotkov                2673 ECB             :                                                 DatumGetTimestampTz(val2),
                               2674                 :                                                 useTz);
                               2675                 : 
 1292 akorotkov                2676 GIC          18 :                 case TIMEOID:
                               2677                 :                 case TIMETZOID:
 1266 akorotkov                2678 CBC          18 :                     *cast_error = true; /* uncomparable types */
 1292 akorotkov                2679 GIC          18 :                     return 0;
 1266 akorotkov                2680 ECB             : 
 1266 akorotkov                2681 LBC           0 :                 default:
 1266 akorotkov                2682 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
 1266 akorotkov                2683 EUB             :                          typid2);
 1292                          2684                 :             }
 1292 akorotkov                2685 GIC          54 :             break;
                               2686                 : 
 1292 akorotkov                2687 CBC         126 :         case TIMEOID:
                               2688                 :             switch (typid2)
 1292 akorotkov                2689 ECB             :             {
 1292 akorotkov                2690 GIC          54 :                 case TIMEOID:
                               2691              54 :                     cmpfunc = time_cmp;
 1292 akorotkov                2692 ECB             : 
 1292 akorotkov                2693 CBC          54 :                     break;
                               2694                 : 
                               2695              36 :                 case TIMETZOID:
 1266 akorotkov                2696 GIC          36 :                     val1 = castTimeToTimeTz(val1, useTz);
 1292 akorotkov                2697 CBC          27 :                     cmpfunc = timetz_cmp;
 1292 akorotkov                2698 ECB             : 
 1292 akorotkov                2699 CBC          27 :                     break;
                               2700                 : 
                               2701              36 :                 case DATEOID:
                               2702                 :                 case TIMESTAMPOID:
 1292 akorotkov                2703 ECB             :                 case TIMESTAMPTZOID:
 1266 akorotkov                2704 GIC          36 :                     *cast_error = true; /* uncomparable types */
 1292                          2705              36 :                     return 0;
 1266 akorotkov                2706 ECB             : 
 1266 akorotkov                2707 LBC           0 :                 default:
 1266 akorotkov                2708 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
 1266 akorotkov                2709 EUB             :                          typid2);
 1292                          2710                 :             }
 1292 akorotkov                2711 GIC          81 :             break;
                               2712                 : 
 1292 akorotkov                2713 CBC         162 :         case TIMETZOID:
                               2714                 :             switch (typid2)
 1292 akorotkov                2715 ECB             :             {
 1292 akorotkov                2716 GIC          36 :                 case TIMEOID:
 1266                          2717              36 :                     val2 = castTimeToTimeTz(val2, useTz);
 1292 akorotkov                2718 CBC          27 :                     cmpfunc = timetz_cmp;
 1292 akorotkov                2719 ECB             : 
 1292 akorotkov                2720 CBC          27 :                     break;
                               2721                 : 
                               2722              90 :                 case TIMETZOID:
 1292 akorotkov                2723 GIC          90 :                     cmpfunc = timetz_cmp;
 1292 akorotkov                2724 ECB             : 
 1292 akorotkov                2725 CBC          90 :                     break;
                               2726                 : 
                               2727              36 :                 case DATEOID:
                               2728                 :                 case TIMESTAMPOID:
 1292 akorotkov                2729 ECB             :                 case TIMESTAMPTZOID:
 1266 akorotkov                2730 GIC          36 :                     *cast_error = true; /* uncomparable types */
 1292                          2731              36 :                     return 0;
 1266 akorotkov                2732 ECB             : 
 1266 akorotkov                2733 LBC           0 :                 default:
 1266 akorotkov                2734 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
 1266 akorotkov                2735 EUB             :                          typid2);
 1292                          2736                 :             }
 1292 akorotkov                2737 GIC         117 :             break;
                               2738                 : 
 1292 akorotkov                2739 CBC         144 :         case TIMESTAMPOID:
                               2740                 :             switch (typid2)
 1292 akorotkov                2741 ECB             :             {
 1292 akorotkov                2742 GIC          36 :                 case DATEOID:
 1266                          2743              36 :                     return -cmpDateToTimestamp(DatumGetDateADT(val2),
 1266 akorotkov                2744 ECB             :                                                DatumGetTimestamp(val1),
                               2745                 :                                                useTz);
                               2746                 : 
 1292 akorotkov                2747 GIC          54 :                 case TIMESTAMPOID:
                               2748              54 :                     cmpfunc = timestamp_cmp;
 1292 akorotkov                2749 ECB             : 
 1292 akorotkov                2750 CBC          54 :                     break;
                               2751                 : 
                               2752              36 :                 case TIMESTAMPTZOID:
 1266 akorotkov                2753 GIC          36 :                     return cmpTimestampToTimestampTz(DatumGetTimestamp(val1),
 1266 akorotkov                2754 ECB             :                                                      DatumGetTimestampTz(val2),
                               2755                 :                                                      useTz);
                               2756                 : 
 1292 akorotkov                2757 GIC          18 :                 case TIMEOID:
                               2758                 :                 case TIMETZOID:
 1266 akorotkov                2759 CBC          18 :                     *cast_error = true; /* uncomparable types */
 1292 akorotkov                2760 GIC          18 :                     return 0;
 1266 akorotkov                2761 ECB             : 
 1266 akorotkov                2762 LBC           0 :                 default:
 1266 akorotkov                2763 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
 1266 akorotkov                2764 EUB             :                          typid2);
 1292                          2765                 :             }
 1292 akorotkov                2766 GIC          54 :             break;
                               2767                 : 
 1292 akorotkov                2768 CBC         171 :         case TIMESTAMPTZOID:
                               2769                 :             switch (typid2)
 1292 akorotkov                2770 ECB             :             {
 1292 akorotkov                2771 GIC          27 :                 case DATEOID:
 1266                          2772              27 :                     return -cmpDateToTimestampTz(DatumGetDateADT(val2),
 1266 akorotkov                2773 ECB             :                                                  DatumGetTimestampTz(val1),
                               2774                 :                                                  useTz);
                               2775                 : 
 1292 akorotkov                2776 GIC          36 :                 case TIMESTAMPOID:
 1266                          2777              36 :                     return -cmpTimestampToTimestampTz(DatumGetTimestamp(val2),
 1266 akorotkov                2778 ECB             :                                                       DatumGetTimestampTz(val1),
                               2779                 :                                                       useTz);
                               2780                 : 
 1292 akorotkov                2781 GIC          90 :                 case TIMESTAMPTZOID:
                               2782              90 :                     cmpfunc = timestamp_cmp;
 1292 akorotkov                2783 ECB             : 
 1292 akorotkov                2784 CBC          90 :                     break;
                               2785                 : 
                               2786              18 :                 case TIMEOID:
                               2787                 :                 case TIMETZOID:
 1266                          2788              18 :                     *cast_error = true; /* uncomparable types */
 1292 akorotkov                2789 GIC          18 :                     return 0;
 1266 akorotkov                2790 ECB             : 
 1266 akorotkov                2791 LBC           0 :                 default:
 1266 akorotkov                2792 UIC           0 :                     elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
 1266 akorotkov                2793 EUB             :                          typid2);
 1292                          2794                 :             }
 1292 akorotkov                2795 GIC          90 :             break;
                               2796                 : 
 1292 akorotkov                2797 LBC           0 :         default:
 1266 akorotkov                2798 UIC           0 :             elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u", typid1);
 1292 akorotkov                2799 EUB             :     }
                               2800                 : 
 1266 akorotkov                2801 GIC         396 :     if (*cast_error)
 1266 akorotkov                2802 UIC           0 :         return 0;               /* cast error */
 1292 akorotkov                2803 ECB             : 
 1292 akorotkov                2804 GBC         396 :     return DatumGetInt32(DirectFunctionCall2(cmpfunc, val1, val2));
                               2805                 : }
        

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