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