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