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