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