1 /*-------------------------------------------------------------------------
4 * I/O routines for jsonb type
6 * Copyright (c) 2014-2025, PostgreSQL Global Development Group
9 * src/backend/utils/adt/jsonb.c
11 *-------------------------------------------------------------------------
15 #include "access/htup_details.h"
16 #include "catalog/pg_proc.h"
17 #include "catalog/pg_type.h"
19 #include "libpq/pqformat.h"
20 #include "miscadmin.h"
21 #include "utils/builtins.h"
22 #include "utils/json.h"
23 #include "utils/jsonb.h"
24 #include "utils/jsonfuncs.h"
25 #include "utils/lsyscache.h"
26 #include "utils/typcache.h"
28 typedef struct JsonbInState
30 JsonbParseState
*parseState
;
36 typedef struct JsonbAggState
39 JsonTypeCategory key_category
;
41 JsonTypeCategory val_category
;
45 static inline Datum
jsonb_from_cstring(char *json
, int len
, bool unique_keys
,
47 static bool checkStringLen(size_t len
, Node
*escontext
);
48 static JsonParseErrorType
jsonb_in_object_start(void *pstate
);
49 static JsonParseErrorType
jsonb_in_object_end(void *pstate
);
50 static JsonParseErrorType
jsonb_in_array_start(void *pstate
);
51 static JsonParseErrorType
jsonb_in_array_end(void *pstate
);
52 static JsonParseErrorType
jsonb_in_object_field_start(void *pstate
, char *fname
, bool isnull
);
53 static void jsonb_put_escaped_value(StringInfo out
, JsonbValue
*scalarVal
);
54 static JsonParseErrorType
jsonb_in_scalar(void *pstate
, char *token
, JsonTokenType tokentype
);
55 static void composite_to_jsonb(Datum composite
, JsonbInState
*result
);
56 static void array_dim_to_jsonb(JsonbInState
*result
, int dim
, int ndims
, int *dims
,
57 const Datum
*vals
, const bool *nulls
, int *valcount
,
58 JsonTypeCategory tcategory
, Oid outfuncoid
);
59 static void array_to_jsonb_internal(Datum array
, JsonbInState
*result
);
60 static void datum_to_jsonb_internal(Datum val
, bool is_null
, JsonbInState
*result
,
61 JsonTypeCategory tcategory
, Oid outfuncoid
,
63 static void add_jsonb(Datum val
, bool is_null
, JsonbInState
*result
,
64 Oid val_type
, bool key_scalar
);
65 static JsonbParseState
*clone_parse_state(JsonbParseState
*state
);
66 static char *JsonbToCStringWorker(StringInfo out
, JsonbContainer
*in
, int estimated_len
, bool indent
);
67 static void add_indent(StringInfo out
, bool indent
, int level
);
70 * jsonb type input function
73 jsonb_in(PG_FUNCTION_ARGS
)
75 char *json
= PG_GETARG_CSTRING(0);
77 return jsonb_from_cstring(json
, strlen(json
), false, fcinfo
->context
);
81 * jsonb type recv function
83 * The type is sent as text in binary mode, so this is almost the same
84 * as the input function, but it's prefixed with a version number so we
85 * can change the binary format sent in future if necessary. For now,
86 * only version 1 is supported.
89 jsonb_recv(PG_FUNCTION_ARGS
)
91 StringInfo buf
= (StringInfo
) PG_GETARG_POINTER(0);
92 int version
= pq_getmsgint(buf
, 1);
97 str
= pq_getmsgtext(buf
, buf
->len
- buf
->cursor
, &nbytes
);
99 elog(ERROR
, "unsupported jsonb version number %d", version
);
101 return jsonb_from_cstring(str
, nbytes
, false, NULL
);
105 * jsonb type output function
108 jsonb_out(PG_FUNCTION_ARGS
)
110 Jsonb
*jb
= PG_GETARG_JSONB_P(0);
113 out
= JsonbToCString(NULL
, &jb
->root
, VARSIZE(jb
));
115 PG_RETURN_CSTRING(out
);
119 * jsonb type send function
121 * Just send jsonb as a version number, then a string of text
124 jsonb_send(PG_FUNCTION_ARGS
)
126 Jsonb
*jb
= PG_GETARG_JSONB_P(0);
128 StringInfo jtext
= makeStringInfo();
131 (void) JsonbToCString(jtext
, &jb
->root
, VARSIZE(jb
));
133 pq_begintypsend(&buf
);
134 pq_sendint8(&buf
, version
);
135 pq_sendtext(&buf
, jtext
->data
, jtext
->len
);
136 destroyStringInfo(jtext
);
138 PG_RETURN_BYTEA_P(pq_endtypsend(&buf
));
144 * Turns json text string into a jsonb Datum.
147 jsonb_from_text(text
*js
, bool unique_keys
)
149 return jsonb_from_cstring(VARDATA_ANY(js
),
150 VARSIZE_ANY_EXHDR(js
),
156 * Get the type name of a jsonb container.
159 JsonbContainerTypeName(JsonbContainer
*jbc
)
163 if (JsonbExtractScalar(jbc
, &scalar
))
164 return JsonbTypeName(&scalar
);
165 else if (JsonContainerIsArray(jbc
))
167 else if (JsonContainerIsObject(jbc
))
171 elog(ERROR
, "invalid jsonb container type: 0x%08x", jbc
->header
);
177 * Get the type name of a jsonb value.
180 JsonbTypeName(JsonbValue
*val
)
185 return JsonbContainerTypeName(val
->val
.binary
.data
);
199 switch (val
->val
.datetime
.typid
)
204 return "time without time zone";
206 return "time with time zone";
208 return "timestamp without time zone";
210 return "timestamp with time zone";
212 elog(ERROR
, "unrecognized jsonb value datetime type: %d",
213 val
->val
.datetime
.typid
);
217 elog(ERROR
, "unrecognized jsonb value type: %d", val
->type
);
223 * SQL function jsonb_typeof(jsonb) -> text
225 * This function is here because the analog json function is in json.c, since
226 * it uses the json parser internals not exposed elsewhere.
229 jsonb_typeof(PG_FUNCTION_ARGS
)
231 Jsonb
*in
= PG_GETARG_JSONB_P(0);
232 const char *result
= JsonbContainerTypeName(&in
->root
);
234 PG_RETURN_TEXT_P(cstring_to_text(result
));
240 * Turns json string into a jsonb Datum.
242 * Uses the json parser (with hooks) to construct a jsonb.
244 * If escontext points to an ErrorSaveContext, errors are reported there
245 * instead of being thrown.
248 jsonb_from_cstring(char *json
, int len
, bool unique_keys
, Node
*escontext
)
254 memset(&state
, 0, sizeof(state
));
255 memset(&sem
, 0, sizeof(sem
));
256 makeJsonLexContextCstringLen(&lex
, json
, len
, GetDatabaseEncoding(), true);
258 state
.unique_keys
= unique_keys
;
259 state
.escontext
= escontext
;
260 sem
.semstate
= &state
;
262 sem
.object_start
= jsonb_in_object_start
;
263 sem
.array_start
= jsonb_in_array_start
;
264 sem
.object_end
= jsonb_in_object_end
;
265 sem
.array_end
= jsonb_in_array_end
;
266 sem
.scalar
= jsonb_in_scalar
;
267 sem
.object_field_start
= jsonb_in_object_field_start
;
269 if (!pg_parse_json_or_errsave(&lex
, &sem
, escontext
))
272 /* after parsing, the item member has the composed jsonb structure */
273 PG_RETURN_POINTER(JsonbValueToJsonb(state
.res
));
277 checkStringLen(size_t len
, Node
*escontext
)
279 if (len
> JENTRY_OFFLENMASK
)
280 ereturn(escontext
, false,
281 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED
),
282 errmsg("string too long to represent as jsonb string"),
283 errdetail("Due to an implementation restriction, jsonb strings cannot exceed %d bytes.",
284 JENTRY_OFFLENMASK
)));
289 static JsonParseErrorType
290 jsonb_in_object_start(void *pstate
)
292 JsonbInState
*_state
= (JsonbInState
*) pstate
;
294 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_BEGIN_OBJECT
, NULL
);
295 _state
->parseState
->unique_keys
= _state
->unique_keys
;
300 static JsonParseErrorType
301 jsonb_in_object_end(void *pstate
)
303 JsonbInState
*_state
= (JsonbInState
*) pstate
;
305 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_END_OBJECT
, NULL
);
310 static JsonParseErrorType
311 jsonb_in_array_start(void *pstate
)
313 JsonbInState
*_state
= (JsonbInState
*) pstate
;
315 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_BEGIN_ARRAY
, NULL
);
320 static JsonParseErrorType
321 jsonb_in_array_end(void *pstate
)
323 JsonbInState
*_state
= (JsonbInState
*) pstate
;
325 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_END_ARRAY
, NULL
);
330 static JsonParseErrorType
331 jsonb_in_object_field_start(void *pstate
, char *fname
, bool isnull
)
333 JsonbInState
*_state
= (JsonbInState
*) pstate
;
336 Assert(fname
!= NULL
);
338 v
.val
.string
.len
= strlen(fname
);
339 if (!checkStringLen(v
.val
.string
.len
, _state
->escontext
))
340 return JSON_SEM_ACTION_FAILED
;
341 v
.val
.string
.val
= fname
;
343 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_KEY
, &v
);
349 jsonb_put_escaped_value(StringInfo out
, JsonbValue
*scalarVal
)
351 switch (scalarVal
->type
)
354 appendBinaryStringInfo(out
, "null", 4);
357 escape_json_with_len(out
, scalarVal
->val
.string
.val
, scalarVal
->val
.string
.len
);
360 appendStringInfoString(out
,
361 DatumGetCString(DirectFunctionCall1(numeric_out
,
362 PointerGetDatum(scalarVal
->val
.numeric
))));
365 if (scalarVal
->val
.boolean
)
366 appendBinaryStringInfo(out
, "true", 4);
368 appendBinaryStringInfo(out
, "false", 5);
371 elog(ERROR
, "unknown jsonb scalar type");
376 * For jsonb we always want the de-escaped value - that's what's in token
378 static JsonParseErrorType
379 jsonb_in_scalar(void *pstate
, char *token
, JsonTokenType tokentype
)
381 JsonbInState
*_state
= (JsonbInState
*) pstate
;
388 case JSON_TOKEN_STRING
:
389 Assert(token
!= NULL
);
391 v
.val
.string
.len
= strlen(token
);
392 if (!checkStringLen(v
.val
.string
.len
, _state
->escontext
))
393 return JSON_SEM_ACTION_FAILED
;
394 v
.val
.string
.val
= token
;
396 case JSON_TOKEN_NUMBER
:
399 * No need to check size of numeric values, because maximum
400 * numeric size is well below the JsonbValue restriction
402 Assert(token
!= NULL
);
404 if (!DirectInputFunctionCallSafe(numeric_in
, token
,
408 return JSON_SEM_ACTION_FAILED
;
409 v
.val
.numeric
= DatumGetNumeric(numd
);
411 case JSON_TOKEN_TRUE
:
413 v
.val
.boolean
= true;
415 case JSON_TOKEN_FALSE
:
417 v
.val
.boolean
= false;
419 case JSON_TOKEN_NULL
:
423 /* should not be possible */
424 elog(ERROR
, "invalid json token type");
428 if (_state
->parseState
== NULL
)
434 va
.val
.array
.rawScalar
= true;
435 va
.val
.array
.nElems
= 1;
437 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_BEGIN_ARRAY
, &va
);
438 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_ELEM
, &v
);
439 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_END_ARRAY
, NULL
);
443 JsonbValue
*o
= &_state
->parseState
->contVal
;
448 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_ELEM
, &v
);
451 _state
->res
= pushJsonbValue(&_state
->parseState
, WJB_VALUE
, &v
);
454 elog(ERROR
, "unexpected parent of nested structure");
463 * Converts jsonb value to a C-string.
465 * If 'out' argument is non-null, the resulting C-string is stored inside the
466 * StringBuffer. The resulting string is always returned.
468 * A typical case for passing the StringInfo in rather than NULL is where the
469 * caller wants access to the len attribute without having to call strlen, e.g.
470 * if they are converting it to a text* object.
473 JsonbToCString(StringInfo out
, JsonbContainer
*in
, int estimated_len
)
475 return JsonbToCStringWorker(out
, in
, estimated_len
, false);
479 * same thing but with indentation turned on
482 JsonbToCStringIndent(StringInfo out
, JsonbContainer
*in
, int estimated_len
)
484 return JsonbToCStringWorker(out
, in
, estimated_len
, true);
488 * common worker for above two functions
491 JsonbToCStringWorker(StringInfo out
, JsonbContainer
*in
, int estimated_len
, bool indent
)
496 JsonbIteratorToken type
= WJB_DONE
;
498 bool redo_switch
= false;
500 /* If we are indenting, don't add a space after a comma */
501 int ispaces
= indent
? 1 : 2;
504 * Don't indent the very first item. This gets set to the indent flag at
505 * the bottom of the loop.
507 bool use_indent
= false;
508 bool raw_scalar
= false;
509 bool last_was_key
= false;
512 out
= makeStringInfo();
514 enlargeStringInfo(out
, (estimated_len
>= 0) ? estimated_len
: 64);
516 it
= JsonbIteratorInit(in
);
518 while (redo_switch
||
519 ((type
= JsonbIteratorNext(&it
, &v
, false)) != WJB_DONE
))
524 case WJB_BEGIN_ARRAY
:
526 appendBinaryStringInfo(out
, ", ", ispaces
);
528 if (!v
.val
.array
.rawScalar
)
530 add_indent(out
, use_indent
&& !last_was_key
, level
);
531 appendStringInfoCharMacro(out
, '[');
539 case WJB_BEGIN_OBJECT
:
541 appendBinaryStringInfo(out
, ", ", ispaces
);
543 add_indent(out
, use_indent
&& !last_was_key
, level
);
544 appendStringInfoCharMacro(out
, '{');
551 appendBinaryStringInfo(out
, ", ", ispaces
);
554 add_indent(out
, use_indent
, level
);
556 /* json rules guarantee this is a string */
557 jsonb_put_escaped_value(out
, &v
);
558 appendBinaryStringInfo(out
, ": ", 2);
560 type
= JsonbIteratorNext(&it
, &v
, false);
561 if (type
== WJB_VALUE
)
564 jsonb_put_escaped_value(out
, &v
);
568 Assert(type
== WJB_BEGIN_OBJECT
|| type
== WJB_BEGIN_ARRAY
);
571 * We need to rerun the current switch() since we need to
572 * output the object which we just got from the iterator
573 * before calling the iterator again.
580 appendBinaryStringInfo(out
, ", ", ispaces
);
584 add_indent(out
, use_indent
, level
);
585 jsonb_put_escaped_value(out
, &v
);
591 add_indent(out
, use_indent
, level
);
592 appendStringInfoCharMacro(out
, ']');
598 add_indent(out
, use_indent
, level
);
599 appendStringInfoCharMacro(out
, '}');
603 elog(ERROR
, "unknown jsonb iterator token type");
606 last_was_key
= redo_switch
;
615 add_indent(StringInfo out
, bool indent
, int level
)
619 appendStringInfoCharMacro(out
, '\n');
620 appendStringInfoSpaces(out
, level
* 4);
626 * Turn a Datum into jsonb, adding it to the result JsonbInState.
628 * tcategory and outfuncoid are from a previous call to json_categorize_type,
629 * except that if is_null is true then they can be invalid.
631 * If key_scalar is true, the value is stored as a key, so insist
632 * it's of an acceptable type, and force it to be a jbvString.
634 * Note: currently, we assume that result->escontext is NULL and errors
638 datum_to_jsonb_internal(Datum val
, bool is_null
, JsonbInState
*result
,
639 JsonTypeCategory tcategory
, Oid outfuncoid
,
645 bool scalar_jsonb
= false;
649 /* Convert val to a JsonbValue in jb (in most cases) */
655 else if (key_scalar
&&
656 (tcategory
== JSONTYPE_ARRAY
||
657 tcategory
== JSONTYPE_COMPOSITE
||
658 tcategory
== JSONTYPE_JSON
||
659 tcategory
== JSONTYPE_JSONB
||
660 tcategory
== JSONTYPE_JSON
))
663 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
664 errmsg("key value must be scalar, not array, composite, or json")));
668 if (tcategory
== JSONTYPE_CAST
)
669 val
= OidFunctionCall1(outfuncoid
, val
);
674 array_to_jsonb_internal(val
, result
);
676 case JSONTYPE_COMPOSITE
:
677 composite_to_jsonb(val
, result
);
682 outputstr
= DatumGetBool(val
) ? "true" : "false";
684 jb
.val
.string
.len
= strlen(outputstr
);
685 jb
.val
.string
.val
= outputstr
;
690 jb
.val
.boolean
= DatumGetBool(val
);
693 case JSONTYPE_NUMERIC
:
694 outputstr
= OidOutputFunctionCall(outfuncoid
, val
);
697 /* always quote keys */
699 jb
.val
.string
.len
= strlen(outputstr
);
700 jb
.val
.string
.val
= outputstr
;
705 * Make it numeric if it's a valid JSON number, otherwise
706 * a string. Invalid numeric output will always have an
707 * 'N' or 'n' in it (I think).
709 numeric_error
= (strchr(outputstr
, 'N') != NULL
||
710 strchr(outputstr
, 'n') != NULL
);
715 jb
.type
= jbvNumeric
;
716 numd
= DirectFunctionCall3(numeric_in
,
717 CStringGetDatum(outputstr
),
718 ObjectIdGetDatum(InvalidOid
),
720 jb
.val
.numeric
= DatumGetNumeric(numd
);
726 jb
.val
.string
.len
= strlen(outputstr
);
727 jb
.val
.string
.val
= outputstr
;
733 jb
.val
.string
.val
= JsonEncodeDateTime(NULL
, val
,
735 jb
.val
.string
.len
= strlen(jb
.val
.string
.val
);
737 case JSONTYPE_TIMESTAMP
:
739 jb
.val
.string
.val
= JsonEncodeDateTime(NULL
, val
,
741 jb
.val
.string
.len
= strlen(jb
.val
.string
.val
);
743 case JSONTYPE_TIMESTAMPTZ
:
745 jb
.val
.string
.val
= JsonEncodeDateTime(NULL
, val
,
746 TIMESTAMPTZOID
, NULL
);
747 jb
.val
.string
.len
= strlen(jb
.val
.string
.val
);
752 /* parse the json right into the existing result object */
755 text
*json
= DatumGetTextPP(val
);
757 makeJsonLexContext(&lex
, json
, true);
759 memset(&sem
, 0, sizeof(sem
));
761 sem
.semstate
= result
;
763 sem
.object_start
= jsonb_in_object_start
;
764 sem
.array_start
= jsonb_in_array_start
;
765 sem
.object_end
= jsonb_in_object_end
;
766 sem
.array_end
= jsonb_in_array_end
;
767 sem
.scalar
= jsonb_in_scalar
;
768 sem
.object_field_start
= jsonb_in_object_field_start
;
770 pg_parse_json_or_ereport(&lex
, &sem
);
771 freeJsonLexContext(&lex
);
776 Jsonb
*jsonb
= DatumGetJsonbP(val
);
779 it
= JsonbIteratorInit(&jsonb
->root
);
781 if (JB_ROOT_IS_SCALAR(jsonb
))
783 (void) JsonbIteratorNext(&it
, &jb
, true);
784 Assert(jb
.type
== jbvArray
);
785 (void) JsonbIteratorNext(&it
, &jb
, true);
790 JsonbIteratorToken type
;
792 while ((type
= JsonbIteratorNext(&it
, &jb
, false))
795 if (type
== WJB_END_ARRAY
|| type
== WJB_END_OBJECT
||
796 type
== WJB_BEGIN_ARRAY
|| type
== WJB_BEGIN_OBJECT
)
797 result
->res
= pushJsonbValue(&result
->parseState
,
800 result
->res
= pushJsonbValue(&result
->parseState
,
807 outputstr
= OidOutputFunctionCall(outfuncoid
, val
);
809 jb
.val
.string
.len
= strlen(outputstr
);
810 (void) checkStringLen(jb
.val
.string
.len
, NULL
);
811 jb
.val
.string
.val
= outputstr
;
816 /* Now insert jb into result, unless we did it recursively */
817 if (!is_null
&& !scalar_jsonb
&&
818 tcategory
>= JSONTYPE_JSON
&& tcategory
<= JSONTYPE_CAST
)
820 /* work has been done recursively */
823 else if (result
->parseState
== NULL
)
825 /* single root scalar */
829 va
.val
.array
.rawScalar
= true;
830 va
.val
.array
.nElems
= 1;
832 result
->res
= pushJsonbValue(&result
->parseState
, WJB_BEGIN_ARRAY
, &va
);
833 result
->res
= pushJsonbValue(&result
->parseState
, WJB_ELEM
, &jb
);
834 result
->res
= pushJsonbValue(&result
->parseState
, WJB_END_ARRAY
, NULL
);
838 JsonbValue
*o
= &result
->parseState
->contVal
;
843 result
->res
= pushJsonbValue(&result
->parseState
, WJB_ELEM
, &jb
);
846 result
->res
= pushJsonbValue(&result
->parseState
,
847 key_scalar
? WJB_KEY
: WJB_VALUE
,
851 elog(ERROR
, "unexpected parent of nested structure");
857 * Process a single dimension of an array.
858 * If it's the innermost dimension, output the values, otherwise call
859 * ourselves recursively to process the next dimension.
862 array_dim_to_jsonb(JsonbInState
*result
, int dim
, int ndims
, int *dims
, const Datum
*vals
,
863 const bool *nulls
, int *valcount
, JsonTypeCategory tcategory
,
870 result
->res
= pushJsonbValue(&result
->parseState
, WJB_BEGIN_ARRAY
, NULL
);
872 for (i
= 1; i
<= dims
[dim
]; i
++)
874 if (dim
+ 1 == ndims
)
876 datum_to_jsonb_internal(vals
[*valcount
], nulls
[*valcount
], result
, tcategory
,
882 array_dim_to_jsonb(result
, dim
+ 1, ndims
, dims
, vals
, nulls
,
883 valcount
, tcategory
, outfuncoid
);
887 result
->res
= pushJsonbValue(&result
->parseState
, WJB_END_ARRAY
, NULL
);
891 * Turn an array into JSON.
894 array_to_jsonb_internal(Datum array
, JsonbInState
*result
)
896 ArrayType
*v
= DatumGetArrayTypeP(array
);
897 Oid element_type
= ARR_ELEMTYPE(v
);
907 JsonTypeCategory tcategory
;
912 nitems
= ArrayGetNItems(ndim
, dim
);
916 result
->res
= pushJsonbValue(&result
->parseState
, WJB_BEGIN_ARRAY
, NULL
);
917 result
->res
= pushJsonbValue(&result
->parseState
, WJB_END_ARRAY
, NULL
);
921 get_typlenbyvalalign(element_type
,
922 &typlen
, &typbyval
, &typalign
);
924 json_categorize_type(element_type
, true,
925 &tcategory
, &outfuncoid
);
927 deconstruct_array(v
, element_type
, typlen
, typbyval
,
928 typalign
, &elements
, &nulls
,
931 array_dim_to_jsonb(result
, 0, ndim
, dim
, elements
, nulls
, &count
, tcategory
,
939 * Turn a composite / record into JSON.
942 composite_to_jsonb(Datum composite
, JsonbInState
*result
)
948 HeapTupleData tmptup
,
952 td
= DatumGetHeapTupleHeader(composite
);
954 /* Extract rowtype info and find a tupdesc */
955 tupType
= HeapTupleHeaderGetTypeId(td
);
956 tupTypmod
= HeapTupleHeaderGetTypMod(td
);
957 tupdesc
= lookup_rowtype_tupdesc(tupType
, tupTypmod
);
959 /* Build a temporary HeapTuple control structure */
960 tmptup
.t_len
= HeapTupleHeaderGetDatumLength(td
);
964 result
->res
= pushJsonbValue(&result
->parseState
, WJB_BEGIN_OBJECT
, NULL
);
966 for (i
= 0; i
< tupdesc
->natts
; i
++)
971 JsonTypeCategory tcategory
;
974 Form_pg_attribute att
= TupleDescAttr(tupdesc
, i
);
976 if (att
->attisdropped
)
979 attname
= NameStr(att
->attname
);
982 /* don't need checkStringLen here - can't exceed maximum name length */
983 v
.val
.string
.len
= strlen(attname
);
984 v
.val
.string
.val
= attname
;
986 result
->res
= pushJsonbValue(&result
->parseState
, WJB_KEY
, &v
);
988 val
= heap_getattr(tuple
, i
+ 1, tupdesc
, &isnull
);
992 tcategory
= JSONTYPE_NULL
;
993 outfuncoid
= InvalidOid
;
996 json_categorize_type(att
->atttypid
, true, &tcategory
,
999 datum_to_jsonb_internal(val
, isnull
, result
, tcategory
, outfuncoid
,
1003 result
->res
= pushJsonbValue(&result
->parseState
, WJB_END_OBJECT
, NULL
);
1004 ReleaseTupleDesc(tupdesc
);
1008 * Append JSON text for "val" to "result".
1010 * This is just a thin wrapper around datum_to_jsonb. If the same type will be
1011 * printed many times, avoid using this; better to do the json_categorize_type
1012 * lookups only once.
1016 add_jsonb(Datum val
, bool is_null
, JsonbInState
*result
,
1017 Oid val_type
, bool key_scalar
)
1019 JsonTypeCategory tcategory
;
1022 if (val_type
== InvalidOid
)
1024 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1025 errmsg("could not determine input data type")));
1029 tcategory
= JSONTYPE_NULL
;
1030 outfuncoid
= InvalidOid
;
1033 json_categorize_type(val_type
, true,
1034 &tcategory
, &outfuncoid
);
1036 datum_to_jsonb_internal(val
, is_null
, result
, tcategory
, outfuncoid
,
1042 * Is the given type immutable when coming out of a JSONB context?
1044 * At present, datetimes are all considered mutable, because they
1045 * depend on timezone. XXX we should also drill down into objects and
1046 * arrays, but do not.
1049 to_jsonb_is_immutable(Oid typoid
)
1051 JsonTypeCategory tcategory
;
1054 json_categorize_type(typoid
, true, &tcategory
, &outfuncoid
);
1061 case JSONTYPE_JSONB
:
1065 case JSONTYPE_TIMESTAMP
:
1066 case JSONTYPE_TIMESTAMPTZ
:
1069 case JSONTYPE_ARRAY
:
1070 return false; /* TODO recurse into elements */
1072 case JSONTYPE_COMPOSITE
:
1073 return false; /* TODO recurse into fields */
1075 case JSONTYPE_NUMERIC
:
1077 case JSONTYPE_OTHER
:
1078 return func_volatile(outfuncoid
) == PROVOLATILE_IMMUTABLE
;
1081 return false; /* not reached */
1085 * SQL function to_jsonb(anyvalue)
1088 to_jsonb(PG_FUNCTION_ARGS
)
1090 Datum val
= PG_GETARG_DATUM(0);
1091 Oid val_type
= get_fn_expr_argtype(fcinfo
->flinfo
, 0);
1092 JsonTypeCategory tcategory
;
1095 if (val_type
== InvalidOid
)
1097 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1098 errmsg("could not determine input data type")));
1100 json_categorize_type(val_type
, true,
1101 &tcategory
, &outfuncoid
);
1103 PG_RETURN_DATUM(datum_to_jsonb(val
, tcategory
, outfuncoid
));
1107 * Turn a Datum into jsonb.
1109 * tcategory and outfuncoid are from a previous call to json_categorize_type.
1112 datum_to_jsonb(Datum val
, JsonTypeCategory tcategory
, Oid outfuncoid
)
1114 JsonbInState result
;
1116 memset(&result
, 0, sizeof(JsonbInState
));
1118 datum_to_jsonb_internal(val
, false, &result
, tcategory
, outfuncoid
,
1121 return JsonbPGetDatum(JsonbValueToJsonb(result
.res
));
1125 jsonb_build_object_worker(int nargs
, const Datum
*args
, const bool *nulls
, const Oid
*types
,
1126 bool absent_on_null
, bool unique_keys
)
1129 JsonbInState result
;
1133 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1134 errmsg("argument list must have even number of elements"),
1135 /* translator: %s is a SQL function name */
1136 errhint("The arguments of %s must consist of alternating keys and values.",
1137 "jsonb_build_object()")));
1139 memset(&result
, 0, sizeof(JsonbInState
));
1141 result
.res
= pushJsonbValue(&result
.parseState
, WJB_BEGIN_OBJECT
, NULL
);
1142 result
.parseState
->unique_keys
= unique_keys
;
1143 result
.parseState
->skip_nulls
= absent_on_null
;
1145 for (i
= 0; i
< nargs
; i
+= 2)
1152 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1153 errmsg("argument %d: key must not be null", i
+ 1)));
1155 /* skip null values if absent_on_null */
1156 skip
= absent_on_null
&& nulls
[i
+ 1];
1158 /* we need to save skipped keys for the key uniqueness check */
1159 if (skip
&& !unique_keys
)
1162 add_jsonb(args
[i
], false, &result
, types
[i
], true);
1165 add_jsonb(args
[i
+ 1], nulls
[i
+ 1], &result
, types
[i
+ 1], false);
1168 result
.res
= pushJsonbValue(&result
.parseState
, WJB_END_OBJECT
, NULL
);
1170 return JsonbPGetDatum(JsonbValueToJsonb(result
.res
));
1174 * SQL function jsonb_build_object(variadic "any")
1177 jsonb_build_object(PG_FUNCTION_ARGS
)
1183 /* build argument values to build the object */
1184 int nargs
= extract_variadic_args(fcinfo
, 0, true,
1185 &args
, &types
, &nulls
);
1190 PG_RETURN_DATUM(jsonb_build_object_worker(nargs
, args
, nulls
, types
, false, false));
1194 * degenerate case of jsonb_build_object where it gets 0 arguments.
1197 jsonb_build_object_noargs(PG_FUNCTION_ARGS
)
1199 JsonbInState result
;
1201 memset(&result
, 0, sizeof(JsonbInState
));
1203 (void) pushJsonbValue(&result
.parseState
, WJB_BEGIN_OBJECT
, NULL
);
1204 result
.res
= pushJsonbValue(&result
.parseState
, WJB_END_OBJECT
, NULL
);
1206 PG_RETURN_POINTER(JsonbValueToJsonb(result
.res
));
1210 jsonb_build_array_worker(int nargs
, const Datum
*args
, const bool *nulls
, const Oid
*types
,
1211 bool absent_on_null
)
1214 JsonbInState result
;
1216 memset(&result
, 0, sizeof(JsonbInState
));
1218 result
.res
= pushJsonbValue(&result
.parseState
, WJB_BEGIN_ARRAY
, NULL
);
1220 for (i
= 0; i
< nargs
; i
++)
1222 if (absent_on_null
&& nulls
[i
])
1225 add_jsonb(args
[i
], nulls
[i
], &result
, types
[i
], false);
1228 result
.res
= pushJsonbValue(&result
.parseState
, WJB_END_ARRAY
, NULL
);
1230 return JsonbPGetDatum(JsonbValueToJsonb(result
.res
));
1234 * SQL function jsonb_build_array(variadic "any")
1237 jsonb_build_array(PG_FUNCTION_ARGS
)
1243 /* build argument values to build the object */
1244 int nargs
= extract_variadic_args(fcinfo
, 0, true,
1245 &args
, &types
, &nulls
);
1250 PG_RETURN_DATUM(jsonb_build_array_worker(nargs
, args
, nulls
, types
, false));
1255 * degenerate case of jsonb_build_array where it gets 0 arguments.
1258 jsonb_build_array_noargs(PG_FUNCTION_ARGS
)
1260 JsonbInState result
;
1262 memset(&result
, 0, sizeof(JsonbInState
));
1264 (void) pushJsonbValue(&result
.parseState
, WJB_BEGIN_ARRAY
, NULL
);
1265 result
.res
= pushJsonbValue(&result
.parseState
, WJB_END_ARRAY
, NULL
);
1267 PG_RETURN_POINTER(JsonbValueToJsonb(result
.res
));
1272 * SQL function jsonb_object(text[])
1274 * take a one or two dimensional array of text as name value pairs
1275 * for a jsonb object.
1279 jsonb_object(PG_FUNCTION_ARGS
)
1281 ArrayType
*in_array
= PG_GETARG_ARRAYTYPE_P(0);
1282 int ndims
= ARR_NDIM(in_array
);
1288 JsonbInState result
;
1290 memset(&result
, 0, sizeof(JsonbInState
));
1292 (void) pushJsonbValue(&result
.parseState
, WJB_BEGIN_OBJECT
, NULL
);
1301 if ((ARR_DIMS(in_array
)[0]) % 2)
1303 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR
),
1304 errmsg("array must have even number of elements")));
1308 if ((ARR_DIMS(in_array
)[1]) != 2)
1310 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR
),
1311 errmsg("array must have two columns")));
1316 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR
),
1317 errmsg("wrong number of array subscripts")));
1320 deconstruct_array_builtin(in_array
, TEXTOID
, &in_datums
, &in_nulls
, &in_count
);
1322 count
= in_count
/ 2;
1324 for (i
= 0; i
< count
; ++i
)
1330 if (in_nulls
[i
* 2])
1332 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED
),
1333 errmsg("null value not allowed for object key")));
1335 str
= TextDatumGetCString(in_datums
[i
* 2]);
1340 v
.val
.string
.len
= len
;
1341 v
.val
.string
.val
= str
;
1343 (void) pushJsonbValue(&result
.parseState
, WJB_KEY
, &v
);
1345 if (in_nulls
[i
* 2 + 1])
1351 str
= TextDatumGetCString(in_datums
[i
* 2 + 1]);
1356 v
.val
.string
.len
= len
;
1357 v
.val
.string
.val
= str
;
1360 (void) pushJsonbValue(&result
.parseState
, WJB_VALUE
, &v
);
1367 result
.res
= pushJsonbValue(&result
.parseState
, WJB_END_OBJECT
, NULL
);
1369 PG_RETURN_POINTER(JsonbValueToJsonb(result
.res
));
1373 * SQL function jsonb_object(text[], text[])
1375 * take separate name and value arrays of text to construct a jsonb object
1379 jsonb_object_two_arg(PG_FUNCTION_ARGS
)
1381 ArrayType
*key_array
= PG_GETARG_ARRAYTYPE_P(0);
1382 ArrayType
*val_array
= PG_GETARG_ARRAYTYPE_P(1);
1383 int nkdims
= ARR_NDIM(key_array
);
1384 int nvdims
= ARR_NDIM(val_array
);
1392 JsonbInState result
;
1394 memset(&result
, 0, sizeof(JsonbInState
));
1396 (void) pushJsonbValue(&result
.parseState
, WJB_BEGIN_OBJECT
, NULL
);
1398 if (nkdims
> 1 || nkdims
!= nvdims
)
1400 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR
),
1401 errmsg("wrong number of array subscripts")));
1406 deconstruct_array_builtin(key_array
, TEXTOID
, &key_datums
, &key_nulls
, &key_count
);
1407 deconstruct_array_builtin(val_array
, TEXTOID
, &val_datums
, &val_nulls
, &val_count
);
1409 if (key_count
!= val_count
)
1411 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR
),
1412 errmsg("mismatched array dimensions")));
1414 for (i
= 0; i
< key_count
; ++i
)
1422 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED
),
1423 errmsg("null value not allowed for object key")));
1425 str
= TextDatumGetCString(key_datums
[i
]);
1430 v
.val
.string
.len
= len
;
1431 v
.val
.string
.val
= str
;
1433 (void) pushJsonbValue(&result
.parseState
, WJB_KEY
, &v
);
1441 str
= TextDatumGetCString(val_datums
[i
]);
1446 v
.val
.string
.len
= len
;
1447 v
.val
.string
.val
= str
;
1450 (void) pushJsonbValue(&result
.parseState
, WJB_VALUE
, &v
);
1459 result
.res
= pushJsonbValue(&result
.parseState
, WJB_END_OBJECT
, NULL
);
1461 PG_RETURN_POINTER(JsonbValueToJsonb(result
.res
));
1466 * shallow clone of a parse state, suitable for use in aggregate
1467 * final functions that will only append to the values rather than
1470 static JsonbParseState
*
1471 clone_parse_state(JsonbParseState
*state
)
1473 JsonbParseState
*result
,
1480 result
= palloc(sizeof(JsonbParseState
));
1485 ocursor
->contVal
= icursor
->contVal
;
1486 ocursor
->size
= icursor
->size
;
1487 ocursor
->unique_keys
= icursor
->unique_keys
;
1488 ocursor
->skip_nulls
= icursor
->skip_nulls
;
1489 icursor
= icursor
->next
;
1490 if (icursor
== NULL
)
1492 ocursor
->next
= palloc(sizeof(JsonbParseState
));
1493 ocursor
= ocursor
->next
;
1495 ocursor
->next
= NULL
;
1501 jsonb_agg_transfn_worker(FunctionCallInfo fcinfo
, bool absent_on_null
)
1503 MemoryContext oldcontext
,
1505 JsonbAggState
*state
;
1508 JsonbInState
*result
;
1509 bool single_scalar
= false;
1513 JsonbIteratorToken type
;
1515 if (!AggCheckCallContext(fcinfo
, &aggcontext
))
1517 /* cannot be called directly because of internal-type argument */
1518 elog(ERROR
, "jsonb_agg_transfn called in non-aggregate context");
1521 /* set up the accumulator on the first go round */
1523 if (PG_ARGISNULL(0))
1525 Oid arg_type
= get_fn_expr_argtype(fcinfo
->flinfo
, 1);
1527 if (arg_type
== InvalidOid
)
1529 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1530 errmsg("could not determine input data type")));
1532 oldcontext
= MemoryContextSwitchTo(aggcontext
);
1533 state
= palloc(sizeof(JsonbAggState
));
1534 result
= palloc0(sizeof(JsonbInState
));
1535 state
->res
= result
;
1536 result
->res
= pushJsonbValue(&result
->parseState
,
1537 WJB_BEGIN_ARRAY
, NULL
);
1538 MemoryContextSwitchTo(oldcontext
);
1540 json_categorize_type(arg_type
, true, &state
->val_category
,
1541 &state
->val_output_func
);
1545 state
= (JsonbAggState
*) PG_GETARG_POINTER(0);
1546 result
= state
->res
;
1549 if (absent_on_null
&& PG_ARGISNULL(1))
1550 PG_RETURN_POINTER(state
);
1552 /* turn the argument into jsonb in the normal function context */
1554 val
= PG_ARGISNULL(1) ? (Datum
) 0 : PG_GETARG_DATUM(1);
1556 memset(&elem
, 0, sizeof(JsonbInState
));
1558 datum_to_jsonb_internal(val
, PG_ARGISNULL(1), &elem
, state
->val_category
,
1559 state
->val_output_func
, false);
1561 jbelem
= JsonbValueToJsonb(elem
.res
);
1563 /* switch to the aggregate context for accumulation operations */
1565 oldcontext
= MemoryContextSwitchTo(aggcontext
);
1567 it
= JsonbIteratorInit(&jbelem
->root
);
1569 while ((type
= JsonbIteratorNext(&it
, &v
, false)) != WJB_DONE
)
1573 case WJB_BEGIN_ARRAY
:
1574 if (v
.val
.array
.rawScalar
)
1575 single_scalar
= true;
1577 result
->res
= pushJsonbValue(&result
->parseState
,
1582 result
->res
= pushJsonbValue(&result
->parseState
,
1585 case WJB_BEGIN_OBJECT
:
1586 case WJB_END_OBJECT
:
1587 result
->res
= pushJsonbValue(&result
->parseState
,
1593 if (v
.type
== jbvString
)
1595 /* copy string values in the aggregate context */
1596 char *buf
= palloc(v
.val
.string
.len
+ 1);
1598 snprintf(buf
, v
.val
.string
.len
+ 1, "%s", v
.val
.string
.val
);
1599 v
.val
.string
.val
= buf
;
1601 else if (v
.type
== jbvNumeric
)
1603 /* same for numeric */
1605 DatumGetNumeric(DirectFunctionCall1(numeric_uplus
,
1606 NumericGetDatum(v
.val
.numeric
)));
1608 result
->res
= pushJsonbValue(&result
->parseState
,
1612 elog(ERROR
, "unknown jsonb iterator token type");
1616 MemoryContextSwitchTo(oldcontext
);
1618 PG_RETURN_POINTER(state
);
1622 * jsonb_agg aggregate function
1625 jsonb_agg_transfn(PG_FUNCTION_ARGS
)
1627 return jsonb_agg_transfn_worker(fcinfo
, false);
1631 * jsonb_agg_strict aggregate function
1634 jsonb_agg_strict_transfn(PG_FUNCTION_ARGS
)
1636 return jsonb_agg_transfn_worker(fcinfo
, true);
1640 jsonb_agg_finalfn(PG_FUNCTION_ARGS
)
1643 JsonbInState result
;
1646 /* cannot be called directly because of internal-type argument */
1647 Assert(AggCheckCallContext(fcinfo
, NULL
));
1649 if (PG_ARGISNULL(0))
1650 PG_RETURN_NULL(); /* returns null iff no input values */
1652 arg
= (JsonbAggState
*) PG_GETARG_POINTER(0);
1655 * We need to do a shallow clone of the argument in case the final
1656 * function is called more than once, so we avoid changing the argument. A
1657 * shallow clone is sufficient as we aren't going to change any of the
1658 * values, just add the final array end marker.
1660 memset(&result
, 0, sizeof(JsonbInState
));
1662 result
.parseState
= clone_parse_state(arg
->res
->parseState
);
1664 result
.res
= pushJsonbValue(&result
.parseState
,
1665 WJB_END_ARRAY
, NULL
);
1667 out
= JsonbValueToJsonb(result
.res
);
1669 PG_RETURN_POINTER(out
);
1673 jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo
,
1674 bool absent_on_null
, bool unique_keys
)
1676 MemoryContext oldcontext
,
1679 JsonbAggState
*state
;
1681 JsonbInState
*result
;
1687 JsonbIteratorToken type
;
1690 if (!AggCheckCallContext(fcinfo
, &aggcontext
))
1692 /* cannot be called directly because of internal-type argument */
1693 elog(ERROR
, "jsonb_object_agg_transfn called in non-aggregate context");
1696 /* set up the accumulator on the first go round */
1698 if (PG_ARGISNULL(0))
1702 oldcontext
= MemoryContextSwitchTo(aggcontext
);
1703 state
= palloc(sizeof(JsonbAggState
));
1704 result
= palloc0(sizeof(JsonbInState
));
1705 state
->res
= result
;
1706 result
->res
= pushJsonbValue(&result
->parseState
,
1707 WJB_BEGIN_OBJECT
, NULL
);
1708 result
->parseState
->unique_keys
= unique_keys
;
1709 result
->parseState
->skip_nulls
= absent_on_null
;
1711 MemoryContextSwitchTo(oldcontext
);
1713 arg_type
= get_fn_expr_argtype(fcinfo
->flinfo
, 1);
1715 if (arg_type
== InvalidOid
)
1717 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1718 errmsg("could not determine input data type")));
1720 json_categorize_type(arg_type
, true, &state
->key_category
,
1721 &state
->key_output_func
);
1723 arg_type
= get_fn_expr_argtype(fcinfo
->flinfo
, 2);
1725 if (arg_type
== InvalidOid
)
1727 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1728 errmsg("could not determine input data type")));
1730 json_categorize_type(arg_type
, true, &state
->val_category
,
1731 &state
->val_output_func
);
1735 state
= (JsonbAggState
*) PG_GETARG_POINTER(0);
1736 result
= state
->res
;
1739 /* turn the argument into jsonb in the normal function context */
1741 if (PG_ARGISNULL(1))
1743 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1744 errmsg("field name must not be null")));
1747 * Skip null values if absent_on_null unless key uniqueness check is
1748 * needed (because we must save keys in this case).
1750 skip
= absent_on_null
&& PG_ARGISNULL(2);
1752 if (skip
&& !unique_keys
)
1753 PG_RETURN_POINTER(state
);
1755 val
= PG_GETARG_DATUM(1);
1757 memset(&elem
, 0, sizeof(JsonbInState
));
1759 datum_to_jsonb_internal(val
, false, &elem
, state
->key_category
,
1760 state
->key_output_func
, true);
1762 jbkey
= JsonbValueToJsonb(elem
.res
);
1764 val
= PG_ARGISNULL(2) ? (Datum
) 0 : PG_GETARG_DATUM(2);
1766 memset(&elem
, 0, sizeof(JsonbInState
));
1768 datum_to_jsonb_internal(val
, PG_ARGISNULL(2), &elem
, state
->val_category
,
1769 state
->val_output_func
, false);
1771 jbval
= JsonbValueToJsonb(elem
.res
);
1773 it
= JsonbIteratorInit(&jbkey
->root
);
1775 /* switch to the aggregate context for accumulation operations */
1777 oldcontext
= MemoryContextSwitchTo(aggcontext
);
1780 * keys should be scalar, and we should have already checked for that
1781 * above when calling datum_to_jsonb, so we only need to look for these
1785 while ((type
= JsonbIteratorNext(&it
, &v
, false)) != WJB_DONE
)
1789 case WJB_BEGIN_ARRAY
:
1790 if (!v
.val
.array
.rawScalar
)
1791 elog(ERROR
, "unexpected structure for key");
1794 if (v
.type
== jbvString
)
1796 /* copy string values in the aggregate context */
1797 char *buf
= palloc(v
.val
.string
.len
+ 1);
1799 snprintf(buf
, v
.val
.string
.len
+ 1, "%s", v
.val
.string
.val
);
1800 v
.val
.string
.val
= buf
;
1805 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
1806 errmsg("object keys must be strings")));
1808 result
->res
= pushJsonbValue(&result
->parseState
,
1814 result
->res
= pushJsonbValue(&result
->parseState
,
1816 MemoryContextSwitchTo(oldcontext
);
1817 PG_RETURN_POINTER(state
);
1824 elog(ERROR
, "unexpected structure for key");
1829 it
= JsonbIteratorInit(&jbval
->root
);
1831 single_scalar
= false;
1834 * values can be anything, including structured and null, so we treat them
1835 * as in json_agg_transfn, except that single scalars are always pushed as
1839 while ((type
= JsonbIteratorNext(&it
, &v
, false)) != WJB_DONE
)
1843 case WJB_BEGIN_ARRAY
:
1844 if (v
.val
.array
.rawScalar
)
1845 single_scalar
= true;
1847 result
->res
= pushJsonbValue(&result
->parseState
,
1852 result
->res
= pushJsonbValue(&result
->parseState
,
1855 case WJB_BEGIN_OBJECT
:
1856 case WJB_END_OBJECT
:
1857 result
->res
= pushJsonbValue(&result
->parseState
,
1863 if (v
.type
== jbvString
)
1865 /* copy string values in the aggregate context */
1866 char *buf
= palloc(v
.val
.string
.len
+ 1);
1868 snprintf(buf
, v
.val
.string
.len
+ 1, "%s", v
.val
.string
.val
);
1869 v
.val
.string
.val
= buf
;
1871 else if (v
.type
== jbvNumeric
)
1873 /* same for numeric */
1875 DatumGetNumeric(DirectFunctionCall1(numeric_uplus
,
1876 NumericGetDatum(v
.val
.numeric
)));
1878 result
->res
= pushJsonbValue(&result
->parseState
,
1879 single_scalar
? WJB_VALUE
: type
,
1883 elog(ERROR
, "unknown jsonb iterator token type");
1887 MemoryContextSwitchTo(oldcontext
);
1889 PG_RETURN_POINTER(state
);
1893 * jsonb_object_agg aggregate function
1896 jsonb_object_agg_transfn(PG_FUNCTION_ARGS
)
1898 return jsonb_object_agg_transfn_worker(fcinfo
, false, false);
1903 * jsonb_object_agg_strict aggregate function
1906 jsonb_object_agg_strict_transfn(PG_FUNCTION_ARGS
)
1908 return jsonb_object_agg_transfn_worker(fcinfo
, true, false);
1912 * jsonb_object_agg_unique aggregate function
1915 jsonb_object_agg_unique_transfn(PG_FUNCTION_ARGS
)
1917 return jsonb_object_agg_transfn_worker(fcinfo
, false, true);
1921 * jsonb_object_agg_unique_strict aggregate function
1924 jsonb_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS
)
1926 return jsonb_object_agg_transfn_worker(fcinfo
, true, true);
1930 jsonb_object_agg_finalfn(PG_FUNCTION_ARGS
)
1933 JsonbInState result
;
1936 /* cannot be called directly because of internal-type argument */
1937 Assert(AggCheckCallContext(fcinfo
, NULL
));
1939 if (PG_ARGISNULL(0))
1940 PG_RETURN_NULL(); /* returns null iff no input values */
1942 arg
= (JsonbAggState
*) PG_GETARG_POINTER(0);
1945 * We need to do a shallow clone of the argument's res field in case the
1946 * final function is called more than once, so we avoid changing the
1947 * aggregate state value. A shallow clone is sufficient as we aren't
1948 * going to change any of the values, just add the final object end
1951 memset(&result
, 0, sizeof(JsonbInState
));
1953 result
.parseState
= clone_parse_state(arg
->res
->parseState
);
1955 result
.res
= pushJsonbValue(&result
.parseState
,
1956 WJB_END_OBJECT
, NULL
);
1958 out
= JsonbValueToJsonb(result
.res
);
1960 PG_RETURN_POINTER(out
);
1965 * Extract scalar value from raw-scalar pseudo-array jsonb.
1968 JsonbExtractScalar(JsonbContainer
*jbc
, JsonbValue
*res
)
1971 JsonbIteratorToken tok PG_USED_FOR_ASSERTS_ONLY
;
1974 if (!JsonContainerIsArray(jbc
) || !JsonContainerIsScalar(jbc
))
1976 /* inform caller about actual type of container */
1977 res
->type
= (JsonContainerIsArray(jbc
)) ? jbvArray
: jbvObject
;
1982 * A root scalar is stored as an array of one element, so we get the array
1983 * and then its first (and only) member.
1985 it
= JsonbIteratorInit(jbc
);
1987 tok
= JsonbIteratorNext(&it
, &tmp
, true);
1988 Assert(tok
== WJB_BEGIN_ARRAY
);
1989 Assert(tmp
.val
.array
.nElems
== 1 && tmp
.val
.array
.rawScalar
);
1991 tok
= JsonbIteratorNext(&it
, res
, true);
1992 Assert(tok
== WJB_ELEM
);
1993 Assert(IsAJsonbScalar(res
));
1995 tok
= JsonbIteratorNext(&it
, &tmp
, true);
1996 Assert(tok
== WJB_END_ARRAY
);
1998 tok
= JsonbIteratorNext(&it
, &tmp
, true);
1999 Assert(tok
== WJB_DONE
);
2005 * Emit correct, translatable cast error message
2008 cannotCastJsonbValue(enum jbvType type
, const char *sqltype
)
2017 {jbvNull
, gettext_noop("cannot cast jsonb null to type %s")},
2018 {jbvString
, gettext_noop("cannot cast jsonb string to type %s")},
2019 {jbvNumeric
, gettext_noop("cannot cast jsonb numeric to type %s")},
2020 {jbvBool
, gettext_noop("cannot cast jsonb boolean to type %s")},
2021 {jbvArray
, gettext_noop("cannot cast jsonb array to type %s")},
2022 {jbvObject
, gettext_noop("cannot cast jsonb object to type %s")},
2023 {jbvBinary
, gettext_noop("cannot cast jsonb array or object to type %s")}
2027 for (i
= 0; i
< lengthof(messages
); i
++)
2028 if (messages
[i
].type
== type
)
2030 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2031 errmsg(messages
[i
].msg
, sqltype
)));
2033 /* should be unreachable */
2034 elog(ERROR
, "unknown jsonb type: %d", (int) type
);
2038 jsonb_bool(PG_FUNCTION_ARGS
)
2040 Jsonb
*in
= PG_GETARG_JSONB_P(0);
2043 if (!JsonbExtractScalar(&in
->root
, &v
))
2044 cannotCastJsonbValue(v
.type
, "boolean");
2046 if (v
.type
== jbvNull
)
2048 PG_FREE_IF_COPY(in
, 0);
2052 if (v
.type
!= jbvBool
)
2053 cannotCastJsonbValue(v
.type
, "boolean");
2055 PG_FREE_IF_COPY(in
, 0);
2057 PG_RETURN_BOOL(v
.val
.boolean
);
2061 jsonb_numeric(PG_FUNCTION_ARGS
)
2063 Jsonb
*in
= PG_GETARG_JSONB_P(0);
2067 if (!JsonbExtractScalar(&in
->root
, &v
))
2068 cannotCastJsonbValue(v
.type
, "numeric");
2070 if (v
.type
== jbvNull
)
2072 PG_FREE_IF_COPY(in
, 0);
2076 if (v
.type
!= jbvNumeric
)
2077 cannotCastJsonbValue(v
.type
, "numeric");
2080 * v.val.numeric points into jsonb body, so we need to make a copy to
2083 retValue
= DatumGetNumericCopy(NumericGetDatum(v
.val
.numeric
));
2085 PG_FREE_IF_COPY(in
, 0);
2087 PG_RETURN_NUMERIC(retValue
);
2091 jsonb_int2(PG_FUNCTION_ARGS
)
2093 Jsonb
*in
= PG_GETARG_JSONB_P(0);
2097 if (!JsonbExtractScalar(&in
->root
, &v
))
2098 cannotCastJsonbValue(v
.type
, "smallint");
2100 if (v
.type
== jbvNull
)
2102 PG_FREE_IF_COPY(in
, 0);
2106 if (v
.type
!= jbvNumeric
)
2107 cannotCastJsonbValue(v
.type
, "smallint");
2109 retValue
= DirectFunctionCall1(numeric_int2
,
2110 NumericGetDatum(v
.val
.numeric
));
2112 PG_FREE_IF_COPY(in
, 0);
2114 PG_RETURN_DATUM(retValue
);
2118 jsonb_int4(PG_FUNCTION_ARGS
)
2120 Jsonb
*in
= PG_GETARG_JSONB_P(0);
2124 if (!JsonbExtractScalar(&in
->root
, &v
))
2125 cannotCastJsonbValue(v
.type
, "integer");
2127 if (v
.type
== jbvNull
)
2129 PG_FREE_IF_COPY(in
, 0);
2133 if (v
.type
!= jbvNumeric
)
2134 cannotCastJsonbValue(v
.type
, "integer");
2136 retValue
= DirectFunctionCall1(numeric_int4
,
2137 NumericGetDatum(v
.val
.numeric
));
2139 PG_FREE_IF_COPY(in
, 0);
2141 PG_RETURN_DATUM(retValue
);
2145 jsonb_int8(PG_FUNCTION_ARGS
)
2147 Jsonb
*in
= PG_GETARG_JSONB_P(0);
2151 if (!JsonbExtractScalar(&in
->root
, &v
))
2152 cannotCastJsonbValue(v
.type
, "bigint");
2154 if (v
.type
== jbvNull
)
2156 PG_FREE_IF_COPY(in
, 0);
2160 if (v
.type
!= jbvNumeric
)
2161 cannotCastJsonbValue(v
.type
, "bigint");
2163 retValue
= DirectFunctionCall1(numeric_int8
,
2164 NumericGetDatum(v
.val
.numeric
));
2166 PG_FREE_IF_COPY(in
, 0);
2168 PG_RETURN_DATUM(retValue
);
2172 jsonb_float4(PG_FUNCTION_ARGS
)
2174 Jsonb
*in
= PG_GETARG_JSONB_P(0);
2178 if (!JsonbExtractScalar(&in
->root
, &v
))
2179 cannotCastJsonbValue(v
.type
, "real");
2181 if (v
.type
== jbvNull
)
2183 PG_FREE_IF_COPY(in
, 0);
2187 if (v
.type
!= jbvNumeric
)
2188 cannotCastJsonbValue(v
.type
, "real");
2190 retValue
= DirectFunctionCall1(numeric_float4
,
2191 NumericGetDatum(v
.val
.numeric
));
2193 PG_FREE_IF_COPY(in
, 0);
2195 PG_RETURN_DATUM(retValue
);
2199 jsonb_float8(PG_FUNCTION_ARGS
)
2201 Jsonb
*in
= PG_GETARG_JSONB_P(0);
2205 if (!JsonbExtractScalar(&in
->root
, &v
))
2206 cannotCastJsonbValue(v
.type
, "double precision");
2208 if (v
.type
== jbvNull
)
2210 PG_FREE_IF_COPY(in
, 0);
2214 if (v
.type
!= jbvNumeric
)
2215 cannotCastJsonbValue(v
.type
, "double precision");
2217 retValue
= DirectFunctionCall1(numeric_float8
,
2218 NumericGetDatum(v
.val
.numeric
));
2220 PG_FREE_IF_COPY(in
, 0);
2222 PG_RETURN_DATUM(retValue
);
2226 * Convert jsonb to a C-string stripping quotes from scalar strings.
2229 JsonbUnquote(Jsonb
*jb
)
2231 if (JB_ROOT_IS_SCALAR(jb
))
2235 (void) JsonbExtractScalar(&jb
->root
, &v
);
2237 if (v
.type
== jbvString
)
2238 return pnstrdup(v
.val
.string
.val
, v
.val
.string
.len
);
2239 else if (v
.type
== jbvBool
)
2240 return pstrdup(v
.val
.boolean
? "true" : "false");
2241 else if (v
.type
== jbvNumeric
)
2242 return DatumGetCString(DirectFunctionCall1(numeric_out
,
2243 PointerGetDatum(v
.val
.numeric
)));
2244 else if (v
.type
== jbvNull
)
2245 return pstrdup("null");
2248 elog(ERROR
, "unrecognized jsonb value type %d", v
.type
);
2253 return JsonbToCString(NULL
, &jb
->root
, VARSIZE(jb
));