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 */
243
244 /* Join type */
245 bool cross;
247 /* Planning control fields */
250 bool reset;
252
253/* Random number to identify JsonTableExecContext for sanity checking */
254#define JSON_TABLE_EXEC_CONTEXT_MAGIC 418352867
255
257{
258 int magic;
259
260 /* State of the plan providing a row evaluated from "root" jsonpath */
262
263 /*
264 * Per-column JsonTablePlanStates for all columns including the nested
265 * ones.
266 */
269
270/* strict/lax flags is decomposed into four [un]wrap/error flags */
271#define jspStrictAbsenceOfErrors(cxt) (!(cxt)->laxMode)
272#define jspAutoUnwrap(cxt) ((cxt)->laxMode)
273#define jspAutoWrap(cxt) ((cxt)->laxMode)
274#define jspIgnoreStructuralErrors(cxt) ((cxt)->ignoreStructuralErrors)
275#define jspThrowErrors(cxt) ((cxt)->throwErrors)
276
277/* Convenience macro: return or throw error depending on context */
278#define RETURN_ERROR(throw_error) \
279do { \
280 if (jspThrowErrors(cxt)) \
281 throw_error; \
282 else \
283 return jperError; \
284} while (0)
285
287 JsonbValue *larg,
288 JsonbValue *rarg,
289 void *param);
291 Node *escontext);
292
296 Jsonb *json, bool throwErrors,
297 JsonValueList *result, bool useTz);
302 JsonValueList *found, bool unwrap);
305 JsonValueList *found, bool unwrapElements);
308 JsonbValue *v, JsonValueList *found);
310 bool unwrap, JsonValueList *found);
312 JsonbValue *jb, bool unwrap, JsonValueList *found);
319 uint32 level, uint32 first, uint32 last,
320 bool ignoreStructuralErrors, bool unwrapNext);
322 JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg,
324 JsonPathPredicateCallback exec, void *param);
327 BinaryArithmFunc func, JsonValueList *found);
330 JsonValueList *found);
332 JsonbValue *whole, JsonbValue *initial, void *param);
334 JsonbValue *rarg, void *param);
337 JsonValueList *found);
339 JsonbValue *jb, JsonValueList *found);
341 JsonbValue *jb, JsonValueList *found);
346static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
348static JsonbValue *GetJsonPathVar(void *cxt, char *varName, int varNameLen,
349 JsonbValue *baseObject, int *baseObjectId);
350static int CountJsonPathVars(void *cxt);
351static void JsonItemFromDatum(Datum val, Oid typid, int32 typmod,
352 JsonbValue *res);
356static int countVariablesFromJsonb(void *varsJsonb);
357static JsonbValue *getJsonPathVariableFromJsonb(void *varsJsonb, char *varName,
358 int varNameLength,
359 JsonbValue *baseObject,
360 int *baseObjectId);
361static int JsonbArraySize(JsonbValue *jb);
363 JsonbValue *rv, void *p);
365 bool useTz);
366static int compareNumeric(Numeric a, Numeric b);
371 JsonbValue *jbv, int32 id);
375static bool JsonValueListIsEmpty(const JsonValueList *jvl);
376static bool JsonValueListIsSingleton(const JsonValueList *jvl);
383static int JsonbType(JsonbValue *jb);
384static JsonbValue *getScalar(JsonbValue *scalar, enum jbvType type);
387 bool useTz, bool *cast_error);
388static void checkTimezoneIsUsedForCast(bool useTz, const char *type1,
389 const char *type2);
390
391static void JsonTableInitOpaque(TableFuncScanState *state, int natts);
395 List *args,
396 MemoryContext mcxt);
398static void JsonTableResetRowPattern(JsonTablePlanState *planstate, Datum item);
399static void JsonTableRescan(JsonTablePlanState *planstate);
402 Oid typid, int32 typmod, bool *isnull);
404static bool JsonTablePlanScanNextRow(JsonTablePlanState *planstate);
405static void JsonTableResetNestedPlan(JsonTablePlanState *planstate);
406static bool JsonTablePlanNextRow(JsonTablePlanState *planstate);
407
409{
411 .SetDocument = JsonTableSetDocument,
412 .SetNamespace = NULL,
413 .SetRowFilter = NULL,
414 .SetColumnFilter = NULL,
415 .FetchRow = JsonTableFetchRow,
416 .GetValue = JsonTableGetValue,
417 .DestroyOpaque = JsonTableDestroyOpaque
418};
419
420/****************** User interface to JsonPath executor ********************/
421
422/*
423 * jsonb_path_exists
424 * Returns true if jsonpath returns at least one item for the specified
425 * jsonb value. This function and jsonb_path_match() are used to
426 * implement @? and @@ operators, which in turn are intended to have an
427 * index support. Thus, it's desirable to make it easier to achieve
428 * consistency between index scan results and sequential scan results.
429 * So, we throw as few errors as possible. Regarding this function,
430 * such behavior also matches behavior of JSON_EXISTS() clause of
431 * SQL/JSON. Regarding jsonb_path_match(), this function doesn't have
432 * an analogy in SQL/JSON, so we define its behavior on our own.
433 */
434static Datum
436{
440 Jsonb *vars = NULL;
441 bool silent = true;
442
443 if (PG_NARGS() == 4)
444 {
447 }
448
451 jb, !silent, NULL, tz);
452
455
456 if (jperIsError(res))
458
459 PG_RETURN_BOOL(res == jperOk);
460}
461
462Datum
467
468Datum
473
474/*
475 * jsonb_path_exists_opr
476 * Implementation of operator "jsonb @? jsonpath" (2-argument version of
477 * jsonb_path_exists()).
478 */
479Datum
481{
482 /* just call the other one -- it can handle both cases */
483 return jsonb_path_exists_internal(fcinfo, false);
484}
485
486/*
487 * jsonb_path_match
488 * Returns jsonpath predicate result item for the specified jsonb value.
489 * See jsonb_path_exists() comment for details regarding error handling.
490 */
491static Datum
493{
496 Jsonb *vars = NULL;
497 bool silent = true;
498 JsonValueList found;
499
500 if (PG_NARGS() == 4)
501 {
504 }
505
506 JsonValueListInit(&found);
507
510 jb, !silent, &found, tz);
511
514
515 if (JsonValueListIsSingleton(&found))
516 {
518
519 if (jbv->type == jbvBool)
520 PG_RETURN_BOOL(jbv->val.boolean);
521
522 if (jbv->type == jbvNull)
524 }
525
526 if (!silent)
529 errmsg("single boolean result is expected")));
530
532}
533
534Datum
536{
537 return jsonb_path_match_internal(fcinfo, false);
538}
539
540Datum
545
546/*
547 * jsonb_path_match_opr
548 * Implementation of operator "jsonb @@ jsonpath" (2-argument version of
549 * jsonb_path_match()).
550 */
551Datum
553{
554 /* just call the other one -- it can handle both cases */
555 return jsonb_path_match_internal(fcinfo, false);
556}
557
558/*
559 * jsonb_path_query
560 * Executes jsonpath for given jsonb document and returns result as
561 * rowset.
562 */
563static Datum
565{
568 JsonbValue *v;
569
570 if (SRF_IS_FIRSTCALL())
571 {
572 JsonPath *jp;
573 Jsonb *jb;
574 Jsonb *vars;
575 bool silent;
576 MemoryContext oldcontext;
577 JsonValueList *found;
578
580 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
581
586
588 JsonValueListInit(found);
589
592 jb, !silent, found, tz);
593
595 JsonValueListInitIterator(found, iter);
596
597 funcctx->user_fctx = iter;
598
599 MemoryContextSwitchTo(oldcontext);
600 }
601
603 iter = funcctx->user_fctx;
604
605 v = JsonValueListNext(iter);
606
607 if (v == NULL)
609
611}
612
613Datum
615{
616 return jsonb_path_query_internal(fcinfo, false);
617}
618
619Datum
624
625/*
626 * jsonb_path_query_array
627 * Executes jsonpath for given jsonb document and returns result as
628 * jsonb array.
629 */
630static Datum
647
648Datum
653
654Datum
659
660/*
661 * jsonb_path_query_first
662 * Executes jsonpath for given jsonb document and returns first result
663 * item. If there are no items, NULL returned.
664 */
665static Datum
685
686Datum
691
692Datum
697
698/********************Execute functions for JsonPath**************************/
699
700/*
701 * Interface to jsonpath executor
702 *
703 * 'path' - jsonpath to be executed
704 * 'vars' - variables to be substituted to jsonpath
705 * 'getVar' - callback used by getJsonPathVariable() to extract variables from
706 * 'vars'
707 * 'countVars' - callback to count the number of jsonpath variables in 'vars'
708 * 'json' - target document for jsonpath evaluation
709 * 'throwErrors' - whether we should throw suppressible errors
710 * 'result' - list to store result items into
711 *
712 * Returns an error if a recoverable error happens during processing, or NULL
713 * on no error.
714 *
715 * Note, jsonb and jsonpath values should be available and untoasted during
716 * work because JsonPathItem, JsonbValue and result item could have pointers
717 * into input values. If caller needs to just check if document matches
718 * jsonpath, then it doesn't provide a result arg. In this case executor
719 * works till first positive result and does not check the rest if possible.
720 * In other case it tries to find all the satisfied result items.
721 */
725 Jsonb *json, bool throwErrors, JsonValueList *result,
726 bool useTz)
727{
732
733 jspInit(&jsp, path);
734
735 if (!JsonbExtractScalar(&json->root, &jbv))
736 JsonbInitBinary(&jbv, json);
737
738 cxt.vars = vars;
739 cxt.getVar = getVar;
740 cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
742 cxt.root = &jbv;
743 cxt.current = &jbv;
744 cxt.baseObject.jbc = NULL;
745 cxt.baseObject.id = 0;
746 /* 1 + number of base objects in vars */
748 cxt.innermostArraySize = -1;
749 cxt.throwErrors = throwErrors;
750 cxt.useTz = useTz;
751
752 if (jspStrictAbsenceOfErrors(&cxt) && !result)
753 {
754 /*
755 * In strict mode we must get a complete list of values to check that
756 * there are no errors at all.
757 */
758 JsonValueList vals;
759 bool isempty;
760
761 JsonValueListInit(&vals);
762
763 res = executeItem(&cxt, &jsp, &jbv, &vals);
764
766 JsonValueListClear(&vals);
767
768 if (jperIsError(res))
769 return res;
770
771 return isempty ? jperNotFound : jperOk;
772 }
773
774 res = executeItem(&cxt, &jsp, &jbv, result);
775
776 Assert(!throwErrors || !jperIsError(res));
777
778 return res;
779}
780
781/*
782 * Execute jsonpath with automatic unwrapping of current item in lax mode.
783 */
790
791/*
792 * Main jsonpath executor function: walks on jsonpath structure, finds
793 * relevant parts of jsonb and evaluates expressions over them.
794 * When 'unwrap' is true current SQL/JSON item is unwrapped if it is an array.
795 */
798 JsonbValue *jb, JsonValueList *found, bool unwrap)
799{
800 JsonPathItem elem;
802 JsonBaseObjectInfo baseObject;
803
806
807 switch (jsp->type)
808 {
809 case jpiNull:
810 case jpiBool:
811 case jpiNumeric:
812 case jpiString:
813 case jpiVariable:
814 {
815 JsonbValue v;
816 bool hasNext = jspGetNext(jsp, &elem);
817
818 if (!hasNext && !found && jsp->type != jpiVariable)
819 {
820 /*
821 * Skip evaluation, but not for variables. We must
822 * trigger an error for the missing variable.
823 */
824 res = jperOk;
825 break;
826 }
827
828 baseObject = cxt->baseObject;
829 getJsonPathItem(cxt, jsp, &v);
830
831 res = executeNextItem(cxt, jsp, &elem,
832 &v, found);
833 cxt->baseObject = baseObject;
834 }
835 break;
836
837 /* all boolean item types: */
838 case jpiAnd:
839 case jpiOr:
840 case jpiNot:
841 case jpiIsUnknown:
842 case jpiEqual:
843 case jpiNotEqual:
844 case jpiLess:
845 case jpiGreater:
846 case jpiLessOrEqual:
848 case jpiExists:
849 case jpiStartsWith:
850 case jpiLikeRegex:
851 {
852 JsonPathBool st = executeBoolItem(cxt, jsp, jb, true);
853
854 res = appendBoolResult(cxt, jsp, found, st);
855 break;
856 }
857
858 case jpiAdd:
859 return executeBinaryArithmExpr(cxt, jsp, jb,
860 numeric_add_safe, found);
861
862 case jpiSub:
863 return executeBinaryArithmExpr(cxt, jsp, jb,
864 numeric_sub_safe, found);
865
866 case jpiMul:
867 return executeBinaryArithmExpr(cxt, jsp, jb,
868 numeric_mul_safe, found);
869
870 case jpiDiv:
871 return executeBinaryArithmExpr(cxt, jsp, jb,
872 numeric_div_safe, found);
873
874 case jpiMod:
875 return executeBinaryArithmExpr(cxt, jsp, jb,
876 numeric_mod_safe, found);
877
878 case jpiPlus:
879 return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
880
881 case jpiMinus:
883 found);
884
885 case jpiAnyArray:
886 if (JsonbType(jb) == jbvArray)
887 {
888 bool hasNext = jspGetNext(jsp, &elem);
889
890 res = executeItemUnwrapTargetArray(cxt, hasNext ? &elem : NULL,
891 jb, found, jspAutoUnwrap(cxt));
892 }
893 else if (jspAutoWrap(cxt))
894 res = executeNextItem(cxt, jsp, NULL, jb, found);
895 else if (!jspIgnoreStructuralErrors(cxt))
898 errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
899 break;
900
901 case jpiAnyKey:
902 if (JsonbType(jb) == jbvObject)
903 {
904 bool hasNext = jspGetNext(jsp, &elem);
905
906 if (jb->type != jbvBinary)
907 elog(ERROR, "invalid jsonb object type: %d", jb->type);
908
909 return executeAnyItem
910 (cxt, hasNext ? &elem : NULL,
911 jb->val.binary.data, found, 1, 1, 1,
912 false, jspAutoUnwrap(cxt));
913 }
914 else if (unwrap && JsonbType(jb) == jbvArray)
915 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
916 else if (!jspIgnoreStructuralErrors(cxt))
917 {
918 Assert(found);
921 errmsg("jsonpath wildcard member accessor can only be applied to an object"))));
922 }
923 break;
924
925 case jpiIndexArray:
926 if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
927 {
928 int innermostArraySize = cxt->innermostArraySize;
929 int i;
930 int size = JsonbArraySize(jb);
931 bool singleton = size < 0;
932 bool hasNext = jspGetNext(jsp, &elem);
933
934 if (singleton)
935 size = 1;
936
937 cxt->innermostArraySize = size; /* for LAST evaluation */
938
939 for (i = 0; i < jsp->content.array.nelems; i++)
940 {
941 JsonPathItem from;
942 JsonPathItem to;
943 int32 index;
946 bool range = jspGetArraySubscript(jsp, &from,
947 &to, i);
948
949 res = getArrayIndex(cxt, &from, jb, &index_from);
950
951 if (jperIsError(res))
952 break;
953
954 if (range)
955 {
956 res = getArrayIndex(cxt, &to, jb, &index_to);
957
958 if (jperIsError(res))
959 break;
960 }
961 else
963
964 if (!jspIgnoreStructuralErrors(cxt) &&
965 (index_from < 0 ||
967 index_to >= size))
970 errmsg("jsonpath array subscript is out of bounds"))));
971
972 if (index_from < 0)
973 index_from = 0;
974
975 if (index_to >= size)
976 index_to = size - 1;
977
978 res = jperNotFound;
979
980 for (index = index_from; index <= index_to; index++)
981 {
982 JsonbValue *v;
983
984 if (singleton)
985 {
986 v = jb;
987 }
988 else
989 {
990 v = getIthJsonbValueFromContainer(jb->val.binary.data,
991 (uint32) index);
992
993 if (v == NULL)
994 continue;
995 }
996
997 if (!hasNext && !found)
998 return jperOk;
999
1000 res = executeNextItem(cxt, jsp, &elem, v, found);
1001
1002 if (jperIsError(res))
1003 break;
1004
1005 if (res == jperOk && !found)
1006 break;
1007 }
1008
1009 if (jperIsError(res))
1010 break;
1011
1012 if (res == jperOk && !found)
1013 break;
1014 }
1015
1016 cxt->innermostArraySize = innermostArraySize;
1017 }
1018 else if (!jspIgnoreStructuralErrors(cxt))
1019 {
1022 errmsg("jsonpath array accessor can only be applied to an array"))));
1023 }
1024 break;
1025
1026 case jpiAny:
1027 {
1028 bool hasNext = jspGetNext(jsp, &elem);
1029
1030 /* first try without any intermediate steps */
1031 if (jsp->content.anybounds.first == 0)
1032 {
1034
1036 cxt->ignoreStructuralErrors = true;
1037 res = executeNextItem(cxt, jsp, &elem,
1038 jb, found);
1040
1041 if (res == jperOk && !found)
1042 break;
1043 }
1044
1045 if (jb->type == jbvBinary)
1046 res = executeAnyItem
1047 (cxt, hasNext ? &elem : NULL,
1048 jb->val.binary.data, found,
1049 1,
1050 jsp->content.anybounds.first,
1051 jsp->content.anybounds.last,
1052 true, jspAutoUnwrap(cxt));
1053 break;
1054 }
1055
1056 case jpiKey:
1057 if (JsonbType(jb) == jbvObject)
1058 {
1059 JsonbValue *v;
1060 JsonbValue key;
1061
1062 key.type = jbvString;
1063 key.val.string.val = jspGetString(jsp, &key.val.string.len);
1064
1065 v = findJsonbValueFromContainer(jb->val.binary.data,
1066 JB_FOBJECT, &key);
1067
1068 if (v != NULL)
1069 {
1070 res = executeNextItem(cxt, jsp, NULL,
1071 v, found);
1072 pfree(v);
1073 }
1074 else if (!jspIgnoreStructuralErrors(cxt))
1075 {
1076 Assert(found);
1077
1078 if (!jspThrowErrors(cxt))
1079 return jperError;
1080
1081 ereport(ERROR,
1083 errmsg("JSON object does not contain key \"%s\"",
1084 pnstrdup(key.val.string.val,
1085 key.val.string.len))));
1086 }
1087 }
1088 else if (unwrap && JsonbType(jb) == jbvArray)
1089 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1090 else if (!jspIgnoreStructuralErrors(cxt))
1091 {
1092 Assert(found);
1095 errmsg("jsonpath member accessor can only be applied to an object"))));
1096 }
1097 break;
1098
1099 case jpiCurrent:
1100 res = executeNextItem(cxt, jsp, NULL, cxt->current, found);
1101 break;
1102
1103 case jpiRoot:
1104 jb = cxt->root;
1105 baseObject = setBaseObject(cxt, jb, 0);
1106 res = executeNextItem(cxt, jsp, NULL, jb, found);
1107 cxt->baseObject = baseObject;
1108 break;
1109
1110 case jpiFilter:
1111 {
1112 JsonPathBool st;
1113
1114 if (unwrap && JsonbType(jb) == jbvArray)
1115 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1116 false);
1117
1118 jspGetArg(jsp, &elem);
1119 st = executeNestedBoolItem(cxt, &elem, jb);
1120 if (st != jpbTrue)
1121 res = jperNotFound;
1122 else
1123 res = executeNextItem(cxt, jsp, NULL,
1124 jb, found);
1125 break;
1126 }
1127
1128 case jpiType:
1129 {
1131
1132 jbv.type = jbvString;
1133 jbv.val.string.val = pstrdup(JsonbTypeName(jb));
1134 jbv.val.string.len = strlen(jbv.val.string.val);
1135
1136 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1137 }
1138 break;
1139
1140 case jpiSize:
1141 {
1142 int size = JsonbArraySize(jb);
1144
1145 if (size < 0)
1146 {
1147 if (!jspAutoWrap(cxt))
1148 {
1149 if (!jspIgnoreStructuralErrors(cxt))
1152 errmsg("jsonpath item method .%s() can only be applied to an array",
1153 jspOperationName(jsp->type)))));
1154 break;
1155 }
1156
1157 size = 1;
1158 }
1159
1160 jbv.type = jbvNumeric;
1161 jbv.val.numeric = int64_to_numeric(size);
1162
1163 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1164 }
1165 break;
1166
1167 case jpiAbs:
1169 found);
1170
1171 case jpiFloor:
1173 found);
1174
1175 case jpiCeiling:
1177 found);
1178
1179 case jpiDouble:
1180 {
1182
1183 if (unwrap && JsonbType(jb) == jbvArray)
1184 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1185 false);
1186
1187 if (jb->type == jbvNumeric)
1188 {
1190 NumericGetDatum(jb->val.numeric)));
1191 double val;
1193
1194 val = float8in_internal(tmp,
1195 NULL,
1196 "double precision",
1197 tmp,
1198 (Node *) &escontext);
1199
1200 if (escontext.error_occurred)
1203 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1204 tmp, jspOperationName(jsp->type), "double precision"))));
1205 if (isinf(val) || isnan(val))
1208 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1209 jspOperationName(jsp->type)))));
1210 res = jperOk;
1211 }
1212 else if (jb->type == jbvString)
1213 {
1214 /* cast string as double */
1215 double val;
1216 char *tmp = pnstrdup(jb->val.string.val,
1217 jb->val.string.len);
1219
1220 val = float8in_internal(tmp,
1221 NULL,
1222 "double precision",
1223 tmp,
1224 (Node *) &escontext);
1225
1226 if (escontext.error_occurred)
1229 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1230 tmp, jspOperationName(jsp->type), "double precision"))));
1231 if (isinf(val) || isnan(val))
1234 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1235 jspOperationName(jsp->type)))));
1236
1237 jb = &jbv;
1238 jb->type = jbvNumeric;
1241 res = jperOk;
1242 }
1243
1244 if (res == jperNotFound)
1247 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1248 jspOperationName(jsp->type)))));
1249
1250 res = executeNextItem(cxt, jsp, NULL, jb, found);
1251 }
1252 break;
1253
1254 case jpiDatetime:
1255 case jpiDate:
1256 case jpiTime:
1257 case jpiTimeTz:
1258 case jpiTimestamp:
1259 case jpiTimestampTz:
1260 if (unwrap && JsonbType(jb) == jbvArray)
1261 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1262
1263 return executeDateTimeMethod(cxt, jsp, jb, found);
1264
1265 case jpiKeyValue:
1266 if (unwrap && JsonbType(jb) == jbvArray)
1267 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1268
1269 return executeKeyValueMethod(cxt, jsp, jb, found);
1270
1271 case jpiLast:
1272 {
1274 int last;
1275 bool hasNext = jspGetNext(jsp, &elem);
1276
1277 if (cxt->innermostArraySize < 0)
1278 elog(ERROR, "evaluating jsonpath LAST outside of array subscript");
1279
1280 if (!hasNext && !found)
1281 {
1282 res = jperOk;
1283 break;
1284 }
1285
1286 last = cxt->innermostArraySize - 1;
1287
1288 jbv.type = jbvNumeric;
1289 jbv.val.numeric = int64_to_numeric(last);
1290
1291 res = executeNextItem(cxt, jsp, &elem,
1292 &jbv, found);
1293 }
1294 break;
1295
1296 case jpiBigint:
1297 {
1299 Datum datum;
1300
1301 if (unwrap && JsonbType(jb) == jbvArray)
1302 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1303 false);
1304
1305 if (jb->type == jbvNumeric)
1306 {
1308 int64 val;
1309
1310 val = numeric_int8_safe(jb->val.numeric,
1311 (Node *) &escontext);
1312 if (escontext.error_occurred)
1315 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1317 NumericGetDatum(jb->val.numeric))),
1318 jspOperationName(jsp->type),
1319 "bigint"))));
1320
1321 datum = Int64GetDatum(val);
1322 res = jperOk;
1323 }
1324 else if (jb->type == jbvString)
1325 {
1326 /* cast string as bigint */
1327 char *tmp = pnstrdup(jb->val.string.val,
1328 jb->val.string.len);
1330 bool noerr;
1331
1333 InvalidOid, -1,
1334 (Node *) &escontext,
1335 &datum);
1336
1337 if (!noerr || escontext.error_occurred)
1340 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1341 tmp, jspOperationName(jsp->type), "bigint"))));
1342 res = jperOk;
1343 }
1344
1345 if (res == jperNotFound)
1348 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1349 jspOperationName(jsp->type)))));
1350
1351 jbv.type = jbvNumeric;
1353 datum));
1354
1355 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1356 }
1357 break;
1358
1359 case jpiBoolean:
1360 {
1362 bool bval;
1363
1364 if (unwrap && JsonbType(jb) == jbvArray)
1365 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1366 false);
1367
1368 if (jb->type == jbvBool)
1369 {
1370 bval = jb->val.boolean;
1371
1372 res = jperOk;
1373 }
1374 else if (jb->type == jbvNumeric)
1375 {
1376 int ival;
1377 Datum datum;
1378 bool noerr;
1380 NumericGetDatum(jb->val.numeric)));
1382
1384 InvalidOid, -1,
1385 (Node *) &escontext,
1386 &datum);
1387
1388 if (!noerr || escontext.error_occurred)
1391 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1392 tmp, jspOperationName(jsp->type), "boolean"))));
1393
1394 ival = DatumGetInt32(datum);
1395 if (ival == 0)
1396 bval = false;
1397 else
1398 bval = true;
1399
1400 res = jperOk;
1401 }
1402 else if (jb->type == jbvString)
1403 {
1404 /* cast string as boolean */
1405 char *tmp = pnstrdup(jb->val.string.val,
1406 jb->val.string.len);
1407
1408 if (!parse_bool(tmp, &bval))
1411 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1412 tmp, jspOperationName(jsp->type), "boolean"))));
1413
1414 res = jperOk;
1415 }
1416
1417 if (res == jperNotFound)
1420 errmsg("jsonpath item method .%s() can only be applied to a boolean, string, or numeric value",
1421 jspOperationName(jsp->type)))));
1422
1423 jbv.type = jbvBool;
1424 jbv.val.boolean = bval;
1425
1426 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1427 }
1428 break;
1429
1430 case jpiDecimal:
1431 case jpiNumber:
1432 {
1434 Numeric num;
1435 char *numstr = NULL;
1436
1437 if (unwrap && JsonbType(jb) == jbvArray)
1438 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1439 false);
1440
1441 if (jb->type == jbvNumeric)
1442 {
1443 num = jb->val.numeric;
1444 if (numeric_is_nan(num) || numeric_is_inf(num))
1447 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1448 jspOperationName(jsp->type)))));
1449
1450 if (jsp->type == jpiDecimal)
1452 NumericGetDatum(num)));
1453 res = jperOk;
1454 }
1455 else if (jb->type == jbvString)
1456 {
1457 /* cast string as number */
1458 Datum datum;
1459 bool noerr;
1461
1462 numstr = pnstrdup(jb->val.string.val, jb->val.string.len);
1463
1465 InvalidOid, -1,
1466 (Node *) &escontext,
1467 &datum);
1468
1469 if (!noerr || escontext.error_occurred)
1472 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1473 numstr, jspOperationName(jsp->type), "numeric"))));
1474
1475 num = DatumGetNumeric(datum);
1476 if (numeric_is_nan(num) || numeric_is_inf(num))
1479 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1480 jspOperationName(jsp->type)))));
1481
1482 res = jperOk;
1483 }
1484
1485 if (res == jperNotFound)
1488 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1489 jspOperationName(jsp->type)))));
1490
1491 /*
1492 * If we have arguments, then they must be the precision and
1493 * optional scale used in .decimal(). Convert them to the
1494 * typmod equivalent and then truncate the numeric value per
1495 * this typmod details.
1496 */
1497 if (jsp->type == jpiDecimal && jsp->content.args.left)
1498 {
1500 int32 dtypmod;
1501 int32 precision;
1502 int32 scale = 0;
1503 bool noerr;
1505
1506 jspGetLeftArg(jsp, &elem);
1507 if (elem.type != jpiNumeric)
1508 elog(ERROR, "invalid jsonpath item type for .decimal() precision");
1509
1510 precision = numeric_int4_safe(jspGetNumeric(&elem),
1511 (Node *) &escontext);
1512 if (escontext.error_occurred)
1515 errmsg("precision of jsonpath item method .%s() is out of range for type integer",
1516 jspOperationName(jsp->type)))));
1517
1518 if (jsp->content.args.right)
1519 {
1520 jspGetRightArg(jsp, &elem);
1521 if (elem.type != jpiNumeric)
1522 elog(ERROR, "invalid jsonpath item type for .decimal() scale");
1523
1525 (Node *) &escontext);
1526 if (escontext.error_occurred)
1529 errmsg("scale of jsonpath item method .%s() is out of range for type integer",
1530 jspOperationName(jsp->type)))));
1531 }
1532
1533 /* Pack the precision and scale into a numeric typmod */
1535 jspThrowErrors(cxt) ? NULL : (Node *) &escontext);
1536 if (escontext.error_occurred)
1537 return jperError;
1538
1539 /* Convert numstr to Numeric with typmod */
1540 Assert(numstr != NULL);
1543 (Node *) &escontext,
1544 &numdatum);
1545
1546 if (!noerr || escontext.error_occurred)
1549 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1550 numstr, jspOperationName(jsp->type), "numeric"))));
1551
1553 }
1554
1555 jbv.type = jbvNumeric;
1556 jbv.val.numeric = num;
1557
1558 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1559 }
1560 break;
1561
1562 case jpiInteger:
1563 {
1565 Datum datum;
1566
1567 if (unwrap && JsonbType(jb) == jbvArray)
1568 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1569 false);
1570
1571 if (jb->type == jbvNumeric)
1572 {
1573 int32 val;
1575
1576 val = numeric_int4_safe(jb->val.numeric,
1577 (Node *) &escontext);
1578 if (escontext.error_occurred)
1581 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1583 NumericGetDatum(jb->val.numeric))),
1584 jspOperationName(jsp->type), "integer"))));
1585
1586 datum = Int32GetDatum(val);
1587 res = jperOk;
1588 }
1589 else if (jb->type == jbvString)
1590 {
1591 /* cast string as integer */
1592 char *tmp = pnstrdup(jb->val.string.val,
1593 jb->val.string.len);
1595 bool noerr;
1596
1598 InvalidOid, -1,
1599 (Node *) &escontext,
1600 &datum);
1601
1602 if (!noerr || escontext.error_occurred)
1605 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1606 tmp, jspOperationName(jsp->type), "integer"))));
1607 res = jperOk;
1608 }
1609
1610 if (res == jperNotFound)
1613 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1614 jspOperationName(jsp->type)))));
1615
1616 jbv.type = jbvNumeric;
1618 datum));
1619
1620 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1621 }
1622 break;
1623
1624 case jpiStringFunc:
1625 {
1627 char *tmp = NULL;
1628
1629 if (unwrap && JsonbType(jb) == jbvArray)
1630 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1631
1632 switch (JsonbType(jb))
1633 {
1634 case jbvString:
1635
1636 /*
1637 * Value is not necessarily null-terminated, so we do
1638 * pnstrdup() here.
1639 */
1640 tmp = pnstrdup(jb->val.string.val,
1641 jb->val.string.len);
1642 break;
1643 case jbvNumeric:
1645 NumericGetDatum(jb->val.numeric)));
1646 break;
1647 case jbvBool:
1648 tmp = (jb->val.boolean) ? "true" : "false";
1649 break;
1650 case jbvDatetime:
1651 {
1652 char buf[MAXDATELEN + 1];
1653
1655 jb->val.datetime.value,
1656 jb->val.datetime.typid,
1657 &jb->val.datetime.tz);
1658 tmp = pstrdup(buf);
1659 }
1660 break;
1661 case jbvNull:
1662 case jbvArray:
1663 case jbvObject:
1664 case jbvBinary:
1667 errmsg("jsonpath item method .%s() can only be applied to a boolean, string, numeric, or datetime value",
1668 jspOperationName(jsp->type)))));
1669 break;
1670 }
1671
1672 Assert(tmp != NULL); /* We must have set tmp above */
1673 jbv.val.string.val = tmp;
1674 jbv.val.string.len = strlen(jbv.val.string.val);
1675 jbv.type = jbvString;
1676
1677 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1678 }
1679 break;
1680
1681 case jpiStrReplace:
1682 case jpiStrLower:
1683 case jpiStrUpper:
1684 case jpiStrLtrim:
1685 case jpiStrRtrim:
1686 case jpiStrBtrim:
1687 case jpiStrInitcap:
1688 case jpiStrSplitPart:
1689 {
1690 if (unwrap && JsonbType(jb) == jbvArray)
1691 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1692
1693 return executeStringInternalMethod(cxt, jsp, jb, found);
1694 }
1695 break;
1696
1697 default:
1698 elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
1699 }
1700
1701 return res;
1702}
1703
1704/*
1705 * Unwrap current array item and execute jsonpath for each of its elements.
1706 */
1707static JsonPathExecResult
1709 JsonbValue *jb, JsonValueList *found,
1710 bool unwrapElements)
1711{
1712 if (jb->type != jbvBinary)
1713 {
1714 Assert(jb->type != jbvArray);
1715 elog(ERROR, "invalid jsonb array value type: %d", jb->type);
1716 }
1717
1718 return executeAnyItem
1719 (cxt, jsp, jb->val.binary.data, found, 1, 1, 1,
1720 false, unwrapElements);
1721}
1722
1723/*
1724 * Execute next jsonpath item if exists. Otherwise put "v" to the "found"
1725 * list if provided.
1726 */
1727static JsonPathExecResult
1730 JsonbValue *v, JsonValueList *found)
1731{
1732 JsonPathItem elem;
1733 bool hasNext;
1734
1735 if (!cur)
1736 hasNext = next != NULL;
1737 else if (next)
1739 else
1740 {
1741 next = &elem;
1743 }
1744
1745 if (hasNext)
1746 return executeItem(cxt, next, v, found);
1747
1748 if (found)
1749 JsonValueListAppend(found, v);
1750
1751 return jperOk;
1752}
1753
1754/*
1755 * Same as executeItem(), but when "unwrap == true" automatically unwraps
1756 * each array item from the resulting sequence in lax mode.
1757 */
1758static JsonPathExecResult
1760 JsonbValue *jb, bool unwrap,
1761 JsonValueList *found)
1762{
1763 if (unwrap && jspAutoUnwrap(cxt))
1764 {
1768 JsonbValue *item;
1769
1771
1772 res = executeItem(cxt, jsp, jb, &seq);
1773
1774 if (jperIsError(res))
1775 {
1777 return res;
1778 }
1779
1781 while ((item = JsonValueListNext(&it)))
1782 {
1783 Assert(item->type != jbvArray);
1784
1785 if (JsonbType(item) == jbvArray)
1786 executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
1787 else
1788 JsonValueListAppend(found, item);
1789 }
1790
1792
1793 return jperOk;
1794 }
1795
1796 return executeItem(cxt, jsp, jb, found);
1797}
1798
1799/*
1800 * Same as executeItemOptUnwrapResult(), but with error suppression.
1801 */
1802static JsonPathExecResult
1805 JsonbValue *jb, bool unwrap,
1806 JsonValueList *found)
1807{
1809 bool throwErrors = cxt->throwErrors;
1810
1811 cxt->throwErrors = false;
1812 res = executeItemOptUnwrapResult(cxt, jsp, jb, unwrap, found);
1813 cxt->throwErrors = throwErrors;
1814
1815 return res;
1816}
1817
1818/* Execute boolean-valued jsonpath expression. */
1819static JsonPathBool
1821 JsonbValue *jb, bool canHaveNext)
1822{
1823 JsonPathItem larg;
1824 JsonPathItem rarg;
1825 JsonPathBool res;
1827
1828 /* since this function recurses, it could be driven to stack overflow */
1830
1831 if (!canHaveNext && jspHasNext(jsp))
1832 elog(ERROR, "boolean jsonpath item cannot have next item");
1833
1834 switch (jsp->type)
1835 {
1836 case jpiAnd:
1837 jspGetLeftArg(jsp, &larg);
1838 res = executeBoolItem(cxt, &larg, jb, false);
1839
1840 if (res == jpbFalse)
1841 return jpbFalse;
1842
1843 /*
1844 * SQL/JSON says that we should check second arg in case of
1845 * jperError
1846 */
1847
1848 jspGetRightArg(jsp, &rarg);
1849 res2 = executeBoolItem(cxt, &rarg, jb, false);
1850
1851 return res2 == jpbTrue ? res : res2;
1852
1853 case jpiOr:
1854 jspGetLeftArg(jsp, &larg);
1855 res = executeBoolItem(cxt, &larg, jb, false);
1856
1857 if (res == jpbTrue)
1858 return jpbTrue;
1859
1860 jspGetRightArg(jsp, &rarg);
1861 res2 = executeBoolItem(cxt, &rarg, jb, false);
1862
1863 return res2 == jpbFalse ? res : res2;
1864
1865 case jpiNot:
1866 jspGetArg(jsp, &larg);
1867
1868 res = executeBoolItem(cxt, &larg, jb, false);
1869
1870 if (res == jpbUnknown)
1871 return jpbUnknown;
1872
1873 return res == jpbTrue ? jpbFalse : jpbTrue;
1874
1875 case jpiIsUnknown:
1876 jspGetArg(jsp, &larg);
1877 res = executeBoolItem(cxt, &larg, jb, false);
1878 return res == jpbUnknown ? jpbTrue : jpbFalse;
1879
1880 case jpiEqual:
1881 case jpiNotEqual:
1882 case jpiLess:
1883 case jpiGreater:
1884 case jpiLessOrEqual:
1885 case jpiGreaterOrEqual:
1886 jspGetLeftArg(jsp, &larg);
1887 jspGetRightArg(jsp, &rarg);
1888 return executePredicate(cxt, jsp, &larg, &rarg, jb, true,
1889 executeComparison, cxt);
1890
1891 case jpiStartsWith: /* 'whole STARTS WITH initial' */
1892 jspGetLeftArg(jsp, &larg); /* 'whole' */
1893 jspGetRightArg(jsp, &rarg); /* 'initial' */
1894 return executePredicate(cxt, jsp, &larg, &rarg, jb, false,
1896
1897 case jpiLikeRegex: /* 'expr LIKE_REGEX pattern FLAGS flags' */
1898 {
1899 /*
1900 * 'expr' is a sequence-returning expression. 'pattern' is a
1901 * regex string literal. SQL/JSON standard requires XQuery
1902 * regexes, but we use Postgres regexes here. 'flags' is a
1903 * string literal converted to integer flags at compile-time.
1904 */
1906
1907 jspInitByBuffer(&larg, jsp->base,
1908 jsp->content.like_regex.expr);
1909
1910 return executePredicate(cxt, jsp, &larg, NULL, jb, false,
1912 }
1913
1914 case jpiExists:
1915 jspGetArg(jsp, &larg);
1916
1917 if (jspStrictAbsenceOfErrors(cxt))
1918 {
1919 /*
1920 * In strict mode we must get a complete list of values to
1921 * check that there are no errors at all.
1922 */
1923 JsonValueList vals;
1925 bool isempty;
1926
1927 JsonValueListInit(&vals);
1928
1929 res = executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1930 false, &vals);
1931
1933 JsonValueListClear(&vals);
1934
1935 if (jperIsError(res))
1936 return jpbUnknown;
1937
1938 return isempty ? jpbFalse : jpbTrue;
1939 }
1940 else
1941 {
1942 JsonPathExecResult res =
1944 false, NULL);
1945
1946 if (jperIsError(res))
1947 return jpbUnknown;
1948
1949 return res == jperOk ? jpbTrue : jpbFalse;
1950 }
1951
1952 default:
1953 elog(ERROR, "invalid boolean jsonpath item type: %d", jsp->type);
1954 return jpbUnknown;
1955 }
1956}
1957
1958/*
1959 * Execute nested (filters etc.) boolean expression pushing current SQL/JSON
1960 * item onto the stack.
1961 */
1962static JsonPathBool
1964 JsonbValue *jb)
1965{
1966 JsonbValue *prev;
1967 JsonPathBool res;
1968
1969 prev = cxt->current;
1970 cxt->current = jb;
1971 res = executeBoolItem(cxt, jsp, jb, false);
1972 cxt->current = prev;
1973
1974 return res;
1975}
1976
1977/*
1978 * Implementation of several jsonpath nodes:
1979 * - jpiAny (.** accessor),
1980 * - jpiAnyKey (.* accessor),
1981 * - jpiAnyArray ([*] accessor)
1982 */
1983static JsonPathExecResult
1985 JsonValueList *found, uint32 level, uint32 first, uint32 last,
1986 bool ignoreStructuralErrors, bool unwrapNext)
1987{
1990 int32 r;
1991 JsonbValue v;
1992
1994
1995 if (level > last)
1996 return res;
1997
1998 it = JsonbIteratorInit(jbc);
1999
2000 /*
2001 * Recursively iterate over jsonb objects/arrays
2002 */
2003 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
2004 {
2005 if (r == WJB_KEY)
2006 {
2007 r = JsonbIteratorNext(&it, &v, true);
2008 Assert(r == WJB_VALUE);
2009 }
2010
2011 if (r == WJB_VALUE || r == WJB_ELEM)
2012 {
2013
2014 if (level >= first ||
2015 (first == PG_UINT32_MAX && last == PG_UINT32_MAX &&
2016 v.type != jbvBinary)) /* leaves only requested */
2017 {
2018 /* check expression */
2019 if (jsp)
2020 {
2021 if (ignoreStructuralErrors)
2022 {
2024
2026 cxt->ignoreStructuralErrors = true;
2027 res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
2029 }
2030 else
2031 res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
2032
2033 if (jperIsError(res))
2034 break;
2035
2036 if (res == jperOk && !found)
2037 break;
2038 }
2039 else if (found)
2040 JsonValueListAppend(found, &v);
2041 else
2042 return jperOk;
2043 }
2044
2045 if (level < last && v.type == jbvBinary)
2046 {
2047 res = executeAnyItem
2048 (cxt, jsp, v.val.binary.data, found,
2049 level + 1, first, last,
2050 ignoreStructuralErrors, unwrapNext);
2051
2052 if (jperIsError(res))
2053 break;
2054
2055 if (res == jperOk && found == NULL)
2056 break;
2057 }
2058 }
2059 }
2060
2061 return res;
2062}
2063
2064/*
2065 * Execute unary or binary predicate.
2066 *
2067 * Predicates have existence semantics, because their operands are item
2068 * sequences. Pairs of items from the left and right operand's sequences are
2069 * checked. TRUE returned only if any pair satisfying the condition is found.
2070 * In strict mode, even if the desired pair has already been found, all pairs
2071 * still need to be examined to check the absence of errors. If any error
2072 * occurs, UNKNOWN (analogous to SQL NULL) is returned.
2073 */
2074static JsonPathBool
2076 JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb,
2078 void *param)
2079{
2084 JsonbValue *lval;
2085 bool error = false;
2086 bool found = false;
2087
2090
2091 /* Left argument is always auto-unwrapped. */
2092 res = executeItemOptUnwrapResultNoThrow(cxt, larg, jb, true, &lseq);
2093 if (jperIsError(res))
2094 {
2095 error = true;
2096 goto exit;
2097 }
2098
2099 if (rarg)
2100 {
2101 /* Right argument is conditionally auto-unwrapped. */
2102 res = executeItemOptUnwrapResultNoThrow(cxt, rarg, jb,
2104 if (jperIsError(res))
2105 {
2106 error = true;
2107 goto exit;
2108 }
2109 }
2110
2112 while ((lval = JsonValueListNext(&lseqit)))
2113 {
2116 bool first = true;
2117
2119 if (rarg)
2121 else
2122 rval = NULL;
2123
2124 /* Loop over right arg sequence or do single pass otherwise */
2125 while (rarg ? (rval != NULL) : first)
2126 {
2127 JsonPathBool res = exec(pred, lval, rval, param);
2128
2129 if (res == jpbUnknown)
2130 {
2131 error = true;
2132 if (jspStrictAbsenceOfErrors(cxt))
2133 {
2134 found = false; /* return unknown, not success */
2135 goto exit;
2136 }
2137 }
2138 else if (res == jpbTrue)
2139 {
2140 found = true;
2141 if (!jspStrictAbsenceOfErrors(cxt))
2142 goto exit;
2143 }
2144
2145 first = false;
2146 if (rarg)
2148 }
2149 }
2150
2151exit:
2154
2155 if (found) /* possible only in strict mode */
2156 return jpbTrue;
2157
2158 if (error) /* possible only in lax mode */
2159 return jpbUnknown;
2160
2161 return jpbFalse;
2162}
2163
2164/*
2165 * Execute binary arithmetic expression on singleton numeric operands.
2166 * Array operands are automatically unwrapped in lax mode.
2167 */
2168static JsonPathExecResult
2171 JsonValueList *found)
2172{
2174 JsonPathItem elem;
2177 JsonbValue *lval;
2180 Numeric res;
2181
2184
2185 jspGetLeftArg(jsp, &elem);
2186
2187 /*
2188 * XXX: By standard only operands of multiplicative expressions are
2189 * unwrapped. We extend it to other binary arithmetic expressions too.
2190 */
2191 jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &lseq);
2192 if (jperIsError(jper))
2193 {
2196 return jper;
2197 }
2198
2199 jspGetRightArg(jsp, &elem);
2200
2201 jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &rseq);
2202 if (jperIsError(jper))
2203 {
2206 return jper;
2207 }
2208
2211 {
2216 errmsg("left operand of jsonpath operator %s is not a single numeric value",
2217 jspOperationName(jsp->type)))));
2218 }
2219
2222 {
2227 errmsg("right operand of jsonpath operator %s is not a single numeric value",
2228 jspOperationName(jsp->type)))));
2229 }
2230
2231 if (jspThrowErrors(cxt))
2232 {
2233 res = func(lval->val.numeric, rval->val.numeric, NULL);
2234 }
2235 else
2236 {
2238
2239 res = func(lval->val.numeric, rval->val.numeric, (Node *) &escontext);
2240
2241 if (escontext.error_occurred)
2242 {
2245 return jperError;
2246 }
2247 }
2248
2251
2252 if (!jspGetNext(jsp, &elem) && !found)
2253 return jperOk;
2254
2255 resval.type = jbvNumeric;
2256 resval.val.numeric = res;
2257
2258 return executeNextItem(cxt, jsp, &elem, &resval, found);
2259}
2260
2261/*
2262 * Execute unary arithmetic expression for each numeric item in its operand's
2263 * sequence. Array operand is automatically unwrapped in lax mode.
2264 */
2265static JsonPathExecResult
2267 JsonbValue *jb, PGFunction func, JsonValueList *found)
2268{
2271 JsonPathItem elem;
2274 JsonbValue *val;
2275 bool hasNext;
2276
2278
2279 jspGetArg(jsp, &elem);
2280 jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &seq);
2281
2282 if (jperIsError(jper))
2283 goto exit;
2284
2286
2287 hasNext = jspGetNext(jsp, &elem);
2288
2290 while ((val = JsonValueListNext(&it)))
2291 {
2292 if ((val = getScalar(val, jbvNumeric)))
2293 {
2294 if (!found && !hasNext)
2295 {
2296 jper = jperOk;
2297 goto exit;
2298 }
2299 }
2300 else
2301 {
2302 if (!found && !hasNext)
2303 continue; /* skip non-numerics processing */
2304
2308 errmsg("operand of unary jsonpath operator %s is not a numeric value",
2309 jspOperationName(jsp->type)))));
2310 }
2311
2312 if (func)
2313 val->val.numeric =
2315 NumericGetDatum(val->val.numeric)));
2316
2317 jper2 = executeNextItem(cxt, jsp, &elem, val, found);
2318
2319 if (jperIsError(jper2))
2320 {
2321 jper = jper2;
2322 goto exit;
2323 }
2324
2325 if (jper2 == jperOk)
2326 {
2327 jper = jperOk;
2328 if (!found)
2329 goto exit;
2330 }
2331 }
2332
2333exit:
2335
2336 return jper;
2337}
2338
2339/*
2340 * STARTS_WITH predicate callback.
2341 *
2342 * Check if the 'whole' string starts from 'initial' string.
2343 */
2344static JsonPathBool
2346 void *param)
2347{
2348 if (!(whole = getScalar(whole, jbvString)))
2349 return jpbUnknown; /* error */
2350
2352 return jpbUnknown; /* error */
2353
2354 if (whole->val.string.len >= initial->val.string.len &&
2355 !memcmp(whole->val.string.val,
2356 initial->val.string.val,
2357 initial->val.string.len))
2358 return jpbTrue;
2359
2360 return jpbFalse;
2361}
2362
2363/*
2364 * LIKE_REGEX predicate callback.
2365 *
2366 * Check if the string matches regex pattern.
2367 */
2368static JsonPathBool
2370 void *param)
2371{
2372 JsonLikeRegexContext *cxt = param;
2373
2374 if (!(str = getScalar(str, jbvString)))
2375 return jpbUnknown;
2376
2377 /* Cache regex text and converted flags. */
2378 if (!cxt->regex)
2379 {
2380 cxt->regex =
2381 cstring_to_text_with_len(jsp->content.like_regex.pattern,
2382 jsp->content.like_regex.patternlen);
2383 (void) jspConvertRegexFlags(jsp->content.like_regex.flags,
2384 &(cxt->cflags), NULL);
2385 }
2386
2387 if (RE_compile_and_execute(cxt->regex, str->val.string.val,
2388 str->val.string.len,
2390 return jpbTrue;
2391
2392 return jpbFalse;
2393}
2394
2395/*
2396 * Execute numeric item methods (.abs(), .floor(), .ceil()) using the specified
2397 * user function 'func'.
2398 */
2399static JsonPathExecResult
2401 JsonbValue *jb, bool unwrap, PGFunction func,
2402 JsonValueList *found)
2403{
2405 Datum datum;
2407
2408 if (unwrap && JsonbType(jb) == jbvArray)
2409 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
2410
2411 if (!(jb = getScalar(jb, jbvNumeric)))
2414 errmsg("jsonpath item method .%s() can only be applied to a numeric value",
2415 jspOperationName(jsp->type)))));
2416
2417 datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
2418
2419 if (!jspGetNext(jsp, &next) && !found)
2420 return jperOk;
2421
2422 jbv.type = jbvNumeric;
2423 jbv.val.numeric = DatumGetNumeric(datum);
2424
2425 return executeNextItem(cxt, jsp, &next, &jbv, found);
2426}
2427
2428/*
2429 * Implementation of the .datetime() and related methods.
2430 *
2431 * Converts a string into a date/time value. The actual type is determined at
2432 * run time.
2433 * If an argument is provided, this argument is used as a template string.
2434 * Otherwise, the first fitting ISO format is selected.
2435 *
2436 * .date(), .time(), .time_tz(), .timestamp(), .timestamp_tz() methods don't
2437 * have a format, so ISO format is used. However, except for .date(), they all
2438 * take an optional time precision.
2439 */
2440static JsonPathExecResult
2442 JsonbValue *jb, JsonValueList *found)
2443{
2445 Datum value;
2446 text *datetime;
2447 Oid collid;
2448 Oid typid;
2449 int32 typmod = -1;
2450 int tz = 0;
2451 bool hasNext;
2453 JsonPathItem elem;
2454 int32 time_precision = -1;
2455
2456 if (!(jb = getScalar(jb, jbvString)))
2459 errmsg("jsonpath item method .%s() can only be applied to a string",
2460 jspOperationName(jsp->type)))));
2461
2462 datetime = cstring_to_text_with_len(jb->val.string.val,
2463 jb->val.string.len);
2464
2465 /*
2466 * At some point we might wish to have callers supply the collation to
2467 * use, but right now it's unclear that they'd be able to do better than
2468 * DEFAULT_COLLATION_OID anyway.
2469 */
2471
2472 /*
2473 * .datetime(template) has an argument, the rest of the methods don't have
2474 * an argument. So we handle that separately.
2475 */
2476 if (jsp->type == jpiDatetime && jsp->content.arg)
2477 {
2478 text *template;
2479 char *template_str;
2480 int template_len;
2482
2483 jspGetArg(jsp, &elem);
2484
2485 if (elem.type != jpiString)
2486 elog(ERROR, "invalid jsonpath item type for .datetime() argument");
2487
2489
2491 template_len);
2492
2493 value = parse_datetime(datetime, template, collid, true,
2494 &typid, &typmod, &tz,
2495 jspThrowErrors(cxt) ? NULL : (Node *) &escontext);
2496
2497 if (escontext.error_occurred)
2498 res = jperError;
2499 else
2500 res = jperOk;
2501 }
2502 else
2503 {
2504 /*
2505 * According to SQL/JSON standard enumerate ISO formats for: date,
2506 * timetz, time, timestamptz, timestamp.
2507 *
2508 * We also support ISO 8601 format (with "T") for timestamps, because
2509 * to_json[b]() functions use this format.
2510 */
2511 static const char *fmt_str[] =
2512 {
2513 "yyyy-mm-dd", /* date */
2514 "HH24:MI:SS.USTZ", /* timetz */
2515 "HH24:MI:SSTZ",
2516 "HH24:MI:SS.US", /* time without tz */
2517 "HH24:MI:SS",
2518 "yyyy-mm-dd HH24:MI:SS.USTZ", /* timestamptz */
2519 "yyyy-mm-dd HH24:MI:SSTZ",
2520 "yyyy-mm-dd\"T\"HH24:MI:SS.USTZ",
2521 "yyyy-mm-dd\"T\"HH24:MI:SSTZ",
2522 "yyyy-mm-dd HH24:MI:SS.US", /* timestamp without tz */
2523 "yyyy-mm-dd HH24:MI:SS",
2524 "yyyy-mm-dd\"T\"HH24:MI:SS.US",
2525 "yyyy-mm-dd\"T\"HH24:MI:SS"
2526 };
2527
2528 /* cache for format texts */
2529 static text *fmt_txt[lengthof(fmt_str)] = {0};
2530
2531 /*
2532 * Check for optional precision for methods other than .datetime() and
2533 * .date()
2534 */
2535 if (jsp->type != jpiDatetime && jsp->type != jpiDate &&
2536 jsp->content.arg)
2537 {
2539
2540 jspGetArg(jsp, &elem);
2541
2542 if (elem.type != jpiNumeric)
2543 elog(ERROR, "invalid jsonpath item type for %s argument",
2544 jspOperationName(jsp->type));
2545
2547 (Node *) &escontext);
2548 if (escontext.error_occurred)
2551 errmsg("time precision of jsonpath item method .%s() is out of range for type integer",
2552 jspOperationName(jsp->type)))));
2553 }
2554
2555 /* loop until datetime format fits */
2556 for (size_t i = 0; i < lengthof(fmt_str); i++)
2557 {
2559
2560 if (!fmt_txt[i])
2561 {
2564
2567 }
2568
2569 value = parse_datetime(datetime, fmt_txt[i], collid, true,
2570 &typid, &typmod, &tz,
2571 (Node *) &escontext);
2572
2573 if (!escontext.error_occurred)
2574 {
2575 res = jperOk;
2576 break;
2577 }
2578 }
2579
2580 if (res == jperNotFound)
2581 {
2582 if (jsp->type == jpiDatetime)
2585 errmsg("%s format is not recognized: \"%s\"",
2586 "datetime", text_to_cstring(datetime)),
2587 errhint("Use a datetime template argument to specify the input data format."))));
2588 else
2591 errmsg("%s format is not recognized: \"%s\"",
2592 jspOperationName(jsp->type), text_to_cstring(datetime)))));
2593
2594 }
2595 }
2596
2597 /*
2598 * parse_datetime() processes the entire input string per the template or
2599 * ISO format and returns the Datum in best fitted datetime type. So, if
2600 * this call is for a specific datatype, then we do the conversion here.
2601 * Throw an error for incompatible types.
2602 */
2603 switch (jsp->type)
2604 {
2605 case jpiDatetime: /* Nothing to do for DATETIME */
2606 break;
2607 case jpiDate:
2608 {
2609 /* Convert result type to date */
2610 switch (typid)
2611 {
2612 case DATEOID: /* Nothing to do for DATE */
2613 break;
2614 case TIMEOID:
2615 case TIMETZOID:
2618 errmsg("%s format is not recognized: \"%s\"",
2619 "date", text_to_cstring(datetime)))));
2620 break;
2621 case TIMESTAMPOID:
2623 value);
2624 break;
2625 case TIMESTAMPTZOID:
2627 "timestamptz", "date");
2629 value);
2630 break;
2631 default:
2632 elog(ERROR, "type with oid %u not supported", typid);
2633 }
2634
2635 typid = DATEOID;
2636 }
2637 break;
2638 case jpiTime:
2639 {
2640 /* Convert result type to time without time zone */
2641 switch (typid)
2642 {
2643 case DATEOID:
2646 errmsg("%s format is not recognized: \"%s\"",
2647 "time", text_to_cstring(datetime)))));
2648 break;
2649 case TIMEOID: /* Nothing to do for TIME */
2650 break;
2651 case TIMETZOID:
2653 "timetz", "time");
2655 value);
2656 break;
2657 case TIMESTAMPOID:
2659 value);
2660 break;
2661 case TIMESTAMPTZOID:
2663 "timestamptz", "time");
2665 value);
2666 break;
2667 default:
2668 elog(ERROR, "type with oid %u not supported", typid);
2669 }
2670
2671 /* Force the user-given time precision, if any */
2672 if (time_precision != -1)
2673 {
2675
2676 /* Get a warning when precision is reduced */
2682
2683 /* Update the typmod value with the user-given precision */
2684 typmod = time_precision;
2685 }
2686
2687 typid = TIMEOID;
2688 }
2689 break;
2690 case jpiTimeTz:
2691 {
2692 /* Convert result type to time with time zone */
2693 switch (typid)
2694 {
2695 case DATEOID:
2696 case TIMESTAMPOID:
2699 errmsg("%s format is not recognized: \"%s\"",
2700 "time_tz", text_to_cstring(datetime)))));
2701 break;
2702 case TIMEOID:
2704 "time", "timetz");
2706 value);
2707 break;
2708 case TIMETZOID: /* Nothing to do for TIMETZ */
2709 break;
2710 case TIMESTAMPTZOID:
2712 value);
2713 break;
2714 default:
2715 elog(ERROR, "type with oid %u not supported", typid);
2716 }
2717
2718 /* Force the user-given time precision, if any */
2719 if (time_precision != -1)
2720 {
2722
2723 /* Get a warning when precision is reduced */
2729
2730 /* Update the typmod value with the user-given precision */
2731 typmod = time_precision;
2732 }
2733
2734 typid = TIMETZOID;
2735 }
2736 break;
2737 case jpiTimestamp:
2738 {
2739 /* Convert result type to timestamp without time zone */
2740 switch (typid)
2741 {
2742 case DATEOID:
2744 value);
2745 break;
2746 case TIMEOID:
2747 case TIMETZOID:
2750 errmsg("%s format is not recognized: \"%s\"",
2751 "timestamp", text_to_cstring(datetime)))));
2752 break;
2753 case TIMESTAMPOID: /* Nothing to do for TIMESTAMP */
2754 break;
2755 case TIMESTAMPTZOID:
2757 "timestamptz", "timestamp");
2759 value);
2760 break;
2761 default:
2762 elog(ERROR, "type with oid %u not supported", typid);
2763 }
2764
2765 /* Force the user-given time precision, if any */
2766 if (time_precision != -1)
2767 {
2770
2771 /* Get a warning when precision is reduced */
2776 (Node *) &escontext);
2777 if (escontext.error_occurred) /* should not happen */
2780 errmsg("time precision of jsonpath item method .%s() is invalid",
2781 jspOperationName(jsp->type)))));
2783
2784 /* Update the typmod value with the user-given precision */
2785 typmod = time_precision;
2786 }
2787
2788 typid = TIMESTAMPOID;
2789 }
2790 break;
2791 case jpiTimestampTz:
2792 {
2793 struct pg_tm tm;
2794 fsec_t fsec;
2795
2796 /* Convert result type to timestamp with time zone */
2797 switch (typid)
2798 {
2799 case DATEOID:
2801 "date", "timestamptz");
2802
2803 /*
2804 * Get the timezone value explicitly since JsonbValue
2805 * keeps that separate.
2806 */
2808 &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
2809 tm.tm_hour = 0;
2810 tm.tm_min = 0;
2811 tm.tm_sec = 0;
2813
2815 value);
2816 break;
2817 case TIMEOID:
2818 case TIMETZOID:
2821 errmsg("%s format is not recognized: \"%s\"",
2822 "timestamp_tz", text_to_cstring(datetime)))));
2823 break;
2824 case TIMESTAMPOID:
2826 "timestamp", "timestamptz");
2827
2828 /*
2829 * Get the timezone value explicitly since JsonbValue
2830 * keeps that separate.
2831 */
2833 &fsec, NULL, NULL) == 0)
2836
2838 value);
2839 break;
2840 case TIMESTAMPTZOID: /* Nothing to do for TIMESTAMPTZ */
2841 break;
2842 default:
2843 elog(ERROR, "type with oid %u not supported", typid);
2844 }
2845
2846 /* Force the user-given time precision, if any */
2847 if (time_precision != -1)
2848 {
2851
2852 /* Get a warning when precision is reduced */
2857 (Node *) &escontext);
2858 if (escontext.error_occurred) /* should not happen */
2861 errmsg("time precision of jsonpath item method .%s() is invalid",
2862 jspOperationName(jsp->type)))));
2864
2865 /* Update the typmod value with the user-given precision */
2866 typmod = time_precision;
2867 }
2868
2869 typid = TIMESTAMPTZOID;
2870 }
2871 break;
2872 default:
2873 elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
2874 }
2875
2876 pfree(datetime);
2877
2878 if (jperIsError(res))
2879 return res;
2880
2881 hasNext = jspGetNext(jsp, &elem);
2882
2883 if (!hasNext && !found)
2884 return res;
2885
2886 jbv.type = jbvDatetime;
2887 jbv.val.datetime.value = value;
2888 jbv.val.datetime.typid = typid;
2889 jbv.val.datetime.typmod = typmod;
2890 jbv.val.datetime.tz = tz;
2891
2892 return executeNextItem(cxt, jsp, &elem, &jbv, found);
2893}
2894
2895/*
2896 * Implementation of .upper(), .lower() et al. string methods,
2897 * that forward their actual implementation to internal functions.
2898 */
2899static JsonPathExecResult
2901 JsonbValue *jb, JsonValueList *found)
2902{
2904 bool hasNext;
2906 JsonPathItem elem;
2907 Datum str; /* Datum representation for the current string
2908 * value. The first argument to internal
2909 * functions */
2910 char *resStr = NULL;
2911
2912 Assert(jsp->type == jpiStrReplace ||
2913 jsp->type == jpiStrLower ||
2914 jsp->type == jpiStrUpper ||
2915 jsp->type == jpiStrLtrim ||
2916 jsp->type == jpiStrRtrim ||
2917 jsp->type == jpiStrBtrim ||
2918 jsp->type == jpiStrInitcap ||
2919 jsp->type == jpiStrSplitPart);
2920
2921 if (!(jb = getScalar(jb, jbvString)))
2924 errmsg("jsonpath item method .%s() can only be applied to a string",
2925 jspOperationName(jsp->type)))));
2926
2927 str = PointerGetDatum(cstring_to_text_with_len(jb->val.string.val, jb->val.string.len));
2928
2929 /* Dispatch to the appropriate internal string function */
2930 switch (jsp->type)
2931 {
2932 case jpiStrReplace:
2933 {
2934 char *from_str,
2935 *to_str;
2936
2937 jspGetLeftArg(jsp, &elem);
2938 if (elem.type != jpiString)
2939 elog(ERROR, "invalid jsonpath item type for .replace() from");
2940
2941 from_str = jspGetString(&elem, NULL);
2942
2943 jspGetRightArg(jsp, &elem);
2944 if (elem.type != jpiString)
2945 elog(ERROR, "invalid jsonpath item type for .replace() to");
2946
2947 to_str = jspGetString(&elem, NULL);
2948
2951 str,
2954 break;
2955 }
2956 case jpiStrLower:
2958 break;
2959 case jpiStrUpper:
2961 break;
2962 case jpiStrLtrim:
2963 case jpiStrRtrim:
2964 case jpiStrBtrim:
2965 {
2968
2969 switch (jsp->type)
2970 {
2971 case jpiStrLtrim:
2972 func1 = ltrim1;
2973 func2 = ltrim;
2974 break;
2975 case jpiStrRtrim:
2976 func1 = rtrim1;
2977 func2 = rtrim;
2978 break;
2979 case jpiStrBtrim:
2980 func1 = btrim1;
2981 func2 = btrim;
2982 break;
2983 default:
2984 break;
2985 }
2986
2987 if (jsp->content.arg)
2988 {
2989 char *characters_str;
2990
2991 jspGetArg(jsp, &elem);
2992 if (elem.type != jpiString)
2993 elog(ERROR, "invalid jsonpath item type for .%s() argument",
2994 jspOperationName(jsp->type));
2995
3000 }
3001 else
3002 {
3005 }
3006 break;
3007 }
3008
3009 case jpiStrInitcap:
3011 break;
3012 case jpiStrSplitPart:
3013 {
3014 char *from_str;
3015 int32 n;
3017
3018 jspGetLeftArg(jsp, &elem);
3019 if (elem.type != jpiString)
3020 elog(ERROR, "invalid jsonpath item type for .split_part()");
3021
3022 from_str = jspGetString(&elem, NULL);
3023
3024 jspGetRightArg(jsp, &elem);
3025 if (elem.type != jpiNumeric)
3026 elog(ERROR, "invalid jsonpath item type for .split_part()");
3027
3029 (Node *) &escontext);
3030 if (escontext.error_occurred)
3033 errmsg("field position of jsonpath item method .%s() is out of range for type integer",
3034 jspOperationName(jsp->type))));
3035
3036 if (n == 0)
3039 errmsg("field position of jsonpath item method .%s() must not be zero",
3040 jspOperationName(jsp->type))));
3041
3044 str,
3046 Int32GetDatum(n)));
3047 break;
3048 }
3049 default:
3050 elog(ERROR, "unsupported jsonpath item type: %d", jsp->type);
3051 }
3052
3053 if (resStr)
3054 res = jperOk;
3055
3056 hasNext = jspGetNext(jsp, &elem);
3057
3058 if (!hasNext && !found)
3059 return res;
3060
3061 jbv.type = jbvString;
3062 jbv.val.string.val = resStr;
3063 jbv.val.string.len = strlen(resStr);
3064
3065 return executeNextItem(cxt, jsp, &elem, &jbv, found);
3066}
3067
3068/*
3069 * Implementation of .keyvalue() method.
3070 *
3071 * .keyvalue() method returns a sequence of object's key-value pairs in the
3072 * following format: '{ "key": key, "value": value, "id": id }'.
3073 *
3074 * "id" field is an object identifier which is constructed from the two parts:
3075 * base object id and its binary offset in base object's jsonb:
3076 * id = 10000000000 * base_object_id + obj_offset_in_base_object
3077 *
3078 * 10000000000 (10^10) -- is a first round decimal number greater than 2^32
3079 * (maximal offset in jsonb). Decimal multiplier is used here to improve the
3080 * readability of identifiers.
3081 *
3082 * Base object is usually a root object of the path: context item '$' or path
3083 * variable '$var', literals can't produce objects for now. But if the path
3084 * contains generated objects (.keyvalue() itself, for example), then they
3085 * become base object for the subsequent .keyvalue().
3086 *
3087 * Id of '$' is 0. Id of '$var' is its ordinal (positive) number in the list
3088 * of variables (see getJsonPathVariable()). Ids for generated objects
3089 * are assigned using global counter JsonPathExecContext.lastGeneratedObjectId.
3090 */
3091static JsonPathExecResult
3093 JsonbValue *jb, JsonValueList *found)
3094{
3097 JsonbContainer *jbc;
3098 JsonbValue key;
3106 int64 id;
3107 bool hasNext;
3108
3109 if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
3112 errmsg("jsonpath item method .%s() can only be applied to an object",
3113 jspOperationName(jsp->type)))));
3114
3115 jbc = jb->val.binary.data;
3116
3117 if (!JsonContainerSize(jbc))
3118 return jperNotFound; /* no key-value pairs */
3119
3121
3122 keystr.type = jbvString;
3123 keystr.val.string.val = "key";
3124 keystr.val.string.len = 3;
3125
3126 valstr.type = jbvString;
3127 valstr.val.string.val = "value";
3128 valstr.val.string.len = 5;
3129
3130 idstr.type = jbvString;
3131 idstr.val.string.val = "id";
3132 idstr.val.string.len = 2;
3133
3134 /* construct object id from its base object and offset inside that */
3135 id = jb->type != jbvBinary ? 0 :
3136 (int64) ((char *) jbc - (char *) cxt->baseObject.jbc);
3137 id += (int64) cxt->baseObject.id * INT64CONST(10000000000);
3138
3139 idval.type = jbvNumeric;
3140 idval.val.numeric = int64_to_numeric(id);
3141
3142 it = JsonbIteratorInit(jbc);
3143
3144 while ((tok = JsonbIteratorNext(&it, &key, true)) != WJB_DONE)
3145 {
3146 JsonBaseObjectInfo baseObject;
3147 JsonbValue obj;
3149 Jsonb *jsonb;
3150
3151 if (tok != WJB_KEY)
3152 continue;
3153
3154 res = jperOk;
3155
3156 if (!hasNext && !found)
3157 break;
3158
3159 tok = JsonbIteratorNext(&it, &val, true);
3160 Assert(tok == WJB_VALUE);
3161
3162 memset(&ps, 0, sizeof(ps));
3163
3165
3167 pushJsonbValue(&ps, WJB_VALUE, &key);
3168
3171
3174
3176
3177 jsonb = JsonbValueToJsonb(ps.result);
3178
3179 JsonbInitBinary(&obj, jsonb);
3180
3181 baseObject = setBaseObject(cxt, &obj, cxt->lastGeneratedObjectId++);
3182
3183 res = executeNextItem(cxt, jsp, &next, &obj, found);
3184
3185 cxt->baseObject = baseObject;
3186
3187 if (jperIsError(res))
3188 return res;
3189
3190 if (res == jperOk && !found)
3191 break;
3192 }
3193
3194 return res;
3195}
3196
3197/*
3198 * Convert boolean execution status 'res' to a boolean JSON item and execute
3199 * next jsonpath.
3200 */
3201static JsonPathExecResult
3203 JsonValueList *found, JsonPathBool res)
3204{
3207
3208 if (!jspGetNext(jsp, &next) && !found)
3209 return jperOk; /* found singleton boolean value */
3210
3211 if (res == jpbUnknown)
3212 {
3213 jbv.type = jbvNull;
3214 }
3215 else
3216 {
3217 jbv.type = jbvBool;
3218 jbv.val.boolean = res == jpbTrue;
3219 }
3220
3221 return executeNextItem(cxt, jsp, &next, &jbv, found);
3222}
3223
3224/*
3225 * Convert jsonpath's scalar or variable node to actual jsonb value.
3226 *
3227 * If node is a variable then its id returned, otherwise 0 returned.
3228 */
3229static void
3232{
3233 switch (item->type)
3234 {
3235 case jpiNull:
3236 value->type = jbvNull;
3237 break;
3238 case jpiBool:
3239 value->type = jbvBool;
3240 value->val.boolean = jspGetBool(item);
3241 break;
3242 case jpiNumeric:
3243 value->type = jbvNumeric;
3244 value->val.numeric = jspGetNumeric(item);
3245 break;
3246 case jpiString:
3247 value->type = jbvString;
3248 value->val.string.val = jspGetString(item,
3249 &value->val.string.len);
3250 break;
3251 case jpiVariable:
3252 getJsonPathVariable(cxt, item, value);
3253 return;
3254 default:
3255 elog(ERROR, "unexpected jsonpath item type");
3256 }
3257}
3258
3259/*
3260 * Returns the computed value of a JSON path variable with given name.
3261 */
3262static JsonbValue *
3263GetJsonPathVar(void *cxt, char *varName, int varNameLen,
3264 JsonbValue *baseObject, int *baseObjectId)
3265{
3266 JsonPathVariable *var = NULL;
3267 List *vars = cxt;
3268 ListCell *lc;
3270 int id = 1;
3271
3272 foreach(lc, vars)
3273 {
3274 JsonPathVariable *curvar = lfirst(lc);
3275
3276 if (curvar->namelen == varNameLen &&
3277 strncmp(curvar->name, varName, varNameLen) == 0)
3278 {
3279 var = curvar;
3280 break;
3281 }
3282
3283 id++;
3284 }
3285
3286 if (var == NULL)
3287 {
3288 *baseObjectId = -1;
3289 return NULL;
3290 }
3291
3293 if (var->isnull)
3294 {
3295 *baseObjectId = 0;
3296 result->type = jbvNull;
3297 }
3298 else
3299 JsonItemFromDatum(var->value, var->typid, var->typmod, result);
3300
3301 *baseObject = *result;
3302 *baseObjectId = id;
3303
3304 return result;
3305}
3306
3307static int
3309{
3310 List *vars = (List *) cxt;
3311
3312 return list_length(vars);
3313}
3314
3315
3316/*
3317 * Initialize JsonbValue to pass to jsonpath executor from given
3318 * datum value of the specified type.
3319 */
3320static void
3322{
3323 switch (typid)
3324 {
3325 case BOOLOID:
3326 res->type = jbvBool;
3327 res->val.boolean = DatumGetBool(val);
3328 break;
3329 case NUMERICOID:
3331 break;
3332 case INT2OID:
3334 break;
3335 case INT4OID:
3337 break;
3338 case INT8OID:
3340 break;
3341 case FLOAT4OID:
3343 break;
3344 case FLOAT8OID:
3346 break;
3347 case TEXTOID:
3348 case VARCHAROID:
3349 res->type = jbvString;
3350 res->val.string.val = VARDATA_ANY(DatumGetPointer(val));
3351 res->val.string.len = VARSIZE_ANY_EXHDR(DatumGetPointer(val));
3352 break;
3353 case DATEOID:
3354 case TIMEOID:
3355 case TIMETZOID:
3356 case TIMESTAMPOID:
3357 case TIMESTAMPTZOID:
3358 res->type = jbvDatetime;
3359 res->val.datetime.value = val;
3360 res->val.datetime.typid = typid;
3361 res->val.datetime.typmod = typmod;
3362 res->val.datetime.tz = 0;
3363 break;
3364 case JSONBOID:
3365 {
3366 JsonbValue *jbv = res;
3368
3369 if (JsonContainerIsScalar(&jb->root))
3370 {
3372
3373 result = JsonbExtractScalar(&jb->root, jbv);
3374 Assert(result);
3375 }
3376 else
3378 break;
3379 }
3380 case JSONOID:
3381 {
3383 char *str = text_to_cstring(txt);
3384 Jsonb *jb;
3385
3388 pfree(str);
3389
3391 break;
3392 }
3393 default:
3394 ereport(ERROR,
3396 errmsg("could not convert value of type %s to jsonpath",
3397 format_type_be(typid)));
3398 }
3399}
3400
3401/* Initialize numeric value from the given datum */
3402static void
3404{
3405 jbv->type = jbvNumeric;
3406 jbv->val.numeric = DatumGetNumeric(num);
3407}
3408
3409/*
3410 * Get the value of variable passed to jsonpath executor
3411 */
3412static void
3415{
3416 char *varName;
3417 int varNameLength;
3418 JsonbValue baseObject;
3419 int baseObjectId;
3420 JsonbValue *v;
3421
3423 varName = jspGetString(variable, &varNameLength);
3424
3425 if (cxt->vars == NULL ||
3426 (v = cxt->getVar(cxt->vars, varName, varNameLength,
3427 &baseObject, &baseObjectId)) == NULL)
3428 ereport(ERROR,
3430 errmsg("could not find jsonpath variable \"%s\"",
3431 pnstrdup(varName, varNameLength))));
3432
3433 if (baseObjectId > 0)
3434 {
3435 *value = *v;
3436 setBaseObject(cxt, &baseObject, baseObjectId);
3437 }
3438}
3439
3440/*
3441 * Definition of JsonPathGetVarCallback for when JsonPathExecContext.vars
3442 * is specified as a jsonb value.
3443 */
3444static JsonbValue *
3446 JsonbValue *baseObject, int *baseObjectId)
3447{
3448 Jsonb *vars = varsJsonb;
3449 JsonbValue tmp;
3451
3452 tmp.type = jbvString;
3453 tmp.val.string.val = varName;
3454 tmp.val.string.len = varNameLength;
3455
3457
3458 if (result == NULL)
3459 {
3460 *baseObjectId = -1;
3461 return NULL;
3462 }
3463
3464 *baseObjectId = 1;
3465 JsonbInitBinary(baseObject, vars);
3466
3467 return result;
3468}
3469
3470/*
3471 * Definition of JsonPathCountVarsCallback for when JsonPathExecContext.vars
3472 * is specified as a jsonb value.
3473 */
3474static int
3476{
3477 Jsonb *vars = varsJsonb;
3478
3479 if (vars && !JsonContainerIsObject(&vars->root))
3480 {
3481 ereport(ERROR,
3483 errmsg("\"vars\" argument is not an object"),
3484 errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object."));
3485 }
3486
3487 /* count of base objects */
3488 return vars != NULL ? 1 : 0;
3489}
3490
3491/**************** Support functions for JsonPath execution *****************/
3492
3493/*
3494 * Returns the size of an array item, or -1 if item is not an array.
3495 */
3496static int
3498{
3499 Assert(jb->type != jbvArray);
3500
3501 if (jb->type == jbvBinary)
3502 {
3503 JsonbContainer *jbc = jb->val.binary.data;
3504
3506 return JsonContainerSize(jbc);
3507 }
3508
3509 return -1;
3510}
3511
3512/* Comparison predicate callback. */
3513static JsonPathBool
3515{
3517
3518 return compareItems(cmp->type, lv, rv, cxt->useTz);
3519}
3520
3521/*
3522 * Perform per-byte comparison of two strings.
3523 */
3524static int
3525binaryCompareStrings(const char *s1, int len1,
3526 const char *s2, int len2)
3527{
3528 int cmp;
3529
3530 cmp = memcmp(s1, s2, Min(len1, len2));
3531
3532 if (cmp != 0)
3533 return cmp;
3534
3535 if (len1 == len2)
3536 return 0;
3537
3538 return len1 < len2 ? -1 : 1;
3539}
3540
3541/*
3542 * Compare two strings in the current server encoding using Unicode codepoint
3543 * collation.
3544 */
3545static int
3547 const char *mbstr2, int mblen2)
3548{
3551 {
3552 /*
3553 * It's known property of UTF-8 strings that their per-byte comparison
3554 * result matches codepoints comparison result. ASCII can be
3555 * considered as special case of UTF-8.
3556 */
3558 }
3559 else
3560 {
3561 char *utf8str1,
3562 *utf8str2;
3563 int cmp,
3564 utf8len1,
3565 utf8len2;
3566
3567 /*
3568 * We have to convert other encodings to UTF-8 first, then compare.
3569 * Input strings may be not null-terminated and pg_server_to_any() may
3570 * return them "as is". So, use strlen() only if there is real
3571 * conversion.
3572 */
3577
3579
3580 /*
3581 * If pg_server_to_any() did no real conversion, then we actually
3582 * compared original strings. So, we already done.
3583 */
3584 if (mbstr1 == utf8str1 && mbstr2 == utf8str2)
3585 return cmp;
3586
3587 /* Free memory if needed */
3588 if (mbstr1 != utf8str1)
3589 pfree(utf8str1);
3590 if (mbstr2 != utf8str2)
3591 pfree(utf8str2);
3592
3593 /*
3594 * When all Unicode codepoints are equal, return result of binary
3595 * comparison. In some edge cases, same characters may have different
3596 * representations in encoding. Then our behavior could diverge from
3597 * standard. However, that allow us to do simple binary comparison
3598 * for "==" operator, which is performance critical in typical cases.
3599 * In future to implement strict standard conformance, we can do
3600 * normalization of input JSON strings.
3601 */
3602 if (cmp == 0)
3604 else
3605 return cmp;
3606 }
3607}
3608
3609/*
3610 * Compare two SQL/JSON items using comparison operation 'op'.
3611 */
3612static JsonPathBool
3614{
3615 int cmp;
3616 bool res;
3617
3618 if (jb1->type != jb2->type)
3619 {
3620 if (jb1->type == jbvNull || jb2->type == jbvNull)
3621
3622 /*
3623 * Equality and order comparison of nulls to non-nulls returns
3624 * always false, but inequality comparison returns true.
3625 */
3626 return op == jpiNotEqual ? jpbTrue : jpbFalse;
3627
3628 /* Non-null items of different types are not comparable. */
3629 return jpbUnknown;
3630 }
3631
3632 switch (jb1->type)
3633 {
3634 case jbvNull:
3635 cmp = 0;
3636 break;
3637 case jbvBool:
3638 cmp = jb1->val.boolean == jb2->val.boolean ? 0 :
3639 jb1->val.boolean ? 1 : -1;
3640 break;
3641 case jbvNumeric:
3642 cmp = compareNumeric(jb1->val.numeric, jb2->val.numeric);
3643 break;
3644 case jbvString:
3645 if (op == jpiEqual)
3646 return jb1->val.string.len != jb2->val.string.len ||
3647 memcmp(jb1->val.string.val,
3648 jb2->val.string.val,
3649 jb1->val.string.len) ? jpbFalse : jpbTrue;
3650
3651 cmp = compareStrings(jb1->val.string.val, jb1->val.string.len,
3652 jb2->val.string.val, jb2->val.string.len);
3653 break;
3654 case jbvDatetime:
3655 {
3656 bool cast_error;
3657
3658 cmp = compareDatetime(jb1->val.datetime.value,
3659 jb1->val.datetime.typid,
3660 jb2->val.datetime.value,
3661 jb2->val.datetime.typid,
3662 useTz,
3663 &cast_error);
3664
3665 if (cast_error)
3666 return jpbUnknown;
3667 }
3668 break;
3669
3670 case jbvBinary:
3671 case jbvArray:
3672 case jbvObject:
3673 return jpbUnknown; /* non-scalars are not comparable */
3674
3675 default:
3676 elog(ERROR, "invalid jsonb value type %d", jb1->type);
3677 }
3678
3679 switch (op)
3680 {
3681 case jpiEqual:
3682 res = (cmp == 0);
3683 break;
3684 case jpiNotEqual:
3685 res = (cmp != 0);
3686 break;
3687 case jpiLess:
3688 res = (cmp < 0);
3689 break;
3690 case jpiGreater:
3691 res = (cmp > 0);
3692 break;
3693 case jpiLessOrEqual:
3694 res = (cmp <= 0);
3695 break;
3696 case jpiGreaterOrEqual:
3697 res = (cmp >= 0);
3698 break;
3699 default:
3700 elog(ERROR, "unrecognized jsonpath operation: %d", op);
3701 return jpbUnknown;
3702 }
3703
3704 return res ? jpbTrue : jpbFalse;
3705}
3706
3707/* Compare two numerics */
3708static int
3715
3716static JsonbValue *
3718{
3720
3721 *dst = *src;
3722
3723 return dst;
3724}
3725
3726/*
3727 * Execute array subscript expression and convert resulting numeric item to
3728 * the integer type with truncation.
3729 */
3730static JsonPathExecResult
3732 int32 *index)
3733{
3734 JsonbValue *jbv;
3735 JsonValueList found;
3739
3740 JsonValueListInit(&found);
3741
3742 res = executeItem(cxt, jsp, jb, &found);
3743
3744 if (jperIsError(res))
3745 {
3746 JsonValueListClear(&found);
3747 return res;
3748 }
3749
3750 if (!JsonValueListIsSingleton(&found) ||
3752 {
3753 JsonValueListClear(&found);
3756 errmsg("jsonpath array subscript is not a single numeric value"))));
3757 }
3758
3760 NumericGetDatum(jbv->val.numeric),
3761 Int32GetDatum(0));
3762
3764 (Node *) &escontext);
3765
3766 JsonValueListClear(&found);
3767
3768 if (escontext.error_occurred)
3771 errmsg("jsonpath array subscript is out of integer range"))));
3772
3773 return jperOk;
3774}
3775
3776/* Save base object and its id needed for the execution of .keyvalue(). */
3777static JsonBaseObjectInfo
3779{
3780 JsonBaseObjectInfo baseObject = cxt->baseObject;
3781
3782 cxt->baseObject.jbc = jbv->type != jbvBinary ? NULL :
3783 (JsonbContainer *) jbv->val.binary.data;
3784 cxt->baseObject.id = id;
3785
3786 return baseObject;
3787}
3788
3789/*
3790 * JsonValueList support functions
3791 */
3792
3793static void
3795{
3796 jvl->nitems = 0;
3797 jvl->maxitems = BASE_JVL_ITEMS;
3798 jvl->next = NULL;
3799 jvl->last = jvl;
3800}
3801
3802static void
3804{
3806
3807 /* Release any extra chunks */
3808 for (JsonValueList *chunk = jvl->next; chunk != NULL; chunk = nxt)
3809 {
3810 nxt = chunk->next;
3811 pfree(chunk);
3812 }
3813 /* ... and reset to empty */
3814 jvl->nitems = 0;
3815 Assert(jvl->maxitems == BASE_JVL_ITEMS);
3816 jvl->next = NULL;
3817 jvl->last = jvl;
3818}
3819
3820static void
3822{
3823 JsonValueList *last = jvl->last;
3824
3825 if (last->nitems < last->maxitems)
3826 {
3827 /* there's still room in the last existing chunk */
3828 last->items[last->nitems] = *jbv;
3829 last->nitems++;
3830 }
3831 else
3832 {
3833 /* need a new last chunk */
3835 int nxtsize;
3836
3837 nxtsize = last->maxitems * 2; /* double the size with each chunk */
3838 nxtsize = Max(nxtsize, MIN_EXTRA_JVL_ITEMS); /* but at least this */
3840 nxtsize * sizeof(JsonbValue));
3841 nxt->nitems = 1;
3842 nxt->maxitems = nxtsize;
3843 nxt->next = NULL;
3844 nxt->items[0] = *jbv;
3845 last->next = nxt;
3846 jvl->last = nxt;
3847 }
3848}
3849
3850static bool
3852{
3853 /* We need not examine extra chunks for this */
3854 return (jvl->nitems == 0);
3855}
3856
3857static bool
3859{
3860#if BASE_JVL_ITEMS > 1
3861 /* We need not examine extra chunks in this case */
3862 return (jvl->nitems == 1);
3863#else
3864 return (jvl->nitems == 1 && jvl->next == NULL);
3865#endif
3866}
3867
3868static bool
3870{
3871#if BASE_JVL_ITEMS > 1
3872 /* We need not examine extra chunks in this case */
3873 return (jvl->nitems > 1);
3874#else
3875 return (jvl->nitems == 1 && jvl->next != NULL);
3876#endif
3877}
3878
3879static JsonbValue *
3881{
3882 Assert(jvl->nitems > 0);
3883 return &jvl->items[0];
3884}
3885
3886/*
3887 * JsonValueListIterator functions
3888 */
3889
3890static void
3892{
3893 it->chunk = jvl;
3894 it->nextitem = 0;
3895}
3896
3897/*
3898 * Get the next item from the sequence advancing iterator.
3899 * Returns NULL if no more items.
3900 */
3901static JsonbValue *
3903{
3904 if (it->chunk == NULL)
3905 return NULL;
3906 if (it->nextitem >= it->chunk->nitems)
3907 {
3908 it->chunk = it->chunk->next;
3909 if (it->chunk == NULL)
3910 return NULL;
3911 it->nextitem = 0;
3912 Assert(it->chunk->nitems > 0);
3913 }
3914 return &it->chunk->items[it->nextitem++];
3915}
3916
3917/*
3918 * Initialize a binary JsonbValue with the given jsonb container.
3919 */
3920static JsonbValue *
3922{
3923 jbv->type = jbvBinary;
3924 jbv->val.binary.data = &jb->root;
3925 jbv->val.binary.len = VARSIZE_ANY_EXHDR(jb);
3926
3927 return jbv;
3928}
3929
3930/*
3931 * Returns jbv* type of JsonbValue. Note, it never returns jbvBinary as is.
3932 */
3933static int
3935{
3936 int type = jb->type;
3937
3938 if (jb->type == jbvBinary)
3939 {
3940 JsonbContainer *jbc = jb->val.binary.data;
3941
3942 /* Scalars should be always extracted during jsonpath execution. */
3944
3945 if (JsonContainerIsObject(jbc))
3946 type = jbvObject;
3947 else if (JsonContainerIsArray(jbc))
3948 type = jbvArray;
3949 else
3950 elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
3951 }
3952
3953 return type;
3954}
3955
3956/* Get scalar of given type or NULL on type mismatch */
3957static JsonbValue *
3959{
3960 /* Scalars should be always extracted during jsonpath execution. */
3961 Assert(scalar->type != jbvBinary ||
3962 !JsonContainerIsScalar(scalar->val.binary.data));
3963
3964 return scalar->type == type ? scalar : NULL;
3965}
3966
3967/* Construct a JSON array from the item list */
3968static JsonbValue *
3970{
3971 JsonbInState ps = {0};
3973 JsonbValue *jbv;
3974
3976
3978 while ((jbv = JsonValueListNext(&it)))
3980
3982
3983 return ps.result;
3984}
3985
3986/* Check if the timezone required for casting from type1 to type2 is used */
3987static void
3988checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
3989{
3990 if (!useTz)
3991 ereport(ERROR,
3993 errmsg("cannot convert value from %s to %s without time zone usage",
3994 type1, type2),
3995 errhint("Use *_tz() function for time zone support.")));
3996}
3997
3998/* Convert time datum to timetz datum */
3999static Datum
4000castTimeToTimeTz(Datum time, bool useTz)
4001{
4002 checkTimezoneIsUsedForCast(useTz, "time", "timetz");
4003
4004 return DirectFunctionCall1(time_timetz, time);
4005}
4006
4007/*
4008 * Compare date to timestamp.
4009 * Note that this doesn't involve any timezone considerations.
4010 */
4011static int
4016
4017/*
4018 * Compare date to timestamptz.
4019 */
4020static int
4022{
4023 checkTimezoneIsUsedForCast(useTz, "date", "timestamptz");
4024
4026}
4027
4028/*
4029 * Compare timestamp to timestamptz.
4030 */
4031static int
4033{
4034 checkTimezoneIsUsedForCast(useTz, "timestamp", "timestamptz");
4035
4037}
4038
4039/*
4040 * Cross-type comparison of two datetime SQL/JSON items. If items are
4041 * uncomparable *cast_error flag is set, otherwise *cast_error is unset.
4042 * If the cast requires timezone and it is not used, then explicit error is thrown.
4043 */
4044static int
4046 bool useTz, bool *cast_error)
4047{
4049
4050 *cast_error = false;
4051
4052 switch (typid1)
4053 {
4054 case DATEOID:
4055 switch (typid2)
4056 {
4057 case DATEOID:
4058 cmpfunc = date_cmp;
4059
4060 break;
4061
4062 case TIMESTAMPOID:
4065 useTz);
4066
4067 case TIMESTAMPTZOID:
4070 useTz);
4071
4072 case TIMEOID:
4073 case TIMETZOID:
4074 *cast_error = true; /* uncomparable types */
4075 return 0;
4076
4077 default:
4078 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4079 typid2);
4080 }
4081 break;
4082
4083 case TIMEOID:
4084 switch (typid2)
4085 {
4086 case TIMEOID:
4087 cmpfunc = time_cmp;
4088
4089 break;
4090
4091 case TIMETZOID:
4092 val1 = castTimeToTimeTz(val1, useTz);
4094
4095 break;
4096
4097 case DATEOID:
4098 case TIMESTAMPOID:
4099 case TIMESTAMPTZOID:
4100 *cast_error = true; /* uncomparable types */
4101 return 0;
4102
4103 default:
4104 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4105 typid2);
4106 }
4107 break;
4108
4109 case TIMETZOID:
4110 switch (typid2)
4111 {
4112 case TIMEOID:
4113 val2 = castTimeToTimeTz(val2, useTz);
4115
4116 break;
4117
4118 case TIMETZOID:
4120
4121 break;
4122
4123 case DATEOID:
4124 case TIMESTAMPOID:
4125 case TIMESTAMPTZOID:
4126 *cast_error = true; /* uncomparable types */
4127 return 0;
4128
4129 default:
4130 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4131 typid2);
4132 }
4133 break;
4134
4135 case TIMESTAMPOID:
4136 switch (typid2)
4137 {
4138 case DATEOID:
4141 useTz);
4142
4143 case TIMESTAMPOID:
4145
4146 break;
4147
4148 case TIMESTAMPTZOID:
4151 useTz);
4152
4153 case TIMEOID:
4154 case TIMETZOID:
4155 *cast_error = true; /* uncomparable types */
4156 return 0;
4157
4158 default:
4159 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4160 typid2);
4161 }
4162 break;
4163
4164 case TIMESTAMPTZOID:
4165 switch (typid2)
4166 {
4167 case DATEOID:
4170 useTz);
4171
4172 case TIMESTAMPOID:
4175 useTz);
4176
4177 case TIMESTAMPTZOID:
4179
4180 break;
4181
4182 case TIMEOID:
4183 case TIMETZOID:
4184 *cast_error = true; /* uncomparable types */
4185 return 0;
4186
4187 default:
4188 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4189 typid2);
4190 }
4191 break;
4192
4193 default:
4194 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u", typid1);
4195 }
4196
4197 if (*cast_error)
4198 return 0; /* cast error */
4199
4201}
4202
4203/*
4204 * Executor-callable JSON_EXISTS implementation
4205 *
4206 * Returns NULL instead of throwing errors if 'error' is not NULL, setting
4207 * *error to true.
4208 */
4209bool
4211{
4213
4214 res = executeJsonPath(jp, vars,
4216 DatumGetJsonbP(jb), !error, NULL, true);
4217
4218 Assert(error || !jperIsError(res));
4219
4220 if (error && jperIsError(res))
4221 *error = true;
4222
4223 return res == jperOk;
4224}
4225
4226/*
4227 * Executor-callable JSON_QUERY implementation
4228 *
4229 * Returns NULL instead of throwing errors if 'error' is not NULL, setting
4230 * *error to true. *empty is set to true if no match is found.
4231 */
4232Datum
4234 bool *error, List *vars,
4235 const char *column_name)
4236{
4237 bool wrap;
4238 JsonValueList found;
4240
4241 JsonValueListInit(&found);
4242
4243 res = executeJsonPath(jp, vars,
4245 DatumGetJsonbP(jb), !error, &found, true);
4246 Assert(error || !jperIsError(res));
4247 if (error && jperIsError(res))
4248 {
4249 *error = true;
4250 *empty = false;
4251 return (Datum) 0;
4252 }
4253
4254 /*
4255 * Determine whether to wrap the result in a JSON array or not.
4256 *
4257 * If the returned JsonValueList is empty, no wrapping is necessary.
4258 *
4259 * If the wrapper mode is JSW_NONE or JSW_UNSPEC, wrapping is explicitly
4260 * disabled. This enforces a WITHOUT WRAPPER clause, which is also the
4261 * default when no WRAPPER clause is specified.
4262 *
4263 * If the mode is JSW_UNCONDITIONAL, wrapping is enforced regardless of
4264 * the number of SQL/JSON items, enforcing a WITH WRAPPER or WITH
4265 * UNCONDITIONAL WRAPPER clause.
4266 *
4267 * For JSW_CONDITIONAL, wrapping occurs only if there is more than one
4268 * SQL/JSON item in the list, enforcing a WITH CONDITIONAL WRAPPER clause.
4269 */
4270 if (JsonValueListIsEmpty(&found))
4271 wrap = false;
4272 else if (wrapper == JSW_NONE || wrapper == JSW_UNSPEC)
4273 wrap = false;
4274 else if (wrapper == JSW_UNCONDITIONAL)
4275 wrap = true;
4276 else if (wrapper == JSW_CONDITIONAL)
4278 else
4279 {
4280 elog(ERROR, "unrecognized json wrapper %d", (int) wrapper);
4281 wrap = false;
4282 }
4283
4284 if (wrap)
4286
4287 /* No wrapping means at most one item is expected. */
4289 {
4290 if (error)
4291 {
4292 *error = true;
4293 return (Datum) 0;
4294 }
4295
4296 if (column_name)
4297 ereport(ERROR,
4299 errmsg("JSON path expression for column \"%s\" must return single item when no wrapper is requested",
4300 column_name),
4301 errhint("Use the WITH WRAPPER clause to wrap SQL/JSON items into an array.")));
4302 else
4303 ereport(ERROR,
4305 errmsg("JSON path expression in JSON_QUERY must return single item when no wrapper is requested"),
4306 errhint("Use the WITH WRAPPER clause to wrap SQL/JSON items into an array.")));
4307 }
4308
4309 if (!JsonValueListIsEmpty(&found))
4311
4312 *empty = true;
4313 return PointerGetDatum(NULL);
4314}
4315
4316/*
4317 * Executor-callable JSON_VALUE implementation
4318 *
4319 * Returns NULL instead of throwing errors if 'error' is not NULL, setting
4320 * *error to true. *empty is set to true if no match is found.
4321 */
4322JsonbValue *
4323JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars,
4324 const char *column_name)
4325{
4326 JsonbValue *res;
4327 JsonValueList found;
4329
4330 JsonValueListInit(&found);
4331
4334 !error, &found, true);
4335
4337
4338 if (error && jperIsError(jper))
4339 {
4340 *error = true;
4341 *empty = false;
4342 return NULL;
4343 }
4344
4345 *empty = JsonValueListIsEmpty(&found);
4346
4347 if (*empty)
4348 return NULL;
4349
4350 /* JSON_VALUE expects to get only singletons. */
4352 {
4353 if (error)
4354 {
4355 *error = true;
4356 return NULL;
4357 }
4358
4359 if (column_name)
4360 ereport(ERROR,
4362 errmsg("JSON path expression for column \"%s\" must return single scalar item",
4363 column_name)));
4364 else
4365 ereport(ERROR,
4367 errmsg("JSON path expression in JSON_VALUE must return single scalar item")));
4368 }
4369
4370 res = copyJsonbValue(JsonValueListHead(&found));
4371 if (res->type == jbvBinary && JsonContainerIsScalar(res->val.binary.data))
4372 JsonbExtractScalar(res->val.binary.data, res);
4373
4374 /* JSON_VALUE expects to get only scalars. */
4375 if (!IsAJsonbScalar(res))
4376 {
4377 if (error)
4378 {
4379 *error = true;
4380 return NULL;
4381 }
4382
4383 if (column_name)
4384 ereport(ERROR,
4386 errmsg("JSON path expression for column \"%s\" must return single scalar item",
4387 column_name)));
4388 else
4389 ereport(ERROR,
4391 errmsg("JSON path expression in JSON_VALUE must return single scalar item")));
4392 }
4393
4394 if (res->type == jbvNull)
4395 return NULL;
4396
4397 return res;
4398}
4399
4400/************************ JSON_TABLE functions ***************************/
4401
4402/*
4403 * Sanity-checks and returns the opaque JsonTableExecContext from the
4404 * given executor state struct.
4405 */
4406static inline JsonTableExecContext *
4408{
4410
4412 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4413 result = (JsonTableExecContext *) state->opaque;
4415 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4416
4417 return result;
4418}
4419
4420/*
4421 * JsonTableInitOpaque
4422 * Fill in TableFuncScanState->opaque for processing JSON_TABLE
4423 *
4424 * This initializes the PASSING arguments and the JsonTablePlanState for
4425 * JsonTablePlan given in TableFunc.
4426 */
4427static void
4429{
4431 PlanState *ps = &state->ss.ps;
4433 TableFunc *tf = tfs->tablefunc;
4434 JsonTablePlan *rootplan = (JsonTablePlan *) tf->plan;
4436 List *args = NIL;
4437
4440
4441 /*
4442 * Evaluate JSON_TABLE() PASSING arguments to be passed to the jsonpath
4443 * executor via JsonPathVariables.
4444 */
4445 if (state->passingvalexprs)
4446 {
4449
4450 Assert(list_length(state->passingvalexprs) ==
4451 list_length(je->passing_names));
4452 forboth(exprlc, state->passingvalexprs,
4453 namelc, je->passing_names)
4454 {
4458
4459 var->name = pstrdup(name->sval);
4460 var->namelen = strlen(var->name);
4461 var->typid = exprType((Node *) state->expr);
4462 var->typmod = exprTypmod((Node *) state->expr);
4463
4464 /*
4465 * Evaluate the expression and save the value to be returned by
4466 * GetJsonPathVar().
4467 */
4468 var->value = ExecEvalExpr(state, ps->ps_ExprContext,
4469 &var->isnull);
4470
4471 args = lappend(args, var);
4472 }
4473 }
4474
4475 cxt->colplanstates = palloc_array(JsonTablePlanState *, list_length(tf->colvalexprs));
4476
4477 /*
4478 * Initialize plan for the root path and, recursively, also any child
4479 * plans that compute the NESTED paths.
4480 */
4481 cxt->rootplanstate = JsonTableInitPlan(cxt, rootplan, NULL, args,
4483
4484 state->opaque = cxt;
4485}
4486
4487/*
4488 * JsonTableDestroyOpaque
4489 * Resets state->opaque
4490 */
4491static void
4493{
4495 GetJsonTableExecContext(state, "JsonTableDestroyOpaque");
4496
4497 /* not valid anymore */
4498 cxt->magic = 0;
4499
4500 state->opaque = NULL;
4501}
4502
4503/*
4504 * JsonTableInitPlan
4505 * Initialize information for evaluating jsonpath in the given
4506 * JsonTablePlan and, recursively, in any child plans
4507 */
4508static JsonTablePlanState *
4511 List *args, MemoryContext mcxt)
4512{
4514
4515 planstate->plan = plan;
4516 planstate->parent = parentstate;
4517 JsonValueListInit(&planstate->found);
4518
4520 {
4522 int i;
4523
4524 planstate->outerJoin = scan->outerJoin;
4525 planstate->path = DatumGetJsonPathP(scan->path->value->constvalue);
4526 planstate->args = args;
4527 planstate->mcxt = AllocSetContextCreate(mcxt, "JsonTableExecContext",
4529
4530 /* No row pattern evaluated yet. */
4531 planstate->current.value = PointerGetDatum(NULL);
4532 planstate->current.isnull = true;
4533
4534 for (i = scan->colMin; i >= 0 && i <= scan->colMax; i++)
4535 cxt->colplanstates[i] = planstate;
4536
4537 planstate->nested = scan->child ?
4538 JsonTableInitPlan(cxt, scan->child, planstate, args, mcxt) : NULL;
4539 }
4540 else if (IsA(plan, JsonTableSiblingJoin))
4541 {
4543
4544 planstate->cross = join->cross;
4545
4546 planstate->left = JsonTableInitPlan(cxt, join->lplan, parentstate,
4547 args, mcxt);
4548 planstate->right = JsonTableInitPlan(cxt, join->rplan, parentstate,
4549 args, mcxt);
4550 }
4551
4552 return planstate;
4553}
4554
4555/*
4556 * JsonTableSetDocument
4557 * Install the input document and evaluate the row pattern
4558 */
4559static void
4567
4568/*
4569 * Evaluate a JsonTablePlan's jsonpath to get a new row pattern from
4570 * the given context item
4571 */
4572static void
4574{
4575 JsonTablePathScan *scan = castNode(JsonTablePathScan, planstate->plan);
4578 Jsonb *js = (Jsonb *) DatumGetJsonbP(item);
4579
4580 JsonValueListClear(&planstate->found);
4581
4582 MemoryContextResetOnly(planstate->mcxt);
4583
4584 oldcxt = MemoryContextSwitchTo(planstate->mcxt);
4585
4586 res = executeJsonPath(planstate->path, planstate->args,
4588 js, scan->errorOnError,
4589 &planstate->found,
4590 true);
4591
4593
4594 if (jperIsError(res))
4595 {
4596 Assert(!scan->errorOnError);
4597 JsonValueListClear(&planstate->found);
4598 }
4599
4600 JsonTableRescan(planstate);
4601}
4602
4603/*
4604 * Fetch next row from a JsonTablePlan.
4605 *
4606 * Returns false if the plan has run out of rows, true otherwise.
4607 */
4608static bool
4610{
4611 if (IsA(planstate->plan, JsonTableSiblingJoin))
4612 {
4613 if (planstate->advanceRight)
4614 {
4615 /* fetch next inner row */
4616 if (JsonTablePlanNextRow(planstate->right))
4617 return true;
4618
4619 /* inner rows are exhausted */
4620 if (planstate->cross)
4621 planstate->advanceRight = false; /* next outer row */
4622 else
4623 return false; /* end of scan */
4624 }
4625
4626 while (!planstate->advanceRight)
4627 {
4628 /* fetch next outer row */
4629 bool more = JsonTablePlanNextRow(planstate->left);
4630
4631 if (planstate->cross)
4632 {
4633 if (!more)
4634 return false; /* end of scan */
4635
4636 JsonTableRescan(planstate->right);
4637
4638 if (!JsonTablePlanNextRow(planstate->right))
4639 continue; /* next outer row */
4640
4641 planstate->advanceRight = true; /* next inner row */
4642 }
4643 else if (!more)
4644 {
4645 if (!JsonTablePlanNextRow(planstate->right))
4646 return false; /* end of scan */
4647
4648 planstate->advanceRight = true; /* next inner row */
4649 }
4650
4651 break;
4652 }
4653 }
4654 else
4655 {
4656 /* reset context item if requested */
4657 if (planstate->reset)
4658 {
4659 JsonTablePlanState *parent = planstate->parent;
4660
4661 Assert(parent != NULL && !parent->current.isnull);
4662 JsonTableResetRowPattern(planstate, parent->current.value);
4663 planstate->reset = false;
4664 }
4665
4666 if (planstate->advanceNested)
4667 {
4668 /* fetch next nested row */
4669 planstate->advanceNested = JsonTablePlanNextRow(planstate->nested);
4670 if (planstate->advanceNested)
4671 return true;
4672 }
4673
4674 for (;;)
4675 {
4676 if (!JsonTablePlanScanNextRow(planstate))
4677 return false;
4678
4679 if (planstate->nested == NULL)
4680 break;
4681
4682 JsonTableResetNestedPlan(planstate->nested);
4683 planstate->advanceNested = JsonTablePlanNextRow(planstate->nested);
4684
4685 if (!planstate->advanceNested && !planstate->outerJoin)
4686 continue;
4687
4688 /*
4689 * We have a row to return: either the nested plan produced one,
4690 * or this is an outer join and we emit the parent row with the
4691 * nested columns set to NULL.
4692 */
4693 break;
4694 }
4695 }
4696
4697 return true;
4698}
4699
4700/*
4701 * Advance a JsonTablePlan's path scan to its next row pattern match.
4702 *
4703 * This only moves this plan's own row pattern iterator forward and makes the
4704 * matched item the current row; driving and joining of any nested plan is the
4705 * responsibility of JsonTablePlanNextRow(). Returns false when this scan's
4706 * row pattern matches are exhausted.
4707 */
4708static bool
4710{
4711 JsonbValue *jbv;
4713
4714 /* Fetch new row from the list of found values to set as active. */
4715 jbv = JsonValueListNext(&planstate->iter);
4716
4717 /* End of list? */
4718 if (jbv == NULL)
4719 {
4720 planstate->current.value = PointerGetDatum(NULL);
4721 planstate->current.isnull = true;
4722 return false;
4723 }
4724
4725 /*
4726 * Set current row item for subsequent JsonTableGetValue() calls for
4727 * evaluating individual columns.
4728 */
4729 oldcxt = MemoryContextSwitchTo(planstate->mcxt);
4731 planstate->current.isnull = false;
4733
4734 /* Next row! */
4735 planstate->ordinal++;
4736
4737 /* There are more rows. */
4738 return true;
4739}
4740
4741/*
4742 * Re-evaluate the row pattern of a nested plan using the new parent row
4743 * pattern.
4744 */
4745static void
4747{
4748 /* This better be a child plan. */
4749 Assert(planstate->parent != NULL);
4750 if (IsA(planstate->plan, JsonTablePathScan))
4751 {
4752 JsonTablePlanState *parent = planstate->parent;
4753
4754 planstate->reset = true;
4755 planstate->advanceNested = false;
4756
4757 if (planstate->nested)
4758 JsonTableResetNestedPlan(planstate->nested);
4759
4760 /*
4761 * Reset this plan's transient scan state so that its columns read as
4762 * NULL until it is actually advanced. Re-evaluating the path against
4763 * the new parent row is deferred (see the reset flag) until the plan
4764 * is advanced by JsonTablePlanNextRow(), so that the path is not
4765 * evaluated more than once per parent row.
4766 */
4767 if (!parent->current.isnull)
4768 JsonTableRescan(planstate);
4769 }
4770 else if (IsA(planstate->plan, JsonTableSiblingJoin))
4771 {
4772 JsonTableResetNestedPlan(planstate->left);
4773 JsonTableResetNestedPlan(planstate->right);
4774 planstate->advanceRight = false;
4775 }
4776}
4777
4778/*
4779 * JsonTableFetchRow
4780 * Prepare the next "current" row for upcoming GetValue calls.
4781 *
4782 * Returns false if no more rows can be returned.
4783 */
4784static bool
4786{
4788 GetJsonTableExecContext(state, "JsonTableFetchRow");
4789
4791}
4792
4793/*
4794 * JsonTableGetValue
4795 * Return the value for column number 'colnum' for the current row.
4796 *
4797 * This leaks memory, so be sure to reset often the context in which it's
4798 * called.
4799 */
4800static Datum
4802 Oid typid, int32 typmod, bool *isnull)
4803{
4805 GetJsonTableExecContext(state, "JsonTableGetValue");
4806 ExprContext *econtext = state->ss.ps.ps_ExprContext;
4807 ExprState *estate = list_nth(state->colvalexprs, colnum);
4808 JsonTablePlanState *planstate = cxt->colplanstates[colnum];
4809 JsonTablePlanRowSource *current = &planstate->current;
4810 Datum result;
4811
4812 /* Row pattern value is NULL */
4813 if (current->isnull)
4814 {
4815 result = (Datum) 0;
4816 *isnull = true;
4817 }
4818 /* Evaluate JsonExpr. */
4819 else if (estate)
4820 {
4822 bool saved_caseIsNull = econtext->caseValue_isNull;
4823
4824 /* Pass the row pattern value via CaseTestExpr. */
4825 econtext->caseValue_datum = current->value;
4826 econtext->caseValue_isNull = false;
4827
4828 result = ExecEvalExpr(estate, econtext, isnull);
4829
4830 econtext->caseValue_datum = saved_caseValue;
4832 }
4833 /* ORDINAL column */
4834 else
4835 {
4836 result = Int32GetDatum(planstate->ordinal);
4837 *isnull = false;
4838 }
4839
4840 return result;
4841}
4842
4843/* Recursively reset planstate and its child nodes */
4844static void
4846{
4847 if (IsA(planstate->plan, JsonTablePathScan))
4848 {
4849 /* Reset plan iterator to the beginning of the item list */
4850 JsonValueListInitIterator(&planstate->found, &planstate->iter);
4851 planstate->current.value = PointerGetDatum(NULL);
4852 planstate->current.isnull = true;
4853 planstate->ordinal = 0;
4854
4855 if (planstate->nested)
4856 JsonTableRescan(planstate->nested);
4857 }
4858 else if (IsA(planstate->plan, JsonTableSiblingJoin))
4859 {
4860 JsonTableRescan(planstate->left);
4861 JsonTableRescan(planstate->right);
4862 planstate->advanceRight = false;
4863 }
4864}
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
int32 make_numeric_typmod_safe(int32 precision, int32 scale, Node *escontext)
Definition numeric.c:1315
Datum float8_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4544
Datum numeric_cmp(PG_FUNCTION_ARGS)
Definition numeric.c:2423
Numeric int64_to_numeric(int64 val)
Definition numeric.c:4270
Datum float4_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4643
Datum int4_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4364
Datum numeric_uminus(PG_FUNCTION_ARGS)
Definition numeric.c:1411
Numeric numeric_mod_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:3366
Datum numeric_ceil(PG_FUNCTION_ARGS)
Definition numeric.c:1638
int32 numeric_int4_safe(Numeric num, Node *escontext)
Definition numeric.c:4375
Numeric numeric_add_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:2889
int64 numeric_int8_safe(Numeric num, Node *escontext)
Definition numeric.c:4451
Numeric numeric_div_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:3163
Numeric numeric_sub_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:2965
Datum numeric_out(PG_FUNCTION_ARGS)
Definition numeric.c:799
Datum numeric_trunc(PG_FUNCTION_ARGS)
Definition numeric.c:1588
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:4495
Numeric numeric_mul_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:3044
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition numeric.c:1384
Datum int8_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4440
bool numeric_is_inf(Numeric num)
Definition numeric.c:845
Datum numeric_floor(PG_FUNCTION_ARGS)
Definition numeric.c:1666
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:689
#define Min(x, y)
Definition c.h:1131
#define PG_UINT32_MAX
Definition c.h:733
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:308
#define Max(x, y)
Definition c.h:1125
#define Assert(condition)
Definition c.h:1002
int64_t int64
Definition c.h:680
int32_t int32
Definition c.h:679
uint32_t uint32
Definition c.h:683
#define lengthof(array)
Definition c.h:932
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:401
#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 @175 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)
static void JsonTableRescan(JsonTablePlanState *planstate)
#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
#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:148
#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:162
#define castNode(_type_, nodeptr)
Definition nodes.h:180
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
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:1770
@ JSW_UNCONDITIONAL
Definition primnodes.h:1774
@ JSW_CONDITIONAL
Definition primnodes.h:1773
@ JSW_UNSPEC
Definition primnodes.h:1771
@ JSW_NONE
Definition primnodes.h:1772
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:96
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:1919
JsonTablePlan * child
Definition primnodes.h:1928
Const * value
Definition primnodes.h:1892
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:1950
JsonTablePlan * lplan
Definition primnodes.h:1949
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:133
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:835
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