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