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);
336static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
338static JsonbValue *GetJsonPathVar(void *cxt, char *varName, int varNameLen,
339 JsonbValue *baseObject, int *baseObjectId);
340static int CountJsonPathVars(void *cxt);
341static void JsonItemFromDatum(Datum val, Oid typid, int32 typmod,
342 JsonbValue *res);
346static int countVariablesFromJsonb(void *varsJsonb);
347static JsonbValue *getJsonPathVariableFromJsonb(void *varsJsonb, char *varName,
348 int varNameLength,
349 JsonbValue *baseObject,
350 int *baseObjectId);
351static int JsonbArraySize(JsonbValue *jb);
353 JsonbValue *rv, void *p);
355 bool useTz);
356static int compareNumeric(Numeric a, Numeric b);
361 JsonbValue *jbv, int32 id);
365static bool JsonValueListIsEmpty(const JsonValueList *jvl);
366static bool JsonValueListIsSingleton(const JsonValueList *jvl);
373static int JsonbType(JsonbValue *jb);
374static JsonbValue *getScalar(JsonbValue *scalar, enum jbvType type);
377 bool useTz, bool *cast_error);
378static void checkTimezoneIsUsedForCast(bool useTz, const char *type1,
379 const char *type2);
380
381static void JsonTableInitOpaque(TableFuncScanState *state, int natts);
385 List *args,
386 MemoryContext mcxt);
388static void JsonTableResetRowPattern(JsonTablePlanState *planstate, Datum item);
391 Oid typid, int32 typmod, bool *isnull);
393static bool JsonTablePlanScanNextRow(JsonTablePlanState *planstate);
394static void JsonTableResetNestedPlan(JsonTablePlanState *planstate);
395static bool JsonTablePlanJoinNextRow(JsonTablePlanState *planstate);
396static bool JsonTablePlanNextRow(JsonTablePlanState *planstate);
397
399{
401 .SetDocument = JsonTableSetDocument,
402 .SetNamespace = NULL,
403 .SetRowFilter = NULL,
404 .SetColumnFilter = NULL,
405 .FetchRow = JsonTableFetchRow,
406 .GetValue = JsonTableGetValue,
407 .DestroyOpaque = JsonTableDestroyOpaque
408};
409
410/****************** User interface to JsonPath executor ********************/
411
412/*
413 * jsonb_path_exists
414 * Returns true if jsonpath returns at least one item for the specified
415 * jsonb value. This function and jsonb_path_match() are used to
416 * implement @? and @@ operators, which in turn are intended to have an
417 * index support. Thus, it's desirable to make it easier to achieve
418 * consistency between index scan results and sequential scan results.
419 * So, we throw as few errors as possible. Regarding this function,
420 * such behavior also matches behavior of JSON_EXISTS() clause of
421 * SQL/JSON. Regarding jsonb_path_match(), this function doesn't have
422 * an analogy in SQL/JSON, so we define its behavior on our own.
423 */
424static Datum
426{
430 Jsonb *vars = NULL;
431 bool silent = true;
432
433 if (PG_NARGS() == 4)
434 {
437 }
438
441 jb, !silent, NULL, tz);
442
445
446 if (jperIsError(res))
448
449 PG_RETURN_BOOL(res == jperOk);
450}
451
452Datum
457
458Datum
463
464/*
465 * jsonb_path_exists_opr
466 * Implementation of operator "jsonb @? jsonpath" (2-argument version of
467 * jsonb_path_exists()).
468 */
469Datum
471{
472 /* just call the other one -- it can handle both cases */
473 return jsonb_path_exists_internal(fcinfo, false);
474}
475
476/*
477 * jsonb_path_match
478 * Returns jsonpath predicate result item for the specified jsonb value.
479 * See jsonb_path_exists() comment for details regarding error handling.
480 */
481static Datum
483{
486 Jsonb *vars = NULL;
487 bool silent = true;
488 JsonValueList found;
489
490 if (PG_NARGS() == 4)
491 {
494 }
495
496 JsonValueListInit(&found);
497
500 jb, !silent, &found, tz);
501
504
505 if (JsonValueListIsSingleton(&found))
506 {
508
509 if (jbv->type == jbvBool)
510 PG_RETURN_BOOL(jbv->val.boolean);
511
512 if (jbv->type == jbvNull)
514 }
515
516 if (!silent)
519 errmsg("single boolean result is expected")));
520
522}
523
524Datum
526{
527 return jsonb_path_match_internal(fcinfo, false);
528}
529
530Datum
535
536/*
537 * jsonb_path_match_opr
538 * Implementation of operator "jsonb @@ jsonpath" (2-argument version of
539 * jsonb_path_match()).
540 */
541Datum
543{
544 /* just call the other one -- it can handle both cases */
545 return jsonb_path_match_internal(fcinfo, false);
546}
547
548/*
549 * jsonb_path_query
550 * Executes jsonpath for given jsonb document and returns result as
551 * rowset.
552 */
553static Datum
555{
558 JsonbValue *v;
559
560 if (SRF_IS_FIRSTCALL())
561 {
562 JsonPath *jp;
563 Jsonb *jb;
564 Jsonb *vars;
565 bool silent;
566 MemoryContext oldcontext;
567 JsonValueList *found;
568
570 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
571
576
578 JsonValueListInit(found);
579
582 jb, !silent, found, tz);
583
585 JsonValueListInitIterator(found, iter);
586
587 funcctx->user_fctx = iter;
588
589 MemoryContextSwitchTo(oldcontext);
590 }
591
593 iter = funcctx->user_fctx;
594
595 v = JsonValueListNext(iter);
596
597 if (v == NULL)
599
601}
602
603Datum
605{
606 return jsonb_path_query_internal(fcinfo, false);
607}
608
609Datum
614
615/*
616 * jsonb_path_query_array
617 * Executes jsonpath for given jsonb document and returns result as
618 * jsonb array.
619 */
620static Datum
637
638Datum
643
644Datum
649
650/*
651 * jsonb_path_query_first
652 * Executes jsonpath for given jsonb document and returns first result
653 * item. If there are no items, NULL returned.
654 */
655static Datum
675
676Datum
681
682Datum
687
688/********************Execute functions for JsonPath**************************/
689
690/*
691 * Interface to jsonpath executor
692 *
693 * 'path' - jsonpath to be executed
694 * 'vars' - variables to be substituted to jsonpath
695 * 'getVar' - callback used by getJsonPathVariable() to extract variables from
696 * 'vars'
697 * 'countVars' - callback to count the number of jsonpath variables in 'vars'
698 * 'json' - target document for jsonpath evaluation
699 * 'throwErrors' - whether we should throw suppressible errors
700 * 'result' - list to store result items into
701 *
702 * Returns an error if a recoverable error happens during processing, or NULL
703 * on no error.
704 *
705 * Note, jsonb and jsonpath values should be available and untoasted during
706 * work because JsonPathItem, JsonbValue and result item could have pointers
707 * into input values. If caller needs to just check if document matches
708 * jsonpath, then it doesn't provide a result arg. In this case executor
709 * works till first positive result and does not check the rest if possible.
710 * In other case it tries to find all the satisfied result items.
711 */
715 Jsonb *json, bool throwErrors, JsonValueList *result,
716 bool useTz)
717{
722
723 jspInit(&jsp, path);
724
725 if (!JsonbExtractScalar(&json->root, &jbv))
726 JsonbInitBinary(&jbv, json);
727
728 cxt.vars = vars;
729 cxt.getVar = getVar;
730 cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
732 cxt.root = &jbv;
733 cxt.current = &jbv;
734 cxt.baseObject.jbc = NULL;
735 cxt.baseObject.id = 0;
736 /* 1 + number of base objects in vars */
738 cxt.innermostArraySize = -1;
739 cxt.throwErrors = throwErrors;
740 cxt.useTz = useTz;
741
742 if (jspStrictAbsenceOfErrors(&cxt) && !result)
743 {
744 /*
745 * In strict mode we must get a complete list of values to check that
746 * there are no errors at all.
747 */
748 JsonValueList vals;
749 bool isempty;
750
751 JsonValueListInit(&vals);
752
753 res = executeItem(&cxt, &jsp, &jbv, &vals);
754
756 JsonValueListClear(&vals);
757
758 if (jperIsError(res))
759 return res;
760
761 return isempty ? jperNotFound : jperOk;
762 }
763
764 res = executeItem(&cxt, &jsp, &jbv, result);
765
766 Assert(!throwErrors || !jperIsError(res));
767
768 return res;
769}
770
771/*
772 * Execute jsonpath with automatic unwrapping of current item in lax mode.
773 */
780
781/*
782 * Main jsonpath executor function: walks on jsonpath structure, finds
783 * relevant parts of jsonb and evaluates expressions over them.
784 * When 'unwrap' is true current SQL/JSON item is unwrapped if it is an array.
785 */
788 JsonbValue *jb, JsonValueList *found, bool unwrap)
789{
790 JsonPathItem elem;
792 JsonBaseObjectInfo baseObject;
793
796
797 switch (jsp->type)
798 {
799 case jpiNull:
800 case jpiBool:
801 case jpiNumeric:
802 case jpiString:
803 case jpiVariable:
804 {
805 JsonbValue v;
806 bool hasNext = jspGetNext(jsp, &elem);
807
808 if (!hasNext && !found && jsp->type != jpiVariable)
809 {
810 /*
811 * Skip evaluation, but not for variables. We must
812 * trigger an error for the missing variable.
813 */
814 res = jperOk;
815 break;
816 }
817
818 baseObject = cxt->baseObject;
819 getJsonPathItem(cxt, jsp, &v);
820
821 res = executeNextItem(cxt, jsp, &elem,
822 &v, found);
823 cxt->baseObject = baseObject;
824 }
825 break;
826
827 /* all boolean item types: */
828 case jpiAnd:
829 case jpiOr:
830 case jpiNot:
831 case jpiIsUnknown:
832 case jpiEqual:
833 case jpiNotEqual:
834 case jpiLess:
835 case jpiGreater:
836 case jpiLessOrEqual:
838 case jpiExists:
839 case jpiStartsWith:
840 case jpiLikeRegex:
841 {
842 JsonPathBool st = executeBoolItem(cxt, jsp, jb, true);
843
844 res = appendBoolResult(cxt, jsp, found, st);
845 break;
846 }
847
848 case jpiAdd:
849 return executeBinaryArithmExpr(cxt, jsp, jb,
850 numeric_add_safe, found);
851
852 case jpiSub:
853 return executeBinaryArithmExpr(cxt, jsp, jb,
854 numeric_sub_safe, found);
855
856 case jpiMul:
857 return executeBinaryArithmExpr(cxt, jsp, jb,
858 numeric_mul_safe, found);
859
860 case jpiDiv:
861 return executeBinaryArithmExpr(cxt, jsp, jb,
862 numeric_div_safe, found);
863
864 case jpiMod:
865 return executeBinaryArithmExpr(cxt, jsp, jb,
866 numeric_mod_safe, found);
867
868 case jpiPlus:
869 return executeUnaryArithmExpr(cxt, jsp, jb, NULL, found);
870
871 case jpiMinus:
873 found);
874
875 case jpiAnyArray:
876 if (JsonbType(jb) == jbvArray)
877 {
878 bool hasNext = jspGetNext(jsp, &elem);
879
880 res = executeItemUnwrapTargetArray(cxt, hasNext ? &elem : NULL,
881 jb, found, jspAutoUnwrap(cxt));
882 }
883 else if (jspAutoWrap(cxt))
884 res = executeNextItem(cxt, jsp, NULL, jb, found);
885 else if (!jspIgnoreStructuralErrors(cxt))
888 errmsg("jsonpath wildcard array accessor can only be applied to an array"))));
889 break;
890
891 case jpiAnyKey:
892 if (JsonbType(jb) == jbvObject)
893 {
894 bool hasNext = jspGetNext(jsp, &elem);
895
896 if (jb->type != jbvBinary)
897 elog(ERROR, "invalid jsonb object type: %d", jb->type);
898
899 return executeAnyItem
900 (cxt, hasNext ? &elem : NULL,
901 jb->val.binary.data, found, 1, 1, 1,
902 false, jspAutoUnwrap(cxt));
903 }
904 else if (unwrap && JsonbType(jb) == jbvArray)
905 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
906 else if (!jspIgnoreStructuralErrors(cxt))
907 {
908 Assert(found);
911 errmsg("jsonpath wildcard member accessor can only be applied to an object"))));
912 }
913 break;
914
915 case jpiIndexArray:
916 if (JsonbType(jb) == jbvArray || jspAutoWrap(cxt))
917 {
918 int innermostArraySize = cxt->innermostArraySize;
919 int i;
920 int size = JsonbArraySize(jb);
921 bool singleton = size < 0;
922 bool hasNext = jspGetNext(jsp, &elem);
923
924 if (singleton)
925 size = 1;
926
927 cxt->innermostArraySize = size; /* for LAST evaluation */
928
929 for (i = 0; i < jsp->content.array.nelems; i++)
930 {
931 JsonPathItem from;
932 JsonPathItem to;
933 int32 index;
936 bool range = jspGetArraySubscript(jsp, &from,
937 &to, i);
938
939 res = getArrayIndex(cxt, &from, jb, &index_from);
940
941 if (jperIsError(res))
942 break;
943
944 if (range)
945 {
946 res = getArrayIndex(cxt, &to, jb, &index_to);
947
948 if (jperIsError(res))
949 break;
950 }
951 else
953
954 if (!jspIgnoreStructuralErrors(cxt) &&
955 (index_from < 0 ||
957 index_to >= size))
960 errmsg("jsonpath array subscript is out of bounds"))));
961
962 if (index_from < 0)
963 index_from = 0;
964
965 if (index_to >= size)
966 index_to = size - 1;
967
968 res = jperNotFound;
969
970 for (index = index_from; index <= index_to; index++)
971 {
972 JsonbValue *v;
973
974 if (singleton)
975 {
976 v = jb;
977 }
978 else
979 {
980 v = getIthJsonbValueFromContainer(jb->val.binary.data,
981 (uint32) index);
982
983 if (v == NULL)
984 continue;
985 }
986
987 if (!hasNext && !found)
988 return jperOk;
989
990 res = executeNextItem(cxt, jsp, &elem, v, found);
991
992 if (jperIsError(res))
993 break;
994
995 if (res == jperOk && !found)
996 break;
997 }
998
999 if (jperIsError(res))
1000 break;
1001
1002 if (res == jperOk && !found)
1003 break;
1004 }
1005
1006 cxt->innermostArraySize = innermostArraySize;
1007 }
1008 else if (!jspIgnoreStructuralErrors(cxt))
1009 {
1012 errmsg("jsonpath array accessor can only be applied to an array"))));
1013 }
1014 break;
1015
1016 case jpiAny:
1017 {
1018 bool hasNext = jspGetNext(jsp, &elem);
1019
1020 /* first try without any intermediate steps */
1021 if (jsp->content.anybounds.first == 0)
1022 {
1024
1026 cxt->ignoreStructuralErrors = true;
1027 res = executeNextItem(cxt, jsp, &elem,
1028 jb, found);
1030
1031 if (res == jperOk && !found)
1032 break;
1033 }
1034
1035 if (jb->type == jbvBinary)
1036 res = executeAnyItem
1037 (cxt, hasNext ? &elem : NULL,
1038 jb->val.binary.data, found,
1039 1,
1040 jsp->content.anybounds.first,
1041 jsp->content.anybounds.last,
1042 true, jspAutoUnwrap(cxt));
1043 break;
1044 }
1045
1046 case jpiKey:
1047 if (JsonbType(jb) == jbvObject)
1048 {
1049 JsonbValue *v;
1050 JsonbValue key;
1051
1052 key.type = jbvString;
1053 key.val.string.val = jspGetString(jsp, &key.val.string.len);
1054
1055 v = findJsonbValueFromContainer(jb->val.binary.data,
1056 JB_FOBJECT, &key);
1057
1058 if (v != NULL)
1059 {
1060 res = executeNextItem(cxt, jsp, NULL,
1061 v, found);
1062 pfree(v);
1063 }
1064 else if (!jspIgnoreStructuralErrors(cxt))
1065 {
1066 Assert(found);
1067
1068 if (!jspThrowErrors(cxt))
1069 return jperError;
1070
1071 ereport(ERROR,
1073 errmsg("JSON object does not contain key \"%s\"",
1074 pnstrdup(key.val.string.val,
1075 key.val.string.len))));
1076 }
1077 }
1078 else if (unwrap && JsonbType(jb) == jbvArray)
1079 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1080 else if (!jspIgnoreStructuralErrors(cxt))
1081 {
1082 Assert(found);
1085 errmsg("jsonpath member accessor can only be applied to an object"))));
1086 }
1087 break;
1088
1089 case jpiCurrent:
1090 res = executeNextItem(cxt, jsp, NULL, cxt->current, found);
1091 break;
1092
1093 case jpiRoot:
1094 jb = cxt->root;
1095 baseObject = setBaseObject(cxt, jb, 0);
1096 res = executeNextItem(cxt, jsp, NULL, jb, found);
1097 cxt->baseObject = baseObject;
1098 break;
1099
1100 case jpiFilter:
1101 {
1102 JsonPathBool st;
1103
1104 if (unwrap && JsonbType(jb) == jbvArray)
1105 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1106 false);
1107
1108 jspGetArg(jsp, &elem);
1109 st = executeNestedBoolItem(cxt, &elem, jb);
1110 if (st != jpbTrue)
1111 res = jperNotFound;
1112 else
1113 res = executeNextItem(cxt, jsp, NULL,
1114 jb, found);
1115 break;
1116 }
1117
1118 case jpiType:
1119 {
1121
1122 jbv.type = jbvString;
1123 jbv.val.string.val = pstrdup(JsonbTypeName(jb));
1124 jbv.val.string.len = strlen(jbv.val.string.val);
1125
1126 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1127 }
1128 break;
1129
1130 case jpiSize:
1131 {
1132 int size = JsonbArraySize(jb);
1134
1135 if (size < 0)
1136 {
1137 if (!jspAutoWrap(cxt))
1138 {
1139 if (!jspIgnoreStructuralErrors(cxt))
1142 errmsg("jsonpath item method .%s() can only be applied to an array",
1143 jspOperationName(jsp->type)))));
1144 break;
1145 }
1146
1147 size = 1;
1148 }
1149
1150 jbv.type = jbvNumeric;
1151 jbv.val.numeric = int64_to_numeric(size);
1152
1153 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1154 }
1155 break;
1156
1157 case jpiAbs:
1159 found);
1160
1161 case jpiFloor:
1163 found);
1164
1165 case jpiCeiling:
1167 found);
1168
1169 case jpiDouble:
1170 {
1172
1173 if (unwrap && JsonbType(jb) == jbvArray)
1174 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1175 false);
1176
1177 if (jb->type == jbvNumeric)
1178 {
1180 NumericGetDatum(jb->val.numeric)));
1181 double val;
1183
1184 val = float8in_internal(tmp,
1185 NULL,
1186 "double precision",
1187 tmp,
1188 (Node *) &escontext);
1189
1190 if (escontext.error_occurred)
1193 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1194 tmp, jspOperationName(jsp->type), "double precision"))));
1195 if (isinf(val) || isnan(val))
1198 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1199 jspOperationName(jsp->type)))));
1200 res = jperOk;
1201 }
1202 else if (jb->type == jbvString)
1203 {
1204 /* cast string as double */
1205 double val;
1206 char *tmp = pnstrdup(jb->val.string.val,
1207 jb->val.string.len);
1209
1210 val = float8in_internal(tmp,
1211 NULL,
1212 "double precision",
1213 tmp,
1214 (Node *) &escontext);
1215
1216 if (escontext.error_occurred)
1219 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1220 tmp, jspOperationName(jsp->type), "double precision"))));
1221 if (isinf(val) || isnan(val))
1224 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1225 jspOperationName(jsp->type)))));
1226
1227 jb = &jbv;
1228 jb->type = jbvNumeric;
1231 res = jperOk;
1232 }
1233
1234 if (res == jperNotFound)
1237 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1238 jspOperationName(jsp->type)))));
1239
1240 res = executeNextItem(cxt, jsp, NULL, jb, found);
1241 }
1242 break;
1243
1244 case jpiDatetime:
1245 case jpiDate:
1246 case jpiTime:
1247 case jpiTimeTz:
1248 case jpiTimestamp:
1249 case jpiTimestampTz:
1250 if (unwrap && JsonbType(jb) == jbvArray)
1251 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1252
1253 return executeDateTimeMethod(cxt, jsp, jb, found);
1254
1255 case jpiKeyValue:
1256 if (unwrap && JsonbType(jb) == jbvArray)
1257 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1258
1259 return executeKeyValueMethod(cxt, jsp, jb, found);
1260
1261 case jpiLast:
1262 {
1264 int last;
1265 bool hasNext = jspGetNext(jsp, &elem);
1266
1267 if (cxt->innermostArraySize < 0)
1268 elog(ERROR, "evaluating jsonpath LAST outside of array subscript");
1269
1270 if (!hasNext && !found)
1271 {
1272 res = jperOk;
1273 break;
1274 }
1275
1276 last = cxt->innermostArraySize - 1;
1277
1278 jbv.type = jbvNumeric;
1279 jbv.val.numeric = int64_to_numeric(last);
1280
1281 res = executeNextItem(cxt, jsp, &elem,
1282 &jbv, found);
1283 }
1284 break;
1285
1286 case jpiBigint:
1287 {
1289 Datum datum;
1290
1291 if (unwrap && JsonbType(jb) == jbvArray)
1292 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1293 false);
1294
1295 if (jb->type == jbvNumeric)
1296 {
1298 int64 val;
1299
1300 val = numeric_int8_safe(jb->val.numeric,
1301 (Node *) &escontext);
1302 if (escontext.error_occurred)
1305 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1307 NumericGetDatum(jb->val.numeric))),
1308 jspOperationName(jsp->type),
1309 "bigint"))));
1310
1311 datum = Int64GetDatum(val);
1312 res = jperOk;
1313 }
1314 else if (jb->type == jbvString)
1315 {
1316 /* cast string as bigint */
1317 char *tmp = pnstrdup(jb->val.string.val,
1318 jb->val.string.len);
1320 bool noerr;
1321
1323 InvalidOid, -1,
1324 (Node *) &escontext,
1325 &datum);
1326
1327 if (!noerr || escontext.error_occurred)
1330 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1331 tmp, jspOperationName(jsp->type), "bigint"))));
1332 res = jperOk;
1333 }
1334
1335 if (res == jperNotFound)
1338 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1339 jspOperationName(jsp->type)))));
1340
1341 jbv.type = jbvNumeric;
1343 datum));
1344
1345 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1346 }
1347 break;
1348
1349 case jpiBoolean:
1350 {
1352 bool bval;
1353
1354 if (unwrap && JsonbType(jb) == jbvArray)
1355 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1356 false);
1357
1358 if (jb->type == jbvBool)
1359 {
1360 bval = jb->val.boolean;
1361
1362 res = jperOk;
1363 }
1364 else if (jb->type == jbvNumeric)
1365 {
1366 int ival;
1367 Datum datum;
1368 bool noerr;
1370 NumericGetDatum(jb->val.numeric)));
1372
1374 InvalidOid, -1,
1375 (Node *) &escontext,
1376 &datum);
1377
1378 if (!noerr || escontext.error_occurred)
1381 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1382 tmp, jspOperationName(jsp->type), "boolean"))));
1383
1384 ival = DatumGetInt32(datum);
1385 if (ival == 0)
1386 bval = false;
1387 else
1388 bval = true;
1389
1390 res = jperOk;
1391 }
1392 else if (jb->type == jbvString)
1393 {
1394 /* cast string as boolean */
1395 char *tmp = pnstrdup(jb->val.string.val,
1396 jb->val.string.len);
1397
1398 if (!parse_bool(tmp, &bval))
1401 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1402 tmp, jspOperationName(jsp->type), "boolean"))));
1403
1404 res = jperOk;
1405 }
1406
1407 if (res == jperNotFound)
1410 errmsg("jsonpath item method .%s() can only be applied to a boolean, string, or numeric value",
1411 jspOperationName(jsp->type)))));
1412
1413 jbv.type = jbvBool;
1414 jbv.val.boolean = bval;
1415
1416 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1417 }
1418 break;
1419
1420 case jpiDecimal:
1421 case jpiNumber:
1422 {
1424 Numeric num;
1425 char *numstr = NULL;
1426
1427 if (unwrap && JsonbType(jb) == jbvArray)
1428 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1429 false);
1430
1431 if (jb->type == jbvNumeric)
1432 {
1433 num = jb->val.numeric;
1434 if (numeric_is_nan(num) || numeric_is_inf(num))
1437 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1438 jspOperationName(jsp->type)))));
1439
1440 if (jsp->type == jpiDecimal)
1442 NumericGetDatum(num)));
1443 res = jperOk;
1444 }
1445 else if (jb->type == jbvString)
1446 {
1447 /* cast string as number */
1448 Datum datum;
1449 bool noerr;
1451
1452 numstr = pnstrdup(jb->val.string.val, jb->val.string.len);
1453
1455 InvalidOid, -1,
1456 (Node *) &escontext,
1457 &datum);
1458
1459 if (!noerr || escontext.error_occurred)
1462 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1463 numstr, jspOperationName(jsp->type), "numeric"))));
1464
1465 num = DatumGetNumeric(datum);
1466 if (numeric_is_nan(num) || numeric_is_inf(num))
1469 errmsg("NaN or Infinity is not allowed for jsonpath item method .%s()",
1470 jspOperationName(jsp->type)))));
1471
1472 res = jperOk;
1473 }
1474
1475 if (res == jperNotFound)
1478 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1479 jspOperationName(jsp->type)))));
1480
1481 /*
1482 * If we have arguments, then they must be the precision and
1483 * optional scale used in .decimal(). Convert them to the
1484 * typmod equivalent and then truncate the numeric value per
1485 * this typmod details.
1486 */
1487 if (jsp->type == jpiDecimal && jsp->content.args.left)
1488 {
1490 Datum dtypmod;
1491 int32 precision;
1492 int32 scale = 0;
1493 bool noerr;
1495 Datum datums[2];
1496 char pstr[12]; /* sign, 10 digits and '\0' */
1497 char sstr[12]; /* sign, 10 digits and '\0' */
1499
1500 jspGetLeftArg(jsp, &elem);
1501 if (elem.type != jpiNumeric)
1502 elog(ERROR, "invalid jsonpath item type for .decimal() precision");
1503
1504 precision = numeric_int4_safe(jspGetNumeric(&elem),
1505 (Node *) &escontext);
1506 if (escontext.error_occurred)
1509 errmsg("precision of jsonpath item method .%s() is out of range for type integer",
1510 jspOperationName(jsp->type)))));
1511
1512 if (jsp->content.args.right)
1513 {
1514 jspGetRightArg(jsp, &elem);
1515 if (elem.type != jpiNumeric)
1516 elog(ERROR, "invalid jsonpath item type for .decimal() scale");
1517
1519 (Node *) &escontext);
1520 if (escontext.error_occurred)
1523 errmsg("scale of jsonpath item method .%s() is out of range for type integer",
1524 jspOperationName(jsp->type)))));
1525 }
1526
1527 /*
1528 * numerictypmodin() takes the precision and scale in the
1529 * form of CString arrays.
1530 */
1531 pg_ltoa(precision, pstr);
1532 datums[0] = CStringGetDatum(pstr);
1533 pg_ltoa(scale, sstr);
1534 datums[1] = CStringGetDatum(sstr);
1536
1539
1540 /* Convert numstr to Numeric with typmod */
1541 Assert(numstr != NULL);
1544 (Node *) &escontext,
1545 &numdatum);
1546
1547 if (!noerr || escontext.error_occurred)
1550 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1551 numstr, jspOperationName(jsp->type), "numeric"))));
1552
1555 }
1556
1557 jbv.type = jbvNumeric;
1558 jbv.val.numeric = num;
1559
1560 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1561 }
1562 break;
1563
1564 case jpiInteger:
1565 {
1567 Datum datum;
1568
1569 if (unwrap && JsonbType(jb) == jbvArray)
1570 return executeItemUnwrapTargetArray(cxt, jsp, jb, found,
1571 false);
1572
1573 if (jb->type == jbvNumeric)
1574 {
1575 int32 val;
1577
1578 val = numeric_int4_safe(jb->val.numeric,
1579 (Node *) &escontext);
1580 if (escontext.error_occurred)
1583 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1585 NumericGetDatum(jb->val.numeric))),
1586 jspOperationName(jsp->type), "integer"))));
1587
1588 datum = Int32GetDatum(val);
1589 res = jperOk;
1590 }
1591 else if (jb->type == jbvString)
1592 {
1593 /* cast string as integer */
1594 char *tmp = pnstrdup(jb->val.string.val,
1595 jb->val.string.len);
1597 bool noerr;
1598
1600 InvalidOid, -1,
1601 (Node *) &escontext,
1602 &datum);
1603
1604 if (!noerr || escontext.error_occurred)
1607 errmsg("argument \"%s\" of jsonpath item method .%s() is invalid for type %s",
1608 tmp, jspOperationName(jsp->type), "integer"))));
1609 res = jperOk;
1610 }
1611
1612 if (res == jperNotFound)
1615 errmsg("jsonpath item method .%s() can only be applied to a string or numeric value",
1616 jspOperationName(jsp->type)))));
1617
1618 jbv.type = jbvNumeric;
1620 datum));
1621
1622 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1623 }
1624 break;
1625
1626 case jpiStringFunc:
1627 {
1629 char *tmp = NULL;
1630
1631 if (unwrap && JsonbType(jb) == jbvArray)
1632 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
1633
1634 switch (JsonbType(jb))
1635 {
1636 case jbvString:
1637
1638 /*
1639 * Value is not necessarily null-terminated, so we do
1640 * pnstrdup() here.
1641 */
1642 tmp = pnstrdup(jb->val.string.val,
1643 jb->val.string.len);
1644 break;
1645 case jbvNumeric:
1647 NumericGetDatum(jb->val.numeric)));
1648 break;
1649 case jbvBool:
1650 tmp = (jb->val.boolean) ? "true" : "false";
1651 break;
1652 case jbvDatetime:
1653 {
1654 char buf[MAXDATELEN + 1];
1655
1657 jb->val.datetime.value,
1658 jb->val.datetime.typid,
1659 &jb->val.datetime.tz);
1660 tmp = pstrdup(buf);
1661 }
1662 break;
1663 case jbvNull:
1664 case jbvArray:
1665 case jbvObject:
1666 case jbvBinary:
1669 errmsg("jsonpath item method .%s() can only be applied to a boolean, string, numeric, or datetime value",
1670 jspOperationName(jsp->type)))));
1671 break;
1672 }
1673
1674 Assert(tmp != NULL); /* We must have set tmp above */
1675 jbv.val.string.val = tmp;
1676 jbv.val.string.len = strlen(jbv.val.string.val);
1677 jbv.type = jbvString;
1678
1679 res = executeNextItem(cxt, jsp, NULL, &jbv, found);
1680 }
1681 break;
1682
1683 default:
1684 elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
1685 }
1686
1687 return res;
1688}
1689
1690/*
1691 * Unwrap current array item and execute jsonpath for each of its elements.
1692 */
1693static JsonPathExecResult
1695 JsonbValue *jb, JsonValueList *found,
1696 bool unwrapElements)
1697{
1698 if (jb->type != jbvBinary)
1699 {
1700 Assert(jb->type != jbvArray);
1701 elog(ERROR, "invalid jsonb array value type: %d", jb->type);
1702 }
1703
1704 return executeAnyItem
1705 (cxt, jsp, jb->val.binary.data, found, 1, 1, 1,
1706 false, unwrapElements);
1707}
1708
1709/*
1710 * Execute next jsonpath item if exists. Otherwise put "v" to the "found"
1711 * list if provided.
1712 */
1713static JsonPathExecResult
1716 JsonbValue *v, JsonValueList *found)
1717{
1718 JsonPathItem elem;
1719 bool hasNext;
1720
1721 if (!cur)
1722 hasNext = next != NULL;
1723 else if (next)
1725 else
1726 {
1727 next = &elem;
1729 }
1730
1731 if (hasNext)
1732 return executeItem(cxt, next, v, found);
1733
1734 if (found)
1735 JsonValueListAppend(found, v);
1736
1737 return jperOk;
1738}
1739
1740/*
1741 * Same as executeItem(), but when "unwrap == true" automatically unwraps
1742 * each array item from the resulting sequence in lax mode.
1743 */
1744static JsonPathExecResult
1746 JsonbValue *jb, bool unwrap,
1747 JsonValueList *found)
1748{
1749 if (unwrap && jspAutoUnwrap(cxt))
1750 {
1754 JsonbValue *item;
1755
1757
1758 res = executeItem(cxt, jsp, jb, &seq);
1759
1760 if (jperIsError(res))
1761 {
1763 return res;
1764 }
1765
1767 while ((item = JsonValueListNext(&it)))
1768 {
1769 Assert(item->type != jbvArray);
1770
1771 if (JsonbType(item) == jbvArray)
1772 executeItemUnwrapTargetArray(cxt, NULL, item, found, false);
1773 else
1774 JsonValueListAppend(found, item);
1775 }
1776
1778
1779 return jperOk;
1780 }
1781
1782 return executeItem(cxt, jsp, jb, found);
1783}
1784
1785/*
1786 * Same as executeItemOptUnwrapResult(), but with error suppression.
1787 */
1788static JsonPathExecResult
1791 JsonbValue *jb, bool unwrap,
1792 JsonValueList *found)
1793{
1795 bool throwErrors = cxt->throwErrors;
1796
1797 cxt->throwErrors = false;
1798 res = executeItemOptUnwrapResult(cxt, jsp, jb, unwrap, found);
1799 cxt->throwErrors = throwErrors;
1800
1801 return res;
1802}
1803
1804/* Execute boolean-valued jsonpath expression. */
1805static JsonPathBool
1807 JsonbValue *jb, bool canHaveNext)
1808{
1809 JsonPathItem larg;
1810 JsonPathItem rarg;
1811 JsonPathBool res;
1813
1814 /* since this function recurses, it could be driven to stack overflow */
1816
1817 if (!canHaveNext && jspHasNext(jsp))
1818 elog(ERROR, "boolean jsonpath item cannot have next item");
1819
1820 switch (jsp->type)
1821 {
1822 case jpiAnd:
1823 jspGetLeftArg(jsp, &larg);
1824 res = executeBoolItem(cxt, &larg, jb, false);
1825
1826 if (res == jpbFalse)
1827 return jpbFalse;
1828
1829 /*
1830 * SQL/JSON says that we should check second arg in case of
1831 * jperError
1832 */
1833
1834 jspGetRightArg(jsp, &rarg);
1835 res2 = executeBoolItem(cxt, &rarg, jb, false);
1836
1837 return res2 == jpbTrue ? res : res2;
1838
1839 case jpiOr:
1840 jspGetLeftArg(jsp, &larg);
1841 res = executeBoolItem(cxt, &larg, jb, false);
1842
1843 if (res == jpbTrue)
1844 return jpbTrue;
1845
1846 jspGetRightArg(jsp, &rarg);
1847 res2 = executeBoolItem(cxt, &rarg, jb, false);
1848
1849 return res2 == jpbFalse ? res : res2;
1850
1851 case jpiNot:
1852 jspGetArg(jsp, &larg);
1853
1854 res = executeBoolItem(cxt, &larg, jb, false);
1855
1856 if (res == jpbUnknown)
1857 return jpbUnknown;
1858
1859 return res == jpbTrue ? jpbFalse : jpbTrue;
1860
1861 case jpiIsUnknown:
1862 jspGetArg(jsp, &larg);
1863 res = executeBoolItem(cxt, &larg, jb, false);
1864 return res == jpbUnknown ? jpbTrue : jpbFalse;
1865
1866 case jpiEqual:
1867 case jpiNotEqual:
1868 case jpiLess:
1869 case jpiGreater:
1870 case jpiLessOrEqual:
1871 case jpiGreaterOrEqual:
1872 jspGetLeftArg(jsp, &larg);
1873 jspGetRightArg(jsp, &rarg);
1874 return executePredicate(cxt, jsp, &larg, &rarg, jb, true,
1875 executeComparison, cxt);
1876
1877 case jpiStartsWith: /* 'whole STARTS WITH initial' */
1878 jspGetLeftArg(jsp, &larg); /* 'whole' */
1879 jspGetRightArg(jsp, &rarg); /* 'initial' */
1880 return executePredicate(cxt, jsp, &larg, &rarg, jb, false,
1882
1883 case jpiLikeRegex: /* 'expr LIKE_REGEX pattern FLAGS flags' */
1884 {
1885 /*
1886 * 'expr' is a sequence-returning expression. 'pattern' is a
1887 * regex string literal. SQL/JSON standard requires XQuery
1888 * regexes, but we use Postgres regexes here. 'flags' is a
1889 * string literal converted to integer flags at compile-time.
1890 */
1892
1893 jspInitByBuffer(&larg, jsp->base,
1894 jsp->content.like_regex.expr);
1895
1896 return executePredicate(cxt, jsp, &larg, NULL, jb, false,
1898 }
1899
1900 case jpiExists:
1901 jspGetArg(jsp, &larg);
1902
1903 if (jspStrictAbsenceOfErrors(cxt))
1904 {
1905 /*
1906 * In strict mode we must get a complete list of values to
1907 * check that there are no errors at all.
1908 */
1909 JsonValueList vals;
1911 bool isempty;
1912
1913 JsonValueListInit(&vals);
1914
1915 res = executeItemOptUnwrapResultNoThrow(cxt, &larg, jb,
1916 false, &vals);
1917
1919 JsonValueListClear(&vals);
1920
1921 if (jperIsError(res))
1922 return jpbUnknown;
1923
1924 return isempty ? jpbFalse : jpbTrue;
1925 }
1926 else
1927 {
1928 JsonPathExecResult res =
1930 false, NULL);
1931
1932 if (jperIsError(res))
1933 return jpbUnknown;
1934
1935 return res == jperOk ? jpbTrue : jpbFalse;
1936 }
1937
1938 default:
1939 elog(ERROR, "invalid boolean jsonpath item type: %d", jsp->type);
1940 return jpbUnknown;
1941 }
1942}
1943
1944/*
1945 * Execute nested (filters etc.) boolean expression pushing current SQL/JSON
1946 * item onto the stack.
1947 */
1948static JsonPathBool
1950 JsonbValue *jb)
1951{
1952 JsonbValue *prev;
1953 JsonPathBool res;
1954
1955 prev = cxt->current;
1956 cxt->current = jb;
1957 res = executeBoolItem(cxt, jsp, jb, false);
1958 cxt->current = prev;
1959
1960 return res;
1961}
1962
1963/*
1964 * Implementation of several jsonpath nodes:
1965 * - jpiAny (.** accessor),
1966 * - jpiAnyKey (.* accessor),
1967 * - jpiAnyArray ([*] accessor)
1968 */
1969static JsonPathExecResult
1971 JsonValueList *found, uint32 level, uint32 first, uint32 last,
1972 bool ignoreStructuralErrors, bool unwrapNext)
1973{
1976 int32 r;
1977 JsonbValue v;
1978
1980
1981 if (level > last)
1982 return res;
1983
1984 it = JsonbIteratorInit(jbc);
1985
1986 /*
1987 * Recursively iterate over jsonb objects/arrays
1988 */
1989 while ((r = JsonbIteratorNext(&it, &v, true)) != WJB_DONE)
1990 {
1991 if (r == WJB_KEY)
1992 {
1993 r = JsonbIteratorNext(&it, &v, true);
1994 Assert(r == WJB_VALUE);
1995 }
1996
1997 if (r == WJB_VALUE || r == WJB_ELEM)
1998 {
1999
2000 if (level >= first ||
2001 (first == PG_UINT32_MAX && last == PG_UINT32_MAX &&
2002 v.type != jbvBinary)) /* leaves only requested */
2003 {
2004 /* check expression */
2005 if (jsp)
2006 {
2007 if (ignoreStructuralErrors)
2008 {
2010
2012 cxt->ignoreStructuralErrors = true;
2013 res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
2015 }
2016 else
2017 res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext);
2018
2019 if (jperIsError(res))
2020 break;
2021
2022 if (res == jperOk && !found)
2023 break;
2024 }
2025 else if (found)
2026 JsonValueListAppend(found, &v);
2027 else
2028 return jperOk;
2029 }
2030
2031 if (level < last && v.type == jbvBinary)
2032 {
2033 res = executeAnyItem
2034 (cxt, jsp, v.val.binary.data, found,
2035 level + 1, first, last,
2036 ignoreStructuralErrors, unwrapNext);
2037
2038 if (jperIsError(res))
2039 break;
2040
2041 if (res == jperOk && found == NULL)
2042 break;
2043 }
2044 }
2045 }
2046
2047 return res;
2048}
2049
2050/*
2051 * Execute unary or binary predicate.
2052 *
2053 * Predicates have existence semantics, because their operands are item
2054 * sequences. Pairs of items from the left and right operand's sequences are
2055 * checked. TRUE returned only if any pair satisfying the condition is found.
2056 * In strict mode, even if the desired pair has already been found, all pairs
2057 * still need to be examined to check the absence of errors. If any error
2058 * occurs, UNKNOWN (analogous to SQL NULL) is returned.
2059 */
2060static JsonPathBool
2062 JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb,
2064 void *param)
2065{
2070 JsonbValue *lval;
2071 bool error = false;
2072 bool found = false;
2073
2076
2077 /* Left argument is always auto-unwrapped. */
2078 res = executeItemOptUnwrapResultNoThrow(cxt, larg, jb, true, &lseq);
2079 if (jperIsError(res))
2080 {
2081 error = true;
2082 goto exit;
2083 }
2084
2085 if (rarg)
2086 {
2087 /* Right argument is conditionally auto-unwrapped. */
2088 res = executeItemOptUnwrapResultNoThrow(cxt, rarg, jb,
2090 if (jperIsError(res))
2091 {
2092 error = true;
2093 goto exit;
2094 }
2095 }
2096
2098 while ((lval = JsonValueListNext(&lseqit)))
2099 {
2102 bool first = true;
2103
2105 if (rarg)
2107 else
2108 rval = NULL;
2109
2110 /* Loop over right arg sequence or do single pass otherwise */
2111 while (rarg ? (rval != NULL) : first)
2112 {
2113 JsonPathBool res = exec(pred, lval, rval, param);
2114
2115 if (res == jpbUnknown)
2116 {
2117 error = true;
2118 if (jspStrictAbsenceOfErrors(cxt))
2119 {
2120 found = false; /* return unknown, not success */
2121 goto exit;
2122 }
2123 }
2124 else if (res == jpbTrue)
2125 {
2126 found = true;
2127 if (!jspStrictAbsenceOfErrors(cxt))
2128 goto exit;
2129 }
2130
2131 first = false;
2132 if (rarg)
2134 }
2135 }
2136
2137exit:
2140
2141 if (found) /* possible only in strict mode */
2142 return jpbTrue;
2143
2144 if (error) /* possible only in lax mode */
2145 return jpbUnknown;
2146
2147 return jpbFalse;
2148}
2149
2150/*
2151 * Execute binary arithmetic expression on singleton numeric operands.
2152 * Array operands are automatically unwrapped in lax mode.
2153 */
2154static JsonPathExecResult
2157 JsonValueList *found)
2158{
2160 JsonPathItem elem;
2163 JsonbValue *lval;
2166 Numeric res;
2167
2170
2171 jspGetLeftArg(jsp, &elem);
2172
2173 /*
2174 * XXX: By standard only operands of multiplicative expressions are
2175 * unwrapped. We extend it to other binary arithmetic expressions too.
2176 */
2177 jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &lseq);
2178 if (jperIsError(jper))
2179 {
2182 return jper;
2183 }
2184
2185 jspGetRightArg(jsp, &elem);
2186
2187 jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &rseq);
2188 if (jperIsError(jper))
2189 {
2192 return jper;
2193 }
2194
2197 {
2202 errmsg("left operand of jsonpath operator %s is not a single numeric value",
2203 jspOperationName(jsp->type)))));
2204 }
2205
2208 {
2213 errmsg("right operand of jsonpath operator %s is not a single numeric value",
2214 jspOperationName(jsp->type)))));
2215 }
2216
2217 if (jspThrowErrors(cxt))
2218 {
2219 res = func(lval->val.numeric, rval->val.numeric, NULL);
2220 }
2221 else
2222 {
2224
2225 res = func(lval->val.numeric, rval->val.numeric, (Node *) &escontext);
2226
2227 if (escontext.error_occurred)
2228 {
2231 return jperError;
2232 }
2233 }
2234
2237
2238 if (!jspGetNext(jsp, &elem) && !found)
2239 return jperOk;
2240
2241 resval.type = jbvNumeric;
2242 resval.val.numeric = res;
2243
2244 return executeNextItem(cxt, jsp, &elem, &resval, found);
2245}
2246
2247/*
2248 * Execute unary arithmetic expression for each numeric item in its operand's
2249 * sequence. Array operand is automatically unwrapped in lax mode.
2250 */
2251static JsonPathExecResult
2253 JsonbValue *jb, PGFunction func, JsonValueList *found)
2254{
2257 JsonPathItem elem;
2260 JsonbValue *val;
2261 bool hasNext;
2262
2264
2265 jspGetArg(jsp, &elem);
2266 jper = executeItemOptUnwrapResult(cxt, &elem, jb, true, &seq);
2267
2268 if (jperIsError(jper))
2269 goto exit;
2270
2272
2273 hasNext = jspGetNext(jsp, &elem);
2274
2276 while ((val = JsonValueListNext(&it)))
2277 {
2278 if ((val = getScalar(val, jbvNumeric)))
2279 {
2280 if (!found && !hasNext)
2281 {
2282 jper = jperOk;
2283 goto exit;
2284 }
2285 }
2286 else
2287 {
2288 if (!found && !hasNext)
2289 continue; /* skip non-numerics processing */
2290
2294 errmsg("operand of unary jsonpath operator %s is not a numeric value",
2295 jspOperationName(jsp->type)))));
2296 }
2297
2298 if (func)
2299 val->val.numeric =
2301 NumericGetDatum(val->val.numeric)));
2302
2303 jper2 = executeNextItem(cxt, jsp, &elem, val, found);
2304
2305 if (jperIsError(jper2))
2306 {
2307 jper = jper2;
2308 goto exit;
2309 }
2310
2311 if (jper2 == jperOk)
2312 {
2313 jper = jperOk;
2314 if (!found)
2315 goto exit;
2316 }
2317 }
2318
2319exit:
2321
2322 return jper;
2323}
2324
2325/*
2326 * STARTS_WITH predicate callback.
2327 *
2328 * Check if the 'whole' string starts from 'initial' string.
2329 */
2330static JsonPathBool
2332 void *param)
2333{
2334 if (!(whole = getScalar(whole, jbvString)))
2335 return jpbUnknown; /* error */
2336
2338 return jpbUnknown; /* error */
2339
2340 if (whole->val.string.len >= initial->val.string.len &&
2341 !memcmp(whole->val.string.val,
2342 initial->val.string.val,
2343 initial->val.string.len))
2344 return jpbTrue;
2345
2346 return jpbFalse;
2347}
2348
2349/*
2350 * LIKE_REGEX predicate callback.
2351 *
2352 * Check if the string matches regex pattern.
2353 */
2354static JsonPathBool
2356 void *param)
2357{
2358 JsonLikeRegexContext *cxt = param;
2359
2360 if (!(str = getScalar(str, jbvString)))
2361 return jpbUnknown;
2362
2363 /* Cache regex text and converted flags. */
2364 if (!cxt->regex)
2365 {
2366 cxt->regex =
2367 cstring_to_text_with_len(jsp->content.like_regex.pattern,
2368 jsp->content.like_regex.patternlen);
2369 (void) jspConvertRegexFlags(jsp->content.like_regex.flags,
2370 &(cxt->cflags), NULL);
2371 }
2372
2373 if (RE_compile_and_execute(cxt->regex, str->val.string.val,
2374 str->val.string.len,
2376 return jpbTrue;
2377
2378 return jpbFalse;
2379}
2380
2381/*
2382 * Execute numeric item methods (.abs(), .floor(), .ceil()) using the specified
2383 * user function 'func'.
2384 */
2385static JsonPathExecResult
2387 JsonbValue *jb, bool unwrap, PGFunction func,
2388 JsonValueList *found)
2389{
2391 Datum datum;
2393
2394 if (unwrap && JsonbType(jb) == jbvArray)
2395 return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false);
2396
2397 if (!(jb = getScalar(jb, jbvNumeric)))
2400 errmsg("jsonpath item method .%s() can only be applied to a numeric value",
2401 jspOperationName(jsp->type)))));
2402
2403 datum = DirectFunctionCall1(func, NumericGetDatum(jb->val.numeric));
2404
2405 if (!jspGetNext(jsp, &next) && !found)
2406 return jperOk;
2407
2408 jbv.type = jbvNumeric;
2409 jbv.val.numeric = DatumGetNumeric(datum);
2410
2411 return executeNextItem(cxt, jsp, &next, &jbv, found);
2412}
2413
2414/*
2415 * Implementation of the .datetime() and related methods.
2416 *
2417 * Converts a string into a date/time value. The actual type is determined at
2418 * run time.
2419 * If an argument is provided, this argument is used as a template string.
2420 * Otherwise, the first fitting ISO format is selected.
2421 *
2422 * .date(), .time(), .time_tz(), .timestamp(), .timestamp_tz() methods don't
2423 * have a format, so ISO format is used. However, except for .date(), they all
2424 * take an optional time precision.
2425 */
2426static JsonPathExecResult
2428 JsonbValue *jb, JsonValueList *found)
2429{
2431 Datum value;
2432 text *datetime;
2433 Oid collid;
2434 Oid typid;
2435 int32 typmod = -1;
2436 int tz = 0;
2437 bool hasNext;
2439 JsonPathItem elem;
2440 int32 time_precision = -1;
2441
2442 if (!(jb = getScalar(jb, jbvString)))
2445 errmsg("jsonpath item method .%s() can only be applied to a string",
2446 jspOperationName(jsp->type)))));
2447
2448 datetime = cstring_to_text_with_len(jb->val.string.val,
2449 jb->val.string.len);
2450
2451 /*
2452 * At some point we might wish to have callers supply the collation to
2453 * use, but right now it's unclear that they'd be able to do better than
2454 * DEFAULT_COLLATION_OID anyway.
2455 */
2457
2458 /*
2459 * .datetime(template) has an argument, the rest of the methods don't have
2460 * an argument. So we handle that separately.
2461 */
2462 if (jsp->type == jpiDatetime && jsp->content.arg)
2463 {
2464 text *template;
2465 char *template_str;
2466 int template_len;
2468
2469 jspGetArg(jsp, &elem);
2470
2471 if (elem.type != jpiString)
2472 elog(ERROR, "invalid jsonpath item type for .datetime() argument");
2473
2475
2477 template_len);
2478
2479 value = parse_datetime(datetime, template, collid, true,
2480 &typid, &typmod, &tz,
2481 jspThrowErrors(cxt) ? NULL : (Node *) &escontext);
2482
2483 if (escontext.error_occurred)
2484 res = jperError;
2485 else
2486 res = jperOk;
2487 }
2488 else
2489 {
2490 /*
2491 * According to SQL/JSON standard enumerate ISO formats for: date,
2492 * timetz, time, timestamptz, timestamp.
2493 *
2494 * We also support ISO 8601 format (with "T") for timestamps, because
2495 * to_json[b]() functions use this format.
2496 */
2497 static const char *fmt_str[] =
2498 {
2499 "yyyy-mm-dd", /* date */
2500 "HH24:MI:SS.USTZ", /* timetz */
2501 "HH24:MI:SSTZ",
2502 "HH24:MI:SS.US", /* time without tz */
2503 "HH24:MI:SS",
2504 "yyyy-mm-dd HH24:MI:SS.USTZ", /* timestamptz */
2505 "yyyy-mm-dd HH24:MI:SSTZ",
2506 "yyyy-mm-dd\"T\"HH24:MI:SS.USTZ",
2507 "yyyy-mm-dd\"T\"HH24:MI:SSTZ",
2508 "yyyy-mm-dd HH24:MI:SS.US", /* timestamp without tz */
2509 "yyyy-mm-dd HH24:MI:SS",
2510 "yyyy-mm-dd\"T\"HH24:MI:SS.US",
2511 "yyyy-mm-dd\"T\"HH24:MI:SS"
2512 };
2513
2514 /* cache for format texts */
2515 static text *fmt_txt[lengthof(fmt_str)] = {0};
2516 int i;
2517
2518 /*
2519 * Check for optional precision for methods other than .datetime() and
2520 * .date()
2521 */
2522 if (jsp->type != jpiDatetime && jsp->type != jpiDate &&
2523 jsp->content.arg)
2524 {
2526
2527 jspGetArg(jsp, &elem);
2528
2529 if (elem.type != jpiNumeric)
2530 elog(ERROR, "invalid jsonpath item type for %s argument",
2531 jspOperationName(jsp->type));
2532
2534 (Node *) &escontext);
2535 if (escontext.error_occurred)
2538 errmsg("time precision of jsonpath item method .%s() is out of range for type integer",
2539 jspOperationName(jsp->type)))));
2540 }
2541
2542 /* loop until datetime format fits */
2543 for (i = 0; i < lengthof(fmt_str); i++)
2544 {
2546
2547 if (!fmt_txt[i])
2548 {
2551
2554 }
2555
2556 value = parse_datetime(datetime, fmt_txt[i], collid, true,
2557 &typid, &typmod, &tz,
2558 (Node *) &escontext);
2559
2560 if (!escontext.error_occurred)
2561 {
2562 res = jperOk;
2563 break;
2564 }
2565 }
2566
2567 if (res == jperNotFound)
2568 {
2569 if (jsp->type == jpiDatetime)
2572 errmsg("%s format is not recognized: \"%s\"",
2573 "datetime", text_to_cstring(datetime)),
2574 errhint("Use a datetime template argument to specify the input data format."))));
2575 else
2578 errmsg("%s format is not recognized: \"%s\"",
2579 jspOperationName(jsp->type), text_to_cstring(datetime)))));
2580
2581 }
2582 }
2583
2584 /*
2585 * parse_datetime() processes the entire input string per the template or
2586 * ISO format and returns the Datum in best fitted datetime type. So, if
2587 * this call is for a specific datatype, then we do the conversion here.
2588 * Throw an error for incompatible types.
2589 */
2590 switch (jsp->type)
2591 {
2592 case jpiDatetime: /* Nothing to do for DATETIME */
2593 break;
2594 case jpiDate:
2595 {
2596 /* Convert result type to date */
2597 switch (typid)
2598 {
2599 case DATEOID: /* Nothing to do for DATE */
2600 break;
2601 case TIMEOID:
2602 case TIMETZOID:
2605 errmsg("%s format is not recognized: \"%s\"",
2606 "date", text_to_cstring(datetime)))));
2607 break;
2608 case TIMESTAMPOID:
2610 value);
2611 break;
2612 case TIMESTAMPTZOID:
2614 "timestamptz", "date");
2616 value);
2617 break;
2618 default:
2619 elog(ERROR, "type with oid %u not supported", typid);
2620 }
2621
2622 typid = DATEOID;
2623 }
2624 break;
2625 case jpiTime:
2626 {
2627 /* Convert result type to time without time zone */
2628 switch (typid)
2629 {
2630 case DATEOID:
2633 errmsg("%s format is not recognized: \"%s\"",
2634 "time", text_to_cstring(datetime)))));
2635 break;
2636 case TIMEOID: /* Nothing to do for TIME */
2637 break;
2638 case TIMETZOID:
2640 "timetz", "time");
2642 value);
2643 break;
2644 case TIMESTAMPOID:
2646 value);
2647 break;
2648 case TIMESTAMPTZOID:
2650 "timestamptz", "time");
2652 value);
2653 break;
2654 default:
2655 elog(ERROR, "type with oid %u not supported", typid);
2656 }
2657
2658 /* Force the user-given time precision, if any */
2659 if (time_precision != -1)
2660 {
2661 TimeADT result;
2662
2663 /* Get a warning when precision is reduced */
2666 result = DatumGetTimeADT(value);
2668 value = TimeADTGetDatum(result);
2669
2670 /* Update the typmod value with the user-given precision */
2671 typmod = time_precision;
2672 }
2673
2674 typid = TIMEOID;
2675 }
2676 break;
2677 case jpiTimeTz:
2678 {
2679 /* Convert result type to time with time zone */
2680 switch (typid)
2681 {
2682 case DATEOID:
2683 case TIMESTAMPOID:
2686 errmsg("%s format is not recognized: \"%s\"",
2687 "time_tz", text_to_cstring(datetime)))));
2688 break;
2689 case TIMEOID:
2691 "time", "timetz");
2693 value);
2694 break;
2695 case TIMETZOID: /* Nothing to do for TIMETZ */
2696 break;
2697 case TIMESTAMPTZOID:
2699 value);
2700 break;
2701 default:
2702 elog(ERROR, "type with oid %u not supported", typid);
2703 }
2704
2705 /* Force the user-given time precision, if any */
2706 if (time_precision != -1)
2707 {
2708 TimeTzADT *result;
2709
2710 /* Get a warning when precision is reduced */
2713 result = DatumGetTimeTzADTP(value);
2715 value = TimeTzADTPGetDatum(result);
2716
2717 /* Update the typmod value with the user-given precision */
2718 typmod = time_precision;
2719 }
2720
2721 typid = TIMETZOID;
2722 }
2723 break;
2724 case jpiTimestamp:
2725 {
2726 /* Convert result type to timestamp without time zone */
2727 switch (typid)
2728 {
2729 case DATEOID:
2731 value);
2732 break;
2733 case TIMEOID:
2734 case TIMETZOID:
2737 errmsg("%s format is not recognized: \"%s\"",
2738 "timestamp", text_to_cstring(datetime)))));
2739 break;
2740 case TIMESTAMPOID: /* Nothing to do for TIMESTAMP */
2741 break;
2742 case TIMESTAMPTZOID:
2744 "timestamptz", "timestamp");
2746 value);
2747 break;
2748 default:
2749 elog(ERROR, "type with oid %u not supported", typid);
2750 }
2751
2752 /* Force the user-given time precision, if any */
2753 if (time_precision != -1)
2754 {
2755 Timestamp result;
2757
2758 /* Get a warning when precision is reduced */
2761 result = DatumGetTimestamp(value);
2763 (Node *) &escontext);
2764 if (escontext.error_occurred) /* should not happen */
2767 errmsg("time precision of jsonpath item method .%s() is invalid",
2768 jspOperationName(jsp->type)))));
2769 value = TimestampGetDatum(result);
2770
2771 /* Update the typmod value with the user-given precision */
2772 typmod = time_precision;
2773 }
2774
2775 typid = TIMESTAMPOID;
2776 }
2777 break;
2778 case jpiTimestampTz:
2779 {
2780 struct pg_tm tm;
2781 fsec_t fsec;
2782
2783 /* Convert result type to timestamp with time zone */
2784 switch (typid)
2785 {
2786 case DATEOID:
2788 "date", "timestamptz");
2789
2790 /*
2791 * Get the timezone value explicitly since JsonbValue
2792 * keeps that separate.
2793 */
2795 &(tm.tm_year), &(tm.tm_mon), &(tm.tm_mday));
2796 tm.tm_hour = 0;
2797 tm.tm_min = 0;
2798 tm.tm_sec = 0;
2800
2802 value);
2803 break;
2804 case TIMEOID:
2805 case TIMETZOID:
2808 errmsg("%s format is not recognized: \"%s\"",
2809 "timestamp_tz", text_to_cstring(datetime)))));
2810 break;
2811 case TIMESTAMPOID:
2813 "timestamp", "timestamptz");
2814
2815 /*
2816 * Get the timezone value explicitly since JsonbValue
2817 * keeps that separate.
2818 */
2820 &fsec, NULL, NULL) == 0)
2823
2825 value);
2826 break;
2827 case TIMESTAMPTZOID: /* Nothing to do for TIMESTAMPTZ */
2828 break;
2829 default:
2830 elog(ERROR, "type with oid %u not supported", typid);
2831 }
2832
2833 /* Force the user-given time precision, if any */
2834 if (time_precision != -1)
2835 {
2836 Timestamp result;
2838
2839 /* Get a warning when precision is reduced */
2842 result = DatumGetTimestampTz(value);
2844 (Node *) &escontext);
2845 if (escontext.error_occurred) /* should not happen */
2848 errmsg("time precision of jsonpath item method .%s() is invalid",
2849 jspOperationName(jsp->type)))));
2850 value = TimestampTzGetDatum(result);
2851
2852 /* Update the typmod value with the user-given precision */
2853 typmod = time_precision;
2854 }
2855
2856 typid = TIMESTAMPTZOID;
2857 }
2858 break;
2859 default:
2860 elog(ERROR, "unrecognized jsonpath item type: %d", jsp->type);
2861 }
2862
2863 pfree(datetime);
2864
2865 if (jperIsError(res))
2866 return res;
2867
2868 hasNext = jspGetNext(jsp, &elem);
2869
2870 if (!hasNext && !found)
2871 return res;
2872
2873 jbv.type = jbvDatetime;
2874 jbv.val.datetime.value = value;
2875 jbv.val.datetime.typid = typid;
2876 jbv.val.datetime.typmod = typmod;
2877 jbv.val.datetime.tz = tz;
2878
2879 return executeNextItem(cxt, jsp, &elem, &jbv, found);
2880}
2881
2882/*
2883 * Implementation of .keyvalue() method.
2884 *
2885 * .keyvalue() method returns a sequence of object's key-value pairs in the
2886 * following format: '{ "key": key, "value": value, "id": id }'.
2887 *
2888 * "id" field is an object identifier which is constructed from the two parts:
2889 * base object id and its binary offset in base object's jsonb:
2890 * id = 10000000000 * base_object_id + obj_offset_in_base_object
2891 *
2892 * 10000000000 (10^10) -- is a first round decimal number greater than 2^32
2893 * (maximal offset in jsonb). Decimal multiplier is used here to improve the
2894 * readability of identifiers.
2895 *
2896 * Base object is usually a root object of the path: context item '$' or path
2897 * variable '$var', literals can't produce objects for now. But if the path
2898 * contains generated objects (.keyvalue() itself, for example), then they
2899 * become base object for the subsequent .keyvalue().
2900 *
2901 * Id of '$' is 0. Id of '$var' is its ordinal (positive) number in the list
2902 * of variables (see getJsonPathVariable()). Ids for generated objects
2903 * are assigned using global counter JsonPathExecContext.lastGeneratedObjectId.
2904 */
2905static JsonPathExecResult
2907 JsonbValue *jb, JsonValueList *found)
2908{
2911 JsonbContainer *jbc;
2912 JsonbValue key;
2920 int64 id;
2921 bool hasNext;
2922
2923 if (JsonbType(jb) != jbvObject || jb->type != jbvBinary)
2926 errmsg("jsonpath item method .%s() can only be applied to an object",
2927 jspOperationName(jsp->type)))));
2928
2929 jbc = jb->val.binary.data;
2930
2931 if (!JsonContainerSize(jbc))
2932 return jperNotFound; /* no key-value pairs */
2933
2935
2936 keystr.type = jbvString;
2937 keystr.val.string.val = "key";
2938 keystr.val.string.len = 3;
2939
2940 valstr.type = jbvString;
2941 valstr.val.string.val = "value";
2942 valstr.val.string.len = 5;
2943
2944 idstr.type = jbvString;
2945 idstr.val.string.val = "id";
2946 idstr.val.string.len = 2;
2947
2948 /* construct object id from its base object and offset inside that */
2949 id = jb->type != jbvBinary ? 0 :
2950 (int64) ((char *) jbc - (char *) cxt->baseObject.jbc);
2951 id += (int64) cxt->baseObject.id * INT64CONST(10000000000);
2952
2953 idval.type = jbvNumeric;
2954 idval.val.numeric = int64_to_numeric(id);
2955
2956 it = JsonbIteratorInit(jbc);
2957
2958 while ((tok = JsonbIteratorNext(&it, &key, true)) != WJB_DONE)
2959 {
2960 JsonBaseObjectInfo baseObject;
2961 JsonbValue obj;
2963 Jsonb *jsonb;
2964
2965 if (tok != WJB_KEY)
2966 continue;
2967
2968 res = jperOk;
2969
2970 if (!hasNext && !found)
2971 break;
2972
2973 tok = JsonbIteratorNext(&it, &val, true);
2974 Assert(tok == WJB_VALUE);
2975
2976 memset(&ps, 0, sizeof(ps));
2977
2979
2981 pushJsonbValue(&ps, WJB_VALUE, &key);
2982
2985
2988
2990
2991 jsonb = JsonbValueToJsonb(ps.result);
2992
2993 JsonbInitBinary(&obj, jsonb);
2994
2995 baseObject = setBaseObject(cxt, &obj, cxt->lastGeneratedObjectId++);
2996
2997 res = executeNextItem(cxt, jsp, &next, &obj, found);
2998
2999 cxt->baseObject = baseObject;
3000
3001 if (jperIsError(res))
3002 return res;
3003
3004 if (res == jperOk && !found)
3005 break;
3006 }
3007
3008 return res;
3009}
3010
3011/*
3012 * Convert boolean execution status 'res' to a boolean JSON item and execute
3013 * next jsonpath.
3014 */
3015static JsonPathExecResult
3017 JsonValueList *found, JsonPathBool res)
3018{
3021
3022 if (!jspGetNext(jsp, &next) && !found)
3023 return jperOk; /* found singleton boolean value */
3024
3025 if (res == jpbUnknown)
3026 {
3027 jbv.type = jbvNull;
3028 }
3029 else
3030 {
3031 jbv.type = jbvBool;
3032 jbv.val.boolean = res == jpbTrue;
3033 }
3034
3035 return executeNextItem(cxt, jsp, &next, &jbv, found);
3036}
3037
3038/*
3039 * Convert jsonpath's scalar or variable node to actual jsonb value.
3040 *
3041 * If node is a variable then its id returned, otherwise 0 returned.
3042 */
3043static void
3046{
3047 switch (item->type)
3048 {
3049 case jpiNull:
3050 value->type = jbvNull;
3051 break;
3052 case jpiBool:
3053 value->type = jbvBool;
3054 value->val.boolean = jspGetBool(item);
3055 break;
3056 case jpiNumeric:
3057 value->type = jbvNumeric;
3058 value->val.numeric = jspGetNumeric(item);
3059 break;
3060 case jpiString:
3061 value->type = jbvString;
3062 value->val.string.val = jspGetString(item,
3063 &value->val.string.len);
3064 break;
3065 case jpiVariable:
3066 getJsonPathVariable(cxt, item, value);
3067 return;
3068 default:
3069 elog(ERROR, "unexpected jsonpath item type");
3070 }
3071}
3072
3073/*
3074 * Returns the computed value of a JSON path variable with given name.
3075 */
3076static JsonbValue *
3077GetJsonPathVar(void *cxt, char *varName, int varNameLen,
3078 JsonbValue *baseObject, int *baseObjectId)
3079{
3080 JsonPathVariable *var = NULL;
3081 List *vars = cxt;
3082 ListCell *lc;
3083 JsonbValue *result;
3084 int id = 1;
3085
3086 foreach(lc, vars)
3087 {
3088 JsonPathVariable *curvar = lfirst(lc);
3089
3090 if (curvar->namelen == varNameLen &&
3091 strncmp(curvar->name, varName, varNameLen) == 0)
3092 {
3093 var = curvar;
3094 break;
3095 }
3096
3097 id++;
3098 }
3099
3100 if (var == NULL)
3101 {
3102 *baseObjectId = -1;
3103 return NULL;
3104 }
3105
3106 result = palloc_object(JsonbValue);
3107 if (var->isnull)
3108 {
3109 *baseObjectId = 0;
3110 result->type = jbvNull;
3111 }
3112 else
3113 JsonItemFromDatum(var->value, var->typid, var->typmod, result);
3114
3115 *baseObject = *result;
3116 *baseObjectId = id;
3117
3118 return result;
3119}
3120
3121static int
3123{
3124 List *vars = (List *) cxt;
3125
3126 return list_length(vars);
3127}
3128
3129
3130/*
3131 * Initialize JsonbValue to pass to jsonpath executor from given
3132 * datum value of the specified type.
3133 */
3134static void
3136{
3137 switch (typid)
3138 {
3139 case BOOLOID:
3140 res->type = jbvBool;
3141 res->val.boolean = DatumGetBool(val);
3142 break;
3143 case NUMERICOID:
3145 break;
3146 case INT2OID:
3148 break;
3149 case INT4OID:
3151 break;
3152 case INT8OID:
3154 break;
3155 case FLOAT4OID:
3157 break;
3158 case FLOAT8OID:
3160 break;
3161 case TEXTOID:
3162 case VARCHAROID:
3163 res->type = jbvString;
3164 res->val.string.val = VARDATA_ANY(DatumGetPointer(val));
3165 res->val.string.len = VARSIZE_ANY_EXHDR(DatumGetPointer(val));
3166 break;
3167 case DATEOID:
3168 case TIMEOID:
3169 case TIMETZOID:
3170 case TIMESTAMPOID:
3171 case TIMESTAMPTZOID:
3172 res->type = jbvDatetime;
3173 res->val.datetime.value = val;
3174 res->val.datetime.typid = typid;
3175 res->val.datetime.typmod = typmod;
3176 res->val.datetime.tz = 0;
3177 break;
3178 case JSONBOID:
3179 {
3180 JsonbValue *jbv = res;
3182
3183 if (JsonContainerIsScalar(&jb->root))
3184 {
3185 bool result PG_USED_FOR_ASSERTS_ONLY;
3186
3187 result = JsonbExtractScalar(&jb->root, jbv);
3188 Assert(result);
3189 }
3190 else
3192 break;
3193 }
3194 case JSONOID:
3195 {
3197 char *str = text_to_cstring(txt);
3198 Jsonb *jb;
3199
3202 pfree(str);
3203
3205 break;
3206 }
3207 default:
3208 ereport(ERROR,
3210 errmsg("could not convert value of type %s to jsonpath",
3211 format_type_be(typid)));
3212 }
3213}
3214
3215/* Initialize numeric value from the given datum */
3216static void
3218{
3219 jbv->type = jbvNumeric;
3220 jbv->val.numeric = DatumGetNumeric(num);
3221}
3222
3223/*
3224 * Get the value of variable passed to jsonpath executor
3225 */
3226static void
3229{
3230 char *varName;
3231 int varNameLength;
3232 JsonbValue baseObject;
3233 int baseObjectId;
3234 JsonbValue *v;
3235
3237 varName = jspGetString(variable, &varNameLength);
3238
3239 if (cxt->vars == NULL ||
3240 (v = cxt->getVar(cxt->vars, varName, varNameLength,
3241 &baseObject, &baseObjectId)) == NULL)
3242 ereport(ERROR,
3244 errmsg("could not find jsonpath variable \"%s\"",
3245 pnstrdup(varName, varNameLength))));
3246
3247 if (baseObjectId > 0)
3248 {
3249 *value = *v;
3250 setBaseObject(cxt, &baseObject, baseObjectId);
3251 }
3252}
3253
3254/*
3255 * Definition of JsonPathGetVarCallback for when JsonPathExecContext.vars
3256 * is specified as a jsonb value.
3257 */
3258static JsonbValue *
3260 JsonbValue *baseObject, int *baseObjectId)
3261{
3262 Jsonb *vars = varsJsonb;
3263 JsonbValue tmp;
3264 JsonbValue *result;
3265
3266 tmp.type = jbvString;
3267 tmp.val.string.val = varName;
3268 tmp.val.string.len = varNameLength;
3269
3270 result = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
3271
3272 if (result == NULL)
3273 {
3274 *baseObjectId = -1;
3275 return NULL;
3276 }
3277
3278 *baseObjectId = 1;
3279 JsonbInitBinary(baseObject, vars);
3280
3281 return result;
3282}
3283
3284/*
3285 * Definition of JsonPathCountVarsCallback for when JsonPathExecContext.vars
3286 * is specified as a jsonb value.
3287 */
3288static int
3290{
3291 Jsonb *vars = varsJsonb;
3292
3293 if (vars && !JsonContainerIsObject(&vars->root))
3294 {
3295 ereport(ERROR,
3297 errmsg("\"vars\" argument is not an object"),
3298 errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object."));
3299 }
3300
3301 /* count of base objects */
3302 return vars != NULL ? 1 : 0;
3303}
3304
3305/**************** Support functions for JsonPath execution *****************/
3306
3307/*
3308 * Returns the size of an array item, or -1 if item is not an array.
3309 */
3310static int
3312{
3313 Assert(jb->type != jbvArray);
3314
3315 if (jb->type == jbvBinary)
3316 {
3317 JsonbContainer *jbc = jb->val.binary.data;
3318
3320 return JsonContainerSize(jbc);
3321 }
3322
3323 return -1;
3324}
3325
3326/* Comparison predicate callback. */
3327static JsonPathBool
3329{
3331
3332 return compareItems(cmp->type, lv, rv, cxt->useTz);
3333}
3334
3335/*
3336 * Perform per-byte comparison of two strings.
3337 */
3338static int
3339binaryCompareStrings(const char *s1, int len1,
3340 const char *s2, int len2)
3341{
3342 int cmp;
3343
3344 cmp = memcmp(s1, s2, Min(len1, len2));
3345
3346 if (cmp != 0)
3347 return cmp;
3348
3349 if (len1 == len2)
3350 return 0;
3351
3352 return len1 < len2 ? -1 : 1;
3353}
3354
3355/*
3356 * Compare two strings in the current server encoding using Unicode codepoint
3357 * collation.
3358 */
3359static int
3361 const char *mbstr2, int mblen2)
3362{
3365 {
3366 /*
3367 * It's known property of UTF-8 strings that their per-byte comparison
3368 * result matches codepoints comparison result. ASCII can be
3369 * considered as special case of UTF-8.
3370 */
3372 }
3373 else
3374 {
3375 char *utf8str1,
3376 *utf8str2;
3377 int cmp,
3378 utf8len1,
3379 utf8len2;
3380
3381 /*
3382 * We have to convert other encodings to UTF-8 first, then compare.
3383 * Input strings may be not null-terminated and pg_server_to_any() may
3384 * return them "as is". So, use strlen() only if there is real
3385 * conversion.
3386 */
3391
3393
3394 /*
3395 * If pg_server_to_any() did no real conversion, then we actually
3396 * compared original strings. So, we already done.
3397 */
3398 if (mbstr1 == utf8str1 && mbstr2 == utf8str2)
3399 return cmp;
3400
3401 /* Free memory if needed */
3402 if (mbstr1 != utf8str1)
3403 pfree(utf8str1);
3404 if (mbstr2 != utf8str2)
3405 pfree(utf8str2);
3406
3407 /*
3408 * When all Unicode codepoints are equal, return result of binary
3409 * comparison. In some edge cases, same characters may have different
3410 * representations in encoding. Then our behavior could diverge from
3411 * standard. However, that allow us to do simple binary comparison
3412 * for "==" operator, which is performance critical in typical cases.
3413 * In future to implement strict standard conformance, we can do
3414 * normalization of input JSON strings.
3415 */
3416 if (cmp == 0)
3418 else
3419 return cmp;
3420 }
3421}
3422
3423/*
3424 * Compare two SQL/JSON items using comparison operation 'op'.
3425 */
3426static JsonPathBool
3428{
3429 int cmp;
3430 bool res;
3431
3432 if (jb1->type != jb2->type)
3433 {
3434 if (jb1->type == jbvNull || jb2->type == jbvNull)
3435
3436 /*
3437 * Equality and order comparison of nulls to non-nulls returns
3438 * always false, but inequality comparison returns true.
3439 */
3440 return op == jpiNotEqual ? jpbTrue : jpbFalse;
3441
3442 /* Non-null items of different types are not comparable. */
3443 return jpbUnknown;
3444 }
3445
3446 switch (jb1->type)
3447 {
3448 case jbvNull:
3449 cmp = 0;
3450 break;
3451 case jbvBool:
3452 cmp = jb1->val.boolean == jb2->val.boolean ? 0 :
3453 jb1->val.boolean ? 1 : -1;
3454 break;
3455 case jbvNumeric:
3456 cmp = compareNumeric(jb1->val.numeric, jb2->val.numeric);
3457 break;
3458 case jbvString:
3459 if (op == jpiEqual)
3460 return jb1->val.string.len != jb2->val.string.len ||
3461 memcmp(jb1->val.string.val,
3462 jb2->val.string.val,
3463 jb1->val.string.len) ? jpbFalse : jpbTrue;
3464
3465 cmp = compareStrings(jb1->val.string.val, jb1->val.string.len,
3466 jb2->val.string.val, jb2->val.string.len);
3467 break;
3468 case jbvDatetime:
3469 {
3470 bool cast_error;
3471
3472 cmp = compareDatetime(jb1->val.datetime.value,
3473 jb1->val.datetime.typid,
3474 jb2->val.datetime.value,
3475 jb2->val.datetime.typid,
3476 useTz,
3477 &cast_error);
3478
3479 if (cast_error)
3480 return jpbUnknown;
3481 }
3482 break;
3483
3484 case jbvBinary:
3485 case jbvArray:
3486 case jbvObject:
3487 return jpbUnknown; /* non-scalars are not comparable */
3488
3489 default:
3490 elog(ERROR, "invalid jsonb value type %d", jb1->type);
3491 }
3492
3493 switch (op)
3494 {
3495 case jpiEqual:
3496 res = (cmp == 0);
3497 break;
3498 case jpiNotEqual:
3499 res = (cmp != 0);
3500 break;
3501 case jpiLess:
3502 res = (cmp < 0);
3503 break;
3504 case jpiGreater:
3505 res = (cmp > 0);
3506 break;
3507 case jpiLessOrEqual:
3508 res = (cmp <= 0);
3509 break;
3510 case jpiGreaterOrEqual:
3511 res = (cmp >= 0);
3512 break;
3513 default:
3514 elog(ERROR, "unrecognized jsonpath operation: %d", op);
3515 return jpbUnknown;
3516 }
3517
3518 return res ? jpbTrue : jpbFalse;
3519}
3520
3521/* Compare two numerics */
3522static int
3529
3530static JsonbValue *
3532{
3534
3535 *dst = *src;
3536
3537 return dst;
3538}
3539
3540/*
3541 * Execute array subscript expression and convert resulting numeric item to
3542 * the integer type with truncation.
3543 */
3544static JsonPathExecResult
3546 int32 *index)
3547{
3548 JsonbValue *jbv;
3549 JsonValueList found;
3553
3554 JsonValueListInit(&found);
3555
3556 res = executeItem(cxt, jsp, jb, &found);
3557
3558 if (jperIsError(res))
3559 {
3560 JsonValueListClear(&found);
3561 return res;
3562 }
3563
3564 if (!JsonValueListIsSingleton(&found) ||
3566 {
3567 JsonValueListClear(&found);
3570 errmsg("jsonpath array subscript is not a single numeric value"))));
3571 }
3572
3574 NumericGetDatum(jbv->val.numeric),
3575 Int32GetDatum(0));
3576
3578 (Node *) &escontext);
3579
3580 JsonValueListClear(&found);
3581
3582 if (escontext.error_occurred)
3585 errmsg("jsonpath array subscript is out of integer range"))));
3586
3587 return jperOk;
3588}
3589
3590/* Save base object and its id needed for the execution of .keyvalue(). */
3591static JsonBaseObjectInfo
3593{
3594 JsonBaseObjectInfo baseObject = cxt->baseObject;
3595
3596 cxt->baseObject.jbc = jbv->type != jbvBinary ? NULL :
3597 (JsonbContainer *) jbv->val.binary.data;
3598 cxt->baseObject.id = id;
3599
3600 return baseObject;
3601}
3602
3603/*
3604 * JsonValueList support functions
3605 */
3606
3607static void
3609{
3610 jvl->nitems = 0;
3611 jvl->maxitems = BASE_JVL_ITEMS;
3612 jvl->next = NULL;
3613 jvl->last = jvl;
3614}
3615
3616static void
3618{
3620
3621 /* Release any extra chunks */
3622 for (JsonValueList *chunk = jvl->next; chunk != NULL; chunk = nxt)
3623 {
3624 nxt = chunk->next;
3625 pfree(chunk);
3626 }
3627 /* ... and reset to empty */
3628 jvl->nitems = 0;
3629 Assert(jvl->maxitems == BASE_JVL_ITEMS);
3630 jvl->next = NULL;
3631 jvl->last = jvl;
3632}
3633
3634static void
3636{
3637 JsonValueList *last = jvl->last;
3638
3639 if (last->nitems < last->maxitems)
3640 {
3641 /* there's still room in the last existing chunk */
3642 last->items[last->nitems] = *jbv;
3643 last->nitems++;
3644 }
3645 else
3646 {
3647 /* need a new last chunk */
3649 int nxtsize;
3650
3651 nxtsize = last->maxitems * 2; /* double the size with each chunk */
3652 nxtsize = Max(nxtsize, MIN_EXTRA_JVL_ITEMS); /* but at least this */
3654 nxtsize * sizeof(JsonbValue));
3655 nxt->nitems = 1;
3656 nxt->maxitems = nxtsize;
3657 nxt->next = NULL;
3658 nxt->items[0] = *jbv;
3659 last->next = nxt;
3660 jvl->last = nxt;
3661 }
3662}
3663
3664static bool
3666{
3667 /* We need not examine extra chunks for this */
3668 return (jvl->nitems == 0);
3669}
3670
3671static bool
3673{
3674#if BASE_JVL_ITEMS > 1
3675 /* We need not examine extra chunks in this case */
3676 return (jvl->nitems == 1);
3677#else
3678 return (jvl->nitems == 1 && jvl->next == NULL);
3679#endif
3680}
3681
3682static bool
3684{
3685#if BASE_JVL_ITEMS > 1
3686 /* We need not examine extra chunks in this case */
3687 return (jvl->nitems > 1);
3688#else
3689 return (jvl->nitems == 1 && jvl->next != NULL);
3690#endif
3691}
3692
3693static JsonbValue *
3695{
3696 Assert(jvl->nitems > 0);
3697 return &jvl->items[0];
3698}
3699
3700/*
3701 * JsonValueListIterator functions
3702 */
3703
3704static void
3706{
3707 it->chunk = jvl;
3708 it->nextitem = 0;
3709}
3710
3711/*
3712 * Get the next item from the sequence advancing iterator.
3713 * Returns NULL if no more items.
3714 */
3715static JsonbValue *
3717{
3718 if (it->chunk == NULL)
3719 return NULL;
3720 if (it->nextitem >= it->chunk->nitems)
3721 {
3722 it->chunk = it->chunk->next;
3723 if (it->chunk == NULL)
3724 return NULL;
3725 it->nextitem = 0;
3726 Assert(it->chunk->nitems > 0);
3727 }
3728 return &it->chunk->items[it->nextitem++];
3729}
3730
3731/*
3732 * Initialize a binary JsonbValue with the given jsonb container.
3733 */
3734static JsonbValue *
3736{
3737 jbv->type = jbvBinary;
3738 jbv->val.binary.data = &jb->root;
3739 jbv->val.binary.len = VARSIZE_ANY_EXHDR(jb);
3740
3741 return jbv;
3742}
3743
3744/*
3745 * Returns jbv* type of JsonbValue. Note, it never returns jbvBinary as is.
3746 */
3747static int
3749{
3750 int type = jb->type;
3751
3752 if (jb->type == jbvBinary)
3753 {
3754 JsonbContainer *jbc = jb->val.binary.data;
3755
3756 /* Scalars should be always extracted during jsonpath execution. */
3758
3759 if (JsonContainerIsObject(jbc))
3760 type = jbvObject;
3761 else if (JsonContainerIsArray(jbc))
3762 type = jbvArray;
3763 else
3764 elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
3765 }
3766
3767 return type;
3768}
3769
3770/* Get scalar of given type or NULL on type mismatch */
3771static JsonbValue *
3773{
3774 /* Scalars should be always extracted during jsonpath execution. */
3775 Assert(scalar->type != jbvBinary ||
3776 !JsonContainerIsScalar(scalar->val.binary.data));
3777
3778 return scalar->type == type ? scalar : NULL;
3779}
3780
3781/* Construct a JSON array from the item list */
3782static JsonbValue *
3784{
3785 JsonbInState ps = {0};
3787 JsonbValue *jbv;
3788
3790
3792 while ((jbv = JsonValueListNext(&it)))
3794
3796
3797 return ps.result;
3798}
3799
3800/* Check if the timezone required for casting from type1 to type2 is used */
3801static void
3802checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
3803{
3804 if (!useTz)
3805 ereport(ERROR,
3807 errmsg("cannot convert value from %s to %s without time zone usage",
3808 type1, type2),
3809 errhint("Use *_tz() function for time zone support.")));
3810}
3811
3812/* Convert time datum to timetz datum */
3813static Datum
3814castTimeToTimeTz(Datum time, bool useTz)
3815{
3816 checkTimezoneIsUsedForCast(useTz, "time", "timetz");
3817
3818 return DirectFunctionCall1(time_timetz, time);
3819}
3820
3821/*
3822 * Compare date to timestamp.
3823 * Note that this doesn't involve any timezone considerations.
3824 */
3825static int
3830
3831/*
3832 * Compare date to timestamptz.
3833 */
3834static int
3836{
3837 checkTimezoneIsUsedForCast(useTz, "date", "timestamptz");
3838
3840}
3841
3842/*
3843 * Compare timestamp to timestamptz.
3844 */
3845static int
3847{
3848 checkTimezoneIsUsedForCast(useTz, "timestamp", "timestamptz");
3849
3851}
3852
3853/*
3854 * Cross-type comparison of two datetime SQL/JSON items. If items are
3855 * uncomparable *cast_error flag is set, otherwise *cast_error is unset.
3856 * If the cast requires timezone and it is not used, then explicit error is thrown.
3857 */
3858static int
3860 bool useTz, bool *cast_error)
3861{
3863
3864 *cast_error = false;
3865
3866 switch (typid1)
3867 {
3868 case DATEOID:
3869 switch (typid2)
3870 {
3871 case DATEOID:
3872 cmpfunc = date_cmp;
3873
3874 break;
3875
3876 case TIMESTAMPOID:
3879 useTz);
3880
3881 case TIMESTAMPTZOID:
3884 useTz);
3885
3886 case TIMEOID:
3887 case TIMETZOID:
3888 *cast_error = true; /* uncomparable types */
3889 return 0;
3890
3891 default:
3892 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
3893 typid2);
3894 }
3895 break;
3896
3897 case TIMEOID:
3898 switch (typid2)
3899 {
3900 case TIMEOID:
3901 cmpfunc = time_cmp;
3902
3903 break;
3904
3905 case TIMETZOID:
3906 val1 = castTimeToTimeTz(val1, useTz);
3908
3909 break;
3910
3911 case DATEOID:
3912 case TIMESTAMPOID:
3913 case TIMESTAMPTZOID:
3914 *cast_error = true; /* uncomparable types */
3915 return 0;
3916
3917 default:
3918 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
3919 typid2);
3920 }
3921 break;
3922
3923 case TIMETZOID:
3924 switch (typid2)
3925 {
3926 case TIMEOID:
3927 val2 = castTimeToTimeTz(val2, useTz);
3929
3930 break;
3931
3932 case TIMETZOID:
3934
3935 break;
3936
3937 case DATEOID:
3938 case TIMESTAMPOID:
3939 case TIMESTAMPTZOID:
3940 *cast_error = true; /* uncomparable types */
3941 return 0;
3942
3943 default:
3944 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
3945 typid2);
3946 }
3947 break;
3948
3949 case TIMESTAMPOID:
3950 switch (typid2)
3951 {
3952 case DATEOID:
3955 useTz);
3956
3957 case TIMESTAMPOID:
3959
3960 break;
3961
3962 case TIMESTAMPTZOID:
3965 useTz);
3966
3967 case TIMEOID:
3968 case TIMETZOID:
3969 *cast_error = true; /* uncomparable types */
3970 return 0;
3971
3972 default:
3973 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
3974 typid2);
3975 }
3976 break;
3977
3978 case TIMESTAMPTZOID:
3979 switch (typid2)
3980 {
3981 case DATEOID:
3984 useTz);
3985
3986 case TIMESTAMPOID:
3989 useTz);
3990
3991 case TIMESTAMPTZOID:
3993
3994 break;
3995
3996 case TIMEOID:
3997 case TIMETZOID:
3998 *cast_error = true; /* uncomparable types */
3999 return 0;
4000
4001 default:
4002 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u",
4003 typid2);
4004 }
4005 break;
4006
4007 default:
4008 elog(ERROR, "unrecognized SQL/JSON datetime type oid: %u", typid1);
4009 }
4010
4011 if (*cast_error)
4012 return 0; /* cast error */
4013
4015}
4016
4017/*
4018 * Executor-callable JSON_EXISTS implementation
4019 *
4020 * Returns NULL instead of throwing errors if 'error' is not NULL, setting
4021 * *error to true.
4022 */
4023bool
4025{
4027
4028 res = executeJsonPath(jp, vars,
4030 DatumGetJsonbP(jb), !error, NULL, true);
4031
4032 Assert(error || !jperIsError(res));
4033
4034 if (error && jperIsError(res))
4035 *error = true;
4036
4037 return res == jperOk;
4038}
4039
4040/*
4041 * Executor-callable JSON_QUERY implementation
4042 *
4043 * Returns NULL instead of throwing errors if 'error' is not NULL, setting
4044 * *error to true. *empty is set to true if no match is found.
4045 */
4046Datum
4048 bool *error, List *vars,
4049 const char *column_name)
4050{
4051 bool wrap;
4052 JsonValueList found;
4054
4055 JsonValueListInit(&found);
4056
4057 res = executeJsonPath(jp, vars,
4059 DatumGetJsonbP(jb), !error, &found, true);
4060 Assert(error || !jperIsError(res));
4061 if (error && jperIsError(res))
4062 {
4063 *error = true;
4064 *empty = false;
4065 return (Datum) 0;
4066 }
4067
4068 /*
4069 * Determine whether to wrap the result in a JSON array or not.
4070 *
4071 * If the returned JsonValueList is empty, no wrapping is necessary.
4072 *
4073 * If the wrapper mode is JSW_NONE or JSW_UNSPEC, wrapping is explicitly
4074 * disabled. This enforces a WITHOUT WRAPPER clause, which is also the
4075 * default when no WRAPPER clause is specified.
4076 *
4077 * If the mode is JSW_UNCONDITIONAL, wrapping is enforced regardless of
4078 * the number of SQL/JSON items, enforcing a WITH WRAPPER or WITH
4079 * UNCONDITIONAL WRAPPER clause.
4080 *
4081 * For JSW_CONDITIONAL, wrapping occurs only if there is more than one
4082 * SQL/JSON item in the list, enforcing a WITH CONDITIONAL WRAPPER clause.
4083 */
4084 if (JsonValueListIsEmpty(&found))
4085 wrap = false;
4086 else if (wrapper == JSW_NONE || wrapper == JSW_UNSPEC)
4087 wrap = false;
4088 else if (wrapper == JSW_UNCONDITIONAL)
4089 wrap = true;
4090 else if (wrapper == JSW_CONDITIONAL)
4092 else
4093 {
4094 elog(ERROR, "unrecognized json wrapper %d", (int) wrapper);
4095 wrap = false;
4096 }
4097
4098 if (wrap)
4100
4101 /* No wrapping means at most one item is expected. */
4103 {
4104 if (error)
4105 {
4106 *error = true;
4107 return (Datum) 0;
4108 }
4109
4110 if (column_name)
4111 ereport(ERROR,
4113 errmsg("JSON path expression for column \"%s\" must return single item when no wrapper is requested",
4114 column_name),
4115 errhint("Use the WITH WRAPPER clause to wrap SQL/JSON items into an array.")));
4116 else
4117 ereport(ERROR,
4119 errmsg("JSON path expression in JSON_QUERY must return single item when no wrapper is requested"),
4120 errhint("Use the WITH WRAPPER clause to wrap SQL/JSON items into an array.")));
4121 }
4122
4123 if (!JsonValueListIsEmpty(&found))
4125
4126 *empty = true;
4127 return PointerGetDatum(NULL);
4128}
4129
4130/*
4131 * Executor-callable JSON_VALUE implementation
4132 *
4133 * Returns NULL instead of throwing errors if 'error' is not NULL, setting
4134 * *error to true. *empty is set to true if no match is found.
4135 */
4136JsonbValue *
4137JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars,
4138 const char *column_name)
4139{
4140 JsonbValue *res;
4141 JsonValueList found;
4143
4144 JsonValueListInit(&found);
4145
4148 !error, &found, true);
4149
4151
4152 if (error && jperIsError(jper))
4153 {
4154 *error = true;
4155 *empty = false;
4156 return NULL;
4157 }
4158
4159 *empty = JsonValueListIsEmpty(&found);
4160
4161 if (*empty)
4162 return NULL;
4163
4164 /* JSON_VALUE expects to get only singletons. */
4166 {
4167 if (error)
4168 {
4169 *error = true;
4170 return NULL;
4171 }
4172
4173 if (column_name)
4174 ereport(ERROR,
4176 errmsg("JSON path expression for column \"%s\" must return single scalar item",
4177 column_name)));
4178 else
4179 ereport(ERROR,
4181 errmsg("JSON path expression in JSON_VALUE must return single scalar item")));
4182 }
4183
4184 res = copyJsonbValue(JsonValueListHead(&found));
4185 if (res->type == jbvBinary && JsonContainerIsScalar(res->val.binary.data))
4186 JsonbExtractScalar(res->val.binary.data, res);
4187
4188 /* JSON_VALUE expects to get only scalars. */
4189 if (!IsAJsonbScalar(res))
4190 {
4191 if (error)
4192 {
4193 *error = true;
4194 return NULL;
4195 }
4196
4197 if (column_name)
4198 ereport(ERROR,
4200 errmsg("JSON path expression for column \"%s\" must return single scalar item",
4201 column_name)));
4202 else
4203 ereport(ERROR,
4205 errmsg("JSON path expression in JSON_VALUE must return single scalar item")));
4206 }
4207
4208 if (res->type == jbvNull)
4209 return NULL;
4210
4211 return res;
4212}
4213
4214/************************ JSON_TABLE functions ***************************/
4215
4216/*
4217 * Sanity-checks and returns the opaque JsonTableExecContext from the
4218 * given executor state struct.
4219 */
4220static inline JsonTableExecContext *
4222{
4223 JsonTableExecContext *result;
4224
4226 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4227 result = (JsonTableExecContext *) state->opaque;
4228 if (result->magic != JSON_TABLE_EXEC_CONTEXT_MAGIC)
4229 elog(ERROR, "%s called with invalid TableFuncScanState", fname);
4230
4231 return result;
4232}
4233
4234/*
4235 * JsonTableInitOpaque
4236 * Fill in TableFuncScanState->opaque for processing JSON_TABLE
4237 *
4238 * This initializes the PASSING arguments and the JsonTablePlanState for
4239 * JsonTablePlan given in TableFunc.
4240 */
4241static void
4243{
4245 PlanState *ps = &state->ss.ps;
4247 TableFunc *tf = tfs->tablefunc;
4248 JsonTablePlan *rootplan = (JsonTablePlan *) tf->plan;
4250 List *args = NIL;
4251
4254
4255 /*
4256 * Evaluate JSON_TABLE() PASSING arguments to be passed to the jsonpath
4257 * executor via JsonPathVariables.
4258 */
4259 if (state->passingvalexprs)
4260 {
4263
4264 Assert(list_length(state->passingvalexprs) ==
4265 list_length(je->passing_names));
4266 forboth(exprlc, state->passingvalexprs,
4267 namelc, je->passing_names)
4268 {
4272
4273 var->name = pstrdup(name->sval);
4274 var->namelen = strlen(var->name);
4275 var->typid = exprType((Node *) state->expr);
4276 var->typmod = exprTypmod((Node *) state->expr);
4277
4278 /*
4279 * Evaluate the expression and save the value to be returned by
4280 * GetJsonPathVar().
4281 */
4282 var->value = ExecEvalExpr(state, ps->ps_ExprContext,
4283 &var->isnull);
4284
4285 args = lappend(args, var);
4286 }
4287 }
4288
4289 cxt->colplanstates = palloc_array(JsonTablePlanState *, list_length(tf->colvalexprs));
4290
4291 /*
4292 * Initialize plan for the root path and, recursively, also any child
4293 * plans that compute the NESTED paths.
4294 */
4295 cxt->rootplanstate = JsonTableInitPlan(cxt, rootplan, NULL, args,
4297
4298 state->opaque = cxt;
4299}
4300
4301/*
4302 * JsonTableDestroyOpaque
4303 * Resets state->opaque
4304 */
4305static void
4307{
4309 GetJsonTableExecContext(state, "JsonTableDestroyOpaque");
4310
4311 /* not valid anymore */
4312 cxt->magic = 0;
4313
4314 state->opaque = NULL;
4315}
4316
4317/*
4318 * JsonTableInitPlan
4319 * Initialize information for evaluating jsonpath in the given
4320 * JsonTablePlan and, recursively, in any child plans
4321 */
4322static JsonTablePlanState *
4325 List *args, MemoryContext mcxt)
4326{
4328
4329 planstate->plan = plan;
4330 planstate->parent = parentstate;
4331 JsonValueListInit(&planstate->found);
4332
4334 {
4336 int i;
4337
4338 planstate->path = DatumGetJsonPathP(scan->path->value->constvalue);
4339 planstate->args = args;
4340 planstate->mcxt = AllocSetContextCreate(mcxt, "JsonTableExecContext",
4342
4343 /* No row pattern evaluated yet. */
4344 planstate->current.value = PointerGetDatum(NULL);
4345 planstate->current.isnull = true;
4346
4347 for (i = scan->colMin; i >= 0 && i <= scan->colMax; i++)
4348 cxt->colplanstates[i] = planstate;
4349
4350 planstate->nested = scan->child ?
4351 JsonTableInitPlan(cxt, scan->child, planstate, args, mcxt) : NULL;
4352 }
4353 else if (IsA(plan, JsonTableSiblingJoin))
4354 {
4356
4357 planstate->left = JsonTableInitPlan(cxt, join->lplan, parentstate,
4358 args, mcxt);
4359 planstate->right = JsonTableInitPlan(cxt, join->rplan, parentstate,
4360 args, mcxt);
4361 }
4362
4363 return planstate;
4364}
4365
4366/*
4367 * JsonTableSetDocument
4368 * Install the input document and evaluate the row pattern
4369 */
4370static void
4378
4379/*
4380 * Evaluate a JsonTablePlan's jsonpath to get a new row pattern from
4381 * the given context item
4382 */
4383static void
4385{
4386 JsonTablePathScan *scan = castNode(JsonTablePathScan, planstate->plan);
4389 Jsonb *js = (Jsonb *) DatumGetJsonbP(item);
4390
4391 JsonValueListClear(&planstate->found);
4392
4393 MemoryContextResetOnly(planstate->mcxt);
4394
4395 oldcxt = MemoryContextSwitchTo(planstate->mcxt);
4396
4397 res = executeJsonPath(planstate->path, planstate->args,
4399 js, scan->errorOnError,
4400 &planstate->found,
4401 true);
4402
4404
4405 if (jperIsError(res))
4406 {
4407 Assert(!scan->errorOnError);
4408 JsonValueListClear(&planstate->found);
4409 }
4410
4411 /* Reset plan iterator to the beginning of the item list */
4412 JsonValueListInitIterator(&planstate->found, &planstate->iter);
4413 planstate->current.value = PointerGetDatum(NULL);
4414 planstate->current.isnull = true;
4415 planstate->ordinal = 0;
4416}
4417
4418/*
4419 * Fetch next row from a JsonTablePlan.
4420 *
4421 * Returns false if the plan has run out of rows, true otherwise.
4422 */
4423static bool
4425{
4426 if (IsA(planstate->plan, JsonTablePathScan))
4427 return JsonTablePlanScanNextRow(planstate);
4428 else if (IsA(planstate->plan, JsonTableSiblingJoin))
4429 return JsonTablePlanJoinNextRow(planstate);
4430 else
4431 elog(ERROR, "invalid JsonTablePlan %d", (int) planstate->plan->type);
4432
4433 Assert(false);
4434 /* Appease compiler */
4435 return false;
4436}
4437
4438/*
4439 * Fetch next row from a JsonTablePlan's path evaluation result and from
4440 * any child nested path(s).
4441 *
4442 * Returns true if any of the paths (this or the nested) has more rows to
4443 * return.
4444 *
4445 * By fetching the nested path(s)'s rows based on the parent row at each
4446 * level, this essentially joins the rows of different levels. If a nested
4447 * path at a given level has no matching rows, the columns of that level will
4448 * compute to NULL, making it an OUTER join.
4449 */
4450static bool
4452{
4453 JsonbValue *jbv;
4455
4456 /*
4457 * If planstate already has an active row and there is a nested plan,
4458 * check if it has an active row to join with the former.
4459 */
4460 if (!planstate->current.isnull)
4461 {
4462 if (planstate->nested && JsonTablePlanNextRow(planstate->nested))
4463 return true;
4464 }
4465
4466 /* Fetch new row from the list of found values to set as active. */
4467 jbv = JsonValueListNext(&planstate->iter);
4468
4469 /* End of list? */
4470 if (jbv == NULL)
4471 {
4472 planstate->current.value = PointerGetDatum(NULL);
4473 planstate->current.isnull = true;
4474 return false;
4475 }
4476
4477 /*
4478 * Set current row item for subsequent JsonTableGetValue() calls for
4479 * evaluating individual columns.
4480 */
4481 oldcxt = MemoryContextSwitchTo(planstate->mcxt);
4483 planstate->current.isnull = false;
4485
4486 /* Next row! */
4487 planstate->ordinal++;
4488
4489 /* Process nested plan(s), if any. */
4490 if (planstate->nested)
4491 {
4492 /* Re-evaluate the nested path using the above parent row. */
4493 JsonTableResetNestedPlan(planstate->nested);
4494
4495 /*
4496 * Now fetch the nested plan's current row to be joined against the
4497 * parent row. Any further nested plans' paths will be re-evaluated
4498 * recursively, level at a time, after setting each nested plan's
4499 * current row.
4500 */
4501 (void) JsonTablePlanNextRow(planstate->nested);
4502 }
4503
4504 /* There are more rows. */
4505 return true;
4506}
4507
4508/*
4509 * Re-evaluate the row pattern of a nested plan using the new parent row
4510 * pattern.
4511 */
4512static void
4514{
4515 /* This better be a child plan. */
4516 Assert(planstate->parent != NULL);
4517 if (IsA(planstate->plan, JsonTablePathScan))
4518 {
4519 JsonTablePlanState *parent = planstate->parent;
4520
4521 if (!parent->current.isnull)
4522 JsonTableResetRowPattern(planstate, parent->current.value);
4523
4524 /*
4525 * If this plan itself has a child nested plan, it will be reset when
4526 * the caller calls JsonTablePlanNextRow() on this plan.
4527 */
4528 }
4529 else if (IsA(planstate->plan, JsonTableSiblingJoin))
4530 {
4531 JsonTableResetNestedPlan(planstate->left);
4532 JsonTableResetNestedPlan(planstate->right);
4533 }
4534}
4535
4536/*
4537 * Fetch the next row from a JsonTableSiblingJoin.
4538 *
4539 * This is essentially a UNION between the rows from left and right siblings.
4540 */
4541static bool
4543{
4544
4545 /* Fetch row from left sibling. */
4546 if (!JsonTablePlanNextRow(planstate->left))
4547 {
4548 /*
4549 * Left sibling ran out of rows, so start fetching from the right
4550 * sibling.
4551 */
4552 if (!JsonTablePlanNextRow(planstate->right))
4553 {
4554 /* Right sibling ran out of row, so there are more rows. */
4555 return false;
4556 }
4557 }
4558
4559 return true;
4560}
4561
4562/*
4563 * JsonTableFetchRow
4564 * Prepare the next "current" row for upcoming GetValue calls.
4565 *
4566 * Returns false if no more rows can be returned.
4567 */
4568static bool
4570{
4572 GetJsonTableExecContext(state, "JsonTableFetchRow");
4573
4575}
4576
4577/*
4578 * JsonTableGetValue
4579 * Return the value for column number 'colnum' for the current row.
4580 *
4581 * This leaks memory, so be sure to reset often the context in which it's
4582 * called.
4583 */
4584static Datum
4586 Oid typid, int32 typmod, bool *isnull)
4587{
4589 GetJsonTableExecContext(state, "JsonTableGetValue");
4590 ExprContext *econtext = state->ss.ps.ps_ExprContext;
4591 ExprState *estate = list_nth(state->colvalexprs, colnum);
4592 JsonTablePlanState *planstate = cxt->colplanstates[colnum];
4593 JsonTablePlanRowSource *current = &planstate->current;
4594 Datum result;
4595
4596 /* Row pattern value is NULL */
4597 if (current->isnull)
4598 {
4599 result = (Datum) 0;
4600 *isnull = true;
4601 }
4602 /* Evaluate JsonExpr. */
4603 else if (estate)
4604 {
4606 bool saved_caseIsNull = econtext->caseValue_isNull;
4607
4608 /* Pass the row pattern value via CaseTestExpr. */
4609 econtext->caseValue_datum = current->value;
4610 econtext->caseValue_isNull = false;
4611
4612 result = ExecEvalExpr(estate, econtext, isnull);
4613
4614 econtext->caseValue_datum = saved_caseValue;
4616 }
4617 /* ORDINAL column */
4618 else
4619 {
4620 result = Int32GetDatum(planstate->ordinal);
4621 *isnull = false;
4622 }
4623
4624 return result;
4625}
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:4521
Datum numeric_cmp(PG_FUNCTION_ARGS)
Definition numeric.c:2415
Numeric int64_to_numeric(int64 val)
Definition numeric.c:4259
Datum float4_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4615
Datum int4_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4353
Datum numeric_uminus(PG_FUNCTION_ARGS)
Definition numeric.c:1403
Numeric numeric_mod_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:3355
Datum numeric_ceil(PG_FUNCTION_ARGS)
Definition numeric.c:1630
int32 numeric_int4_safe(Numeric num, Node *escontext)
Definition numeric.c:4364
Datum numerictypmodin(PG_FUNCTION_ARGS)
Definition numeric.c:1307
Numeric numeric_add_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:2881
int64 numeric_int8_safe(Numeric num, Node *escontext)
Definition numeric.c:4434
Numeric numeric_div_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:3152
Numeric numeric_sub_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:2957
Datum numeric_out(PG_FUNCTION_ARGS)
Definition numeric.c:799
Datum numeric_trunc(PG_FUNCTION_ARGS)
Definition numeric.c:1580
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:4472
Numeric numeric_mul_safe(Numeric num1, Numeric num2, Node *escontext)
Definition numeric.c:3033
Datum numeric_abs(PG_FUNCTION_ARGS)
Definition numeric.c:1376
Datum int8_numeric(PG_FUNCTION_ARGS)
Definition numeric.c:4423
bool numeric_is_inf(Numeric num)
Definition numeric.c:845
Datum numeric_floor(PG_FUNCTION_ARGS)
Definition numeric.c:1658
Datum timestamp_cmp(PG_FUNCTION_ARGS)
Definition timestamp.c:2261
bool AdjustTimestampForTypmod(Timestamp *time, int32 typmod, Node *escontext)
Definition timestamp.c:359
Datum timestamp_timestamptz(PG_FUNCTION_ARGS)
Definition timestamp.c:6421
int32 timestamp_cmp_timestamptz_internal(Timestamp timestampVal, TimestampTz dt2)
Definition timestamp.c:2354
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition timestamp.c:1901
int32 anytimestamp_typmod_check(bool istz, int32 typmod)
Definition timestamp.c:116
Datum timestamptz_timestamp(PG_FUNCTION_ARGS)
Definition timestamp.c:6484
static int32 next
Definition blutils.c:225
bool parse_bool(const char *value, bool *result)
Definition bool.c:31
#define INT64CONST(x)
Definition c.h:632
#define Min(x, y)
Definition c.h:1093
#define PG_UINT32_MAX
Definition c.h:676
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:243
#define Max(x, y)
Definition c.h:1087
#define Assert(condition)
Definition c.h:945
int64_t int64
Definition c.h:615
int32_t int32
Definition c.h:614
uint32_t uint32
Definition c.h:618
#define lengthof(array)
Definition c.h:875
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:768
Datum date_cmp(PG_FUNCTION_ARGS)
Definition date.c:438
Datum time_cmp(PG_FUNCTION_ARGS)
Definition date.c:1822
Datum timestamp_time(PG_FUNCTION_ARGS)
Definition date.c:1993
int32 anytime_typmod_check(bool istz, int32 typmod)
Definition date.c:65
Datum date_timestamptz(PG_FUNCTION_ARGS)
Definition date.c:1386
Datum timetz_cmp(PG_FUNCTION_ARGS)
Definition date.c:2612
Datum timetz_time(PG_FUNCTION_ARGS)
Definition date.c:2903
Datum time_timetz(PG_FUNCTION_ARGS)
Definition date.c:2916
Datum timestamptz_timetz(PG_FUNCTION_ARGS)
Definition date.c:2942
void AdjustTimeForTypmod(TimeADT *time, int32 typmod)
Definition date.c:1733
Datum timestamptz_date(PG_FUNCTION_ARGS)
Definition date.c:1401
Datum timestamp_date(PG_FUNCTION_ARGS)
Definition date.c:1327
int32 date_cmp_timestamptz_internal(DateADT dateVal, TimestampTz dt2)
Definition date.c:849
Datum timestamptz_time(PG_FUNCTION_ARGS)
Definition date.c:2023
Datum date_timestamp(PG_FUNCTION_ARGS)
Definition date.c:1313
static TimeTzADT * DatumGetTimeTzADTP(Datum X)
Definition date.h:72
int32 DateADT
Definition date.h:21
static DateADT DatumGetDateADT(Datum X)
Definition date.h:60
static TimeADT DatumGetTimeADT(Datum X)
Definition date.h:66
static Datum TimeTzADTPGetDatum(const TimeTzADT *X)
Definition date.h:90
int64 TimeADT
Definition date.h:23
static Datum TimeADTGetDatum(TimeADT X)
Definition date.h:84
struct cursor * cur
Definition ecpg.c:29
int errcode(int sqlerrcode)
Definition elog.c:874
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
static Datum ExecEvalExpr(ExprState *state, ExprContext *econtext, bool *isNull)
Definition executor.h:396
#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:412
bool DirectInputFunctionCallSafe(PGFunction func, char *str, Oid typioparam, int32 typmod, Node *escontext, Datum *result)
Definition fmgr.c:1641
#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 @174 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:1166
void jspGetArg(JsonPathItem *v, JsonPathItem *a)
Definition jsonpath.c:1081
void jspInitByBuffer(JsonPathItem *v, char *base, int32 pos)
Definition jsonpath.c:990
bool jspGetBool(JsonPathItem *v)
Definition jsonpath.c:1210
void jspInit(JsonPathItem *v, JsonPath *js)
Definition jsonpath.c:980
char * jspGetString(JsonPathItem *v, int32 *len)
Definition jsonpath.c:1226
Numeric jspGetNumeric(JsonPathItem *v)
Definition jsonpath.c:1218
bool jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to, int i)
Definition jsonpath.c:1238
const char * jspOperationName(JsonPathItemType type)
Definition jsonpath.c:843
bool jspGetNext(JsonPathItem *v, JsonPathItem *a)
Definition jsonpath.c:1099
void jspGetRightArg(JsonPathItem *v, JsonPathItem *a)
Definition jsonpath.c:1188
bool jspConvertRegexFlags(uint32 xflags, int *result, struct Node *escontext)
#define jspHasNext(jsp)
Definition jsonpath.h:194
#define PG_GETARG_JSONPATH_P(x)
Definition jsonpath.h:46
#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
@ jpiBigint
Definition jsonpath.h:107
@ jpiBool
Definition jsonpath.h:67
@ jpiType
Definition jsonpath.h:95
@ jpiFloor
Definition jsonpath.h:98
@ jpiAnyArray
Definition jsonpath.h:85
@ jpiExists
Definition jsonpath.h:94
@ jpiSize
Definition jsonpath.h:96
@ jpiSub
Definition jsonpath.h:79
@ jpiNotEqual
Definition jsonpath.h:73
@ jpiMul
Definition jsonpath.h:80
@ jpiVariable
Definition jsonpath.h:92
@ jpiTimeTz
Definition jsonpath.h:115
@ jpiNot
Definition jsonpath.h:70
@ jpiDate
Definition jsonpath.h:109
@ jpiGreaterOrEqual
Definition jsonpath.h:77
@ jpiPlus
Definition jsonpath.h:83
@ jpiDouble
Definition jsonpath.h:100
@ jpiGreater
Definition jsonpath.h:75
@ jpiNumber
Definition jsonpath.h:112
@ jpiAnd
Definition jsonpath.h:68
@ jpiStartsWith
Definition jsonpath.h:105
@ jpiOr
Definition jsonpath.h:69
@ jpiMod
Definition jsonpath.h:82
@ jpiTimestamp
Definition jsonpath.h:116
@ jpiLikeRegex
Definition jsonpath.h:106
@ jpiTimestampTz
Definition jsonpath.h:117
@ jpiInteger
Definition jsonpath.h:111
@ jpiRoot
Definition jsonpath.h:91
@ jpiFilter
Definition jsonpath.h:93
@ jpiNull
Definition jsonpath.h:64
@ jpiLess
Definition jsonpath.h:74
@ jpiCurrent
Definition jsonpath.h:90
@ jpiEqual
Definition jsonpath.h:72
@ jpiKey
Definition jsonpath.h:89
@ jpiDiv
Definition jsonpath.h:81
@ jpiTime
Definition jsonpath.h:114
@ jpiLast
Definition jsonpath.h:104
@ jpiMinus
Definition jsonpath.h:84
@ jpiLessOrEqual
Definition jsonpath.h:76
@ jpiCeiling
Definition jsonpath.h:99
@ jpiIsUnknown
Definition jsonpath.h:71
@ jpiKeyValue
Definition jsonpath.h:102
@ jpiNumeric
Definition jsonpath.h:66
@ jpiBoolean
Definition jsonpath.h:108
@ jpiStringFunc
Definition jsonpath.h:113
@ jpiDecimal
Definition jsonpath.h:110
@ jpiAnyKey
Definition jsonpath.h:86
#define JSONPATH_LAX
Definition jsonpath.h:31
static JsonPathBool executeComparison(JsonPathItem *cmp, JsonbValue *lv, JsonbValue *rv, void *p)
bool JsonPathExists(Datum jb, JsonPath *jp, bool *error, List *vars)
static Datum jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz)
static JsonPathExecResult executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found, bool unwrap)
Datum jsonb_path_query_tz(PG_FUNCTION_ARGS)
#define jspAutoUnwrap(cxt)
Datum jsonb_path_exists_opr(PG_FUNCTION_ARGS)
static int cmpDateToTimestamp(DateADT date1, Timestamp ts2, bool useTz)
static JsonPathBool executeBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, bool canHaveNext)
static int JsonbArraySize(JsonbValue *jb)
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)
Datum jsonb_path_match(PG_FUNCTION_ARGS)
#define jspStrictAbsenceOfErrors(cxt)
static void JsonTableDestroyOpaque(TableFuncScanState *state)
static void JsonValueListClear(JsonValueList *jvl)
static void JsonTableInitOpaque(TableFuncScanState *state, int natts)
Datum jsonb_path_exists(PG_FUNCTION_ARGS)
#define jperIsError(jper)
static Datum jsonb_path_exists_internal(FunctionCallInfo fcinfo, bool tz)
JsonbValue * JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars, const char *column_name)
static bool JsonTablePlanNextRow(JsonTablePlanState *planstate)
Datum jsonb_path_query_array_tz(PG_FUNCTION_ARGS)
static JsonTablePlanState * JsonTableInitPlan(JsonTableExecContext *cxt, JsonTablePlan *plan, JsonTablePlanState *parentstate, List *args, MemoryContext mcxt)
static JsonPathExecResult executeItemUnwrapTargetArray(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, JsonValueList *found, bool unwrapElements)
static int cmpTimestampToTimestampTz(Timestamp ts1, TimestampTz tstz2, bool useTz)
static JsonPathBool executeLikeRegex(JsonPathItem *jsp, JsonbValue *str, JsonbValue *rarg, void *param)
#define jspIgnoreStructuralErrors(cxt)
JsonPathExecResult
@ jperError
@ jperNotFound
@ jperOk
static void JsonbValueInitNumericDatum(JsonbValue *jbv, Datum num)
static int CountJsonPathVars(void *cxt)
static int compareNumeric(Numeric a, Numeric b)
static Datum JsonTableGetValue(TableFuncScanState *state, int colnum, Oid typid, int32 typmod, bool *isnull)
static JsonPathBool compareItems(int32 op, JsonbValue *jb1, JsonbValue *jb2, bool useTz)
static JsonPathExecResult getArrayIndex(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, int32 *index)
Datum jsonb_path_query_first_tz(PG_FUNCTION_ARGS)
#define MIN_EXTRA_JVL_ITEMS
Datum jsonb_path_query_array(PG_FUNCTION_ARGS)
static JsonPathExecResult executeItemOptUnwrapResult(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, bool unwrap, JsonValueList *found)
static JsonPathExecResult executeNumericItemMethod(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbValue *jb, bool unwrap, PGFunction func, JsonValueList *found)
static void getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable, JsonbValue *value)
static JsonbValue * JsonValueListHead(JsonValueList *jvl)
static void JsonValueListInitIterator(JsonValueList *jvl, JsonValueListIterator *it)
Datum jsonb_path_exists_tz(PG_FUNCTION_ARGS)
static bool JsonTableFetchRow(TableFuncScanState *state)
static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item, JsonbValue *value)
static JsonPathExecResult executeNextItem(JsonPathExecContext *cxt, JsonPathItem *cur, JsonPathItem *next, JsonbValue *v, JsonValueList *found)
static JsonPathBool executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb, bool unwrapRightArg, JsonPathPredicateCallback exec, void *param)
static int binaryCompareStrings(const char *s1, int len1, const char *s2, int len2)
static bool JsonValueListHasMultipleItems(const JsonValueList *jvl)
const TableFuncRoutine JsonbTableRoutine
static void JsonValueListAppend(JsonValueList *jvl, const JsonbValue *jbv)
static JsonbValue * wrapItemsInArray(JsonValueList *items)
int(* JsonPathCountVarsCallback)(void *vars)
static JsonbValue * JsonbInitBinary(JsonbValue *jbv, Jsonb *jb)
static void checkTimezoneIsUsedForCast(bool useTz, const char *type1, const char *type2)
static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars, JsonPathGetVarCallback getVar, JsonPathCountVarsCallback countVars, Jsonb *json, bool throwErrors, JsonValueList *result, bool useTz)
JsonPathBool
@ jpbUnknown
@ jpbFalse
@ jpbTrue
static bool JsonTablePlanJoinNextRow(JsonTablePlanState *planstate)
#define jspThrowErrors(cxt)
static JsonbValue * copyJsonbValue(JsonbValue *src)
List * lappend(List *list, void *datum)
Definition list.c:339
static struct pg_tm tm
Definition localtime.c:104
#define PG_UTF8
Definition mbprint.c:43
int GetDatabaseEncoding(void)
Definition mbutils.c:1389
char * pg_server_to_any(const char *s, int len, int encoding)
Definition mbutils.c:760
char * pstrdup(const char *in)
Definition mcxt.c: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:123
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
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:518
static void * list_nth(const List *list, int n)
Definition pg_list.h:299
#define plan(x)
Definition pg_regress.c:161
static char buf[DEFAULT_XLOG_SEG_SIZE]
@ PG_SQL_ASCII
Definition pg_wchar.h:226
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:1776
@ JSW_UNCONDITIONAL
Definition primnodes.h:1780
@ JSW_CONDITIONAL
Definition primnodes.h:1779
@ JSW_UNSPEC
Definition primnodes.h:1777
@ JSW_NONE
Definition primnodes.h:1778
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:311
Datum caseValue_datum
Definition execnodes.h:309
JsonbContainer * jbc
JsonPathGetVarCallback getVar
JsonBaseObjectInfo baseObject
char * base
Definition jsonpath.h:146
JsonPathItemType type
Definition jsonpath.h:137
uint32 header
Definition jsonpath.h:26
JsonTablePlanState * rootplanstate
JsonTablePlanState ** colplanstates
JsonTablePath * path
Definition primnodes.h:1925
JsonTablePlan * child
Definition primnodes.h:1934
Const * value
Definition primnodes.h:1898
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:1955
JsonTablePlan * lplan
Definition primnodes.h:1954
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
TimeADT time
Definition date.h:27
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:778
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
text * cstring_to_text(const char *s)
Definition varlena.c:184
char * text_to_cstring(const text *t)
Definition varlena.c:217
const char * type
const char * name