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