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-2024, 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 "miscadmin.h"
67 #include "nodes/miscnodes.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/float.h"
74 #include "utils/formatting.h"
75 #include "utils/jsonpath.h"
76 #include "utils/lsyscache.h"
77 #include "utils/memutils.h"
78 #include "utils/timestamp.h"
79 
80 /*
81  * Represents "base object" and it's "id" for .keyvalue() evaluation.
82  */
83 typedef struct JsonBaseObjectInfo
84 {
86  int id;
88 
89 /* Callbacks for executeJsonPath() */
90 typedef JsonbValue *(*JsonPathGetVarCallback) (void *vars, char *varName, int varNameLen,
91  JsonbValue *baseObject, int *baseObjectId);
92 typedef int (*JsonPathCountVarsCallback) (void *vars);
93 
94 /*
95  * Context of jsonpath execution.
96  */
97 typedef struct JsonPathExecContext
98 {
99  void *vars; /* variables to substitute into jsonpath */
100  JsonPathGetVarCallback getVar; /* callback to extract a given variable
101  * from 'vars' */
102  JsonbValue *root; /* for $ evaluation */
103  JsonbValue *current; /* for @ evaluation */
104  JsonBaseObjectInfo baseObject; /* "base object" for .keyvalue()
105  * evaluation */
106  int lastGeneratedObjectId; /* "id" counter for .keyvalue()
107  * evaluation */
108  int innermostArraySize; /* for LAST array index evaluation */
109  bool laxMode; /* true for "lax" mode, false for "strict"
110  * mode */
111  bool ignoreStructuralErrors; /* with "true" structural errors such
112  * as absence of required json item or
113  * unexpected json item type are
114  * ignored */
115  bool throwErrors; /* with "false" all suppressible errors are
116  * suppressed */
117  bool useTz;
119 
120 /* Context for LIKE_REGEX execution. */
121 typedef struct JsonLikeRegexContext
122 {
124  int cflags;
126 
127 /* Result of jsonpath predicate evaluation */
128 typedef enum JsonPathBool
129 {
130  jpbFalse = 0,
131  jpbTrue = 1,
132  jpbUnknown = 2
134 
135 /* Result of jsonpath expression evaluation */
136 typedef enum JsonPathExecResult
137 {
138  jperOk = 0,
140  jperError = 2
142 
143 #define jperIsError(jper) ((jper) == jperError)
144 
145 /*
146  * List of jsonb values with shortcut for single-value list.
147  */
148 typedef struct JsonValueList
149 {
153 
154 typedef struct JsonValueListIterator
155 {
160 
161 /* Structures for JSON_TABLE execution */
162 
163 /*
164  * Struct holding the result of jsonpath evaluation, to be used as source row
165  * for JsonTableGetValue() which in turn computes the values of individual
166  * JSON_TABLE columns.
167  */
169 {
171  bool isnull;
173 
174 /*
175  * State of evaluation of row pattern derived by applying jsonpath given in
176  * a JsonTablePlan to an input document given in the parent TableFunc.
177  */
178 typedef struct JsonTablePlanState
179 {
180  /* Original plan */
182 
183  /* The following fields are only valid for JsonTablePathScan plans */
184 
185  /* jsonpath to evaluate against the input doc to get the row pattern */
187 
188  /*
189  * Memory context to use when evaluating the row pattern from the jsonpath
190  */
192 
193  /* PASSING arguments passed to jsonpath executor */
195 
196  /* List and iterator of jsonpath result values */
199 
200  /* Currently selected row for JsonTableGetValue() to use */
202 
203  /* Counter for ORDINAL columns */
204  int ordinal;
205 
206  /* Nested plan, if any */
208 
209  /* Left sibling, if any */
211 
212  /* Right sibling, if any */
214 
215  /* Parent plan, if this is a nested plan */
218 
219 /* Random number to identify JsonTableExecContext for sanity checking */
220 #define JSON_TABLE_EXEC_CONTEXT_MAGIC 418352867
221 
222 typedef struct JsonTableExecContext
223 {
224  int magic;
225 
226  /* State of the plan providing a row evaluated from "root" jsonpath */
228 
229  /*
230  * Per-column JsonTablePlanStates for all columns including the nested
231  * ones.
232  */
235 
236 /* strict/lax flags is decomposed into four [un]wrap/error flags */
237 #define jspStrictAbsenceOfErrors(cxt) (!(cxt)->laxMode)
238 #define jspAutoUnwrap(cxt) ((cxt)->laxMode)
239 #define jspAutoWrap(cxt) ((cxt)->laxMode)
240 #define jspIgnoreStructuralErrors(cxt) ((cxt)->ignoreStructuralErrors)
241 #define jspThrowErrors(cxt) ((cxt)->throwErrors)
242 
243 /* Convenience macro: return or throw error depending on context */
244 #define RETURN_ERROR(throw_error) \
245 do { \
246  if (jspThrowErrors(cxt)) \
247  throw_error; \
248  else \
249  return jperError; \
250 } while (0)
251 
253  JsonbValue *larg,
254  JsonbValue *rarg,
255  void *param);
256 typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
257 
258 static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars,
259  JsonPathGetVarCallback getVar,
260  JsonPathCountVarsCallback countVars,
261  Jsonb *json, bool throwErrors,
262  JsonValueList *result, bool useTz);
264  JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found);
266  JsonPathItem *jsp, JsonbValue *jb,
267  JsonValueList *found, bool unwrap);
269  JsonPathItem *jsp, JsonbValue *jb,
270  JsonValueList *found, bool unwrapElements);
273  JsonbValue *v, JsonValueList *found, bool copy);
275  bool unwrap, JsonValueList *found);
277  JsonbValue *jb, bool unwrap, JsonValueList *found);
279  JsonPathItem *jsp, JsonbValue *jb, bool canHaveNext);
281  JsonPathItem *jsp, JsonbValue *jb);
283  JsonPathItem *jsp, JsonbContainer *jbc, JsonValueList *found,
284  uint32 level, uint32 first, uint32 last,
285  bool ignoreStructuralErrors, bool unwrapNext);
287  JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg,
288  JsonbValue *jb, bool unwrapRightArg,
289  JsonPathPredicateCallback exec, void *param);
291  JsonPathItem *jsp, JsonbValue *jb,
292  BinaryArithmFunc func, JsonValueList *found);
294  JsonPathItem *jsp, JsonbValue *jb, PGFunction func,
295  JsonValueList *found);
297  JsonbValue *whole, JsonbValue *initial, void *param);
299  JsonbValue *rarg, void *param);
301  JsonPathItem *jsp, JsonbValue *jb, bool unwrap, PGFunction func,
302  JsonValueList *found);
304  JsonbValue *jb, JsonValueList *found);
306  JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found);
309 static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
310  JsonbValue *value);
311 static JsonbValue *GetJsonPathVar(void *cxt, char *varName, int varNameLen,
312  JsonbValue *baseObject, int *baseObjectId);
313 static int CountJsonPathVars(void *cxt);
314 static void JsonItemFromDatum(Datum val, Oid typid, int32 typmod,
315  JsonbValue *res);
316 static void JsonbValueInitNumericDatum(JsonbValue *jbv, Datum num);
319 static int countVariablesFromJsonb(void *varsJsonb);
320 static JsonbValue *getJsonPathVariableFromJsonb(void *varsJsonb, char *varName,
321  int varNameLen,
322  JsonbValue *baseObject,
323  int *baseObjectId);
324 static int JsonbArraySize(JsonbValue *jb);
326  JsonbValue *rv, void *p);
327 static JsonPathBool compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2,
328  bool useTz);
329 static int compareNumeric(Numeric a, Numeric b);
330 static JsonbValue *copyJsonbValue(JsonbValue *src);
332  JsonPathItem *jsp, JsonbValue *jb, int32 *index);
334  JsonbValue *jbv, int32 id);
335 static void JsonValueListClear(JsonValueList *jvl);
336 static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv);
337 static int JsonValueListLength(const JsonValueList *jvl);
338 static bool JsonValueListIsEmpty(JsonValueList *jvl);
341 static void JsonValueListInitIterator(const JsonValueList *jvl,
343 static JsonbValue *JsonValueListNext(const JsonValueList *jvl,
345 static int JsonbType(JsonbValue *jb);
346 static JsonbValue *JsonbInitBinary(JsonbValue *jbv, Jsonb *jb);
347 static int JsonbType(JsonbValue *jb);
348 static JsonbValue *getScalar(JsonbValue *scalar, enum jbvType type);
350 static int compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
351  bool useTz, bool *cast_error);
352 static void checkTimezoneIsUsedForCast(bool useTz, const char *type1,
353  const char *type2);
354 
355 static void JsonTableInitOpaque(TableFuncScanState *state, int natts);
358  JsonTablePlanState *parentstate,
359  List *args,
360  MemoryContext mcxt);
364 static Datum JsonTableGetValue(TableFuncScanState *state, int colnum,
365  Oid typid, int32 typmod, bool *isnull);
367 static bool JsonTablePlanScanNextRow(JsonTablePlanState *planstate);
368 static void JsonTableResetNestedPlan(JsonTablePlanState *planstate);
369 static bool JsonTablePlanJoinNextRow(JsonTablePlanState *planstate);
370 static bool JsonTablePlanNextRow(JsonTablePlanState *planstate);
371 
373 {
375  .SetDocument = JsonTableSetDocument,
376  .SetNamespace = NULL,
377  .SetRowFilter = NULL,
378  .SetColumnFilter = NULL,
379  .FetchRow = JsonTableFetchRow,
380  .GetValue = JsonTableGetValue,
381  .DestroyOpaque = JsonTableDestroyOpaque
382 };
383 
384 /****************** User interface to JsonPath executor ********************/
385 
386 /*
387  * jsonb_path_exists
388  * Returns true if jsonpath returns at least one item for the specified
389  * jsonb value. This function and jsonb_path_match() are used to
390  * implement @? and @@ operators, which in turn are intended to have an
391  * index support. Thus, it's desirable to make it easier to achieve
392  * consistency between index scan results and sequential scan results.
393  * So, we throw as few errors as possible. Regarding this function,
394  * such behavior also matches behavior of JSON_EXISTS() clause of
395  * SQL/JSON. Regarding jsonb_path_match(), this function doesn't have
396  * an analogy in SQL/JSON, so we define its behavior on our own.
397  */
398 static Datum
400 {
401  Jsonb *jb = PG_GETARG_JSONB_P(0);
404  Jsonb *vars = NULL;
405  bool silent = true;
406 
407  if (PG_NARGS() == 4)
408  {
409  vars = PG_GETARG_JSONB_P(2);
410  silent = PG_GETARG_BOOL(3);
411  }
412 
415  jb, !silent, NULL, tz);
416 
417  PG_FREE_IF_COPY(jb, 0);
418  PG_FREE_IF_COPY(jp, 1);
419 
420  if (jperIsError(res))
421  PG_RETURN_NULL();
422 
424 }
425 
426 Datum
428 {
429  return jsonb_path_exists_internal(fcinfo, false);
430 }
431 
432 Datum
434 {
435  return jsonb_path_exists_internal(fcinfo, true);
436 }
437 
438 /*
439  * jsonb_path_exists_opr
440  * Implementation of operator "jsonb @? jsonpath" (2-argument version of
441  * jsonb_path_exists()).
442  */
443 Datum
445 {
446  /* just call the other one -- it can handle both cases */
447  return jsonb_path_exists_internal(fcinfo, false);
448 }
449 
450 /*
451  * jsonb_path_match
452  * Returns jsonpath predicate result item for the specified jsonb value.
453  * See jsonb_path_exists() comment for details regarding error handling.
454  */
455 static Datum
457 {
458  Jsonb *jb = PG_GETARG_JSONB_P(0);
460  JsonValueList found = {0};
461  Jsonb *vars = NULL;
462  bool silent = true;
463 
464  if (PG_NARGS() == 4)
465  {
466  vars = PG_GETARG_JSONB_P(2);
467  silent = PG_GETARG_BOOL(3);
468  }
469 
472  jb, !silent, &found, tz);
473 
474  PG_FREE_IF_COPY(jb, 0);
475  PG_FREE_IF_COPY(jp, 1);
476 
477  if (JsonValueListLength(&found) == 1)
478  {
479  JsonbValue *jbv = JsonValueListHead(&found);
480 
481  if (jbv->type == jbvBool)
482  PG_RETURN_BOOL(jbv->val.boolean);
483 
484  if (jbv->type == jbvNull)
485  PG_RETURN_NULL();
486  }
487 
488  if (!silent)
489  ereport(ERROR,
490  (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
491  errmsg("single boolean result is expected")));
492 
493  PG_RETURN_NULL();
494 }
495 
496 Datum
498 {
499  return jsonb_path_match_internal(fcinfo, false);
500 }
501 
502 Datum
504 {
505  return jsonb_path_match_internal(fcinfo, true);
506 }
507 
508 /*
509  * jsonb_path_match_opr
510  * Implementation of operator "jsonb @@ jsonpath" (2-argument version of
511  * jsonb_path_match()).
512  */
513 Datum
515 {
516  /* just call the other one -- it can handle both cases */
517  return jsonb_path_match_internal(fcinfo, false);
518 }
519 
520 /*
521  * jsonb_path_query
522  * Executes jsonpath for given jsonb document and returns result as
523  * rowset.
524  */
525 static Datum
527 {
528  FuncCallContext *funcctx;
529  List *found;
530  JsonbValue *v;
531  ListCell *c;
532 
533  if (SRF_IS_FIRSTCALL())
534  {
535  JsonPath *jp;
536  Jsonb *jb;
537  MemoryContext oldcontext;
538  Jsonb *vars;
539  bool silent;
540  JsonValueList found = {0};
541 
542  funcctx = SRF_FIRSTCALL_INIT();
543  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
544 
545  jb = PG_GETARG_JSONB_P_COPY(0);
548  silent = PG_GETARG_BOOL(3);
549 
552  jb, !silent, &found, tz);
553 
554  funcctx->user_fctx = JsonValueListGetList(&found);
555 
556  MemoryContextSwitchTo(oldcontext);
557  }
558 
559  funcctx = SRF_PERCALL_SETUP();
560  found = funcctx->user_fctx;
561 
562  c = list_head(found);
563 
564  if (c == NULL)
565  SRF_RETURN_DONE(funcctx);
566 
567  v = lfirst(c);
568  funcctx->user_fctx = list_delete_first(found);
569 
571 }
572 
573 Datum
575 {
576  return jsonb_path_query_internal(fcinfo, false);
577 }
578 
579 Datum
581 {
582  return jsonb_path_query_internal(fcinfo, true);
583 }
584 
585 /*
586  * jsonb_path_query_array
587  * Executes jsonpath for given jsonb document and returns result as
588  * jsonb array.
589  */
590 static Datum
592 {
593  Jsonb *jb = PG_GETARG_JSONB_P(0);
595  JsonValueList found = {0};
597  bool silent = PG_GETARG_BOOL(3);
598 
601  jb, !silent, &found, tz);
602 
604 }
605 
606 Datum
608 {
609  return jsonb_path_query_array_internal(fcinfo, false);
610 }
611 
612 Datum
614 {
615  return jsonb_path_query_array_internal(fcinfo, true);
616 }
617 
618 /*
619  * jsonb_path_query_first
620  * Executes jsonpath for given jsonb document and returns first result
621  * item. If there are no items, NULL returned.
622  */
623 static Datum
625 {
626  Jsonb *jb = PG_GETARG_JSONB_P(0);
628  JsonValueList found = {0};
630  bool silent = PG_GETARG_BOOL(3);
631 
634  jb, !silent, &found, tz);
635 
636  if (JsonValueListLength(&found) >= 1)
638  else
639  PG_RETURN_NULL();
640 }
641 
642 Datum
644 {
645  return jsonb_path_query_first_internal(fcinfo, false);
646 }
647 
648 Datum
650 {
651  return jsonb_path_query_first_internal(fcinfo, true);
652 }
653 
654 /********************Execute functions for JsonPath**************************/
655 
656 /*
657  * Interface to jsonpath executor
658  *
659  * 'path' - jsonpath to be executed
660  * 'vars' - variables to be substituted to jsonpath
661  * 'getVar' - callback used by getJsonPathVariable() to extract variables from
662  * 'vars'
663  * 'countVars' - callback to count the number of jsonpath variables in 'vars'
664  * 'json' - target document for jsonpath evaluation
665  * 'throwErrors' - whether we should throw suppressible errors
666  * 'result' - list to store result items into
667  *
668  * Returns an error if a recoverable error happens during processing, or NULL
669  * on no error.
670  *
671  * Note, jsonb and jsonpath values should be available and untoasted during
672  * work because JsonPathItem, JsonbValue and result item could have pointers
673  * into input values. If caller needs to just check if document matches
674  * jsonpath, then it doesn't provide a result arg. In this case executor
675  * works till first positive result and does not check the rest if possible.
676  * In other case it tries to find all the satisfied result items.
677  */
678 static JsonPathExecResult
680  JsonPathCountVarsCallback countVars,
681  Jsonb *json, bool throwErrors, JsonValueList *result,
682  bool useTz)
683 {
686  JsonPathItem jsp;
687  JsonbValue jbv;
688 
689  jspInit(&jsp, path);
690 
691  if (!JsonbExtractScalar(&json->root, &jbv))
692  JsonbInitBinary(&jbv, json);
693 
694  cxt.vars = vars;
695  cxt.getVar = getVar;
696  cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
698  cxt.root = &jbv;
699  cxt.current = &jbv;
700  cxt.baseObject.jbc = NULL;
701  cxt.baseObject.id = 0;
702  /* 1 + number of base objects in vars */
703  cxt.lastGeneratedObjectId = 1 + countVars(vars);
704  cxt.innermostArraySize = -1;
705  cxt.throwErrors = throwErrors;
706  cxt.useTz = useTz;
707 
708  if (jspStrictAbsenceOfErrors(&cxt) && !result)
709  {
710  /*
711  * In strict mode we must get a complete list of values to check that
712  * there are no errors at all.
713  */
714  JsonValueList vals = {0};
715 
716  res = executeItem(&cxt, &jsp, &jbv, &vals);
717 
718  if (jperIsError(res))
719  return res;
720 
721  return JsonValueListIsEmpty(&vals) ? jperNotFound : jperOk;
722  }
723 
724  res = executeItem(&cxt, &jsp, &jbv, result);
725 
726  Assert(!throwErrors || !jperIsError(res));
727 
728  return res;
729 }
730 
731 /*
732  * Execute jsonpath with automatic unwrapping of current item in lax mode.
733  */
734 static JsonPathExecResult
736  JsonbValue *jb, JsonValueList *found)
737 {
738  return executeItemOptUnwrapTarget(cxt, jsp, jb, found, jspAutoUnwrap(cxt));
739 }
740 
741 /*
742  * Main jsonpath executor function: walks on jsonpath structure, finds
743  * relevant parts of jsonb and evaluates expressions over them.
744  * When 'unwrap' is true current SQL/JSON item is unwrapped if it is an array.
745  */
746 static JsonPathExecResult
748  JsonbValue *jb, JsonValueList *found, bool unwrap)
749 {
750  JsonPathItem elem;
752  JsonBaseObjectInfo baseObject;
753 
756 
757  switch (jsp->type)
758  {
759  case jpiNull:
760  case jpiBool:
761  case jpiNumeric:
762  case jpiString:
763  case jpiVariable:
764  {
765  JsonbValue vbuf;
766  JsonbValue *v;
767  bool hasNext = jspGetNext(jsp, &elem);
768 
769  if (!hasNext && !found && jsp->type != jpiVariable)
770  {
771  /*
772  * Skip evaluation, but not for variables. We must
773  * trigger an error for the missing variable.
774  */
775  res = jperOk;
776  break;
777  }
778 
779  v = hasNext ? &vbuf : palloc(sizeof(*v));
780 
781  baseObject = cxt->baseObject;
782  getJsonPathItem(cxt, jsp, v);
783 
784  res = executeNextItem(cxt, jsp, &elem,
785  v, found, hasNext);
786  cxt->baseObject = baseObject;
787  }
788  break;
789 
790  /* all boolean item types: */
791  case jpiAnd:
792  case jpiOr:
793  case jpiNot:
794  case jpiIsUnknown:
795  case jpiEqual:
796  case jpiNotEqual:
797  case jpiLess:
798  case jpiGreater:
799  case jpiLessOrEqual:
800  case jpiGreaterOrEqual:
801  case jpiExists:
802  case jpiStartsWith:
803  case jpiLikeRegex:
804  {
805  JsonPathBool st = executeBoolItem(cxt, jsp, jb, true);
806 
807  res = appendBoolResult(cxt, jsp, found, st);
808  break;
809  }
810 
811  case jpiAdd:
812  return executeBinaryArithmExpr(cxt, jsp, jb,
813  numeric_add_opt_error, found);
814 
815  case jpiSub:
816  return executeBinaryArithmExpr(cxt, jsp, jb,
817  numeric_sub_opt_error, found);
818 
819  case jpiMul:
820  return executeBinaryArithmExpr(cxt, jsp, jb,
821  numeric_mul_opt_error, found);
822 
823  case jpiDiv:
824  return executeBinaryArithmExpr(cxt, jsp, jb,
825  numeric_div_opt_error, found);
826 
827  case jpiMod:
828  return executeBinaryArithmExpr(cxt, jsp, jb,
829  numeric_mod_opt_error, found);
830 
831  case jpiPlus:
832  return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
833 
834  case jpiMinus:
835  return executeUnaryArithmExpr(cxt, jsp, jb, numeric_uminus,
836  found);
837 
838  case jpiAnyArray:
839  if (JsonbType(jb) == jbvArray)
840  {
841  bool hasNext = jspGetNext(jsp, &elem);
842 
843  res = executeItemUnwrapTargetArray(cxt, hasNext ? &elem : NULL,
844  jb, found, jspAutoUnwrap(cxt));
845  }
846  else if (jspAutoWrap(cxt))
847  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
848  else if (!jspIgnoreStructuralErrors(cxt))
850  (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
851  errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
852  break;
853 
854  case jpiAnyKey:
855  if (JsonbType(jb) == jbvObject)
856  {
857  bool hasNext = jspGetNext(jsp, &elem);
858 
859  if (jb->type != jbvBinary)
860  elog(ERROR, "invalid jsonb object type: %d", jb->type);
861 
862  return executeAnyItem
863  (cxt, hasNext ? &elem : NULL,
864  jb->val.binary.data, found, 1, 1, 1,
865  false, jspAutoUnwrap(cxt));
866  }
867  else if (unwrap && JsonbType(jb) == jbvArray)
868  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
869  else if (!jspIgnoreStructuralErrors(cxt))
870  {
871  Assert(found);
873  (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
874  errmsg("jsonpath wildcard member accessor can only be applied to an object"))));
875  }
876  break;
877 
878  case jpiIndexArray:
879  if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
880  {
881  int innermostArraySize = cxt->innermostArraySize;
882  int i;
883  int size = JsonbArraySize(jb);
884  bool singleton = size < 0;
885  bool hasNext = jspGetNext(jsp, &elem);
886 
887  if (singleton)
888  size = 1;
889 
890  cxt->innermostArraySize = size; /* for LAST evaluation */
891 
892  for (i = 0; i < jsp->content.array.nelems; i++)
893  {
894  JsonPathItem from;
895  JsonPathItem to;
896  int32 index;
897  int32 index_from;
898  int32 index_to;
899  bool range = jspGetArraySubscript(jsp, &from,
900  &to, i);
901 
902  res = getArrayIndex(cxt, &from, jb, &index_from);
903 
904  if (jperIsError(res))
905  break;
906 
907  if (range)
908  {
909  res = getArrayIndex(cxt, &to, jb, &index_to);
910 
911  if (jperIsError(res))
912  break;
913  }
914  else
915  index_to = index_from;
916 
917  if (!jspIgnoreStructuralErrors(cxt) &&
918  (index_from < 0 ||
919  index_from > index_to ||
920  index_to >= size))
922  (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
923  errmsg("jsonpath array subscript is out of bounds"))));
924 
925  if (index_from < 0)
926  index_from = 0;
927 
928  if (index_to >= size)
929  index_to = size - 1;
930 
931  res = jperNotFound;
932 
933  for (index = index_from; index <= index_to; index++)
934  {
935  JsonbValue *v;
936  bool copy;
937 
938  if (singleton)
939  {
940  v = jb;
941  copy = true;
942  }
943  else
944  {
945  v = getIthJsonbValueFromContainer(jb->val.binary.data,
946  (uint32) index);
947 
948  if (v == NULL)
949  continue;
950 
951  copy = false;
952  }
953 
954  if (!hasNext && !found)
955  return jperOk;
956 
957  res = executeNextItem(cxt, jsp, &elem, v, found,
958  copy);
959 
960  if (jperIsError(res))
961  break;
962 
963  if (res == jperOk && !found)
964  break;
965  }
966 
967  if (jperIsError(res))
968  break;
969 
970  if (res == jperOk && !found)
971  break;
972  }
973 
974  cxt->innermostArraySize = innermostArraySize;
975  }
976  else if (!jspIgnoreStructuralErrors(cxt))
977  {
979  (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
980  errmsg("jsonpath array accessor can only be applied to an array"))));
981  }
982  break;
983 
984  case jpiAny:
985  {
986  bool hasNext = jspGetNext(jsp, &elem);
987 
988  /* first try without any intermediate steps */
989  if (jsp->content.anybounds.first == 0)
990  {
991  bool savedIgnoreStructuralErrors;
992 
993  savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
994  cxt->ignoreStructuralErrors = true;
995  res = executeNextItem(cxt, jsp, &elem,
996  jb, found, true);
997  cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
998 
999  if (res == jperOk && !found)
1000  break;
1001  }
1002 
1003  if (jb->type == jbvBinary)
1005  (cxt, hasNext ? &elem : NULL,
1006  jb->val.binary.data, found,
1007  1,
1008  jsp->content.anybounds.first,
1009  jsp->content.anybounds.last,
1010  true, jspAutoUnwrap(cxt));
1011  break;
1012  }
1013 
1014  case jpiKey:
1015  if (JsonbType(jb) == jbvObject)
1016  {
1017  JsonbValue *v;
1018  JsonbValue key;
1019 
1020  key.type = jbvString;
1021  key.val.string.val = jspGetString(jsp, &key.val.string.len);
1022 
1023  v = findJsonbValueFromContainer(jb->val.binary.data,
1024  JB_FOBJECT, &key);
1025 
1026  if (v != NULL)
1027  {
1028  res = executeNextItem(cxt, jsp, NULL,
1029  v, found, false);
1030 
1031  /* free value if it was not added to found list */
1032  if (jspHasNext(jsp) || !found)
1033  pfree(v);
1034  }
1035  else if (!jspIgnoreStructuralErrors(cxt))
1036  {
1037  Assert(found);
1038 
1039  if (!jspThrowErrors(cxt))
1040  return jperError;
1041 
1042  ereport(ERROR,
1043  (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND), \
1044  errmsg("JSON object does not contain key \"%s\"",
1045  pnstrdup(key.val.string.val,
1046  key.val.string.len))));
1047  }
1048  }
1049  else if (unwrap && JsonbType(jb) == jbvArray)
1050  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1051  else if (!jspIgnoreStructuralErrors(cxt))
1052  {
1053  Assert(found);
1055  (errcode(ERRCODE_SQL_JSON_MEMBER_NOT_FOUND),
1056  errmsg("jsonpath member accessor can only be applied to an object"))));
1057  }
1058  break;
1059 
1060  case jpiCurrent:
1061  res = executeNextItem(cxt, jsp, NULL, cxt->current,
1062  found, true);
1063  break;
1064 
1065  case jpiRoot:
1066  jb = cxt->root;
1067  baseObject = setBaseObject(cxt, jb, 0);
1068  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1069  cxt->baseObject = baseObject;
1070  break;
1071 
1072  case jpiFilter:
1073  {
1074  JsonPathBool st;
1075 
1076  if (unwrap && JsonbType(jb) == jbvArray)
1077  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1078  false);
1079 
1080  jspGetArg(jsp, &elem);
1081  st = executeNestedBoolItem(cxt, &elem, jb);
1082  if (st != jpbTrue)
1083  res = jperNotFound;
1084  else
1085  res = executeNextItem(cxt, jsp, NULL,
1086  jb, found, true);
1087  break;
1088  }
1089 
1090  case jpiType:
1091  {
1092  JsonbValue *jbv = palloc(sizeof(*jbv));
1093 
1094  jbv->type = jbvString;
1095  jbv->val.string.val = pstrdup(JsonbTypeName(jb));
1096  jbv->val.string.len = strlen(jbv->val.string.val);
1097 
1098  res = executeNextItem(cxt, jsp, NULL, jbv,
1099  found, false);
1100  }
1101  break;
1102 
1103  case jpiSize:
1104  {
1105  int size = JsonbArraySize(jb);
1106 
1107  if (size < 0)
1108  {
1109  if (!jspAutoWrap(cxt))
1110  {
1111  if (!jspIgnoreStructuralErrors(cxt))
1113  (errcode(ERRCODE_SQL_JSON_ARRAY_NOT_FOUND),
1114  errmsg("jsonpath item method .%s() can only be applied to an array",
1115  jspOperationName(jsp->type)))));
1116  break;
1117  }
1118 
1119  size = 1;
1120  }
1121 
1122  jb = palloc(sizeof(*jb));
1123 
1124  jb->type = jbvNumeric;
1125  jb->val.numeric = int64_to_numeric(size);
1126 
1127  res = executeNextItem(cxt, jsp, NULL, jb, found, false);
1128  }
1129  break;
1130 
1131  case jpiAbs:
1132  return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_abs,
1133  found);
1134 
1135  case jpiFloor:
1136  return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_floor,
1137  found);
1138 
1139  case jpiCeiling:
1140  return executeNumericItemMethod(cxt, jsp, jb, unwrap, numeric_ceil,
1141  found);
1142 
1143  case jpiDouble:
1144  {
1145  JsonbValue jbv;
1146 
1147  if (unwrap && JsonbType(jb) == jbvArray)
1148  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1149  false);
1150 
1151  if (jb->type == jbvNumeric)
1152  {
1154  NumericGetDatum(jb->val.numeric)));
1155  double val;
1156  ErrorSaveContext escontext = {T_ErrorSaveContext};
1157 
1158  val = float8in_internal(tmp,
1159  NULL,
1160  "double precision",
1161  tmp,
1162  (Node *) &escontext);
1163 
1164  if (escontext.error_occurred)
1166  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1167  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type double precision",
1168  tmp, jspOperationName(jsp->type)))));
1169  if (isinf(val) || isnan(val))
1171  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1172  errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1173  jspOperationName(jsp->type)))));
1174  res = jperOk;
1175  }
1176  else if (jb->type == jbvString)
1177  {
1178  /* cast string as double */
1179  double val;
1180  char *tmp = pnstrdup(jb->val.string.val,
1181  jb->val.string.len);
1182  ErrorSaveContext escontext = {T_ErrorSaveContext};
1183 
1184  val = float8in_internal(tmp,
1185  NULL,
1186  "double precision",
1187  tmp,
1188  (Node *) &escontext);
1189 
1190  if (escontext.error_occurred)
1192  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1193  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type double precision",
1194  tmp, jspOperationName(jsp->type)))));
1195  if (isinf(val) || isnan(val))
1197  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1198  errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1199  jspOperationName(jsp->type)))));
1200 
1201  jb = &jbv;
1202  jb->type = jbvNumeric;
1204  Float8GetDatum(val)));
1205  res = jperOk;
1206  }
1207 
1208  if (res == jperNotFound)
1210  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1211  errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1212  jspOperationName(jsp->type)))));
1213 
1214  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1215  }
1216  break;
1217 
1218  case jpiDatetime:
1219  case jpiDate:
1220  case jpiTime:
1221  case jpiTimeTz:
1222  case jpiTimestamp:
1223  case jpiTimestampTz:
1224  if (unwrap && JsonbType(jb) == jbvArray)
1225  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1226 
1227  return executeDateTimeMethod(cxt, jsp, jb, found);
1228 
1229  case jpiKeyValue:
1230  if (unwrap && JsonbType(jb) == jbvArray)
1231  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1232 
1233  return executeKeyValueMethod(cxt, jsp, jb, found);
1234 
1235  case jpiLast:
1236  {
1237  JsonbValue tmpjbv;
1238  JsonbValue *lastjbv;
1239  int last;
1240  bool hasNext = jspGetNext(jsp, &elem);
1241 
1242  if (cxt->innermostArraySize < 0)
1243  elog(ERROR, "evaluating jsonpath LAST outside of array subscript");
1244 
1245  if (!hasNext && !found)
1246  {
1247  res = jperOk;
1248  break;
1249  }
1250 
1251  last = cxt->innermostArraySize - 1;
1252 
1253  lastjbv = hasNext ? &tmpjbv : palloc(sizeof(*lastjbv));
1254 
1255  lastjbv->type = jbvNumeric;
1256  lastjbv->val.numeric = int64_to_numeric(last);
1257 
1258  res = executeNextItem(cxt, jsp, &elem,
1259  lastjbv, found, hasNext);
1260  }
1261  break;
1262 
1263  case jpiBigint:
1264  {
1265  JsonbValue jbv;
1266  Datum datum;
1267 
1268  if (unwrap && JsonbType(jb) == jbvArray)
1269  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1270  false);
1271 
1272  if (jb->type == jbvNumeric)
1273  {
1274  bool have_error;
1275  int64 val;
1276 
1277  val = numeric_int8_opt_error(jb->val.numeric, &have_error);
1278  if (have_error)
1280  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1281  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type bigint",
1283  NumericGetDatum(jb->val.numeric))),
1284  jspOperationName(jsp->type)))));
1285 
1286  datum = Int64GetDatum(val);
1287  res = jperOk;
1288  }
1289  else if (jb->type == jbvString)
1290  {
1291  /* cast string as bigint */
1292  char *tmp = pnstrdup(jb->val.string.val,
1293  jb->val.string.len);
1294  ErrorSaveContext escontext = {T_ErrorSaveContext};
1295  bool noerr;
1296 
1297  noerr = DirectInputFunctionCallSafe(int8in, tmp,
1298  InvalidOid, -1,
1299  (Node *) &escontext,
1300  &datum);
1301 
1302  if (!noerr || escontext.error_occurred)
1304  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1305  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type bigint",
1306  tmp, jspOperationName(jsp->type)))));
1307  res = jperOk;
1308  }
1309 
1310  if (res == jperNotFound)
1312  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1313  errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1314  jspOperationName(jsp->type)))));
1315 
1316  jb = &jbv;
1317  jb->type = jbvNumeric;
1319  datum));
1320 
1321  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1322  }
1323  break;
1324 
1325  case jpiBoolean:
1326  {
1327  JsonbValue jbv;
1328  bool bval;
1329 
1330  if (unwrap && JsonbType(jb) == jbvArray)
1331  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1332  false);
1333 
1334  if (jb->type == jbvBool)
1335  {
1336  bval = jb->val.boolean;
1337 
1338  res = jperOk;
1339  }
1340  else if (jb->type == jbvNumeric)
1341  {
1342  int ival;
1343  Datum datum;
1344  bool noerr;
1346  NumericGetDatum(jb->val.numeric)));
1347  ErrorSaveContext escontext = {T_ErrorSaveContext};
1348 
1349  noerr = DirectInputFunctionCallSafe(int4in, tmp,
1350  InvalidOid, -1,
1351  (Node *) &escontext,
1352  &datum);
1353 
1354  if (!noerr || escontext.error_occurred)
1356  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1357  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type boolean",
1358  tmp, jspOperationName(jsp->type)))));
1359 
1360  ival = DatumGetInt32(datum);
1361  if (ival == 0)
1362  bval = false;
1363  else
1364  bval = true;
1365 
1366  res = jperOk;
1367  }
1368  else if (jb->type == jbvString)
1369  {
1370  /* cast string as boolean */
1371  char *tmp = pnstrdup(jb->val.string.val,
1372  jb->val.string.len);
1373 
1374  if (!parse_bool(tmp, &bval))
1376  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1377  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type boolean",
1378  tmp, jspOperationName(jsp->type)))));
1379 
1380  res = jperOk;
1381  }
1382 
1383  if (res == jperNotFound)
1385  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1386  errmsg("jsonpath item method .%s() can only be applied to a bool, string, or numeric value",
1387  jspOperationName(jsp->type)))));
1388 
1389  jb = &jbv;
1390  jb->type = jbvBool;
1391  jb->val.boolean = bval;
1392 
1393  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1394  }
1395  break;
1396 
1397  case jpiDecimal:
1398  case jpiNumber:
1399  {
1400  JsonbValue jbv;
1401  Numeric num;
1402  char *numstr = NULL;
1403 
1404  if (unwrap && JsonbType(jb) == jbvArray)
1405  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1406  false);
1407 
1408  if (jb->type == jbvNumeric)
1409  {
1410  num = jb->val.numeric;
1411  if (numeric_is_nan(num) || numeric_is_inf(num))
1413  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1414  errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1415  jspOperationName(jsp->type)))));
1416 
1417  if (jsp->type == jpiDecimal)
1419  NumericGetDatum(num)));
1420  res = jperOk;
1421  }
1422  else if (jb->type == jbvString)
1423  {
1424  /* cast string as number */
1425  Datum datum;
1426  bool noerr;
1427  ErrorSaveContext escontext = {T_ErrorSaveContext};
1428 
1429  numstr = pnstrdup(jb->val.string.val, jb->val.string.len);
1430 
1431  noerr = DirectInputFunctionCallSafe(numeric_in, numstr,
1432  InvalidOid, -1,
1433  (Node *) &escontext,
1434  &datum);
1435 
1436  if (!noerr || escontext.error_occurred)
1438  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1439  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type numeric",
1440  numstr, jspOperationName(jsp->type)))));
1441 
1442  num = DatumGetNumeric(datum);
1443  if (numeric_is_nan(num) || numeric_is_inf(num))
1445  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1446  errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1447  jspOperationName(jsp->type)))));
1448 
1449  res = jperOk;
1450  }
1451 
1452  if (res == jperNotFound)
1454  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1455  errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1456  jspOperationName(jsp->type)))));
1457 
1458  /*
1459  * If we have arguments, then they must be the precision and
1460  * optional scale used in .decimal(). Convert them to the
1461  * typmod equivalent and then truncate the numeric value per
1462  * this typmod details.
1463  */
1464  if (jsp->type == jpiDecimal && jsp->content.args.left)
1465  {
1466  Datum numdatum;
1467  Datum dtypmod;
1468  int32 precision;
1469  int32 scale = 0;
1470  bool have_error;
1471  bool noerr;
1472  ArrayType *arrtypmod;
1473  Datum datums[2];
1474  char pstr[12]; /* sign, 10 digits and '\0' */
1475  char sstr[12]; /* sign, 10 digits and '\0' */
1476  ErrorSaveContext escontext = {T_ErrorSaveContext};
1477 
1478  jspGetLeftArg(jsp, &elem);
1479  if (elem.type != jpiNumeric)
1480  elog(ERROR, "invalid jsonpath item type for .decimal() precision");
1481 
1482  precision = numeric_int4_opt_error(jspGetNumeric(&elem),
1483  &have_error);
1484  if (have_error)
1486  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1487  errmsg("precision of jsonpath item method .%s() is out of range for type integer",
1488  jspOperationName(jsp->type)))));
1489 
1490  if (jsp->content.args.right)
1491  {
1492  jspGetRightArg(jsp, &elem);
1493  if (elem.type != jpiNumeric)
1494  elog(ERROR, "invalid jsonpath item type for .decimal() scale");
1495 
1497  &have_error);
1498  if (have_error)
1500  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1501  errmsg("scale of jsonpath item method .%s() is out of range for type integer",
1502  jspOperationName(jsp->type)))));
1503  }
1504 
1505  /*
1506  * numerictypmodin() takes the precision and scale in the
1507  * form of CString arrays.
1508  */
1509  pg_ltoa(precision, pstr);
1510  datums[0] = CStringGetDatum(pstr);
1511  pg_ltoa(scale, sstr);
1512  datums[1] = CStringGetDatum(sstr);
1513  arrtypmod = construct_array_builtin(datums, 2, CSTRINGOID);
1514 
1516  PointerGetDatum(arrtypmod));
1517 
1518  /* Convert numstr to Numeric with typmod */
1519  Assert(numstr != NULL);
1520  noerr = DirectInputFunctionCallSafe(numeric_in, numstr,
1521  InvalidOid, dtypmod,
1522  (Node *) &escontext,
1523  &numdatum);
1524 
1525  if (!noerr || escontext.error_occurred)
1527  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1528  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type numeric",
1529  numstr, jspOperationName(jsp->type)))));
1530 
1531  num = DatumGetNumeric(numdatum);
1532  pfree(arrtypmod);
1533  }
1534 
1535  jb = &jbv;
1536  jb->type = jbvNumeric;
1537  jb->val.numeric = num;
1538 
1539  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1540  }
1541  break;
1542 
1543  case jpiInteger:
1544  {
1545  JsonbValue jbv;
1546  Datum datum;
1547 
1548  if (unwrap && JsonbType(jb) == jbvArray)
1549  return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1550  false);
1551 
1552  if (jb->type == jbvNumeric)
1553  {
1554  bool have_error;
1555  int32 val;
1556 
1557  val = numeric_int4_opt_error(jb->val.numeric, &have_error);
1558  if (have_error)
1560  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1561  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type integer",
1563  NumericGetDatum(jb->val.numeric))),
1564  jspOperationName(jsp->type)))));
1565 
1566  datum = Int32GetDatum(val);
1567  res = jperOk;
1568  }
1569  else if (jb->type == jbvString)
1570  {
1571  /* cast string as integer */
1572  char *tmp = pnstrdup(jb->val.string.val,
1573  jb->val.string.len);
1574  ErrorSaveContext escontext = {T_ErrorSaveContext};
1575  bool noerr;
1576 
1577  noerr = DirectInputFunctionCallSafe(int4in, tmp,
1578  InvalidOid, -1,
1579  (Node *) &escontext,
1580  &datum);
1581 
1582  if (!noerr || escontext.error_occurred)
1584  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1585  errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type integer",
1586  tmp, jspOperationName(jsp->type)))));
1587  res = jperOk;
1588  }
1589 
1590  if (res == jperNotFound)
1592  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1593  errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1594  jspOperationName(jsp->type)))));
1595 
1596  jb = &jbv;
1597  jb->type = jbvNumeric;
1599  datum));
1600 
1601  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1602  }
1603  break;
1604 
1605  case jpiStringFunc:
1606  {
1607  JsonbValue jbv;
1608  char *tmp = NULL;
1609 
1610  switch (JsonbType(jb))
1611  {
1612  case jbvString:
1613 
1614  /*
1615  * Value is not necessarily null-terminated, so we do
1616  * pnstrdup() here.
1617  */
1618  tmp = pnstrdup(jb->val.string.val,
1619  jb->val.string.len);
1620  break;
1621  case jbvNumeric:
1623  NumericGetDatum(jb->val.numeric)));
1624  break;
1625  case jbvBool:
1626  tmp = (jb->val.boolean) ? "true" : "false";
1627  break;
1628  case jbvDatetime:
1629  {
1630  switch (jb->val.datetime.typid)
1631  {
1632  case DATEOID:
1634  jb->val.datetime.value));
1635  break;
1636  case TIMEOID:
1638  jb->val.datetime.value));
1639  break;
1640  case TIMETZOID:
1642  jb->val.datetime.value));
1643  break;
1644  case TIMESTAMPOID:
1646  jb->val.datetime.value));
1647  break;
1648  case TIMESTAMPTZOID:
1650  jb->val.datetime.value));
1651  break;
1652  default:
1653  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
1654  jb->val.datetime.typid);
1655  }
1656  }
1657  break;
1658  case jbvNull:
1659  case jbvArray:
1660  case jbvObject:
1661  case jbvBinary:
1663  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
1664  errmsg("jsonpath item method .%s() can only be applied to a bool, string, numeric, or datetime value",
1665  jspOperationName(jsp->type)))));
1666  break;
1667  }
1668 
1669  jb = &jbv;
1670  Assert(tmp != NULL); /* We must have set tmp above */
1671  jb->val.string.val = tmp;
1672  jb->val.string.len = strlen(jb->val.string.val);
1673  jb->type = jbvString;
1674 
1675  res = executeNextItem(cxt, jsp, NULL, jb, found, true);
1676  }
1677  break;
1678 
1679  default:
1680  elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
1681  }
1682 
1683  return res;
1684 }
1685 
1686 /*
1687  * Unwrap current array item and execute jsonpath for each of its elements.
1688  */
1689 static JsonPathExecResult
1691  JsonbValue *jb, JsonValueList *found,
1692  bool unwrapElements)
1693 {
1694  if (jb->type != jbvBinary)
1695  {
1696  Assert(jb->type != jbvArray);
1697  elog(ERROR, "invalid jsonb array value type: %d", jb->type);
1698  }
1699 
1700  return executeAnyItem
1701  (cxt, jsp, jb->val.binary.data, found, 1, 1, 1,
1702  false, unwrapElements);
1703 }
1704 
1705 /*
1706  * Execute next jsonpath item if exists. Otherwise put "v" to the "found"
1707  * list if provided.
1708  */
1709 static JsonPathExecResult
1712  JsonbValue *v, JsonValueList *found, bool copy)
1713 {
1714  JsonPathItem elem;
1715  bool hasNext;
1716 
1717  if (!cur)
1718  hasNext = next != NULL;
1719  else if (next)
1720  hasNext = jspHasNext(cur);
1721  else
1722  {
1723  next = &elem;
1724  hasNext = jspGetNext(cur, next);
1725  }
1726 
1727  if (hasNext)
1728  return executeItem(cxt, next, v, found);
1729 
1730  if (found)
1731  JsonValueListAppend(found, copy ? copyJsonbValue(v) : v);
1732 
1733  return jperOk;
1734 }
1735 
1736 /*
1737  * Same as executeItem(), but when "unwrap == true" automatically unwraps
1738  * each array item from the resulting sequence in lax mode.
1739  */
1740 static JsonPathExecResult
1742  JsonbValue *jb, bool unwrap,
1743  JsonValueList *found)
1744 {
1745  if (unwrap && jspAutoUnwrap(cxt))
1746  {
1747  JsonValueList seq = {0};
1749  JsonPathExecResult res = executeItem(cxt, jsp, jb, &seq);
1750  JsonbValue *item;
1751 
1752  if (jperIsError(res))
1753  return res;
1754 
1755  JsonValueListInitIterator(&seq, &it);
1756  while ((item = JsonValueListNext(&seq, &it)))
1757  {
1758  Assert(item->type != jbvArray);
1759 
1760  if (JsonbType(item) == jbvArray)
1761  executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
1762  else
1763  JsonValueListAppend(found, item);
1764  }
1765 
1766  return jperOk;
1767  }
1768 
1769  return executeItem(cxt, jsp, jb, found);
1770 }
1771 
1772 /*
1773  * Same as executeItemOptUnwrapResult(), but with error suppression.
1774  */
1775 static JsonPathExecResult
1777  JsonPathItem *jsp,
1778  JsonbValue *jb, bool unwrap,
1779  JsonValueList *found)
1780 {
1782  bool throwErrors = cxt->throwErrors;
1783 
1784  cxt->throwErrors = false;
1785  res = executeItemOptUnwrapResult(cxt, jsp, jb, unwrap, found);
1786  cxt->throwErrors = throwErrors;
1787 
1788  return res;
1789 }
1790 
1791 /* Execute boolean-valued jsonpath expression. */
1792 static JsonPathBool
1794  JsonbValue *jb, bool canHaveNext)
1795 {
1796  JsonPathItem larg;
1797  JsonPathItem rarg;
1798  JsonPathBool res;
1799  JsonPathBool res2;
1800 
1801  /* since this function recurses, it could be driven to stack overflow */
1803 
1804  if (!canHaveNext && jspHasNext(jsp))
1805  elog(ERROR, "boolean jsonpath item cannot have next item");
1806 
1807  switch (jsp->type)
1808  {
1809  case jpiAnd:
1810  jspGetLeftArg(jsp, &larg);
1811  res = executeBoolItem(cxt, &larg, jb, false);
1812 
1813  if (res == jpbFalse)
1814  return jpbFalse;
1815 
1816  /*
1817  * SQL/JSON says that we should check second arg in case of
1818  * jperError
1819  */
1820 
1821  jspGetRightArg(jsp, &rarg);
1822  res2 = executeBoolItem(cxt, &rarg, jb, false);
1823 
1824  return res2 == jpbTrue ? res : res2;
1825 
1826  case jpiOr:
1827  jspGetLeftArg(jsp, &larg);
1828  res = executeBoolItem(cxt, &larg, jb, false);
1829 
1830  if (res == jpbTrue)
1831  return jpbTrue;
1832 
1833  jspGetRightArg(jsp, &rarg);
1834  res2 = executeBoolItem(cxt, &rarg, jb, false);
1835 
1836  return res2 == jpbFalse ? res : res2;
1837 
1838  case jpiNot:
1839  jspGetArg(jsp, &larg);
1840 
1841  res = executeBoolItem(cxt, &larg, jb, false);
1842 
1843  if (res == jpbUnknown)
1844  return jpbUnknown;
1845 
1846  return res == jpbTrue ? jpbFalse : jpbTrue;
1847 
1848  case jpiIsUnknown:
1849  jspGetArg(jsp, &larg);
1850  res = executeBoolItem(cxt, &larg, jb, false);
1851  return res == jpbUnknown ? jpbTrue : jpbFalse;
1852 
1853  case jpiEqual:
1854  case jpiNotEqual:
1855  case jpiLess:
1856  case jpiGreater:
1857  case jpiLessOrEqual:
1858  case jpiGreaterOrEqual:
1859  jspGetLeftArg(jsp, &larg);
1860  jspGetRightArg(jsp, &rarg);
1861  return executePredicate(cxt, jsp, &larg, &rarg, jb, true,
1862  executeComparison, cxt);
1863 
1864  case jpiStartsWith: /* 'whole STARTS WITH initial' */
1865  jspGetLeftArg(jsp, &larg); /* 'whole' */
1866  jspGetRightArg(jsp, &rarg); /* 'initial' */
1867  return executePredicate(cxt, jsp, &larg, &rarg, jb, false,
1868  executeStartsWith, NULL);
1869 
1870  case jpiLikeRegex: /* 'expr LIKE_REGEX pattern FLAGS flags' */
1871  {
1872  /*
1873  * 'expr' is a sequence-returning expression. 'pattern' is a
1874  * regex string literal. SQL/JSON standard requires XQuery
1875  * regexes, but we use Postgres regexes here. 'flags' is a
1876  * string literal converted to integer flags at compile-time.
1877  */
1878  JsonLikeRegexContext lrcxt = {0};
1879 
1880  jspInitByBuffer(&larg, jsp->base,
1881  jsp->content.like_regex.expr);
1882 
1883  return executePredicate(cxt, jsp, &larg, NULL, jb, false,
1884  executeLikeRegex, &lrcxt);
1885  }
1886 
1887  case jpiExists:
1888  jspGetArg(jsp, &larg);
1889 
1890  if (jspStrictAbsenceOfErrors(cxt))
1891  {
1892  /*
1893  * In strict mode we must get a complete list of values to
1894  * check that there are no errors at all.
1895  */
1896  JsonValueList vals = {0};
1898  executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1899  false, &vals);
1900 
1901  if (jperIsError(res))
1902  return jpbUnknown;
1903 
1904  return JsonValueListIsEmpty(&vals) ? jpbFalse : jpbTrue;
1905  }
1906  else
1907  {
1909  executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1910  false, NULL);
1911 
1912  if (jperIsError(res))
1913  return jpbUnknown;
1914 
1915  return res == jperOk ? jpbTrue : jpbFalse;
1916  }
1917 
1918  default:
1919  elog(ERROR, "invalid boolean jsonpath item type: %d", jsp->type);
1920  return jpbUnknown;
1921  }
1922 }
1923 
1924 /*
1925  * Execute nested (filters etc.) boolean expression pushing current SQL/JSON
1926  * item onto the stack.
1927  */
1928 static JsonPathBool
1930  JsonbValue *jb)
1931 {
1932  JsonbValue *prev;
1933  JsonPathBool res;
1934 
1935  prev = cxt->current;
1936  cxt->current = jb;
1937  res = executeBoolItem(cxt, jsp, jb, false);
1938  cxt->current = prev;
1939 
1940  return res;
1941 }
1942 
1943 /*
1944  * Implementation of several jsonpath nodes:
1945  * - jpiAny (.** accessor),
1946  * - jpiAnyKey (.* accessor),
1947  * - jpiAnyArray ([*] accessor)
1948  */
1949 static JsonPathExecResult
1951  JsonValueList *found, uint32 level, uint32 first, uint32 last,
1952  bool ignoreStructuralErrors, bool unwrapNext)
1953 {
1955  JsonbIterator *it;
1956  int32 r;
1957  JsonbValue v;
1958 
1960 
1961  if (level > last)
1962  return res;
1963 
1964  it = JsonbIteratorInit(jbc);
1965 
1966  /*
1967  * Recursively iterate over jsonb objects/arrays
1968  */
1969  while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
1970  {
1971  if (r == WJB_KEY)
1972  {
1973  r = JsonbIteratorNext(&it, &v, true);
1974  Assert(r == WJB_VALUE);
1975  }
1976 
1977  if (r == WJB_VALUE || r == WJB_ELEM)
1978  {
1979 
1980  if (level >= first ||
1981  (first == PG_UINT32_MAX && last == PG_UINT32_MAX &&
1982  v.type != jbvBinary)) /* leaves only requested */
1983  {
1984  /* check expression */
1985  if (jsp)
1986  {
1987  if (ignoreStructuralErrors)
1988  {
1989  bool savedIgnoreStructuralErrors;
1990 
1991  savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors;
1992  cxt->ignoreStructuralErrors = true;
1993  res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
1994  cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors;
1995  }
1996  else
1997  res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
1998 
1999  if (jperIsError(res))
2000  break;
2001 
2002  if (res == jperOk && !found)
2003  break;
2004  }
2005  else if (found)
2006  JsonValueListAppend(found, copyJsonbValue(&v));
2007  else
2008  return jperOk;
2009  }
2010 
2011  if (level < last && v.type == jbvBinary)
2012  {
2014  (cxt, jsp, v.val.binary.data, found,
2015  level + 1, first, last,
2016  ignoreStructuralErrors, unwrapNext);
2017 
2018  if (jperIsError(res))
2019  break;
2020 
2021  if (res == jperOk && found == NULL)
2022  break;
2023  }
2024  }
2025  }
2026 
2027  return res;
2028 }
2029 
2030 /*
2031  * Execute unary or binary predicate.
2032  *
2033  * Predicates have existence semantics, because their operands are item
2034  * sequences. Pairs of items from the left and right operand's sequences are
2035  * checked. TRUE returned only if any pair satisfying the condition is found.
2036  * In strict mode, even if the desired pair has already been found, all pairs
2037  * still need to be examined to check the absence of errors. If any error
2038  * occurs, UNKNOWN (analogous to SQL NULL) is returned.
2039  */
2040 static JsonPathBool
2042  JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb,
2043  bool unwrapRightArg, JsonPathPredicateCallback exec,
2044  void *param)
2045 {
2047  JsonValueListIterator lseqit;
2048  JsonValueList lseq = {0};
2049  JsonValueList rseq = {0};
2050  JsonbValue *lval;
2051  bool error = false;
2052  bool found = false;
2053 
2054  /* Left argument is always auto-unwrapped. */
2055  res = executeItemOptUnwrapResultNoThrow(cxt, larg, jb, true, &lseq);
2056  if (jperIsError(res))
2057  return jpbUnknown;
2058 
2059  if (rarg)
2060  {
2061  /* Right argument is conditionally auto-unwrapped. */
2062  res = executeItemOptUnwrapResultNoThrow(cxt, rarg, jb,
2063  unwrapRightArg, &rseq);
2064  if (jperIsError(res))
2065  return jpbUnknown;
2066  }
2067 
2068  JsonValueListInitIterator(&lseq, &lseqit);
2069  while ((lval = JsonValueListNext(&lseq, &lseqit)))
2070  {
2071  JsonValueListIterator rseqit;
2072  JsonbValue *rval;
2073  bool first = true;
2074 
2075  JsonValueListInitIterator(&rseq, &rseqit);
2076  if (rarg)
2077  rval = JsonValueListNext(&rseq, &rseqit);
2078  else
2079  rval = NULL;
2080 
2081  /* Loop over right arg sequence or do single pass otherwise */
2082  while (rarg ? (rval != NULL) : first)
2083  {
2084  JsonPathBool res = exec(pred, lval, rval, param);
2085 
2086  if (res == jpbUnknown)
2087  {
2088  if (jspStrictAbsenceOfErrors(cxt))
2089  return jpbUnknown;
2090 
2091  error = true;
2092  }
2093  else if (res == jpbTrue)
2094  {
2095  if (!jspStrictAbsenceOfErrors(cxt))
2096  return jpbTrue;
2097 
2098  found = true;
2099  }
2100 
2101  first = false;
2102  if (rarg)
2103  rval = JsonValueListNext(&rseq, &rseqit);
2104  }
2105  }
2106 
2107  if (found) /* possible only in strict mode */
2108  return jpbTrue;
2109 
2110  if (error) /* possible only in lax mode */
2111  return jpbUnknown;
2112 
2113  return jpbFalse;
2114 }
2115 
2116 /*
2117  * Execute binary arithmetic expression on singleton numeric operands.
2118  * Array operands are automatically unwrapped in lax mode.
2119  */
2120 static JsonPathExecResult
2122  JsonbValue *jb, BinaryArithmFunc func,
2123  JsonValueList *found)
2124 {
2125  JsonPathExecResult jper;
2126  JsonPathItem elem;
2127  JsonValueList lseq = {0};
2128  JsonValueList rseq = {0};
2129  JsonbValue *lval;
2130  JsonbValue *rval;
2131  Numeric res;
2132 
2133  jspGetLeftArg(jsp, &elem);
2134 
2135  /*
2136  * XXX: By standard only operands of multiplicative expressions are
2137  * unwrapped. We extend it to other binary arithmetic expressions too.
2138  */
2139  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &lseq);
2140  if (jperIsError(jper))
2141  return jper;
2142 
2143  jspGetRightArg(jsp, &elem);
2144 
2145  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &rseq);
2146  if (jperIsError(jper))
2147  return jper;
2148 
2149  if (JsonValueListLength(&lseq) != 1 ||
2150  !(lval = getScalar(JsonValueListHead(&lseq), jbvNumeric)))
2152  (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
2153  errmsg("left operand of jsonpath operator %s is not a single numeric value",
2154  jspOperationName(jsp->type)))));
2155 
2156  if (JsonValueListLength(&rseq) != 1 ||
2157  !(rval = getScalar(JsonValueListHead(&rseq), jbvNumeric)))
2159  (errcode(ERRCODE_SINGLETON_SQL_JSON_ITEM_REQUIRED),
2160  errmsg("right operand of jsonpath operator %s is not a single numeric value",
2161  jspOperationName(jsp->type)))));
2162 
2163  if (jspThrowErrors(cxt))
2164  {
2165  res = func(lval->val.numeric, rval->val.numeric, NULL);
2166  }
2167  else
2168  {
2169  bool error = false;
2170 
2171  res = func(lval->val.numeric, rval->val.numeric, &error);
2172 
2173  if (error)
2174  return jperError;
2175  }
2176 
2177  if (!jspGetNext(jsp, &elem) && !found)
2178  return jperOk;
2179 
2180  lval = palloc(sizeof(*lval));
2181  lval->type = jbvNumeric;
2182  lval->val.numeric = res;
2183 
2184  return executeNextItem(cxt, jsp, &elem, lval, found, false);
2185 }
2186 
2187 /*
2188  * Execute unary arithmetic expression for each numeric item in its operand's
2189  * sequence. Array operand is automatically unwrapped in lax mode.
2190  */
2191 static JsonPathExecResult
2193  JsonbValue *jb, PGFunction func, JsonValueList *found)
2194 {
2195  JsonPathExecResult jper;
2196  JsonPathExecResult jper2;
2197  JsonPathItem elem;
2198  JsonValueList seq = {0};
2200  JsonbValue *val;
2201  bool hasNext;
2202 
2203  jspGetArg(jsp, &elem);
2204  jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &seq);
2205 
2206  if (jperIsError(jper))
2207  return jper;
2208 
2209  jper = jperNotFound;
2210 
2211  hasNext = jspGetNext(jsp, &elem);
2212 
2213  JsonValueListInitIterator(&seq, &it);
2214  while ((val = JsonValueListNext(&seq, &it)))
2215  {
2216  if ((val = getScalar(val, jbvNumeric)))
2217  {
2218  if (!found && !hasNext)
2219  return jperOk;
2220  }
2221  else
2222  {
2223  if (!found && !hasNext)
2224  continue; /* skip non-numerics processing */
2225 
2227  (errcode(ERRCODE_SQL_JSON_NUMBER_NOT_FOUND),
2228  errmsg("operand of unary jsonpath operator %s is not a numeric value",
2229  jspOperationName(jsp->type)))));
2230  }
2231 
2232  if (func)
2233  val->val.numeric =
2235  NumericGetDatum(val->val.numeric)));
2236 
2237  jper2 = executeNextItem(cxt, jsp, &elem, val, found, false);
2238 
2239  if (jperIsError(jper2))
2240  return jper2;
2241 
2242  if (jper2 == jperOk)
2243  {
2244  if (!found)
2245  return jperOk;
2246  jper = jperOk;
2247  }
2248  }
2249 
2250  return jper;
2251 }
2252 
2253 /*
2254  * STARTS_WITH predicate callback.
2255  *
2256  * Check if the 'whole' string starts from 'initial' string.
2257  */
2258 static JsonPathBool
2260  void *param)
2261 {
2262  if (!(whole = getScalar(whole, jbvString)))
2263  return jpbUnknown; /* error */
2264 
2265  if (!(initial = getScalar(initial, jbvString)))
2266  return jpbUnknown; /* error */
2267 
2268  if (whole->val.string.len >= initial->val.string.len &&
2269  !memcmp(whole->val.string.val,
2270  initial->val.string.val,
2271  initial->val.string.len))
2272  return jpbTrue;
2273 
2274  return jpbFalse;
2275 }
2276 
2277 /*
2278  * LIKE_REGEX predicate callback.
2279  *
2280  * Check if the string matches regex pattern.
2281  */
2282 static JsonPathBool
2284  void *param)
2285 {
2286  JsonLikeRegexContext *cxt = param;
2287 
2288  if (!(str = getScalar(str, jbvString)))
2289  return jpbUnknown;
2290 
2291  /* Cache regex text and converted flags. */
2292  if (!cxt->regex)
2293  {
2294  cxt->regex =
2296  jsp->content.like_regex.patternlen);
2297  (void) jspConvertRegexFlags(jsp->content.like_regex.flags,
2298  &(cxt->cflags), NULL);
2299  }
2300 
2301  if (RE_compile_and_execute(cxt->regex, str->val.string.val,
2302  str->val.string.len,
2303  cxt->cflags, DEFAULT_COLLATION_OID, 0, NULL))
2304  return jpbTrue;
2305 
2306  return jpbFalse;
2307 }
2308 
2309 /*
2310  * Execute numeric item methods (.abs(), .floor(), .ceil()) using the specified
2311  * user function 'func'.
2312  */
2313 static JsonPathExecResult
2315  JsonbValue *jb, bool unwrap, PGFunction func,
2316  JsonValueList *found)
2317 {
2319  Datum datum;
2320 
2321  if (unwrap && JsonbType(jb) == jbvArray)
2322  return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
2323 
2324  if (!(jb = getScalar(jb, jbvNumeric)))
2326  (errcode(ERRCODE_NON_NUMERIC_SQL_JSON_ITEM),
2327  errmsg("jsonpath item method .%s() can only be applied to a numeric value",
2328  jspOperationName(jsp->type)))));
2329 
2330  datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
2331 
2332  if (!jspGetNext(jsp, &next) && !found)
2333  return jperOk;
2334 
2335  jb = palloc(sizeof(*jb));
2336  jb->type = jbvNumeric;
2337  jb->val.numeric = DatumGetNumeric(datum);
2338 
2339  return executeNextItem(cxt, jsp, &next, jb, found, false);
2340 }
2341 
2342 /*
2343  * Implementation of the .datetime() and related methods.
2344  *
2345  * Converts a string into a date/time value. The actual type is determined at
2346  * run time.
2347  * If an argument is provided, this argument is used as a template string.
2348  * Otherwise, the first fitting ISO format is selected.
2349  *
2350  * .date(), .time(), .time_tz(), .timestamp(), .timestamp_tz() methods don't
2351  * have a format, so ISO format is used. However, except for .date(), they all
2352  * take an optional time precision.
2353  */
2354 static JsonPathExecResult
2356  JsonbValue *jb, JsonValueList *found)
2357 {
2358  JsonbValue jbvbuf;
2359  Datum value;
2360  text *datetime;
2361  Oid collid;
2362  Oid typid;
2363  int32 typmod = -1;
2364  int tz = 0;
2365  bool hasNext;
2367  JsonPathItem elem;
2368  int32 time_precision = -1;
2369 
2370  if (!(jb = getScalar(jb, jbvString)))
2372  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2373  errmsg("jsonpath item method .%s() can only be applied to a string",
2374  jspOperationName(jsp->type)))));
2375 
2376  datetime = cstring_to_text_with_len(jb->val.string.val,
2377  jb->val.string.len);
2378 
2379  /*
2380  * At some point we might wish to have callers supply the collation to
2381  * use, but right now it's unclear that they'd be able to do better than
2382  * DEFAULT_COLLATION_OID anyway.
2383  */
2384  collid = DEFAULT_COLLATION_OID;
2385 
2386  /*
2387  * .datetime(template) has an argument, the rest of the methods don't have
2388  * an argument. So we handle that separately.
2389  */
2390  if (jsp->type == jpiDatetime && jsp->content.arg)
2391  {
2392  text *template;
2393  char *template_str;
2394  int template_len;
2395  ErrorSaveContext escontext = {T_ErrorSaveContext};
2396 
2397  jspGetArg(jsp, &elem);
2398 
2399  if (elem.type != jpiString)
2400  elog(ERROR, "invalid jsonpath item type for .datetime() argument");
2401 
2402  template_str = jspGetString(&elem, &template_len);
2403 
2404  template = cstring_to_text_with_len(template_str,
2405  template_len);
2406 
2407  value = parse_datetime(datetime, template, collid, true,
2408  &typid, &typmod, &tz,
2409  jspThrowErrors(cxt) ? NULL : (Node *) &escontext);
2410 
2411  if (escontext.error_occurred)
2412  res = jperError;
2413  else
2414  res = jperOk;
2415  }
2416  else
2417  {
2418  /*
2419  * According to SQL/JSON standard enumerate ISO formats for: date,
2420  * timetz, time, timestamptz, timestamp.
2421  *
2422  * We also support ISO 8601 format (with "T") for timestamps, because
2423  * to_json[b]() functions use this format.
2424  */
2425  static const char *fmt_str[] =
2426  {
2427  "yyyy-mm-dd", /* date */
2428  "HH24:MI:SS.USTZ", /* timetz */
2429  "HH24:MI:SSTZ",
2430  "HH24:MI:SS.US", /* time without tz */
2431  "HH24:MI:SS",
2432  "yyyy-mm-dd HH24:MI:SS.USTZ", /* timestamptz */
2433  "yyyy-mm-dd HH24:MI:SSTZ",
2434  "yyyy-mm-dd\"T\"HH24:MI:SS.USTZ",
2435  "yyyy-mm-dd\"T\"HH24:MI:SSTZ",
2436  "yyyy-mm-dd HH24:MI:SS.US", /* timestamp without tz */
2437  "yyyy-mm-dd HH24:MI:SS",
2438  "yyyy-mm-dd\"T\"HH24:MI:SS.US",
2439  "yyyy-mm-dd\"T\"HH24:MI:SS"
2440  };
2441 
2442  /* cache for format texts */
2443  static text *fmt_txt[lengthof(fmt_str)] = {0};
2444  int i;
2445 
2446  /*
2447  * Check for optional precision for methods other than .datetime() and
2448  * .date()
2449  */
2450  if (jsp->type != jpiDatetime && jsp->type != jpiDate &&
2451  jsp->content.arg)
2452  {
2453  bool have_error;
2454 
2455  jspGetArg(jsp, &elem);
2456 
2457  if (elem.type != jpiNumeric)
2458  elog(ERROR, "invalid jsonpath item type for %s argument",
2459  jspOperationName(jsp->type));
2460 
2461  time_precision = numeric_int4_opt_error(jspGetNumeric(&elem),
2462  &have_error);
2463  if (have_error)
2465  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2466  errmsg("time precision of jsonpath item method .%s() is out of range for type integer",
2467  jspOperationName(jsp->type)))));
2468  }
2469 
2470  /* loop until datetime format fits */
2471  for (i = 0; i < lengthof(fmt_str); i++)
2472  {
2473  ErrorSaveContext escontext = {T_ErrorSaveContext};
2474 
2475  if (!fmt_txt[i])
2476  {
2477  MemoryContext oldcxt =
2479 
2480  fmt_txt[i] = cstring_to_text(fmt_str[i]);
2481  MemoryContextSwitchTo(oldcxt);
2482  }
2483 
2484  value = parse_datetime(datetime, fmt_txt[i], collid, true,
2485  &typid, &typmod, &tz,
2486  (Node *) &escontext);
2487 
2488  if (!escontext.error_occurred)
2489  {
2490  res = jperOk;
2491  break;
2492  }
2493  }
2494 
2495  if (res == jperNotFound)
2496  {
2497  if (jsp->type == jpiDatetime)
2499  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2500  errmsg("%s format is not recognized: \"%s\"",
2501  "datetime", text_to_cstring(datetime)),
2502  errhint("Use a datetime template argument to specify the input data format."))));
2503  else
2505  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2506  errmsg("%s format is not recognized: \"%s\"",
2507  jspOperationName(jsp->type), text_to_cstring(datetime)))));
2508 
2509  }
2510  }
2511 
2512  /*
2513  * parse_datetime() processes the entire input string per the template or
2514  * ISO format and returns the Datum in best fitted datetime type. So, if
2515  * this call is for a specific datatype, then we do the conversion here.
2516  * Throw an error for incompatible types.
2517  */
2518  switch (jsp->type)
2519  {
2520  case jpiDatetime: /* Nothing to do for DATETIME */
2521  break;
2522  case jpiDate:
2523  {
2524  /* Convert result type to date */
2525  switch (typid)
2526  {
2527  case DATEOID: /* Nothing to do for DATE */
2528  break;
2529  case TIMEOID:
2530  case TIMETZOID:
2532  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2533  errmsg("%s format is not recognized: \"%s\"",
2534  "date", text_to_cstring(datetime)))));
2535  break;
2536  case TIMESTAMPOID:
2538  value);
2539  break;
2540  case TIMESTAMPTZOID:
2542  "timestamptz", "date");
2544  value);
2545  break;
2546  default:
2547  elog(ERROR, "type with oid %u not supported", typid);
2548  }
2549 
2550  typid = DATEOID;
2551  }
2552  break;
2553  case jpiTime:
2554  {
2555  /* Convert result type to time without time zone */
2556  switch (typid)
2557  {
2558  case DATEOID:
2560  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2561  errmsg("%s format is not recognized: \"%s\"",
2562  "time", text_to_cstring(datetime)))));
2563  break;
2564  case TIMEOID: /* Nothing to do for TIME */
2565  break;
2566  case TIMETZOID:
2568  "timetz", "time");
2570  value);
2571  break;
2572  case TIMESTAMPOID:
2574  value);
2575  break;
2576  case TIMESTAMPTZOID:
2578  "timestamptz", "time");
2580  value);
2581  break;
2582  default:
2583  elog(ERROR, "type with oid %u not supported", typid);
2584  }
2585 
2586  /* Force the user-given time precision, if any */
2587  if (time_precision != -1)
2588  {
2589  TimeADT result;
2590 
2591  /* Get a warning when precision is reduced */
2592  time_precision = anytime_typmod_check(false,
2593  time_precision);
2594  result = DatumGetTimeADT(value);
2595  AdjustTimeForTypmod(&result, time_precision);
2596  value = TimeADTGetDatum(result);
2597 
2598  /* Update the typmod value with the user-given precision */
2599  typmod = time_precision;
2600  }
2601 
2602  typid = TIMEOID;
2603  }
2604  break;
2605  case jpiTimeTz:
2606  {
2607  /* Convert result type to time with time zone */
2608  switch (typid)
2609  {
2610  case DATEOID:
2611  case TIMESTAMPOID:
2613  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2614  errmsg("%s format is not recognized: \"%s\"",
2615  "time_tz", text_to_cstring(datetime)))));
2616  break;
2617  case TIMEOID:
2619  "time", "timetz");
2621  value);
2622  break;
2623  case TIMETZOID: /* Nothing to do for TIMETZ */
2624  break;
2625  case TIMESTAMPTZOID:
2627  value);
2628  break;
2629  default:
2630  elog(ERROR, "type with oid %u not supported", typid);
2631  }
2632 
2633  /* Force the user-given time precision, if any */
2634  if (time_precision != -1)
2635  {
2636  TimeTzADT *result;
2637 
2638  /* Get a warning when precision is reduced */
2639  time_precision = anytime_typmod_check(true,
2640  time_precision);
2641  result = DatumGetTimeTzADTP(value);
2642  AdjustTimeForTypmod(&result->time, time_precision);
2643  value = TimeTzADTPGetDatum(result);
2644 
2645  /* Update the typmod value with the user-given precision */
2646  typmod = time_precision;
2647  }
2648 
2649  typid = TIMETZOID;
2650  }
2651  break;
2652  case jpiTimestamp:
2653  {
2654  /* Convert result type to timestamp without time zone */
2655  switch (typid)
2656  {
2657  case DATEOID:
2659  value);
2660  break;
2661  case TIMEOID:
2662  case TIMETZOID:
2664  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2665  errmsg("%s format is not recognized: \"%s\"",
2666  "timestamp", text_to_cstring(datetime)))));
2667  break;
2668  case TIMESTAMPOID: /* Nothing to do for TIMESTAMP */
2669  break;
2670  case TIMESTAMPTZOID:
2672  "timestamptz", "timestamp");
2674  value);
2675  break;
2676  default:
2677  elog(ERROR, "type with oid %u not supported", typid);
2678  }
2679 
2680  /* Force the user-given time precision, if any */
2681  if (time_precision != -1)
2682  {
2683  Timestamp result;
2684  ErrorSaveContext escontext = {T_ErrorSaveContext};
2685 
2686  /* Get a warning when precision is reduced */
2687  time_precision = anytimestamp_typmod_check(false,
2688  time_precision);
2689  result = DatumGetTimestamp(value);
2690  AdjustTimestampForTypmod(&result, time_precision,
2691  (Node *) &escontext);
2692  if (escontext.error_occurred) /* should not happen */
2694  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2695  errmsg("time precision of jsonpath item method .%s() is invalid",
2696  jspOperationName(jsp->type)))));
2697  value = TimestampGetDatum(result);
2698 
2699  /* Update the typmod value with the user-given precision */
2700  typmod = time_precision;
2701  }
2702 
2703  typid = TIMESTAMPOID;
2704  }
2705  break;
2706  case jpiTimestampTz:
2707  {
2708  /* Convert result type to timestamp with time zone */
2709  switch (typid)
2710  {
2711  case DATEOID:
2713  "date", "timestamptz");
2715  value);
2716  break;
2717  case TIMEOID:
2718  case TIMETZOID:
2720  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2721  errmsg("%s format is not recognized: \"%s\"",
2722  "timestamp_tz", text_to_cstring(datetime)))));
2723  break;
2724  case TIMESTAMPOID:
2726  "timestamp", "timestamptz");
2728  value);
2729  break;
2730  case TIMESTAMPTZOID: /* Nothing to do for TIMESTAMPTZ */
2731  break;
2732  default:
2733  elog(ERROR, "type with oid %u not supported", typid);
2734  }
2735 
2736  /* Force the user-given time precision, if any */
2737  if (time_precision != -1)
2738  {
2739  Timestamp result;
2740  ErrorSaveContext escontext = {T_ErrorSaveContext};
2741 
2742  /* Get a warning when precision is reduced */
2743  time_precision = anytimestamp_typmod_check(true,
2744  time_precision);
2745  result = DatumGetTimestampTz(value);
2746  AdjustTimestampForTypmod(&result, time_precision,
2747  (Node *) &escontext);
2748  if (escontext.error_occurred) /* should not happen */
2750  (errcode(ERRCODE_INVALID_ARGUMENT_FOR_SQL_JSON_DATETIME_FUNCTION),
2751  errmsg("time precision of jsonpath item method .%s() is invalid",
2752  jspOperationName(jsp->type)))));
2753  value = TimestampTzGetDatum(result);
2754 
2755  /* Update the typmod value with the user-given precision */
2756  typmod = time_precision;
2757  }
2758 
2759  typid = TIMESTAMPTZOID;
2760  }
2761  break;
2762  default:
2763  elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
2764  }
2765 
2766  pfree(datetime);
2767 
2768  if (jperIsError(res))
2769  return res;
2770 
2771  hasNext = jspGetNext(jsp, &elem);
2772 
2773  if (!hasNext && !found)
2774  return res;
2775 
2776  jb = hasNext ? &jbvbuf : palloc(sizeof(*jb));
2777 
2778  jb->type = jbvDatetime;
2779  jb->val.datetime.value = value;
2780  jb->val.datetime.typid = typid;
2781  jb->val.datetime.typmod = typmod;
2782  jb->val.datetime.tz = tz;
2783 
2784  return executeNextItem(cxt, jsp, &elem, jb, found, hasNext);
2785 }
2786 
2787 /*
2788  * Implementation of .keyvalue() method.
2789  *
2790  * .keyvalue() method returns a sequence of object's key-value pairs in the
2791  * following format: '{ "key": key, "value": value, "id": id }'.
2792  *
2793  * "id" field is an object identifier which is constructed from the two parts:
2794  * base object id and its binary offset in base object's jsonb:
2795  * id = 10000000000 * base_object_id + obj_offset_in_base_object
2796  *
2797  * 10000000000 (10^10) -- is a first round decimal number greater than 2^32
2798  * (maximal offset in jsonb). Decimal multiplier is used here to improve the
2799  * readability of identifiers.
2800  *
2801  * Base object is usually a root object of the path: context item '$' or path
2802  * variable '$var', literals can't produce objects for now. But if the path
2803  * contains generated objects (.keyvalue() itself, for example), then they
2804  * become base object for the subsequent .keyvalue().
2805  *
2806  * Id of '$' is 0. Id of '$var' is its ordinal (positive) number in the list
2807  * of variables (see getJsonPathVariable()). Ids for generated objects
2808  * are assigned using global counter JsonPathExecContext.lastGeneratedObjectId.
2809  */
2810 static JsonPathExecResult
2812  JsonbValue *jb, JsonValueList *found)
2813 {
2816  JsonbContainer *jbc;
2817  JsonbValue key;
2818  JsonbValue val;
2819  JsonbValue idval;
2820  JsonbValue keystr;
2821  JsonbValue valstr;
2822  JsonbValue idstr;
2823  JsonbIterator *it;
2824  JsonbIteratorToken tok;
2825  int64 id;
2826  bool hasNext;
2827 
2828  if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
2830  (errcode(ERRCODE_SQL_JSON_OBJECT_NOT_FOUND),
2831  errmsg("jsonpath item method .%s() can only be applied to an object",
2832  jspOperationName(jsp->type)))));
2833 
2834  jbc = jb->val.binary.data;
2835 
2836  if (!JsonContainerSize(jbc))
2837  return jperNotFound; /* no key-value pairs */
2838 
2839  hasNext = jspGetNext(jsp, &next);
2840 
2841  keystr.type = jbvString;
2842  keystr.val.string.val = "key";
2843  keystr.val.string.len = 3;
2844 
2845  valstr.type = jbvString;
2846  valstr.val.string.val = "value";
2847  valstr.val.string.len = 5;
2848 
2849  idstr.type = jbvString;
2850  idstr.val.string.val = "id";
2851  idstr.val.string.len = 2;
2852 
2853  /* construct object id from its base object and offset inside that */
2854  id = jb->type != jbvBinary ? 0 :
2855  (int64) ((char *) jbc - (char *) cxt->baseObject.jbc);
2856  id += (int64) cxt->baseObject.id * INT64CONST(10000000000);
2857 
2858  idval.type = jbvNumeric;
2859  idval.val.numeric = int64_to_numeric(id);
2860 
2861  it = JsonbIteratorInit(jbc);
2862 
2863  while ((tok = JsonbIteratorNext(&it, &key, true)) != WJB_DONE)
2864  {
2865  JsonBaseObjectInfo baseObject;
2866  JsonbValue obj;
2868  JsonbValue *keyval;
2869  Jsonb *jsonb;
2870 
2871  if (tok != WJB_KEY)
2872  continue;
2873 
2874  res = jperOk;
2875 
2876  if (!hasNext && !found)
2877  break;
2878 
2879  tok = JsonbIteratorNext(&it, &val, true);
2880  Assert(tok == WJB_VALUE);
2881 
2882  ps = NULL;
2884 
2885  pushJsonbValue(&ps, WJB_KEY, &keystr);
2887 
2888  pushJsonbValue(&ps, WJB_KEY, &valstr);
2890 
2891  pushJsonbValue(&ps, WJB_KEY, &idstr);
2892  pushJsonbValue(&ps, WJB_VALUE, &idval);
2893 
2894  keyval = pushJsonbValue(&ps, WJB_END_OBJECT, NULL);
2895 
2896  jsonb = JsonbValueToJsonb(keyval);
2897 
2898  JsonbInitBinary(&obj, jsonb);
2899 
2900  baseObject = setBaseObject(cxt, &obj, cxt->lastGeneratedObjectId++);
2901 
2902  res = executeNextItem(cxt, jsp, &next, &obj, found, true);
2903 
2904  cxt->baseObject = baseObject;
2905 
2906  if (jperIsError(res))
2907  return res;
2908 
2909  if (res == jperOk && !found)
2910  break;
2911  }
2912 
2913  return res;
2914 }
2915 
2916 /*
2917  * Convert boolean execution status 'res' to a boolean JSON item and execute
2918  * next jsonpath.
2919  */
2920 static JsonPathExecResult
2922  JsonValueList *found, JsonPathBool res)
2923 {
2925  JsonbValue jbv;
2926 
2927  if (!jspGetNext(jsp, &next) && !found)
2928  return jperOk; /* found singleton boolean value */
2929 
2930  if (res == jpbUnknown)
2931  {
2932  jbv.type = jbvNull;
2933  }
2934  else
2935  {
2936  jbv.type = jbvBool;
2937  jbv.val.boolean = res == jpbTrue;
2938  }
2939 
2940  return executeNextItem(cxt, jsp, &next, &jbv, found, true);
2941 }
2942 
2943 /*
2944  * Convert jsonpath's scalar or variable node to actual jsonb value.
2945  *
2946  * If node is a variable then its id returned, otherwise 0 returned.
2947  */
2948 static void
2950  JsonbValue *value)
2951 {
2952  switch (item->type)
2953  {
2954  case jpiNull:
2955  value->type = jbvNull;
2956  break;
2957  case jpiBool:
2958  value->type = jbvBool;
2959  value->val.boolean = jspGetBool(item);
2960  break;
2961  case jpiNumeric:
2962  value->type = jbvNumeric;
2963  value->val.numeric = jspGetNumeric(item);
2964  break;
2965  case jpiString:
2966  value->type = jbvString;
2967  value->val.string.val = jspGetString(item,
2968  &value->val.string.len);
2969  break;
2970  case jpiVariable:
2971  getJsonPathVariable(cxt, item, value);
2972  return;
2973  default:
2974  elog(ERROR, "unexpected jsonpath item type");
2975  }
2976 }
2977 
2978 /*
2979  * Returns the computed value of a JSON path variable with given name.
2980  */
2981 static JsonbValue *
2982 GetJsonPathVar(void *cxt, char *varName, int varNameLen,
2983  JsonbValue *baseObject, int *baseObjectId)
2984 {
2985  JsonPathVariable *var = NULL;
2986  List *vars = cxt;
2987  ListCell *lc;
2988  JsonbValue *result;
2989  int id = 1;
2990 
2991  foreach(lc, vars)
2992  {
2993  JsonPathVariable *curvar = lfirst(lc);
2994 
2995  if (!strncmp(curvar->name, varName, varNameLen))
2996  {
2997  var = curvar;
2998  break;
2999  }
3000 
3001  id++;
3002  }
3003 
3004  if (var == NULL)
3005  {
3006  *baseObjectId = -1;
3007  return NULL;
3008  }
3009 
3010  result = palloc(sizeof(JsonbValue));
3011  if (var->isnull)
3012  {
3013  *baseObjectId = 0;
3014  result->type = jbvNull;
3015  }
3016  else
3017  JsonItemFromDatum(var->value, var->typid, var->typmod, result);
3018 
3019  *baseObject = *result;
3020  *baseObjectId = id;
3021 
3022  return result;
3023 }
3024 
3025 static int
3027 {
3028  List *vars = (List *) cxt;
3029 
3030  return list_length(vars);
3031 }
3032 
3033 
3034 /*
3035  * Initialize JsonbValue to pass to jsonpath executor from given
3036  * datum value of the specified type.
3037  */
3038 static void
3040 {
3041  switch (typid)
3042  {
3043  case BOOLOID:
3044  res->type = jbvBool;
3045  res->val.boolean = DatumGetBool(val);
3046  break;
3047  case NUMERICOID:
3049  break;
3050  case INT2OID:
3052  break;
3053  case INT4OID:
3055  break;
3056  case INT8OID:
3058  break;
3059  case FLOAT4OID:
3061  break;
3062  case FLOAT8OID:
3064  break;
3065  case TEXTOID:
3066  case VARCHAROID:
3067  res->type = jbvString;
3068  res->val.string.val = VARDATA_ANY(val);
3069  res->val.string.len = VARSIZE_ANY_EXHDR(val);
3070  break;
3071  case DATEOID:
3072  case TIMEOID:
3073  case TIMETZOID:
3074  case TIMESTAMPOID:
3075  case TIMESTAMPTZOID:
3076  res->type = jbvDatetime;
3077  res->val.datetime.value = val;
3078  res->val.datetime.typid = typid;
3079  res->val.datetime.typmod = typmod;
3080  res->val.datetime.tz = 0;
3081  break;
3082  case JSONBOID:
3083  {
3084  JsonbValue *jbv = res;
3085  Jsonb *jb = DatumGetJsonbP(val);
3086 
3087  if (JsonContainerIsScalar(&jb->root))
3088  {
3089  bool result PG_USED_FOR_ASSERTS_ONLY;
3090 
3091  result = JsonbExtractScalar(&jb->root, jbv);
3092  Assert(result);
3093  }
3094  else
3095  JsonbInitBinary(jbv, jb);
3096  break;
3097  }
3098  case JSONOID:
3099  {
3100  text *txt = DatumGetTextP(val);
3101  char *str = text_to_cstring(txt);
3102  Jsonb *jb;
3103 
3105  CStringGetDatum(str)));
3106  pfree(str);
3107 
3108  JsonItemFromDatum(JsonbPGetDatum(jb), JSONBOID, -1, res);
3109  break;
3110  }
3111  default:
3112  ereport(ERROR,
3113  errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3114  errmsg("could not convert value of type %s to jsonpath",
3115  format_type_be(typid)));
3116  }
3117 }
3118 
3119 /* Initialize numeric value from the given datum */
3120 static void
3122 {
3123  jbv->type = jbvNumeric;
3124  jbv->val.numeric = DatumGetNumeric(num);
3125 }
3126 
3127 /*
3128  * Get the value of variable passed to jsonpath executor
3129  */
3130 static void
3132  JsonbValue *value)
3133 {
3134  char *varName;
3135  int varNameLength;
3136  JsonbValue baseObject;
3137  int baseObjectId;
3138  JsonbValue *v;
3139 
3141  varName = jspGetString(variable, &varNameLength);
3142 
3143  if (cxt->vars == NULL ||
3144  (v = cxt->getVar(cxt->vars, varName, varNameLength,
3145  &baseObject, &baseObjectId)) == NULL)
3146  ereport(ERROR,
3147  (errcode(ERRCODE_UNDEFINED_OBJECT),
3148  errmsg("could not find jsonpath variable \"%s\"",
3149  pnstrdup(varName, varNameLength))));
3150 
3151  if (baseObjectId > 0)
3152  {
3153  *value = *v;
3154  setBaseObject(cxt, &baseObject, baseObjectId);
3155  }
3156 }
3157 
3158 /*
3159  * Definition of JsonPathGetVarCallback for when JsonPathExecContext.vars
3160  * is specified as a jsonb value.
3161  */
3162 static JsonbValue *
3163 getJsonPathVariableFromJsonb(void *varsJsonb, char *varName, int varNameLength,
3164  JsonbValue *baseObject, int *baseObjectId)
3165 {
3166  Jsonb *vars = varsJsonb;
3167  JsonbValue tmp;
3168  JsonbValue *result;
3169 
3170  tmp.type = jbvString;
3171  tmp.val.string.val = varName;
3172  tmp.val.string.len = varNameLength;
3173 
3174  result = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
3175 
3176  if (result == NULL)
3177  {
3178  *baseObjectId = -1;
3179  return NULL;
3180  }
3181 
3182  *baseObjectId = 1;
3183  JsonbInitBinary(baseObject, vars);
3184 
3185  return result;
3186 }
3187 
3188 /*
3189  * Definition of JsonPathCountVarsCallback for when JsonPathExecContext.vars
3190  * is specified as a jsonb value.
3191  */
3192 static int
3193 countVariablesFromJsonb(void *varsJsonb)
3194 {
3195  Jsonb *vars = varsJsonb;
3196 
3197  if (vars && !JsonContainerIsObject(&vars->root))
3198  {
3199  ereport(ERROR,
3200  errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3201  errmsg("\"vars\" argument is not an object"),
3202  errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object."));
3203  }
3204 
3205  /* count of base objects */
3206  return vars != NULL ? 1 : 0;
3207 }
3208 
3209 /**************** Support functions for JsonPath execution *****************/
3210 
3211 /*
3212  * Returns the size of an array item, or -1 if item is not an array.
3213  */
3214 static int
3216 {
3217  Assert(jb->type != jbvArray);
3218 
3219  if (jb->type == jbvBinary)
3220  {
3221  JsonbContainer *jbc = jb->val.binary.data;
3222 
3223  if (JsonContainerIsArray(jbc) && !JsonContainerIsScalar(jbc))
3224  return JsonContainerSize(jbc);
3225  }
3226 
3227  return -1;
3228 }
3229 
3230 /* Comparison predicate callback. */
3231 static JsonPathBool
3233 {
3235 
3236  return compareItems(cmp->type, lv, rv, cxt->useTz);
3237 }
3238 
3239 /*
3240  * Perform per-byte comparison of two strings.
3241  */
3242 static int
3243 binaryCompareStrings(const char *s1, int len1,
3244  const char *s2, int len2)
3245 {
3246  int cmp;
3247 
3248  cmp = memcmp(s1, s2, Min(len1, len2));
3249 
3250  if (cmp != 0)
3251  return cmp;
3252 
3253  if (len1 == len2)
3254  return 0;
3255 
3256  return len1 < len2 ? -1 : 1;
3257 }
3258 
3259 /*
3260  * Compare two strings in the current server encoding using Unicode codepoint
3261  * collation.
3262  */
3263 static int
3264 compareStrings(const char *mbstr1, int mblen1,
3265  const char *mbstr2, int mblen2)
3266 {
3267  if (GetDatabaseEncoding() == PG_SQL_ASCII ||
3269  {
3270  /*
3271  * It's known property of UTF-8 strings that their per-byte comparison
3272  * result matches codepoints comparison result. ASCII can be
3273  * considered as special case of UTF-8.
3274  */
3275  return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
3276  }
3277  else
3278  {
3279  char *utf8str1,
3280  *utf8str2;
3281  int cmp,
3282  utf8len1,
3283  utf8len2;
3284 
3285  /*
3286  * We have to convert other encodings to UTF-8 first, then compare.
3287  * Input strings may be not null-terminated and pg_server_to_any() may
3288  * return them "as is". So, use strlen() only if there is real
3289  * conversion.
3290  */
3291  utf8str1 = pg_server_to_any(mbstr1, mblen1, PG_UTF8);
3292  utf8str2 = pg_server_to_any(mbstr2, mblen2, PG_UTF8);
3293  utf8len1 = (mbstr1 == utf8str1) ? mblen1 : strlen(utf8str1);
3294  utf8len2 = (mbstr2 == utf8str2) ? mblen2 : strlen(utf8str2);
3295 
3296  cmp = binaryCompareStrings(utf8str1, utf8len1, utf8str2, utf8len2);
3297 
3298  /*
3299  * If pg_server_to_any() did no real conversion, then we actually
3300  * compared original strings. So, we already done.
3301  */
3302  if (mbstr1 == utf8str1 && mbstr2 == utf8str2)
3303  return cmp;
3304 
3305  /* Free memory if needed */
3306  if (mbstr1 != utf8str1)
3307  pfree(utf8str1);
3308  if (mbstr2 != utf8str2)
3309  pfree(utf8str2);
3310 
3311  /*
3312  * When all Unicode codepoints are equal, return result of binary
3313  * comparison. In some edge cases, same characters may have different
3314  * representations in encoding. Then our behavior could diverge from
3315  * standard. However, that allow us to do simple binary comparison
3316  * for "==" operator, which is performance critical in typical cases.
3317  * In future to implement strict standard conformance, we can do
3318  * normalization of input JSON strings.
3319  */
3320  if (cmp == 0)
3321  return binaryCompareStrings(mbstr1, mblen1, mbstr2, mblen2);
3322  else
3323  return cmp;
3324  }
3325 }
3326 
3327 /*
3328  * Compare two SQL/JSON items using comparison operation 'op'.
3329  */
3330 static JsonPathBool
3331 compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2, bool useTz)
3332 {
3333  int cmp;
3334  bool res;
3335 
3336  if (jb1->type != jb2->type)
3337  {
3338  if (jb1->type == jbvNull || jb2->type == jbvNull)
3339 
3340  /*
3341  * Equality and order comparison of nulls to non-nulls returns
3342  * always false, but inequality comparison returns true.
3343  */
3344  return op == jpiNotEqual ? jpbTrue : jpbFalse;
3345 
3346  /* Non-null items of different types are not comparable. */
3347  return jpbUnknown;
3348  }
3349 
3350  switch (jb1->type)
3351  {
3352  case jbvNull:
3353  cmp = 0;
3354  break;
3355  case jbvBool:
3356  cmp = jb1->val.boolean == jb2->val.boolean ? 0 :
3357  jb1->val.boolean ? 1 : -1;
3358  break;
3359  case jbvNumeric:
3360  cmp = compareNumeric(jb1->val.numeric, jb2->val.numeric);
3361  break;
3362  case jbvString:
3363  if (op == jpiEqual)
3364  return jb1->val.string.len != jb2->val.string.len ||
3365  memcmp(jb1->val.string.val,
3366  jb2->val.string.val,
3367  jb1->val.string.len) ? jpbFalse : jpbTrue;
3368 
3369  cmp = compareStrings(jb1->val.string.val, jb1->val.string.len,
3370  jb2->val.string.val, jb2->val.string.len);
3371  break;
3372  case jbvDatetime:
3373  {
3374  bool cast_error;
3375 
3376  cmp = compareDatetime(jb1->val.datetime.value,
3377  jb1->val.datetime.typid,
3378  jb2->val.datetime.value,
3379  jb2->val.datetime.typid,
3380  useTz,
3381  &cast_error);
3382 
3383  if (cast_error)
3384  return jpbUnknown;
3385  }
3386  break;
3387 
3388  case jbvBinary:
3389  case jbvArray:
3390  case jbvObject:
3391  return jpbUnknown; /* non-scalars are not comparable */
3392 
3393  default:
3394  elog(ERROR, "invalid jsonb value type %d", jb1->type);
3395  }
3396 
3397  switch (op)
3398  {
3399  case jpiEqual:
3400  res = (cmp == 0);
3401  break;
3402  case jpiNotEqual:
3403  res = (cmp != 0);
3404  break;
3405  case jpiLess:
3406  res = (cmp < 0);
3407  break;
3408  case jpiGreater:
3409  res = (cmp > 0);
3410  break;
3411  case jpiLessOrEqual:
3412  res = (cmp <= 0);
3413  break;
3414  case jpiGreaterOrEqual:
3415  res = (cmp >= 0);
3416  break;
3417  default:
3418  elog(ERROR, "unrecognized jsonpath operation: %d", op);
3419  return jpbUnknown;
3420  }
3421 
3422  return res ? jpbTrue : jpbFalse;
3423 }
3424 
3425 /* Compare two numerics */
3426 static int
3428 {
3430  NumericGetDatum(a),
3431  NumericGetDatum(b)));
3432 }
3433 
3434 static JsonbValue *
3436 {
3437  JsonbValue *dst = palloc(sizeof(*dst));
3438 
3439  *dst = *src;
3440 
3441  return dst;
3442 }
3443 
3444 /*
3445  * Execute array subscript expression and convert resulting numeric item to
3446  * the integer type with truncation.
3447  */
3448 static JsonPathExecResult
3450  int32 *index)
3451 {
3452  JsonbValue *jbv;
3453  JsonValueList found = {0};
3454  JsonPathExecResult res = executeItem(cxt, jsp, jb, &found);
3455  Datum numeric_index;
3456  bool have_error = false;
3457 
3458  if (jperIsError(res))
3459  return res;
3460 
3461  if (JsonValueListLength(&found) != 1 ||
3462  !(jbv = getScalar(JsonValueListHead(&found), jbvNumeric)))
3464  (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
3465  errmsg("jsonpath array subscript is not a single numeric value"))));
3466 
3467  numeric_index = DirectFunctionCall2(numeric_trunc,
3468  NumericGetDatum(jbv->val.numeric),
3469  Int32GetDatum(0));
3470 
3471  *index = numeric_int4_opt_error(DatumGetNumeric(numeric_index),
3472  &have_error);
3473 
3474  if (have_error)
3476  (errcode(ERRCODE_INVALID_SQL_JSON_SUBSCRIPT),
3477  errmsg("jsonpath array subscript is out of integer range"))));
3478 
3479  return jperOk;
3480 }
3481 
3482 /* Save base object and its id needed for the execution of .keyvalue(). */
3483 static JsonBaseObjectInfo
3485 {
3486  JsonBaseObjectInfo baseObject = cxt->baseObject;
3487 
3488  cxt->baseObject.jbc = jbv->type != jbvBinary ? NULL :
3489  (JsonbContainer *) jbv->val.binary.data;
3490  cxt->baseObject.id = id;
3491 
3492  return baseObject;
3493 }
3494 
3495 static void
3497 {
3498  jvl->singleton = NULL;
3499  jvl->list = NIL;
3500 }
3501 
3502 static void
3504 {
3505  if (jvl->singleton)
3506  {
3507  jvl->list = list_make2(jvl->singleton, jbv);
3508  jvl->singleton = NULL;
3509  }
3510  else if (!jvl->list)
3511  jvl->singleton = jbv;
3512  else
3513  jvl->list = lappend(jvl->list, jbv);
3514 }
3515 
3516 static int
3518 {
3519  return jvl->singleton ? 1 : list_length(jvl->list);
3520 }
3521 
3522 static bool
3524 {
3525  return !jvl->singleton && (jvl->list == NIL);
3526 }
3527 
3528 static JsonbValue *
3530 {
3531  return jvl->singleton ? jvl->singleton : linitial(jvl->list);
3532 }
3533 
3534 static List *
3536 {
3537  if (jvl->singleton)
3538  return list_make1(jvl->singleton);
3539 
3540  return jvl->list;
3541 }
3542 
3543 static void
3545 {
3546  if (jvl->singleton)
3547  {
3548  it->value = jvl->singleton;
3549  it->list = NIL;
3550  it->next = NULL;
3551  }
3552  else if (jvl->list != NIL)
3553  {
3554  it->value = (JsonbValue *) linitial(jvl->list);
3555  it->list = jvl->list;
3556  it->next = list_second_cell(jvl->list);
3557  }
3558  else
3559  {
3560  it->value = NULL;
3561  it->list = NIL;
3562  it->next = NULL;
3563  }
3564 }
3565 
3566 /*
3567  * Get the next item from the sequence advancing iterator.
3568  */
3569 static JsonbValue *
3571 {
3572  JsonbValue *result = it->value;
3573 
3574  if (it->next)
3575  {
3576  it->value = lfirst(it->next);
3577  it->next = lnext(it->list, it->next);
3578  }
3579  else
3580  {
3581  it->value = NULL;
3582  }
3583 
3584  return result;
3585 }
3586 
3587 /*
3588  * Initialize a binary JsonbValue with the given jsonb container.
3589  */
3590 static JsonbValue *
3592 {
3593  jbv->type = jbvBinary;
3594  jbv->val.binary.data = &jb->root;
3595  jbv->val.binary.len = VARSIZE_ANY_EXHDR(jb);
3596 
3597  return jbv;
3598 }
3599 
3600 /*
3601  * Returns jbv* type of JsonbValue. Note, it never returns jbvBinary as is.
3602  */
3603 static int
3605 {
3606  int type = jb->type;
3607 
3608  if (jb->type == jbvBinary)
3609  {
3610  JsonbContainer *jbc = (void *) jb->val.binary.data;
3611 
3612  /* Scalars should be always extracted during jsonpath execution. */
3614 
3615  if (JsonContainerIsObject(jbc))
3616  type = jbvObject;
3617  else if (JsonContainerIsArray(jbc))
3618  type = jbvArray;
3619  else
3620  elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
3621  }
3622 
3623  return type;
3624 }
3625 
3626 /* Get scalar of given type or NULL on type mismatch */
3627 static JsonbValue *
3629 {
3630  /* Scalars should be always extracted during jsonpath execution. */
3631  Assert(scalar->type != jbvBinary ||
3632  !JsonContainerIsScalar(scalar->val.binary.data));
3633 
3634  return scalar->type == type ? scalar : NULL;
3635 }
3636 
3637 /* Construct a JSON array from the item list */
3638 static JsonbValue *
3640 {
3641  JsonbParseState *ps = NULL;
3643  JsonbValue *jbv;
3644 
3646 
3648  while ((jbv = JsonValueListNext(items, &it)))
3649  pushJsonbValue(&ps, WJB_ELEM, jbv);
3650 
3651  return pushJsonbValue(&ps, WJB_END_ARRAY, NULL);
3652 }
3653 
3654 /* Check if the timezone required for casting from type1 to type2 is used */
3655 static void
3656 checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
3657 {
3658  if (!useTz)
3659  ereport(ERROR,
3660  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3661  errmsg("cannot convert value from %s to %s without time zone usage",
3662  type1, type2),
3663  errhint("Use *_tz() function for time zone support.")));
3664 }
3665 
3666 /* Convert time datum to timetz datum */
3667 static Datum
3668 castTimeToTimeTz(Datum time, bool useTz)
3669 {
3670  checkTimezoneIsUsedForCast(useTz, "time", "timetz");
3671 
3672  return DirectFunctionCall1(time_timetz, time);
3673 }
3674 
3675 /*
3676  * Compare date to timestamp.
3677  * Note that this doesn't involve any timezone considerations.
3678  */
3679 static int
3680 cmpDateToTimestamp(DateADT date1, Timestamp ts2, bool useTz)
3681 {
3682  return date_cmp_timestamp_internal(date1, ts2);
3683 }
3684 
3685 /*
3686  * Compare date to timestamptz.
3687  */
3688 static int
3689 cmpDateToTimestampTz(DateADT date1, TimestampTz tstz2, bool useTz)
3690 {
3691  checkTimezoneIsUsedForCast(useTz, "date", "timestamptz");
3692 
3693  return date_cmp_timestamptz_internal(date1, tstz2);
3694 }
3695 
3696 /*
3697  * Compare timestamp to timestamptz.
3698  */
3699 static int
3701 {
3702  checkTimezoneIsUsedForCast(useTz, "timestamp", "timestamptz");
3703 
3704  return timestamp_cmp_timestamptz_internal(ts1, tstz2);
3705 }
3706 
3707 /*
3708  * Cross-type comparison of two datetime SQL/JSON items. If items are
3709  * uncomparable *cast_error flag is set, otherwise *cast_error is unset.
3710  * If the cast requires timezone and it is not used, then explicit error is thrown.
3711  */
3712 static int
3713 compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
3714  bool useTz, bool *cast_error)
3715 {
3716  PGFunction cmpfunc;
3717 
3718  *cast_error = false;
3719 
3720  switch (typid1)
3721  {
3722  case DATEOID:
3723  switch (typid2)
3724  {
3725  case DATEOID:
3726  cmpfunc = date_cmp;
3727 
3728  break;
3729 
3730  case TIMESTAMPOID:
3731  return cmpDateToTimestamp(DatumGetDateADT(val1),
3732  DatumGetTimestamp(val2),
3733  useTz);
3734 
3735  case TIMESTAMPTZOID:
3737  DatumGetTimestampTz(val2),
3738  useTz);
3739 
3740  case TIMEOID:
3741  case TIMETZOID:
3742  *cast_error = true; /* uncomparable types */
3743  return 0;
3744 
3745  default:
3746  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
3747  typid2);
3748  }
3749  break;
3750 
3751  case TIMEOID:
3752  switch (typid2)
3753  {
3754  case TIMEOID:
3755  cmpfunc = time_cmp;
3756 
3757  break;
3758 
3759  case TIMETZOID:
3760  val1 = castTimeToTimeTz(val1, useTz);
3761  cmpfunc = timetz_cmp;
3762 
3763  break;
3764 
3765  case DATEOID:
3766  case TIMESTAMPOID:
3767  case TIMESTAMPTZOID:
3768  *cast_error = true; /* uncomparable types */
3769  return 0;
3770 
3771  default:
3772  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
3773  typid2);
3774  }
3775  break;
3776 
3777  case TIMETZOID:
3778  switch (typid2)
3779  {
3780  case TIMEOID:
3781  val2 = castTimeToTimeTz(val2, useTz);
3782  cmpfunc = timetz_cmp;
3783 
3784  break;
3785 
3786  case TIMETZOID:
3787  cmpfunc = timetz_cmp;
3788 
3789  break;
3790 
3791  case DATEOID:
3792  case TIMESTAMPOID:
3793  case TIMESTAMPTZOID:
3794  *cast_error = true; /* uncomparable types */
3795  return 0;
3796 
3797  default:
3798  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
3799  typid2);
3800  }
3801  break;
3802 
3803  case TIMESTAMPOID:
3804  switch (typid2)
3805  {
3806  case DATEOID:
3807  return -cmpDateToTimestamp(DatumGetDateADT(val2),
3808  DatumGetTimestamp(val1),
3809  useTz);
3810 
3811  case TIMESTAMPOID:
3812  cmpfunc = timestamp_cmp;
3813 
3814  break;
3815 
3816  case TIMESTAMPTZOID:
3818  DatumGetTimestampTz(val2),
3819  useTz);
3820 
3821  case TIMEOID:
3822  case TIMETZOID:
3823  *cast_error = true; /* uncomparable types */
3824  return 0;
3825 
3826  default:
3827  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
3828  typid2);
3829  }
3830  break;
3831 
3832  case TIMESTAMPTZOID:
3833  switch (typid2)
3834  {
3835  case DATEOID:
3836  return -cmpDateToTimestampTz(DatumGetDateADT(val2),
3837  DatumGetTimestampTz(val1),
3838  useTz);
3839 
3840  case TIMESTAMPOID:
3842  DatumGetTimestampTz(val1),
3843  useTz);
3844 
3845  case TIMESTAMPTZOID:
3846  cmpfunc = timestamp_cmp;
3847 
3848  break;
3849 
3850  case TIMEOID:
3851  case TIMETZOID:
3852  *cast_error = true; /* uncomparable types */
3853  return 0;
3854 
3855  default:
3856  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
3857  typid2);
3858  }
3859  break;
3860 
3861  default:
3862  elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u", typid1);
3863  }
3864 
3865  if (*cast_error)
3866  return 0; /* cast error */
3867 
3868  return DatumGetInt32(DirectFunctionCall2(cmpfunc, val1, val2));
3869 }
3870 
3871 /*
3872  * Executor-callable JSON_EXISTS implementation
3873  *
3874  * Returns NULL instead of throwing errors if 'error' is not NULL, setting
3875  * *error to true.
3876  */
3877 bool
3879 {
3881 
3882  res = executeJsonPath(jp, vars,
3884  DatumGetJsonbP(jb), !error, NULL, true);
3885 
3886  Assert(error || !jperIsError(res));
3887 
3888  if (error && jperIsError(res))
3889  *error = true;
3890 
3891  return res == jperOk;
3892 }
3893 
3894 /*
3895  * Executor-callable JSON_QUERY implementation
3896  *
3897  * Returns NULL instead of throwing errors if 'error' is not NULL, setting
3898  * *error to true. *empty is set to true if no match is found.
3899  */
3900 Datum
3901 JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
3902  bool *error, List *vars)
3903 {
3904  JsonbValue *singleton;
3905  bool wrap;
3906  JsonValueList found = {0};
3908  int count;
3909 
3910  res = executeJsonPath(jp, vars,
3912  DatumGetJsonbP(jb), !error, &found, true);
3913  Assert(error || !jperIsError(res));
3914  if (error && jperIsError(res))
3915  {
3916  *error = true;
3917  *empty = false;
3918  return (Datum) 0;
3919  }
3920 
3921  /* WRAP or not? */
3922  count = JsonValueListLength(&found);
3923  singleton = count > 0 ? JsonValueListHead(&found) : NULL;
3924  if (singleton == NULL)
3925  wrap = false;
3926  else if (wrapper == JSW_NONE || wrapper == JSW_UNSPEC)
3927  wrap = false;
3928  else if (wrapper == JSW_UNCONDITIONAL)
3929  wrap = true;
3930  else if (wrapper == JSW_CONDITIONAL)
3931  wrap = count > 1 ||
3932  IsAJsonbScalar(singleton) ||
3933  (singleton->type == jbvBinary &&
3934  JsonContainerIsScalar(singleton->val.binary.data));
3935  else
3936  {
3937  elog(ERROR, "unrecognized json wrapper %d", wrapper);
3938  wrap = false;
3939  }
3940 
3941  if (wrap)
3943 
3944  /* No wrapping means only one item is expected. */
3945  if (count > 1)
3946  {
3947  if (error)
3948  {
3949  *error = true;
3950  return (Datum) 0;
3951  }
3952 
3953  ereport(ERROR,
3954  (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM),
3955  errmsg("JSON path expression in JSON_QUERY should return singleton item without wrapper"),
3956  errhint("Use WITH WRAPPER clause to wrap SQL/JSON item sequence into array.")));
3957  }
3958 
3959  if (singleton)
3960  return JsonbPGetDatum(JsonbValueToJsonb(singleton));
3961 
3962  *empty = true;
3963  return PointerGetDatum(NULL);
3964 }
3965 
3966 /*
3967  * Executor-callable JSON_VALUE implementation
3968  *
3969  * Returns NULL instead of throwing errors if 'error' is not NULL, setting
3970  * *error to true. *empty is set to true if no match is found.
3971  */
3972 JsonbValue *
3973 JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars)
3974 {
3975  JsonbValue *res;
3976  JsonValueList found = {0};
3978  int count;
3979 
3981  DatumGetJsonbP(jb),
3982  !error, &found, true);
3983 
3984  Assert(error || !jperIsError(jper));
3985 
3986  if (error && jperIsError(jper))
3987  {
3988  *error = true;
3989  *empty = false;
3990  return NULL;
3991  }
3992 
3993  count = JsonValueListLength(&found);
3994 
3995  *empty = (count == 0);
3996 
3997  if (*empty)
3998  return NULL;
3999 
4000  /* JSON_VALUE expects to get only singletons. */
4001  if (count > 1)
4002  {
4003  if (error)
4004  {
4005  *error = true;
4006  return NULL;
4007  }
4008 
4009  ereport(ERROR,
4010  (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM),
4011  errmsg("JSON path expression in JSON_VALUE should return singleton scalar item")));
4012  }
4013 
4014  res = JsonValueListHead(&found);
4015  if (res->type == jbvBinary && JsonContainerIsScalar(res->val.binary.data))
4016  JsonbExtractScalar(res->val.binary.data, res);
4017 
4018  /* JSON_VALUE expects to get only scalars. */
4019  if (!IsAJsonbScalar(res))
4020  {
4021  if (error)
4022  {
4023  *error = true;
4024  return NULL;
4025  }
4026 
4027  ereport(ERROR,
4028  (errcode(ERRCODE_SQL_JSON_SCALAR_REQUIRED),
4029  errmsg("JSON path expression in JSON_VALUE should return singleton scalar item")));
4030  }
4031 
4032  if (res->type == jbvNull)
4033  return NULL;
4034 
4035  return res;
4036 }
4037 
4038 /************************ JSON_TABLE functions ***************************/
4039 
4040 /*
4041  * Sanity-checks and returns the opaque JsonTableExecContext from the
4042  * given executor state struct.
4043  */
4044 static inline JsonTableExecContext *
4046 {
4047  JsonTableExecContext *result;
4048 
4049  if (!IsA(state, TableFuncScanState))
4050  elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4051  result = (JsonTableExecContext *) state->opaque;
4053  elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4054 
4055  return result;
4056 }
4057 
4058 /*
4059  * JsonTableInitOpaque
4060  * Fill in TableFuncScanState->opaque for processing JSON_TABLE
4061  *
4062  * This initializes the PASSING arguments and the JsonTablePlanState for
4063  * JsonTablePlan given in TableFunc.
4064  */
4065 static void
4067 {
4068  JsonTableExecContext *cxt;
4069  PlanState *ps = &state->ss.ps;
4070  TableFuncScan *tfs = castNode(TableFuncScan, ps->plan);
4071  TableFunc *tf = tfs->tablefunc;
4072  JsonTablePlan *rootplan = (JsonTablePlan *) tf->plan;
4073  JsonExpr *je = castNode(JsonExpr, tf->docexpr);
4074  List *args = NIL;
4075 
4076  cxt = palloc0(sizeof(JsonTableExecContext));
4078 
4079  /*
4080  * Evaluate JSON_TABLE() PASSING arguments to be passed to the jsonpath
4081  * executor via JsonPathVariables.
4082  */
4083  if (state->passingvalexprs)
4084  {
4085  ListCell *exprlc;
4086  ListCell *namelc;
4087 
4088  Assert(list_length(state->passingvalexprs) ==
4089  list_length(je->passing_names));
4090  forboth(exprlc, state->passingvalexprs,
4091  namelc, je->passing_names)
4092  {
4093  ExprState *state = lfirst_node(ExprState, exprlc);
4094  String *name = lfirst_node(String, namelc);
4095  JsonPathVariable *var = palloc(sizeof(*var));
4096 
4097  var->name = pstrdup(name->sval);
4098  var->typid = exprType((Node *) state->expr);
4099  var->typmod = exprTypmod((Node *) state->expr);
4100 
4101  /*
4102  * Evaluate the expression and save the value to be returned by
4103  * GetJsonPathVar().
4104  */
4105  var->value = ExecEvalExpr(state, ps->ps_ExprContext,
4106  &var->isnull);
4107 
4108  args = lappend(args, var);
4109  }
4110  }
4111 
4112  cxt->colplanstates = palloc(sizeof(JsonTablePlanState *) *
4113  list_length(tf->colvalexprs));
4114 
4115  /*
4116  * Initialize plan for the root path and, recursively, also any child
4117  * plans that compute the NESTED paths.
4118  */
4119  cxt->rootplanstate = JsonTableInitPlan(cxt, rootplan, NULL, args,
4121 
4122  state->opaque = cxt;
4123 }
4124 
4125 /*
4126  * JsonTableDestroyOpaque
4127  * Resets state->opaque
4128  */
4129 static void
4131 {
4132  JsonTableExecContext *cxt =
4133  GetJsonTableExecContext(state, "JsonTableDestroyOpaque");
4134 
4135  /* not valid anymore */
4136  cxt->magic = 0;
4137 
4138  state->opaque = NULL;
4139 }
4140 
4141 /*
4142  * JsonTableInitPlan
4143  * Initialize information for evaluating jsonpath in the given
4144  * JsonTablePlan and, recursively, in any child plans
4145  */
4146 static JsonTablePlanState *
4148  JsonTablePlanState *parentstate,
4149  List *args, MemoryContext mcxt)
4150 {
4151  JsonTablePlanState *planstate = palloc0(sizeof(*planstate));
4152 
4153  planstate->plan = plan;
4154  planstate->parent = parentstate;
4155 
4156  if (IsA(plan, JsonTablePathScan))
4157  {
4159  int i;
4160 
4161  planstate->path = DatumGetJsonPathP(scan->path->value->constvalue);
4162  planstate->args = args;
4163  planstate->mcxt = AllocSetContextCreate(mcxt, "JsonTableExecContext",
4165 
4166  /* No row pattern evaluated yet. */
4167  planstate->current.value = PointerGetDatum(NULL);
4168  planstate->current.isnull = true;
4169 
4170  for (i = scan->colMin; i >= 0 && i <= scan->colMax; i++)
4171  cxt->colplanstates[i] = planstate;
4172 
4173  planstate->nested = scan->child ?
4174  JsonTableInitPlan(cxt, scan->child, planstate, args, mcxt) : NULL;
4175  }
4176  else if (IsA(plan, JsonTableSiblingJoin))
4177  {
4179 
4180  planstate->left = JsonTableInitPlan(cxt, join->lplan, parentstate,
4181  args, mcxt);
4182  planstate->right = JsonTableInitPlan(cxt, join->rplan, parentstate,
4183  args, mcxt);
4184  }
4185 
4186  return planstate;
4187 }
4188 
4189 /*
4190  * JsonTableSetDocument
4191  * Install the input document and evaluate the row pattern
4192  */
4193 static void
4195 {
4196  JsonTableExecContext *cxt =
4197  GetJsonTableExecContext(state, "JsonTableSetDocument");
4198 
4200 }
4201 
4202 /*
4203  * Evaluate a JsonTablePlan's jsonpath to get a new row pattren from
4204  * the given context item
4205  */
4206 static void
4208 {
4209  JsonTablePathScan *scan = castNode(JsonTablePathScan, planstate->plan);
4210  MemoryContext oldcxt;
4212  Jsonb *js = (Jsonb *) DatumGetJsonbP(item);
4213 
4214  JsonValueListClear(&planstate->found);
4215 
4216  MemoryContextResetOnly(planstate->mcxt);
4217 
4218  oldcxt = MemoryContextSwitchTo(planstate->mcxt);
4219 
4220  res = executeJsonPath(planstate->path, planstate->args,
4222  js, scan->errorOnError,
4223  &planstate->found,
4224  true);
4225 
4226  MemoryContextSwitchTo(oldcxt);
4227 
4228  if (jperIsError(res))
4229  {
4230  Assert(!scan->errorOnError);
4231  JsonValueListClear(&planstate->found);
4232  }
4233 
4234  /* Reset plan iterator to the beginning of the item list */
4235  JsonValueListInitIterator(&planstate->found, &planstate->iter);
4236  planstate->current.value = PointerGetDatum(NULL);
4237  planstate->current.isnull = true;
4238  planstate->ordinal = 0;
4239 }
4240 
4241 /*
4242  * Fetch next row from a JsonTablePlan.
4243  *
4244  * Returns false if the plan has run out of rows, true otherwise.
4245  */
4246 static bool
4248 {
4249  if (IsA(planstate->plan, JsonTablePathScan))
4250  return JsonTablePlanScanNextRow(planstate);
4251  else if (IsA(planstate->plan, JsonTableSiblingJoin))
4252  return JsonTablePlanJoinNextRow(planstate);
4253  else
4254  elog(ERROR, "invalid JsonTablePlan %d", (int) planstate->plan->type);
4255 
4256  Assert(false);
4257  /* Appease compiler */
4258  return false;
4259 }
4260 
4261 /*
4262  * Fetch next row from a JsonTablePlan's path evaluation result and from
4263  * any child nested path(s).
4264  *
4265  * Returns true if any of the paths (this or the nested) has more rows to
4266  * return.
4267  *
4268  * By fetching the nested path(s)'s rows based on the parent row at each
4269  * level, this essentially joins the rows of different levels. If a nested
4270  * path at a given level has no matching rows, the columns of that level will
4271  * compute to NULL, making it an OUTER join.
4272  */
4273 static bool
4275 {
4276  JsonbValue *jbv;
4277  MemoryContext oldcxt;
4278 
4279  /*
4280  * If planstate already has an active row and there is a nested plan,
4281  * check if it has an active row to join with the former.
4282  */
4283  if (!planstate->current.isnull)
4284  {
4285  if (planstate->nested && JsonTablePlanNextRow(planstate->nested))
4286  return true;
4287  }
4288 
4289  /* Fetch new row from the list of found values to set as active. */
4290  jbv = JsonValueListNext(&planstate->found, &planstate->iter);
4291 
4292  /* End of list? */
4293  if (jbv == NULL)
4294  {
4295  planstate->current.value = PointerGetDatum(NULL);
4296  planstate->current.isnull = true;
4297  return false;
4298  }
4299 
4300  /*
4301  * Set current row item for subsequent JsonTableGetValue() calls for
4302  * evaluating individual columns.
4303  */
4304  oldcxt = MemoryContextSwitchTo(planstate->mcxt);
4305  planstate->current.value = JsonbPGetDatum(JsonbValueToJsonb(jbv));
4306  planstate->current.isnull = false;
4307  MemoryContextSwitchTo(oldcxt);
4308 
4309  /* Next row! */
4310  planstate->ordinal++;
4311 
4312  /* Process nested plan(s), if any. */
4313  if (planstate->nested)
4314  {
4315  /* Re-evaluate the nested path using the above parent row. */
4316  JsonTableResetNestedPlan(planstate->nested);
4317 
4318  /*
4319  * Now fetch the nested plan's current row to be joined against the
4320  * parent row. Any further nested plans' paths will be re-evaluated
4321  * reursively, level at a time, after setting each nested plan's
4322  * current row.
4323  */
4324  (void) JsonTablePlanNextRow(planstate->nested);
4325  }
4326 
4327  /* There are more rows. */
4328  return true;
4329 }
4330 
4331 /*
4332  * Re-evaluate the row pattern of a nested plan using the new parent row
4333  * pattern.
4334  */
4335 static void
4337 {
4338  /* This better be a child plan. */
4339  Assert(planstate->parent != NULL);
4340  if (IsA(planstate->plan, JsonTablePathScan))
4341  {
4342  JsonTablePlanState *parent = planstate->parent;
4343 
4344  if (!parent->current.isnull)
4345  JsonTableResetRowPattern(planstate, parent->current.value);
4346 
4347  /*
4348  * If this plan itself has a child nested plan, it will be reset when
4349  * the caller calls JsonTablePlanNextRow() on this plan.
4350  */
4351  }
4352  else if (IsA(planstate->plan, JsonTableSiblingJoin))
4353  {
4354  JsonTableResetNestedPlan(planstate->left);
4355  JsonTableResetNestedPlan(planstate->right);
4356  }
4357 }
4358 
4359 /*
4360  * Fetch the next row from a JsonTableSiblingJoin.
4361  *
4362  * This is essentially a UNION between the rows from left and right siblings.
4363  */
4364 static bool
4366 {
4367 
4368  /* Fetch row from left sibling. */
4369  if (!JsonTablePlanNextRow(planstate->left))
4370  {
4371  /*
4372  * Left sibling ran out of rows, so start fetching from the right
4373  * sibling.
4374  */
4375  if (!JsonTablePlanNextRow(planstate->right))
4376  {
4377  /* Right sibling ran out of row, so there are more rows. */
4378  return false;
4379  }
4380  }
4381 
4382  return true;
4383 }
4384 
4385 /*
4386  * JsonTableFetchRow
4387  * Prepare the next "current" row for upcoming GetValue calls.
4388  *
4389  * Returns false if no more rows can be returned.
4390  */
4391 static bool
4393 {
4394  JsonTableExecContext *cxt =
4395  GetJsonTableExecContext(state, "JsonTableFetchRow");
4396 
4397  return JsonTablePlanNextRow(cxt->rootplanstate);
4398 }
4399 
4400 /*
4401  * JsonTableGetValue
4402  * Return the value for column number 'colnum' for the current row.
4403  *
4404  * This leaks memory, so be sure to reset often the context in which it's
4405  * called.
4406  */
4407 static Datum
4409  Oid typid, int32 typmod, bool *isnull)
4410 {
4411  JsonTableExecContext *cxt =
4412  GetJsonTableExecContext(state, "JsonTableGetValue");
4413  ExprContext *econtext = state->ss.ps.ps_ExprContext;
4414  ExprState *estate = list_nth(state->colvalexprs, colnum);
4415  JsonTablePlanState *planstate = cxt->colplanstates[colnum];
4416  JsonTablePlanRowSource *current = &planstate->current;
4417  Datum result;
4418 
4419  /* Row pattern value is NULL */
4420  if (current->isnull)
4421  {
4422  result = (Datum) 0;
4423  *isnull = true;
4424  }
4425  /* Evaluate JsonExpr. */
4426  else if (estate)
4427  {
4428  Datum saved_caseValue = econtext->caseValue_datum;
4429  bool saved_caseIsNull = econtext->caseValue_isNull;
4430 
4431  /* Pass the row pattern value via CaseTestExpr. */
4432  econtext->caseValue_datum = current->value;
4433  econtext->caseValue_isNull = false;
4434 
4435  result = ExecEvalExpr(estate, econtext, isnull);
4436 
4437  econtext->caseValue_datum = saved_caseValue;
4438  econtext->caseValue_isNull = saved_caseIsNull;
4439  }
4440  /* ORDINAL column */
4441  else
4442  {
4443  result = Int32GetDatum(planstate->ordinal);
4444  *isnull = false;
4445  }
4446 
4447  return result;
4448 }
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3374
int32 numeric_int4_opt_error(Numeric num, bool *have_error)
Definition: numeric.c:4397
Datum float8_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4593
Datum numeric_cmp(PG_FUNCTION_ARGS)
Definition: numeric.c:2399
Numeric numeric_mod_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:3368
Numeric numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:3144
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4283
Datum float4_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4687
Datum int4_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4389
Datum numeric_uminus(PG_FUNCTION_ARGS)
Definition: numeric.c:1411
Datum numeric_ceil(PG_FUNCTION_ARGS)
Definition: numeric.c:1630
Datum numerictypmodin(PG_FUNCTION_ARGS)
Definition: numeric.c:1315
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:807
int64 numeric_int8_opt_error(Numeric num, bool *have_error)
Definition: numeric.c:4485
Datum numeric_trunc(PG_FUNCTION_ARGS)
Definition: numeric.c:1583
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:628
bool numeric_is_nan(Numeric num)
Definition: numeric.c:842
Numeric numeric_sub_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:2945
Numeric numeric_mul_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:3023
Datum int2_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4544
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition: numeric.c:1384
Datum int8_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:4477
Numeric numeric_add_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:2867
bool numeric_is_inf(Numeric num)
Definition: numeric.c:853
Datum numeric_floor(PG_FUNCTION_ARGS)
Definition: numeric.c:1658
Datum timestamp_cmp(PG_FUNCTION_ARGS)
Definition: timestamp.c:2270
bool AdjustTimestampForTypmod(Timestamp *time, int32 typmod, Node *escontext)
Definition: timestamp.c:366
Datum timestamp_timestamptz(PG_FUNCTION_ARGS)
Definition: timestamp.c:6274
int32 timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
Definition: timestamp.c:2325
int32 anytimestamp_typmod_check(bool istz, int32 typmod)
Definition: timestamp.c:123
Datum timestamptz_timestamp(PG_FUNCTION_ARGS)
Definition: timestamp.c:6353
Datum timestamptz_out(PG_FUNCTION_ARGS)
Definition: timestamp.c:785
Datum timestamp_out(PG_FUNCTION_ARGS)
Definition: timestamp.c:232
static int32 next
Definition: blutils.c:221
bool parse_bool(const char *value, bool *result)
Definition: bool.c:30
unsigned int uint32
Definition: c.h:506
#define Min(x, y)
Definition: c.h:1004
#define PG_UINT32_MAX
Definition: c.h:590
signed int int32
Definition: c.h:494
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:182
#define Assert(condition)
Definition: c.h:858
#define lengthof(array)
Definition: c.h:788
Oid collid
int64 Timestamp
Definition: timestamp.h:38
int64 TimestampTz
Definition: timestamp.h:39
int32 date_cmp_timestamp_internal(DateADT dateVal, Timestamp dt2)
Definition: date.c:743
Datum date_cmp(PG_FUNCTION_ARGS)
Definition: date.c:437
Datum time_cmp(PG_FUNCTION_ARGS)
Definition: date.c:1734
Datum timestamp_time(PG_FUNCTION_ARGS)
Definition: date.c:1905
int32 anytime_typmod_check(bool istz, int32 typmod)
Definition: date.c:71
Datum date_timestamptz(PG_FUNCTION_ARGS)
Definition: date.c:1327
Datum timetz_cmp(PG_FUNCTION_ARGS)
Definition: date.c:2524
Datum date_out(PG_FUNCTION_ARGS)
Definition: date.c:184
Datum timetz_time(PG_FUNCTION_ARGS)
Definition: date.c:2815
Datum time_timetz(PG_FUNCTION_ARGS)
Definition: date.c:2828
Datum time_out(PG_FUNCTION_ARGS)
Definition: date.c:1501
Datum timestamptz_timetz(PG_FUNCTION_ARGS)
Definition: date.c:2854
void AdjustTimeForTypmod(TimeADT *time, int32 typmod)
Definition: date.c:1645
Datum timestamptz_date(PG_FUNCTION_ARGS)
Definition: date.c:1342
Datum timestamp_date(PG_FUNCTION_ARGS)
Definition: date.c:1297
int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2)
Definition: date.c:823
Datum timestamptz_time(PG_FUNCTION_ARGS)
Definition: date.c:1935
Datum timetz_out(PG_FUNCTION_ARGS)
Definition: date.c:2314
Datum date_timestamp(PG_FUNCTION_ARGS)
Definition: date.c:1283
int32 DateADT
Definition: date.h:23
static DateADT DatumGetDateADT(Datum X)
Definition: date.h:54
static TimeADT DatumGetTimeADT(Datum X)
Definition: date.h:60
static Datum TimeTzADTPGetDatum(const TimeTzADT *X)
Definition: date.h:84
static TimeTzADT * DatumGetTimeTzADTP(Datum X)
Definition: date.h:66
int64 TimeADT
Definition: date.h:25
static Datum TimeADTGetDatum(TimeADT X)
Definition: date.h:78
struct cursor * cur
Definition: ecpg.c:28
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:333
float8 float8in_internal(char *num, char **endptr_p, const char *type_name, const char *orig_string, struct Node *escontext)
Definition: float.c:388
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1816
bool DirectInputFunctionCallSafe(PGFunction func, char *str, Oid typioparam, int32 typmod, fmNodePtr escontext, Datum *result)
Definition: fmgr.c:1640
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
Datum(* PGFunction)(FunctionCallInfo fcinfo)
Definition: fmgr.h:40
#define DatumGetTextP(X)
Definition: fmgr.h:332
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
Datum parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict, Oid *typid, int32 *typmod, int *tz, Node *escontext)
Definition: formatting.c:4455
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
const char * str
struct parser_state ps
long val
Definition: informix.c:670
static struct @155 value
Datum int8in(PG_FUNCTION_ARGS)
Definition: int8.c:50
Datum int4in(PG_FUNCTION_ARGS)
Definition: int.c:287
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Datum jsonb_in(PG_FUNCTION_ARGS)
Definition: jsonb.c:73
const char * JsonbTypeName(JsonbValue *val)
Definition: jsonb.c:180
bool JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
Definition: jsonb.c:1968
jbvType
Definition: jsonb.h:226
@ jbvObject
Definition: jsonb.h:234
@ jbvNumeric
Definition: jsonb.h:230
@ jbvBool
Definition: jsonb.h:231
@ jbvArray
Definition: jsonb.h:233
@ jbvBinary
Definition: jsonb.h:236
@ jbvNull
Definition: jsonb.h:228
@ jbvDatetime
Definition: jsonb.h:244
@ jbvString
Definition: jsonb.h:229
#define JsonContainerIsScalar(jc)
Definition: jsonb.h:207
#define JsonContainerIsArray(jc)
Definition: jsonb.h:209
static Jsonb * DatumGetJsonbP(Datum d)
Definition: jsonb.h:374
#define JsonContainerSize(jc)
Definition: jsonb.h:206
#define PG_GETARG_JSONB_P_COPY(x)
Definition: jsonb.h:392
static Datum JsonbPGetDatum(const Jsonb *p)
Definition: jsonb.h:386
#define IsAJsonbScalar(jsonbval)
Definition: jsonb.h:297
#define PG_RETURN_JSONB_P(x)
Definition: jsonb.h:393
#define PG_GETARG_JSONB_P(x)
Definition: jsonb.h:391
#define JsonContainerIsObject(jc)
Definition: jsonb.h:208
JsonbIteratorToken
Definition: jsonb.h:21
@ WJB_KEY
Definition: jsonb.h:23
@ WJB_DONE
Definition: jsonb.h:22
@ WJB_END_ARRAY
Definition: jsonb.h:27
@ WJB_VALUE
Definition: jsonb.h:24
@ WJB_END_OBJECT
Definition: jsonb.h:29
@ WJB_ELEM
Definition: jsonb.h:25
@ WJB_BEGIN_OBJECT
Definition: jsonb.h:28
@ WJB_BEGIN_ARRAY
Definition: jsonb.h:26
#define JB_FOBJECT
Definition: jsonb.h:202
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition: jsonb_util.c:817
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition: jsonb_util.c:92
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition: jsonb_util.c:468
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition: jsonb_util.c:853
JsonbValue * pushJsonbValue(JsonbParseState **pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition: jsonb_util.c:566
JsonbValue * findJsonbValueFromContainer(JsonbContainer *container, uint32 flags, JsonbValue *key)
Definition: jsonb_util.c:344
void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1159
void jspGetArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1074
void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
Definition: jsonpath.c:983
bool jspGetBool(JsonPathItem *v)
Definition: jsonpath.c:1203
void jspInit(JsonPathItem *v, JsonPath *js)
Definition: jsonpath.c:973
const char * jspOperationName(JsonPathItemType type)
Definition: jsonpath.c:836
Numeric jspGetNumeric(JsonPathItem *v)
Definition: jsonpath.c:1211
bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to, int i)
Definition: jsonpath.c:1231
bool jspGetNext(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1092
void jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
Definition: jsonpath.c:1181
char * jspGetString(JsonPathItem *v, int32 *len)
Definition: jsonpath.c:1219
bool jspConvertRegexFlags(uint32 xflags, int *result, struct Node *escontext)
#define jspHasNext(jsp)
Definition: jsonpath.h:194
#define PG_GETARG_JSONPATH_P(x)
Definition: jsonpath.h:46
static JsonPath * DatumGetJsonPathP(Datum d)
Definition: jsonpath.h:35
#define PG_GETARG_JSONPATH_P_COPY(x)
Definition: jsonpath.h:47
@ jpiAdd
Definition: jsonpath.h:78
@ jpiString
Definition: jsonpath.h:65
@ jpiAbs
Definition: jsonpath.h:97
@ jpiIndexArray
Definition: jsonpath.h:87
@ jpiAny
Definition: jsonpath.h:88
@ jpiDatetime
Definition: jsonpath.h:101
@ jpiBigint
Definition: jsonpath.h:107
@ jpiBool
Definition: jsonpath.h:67
@ jpiType
Definition: jsonpath.h:95
@ jpiFloor
Definition: jsonpath.h:98
@ jpiAnyArray
Definition: jsonpath.h:85
@ jpiExists
Definition: jsonpath.h:94
@ jpiSize
Definition: jsonpath.h:96
@ jpiSub
Definition: jsonpath.h:79
@ jpiNotEqual
Definition: jsonpath.h:73
@ jpiMul
Definition: jsonpath.h:80
@ jpiVariable
Definition: jsonpath.h:92
@ jpiTimeTz
Definition: jsonpath.h:115
@ jpiNot
Definition: jsonpath.h:70
@ jpiDate
Definition: jsonpath.h:109
@ jpiGreaterOrEqual
Definition: jsonpath.h:77
@ jpiPlus
Definition: jsonpath.h:83
@ jpiDouble
Definition: jsonpath.h:100
@ jpiGreater
Definition: jsonpath.h:75
@ jpiNumber
Definition: jsonpath.h:112
@ jpiAnd
Definition: jsonpath.h:68
@ jpiStartsWith
Definition: jsonpath.h:105
@ jpiOr
Definition: jsonpath.h:69
@ jpiMod
Definition: jsonpath.h:82
@ jpiTimestamp
Definition: jsonpath.h:116
@ jpiLikeRegex
Definition: jsonpath.h:106
@ jpiTimestampTz
Definition: jsonpath.h:117
@ jpiInteger
Definition: jsonpath.h:111
@ jpiRoot
Definition: jsonpath.h:91
@ jpiFilter
Definition: jsonpath.h:93
@ jpiNull
Definition: jsonpath.h:64
@ jpiLess
Definition: jsonpath.h:74
@ jpiCurrent
Definition: jsonpath.h:90
@ jpiEqual
Definition: jsonpath.h:72
@ jpiKey
Definition: jsonpath.h:89
@ jpiDiv
Definition: jsonpath.h:81
@ jpiTime
Definition: jsonpath.h:114
@ jpiLast
Definition: jsonpath.h:104
@ jpiMinus
Definition: jsonpath.h:84
@ jpiLessOrEqual
Definition: jsonpath.h:76
@ jpiCeiling
Definition: jsonpath.h:99
@ jpiIsUnknown
Definition: jsonpath.h:71
@ jpiKeyValue
Definition: jsonpath.h:102
@ jpiNumeric
Definition: jsonpath.h:66
@ jpiBoolean
Definition: jsonpath.h:108
@ jpiStringFunc
Definition: jsonpath.h:113
@ jpiDecimal
Definition: jsonpath.h:110
@ jpiAnyKey
Definition: jsonpath.h:86
#define JSONPATH_LAX
Definition: jsonpath.h:31
static JsonPathBool executeComparison(JsonPathItem *cmp, JsonbValue *lv, JsonbValue *rv, void *p)
bool JsonPathExists(Datum jb, JsonPath *jp, bool *error, List *vars)
static Datum jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz)
static JsonPathExecResult executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found, bool unwrap)
Datum jsonb_path_query_tz(PG_FUNCTION_ARGS)
#define jspAutoUnwrap(cxt)
Datum jsonb_path_exists_opr(PG_FUNCTION_ARGS)
static int cmpDateToTimestamp(DateADT date1, Timestamp ts2, bool useTz)
static JsonPathBool executeBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, bool canHaveNext)
static int JsonbArraySize(JsonbValue *jb)
struct JsonBaseObjectInfo JsonBaseObjectInfo
Numeric(* BinaryArithmFunc)(Numeric num1, Numeric num2, bool *error)
struct JsonTablePlanState JsonTablePlanState
static JsonbValue * getJsonPathVariableFromJsonb(void *varsJsonb, char *varName, int varNameLen, JsonbValue *baseObject, int *baseObjectId)
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)
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)
static JsonPathExecResult executeBinaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, BinaryArithmFunc func, JsonValueList *found)
static int countVariablesFromJsonb(void *varsJsonb)
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)
#define JSON_TABLE_EXEC_CONTEXT_MAGIC
static JsonPathExecResult executeItemOptUnwrapResultNoThrow(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, bool unwrap, JsonValueList *found)
static JsonPathExecResult executeAnyItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbContainer *jbc, JsonValueList *found, uint32 level, uint32 first, uint32 last, bool ignoreStructuralErrors, bool unwrapNext)
#define jspAutoWrap(cxt)
static JsonPathExecResult executeKeyValueMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found)
static JsonPathBool executeStartsWith(JsonPathItem *jsp, JsonbValue *whole, JsonbValue *initial, void *param)
static Datum jsonb_path_match_internal(FunctionCallInfo fcinfo, bool tz)
static JsonBaseObjectInfo setBaseObject(JsonPathExecContext *cxt, JsonbValue *jbv, int32 id)
static Datum castTimeToTimeTz(Datum time, bool useTz)
static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv)
static JsonPathExecResult executeUnaryArithmExpr(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, PGFunction func, JsonValueList *found)
static int JsonbType(JsonbValue *jb)
static void JsonTableResetNestedPlan(JsonTablePlanState *planstate)
static JsonPathExecResult executeDateTimeMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found)
static JsonbValue * getScalar(JsonbValue *scalar, enum jbvType type)
static void JsonItemFromDatum(Datum val, Oid typid, int32 typmod, JsonbValue *res)
struct JsonPathExecContext JsonPathExecContext
Datum jsonb_path_match_tz(PG_FUNCTION_ARGS)
static JsonTableExecContext * GetJsonTableExecContext(TableFuncScanState *state, const char *fname)
static JsonPathExecResult executeItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found)
Datum jsonb_path_query(PG_FUNCTION_ARGS)
static bool JsonTablePlanScanNextRow(JsonTablePlanState *planstate)
Datum jsonb_path_match_opr(PG_FUNCTION_ARGS)
JsonPathBool(* JsonPathPredicateCallback)(JsonPathItem *jsp, JsonbValue *larg, JsonbValue *rarg, void *param)
static JsonbValue * GetJsonPathVar(void *cxt, char *varName, int varNameLen, JsonbValue *baseObject, int *baseObjectId)
struct JsonTablePlanRowSource JsonTablePlanRowSource
static void JsonValueListInitIterator(const JsonValueList *jvl, JsonValueListIterator *it)
static JsonPathBool executeNestedBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb)
static int compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2, bool useTz, bool *cast_error)
static int cmpDateToTimestampTz(DateADT date1, TimestampTz tstz2, bool useTz)
Datum jsonb_path_match(PG_FUNCTION_ARGS)
static JsonbValue * wrapItemsInArray(const JsonValueList *items)
static JsonbValue * JsonValueListNext(const JsonValueList *jvl, JsonValueListIterator *it)
#define jspStrictAbsenceOfErrors(cxt)
static void JsonTableDestroyOpaque(TableFuncScanState *state)
static void JsonValueListClear(JsonValueList *jvl)
static void JsonTableInitOpaque(TableFuncScanState *state, int natts)
static JsonPathExecResult executeNextItem(JsonPathExecContext *cxt, JsonPathItem *cur, JsonPathItem *next, JsonbValue *v, JsonValueList *found, bool copy)
Datum jsonb_path_exists(PG_FUNCTION_ARGS)
#define jperIsError(jper)
static Datum jsonb_path_exists_internal(FunctionCallInfo fcinfo, bool tz)
static bool JsonTablePlanNextRow(JsonTablePlanState *planstate)
struct JsonValueListIterator JsonValueListIterator
Datum jsonb_path_query_array_tz(PG_FUNCTION_ARGS)
static JsonTablePlanState * JsonTableInitPlan(JsonTableExecContext *cxt, JsonTablePlan *plan, JsonTablePlanState *parentstate, List *args, MemoryContext mcxt)
static JsonPathExecResult executeItemUnwrapTargetArray(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found, bool unwrapElements)
static int cmpTimestampToTimestampTz(Timestamp ts1, TimestampTz tstz2, bool useTz)
static JsonPathBool executeLikeRegex(JsonPathItem *jsp, JsonbValue *str, JsonbValue *rarg, void *param)
static int JsonValueListLength(const JsonValueList *jvl)
static bool JsonValueListIsEmpty(JsonValueList *jvl)
#define jspIgnoreStructuralErrors(cxt)
JsonPathExecResult
@ jperError
@ jperNotFound
@ jperOk
struct JsonLikeRegexContext JsonLikeRegexContext
static void JsonbValueInitNumericDatum(JsonbValue *jbv, Datum num)
static int CountJsonPathVars(void *cxt)
struct JsonTableExecContext JsonTableExecContext
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)
JsonbValue *(* JsonPathGetVarCallback)(void *vars, char *varName, int varNameLen, JsonbValue *baseObject, int *baseObjectId)
Definition: jsonpath_exec.c:90
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)
Datum jsonb_path_exists_tz(PG_FUNCTION_ARGS)
static void JsonTableResetRowPattern(JsonTablePlanState *plan, Datum item)
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)
int(* JsonPathCountVarsCallback)(void *vars)
Definition: jsonpath_exec.c:92
static JsonbValue * JsonbInitBinary(JsonbValue *jbv, Jsonb *jb)
static void checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars, JsonPathGetVarCallback getVar, JsonPathCountVarsCallback countVars, Jsonb *json, bool throwErrors, JsonValueList *result, bool useTz)
JsonPathBool
@ jpbUnknown
@ jpbFalse
@ jpbTrue
static bool JsonTablePlanJoinNextRow(JsonTablePlanState *planstate)
#define jspThrowErrors(cxt)
static JsonbValue * copyJsonbValue(JsonbValue *src)
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_delete_first(List *list)
Definition: list.c:943
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
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:1706
char * pstrdup(const char *in)
Definition: mcxt.c:1695
void pfree(void *pointer)
Definition: mcxt.c:1520
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * palloc0(Size size)
Definition: mcxt.c:1346
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void * palloc(Size size)
Definition: mcxt.c:1316
void MemoryContextResetOnly(MemoryContext context)
Definition: mcxt.c:402
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:298
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define castNode(_type_, nodeptr)
Definition: nodes.h:176
static Numeric DatumGetNumeric(Datum X)
Definition: numeric.h:61
struct NumericData * Numeric
Definition: numeric.h:54
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:73
int pg_ltoa(int32 value, char *a)
Definition: numutils.c:1122
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
#define list_make1(x1)
Definition: pg_list.h:212
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
#define linitial(l)
Definition: pg_list.h:178
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
#define list_make2(x1, x2)
Definition: pg_list.h:214
static ListCell * list_second_cell(const List *l)
Definition: pg_list.h:142
#define plan(x)
Definition: pg_regress.c:162
@ PG_SQL_ASCII
Definition: pg_wchar.h:226
@ PG_UTF8
Definition: pg_wchar.h:232
int scale
Definition: pgbench.c:181
void check_stack_depth(void)
Definition: postgres.c:3531
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static char * DatumGetCString(Datum X)
Definition: postgres.h:335
uintptr_t Datum
Definition: postgres.h:64
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
char * c
char * s1
char * s2
JsonWrapper
Definition: primnodes.h:1715
@ JSW_UNCONDITIONAL
Definition: primnodes.h:1719
@ JSW_CONDITIONAL
Definition: primnodes.h:1718
@ JSW_UNSPEC
Definition: primnodes.h:1716
@ JSW_NONE
Definition: primnodes.h:1717
MemoryContextSwitchTo(old_ctx)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:412
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
bool RE_compile_and_execute(text *text_re, char *dat, int dat_len, int cflags, Oid collation, int nmatch, regmatch_t *pmatch)
Definition: regexp.c:358
static pg_noinline void Size size
Definition:<