PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, PostgreSQL Global Development Group
53 *
54 * IDENTIFICATION
55 * src/backend/utils/adt/jsonpath_exec.c
56 *
57 *-------------------------------------------------------------------------
58 */
59
60#include "postgres.h"
61
63#include "catalog/pg_type.h"
64#include "funcapi.h"
65#include "miscadmin.h"
66#include "nodes/miscnodes.h"
67#include "nodes/nodeFuncs.h"
68#include "regex/regex.h"
69#include "utils/builtins.h"
70#include "utils/date.h"
71#include "utils/datetime.h"
72#include "utils/float.h"
73#include "utils/formatting.h"
74#include "utils/json.h"
75#include "utils/jsonpath.h"
76#include "utils/memutils.h"
77#include "utils/timestamp.h"
78
79/*
80 * Represents "base object" and its "id" for .keyvalue() evaluation.
81 */
87
88/* Callbacks for executeJsonPath() */
89typedef JsonbValue *(*JsonPathGetVarCallback) (void *vars, char *varName, int varNameLen,
90 JsonbValue *baseObject, int *baseObjectId);
92
93/*
94 * Context of jsonpath execution.
95 */
96typedef struct JsonPathExecContext
97{
98 void *vars; /* variables to substitute into jsonpath */
99 JsonPathGetVarCallback getVar; /* callback to extract a given variable
100 * from 'vars' */
101 JsonbValue *root; /* for $ evaluation */
102 JsonbValue *current; /* for @ evaluation */
103 JsonBaseObjectInfo baseObject; /* "base object" for .keyvalue()
104 * evaluation */
105 int lastGeneratedObjectId; /* "id" counter for .keyvalue()
106 * evaluation */
107 int innermostArraySize; /* for LAST array index evaluation */
108 bool laxMode; /* true for "lax" mode, false for "strict"
109 * mode */
110 bool ignoreStructuralErrors; /* with "true" structural errors such
111 * as absence of required json item or
112 * unexpected json item type are
113 * ignored */
114 bool throwErrors; /* with "false" all suppressible errors are
115 * suppressed */
116 bool useTz;
118
119/* Context for LIKE_REGEX execution. */
125
126/* Result of jsonpath predicate evaluation */
133
134/* Result of jsonpath expression evaluation */
141
142#define jperIsError(jper) ((jper) == jperError)
143
144/*
145 * List (or really array) of JsonbValues. This is the output representation
146 * of jsonpath evaluation.
147 *
148 * The initial or "base" chunk of a list is typically a local variable in
149 * a calling function. If we need more entries than will fit in the base
150 * chunk, we palloc more chunks. For notational simplicity, those are also
151 * treated as being of type JsonValueList, although they will have items[]
152 * arrays that are larger than BASE_JVL_ITEMS.
153 *
154 * Callers *must* initialize the base chunk with JsonValueListInit().
155 * Typically they should free any extra chunks when done, using
156 * JsonValueListClear(), although some top-level functions skip that
157 * on the assumption that the caller's context will be reset soon.
158 *
159 * Note that most types of JsonbValue include pointers to external data, which
160 * will not be managed by the JsonValueList functions. We expect that such
161 * data is part of the input to the jsonpath operation, and the caller will
162 * see to it that it holds still for the duration of the operation.
163 *
164 * Most lists are short, though some can be quite long. So we set
165 * BASE_JVL_ITEMS small to conserve stack space, but grow the extra
166 * chunks aggressively.
167 */
168#define BASE_JVL_ITEMS 2 /* number of items a base chunk holds */
169#define MIN_EXTRA_JVL_ITEMS 16 /* min number of items an extra chunk holds */
170
171typedef struct JsonValueList
172{
173 int nitems; /* number of items stored in this chunk */
174 int maxitems; /* allocated length of items[] */
175 struct JsonValueList *next; /* => next chunk, if any */
176 struct JsonValueList *last; /* => last chunk (only valid in base chunk) */
179
180/* State data for iterating through a JsonValueList */
182{
183 JsonValueList *chunk; /* current chunk of list */
184 int nextitem; /* index of next value to return in chunk */
186
187/* Structures for JSON_TABLE execution */
188
189/*
190 * Struct holding the result of jsonpath evaluation, to be used as source row
191 * for JsonTableGetValue() which in turn computes the values of individual
192 * JSON_TABLE columns.
193 */
199
200/*
201 * State of evaluation of row pattern derived by applying jsonpath given in
202 * a JsonTablePlan to an input document given in the parent TableFunc.
203 */
204typedef struct JsonTablePlanState
205{
206 /* Original plan */
208
209 /* The following fields are only valid for JsonTablePathScan plans */
210
211 /* jsonpath to evaluate against the input doc to get the row pattern */
213
214 /*
215 * Memory context to use when evaluating the row pattern from the jsonpath
216 */
218
219 /* PASSING arguments passed to jsonpath executor */
221
222 /* List and iterator of jsonpath result values */
225
226 /* Currently selected row for JsonTableGetValue() to use */
228
229 /* Counter for ORDINAL columns */
231
232 /* Nested plan, if any */
234
235 /* Left sibling, if any */
237
238 /* Right sibling, if any */
240
241 /* Parent plan, if this is a nested plan */
244
245/* Random number to identify JsonTableExecContext for sanity checking */
246#define JSON_TABLE_EXEC_CONTEXT_MAGIC 418352867
247
249{
250 int magic;
251
252 /* State of the plan providing a row evaluated from "root" jsonpath */
254
255 /*
256 * Per-column JsonTablePlanStates for all columns including the nested
257 * ones.
258 */
261
262/* strict/lax flags is decomposed into four [un]wrap/error flags */
263#define jspStrictAbsenceOfErrors(cxt) (!(cxt)->laxMode)
264#define jspAutoUnwrap(cxt) ((cxt)->laxMode)
265#define jspAutoWrap(cxt) ((cxt)->laxMode)
266#define jspIgnoreStructuralErrors(cxt) ((cxt)->ignoreStructuralErrors)
267#define jspThrowErrors(cxt) ((cxt)->throwErrors)
268
269/* Convenience macro: return or throw error depending on context */
270#define RETURN_ERROR(throw_error) \
271do { \
272 if (jspThrowErrors(cxt)) \
273 throw_error; \
274 else \
275 return jperError; \
276} while (0)
277
279 JsonbValue *larg,
280 JsonbValue *rarg,
281 void *param);
283 Node *escontext);
284
288 Jsonb *json, bool throwErrors,
289 JsonValueList *result, bool useTz);
294 JsonValueList *found, bool unwrap);
297 JsonValueList *found, bool unwrapElements);
300 JsonbValue *v, JsonValueList *found);
302 bool unwrap, JsonValueList *found);
304 JsonbValue *jb, bool unwrap, JsonValueList *found);
311 uint32 level, uint32 first, uint32 last,
312 bool ignoreStructuralErrors, bool unwrapNext);
314 JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg,
316 JsonPathPredicateCallback exec, void *param);
319 BinaryArithmFunc func, JsonValueList *found);
322 JsonValueList *found);
324 JsonbValue *whole, JsonbValue *initial, void *param);
326 JsonbValue *rarg, void *param);
329 JsonValueList *found);
331 JsonbValue *jb, JsonValueList *found);
333 JsonbValue *jb, JsonValueList *found);
338static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
340static JsonbValue *GetJsonPathVar(void *cxt, char *varName, int varNameLen,
341 JsonbValue *baseObject, int *baseObjectId);
342static int CountJsonPathVars(void *cxt);
343static void JsonItemFromDatum(Datum val, Oid typid, int32 typmod,
344 JsonbValue *res);
348static int countVariablesFromJsonb(void *varsJsonb);
349static JsonbValue *getJsonPathVariableFromJsonb(void *varsJsonb, char *varName,
350 int varNameLength,
351 JsonbValue *baseObject,
352 int *baseObjectId);
353static int JsonbArraySize(JsonbValue *jb);
355 JsonbValue *rv, void *p);
357 bool useTz);
358static int compareNumeric(Numeric a, Numeric b);
363 JsonbValue *jbv, int32 id);
367static bool JsonValueListIsEmpty(const JsonValueList *jvl);
368static bool JsonValueListIsSingleton(const JsonValueList *jvl);
375static int JsonbType(JsonbValue *jb);
376static JsonbValue *getScalar(JsonbValue *scalar, enum jbvType type);
379 bool useTz, bool *cast_error);
380static void checkTimezoneIsUsedForCast(bool useTz, const char *type1,
381 const char *type2);
382
383static void JsonTableInitOpaque(TableFuncScanState *state, int natts);
387 List *args,
388 MemoryContext mcxt);
390static void JsonTableResetRowPattern(JsonTablePlanState *planstate, Datum item);
393 Oid typid, int32 typmod, bool *isnull);
395static bool JsonTablePlanScanNextRow(JsonTablePlanState *planstate);
396static void JsonTableResetNestedPlan(JsonTablePlanState *planstate);
397static bool JsonTablePlanJoinNextRow(JsonTablePlanState *planstate);
398static bool JsonTablePlanNextRow(JsonTablePlanState *planstate);
399
401{
403 .SetDocument = JsonTableSetDocument,
404 .SetNamespace = NULL,
405 .SetRowFilter = NULL,
406 .SetColumnFilter = NULL,
407 .FetchRow = JsonTableFetchRow,
408 .GetValue = JsonTableGetValue,
409 .DestroyOpaque = JsonTableDestroyOpaque
410};
411
412/****************** User interface to JsonPath executor ********************/
413
414/*
415 * jsonb_path_exists
416 * Returns true if jsonpath returns at least one item for the specified
417 * jsonb value. This function and jsonb_path_match() are used to
418 * implement @? and @@ operators, which in turn are intended to have an
419 * index support. Thus, it's desirable to make it easier to achieve
420 * consistency between index scan results and sequential scan results.
421 * So, we throw as few errors as possible. Regarding this function,
422 * such behavior also matches behavior of JSON_EXISTS() clause of
423 * SQL/JSON. Regarding jsonb_path_match(), this function doesn't have
424 * an analogy in SQL/JSON, so we define its behavior on our own.
425 */
426static Datum
428{
432 Jsonb *vars = NULL;
433 bool silent = true;
434
435 if (PG_NARGS() == 4)
436 {
439 }
440
443 jb, !silent, NULL, tz);
444
447
448 if (jperIsError(res))
450
451 PG_RETURN_BOOL(res == jperOk);
452}
453
454Datum
459
460Datum
465
466/*
467 * jsonb_path_exists_opr
468 * Implementation of operator "jsonb @? jsonpath" (2-argument version of
469 * jsonb_path_exists()).
470 */
471Datum
473{
474 /* just call the other one -- it can handle both cases */
475 return jsonb_path_exists_internal(fcinfo, false);
476}
477
478/*
479 * jsonb_path_match
480 * Returns jsonpath predicate result item for the specified jsonb value.
481 * See jsonb_path_exists() comment for details regarding error handling.
482 */
483static Datum
485{
488 Jsonb *vars = NULL;
489 bool silent = true;
490 JsonValueList found;
491
492 if (PG_NARGS() == 4)
493 {
496 }
497
498 JsonValueListInit(&found);
499
502 jb, !silent, &found, tz);
503
506
507 if (JsonValueListIsSingleton(&found))
508 {
510
511 if (jbv->type == jbvBool)
512 PG_RETURN_BOOL(jbv->val.boolean);
513
514 if (jbv->type == jbvNull)
516 }
517
518 if (!silent)
521 errmsg("single boolean result is expected")));
522
524}
525
526Datum
528{
529 return jsonb_path_match_internal(fcinfo, false);
530}
531
532Datum
537
538/*
539 * jsonb_path_match_opr
540 * Implementation of operator "jsonb @@ jsonpath" (2-argument version of
541 * jsonb_path_match()).
542 */
543Datum
545{
546 /* just call the other one -- it can handle both cases */
547 return jsonb_path_match_internal(fcinfo, false);
548}
549
550/*
551 * jsonb_path_query
552 * Executes jsonpath for given jsonb document and returns result as
553 * rowset.
554 */
555static Datum
557{
560 JsonbValue *v;
561
562 if (SRF_IS_FIRSTCALL())
563 {
564 JsonPath *jp;
565 Jsonb *jb;
566 Jsonb *vars;
567 bool silent;
568 MemoryContext oldcontext;
569 JsonValueList *found;
570
572 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
573
578
580 JsonValueListInit(found);
581
584 jb, !silent, found, tz);
585
587 JsonValueListInitIterator(found, iter);
588
589 funcctx->user_fctx = iter;
590
591 MemoryContextSwitchTo(oldcontext);
592 }
593
595 iter = funcctx->user_fctx;
596
597 v = JsonValueListNext(iter);
598
599 if (v == NULL)
601
603}
604
605Datum
607{
608 return jsonb_path_query_internal(fcinfo, false);
609}
610
611Datum
616
617/*
618 * jsonb_path_query_array
619 * Executes jsonpath for given jsonb document and returns result as
620 * jsonb array.
621 */
622static Datum
639
640Datum
645
646Datum
651
652/*
653 * jsonb_path_query_first
654 * Executes jsonpath for given jsonb document and returns first result
655 * item. If there are no items, NULL returned.
656 */
657static Datum
677
678Datum
683
684Datum
689
690/********************Execute functions for JsonPath**************************/
691
692/*
693 * Interface to jsonpath executor
694 *
695 * 'path' - jsonpath to be executed
696 * 'vars' - variables to be substituted to jsonpath
697 * 'getVar' - callback used by getJsonPathVariable() to extract variables from
698 * 'vars'
699 * 'countVars' - callback to count the number of jsonpath variables in 'vars'
700 * 'json' - target document for jsonpath evaluation
701 * 'throwErrors' - whether we should throw suppressible errors
702 * 'result' - list to store result items into
703 *
704 * Returns an error if a recoverable error happens during processing, or NULL
705 * on no error.
706 *
707 * Note, jsonb and jsonpath values should be available and untoasted during
708 * work because JsonPathItem, JsonbValue and result item could have pointers
709 * into input values. If caller needs to just check if document matches
710 * jsonpath, then it doesn't provide a result arg. In this case executor
711 * works till first positive result and does not check the rest if possible.
712 * In other case it tries to find all the satisfied result items.
713 */
717 Jsonb *json, bool throwErrors, JsonValueList *result,
718 bool useTz)
719{
724
725 jspInit(&jsp, path);
726
727 if (!JsonbExtractScalar(&json->root, &jbv))
728 JsonbInitBinary(&jbv, json);
729
730 cxt.vars = vars;
731 cxt.getVar = getVar;
732 cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
734 cxt.root = &jbv;
735 cxt.current = &jbv;
736 cxt.baseObject.jbc = NULL;
737 cxt.baseObject.id = 0;
738 /* 1 + number of base objects in vars */
740 cxt.innermostArraySize = -1;
741 cxt.throwErrors = throwErrors;
742 cxt.useTz = useTz;
743
744 if (jspStrictAbsenceOfErrors(&cxt) && !result)
745 {
746 /*
747 * In strict mode we must get a complete list of values to check that
748 * there are no errors at all.
749 */
750 JsonValueList vals;
751 bool isempty;
752
753 JsonValueListInit(&vals);
754
755 res = executeItem(&cxt, &jsp, &jbv, &vals);
756
758 JsonValueListClear(&vals);
759
760 if (jperIsError(res))
761 return res;
762
763 return isempty ? jperNotFound : jperOk;
764 }
765
766 res = executeItem(&cxt, &jsp, &jbv, result);
767
768 Assert(!throwErrors || !jperIsError(res));
769
770 return res;
771}
772
773/*
774 * Execute jsonpath with automatic unwrapping of current item in lax mode.
775 */
782
783/*
784 * Main jsonpath executor function: walks on jsonpath structure, finds
785 * relevant parts of jsonb and evaluates expressions over them.
786 * When 'unwrap' is true current SQL/JSON item is unwrapped if it is an array.
787 */
790 JsonbValue *jb, JsonValueList *found, bool unwrap)
791{
792 JsonPathItem elem;
794 JsonBaseObjectInfo baseObject;
795
798
799 switch (jsp->type)
800 {
801 case jpiNull:
802 case jpiBool:
803 case jpiNumeric:
804 case jpiString:
805 case jpiVariable:
806 {
807 JsonbValue v;
808 bool hasNext = jspGetNext(jsp, &elem);
809
810 if (!hasNext && !found && jsp->type != jpiVariable)
811 {
812 /*
813 * Skip evaluation, but not for variables. We must
814 * trigger an error for the missing variable.
815 */
816 res = jperOk;
817 break;
818 }
819
820 baseObject = cxt->baseObject;
821 getJsonPathItem(cxt, jsp, &v);
822
823 res = executeNextItem(cxt, jsp, &elem,
824 &v, found);
825 cxt->baseObject = baseObject;
826 }
827 break;
828
829 /* all boolean item types: */
830 case jpiAnd:
831 case jpiOr:
832 case jpiNot:
833 case jpiIsUnknown:
834 case jpiEqual:
835 case jpiNotEqual:
836 case jpiLess:
837 case jpiGreater:
838 case jpiLessOrEqual:
840 case jpiExists:
841 case jpiStartsWith:
842 case jpiLikeRegex:
843 {
844 JsonPathBool st = executeBoolItem(cxt, jsp, jb, true);
845
846 res = appendBoolResult(cxt, jsp, found, st);
847 break;
848 }
849
850 case jpiAdd:
851 return executeBinaryArithmExpr(cxt, jsp, jb,
852 numeric_add_safe, found);
853
854 case jpiSub:
855 return executeBinaryArithmExpr(cxt, jsp, jb,
856 numeric_sub_safe, found);
857
858 case jpiMul:
859 return executeBinaryArithmExpr(cxt, jsp, jb,
860 numeric_mul_safe, found);
861
862 case jpiDiv:
863 return executeBinaryArithmExpr(cxt, jsp, jb,
864 numeric_div_safe, found);
865
866 case jpiMod:
867 return executeBinaryArithmExpr(cxt, jsp, jb,
868 numeric_mod_safe, found);
869
870 case jpiPlus:
871 return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
872
873 case jpiMinus:
875 found);
876
877 case jpiAnyArray:
878 if (JsonbType(jb) == jbvArray)
879 {
880 bool hasNext = jspGetNext(jsp, &elem);
881
882 res = executeItemUnwrapTargetArray(cxt, hasNext ? &elem : NULL,
883 jb, found, jspAutoUnwrap(cxt));
884 }
885 else if (jspAutoWrap(cxt))
886 res = executeNextItem(cxt, jsp, NULL, jb, found);
887 else if (!jspIgnoreStructuralErrors(cxt))
890 errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
891 break;
892
893 case jpiAnyKey:
894 if (JsonbType(jb) == jbvObject)
895 {
896 bool hasNext = jspGetNext(jsp, &elem);
897
898 if (jb->type != jbvBinary)
899 elog(ERROR, "invalid jsonb object type: %d", jb->type);
900
901 return executeAnyItem
902 (cxt, hasNext ? &elem : NULL,
903 jb->val.binary.data, found, 1, 1, 1,
904 false, jspAutoUnwrap(cxt));
905 }
906 else if (unwrap && JsonbType(jb) == jbvArray)
907 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
908 else if (!jspIgnoreStructuralErrors(cxt))
909 {
910 Assert(found);
913 errmsg("jsonpath wildcard member accessor can only be applied to an object"))));
914 }
915 break;
916
917 case jpiIndexArray:
918 if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
919 {
920 int innermostArraySize = cxt->innermostArraySize;
921 int i;
922 int size = JsonbArraySize(jb);
923 bool singleton = size < 0;
924 bool hasNext = jspGetNext(jsp, &elem);
925
926 if (singleton)
927 size = 1;
928
929 cxt->innermostArraySize = size; /* for LAST evaluation */
930
931 for (i = 0; i < jsp->content.array.nelems; i++)
932 {
933 JsonPathItem from;
934 JsonPathItem to;
935 int32 index;
938 bool range = jspGetArraySubscript(jsp, &from,
939 &to, i);
940
941 res = getArrayIndex(cxt, &from, jb, &index_from);
942
943 if (jperIsError(res))
944 break;
945
946 if (range)
947 {
948 res = getArrayIndex(cxt, &to, jb, &index_to);
949
950 if (jperIsError(res))
951 break;
952 }
953 else
955
956 if (!jspIgnoreStructuralErrors(cxt) &&
957 (index_from < 0 ||
959 index_to >= size))
962 errmsg("jsonpath array subscript is out of bounds"))));
963
964 if (index_from < 0)
965 index_from = 0;
966
967 if (index_to >= size)
968 index_to = size - 1;
969
970 res = jperNotFound;
971
972 for (index = index_from; index <= index_to; index++)
973 {
974 JsonbValue *v;
975
976 if (singleton)
977 {
978 v = jb;
979 }
980 else
981 {
982 v = getIthJsonbValueFromContainer(jb->val.binary.data,
983 (uint32) index);
984
985 if (v == NULL)
986 continue;
987 }
988
989 if (!hasNext && !found)
990 return jperOk;
991
992 res = executeNextItem(cxt, jsp, &elem, v, found);
993
994 if (jperIsError(res))
995 break;
996
997 if (res == jperOk && !found)
998 break;
999 }
1000
1001 if (jperIsError(res))
1002 break;
1003
1004 if (res == jperOk && !found)
1005 break;
1006 }
1007
1008 cxt->innermostArraySize = innermostArraySize;
1009 }
1010 else if (!jspIgnoreStructuralErrors(cxt))
1011 {
1014 errmsg("jsonpath array accessor can only be applied to an array"))));
1015 }
1016 break;
1017
1018 case jpiAny:
1019 {
1020 bool hasNext = jspGetNext(jsp, &elem);
1021
1022 /* first try without any intermediate steps */
1023 if (jsp->content.anybounds.first == 0)
1024 {
1026
1028 cxt->ignoreStructuralErrors = true;
1029 res = executeNextItem(cxt, jsp, &elem,
1030 jb, found);
1032
1033 if (res == jperOk && !found)
1034 break;
1035 }
1036
1037 if (jb->type == jbvBinary)
1038 res = executeAnyItem
1039 (cxt, hasNext ? &elem : NULL,
1040 jb->val.binary.data, found,
1041 1,
1042 jsp->content.anybounds.first,
1043 jsp->content.anybounds.last,
1044 true, jspAutoUnwrap(cxt));
1045 break;
1046 }
1047
1048 case jpiKey:
1049 if (JsonbType(jb) == jbvObject)
1050 {
1051 JsonbValue *v;
1052 JsonbValue key;
1053
1054 key.type = jbvString;
1055 key.val.string.val = jspGetString(jsp, &key.val.string.len);
1056
1057 v = findJsonbValueFromContainer(jb->val.binary.data,
1058 JB_FOBJECT, &key);
1059
1060 if (v != NULL)
1061 {
1062 res = executeNextItem(cxt, jsp, NULL,
1063 v, found);
1064 pfree(v);
1065 }
1066 else if (!jspIgnoreStructuralErrors(cxt))
1067 {
1068 Assert(found);
1069
1070 if (!jspThrowErrors(cxt))
1071 return jperError;
1072
1073 ereport(ERROR,
1075 errmsg("JSON object does not contain key \"%s\"",
1076 pnstrdup(key.val.string.val,
1077 key.val.string.len))));
1078 }
1079 }
1080 else if (unwrap && JsonbType(jb) == jbvArray)
1081 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1082 else if (!jspIgnoreStructuralErrors(cxt))
1083 {
1084 Assert(found);
1087 errmsg("jsonpath member accessor can only be applied to an object"))));
1088 }
1089 break;
1090
1091 case jpiCurrent:
1092 res = executeNextItem(cxt, jsp, NULL, cxt->current, found);
1093 break;
1094
1095 case jpiRoot:
1096 jb = cxt->root;
1097 baseObject = setBaseObject(cxt, jb, 0);
1098 res = executeNextItem(cxt, jsp, NULL, jb, found);
1099 cxt->baseObject = baseObject;
1100 break;
1101
1102 case jpiFilter:
1103 {
1104 JsonPathBool st;
1105
1106 if (unwrap && JsonbType(jb) == jbvArray)
1107 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1108 false);
1109
1110 jspGetArg(jsp, &elem);
1111 st = executeNestedBoolItem(cxt, &elem, jb);
1112 if (st != jpbTrue)
1113 res = jperNotFound;
1114 else
1115 res = executeNextItem(cxt, jsp, NULL,
1116 jb, found);
1117 break;
1118 }
1119
1120 case jpiType:
1121 {
1123
1124 jbv.type = jbvString;
1125 jbv.val.string.val = pstrdup(JsonbTypeName(jb));
1126 jbv.val.string.len = strlen(jbv.val.string.val);
1127
1128 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1129 }
1130 break;
1131
1132 case jpiSize:
1133 {
1134 int size = JsonbArraySize(jb);
1136
1137 if (size < 0)
1138 {
1139 if (!jspAutoWrap(cxt))
1140 {
1141 if (!jspIgnoreStructuralErrors(cxt))
1144 errmsg("jsonpath item method .%s() can only be applied to an array",
1145 jspOperationName(jsp->type)))));
1146 break;
1147 }
1148
1149 size = 1;
1150 }
1151
1152 jbv.type = jbvNumeric;
1153 jbv.val.numeric = int64_to_numeric(size);
1154
1155 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1156 }
1157 break;
1158
1159 case jpiAbs:
1161 found);
1162
1163 case jpiFloor:
1165 found);
1166
1167 case jpiCeiling:
1169 found);
1170
1171 case jpiDouble:
1172 {
1174
1175 if (unwrap && JsonbType(jb) == jbvArray)
1176 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1177 false);
1178
1179 if (jb->type == jbvNumeric)
1180 {
1182 NumericGetDatum(jb->val.numeric)));
1183 double val;
1185
1186 val = float8in_internal(tmp,
1187 NULL,
1188 "double precision",
1189 tmp,
1190 (Node *) &escontext);
1191
1192 if (escontext.error_occurred)
1195 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1196 tmp, jspOperationName(jsp->type), "double precision"))));
1197 if (isinf(val) || isnan(val))
1200 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1201 jspOperationName(jsp->type)))));
1202 res = jperOk;
1203 }
1204 else if (jb->type == jbvString)
1205 {
1206 /* cast string as double */
1207 double val;
1208 char *tmp = pnstrdup(jb->val.string.val,
1209 jb->val.string.len);
1211
1212 val = float8in_internal(tmp,
1213 NULL,
1214 "double precision",
1215 tmp,
1216 (Node *) &escontext);
1217
1218 if (escontext.error_occurred)
1221 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1222 tmp, jspOperationName(jsp->type), "double precision"))));
1223 if (isinf(val) || isnan(val))
1226 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1227 jspOperationName(jsp->type)))));
1228
1229 jb = &jbv;
1230 jb->type = jbvNumeric;
1233 res = jperOk;
1234 }
1235
1236 if (res == jperNotFound)
1239 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1240 jspOperationName(jsp->type)))));
1241
1242 res = executeNextItem(cxt, jsp, NULL, jb, found);
1243 }
1244 break;
1245
1246 case jpiDatetime:
1247 case jpiDate:
1248 case jpiTime:
1249 case jpiTimeTz:
1250 case jpiTimestamp:
1251 case jpiTimestampTz:
1252 if (unwrap && JsonbType(jb) == jbvArray)
1253 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1254
1255 return executeDateTimeMethod(cxt, jsp, jb, found);
1256
1257 case jpiKeyValue:
1258 if (unwrap && JsonbType(jb) == jbvArray)
1259 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1260
1261 return executeKeyValueMethod(cxt, jsp, jb, found);
1262
1263 case jpiLast:
1264 {
1266 int last;
1267 bool hasNext = jspGetNext(jsp, &elem);
1268
1269 if (cxt->innermostArraySize < 0)
1270 elog(ERROR, "evaluating jsonpath LAST outside of array subscript");
1271
1272 if (!hasNext && !found)
1273 {
1274 res = jperOk;
1275 break;
1276 }
1277
1278 last = cxt->innermostArraySize - 1;
1279
1280 jbv.type = jbvNumeric;
1281 jbv.val.numeric = int64_to_numeric(last);
1282
1283 res = executeNextItem(cxt, jsp, &elem,
1284 &jbv, found);
1285 }
1286 break;
1287
1288 case jpiBigint:
1289 {
1291 Datum datum;
1292
1293 if (unwrap && JsonbType(jb) == jbvArray)
1294 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1295 false);
1296
1297 if (jb->type == jbvNumeric)
1298 {
1300 int64 val;
1301
1302 val = numeric_int8_safe(jb->val.numeric,
1303 (Node *) &escontext);
1304 if (escontext.error_occurred)
1307 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1309 NumericGetDatum(jb->val.numeric))),
1310 jspOperationName(jsp->type),
1311 "bigint"))));
1312
1313 datum = Int64GetDatum(val);
1314 res = jperOk;
1315 }
1316 else if (jb->type == jbvString)
1317 {
1318 /* cast string as bigint */
1319 char *tmp = pnstrdup(jb->val.string.val,
1320 jb->val.string.len);
1322 bool noerr;
1323
1325 InvalidOid, -1,
1326 (Node *) &escontext,
1327 &datum);
1328
1329 if (!noerr || escontext.error_occurred)
1332 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1333 tmp, jspOperationName(jsp->type), "bigint"))));
1334 res = jperOk;
1335 }
1336
1337 if (res == jperNotFound)
1340 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1341 jspOperationName(jsp->type)))));
1342
1343 jbv.type = jbvNumeric;
1345 datum));
1346
1347 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1348 }
1349 break;
1350
1351 case jpiBoolean:
1352 {
1354 bool bval;
1355
1356 if (unwrap && JsonbType(jb) == jbvArray)
1357 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1358 false);
1359
1360 if (jb->type == jbvBool)
1361 {
1362 bval = jb->val.boolean;
1363
1364 res = jperOk;
1365 }
1366 else if (jb->type == jbvNumeric)
1367 {
1368 int ival;
1369 Datum datum;
1370 bool noerr;
1372 NumericGetDatum(jb->val.numeric)));
1374
1376 InvalidOid, -1,
1377 (Node *) &escontext,
1378 &datum);
1379
1380 if (!noerr || escontext.error_occurred)
1383 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1384 tmp, jspOperationName(jsp->type), "boolean"))));
1385
1386 ival = DatumGetInt32(datum);
1387 if (ival == 0)
1388 bval = false;
1389 else
1390 bval = true;
1391
1392 res = jperOk;
1393 }
1394 else if (jb->type == jbvString)
1395 {
1396 /* cast string as boolean */
1397 char *tmp = pnstrdup(jb->val.string.val,
1398 jb->val.string.len);
1399
1400 if (!parse_bool(tmp, &bval))
1403 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1404 tmp, jspOperationName(jsp->type), "boolean"))));
1405
1406 res = jperOk;
1407 }
1408
1409 if (res == jperNotFound)
1412 errmsg("jsonpath item method .%s() can only be applied to a boolean, string, or numeric value",
1413 jspOperationName(jsp->type)))));
1414
1415 jbv.type = jbvBool;
1416 jbv.val.boolean = bval;
1417
1418 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1419 }
1420 break;
1421
1422 case jpiDecimal:
1423 case jpiNumber:
1424 {
1426 Numeric num;
1427 char *numstr = NULL;
1428
1429 if (unwrap && JsonbType(jb) == jbvArray)
1430 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1431 false);
1432
1433 if (jb->type == jbvNumeric)
1434 {
1435 num = jb->val.numeric;
1436 if (numeric_is_nan(num) || numeric_is_inf(num))
1439 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1440 jspOperationName(jsp->type)))));
1441
1442 if (jsp->type == jpiDecimal)
1444 NumericGetDatum(num)));
1445 res = jperOk;
1446 }
1447 else if (jb->type == jbvString)
1448 {
1449 /* cast string as number */
1450 Datum datum;
1451 bool noerr;
1453
1454 numstr = pnstrdup(jb->val.string.val, jb->val.string.len);
1455
1457 InvalidOid, -1,
1458 (Node *) &escontext,
1459 &datum);
1460
1461 if (!noerr || escontext.error_occurred)
1464 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1465 numstr, jspOperationName(jsp->type), "numeric"))));
1466
1467 num = DatumGetNumeric(datum);
1468 if (numeric_is_nan(num) || numeric_is_inf(num))
1471 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1472 jspOperationName(jsp->type)))));
1473
1474 res = jperOk;
1475 }
1476
1477 if (res == jperNotFound)
1480 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1481 jspOperationName(jsp->type)))));
1482
1483 /*
1484 * If we have arguments, then they must be the precision and
1485 * optional scale used in .decimal(). Convert them to the
1486 * typmod equivalent and then truncate the numeric value per
1487 * this typmod details.
1488 */
1489 if (jsp->type == jpiDecimal && jsp->content.args.left)
1490 {
1492 Datum dtypmod;
1493 int32 precision;
1494 int32 scale = 0;
1495 bool noerr;
1497 Datum datums[2];
1498 char pstr[12]; /* sign, 10 digits and '\0' */
1499 char sstr[12]; /* sign, 10 digits and '\0' */
1501
1502 jspGetLeftArg(jsp, &elem);
1503 if (elem.type != jpiNumeric)
1504 elog(ERROR, "invalid jsonpath item type for .decimal() precision");
1505
1506 precision = numeric_int4_safe(jspGetNumeric(&elem),
1507 (Node *) &escontext);
1508 if (escontext.error_occurred)
1511 errmsg("precision of jsonpath item method .%s() is out of range for type integer",
1512 jspOperationName(jsp->type)))));
1513
1514 if (jsp->content.args.right)
1515 {
1516 jspGetRightArg(jsp, &elem);
1517 if (elem.type != jpiNumeric)
1518 elog(ERROR, "invalid jsonpath item type for .decimal() scale");
1519
1521 (Node *) &escontext);
1522 if (escontext.error_occurred)
1525 errmsg("scale of jsonpath item method .%s() is out of range for type integer",
1526 jspOperationName(jsp->type)))));
1527 }
1528
1529 /*
1530 * numerictypmodin() takes the precision and scale in the
1531 * form of CString arrays.
1532 */
1533 pg_ltoa(precision, pstr);
1534 datums[0] = CStringGetDatum(pstr);
1535 pg_ltoa(scale, sstr);
1536 datums[1] = CStringGetDatum(sstr);
1538
1541
1542 /* Convert numstr to Numeric with typmod */
1543 Assert(numstr != NULL);
1546 (Node *) &escontext,
1547 &numdatum);
1548
1549 if (!noerr || escontext.error_occurred)
1552 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1553 numstr, jspOperationName(jsp->type), "numeric"))));
1554
1557 }
1558
1559 jbv.type = jbvNumeric;
1560 jbv.val.numeric = num;
1561
1562 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1563 }
1564 break;
1565
1566 case jpiInteger:
1567 {
1569 Datum datum;
1570
1571 if (unwrap && JsonbType(jb) == jbvArray)
1572 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1573 false);
1574
1575 if (jb->type == jbvNumeric)
1576 {
1577 int32 val;
1579
1580 val = numeric_int4_safe(jb->val.numeric,
1581 (Node *) &escontext);
1582 if (escontext.error_occurred)
1585 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1587 NumericGetDatum(jb->val.numeric))),
1588 jspOperationName(jsp->type), "integer"))));
1589
1590 datum = Int32GetDatum(val);
1591 res = jperOk;
1592 }
1593 else if (jb->type == jbvString)
1594 {
1595 /* cast string as integer */
1596 char *tmp = pnstrdup(jb->val.string.val,
1597 jb->val.string.len);
1599 bool noerr;
1600
1602 InvalidOid, -1,
1603 (Node *) &escontext,
1604 &datum);
1605
1606 if (!noerr || escontext.error_occurred)
1609 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1610 tmp, jspOperationName(jsp->type), "integer"))));
1611 res = jperOk;
1612 }
1613
1614 if (res == jperNotFound)
1617 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1618 jspOperationName(jsp->type)))));
1619
1620 jbv.type = jbvNumeric;
1622 datum));
1623
1624 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1625 }
1626 break;
1627
1628 case jpiStringFunc:
1629 {
1631 char *tmp = NULL;
1632
1633 if (unwrap && JsonbType(jb) == jbvArray)
1634 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1635
1636 switch (JsonbType(jb))
1637 {
1638 case jbvString:
1639
1640 /*
1641 * Value is not necessarily null-terminated, so we do
1642 * pnstrdup() here.
1643 */
1644 tmp = pnstrdup(jb->val.string.val,
1645 jb->val.string.len);
1646 break;
1647 case jbvNumeric:
1649 NumericGetDatum(jb->val.numeric)));
1650 break;
1651 case jbvBool:
1652 tmp = (jb->val.boolean) ? "true" : "false";
1653 break;
1654 case jbvDatetime:
1655 {
1656 char buf[MAXDATELEN + 1];
1657
1659 jb->val.datetime.value,
1660 jb->val.datetime.typid,
1661 &jb->val.datetime.tz);
1662 tmp = pstrdup(buf);
1663 }
1664 break;
1665 case jbvNull:
1666 case jbvArray:
1667 case jbvObject:
1668 case jbvBinary:
1671 errmsg("jsonpath item method .%s() can only be applied to a boolean, string, numeric, or datetime value",
1672 jspOperationName(jsp->type)))));
1673 break;
1674 }
1675
1676 Assert(tmp != NULL); /* We must have set tmp above */
1677 jbv.val.string.val = tmp;
1678 jbv.val.string.len = strlen(jbv.val.string.val);
1679 jbv.type = jbvString;
1680
1681 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1682 }
1683 break;
1684
1685 case jpiStrReplace:
1686 case jpiStrLower:
1687 case jpiStrUpper:
1688 case jpiStrLtrim:
1689 case jpiStrRtrim:
1690 case jpiStrBtrim:
1691 case jpiStrInitcap:
1692 case jpiStrSplitPart:
1693 {
1694 if (unwrap && JsonbType(jb) == jbvArray)
1695 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1696
1697 return executeStringInternalMethod(cxt, jsp, jb, found);
1698 }
1699 break;
1700
1701 default:
1702 elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
1703 }
1704
1705 return res;
1706}
1707
1708/*
1709 * Unwrap current array item and execute jsonpath for each of its elements.
1710 */
1711static JsonPathExecResult
1713 JsonbValue *jb, JsonValueList *found,
1714 bool unwrapElements)
1715{
1716 if (jb->type != jbvBinary)
1717 {
1718 Assert(jb->type != jbvArray);
1719 elog(ERROR, "invalid jsonb array value type: %d", jb->type);
1720 }
1721
1722 return executeAnyItem
1723 (cxt, jsp, jb->val.binary.data, found, 1, 1, 1,
1724 false, unwrapElements);
1725}
1726
1727/*
1728 * Execute next jsonpath item if exists. Otherwise put "v" to the "found"
1729 * list if provided.
1730 */
1731static JsonPathExecResult
1734 JsonbValue *v, JsonValueList *found)
1735{
1736 JsonPathItem elem;
1737 bool hasNext;
1738
1739 if (!cur)
1740 hasNext = next != NULL;
1741 else if (next)
1743 else
1744 {
1745 next = &elem;
1747 }
1748
1749 if (hasNext)
1750 return executeItem(cxt, next, v, found);
1751
1752 if (found)
1753 JsonValueListAppend(found, v);
1754
1755 return jperOk;
1756}
1757
1758/*
1759 * Same as executeItem(), but when "unwrap == true" automatically unwraps
1760 * each array item from the resulting sequence in lax mode.
1761 */
1762static JsonPathExecResult
1764 JsonbValue *jb, bool unwrap,
1765 JsonValueList *found)
1766{
1767 if (unwrap && jspAutoUnwrap(cxt))
1768 {
1772 JsonbValue *item;
1773
1775
1776 res = executeItem(cxt, jsp, jb, &seq);
1777
1778 if (jperIsError(res))
1779 {
1781 return res;
1782 }
1783
1785 while ((item = JsonValueListNext(&it)))
1786 {
1787 Assert(item->type != jbvArray);
1788
1789 if (JsonbType(item) == jbvArray)
1790 executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
1791 else
1792 JsonValueListAppend(found, item);
1793 }
1794
1796
1797 return jperOk;
1798 }
1799
1800 return executeItem(cxt, jsp, jb, found);
1801}
1802
1803/*
1804 * Same as executeItemOptUnwrapResult(), but with error suppression.
1805 */
1806static JsonPathExecResult
1809 JsonbValue *jb, bool unwrap,
1810 JsonValueList *found)
1811{
1813 bool throwErrors = cxt->throwErrors;
1814
1815 cxt->throwErrors = false;
1816 res = executeItemOptUnwrapResult(cxt, jsp, jb, unwrap, found);
1817 cxt->throwErrors = throwErrors;
1818
1819 return res;
1820}
1821
1822/* Execute boolean-valued jsonpath expression. */
1823static JsonPathBool
1825 JsonbValue *jb, bool canHaveNext)
1826{
1827 JsonPathItem larg;
1828 JsonPathItem rarg;
1829 JsonPathBool res;
1831
1832 /* since this function recurses, it could be driven to stack overflow */
1834
1835 if (!canHaveNext && jspHasNext(jsp))
1836 elog(ERROR, "boolean jsonpath item cannot have next item");
1837
1838 switch (jsp->type)
1839 {
1840 case jpiAnd:
1841 jspGetLeftArg(jsp, &larg);
1842 res = executeBoolItem(cxt, &larg, jb, false);
1843
1844 if (res == jpbFalse)
1845 return jpbFalse;
1846
1847 /*
1848 * SQL/JSON says that we should check second arg in case of
1849 * jperError
1850 */
1851
1852 jspGetRightArg(jsp, &rarg);
1853 res2 = executeBoolItem(cxt, &rarg, jb, false);
1854
1855 return res2 == jpbTrue ? res : res2;
1856
1857 case jpiOr:
1858 jspGetLeftArg(jsp, &larg);
1859 res = executeBoolItem(cxt, &larg, jb, false);
1860
1861 if (res == jpbTrue)
1862 return jpbTrue;
1863
1864 jspGetRightArg(jsp, &rarg);
1865 res2 = executeBoolItem(cxt, &rarg, jb, false);
1866
1867 return res2 == jpbFalse ? res : res2;
1868
1869 case jpiNot:
1870 jspGetArg(jsp, &larg);
1871
1872 res = executeBoolItem(cxt, &larg, jb, false);
1873
1874 if (res == jpbUnknown)
1875 return jpbUnknown;
1876
1877 return res == jpbTrue ? jpbFalse : jpbTrue;
1878
1879 case jpiIsUnknown:
1880 jspGetArg(jsp, &larg);
1881 res = executeBoolItem(cxt, &larg, jb, false);
1882 return res == jpbUnknown ? jpbTrue : jpbFalse;
1883
1884 case jpiEqual:
1885 case jpiNotEqual:
1886 case jpiLess:
1887 case jpiGreater:
1888 case jpiLessOrEqual:
1889 case jpiGreaterOrEqual:
1890 jspGetLeftArg(jsp, &larg);
1891 jspGetRightArg(jsp, &rarg);
1892 return executePredicate(cxt, jsp, &larg, &rarg, jb, true,
1893 executeComparison, cxt);
1894
1895 case jpiStartsWith: /* 'whole STARTS WITH initial' */
1896 jspGetLeftArg(jsp, &larg); /* 'whole' */
1897 jspGetRightArg(jsp, &rarg); /* 'initial' */
1898 return executePredicate(cxt, jsp, &larg, &rarg, jb, false,
1900
1901 case jpiLikeRegex: /* 'expr LIKE_REGEX pattern FLAGS flags' */
1902 {
1903 /*
1904 * 'expr' is a sequence-returning expression. 'pattern' is a
1905 * regex string literal. SQL/JSON standard requires XQuery
1906 * regexes, but we use Postgres regexes here. 'flags' is a
1907 * string literal converted to integer flags at compile-time.
1908 */
1910
1911 jspInitByBuffer(&larg, jsp->base,
1912 jsp->content.like_regex.expr);
1913
1914 return executePredicate(cxt, jsp, &larg, NULL, jb, false,
1916 }
1917
1918 case jpiExists:
1919 jspGetArg(jsp, &larg);
1920
1921 if (jspStrictAbsenceOfErrors(cxt))
1922 {
1923 /*
1924 * In strict mode we must get a complete list of values to
1925 * check that there are no errors at all.
1926 */
1927 JsonValueList vals;
1929 bool isempty;
1930
1931 JsonValueListInit(&vals);
1932
1933 res = executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1934 false, &vals);
1935
1937 JsonValueListClear(&vals);
1938
1939 if (jperIsError(res))
1940 return jpbUnknown;
1941
1942 return isempty ? jpbFalse : jpbTrue;
1943 }
1944 else
1945 {
1946 JsonPathExecResult res =
1948 false, NULL);
1949
1950 if (jperIsError(res))
1951 return jpbUnknown;
1952
1953 return res == jperOk ? jpbTrue : jpbFalse;
1954 }
1955
1956 default:
1957 elog(ERROR, "invalid boolean jsonpath item type: %d", jsp->type);
1958 return jpbUnknown;
1959 }
1960}
1961
1962/*
1963 * Execute nested (filters etc.) boolean expression pushing current SQL/JSON
1964 * item onto the stack.
1965 */
1966static JsonPathBool
1968 JsonbValue *jb)
1969{
1970 JsonbValue *prev;
1971 JsonPathBool res;
1972
1973 prev = cxt->current;
1974 cxt->current = jb;
1975 res = executeBoolItem(cxt, jsp, jb, false);
1976 cxt->current = prev;
1977
1978 return res;
1979}
1980
1981/*
1982 * Implementation of several jsonpath nodes:
1983 * - jpiAny (.** accessor),
1984 * - jpiAnyKey (.* accessor),
1985 * - jpiAnyArray ([*] accessor)
1986 */
1987static JsonPathExecResult
1989 JsonValueList *found, uint32 level, uint32 first, uint32 last,
1990 bool ignoreStructuralErrors, bool unwrapNext)
1991{
1994 int32 r;
1995 JsonbValue v;
1996
1998
1999 if (level > last)
2000 return res;
2001
2002 it = JsonbIteratorInit(jbc);
2003
2004 /*
2005 * Recursively iterate over jsonb objects/arrays
2006 */
2007 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
2008 {
2009 if (r == WJB_KEY)
2010 {
2011 r = JsonbIteratorNext(&it, &v, true);
2012 Assert(r == WJB_VALUE);
2013 }
2014
2015 if (r == WJB_VALUE || r == WJB_ELEM)
2016 {
2017
2018 if (level >= first ||
2019 (first == PG_UINT32_MAX && last == PG_UINT32_MAX &&
2020 v.type != jbvBinary)) /* leaves only requested */
2021 {
2022 /* check expression */
2023 if (jsp)
2024 {
2025 if (ignoreStructuralErrors)
2026 {
2028
2030 cxt->ignoreStructuralErrors = true;
2031 res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
2033 }
2034 else
2035 res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
2036
2037 if (jperIsError(res))
2038 break;
2039
2040 if (res == jperOk && !found)
2041 break;
2042 }
2043 else if (found)
2044 JsonValueListAppend(found, &v);
2045 else
2046 return jperOk;
2047 }
2048
2049 if (level < last && v.type == jbvBinary)
2050 {
2051 res = executeAnyItem
2052 (cxt, jsp, v.val.binary.data, found,
2053 level + 1, first, last,
2054 ignoreStructuralErrors, unwrapNext);
2055
2056 if (jperIsError(res))
2057 break;
2058
2059 if (res == jperOk && found == NULL)
2060 break;
2061 }
2062 }
2063 }
2064
2065 return res;
2066}
2067
2068/*
2069 * Execute unary or binary predicate.
2070 *
2071 * Predicates have existence semantics, because their operands are item
2072 * sequences. Pairs of items from the left and right operand's sequences are
2073 * checked. TRUE returned only if any pair satisfying the condition is found.
2074 * In strict mode, even if the desired pair has already been found, all pairs
2075 * still need to be examined to check the absence of errors. If any error
2076 * occurs, UNKNOWN (analogous to SQL NULL) is returned.
2077 */
2078static JsonPathBool
2080 JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb,
2082 void *param)
2083{
2088 JsonbValue *lval;
2089 bool error = false;
2090 bool found = false;
2091
2094
2095 /* Left argument is always auto-unwrapped. */
2096 res = executeItemOptUnwrapResultNoThrow(cxt, larg, jb, true, &lseq);
2097 if (jperIsError(res))
2098 {
2099 error = true;
2100 goto exit;
2101 }
2102
2103 if (rarg)
2104 {
2105 /* Right argument is conditionally auto-unwrapped. */
2106 res = executeItemOptUnwrapResultNoThrow(cxt, rarg, jb,
2108 if (jperIsError(res))
2109 {
2110 error = true;
2111 goto exit;
2112 }
2113 }
2114
2116 while ((lval = JsonValueListNext(&lseqit)))
2117 {
2120 bool first = true;
2121
2123 if (rarg)
2125 else
2126 rval = NULL;
2127
2128 /* Loop over right arg sequence or do single pass otherwise */
2129 while (rarg ? (rval != NULL) : first)
2130 {
2131 JsonPathBool res = exec(pred, lval, rval, param);
2132
2133 if (res == jpbUnknown)
2134 {
2135 error = true;
2136 if (jspStrictAbsenceOfErrors(cxt))
2137 {
2138 found = false; /* return unknown, not success */
2139 goto exit;
2140 }
2141 }
2142 else if (res == jpbTrue)
2143 {
2144 found = true;
2145 if (!jspStrictAbsenceOfErrors(cxt))
2146 goto exit;
2147 }
2148
2149 first = false;
2150 if (rarg)
2152 }
2153 }
2154
2155exit:
2158
2159 if (found) /* possible only in strict mode */
2160 return jpbTrue;
2161
2162 if (error) /* possible only in lax mode */
2163 return jpbUnknown;
2164
2165 return jpbFalse;
2166}
2167
2168/*
2169 * Execute binary arithmetic expression on singleton numeric operands.
2170 * Array operands are automatically unwrapped in lax mode.
2171 */
2172static JsonPathExecResult
2175 JsonValueList *found)
2176{
2178 JsonPathItem elem;
2181 JsonbValue *lval;
2184 Numeric res;
2185
2188
2189 jspGetLeftArg(jsp, &elem);
2190
2191 /*
2192 * XXX: By standard only operands of multiplicative expressions are
2193 * unwrapped. We extend it to other binary arithmetic expressions too.
2194 */
2195 jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &lseq);
2196 if (jperIsError(jper))
2197 {
2200 return jper;
2201 }
2202
2203 jspGetRightArg(jsp, &elem);
2204
2205 jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &rseq);
2206 if (jperIsError(jper))
2207 {
2210 return jper;
2211 }
2212
2215 {
2220 errmsg("left operand of jsonpath operator %s is not a single numeric value",
2221 jspOperationName(jsp->type)))));
2222 }
2223
2226 {
2231 errmsg("right operand of jsonpath operator %s is not a single numeric value",
2232 jspOperationName(jsp->type)))));
2233 }
2234
2235 if (jspThrowErrors(cxt))
2236 {
2237 res = func(lval->val.numeric, rval->val.numeric, NULL);
2238 }
2239 else
2240 {
2242
2243 res = func(lval->val.numeric, rval->val.numeric, (Node *) &escontext);
2244
2245 if (escontext.error_occurred)
2246 {
2249 return jperError;
2250 }
2251 }
2252
2255
2256 if (!jspGetNext(jsp, &elem) && !found)
2257 return jperOk;
2258
2259 resval.type = jbvNumeric;
2260 resval.val.numeric = res;
2261
2262 return executeNextItem(cxt, jsp, &elem, &resval, found);
2263}
2264
2265/*
2266 * Execute unary arithmetic expression for each numeric item in its operand's
2267 * sequence. Array operand is automatically unwrapped in lax mode.
2268 */
2269static JsonPathExecResult
2271 JsonbValue *jb, PGFunction func, JsonValueList *found)
2272{
2275 JsonPathItem elem;
2278 JsonbValue *val;
2279 bool hasNext;
2280
2282
2283 jspGetArg(jsp, &elem);
2284 jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &seq);
2285
2286 if (jperIsError(jper))
2287 goto exit;
2288
2290
2291 hasNext = jspGetNext(jsp, &elem);
2292
2294 while ((val = JsonValueListNext(&it)))
2295 {
2296 if ((val = getScalar(val, jbvNumeric)))
2297 {
2298 if (!found && !hasNext)
2299 {
2300 jper = jperOk;
2301 goto exit;
2302 }
2303 }
2304 else
2305 {
2306 if (!found && !hasNext)
2307 continue; /* skip non-numerics processing */
2308
2312 errmsg("operand of unary jsonpath operator %s is not a numeric value",
2313 jspOperationName(jsp->type)))));
2314 }
2315
2316 if (func)
2317 val->val.numeric =
2319 NumericGetDatum(val->val.numeric)));
2320
2321 jper2 = executeNextItem(cxt, jsp, &elem, val, found);
2322
2323 if (jperIsError(jper2))
2324 {
2325 jper = jper2;
2326 goto exit;
2327 }
2328
2329 if (jper2 == jperOk)
2330 {
2331 jper = jperOk;
2332 if (!found)
2333 goto exit;
2334 }
2335 }
2336
2337exit:
2339
2340 return jper;
2341}
2342
2343/*
2344 * STARTS_WITH predicate callback.
2345 *
2346 * Check if the 'whole' string starts from 'initial' string.
2347 */
2348static JsonPathBool
2350 void *param)
2351{
2352 if (!(whole = getScalar(whole, jbvString)))
2353 return jpbUnknown; /* error */
2354
2356 return jpbUnknown; /* error */
2357
2358 if (whole->val.string.len >= initial->val.string.len &&
2359 !memcmp(whole->val.string.val,
2360 initial->val.string.val,
2361 initial->val.string.len))
2362 return jpbTrue;
2363
2364 return jpbFalse;
2365}
2366
2367/*
2368 * LIKE_REGEX predicate callback.
2369 *
2370 * Check if the string matches regex pattern.
2371 */
2372static JsonPathBool
2374 void *param)
2375{
2376 JsonLikeRegexContext *cxt = param;
2377
2378 if (!(str = getScalar(str, jbvString)))
2379 return jpbUnknown;
2380
2381 /* Cache regex text and converted flags. */
2382 if (!cxt->regex)
2383 {
2384 cxt->regex =
2385 cstring_to_text_with_len(jsp->content.like_regex.pattern,
2386 jsp->content.like_regex.patternlen);
2387 (void) jspConvertRegexFlags(jsp->content.like_regex.flags,
2388 &(cxt->cflags), NULL);
2389 }
2390
2391 if (RE_compile_and_execute(cxt->regex, str->val.string.val,
2392 str->val.string.len,
2394 return jpbTrue;
2395
2396 return jpbFalse;
2397}
2398
2399/*
2400 * Execute numeric item methods (.abs(), .floor(), .ceil()) using the specified
2401 * user function 'func'.
2402 */
2403static JsonPathExecResult
2405 JsonbValue *jb, bool unwrap, PGFunction func,
2406 JsonValueList *found)
2407{
2409 Datum datum;
2411
2412 if (unwrap && JsonbType(jb) == jbvArray)
2413 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
2414
2415 if (!(jb = getScalar(jb, jbvNumeric)))
2418 errmsg("jsonpath item method .%s() can only be applied to a numeric value",
2419 jspOperationName(jsp->type)))));
2420
2421 datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
2422
2423 if (!jspGetNext(jsp, &next) && !found)
2424 return jperOk;
2425
2426 jbv.type = jbvNumeric;
2427 jbv.val.numeric = DatumGetNumeric(datum);
2428
2429 return executeNextItem(cxt, jsp, &next, &jbv, found);
2430}
2431
2432/*
2433 * Implementation of the .datetime() and related methods.
2434 *
2435 * Converts a string into a date/time value. The actual type is determined at
2436 * run time.
2437 * If an argument is provided, this argument is used as a template string.
2438 * Otherwise, the first fitting ISO format is selected.
2439 *
2440 * .date(), .time(), .time_tz(), .timestamp(), .timestamp_tz() methods don't
2441 * have a format, so ISO format is used. However, except for .date(), they all
2442 * take an optional time precision.
2443 */
2444static JsonPathExecResult
2446 JsonbValue *jb, JsonValueList *found)
2447{
2449 Datum value;
2450 text *datetime;
2451 Oid collid;
2452 Oid typid;
2453 int32 typmod = -1;
2454 int tz = 0;
2455 bool hasNext;
2457 JsonPathItem elem;
2458 int32 time_precision = -1;
2459
2460 if (!(jb = getScalar(jb, jbvString)))
2463 errmsg("jsonpath item method .%s() can only be applied to a string",
2464 jspOperationName(jsp->type)))));
2465
2466 datetime = cstring_to_text_with_len(jb->val.string.val,
2467 jb->val.string.len);
2468
2469 /*
2470 * At some point we might wish to have callers supply the collation to
2471 * use, but right now it's unclear that they'd be able to do better than
2472 * DEFAULT_COLLATION_OID anyway.
2473 */
2475
2476 /*
2477 * .datetime(template) has an argument, the rest of the methods don't have
2478 * an argument. So we handle that separately.
2479 */
2480 if (jsp->type == jpiDatetime && jsp->content.arg)
2481 {
2482 text *template;
2483 char *template_str;
2484 int template_len;
2486
2487 jspGetArg(jsp, &elem);
2488
2489 if (elem.type != jpiString)
2490 elog(ERROR, "invalid jsonpath item type for .datetime() argument");
2491
2493
2495 template_len);
2496
2497 value = parse_datetime(datetime, template, collid, true,
2498 &typid, &typmod, &tz,
2499 jspThrowErrors(cxt) ? NULL : (Node *) &escontext);
2500
2501 if (escontext.error_occurred)
2502 res = jperError;
2503 else
2504 res = jperOk;
2505 }
2506 else
2507 {
2508 /*
2509 * According to SQL/JSON standard enumerate ISO formats for: date,
2510 * timetz, time, timestamptz, timestamp.
2511 *
2512 * We also support ISO 8601 format (with "T") for timestamps, because
2513 * to_json[b]() functions use this format.
2514 */
2515 static const char *fmt_str[] =
2516 {
2517 "yyyy-mm-dd", /* date */
2518 "HH24:MI:SS.USTZ", /* timetz */
2519 "HH24:MI:SSTZ",
2520 "HH24:MI:SS.US", /* time without tz */
2521 "HH24:MI:SS",
2522 "yyyy-mm-dd HH24:MI:SS.USTZ", /* timestamptz */
2523 "yyyy-mm-dd HH24:MI:SSTZ",
2524 "yyyy-mm-dd\"T\"HH24:MI:SS.USTZ",
2525 "yyyy-mm-dd\"T\"HH24:MI:SSTZ",
2526 "yyyy-mm-dd HH24:MI:SS.US", /* timestamp without tz */
2527 "yyyy-mm-dd HH24:MI:SS",
2528 "yyyy-mm-dd\"T\"HH24:MI:SS.US",
2529 "yyyy-mm-dd\"T\"HH24:MI:SS"
2530 };
2531
2532 /* cache for format texts */
2533 static text *fmt_txt[lengthof(fmt_str)] = {0};
2534 int i;
2535
2536 /*
2537 * Check for optional precision for methods other than .datetime() and
2538 * .date()
2539 */
2540 if (jsp->type != jpiDatetime && jsp->type != jpiDate &&
2541 jsp->content.arg)
2542 {
2544
2545 jspGetArg(jsp, &elem);
2546
2547 if (elem.type != jpiNumeric)
2548 elog(ERROR, "invalid jsonpath item type for %s argument",
2549 jspOperationName(jsp->type));
2550
2552 (Node *) &escontext);
2553 if (escontext.error_occurred)
2556 errmsg("time precision of jsonpath item method .%s() is out of range for type integer",
2557 jspOperationName(jsp->type)))));
2558 }
2559
2560 /* loop until datetime format fits */
2561 for (i = 0; i < lengthof(fmt_str); i++)
2562 {
2564
2565 if (!fmt_txt[i])
2566 {
2569
2572 }
2573
2574 value = parse_datetime(datetime, fmt_txt[i], collid, true,
2575 &typid, &typmod, &tz,
2576 (Node *) &escontext);
2577
2578 if (!escontext.error_occurred)
2579 {
2580 res = jperOk;
2581 break;
2582 }
2583 }
2584
2585 if (res == jperNotFound)
2586 {
2587 if (jsp->type == jpiDatetime)
2590 errmsg("%s format is not recognized: \"%s\"",
2591 "datetime", text_to_cstring(datetime)),
2592 errhint("Use a datetime template argument to specify the input data format."))));
2593 else
2596 errmsg("%s format is not recognized: \"%s\"",
2597 jspOperationName(jsp->type), text_to_cstring(datetime)))));
2598
2599 }
2600 }
2601
2602 /*
2603 * parse_datetime() processes the entire input string per the template or
2604 * ISO format and returns the Datum in best fitted datetime type. So, if
2605 * this call is for a specific datatype, then we do the conversion here.
2606 * Throw an error for incompatible types.
2607 */
2608 switch (jsp->type)
2609 {
2610 case jpiDatetime: /* Nothing to do for DATETIME */
2611 break;
2612 case jpiDate:
2613 {
2614 /* Convert result type to date */
2615 switch (typid)
2616 {
2617 case DATEOID: /* Nothing to do for DATE */
2618 break;
2619 case TIMEOID:
2620 case TIMETZOID:
2623 errmsg("%s format is not recognized: \"%s\"",
2624 "date", text_to_cstring(datetime)))));
2625 break;
2626 case TIMESTAMPOID:
2628 value);
2629 break;
2630 case TIMESTAMPTZOID:
2632 "timestamptz", "date");
2634 value);
2635 break;
2636 default:
2637 elog(ERROR, "type with oid %u not supported", typid);
2638 }
2639
2640 typid = DATEOID;
2641 }
2642 break;
2643 case jpiTime:
2644 {
2645 /* Convert result type to time without time zone */
2646 switch (typid)
2647 {
2648 case DATEOID:
2651 errmsg("%s format is not recognized: \"%s\"",
2652 "time", text_to_cstring(datetime)))));
2653 break;
2654 case TIMEOID: /* Nothing to do for TIME */
2655 break;
2656 case TIMETZOID:
2658 "timetz", "time");
2660 value);
2661 break;
2662 case TIMESTAMPOID:
2664 value);
2665 break;
2666 case TIMESTAMPTZOID:
2668 "timestamptz", "time");
2670 value);
2671 break;
2672 default:
2673 elog(ERROR, "type with oid %u not supported", typid);
2674 }
2675
2676 /* Force the user-given time precision, if any */
2677 if (time_precision != -1)
2678 {
2680
2681 /* Get a warning when precision is reduced */
2687
2688 /* Update the typmod value with the user-given precision */
2689 typmod = time_precision;
2690 }
2691
2692 typid = TIMEOID;
2693 }
2694 break;
2695 case jpiTimeTz:
2696 {
2697 /* Convert result type to time with time zone */
2698 switch (typid)
2699 {
2700 case DATEOID:
2701 case TIMESTAMPOID:
2704 errmsg("%s format is not recognized: \"%s\"",
2705 "time_tz", text_to_cstring(datetime)))));
2706 break;
2707 case TIMEOID:
2709 "time", "timetz");
2711 value);
2712 break;
2713 case TIMETZOID: /* Nothing to do for TIMETZ */
2714 break;
2715 case TIMESTAMPTZOID:
2717 value);
2718 break;
2719 default:
2720 elog(ERROR, "type with oid %u not supported", typid);
2721 }
2722
2723 /* Force the user-given time precision, if any */
2724 if (time_precision != -1)
2725 {
2727
2728 /* Get a warning when precision is reduced */
2734
2735 /* Update the typmod value with the user-given precision */
2736 typmod = time_precision;
2737 }
2738
2739 typid = TIMETZOID;
2740 }
2741 break;
2742 case jpiTimestamp:
2743 {
2744 /* Convert result type to timestamp without time zone */
2745 switch (typid)
2746 {
2747 case DATEOID:
2749 value);
2750 break;
2751 case TIMEOID:
2752 case TIMETZOID:
2755 errmsg("%s format is not recognized: \"%s\"",
2756 "timestamp", text_to_cstring(datetime)))));
2757 break;
2758 case TIMESTAMPOID: /* Nothing to do for TIMESTAMP */
2759 break;
2760 case TIMESTAMPTZOID:
2762 "timestamptz", "timestamp");
2764 value);
2765 break;
2766 default:
2767 elog(ERROR, "type with oid %u not supported", typid);
2768 }
2769
2770 /* Force the user-given time precision, if any */
2771 if (time_precision != -1)
2772 {
2775
2776 /* Get a warning when precision is reduced */
2781 (Node *) &escontext);
2782 if (escontext.error_occurred) /* should not happen */
2785 errmsg("time precision of jsonpath item method .%s() is invalid",
2786 jspOperationName(jsp->type)))));
2788
2789 /* Update the typmod value with the user-given precision */
2790 typmod = time_precision;
2791 }
2792
2793 typid = TIMESTAMPOID;
2794 }
2795 break;
2796 case jpiTimestampTz:
2797 {
2798 struct pg_tm tm;
2799 fsec_t fsec;
2800
2801 /* Convert result type to timestamp with time zone */
2802 switch (typid)
2803 {
2804 case DATEOID:
2806 "date", "timestamptz");
2807
2808 /*
2809 * Get the timezone value explicitly since JsonbValue
2810 * keeps that separate.
2811 */
2813 &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
2814 tm.tm_hour = 0;
2815 tm.tm_min = 0;
2816 tm.tm_sec = 0;
2818
2820 value);
2821 break;
2822 case TIMEOID:
2823 case TIMETZOID:
2826 errmsg("%s format is not recognized: \"%s\"",
2827 "timestamp_tz", text_to_cstring(datetime)))));
2828 break;
2829 case TIMESTAMPOID:
2831 "timestamp", "timestamptz");
2832
2833 /*
2834 * Get the timezone value explicitly since JsonbValue
2835 * keeps that separate.
2836 */
2838 &fsec, NULL, NULL) == 0)
2841
2843 value);
2844 break;
2845 case TIMESTAMPTZOID: /* Nothing to do for TIMESTAMPTZ */
2846 break;
2847 default:
2848 elog(ERROR, "type with oid %u not supported", typid);
2849 }
2850
2851 /* Force the user-given time precision, if any */
2852 if (time_precision != -1)
2853 {
2856
2857 /* Get a warning when precision is reduced */
2862 (Node *) &escontext);
2863 if (escontext.error_occurred) /* should not happen */
2866 errmsg("time precision of jsonpath item method .%s() is invalid",
2867 jspOperationName(jsp->type)))));
2869
2870 /* Update the typmod value with the user-given precision */
2871 typmod = time_precision;
2872 }
2873
2874 typid = TIMESTAMPTZOID;
2875 }
2876 break;
2877 default:
2878 elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
2879 }
2880
2881 pfree(datetime);
2882
2883 if (jperIsError(res))
2884 return res;
2885
2886 hasNext = jspGetNext(jsp, &elem);
2887
2888 if (!hasNext && !found)
2889 return res;
2890
2891 jbv.type = jbvDatetime;
2892 jbv.val.datetime.value = value;
2893 jbv.val.datetime.typid = typid;
2894 jbv.val.datetime.typmod = typmod;
2895 jbv.val.datetime.tz = tz;
2896
2897 return executeNextItem(cxt, jsp, &elem, &jbv, found);
2898}
2899
2900/*
2901 * Implementation of .upper(), .lower() et al. string methods,
2902 * that forward their actual implementation to internal functions.
2903 */
2904static JsonPathExecResult
2906 JsonbValue *jb, JsonValueList *found)
2907{
2909 bool hasNext;
2911 JsonPathItem elem;
2912 Datum str; /* Datum representation for the current string
2913 * value. The first argument to internal
2914 * functions */
2915 char *resStr = NULL;
2916
2917 Assert(jsp->type == jpiStrReplace ||
2918 jsp->type == jpiStrLower ||
2919 jsp->type == jpiStrUpper ||
2920 jsp->type == jpiStrLtrim ||
2921 jsp->type == jpiStrRtrim ||
2922 jsp->type == jpiStrBtrim ||
2923 jsp->type == jpiStrInitcap ||
2924 jsp->type == jpiStrSplitPart);
2925
2926 if (!(jb = getScalar(jb, jbvString)))
2929 errmsg("jsonpath item method .%s() can only be applied to a string",
2930 jspOperationName(jsp->type)))));
2931
2932 str = PointerGetDatum(cstring_to_text_with_len(jb->val.string.val, jb->val.string.len));
2933
2934 /* Dispatch to the appropriate internal string function */
2935 switch (jsp->type)
2936 {
2937 case jpiStrReplace:
2938 {
2939 char *from_str,
2940 *to_str;
2941
2942 jspGetLeftArg(jsp, &elem);
2943 if (elem.type != jpiString)
2944 elog(ERROR, "invalid jsonpath item type for .replace() from");
2945
2946 from_str = jspGetString(&elem, NULL);
2947
2948 jspGetRightArg(jsp, &elem);
2949 if (elem.type != jpiString)
2950 elog(ERROR, "invalid jsonpath item type for .replace() to");
2951
2952 to_str = jspGetString(&elem, NULL);
2953
2956 str,
2959 break;
2960 }
2961 case jpiStrLower:
2963 break;
2964 case jpiStrUpper:
2966 break;
2967 case jpiStrLtrim:
2968 case jpiStrRtrim:
2969 case jpiStrBtrim:
2970 {
2973
2974 switch (jsp->type)
2975 {
2976 case jpiStrLtrim:
2977 func1 = ltrim1;
2978 func2 = ltrim;
2979 break;
2980 case jpiStrRtrim:
2981 func1 = rtrim1;
2982 func2 = rtrim;
2983 break;
2984 case jpiStrBtrim:
2985 func1 = btrim1;
2986 func2 = btrim;
2987 break;
2988 default:
2989 break;
2990 }
2991
2992 if (jsp->content.arg)
2993 {
2994 char *characters_str;
2995
2996 jspGetArg(jsp, &elem);
2997 if (elem.type != jpiString)
2998 elog(ERROR, "invalid jsonpath item type for .%s() argument",
2999 jspOperationName(jsp->type));
3000
3005 }
3006 else
3007 {
3010 }
3011 break;
3012 }
3013
3014 case jpiStrInitcap:
3016 break;
3017 case jpiStrSplitPart:
3018 {
3019 char *from_str;
3020 int32 n;
3022
3023 jspGetLeftArg(jsp, &elem);
3024 if (elem.type != jpiString)
3025 elog(ERROR, "invalid jsonpath item type for .split_part()");
3026
3027 from_str = jspGetString(&elem, NULL);
3028
3029 jspGetRightArg(jsp, &elem);
3030 if (elem.type != jpiNumeric)
3031 elog(ERROR, "invalid jsonpath item type for .split_part()");
3032
3034 (Node *) &escontext);
3035 if (escontext.error_occurred)
3038 errmsg("field position of jsonpath item method .%s() is out of range for type integer",
3039 jspOperationName(jsp->type))));
3040
3041 if (n == 0)
3044 errmsg("field position of jsonpath item method .%s() must not be zero",
3045 jspOperationName(jsp->type))));
3046
3049 str,
3051 Int32GetDatum(n)));
3052 break;
3053 }
3054 default:
3055 elog(ERROR, "unsupported jsonpath item type: %d", jsp->type);
3056 }
3057
3058 if (resStr)
3059 res = jperOk;
3060
3061 hasNext = jspGetNext(jsp, &elem);
3062
3063 if (!hasNext && !found)
3064 return res;
3065
3066 jbv.type = jbvString;
3067 jbv.val.string.val = resStr;
3068 jbv.val.string.len = strlen(resStr);
3069
3070 return executeNextItem(cxt, jsp, &elem, &jbv, found);
3071}
3072
3073/*
3074 * Implementation of .keyvalue() method.
3075 *
3076 * .keyvalue() method returns a sequence of object's key-value pairs in the
3077 * following format: '{ "key": key, "value": value, "id": id }'.
3078 *
3079 * "id" field is an object identifier which is constructed from the two parts:
3080 * base object id and its binary offset in base object's jsonb:
3081 * id = 10000000000 * base_object_id + obj_offset_in_base_object
3082 *
3083 * 10000000000 (10^10) -- is a first round decimal number greater than 2^32
3084 * (maximal offset in jsonb). Decimal multiplier is used here to improve the
3085 * readability of identifiers.
3086 *
3087 * Base object is usually a root object of the path: context item '$' or path
3088 * variable '$var', literals can't produce objects for now. But if the path
3089 * contains generated objects (.keyvalue() itself, for example), then they
3090 * become base object for the subsequent .keyvalue().
3091 *
3092 * Id of '$' is 0. Id of '$var' is its ordinal (positive) number in the list
3093 * of variables (see getJsonPathVariable()). Ids for generated objects
3094 * are assigned using global counter JsonPathExecContext.lastGeneratedObjectId.
3095 */
3096static JsonPathExecResult
3098 JsonbValue *jb, JsonValueList *found)
3099{
3102 JsonbContainer *jbc;
3103 JsonbValue key;
3111 int64 id;
3112 bool hasNext;
3113
3114 if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
3117 errmsg("jsonpath item method .%s() can only be applied to an object",
3118 jspOperationName(jsp->type)))));
3119
3120 jbc = jb->val.binary.data;
3121
3122 if (!JsonContainerSize(jbc))
3123 return jperNotFound; /* no key-value pairs */
3124
3126
3127 keystr.type = jbvString;
3128 keystr.val.string.val = "key";
3129 keystr.val.string.len = 3;
3130
3131 valstr.type = jbvString;
3132 valstr.val.string.val = "value";
3133 valstr.val.string.len = 5;
3134
3135 idstr.type = jbvString;
3136 idstr.val.string.val = "id";
3137 idstr.val.string.len = 2;
3138
3139 /* construct object id from its base object and offset inside that */
3140 id = jb->type != jbvBinary ? 0 :
3141 (int64) ((char *) jbc - (char *) cxt->baseObject.jbc);
3142 id += (int64) cxt->baseObject.id * INT64CONST(10000000000);
3143
3144 idval.type = jbvNumeric;
3145 idval.val.numeric = int64_to_numeric(id);
3146
3147 it = JsonbIteratorInit(jbc);
3148
3149 while ((tok = JsonbIteratorNext(&it, &key, true)) != WJB_DONE)
3150 {
3151 JsonBaseObjectInfo baseObject;
3152 JsonbValue obj;
3154 Jsonb *jsonb;
3155
3156 if (tok != WJB_KEY)
3157 continue;
3158
3159 res = jperOk;
3160
3161 if (!hasNext && !found)
3162 break;
3163
3164 tok = JsonbIteratorNext(&it, &val, true);
3165 Assert(tok == WJB_VALUE);
3166
3167 memset(&ps, 0, sizeof(ps));
3168
3170
3172 pushJsonbValue(&ps, WJB_VALUE, &key);
3173
3176
3179
3181
3182 jsonb = JsonbValueToJsonb(ps.result);
3183
3184 JsonbInitBinary(&obj, jsonb);
3185
3186 baseObject = setBaseObject(cxt, &obj, cxt->lastGeneratedObjectId++);
3187
3188 res = executeNextItem(cxt, jsp, &next, &obj, found);
3189
3190 cxt->baseObject = baseObject;
3191
3192 if (jperIsError(res))
3193 return res;
3194
3195 if (res == jperOk && !found)
3196 break;
3197 }
3198
3199 return res;
3200}
3201
3202/*
3203 * Convert boolean execution status 'res' to a boolean JSON item and execute
3204 * next jsonpath.
3205 */
3206static JsonPathExecResult
3208 JsonValueList *found, JsonPathBool res)
3209{
3212
3213 if (!jspGetNext(jsp, &next) && !found)
3214 return jperOk; /* found singleton boolean value */
3215
3216 if (res == jpbUnknown)
3217 {
3218 jbv.type = jbvNull;
3219 }
3220 else
3221 {
3222 jbv.type = jbvBool;
3223 jbv.val.boolean = res == jpbTrue;
3224 }
3225
3226 return executeNextItem(cxt, jsp, &next, &jbv, found);
3227}
3228
3229/*
3230 * Convert jsonpath's scalar or variable node to actual jsonb value.
3231 *
3232 * If node is a variable then its id returned, otherwise 0 returned.
3233 */
3234static void
3237{
3238 switch (item->type)
3239 {
3240 case jpiNull:
3241 value->type = jbvNull;
3242 break;
3243 case jpiBool:
3244 value->type = jbvBool;
3245 value->val.boolean = jspGetBool(item);
3246 break;
3247 case jpiNumeric:
3248 value->type = jbvNumeric;
3249 value->val.numeric = jspGetNumeric(item);
3250 break;
3251 case jpiString:
3252 value->type = jbvString;
3253 value->val.string.val = jspGetString(item,
3254 &value->val.string.len);
3255 break;
3256 case jpiVariable:
3257 getJsonPathVariable(cxt, item, value);
3258 return;
3259 default:
3260 elog(ERROR, "unexpected jsonpath item type");
3261 }
3262}
3263
3264/*
3265 * Returns the computed value of a JSON path variable with given name.
3266 */
3267static JsonbValue *
3268GetJsonPathVar(void *cxt, char *varName, int varNameLen,
3269 JsonbValue *baseObject, int *baseObjectId)
3270{
3271 JsonPathVariable *var = NULL;
3272 List *vars = cxt;
3273 ListCell *lc;
3275 int id = 1;
3276
3277 foreach(lc, vars)
3278 {
3279 JsonPathVariable *curvar = lfirst(lc);
3280
3281 if (curvar->namelen == varNameLen &&
3282 strncmp(curvar->name, varName, varNameLen) == 0)
3283 {
3284 var = curvar;
3285 break;
3286 }
3287
3288 id++;
3289 }
3290
3291 if (var == NULL)
3292 {
3293 *baseObjectId = -1;
3294 return NULL;
3295 }
3296
3298 if (var->isnull)
3299 {
3300 *baseObjectId = 0;
3301 result->type = jbvNull;
3302 }
3303 else
3304 JsonItemFromDatum(var->value, var->typid, var->typmod, result);
3305
3306 *baseObject = *result;
3307 *baseObjectId = id;
3308
3309 return result;
3310}
3311
3312static int
3314{
3315 List *vars = (List *) cxt;
3316
3317 return list_length(vars);
3318}
3319
3320
3321/*
3322 * Initialize JsonbValue to pass to jsonpath executor from given
3323 * datum value of the specified type.
3324 */
3325static void
3327{
3328 switch (typid)
3329 {
3330 case BOOLOID:
3331 res->type = jbvBool;
3332 res->val.boolean = DatumGetBool(val);
3333 break;
3334 case NUMERICOID:
3336 break;
3337 case INT2OID:
3339 break;
3340 case INT4OID:
3342 break;
3343 case INT8OID:
3345 break;
3346 case FLOAT4OID:
3348 break;
3349 case FLOAT8OID:
3351 break;
3352 case TEXTOID:
3353 case VARCHAROID:
3354 res->type = jbvString;
3355 res->val.string.val = VARDATA_ANY(DatumGetPointer(val));
3356 res->val.string.len = VARSIZE_ANY_EXHDR(DatumGetPointer(val));
3357 break;
3358 case DATEOID:
3359 case TIMEOID:
3360 case TIMETZOID:
3361 case TIMESTAMPOID:
3362 case TIMESTAMPTZOID:
3363 res->type = jbvDatetime;
3364 res->val.datetime.value = val;
3365 res->val.datetime.typid = typid;
3366 res->val.datetime.typmod = typmod;
3367 res->val.datetime.tz = 0;
3368 break;
3369 case JSONBOID:
3370 {
3371 JsonbValue *jbv = res;
3373
3374 if (JsonContainerIsScalar(&jb->root))
3375 {
3377
3378 result = JsonbExtractScalar(&jb->root, jbv);
3379 Assert(result);
3380 }
3381 else
3383 break;
3384 }
3385 case JSONOID:
3386 {
3388 char *str = text_to_cstring(txt);
3389 Jsonb *jb;
3390
3393 pfree(str);
3394
3396 break;
3397 }
3398 default:
3399 ereport(ERROR,
3401 errmsg("could not convert value of type %s to jsonpath",
3402 format_type_be(typid)));
3403 }
3404}
3405
3406/* Initialize numeric value from the given datum */
3407static void
3409{
3410 jbv->type = jbvNumeric;
3411 jbv->val.numeric = DatumGetNumeric(num);
3412}
3413
3414/*
3415 * Get the value of variable passed to jsonpath executor
3416 */
3417static void
3420{
3421 char *varName;
3422 int varNameLength;
3423 JsonbValue baseObject;
3424 int baseObjectId;
3425 JsonbValue *v;
3426
3428 varName = jspGetString(variable, &varNameLength);
3429
3430 if (cxt->vars == NULL ||
3431 (v = cxt->getVar(cxt->vars, varName, varNameLength,
3432 &baseObject, &baseObjectId)) == NULL)
3433 ereport(ERROR,
3435 errmsg("could not find jsonpath variable \"%s\"",
3436 pnstrdup(varName, varNameLength))));
3437
3438 if (baseObjectId > 0)
3439 {
3440 *value = *v;
3441 setBaseObject(cxt, &baseObject, baseObjectId);
3442 }
3443}
3444
3445/*
3446 * Definition of JsonPathGetVarCallback for when JsonPathExecContext.vars
3447 * is specified as a jsonb value.
3448 */
3449static JsonbValue *
3451 JsonbValue *baseObject, int *baseObjectId)
3452{
3453 Jsonb *vars = varsJsonb;
3454 JsonbValue tmp;
3456
3457 tmp.type = jbvString;
3458 tmp.val.string.val = varName;
3459 tmp.val.string.len = varNameLength;
3460
3462
3463 if (result == NULL)
3464 {
3465 *baseObjectId = -1;
3466 return NULL;
3467 }
3468
3469 *baseObjectId = 1;
3470 JsonbInitBinary(baseObject, vars);
3471
3472 return result;
3473}
3474
3475/*
3476 * Definition of JsonPathCountVarsCallback for when JsonPathExecContext.vars
3477 * is specified as a jsonb value.
3478 */
3479static int
3481{
3482 Jsonb *vars = varsJsonb;
3483
3484 if (vars && !JsonContainerIsObject(&vars->root))
3485 {
3486 ereport(ERROR,
3488 errmsg("\"vars\" argument is not an object"),
3489 errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object."));
3490 }
3491
3492 /* count of base objects */
3493 return vars != NULL ? 1 : 0;
3494}
3495
3496/**************** Support functions for JsonPath execution *****************/
3497
3498/*
3499 * Returns the size of an array item, or -1 if item is not an array.
3500 */
3501static int
3503{
3504 Assert(jb->type != jbvArray);
3505
3506 if (jb->type == jbvBinary)
3507 {
3508 JsonbContainer *jbc = jb->val.binary.data;
3509
3511 return JsonContainerSize(jbc);
3512 }
3513
3514 return -1;
3515}
3516
3517/* Comparison predicate callback. */
3518static JsonPathBool
3520{
3522
3523 return compareItems(cmp->type, lv, rv, cxt->useTz);
3524}
3525
3526/*
3527 * Perform per-byte comparison of two strings.
3528 */
3529static int
3530binaryCompareStrings(const char *s1, int len1,
3531 const char *s2, int len2)
3532{
3533 int cmp;
3534
3535 cmp = memcmp(s1, s2, Min(len1, len2));
3536
3537 if (cmp != 0)
3538 return cmp;
3539
3540 if (len1 == len2)
3541 return 0;
3542
3543 return len1 < len2 ? -1 : 1;
3544}
3545
3546/*
3547 * Compare two strings in the current server encoding using Unicode codepoint
3548 * collation.
3549 */
3550static int
3552 const char *mbstr2, int mblen2)
3553{
3556 {
3557 /*
3558 * It's known property of UTF-8 strings that their per-byte comparison
3559 * result matches codepoints comparison result. ASCII can be
3560 * considered as special case of UTF-8.
3561 */
3563 }
3564 else
3565 {
3566 char *utf8str1,
3567 *utf8str2;
3568 int cmp,
3569 utf8len1,
3570 utf8len2;
3571
3572 /*
3573 * We have to convert other encodings to UTF-8 first, then compare.
3574 * Input strings may be not null-terminated and pg_server_to_any() may
3575 * return them "as is". So, use strlen() only if there is real
3576 * conversion.
3577 */
3582
3584
3585 /*
3586 * If pg_server_to_any() did no real conversion, then we actually
3587 * compared original strings. So, we already done.
3588 */
3589 if (mbstr1 == utf8str1 && mbstr2 == utf8str2)
3590 return cmp;
3591
3592 /* Free memory if needed */
3593 if (mbstr1 != utf8str1)
3594 pfree(utf8str1);
3595 if (mbstr2 != utf8str2)
3596 pfree(utf8str2);
3597
3598 /*
3599 * When all Unicode codepoints are equal, return result of binary
3600 * comparison. In some edge cases, same characters may have different
3601 * representations in encoding. Then our behavior could diverge from
3602 * standard. However, that allow us to do simple binary comparison
3603 * for "==" operator, which is performance critical in typical cases.
3604 * In future to implement strict standard conformance, we can do
3605 * normalization of input JSON strings.
3606 */
3607 if (cmp == 0)
3609 else
3610 return cmp;
3611 }
3612}
3613
3614/*
3615 * Compare two SQL/JSON items using comparison operation 'op'.
3616 */
3617static JsonPathBool
3619{
3620 int cmp;
3621 bool res;
3622
3623 if (jb1->type != jb2->type)
3624 {
3625 if (jb1->type == jbvNull || jb2->type == jbvNull)
3626
3627 /*
3628 * Equality and order comparison of nulls to non-nulls returns
3629 * always false, but inequality comparison returns true.
3630 */
3631 return op == jpiNotEqual ? jpbTrue : jpbFalse;
3632
3633 /* Non-null items of different types are not comparable. */
3634 return jpbUnknown;
3635 }
3636
3637 switch (jb1->type)
3638 {
3639 case jbvNull:
3640 cmp = 0;
3641 break;
3642 case jbvBool:
3643 cmp = jb1->val.boolean == jb2->val.boolean ? 0 :
3644 jb1->val.boolean ? 1 : -1;
3645 break;
3646 case jbvNumeric:
3647 cmp = compareNumeric(jb1->val.numeric, jb2->val.numeric);
3648 break;
3649 case jbvString:
3650 if (op == jpiEqual)
3651 return jb1->val.string.len != jb2->val.string.len ||
3652 memcmp(jb1->val.string.val,
3653 jb2->val.string.val,
3654 jb1->val.string.len) ? jpbFalse : jpbTrue;
3655
3656 cmp = compareStrings(jb1->val.string.val, jb1->val.string.len,
3657 jb2->val.string.val, jb2->val.string.len);
3658 break;
3659 case jbvDatetime:
3660 {
3661 bool cast_error;
3662
3663 cmp = compareDatetime(jb1->val.datetime.value,
3664 jb1->val.datetime.typid,
3665 jb2->val.datetime.value,
3666 jb2->val.datetime.typid,
3667 useTz,
3668 &cast_error);
3669
3670 if (cast_error)
3671 return jpbUnknown;
3672 }
3673 break;
3674
3675 case jbvBinary:
3676 case jbvArray:
3677 case jbvObject:
3678 return jpbUnknown; /* non-scalars are not comparable */
3679
3680 default:
3681 elog(ERROR, "invalid jsonb value type %d", jb1->type);
3682 }
3683
3684 switch (op)
3685 {
3686 case jpiEqual:
3687 res = (cmp == 0);
3688 break;
3689 case jpiNotEqual:
3690 res = (cmp != 0);
3691 break;
3692 case jpiLess:
3693 res = (cmp < 0);
3694 break;
3695 case jpiGreater:
3696 res = (cmp > 0);
3697 break;
3698 case jpiLessOrEqual:
3699 res = (cmp <= 0);
3700 break;
3701 case jpiGreaterOrEqual:
3702 res = (cmp >= 0);
3703 break;
3704 default:
3705 elog(ERROR, "unrecognized jsonpath operation: %d", op);
3706 return jpbUnknown;
3707 }
3708
3709 return res ? jpbTrue : jpbFalse;
3710}
3711
3712/* Compare two numerics */
3713static int
3720
3721static JsonbValue *
3723{
3725
3726 *dst = *src;
3727
3728 return dst;
3729}
3730
3731/*
3732 * Execute array subscript expression and convert resulting numeric item to
3733 * the integer type with truncation.
3734 */
3735static JsonPathExecResult
3737 int32 *index)
3738{
3739 JsonbValue *jbv;
3740 JsonValueList found;
3744
3745 JsonValueListInit(&found);
3746
3747 res = executeItem(cxt, jsp, jb, &found);
3748
3749 if (jperIsError(res))
3750 {
3751 JsonValueListClear(&found);
3752 return res;
3753 }
3754
3755 if (!JsonValueListIsSingleton(&found) ||
3757 {
3758 JsonValueListClear(&found);
3761 errmsg("jsonpath array subscript is not a single numeric value"))));
3762 }
3763
3765 NumericGetDatum(jbv->val.numeric),
3766 Int32GetDatum(0));
3767
3769 (Node *) &escontext);
3770
3771 JsonValueListClear(&found);
3772
3773 if (escontext.error_occurred)
3776 errmsg("jsonpath array subscript is out of integer range"))));
3777
3778 return jperOk;
3779}
3780
3781/* Save base object and its id needed for the execution of .keyvalue(). */
3782static JsonBaseObjectInfo
3784{
3785 JsonBaseObjectInfo baseObject = cxt->baseObject;
3786
3787 cxt->baseObject.jbc = jbv->type != jbvBinary ? NULL :
3788 (JsonbContainer *) jbv->val.binary.data;
3789 cxt->baseObject.id = id;
3790
3791 return baseObject;
3792}
3793
3794/*
3795 * JsonValueList support functions
3796 */
3797
3798static void
3800{
3801 jvl->nitems = 0;
3802 jvl->maxitems = BASE_JVL_ITEMS;
3803 jvl->next = NULL;
3804 jvl->last = jvl;
3805}
3806
3807static void
3809{
3811
3812 /* Release any extra chunks */
3813 for (JsonValueList *chunk = jvl->next; chunk != NULL; chunk = nxt)
3814 {
3815 nxt = chunk->next;
3816 pfree(chunk);
3817 }
3818 /* ... and reset to empty */
3819 jvl->nitems = 0;
3820 Assert(jvl->maxitems == BASE_JVL_ITEMS);
3821 jvl->next = NULL;
3822 jvl->last = jvl;
3823}
3824
3825static void
3827{
3828 JsonValueList *last = jvl->last;
3829
3830 if (last->nitems < last->maxitems)
3831 {
3832 /* there's still room in the last existing chunk */
3833 last->items[last->nitems] = *jbv;
3834 last->nitems++;
3835 }
3836 else
3837 {
3838 /* need a new last chunk */
3840 int nxtsize;
3841
3842 nxtsize = last->maxitems * 2; /* double the size with each chunk */
3843 nxtsize = Max(nxtsize, MIN_EXTRA_JVL_ITEMS); /* but at least this */
3845 nxtsize * sizeof(JsonbValue));
3846 nxt->nitems = 1;
3847 nxt->maxitems = nxtsize;
3848 nxt->next = NULL;
3849 nxt->items[0] = *jbv;
3850 last->next = nxt;
3851 jvl->last = nxt;
3852 }
3853}
3854
3855static bool
3857{
3858 /* We need not examine extra chunks for this */
3859 return (jvl->nitems == 0);
3860}
3861
3862static bool
3864{
3865#if BASE_JVL_ITEMS > 1
3866 /* We need not examine extra chunks in this case */
3867 return (jvl->nitems == 1);
3868#else
3869 return (jvl->nitems == 1 && jvl->next == NULL);
3870#endif
3871}
3872
3873static bool
3875{
3876#if BASE_JVL_ITEMS > 1
3877 /* We need not examine extra chunks in this case */
3878 return (jvl->nitems > 1);
3879#else
3880 return (jvl->nitems == 1 && jvl->next != NULL);
3881#endif
3882}
3883
3884static JsonbValue *
3886{
3887 Assert(jvl->nitems > 0);
3888 return &jvl->items[0];
3889}
3890
3891/*
3892 * JsonValueListIterator functions
3893 */
3894
3895static void
3897{
3898 it->chunk = jvl;
3899 it->nextitem = 0;
3900}
3901
3902/*
3903 * Get the next item from the sequence advancing iterator.
3904 * Returns NULL if no more items.
3905 */
3906static JsonbValue *
3908{
3909 if (it->chunk == NULL)
3910 return NULL;
3911 if (it->nextitem >= it->chunk->nitems)
3912 {
3913 it->chunk = it->chunk->next;
3914 if (it->chunk == NULL)
3915 return NULL;
3916 it->nextitem = 0;
3917 Assert(it->chunk->nitems > 0);
3918 }
3919 return &it->chunk->items[it->nextitem++];
3920}
3921
3922/*
3923 * Initialize a binary JsonbValue with the given jsonb container.
3924 */
3925static JsonbValue *
3927{
3928 jbv->type = jbvBinary;
3929 jbv->val.binary.data = &jb->root;
3930 jbv->val.binary.len = VARSIZE_ANY_EXHDR(jb);
3931
3932 return jbv;
3933}
3934
3935/*
3936 * Returns jbv* type of JsonbValue. Note, it never returns jbvBinary as is.
3937 */
3938static int
3940{
3941 int type = jb->type;
3942
3943 if (jb->type == jbvBinary)
3944 {
3945 JsonbContainer *jbc = jb->val.binary.data;
3946
3947 /* Scalars should be always extracted during jsonpath execution. */
3949
3950 if (JsonContainerIsObject(jbc))
3951 type = jbvObject;
3952 else if (JsonContainerIsArray(jbc))
3953 type = jbvArray;
3954 else
3955 elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
3956 }
3957
3958 return type;
3959}
3960
3961/* Get scalar of given type or NULL on type mismatch */
3962static JsonbValue *
3964{
3965 /* Scalars should be always extracted during jsonpath execution. */
3966 Assert(scalar->type != jbvBinary ||
3967 !JsonContainerIsScalar(scalar->val.binary.data));
3968
3969 return scalar->type == type ? scalar : NULL;
3970}
3971
3972/* Construct a JSON array from the item list */
3973static JsonbValue *
3975{
3976 JsonbInState ps = {0};
3978 JsonbValue *jbv;
3979
3981
3983 while ((jbv = JsonValueListNext(&it)))
3985
3987
3988 return ps.result;
3989}
3990
3991/* Check if the timezone required for casting from type1 to type2 is used */
3992static void
3993checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
3994{
3995 if (!useTz)
3996 ereport(ERROR,
3998 errmsg("cannot convert value from %s to %s without time zone usage",
3999 type1, type2),
4000 errhint("Use *_tz() function for time zone support.")));
4001}
4002
4003/* Convert time datum to timetz datum */
4004static Datum
4005castTimeToTimeTz(Datum time, bool useTz)
4006{
4007 checkTimezoneIsUsedForCast(useTz, "time", "timetz");
4008
4009 return DirectFunctionCall1(time_timetz, time);
4010}
4011
4012/*
4013 * Compare date to timestamp.
4014 * Note that this doesn't involve any timezone considerations.
4015 */
4016static int
4021
4022/*
4023 * Compare date to timestamptz.
4024 */
4025static int
4027{
4028 checkTimezoneIsUsedForCast(useTz, "date", "timestamptz");
4029
4031}
4032
4033/*
4034 * Compare timestamp to timestamptz.
4035 */
4036static int
4038{
4039 checkTimezoneIsUsedForCast(useTz, "timestamp", "timestamptz");
4040
4042}
4043
4044/*
4045 * Cross-type comparison of two datetime SQL/JSON items. If items are
4046 * uncomparable *cast_error flag is set, otherwise *cast_error is unset.
4047 * If the cast requires timezone and it is not used, then explicit error is thrown.
4048 */
4049static int
4051 bool useTz, bool *cast_error)
4052{
4054
4055 *cast_error = false;
4056
4057 switch (typid1)
4058 {
4059 case DATEOID:
4060 switch (typid2)
4061 {
4062 case DATEOID:
4063 cmpfunc = date_cmp;
4064
4065 break;
4066
4067 case TIMESTAMPOID:
4070 useTz);
4071
4072 case TIMESTAMPTZOID:
4075 useTz);
4076
4077 case TIMEOID:
4078 case TIMETZOID:
4079 *cast_error = true; /* uncomparable types */
4080 return 0;
4081
4082 default:
4083 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4084 typid2);
4085 }
4086 break;
4087
4088 case TIMEOID:
4089 switch (typid2)
4090 {
4091 case TIMEOID:
4092 cmpfunc = time_cmp;
4093
4094 break;
4095
4096 case TIMETZOID:
4097 val1 = castTimeToTimeTz(val1, useTz);
4099
4100 break;
4101
4102 case DATEOID:
4103 case TIMESTAMPOID:
4104 case TIMESTAMPTZOID:
4105 *cast_error = true; /* uncomparable types */
4106 return 0;
4107
4108 default:
4109 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4110 typid2);
4111 }
4112 break;
4113
4114 case TIMETZOID:
4115 switch (typid2)
4116 {
4117 case TIMEOID:
4118 val2 = castTimeToTimeTz(val2, useTz);
4120
4121 break;
4122
4123 case TIMETZOID:
4125
4126 break;
4127
4128 case DATEOID:
4129 case TIMESTAMPOID:
4130 case TIMESTAMPTZOID:
4131 *cast_error = true; /* uncomparable types */
4132 return 0;
4133
4134 default:
4135 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4136 typid2);
4137 }
4138 break;
4139
4140 case TIMESTAMPOID:
4141 switch (typid2)
4142 {
4143 case DATEOID:
4146 useTz);
4147
4148 case TIMESTAMPOID:
4150
4151 break;
4152
4153 case TIMESTAMPTZOID:
4156 useTz);
4157
4158 case TIMEOID:
4159 case TIMETZOID:
4160 *cast_error = true; /* uncomparable types */
4161 return 0;
4162
4163 default:
4164 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4165 typid2);
4166 }
4167 break;
4168
4169 case TIMESTAMPTZOID:
4170 switch (typid2)
4171 {
4172 case DATEOID:
4175 useTz);
4176
4177 case TIMESTAMPOID:
4180 useTz);
4181
4182 case TIMESTAMPTZOID:
4184
4185 break;
4186
4187 case TIMEOID:
4188 case TIMETZOID:
4189 *cast_error = true; /* uncomparable types */
4190 return 0;
4191
4192 default:
4193 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4194 typid2);
4195 }
4196 break;
4197
4198 default:
4199 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u", typid1);
4200 }
4201
4202 if (*cast_error)
4203 return 0; /* cast error */
4204
4206}
4207
4208/*
4209 * Executor-callable JSON_EXISTS implementation
4210 *
4211 * Returns NULL instead of throwing errors if 'error' is not NULL, setting
4212 * *error to true.
4213 */
4214bool
4216{
4218
4219 res = executeJsonPath(jp, vars,
4221 DatumGetJsonbP(jb), !error, NULL, true);
4222
4223 Assert(error || !jperIsError(res));
4224
4225 if (error && jperIsError(res))
4226 *error = true;
4227
4228 return res == jperOk;
4229}
4230
4231/*
4232 * Executor-callable JSON_QUERY implementation
4233 *
4234 * Returns NULL instead of throwing errors if 'error' is not NULL, setting
4235 * *error to true. *empty is set to true if no match is found.
4236 */
4237Datum
4239 bool *error, List *vars,
4240 const char *column_name)
4241{
4242 bool wrap;
4243 JsonValueList found;
4245
4246 JsonValueListInit(&found);
4247
4248 res = executeJsonPath(jp, vars,
4250 DatumGetJsonbP(jb), !error, &found, true);
4251 Assert(error || !jperIsError(res));
4252 if (error && jperIsError(res))
4253 {
4254 *error = true;
4255 *empty = false;
4256 return (Datum) 0;
4257 }
4258
4259 /*
4260 * Determine whether to wrap the result in a JSON array or not.
4261 *
4262 * If the returned JsonValueList is empty, no wrapping is necessary.
4263 *
4264 * If the wrapper mode is JSW_NONE or JSW_UNSPEC, wrapping is explicitly
4265 * disabled. This enforces a WITHOUT WRAPPER clause, which is also the
4266 * default when no WRAPPER clause is specified.
4267 *
4268 * If the mode is JSW_UNCONDITIONAL, wrapping is enforced regardless of
4269 * the number of SQL/JSON items, enforcing a WITH WRAPPER or WITH
4270 * UNCONDITIONAL WRAPPER clause.
4271 *
4272 * For JSW_CONDITIONAL, wrapping occurs only if there is more than one
4273 * SQL/JSON item in the list, enforcing a WITH CONDITIONAL WRAPPER clause.
4274 */
4275 if (JsonValueListIsEmpty(&found))
4276 wrap = false;
4277 else if (wrapper == JSW_NONE || wrapper == JSW_UNSPEC)
4278 wrap = false;
4279 else if (wrapper == JSW_UNCONDITIONAL)
4280 wrap = true;
4281 else if (wrapper == JSW_CONDITIONAL)
4283 else
4284 {
4285 elog(ERROR, "unrecognized json wrapper %d", (int) wrapper);
4286 wrap = false;
4287 }
4288
4289 if (wrap)
4291
4292 /* No wrapping means at most one item is expected. */
4294 {
4295 if (error)
4296 {
4297 *error = true;
4298 return (Datum) 0;
4299 }
4300
4301 if (column_name)
4302 ereport(ERROR,
4304 errmsg("JSON path expression for column \"%s\" must return single item when no wrapper is requested",
4305 column_name),
4306 errhint("Use the WITH WRAPPER clause to wrap SQL/JSON items into an array.")));
4307 else
4308 ereport(ERROR,
4310 errmsg("JSON path expression in JSON_QUERY must return single item when no wrapper is requested"),
4311 errhint("Use the WITH WRAPPER clause to wrap SQL/JSON items into an array.")));
4312 }
4313
4314 if (!JsonValueListIsEmpty(&found))
4316
4317 *empty = true;
4318 return PointerGetDatum(NULL);
4319}
4320
4321/*
4322 * Executor-callable JSON_VALUE implementation
4323 *
4324 * Returns NULL instead of throwing errors if 'error' is not NULL, setting
4325 * *error to true. *empty is set to true if no match is found.
4326 */
4327JsonbValue *
4328JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars,
4329 const char *column_name)
4330{
4331 JsonbValue *res;
4332 JsonValueList found;
4334
4335 JsonValueListInit(&found);
4336
4339 !error, &found, true);
4340
4342
4343 if (error && jperIsError(jper))
4344 {
4345 *error = true;
4346 *empty = false;
4347 return NULL;
4348 }
4349
4350 *empty = JsonValueListIsEmpty(&found);
4351
4352 if (*empty)
4353 return NULL;
4354
4355 /* JSON_VALUE expects to get only singletons. */
4357 {
4358 if (error)
4359 {
4360 *error = true;
4361 return NULL;
4362 }
4363
4364 if (column_name)
4365 ereport(ERROR,
4367 errmsg("JSON path expression for column \"%s\" must return single scalar item",
4368 column_name)));
4369 else
4370 ereport(ERROR,
4372 errmsg("JSON path expression in JSON_VALUE must return single scalar item")));
4373 }
4374
4375 res = copyJsonbValue(JsonValueListHead(&found));
4376 if (res->type == jbvBinary && JsonContainerIsScalar(res->val.binary.data))
4377 JsonbExtractScalar(res->val.binary.data, res);
4378
4379 /* JSON_VALUE expects to get only scalars. */
4380 if (!IsAJsonbScalar(res))
4381 {
4382 if (error)
4383 {
4384 *error = true;
4385 return NULL;
4386 }
4387
4388 if (column_name)
4389 ereport(ERROR,
4391 errmsg("JSON path expression for column \"%s\" must return single scalar item",
4392 column_name)));
4393 else
4394 ereport(ERROR,
4396 errmsg("JSON path expression in JSON_VALUE must return single scalar item")));
4397 }
4398
4399 if (res->type == jbvNull)
4400 return NULL;
4401
4402 return res;
4403}
4404
4405/************************ JSON_TABLE functions ***************************/
4406
4407/*
4408 * Sanity-checks and returns the opaque JsonTableExecContext from the
4409 * given executor state struct.
4410 */
4411static inline JsonTableExecContext *
4413{
4415
4417 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4418 result = (JsonTableExecContext *) state->opaque;
4420 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4421
4422 return result;
4423}
4424
4425/*
4426 * JsonTableInitOpaque
4427 * Fill in TableFuncScanState->opaque for processing JSON_TABLE
4428 *
4429 * This initializes the PASSING arguments and the JsonTablePlanState for
4430 * JsonTablePlan given in TableFunc.
4431 */
4432static void
4434{
4436 PlanState *ps = &state->ss.ps;
4438 TableFunc *tf = tfs->tablefunc;
4439 JsonTablePlan *rootplan = (JsonTablePlan *) tf->plan;
4441 List *args = NIL;
4442
4445
4446 /*
4447 * Evaluate JSON_TABLE() PASSING arguments to be passed to the jsonpath
4448 * executor via JsonPathVariables.
4449 */
4450 if (state->passingvalexprs)
4451 {
4454
4455 Assert(list_length(state->passingvalexprs) ==
4456 list_length(je->passing_names));
4457 forboth(exprlc, state->passingvalexprs,
4458 namelc, je->passing_names)
4459 {
4463
4464 var->name = pstrdup(name->sval);
4465 var->namelen = strlen(var->name);
4466 var->typid = exprType((Node *) state->expr);
4467 var->typmod = exprTypmod((Node *) state->expr);
4468
4469 /*
4470 * Evaluate the expression and save the value to be returned by
4471 * GetJsonPathVar().
4472 */
4473 var->value = ExecEvalExpr(state, ps->ps_ExprContext,
4474 &var->isnull);
4475
4476 args = lappend(args, var);
4477 }
4478 }
4479
4480 cxt->colplanstates = palloc_array(JsonTablePlanState *, list_length(tf->colvalexprs));
4481
4482 /*
4483 * Initialize plan for the root path and, recursively, also any child
4484 * plans that compute the NESTED paths.
4485 */
4486 cxt->rootplanstate = JsonTableInitPlan(cxt, rootplan, NULL, args,
4488
4489 state->opaque = cxt;
4490}
4491
4492/*
4493 * JsonTableDestroyOpaque
4494 * Resets state->opaque
4495 */
4496static void
4498{
4500 GetJsonTableExecContext(state, "JsonTableDestroyOpaque");
4501
4502 /* not valid anymore */
4503 cxt->magic = 0;
4504
4505 state->opaque = NULL;
4506}
4507
4508/*
4509 * JsonTableInitPlan
4510 * Initialize information for evaluating jsonpath in the given
4511 * JsonTablePlan and, recursively, in any child plans
4512 */
4513static JsonTablePlanState *
4516 List *args, MemoryContext mcxt)
4517{
4519
4520 planstate->plan = plan;
4521 planstate->parent = parentstate;
4522 JsonValueListInit(&planstate->found);
4523
4525 {
4527 int i;
4528
4529 planstate->path = DatumGetJsonPathP(scan->path->value->constvalue);
4530 planstate->args = args;
4531 planstate->mcxt = AllocSetContextCreate(mcxt, "JsonTableExecContext",
4533
4534 /* No row pattern evaluated yet. */
4535 planstate->current.value = PointerGetDatum(NULL);
4536 planstate->current.isnull = true;
4537
4538 for (i = scan->colMin; i >= 0 && i <= scan->colMax; i++)
4539 cxt->colplanstates[i] = planstate;
4540
4541 planstate->nested = scan->child ?
4542 JsonTableInitPlan(cxt, scan->child, planstate, args, mcxt) : NULL;
4543 }
4544 else if (IsA(plan, JsonTableSiblingJoin))
4545 {
4547
4548 planstate->left = JsonTableInitPlan(cxt, join->lplan, parentstate,
4549 args, mcxt);
4550 planstate->right = JsonTableInitPlan(cxt, join->rplan, parentstate,
4551 args, mcxt);
4552 }
4553
4554 return planstate;
4555}
4556
4557/*
4558 * JsonTableSetDocument
4559 * Install the input document and evaluate the row pattern
4560 */
4561static void
4569
4570/*
4571 * Evaluate a JsonTablePlan's jsonpath to get a new row pattern from
4572 * the given context item
4573 */
4574static void
4576{
4577 JsonTablePathScan *scan = castNode(JsonTablePathScan, planstate->plan);
4580 Jsonb *js = (Jsonb *) DatumGetJsonbP(item);
4581
4582 JsonValueListClear(&planstate->found);
4583
4584 MemoryContextResetOnly(planstate->mcxt);
4585
4586 oldcxt = MemoryContextSwitchTo(planstate->mcxt);
4587
4588 res = executeJsonPath(planstate->path, planstate->args,
4590 js, scan->errorOnError,
4591 &planstate->found,
4592 true);
4593
4595
4596 if (jperIsError(res))
4597 {
4598 Assert(!scan->errorOnError);
4599 JsonValueListClear(&planstate->found);
4600 }
4601
4602 /* Reset plan iterator to the beginning of the item list */
4603 JsonValueListInitIterator(&planstate->found, &planstate->iter);
4604 planstate->current.value = PointerGetDatum(NULL);
4605 planstate->current.isnull = true;
4606 planstate->ordinal = 0;
4607}
4608
4609/*
4610 * Fetch next row from a JsonTablePlan.
4611 *
4612 * Returns false if the plan has run out of rows, true otherwise.
4613 */
4614static bool
4616{
4617 if (IsA(planstate->plan, JsonTablePathScan))
4618 return JsonTablePlanScanNextRow(planstate);
4619 else if (IsA(planstate->plan, JsonTableSiblingJoin))
4620 return JsonTablePlanJoinNextRow(planstate);
4621 else
4622 elog(ERROR, "invalid JsonTablePlan %d", (int) planstate->plan->type);
4623
4624 Assert(false);
4625 /* Appease compiler */
4626 return false;
4627}
4628
4629/*
4630 * Fetch next row from a JsonTablePlan's path evaluation result and from
4631 * any child nested path(s).
4632 *
4633 * Returns true if any of the paths (this or the nested) has more rows to
4634 * return.
4635 *
4636 * By fetching the nested path(s)'s rows based on the parent row at each
4637 * level, this essentially joins the rows of different levels. If a nested
4638 * path at a given level has no matching rows, the columns of that level will
4639 * compute to NULL, making it an OUTER join.
4640 */
4641static bool
4643{
4644 JsonbValue *jbv;
4646
4647 /*
4648 * If planstate already has an active row and there is a nested plan,
4649 * check if it has an active row to join with the former.
4650 */
4651 if (!planstate->current.isnull)
4652 {
4653 if (planstate->nested && JsonTablePlanNextRow(planstate->nested))
4654 return true;
4655 }
4656
4657 /* Fetch new row from the list of found values to set as active. */
4658 jbv = JsonValueListNext(&planstate->iter);
4659
4660 /* End of list? */
4661 if (jbv == NULL)
4662 {
4663 planstate->current.value = PointerGetDatum(NULL);
4664 planstate->current.isnull = true;
4665 return false;
4666 }
4667
4668 /*
4669 * Set current row item for subsequent JsonTableGetValue() calls for
4670 * evaluating individual columns.
4671 */
4672 oldcxt = MemoryContextSwitchTo(planstate->mcxt);
4674 planstate->current.isnull = false;
4676
4677 /* Next row! */
4678 planstate->ordinal++;
4679
4680 /* Process nested plan(s), if any. */
4681 if (planstate->nested)
4682 {
4683 /* Re-evaluate the nested path using the above parent row. */
4684 JsonTableResetNestedPlan(planstate->nested);
4685
4686 /*
4687 * Now fetch the nested plan's current row to be joined against the
4688 * parent row. Any further nested plans' paths will be re-evaluated
4689 * recursively, level at a time, after setting each nested plan's
4690 * current row.
4691 */
4692 (void) JsonTablePlanNextRow(planstate->nested);
4693 }
4694
4695 /* There are more rows. */
4696 return true;
4697}
4698
4699/*
4700 * Re-evaluate the row pattern of a nested plan using the new parent row
4701 * pattern.
4702 */
4703static void
4705{
4706 /* This better be a child plan. */
4707 Assert(planstate->parent != NULL);
4708 if (IsA(planstate->plan, JsonTablePathScan))
4709 {
4710 JsonTablePlanState *parent = planstate->parent;
4711
4712 if (!parent->current.isnull)
4713 JsonTableResetRowPattern(planstate, parent->current.value);
4714
4715 /*
4716 * If this plan itself has a child nested plan, it will be reset when
4717 * the caller calls JsonTablePlanNextRow() on this plan.
4718 */
4719 }
4720 else if (IsA(planstate->plan, JsonTableSiblingJoin))
4721 {
4722 JsonTableResetNestedPlan(planstate->left);
4723 JsonTableResetNestedPlan(planstate->right);
4724 }
4725}
4726
4727/*
4728 * Fetch the next row from a JsonTableSiblingJoin.
4729 *
4730 * This is essentially a UNION between the rows from left and right siblings.
4731 */
4732static bool
4734{
4735
4736 /* Fetch row from left sibling. */
4737 if (!JsonTablePlanNextRow(planstate->left))
4738 {
4739 /*
4740 * Left sibling ran out of rows, so start fetching from the right
4741 * sibling.
4742 */
4743 if (!JsonTablePlanNextRow(planstate->right))
4744 {
4745 /* Right sibling ran out of rows too, so there are no more rows. */
4746 return false;
4747 }
4748 }
4749
4750 return true;
4751}
4752
4753/*
4754 * JsonTableFetchRow
4755 * Prepare the next "current" row for upcoming GetValue calls.
4756 *
4757 * Returns false if no more rows can be returned.
4758 */
4759static bool
4761{
4763 GetJsonTableExecContext(state, "JsonTableFetchRow");
4764
4766}
4767
4768/*
4769 * JsonTableGetValue
4770 * Return the value for column number 'colnum' for the current row.
4771 *
4772 * This leaks memory, so be sure to reset often the context in which it's
4773 * called.
4774 */
4775static Datum
4777 Oid typid, int32 typmod, bool *isnull)
4778{
4780 GetJsonTableExecContext(state, "JsonTableGetValue");
4781 ExprContext *econtext = state->ss.ps.ps_ExprContext;
4782 ExprState *estate = list_nth(state->colvalexprs, colnum);
4783 JsonTablePlanState *planstate = cxt->colplanstates[colnum];
4784 JsonTablePlanRowSource *current = &planstate->current;
4785 Datum result;
4786
4787 /* Row pattern value is NULL */
4788 if (current->isnull)
4789 {
4790 result = (Datum) 0;
4791 *isnull = true;
4792 }
4793 /* Evaluate JsonExpr. */
4794 else if (estate)
4795 {
4797 bool saved_caseIsNull = econtext->caseValue_isNull;
4798
4799 /* Pass the row pattern value via CaseTestExpr. */
4800 econtext->caseValue_datum = current->value;
4801 econtext->caseValue_isNull = false;
4802
4803 result = ExecEvalExpr(estate, econtext, isnull);
4804
4805 econtext->caseValue_datum = saved_caseValue;
4807 }
4808 /* ORDINAL column */
4809 else
4810 {
4811 result = Int32GetDatum(planstate->ordinal);
4812 *isnull = false;
4813 }
4814
4815 return result;
4816}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition datetime.c:1608
void j2date(int jd, int *year, int *month, int *day)
Definition datetime.c:322
Datum float8_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4538
Datum numeric_cmp(PG_FUNCTION_ARGS)
Definition numeric.c:2417
Numeric int64_to_numeric(int64 val)
Definition numeric.c:4264
Datum float4_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4637
Datum int4_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4358
Datum numeric_uminus(PG_FUNCTION_ARGS)
Definition numeric.c:1405
Numeric numeric_mod_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:3360
Datum numeric_ceil(PG_FUNCTION_ARGS)
Definition numeric.c:1632
int32 numeric_int4_safe(Numeric num, Node *escontext)
Definition numeric.c:4369
Datum numerictypmodin(PG_FUNCTION_ARGS)
Definition numeric.c:1309
Numeric numeric_add_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:2883
int64 numeric_int8_safe(Numeric num, Node *escontext)
Definition numeric.c:4445
Numeric numeric_div_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:3157
Numeric numeric_sub_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:2959
Datum numeric_out(PG_FUNCTION_ARGS)
Definition numeric.c:799
Datum numeric_trunc(PG_FUNCTION_ARGS)
Definition numeric.c:1582
Datum numeric_in(PG_FUNCTION_ARGS)
Definition numeric.c:626
bool numeric_is_nan(Numeric num)
Definition numeric.c:834
Datum int2_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4489
Numeric numeric_mul_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:3038
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition numeric.c:1378
Datum int8_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4434
bool numeric_is_inf(Numeric num)
Definition numeric.c:845
Datum numeric_floor(PG_FUNCTION_ARGS)
Definition numeric.c:1660
Datum timestamp_cmp(PG_FUNCTION_ARGS)
Definition timestamp.c:2282
bool AdjustTimestampForTypmod(Timestamp *time, int32 typmod, Node *escontext)
Definition timestamp.c:363
Datum timestamp_timestamptz(PG_FUNCTION_ARGS)
Definition timestamp.c:6470
int32 timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
Definition timestamp.c:2375
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition timestamp.c:1918
int32 anytimestamp_typmod_check(bool istz, int32 typmod)
Definition timestamp.c:116
Datum timestamptz_timestamp(PG_FUNCTION_ARGS)
Definition timestamp.c:6539
static int32 next
Definition blutils.c:225
bool parse_bool(const char *value, bool *result)
Definition bool.c:31
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define TextDatumGetCString(d)
Definition builtins.h:99
#define INT64CONST(x)
Definition c.h:630
#define Min(x, y)
Definition c.h:1091
#define PG_UINT32_MAX
Definition c.h:674
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:249
#define Max(x, y)
Definition c.h:1085
#define Assert(condition)
Definition c.h:943
int64_t int64
Definition c.h:621
int32_t int32
Definition c.h:620
uint32_t uint32
Definition c.h:624
#define lengthof(array)
Definition c.h:873
uint32 result
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:764
Datum date_cmp(PG_FUNCTION_ARGS)
Definition date.c:440
Datum time_cmp(PG_FUNCTION_ARGS)
Definition date.c:1842
Datum timestamp_time(PG_FUNCTION_ARGS)
Definition date.c:2015
int32 anytime_typmod_check(bool istz, int32 typmod)
Definition date.c:65
Datum date_timestamptz(PG_FUNCTION_ARGS)
Definition date.c:1393
Datum timetz_cmp(PG_FUNCTION_ARGS)
Definition date.c:2645
Datum timetz_time(PG_FUNCTION_ARGS)
Definition date.c:2939
Datum time_timetz(PG_FUNCTION_ARGS)
Definition date.c:2952
Datum timestamptz_timetz(PG_FUNCTION_ARGS)
Definition date.c:2979
void AdjustTimeForTypmod(TimeADT *time, int32 typmod)
Definition date.c:1753
Datum timestamptz_date(PG_FUNCTION_ARGS)
Definition date.c:1411
Datum timestamp_date(PG_FUNCTION_ARGS)
Definition date.c:1330
int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2)
Definition date.c:845
Datum timestamptz_time(PG_FUNCTION_ARGS)
Definition date.c:2046
Datum date_timestamp(PG_FUNCTION_ARGS)
Definition date.c:1313
static TimeTzADT * DatumGetTimeTzADTP(Datum X)
Definition date.h:72
int32 DateADT
Definition date.h:21
static DateADT DatumGetDateADT(Datum X)
Definition date.h:60
static TimeADT DatumGetTimeADT(Datum X)
Definition date.h:66
static Datum TimeTzADTPGetDatum(const TimeTzADT *X)
Definition date.h:90
int64 TimeADT
Definition date.h:23
static Datum TimeADTGetDatum(TimeADT X)
Definition date.h:84
struct cursor * cur
Definition ecpg.c:29
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:403
#define palloc_object(type)
Definition fe_memutils.h:89
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define palloc0_object(type)
Definition fe_memutils.h:90
float8 float8in_internal(char *num, char **endptr_p, const char *type_name, const char *orig_string, struct Node *escontext)
Definition float.c:436
Datum DirectFunctionCall2Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2)
Definition fmgr.c:814
bool DirectInputFunctionCallSafe(PGFunction func, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition fmgr.c:1641
Datum DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
Definition fmgr.c:794
Datum DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition fmgr.c:836
#define PG_FREE_IF_COPY(ptr, n)
Definition fmgr.h:260
#define DirectFunctionCall2(func, arg1, arg2)
Definition fmgr.h:690
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:688
#define PG_NARGS()
Definition fmgr.h:203
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_GETARG_BOOL(n)
Definition fmgr.h:274
Datum(* PGFunction)(FunctionCallInfo fcinfo)
Definition fmgr.h:40
#define DatumGetTextP(X)
Definition fmgr.h:333
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
char * format_type_be(Oid type_oid)
Datum parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict, Oid *typid, int32 *typmod, int *tz, Node *escontext)
#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 @177 value
Datum int8in(PG_FUNCTION_ARGS)
Definition int8.c:51
Datum int4in(PG_FUNCTION_ARGS)
Definition int.c:316
int b
Definition isn.c:74
int a
Definition isn.c:73
int i
Definition isn.c:77
char * JsonEncodeDateTime(char *buf, Datum value, Oid typid, const int *tzp)
Definition json.c:309
Datum jsonb_in(PG_FUNCTION_ARGS)
Definition jsonb.c:64
const char * JsonbTypeName(JsonbValue *val)
Definition jsonb.c:172
bool JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
Definition jsonb.c:1749
jbvType
Definition jsonb.h:228
@ jbvObject
Definition jsonb.h:236
@ jbvNumeric
Definition jsonb.h:232
@ jbvBool
Definition jsonb.h:233
@ jbvArray
Definition jsonb.h:235
@ jbvBinary
Definition jsonb.h:238
@ jbvNull
Definition jsonb.h:230
@ jbvDatetime
Definition jsonb.h:246
@ jbvString
Definition jsonb.h:231
#define JsonContainerIsScalar(jc)
Definition jsonb.h:209
#define JsonContainerIsArray(jc)
Definition jsonb.h:211
#define JsonContainerSize(jc)
Definition jsonb.h:208
#define PG_GETARG_JSONB_P_COPY(x)
Definition jsonb.h:419
static Datum JsonbPGetDatum(const Jsonb *p)
Definition jsonb.h:413
#define IsAJsonbScalar(jsonbval)
Definition jsonb.h:299
#define PG_RETURN_JSONB_P(x)
Definition jsonb.h:420
#define PG_GETARG_JSONB_P(x)
Definition jsonb.h:418
#define JsonContainerIsObject(jc)
Definition jsonb.h:210
static Jsonb * DatumGetJsonbP(Datum d)
Definition jsonb.h:401
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:204
void pushJsonbValue(JsonbInState *pstate, JsonbIteratorToken seq, JsonbValue *jbval)
Definition jsonb_util.c:583
JsonbIterator * JsonbIteratorInit(JsonbContainer *container)
Definition jsonb_util.c:935
JsonbValue * findJsonbValueFromContainer(JsonbContainer *container, uint32 flags, JsonbValue *key)
Definition jsonb_util.c:348
JsonbIteratorToken JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
Definition jsonb_util.c:973
JsonbValue * getIthJsonbValueFromContainer(JsonbContainer *container, uint32 i)
Definition jsonb_util.c:472
Jsonb * JsonbValueToJsonb(JsonbValue *val)
Definition jsonb_util.c:96
void jspGetLeftArg(JsonPathItem *v, JsonPathItem *a)
Definition jsonpath.c:1263
void jspGetArg(JsonPathItem *v, JsonPathItem *a)
Definition jsonpath.c:1167
void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
Definition jsonpath.c:1068
bool jspGetBool(JsonPathItem *v)
Definition jsonpath.c:1311
void jspInit(JsonPathItem *v, JsonPath *js)
Definition jsonpath.c:1058
char * jspGetString(JsonPathItem *v, int32 *len)
Definition jsonpath.c:1327
Numeric jspGetNumeric(JsonPathItem *v)
Definition jsonpath.c:1319
bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to, int i)
Definition jsonpath.c:1339
const char * jspOperationName(JsonPathItemType type)
Definition jsonpath.c:905
bool jspGetNext(JsonPathItem *v, JsonPathItem *a)
Definition jsonpath.c:1188
void jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
Definition jsonpath.c:1287
bool jspConvertRegexFlags(uint32 xflags, int *result, struct Node *escontext)
#define jspHasNext(jsp)
Definition jsonpath.h:202
#define PG_GETARG_JSONPATH_P(x)
Definition jsonpath.h:46
#define PG_GETARG_JSONPATH_P_COPY(x)
Definition jsonpath.h:47
static JsonPath * DatumGetJsonPathP(Datum d)
Definition jsonpath.h:35
@ 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
@ jpiStrRtrim
Definition jsonpath.h:122
@ jpiBigint
Definition jsonpath.h:107
@ jpiBool
Definition jsonpath.h:67
@ jpiType
Definition jsonpath.h:95
@ jpiStrUpper
Definition jsonpath.h:120
@ jpiFloor
Definition jsonpath.h:98
@ jpiStrBtrim
Definition jsonpath.h:123
@ jpiAnyArray
Definition jsonpath.h:85
@ jpiExists
Definition jsonpath.h:94
@ jpiSize
Definition jsonpath.h:96
@ jpiStrReplace
Definition jsonpath.h:118
@ 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
@ jpiStrInitcap
Definition jsonpath.h:124
@ jpiDouble
Definition jsonpath.h:100
@ jpiGreater
Definition jsonpath.h:75
@ jpiNumber
Definition jsonpath.h:112
@ jpiStrLtrim
Definition jsonpath.h:121
@ 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
@ jpiStrSplitPart
Definition jsonpath.h:125
@ 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
@ jpiStrLower
Definition jsonpath.h:119
@ 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)
static JsonbValue * JsonValueListNext(JsonValueListIterator *it)
static void JsonTableResetRowPattern(JsonTablePlanState *planstate, Datum item)
static int compareStrings(const char *mbstr1, int mblen1, const char *mbstr2, int mblen2)
static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonValueList *found, JsonPathBool res)
#define BASE_JVL_ITEMS
Datum jsonb_path_query_first(PG_FUNCTION_ARGS)
static void JsonTableSetDocument(TableFuncScanState *state, Datum value)
static bool JsonValueListIsEmpty(const JsonValueList *jvl)
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 JsonTableExecContext * GetJsonTableExecContext(TableFuncScanState *state, const char *fname)
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)
Numeric(* BinaryArithmFunc)(Numeric num1, Numeric num2, Node *escontext)
static JsonBaseObjectInfo setBaseObject(JsonPathExecContext *cxt, JsonbValue *jbv, int32 id)
static Datum castTimeToTimeTz(Datum time, bool useTz)
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)
JsonbValue *(* JsonPathGetVarCallback)(void *vars, char *varName, int varNameLen, JsonbValue *baseObject, int *baseObjectId)
Datum jsonb_path_match_tz(PG_FUNCTION_ARGS)
static JsonPathExecResult executeItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found)
static void JsonValueListInit(JsonValueList *jvl)
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)
static bool JsonValueListIsSingleton(const JsonValueList *jvl)
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)
static JsonPathExecResult executeStringInternalMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found)
Datum jsonb_path_match(PG_FUNCTION_ARGS)
#define jspStrictAbsenceOfErrors(cxt)
static void JsonTableDestroyOpaque(TableFuncScanState *state)
static void JsonValueListClear(JsonValueList *jvl)
static void JsonTableInitOpaque(TableFuncScanState *state, int natts)
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)
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)
#define jspIgnoreStructuralErrors(cxt)
JsonPathExecResult
@ jperError
@ jperNotFound
@ jperOk
static void JsonbValueInitNumericDatum(JsonbValue *jbv, Datum num)
static int CountJsonPathVars(void *cxt)
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)
#define MIN_EXTRA_JVL_ITEMS
Datum jsonb_path_query_array(PG_FUNCTION_ARGS)
static JsonPathExecResult executeItemOptUnwrapResult(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, bool unwrap, JsonValueList *found)
static JsonPathExecResult executeNumericItemMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, bool unwrap, PGFunction func, JsonValueList *found)
static void getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable, JsonbValue *value)
static JsonbValue * JsonValueListHead(JsonValueList *jvl)
static void JsonValueListInitIterator(JsonValueList *jvl, JsonValueListIterator *it)
Datum jsonb_path_exists_tz(PG_FUNCTION_ARGS)
static bool JsonTableFetchRow(TableFuncScanState *state)
static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item, JsonbValue *value)
static JsonPathExecResult executeNextItem(JsonPathExecContext *cxt, JsonPathItem *cur, JsonPathItem *next, JsonbValue *v, JsonValueList *found)
static JsonPathBool executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb, bool unwrapRightArg, JsonPathPredicateCallback exec, void *param)
static int binaryCompareStrings(const char *s1, int len1, const char *s2, int len2)
static bool JsonValueListHasMultipleItems(const JsonValueList *jvl)
const TableFuncRoutine JsonbTableRoutine
static void JsonValueListAppend(JsonValueList *jvl, const JsonbValue *jbv)
static JsonbValue * wrapItemsInArray(JsonValueList *items)
int(* JsonPathCountVarsCallback)(void *vars)
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
static struct pg_tm tm
Definition localtime.c:104
#define PG_UTF8
Definition mbprint.c:43
int GetDatabaseEncoding(void)
Definition mbutils.c:1389
char * pg_server_to_any(const char *s, int len, int encoding)
Definition mbutils.c:760
char * pstrdup(const char *in)
Definition mcxt.c:1910
void pfree(void *pointer)
Definition mcxt.c:1619
MemoryContext TopMemoryContext
Definition mcxt.c:167
void * palloc(Size size)
Definition mcxt.c:1390
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
char * pnstrdup(const char *in, Size len)
Definition mcxt.c:1921
void MemoryContextResetOnly(MemoryContext context)
Definition mcxt.c:425
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
Oid exprType(const Node *expr)
Definition nodeFuncs.c:42
int32 exprTypmod(const Node *expr)
Definition nodeFuncs.c:304
#define IsA(nodeptr, _type_)
Definition nodes.h:164
#define castNode(_type_, nodeptr)
Definition nodes.h:182
static Numeric DatumGetNumeric(Datum X)
Definition numeric.h:64
struct NumericData * Numeric
Definition numeric.h:57
static Datum NumericGetDatum(Numeric X)
Definition numeric.h:76
int pg_ltoa(int32 value, char *a)
Definition numutils.c:1119
static char * errmsg
Datum ltrim(PG_FUNCTION_ARGS)
Datum lower(PG_FUNCTION_ARGS)
Datum initcap(PG_FUNCTION_ARGS)
Datum upper(PG_FUNCTION_ARGS)
Datum rtrim(PG_FUNCTION_ARGS)
Datum ltrim1(PG_FUNCTION_ARGS)
Datum btrim1(PG_FUNCTION_ARGS)
Datum rtrim1(PG_FUNCTION_ARGS)
Datum btrim(PG_FUNCTION_ARGS)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
#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:550
static void * list_nth(const List *list, int n)
Definition pg_list.h:331
#define plan(x)
Definition pg_regress.c:164
static char buf[DEFAULT_XLOG_SEG_SIZE]
@ PG_SQL_ASCII
Definition pg_wchar.h:76
static int scale
Definition pgbench.c:182
PGDLLIMPORT pg_tz * session_timezone
Definition pgtz.c:28
static Datum Int64GetDatum(int64 X)
Definition postgres.h:426
static bool DatumGetBool(Datum X)
Definition postgres.h:100
static char * DatumGetCString(Datum X)
Definition postgres.h:365
uint64_t Datum
Definition postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition postgres.h:332
static Datum Float8GetDatum(float8 X)
Definition postgres.h:515
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
static int32 DatumGetInt32(Datum X)
Definition postgres.h:202
#define PointerGetDatum(X)
Definition postgres.h:354
#define InvalidOid
unsigned int Oid
static int fb(int x)
char * s1
char * s2
JsonWrapper
Definition primnodes.h:1789
@ JSW_UNCONDITIONAL
Definition primnodes.h:1793
@ JSW_CONDITIONAL
Definition primnodes.h:1792
@ JSW_UNSPEC
Definition primnodes.h:1790
@ JSW_NONE
Definition primnodes.h:1791
static int cmp(const chr *x, const chr *y, size_t len)
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
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 void error(void)
void check_stack_depth(void)
Definition stack_depth.c:95
bool caseValue_isNull
Definition execnodes.h:314
Datum caseValue_datum
Definition execnodes.h:312
JsonbContainer * jbc
JsonPathGetVarCallback getVar
JsonBaseObjectInfo baseObject
char * base
Definition jsonpath.h:154
JsonPathItemType type
Definition jsonpath.h:145
uint32 header
Definition jsonpath.h:26
JsonTablePlanState * rootplanstate
JsonTablePlanState ** colplanstates
JsonTablePath * path
Definition primnodes.h:1938
JsonTablePlan * child
Definition primnodes.h:1947
Const * value
Definition primnodes.h:1911
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:1968
JsonTablePlan * lplan
Definition primnodes.h:1967
JsonValueList * chunk
struct JsonValueList * last
JsonbValue items[BASE_JVL_ITEMS]
struct JsonValueList * next
uint32 header
Definition jsonb.h:194
enum jbvType type
Definition jsonb.h:257
char * val
Definition jsonb.h:266
Definition jsonb.h:215
JsonbContainer root
Definition jsonb.h:217
Definition pg_list.h:54
Definition nodes.h:135
Definition value.h:64
void(* InitOpaque)(TableFuncScanState *state, int natts)
Definition tablefunc.h:54
Node * docexpr
Definition primnodes.h:121
Definition type.h:117
Definition type.h:97
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
enum ECPGttype type
Definition c.h:776
static ItemArray items
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
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486
text * cstring_to_text_with_len(const char *s, int len)
Definition varlena.c:196
Datum split_part(PG_FUNCTION_ARGS)
Definition varlena.c:3509
text * cstring_to_text(const char *s)
Definition varlena.c:184
char * text_to_cstring(const text *t)
Definition varlena.c:217
Datum replace_text(PG_FUNCTION_ARGS)
Definition varlena.c:3137
const char * type
const char * name