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  double val;
1048  bool have_error = false;
1049 
1050  val = float8in_internal_opt_error(tmp,
1051  NULL,
1052  "double precision",
1053  tmp,
1054  &have_error);
1055 
1056  if (have_error || isinf(val) || isnan(val))
1058  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1059  errmsg("numeric argument of jsonpath item method .%s() is out of range for type double precision",
1060  jspOperationName(jsp->type)))));
1061  res = jperOk;
1062  }
1063  else if (jb->type == jbvString)
1064  {
1065  /* cast string as double */
1066  double val;
1067  char *tmp = pnstrdup(jb->val.string.val,
1068  jb->val.string.len);
1069  bool have_error = false;
1070 
1071  val = float8in_internal_opt_error(tmp,
1072  NULL,
1073  "double precision",
1074  tmp,
1075  &have_error);
1076 
1077  if (have_error || isinf(val) || isnan(val))
1079  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1080  errmsg("string argument of jsonpath item method .%s() is not a valid representation of a double precision number",
1081  jspOperationName(jsp->type)))));
1082 
1083  jb = &jbv;
1084  jb->type = jbvNumeric;
1086  Float8GetDatum(val)));
1087  res = jperOk;
1088  }
1089 
1090  if (res == jperNotFound)
1092  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1093  errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1094  jspOperationName(jsp->type)))));
1095 
1096  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1097  }
1098  break;
1099 
1100  case jpiDatetime:
1101  if (unwrap && JsonbType(jb) == jbvArray)
1102  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1103 
1104  return executeDateTimeMethod(cxt, jsp, jb, found);
1105 
1106  case jpiKeyValue:
1107  if (unwrap && JsonbType(jb) == jbvArray)
1108  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1109 
1110  return executeKeyValueMethod(cxt, jsp, jb, found);
1111 
1112  default:
1113  elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
1114  }
1115 
1116  return res;
1117 }
1118 
1119 /*
1120  * Unwrap current array item and execute jsonpath for each of its elements.
1121  */
1122 static JsonPathExecResult
1124  JsonbValue *jb, JsonValueList *found,
1125  bool unwrapElements)
1126 {
1127  if (jb->type != jbvBinary)
1128  {
1129  Assert(jb->type != jbvArray);
1130  elog(ERROR, "invalid jsonb array value type: %d", jb->type);
1131  }
1132 
1133  return executeAnyItem
1134  (cxt, jsp, jb->val.binary.data, found, 1, 1, 1,
1135  false, unwrapElements);
1136 }
1137 
1138 /*
1139  * Execute next jsonpath item if exists. Otherwise put "v" to the "found"
1140  * list if provided.
1141  */
1142 static JsonPathExecResult
1145  JsonbValue *v, JsonValueList *found, bool copy)
1146 {
1147  JsonPathItem elem;
1148  bool hasNext;
1149 
1150  if (!cur)
1151  hasNext = next != NULL;
1152  else if (next)
1153  hasNext = jspHasNext(cur);
1154  else
1155  {
1156  next = &elem;
1157  hasNext = jspGetNext(cur, next);
1158  }
1159 
1160  if (hasNext)
1161  return executeItem(cxt, next, v, found);
1162 
1163  if (found)
1164  JsonValueListAppend(found, copy ? copyJsonbValue(v) : v);
1165 
1166  return jperOk;
1167 }
1168 
1169 /*
1170  * Same as executeItem(), but when "unwrap == true" automatically unwraps
1171  * each array item from the resulting sequence in lax mode.
1172  */
1173 static JsonPathExecResult
1175  JsonbValue *jb, bool unwrap,
1176  JsonValueList *found)
1177 {
1178  if (unwrap && jspAutoUnwrap(cxt))
1179  {
1180  JsonValueList seq = {0};
1182  JsonPathExecResult res = executeItem(cxt, jsp, jb, &seq);
1183  JsonbValue *item;
1184 
1185  if (jperIsError(res))
1186  return res;
1187 
1188  JsonValueListInitIterator(&seq, &it);
1189  while ((item = JsonValueListNext(&seq, &it)))
1190  {
1191  Assert(item->type != jbvArray);
1192 
1193  if (JsonbType(item) == jbvArray)
1194  executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
1195  else
1196  JsonValueListAppend(found, item);
1197  }
1198 
1199  return jperOk;
1200  }
1201 
1202  return executeItem(cxt, jsp, jb, found);
1203 }
1204 
1205 /*
1206  * Same as executeItemOptUnwrapResult(), but with error suppression.
1207  */
1208 static JsonPathExecResult
1210  JsonPathItem *jsp,
1211  JsonbValue *jb, bool unwrap,
1212  JsonValueList *found)
1213 {
1214  JsonPathExecResult res;
1215  bool throwErrors = cxt->throwErrors;
1216 
1217  cxt->throwErrors = false;
1218  res = executeItemOptUnwrapResult(cxt, jsp, jb, unwrap, found);
1219  cxt->throwErrors = throwErrors;
1220 
1221  return res;
1222 }
1223 
1224 /* Execute boolean-valued jsonpath expression. */
1225 static JsonPathBool
1227  JsonbValue *jb, bool canHaveNext)
1228 {
1229  JsonPathItem larg;
1230  JsonPathItem rarg;
1231  JsonPathBool res;
1232  JsonPathBool res2;
1233 
1234  if (!canHaveNext && jspHasNext(jsp))
1235  elog(ERROR, "boolean jsonpath item cannot have next item");
1236 
1237  switch (jsp->type)
1238  {
1239  case jpiAnd:
1240  jspGetLeftArg(jsp, &larg);
1241  res = executeBoolItem(cxt, &larg, jb, false);
1242 
1243  if (res == jpbFalse)
1244  return jpbFalse;
1245 
1246  /*
1247  * SQL/JSON says that we should check second arg in case of
1248  * jperError
1249  */
1250 
1251  jspGetRightArg(jsp, &rarg);
1252  res2 = executeBoolItem(cxt, &rarg, jb, false);
1253 
1254  return res2 == jpbTrue ? res : res2;
1255 
1256  case jpiOr:
1257  jspGetLeftArg(jsp, &larg);
1258  res = executeBoolItem(cxt, &larg, jb, false);
1259 
1260  if (res == jpbTrue)
1261  return jpbTrue;
1262 
1263  jspGetRightArg(jsp, &rarg);
1264  res2 = executeBoolItem(cxt, &rarg, jb, false);
1265 
1266  return res2 == jpbFalse ? res : res2;
1267 
1268  case jpiNot:
1269  jspGetArg(jsp, &larg);
1270 
1271  res = executeBoolItem(cxt, &larg, jb, false);
1272 
1273  if (res == jpbUnknown)
1274  return jpbUnknown;
1275 
1276  return res == jpbTrue ? jpbFalse : jpbTrue;
1277 
1278  case jpiIsUnknown:
1279  jspGetArg(jsp, &larg);
1280  res = executeBoolItem(cxt, &larg, jb, false);
1281  return res == jpbUnknown ? jpbTrue : jpbFalse;
1282 
1283  case jpiEqual:
1284  case jpiNotEqual:
1285  case jpiLess:
1286  case jpiGreater:
1287  case jpiLessOrEqual:
1288  case jpiGreaterOrEqual:
1289  jspGetLeftArg(jsp, &larg);
1290  jspGetRightArg(jsp, &rarg);
1291  return executePredicate(cxt, jsp, &larg, &rarg, jb, true,
1292  executeComparison, cxt);
1293 
1294  case jpiStartsWith: /* 'whole STARTS WITH initial' */
1295  jspGetLeftArg(jsp, &larg); /* 'whole' */
1296  jspGetRightArg(jsp, &rarg); /* 'initial' */
1297  return executePredicate(cxt, jsp, &larg, &rarg, jb, false,
1298  executeStartsWith, NULL);
1299 
1300  case jpiLikeRegex: /* 'expr LIKE_REGEX pattern FLAGS flags' */
1301  {
1302  /*
1303  * 'expr' is a sequence-returning expression. 'pattern' is a
1304  * regex string literal. SQL/JSON standard requires XQuery
1305  * regexes, but we use Postgres regexes here. 'flags' is a
1306  * string literal converted to integer flags at compile-time.
1307  */
1308  JsonLikeRegexContext lrcxt = {0};
1309 
1310  jspInitByBuffer(&larg, jsp->base,
1311  jsp->content.like_regex.expr);
1312 
1313  return executePredicate(cxt, jsp, &larg, NULL, jb, false,
1314  executeLikeRegex, &lrcxt);
1315  }
1316 
1317  case jpiExists:
1318  jspGetArg(jsp, &larg);
1319 
1320  if (jspStrictAbsenseOfErrors(cxt))
1321  {
1322  /*
1323  * In strict mode we must get a complete list of values to
1324  * check that there are no errors at all.
1325  */
1326  JsonValueList vals = {0};
1327  JsonPathExecResult res =
1328  executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1329  false, &vals);
1330 
1331  if (jperIsError(res))
1332  return jpbUnknown;
1333 
1334  return JsonValueListIsEmpty(&vals) ? jpbFalse : jpbTrue;
1335  }
1336  else
1337  {
1338  JsonPathExecResult res =
1339  executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1340  false, NULL);
1341 
1342  if (jperIsError(res))
1343  return jpbUnknown;
1344 
1345  return res == jperOk ? jpbTrue : jpbFalse;
1346  }
1347 
1348  default:
1349  elog(ERROR, "invalid boolean jsonpath item type: %d", jsp->type);
1350  return jpbUnknown;
1351  }
1352 }
1353 
1354 /*
1355  * Execute nested (filters etc.) boolean expression pushing current SQL/JSON
1356  * item onto the stack.
1357  */
1358 static JsonPathBool
1360  JsonbValue *jb)
1361 {
1362  JsonbValue *prev;
1363  JsonPathBool res;
1364 
1365  prev = cxt->current;
1366  cxt->current = jb;
1367  res = executeBoolItem(cxt, jsp, jb, false);
1368  cxt->current = prev;
1369 
1370  return res;
1371 }
1372 
1373 /*
1374  * Implementation of several jsonpath nodes:
1375  * - jpiAny (.** accessor),
1376  * - jpiAnyKey (.* accessor),
1377  * - jpiAnyArray ([*] accessor)
1378  */
1379 static JsonPathExecResult
1381  JsonValueList *found, uint32 level, uint32 first, uint32 last,
1382  bool ignoreStructuralErrors, bool unwrapNext)
1383 {
1385  JsonbIterator *it;
1386  int32 r;
1387  JsonbValue v;
1388 
1390 
1391  if (level > last)
1392  return res;
1393 
1394  it = JsonbIteratorInit(jbc);
1395 
1396  /*
1397  * Recursively iterate over jsonb objects/arrays
1398  */
1399  while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
1400  {
1401  if (r == WJB_KEY)
1402  {
1403  r = JsonbIteratorNext(&it, &v, true);
1404  Assert(r == WJB_VALUE);
1405  }
1406 
1407  if (r == WJB_VALUE || r == WJB_ELEM)
1408  {
1409 
1410  if (level >= first ||
1411  (first == PG_UINT32_MAX && last == PG_UINT32_MAX &&
1412  v.type != jbvBinary)) /* leaves only requested */
1413  {
1414  /* check expression */
1415  if (jsp)
1416  {
1417  if (ignoreStructuralErrors)
1418  {
1419  bool savedIgnoreStructuralErrors;
1420 
1421  savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
1422  cxt->ignoreStructuralErrors = true;
1423  res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
1424  cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
1425  }
1426  else
1427  res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
1428 
1429  if (jperIsError(res))
1430  break;
1431 
1432  if (res == jperOk && !found)
1433  break;
1434  }
1435  else if (found)
1436  JsonValueListAppend(found, copyJsonbValue(&v));
1437  else
1438  return jperOk;
1439  }
1440 
1441  if (level < last && v.type == jbvBinary)
1442  {
1443  res = executeAnyItem
1444  (cxt, jsp, v.val.binary.data, found,
1445  level + 1, first, last,
1446  ignoreStructuralErrors, unwrapNext);
1447 
1448  if (jperIsError(res))
1449  break;
1450 
1451  if (res == jperOk && found == NULL)
1452  break;
1453  }
1454  }
1455  }
1456 
1457  return res;
1458 }
1459 
1460 /*
1461  * Execute unary or binary predicate.
1462  *
1463  * Predicates have existence semantics, because their operands are item
1464  * sequences. Pairs of items from the left and right operand's sequences are
1465  * checked. TRUE returned only if any pair satisfying the condition is found.
1466  * In strict mode, even if the desired pair has already been found, all pairs
1467  * still need to be examined to check the absence of errors. If any error
1468  * occurs, UNKNOWN (analogous to SQL NULL) is returned.
1469  */
1470 static JsonPathBool
1472  JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb,
1473  bool unwrapRightArg, JsonPathPredicateCallback exec,
1474  void *param)
1475 {
1476  JsonPathExecResult res;
1477  JsonValueListIterator lseqit;
1478  JsonValueList lseq = {0};
1479  JsonValueList rseq = {0};
1480  JsonbValue *lval;
1481  bool error = false;
1482  bool found = false;
1483 
1484  /* Left argument is always auto-unwrapped. */
1485  res = executeItemOptUnwrapResultNoThrow(cxt, larg, jb, true, &lseq);
1486  if (jperIsError(res))
1487  return jpbUnknown;
1488 
1489  if (rarg)
1490  {
1491  /* Right argument is conditionally auto-unwrapped. */
1492  res = executeItemOptUnwrapResultNoThrow(cxt, rarg, jb,
1493  unwrapRightArg, &rseq);
1494  if (jperIsError(res))
1495  return jpbUnknown;
1496  }
1497 
1498  JsonValueListInitIterator(&lseq, &lseqit);
1499  while ((lval = JsonValueListNext(&lseq, &lseqit)))
1500  {
1501  JsonValueListIterator rseqit;
1502  JsonbValue *rval;
1503  bool first = true;
1504 
1505  JsonValueListInitIterator(&rseq, &rseqit);
1506  if (rarg)
1507  rval = JsonValueListNext(&rseq, &rseqit);
1508  else
1509  rval = NULL;
1510 
1511  /* Loop over right arg sequence or do single pass otherwise */
1512  while (rarg ? (rval != NULL) : first)
1513  {
1514  JsonPathBool res = exec(pred, lval, rval, param);
1515 
1516  if (res == jpbUnknown)
1517  {
1518  if (jspStrictAbsenseOfErrors(cxt))
1519  return jpbUnknown;
1520 
1521  error = true;
1522  }
1523  else if (res == jpbTrue)
1524  {
1525  if (!jspStrictAbsenseOfErrors(cxt))
1526  return jpbTrue;
1527 
1528  found = true;
1529  }
1530 
1531  first = false;
1532  if (rarg)
1533  rval = JsonValueListNext(&rseq, &rseqit);
1534  }
1535  }
1536 
1537  if (found) /* possible only in strict mode */
1538  return jpbTrue;
1539 
1540  if (error) /* possible only in lax mode */
1541  return jpbUnknown;
1542 
1543  return jpbFalse;
1544 }
1545 
1546 /*
1547  * Execute binary arithmetic expression on singleton numeric operands.
1548  * Array operands are automatically unwrapped in lax mode.
1549  */
1550 static JsonPathExecResult
1552  JsonbValue *jb, BinaryArithmFunc func,
1553  JsonValueList *found)
1554 {
1555  JsonPathExecResult jper;
1556  JsonPathItem elem;
1557  JsonValueList lseq = {0};
1558  JsonValueList rseq = {0};
1559  JsonbValue *lval;
1560  JsonbValue *rval;
1561  Numeric res;
1562 
1563  jspGetLeftArg(jsp, &elem);
1564 
1565  /*
1566  * XXX: By standard only operands of multiplicative expressions are
1567  * unwrapped. We extend it to other binary arithmetic expressions too.
1568  */
1569  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &lseq);
1570  if (jperIsError(jper))
1571  return jper;
1572 
1573  jspGetRightArg(jsp, &elem);
1574 
1575  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &rseq);
1576  if (jperIsError(jper))
1577  return jper;
1578 
1579  if (JsonValueListLength(&lseq) != 1 ||
1580  !(lval = getScalar(JsonValueListHead(&lseq), jbvNumeric)))
1582  (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
1583  errmsg("left operand of jsonpath operator %s is not a single numeric value",
1584  jspOperationName(jsp->type)))));
1585 
1586  if (JsonValueListLength(&rseq) != 1 ||
1587  !(rval = getScalar(JsonValueListHead(&rseq), jbvNumeric)))
1589  (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
1590  errmsg("right operand of jsonpath operator %s is not a single numeric value",
1591  jspOperationName(jsp->type)))));
1592 
1593  if (jspThrowErrors(cxt))
1594  {
1595  res = func(lval->val.numeric, rval->val.numeric, NULL);
1596  }
1597  else
1598  {
1599  bool error = false;
1600 
1601  res = func(lval->val.numeric, rval->val.numeric, &error);
1602 
1603  if (error)
1604  return jperError;
1605  }
1606 
1607  if (!jspGetNext(jsp, &elem) && !found)
1608  return jperOk;
1609 
1610  lval = palloc(sizeof(*lval));
1611  lval->type = jbvNumeric;
1612  lval->val.numeric = res;
1613 
1614  return executeNextItem(cxt, jsp, &elem, lval, found, false);
1615 }
1616 
1617 /*
1618  * Execute unary arithmetic expression for each numeric item in its operand's
1619  * sequence. Array operand is automatically unwrapped in lax mode.
1620  */
1621 static JsonPathExecResult
1623  JsonbValue *jb, PGFunction func, JsonValueList *found)
1624 {
1625  JsonPathExecResult jper;
1626  JsonPathExecResult jper2;
1627  JsonPathItem elem;
1628  JsonValueList seq = {0};
1630  JsonbValue *val;
1631  bool hasNext;
1632 
1633  jspGetArg(jsp, &elem);
1634  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &seq);
1635 
1636  if (jperIsError(jper))
1637  return jper;
1638 
1639  jper = jperNotFound;
1640 
1641  hasNext = jspGetNext(jsp, &elem);
1642 
1643  JsonValueListInitIterator(&seq, &it);
1644  while ((val = JsonValueListNext(&seq, &it)))
1645  {
1646  if ((val = getScalar(val, jbvNumeric)))
1647  {
1648  if (!found && !hasNext)
1649  return jperOk;
1650  }
1651  else
1652  {
1653  if (!found && !hasNext)
1654  continue; /* skip non-numerics processing */
1655 
1657  (errcode(ERRCODE_SQL_JSON_NUMBER_NOT_FOUND),
1658  errmsg("operand of unary jsonpath operator %s is not a numeric value",
1659  jspOperationName(jsp->type)))));
1660  }
1661 
1662  if (func)
1663  val->val.numeric =
1665  NumericGetDatum(val->val.numeric)));
1666 
1667  jper2 = executeNextItem(cxt, jsp, &elem, val, found, false);
1668 
1669  if (jperIsError(jper2))
1670  return jper2;
1671 
1672  if (jper2 == jperOk)
1673  {
1674  if (!found)
1675  return jperOk;
1676  jper = jperOk;
1677  }
1678  }
1679 
1680  return jper;
1681 }
1682 
1683 /*
1684  * STARTS_WITH predicate callback.
1685  *
1686  * Check if the 'whole' string starts from 'initial' string.
1687  */
1688 static JsonPathBool
1690  void *param)
1691 {
1692  if (!(whole = getScalar(whole, jbvString)))
1693  return jpbUnknown; /* error */
1694 
1695  if (!(initial = getScalar(initial, jbvString)))
1696  return jpbUnknown; /* error */
1697 
1698  if (whole->val.string.len >= initial->val.string.len &&
1699  !memcmp(whole->val.string.val,
1700  initial->val.string.val,
1701  initial->val.string.len))
1702  return jpbTrue;
1703 
1704  return jpbFalse;
1705 }
1706 
1707 /*
1708  * LIKE_REGEX predicate callback.
1709  *
1710  * Check if the string matches regex pattern.
1711  */
1712 static JsonPathBool
1714  void *param)
1715 {
1716  JsonLikeRegexContext *cxt = param;
1717 
1718  if (!(str = getScalar(str, jbvString)))
1719  return jpbUnknown;
1720 
1721  /* Cache regex text and converted flags. */
1722  if (!cxt->regex)
1723  {
1724  cxt->regex =
1726  jsp->content.like_regex.patternlen);
1727  cxt->cflags = jspConvertRegexFlags(jsp->content.like_regex.flags);
1728  }
1729 
1730  if (RE_compile_and_execute(cxt->regex, str->val.string.val,
1731  str->val.string.len,
1732  cxt->cflags, DEFAULT_COLLATION_OID, 0, NULL))
1733  return jpbTrue;
1734 
1735  return jpbFalse;
1736 }
1737 
1738 /*
1739  * Execute numeric item methods (.abs(), .floor(), .ceil()) using the specified
1740  * user function 'func'.
1741  */
1742 static JsonPathExecResult
1744  JsonbValue *jb, bool unwrap, PGFunction func,
1745  JsonValueList *found)
1746 {
1748  Datum datum;
1749 
1750  if (unwrap && JsonbType(jb) == jbvArray)
1751  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1752 
1753  if (!(jb = getScalar(jb, jbvNumeric)))
1755  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1756  errmsg("jsonpath item method .%s() can only be applied to a numeric value",
1757  jspOperationName(jsp->type)))));
1758 
1759  datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
1760 
1761  if (!jspGetNext(jsp, &next) && !found)
1762  return jperOk;
1763 
1764  jb = palloc(sizeof(*jb));
1765  jb->type = jbvNumeric;
1766  jb->val.numeric = DatumGetNumeric(datum);
1767 
1768  return executeNextItem(cxt, jsp, &next, jb, found, false);
1769 }
1770 
1771 /*
1772  * Implementation of the .datetime() method.
1773  *
1774  * Converts a string into a date/time value. The actual type is determined at run time.
1775  * If an argument is provided, this argument is used as a template string.
1776  * Otherwise, the first fitting ISO format is selected.
1777  */
1778 static JsonPathExecResult
1780  JsonbValue *jb, JsonValueList *found)
1781 {
1782  JsonbValue jbvbuf;
1783  Datum value;
1784  text *datetime;
1785  Oid collid;
1786  Oid typid;
1787  int32 typmod = -1;
1788  int tz = 0;
1789  bool hasNext;
1791  JsonPathItem elem;
1792 
1793  if (!(jb = getScalar(jb, jbvString)))
1795  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
1796  errmsg("jsonpath item method .%s() can only be applied to a string",
1797  jspOperationName(jsp->type)))));
1798 
1799  datetime = cstring_to_text_with_len(jb->val.string.val,
1800  jb->val.string.len);
1801 
1802  /*
1803  * At some point we might wish to have callers supply the collation to
1804  * use, but right now it's unclear that they'd be able to do better than
1805  * DEFAULT_COLLATION_OID anyway.
1806  */
1807  collid = DEFAULT_COLLATION_OID;
1808 
1809  if (jsp->content.arg)
1810  {
1811  text *template;
1812  char *template_str;
1813  int template_len;
1814  bool have_error = false;
1815 
1816  jspGetArg(jsp, &elem);
1817 
1818  if (elem.type != jpiString)
1819  elog(ERROR, "invalid jsonpath item type for .datetime() argument");
1820 
1821  template_str = jspGetString(&elem, &template_len);
1822 
1823  template = cstring_to_text_with_len(template_str,
1824  template_len);
1825 
1826  value = parse_datetime(datetime, template, collid, true,
1827  &typid, &typmod, &tz,
1828  jspThrowErrors(cxt) ? NULL : &have_error);
1829 
1830  if (have_error)
1831  res = jperError;
1832  else
1833  res = jperOk;
1834  }
1835  else
1836  {
1837  /*
1838  * According to SQL/JSON standard enumerate ISO formats for: date,
1839  * timetz, time, timestamptz, timestamp.
1840  */
1841  static const char *fmt_str[] =
1842  {
1843  "yyyy-mm-dd",
1844  "HH24:MI:SS TZH:TZM",
1845  "HH24:MI:SS TZH",
1846  "HH24:MI:SS",
1847  "yyyy-mm-dd HH24:MI:SS TZH:TZM",
1848  "yyyy-mm-dd HH24:MI:SS TZH",
1849  "yyyy-mm-dd HH24:MI:SS"
1850  };
1851 
1852  /* cache for format texts */
1853  static text *fmt_txt[lengthof(fmt_str)] = {0};
1854  int i;
1855 
1856  /* loop until datetime format fits */
1857  for (i = 0; i < lengthof(fmt_str); i++)
1858  {
1859  bool have_error = false;
1860 
1861  if (!fmt_txt[i])
1862  {
1863  MemoryContext oldcxt =
1865 
1866  fmt_txt[i] = cstring_to_text(fmt_str[i]);
1867  MemoryContextSwitchTo(oldcxt);
1868  }
1869 
1870  value = parse_datetime(datetime, fmt_txt[i], collid, true,
1871  &typid, &typmod, &tz,
1872  &have_error);
1873 
1874  if (!have_error)
1875  {
1876  res = jperOk;
1877  break;
1878  }
1879  }
1880 
1881  if (res == jperNotFound)
1883  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
1884  errmsg("datetime format is not recognized: \"%s\"",
1885  text_to_cstring(datetime)),
1886  errhint("Use a datetime template argument to specify the input data format."))));
1887  }
1888 
1889  pfree(datetime);
1890 
1891  if (jperIsError(res))
1892  return res;
1893 
1894  hasNext = jspGetNext(jsp, &elem);
1895 
1896  if (!hasNext && !found)
1897  return res;
1898 
1899  jb = hasNext ? &jbvbuf : palloc(sizeof(*jb));
1900 
1901  jb->type = jbvDatetime;
1902  jb->val.datetime.value = value;
1903  jb->val.datetime.typid = typid;
1904  jb->val.datetime.typmod = typmod;
1905  jb->val.datetime.tz = tz;
1906 
1907  return executeNextItem(cxt, jsp, &elem, jb, found, hasNext);
1908 }
1909 
1910 /*
1911  * Implementation of .keyvalue() method.
1912  *
1913  * .keyvalue() method returns a sequence of object's key-value pairs in the
1914  * following format: '{ "key": key, "value": value, "id": id }'.
1915  *
1916  * "id" field is an object identifier which is constructed from the two parts:
1917  * base object id and its binary offset in base object's jsonb:
1918  * id = 10000000000 * base_object_id + obj_offset_in_base_object
1919  *
1920  * 10000000000 (10^10) -- is a first round decimal number greater than 2^32
1921  * (maximal offset in jsonb). Decimal multiplier is used here to improve the
1922  * readability of identifiers.
1923  *
1924  * Base object is usually a root object of the path: context item '$' or path
1925  * variable '$var', literals can't produce objects for now. But if the path
1926  * contains generated objects (.keyvalue() itself, for example), then they
1927  * become base object for the subsequent .keyvalue().
1928  *
1929  * Id of '$' is 0. Id of '$var' is its ordinal (positive) number in the list
1930  * of variables (see getJsonPathVariable()). Ids for generated objects
1931  * are assigned using global counter JsonPathExecContext.lastGeneratedObjectId.
1932  */
1933 static JsonPathExecResult
1935  JsonbValue *jb, JsonValueList *found)
1936 {
1940  JsonbValue key;
1941  JsonbValue val;
1942  JsonbValue idval;
1943  JsonbValue keystr;
1944  JsonbValue valstr;
1945  JsonbValue idstr;
1946  JsonbIterator *it;
1947  JsonbIteratorToken tok;
1948  int64 id;
1949  bool hasNext;
1950 
1951  if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
1953  (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
1954  errmsg("jsonpath item method .%s() can only be applied to an object",
1955  jspOperationName(jsp->type)))));
1956 
1957  jbc = jb->val.binary.data;
1958 
1959  if (!JsonContainerSize(jbc))
1960  return jperNotFound; /* no key-value pairs */
1961 
1962  hasNext = jspGetNext(jsp, &next);
1963 
1964  keystr.type = jbvString;
1965  keystr.val.string.val = "key";
1966  keystr.val.string.len = 3;
1967 
1968  valstr.type = jbvString;
1969  valstr.val.string.val = "value";
1970  valstr.val.string.len = 5;
1971 
1972  idstr.type = jbvString;
1973  idstr.val.string.val = "id";
1974  idstr.val.string.len = 2;
1975 
1976  /* construct object id from its base object and offset inside that */
1977  id = jb->type != jbvBinary ? 0 :
1978  (int64) ((char *) jbc - (char *) cxt->baseObject.jbc);
1979  id += (int64) cxt->baseObject.id * INT64CONST(10000000000);
1980 
1981  idval.type = jbvNumeric;
1983  Int64GetDatum(id)));
1984 
1985  it = JsonbIteratorInit(jbc);
1986 
1987  while ((tok = JsonbIteratorNext(&it, &key, true)) != WJB_DONE)
1988  {
1989  JsonBaseObjectInfo baseObject;
1990  JsonbValue obj;
1991  JsonbParseState *ps;
1992  JsonbValue *keyval;
1993  Jsonb *jsonb;
1994 
1995  if (tok != WJB_KEY)
1996  continue;
1997 
1998  res = jperOk;
1999 
2000  if (!hasNext && !found)
2001  break;
2002 
2003  tok = JsonbIteratorNext(&it, &val, true);
2004  Assert(tok == WJB_VALUE);
2005 
2006  ps = NULL;
2007  pushJsonbValue(&ps, WJB_BEGIN_OBJECT, NULL);
2008 
2009  pushJsonbValue(&ps, WJB_KEY, &keystr);
2010  pushJsonbValue(&ps, WJB_VALUE, &key);
2011 
2012  pushJsonbValue(&ps, WJB_KEY, &valstr);
2013  pushJsonbValue(&ps, WJB_VALUE, &val);
2014 
2015  pushJsonbValue(&ps, WJB_KEY, &idstr);
2016  pushJsonbValue(&ps, WJB_VALUE, &idval);
2017 
2018  keyval = pushJsonbValue(&ps, WJB_END_OBJECT, NULL);
2019 
2020  jsonb = JsonbValueToJsonb(keyval);
2021 
2022  JsonbInitBinary(&obj, jsonb);
2023 
2024  baseObject = setBaseObject(cxt, &obj, cxt->lastGeneratedObjectId++);
2025 
2026  res = executeNextItem(cxt, jsp, &next, &obj, found, true);
2027 
2028  cxt->baseObject = baseObject;
2029 
2030  if (jperIsError(res))
2031  return res;
2032 
2033  if (res == jperOk && !found)
2034  break;
2035  }
2036 
2037  return res;
2038 }
2039 
2040 /*
2041  * Convert boolean execution status 'res' to a boolean JSON item and execute
2042  * next jsonpath.
2043  */
2044 static JsonPathExecResult
2046  JsonValueList *found, JsonPathBool res)
2047 {
2049  JsonbValue jbv;
2050 
2051  if (!jspGetNext(jsp, &next) && !found)
2052  return jperOk; /* found singleton boolean value */
2053 
2054  if (res == jpbUnknown)
2055  {
2056  jbv.type = jbvNull;
2057  }
2058  else
2059  {
2060  jbv.type = jbvBool;
2061  jbv.val.boolean = res == jpbTrue;
2062  }
2063 
2064  return executeNextItem(cxt, jsp, &next, &jbv, found, true);
2065 }
2066 
2067 /*
2068  * Convert jsonpath's scalar or variable node to actual jsonb value.
2069  *
2070  * If node is a variable then its id returned, otherwise 0 returned.
2071  */
2072 static void
2074  JsonbValue *value)
2075 {
2076  switch (item->type)
2077  {
2078  case jpiNull:
2079  value->type = jbvNull;
2080  break;
2081  case jpiBool:
2082  value->type = jbvBool;
2083  value->val.boolean = jspGetBool(item);
2084  break;
2085  case jpiNumeric:
2086  value->type = jbvNumeric;
2087  value->val.numeric = jspGetNumeric(item);
2088  break;
2089  case jpiString:
2090  value->type = jbvString;
2091  value->val.string.val = jspGetString(item,
2092  &value->val.string.len);
2093  break;
2094  case jpiVariable:
2095  getJsonPathVariable(cxt, item, cxt->vars, value);
2096  return;
2097  default:
2098  elog(ERROR, "unexpected jsonpath item type");
2099  }
2100 }
2101 
2102 /*
2103  * Get the value of variable passed to jsonpath executor
2104  */
2105 static void
2108 {
2109  char *varName;
2110  int varNameLength;
2111  JsonbValue tmp;
2112  JsonbValue *v;
2113 
2114  if (!vars)
2115  {
2116  value->type = jbvNull;
2117  return;
2118  }
2119 
2120  Assert(variable->type == jpiVariable);
2121  varName = jspGetString(variable, &varNameLength);
2122  tmp.type = jbvString;
2123  tmp.val.string.val = varName;
2124  tmp.val.string.len = varNameLength;
2125 
2126  v = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
2127 
2128  if (v)
2129  {
2130  *value = *v;
2131  pfree(v);
2132  }
2133  else
2134  {
2135  ereport(ERROR,
2136  (errcode(ERRCODE_UNDEFINED_OBJECT),
2137  errmsg("could not find jsonpath variable \"%s\"",
2138  pnstrdup(varName, varNameLength))));
2139  }
2140 
2141  JsonbInitBinary(&tmp, vars);
2142  setBaseObject(cxt, &tmp, 1);
2143 }
2144 
2145 /**************** Support functions for JsonPath execution *****************/
2146 
2147 /*
2148  * Returns the size of an array item, or -1 if item is not an array.
2149  */
2150 static int
2152 {
2153  Assert(jb->type != jbvArray);
2154 
2155  if (jb->type == jbvBinary)
2156  {
2157  JsonbContainer *jbc = jb->val.binary.data;
2158 
2159  if (JsonContainerIsArray(jbc) && !JsonContainerIsScalar(jbc))
2160  return JsonContainerSize(jbc);
2161  }
2162 
2163  return -1;
2164 }
2165 
2166 /* Comparison predicate callback. */
2167 static JsonPathBool
2169 {
2171 
2172  return compareItems(cmp->type, lv, rv, cxt->useTz);
2173 }
2174 
2175 /*
2176  * Perform per-byte comparison of two strings.
2177  */
2178 static int
2179 binaryCompareStrings(const char *s1, int len1,
2180  const char *s2, int len2)
2181 {
2182  int cmp;
2183 
2184  cmp = memcmp(s1, s2, Min(len1, len2));
2185 
2186  if (cmp != 0)
2187  return cmp;
2188 
2189  if (len1 == len2)
2190  return 0;
2191 
2192  return len1 < len2 ? -1 : 1;
2193 }
2194 
2195 /*
2196  * Compare two strings in the current server encoding using Unicode codepoint
2197  * collation.
2198  */
2199 static int
2200 compareStrings(const char *mbstr1, int mblen1,
2201  const char *mbstr2, int mblen2)
2202 {
2203  if (GetDatabaseEncoding() == PG_SQL_ASCII ||
2205  {
2206  /*
2207  * It's known property of UTF-8 strings that their per-byte comparison
2208  * result matches codepoints comparison result. ASCII can be
2209  * considered as special case of UTF-8.
2210  */
2211  return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
2212  }
2213  else
2214  {
2215  char *utf8str1,
2216  *utf8str2;
2217  int cmp,
2218  utf8len1,
2219  utf8len2;
2220 
2221  /*
2222  * We have to convert other encodings to UTF-8 first, then compare.
2223  * Input strings may be not null-terminated and pg_server_to_any() may
2224  * return them "as is". So, use strlen() only if there is real
2225  * conversion.
2226  */
2227  utf8str1 = pg_server_to_any(mbstr1, mblen1, PG_UTF8);
2228  utf8str2 = pg_server_to_any(mbstr2, mblen2, PG_UTF8);
2229  utf8len1 = (mbstr1 == utf8str1) ? mblen1 : strlen(utf8str1);
2230  utf8len2 = (mbstr2 == utf8str2) ? mblen2 : strlen(utf8str2);
2231 
2232  cmp = binaryCompareStrings(utf8str1, utf8len1, utf8str2, utf8len2);
2233 
2234  /*
2235  * If pg_server_to_any() did no real conversion, then we actually
2236  * compared original strings. So, we already done.
2237  */
2238  if (mbstr1 == utf8str1 && mbstr2 == utf8str2)
2239  return cmp;
2240 
2241  /* Free memory if needed */
2242  if (mbstr1 != utf8str1)
2243  pfree(utf8str1);
2244  if (mbstr2 != utf8str2)
2245  pfree(utf8str2);
2246 
2247  /*
2248  * When all Unicode codepoints are equal, return result of binary
2249  * comparison. In some edge cases, same characters may have different
2250  * representations in encoding. Then our behavior could diverge from
2251  * standard. However, that allow us to do simple binary comparison
2252  * for "==" operator, which is performance critical in typical cases.
2253  * In future to implement strict standard conformance, we can do
2254  * normalization of input JSON strings.
2255  */
2256  if (cmp == 0)
2257  return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
2258  else
2259  return cmp;
2260  }
2261 }
2262 
2263 /*
2264  * Compare two SQL/JSON items using comparison operation 'op'.
2265  */
2266 static JsonPathBool
2267 compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2, bool useTz)
2268 {
2269  int cmp;
2270  bool res;
2271 
2272  if (jb1->type != jb2->type)
2273  {
2274  if (jb1->type == jbvNull || jb2->type == jbvNull)
2275 
2276  /*
2277  * Equality and order comparison of nulls to non-nulls returns
2278  * always false, but inequality comparison returns true.
2279  */
2280  return op == jpiNotEqual ? jpbTrue : jpbFalse;
2281 
2282  /* Non-null items of different types are not comparable. */
2283  return jpbUnknown;
2284  }
2285 
2286  switch (jb1->type)
2287  {
2288  case jbvNull:
2289  cmp = 0;
2290  break;
2291  case jbvBool:
2292  cmp = jb1->val.boolean == jb2->val.boolean ? 0 :
2293  jb1->val.boolean ? 1 : -1;
2294  break;
2295  case jbvNumeric:
2296  cmp = compareNumeric(jb1->val.numeric, jb2->val.numeric);
2297  break;
2298  case jbvString:
2299  if (op == jpiEqual)
2300  return jb1->val.string.len != jb2->val.string.len ||
2301  memcmp(jb1->val.string.val,
2302  jb2->val.string.val,
2303  jb1->val.string.len) ? jpbFalse : jpbTrue;
2304 
2305  cmp = compareStrings(jb1->val.string.val, jb1->val.string.len,
2306  jb2->val.string.val, jb2->val.string.len);
2307  break;
2308  case jbvDatetime:
2309  {
2310  bool cast_error;
2311 
2312  cmp = compareDatetime(jb1->val.datetime.value,
2313  jb1->val.datetime.typid,
2314  jb2->val.datetime.value,
2315  jb2->val.datetime.typid,
2316  useTz,
2317  &cast_error);
2318 
2319  if (cast_error)
2320  return jpbUnknown;
2321  }
2322  break;
2323 
2324  case jbvBinary:
2325  case jbvArray:
2326  case jbvObject:
2327  return jpbUnknown; /* non-scalars are not comparable */
2328 
2329  default:
2330  elog(ERROR, "invalid jsonb value type %d", jb1->type);
2331  }
2332 
2333  switch (op)
2334  {
2335  case jpiEqual:
2336  res = (cmp == 0);
2337  break;
2338  case jpiNotEqual:
2339  res = (cmp != 0);
2340  break;
2341  case jpiLess:
2342  res = (cmp < 0);
2343  break;
2344  case jpiGreater:
2345  res = (cmp > 0);
2346  break;
2347  case jpiLessOrEqual:
2348  res = (cmp <= 0);
2349  break;
2350  case jpiGreaterOrEqual:
2351  res = (cmp >= 0);
2352  break;
2353  default:
2354  elog(ERROR, "unrecognized jsonpath operation: %d", op);
2355  return jpbUnknown;
2356  }
2357 
2358  return res ? jpbTrue : jpbFalse;
2359 }
2360 
2361 /* Compare two numerics */
2362 static int
2364 {
2366  NumericGetDatum(a),
2367  NumericGetDatum(b)));
2368 }
2369 
2370 static JsonbValue *
2372 {
2373  JsonbValue *dst = palloc(sizeof(*dst));
2374 
2375  *dst = *src;
2376 
2377  return dst;
2378 }
2379 
2380 /*
2381  * Execute array subscript expression and convert resulting numeric item to
2382  * the integer type with truncation.
2383  */
2384 static JsonPathExecResult
2386  int32 *index)
2387 {
2388  JsonbValue *jbv;
2389  JsonValueList found = {0};
2390  JsonPathExecResult res = executeItem(cxt, jsp, jb, &found);
2391  Datum numeric_index;
2392  bool have_error = false;
2393 
2394  if (jperIsError(res))
2395  return res;
2396 
2397  if (JsonValueListLength(&found) != 1 ||
2398  !(jbv = getScalar(JsonValueListHead(&found), jbvNumeric)))
2400  (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
2401  errmsg("jsonpath array subscript is not a single numeric value"))));
2402 
2403  numeric_index = DirectFunctionCall2(numeric_trunc,
2404  NumericGetDatum(jbv->val.numeric),
2405  Int32GetDatum(0));
2406 
2407  *index = numeric_int4_opt_error(DatumGetNumeric(numeric_index),
2408  &have_error);
2409 
2410  if (have_error)
2412  (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
2413  errmsg("jsonpath array subscript is out of integer range"))));
2414 
2415  return jperOk;
2416 }
2417 
2418 /* Save base object and its id needed for the execution of .keyvalue(). */
2419 static JsonBaseObjectInfo
2421 {
2422  JsonBaseObjectInfo baseObject = cxt->baseObject;
2423 
2424  cxt->baseObject.jbc = jbv->type != jbvBinary ? NULL :
2425  (JsonbContainer *) jbv->val.binary.data;
2426  cxt->baseObject.id = id;
2427 
2428  return baseObject;
2429 }
2430 
2431 static void
2433 {
2434  if (jvl->singleton)
2435  {
2436  jvl->list = list_make2(jvl->singleton, jbv);
2437  jvl->singleton = NULL;
2438  }
2439  else if (!jvl->list)
2440  jvl->singleton = jbv;
2441  else
2442  jvl->list = lappend(jvl->list, jbv);
2443 }
2444 
2445 static int
2447 {
2448  return jvl->singleton ? 1 : list_length(jvl->list);
2449 }
2450 
2451 static bool
2453 {
2454  return !jvl->singleton && list_length(jvl->list) <= 0;
2455 }
2456 
2457 static JsonbValue *
2459 {
2460  return jvl->singleton ? jvl->singleton : linitial(jvl->list);
2461 }
2462 
2463 static List *
2465 {
2466  if (jvl->singleton)
2467  return list_make1(jvl->singleton);
2468 
2469  return jvl->list;
2470 }
2471 
2472 static void
2474 {
2475  if (jvl->singleton)
2476  {
2477  it->value = jvl->singleton;
2478  it->list = NIL;
2479  it->next = NULL;
2480  }
2481  else if (jvl->list != NIL)
2482  {
2483  it->value = (JsonbValue *) linitial(jvl->list);
2484  it->list = jvl->list;
2485  it->next = list_second_cell(jvl->list);
2486  }
2487  else
2488  {
2489  it->value = NULL;
2490  it->list = NIL;
2491  it->next = NULL;
2492  }
2493 }
2494 
2495 /*
2496  * Get the next item from the sequence advancing iterator.
2497  */
2498 static JsonbValue *
2500 {
2501  JsonbValue *result = it->value;
2502 
2503  if (it->next)
2504  {
2505  it->value = lfirst(it->next);
2506  it->next = lnext(it->list, it->next);
2507  }
2508  else
2509  {
2510  it->value = NULL;
2511  }
2512 
2513  return result;
2514 }
2515 
2516 /*
2517  * Initialize a binary JsonbValue with the given jsonb container.
2518  */
2519 static JsonbValue *
2521 {
2522  jbv->type = jbvBinary;
2523  jbv->val.binary.data = &jb->root;
2524  jbv->val.binary.len = VARSIZE_ANY_EXHDR(jb);
2525 
2526  return jbv;
2527 }
2528 
2529 /*
2530  * Returns jbv* type of JsonbValue. Note, it never returns jbvBinary as is.
2531  */
2532 static int
2534 {
2535  int type = jb->type;
2536 
2537  if (jb->type == jbvBinary)
2538  {
2539  JsonbContainer *jbc = (void *) jb->val.binary.data;
2540 
2541  /* Scalars should be always extracted during jsonpath execution. */
2543 
2544  if (JsonContainerIsObject(jbc))
2545  type = jbvObject;
2546  else if (JsonContainerIsArray(jbc))
2547  type = jbvArray;
2548  else
2549  elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
2550  }
2551 
2552  return type;
2553 }
2554 
2555 /* Get scalar of given type or NULL on type mismatch */
2556 static JsonbValue *
2558 {
2559  /* Scalars should be always extracted during jsonpath execution. */
2560  Assert(scalar->type != jbvBinary ||
2561  !JsonContainerIsScalar(scalar->val.binary.data));
2562 
2563  return scalar->type == type ? scalar : NULL;
2564 }
2565 
2566 /* Construct a JSON array from the item list */
2567 static JsonbValue *
2569 {
2570  JsonbParseState *ps = NULL;
2572  JsonbValue *jbv;
2573 
2574  pushJsonbValue(&ps, WJB_BEGIN_ARRAY, NULL);
2575 
2576  JsonValueListInitIterator(items, &it);
2577  while ((jbv = JsonValueListNext(items, &it)))
2578  pushJsonbValue(&ps, WJB_ELEM, jbv);
2579 
2580  return pushJsonbValue(&ps, WJB_END_ARRAY, NULL);
2581 }
2582 
2583 /* Check if the timezone required for casting from type1 to type2 is used */
2584 static void
2585 checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
2586 {
2587  if (!useTz)
2588  ereport(ERROR,
2589  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2590  errmsg("cannot convert value from %s to %s without timezone usage",
2591  type1, type2),
2592  errhint("Use *_tz() function for timezone support.")));
2593 }
2594 
2595 /* Convert time datum to timetz datum */
2596 static Datum
2597 castTimeToTimeTz(Datum time, bool useTz)
2598 {
2599  checkTimezoneIsUsedForCast(useTz, "time", "timetz");
2600 
2601  return DirectFunctionCall1(time_timetz, time);
2602 }
2603 
2604 /*---
2605  * Compares 'ts1' and 'ts2' timestamp, assuming that ts1 might be overflowed
2606  * during cast from another datatype.
2607  *
2608  * 'overflow1' specifies overflow of 'ts1' value:
2609  * 0 - no overflow,
2610  * -1 - exceed lower boundary,
2611  * 1 - exceed upper boundary.
2612  */
2613 static int
2615 {
2616  /*
2617  * All the timestamps we deal with in jsonpath are produced by
2618  * to_datetime() method. So, they should be valid.
2619  */
2620  Assert(IS_VALID_TIMESTAMP(ts2));
2621 
2622  /*
2623  * Timestamp, which exceed lower (upper) bound, is always lower (higher)
2624  * than any valid timestamp except minus (plus) infinity.
2625  */
2626  if (overflow1)
2627  {
2628  if (overflow1 < 0)
2629  {
2630  if (TIMESTAMP_IS_NOBEGIN(ts2))
2631  return 1;
2632  else
2633  return -1;
2634  }
2635  if (overflow1 > 0)
2636  {
2637  if (TIMESTAMP_IS_NOEND(ts2))
2638  return -1;
2639  else
2640  return 1;
2641  }
2642  }
2643 
2644  return timestamp_cmp_internal(ts1, ts2);
2645 }
2646 
2647 /*
2648  * Compare date to timestamptz without throwing overflow error during cast.
2649  */
2650 static int
2651 cmpDateToTimestamp(DateADT date1, Timestamp ts2, bool useTz)
2652 {
2653  TimestampTz ts1;
2654  int overflow = 0;
2655 
2656  ts1 = date2timestamp_opt_overflow(date1, &overflow);
2657 
2658  return cmpTimestampWithOverflow(ts1, overflow, ts2);
2659 }
2660 
2661 /*
2662  * Compare date to timestamptz without throwing overflow error during cast.
2663  */
2664 static int
2665 cmpDateToTimestampTz(DateADT date1, TimestampTz tstz2, bool useTz)
2666 {
2667  TimestampTz tstz1;
2668  int overflow = 0;
2669 
2670  checkTimezoneIsUsedForCast(useTz, "date", "timestamptz");
2671 
2672  tstz1 = date2timestamptz_opt_overflow(date1, &overflow);
2673 
2674  return cmpTimestampWithOverflow(tstz1, overflow, tstz2);
2675 }
2676 
2677 /*
2678  * Compare timestamp to timestamptz without throwing overflow error during cast.
2679  */
2680 static int
2682 {
2683  TimestampTz tstz1;
2684  int overflow = 0;
2685 
2686  checkTimezoneIsUsedForCast(useTz, "timestamp", "timestamptz");
2687 
2688  tstz1 = timestamp2timestamptz_opt_overflow(ts1, &overflow);
2689 
2690  return cmpTimestampWithOverflow(tstz1, overflow, tstz2);
2691 }
2692 
2693 /*
2694  * Cross-type comparison of two datetime SQL/JSON items. If items are
2695  * uncomparable *cast_error flag is set, otherwise *cast_error is unset.
2696  * If the cast requires timezone and it is not used, then explicit error is thrown.
2697  */
2698 static int
2699 compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
2700  bool useTz, bool *cast_error)
2701 {
2702  PGFunction cmpfunc;
2703 
2704  *cast_error = false;
2705 
2706  switch (typid1)
2707  {
2708  case DATEOID:
2709  switch (typid2)
2710  {
2711  case DATEOID:
2712  cmpfunc = date_cmp;
2713 
2714  break;
2715 
2716  case TIMESTAMPOID:
2717  return cmpDateToTimestamp(DatumGetDateADT(val1),
2718  DatumGetTimestamp(val2),
2719  useTz);
2720 
2721  case TIMESTAMPTZOID:
2723  DatumGetTimestampTz(val2),
2724  useTz);
2725 
2726  case TIMEOID:
2727  case TIMETZOID:
2728  *cast_error = true; /* uncomparable types */
2729  return 0;
2730 
2731  default:
2732  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2733  typid2);
2734  }
2735  break;
2736 
2737  case TIMEOID:
2738  switch (typid2)
2739  {
2740  case TIMEOID:
2741  cmpfunc = time_cmp;
2742 
2743  break;
2744 
2745  case TIMETZOID:
2746  val1 = castTimeToTimeTz(val1, useTz);
2747  cmpfunc = timetz_cmp;
2748 
2749  break;
2750 
2751  case DATEOID:
2752  case TIMESTAMPOID:
2753  case TIMESTAMPTZOID:
2754  *cast_error = true; /* uncomparable types */
2755  return 0;
2756 
2757  default:
2758  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2759  typid2);
2760  }
2761  break;
2762 
2763  case TIMETZOID:
2764  switch (typid2)
2765  {
2766  case TIMEOID:
2767  val2 = castTimeToTimeTz(val2, useTz);
2768  cmpfunc = timetz_cmp;
2769 
2770  break;
2771 
2772  case TIMETZOID:
2773  cmpfunc = timetz_cmp;
2774 
2775  break;
2776 
2777  case DATEOID:
2778  case TIMESTAMPOID:
2779  case TIMESTAMPTZOID:
2780  *cast_error = true; /* uncomparable types */
2781  return 0;
2782 
2783  default:
2784  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2785  typid2);
2786  }
2787  break;
2788 
2789  case TIMESTAMPOID:
2790  switch (typid2)
2791  {
2792  case DATEOID:
2793  return -cmpDateToTimestamp(DatumGetDateADT(val2),
2794  DatumGetTimestamp(val1),
2795  useTz);
2796 
2797  case TIMESTAMPOID:
2798  cmpfunc = timestamp_cmp;
2799 
2800  break;
2801 
2802  case TIMESTAMPTZOID:
2804  DatumGetTimestampTz(val2),
2805  useTz);
2806 
2807  case TIMEOID:
2808  case TIMETZOID:
2809  *cast_error = true; /* uncomparable types */
2810  return 0;
2811 
2812  default:
2813  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2814  typid2);
2815  }
2816  break;
2817 
2818  case TIMESTAMPTZOID:
2819  switch (typid2)
2820  {
2821  case DATEOID:
2822  return -cmpDateToTimestampTz(DatumGetDateADT(val2),
2823  DatumGetTimestampTz(val1),
2824  useTz);
2825 
2826  case TIMESTAMPOID:
2828  DatumGetTimestampTz(val1),
2829  useTz);
2830 
2831  case TIMESTAMPTZOID:
2832  cmpfunc = timestamp_cmp;
2833 
2834  break;
2835 
2836  case TIMEOID:
2837  case TIMETZOID:
2838  *cast_error = true; /* uncomparable types */
2839  return 0;
2840 
2841  default:
2842  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2843  typid2);
2844  }
2845  break;
2846 
2847  default:
2848  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u", typid1);
2849  }
2850 
2851  if (*cast_error)
2852  return 0; /* cast error */
2853 
2854  return DatumGetInt32(DirectFunctionCall2(cmpfunc, val1, val2));
2855 }
#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:2331
#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:1278
int errhint(const char *fmt,...)
Definition: elog.c:1071
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:218
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:2052
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:2112
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 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:2424
int64 TimestampTz
Definition: timestamp.h:39
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:293
#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:2596
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:927
#define JsonContainerIsScalar(jc)
Definition: jsonb.h:215
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:651
Datum numeric_cmp(PG_FUNCTION_ARGS)
Definition: numeric.c:2042
#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
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:610
static JsonbValue * getScalar(JsonbValue *scalar, enum jbvType type)
static int cmpTimestampWithOverflow(Timestamp ts1, int overflow1, Timestamp ts2)
Datum parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict, Oid *typid, int32 *typmod, int *tz, bool *have_error)
Definition: formatting.c:4226
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:624
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define lengthof(array)
Definition: c.h:675
#define PG_UINT32_MAX
Definition: c.h:458
unsigned int Oid
Definition: postgres_ext.h:31
struct NumericData * Numeric
Definition: numeric.h:43
struct JsonPathItem::@128::@130 array
Datum int8_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:3477
JsonBaseObjectInfo baseObject
Definition: jsonpath_exec.c:97
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:297
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:2536
static int compareNumeric(Numeric a, Numeric b)
JsonPathBool
char * pg_server_to_any(const char *s, int len, int encoding)
Definition: mbutils.c:692
signed int int32
Definition: c.h:362
static JsonPathExecResult getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, int32 *index)
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1710
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:299
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:1125
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition: numeric.c:1097
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:1587
Timestamp date2timestamp_opt_overflow(DateADT dateVal, int *overflow)
Definition: date.c:563
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
#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:617
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:184
void check_stack_depth(void)
Definition: postgres.c:3312
#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:957
static JsonPathExecResult executeItemUnwrapTargetArray(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found, bool unwrapElements)
TimestampTz timestamp2timestamptz_opt_overflow(Timestamp timestamp, int *overflow)
Definition: timestamp.c:5182
#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:374
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:1701
struct JsonLikeRegexContext JsonLikeRegexContext
static void checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
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:321
int64 Timestamp
Definition: timestamp.h:38
Datum numeric_floor(PG_FUNCTION_ARGS)
Definition: numeric.c:1350
#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:3385
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:3403
char * s2
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:358
uintptr_t Datum
Definition: postgres.h:367
Definition: type.h:109
#define JsonContainerIsObject(jc)
Definition: jsonb.h:216
int GetDatabaseEncoding(void)
Definition: mbutils.c:1151
JsonbContainer * jbc
Definition: jsonpath_exec.c:85
Numeric(* BinaryArithmFunc)(Numeric num1, Numeric num2, bool *error)
union JsonPathItem::@128 content
Datum float8_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:3575
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:2716
static struct @143 value
#define ereport(elevel,...)
Definition: elog.h:144
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:172
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:745
#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:429
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
struct JsonPathExecContext JsonPathExecContext
int jspConvertRegexFlags(uint32 xflags)
#define jspAutoWrap(cxt)
#define PG_NARGS()
Definition: fmgr.h:203
struct JsonPathItem::@128::@131 anybounds
static JsonPathExecResult executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found)
Datum jsonb_path_match_tz(PG_FUNCTION_ARGS)
enum jbvType type
Definition: jsonb.h:263
Datum time_timetz(PG_FUNCTION_ARGS)
Definition: date.c:2623
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)
char * text_to_cstring(const text *t)
Definition: varlena.c:205
#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:824
Datum numeric_ceil(PG_FUNCTION_ARGS)
Definition: numeric.c:1325
struct JsonPathItem::@128::@133 like_regex
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:2480
#define elog(elevel,...)
Definition: elog.h:214
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:391
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:562
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#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
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:626
#define PG_RETURN_NULL()
Definition: fmgr.h:344
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:860
static int cmpTimestampToTimestampTz(Timestamp ts1, TimestampTz tstz2, bool useTz)
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:317
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:295