Cache NO ACTION foreign keys separately from RESTRICT foreign keys
[pgsql.git] / src / backend / utils / adt / jsonb.c
blob8394a20e0e5e6c8dcffdeb94dc4bbaf8ac5d10bc
1 /*-------------------------------------------------------------------------
3 * jsonb.c
4 * I/O routines for jsonb type
6 * Copyright (c) 2014-2025, PostgreSQL Global Development Group
8 * IDENTIFICATION
9 * src/backend/utils/adt/jsonb.c
11 *-------------------------------------------------------------------------
13 #include "postgres.h"
15 #include "access/htup_details.h"
16 #include "catalog/pg_proc.h"
17 #include "catalog/pg_type.h"
18 #include "funcapi.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;
31 JsonbValue *res;
32 bool unique_keys;
33 Node *escontext;
34 } JsonbInState;
36 typedef struct JsonbAggState
38 JsonbInState *res;
39 JsonTypeCategory key_category;
40 Oid key_output_func;
41 JsonTypeCategory val_category;
42 Oid val_output_func;
43 } JsonbAggState;
45 static inline Datum jsonb_from_cstring(char *json, int len, bool unique_keys,
46 Node *escontext);
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,
62 bool key_scalar);
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
72 Datum
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.
88 Datum
89 jsonb_recv(PG_FUNCTION_ARGS)
91 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
92 int version = pq_getmsgint(buf, 1);
93 char *str;
94 int nbytes;
96 if (version == 1)
97 str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
98 else
99 elog(ERROR, "unsupported jsonb version number %d", version);
101 return jsonb_from_cstring(str, nbytes, false, NULL);
105 * jsonb type output function
107 Datum
108 jsonb_out(PG_FUNCTION_ARGS)
110 Jsonb *jb = PG_GETARG_JSONB_P(0);
111 char *out;
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
123 Datum
124 jsonb_send(PG_FUNCTION_ARGS)
126 Jsonb *jb = PG_GETARG_JSONB_P(0);
127 StringInfoData buf;
128 StringInfo jtext = makeStringInfo();
129 int version = 1;
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));
142 * jsonb_from_text
144 * Turns json text string into a jsonb Datum.
146 Datum
147 jsonb_from_text(text *js, bool unique_keys)
149 return jsonb_from_cstring(VARDATA_ANY(js),
150 VARSIZE_ANY_EXHDR(js),
151 unique_keys,
152 NULL);
156 * Get the type name of a jsonb container.
158 static const char *
159 JsonbContainerTypeName(JsonbContainer *jbc)
161 JsonbValue scalar;
163 if (JsonbExtractScalar(jbc, &scalar))
164 return JsonbTypeName(&scalar);
165 else if (JsonContainerIsArray(jbc))
166 return "array";
167 else if (JsonContainerIsObject(jbc))
168 return "object";
169 else
171 elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
172 return "unknown";
177 * Get the type name of a jsonb value.
179 const char *
180 JsonbTypeName(JsonbValue *val)
182 switch (val->type)
184 case jbvBinary:
185 return JsonbContainerTypeName(val->val.binary.data);
186 case jbvObject:
187 return "object";
188 case jbvArray:
189 return "array";
190 case jbvNumeric:
191 return "number";
192 case jbvString:
193 return "string";
194 case jbvBool:
195 return "boolean";
196 case jbvNull:
197 return "null";
198 case jbvDatetime:
199 switch (val->val.datetime.typid)
201 case DATEOID:
202 return "date";
203 case TIMEOID:
204 return "time without time zone";
205 case TIMETZOID:
206 return "time with time zone";
207 case TIMESTAMPOID:
208 return "timestamp without time zone";
209 case TIMESTAMPTZOID:
210 return "timestamp with time zone";
211 default:
212 elog(ERROR, "unrecognized jsonb value datetime type: %d",
213 val->val.datetime.typid);
215 return "unknown";
216 default:
217 elog(ERROR, "unrecognized jsonb value type: %d", val->type);
218 return "unknown";
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.
228 Datum
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));
238 * jsonb_from_cstring
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.
247 static inline Datum
248 jsonb_from_cstring(char *json, int len, bool unique_keys, Node *escontext)
250 JsonLexContext lex;
251 JsonbInState state;
252 JsonSemAction sem;
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))
270 return (Datum) 0;
272 /* after parsing, the item member has the composed jsonb structure */
273 PG_RETURN_POINTER(JsonbValueToJsonb(state.res));
276 static bool
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)));
286 return true;
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;
297 return JSON_SUCCESS;
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);
307 return JSON_SUCCESS;
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);
317 return JSON_SUCCESS;
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);
327 return JSON_SUCCESS;
330 static JsonParseErrorType
331 jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
333 JsonbInState *_state = (JsonbInState *) pstate;
334 JsonbValue v;
336 Assert(fname != NULL);
337 v.type = jbvString;
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);
345 return JSON_SUCCESS;
348 static void
349 jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal)
351 switch (scalarVal->type)
353 case jbvNull:
354 appendBinaryStringInfo(out, "null", 4);
355 break;
356 case jbvString:
357 escape_json_with_len(out, scalarVal->val.string.val, scalarVal->val.string.len);
358 break;
359 case jbvNumeric:
360 appendStringInfoString(out,
361 DatumGetCString(DirectFunctionCall1(numeric_out,
362 PointerGetDatum(scalarVal->val.numeric))));
363 break;
364 case jbvBool:
365 if (scalarVal->val.boolean)
366 appendBinaryStringInfo(out, "true", 4);
367 else
368 appendBinaryStringInfo(out, "false", 5);
369 break;
370 default:
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;
382 JsonbValue v;
383 Datum numd;
385 switch (tokentype)
388 case JSON_TOKEN_STRING:
389 Assert(token != NULL);
390 v.type = jbvString;
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;
395 break;
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);
403 v.type = jbvNumeric;
404 if (!DirectInputFunctionCallSafe(numeric_in, token,
405 InvalidOid, -1,
406 _state->escontext,
407 &numd))
408 return JSON_SEM_ACTION_FAILED;
409 v.val.numeric = DatumGetNumeric(numd);
410 break;
411 case JSON_TOKEN_TRUE:
412 v.type = jbvBool;
413 v.val.boolean = true;
414 break;
415 case JSON_TOKEN_FALSE:
416 v.type = jbvBool;
417 v.val.boolean = false;
418 break;
419 case JSON_TOKEN_NULL:
420 v.type = jbvNull;
421 break;
422 default:
423 /* should not be possible */
424 elog(ERROR, "invalid json token type");
425 break;
428 if (_state->parseState == NULL)
430 /* single scalar */
431 JsonbValue va;
433 va.type = jbvArray;
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);
441 else
443 JsonbValue *o = &_state->parseState->contVal;
445 switch (o->type)
447 case jbvArray:
448 _state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
449 break;
450 case jbvObject:
451 _state->res = pushJsonbValue(&_state->parseState, WJB_VALUE, &v);
452 break;
453 default:
454 elog(ERROR, "unexpected parent of nested structure");
458 return JSON_SUCCESS;
462 * JsonbToCString
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.
472 char *
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
481 char *
482 JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
484 return JsonbToCStringWorker(out, in, estimated_len, true);
488 * common worker for above two functions
490 static char *
491 JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent)
493 bool first = true;
494 JsonbIterator *it;
495 JsonbValue v;
496 JsonbIteratorToken type = WJB_DONE;
497 int level = 0;
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;
511 if (out == NULL)
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))
521 redo_switch = false;
522 switch (type)
524 case WJB_BEGIN_ARRAY:
525 if (!first)
526 appendBinaryStringInfo(out, ", ", ispaces);
528 if (!v.val.array.rawScalar)
530 add_indent(out, use_indent && !last_was_key, level);
531 appendStringInfoCharMacro(out, '[');
533 else
534 raw_scalar = true;
536 first = true;
537 level++;
538 break;
539 case WJB_BEGIN_OBJECT:
540 if (!first)
541 appendBinaryStringInfo(out, ", ", ispaces);
543 add_indent(out, use_indent && !last_was_key, level);
544 appendStringInfoCharMacro(out, '{');
546 first = true;
547 level++;
548 break;
549 case WJB_KEY:
550 if (!first)
551 appendBinaryStringInfo(out, ", ", ispaces);
552 first = true;
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)
563 first = false;
564 jsonb_put_escaped_value(out, &v);
566 else
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.
575 redo_switch = true;
577 break;
578 case WJB_ELEM:
579 if (!first)
580 appendBinaryStringInfo(out, ", ", ispaces);
581 first = false;
583 if (!raw_scalar)
584 add_indent(out, use_indent, level);
585 jsonb_put_escaped_value(out, &v);
586 break;
587 case WJB_END_ARRAY:
588 level--;
589 if (!raw_scalar)
591 add_indent(out, use_indent, level);
592 appendStringInfoCharMacro(out, ']');
594 first = false;
595 break;
596 case WJB_END_OBJECT:
597 level--;
598 add_indent(out, use_indent, level);
599 appendStringInfoCharMacro(out, '}');
600 first = false;
601 break;
602 default:
603 elog(ERROR, "unknown jsonb iterator token type");
605 use_indent = indent;
606 last_was_key = redo_switch;
609 Assert(level == 0);
611 return out->data;
614 static void
615 add_indent(StringInfo out, bool indent, int level)
617 if (indent)
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
635 * will be thrown.
637 static void
638 datum_to_jsonb_internal(Datum val, bool is_null, JsonbInState *result,
639 JsonTypeCategory tcategory, Oid outfuncoid,
640 bool key_scalar)
642 char *outputstr;
643 bool numeric_error;
644 JsonbValue jb;
645 bool scalar_jsonb = false;
647 check_stack_depth();
649 /* Convert val to a JsonbValue in jb (in most cases) */
650 if (is_null)
652 Assert(!key_scalar);
653 jb.type = jbvNull;
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))
662 ereport(ERROR,
663 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
664 errmsg("key value must be scalar, not array, composite, or json")));
666 else
668 if (tcategory == JSONTYPE_CAST)
669 val = OidFunctionCall1(outfuncoid, val);
671 switch (tcategory)
673 case JSONTYPE_ARRAY:
674 array_to_jsonb_internal(val, result);
675 break;
676 case JSONTYPE_COMPOSITE:
677 composite_to_jsonb(val, result);
678 break;
679 case JSONTYPE_BOOL:
680 if (key_scalar)
682 outputstr = DatumGetBool(val) ? "true" : "false";
683 jb.type = jbvString;
684 jb.val.string.len = strlen(outputstr);
685 jb.val.string.val = outputstr;
687 else
689 jb.type = jbvBool;
690 jb.val.boolean = DatumGetBool(val);
692 break;
693 case JSONTYPE_NUMERIC:
694 outputstr = OidOutputFunctionCall(outfuncoid, val);
695 if (key_scalar)
697 /* always quote keys */
698 jb.type = jbvString;
699 jb.val.string.len = strlen(outputstr);
700 jb.val.string.val = outputstr;
702 else
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);
711 if (!numeric_error)
713 Datum numd;
715 jb.type = jbvNumeric;
716 numd = DirectFunctionCall3(numeric_in,
717 CStringGetDatum(outputstr),
718 ObjectIdGetDatum(InvalidOid),
719 Int32GetDatum(-1));
720 jb.val.numeric = DatumGetNumeric(numd);
721 pfree(outputstr);
723 else
725 jb.type = jbvString;
726 jb.val.string.len = strlen(outputstr);
727 jb.val.string.val = outputstr;
730 break;
731 case JSONTYPE_DATE:
732 jb.type = jbvString;
733 jb.val.string.val = JsonEncodeDateTime(NULL, val,
734 DATEOID, NULL);
735 jb.val.string.len = strlen(jb.val.string.val);
736 break;
737 case JSONTYPE_TIMESTAMP:
738 jb.type = jbvString;
739 jb.val.string.val = JsonEncodeDateTime(NULL, val,
740 TIMESTAMPOID, NULL);
741 jb.val.string.len = strlen(jb.val.string.val);
742 break;
743 case JSONTYPE_TIMESTAMPTZ:
744 jb.type = jbvString;
745 jb.val.string.val = JsonEncodeDateTime(NULL, val,
746 TIMESTAMPTZOID, NULL);
747 jb.val.string.len = strlen(jb.val.string.val);
748 break;
749 case JSONTYPE_CAST:
750 case JSONTYPE_JSON:
752 /* parse the json right into the existing result object */
753 JsonLexContext lex;
754 JsonSemAction sem;
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);
773 break;
774 case JSONTYPE_JSONB:
776 Jsonb *jsonb = DatumGetJsonbP(val);
777 JsonbIterator *it;
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);
786 scalar_jsonb = true;
788 else
790 JsonbIteratorToken type;
792 while ((type = JsonbIteratorNext(&it, &jb, false))
793 != WJB_DONE)
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,
798 type, NULL);
799 else
800 result->res = pushJsonbValue(&result->parseState,
801 type, &jb);
805 break;
806 default:
807 outputstr = OidOutputFunctionCall(outfuncoid, val);
808 jb.type = jbvString;
809 jb.val.string.len = strlen(outputstr);
810 (void) checkStringLen(jb.val.string.len, NULL);
811 jb.val.string.val = outputstr;
812 break;
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 */
821 return;
823 else if (result->parseState == NULL)
825 /* single root scalar */
826 JsonbValue va;
828 va.type = jbvArray;
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);
836 else
838 JsonbValue *o = &result->parseState->contVal;
840 switch (o->type)
842 case jbvArray:
843 result->res = pushJsonbValue(&result->parseState, WJB_ELEM, &jb);
844 break;
845 case jbvObject:
846 result->res = pushJsonbValue(&result->parseState,
847 key_scalar ? WJB_KEY : WJB_VALUE,
848 &jb);
849 break;
850 default:
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.
861 static void
862 array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, const Datum *vals,
863 const bool *nulls, int *valcount, JsonTypeCategory tcategory,
864 Oid outfuncoid)
866 int i;
868 Assert(dim < ndims);
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,
877 outfuncoid, false);
878 (*valcount)++;
880 else
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.
893 static void
894 array_to_jsonb_internal(Datum array, JsonbInState *result)
896 ArrayType *v = DatumGetArrayTypeP(array);
897 Oid element_type = ARR_ELEMTYPE(v);
898 int *dim;
899 int ndim;
900 int nitems;
901 int count = 0;
902 Datum *elements;
903 bool *nulls;
904 int16 typlen;
905 bool typbyval;
906 char typalign;
907 JsonTypeCategory tcategory;
908 Oid outfuncoid;
910 ndim = ARR_NDIM(v);
911 dim = ARR_DIMS(v);
912 nitems = ArrayGetNItems(ndim, dim);
914 if (nitems <= 0)
916 result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL);
917 result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
918 return;
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,
929 &nitems);
931 array_dim_to_jsonb(result, 0, ndim, dim, elements, nulls, &count, tcategory,
932 outfuncoid);
934 pfree(elements);
935 pfree(nulls);
939 * Turn a composite / record into JSON.
941 static void
942 composite_to_jsonb(Datum composite, JsonbInState *result)
944 HeapTupleHeader td;
945 Oid tupType;
946 int32 tupTypmod;
947 TupleDesc tupdesc;
948 HeapTupleData tmptup,
949 *tuple;
950 int i;
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);
961 tmptup.t_data = td;
962 tuple = &tmptup;
964 result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_OBJECT, NULL);
966 for (i = 0; i < tupdesc->natts; i++)
968 Datum val;
969 bool isnull;
970 char *attname;
971 JsonTypeCategory tcategory;
972 Oid outfuncoid;
973 JsonbValue v;
974 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
976 if (att->attisdropped)
977 continue;
979 attname = NameStr(att->attname);
981 v.type = jbvString;
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);
990 if (isnull)
992 tcategory = JSONTYPE_NULL;
993 outfuncoid = InvalidOid;
995 else
996 json_categorize_type(att->atttypid, true, &tcategory,
997 &outfuncoid);
999 datum_to_jsonb_internal(val, isnull, result, tcategory, outfuncoid,
1000 false);
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.
1015 static void
1016 add_jsonb(Datum val, bool is_null, JsonbInState *result,
1017 Oid val_type, bool key_scalar)
1019 JsonTypeCategory tcategory;
1020 Oid outfuncoid;
1022 if (val_type == InvalidOid)
1023 ereport(ERROR,
1024 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1025 errmsg("could not determine input data type")));
1027 if (is_null)
1029 tcategory = JSONTYPE_NULL;
1030 outfuncoid = InvalidOid;
1032 else
1033 json_categorize_type(val_type, true,
1034 &tcategory, &outfuncoid);
1036 datum_to_jsonb_internal(val, is_null, result, tcategory, outfuncoid,
1037 key_scalar);
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.
1048 bool
1049 to_jsonb_is_immutable(Oid typoid)
1051 JsonTypeCategory tcategory;
1052 Oid outfuncoid;
1054 json_categorize_type(typoid, true, &tcategory, &outfuncoid);
1056 switch (tcategory)
1058 case JSONTYPE_NULL:
1059 case JSONTYPE_BOOL:
1060 case JSONTYPE_JSON:
1061 case JSONTYPE_JSONB:
1062 return true;
1064 case JSONTYPE_DATE:
1065 case JSONTYPE_TIMESTAMP:
1066 case JSONTYPE_TIMESTAMPTZ:
1067 return false;
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:
1076 case JSONTYPE_CAST:
1077 case JSONTYPE_OTHER:
1078 return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
1081 return false; /* not reached */
1085 * SQL function to_jsonb(anyvalue)
1087 Datum
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;
1093 Oid outfuncoid;
1095 if (val_type == InvalidOid)
1096 ereport(ERROR,
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.
1111 Datum
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,
1119 false);
1121 return JsonbPGetDatum(JsonbValueToJsonb(result.res));
1124 Datum
1125 jsonb_build_object_worker(int nargs, const Datum *args, const bool *nulls, const Oid *types,
1126 bool absent_on_null, bool unique_keys)
1128 int i;
1129 JsonbInState result;
1131 if (nargs % 2 != 0)
1132 ereport(ERROR,
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)
1147 /* process key */
1148 bool skip;
1150 if (nulls[i])
1151 ereport(ERROR,
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)
1160 continue;
1162 add_jsonb(args[i], false, &result, types[i], true);
1164 /* process value */
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")
1176 Datum
1177 jsonb_build_object(PG_FUNCTION_ARGS)
1179 Datum *args;
1180 bool *nulls;
1181 Oid *types;
1183 /* build argument values to build the object */
1184 int nargs = extract_variadic_args(fcinfo, 0, true,
1185 &args, &types, &nulls);
1187 if (nargs < 0)
1188 PG_RETURN_NULL();
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.
1196 Datum
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));
1209 Datum
1210 jsonb_build_array_worker(int nargs, const Datum *args, const bool *nulls, const Oid *types,
1211 bool absent_on_null)
1213 int i;
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])
1223 continue;
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")
1236 Datum
1237 jsonb_build_array(PG_FUNCTION_ARGS)
1239 Datum *args;
1240 bool *nulls;
1241 Oid *types;
1243 /* build argument values to build the object */
1244 int nargs = extract_variadic_args(fcinfo, 0, true,
1245 &args, &types, &nulls);
1247 if (nargs < 0)
1248 PG_RETURN_NULL();
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.
1257 Datum
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.
1278 Datum
1279 jsonb_object(PG_FUNCTION_ARGS)
1281 ArrayType *in_array = PG_GETARG_ARRAYTYPE_P(0);
1282 int ndims = ARR_NDIM(in_array);
1283 Datum *in_datums;
1284 bool *in_nulls;
1285 int in_count,
1286 count,
1288 JsonbInState result;
1290 memset(&result, 0, sizeof(JsonbInState));
1292 (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1294 switch (ndims)
1296 case 0:
1297 goto close_object;
1298 break;
1300 case 1:
1301 if ((ARR_DIMS(in_array)[0]) % 2)
1302 ereport(ERROR,
1303 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1304 errmsg("array must have even number of elements")));
1305 break;
1307 case 2:
1308 if ((ARR_DIMS(in_array)[1]) != 2)
1309 ereport(ERROR,
1310 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1311 errmsg("array must have two columns")));
1312 break;
1314 default:
1315 ereport(ERROR,
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)
1326 JsonbValue v;
1327 char *str;
1328 int len;
1330 if (in_nulls[i * 2])
1331 ereport(ERROR,
1332 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1333 errmsg("null value not allowed for object key")));
1335 str = TextDatumGetCString(in_datums[i * 2]);
1336 len = strlen(str);
1338 v.type = jbvString;
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])
1347 v.type = jbvNull;
1349 else
1351 str = TextDatumGetCString(in_datums[i * 2 + 1]);
1352 len = strlen(str);
1354 v.type = jbvString;
1356 v.val.string.len = len;
1357 v.val.string.val = str;
1360 (void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
1363 pfree(in_datums);
1364 pfree(in_nulls);
1366 close_object:
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
1376 * pairwise.
1378 Datum
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);
1385 Datum *key_datums,
1386 *val_datums;
1387 bool *key_nulls,
1388 *val_nulls;
1389 int key_count,
1390 val_count,
1392 JsonbInState result;
1394 memset(&result, 0, sizeof(JsonbInState));
1396 (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1398 if (nkdims > 1 || nkdims != nvdims)
1399 ereport(ERROR,
1400 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1401 errmsg("wrong number of array subscripts")));
1403 if (nkdims == 0)
1404 goto close_object;
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)
1410 ereport(ERROR,
1411 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1412 errmsg("mismatched array dimensions")));
1414 for (i = 0; i < key_count; ++i)
1416 JsonbValue v;
1417 char *str;
1418 int len;
1420 if (key_nulls[i])
1421 ereport(ERROR,
1422 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1423 errmsg("null value not allowed for object key")));
1425 str = TextDatumGetCString(key_datums[i]);
1426 len = strlen(str);
1428 v.type = jbvString;
1430 v.val.string.len = len;
1431 v.val.string.val = str;
1433 (void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
1435 if (val_nulls[i])
1437 v.type = jbvNull;
1439 else
1441 str = TextDatumGetCString(val_datums[i]);
1442 len = strlen(str);
1444 v.type = jbvString;
1446 v.val.string.len = len;
1447 v.val.string.val = str;
1450 (void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
1453 pfree(key_datums);
1454 pfree(key_nulls);
1455 pfree(val_datums);
1456 pfree(val_nulls);
1458 close_object:
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
1468 * change them.
1470 static JsonbParseState *
1471 clone_parse_state(JsonbParseState *state)
1473 JsonbParseState *result,
1474 *icursor,
1475 *ocursor;
1477 if (state == NULL)
1478 return NULL;
1480 result = palloc(sizeof(JsonbParseState));
1481 icursor = state;
1482 ocursor = result;
1483 for (;;)
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)
1491 break;
1492 ocursor->next = palloc(sizeof(JsonbParseState));
1493 ocursor = ocursor->next;
1495 ocursor->next = NULL;
1497 return result;
1500 static Datum
1501 jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
1503 MemoryContext oldcontext,
1504 aggcontext;
1505 JsonbAggState *state;
1506 JsonbInState elem;
1507 Datum val;
1508 JsonbInState *result;
1509 bool single_scalar = false;
1510 JsonbIterator *it;
1511 Jsonb *jbelem;
1512 JsonbValue v;
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)
1528 ereport(ERROR,
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);
1543 else
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)
1571 switch (type)
1573 case WJB_BEGIN_ARRAY:
1574 if (v.val.array.rawScalar)
1575 single_scalar = true;
1576 else
1577 result->res = pushJsonbValue(&result->parseState,
1578 type, NULL);
1579 break;
1580 case WJB_END_ARRAY:
1581 if (!single_scalar)
1582 result->res = pushJsonbValue(&result->parseState,
1583 type, NULL);
1584 break;
1585 case WJB_BEGIN_OBJECT:
1586 case WJB_END_OBJECT:
1587 result->res = pushJsonbValue(&result->parseState,
1588 type, NULL);
1589 break;
1590 case WJB_ELEM:
1591 case WJB_KEY:
1592 case WJB_VALUE:
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 */
1604 v.val.numeric =
1605 DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
1606 NumericGetDatum(v.val.numeric)));
1608 result->res = pushJsonbValue(&result->parseState,
1609 type, &v);
1610 break;
1611 default:
1612 elog(ERROR, "unknown jsonb iterator token type");
1616 MemoryContextSwitchTo(oldcontext);
1618 PG_RETURN_POINTER(state);
1622 * jsonb_agg aggregate function
1624 Datum
1625 jsonb_agg_transfn(PG_FUNCTION_ARGS)
1627 return jsonb_agg_transfn_worker(fcinfo, false);
1631 * jsonb_agg_strict aggregate function
1633 Datum
1634 jsonb_agg_strict_transfn(PG_FUNCTION_ARGS)
1636 return jsonb_agg_transfn_worker(fcinfo, true);
1639 Datum
1640 jsonb_agg_finalfn(PG_FUNCTION_ARGS)
1642 JsonbAggState *arg;
1643 JsonbInState result;
1644 Jsonb *out;
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);
1672 static Datum
1673 jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
1674 bool absent_on_null, bool unique_keys)
1676 MemoryContext oldcontext,
1677 aggcontext;
1678 JsonbInState elem;
1679 JsonbAggState *state;
1680 Datum val;
1681 JsonbInState *result;
1682 bool single_scalar;
1683 JsonbIterator *it;
1684 Jsonb *jbkey,
1685 *jbval;
1686 JsonbValue v;
1687 JsonbIteratorToken type;
1688 bool skip;
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))
1700 Oid arg_type;
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)
1716 ereport(ERROR,
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)
1726 ereport(ERROR,
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);
1733 else
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))
1742 ereport(ERROR,
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
1782 * things.
1785 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1787 switch (type)
1789 case WJB_BEGIN_ARRAY:
1790 if (!v.val.array.rawScalar)
1791 elog(ERROR, "unexpected structure for key");
1792 break;
1793 case WJB_ELEM:
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;
1802 else
1804 ereport(ERROR,
1805 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1806 errmsg("object keys must be strings")));
1808 result->res = pushJsonbValue(&result->parseState,
1809 WJB_KEY, &v);
1811 if (skip)
1813 v.type = jbvNull;
1814 result->res = pushJsonbValue(&result->parseState,
1815 WJB_VALUE, &v);
1816 MemoryContextSwitchTo(oldcontext);
1817 PG_RETURN_POINTER(state);
1820 break;
1821 case WJB_END_ARRAY:
1822 break;
1823 default:
1824 elog(ERROR, "unexpected structure for key");
1825 break;
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
1836 * WJB_VALUE items.
1839 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1841 switch (type)
1843 case WJB_BEGIN_ARRAY:
1844 if (v.val.array.rawScalar)
1845 single_scalar = true;
1846 else
1847 result->res = pushJsonbValue(&result->parseState,
1848 type, NULL);
1849 break;
1850 case WJB_END_ARRAY:
1851 if (!single_scalar)
1852 result->res = pushJsonbValue(&result->parseState,
1853 type, NULL);
1854 break;
1855 case WJB_BEGIN_OBJECT:
1856 case WJB_END_OBJECT:
1857 result->res = pushJsonbValue(&result->parseState,
1858 type, NULL);
1859 break;
1860 case WJB_ELEM:
1861 case WJB_KEY:
1862 case WJB_VALUE:
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 */
1874 v.val.numeric =
1875 DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
1876 NumericGetDatum(v.val.numeric)));
1878 result->res = pushJsonbValue(&result->parseState,
1879 single_scalar ? WJB_VALUE : type,
1880 &v);
1881 break;
1882 default:
1883 elog(ERROR, "unknown jsonb iterator token type");
1887 MemoryContextSwitchTo(oldcontext);
1889 PG_RETURN_POINTER(state);
1893 * jsonb_object_agg aggregate function
1895 Datum
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
1905 Datum
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
1914 Datum
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
1923 Datum
1924 jsonb_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS)
1926 return jsonb_object_agg_transfn_worker(fcinfo, true, true);
1929 Datum
1930 jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
1932 JsonbAggState *arg;
1933 JsonbInState result;
1934 Jsonb *out;
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
1949 * marker.
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.
1967 bool
1968 JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
1970 JsonbIterator *it;
1971 JsonbIteratorToken tok PG_USED_FOR_ASSERTS_ONLY;
1972 JsonbValue tmp;
1974 if (!JsonContainerIsArray(jbc) || !JsonContainerIsScalar(jbc))
1976 /* inform caller about actual type of container */
1977 res->type = (JsonContainerIsArray(jbc)) ? jbvArray : jbvObject;
1978 return false;
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);
2001 return true;
2005 * Emit correct, translatable cast error message
2007 static void
2008 cannotCastJsonbValue(enum jbvType type, const char *sqltype)
2010 static const struct
2012 enum jbvType type;
2013 const char *msg;
2015 messages[] =
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")}
2025 int i;
2027 for (i = 0; i < lengthof(messages); i++)
2028 if (messages[i].type == type)
2029 ereport(ERROR,
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);
2037 Datum
2038 jsonb_bool(PG_FUNCTION_ARGS)
2040 Jsonb *in = PG_GETARG_JSONB_P(0);
2041 JsonbValue v;
2043 if (!JsonbExtractScalar(&in->root, &v))
2044 cannotCastJsonbValue(v.type, "boolean");
2046 if (v.type == jbvNull)
2048 PG_FREE_IF_COPY(in, 0);
2049 PG_RETURN_NULL();
2052 if (v.type != jbvBool)
2053 cannotCastJsonbValue(v.type, "boolean");
2055 PG_FREE_IF_COPY(in, 0);
2057 PG_RETURN_BOOL(v.val.boolean);
2060 Datum
2061 jsonb_numeric(PG_FUNCTION_ARGS)
2063 Jsonb *in = PG_GETARG_JSONB_P(0);
2064 JsonbValue v;
2065 Numeric retValue;
2067 if (!JsonbExtractScalar(&in->root, &v))
2068 cannotCastJsonbValue(v.type, "numeric");
2070 if (v.type == jbvNull)
2072 PG_FREE_IF_COPY(in, 0);
2073 PG_RETURN_NULL();
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
2081 * return
2083 retValue = DatumGetNumericCopy(NumericGetDatum(v.val.numeric));
2085 PG_FREE_IF_COPY(in, 0);
2087 PG_RETURN_NUMERIC(retValue);
2090 Datum
2091 jsonb_int2(PG_FUNCTION_ARGS)
2093 Jsonb *in = PG_GETARG_JSONB_P(0);
2094 JsonbValue v;
2095 Datum retValue;
2097 if (!JsonbExtractScalar(&in->root, &v))
2098 cannotCastJsonbValue(v.type, "smallint");
2100 if (v.type == jbvNull)
2102 PG_FREE_IF_COPY(in, 0);
2103 PG_RETURN_NULL();
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);
2117 Datum
2118 jsonb_int4(PG_FUNCTION_ARGS)
2120 Jsonb *in = PG_GETARG_JSONB_P(0);
2121 JsonbValue v;
2122 Datum retValue;
2124 if (!JsonbExtractScalar(&in->root, &v))
2125 cannotCastJsonbValue(v.type, "integer");
2127 if (v.type == jbvNull)
2129 PG_FREE_IF_COPY(in, 0);
2130 PG_RETURN_NULL();
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);
2144 Datum
2145 jsonb_int8(PG_FUNCTION_ARGS)
2147 Jsonb *in = PG_GETARG_JSONB_P(0);
2148 JsonbValue v;
2149 Datum retValue;
2151 if (!JsonbExtractScalar(&in->root, &v))
2152 cannotCastJsonbValue(v.type, "bigint");
2154 if (v.type == jbvNull)
2156 PG_FREE_IF_COPY(in, 0);
2157 PG_RETURN_NULL();
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);
2171 Datum
2172 jsonb_float4(PG_FUNCTION_ARGS)
2174 Jsonb *in = PG_GETARG_JSONB_P(0);
2175 JsonbValue v;
2176 Datum retValue;
2178 if (!JsonbExtractScalar(&in->root, &v))
2179 cannotCastJsonbValue(v.type, "real");
2181 if (v.type == jbvNull)
2183 PG_FREE_IF_COPY(in, 0);
2184 PG_RETURN_NULL();
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);
2198 Datum
2199 jsonb_float8(PG_FUNCTION_ARGS)
2201 Jsonb *in = PG_GETARG_JSONB_P(0);
2202 JsonbValue v;
2203 Datum retValue;
2205 if (!JsonbExtractScalar(&in->root, &v))
2206 cannotCastJsonbValue(v.type, "double precision");
2208 if (v.type == jbvNull)
2210 PG_FREE_IF_COPY(in, 0);
2211 PG_RETURN_NULL();
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.
2228 char *
2229 JsonbUnquote(Jsonb *jb)
2231 if (JB_ROOT_IS_SCALAR(jb))
2233 JsonbValue v;
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");
2246 else
2248 elog(ERROR, "unrecognized jsonb value type %d", v.type);
2249 return NULL;
2252 else
2253 return JsonbToCString(NULL, &jb->root, VARSIZE(jb));