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