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/datum.h"
70 #include "utils/formatting.h"
71 #include "utils/float.h"
72 #include "utils/guc.h"
73 #include "utils/json.h"
74 #include "utils/jsonpath.h"
75 #include "utils/date.h"
76 #include "utils/timestamp.h"
77 #include "utils/varlena.h"
78 
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 */
111 
112 /* Context for LIKE_REGEX execution. */
113 typedef struct JsonLikeRegexContext
114 {
116  int cflags;
118 
119 /* Result of jsonpath predicate evaluation */
120 typedef enum JsonPathBool
121 {
122  jpbFalse = 0,
123  jpbTrue = 1,
125 } JsonPathBool;
126 
127 /* Result of jsonpath expression evaluation */
128 typedef enum JsonPathExecResult
129 {
130  jperOk = 0,
134 
135 #define jperIsError(jper) ((jper) == jperError)
136 
137 /*
138  * List of jsonb values with shortcut for single-value list.
139  */
140 typedef struct JsonValueList
141 {
144 } JsonValueList;
145 
146 typedef struct JsonValueListIterator
147 {
152 
153 /* strict/lax flags is decomposed into four [un]wrap/error flags */
154 #define jspStrictAbsenseOfErrors(cxt) (!(cxt)->laxMode)
155 #define jspAutoUnwrap(cxt) ((cxt)->laxMode)
156 #define jspAutoWrap(cxt) ((cxt)->laxMode)
157 #define jspIgnoreStructuralErrors(cxt) ((cxt)->ignoreStructuralErrors)
158 #define jspThrowErrors(cxt) ((cxt)->throwErrors)
159 
160 /* Convenience macro: return or throw error depending on context */
161 #define RETURN_ERROR(throw_error) \
162 do { \
163  if (jspThrowErrors(cxt)) \
164  throw_error; \
165  else \
166  return jperError; \
167 } while (0)
168 
170  JsonbValue *larg,
171  JsonbValue *rarg,
172  void *param);
173 typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
174 
176  Jsonb *json, bool throwErrors, JsonValueList *result);
178  JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found);
180  JsonPathItem *jsp, JsonbValue *jb,
181  JsonValueList *found, bool unwrap);
183  JsonPathItem *jsp, JsonbValue *jb,
184  JsonValueList *found, bool unwrapElements);
187  JsonbValue *v, JsonValueList *found, bool copy);
189  bool unwrap, JsonValueList *found);
191  JsonbValue *jb, bool unwrap, JsonValueList *found);
193  JsonPathItem *jsp, JsonbValue *jb, bool canHaveNext);
195  JsonPathItem *jsp, JsonbValue *jb);
198  uint32 level, uint32 first, uint32 last,
199  bool ignoreStructuralErrors, bool unwrapNext);
201  JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg,
202  JsonbValue *jb, bool unwrapRightArg,
203  JsonPathPredicateCallback exec, void *param);
205  JsonPathItem *jsp, JsonbValue *jb,
206  BinaryArithmFunc func, JsonValueList *found);
208  JsonPathItem *jsp, JsonbValue *jb, PGFunction func,
209  JsonValueList *found);
211  JsonbValue *whole, JsonbValue *initial, void *param);
213  JsonbValue *rarg, void *param);
215  JsonPathItem *jsp, JsonbValue *jb, bool unwrap, PGFunction func,
216  JsonValueList *found);
218  JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found);
220  JsonPathItem *jsp, JsonValueList *found, JsonPathBool res);
221 static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
222  JsonbValue *value);
225 static int JsonbArraySize(JsonbValue *jb);
227  JsonbValue *rv, void *p);
228 static JsonPathBool compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2);
229 static int compareNumeric(Numeric a, Numeric b);
230 static JsonbValue *copyJsonbValue(JsonbValue *src);
232  JsonPathItem *jsp, JsonbValue *jb, int32 *index);
234  JsonbValue *jbv, int32 id);
235 static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv);
236 static int JsonValueListLength(const JsonValueList *jvl);
237 static bool JsonValueListIsEmpty(JsonValueList *jvl);
240 static void JsonValueListInitIterator(const JsonValueList *jvl,
242 static JsonbValue *JsonValueListNext(const JsonValueList *jvl,
244 static int JsonbType(JsonbValue *jb);
245 static JsonbValue *JsonbInitBinary(JsonbValue *jbv, Jsonb *jb);
246 static int JsonbType(JsonbValue *jb);
247 static JsonbValue *getScalar(JsonbValue *scalar, enum jbvType type);
248 static JsonbValue *wrapItemsInArray(const JsonValueList *items);
249 
250 /****************** User interface to JsonPath executor ********************/
251 
252 /*
253  * jsonb_path_exists
254  * Returns true if jsonpath returns at least one item for the specified
255  * jsonb value. This function and jsonb_path_match() are used to
256  * implement @? and @@ operators, which in turn are intended to have an
257  * index support. Thus, it's desirable to make it easier to achieve
258  * consistency between index scan results and sequential scan results.
259  * So, we throw as less errors as possible. Regarding this function,
260  * such behavior also matches behavior of JSON_EXISTS() clause of
261  * SQL/JSON. Regarding jsonb_path_match(), this function doesn't have
262  * an analogy in SQL/JSON, so we define its behavior on our own.
263  */
264 Datum
266 {
267  Jsonb *jb = PG_GETARG_JSONB_P(0);
269  JsonPathExecResult res;
270  Jsonb *vars = NULL;
271  bool silent = true;
272 
273  if (PG_NARGS() == 4)
274  {
275  vars = PG_GETARG_JSONB_P(2);
276  silent = PG_GETARG_BOOL(3);
277  }
278 
279  res = executeJsonPath(jp, vars, jb, !silent, NULL);
280 
281  PG_FREE_IF_COPY(jb, 0);
282  PG_FREE_IF_COPY(jp, 1);
283 
284  if (jperIsError(res))
285  PG_RETURN_NULL();
286 
287  PG_RETURN_BOOL(res == jperOk);
288 }
289 
290 /*
291  * jsonb_path_exists_opr
292  * Implementation of operator "jsonb @? jsonpath" (2-argument version of
293  * jsonb_path_exists()).
294  */
295 Datum
297 {
298  /* just call the other one -- it can handle both cases */
299  return jsonb_path_exists(fcinfo);
300 }
301 
302 /*
303  * jsonb_path_match
304  * Returns jsonpath predicate result item for the specified jsonb value.
305  * See jsonb_path_exists() comment for details regarding error handling.
306  */
307 Datum
309 {
310  Jsonb *jb = PG_GETARG_JSONB_P(0);
312  JsonValueList found = {0};
313  Jsonb *vars = NULL;
314  bool silent = true;
315 
316  if (PG_NARGS() == 4)
317  {
318  vars = PG_GETARG_JSONB_P(2);
319  silent = PG_GETARG_BOOL(3);
320  }
321 
322  (void) executeJsonPath(jp, vars, jb, !silent, &found);
323 
324  PG_FREE_IF_COPY(jb, 0);
325  PG_FREE_IF_COPY(jp, 1);
326 
327  if (JsonValueListLength(&found) == 1)
328  {
329  JsonbValue *jbv = JsonValueListHead(&found);
330 
331  if (jbv->type == jbvBool)
332  PG_RETURN_BOOL(jbv->val.boolean);
333 
334  if (jbv->type == jbvNull)
335  PG_RETURN_NULL();
336  }
337 
338  if (!silent)
339  ereport(ERROR,
340  (errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
341  errmsg("single boolean result is expected")));
342 
343  PG_RETURN_NULL();
344 }
345 
346 /*
347  * jsonb_path_match_opr
348  * Implementation of operator "jsonb @@ jsonpath" (2-argument version of
349  * jsonb_path_match()).
350  */
351 Datum
353 {
354  /* just call the other one -- it can handle both cases */
355  return jsonb_path_match(fcinfo);
356 }
357 
358 /*
359  * jsonb_path_query
360  * Executes jsonpath for given jsonb document and returns result as
361  * rowset.
362  */
363 Datum
365 {
366  FuncCallContext *funcctx;
367  List *found;
368  JsonbValue *v;
369  ListCell *c;
370 
371  if (SRF_IS_FIRSTCALL())
372  {
373  JsonPath *jp;
374  Jsonb *jb;
375  MemoryContext oldcontext;
376  Jsonb *vars;
377  bool silent;
378  JsonValueList found = {0};
379 
380  funcctx = SRF_FIRSTCALL_INIT();
381  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
382 
383  jb = PG_GETARG_JSONB_P_COPY(0);
385  vars = PG_GETARG_JSONB_P_COPY(2);
386  silent = PG_GETARG_BOOL(3);
387 
388  (void) executeJsonPath(jp, vars, jb, !silent, &found);
389 
390  funcctx->user_fctx = JsonValueListGetList(&found);
391 
392  MemoryContextSwitchTo(oldcontext);
393  }
394 
395  funcctx = SRF_PERCALL_SETUP();
396  found = funcctx->user_fctx;
397 
398  c = list_head(found);
399 
400  if (c == NULL)
401  SRF_RETURN_DONE(funcctx);
402 
403  v = lfirst(c);
404  funcctx->user_fctx = list_delete_first(found);
405 
407 }
408 
409 /*
410  * jsonb_path_query_array
411  * Executes jsonpath for given jsonb document and returns result as
412  * jsonb array.
413  */
414 Datum
416 {
417  Jsonb *jb = PG_GETARG_JSONB_P(0);
419  JsonValueList found = {0};
421  bool silent = PG_GETARG_BOOL(3);
422 
423  (void) executeJsonPath(jp, vars, jb, !silent, &found);
424 
426 }
427 
428 /*
429  * jsonb_path_query_first
430  * Executes jsonpath for given jsonb document and returns first result
431  * item. If there are no items, NULL returned.
432  */
433 Datum
435 {
436  Jsonb *jb = PG_GETARG_JSONB_P(0);
438  JsonValueList found = {0};
440  bool silent = PG_GETARG_BOOL(3);
441 
442  (void) executeJsonPath(jp, vars, jb, !silent, &found);
443 
444  if (JsonValueListLength(&found) >= 1)
446  else
447  PG_RETURN_NULL();
448 }
449 
450 /********************Execute functions for JsonPath**************************/
451 
452 /*
453  * Interface to jsonpath executor
454  *
455  * 'path' - jsonpath to be executed
456  * 'vars' - variables to be substituted to jsonpath
457  * 'json' - target document for jsonpath evaluation
458  * 'throwErrors' - whether we should throw suppressible errors
459  * 'result' - list to store result items into
460  *
461  * Returns an error if a recoverable error happens during processing, or NULL
462  * on no error.
463  *
464  * Note, jsonb and jsonpath values should be available and untoasted during
465  * work because JsonPathItem, JsonbValue and result item could have pointers
466  * into input values. If caller needs to just check if document matches
467  * jsonpath, then it doesn't provide a result arg. In this case executor
468  * works till first positive result and does not check the rest if possible.
469  * In other case it tries to find all the satisfied result items.
470  */
471 static JsonPathExecResult
472 executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
473  JsonValueList *result)
474 {
476  JsonPathExecResult res;
477  JsonPathItem jsp;
478  JsonbValue jbv;
479 
480  jspInit(&jsp, path);
481 
482  if (!JsonbExtractScalar(&json->root, &jbv))
483  JsonbInitBinary(&jbv, json);
484 
485  if (vars && !JsonContainerIsObject(&vars->root))
486  {
487  ereport(ERROR,
488  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
489  errmsg("\"vars\" argument is not an object"),
490  errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
491  }
492 
493  cxt.vars = vars;
494  cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
496  cxt.root = &jbv;
497  cxt.current = &jbv;
498  cxt.baseObject.jbc = NULL;
499  cxt.baseObject.id = 0;
500  cxt.lastGeneratedObjectId = vars ? 2 : 1;
501  cxt.innermostArraySize = -1;
502  cxt.throwErrors = throwErrors;
503 
504  if (jspStrictAbsenseOfErrors(&cxt) && !result)
505  {
506  /*
507  * In strict mode we must get a complete list of values to check that
508  * there are no errors at all.
509  */
510  JsonValueList vals = {0};
511 
512  res = executeItem(&cxt, &jsp, &jbv, &vals);
513 
514  if (jperIsError(res))
515  return res;
516 
517  return JsonValueListIsEmpty(&vals) ? jperNotFound : jperOk;
518  }
519 
520  res = executeItem(&cxt, &jsp, &jbv, result);
521 
522  Assert(!throwErrors || !jperIsError(res));
523 
524  return res;
525 }
526 
527 /*
528  * Execute jsonpath with automatic unwrapping of current item in lax mode.
529  */
530 static JsonPathExecResult
532  JsonbValue *jb, JsonValueList *found)
533 {
534  return executeItemOptUnwrapTarget(cxt, jsp, jb, found, jspAutoUnwrap(cxt));
535 }
536 
537 /*
538  * Main jsonpath executor function: walks on jsonpath structure, finds
539  * relevant parts of jsonb and evaluates expressions over them.
540  * When 'unwrap' is true current SQL/JSON item is unwrapped if it is an array.
541  */
542 static JsonPathExecResult
544  JsonbValue *jb, JsonValueList *found, bool unwrap)
545 {
546  JsonPathItem elem;
548  JsonBaseObjectInfo baseObject;
549 
552 
553  switch (jsp->type)
554  {
555  /* all boolean item types: */
556  case jpiAnd:
557  case jpiOr:
558  case jpiNot:
559  case jpiIsUnknown:
560  case jpiEqual:
561  case jpiNotEqual:
562  case jpiLess:
563  case jpiGreater:
564  case jpiLessOrEqual:
565  case jpiGreaterOrEqual:
566  case jpiExists:
567  case jpiStartsWith:
568  case jpiLikeRegex:
569  {
570  JsonPathBool st = executeBoolItem(cxt, jsp, jb, true);
571 
572  res = appendBoolResult(cxt, jsp, found, st);
573  break;
574  }
575 
576  case jpiKey:
577  if (JsonbType(jb) == jbvObject)
578  {
579  JsonbValue *v;
580  JsonbValue key;
581 
582  key.type = jbvString;
583  key.val.string.val = jspGetString(jsp, &key.val.string.len);
584 
585  v = findJsonbValueFromContainer(jb->val.binary.data,
586  JB_FOBJECT, &key);
587 
588  if (v != NULL)
589  {
590  res = executeNextItem(cxt, jsp, NULL,
591  v, found, false);
592 
593  /* free value if it was not added to found list */
594  if (jspHasNext(jsp) || !found)
595  pfree(v);
596  }
597  else if (!jspIgnoreStructuralErrors(cxt))
598  {
599  Assert(found);
600 
601  if (!jspThrowErrors(cxt))
602  return jperError;
603 
604  ereport(ERROR,
605  (errcode(ERRCODE_JSON_MEMBER_NOT_FOUND), \
606  errmsg("JSON object does not contain key \"%s\"",
607  pnstrdup(key.val.string.val,
608  key.val.string.len))));
609  }
610  }
611  else if (unwrap && JsonbType(jb) == jbvArray)
612  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
613  else if (!jspIgnoreStructuralErrors(cxt))
614  {
615  Assert(found);
617  (errcode(ERRCODE_JSON_MEMBER_NOT_FOUND),
618  errmsg("jsonpath member accessor can only be applied to an object"))));
619  }
620  break;
621 
622  case jpiRoot:
623  jb = cxt->root;
624  baseObject = setBaseObject(cxt, jb, 0);
625  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
626  cxt->baseObject = baseObject;
627  break;
628 
629  case jpiCurrent:
630  res = executeNextItem(cxt, jsp, NULL, cxt->current,
631  found, true);
632  break;
633 
634  case jpiAnyArray:
635  if (JsonbType(jb) == jbvArray)
636  {
637  bool hasNext = jspGetNext(jsp, &elem);
638 
639  res = executeItemUnwrapTargetArray(cxt, hasNext ? &elem : NULL,
640  jb, found, jspAutoUnwrap(cxt));
641  }
642  else if (jspAutoWrap(cxt))
643  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
644  else if (!jspIgnoreStructuralErrors(cxt))
646  (errcode(ERRCODE_JSON_ARRAY_NOT_FOUND),
647  errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
648  break;
649 
650  case jpiIndexArray:
651  if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
652  {
653  int innermostArraySize = cxt->innermostArraySize;
654  int i;
655  int size = JsonbArraySize(jb);
656  bool singleton = size < 0;
657  bool hasNext = jspGetNext(jsp, &elem);
658 
659  if (singleton)
660  size = 1;
661 
662  cxt->innermostArraySize = size; /* for LAST evaluation */
663 
664  for (i = 0; i < jsp->content.array.nelems; i++)
665  {
666  JsonPathItem from;
667  JsonPathItem to;
668  int32 index;
669  int32 index_from;
670  int32 index_to;
671  bool range = jspGetArraySubscript(jsp, &from,
672  &to, i);
673 
674  res = getArrayIndex(cxt, &from, jb, &index_from);
675 
676  if (jperIsError(res))
677  break;
678 
679  if (range)
680  {
681  res = getArrayIndex(cxt, &to, jb, &index_to);
682 
683  if (jperIsError(res))
684  break;
685  }
686  else
687  index_to = index_from;
688 
689  if (!jspIgnoreStructuralErrors(cxt) &&
690  (index_from < 0 ||
691  index_from > index_to ||
692  index_to >= size))
694  (errcode(ERRCODE_INVALID_JSON_SUBSCRIPT),
695  errmsg("jsonpath array subscript is out of bounds"))));
696 
697  if (index_from < 0)
698  index_from = 0;
699 
700  if (index_to >= size)
701  index_to = size - 1;
702 
703  res = jperNotFound;
704 
705  for (index = index_from; index <= index_to; index++)
706  {
707  JsonbValue *v;
708  bool copy;
709 
710  if (singleton)
711  {
712  v = jb;
713  copy = true;
714  }
715  else
716  {
717  v = getIthJsonbValueFromContainer(jb->val.binary.data,
718  (uint32) index);
719 
720  if (v == NULL)
721  continue;
722 
723  copy = false;
724  }
725 
726  if (!hasNext && !found)
727  return jperOk;
728 
729  res = executeNextItem(cxt, jsp, &elem, v, found,
730  copy);
731 
732  if (jperIsError(res))
733  break;
734 
735  if (res == jperOk && !found)
736  break;
737  }
738 
739  if (jperIsError(res))
740  break;
741 
742  if (res == jperOk && !found)
743  break;
744  }
745 
746  cxt->innermostArraySize = innermostArraySize;
747  }
748  else if (!jspIgnoreStructuralErrors(cxt))
749  {
751  (errcode(ERRCODE_JSON_ARRAY_NOT_FOUND),
752  errmsg("jsonpath array accessor can only be applied to an array"))));
753  }
754  break;
755 
756  case jpiLast:
757  {
758  JsonbValue tmpjbv;
759  JsonbValue *lastjbv;
760  int last;
761  bool hasNext = jspGetNext(jsp, &elem);
762 
763  if (cxt->innermostArraySize < 0)
764  elog(ERROR, "evaluating jsonpath LAST outside of array subscript");
765 
766  if (!hasNext && !found)
767  {
768  res = jperOk;
769  break;
770  }
771 
772  last = cxt->innermostArraySize - 1;
773 
774  lastjbv = hasNext ? &tmpjbv : palloc(sizeof(*lastjbv));
775 
776  lastjbv->type = jbvNumeric;
777  lastjbv->val.numeric =
779  Int32GetDatum(last)));
780 
781  res = executeNextItem(cxt, jsp, &elem,
782  lastjbv, found, hasNext);
783  }
784  break;
785 
786  case jpiAnyKey:
787  if (JsonbType(jb) == jbvObject)
788  {
789  bool hasNext = jspGetNext(jsp, &elem);
790 
791  if (jb->type != jbvBinary)
792  elog(ERROR, "invalid jsonb object type: %d", jb->type);
793 
794  return executeAnyItem
795  (cxt, hasNext ? &elem : NULL,
796  jb->val.binary.data, found, 1, 1, 1,
797  false, jspAutoUnwrap(cxt));
798  }
799  else if (unwrap && JsonbType(jb) == jbvArray)
800  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
801  else if (!jspIgnoreStructuralErrors(cxt))
802  {
803  Assert(found);
805  (errcode(ERRCODE_JSON_OBJECT_NOT_FOUND),
806  errmsg("jsonpath wildcard member accessor can only be applied to an object"))));
807  }
808  break;
809 
810  case jpiAdd:
811  return executeBinaryArithmExpr(cxt, jsp, jb,
812  numeric_add_opt_error, found);
813 
814  case jpiSub:
815  return executeBinaryArithmExpr(cxt, jsp, jb,
816  numeric_sub_opt_error, found);
817 
818  case jpiMul:
819  return executeBinaryArithmExpr(cxt, jsp, jb,
820  numeric_mul_opt_error, found);
821 
822  case jpiDiv:
823  return executeBinaryArithmExpr(cxt, jsp, jb,
824  numeric_div_opt_error, found);
825 
826  case jpiMod:
827  return executeBinaryArithmExpr(cxt, jsp, jb,
828  numeric_mod_opt_error, found);
829 
830  case jpiPlus:
831  return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
832 
833  case jpiMinus:
834  return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus,
835  found);
836 
837  case jpiFilter:
838  {
839  JsonPathBool st;
840 
841  if (unwrap && JsonbType(jb) == jbvArray)
842  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
843  false);
844 
845  jspGetArg(jsp, &elem);
846  st = executeNestedBoolItem(cxt, &elem, jb);
847  if (st != jpbTrue)
848  res = jperNotFound;
849  else
850  res = executeNextItem(cxt, jsp, NULL,
851  jb, found, true);
852  break;
853  }
854 
855  case jpiAny:
856  {
857  bool hasNext = jspGetNext(jsp, &elem);
858 
859  /* first try without any intermediate steps */
860  if (jsp->content.anybounds.first == 0)
861  {
862  bool savedIgnoreStructuralErrors;
863 
864  savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
865  cxt->ignoreStructuralErrors = true;
866  res = executeNextItem(cxt, jsp, &elem,
867  jb, found, true);
868  cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
869 
870  if (res == jperOk && !found)
871  break;
872  }
873 
874  if (jb->type == jbvBinary)
875  res = executeAnyItem
876  (cxt, hasNext ? &elem : NULL,
877  jb->val.binary.data, found,
878  1,
879  jsp->content.anybounds.first,
880  jsp->content.anybounds.last,
881  true, jspAutoUnwrap(cxt));
882  break;
883  }
884 
885  case jpiNull:
886  case jpiBool:
887  case jpiNumeric:
888  case jpiString:
889  case jpiVariable:
890  {
891  JsonbValue vbuf;
892  JsonbValue *v;
893  bool hasNext = jspGetNext(jsp, &elem);
894 
895  if (!hasNext && !found)
896  {
897  res = jperOk; /* skip evaluation */
898  break;
899  }
900 
901  v = hasNext ? &vbuf : palloc(sizeof(*v));
902 
903  baseObject = cxt->baseObject;
904  getJsonPathItem(cxt, jsp, v);
905 
906  res = executeNextItem(cxt, jsp, &elem,
907  v, found, hasNext);
908  cxt->baseObject = baseObject;
909  }
910  break;
911 
912  case jpiType:
913  {
914  JsonbValue *jbv = palloc(sizeof(*jbv));
915 
916  jbv->type = jbvString;
917  jbv->val.string.val = pstrdup(JsonbTypeName(jb));
918  jbv->val.string.len = strlen(jbv->val.string.val);
919 
920  res = executeNextItem(cxt, jsp, NULL, jbv,
921  found, false);
922  }
923  break;
924 
925  case jpiSize:
926  {
927  int size = JsonbArraySize(jb);
928 
929  if (size < 0)
930  {
931  if (!jspAutoWrap(cxt))
932  {
933  if (!jspIgnoreStructuralErrors(cxt))
935  (errcode(ERRCODE_JSON_ARRAY_NOT_FOUND),
936  errmsg("jsonpath item method .%s() can only be applied to an array",
937  jspOperationName(jsp->type)))));
938  break;
939  }
940 
941  size = 1;
942  }
943 
944  jb = palloc(sizeof(*jb));
945 
946  jb->type = jbvNumeric;
947  jb->val.numeric =
949  Int32GetDatum(size)));
950 
951  res = executeNextItem(cxt, jsp, NULL, jb, found, false);
952  }
953  break;
954 
955  case jpiAbs:
956  return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_abs,
957  found);
958 
959  case jpiFloor:
960  return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_floor,
961  found);
962 
963  case jpiCeiling:
964  return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_ceil,
965  found);
966 
967  case jpiDouble:
968  {
969  JsonbValue jbv;
970 
971  if (unwrap && JsonbType(jb) == jbvArray)
972  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
973  false);
974 
975  if (jb->type == jbvNumeric)
976  {
978  NumericGetDatum(jb->val.numeric)));
979  bool have_error = false;
980 
981  (void) float8in_internal_opt_error(tmp,
982  NULL,
983  "double precision",
984  tmp,
985  &have_error);
986 
987  if (have_error)
989  (errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
990  errmsg("jsonpath item method .%s() can only be applied to a numeric value",
991  jspOperationName(jsp->type)))));
992  res = jperOk;
993  }
994  else if (jb->type == jbvString)
995  {
996  /* cast string as double */
997  double val;
998  char *tmp = pnstrdup(jb->val.string.val,
999  jb->val.string.len);
1000  bool have_error = false;
1001 
1002  val = float8in_internal_opt_error(tmp,
1003  NULL,
1004  "double precision",
1005  tmp,
1006  &have_error);
1007 
1008  if (have_error || isinf(val))
1010  (errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
1011  errmsg("jsonpath item method .%s() can only be applied to a numeric value",
1012  jspOperationName(jsp->type)))));
1013 
1014  jb = &jbv;
1015  jb->type = jbvNumeric;
1017  Float8GetDatum(val)));
1018  res = jperOk;
1019  }
1020 
1021  if (res == jperNotFound)
1023  (errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
1024  errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1025  jspOperationName(jsp->type)))));
1026 
1027  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1028  }
1029  break;
1030 
1031  case jpiKeyValue:
1032  if (unwrap && JsonbType(jb) == jbvArray)
1033  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1034 
1035  return executeKeyValueMethod(cxt, jsp, jb, found);
1036 
1037  default:
1038  elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
1039  }
1040 
1041  return res;
1042 }
1043 
1044 /*
1045  * Unwrap current array item and execute jsonpath for each of its elements.
1046  */
1047 static JsonPathExecResult
1049  JsonbValue *jb, JsonValueList *found,
1050  bool unwrapElements)
1051 {
1052  if (jb->type != jbvBinary)
1053  {
1054  Assert(jb->type != jbvArray);
1055  elog(ERROR, "invalid jsonb array value type: %d", jb->type);
1056  }
1057 
1058  return executeAnyItem
1059  (cxt, jsp, jb->val.binary.data, found, 1, 1, 1,
1060  false, unwrapElements);
1061 }
1062 
1063 /*
1064  * Execute next jsonpath item if exists. Otherwise put "v" to the "found"
1065  * list if provided.
1066  */
1067 static JsonPathExecResult
1070  JsonbValue *v, JsonValueList *found, bool copy)
1071 {
1072  JsonPathItem elem;
1073  bool hasNext;
1074 
1075  if (!cur)
1076  hasNext = next != NULL;
1077  else if (next)
1078  hasNext = jspHasNext(cur);
1079  else
1080  {
1081  next = &elem;
1082  hasNext = jspGetNext(cur, next);
1083  }
1084 
1085  if (hasNext)
1086  return executeItem(cxt, next, v, found);
1087 
1088  if (found)
1089  JsonValueListAppend(found, copy ? copyJsonbValue(v) : v);
1090 
1091  return jperOk;
1092 }
1093 
1094 /*
1095  * Same as executeItem(), but when "unwrap == true" automatically unwraps
1096  * each array item from the resulting sequence in lax mode.
1097  */
1098 static JsonPathExecResult
1100  JsonbValue *jb, bool unwrap,
1101  JsonValueList *found)
1102 {
1103  if (unwrap && jspAutoUnwrap(cxt))
1104  {
1105  JsonValueList seq = {0};
1107  JsonPathExecResult res = executeItem(cxt, jsp, jb, &seq);
1108  JsonbValue *item;
1109 
1110  if (jperIsError(res))
1111  return res;
1112 
1113  JsonValueListInitIterator(&seq, &it);
1114  while ((item = JsonValueListNext(&seq, &it)))
1115  {
1116  Assert(item->type != jbvArray);
1117 
1118  if (JsonbType(item) == jbvArray)
1119  executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
1120  else
1121  JsonValueListAppend(found, item);
1122  }
1123 
1124  return jperOk;
1125  }
1126 
1127  return executeItem(cxt, jsp, jb, found);
1128 }
1129 
1130 /*
1131  * Same as executeItemOptUnwrapResult(), but with error suppression.
1132  */
1133 static JsonPathExecResult
1135  JsonPathItem *jsp,
1136  JsonbValue *jb, bool unwrap,
1137  JsonValueList *found)
1138 {
1139  JsonPathExecResult res;
1140  bool throwErrors = cxt->throwErrors;
1141 
1142  cxt->throwErrors = false;
1143  res = executeItemOptUnwrapResult(cxt, jsp, jb, unwrap, found);
1144  cxt->throwErrors = throwErrors;
1145 
1146  return res;
1147 }
1148 
1149 /* Execute boolean-valued jsonpath expression. */
1150 static JsonPathBool
1152  JsonbValue *jb, bool canHaveNext)
1153 {
1154  JsonPathItem larg;
1155  JsonPathItem rarg;
1156  JsonPathBool res;
1157  JsonPathBool res2;
1158 
1159  if (!canHaveNext && jspHasNext(jsp))
1160  elog(ERROR, "boolean jsonpath item cannot have next item");
1161 
1162  switch (jsp->type)
1163  {
1164  case jpiAnd:
1165  jspGetLeftArg(jsp, &larg);
1166  res = executeBoolItem(cxt, &larg, jb, false);
1167 
1168  if (res == jpbFalse)
1169  return jpbFalse;
1170 
1171  /*
1172  * SQL/JSON says that we should check second arg in case of
1173  * jperError
1174  */
1175 
1176  jspGetRightArg(jsp, &rarg);
1177  res2 = executeBoolItem(cxt, &rarg, jb, false);
1178 
1179  return res2 == jpbTrue ? res : res2;
1180 
1181  case jpiOr:
1182  jspGetLeftArg(jsp, &larg);
1183  res = executeBoolItem(cxt, &larg, jb, false);
1184 
1185  if (res == jpbTrue)
1186  return jpbTrue;
1187 
1188  jspGetRightArg(jsp, &rarg);
1189  res2 = executeBoolItem(cxt, &rarg, jb, false);
1190 
1191  return res2 == jpbFalse ? res : res2;
1192 
1193  case jpiNot:
1194  jspGetArg(jsp, &larg);
1195 
1196  res = executeBoolItem(cxt, &larg, jb, false);
1197 
1198  if (res == jpbUnknown)
1199  return jpbUnknown;
1200 
1201  return res == jpbTrue ? jpbFalse : jpbTrue;
1202 
1203  case jpiIsUnknown:
1204  jspGetArg(jsp, &larg);
1205  res = executeBoolItem(cxt, &larg, jb, false);
1206  return res == jpbUnknown ? jpbTrue : jpbFalse;
1207 
1208  case jpiEqual:
1209  case jpiNotEqual:
1210  case jpiLess:
1211  case jpiGreater:
1212  case jpiLessOrEqual:
1213  case jpiGreaterOrEqual:
1214  jspGetLeftArg(jsp, &larg);
1215  jspGetRightArg(jsp, &rarg);
1216  return executePredicate(cxt, jsp, &larg, &rarg, jb, true,
1217  executeComparison, NULL);
1218 
1219  case jpiStartsWith: /* 'whole STARTS WITH initial' */
1220  jspGetLeftArg(jsp, &larg); /* 'whole' */
1221  jspGetRightArg(jsp, &rarg); /* 'initial' */
1222  return executePredicate(cxt, jsp, &larg, &rarg, jb, false,
1223  executeStartsWith, NULL);
1224 
1225  case jpiLikeRegex: /* 'expr LIKE_REGEX pattern FLAGS flags' */
1226  {
1227  /*
1228  * 'expr' is a sequence-returning expression. 'pattern' is a
1229  * regex string literal. SQL/JSON standard requires XQuery
1230  * regexes, but we use Postgres regexes here. 'flags' is a
1231  * string literal converted to integer flags at compile-time.
1232  */
1233  JsonLikeRegexContext lrcxt = {0};
1234 
1235  jspInitByBuffer(&larg, jsp->base,
1236  jsp->content.like_regex.expr);
1237 
1238  return executePredicate(cxt, jsp, &larg, NULL, jb, false,
1239  executeLikeRegex, &lrcxt);
1240  }
1241 
1242  case jpiExists:
1243  jspGetArg(jsp, &larg);
1244 
1245  if (jspStrictAbsenseOfErrors(cxt))
1246  {
1247  /*
1248  * In strict mode we must get a complete list of values to
1249  * check that there are no errors at all.
1250  */
1251  JsonValueList vals = {0};
1252  JsonPathExecResult res =
1253  executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1254  false, &vals);
1255 
1256  if (jperIsError(res))
1257  return jpbUnknown;
1258 
1259  return JsonValueListIsEmpty(&vals) ? jpbFalse : jpbTrue;
1260  }
1261  else
1262  {
1263  JsonPathExecResult res =
1264  executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1265  false, NULL);
1266 
1267  if (jperIsError(res))
1268  return jpbUnknown;
1269 
1270  return res == jperOk ? jpbTrue : jpbFalse;
1271  }
1272 
1273  default:
1274  elog(ERROR, "invalid boolean jsonpath item type: %d", jsp->type);
1275  return jpbUnknown;
1276  }
1277 }
1278 
1279 /*
1280  * Execute nested (filters etc.) boolean expression pushing current SQL/JSON
1281  * item onto the stack.
1282  */
1283 static JsonPathBool
1285  JsonbValue *jb)
1286 {
1287  JsonbValue *prev;
1288  JsonPathBool res;
1289 
1290  prev = cxt->current;
1291  cxt->current = jb;
1292  res = executeBoolItem(cxt, jsp, jb, false);
1293  cxt->current = prev;
1294 
1295  return res;
1296 }
1297 
1298 /*
1299  * Implementation of several jsonpath nodes:
1300  * - jpiAny (.** accessor),
1301  * - jpiAnyKey (.* accessor),
1302  * - jpiAnyArray ([*] accessor)
1303  */
1304 static JsonPathExecResult
1306  JsonValueList *found, uint32 level, uint32 first, uint32 last,
1307  bool ignoreStructuralErrors, bool unwrapNext)
1308 {
1310  JsonbIterator *it;
1311  int32 r;
1312  JsonbValue v;
1313 
1315 
1316  if (level > last)
1317  return res;
1318 
1319  it = JsonbIteratorInit(jbc);
1320 
1321  /*
1322  * Recursively iterate over jsonb objects/arrays
1323  */
1324  while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
1325  {
1326  if (r == WJB_KEY)
1327  {
1328  r = JsonbIteratorNext(&it, &v, true);
1329  Assert(r == WJB_VALUE);
1330  }
1331 
1332  if (r == WJB_VALUE || r == WJB_ELEM)
1333  {
1334 
1335  if (level >= first ||
1336  (first == PG_UINT32_MAX && last == PG_UINT32_MAX &&
1337  v.type != jbvBinary)) /* leaves only requested */
1338  {
1339  /* check expression */
1340  if (jsp)
1341  {
1342  if (ignoreStructuralErrors)
1343  {
1344  bool savedIgnoreStructuralErrors;
1345 
1346  savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
1347  cxt->ignoreStructuralErrors = true;
1348  res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
1349  cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
1350  }
1351  else
1352  res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
1353 
1354  if (jperIsError(res))
1355  break;
1356 
1357  if (res == jperOk && !found)
1358  break;
1359  }
1360  else if (found)
1361  JsonValueListAppend(found, copyJsonbValue(&v));
1362  else
1363  return jperOk;
1364  }
1365 
1366  if (level < last && v.type == jbvBinary)
1367  {
1368  res = executeAnyItem
1369  (cxt, jsp, v.val.binary.data, found,
1370  level + 1, first, last,
1371  ignoreStructuralErrors, unwrapNext);
1372 
1373  if (jperIsError(res))
1374  break;
1375 
1376  if (res == jperOk && found == NULL)
1377  break;
1378  }
1379  }
1380  }
1381 
1382  return res;
1383 }
1384 
1385 /*
1386  * Execute unary or binary predicate.
1387  *
1388  * Predicates have existence semantics, because their operands are item
1389  * sequences. Pairs of items from the left and right operand's sequences are
1390  * checked. TRUE returned only if any pair satisfying the condition is found.
1391  * In strict mode, even if the desired pair has already been found, all pairs
1392  * still need to be examined to check the absence of errors. If any error
1393  * occurs, UNKNOWN (analogous to SQL NULL) is returned.
1394  */
1395 static JsonPathBool
1397  JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb,
1398  bool unwrapRightArg, JsonPathPredicateCallback exec,
1399  void *param)
1400 {
1401  JsonPathExecResult res;
1402  JsonValueListIterator lseqit;
1403  JsonValueList lseq = {0};
1404  JsonValueList rseq = {0};
1405  JsonbValue *lval;
1406  bool error = false;
1407  bool found = false;
1408 
1409  /* Left argument is always auto-unwrapped. */
1410  res = executeItemOptUnwrapResultNoThrow(cxt, larg, jb, true, &lseq);
1411  if (jperIsError(res))
1412  return jpbUnknown;
1413 
1414  if (rarg)
1415  {
1416  /* Right argument is conditionally auto-unwrapped. */
1417  res = executeItemOptUnwrapResultNoThrow(cxt, rarg, jb,
1418  unwrapRightArg, &rseq);
1419  if (jperIsError(res))
1420  return jpbUnknown;
1421  }
1422 
1423  JsonValueListInitIterator(&lseq, &lseqit);
1424  while ((lval = JsonValueListNext(&lseq, &lseqit)))
1425  {
1426  JsonValueListIterator rseqit;
1427  JsonbValue *rval;
1428  bool first = true;
1429 
1430  JsonValueListInitIterator(&rseq, &rseqit);
1431  if (rarg)
1432  rval = JsonValueListNext(&rseq, &rseqit);
1433  else
1434  rval = NULL;
1435 
1436  /* Loop over right arg sequence or do single pass otherwise */
1437  while (rarg ? (rval != NULL) : first)
1438  {
1439  JsonPathBool res = exec(pred, lval, rval, param);
1440 
1441  if (res == jpbUnknown)
1442  {
1443  if (jspStrictAbsenseOfErrors(cxt))
1444  return jpbUnknown;
1445 
1446  error = true;
1447  }
1448  else if (res == jpbTrue)
1449  {
1450  if (!jspStrictAbsenseOfErrors(cxt))
1451  return jpbTrue;
1452 
1453  found = true;
1454  }
1455 
1456  first = false;
1457  if (rarg)
1458  rval = JsonValueListNext(&rseq, &rseqit);
1459  }
1460  }
1461 
1462  if (found) /* possible only in strict mode */
1463  return jpbTrue;
1464 
1465  if (error) /* possible only in lax mode */
1466  return jpbUnknown;
1467 
1468  return jpbFalse;
1469 }
1470 
1471 /*
1472  * Execute binary arithmetic expression on singleton numeric operands.
1473  * Array operands are automatically unwrapped in lax mode.
1474  */
1475 static JsonPathExecResult
1477  JsonbValue *jb, BinaryArithmFunc func,
1478  JsonValueList *found)
1479 {
1480  JsonPathExecResult jper;
1481  JsonPathItem elem;
1482  JsonValueList lseq = {0};
1483  JsonValueList rseq = {0};
1484  JsonbValue *lval;
1485  JsonbValue *rval;
1486  Numeric res;
1487 
1488  jspGetLeftArg(jsp, &elem);
1489 
1490  /*
1491  * XXX: By standard only operands of multiplicative expressions are
1492  * unwrapped. We extend it to other binary arithmetic expressions too.
1493  */
1494  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &lseq);
1495  if (jperIsError(jper))
1496  return jper;
1497 
1498  jspGetRightArg(jsp, &elem);
1499 
1500  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &rseq);
1501  if (jperIsError(jper))
1502  return jper;
1503 
1504  if (JsonValueListLength(&lseq) != 1 ||
1505  !(lval = getScalar(JsonValueListHead(&lseq), jbvNumeric)))
1507  (errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
1508  errmsg("left operand of jsonpath operator %s is not a single numeric value",
1509  jspOperationName(jsp->type)))));
1510 
1511  if (JsonValueListLength(&rseq) != 1 ||
1512  !(rval = getScalar(JsonValueListHead(&rseq), jbvNumeric)))
1514  (errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
1515  errmsg("right operand of jsonpath operator %s is not a single numeric value",
1516  jspOperationName(jsp->type)))));
1517 
1518  if (jspThrowErrors(cxt))
1519  {
1520  res = func(lval->val.numeric, rval->val.numeric, NULL);
1521  }
1522  else
1523  {
1524  bool error = false;
1525 
1526  res = func(lval->val.numeric, rval->val.numeric, &error);
1527 
1528  if (error)
1529  return jperError;
1530  }
1531 
1532  if (!jspGetNext(jsp, &elem) && !found)
1533  return jperOk;
1534 
1535  lval = palloc(sizeof(*lval));
1536  lval->type = jbvNumeric;
1537  lval->val.numeric = res;
1538 
1539  return executeNextItem(cxt, jsp, &elem, lval, found, false);
1540 }
1541 
1542 /*
1543  * Execute unary arithmetic expression for each numeric item in its operand's
1544  * sequence. Array operand is automatically unwrapped in lax mode.
1545  */
1546 static JsonPathExecResult
1548  JsonbValue *jb, PGFunction func, JsonValueList *found)
1549 {
1550  JsonPathExecResult jper;
1551  JsonPathExecResult jper2;
1552  JsonPathItem elem;
1553  JsonValueList seq = {0};
1555  JsonbValue *val;
1556  bool hasNext;
1557 
1558  jspGetArg(jsp, &elem);
1559  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &seq);
1560 
1561  if (jperIsError(jper))
1562  return jper;
1563 
1564  jper = jperNotFound;
1565 
1566  hasNext = jspGetNext(jsp, &elem);
1567 
1568  JsonValueListInitIterator(&seq, &it);
1569  while ((val = JsonValueListNext(&seq, &it)))
1570  {
1571  if ((val = getScalar(val, jbvNumeric)))
1572  {
1573  if (!found && !hasNext)
1574  return jperOk;
1575  }
1576  else
1577  {
1578  if (!found && !hasNext)
1579  continue; /* skip non-numerics processing */
1580 
1582  (errcode(ERRCODE_JSON_NUMBER_NOT_FOUND),
1583  errmsg("operand of unary jsonpath operator %s is not a numeric value",
1584  jspOperationName(jsp->type)))));
1585  }
1586 
1587  if (func)
1588  val->val.numeric =
1590  NumericGetDatum(val->val.numeric)));
1591 
1592  jper2 = executeNextItem(cxt, jsp, &elem, val, found, false);
1593 
1594  if (jperIsError(jper2))
1595  return jper2;
1596 
1597  if (jper2 == jperOk)
1598  {
1599  if (!found)
1600  return jperOk;
1601  jper = jperOk;
1602  }
1603  }
1604 
1605  return jper;
1606 }
1607 
1608 /*
1609  * STARTS_WITH predicate callback.
1610  *
1611  * Check if the 'whole' string starts from 'initial' string.
1612  */
1613 static JsonPathBool
1615  void *param)
1616 {
1617  if (!(whole = getScalar(whole, jbvString)))
1618  return jpbUnknown; /* error */
1619 
1620  if (!(initial = getScalar(initial, jbvString)))
1621  return jpbUnknown; /* error */
1622 
1623  if (whole->val.string.len >= initial->val.string.len &&
1624  !memcmp(whole->val.string.val,
1625  initial->val.string.val,
1626  initial->val.string.len))
1627  return jpbTrue;
1628 
1629  return jpbFalse;
1630 }
1631 
1632 /*
1633  * LIKE_REGEX predicate callback.
1634  *
1635  * Check if the string matches regex pattern.
1636  */
1637 static JsonPathBool
1639  void *param)
1640 {
1641  JsonLikeRegexContext *cxt = param;
1642 
1643  if (!(str = getScalar(str, jbvString)))
1644  return jpbUnknown;
1645 
1646  /* Cache regex text and converted flags. */
1647  if (!cxt->regex)
1648  {
1649  uint32 flags = jsp->content.like_regex.flags;
1650 
1651  cxt->regex =
1653  jsp->content.like_regex.patternlen);
1654 
1655  /* Convert regex flags. */
1656  cxt->cflags = REG_ADVANCED;
1657 
1658  if (flags & JSP_REGEX_ICASE)
1659  cxt->cflags |= REG_ICASE;
1660  if (flags & JSP_REGEX_MLINE)
1661  cxt->cflags |= REG_NEWLINE;
1662  if (flags & JSP_REGEX_SLINE)
1663  cxt->cflags &= ~REG_NEWLINE;
1664  if (flags & JSP_REGEX_WSPACE)
1665  cxt->cflags |= REG_EXPANDED;
1666 
1667  /*
1668  * 'q' flag can work together only with 'i'. When other is specified,
1669  * then 'q' has no effect.
1670  */
1671  if ((flags & JSP_REGEX_QUOTE) &&
1672  !(flags & (JSP_REGEX_MLINE | JSP_REGEX_SLINE | JSP_REGEX_WSPACE)))
1673  {
1674  cxt->cflags &= ~REG_ADVANCED;
1675  cxt->cflags |= REG_QUOTE;
1676  }
1677  }
1678 
1679  if (RE_compile_and_execute(cxt->regex, str->val.string.val,
1680  str->val.string.len,
1681  cxt->cflags, DEFAULT_COLLATION_OID, 0, NULL))
1682  return jpbTrue;
1683 
1684  return jpbFalse;
1685 }
1686 
1687 /*
1688  * Execute numeric item methods (.abs(), .floor(), .ceil()) using the specified
1689  * user function 'func'.
1690  */
1691 static JsonPathExecResult
1693  JsonbValue *jb, bool unwrap, PGFunction func,
1694  JsonValueList *found)
1695 {
1697  Datum datum;
1698 
1699  if (unwrap && JsonbType(jb) == jbvArray)
1700  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1701 
1702  if (!(jb = getScalar(jb, jbvNumeric)))
1704  (errcode(ERRCODE_NON_NUMERIC_JSON_ITEM),
1705  errmsg("jsonpath item method .%s() can only be applied to a numeric value",
1706  jspOperationName(jsp->type)))));
1707 
1708  datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
1709 
1710  if (!jspGetNext(jsp, &next) && !found)
1711  return jperOk;
1712 
1713  jb = palloc(sizeof(*jb));
1714  jb->type = jbvNumeric;
1715  jb->val.numeric = DatumGetNumeric(datum);
1716 
1717  return executeNextItem(cxt, jsp, &next, jb, found, false);
1718 }
1719 
1720 /*
1721  * Implementation of .keyvalue() method.
1722  *
1723  * .keyvalue() method returns a sequence of object's key-value pairs in the
1724  * following format: '{ "key": key, "value": value, "id": id }'.
1725  *
1726  * "id" field is an object identifier which is constructed from the two parts:
1727  * base object id and its binary offset in base object's jsonb:
1728  * id = 10000000000 * base_object_id + obj_offset_in_base_object
1729  *
1730  * 10000000000 (10^10) -- is a first round decimal number greater than 2^32
1731  * (maximal offset in jsonb). Decimal multiplier is used here to improve the
1732  * readability of identifiers.
1733  *
1734  * Base object is usually a root object of the path: context item '$' or path
1735  * variable '$var', literals can't produce objects for now. But if the path
1736  * contains generated objects (.keyvalue() itself, for example), then they
1737  * become base object for the subsequent .keyvalue().
1738  *
1739  * Id of '$' is 0. Id of '$var' is its ordinal (positive) number in the list
1740  * of variables (see getJsonPathVariable()). Ids for generated objects
1741  * are assigned using global counter JsonPathExecContext.lastGeneratedObjectId.
1742  */
1743 static JsonPathExecResult
1745  JsonbValue *jb, JsonValueList *found)
1746 {
1750  JsonbValue key;
1751  JsonbValue val;
1752  JsonbValue idval;
1753  JsonbValue keystr;
1754  JsonbValue valstr;
1755  JsonbValue idstr;
1756  JsonbIterator *it;
1757  JsonbIteratorToken tok;
1758  int64 id;
1759  bool hasNext;
1760 
1761  if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
1763  (errcode(ERRCODE_JSON_OBJECT_NOT_FOUND),
1764  errmsg("jsonpath item method .%s() can only be applied to an object",
1765  jspOperationName(jsp->type)))));
1766 
1767  jbc = jb->val.binary.data;
1768 
1769  if (!JsonContainerSize(jbc))
1770  return jperNotFound; /* no key-value pairs */
1771 
1772  hasNext = jspGetNext(jsp, &next);
1773 
1774  keystr.type = jbvString;
1775  keystr.val.string.val = "key";
1776  keystr.val.string.len = 3;
1777 
1778  valstr.type = jbvString;
1779  valstr.val.string.val = "value";
1780  valstr.val.string.len = 5;
1781 
1782  idstr.type = jbvString;
1783  idstr.val.string.val = "id";
1784  idstr.val.string.len = 2;
1785 
1786  /* construct object id from its base object and offset inside that */
1787  id = jb->type != jbvBinary ? 0 :
1788  (int64) ((char *) jbc - (char *) cxt->baseObject.jbc);
1789  id += (int64) cxt->baseObject.id * INT64CONST(10000000000);
1790 
1791  idval.type = jbvNumeric;
1793  Int64GetDatum(id)));
1794 
1795  it = JsonbIteratorInit(jbc);
1796 
1797  while ((tok = JsonbIteratorNext(&it, &key, true)) != WJB_DONE)
1798  {
1799  JsonBaseObjectInfo baseObject;
1800  JsonbValue obj;
1801  JsonbParseState *ps;
1802  JsonbValue *keyval;
1803  Jsonb *jsonb;
1804 
1805  if (tok != WJB_KEY)
1806  continue;
1807 
1808  res = jperOk;
1809 
1810  if (!hasNext && !found)
1811  break;
1812 
1813  tok = JsonbIteratorNext(&it, &val, true);
1814  Assert(tok == WJB_VALUE);
1815 
1816  ps = NULL;
1817  pushJsonbValue(&ps, WJB_BEGIN_OBJECT, NULL);
1818 
1819  pushJsonbValue(&ps, WJB_KEY, &keystr);
1820  pushJsonbValue(&ps, WJB_VALUE, &key);
1821 
1822  pushJsonbValue(&ps, WJB_KEY, &valstr);
1823  pushJsonbValue(&ps, WJB_VALUE, &val);
1824 
1825  pushJsonbValue(&ps, WJB_KEY, &idstr);
1826  pushJsonbValue(&ps, WJB_VALUE, &idval);
1827 
1828  keyval = pushJsonbValue(&ps, WJB_END_OBJECT, NULL);
1829 
1830  jsonb = JsonbValueToJsonb(keyval);
1831 
1832  JsonbInitBinary(&obj, jsonb);
1833 
1834  baseObject = setBaseObject(cxt, &obj, cxt->lastGeneratedObjectId++);
1835 
1836  res = executeNextItem(cxt, jsp, &next, &obj, found, true);
1837 
1838  cxt->baseObject = baseObject;
1839 
1840  if (jperIsError(res))
1841  return res;
1842 
1843  if (res == jperOk && !found)
1844  break;
1845  }
1846 
1847  return res;
1848 }
1849 
1850 /*
1851  * Convert boolean execution status 'res' to a boolean JSON item and execute
1852  * next jsonpath.
1853  */
1854 static JsonPathExecResult
1856  JsonValueList *found, JsonPathBool res)
1857 {
1859  JsonbValue jbv;
1860 
1861  if (!jspGetNext(jsp, &next) && !found)
1862  return jperOk; /* found singleton boolean value */
1863 
1864  if (res == jpbUnknown)
1865  {
1866  jbv.type = jbvNull;
1867  }
1868  else
1869  {
1870  jbv.type = jbvBool;
1871  jbv.val.boolean = res == jpbTrue;
1872  }
1873 
1874  return executeNextItem(cxt, jsp, &next, &jbv, found, true);
1875 }
1876 
1877 /*
1878  * Convert jsonpath's scalar or variable node to actual jsonb value.
1879  *
1880  * If node is a variable then its id returned, otherwise 0 returned.
1881  */
1882 static void
1884  JsonbValue *value)
1885 {
1886  switch (item->type)
1887  {
1888  case jpiNull:
1889  value->type = jbvNull;
1890  break;
1891  case jpiBool:
1892  value->type = jbvBool;
1893  value->val.boolean = jspGetBool(item);
1894  break;
1895  case jpiNumeric:
1896  value->type = jbvNumeric;
1897  value->val.numeric = jspGetNumeric(item);
1898  break;
1899  case jpiString:
1900  value->type = jbvString;
1901  value->val.string.val = jspGetString(item,
1902  &value->val.string.len);
1903  break;
1904  case jpiVariable:
1905  getJsonPathVariable(cxt, item, cxt->vars, value);
1906  return;
1907  default:
1908  elog(ERROR, "unexpected jsonpath item type");
1909  }
1910 }
1911 
1912 /*
1913  * Get the value of variable passed to jsonpath executor
1914  */
1915 static void
1918 {
1919  char *varName;
1920  int varNameLength;
1921  JsonbValue tmp;
1922  JsonbValue *v;
1923 
1924  if (!vars)
1925  {
1926  value->type = jbvNull;
1927  return;
1928  }
1929 
1930  Assert(variable->type == jpiVariable);
1931  varName = jspGetString(variable, &varNameLength);
1932  tmp.type = jbvString;
1933  tmp.val.string.val = varName;
1934  tmp.val.string.len = varNameLength;
1935 
1936  v = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
1937 
1938  if (v)
1939  {
1940  *value = *v;
1941  pfree(v);
1942  }
1943  else
1944  {
1945  ereport(ERROR,
1946  (errcode(ERRCODE_UNDEFINED_OBJECT),
1947  errmsg("could not find jsonpath variable \"%s\"",
1948  pnstrdup(varName, varNameLength))));
1949  }
1950 
1951  JsonbInitBinary(&tmp, vars);
1952  setBaseObject(cxt, &tmp, 1);
1953 }
1954 
1955 /**************** Support functions for JsonPath execution *****************/
1956 
1957 /*
1958  * Returns the size of an array item, or -1 if item is not an array.
1959  */
1960 static int
1962 {
1963  Assert(jb->type != jbvArray);
1964 
1965  if (jb->type == jbvBinary)
1966  {
1967  JsonbContainer *jbc = jb->val.binary.data;
1968 
1969  if (JsonContainerIsArray(jbc) && !JsonContainerIsScalar(jbc))
1970  return JsonContainerSize(jbc);
1971  }
1972 
1973  return -1;
1974 }
1975 
1976 /* Comparison predicate callback. */
1977 static JsonPathBool
1979 {
1980  return compareItems(cmp->type, lv, rv);
1981 }
1982 
1983 /*
1984  * Perform per-byte comparison of two strings.
1985  */
1986 static int
1987 binaryCompareStrings(const char *s1, int len1,
1988  const char *s2, int len2)
1989 {
1990  int cmp;
1991 
1992  cmp = memcmp(s1, s2, Min(len1, len2));
1993 
1994  if (cmp != 0)
1995  return cmp;
1996 
1997  if (len1 == len2)
1998  return 0;
1999 
2000  return len1 < len2 ? -1 : 1;
2001 }
2002 
2003 /*
2004  * Compare two strings in the current server encoding using Unicode codepoint
2005  * collation.
2006  */
2007 static int
2008 compareStrings(const char *mbstr1, int mblen1,
2009  const char *mbstr2, int mblen2)
2010 {
2011  if (GetDatabaseEncoding() == PG_SQL_ASCII ||
2013  {
2014  /*
2015  * It's known property of UTF-8 strings that their per-byte comparison
2016  * result matches codepoints comparison result. ASCII can be
2017  * considered as special case of UTF-8.
2018  */
2019  return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
2020  }
2021  else
2022  {
2023  char *utf8str1,
2024  *utf8str2;
2025  int cmp,
2026  utf8len1,
2027  utf8len2;
2028 
2029  /*
2030  * We have to convert other encodings to UTF-8 first, then compare.
2031  * Input strings may be not null-terminated and pg_server_to_any() may
2032  * return them "as is". So, use strlen() only if there is real
2033  * conversion.
2034  */
2035  utf8str1 = pg_server_to_any(mbstr1, mblen1, PG_UTF8);
2036  utf8str2 = pg_server_to_any(mbstr2, mblen2, PG_UTF8);
2037  utf8len1 = (mbstr1 == utf8str1) ? mblen1 : strlen(utf8str1);
2038  utf8len2 = (mbstr2 == utf8str2) ? mblen2 : strlen(utf8str2);
2039 
2040  cmp = binaryCompareStrings(utf8str1, utf8len1, utf8str2, utf8len2);
2041 
2042  /*
2043  * If pg_server_to_any() did no real conversion, then we actually
2044  * compared original strings. So, we already done.
2045  */
2046  if (mbstr1 == utf8str1 && mbstr2 == utf8str2)
2047  return cmp;
2048 
2049  /* Free memory if needed */
2050  if (mbstr1 != utf8str1)
2051  pfree(utf8str1);
2052  if (mbstr2 != utf8str2)
2053  pfree(utf8str2);
2054 
2055  /*
2056  * When all Unicode codepoints are equal, return result of binary
2057  * comparison. In some edge cases, same characters may have different
2058  * representations in encoding. Then our behavior could diverge from
2059  * standard. However, that allow us to do simple binary comparison
2060  * for "==" operator, which is performance critical in typical cases.
2061  * In future to implement strict standard conformance, we can do
2062  * normalization of input JSON strings.
2063  */
2064  if (cmp == 0)
2065  return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
2066  else
2067  return cmp;
2068  }
2069 }
2070 
2071 /*
2072  * Compare two SQL/JSON items using comparison operation 'op'.
2073  */
2074 static JsonPathBool
2076 {
2077  int cmp;
2078  bool res;
2079 
2080  if (jb1->type != jb2->type)
2081  {
2082  if (jb1->type == jbvNull || jb2->type == jbvNull)
2083 
2084  /*
2085  * Equality and order comparison of nulls to non-nulls returns
2086  * always false, but inequality comparison returns true.
2087  */
2088  return op == jpiNotEqual ? jpbTrue : jpbFalse;
2089 
2090  /* Non-null items of different types are not comparable. */
2091  return jpbUnknown;
2092  }
2093 
2094  switch (jb1->type)
2095  {
2096  case jbvNull:
2097  cmp = 0;
2098  break;
2099  case jbvBool:
2100  cmp = jb1->val.boolean == jb2->val.boolean ? 0 :
2101  jb1->val.boolean ? 1 : -1;
2102  break;
2103  case jbvNumeric:
2104  cmp = compareNumeric(jb1->val.numeric, jb2->val.numeric);
2105  break;
2106  case jbvString:
2107  if (op == jpiEqual)
2108  return jb1->val.string.len != jb2->val.string.len ||
2109  memcmp(jb1->val.string.val,
2110  jb2->val.string.val,
2111  jb1->val.string.len) ? jpbFalse : jpbTrue;
2112 
2113  cmp = compareStrings(jb1->val.string.val, jb1->val.string.len,
2114  jb2->val.string.val, jb2->val.string.len);
2115  break;
2116 
2117  case jbvBinary:
2118  case jbvArray:
2119  case jbvObject:
2120  return jpbUnknown; /* non-scalars are not comparable */
2121 
2122  default:
2123  elog(ERROR, "invalid jsonb value type %d", jb1->type);
2124  }
2125 
2126  switch (op)
2127  {
2128  case jpiEqual:
2129  res = (cmp == 0);
2130  break;
2131  case jpiNotEqual:
2132  res = (cmp != 0);
2133  break;
2134  case jpiLess:
2135  res = (cmp < 0);
2136  break;
2137  case jpiGreater:
2138  res = (cmp > 0);
2139  break;
2140  case jpiLessOrEqual:
2141  res = (cmp <= 0);
2142  break;
2143  case jpiGreaterOrEqual:
2144  res = (cmp >= 0);
2145  break;
2146  default:
2147  elog(ERROR, "unrecognized jsonpath operation: %d", op);
2148  return jpbUnknown;
2149  }
2150 
2151  return res ? jpbTrue : jpbFalse;
2152 }
2153 
2154 /* Compare two numerics */
2155 static int
2157 {
2159  NumericGetDatum(a),
2160  NumericGetDatum(b)));
2161 }
2162 
2163 static JsonbValue *
2165 {
2166  JsonbValue *dst = palloc(sizeof(*dst));
2167 
2168  *dst = *src;
2169 
2170  return dst;
2171 }
2172 
2173 /*
2174  * Execute array subscript expression and convert resulting numeric item to
2175  * the integer type with truncation.
2176  */
2177 static JsonPathExecResult
2179  int32 *index)
2180 {
2181  JsonbValue *jbv;
2182  JsonValueList found = {0};
2183  JsonPathExecResult res = executeItem(cxt, jsp, jb, &found);
2184  Datum numeric_index;
2185  bool have_error = false;
2186 
2187  if (jperIsError(res))
2188  return res;
2189 
2190  if (JsonValueListLength(&found) != 1 ||
2191  !(jbv = getScalar(JsonValueListHead(&found), jbvNumeric)))
2193  (errcode(ERRCODE_INVALID_JSON_SUBSCRIPT),
2194  errmsg("jsonpath array subscript is not a single numeric value"))));
2195 
2196  numeric_index = DirectFunctionCall2(numeric_trunc,
2197  NumericGetDatum(jbv->val.numeric),
2198  Int32GetDatum(0));
2199 
2200  *index = numeric_int4_opt_error(DatumGetNumeric(numeric_index),
2201  &have_error);
2202 
2203  if (have_error)
2205  (errcode(ERRCODE_INVALID_JSON_SUBSCRIPT),
2206  errmsg("jsonpath array subscript is out of integer range"))));
2207 
2208  return jperOk;
2209 }
2210 
2211 /* Save base object and its id needed for the execution of .keyvalue(). */
2212 static JsonBaseObjectInfo
2214 {
2215  JsonBaseObjectInfo baseObject = cxt->baseObject;
2216 
2217  cxt->baseObject.jbc = jbv->type != jbvBinary ? NULL :
2218  (JsonbContainer *) jbv->val.binary.data;
2219  cxt->baseObject.id = id;
2220 
2221  return baseObject;
2222 }
2223 
2224 static void
2226 {
2227  if (jvl->singleton)
2228  {
2229  jvl->list = list_make2(jvl->singleton, jbv);
2230  jvl->singleton = NULL;
2231  }
2232  else if (!jvl->list)
2233  jvl->singleton = jbv;
2234  else
2235  jvl->list = lappend(jvl->list, jbv);
2236 }
2237 
2238 static int
2240 {
2241  return jvl->singleton ? 1 : list_length(jvl->list);
2242 }
2243 
2244 static bool
2246 {
2247  return !jvl->singleton && list_length(jvl->list) <= 0;
2248 }
2249 
2250 static JsonbValue *
2252 {
2253  return jvl->singleton ? jvl->singleton : linitial(jvl->list);
2254 }
2255 
2256 static List *
2258 {
2259  if (jvl->singleton)
2260  return list_make1(jvl->singleton);
2261 
2262  return jvl->list;
2263 }
2264 
2265 static void
2267 {
2268  if (jvl->singleton)
2269  {
2270  it->value = jvl->singleton;
2271  it->list = NIL;
2272  it->next = NULL;
2273  }
2274  else if (jvl->list != NIL)
2275  {
2276  it->value = (JsonbValue *) linitial(jvl->list);
2277  it->list = jvl->list;
2278  it->next = list_second_cell(jvl->list);
2279  }
2280  else
2281  {
2282  it->value = NULL;
2283  it->list = NIL;
2284  it->next = NULL;
2285  }
2286 }
2287 
2288 /*
2289  * Get the next item from the sequence advancing iterator.
2290  */
2291 static JsonbValue *
2293 {
2294  JsonbValue *result = it->value;
2295 
2296  if (it->next)
2297  {
2298  it->value = lfirst(it->next);
2299  it->next = lnext(it->list, it->next);
2300  }
2301  else
2302  {
2303  it->value = NULL;
2304  }
2305 
2306  return result;
2307 }
2308 
2309 /*
2310  * Initialize a binary JsonbValue with the given jsonb container.
2311  */
2312 static JsonbValue *
2314 {
2315  jbv->type = jbvBinary;
2316  jbv->val.binary.data = &jb->root;
2317  jbv->val.binary.len = VARSIZE_ANY_EXHDR(jb);
2318 
2319  return jbv;
2320 }
2321 
2322 /*
2323  * Returns jbv* type of of JsonbValue. Note, it never returns jbvBinary as is.
2324  */
2325 static int
2327 {
2328  int type = jb->type;
2329 
2330  if (jb->type == jbvBinary)
2331  {
2332  JsonbContainer *jbc = (void *) jb->val.binary.data;
2333 
2334  /* Scalars should be always extracted during jsonpath execution. */
2336 
2337  if (JsonContainerIsObject(jbc))
2338  type = jbvObject;
2339  else if (JsonContainerIsArray(jbc))
2340  type = jbvArray;
2341  else
2342  elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
2343  }
2344 
2345  return type;
2346 }
2347 
2348 /* Get scalar of given type or NULL on type mismatch */
2349 static JsonbValue *
2351 {
2352  /* Scalars should be always extracted during jsonpath execution. */
2353  Assert(scalar->type != jbvBinary ||
2354  !JsonContainerIsScalar(scalar->val.binary.data));
2355 
2356  return scalar->type == type ? scalar : NULL;
2357 }
2358 
2359 /* Construct a JSON array from the item list */
2360 static JsonbValue *
2362 {
2363  JsonbParseState *ps = NULL;
2365  JsonbValue *jbv;
2366 
2367  pushJsonbValue(&ps, WJB_BEGIN_ARRAY, NULL);
2368 
2369  JsonValueListInitIterator(items, &it);
2370  while ((jbv = JsonValueListNext(items, &it)))
2371  pushJsonbValue(&ps, WJB_ELEM, jbv);
2372 
2373  return pushJsonbValue(&ps, WJB_END_ARRAY, NULL);
2374 }
#define list_make2(x1, x2)
Definition: pg_list.h:229
static void JsonValueListInitIterator(const JsonValueList *jvl, JsonValueListIterator *it)
#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)
Datum numeric_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:1282
bool JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
Definition: jsonb.c:1874
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1172
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition: jsonb_util.c:79
Definition: jsonb.h:220
static int32 next
Definition: blutils.c:213
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:922
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)
Definition: jsonpath.h:50
static JsonPathBool executeNestedBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb)
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
#define REG_QUOTE
Definition: regex.h:104
char * pstrdup(const char *in)
Definition: mcxt.c:1161
char * val
Definition: jsonb.h:264
char * base
Definition: jsonpath.h:115
#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
static struct @144 value
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:163
Definition: jsonb.h:22
struct cursor * cur
Definition: ecpg.c:28
void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
Definition: jsonpath.c:830
int errcode(int sqlerrcode)
Definition: elog.c:570
static JsonbValue * getScalar(JsonbValue *scalar, enum jbvType type)
#define JSP_REGEX_ICASE
Definition: jsonpath.h:90
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:616
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:269
#define PG_UINT32_MAX
Definition: c.h:442
struct NumericData * Numeric
Definition: numeric.h:43
#define REG_ICASE
Definition: regex.h:106
Datum int8_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:3285
JsonBaseObjectInfo baseObject
Definition: jsonpath_exec.c:97
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:287
Datum jsonb_path_match(PG_FUNCTION_ARGS)
#define JSONPATH_LAX
Definition: jsonpath.h:29
Datum jsonb_path_exists_opr(PG_FUNCTION_ARGS)
Numeric numeric_mul_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:2540
static int compareNumeric(Numeric a, Numeric b)
static JsonPathExecResult executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors, JsonValueList *result)
JsonPathBool
char * pg_server_to_any(const char *s, int len, int encoding)
Definition: mbutils.c:626
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
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
JsonbValue * pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition: jsonb_util.c:517
static JsonPathExecResult executeNumericItemMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, bool unwrap, PGFunction func, JsonValueList *found)
void pfree(void *pointer)
Definition: mcxt.c:1031
#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)
#define JSP_REGEX_MLINE
Definition: jsonpath.h:92
char * s1
static JsonPathBool compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2)
#define DatumGetCString(X)
Definition: postgres.h:566
JsonPathExecResult
static List * JsonValueListGetList(JsonValueList *jvl)
#define JSP_REGEX_WSPACE
Definition: jsonpath.h:93
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
struct JsonValueListIterator JsonValueListIterator
const char * JsonbTypeName(JsonbValue *jbv)
Definition: jsonb.c:191
char * c
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
struct JsonPathItem::@129::@131 array
static JsonPathExecResult executeItemUnwrapTargetArray(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found, bool unwrapElements)
#define JSP_REGEX_QUOTE
Definition: jsonpath.h:94
#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
#define REG_NEWLINE
Definition: regex.h:111
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)
struct JsonPathItem::@129::@132 anybounds
#define REG_ADVANCED
Definition: regex.h:103
#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:95
JsonbIteratorToken
Definition: jsonb.h:20
List * lappend(List *list, void *datum)
Definition: list.c:321
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
struct JsonPathItem::@129::@134 like_regex
static JsonPathBool executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb, bool unwrapRightArg, JsonPathPredicateCallback exec, void *param)
union JsonPathItem::@129 content
static JsonPathBool executeLikeRegex(JsonPathItem *jsp, JsonbValue *str, JsonbValue *rarg, void *param)
const char * jspOperationName(JsonPathItemType type)
Definition: jsonpath.c:707
Datum jsonb_path_query(PG_FUNCTION_ARGS)
uint32 header
Definition: jsonb.h:200
void jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:997
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:996
JsonbContainer * jbc
Definition: jsonpath_exec.c:85
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:1018
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
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition: jsonb_util.c:419
static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv)
#define DatumGetNumeric(X)
Definition: numeric.h:49
bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to, int i)
Definition: jsonpath.c:1046
void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:976
#define Assert(condition)
Definition: c.h:732
#define lfirst(lc)
Definition: pg_list.h:190
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition: jsonb_util.c:718
#define JB_FOBJECT
Definition: jsonb.h:210
static int binaryCompareStrings(const char *s1, int len1, const char *s2, int len2)
JsonPathItemType type
Definition: jsonpath.h:106
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:96
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
struct JsonPathExecContext JsonPathExecContext
#define jspAutoWrap(cxt)
#define PG_NARGS()
Definition: fmgr.h:198
static JsonPathExecResult executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found)
enum jbvType type
Definition: jsonb.h:255
static void getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable, Jsonb *vars, JsonbValue *value)
static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonValueList *found, JsonPathBool res)
#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:924
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:820
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 REG_EXPANDED
Definition: regex.h:108
#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
JsonbValue * findJsonbValueFromContainer(JsonbContainer *container, uint32 flags, JsonbValue *key)
Definition: jsonb_util.c:327
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:909
Definition: regcomp.c:224
Definition: pg_list.h:50
char * jspGetString(JsonPathItem *v, int32 *len)
Definition: jsonpath.c:1034
static JsonbValue * JsonValueListHead(JsonValueList *jvl)
long val
Definition: informix.c:684
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:618
#define PG_RETURN_NULL()
Definition: fmgr.h:335
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:754
Definition: jsonb.h:25
#define JSP_REGEX_SLINE
Definition: jsonpath.h:91
static int JsonbArraySize(JsonbValue *jb)
List * list_delete_first(List *list)
Definition: list.c:857
#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
Numeric jspGetNumeric(JsonPathItem *v)
Definition: jsonpath.c:1026
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:285