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