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-2022, 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 "executor/execExpr.h"
65 #include "funcapi.h"
66 #include "lib/stringinfo.h"
67 #include "miscadmin.h"
68 #include "nodes/nodeFuncs.h"
69 #include "regex/regex.h"
70 #include "utils/builtins.h"
71 #include "utils/date.h"
72 #include "utils/datetime.h"
73 #include "utils/datum.h"
74 #include "utils/float.h"
75 #include "utils/formatting.h"
76 #include "utils/guc.h"
77 #include "utils/json.h"
78 #include "utils/jsonpath.h"
79 #include "utils/lsyscache.h"
80 #include "utils/memutils.h"
81 #include "utils/timestamp.h"
82 #include "utils/varlena.h"
83 
84 /*
85  * Represents "base object" and it's "id" for .keyvalue() evaluation.
86  */
87 typedef struct JsonBaseObjectInfo
88 {
90  int id;
92 
93 typedef int (*JsonPathVarCallback) (void *vars, char *varName, int varNameLen,
94  JsonbValue *val, JsonbValue *baseObject);
95 
96 /*
97  * Context of jsonpath execution.
98  */
99 typedef struct JsonPathExecContext
100 {
101  void *vars; /* variables to substitute into jsonpath */
103  JsonbValue *root; /* for $ evaluation */
104  JsonbValue *current; /* for @ evaluation */
105  JsonBaseObjectInfo baseObject; /* "base object" for .keyvalue()
106  * evaluation */
107  int lastGeneratedObjectId; /* "id" counter for .keyvalue()
108  * evaluation */
109  int innermostArraySize; /* for LAST array index evaluation */
110  bool laxMode; /* true for "lax" mode, false for "strict"
111  * mode */
112  bool ignoreStructuralErrors; /* with "true" structural errors such
113  * as absence of required json item or
114  * unexpected json item type are
115  * ignored */
116  bool throwErrors; /* with "false" all suppressible errors are
117  * suppressed */
118  bool useTz;
120 
121 /* Context for LIKE_REGEX execution. */
122 typedef struct JsonLikeRegexContext
123 {
125  int cflags;
127 
128 /* Result of jsonpath predicate evaluation */
129 typedef enum JsonPathBool
130 {
131  jpbFalse = 0,
132  jpbTrue = 1,
133  jpbUnknown = 2
135 
136 /* Result of jsonpath expression evaluation */
137 typedef enum JsonPathExecResult
138 {
139  jperOk = 0,
141  jperError = 2
143 
144 #define jperIsError(jper) ((jper) == jperError)
145 
146 /*
147  * List of jsonb values with shortcut for single-value list.
148  */
149 typedef struct JsonValueList
150 {
154 
155 typedef struct JsonValueListIterator
156 {
161 
162 /* Structures for JSON_TABLE execution */
165 
167 {
176  int ordinal;
178  bool outerJoin;
181  bool reset;
182 };
183 
185 {
186  union
187  {
188  struct
189  {
192  bool cross;
194  } join;
196  } u;
197  bool is_join;
198 };
199 
200 /* random number to identify JsonTableContext */
201 #define JSON_TABLE_CONTEXT_MAGIC 418352867
202 
203 typedef struct JsonTableContext
204 {
205  int magic;
206  struct
207  {
212  bool empty;
214 
215 /* strict/lax flags is decomposed into four [un]wrap/error flags */
216 #define jspStrictAbsenseOfErrors(cxt) (!(cxt)->laxMode)
217 #define jspAutoUnwrap(cxt) ((cxt)->laxMode)
218 #define jspAutoWrap(cxt) ((cxt)->laxMode)
219 #define jspIgnoreStructuralErrors(cxt) ((cxt)->ignoreStructuralErrors)
220 #define jspThrowErrors(cxt) ((cxt)->throwErrors)
221 
222 /* Convenience macro: return or throw error depending on context */
223 #define RETURN_ERROR(throw_error) \
224 do { \
225  if (jspThrowErrors(cxt)) \
226  throw_error; \
227  else \
228  return jperError; \
229 } while (0)
230 
232  JsonbValue *larg,
233  JsonbValue *rarg,
234  void *param);
235 typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
236 
237 static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars,
238  JsonPathVarCallback getVar,
239  Jsonb *json, bool throwErrors,
240  JsonValueList *result, bool useTz);
242  JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found);
244  JsonPathItem *jsp, JsonbValue *jb,
245  JsonValueList *found, bool unwrap);
247  JsonPathItem *jsp, JsonbValue *jb,
248  JsonValueList *found, bool unwrapElements);
251  JsonbValue *v, JsonValueList *found, bool copy);
253  bool unwrap, JsonValueList *found);
255  JsonbValue *jb, bool unwrap, JsonValueList *found);
257  JsonPathItem *jsp, JsonbValue *jb, bool canHaveNext);
259  JsonPathItem *jsp, JsonbValue *jb);
261  JsonPathItem *jsp, JsonbContainer *jbc, JsonValueList *found,
262  uint32 level, uint32 first, uint32 last,
263  bool ignoreStructuralErrors, bool unwrapNext);
265  JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg,
266  JsonbValue *jb, bool unwrapRightArg,
267  JsonPathPredicateCallback exec, void *param);
269  JsonPathItem *jsp, JsonbValue *jb,
270  BinaryArithmFunc func, JsonValueList *found);
272  JsonPathItem *jsp, JsonbValue *jb, PGFunction func,
273  JsonValueList *found);
275  JsonbValue *whole, JsonbValue *initial, void *param);
277  JsonbValue *rarg, void *param);
279  JsonPathItem *jsp, JsonbValue *jb, bool unwrap, PGFunction func,
280  JsonValueList *found);
282  JsonbValue *jb, JsonValueList *found);
284  JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found);
287 static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
288  JsonbValue *value);
291 static int getJsonPathVariableFromJsonb(void *varsJsonb, char *varName,
292  int varNameLen, JsonbValue *val,
293  JsonbValue *baseObject);
294 static int JsonbArraySize(JsonbValue *jb);
296  JsonbValue *rv, void *p);
297 static JsonPathBool compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2,
298  bool useTz);
299 static int compareNumeric(Numeric a, Numeric b);
300 static JsonbValue *copyJsonbValue(JsonbValue *src);
302  JsonPathItem *jsp, JsonbValue *jb, int32 *index);
304  JsonbValue *jbv, int32 id);
305 static void JsonValueListClear(JsonValueList *jvl);
306 static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv);
307 static int JsonValueListLength(const JsonValueList *jvl);
308 static bool JsonValueListIsEmpty(JsonValueList *jvl);
311 static void JsonValueListInitIterator(const JsonValueList *jvl,
313 static JsonbValue *JsonValueListNext(const JsonValueList *jvl,
315 static int JsonbType(JsonbValue *jb);
316 static JsonbValue *JsonbInitBinary(JsonbValue *jbv, Jsonb *jb);
317 static int JsonbType(JsonbValue *jb);
318 static JsonbValue *getScalar(JsonbValue *scalar, enum jbvType type);
319 static JsonbValue *wrapItemsInArray(const JsonValueList *items);
320 static int compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
321  bool useTz, bool *have_error);
322 
323 
325  Node *plan, JsonTableScanState *parent);
326 static bool JsonTableNextRow(JsonTableScanState *scan);
327 
328 
329 /****************** User interface to JsonPath executor ********************/
330 
331 /*
332  * jsonb_path_exists
333  * Returns true if jsonpath returns at least one item for the specified
334  * jsonb value. This function and jsonb_path_match() are used to
335  * implement @? and @@ operators, which in turn are intended to have an
336  * index support. Thus, it's desirable to make it easier to achieve
337  * consistency between index scan results and sequential scan results.
338  * So, we throw as few errors as possible. Regarding this function,
339  * such behavior also matches behavior of JSON_EXISTS() clause of
340  * SQL/JSON. Regarding jsonb_path_match(), this function doesn't have
341  * an analogy in SQL/JSON, so we define its behavior on our own.
342  */
343 static Datum
345 {
346  Jsonb *jb = PG_GETARG_JSONB_P(0);
349  Jsonb *vars = NULL;
350  bool silent = true;
351 
352  if (PG_NARGS() == 4)
353  {
354  vars = PG_GETARG_JSONB_P(2);
355  silent = PG_GETARG_BOOL(3);
356  }
357 
359  jb, !silent, NULL, tz);
360 
361  PG_FREE_IF_COPY(jb, 0);
362  PG_FREE_IF_COPY(jp, 1);
363 
364  if (jperIsError(res))
365  PG_RETURN_NULL();
366 
368 }
369 
370 Datum
372 {
373  return jsonb_path_exists_internal(fcinfo, false);
374 }
375 
376 Datum
378 {
379  return jsonb_path_exists_internal(fcinfo, true);
380 }
381 
382 /*
383  * jsonb_path_exists_opr
384  * Implementation of operator "jsonb @? jsonpath" (2-argument version of
385  * jsonb_path_exists()).
386  */
387 Datum
389 {
390  /* just call the other one -- it can handle both cases */
391  return jsonb_path_exists_internal(fcinfo, false);
392 }
393 
394 /*
395  * jsonb_path_match
396  * Returns jsonpath predicate result item for the specified jsonb value.
397  * See jsonb_path_exists() comment for details regarding error handling.
398  */
399 static Datum
401 {
402  Jsonb *jb = PG_GETARG_JSONB_P(0);
404  JsonValueList found = {0};
405  Jsonb *vars = NULL;
406  bool silent = true;
407 
408  if (PG_NARGS() == 4)
409  {
410  vars = PG_GETARG_JSONB_P(2);
411  silent = PG_GETARG_BOOL(3);
412  }
413 
415  jb, !silent, &found, tz);
416 
417  PG_FREE_IF_COPY(jb, 0);
418  PG_FREE_IF_COPY(jp, 1);
419 
420  if (JsonValueListLength(&found) == 1)
421  {
422  JsonbValue *jbv = JsonValueListHead(&found);
423 
424  if (jbv->type == jbvBool)
425  PG_RETURN_BOOL(jbv->val.boolean);
426 
427  if (jbv->type == jbvNull)
428  PG_RETURN_NULL();
429  }
430 
431  if (!silent)
432  ereport(ERROR,
433  (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
434  errmsg("single boolean result is expected")));
435 
436  PG_RETURN_NULL();
437 }
438 
439 Datum
441 {
442  return jsonb_path_match_internal(fcinfo, false);
443 }
444 
445 Datum
447 {
448  return jsonb_path_match_internal(fcinfo, true);
449 }
450 
451 /*
452  * jsonb_path_match_opr
453  * Implementation of operator "jsonb @@ jsonpath" (2-argument version of
454  * jsonb_path_match()).
455  */
456 Datum
458 {
459  /* just call the other one -- it can handle both cases */
460  return jsonb_path_match_internal(fcinfo, false);
461 }
462 
463 /*
464  * jsonb_path_query
465  * Executes jsonpath for given jsonb document and returns result as
466  * rowset.
467  */
468 static Datum
470 {
471  FuncCallContext *funcctx;
472  List *found;
473  JsonbValue *v;
474  ListCell *c;
475 
476  if (SRF_IS_FIRSTCALL())
477  {
478  JsonPath *jp;
479  Jsonb *jb;
480  MemoryContext oldcontext;
481  Jsonb *vars;
482  bool silent;
483  JsonValueList found = {0};
484 
485  funcctx = SRF_FIRSTCALL_INIT();
486  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
487 
488  jb = PG_GETARG_JSONB_P_COPY(0);
491  silent = PG_GETARG_BOOL(3);
492 
494  jb, !silent, &found, tz);
495 
496  funcctx->user_fctx = JsonValueListGetList(&found);
497 
498  MemoryContextSwitchTo(oldcontext);
499  }
500 
501  funcctx = SRF_PERCALL_SETUP();
502  found = funcctx->user_fctx;
503 
504  c = list_head(found);
505 
506  if (c == NULL)
507  SRF_RETURN_DONE(funcctx);
508 
509  v = lfirst(c);
510  funcctx->user_fctx = list_delete_first(found);
511 
513 }
514 
515 Datum
517 {
518  return jsonb_path_query_internal(fcinfo, false);
519 }
520 
521 Datum
523 {
524  return jsonb_path_query_internal(fcinfo, true);
525 }
526 
527 /*
528  * jsonb_path_query_array
529  * Executes jsonpath for given jsonb document and returns result as
530  * jsonb array.
531  */
532 static Datum
534 {
535  Jsonb *jb = PG_GETARG_JSONB_P(0);
537  JsonValueList found = {0};
539  bool silent = PG_GETARG_BOOL(3);
540 
542  jb, !silent, &found, tz);
543 
545 }
546 
547 Datum
549 {
550  return jsonb_path_query_array_internal(fcinfo, false);
551 }
552 
553 Datum
555 {
556  return jsonb_path_query_array_internal(fcinfo, true);
557 }
558 
559 /*
560  * jsonb_path_query_first
561  * Executes jsonpath for given jsonb document and returns first result
562  * item. If there are no items, NULL returned.
563  */
564 static Datum
566 {
567  Jsonb *jb = PG_GETARG_JSONB_P(0);
569  JsonValueList found = {0};
571  bool silent = PG_GETARG_BOOL(3);
572 
574  jb, !silent, &found, tz);
575 
576  if (JsonValueListLength(&found) >= 1)
578  else
579  PG_RETURN_NULL();
580 }
581 
582 Datum
584 {
585  return jsonb_path_query_first_internal(fcinfo, false);
586 }
587 
588 Datum
590 {
591  return jsonb_path_query_first_internal(fcinfo, true);
592 }
593 
594 /********************Execute functions for JsonPath**************************/
595 
596 /*
597  * Interface to jsonpath executor
598  *
599  * 'path' - jsonpath to be executed
600  * 'vars' - variables to be substituted to jsonpath
601  * 'json' - target document for jsonpath evaluation
602  * 'throwErrors' - whether we should throw suppressible errors
603  * 'result' - list to store result items into
604  *
605  * Returns an error if a recoverable error happens during processing, or NULL
606  * on no error.
607  *
608  * Note, jsonb and jsonpath values should be available and untoasted during
609  * work because JsonPathItem, JsonbValue and result item could have pointers
610  * into input values. If caller needs to just check if document matches
611  * jsonpath, then it doesn't provide a result arg. In this case executor
612  * works till first positive result and does not check the rest if possible.
613  * In other case it tries to find all the satisfied result items.
614  */
615 static JsonPathExecResult
617  Jsonb *json, bool throwErrors, JsonValueList *result,
618  bool useTz)
619 {
622  JsonPathItem jsp;
623  JsonbValue jbv;
624 
625  jspInit(&jsp, path);
626 
627  if (!JsonbExtractScalar(&json->root, &jbv))
628  JsonbInitBinary(&jbv, json);
629 
630  cxt.vars = vars;
631  cxt.getVar = getVar;
632  cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
634  cxt.root = &jbv;
635  cxt.current = &jbv;
636  cxt.baseObject.jbc = NULL;
637  cxt.baseObject.id = 0;
638  /* 1 + number of base objects in vars */
639  cxt.lastGeneratedObjectId = 1 + getVar(vars, NULL, 0, NULL, NULL);
640  cxt.innermostArraySize = -1;
641  cxt.throwErrors = throwErrors;
642  cxt.useTz = useTz;
643 
644  if (jspStrictAbsenseOfErrors(&cxt) && !result)
645  {
646  /*
647  * In strict mode we must get a complete list of values to check that
648  * there are no errors at all.
649  */
650  JsonValueList vals = {0};
651 
652  res = executeItem(&cxt, &jsp, &jbv, &vals);
653 
654  if (jperIsError(res))
655  return res;
656 
657  return JsonValueListIsEmpty(&vals) ? jperNotFound : jperOk;
658  }
659 
660  res = executeItem(&cxt, &jsp, &jbv, result);
661 
662  Assert(!throwErrors || !jperIsError(res));
663 
664  return res;
665 }
666 
667 /*
668  * Execute jsonpath with automatic unwrapping of current item in lax mode.
669  */
670 static JsonPathExecResult
672  JsonbValue *jb, JsonValueList *found)
673 {
674  return executeItemOptUnwrapTarget(cxt, jsp, jb, found, jspAutoUnwrap(cxt));
675 }
676 
677 /*
678  * Main jsonpath executor function: walks on jsonpath structure, finds
679  * relevant parts of jsonb and evaluates expressions over them.
680  * When 'unwrap' is true current SQL/JSON item is unwrapped if it is an array.
681  */
682 static JsonPathExecResult
684  JsonbValue *jb, JsonValueList *found, bool unwrap)
685 {
686  JsonPathItem elem;
688  JsonBaseObjectInfo baseObject;
689 
692 
693  switch (jsp->type)
694  {
695  /* all boolean item types: */
696  case jpiAnd:
697  case jpiOr:
698  case jpiNot:
699  case jpiIsUnknown:
700  case jpiEqual:
701  case jpiNotEqual:
702  case jpiLess:
703  case jpiGreater:
704  case jpiLessOrEqual:
705  case jpiGreaterOrEqual:
706  case jpiExists:
707  case jpiStartsWith:
708  case jpiLikeRegex:
709  {
710  JsonPathBool st = executeBoolItem(cxt, jsp, jb, true);
711 
712  res = appendBoolResult(cxt, jsp, found, st);
713  break;
714  }
715 
716  case jpiKey:
717  if (JsonbType(jb) == jbvObject)
718  {
719  JsonbValue *v;
720  JsonbValue key;
721 
722  key.type = jbvString;
723  key.val.string.val = jspGetString(jsp, &key.val.string.len);
724 
725  v = findJsonbValueFromContainer(jb->val.binary.data,
726  JB_FOBJECT, &key);
727 
728  if (v != NULL)
729  {
730  res = executeNextItem(cxt, jsp, NULL,
731  v, found, false);
732 
733  /* free value if it was not added to found list */
734  if (jspHasNext(jsp) || !found)
735  pfree(v);
736  }
737  else if (!jspIgnoreStructuralErrors(cxt))
738  {
739  Assert(found);
740 
741  if (!jspThrowErrors(cxt))
742  return jperError;
743 
744  ereport(ERROR,
745  (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND), \
746  errmsg("JSON object does not contain key \"%s\"",
747  pnstrdup(key.val.string.val,
748  key.val.string.len))));
749  }
750  }
751  else if (unwrap && JsonbType(jb) == jbvArray)
752  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
753  else if (!jspIgnoreStructuralErrors(cxt))
754  {
755  Assert(found);
757  (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND),
758  errmsg("jsonpath member accessor can only be applied to an object"))));
759  }
760  break;
761 
762  case jpiRoot:
763  jb = cxt->root;
764  baseObject = setBaseObject(cxt, jb, 0);
765  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
766  cxt->baseObject = baseObject;
767  break;
768 
769  case jpiCurrent:
770  res = executeNextItem(cxt, jsp, NULL, cxt->current,
771  found, true);
772  break;
773 
774  case jpiAnyArray:
775  if (JsonbType(jb) == jbvArray)
776  {
777  bool hasNext = jspGetNext(jsp, &elem);
778 
779  res = executeItemUnwrapTargetArray(cxt, hasNext ? &elem : NULL,
780  jb, found, jspAutoUnwrap(cxt));
781  }
782  else if (jspAutoWrap(cxt))
783  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
784  else if (!jspIgnoreStructuralErrors(cxt))
786  (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
787  errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
788  break;
789 
790  case jpiIndexArray:
791  if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
792  {
793  int innermostArraySize = cxt->innermostArraySize;
794  int i;
795  int size = JsonbArraySize(jb);
796  bool singleton = size < 0;
797  bool hasNext = jspGetNext(jsp, &elem);
798 
799  if (singleton)
800  size = 1;
801 
802  cxt->innermostArraySize = size; /* for LAST evaluation */
803 
804  for (i = 0; i < jsp->content.array.nelems; i++)
805  {
806  JsonPathItem from;
807  JsonPathItem to;
808  int32 index;
809  int32 index_from;
810  int32 index_to;
811  bool range = jspGetArraySubscript(jsp, &from,
812  &to, i);
813 
814  res = getArrayIndex(cxt, &from, jb, &index_from);
815 
816  if (jperIsError(res))
817  break;
818 
819  if (range)
820  {
821  res = getArrayIndex(cxt, &to, jb, &index_to);
822 
823  if (jperIsError(res))
824  break;
825  }
826  else
827  index_to = index_from;
828 
829  if (!jspIgnoreStructuralErrors(cxt) &&
830  (index_from < 0 ||
831  index_from > index_to ||
832  index_to >= size))
834  (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
835  errmsg("jsonpath array subscript is out of bounds"))));
836 
837  if (index_from < 0)
838  index_from = 0;
839 
840  if (index_to >= size)
841  index_to = size - 1;
842 
843  res = jperNotFound;
844 
845  for (index = index_from; index <= index_to; index++)
846  {
847  JsonbValue *v;
848  bool copy;
849 
850  if (singleton)
851  {
852  v = jb;
853  copy = true;
854  }
855  else
856  {
857  v = getIthJsonbValueFromContainer(jb->val.binary.data,
858  (uint32) index);
859 
860  if (v == NULL)
861  continue;
862 
863  copy = false;
864  }
865 
866  if (!hasNext && !found)
867  return jperOk;
868 
869  res = executeNextItem(cxt, jsp, &elem, v, found,
870  copy);
871 
872  if (jperIsError(res))
873  break;
874 
875  if (res == jperOk && !found)
876  break;
877  }
878 
879  if (jperIsError(res))
880  break;
881 
882  if (res == jperOk && !found)
883  break;
884  }
885 
886  cxt->innermostArraySize = innermostArraySize;
887  }
888  else if (!jspIgnoreStructuralErrors(cxt))
889  {
891  (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
892  errmsg("jsonpath array accessor can only be applied to an array"))));
893  }
894  break;
895 
896  case jpiLast:
897  {
898  JsonbValue tmpjbv;
899  JsonbValue *lastjbv;
900  int last;
901  bool hasNext = jspGetNext(jsp, &elem);
902 
903  if (cxt->innermostArraySize < 0)
904  elog(ERROR, "evaluating jsonpath LAST outside of array subscript");
905 
906  if (!hasNext && !found)
907  {
908  res = jperOk;
909  break;
910  }
911 
912  last = cxt->innermostArraySize - 1;
913 
914  lastjbv = hasNext ? &tmpjbv : palloc(sizeof(*lastjbv));
915 
916  lastjbv->type = jbvNumeric;
917  lastjbv->val.numeric = int64_to_numeric(last);
918 
919  res = executeNextItem(cxt, jsp, &elem,
920  lastjbv, found, hasNext);
921  }
922  break;
923 
924  case jpiAnyKey:
925  if (JsonbType(jb) == jbvObject)
926  {
927  bool hasNext = jspGetNext(jsp, &elem);
928 
929  if (jb->type != jbvBinary)
930  elog(ERROR, "invalid jsonb object type: %d", jb->type);
931 
932  return executeAnyItem
933  (cxt, hasNext ? &elem : NULL,
934  jb->val.binary.data, found, 1, 1, 1,
935  false, jspAutoUnwrap(cxt));
936  }
937  else if (unwrap && JsonbType(jb) == jbvArray)
938  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
939  else if (!jspIgnoreStructuralErrors(cxt))
940  {
941  Assert(found);
943  (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
944  errmsg("jsonpath wildcard member accessor can only be applied to an object"))));
945  }
946  break;
947 
948  case jpiAdd:
949  return executeBinaryArithmExpr(cxt, jsp, jb,
950  numeric_add_opt_error, found);
951 
952  case jpiSub:
953  return executeBinaryArithmExpr(cxt, jsp, jb,
954  numeric_sub_opt_error, found);
955 
956  case jpiMul:
957  return executeBinaryArithmExpr(cxt, jsp, jb,
958  numeric_mul_opt_error, found);
959 
960  case jpiDiv:
961  return executeBinaryArithmExpr(cxt, jsp, jb,
962  numeric_div_opt_error, found);
963 
964  case jpiMod:
965  return executeBinaryArithmExpr(cxt, jsp, jb,
966  numeric_mod_opt_error, found);
967 
968  case jpiPlus:
969  return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
970 
971  case jpiMinus:
972  return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus,
973  found);
974 
975  case jpiFilter:
976  {
977  JsonPathBool st;
978 
979  if (unwrap && JsonbType(jb) == jbvArray)
980  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
981  false);
982 
983  jspGetArg(jsp, &elem);
984  st = executeNestedBoolItem(cxt, &elem, jb);
985  if (st != jpbTrue)
986  res = jperNotFound;
987  else
988  res = executeNextItem(cxt, jsp, NULL,
989  jb, found, true);
990  break;
991  }
992 
993  case jpiAny:
994  {
995  bool hasNext = jspGetNext(jsp, &elem);
996 
997  /* first try without any intermediate steps */
998  if (jsp->content.anybounds.first == 0)
999  {
1000  bool savedIgnoreStructuralErrors;
1001 
1002  savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
1003  cxt->ignoreStructuralErrors = true;
1004  res = executeNextItem(cxt, jsp, &elem,
1005  jb, found, true);
1006  cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
1007 
1008  if (res == jperOk && !found)
1009  break;
1010  }
1011 
1012  if (jb->type == jbvBinary)
1014  (cxt, hasNext ? &elem : NULL,
1015  jb->val.binary.data, found,
1016  1,
1017  jsp->content.anybounds.first,
1018  jsp->content.anybounds.last,
1019  true, jspAutoUnwrap(cxt));
1020  break;
1021  }
1022 
1023  case jpiNull:
1024  case jpiBool:
1025  case jpiNumeric:
1026  case jpiString:
1027  case jpiVariable:
1028  {
1029  JsonbValue vbuf;
1030  JsonbValue *v;
1031  bool hasNext = jspGetNext(jsp, &elem);
1032 
1033  if (!hasNext && !found)
1034  {
1035  res = jperOk; /* skip evaluation */
1036  break;
1037  }
1038 
1039  v = hasNext ? &vbuf : palloc(sizeof(*v));
1040 
1041  baseObject = cxt->baseObject;
1042  getJsonPathItem(cxt, jsp, v);
1043 
1044  res = executeNextItem(cxt, jsp, &elem,
1045  v, found, hasNext);
1046  cxt->baseObject = baseObject;
1047  }
1048  break;
1049 
1050  case jpiType:
1051  {
1052  JsonbValue *jbv = palloc(sizeof(*jbv));
1053 
1054  jbv->type = jbvString;
1055  jbv->val.string.val = pstrdup(JsonbTypeName(jb));
1056  jbv->val.string.len = strlen(jbv->val.string.val);
1057 
1058  res = executeNextItem(cxt, jsp, NULL, jbv,
1059  found, false);
1060  }
1061  break;
1062 
1063  case jpiSize:
1064  {
1065  int size = JsonbArraySize(jb);
1066 
1067  if (size < 0)
1068  {
1069  if (!jspAutoWrap(cxt))
1070  {
1071  if (!jspIgnoreStructuralErrors(cxt))
1073  (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
1074  errmsg("jsonpath item method .%s() can only be applied to an array",
1075  jspOperationName(jsp->type)))));
1076  break;
1077  }
1078 
1079  size = 1;
1080  }
1081 
1082  jb = palloc(sizeof(*jb));
1083 
1084  jb->type = jbvNumeric;
1085  jb->val.numeric = int64_to_numeric(size);
1086 
1087  res = executeNextItem(cxt, jsp, NULL, jb, found, false);
1088  }
1089  break;
1090 
1091  case jpiAbs:
1092  return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_abs,
1093  found);
1094 
1095  case jpiFloor:
1096  return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_floor,
1097  found);
1098 
1099  case jpiCeiling:
1100  return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_ceil,
1101  found);
1102 
1103  case jpiDouble:
1104  {
1105  JsonbValue jbv;
1106 
1107  if (unwrap && JsonbType(jb) == jbvArray)
1108  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1109  false);
1110 
1111  if (jb->type == jbvNumeric)
1112  {
1114  NumericGetDatum(jb->val.numeric)));
1115  double val;
1116  bool have_error = false;
1117 
1119  NULL,
1120  "double precision",
1121  tmp,
1122  &have_error);
1123 
1124  if (have_error || isinf(val) || isnan(val))
1126  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1127  errmsg("numeric argument of jsonpath item method .%s() is out of range for type double precision",
1128  jspOperationName(jsp->type)))));
1129  res = jperOk;
1130  }
1131  else if (jb->type == jbvString)
1132  {
1133  /* cast string as double */
1134  double val;
1135  char *tmp = pnstrdup(jb->val.string.val,
1136  jb->val.string.len);
1137  bool have_error = false;
1138 
1140  NULL,
1141  "double precision",
1142  tmp,
1143  &have_error);
1144 
1145  if (have_error || isinf(val) || isnan(val))
1147  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1148  errmsg("string argument of jsonpath item method .%s() is not a valid representation of a double precision number",
1149  jspOperationName(jsp->type)))));
1150 
1151  jb = &jbv;
1152  jb->type = jbvNumeric;
1154  Float8GetDatum(val)));
1155  res = jperOk;
1156  }
1157 
1158  if (res == jperNotFound)
1160  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1161  errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1162  jspOperationName(jsp->type)))));
1163 
1164  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1165  }
1166  break;
1167 
1168  case jpiDatetime:
1169  if (unwrap && JsonbType(jb) == jbvArray)
1170  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1171 
1172  return executeDateTimeMethod(cxt, jsp, jb, found);
1173 
1174  case jpiKeyValue:
1175  if (unwrap && JsonbType(jb) == jbvArray)
1176  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1177 
1178  return executeKeyValueMethod(cxt, jsp, jb, found);
1179 
1180  default:
1181  elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
1182  }
1183 
1184  return res;
1185 }
1186 
1187 /*
1188  * Unwrap current array item and execute jsonpath for each of its elements.
1189  */
1190 static JsonPathExecResult
1192  JsonbValue *jb, JsonValueList *found,
1193  bool unwrapElements)
1194 {
1195  if (jb->type != jbvBinary)
1196  {
1197  Assert(jb->type != jbvArray);
1198  elog(ERROR, "invalid jsonb array value type: %d", jb->type);
1199  }
1200 
1201  return executeAnyItem
1202  (cxt, jsp, jb->val.binary.data, found, 1, 1, 1,
1203  false, unwrapElements);
1204 }
1205 
1206 /*
1207  * Execute next jsonpath item if exists. Otherwise put "v" to the "found"
1208  * list if provided.
1209  */
1210 static JsonPathExecResult
1213  JsonbValue *v, JsonValueList *found, bool copy)
1214 {
1215  JsonPathItem elem;
1216  bool hasNext;
1217 
1218  if (!cur)
1219  hasNext = next != NULL;
1220  else if (next)
1221  hasNext = jspHasNext(cur);
1222  else
1223  {
1224  next = &elem;
1225  hasNext = jspGetNext(cur, next);
1226  }
1227 
1228  if (hasNext)
1229  return executeItem(cxt, next, v, found);
1230 
1231  if (found)
1232  JsonValueListAppend(found, copy ? copyJsonbValue(v) : v);
1233 
1234  return jperOk;
1235 }
1236 
1237 /*
1238  * Same as executeItem(), but when "unwrap == true" automatically unwraps
1239  * each array item from the resulting sequence in lax mode.
1240  */
1241 static JsonPathExecResult
1243  JsonbValue *jb, bool unwrap,
1244  JsonValueList *found)
1245 {
1246  if (unwrap && jspAutoUnwrap(cxt))
1247  {
1248  JsonValueList seq = {0};
1250  JsonPathExecResult res = executeItem(cxt, jsp, jb, &seq);
1251  JsonbValue *item;
1252 
1253  if (jperIsError(res))
1254  return res;
1255 
1256  JsonValueListInitIterator(&seq, &it);
1257  while ((item = JsonValueListNext(&seq, &it)))
1258  {
1259  Assert(item->type != jbvArray);
1260 
1261  if (JsonbType(item) == jbvArray)
1262  executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
1263  else
1264  JsonValueListAppend(found, item);
1265  }
1266 
1267  return jperOk;
1268  }
1269 
1270  return executeItem(cxt, jsp, jb, found);
1271 }
1272 
1273 /*
1274  * Same as executeItemOptUnwrapResult(), but with error suppression.
1275  */
1276 static JsonPathExecResult
1278  JsonPathItem *jsp,
1279  JsonbValue *jb, bool unwrap,
1280  JsonValueList *found)
1281 {
1283  bool throwErrors = cxt->throwErrors;
1284 
1285  cxt->throwErrors = false;
1286  res = executeItemOptUnwrapResult(cxt, jsp, jb, unwrap, found);
1287  cxt->throwErrors = throwErrors;
1288 
1289  return res;
1290 }
1291 
1292 /* Execute boolean-valued jsonpath expression. */
1293 static JsonPathBool
1295  JsonbValue *jb, bool canHaveNext)
1296 {
1297  JsonPathItem larg;
1298  JsonPathItem rarg;
1299  JsonPathBool res;
1300  JsonPathBool res2;
1301 
1302  if (!canHaveNext && jspHasNext(jsp))
1303  elog(ERROR, "boolean jsonpath item cannot have next item");
1304 
1305  switch (jsp->type)
1306  {
1307  case jpiAnd:
1308  jspGetLeftArg(jsp, &larg);
1309  res = executeBoolItem(cxt, &larg, jb, false);
1310 
1311  if (res == jpbFalse)
1312  return jpbFalse;
1313 
1314  /*
1315  * SQL/JSON says that we should check second arg in case of
1316  * jperError
1317  */
1318 
1319  jspGetRightArg(jsp, &rarg);
1320  res2 = executeBoolItem(cxt, &rarg, jb, false);
1321 
1322  return res2 == jpbTrue ? res : res2;
1323 
1324  case jpiOr:
1325  jspGetLeftArg(jsp, &larg);
1326  res = executeBoolItem(cxt, &larg, jb, false);
1327 
1328  if (res == jpbTrue)
1329  return jpbTrue;
1330 
1331  jspGetRightArg(jsp, &rarg);
1332  res2 = executeBoolItem(cxt, &rarg, jb, false);
1333 
1334  return res2 == jpbFalse ? res : res2;
1335 
1336  case jpiNot:
1337  jspGetArg(jsp, &larg);
1338 
1339  res = executeBoolItem(cxt, &larg, jb, false);
1340 
1341  if (res == jpbUnknown)
1342  return jpbUnknown;
1343 
1344  return res == jpbTrue ? jpbFalse : jpbTrue;
1345 
1346  case jpiIsUnknown:
1347  jspGetArg(jsp, &larg);
1348  res = executeBoolItem(cxt, &larg, jb, false);
1349  return res == jpbUnknown ? jpbTrue : jpbFalse;
1350 
1351  case jpiEqual:
1352  case jpiNotEqual:
1353  case jpiLess:
1354  case jpiGreater:
1355  case jpiLessOrEqual:
1356  case jpiGreaterOrEqual:
1357  jspGetLeftArg(jsp, &larg);
1358  jspGetRightArg(jsp, &rarg);
1359  return executePredicate(cxt, jsp, &larg, &rarg, jb, true,
1360  executeComparison, cxt);
1361 
1362  case jpiStartsWith: /* 'whole STARTS WITH initial' */
1363  jspGetLeftArg(jsp, &larg); /* 'whole' */
1364  jspGetRightArg(jsp, &rarg); /* 'initial' */
1365  return executePredicate(cxt, jsp, &larg, &rarg, jb, false,
1366  executeStartsWith, NULL);
1367 
1368  case jpiLikeRegex: /* 'expr LIKE_REGEX pattern FLAGS flags' */
1369  {
1370  /*
1371  * 'expr' is a sequence-returning expression. 'pattern' is a
1372  * regex string literal. SQL/JSON standard requires XQuery
1373  * regexes, but we use Postgres regexes here. 'flags' is a
1374  * string literal converted to integer flags at compile-time.
1375  */
1376  JsonLikeRegexContext lrcxt = {0};
1377 
1378  jspInitByBuffer(&larg, jsp->base,
1379  jsp->content.like_regex.expr);
1380 
1381  return executePredicate(cxt, jsp, &larg, NULL, jb, false,
1382  executeLikeRegex, &lrcxt);
1383  }
1384 
1385  case jpiExists:
1386  jspGetArg(jsp, &larg);
1387 
1388  if (jspStrictAbsenseOfErrors(cxt))
1389  {
1390  /*
1391  * In strict mode we must get a complete list of values to
1392  * check that there are no errors at all.
1393  */
1394  JsonValueList vals = {0};
1396  executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1397  false, &vals);
1398 
1399  if (jperIsError(res))
1400  return jpbUnknown;
1401 
1402  return JsonValueListIsEmpty(&vals) ? jpbFalse : jpbTrue;
1403  }
1404  else
1405  {
1407  executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1408  false, NULL);
1409 
1410  if (jperIsError(res))
1411  return jpbUnknown;
1412 
1413  return res == jperOk ? jpbTrue : jpbFalse;
1414  }
1415 
1416  default:
1417  elog(ERROR, "invalid boolean jsonpath item type: %d", jsp->type);
1418  return jpbUnknown;
1419  }
1420 }
1421 
1422 /*
1423  * Execute nested (filters etc.) boolean expression pushing current SQL/JSON
1424  * item onto the stack.
1425  */
1426 static JsonPathBool
1428  JsonbValue *jb)
1429 {
1430  JsonbValue *prev;
1431  JsonPathBool res;
1432 
1433  prev = cxt->current;
1434  cxt->current = jb;
1435  res = executeBoolItem(cxt, jsp, jb, false);
1436  cxt->current = prev;
1437 
1438  return res;
1439 }
1440 
1441 /*
1442  * Implementation of several jsonpath nodes:
1443  * - jpiAny (.** accessor),
1444  * - jpiAnyKey (.* accessor),
1445  * - jpiAnyArray ([*] accessor)
1446  */
1447 static JsonPathExecResult
1449  JsonValueList *found, uint32 level, uint32 first, uint32 last,
1450  bool ignoreStructuralErrors, bool unwrapNext)
1451 {
1453  JsonbIterator *it;
1454  int32 r;
1455  JsonbValue v;
1456 
1458 
1459  if (level > last)
1460  return res;
1461 
1462  it = JsonbIteratorInit(jbc);
1463 
1464  /*
1465  * Recursively iterate over jsonb objects/arrays
1466  */
1467  while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
1468  {
1469  if (r == WJB_KEY)
1470  {
1471  r = JsonbIteratorNext(&it, &v, true);
1472  Assert(r == WJB_VALUE);
1473  }
1474 
1475  if (r == WJB_VALUE || r == WJB_ELEM)
1476  {
1477 
1478  if (level >= first ||
1479  (first == PG_UINT32_MAX && last == PG_UINT32_MAX &&
1480  v.type != jbvBinary)) /* leaves only requested */
1481  {
1482  /* check expression */
1483  if (jsp)
1484  {
1485  if (ignoreStructuralErrors)
1486  {
1487  bool savedIgnoreStructuralErrors;
1488 
1489  savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
1490  cxt->ignoreStructuralErrors = true;
1491  res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
1492  cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
1493  }
1494  else
1495  res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
1496 
1497  if (jperIsError(res))
1498  break;
1499 
1500  if (res == jperOk && !found)
1501  break;
1502  }
1503  else if (found)
1504  JsonValueListAppend(found, copyJsonbValue(&v));
1505  else
1506  return jperOk;
1507  }
1508 
1509  if (level < last && v.type == jbvBinary)
1510  {
1512  (cxt, jsp, v.val.binary.data, found,
1513  level + 1, first, last,
1514  ignoreStructuralErrors, unwrapNext);
1515 
1516  if (jperIsError(res))
1517  break;
1518 
1519  if (res == jperOk && found == NULL)
1520  break;
1521  }
1522  }
1523  }
1524 
1525  return res;
1526 }
1527 
1528 /*
1529  * Execute unary or binary predicate.
1530  *
1531  * Predicates have existence semantics, because their operands are item
1532  * sequences. Pairs of items from the left and right operand's sequences are
1533  * checked. TRUE returned only if any pair satisfying the condition is found.
1534  * In strict mode, even if the desired pair has already been found, all pairs
1535  * still need to be examined to check the absence of errors. If any error
1536  * occurs, UNKNOWN (analogous to SQL NULL) is returned.
1537  */
1538 static JsonPathBool
1540  JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb,
1541  bool unwrapRightArg, JsonPathPredicateCallback exec,
1542  void *param)
1543 {
1545  JsonValueListIterator lseqit;
1546  JsonValueList lseq = {0};
1547  JsonValueList rseq = {0};
1548  JsonbValue *lval;
1549  bool error = false;
1550  bool found = false;
1551 
1552  /* Left argument is always auto-unwrapped. */
1553  res = executeItemOptUnwrapResultNoThrow(cxt, larg, jb, true, &lseq);
1554  if (jperIsError(res))
1555  return jpbUnknown;
1556 
1557  if (rarg)
1558  {
1559  /* Right argument is conditionally auto-unwrapped. */
1560  res = executeItemOptUnwrapResultNoThrow(cxt, rarg, jb,
1561  unwrapRightArg, &rseq);
1562  if (jperIsError(res))
1563  return jpbUnknown;
1564  }
1565 
1566  JsonValueListInitIterator(&lseq, &lseqit);
1567  while ((lval = JsonValueListNext(&lseq, &lseqit)))
1568  {
1569  JsonValueListIterator rseqit;
1570  JsonbValue *rval;
1571  bool first = true;
1572 
1573  JsonValueListInitIterator(&rseq, &rseqit);
1574  if (rarg)
1575  rval = JsonValueListNext(&rseq, &rseqit);
1576  else
1577  rval = NULL;
1578 
1579  /* Loop over right arg sequence or do single pass otherwise */
1580  while (rarg ? (rval != NULL) : first)
1581  {
1582  JsonPathBool res = exec(pred, lval, rval, param);
1583 
1584  if (res == jpbUnknown)
1585  {
1586  if (jspStrictAbsenseOfErrors(cxt))
1587  return jpbUnknown;
1588 
1589  error = true;
1590  }
1591  else if (res == jpbTrue)
1592  {
1593  if (!jspStrictAbsenseOfErrors(cxt))
1594  return jpbTrue;
1595 
1596  found = true;
1597  }
1598 
1599  first = false;
1600  if (rarg)
1601  rval = JsonValueListNext(&rseq, &rseqit);
1602  }
1603  }
1604 
1605  if (found) /* possible only in strict mode */
1606  return jpbTrue;
1607 
1608  if (error) /* possible only in lax mode */
1609  return jpbUnknown;
1610 
1611  return jpbFalse;
1612 }
1613 
1614 /*
1615  * Execute binary arithmetic expression on singleton numeric operands.
1616  * Array operands are automatically unwrapped in lax mode.
1617  */
1618 static JsonPathExecResult
1620  JsonbValue *jb, BinaryArithmFunc func,
1621  JsonValueList *found)
1622 {
1623  JsonPathExecResult jper;
1624  JsonPathItem elem;
1625  JsonValueList lseq = {0};
1626  JsonValueList rseq = {0};
1627  JsonbValue *lval;
1628  JsonbValue *rval;
1629  Numeric res;
1630 
1631  jspGetLeftArg(jsp, &elem);
1632 
1633  /*
1634  * XXX: By standard only operands of multiplicative expressions are
1635  * unwrapped. We extend it to other binary arithmetic expressions too.
1636  */
1637  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &lseq);
1638  if (jperIsError(jper))
1639  return jper;
1640 
1641  jspGetRightArg(jsp, &elem);
1642 
1643  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &rseq);
1644  if (jperIsError(jper))
1645  return jper;
1646 
1647  if (JsonValueListLength(&lseq) != 1 ||
1648  !(lval = getScalar(JsonValueListHead(&lseq), jbvNumeric)))
1650  (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
1651  errmsg("left operand of jsonpath operator %s is not a single numeric value",
1652  jspOperationName(jsp->type)))));
1653 
1654  if (JsonValueListLength(&rseq) != 1 ||
1655  !(rval = getScalar(JsonValueListHead(&rseq), jbvNumeric)))
1657  (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
1658  errmsg("right operand of jsonpath operator %s is not a single numeric value",
1659  jspOperationName(jsp->type)))));
1660 
1661  if (jspThrowErrors(cxt))
1662  {
1663  res = func(lval->val.numeric, rval->val.numeric, NULL);
1664  }
1665  else
1666  {
1667  bool error = false;
1668 
1669  res = func(lval->val.numeric, rval->val.numeric, &error);
1670 
1671  if (error)
1672  return jperError;
1673  }
1674 
1675  if (!jspGetNext(jsp, &elem) && !found)
1676  return jperOk;
1677 
1678  lval = palloc(sizeof(*lval));
1679  lval->type = jbvNumeric;
1680  lval->val.numeric = res;
1681 
1682  return executeNextItem(cxt, jsp, &elem, lval, found, false);
1683 }
1684 
1685 /*
1686  * Execute unary arithmetic expression for each numeric item in its operand's
1687  * sequence. Array operand is automatically unwrapped in lax mode.
1688  */
1689 static JsonPathExecResult
1691  JsonbValue *jb, PGFunction func, JsonValueList *found)
1692 {
1693  JsonPathExecResult jper;
1694  JsonPathExecResult jper2;
1695  JsonPathItem elem;
1696  JsonValueList seq = {0};
1698  JsonbValue *val;
1699  bool hasNext;
1700 
1701  jspGetArg(jsp, &elem);
1702  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &seq);
1703 
1704  if (jperIsError(jper))
1705  return jper;
1706 
1707  jper = jperNotFound;
1708 
1709  hasNext = jspGetNext(jsp, &elem);
1710 
1711  JsonValueListInitIterator(&seq, &it);
1712  while ((val = JsonValueListNext(&seq, &it)))
1713  {
1714  if ((val = getScalar(val, jbvNumeric)))
1715  {
1716  if (!found && !hasNext)
1717  return jperOk;
1718  }
1719  else
1720  {
1721  if (!found && !hasNext)
1722  continue; /* skip non-numerics processing */
1723 
1725  (errcode(ERRCODE_SQL_JSON_NUMBER_NOT_FOUND),
1726  errmsg("operand of unary jsonpath operator %s is not a numeric value",
1727  jspOperationName(jsp->type)))));
1728  }
1729 
1730  if (func)
1731  val->val.numeric =
1733  NumericGetDatum(val->val.numeric)));
1734 
1735  jper2 = executeNextItem(cxt, jsp, &elem, val, found, false);
1736 
1737  if (jperIsError(jper2))
1738  return jper2;
1739 
1740  if (jper2 == jperOk)
1741  {
1742  if (!found)
1743  return jperOk;
1744  jper = jperOk;
1745  }
1746  }
1747 
1748  return jper;
1749 }
1750 
1751 /*
1752  * STARTS_WITH predicate callback.
1753  *
1754  * Check if the 'whole' string starts from 'initial' string.
1755  */
1756 static JsonPathBool
1758  void *param)
1759 {
1760  if (!(whole = getScalar(whole, jbvString)))
1761  return jpbUnknown; /* error */
1762 
1763  if (!(initial = getScalar(initial, jbvString)))
1764  return jpbUnknown; /* error */
1765 
1766  if (whole->val.string.len >= initial->val.string.len &&
1767  !memcmp(whole->val.string.val,
1768  initial->val.string.val,
1769  initial->val.string.len))
1770  return jpbTrue;
1771 
1772  return jpbFalse;
1773 }
1774 
1775 /*
1776  * LIKE_REGEX predicate callback.
1777  *
1778  * Check if the string matches regex pattern.
1779  */
1780 static JsonPathBool
1782  void *param)
1783 {
1784  JsonLikeRegexContext *cxt = param;
1785 
1786  if (!(str = getScalar(str, jbvString)))
1787  return jpbUnknown;
1788 
1789  /* Cache regex text and converted flags. */
1790  if (!cxt->regex)
1791  {
1792  cxt->regex =
1794  jsp->content.like_regex.patternlen);
1795  cxt->cflags = jspConvertRegexFlags(jsp->content.like_regex.flags);
1796  }
1797 
1798  if (RE_compile_and_execute(cxt->regex, str->val.string.val,
1799  str->val.string.len,
1800  cxt->cflags, DEFAULT_COLLATION_OID, 0, NULL))
1801  return jpbTrue;
1802 
1803  return jpbFalse;
1804 }
1805 
1806 /*
1807  * Execute numeric item methods (.abs(), .floor(), .ceil()) using the specified
1808  * user function 'func'.
1809  */
1810 static JsonPathExecResult
1812  JsonbValue *jb, bool unwrap, PGFunction func,
1813  JsonValueList *found)
1814 {
1816  Datum datum;
1817 
1818  if (unwrap && JsonbType(jb) == jbvArray)
1819  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1820 
1821  if (!(jb = getScalar(jb, jbvNumeric)))
1823  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1824  errmsg("jsonpath item method .%s() can only be applied to a numeric value",
1825  jspOperationName(jsp->type)))));
1826 
1827  datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
1828 
1829  if (!jspGetNext(jsp, &next) && !found)
1830  return jperOk;
1831 
1832  jb = palloc(sizeof(*jb));
1833  jb->type = jbvNumeric;
1834  jb->val.numeric = DatumGetNumeric(datum);
1835 
1836  return executeNextItem(cxt, jsp, &next, jb, found, false);
1837 }
1838 
1839 /*
1840  * Implementation of the .datetime() method.
1841  *
1842  * Converts a string into a date/time value. The actual type is determined at run time.
1843  * If an argument is provided, this argument is used as a template string.
1844  * Otherwise, the first fitting ISO format is selected.
1845  */
1846 static JsonPathExecResult
1848  JsonbValue *jb, JsonValueList *found)
1849 {
1850  JsonbValue jbvbuf;
1851  Datum value;
1852  text *datetime;
1853  Oid collid;
1854  Oid typid;
1855  int32 typmod = -1;
1856  int tz = 0;
1857  bool hasNext;
1859  JsonPathItem elem;
1860 
1861  if (!(jb = getScalar(jb, jbvString)))
1863  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
1864  errmsg("jsonpath item method .%s() can only be applied to a string",
1865  jspOperationName(jsp->type)))));
1866 
1867  datetime = cstring_to_text_with_len(jb->val.string.val,
1868  jb->val.string.len);
1869 
1870  /*
1871  * At some point we might wish to have callers supply the collation to
1872  * use, but right now it's unclear that they'd be able to do better than
1873  * DEFAULT_COLLATION_OID anyway.
1874  */
1875  collid = DEFAULT_COLLATION_OID;
1876 
1877  if (jsp->content.arg)
1878  {
1879  text *template;
1880  char *template_str;
1881  int template_len;
1882  bool have_error = false;
1883 
1884  jspGetArg(jsp, &elem);
1885 
1886  if (elem.type != jpiString)
1887  elog(ERROR, "invalid jsonpath item type for .datetime() argument");
1888 
1889  template_str = jspGetString(&elem, &template_len);
1890 
1891  template = cstring_to_text_with_len(template_str,
1892  template_len);
1893 
1894  value = parse_datetime(datetime, template, collid, true,
1895  &typid, &typmod, &tz,
1896  jspThrowErrors(cxt) ? NULL : &have_error);
1897 
1898  if (have_error)
1899  res = jperError;
1900  else
1901  res = jperOk;
1902  }
1903  else
1904  {
1905  /*
1906  * According to SQL/JSON standard enumerate ISO formats for: date,
1907  * timetz, time, timestamptz, timestamp.
1908  *
1909  * We also support ISO 8601 for timestamps, because to_json[b]()
1910  * functions use this format.
1911  */
1912  static const char *fmt_str[] =
1913  {
1914  "yyyy-mm-dd",
1915  "HH24:MI:SSTZH:TZM",
1916  "HH24:MI:SSTZH",
1917  "HH24:MI:SS",
1918  "yyyy-mm-dd HH24:MI:SSTZH:TZM",
1919  "yyyy-mm-dd HH24:MI:SSTZH",
1920  "yyyy-mm-dd HH24:MI:SS",
1921  "yyyy-mm-dd\"T\"HH24:MI:SSTZH:TZM",
1922  "yyyy-mm-dd\"T\"HH24:MI:SSTZH",
1923  "yyyy-mm-dd\"T\"HH24:MI:SS"
1924  };
1925 
1926  /* cache for format texts */
1927  static text *fmt_txt[lengthof(fmt_str)] = {0};
1928  int i;
1929 
1930  /* loop until datetime format fits */
1931  for (i = 0; i < lengthof(fmt_str); i++)
1932  {
1933  bool have_error = false;
1934 
1935  if (!fmt_txt[i])
1936  {
1937  MemoryContext oldcxt =
1939 
1940  fmt_txt[i] = cstring_to_text(fmt_str[i]);
1941  MemoryContextSwitchTo(oldcxt);
1942  }
1943 
1944  value = parse_datetime(datetime, fmt_txt[i], collid, true,
1945  &typid, &typmod, &tz,
1946  &have_error);
1947 
1948  if (!have_error)
1949  {
1950  res = jperOk;
1951  break;
1952  }
1953  }
1954 
1955  if (res == jperNotFound)
1957  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
1958  errmsg("datetime format is not recognized: \"%s\"",
1959  text_to_cstring(datetime)),
1960  errhint("Use a datetime template argument to specify the input data format."))));
1961  }
1962 
1963  pfree(datetime);
1964 
1965  if (jperIsError(res))
1966  return res;
1967 
1968  hasNext = jspGetNext(jsp, &elem);
1969 
1970  if (!hasNext && !found)
1971  return res;
1972 
1973  jb = hasNext ? &jbvbuf : palloc(sizeof(*jb));
1974 
1975  jb->type = jbvDatetime;
1976  jb->val.datetime.value = value;
1977  jb->val.datetime.typid = typid;
1978  jb->val.datetime.typmod = typmod;
1979  jb->val.datetime.tz = tz;
1980 
1981  return executeNextItem(cxt, jsp, &elem, jb, found, hasNext);
1982 }
1983 
1984 /*
1985  * Implementation of .keyvalue() method.
1986  *
1987  * .keyvalue() method returns a sequence of object's key-value pairs in the
1988  * following format: '{ "key": key, "value": value, "id": id }'.
1989  *
1990  * "id" field is an object identifier which is constructed from the two parts:
1991  * base object id and its binary offset in base object's jsonb:
1992  * id = 10000000000 * base_object_id + obj_offset_in_base_object
1993  *
1994  * 10000000000 (10^10) -- is a first round decimal number greater than 2^32
1995  * (maximal offset in jsonb). Decimal multiplier is used here to improve the
1996  * readability of identifiers.
1997  *
1998  * Base object is usually a root object of the path: context item '$' or path
1999  * variable '$var', literals can't produce objects for now. But if the path
2000  * contains generated objects (.keyvalue() itself, for example), then they
2001  * become base object for the subsequent .keyvalue().
2002  *
2003  * Id of '$' is 0. Id of '$var' is its ordinal (positive) number in the list
2004  * of variables (see getJsonPathVariable()). Ids for generated objects
2005  * are assigned using global counter JsonPathExecContext.lastGeneratedObjectId.
2006  */
2007 static JsonPathExecResult
2009  JsonbValue *jb, JsonValueList *found)
2010 {
2013  JsonbContainer *jbc;
2014  JsonbValue key;
2015  JsonbValue val;
2016  JsonbValue idval;
2017  JsonbValue keystr;
2018  JsonbValue valstr;
2019  JsonbValue idstr;
2020  JsonbIterator *it;
2021  JsonbIteratorToken tok;
2022  int64 id;
2023  bool hasNext;
2024 
2025  if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
2027  (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
2028  errmsg("jsonpath item method .%s() can only be applied to an object",
2029  jspOperationName(jsp->type)))));
2030 
2031  jbc = jb->val.binary.data;
2032 
2033  if (!JsonContainerSize(jbc))
2034  return jperNotFound; /* no key-value pairs */
2035 
2036  hasNext = jspGetNext(jsp, &next);
2037 
2038  keystr.type = jbvString;
2039  keystr.val.string.val = "key";
2040  keystr.val.string.len = 3;
2041 
2042  valstr.type = jbvString;
2043  valstr.val.string.val = "value";
2044  valstr.val.string.len = 5;
2045 
2046  idstr.type = jbvString;
2047  idstr.val.string.val = "id";
2048  idstr.val.string.len = 2;
2049 
2050  /* construct object id from its base object and offset inside that */
2051  id = jb->type != jbvBinary ? 0 :
2052  (int64) ((char *) jbc - (char *) cxt->baseObject.jbc);
2053  id += (int64) cxt->baseObject.id * INT64CONST(10000000000);
2054 
2055  idval.type = jbvNumeric;
2056  idval.val.numeric = int64_to_numeric(id);
2057 
2058  it = JsonbIteratorInit(jbc);
2059 
2060  while ((tok = JsonbIteratorNext(&it, &key, true)) != WJB_DONE)
2061  {
2062  JsonBaseObjectInfo baseObject;
2063  JsonbValue obj;
2064  JsonbParseState *ps;
2065  JsonbValue *keyval;
2066  Jsonb *jsonb;
2067 
2068  if (tok != WJB_KEY)
2069  continue;
2070 
2071  res = jperOk;
2072 
2073  if (!hasNext && !found)
2074  break;
2075 
2076  tok = JsonbIteratorNext(&it, &val, true);
2077  Assert(tok == WJB_VALUE);
2078 
2079  ps = NULL;
2080  pushJsonbValue(&ps, WJB_BEGIN_OBJECT, NULL);
2081 
2082  pushJsonbValue(&ps, WJB_KEY, &keystr);
2083  pushJsonbValue(&ps, WJB_VALUE, &key);
2084 
2085  pushJsonbValue(&ps, WJB_KEY, &valstr);
2086  pushJsonbValue(&ps, WJB_VALUE, &val);
2087 
2088  pushJsonbValue(&ps, WJB_KEY, &idstr);
2089  pushJsonbValue(&ps, WJB_VALUE, &idval);
2090 
2091  keyval = pushJsonbValue(&ps, WJB_END_OBJECT, NULL);
2092 
2093  jsonb = JsonbValueToJsonb(keyval);
2094 
2095  JsonbInitBinary(&obj, jsonb);
2096 
2097  baseObject = setBaseObject(cxt, &obj, cxt->lastGeneratedObjectId++);
2098 
2099  res = executeNextItem(cxt, jsp, &next, &obj, found, true);
2100 
2101  cxt->baseObject = baseObject;
2102 
2103  if (jperIsError(res))
2104  return res;
2105 
2106  if (res == jperOk && !found)
2107  break;
2108  }
2109 
2110  return res;
2111 }
2112 
2113 /*
2114  * Convert boolean execution status 'res' to a boolean JSON item and execute
2115  * next jsonpath.
2116  */
2117 static JsonPathExecResult
2119  JsonValueList *found, JsonPathBool res)
2120 {
2122  JsonbValue jbv;
2123 
2124  if (!jspGetNext(jsp, &next) && !found)
2125  return jperOk; /* found singleton boolean value */
2126 
2127  if (res == jpbUnknown)
2128  {
2129  jbv.type = jbvNull;
2130  }
2131  else
2132  {
2133  jbv.type = jbvBool;
2134  jbv.val.boolean = res == jpbTrue;
2135  }
2136 
2137  return executeNextItem(cxt, jsp, &next, &jbv, found, true);
2138 }
2139 
2140 /*
2141  * Convert jsonpath's scalar or variable node to actual jsonb value.
2142  *
2143  * If node is a variable then its id returned, otherwise 0 returned.
2144  */
2145 static void
2147  JsonbValue *value)
2148 {
2149  switch (item->type)
2150  {
2151  case jpiNull:
2152  value->type = jbvNull;
2153  break;
2154  case jpiBool:
2155  value->type = jbvBool;
2156  value->val.boolean = jspGetBool(item);
2157  break;
2158  case jpiNumeric:
2159  value->type = jbvNumeric;
2160  value->val.numeric = jspGetNumeric(item);
2161  break;
2162  case jpiString:
2163  value->type = jbvString;
2164  value->val.string.val = jspGetString(item,
2165  &value->val.string.len);
2166  break;
2167  case jpiVariable:
2168  getJsonPathVariable(cxt, item, value);
2169  return;
2170  default:
2171  elog(ERROR, "unexpected jsonpath item type");
2172  }
2173 }
2174 
2175 /*
2176  * Get the value of variable passed to jsonpath executor
2177  */
2178 static void
2180  JsonbValue *value)
2181 {
2182  char *varName;
2183  int varNameLength;
2184  JsonbValue baseObject;
2185  int baseObjectId;
2186 
2188  varName = jspGetString(variable, &varNameLength);
2189 
2190  if (!cxt->vars ||
2191  (baseObjectId = cxt->getVar(cxt->vars, varName, varNameLength, value,
2192  &baseObject)) < 0)
2193  ereport(ERROR,
2194  (errcode(ERRCODE_UNDEFINED_OBJECT),
2195  errmsg("could not find jsonpath variable \"%s\"",
2196  pnstrdup(varName, varNameLength))));
2197 
2198  if (baseObjectId > 0)
2199  setBaseObject(cxt, &baseObject, baseObjectId);
2200 }
2201 
2202 static int
2203 getJsonPathVariableFromJsonb(void *varsJsonb, char *varName, int varNameLength,
2204  JsonbValue *value, JsonbValue *baseObject)
2205 {
2206  Jsonb *vars = varsJsonb;
2207  JsonbValue tmp;
2208  JsonbValue *v;
2209 
2210  if (!varName)
2211  {
2212  if (vars && !JsonContainerIsObject(&vars->root))
2213  {
2214  ereport(ERROR,
2215  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2216  errmsg("\"vars\" argument is not an object"),
2217  errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
2218  }
2219 
2220  return vars ? 1 : 0; /* count of base objects */
2221  }
2222 
2223  tmp.type = jbvString;
2224  tmp.val.string.val = varName;
2225  tmp.val.string.len = varNameLength;
2226 
2227  v = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
2228 
2229  if (!v)
2230  return -1;
2231 
2232  *value = *v;
2233  pfree(v);
2234 
2235  JsonbInitBinary(baseObject, vars);
2236  return 1;
2237 }
2238 
2239 /**************** Support functions for JsonPath execution *****************/
2240 
2241 /*
2242  * Returns the size of an array item, or -1 if item is not an array.
2243  */
2244 static int
2246 {
2247  Assert(jb->type != jbvArray);
2248 
2249  if (jb->type == jbvBinary)
2250  {
2251  JsonbContainer *jbc = jb->val.binary.data;
2252 
2253  if (JsonContainerIsArray(jbc) && !JsonContainerIsScalar(jbc))
2254  return JsonContainerSize(jbc);
2255  }
2256 
2257  return -1;
2258 }
2259 
2260 /* Comparison predicate callback. */
2261 static JsonPathBool
2263 {
2265 
2266  return compareItems(cmp->type, lv, rv, cxt->useTz);
2267 }
2268 
2269 /*
2270  * Perform per-byte comparison of two strings.
2271  */
2272 static int
2273 binaryCompareStrings(const char *s1, int len1,
2274  const char *s2, int len2)
2275 {
2276  int cmp;
2277 
2278  cmp = memcmp(s1, s2, Min(len1, len2));
2279 
2280  if (cmp != 0)
2281  return cmp;
2282 
2283  if (len1 == len2)
2284  return 0;
2285 
2286  return len1 < len2 ? -1 : 1;
2287 }
2288 
2289 /*
2290  * Compare two strings in the current server encoding using Unicode codepoint
2291  * collation.
2292  */
2293 static int
2294 compareStrings(const char *mbstr1, int mblen1,
2295  const char *mbstr2, int mblen2)
2296 {
2297  if (GetDatabaseEncoding() == PG_SQL_ASCII ||
2299  {
2300  /*
2301  * It's known property of UTF-8 strings that their per-byte comparison
2302  * result matches codepoints comparison result. ASCII can be
2303  * considered as special case of UTF-8.
2304  */
2305  return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
2306  }
2307  else
2308  {
2309  char *utf8str1,
2310  *utf8str2;
2311  int cmp,
2312  utf8len1,
2313  utf8len2;
2314 
2315  /*
2316  * We have to convert other encodings to UTF-8 first, then compare.
2317  * Input strings may be not null-terminated and pg_server_to_any() may
2318  * return them "as is". So, use strlen() only if there is real
2319  * conversion.
2320  */
2321  utf8str1 = pg_server_to_any(mbstr1, mblen1, PG_UTF8);
2322  utf8str2 = pg_server_to_any(mbstr2, mblen2, PG_UTF8);
2323  utf8len1 = (mbstr1 == utf8str1) ? mblen1 : strlen(utf8str1);
2324  utf8len2 = (mbstr2 == utf8str2) ? mblen2 : strlen(utf8str2);
2325 
2326  cmp = binaryCompareStrings(utf8str1, utf8len1, utf8str2, utf8len2);
2327 
2328  /*
2329  * If pg_server_to_any() did no real conversion, then we actually
2330  * compared original strings. So, we already done.
2331  */
2332  if (mbstr1 == utf8str1 && mbstr2 == utf8str2)
2333  return cmp;
2334 
2335  /* Free memory if needed */
2336  if (mbstr1 != utf8str1)
2337  pfree(utf8str1);
2338  if (mbstr2 != utf8str2)
2339  pfree(utf8str2);
2340 
2341  /*
2342  * When all Unicode codepoints are equal, return result of binary
2343  * comparison. In some edge cases, same characters may have different
2344  * representations in encoding. Then our behavior could diverge from
2345  * standard. However, that allow us to do simple binary comparison
2346  * for "==" operator, which is performance critical in typical cases.
2347  * In future to implement strict standard conformance, we can do
2348  * normalization of input JSON strings.
2349  */
2350  if (cmp == 0)
2351  return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
2352  else
2353  return cmp;
2354  }
2355 }
2356 
2357 /*
2358  * Compare two SQL/JSON items using comparison operation 'op'.
2359  */
2360 static JsonPathBool
2361 compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2, bool useTz)
2362 {
2363  int cmp;
2364  bool res;
2365 
2366  if (jb1->type != jb2->type)
2367  {
2368  if (jb1->type == jbvNull || jb2->type == jbvNull)
2369 
2370  /*
2371  * Equality and order comparison of nulls to non-nulls returns
2372  * always false, but inequality comparison returns true.
2373  */
2374  return op == jpiNotEqual ? jpbTrue : jpbFalse;
2375 
2376  /* Non-null items of different types are not comparable. */
2377  return jpbUnknown;
2378  }
2379 
2380  switch (jb1->type)
2381  {
2382  case jbvNull:
2383  cmp = 0;
2384  break;
2385  case jbvBool:
2386  cmp = jb1->val.boolean == jb2->val.boolean ? 0 :
2387  jb1->val.boolean ? 1 : -1;
2388  break;
2389  case jbvNumeric:
2390  cmp = compareNumeric(jb1->val.numeric, jb2->val.numeric);
2391  break;
2392  case jbvString:
2393  if (op == jpiEqual)
2394  return jb1->val.string.len != jb2->val.string.len ||
2395  memcmp(jb1->val.string.val,
2396  jb2->val.string.val,
2397  jb1->val.string.len) ? jpbFalse : jpbTrue;
2398 
2399  cmp = compareStrings(jb1->val.string.val, jb1->val.string.len,
2400  jb2->val.string.val, jb2->val.string.len);
2401  break;
2402  case jbvDatetime:
2403  {
2404  bool cast_error;
2405 
2406  cmp = compareDatetime(jb1->val.datetime.value,
2407  jb1->val.datetime.typid,
2408  jb2->val.datetime.value,
2409  jb2->val.datetime.typid,
2410  useTz,
2411  &cast_error);
2412 
2413  if (cast_error)
2414  return jpbUnknown;
2415  }
2416  break;
2417 
2418  case jbvBinary:
2419  case jbvArray:
2420  case jbvObject:
2421  return jpbUnknown; /* non-scalars are not comparable */
2422 
2423  default:
2424  elog(ERROR, "invalid jsonb value type %d", jb1->type);
2425  }
2426 
2427  switch (op)
2428  {
2429  case jpiEqual:
2430  res = (cmp == 0);
2431  break;
2432  case jpiNotEqual:
2433  res = (cmp != 0);
2434  break;
2435  case jpiLess:
2436  res = (cmp < 0);
2437  break;
2438  case jpiGreater:
2439  res = (cmp > 0);
2440  break;
2441  case jpiLessOrEqual:
2442  res = (cmp <= 0);
2443  break;
2444  case jpiGreaterOrEqual:
2445  res = (cmp >= 0);
2446  break;
2447  default:
2448  elog(ERROR, "unrecognized jsonpath operation: %d", op);
2449  return jpbUnknown;
2450  }
2451 
2452  return res ? jpbTrue : jpbFalse;
2453 }
2454 
2455 /* Compare two numerics */
2456 static int
2458 {
2460  NumericGetDatum(a),
2461  NumericGetDatum(b)));
2462 }
2463 
2464 static JsonbValue *
2466 {
2467  JsonbValue *dst = palloc(sizeof(*dst));
2468 
2469  *dst = *src;
2470 
2471  return dst;
2472 }
2473 
2474 /*
2475  * Execute array subscript expression and convert resulting numeric item to
2476  * the integer type with truncation.
2477  */
2478 static JsonPathExecResult
2480  int32 *index)
2481 {
2482  JsonbValue *jbv;
2483  JsonValueList found = {0};
2484  JsonPathExecResult res = executeItem(cxt, jsp, jb, &found);
2485  Datum numeric_index;
2486  bool have_error = false;
2487 
2488  if (jperIsError(res))
2489  return res;
2490 
2491  if (JsonValueListLength(&found) != 1 ||
2492  !(jbv = getScalar(JsonValueListHead(&found), jbvNumeric)))
2494  (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
2495  errmsg("jsonpath array subscript is not a single numeric value"))));
2496 
2497  numeric_index = DirectFunctionCall2(numeric_trunc,
2498  NumericGetDatum(jbv->val.numeric),
2499  Int32GetDatum(0));
2500 
2501  *index = numeric_int4_opt_error(DatumGetNumeric(numeric_index),
2502  &have_error);
2503 
2504  if (have_error)
2506  (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
2507  errmsg("jsonpath array subscript is out of integer range"))));
2508 
2509  return jperOk;
2510 }
2511 
2512 /* Save base object and its id needed for the execution of .keyvalue(). */
2513 static JsonBaseObjectInfo
2515 {
2516  JsonBaseObjectInfo baseObject = cxt->baseObject;
2517 
2518  cxt->baseObject.jbc = jbv->type != jbvBinary ? NULL :
2519  (JsonbContainer *) jbv->val.binary.data;
2520  cxt->baseObject.id = id;
2521 
2522  return baseObject;
2523 }
2524 
2525 static void
2527 {
2528  jvl->singleton = NULL;
2529  jvl->list = NULL;
2530 }
2531 
2532 static void
2534 {
2535  if (jvl->singleton)
2536  {
2537  jvl->list = list_make2(jvl->singleton, jbv);
2538  jvl->singleton = NULL;
2539  }
2540  else if (!jvl->list)
2541  jvl->singleton = jbv;
2542  else
2543  jvl->list = lappend(jvl->list, jbv);
2544 }
2545 
2546 static int
2548 {
2549  return jvl->singleton ? 1 : list_length(jvl->list);
2550 }
2551 
2552 static bool
2554 {
2555  return !jvl->singleton && list_length(jvl->list) <= 0;
2556 }
2557 
2558 static JsonbValue *
2560 {
2561  return jvl->singleton ? jvl->singleton : linitial(jvl->list);
2562 }
2563 
2564 static List *
2566 {
2567  if (jvl->singleton)
2568  return list_make1(jvl->singleton);
2569 
2570  return jvl->list;
2571 }
2572 
2573 static void
2575 {
2576  if (jvl->singleton)
2577  {
2578  it->value = jvl->singleton;
2579  it->list = NIL;
2580  it->next = NULL;
2581  }
2582  else if (jvl->list != NIL)
2583  {
2584  it->value = (JsonbValue *) linitial(jvl->list);
2585  it->list = jvl->list;
2586  it->next = list_second_cell(jvl->list);
2587  }
2588  else
2589  {
2590  it->value = NULL;
2591  it->list = NIL;
2592  it->next = NULL;
2593  }
2594 }
2595 
2596 /*
2597  * Get the next item from the sequence advancing iterator.
2598  */
2599 static JsonbValue *
2601 {
2602  JsonbValue *result = it->value;
2603 
2604  if (it->next)
2605  {
2606  it->value = lfirst(it->next);
2607  it->next = lnext(it->list, it->next);
2608  }
2609  else
2610  {
2611  it->value = NULL;
2612  }
2613 
2614  return result;
2615 }
2616 
2617 /*
2618  * Initialize a binary JsonbValue with the given jsonb container.
2619  */
2620 static JsonbValue *
2622 {
2623  jbv->type = jbvBinary;
2624  jbv->val.binary.data = &jb->root;
2625  jbv->val.binary.len = VARSIZE_ANY_EXHDR(jb);
2626 
2627  return jbv;
2628 }
2629 
2630 /*
2631  * Returns jbv* type of JsonbValue. Note, it never returns jbvBinary as is.
2632  */
2633 static int
2635 {
2636  int type = jb->type;
2637 
2638  if (jb->type == jbvBinary)
2639  {
2640  JsonbContainer *jbc = (void *) jb->val.binary.data;
2641 
2642  /* Scalars should be always extracted during jsonpath execution. */
2644 
2645  if (JsonContainerIsObject(jbc))
2646  type = jbvObject;
2647  else if (JsonContainerIsArray(jbc))
2648  type = jbvArray;
2649  else
2650  elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
2651  }
2652 
2653  return type;
2654 }
2655 
2656 /* Get scalar of given type or NULL on type mismatch */
2657 static JsonbValue *
2659 {
2660  /* Scalars should be always extracted during jsonpath execution. */
2661  Assert(scalar->type != jbvBinary ||
2662  !JsonContainerIsScalar(scalar->val.binary.data));
2663 
2664  return scalar->type == type ? scalar : NULL;
2665 }
2666 
2667 /* Construct a JSON array from the item list */
2668 static JsonbValue *
2670 {
2671  JsonbParseState *ps = NULL;
2673  JsonbValue *jbv;
2674 
2675  pushJsonbValue(&ps, WJB_BEGIN_ARRAY, NULL);
2676 
2677  JsonValueListInitIterator(items, &it);
2678  while ((jbv = JsonValueListNext(items, &it)))
2679  pushJsonbValue(&ps, WJB_ELEM, jbv);
2680 
2681  return pushJsonbValue(&ps, WJB_END_ARRAY, NULL);
2682 }
2683 
2684 /* Check if the timezone required for casting from type1 to type2 is used */
2685 static void
2686 checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
2687 {
2688  if (!useTz)
2689  ereport(ERROR,
2690  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2691  errmsg("cannot convert value from %s to %s without time zone usage",
2692  type1, type2),
2693  errhint("Use *_tz() function for time zone support.")));
2694 }
2695 
2696 /* Convert time datum to timetz datum */
2697 static Datum
2698 castTimeToTimeTz(Datum time, bool useTz)
2699 {
2700  checkTimezoneIsUsedForCast(useTz, "time", "timetz");
2701 
2702  return DirectFunctionCall1(time_timetz, time);
2703 }
2704 
2705 /*
2706  * Compare date to timestamp.
2707  * Note that this doesn't involve any timezone considerations.
2708  */
2709 static int
2710 cmpDateToTimestamp(DateADT date1, Timestamp ts2, bool useTz)
2711 {
2712  return date_cmp_timestamp_internal(date1, ts2);
2713 }
2714 
2715 /*
2716  * Compare date to timestamptz.
2717  */
2718 static int
2719 cmpDateToTimestampTz(DateADT date1, TimestampTz tstz2, bool useTz)
2720 {
2721  checkTimezoneIsUsedForCast(useTz, "date", "timestamptz");
2722 
2723  return date_cmp_timestamptz_internal(date1, tstz2);
2724 }
2725 
2726 /*
2727  * Compare timestamp to timestamptz.
2728  */
2729 static int
2731 {
2732  checkTimezoneIsUsedForCast(useTz, "timestamp", "timestamptz");
2733 
2734  return timestamp_cmp_timestamptz_internal(ts1, tstz2);
2735 }
2736 
2737 /*
2738  * Cross-type comparison of two datetime SQL/JSON items. If items are
2739  * uncomparable *cast_error flag is set, otherwise *cast_error is unset.
2740  * If the cast requires timezone and it is not used, then explicit error is thrown.
2741  */
2742 static int
2743 compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
2744  bool useTz, bool *cast_error)
2745 {
2746  PGFunction cmpfunc;
2747 
2748  *cast_error = false;
2749 
2750  switch (typid1)
2751  {
2752  case DATEOID:
2753  switch (typid2)
2754  {
2755  case DATEOID:
2756  cmpfunc = date_cmp;
2757 
2758  break;
2759 
2760  case TIMESTAMPOID:
2761  return cmpDateToTimestamp(DatumGetDateADT(val1),
2762  DatumGetTimestamp(val2),
2763  useTz);
2764 
2765  case TIMESTAMPTZOID:
2767  DatumGetTimestampTz(val2),
2768  useTz);
2769 
2770  case TIMEOID:
2771  case TIMETZOID:
2772  *cast_error = true; /* uncomparable types */
2773  return 0;
2774 
2775  default:
2776  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2777  typid2);
2778  }
2779  break;
2780 
2781  case TIMEOID:
2782  switch (typid2)
2783  {
2784  case TIMEOID:
2785  cmpfunc = time_cmp;
2786 
2787  break;
2788 
2789  case TIMETZOID:
2790  val1 = castTimeToTimeTz(val1, useTz);
2791  cmpfunc = timetz_cmp;
2792 
2793  break;
2794 
2795  case DATEOID:
2796  case TIMESTAMPOID:
2797  case TIMESTAMPTZOID:
2798  *cast_error = true; /* uncomparable types */
2799  return 0;
2800 
2801  default:
2802  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2803  typid2);
2804  }
2805  break;
2806 
2807  case TIMETZOID:
2808  switch (typid2)
2809  {
2810  case TIMEOID:
2811  val2 = castTimeToTimeTz(val2, useTz);
2812  cmpfunc = timetz_cmp;
2813 
2814  break;
2815 
2816  case TIMETZOID:
2817  cmpfunc = timetz_cmp;
2818 
2819  break;
2820 
2821  case DATEOID:
2822  case TIMESTAMPOID:
2823  case TIMESTAMPTZOID:
2824  *cast_error = true; /* uncomparable types */
2825  return 0;
2826 
2827  default:
2828  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2829  typid2);
2830  }
2831  break;
2832 
2833  case TIMESTAMPOID:
2834  switch (typid2)
2835  {
2836  case DATEOID:
2837  return -cmpDateToTimestamp(DatumGetDateADT(val2),
2838  DatumGetTimestamp(val1),
2839  useTz);
2840 
2841  case TIMESTAMPOID:
2842  cmpfunc = timestamp_cmp;
2843 
2844  break;
2845 
2846  case TIMESTAMPTZOID:
2848  DatumGetTimestampTz(val2),
2849  useTz);
2850 
2851  case TIMEOID:
2852  case TIMETZOID:
2853  *cast_error = true; /* uncomparable types */
2854  return 0;
2855 
2856  default:
2857  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2858  typid2);
2859  }
2860  break;
2861 
2862  case TIMESTAMPTZOID:
2863  switch (typid2)
2864  {
2865  case DATEOID:
2866  return -cmpDateToTimestampTz(DatumGetDateADT(val2),
2867  DatumGetTimestampTz(val1),
2868  useTz);
2869 
2870  case TIMESTAMPOID:
2872  DatumGetTimestampTz(val1),
2873  useTz);
2874 
2875  case TIMESTAMPTZOID:
2876  cmpfunc = timestamp_cmp;
2877 
2878  break;
2879 
2880  case TIMEOID:
2881  case TIMETZOID:
2882  *cast_error = true; /* uncomparable types */
2883  return 0;
2884 
2885  default:
2886  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
2887  typid2);
2888  }
2889  break;
2890 
2891  default:
2892  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u", typid1);
2893  }
2894 
2895  if (*cast_error)
2896  return 0; /* cast error */
2897 
2898  return DatumGetInt32(DirectFunctionCall2(cmpfunc, val1, val2));
2899 }
2900 
2901 /********************Interface to pgsql's executor***************************/
2902 
2903 bool
2905 {
2907  DatumGetJsonbP(jb), !error, NULL,
2908  true);
2909 
2910  Assert(error || !jperIsError(res));
2911 
2912  if (error && jperIsError(res))
2913  *error = true;
2914 
2915  return res == jperOk;
2916 }
2917 
2918 Datum
2919 JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
2920  bool *error, List *vars)
2921 {
2922  JsonbValue *first;
2923  bool wrap;
2924  JsonValueList found = {0};
2926  int count;
2927 
2929  &found, true);
2930 
2931  Assert(error || !jperIsError(res));
2932 
2933  if (error && jperIsError(res))
2934  {
2935  *error = true;
2936  *empty = false;
2937  return (Datum) 0;
2938  }
2939 
2940  count = JsonValueListLength(&found);
2941 
2942  first = count ? JsonValueListHead(&found) : NULL;
2943 
2944  if (!first)
2945  wrap = false;
2946  else if (wrapper == JSW_NONE)
2947  wrap = false;
2948  else if (wrapper == JSW_UNCONDITIONAL)
2949  wrap = true;
2950  else if (wrapper == JSW_CONDITIONAL)
2951  wrap = count > 1 ||
2952  IsAJsonbScalar(first) ||
2953  (first->type == jbvBinary &&
2954  JsonContainerIsScalar(first->val.binary.data));
2955  else
2956  {
2957  elog(ERROR, "unrecognized json wrapper %d", wrapper);
2958  wrap = false;
2959  }
2960 
2961  if (wrap)
2963 
2964  if (count > 1)
2965  {
2966  if (error)
2967  {
2968  *error = true;
2969  return (Datum) 0;
2970  }
2971 
2972  ereport(ERROR,
2973  (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM),
2974  errmsg("JSON path expression in JSON_QUERY should return "
2975  "singleton item without wrapper"),
2976  errhint("use WITH WRAPPER clause to wrap SQL/JSON item "
2977  "sequence into array")));
2978  }
2979 
2980  if (first)
2981  return JsonbPGetDatum(JsonbValueToJsonb(first));
2982 
2983  *empty = true;
2984  return PointerGetDatum(NULL);
2985 }
2986 
2987 JsonbValue *
2988 JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars)
2989 {
2990  JsonbValue *res;
2991  JsonValueList found = {0};
2993  int count;
2994 
2996  &found, true);
2997 
2998  Assert(error || !jperIsError(jper));
2999 
3000  if (error && jperIsError(jper))
3001  {
3002  *error = true;
3003  *empty = false;
3004  return NULL;
3005  }
3006 
3007  count = JsonValueListLength(&found);
3008 
3009  *empty = !count;
3010 
3011  if (*empty)
3012  return NULL;
3013 
3014  if (count > 1)
3015  {
3016  if (error)
3017  {
3018  *error = true;
3019  return NULL;
3020  }
3021 
3022  ereport(ERROR,
3023  (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM),
3024  errmsg("JSON path expression in JSON_VALUE should return "
3025  "singleton scalar item")));
3026  }
3027 
3028  res = JsonValueListHead(&found);
3029 
3030  if (res->type == jbvBinary &&
3031  JsonContainerIsScalar(res->val.binary.data))
3032  JsonbExtractScalar(res->val.binary.data, res);
3033 
3034  if (!IsAJsonbScalar(res))
3035  {
3036  if (error)
3037  {
3038  *error = true;
3039  return NULL;
3040  }
3041 
3042  ereport(ERROR,
3043  (errcode(ERRCODE_SQL_JSON_SCALAR_REQUIRED),
3044  errmsg("JSON path expression in JSON_VALUE should return "
3045  "singleton scalar item")));
3046  }
3047 
3048  if (res->type == jbvNull)
3049  return NULL;
3050 
3051  return res;
3052 }
3053 
3054 static void
3056 {
3057  jbv->type = jbvNumeric;
3058  jbv->val.numeric = DatumGetNumeric(num);
3059 }
3060 
3061 void
3063 {
3064  switch (typid)
3065  {
3066  case BOOLOID:
3067  res->type = jbvBool;
3068  res->val.boolean = DatumGetBool(val);
3069  break;
3070  case NUMERICOID:
3072  break;
3073  case INT2OID:
3075  break;
3076  case INT4OID:
3078  break;
3079  case INT8OID:
3081  break;
3082  case FLOAT4OID:
3084  break;
3085  case FLOAT8OID:
3087  break;
3088  case TEXTOID:
3089  case VARCHAROID:
3090  res->type = jbvString;
3091  res->val.string.val = VARDATA_ANY(val);
3092  res->val.string.len = VARSIZE_ANY_EXHDR(val);
3093  break;
3094  case DATEOID:
3095  case TIMEOID:
3096  case TIMETZOID:
3097  case TIMESTAMPOID:
3098  case TIMESTAMPTZOID:
3099  res->type = jbvDatetime;
3100  res->val.datetime.value = val;
3101  res->val.datetime.typid = typid;
3102  res->val.datetime.typmod = typmod;
3103  res->val.datetime.tz = 0;
3104  break;
3105  case JSONBOID:
3106  {
3107  JsonbValue *jbv = res;
3108  Jsonb *jb = DatumGetJsonbP(val);
3109 
3110  if (JsonContainerIsScalar(&jb->root))
3111  {
3113 
3114  res = JsonbExtractScalar(&jb->root, jbv);
3115  Assert(res);
3116  }
3117  else
3118  JsonbInitBinary(jbv, jb);
3119  break;
3120  }
3121  case JSONOID:
3122  {
3123  text *txt = DatumGetTextP(val);
3124  char *str = text_to_cstring(txt);
3125  Jsonb *jb =
3127  CStringGetDatum(str)));
3128 
3129  pfree(str);
3130 
3131  JsonItemFromDatum(JsonbPGetDatum(jb), JSONBOID, -1, res);
3132  break;
3133  }
3134  default:
3135  ereport(ERROR,
3136  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3137  errmsg("only bool, numeric, and text types could be "
3138  "casted to supported jsonpath types.")));
3139  }
3140 }
3141 
3142 /************************ JSON_TABLE functions ***************************/
3143 
3144 /*
3145  * Returns private data from executor state. Ensure validity by check with
3146  * MAGIC number.
3147  */
3148 static inline JsonTableContext *
3150 {
3151  JsonTableContext *result;
3152 
3153  if (!IsA(state, TableFuncScanState))
3154  elog(ERROR, "%s called with invalid TableFuncScanState", fname);
3155  result = (JsonTableContext *) state->opaque;
3156  if (result->magic != JSON_TABLE_CONTEXT_MAGIC)
3157  elog(ERROR, "%s called with invalid TableFuncScanState", fname);
3158 
3159  return result;
3160 }
3161 
3162 /* Recursively initialize JSON_TABLE scan state */
3163 static void
3165  JsonTableParent *node, JsonTableScanState *parent,
3166  List *args, MemoryContext mcxt)
3167 {
3168  int i;
3169 
3170  scan->parent = parent;
3171  scan->outerJoin = node->outerJoin;
3172  scan->errorOnError = node->errorOnError;
3173  scan->path = DatumGetJsonPathP(node->path->constvalue);
3174  scan->args = args;
3175  scan->mcxt = AllocSetContextCreate(mcxt, "JsonTableContext",
3177  scan->nested = node->child ?
3178  JsonTableInitPlanState(cxt, node->child, scan) : NULL;
3179  scan->current = PointerGetDatum(NULL);
3180  scan->currentIsNull = true;
3181 
3182  for (i = node->colMin; i <= node->colMax; i++)
3183  cxt->colexprs[i].scan = scan;
3184 }
3185 
3186 /* Recursively initialize JSON_TABLE scan state */
3187 static JsonTableJoinState *
3189  JsonTableScanState *parent)
3190 {
3191  JsonTableJoinState *state = palloc0(sizeof(*state));
3192 
3193  if (IsA(plan, JsonTableSibling))
3194  {
3196 
3197  state->is_join = true;
3198  state->u.join.cross = join->cross;
3199  state->u.join.left = JsonTableInitPlanState(cxt, join->larg, parent);
3200  state->u.join.right = JsonTableInitPlanState(cxt, join->rarg, parent);
3201  }
3202  else
3203  {
3204  JsonTableParent *node = castNode(JsonTableParent, plan);
3205 
3206  state->is_join = false;
3207 
3208  JsonTableInitScanState(cxt, &state->u.scan, node, parent,
3209  parent->args, parent->mcxt);
3210  }
3211 
3212  return state;
3213 }
3214 
3215 /*
3216  * JsonTableInitOpaque
3217  * Fill in TableFuncScanState->opaque for JsonTable processor
3218  */
3219 static void
3221 {
3222  JsonTableContext *cxt;
3223  PlanState *ps = &state->ss.ps;
3225  TableFunc *tf = tfs->tablefunc;
3226  JsonExpr *ci = castNode(JsonExpr, tf->docexpr);
3228  List *args = NIL;
3229  ListCell *lc;
3230  int i;
3231 
3232  cxt = palloc0(sizeof(JsonTableContext));
3234 
3235  if (ci->passing_values)
3236  {
3237  ListCell *exprlc;
3238  ListCell *namelc;
3239 
3240  forboth(exprlc, ci->passing_values,
3241  namelc, ci->passing_names)
3242  {
3243  Expr *expr = (Expr *) lfirst(exprlc);
3244  String *name = lfirst_node(String, namelc);
3245  JsonPathVariableEvalContext *var = palloc(sizeof(*var));
3246 
3247  var->name = pstrdup(name->sval);
3248  var->typid = exprType((Node *) expr);
3249  var->typmod = exprTypmod((Node *) expr);
3250  var->estate = ExecInitExpr(expr, ps);
3251  var->econtext = ps->ps_ExprContext;
3252  var->mcxt = CurrentMemoryContext;
3253  var->evaluated = false;
3254  var->value = (Datum) 0;
3255  var->isnull = true;
3256 
3257  args = lappend(args, var);
3258  }
3259  }
3260 
3261  cxt->colexprs = palloc(sizeof(*cxt->colexprs) *
3262  list_length(tf->colvalexprs));
3263 
3264  JsonTableInitScanState(cxt, &cxt->root, root, NULL, args,
3266 
3267  i = 0;
3268 
3269  foreach(lc, tf->colvalexprs)
3270  {
3271  Expr *expr = lfirst(lc);
3272 
3273  cxt->colexprs[i].expr =
3274  ExecInitExprWithCaseValue(expr, ps,
3275  &cxt->colexprs[i].scan->current,
3276  &cxt->colexprs[i].scan->currentIsNull);
3277 
3278  i++;
3279  }
3280 
3281  state->opaque = cxt;
3282 }
3283 
3284 /* Reset scan iterator to the beginning of the item list */
3285 static void
3287 {
3288  JsonValueListInitIterator(&scan->found, &scan->iter);
3289  scan->current = PointerGetDatum(NULL);
3290  scan->currentIsNull = true;
3291  scan->advanceNested = false;
3292  scan->ordinal = 0;
3293 }
3294 
3295 /* Reset context item of a scan, execute JSON path and reset a scan */
3296 static void
3298 {
3299  MemoryContext oldcxt;
3301  Jsonb *js = (Jsonb *) DatumGetJsonbP(item);
3302 
3303  JsonValueListClear(&scan->found);
3304 
3306 
3307  oldcxt = MemoryContextSwitchTo(scan->mcxt);
3308 
3309  res = executeJsonPath(scan->path, scan->args, EvalJsonPathVar, js,
3310  scan->errorOnError, &scan->found, false /* FIXME */ );
3311 
3312  MemoryContextSwitchTo(oldcxt);
3313 
3314  if (jperIsError(res))
3315  {
3316  Assert(!scan->errorOnError);
3317  JsonValueListClear(&scan->found); /* EMPTY ON ERROR case */
3318  }
3319 
3320  JsonTableRescan(scan);
3321 }
3322 
3323 /*
3324  * JsonTableSetDocument
3325  * Install the input document
3326  */
3327 static void
3329 {
3330  JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableSetDocument");
3331 
3333 }
3334 
3335 /* Recursively reset scan and its child nodes */
3336 static void
3338 {
3339  if (state->is_join)
3340  {
3341  JsonTableRescanRecursive(state->u.join.left);
3342  JsonTableRescanRecursive(state->u.join.right);
3343  state->u.join.advanceRight = false;
3344  }
3345  else
3346  {
3347  JsonTableRescan(&state->u.scan);
3348  if (state->u.scan.nested)
3349  JsonTableRescanRecursive(state->u.scan.nested);
3350  }
3351 }
3352 
3353 /*
3354  * Fetch next row from a cross/union joined scan.
3355  *
3356  * Returns false at the end of a scan, true otherwise.
3357  */
3358 static bool
3360 {
3361  if (!state->is_join)
3362  return JsonTableNextRow(&state->u.scan);
3363 
3364  if (state->u.join.advanceRight)
3365  {
3366  /* fetch next inner row */
3367  if (JsonTableNextJoinRow(state->u.join.right))
3368  return true;
3369 
3370  /* inner rows are exhausted */
3371  if (state->u.join.cross)
3372  state->u.join.advanceRight = false; /* next outer row */
3373  else
3374  return false; /* end of scan */
3375  }
3376 
3377  while (!state->u.join.advanceRight)
3378  {
3379  /* fetch next outer row */
3380  bool left = JsonTableNextJoinRow(state->u.join.left);
3381 
3382  if (state->u.join.cross)
3383  {
3384  if (!left)
3385  return false; /* end of scan */
3386 
3387  JsonTableRescanRecursive(state->u.join.right);
3388 
3389  if (!JsonTableNextJoinRow(state->u.join.right))
3390  continue; /* next outer row */
3391 
3392  state->u.join.advanceRight = true; /* next inner row */
3393  }
3394  else if (!left)
3395  {
3396  if (!JsonTableNextJoinRow(state->u.join.right))
3397  return false; /* end of scan */
3398 
3399  state->u.join.advanceRight = true; /* next inner row */
3400  }
3401 
3402  break;
3403  }
3404 
3405  return true;
3406 }
3407 
3408 /* Recursively set 'reset' flag of scan and its child nodes */
3409 static void
3411 {
3412  if (state->is_join)
3413  {
3414  JsonTableJoinReset(state->u.join.left);
3415  JsonTableJoinReset(state->u.join.right);
3416  state->u.join.advanceRight = false;
3417  }
3418  else
3419  {
3420  state->u.scan.reset = true;
3421  state->u.scan.advanceNested = false;
3422 
3423  if (state->u.scan.nested)
3424  JsonTableJoinReset(state->u.scan.nested);
3425  }
3426 }
3427 
3428 /*
3429  * Fetch next row from a simple scan with outer/inner joined nested subscans.
3430  *
3431  * Returns false at the end of a scan, true otherwise.
3432  */
3433 static bool
3435 {
3436  /* reset context item if requested */
3437  if (scan->reset)
3438  {
3439  Assert(!scan->parent->currentIsNull);
3441  scan->reset = false;
3442  }
3443 
3444  if (scan->advanceNested)
3445  {
3446  /* fetch next nested row */
3447  scan->advanceNested = JsonTableNextJoinRow(scan->nested);
3448 
3449  if (scan->advanceNested)
3450  return true;
3451  }
3452 
3453  for (;;)
3454  {
3455  /* fetch next row */
3456  JsonbValue *jbv = JsonValueListNext(&scan->found, &scan->iter);
3457  MemoryContext oldcxt;
3458 
3459  if (!jbv)
3460  {
3461  scan->current = PointerGetDatum(NULL);
3462  scan->currentIsNull = true;
3463  return false; /* end of scan */
3464  }
3465 
3466  /* set current row item */
3467  oldcxt = MemoryContextSwitchTo(scan->mcxt);
3469  scan->currentIsNull = false;
3470  MemoryContextSwitchTo(oldcxt);
3471 
3472  scan->ordinal++;
3473 
3474  if (!scan->nested)
3475  break;
3476 
3477  JsonTableJoinReset(scan->nested);
3478 
3479  scan->advanceNested = JsonTableNextJoinRow(scan->nested);
3480 
3481  if (scan->advanceNested || scan->outerJoin)
3482  break;
3483  }
3484 
3485  return true;
3486 }
3487 
3488 /*
3489  * JsonTableFetchRow
3490  * Prepare the next "current" tuple for upcoming GetValue calls.
3491  * Returns FALSE if the row-filter expression returned no more rows.
3492  */
3493 static bool
3495 {
3496  JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableFetchRow");
3497 
3498  if (cxt->empty)
3499  return false;
3500 
3501  return JsonTableNextRow(&cxt->root);
3502 }
3503 
3504 /*
3505  * JsonTableGetValue
3506  * Return the value for column number 'colnum' for the current row.
3507  *
3508  * This leaks memory, so be sure to reset often the context in which it's
3509  * called.
3510  */
3511 static Datum
3513  Oid typid, int32 typmod, bool *isnull)
3514 {
3515  JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableGetValue");
3516  ExprContext *econtext = state->ss.ps.ps_ExprContext;
3517  ExprState *estate = cxt->colexprs[colnum].expr;
3518  JsonTableScanState *scan = cxt->colexprs[colnum].scan;
3519  Datum result;
3520 
3521  if (scan->currentIsNull) /* NULL from outer/union join */
3522  {
3523  result = (Datum) 0;
3524  *isnull = true;
3525  }
3526  else if (estate) /* regular column */
3527  {
3528  result = ExecEvalExpr(estate, econtext, isnull);
3529  }
3530  else
3531  {
3532  result = Int32GetDatum(scan->ordinal); /* ordinality column */
3533  *isnull = false;
3534  }
3535 
3536  return result;
3537 }
3538 
3539 /*
3540  * JsonTableDestroyOpaque
3541  */
3542 static void
3544 {
3545  JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableDestroyOpaque");
3546 
3547  /* not valid anymore */
3548  cxt->magic = 0;
3549 
3550  state->opaque = NULL;
3551 }
3552 
3554 {
3557  NULL,
3558  NULL,
3559  NULL,
3563 };
int32 numeric_int4_opt_error(Numeric num, bool *have_error)
Definition: numeric.c:4223
Datum float8_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4392
Datum numeric_cmp(PG_FUNCTION_ARGS)
Definition: numeric.c:2316
Numeric numeric_mod_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:3285
Numeric numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:3061
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4137
Datum float4_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4485
Datum int4_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4215
Datum numeric_uminus(PG_FUNCTION_ARGS)
Definition: numeric.c:1339
Datum numeric_ceil(PG_FUNCTION_ARGS)
Definition: numeric.c:1558
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:735
Datum numeric_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:1511
Numeric numeric_sub_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:2862
Numeric numeric_mul_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:2940
Datum int2_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4343
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition: numeric.c:1312
Datum int8_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4303
Numeric numeric_add_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:2784
Datum numeric_floor(PG_FUNCTION_ARGS)
Definition: numeric.c:1586
Datum timestamp_cmp(PG_FUNCTION_ARGS)
Definition: timestamp.c:2171
int32 timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
Definition: timestamp.c:2226
static int32 next
Definition: blutils.c:219
unsigned int uint32
Definition: c.h:441
#define Min(x, y)
Definition: c.h:986
#define PG_UINT32_MAX
Definition: c.h:525
signed int int32
Definition: c.h:429
#define lengthof(array)
Definition: c.h:734
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:155
int64 Timestamp
Definition: timestamp.h:38
int64 TimestampTz
Definition: timestamp.h:39
int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2)
Definition: date.c:736
Datum date_cmp(PG_FUNCTION_ARGS)
Definition: date.c:430
Datum time_cmp(PG_FUNCTION_ARGS)
Definition: date.c:1722
Datum timetz_cmp(PG_FUNCTION_ARGS)
Definition: date.c:2498
Datum time_timetz(PG_FUNCTION_ARGS)
Definition: date.c:2790
int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2)
Definition: date.c:816
int32 DateADT
Definition: date.h:23
#define DatumGetDateADT(X)
Definition: date.h:53
struct cursor * cur
Definition: ecpg.c:28
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errhint(const char *fmt,...)
Definition: elog.c:1151
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define ereport(elevel,...)
Definition: elog.h:143
const char * name
Definition: encode.c:561
int EvalJsonPathVar(void *cxt, char *varName, int varNameLen, JsonbValue *val, JsonbValue *baseObject)
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:160
ExprState * ExecInitExprWithCaseValue(Expr *node, PlanState *parent, Datum *caseval, bool *casenull)
Definition: execExpr.c:184
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:320
double float8in_internal_opt_error(char *num, char **endptr_p, const char *type_name, const char *orig_string, bool *have_error)
Definition: float.c:380
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1692
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:633
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:631
#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 DatumGetTextP(X)
Definition: fmgr.h:332
#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, bool *have_error)
Definition: formatting.c:4324
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:299
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:303
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:305
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:301
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:323
static struct @151 value
long val
Definition: informix.c:664
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
Datum jsonb_in(PG_FUNCTION_ARGS)
Definition: jsonb.c:76
bool JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
Definition: jsonb.c:2027
const char * JsonbTypeName(JsonbValue *jbv)
Definition: jsonb.c:178
jbvType
Definition: jsonb.h:234
@ jbvObject
Definition: jsonb.h:242
@ jbvNumeric
Definition: jsonb.h:238
@ jbvBool
Definition: jsonb.h:239
@ jbvArray
Definition: jsonb.h:241
@ jbvBinary
Definition: jsonb.h:244
@ jbvNull
Definition: jsonb.h:236
@ jbvDatetime
Definition: jsonb.h:252
@ jbvString
Definition: jsonb.h:237
#define JsonContainerIsScalar(jc)
Definition: jsonb.h:215
#define JsonContainerIsArray(jc)
Definition: jsonb.h:217
#define JsonContainerSize(jc)
Definition: jsonb.h:214
#define PG_GETARG_JSONB_P_COPY(x)
Definition: jsonb.h:75
#define IsAJsonbScalar(jsonbval)
Definition: jsonb.h:305
#define JsonbPGetDatum(p)
Definition: jsonb.h:73
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:76
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:74
#define JsonContainerIsObject(jc)
Definition: jsonb.h:216
#define DatumGetJsonbP(d)
Definition: jsonb.h:71
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:210
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:998
void jspGetArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:929
void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
Definition: jsonpath.c:849
bool jspGetBool(JsonPathItem *v)
Definition: jsonpath.c:1040
void jspInit(JsonPathItem *v, JsonPath *js)
Definition: jsonpath.c:839
const char * jspOperationName(JsonPathItemType type)
Definition: jsonpath.c:724
Numeric jspGetNumeric(JsonPathItem *v)
Definition: jsonpath.c:1048
bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to, int i)
Definition: jsonpath.c:1068
bool jspGetNext(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:943
void jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1019
char * jspGetString(JsonPathItem *v, int32 *len)
Definition: jsonpath.c:1056
int jspConvertRegexFlags(uint32 xflags)
#define DatumGetJsonPathP(d)
Definition: jsonpath.h:35
#define jspHasNext(jsp)
Definition: jsonpath.h:167
#define PG_GETARG_JSONPATH_P(x)
Definition: jsonpath.h:37
#define PG_GETARG_JSONPATH_P_COPY(x)
Definition: jsonpath.h:38
@ jpiAdd
Definition: jsonpath.h:62
@ jpiString
Definition: jsonpath.h:49
@ jpiAbs
Definition: jsonpath.h:81
@ jpiIndexArray
Definition: jsonpath.h:71
@ jpiAny
Definition: jsonpath.h:72
@ jpiDatetime
Definition: jsonpath.h:85
@ jpiBool
Definition: jsonpath.h:51
@ jpiType
Definition: jsonpath.h:79
@ jpiFloor
Definition: jsonpath.h:82
@ jpiAnyArray
Definition: jsonpath.h:69
@ jpiExists
Definition: jsonpath.h:78
@ jpiSize
Definition: jsonpath.h:80
@ jpiSub
Definition: jsonpath.h:63
@ jpiNotEqual
Definition: jsonpath.h:57
@ jpiMul
Definition: jsonpath.h:64
@ jpiVariable
Definition: jsonpath.h:76
@ jpiNot
Definition: jsonpath.h:54
@ jpiGreaterOrEqual
Definition: jsonpath.h:61
@ jpiPlus
Definition: jsonpath.h:67
@ jpiDouble
Definition: jsonpath.h:84
@ jpiGreater
Definition: jsonpath.h:59
@ jpiAnd
Definition: jsonpath.h:52
@ jpiStartsWith
Definition: jsonpath.h:89
@ jpiOr
Definition: jsonpath.h:53
@ jpiMod
Definition: jsonpath.h:66
@ jpiLikeRegex
Definition: jsonpath.h:90
@ jpiRoot
Definition: jsonpath.h:75
@ jpiFilter
Definition: jsonpath.h:77
@ jpiNull
Definition: jsonpath.h:48
@ jpiLess
Definition: jsonpath.h:58
@ jpiCurrent
Definition: jsonpath.h:74
@ jpiEqual
Definition: jsonpath.h:56
@ jpiKey
Definition: jsonpath.h:73
@ jpiDiv
Definition: jsonpath.h:65
@ jpiLast
Definition: jsonpath.h:88
@ jpiMinus
Definition: jsonpath.h:68
@ jpiLessOrEqual
Definition: jsonpath.h:60
@ jpiCeiling
Definition: jsonpath.h:83
@ jpiIsUnknown
Definition: jsonpath.h:55
@ jpiKeyValue
Definition: jsonpath.h:86
@ jpiNumeric
Definition: jsonpath.h:50
@ jpiAnyKey
Definition: jsonpath.h:70
#define JSONPATH_LAX
Definition: jsonpath.h:32
static JsonPathBool executeComparison(JsonPathItem *cmp, JsonbValue *lv, JsonbValue *rv, void *p)
static Datum jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz)
static JsonTableContext * GetJsonTableContext(TableFuncScanState *state, const char *fname)
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 bool JsonTableNextRow(JsonTableScanState *scan)
static void JsonTableRescan(JsonTableScanState *scan)
Datum jsonb_path_query_first(PG_FUNCTION_ARGS)
static void JsonTableSetDocument(TableFuncScanState *state, Datum value)
static Datum jsonb_path_query_array_internal(FunctionCallInfo fcinfo, bool tz)
void JsonItemFromDatum(Datum val, Oid typid, int32 typmod, JsonbValue *res)
static JsonPathExecResult executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, BinaryArithmFunc func, JsonValueList *found)
Datum JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty, bool *error, List *vars)
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 getJsonPathVariableFromJsonb(void *varsJsonb, char *varName, int varNameLen, JsonbValue *val, JsonbValue *baseObject)
static int compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2, bool useTz, bool *have_error)
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)
int(* JsonPathVarCallback)(void *vars, char *varName, int varNameLen, JsonbValue *val, JsonbValue *baseObject)
Definition: jsonpath_exec.c:93
Datum jsonb_path_match_opr(PG_FUNCTION_ARGS)
JsonPathBool(* JsonPathPredicateCallback)(JsonPathItem *jsp, JsonbValue *larg, JsonbValue *rarg, void *param)
bool JsonPathExists(Datum jb, JsonPath *jp, List *vars, bool *error)
static void JsonValueListInitIterator(const JsonValueList *jvl, JsonValueListIterator *it)
static JsonPathBool executeNestedBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb)
static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars, JsonPathVarCallback getVar, Jsonb *json, bool throwErrors, JsonValueList *result, bool useTz)
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 void JsonTableDestroyOpaque(TableFuncScanState *state)
static void JsonValueListClear(JsonValueList *jvl)
static void JsonTableInitOpaque(TableFuncScanState *state, int natts)
static void JsonTableInitScanState(JsonTableContext *cxt, JsonTableScanState *scan, JsonTableParent *node, JsonTableScanState *parent, List *args, MemoryContext mcxt)
static bool JsonTableNextJoinRow(JsonTableJoinState *state)
static JsonPathExecResult executeNextItem(JsonPathExecContext *cxt, JsonPathItem *cur, JsonPathItem *next, JsonbValue *v, JsonValueList *found, bool copy)
#define JSON_TABLE_CONTEXT_MAGIC
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 void JsonTableJoinReset(JsonTableJoinState *state)
static JsonPathBool executeLikeRegex(JsonPathItem *jsp, JsonbValue *str, JsonbValue *rarg, void *param)
static void JsonTableResetContextItem(JsonTableScanState *scan, Datum item)
static int JsonValueListLength(const JsonValueList *jvl)
static bool JsonValueListIsEmpty(JsonValueList *jvl)
static JsonTableJoinState * JsonTableInitPlanState(JsonTableContext *cxt, Node *plan, JsonTableScanState *parent)
#define jspIgnoreStructuralErrors(cxt)
JsonPathExecResult
@ jperError
@ jperNotFound
@ jperOk
struct JsonTableContext JsonTableContext
struct JsonLikeRegexContext JsonLikeRegexContext
static void JsonbValueInitNumericDatum(JsonbValue *jbv, Datum num)
static int compareNumeric(Numeric a, Numeric b)
static Datum JsonTableGetValue(TableFuncScanState *state, int colnum, Oid typid, int32 typmod, bool *isnull)
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 void getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable, JsonbValue *value)
static JsonbValue * JsonValueListHead(JsonValueList *jvl)
static void JsonTableRescanRecursive(JsonTableJoinState *state)
Datum jsonb_path_exists_tz(PG_FUNCTION_ARGS)
static bool JsonTableFetchRow(TableFuncScanState *state)
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)
const TableFuncRoutine JsonbTableRoutine
JsonbValue * JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars)
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:336
List * list_delete_first(List *list)
Definition: list.c:902
int GetDatabaseEncoding(void)
Definition: mbutils.c:1210
char * pg_server_to_any(const char *s, int len, int encoding)
Definition: mbutils.c:749
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1316
char * pstrdup(const char *in)
Definition: mcxt.c:1305
void pfree(void *pointer)
Definition: mcxt.c:1175
MemoryContext TopMemoryContext
Definition: mcxt.c:48
void * palloc0(Size size)
Definition: mcxt.c:1099
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void * palloc(Size size)
Definition: mcxt.c:1068
void MemoryContextResetOnly(MemoryContext context)
Definition: mcxt.c:162
#define AllocSetContextCreate
Definition: memutils.h:173
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:286
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
#define castNode(_type_, nodeptr)
Definition: nodes.h:642
#define DatumGetNumeric(X)
Definition: numeric.h:59
#define NumericGetDatum(X)
Definition: numeric.h:61
struct NumericData * Numeric
Definition: numeric.h:53
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define lfirst(lc)
Definition: pg_list.h:169
#define lfirst_node(type, lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:149
#define NIL
Definition: pg_list.h:65
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:446
#define list_make1(x1)
Definition: pg_list.h:206
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
#define linitial(l)
Definition: pg_list.h:174
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
#define list_make2(x1, x2)
Definition: pg_list.h:208
static ListCell * list_second_cell(const List *l)
Definition: pg_list.h:139
@ PG_SQL_ASCII
Definition: pg_wchar.h:224
@ PG_UTF8
Definition: pg_wchar.h:230
void check_stack_depth(void)
Definition: postgres.c:3500
#define CStringGetDatum(X)
Definition: postgres.h:622
uintptr_t Datum
Definition: postgres.h:411
#define DatumGetBool(X)
Definition: postgres.h:437
#define VARDATA_ANY(PTR)
Definition: postgres.h:361
#define DatumGetInt32(X)
Definition: postgres.h:516
#define Int32GetDatum(X)
Definition: postgres.h:523
#define DatumGetCString(X)
Definition: postgres.h:610
#define PointerGetDatum(X)
Definition: postgres.h:600
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:354
unsigned int Oid
Definition: postgres_ext.h:31
char * c
char * s1
char * s2
JsonWrapper
Definition: primnodes.h:1306
@ JSW_UNCONDITIONAL
Definition: primnodes.h:1309
@ JSW_CONDITIONAL
Definition: primnodes.h:1308
@ JSW_NONE
Definition: primnodes.h:1307
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:747
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:344
static void error(void)
Definition: sql-dyntest.c:147
Datum constvalue
Definition: primnodes.h:228
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
JsonbContainer * jbc
Definition: jsonpath_exec.c:89
List * passing_values
Definition: primnodes.h:1459
List * passing_names
Definition: primnodes.h:1458
JsonPathVarCallback getVar
JsonbValue * current
JsonBaseObjectInfo baseObject
char * base
Definition: jsonpath.h:119
struct JsonPathItem::@136::@141 like_regex
int32 arg
Definition: jsonpath.h:131
JsonPathItemType type
Definition: jsonpath.h:110
struct JsonPathItem::@136::@139 anybounds
struct JsonPathItem::@136::@138 array
union JsonPathItem::@136 content
struct ExprState * estate
Definition: jsonpath.h:266
struct ExprContext * econtext
Definition: jsonpath.h:265
uint32 header
Definition: jsonpath.h:27
ExprState * expr
struct JsonTableContext::@27 * colexprs
JsonTableScanState * scan
JsonTableScanState root
struct JsonTableJoinState::@25::@26 join
union JsonTableJoinState::@25 u
JsonTableScanState scan
JsonTableJoinState * left
JsonTableJoinState * right
JsonTableJoinState * nested
JsonValueListIterator iter
MemoryContext mcxt
JsonValueList found
JsonTableScanState * parent
JsonbValue * singleton
uint32 header
Definition: jsonb.h:200
enum jbvType type
Definition: jsonb.h:263
char * val
Definition: jsonb.h:272
Definition: jsonb.h:221
JsonbContainer root
Definition: jsonb.h:223
Definition: pg_list.h:51
Definition: nodes.h:574
Plan * plan
Definition: execnodes.h:998
ExprContext * ps_ExprContext
Definition: execnodes.h:1037
Definition: value.h:58
TableFunc * tablefunc
Definition: plannodes.h:591
List * colvalexprs
Definition: primnodes.h:102
Node * docexpr
Definition: primnodes.h:94
Node * plan
Definition: primnodes.h:104
Definition: type.h:110
Definition: type.h:90
int binary
Definition: libpq-int.h:180
Definition: regguts.h:318
enum ECPGttype type
Definition: c.h:622
Definition: regcomp.c:238
#define DatumGetTimestamp(X)
Definition: timestamp.h:27
#define DatumGetTimestampTz(X)
Definition: timestamp.h:28
char * text_to_cstring(const text *t)
Definition: varlena.c:221
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:200
text * cstring_to_text(const char *s)
Definition: varlena.c:188