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