1/*-------------------------------------------------------------------------
2 *
3 * jsonb.c
4 * I/O routines for jsonb type
5 *
6 * Copyright (c) 2014-2019, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * src/backend/utils/adt/jsonb.c
10 *
11 *-------------------------------------------------------------------------
12 */
13#include "postgres.h"
14
15#include "miscadmin.h"
16#include "access/htup_details.h"
17#include "access/transam.h"
18#include "catalog/pg_type.h"
19#include "funcapi.h"
20#include "libpq/pqformat.h"
21#include "parser/parse_coerce.h"
22#include "utils/builtins.h"
23#include "utils/date.h"
24#include "utils/datetime.h"
25#include "utils/lsyscache.h"
26#include "utils/json.h"
27#include "utils/jsonapi.h"
28#include "utils/jsonb.h"
29#include "utils/syscache.h"
30#include "utils/typcache.h"
31
32typedef struct JsonbInState
33{
34 JsonbParseState *parseState;
35 JsonbValue *res;
36} JsonbInState;
37
38/* unlike with json categories, we need to treat json and jsonb differently */
39typedef enum /* type categories for datum_to_jsonb */
40{
41 JSONBTYPE_NULL, /* null, so we didn't bother to identify */
42 JSONBTYPE_BOOL, /* boolean (built-in types only) */
43 JSONBTYPE_NUMERIC, /* numeric (ditto) */
44 JSONBTYPE_DATE, /* we use special formatting for datetimes */
45 JSONBTYPE_TIMESTAMP, /* we use special formatting for timestamp */
46 JSONBTYPE_TIMESTAMPTZ, /* ... and timestamptz */
47 JSONBTYPE_JSON, /* JSON */
48 JSONBTYPE_JSONB, /* JSONB */
49 JSONBTYPE_ARRAY, /* array */
50 JSONBTYPE_COMPOSITE, /* composite */
51 JSONBTYPE_JSONCAST, /* something with an explicit cast to JSON */
52 JSONBTYPE_OTHER /* all else */
53} JsonbTypeCategory;
54
55typedef struct JsonbAggState
56{
57 JsonbInState *res;
58 JsonbTypeCategory key_category;
59 Oid key_output_func;
60 JsonbTypeCategory val_category;
61 Oid val_output_func;
62} JsonbAggState;
63
64static inline Datum jsonb_from_cstring(char *json, int len);
65static size_t checkStringLen(size_t len);
66static void jsonb_in_object_start(void *pstate);
67static void jsonb_in_object_end(void *pstate);
68static void jsonb_in_array_start(void *pstate);
69static void jsonb_in_array_end(void *pstate);
70static void jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
71static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal);
72static void jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
73static void jsonb_categorize_type(Oid typoid,
74 JsonbTypeCategory *tcategory,
75 Oid *outfuncoid);
76static void composite_to_jsonb(Datum composite, JsonbInState *result);
77static void array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims,
78 Datum *vals, bool *nulls, int *valcount,
79 JsonbTypeCategory tcategory, Oid outfuncoid);
80static void array_to_jsonb_internal(Datum array, JsonbInState *result);
81static void jsonb_categorize_type(Oid typoid,
82 JsonbTypeCategory *tcategory,
83 Oid *outfuncoid);
84static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
85 JsonbTypeCategory tcategory, Oid outfuncoid,
86 bool key_scalar);
87static void add_jsonb(Datum val, bool is_null, JsonbInState *result,
88 Oid val_type, bool key_scalar);
89static JsonbParseState *clone_parse_state(JsonbParseState *state);
90static char *JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent);
91static void add_indent(StringInfo out, bool indent, int level);
92
93/*
94 * jsonb type input function
95 */
96Datum
97jsonb_in(PG_FUNCTION_ARGS)
98{
99 char *json = PG_GETARG_CSTRING(0);
100
101 return jsonb_from_cstring(json, strlen(json));
102}
103
104/*
105 * jsonb type recv function
106 *
107 * The type is sent as text in binary mode, so this is almost the same
108 * as the input function, but it's prefixed with a version number so we
109 * can change the binary format sent in future if necessary. For now,
110 * only version 1 is supported.
111 */
112Datum
113jsonb_recv(PG_FUNCTION_ARGS)
114{
115 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
116 int version = pq_getmsgint(buf, 1);
117 char *str;
118 int nbytes;
119
120 if (version == 1)
121 str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
122 else
123 elog(ERROR, "unsupported jsonb version number %d", version);
124
125 return jsonb_from_cstring(str, nbytes);
126}
127
128/*
129 * jsonb type output function
130 */
131Datum
132jsonb_out(PG_FUNCTION_ARGS)
133{
134 Jsonb *jb = PG_GETARG_JSONB_P(0);
135 char *out;
136
137 out = JsonbToCString(NULL, &jb->root, VARSIZE(jb));
138
139 PG_RETURN_CSTRING(out);
140}
141
142/*
143 * jsonb type send function
144 *
145 * Just send jsonb as a version number, then a string of text
146 */
147Datum
148jsonb_send(PG_FUNCTION_ARGS)
149{
150 Jsonb *jb = PG_GETARG_JSONB_P(0);
151 StringInfoData buf;
152 StringInfo jtext = makeStringInfo();
153 int version = 1;
154
155 (void) JsonbToCString(jtext, &jb->root, VARSIZE(jb));
156
157 pq_begintypsend(&buf);
158 pq_sendint8(&buf, version);
159 pq_sendtext(&buf, jtext->data, jtext->len);
160 pfree(jtext->data);
161 pfree(jtext);
162
163 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
164}
165
166/*
167 * Get the type name of a jsonb container.
168 */
169static const char *
170JsonbContainerTypeName(JsonbContainer *jbc)
171{
172 JsonbValue scalar;
173
174 if (JsonbExtractScalar(jbc, &scalar))
175 return JsonbTypeName(&scalar);
176 else if (JsonContainerIsArray(jbc))
177 return "array";
178 else if (JsonContainerIsObject(jbc))
179 return "object";
180 else
181 {
182 elog(ERROR, "invalid jsonb container type: 0x%08x", jbc->header);
183 return "unknown";
184 }
185}
186
187/*
188 * Get the type name of a jsonb value.
189 */
190const char *
191JsonbTypeName(JsonbValue *jbv)
192{
193 switch (jbv->type)
194 {
195 case jbvBinary:
196 return JsonbContainerTypeName(jbv->val.binary.data);
197 case jbvObject:
198 return "object";
199 case jbvArray:
200 return "array";
201 case jbvNumeric:
202 return "number";
203 case jbvString:
204 return "string";
205 case jbvBool:
206 return "boolean";
207 case jbvNull:
208 return "null";
209 default:
210 elog(ERROR, "unrecognized jsonb value type: %d", jbv->type);
211 return "unknown";
212 }
213}
214
215/*
216 * SQL function jsonb_typeof(jsonb) -> text
217 *
218 * This function is here because the analog json function is in json.c, since
219 * it uses the json parser internals not exposed elsewhere.
220 */
221Datum
222jsonb_typeof(PG_FUNCTION_ARGS)
223{
224 Jsonb *in = PG_GETARG_JSONB_P(0);
225 const char *result = JsonbContainerTypeName(&in->root);
226
227 PG_RETURN_TEXT_P(cstring_to_text(result));
228}
229
230/*
231 * jsonb_from_cstring
232 *
233 * Turns json string into a jsonb Datum.
234 *
235 * Uses the json parser (with hooks) to construct a jsonb.
236 */
237static inline Datum
238jsonb_from_cstring(char *json, int len)
239{
240 JsonLexContext *lex;
241 JsonbInState state;
242 JsonSemAction sem;
243
244 memset(&state, 0, sizeof(state));
245 memset(&sem, 0, sizeof(sem));
246 lex = makeJsonLexContextCstringLen(json, len, true);
247
248 sem.semstate = (void *) &state;
249
250 sem.object_start = jsonb_in_object_start;
251 sem.array_start = jsonb_in_array_start;
252 sem.object_end = jsonb_in_object_end;
253 sem.array_end = jsonb_in_array_end;
254 sem.scalar = jsonb_in_scalar;
255 sem.object_field_start = jsonb_in_object_field_start;
256
257 pg_parse_json(lex, &sem);
258
259 /* after parsing, the item member has the composed jsonb structure */
260 PG_RETURN_POINTER(JsonbValueToJsonb(state.res));
261}
262
263static size_t
264checkStringLen(size_t len)
265{
266 if (len > JENTRY_OFFLENMASK)
267 ereport(ERROR,
268 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
269 errmsg("string too long to represent as jsonb string"),
270 errdetail("Due to an implementation restriction, jsonb strings cannot exceed %d bytes.",
271 JENTRY_OFFLENMASK)));
272
273 return len;
274}
275
276static void
277jsonb_in_object_start(void *pstate)
278{
279 JsonbInState *_state = (JsonbInState *) pstate;
280
281 _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_OBJECT, NULL);
282}
283
284static void
285jsonb_in_object_end(void *pstate)
286{
287 JsonbInState *_state = (JsonbInState *) pstate;
288
289 _state->res = pushJsonbValue(&_state->parseState, WJB_END_OBJECT, NULL);
290}
291
292static void
293jsonb_in_array_start(void *pstate)
294{
295 JsonbInState *_state = (JsonbInState *) pstate;
296
297 _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, NULL);
298}
299
300static void
301jsonb_in_array_end(void *pstate)
302{
303 JsonbInState *_state = (JsonbInState *) pstate;
304
305 _state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
306}
307
308static void
309jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
310{
311 JsonbInState *_state = (JsonbInState *) pstate;
312 JsonbValue v;
313
314 Assert(fname != NULL);
315 v.type = jbvString;
316 v.val.string.len = checkStringLen(strlen(fname));
317 v.val.string.val = fname;
318
319 _state->res = pushJsonbValue(&_state->parseState, WJB_KEY, &v);
320}
321
322static void
323jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal)
324{
325 switch (scalarVal->type)
326 {
327 case jbvNull:
328 appendBinaryStringInfo(out, "null", 4);
329 break;
330 case jbvString:
331 escape_json(out, pnstrdup(scalarVal->val.string.val, scalarVal->val.string.len));
332 break;
333 case jbvNumeric:
334 appendStringInfoString(out,
335 DatumGetCString(DirectFunctionCall1(numeric_out,
336 PointerGetDatum(scalarVal->val.numeric))));
337 break;
338 case jbvBool:
339 if (scalarVal->val.boolean)
340 appendBinaryStringInfo(out, "true", 4);
341 else
342 appendBinaryStringInfo(out, "false", 5);
343 break;
344 default:
345 elog(ERROR, "unknown jsonb scalar type");
346 }
347}
348
349/*
350 * For jsonb we always want the de-escaped value - that's what's in token
351 */
352static void
353jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
354{
355 JsonbInState *_state = (JsonbInState *) pstate;
356 JsonbValue v;
357 Datum numd;
358
359 switch (tokentype)
360 {
361
362 case JSON_TOKEN_STRING:
363 Assert(token != NULL);
364 v.type = jbvString;
365 v.val.string.len = checkStringLen(strlen(token));
366 v.val.string.val = token;
367 break;
368 case JSON_TOKEN_NUMBER:
369
370 /*
371 * No need to check size of numeric values, because maximum
372 * numeric size is well below the JsonbValue restriction
373 */
374 Assert(token != NULL);
375 v.type = jbvNumeric;
376 numd = DirectFunctionCall3(numeric_in,
377 CStringGetDatum(token),
378 ObjectIdGetDatum(InvalidOid),
379 Int32GetDatum(-1));
380 v.val.numeric = DatumGetNumeric(numd);
381 break;
382 case JSON_TOKEN_TRUE:
383 v.type = jbvBool;
384 v.val.boolean = true;
385 break;
386 case JSON_TOKEN_FALSE:
387 v.type = jbvBool;
388 v.val.boolean = false;
389 break;
390 case JSON_TOKEN_NULL:
391 v.type = jbvNull;
392 break;
393 default:
394 /* should not be possible */
395 elog(ERROR, "invalid json token type");
396 break;
397 }
398
399 if (_state->parseState == NULL)
400 {
401 /* single scalar */
402 JsonbValue va;
403
404 va.type = jbvArray;
405 va.val.array.rawScalar = true;
406 va.val.array.nElems = 1;
407
408 _state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, &va);
409 _state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
410 _state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
411 }
412 else
413 {
414 JsonbValue *o = &_state->parseState->contVal;
415
416 switch (o->type)
417 {
418 case jbvArray:
419 _state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
420 break;
421 case jbvObject:
422 _state->res = pushJsonbValue(&_state->parseState, WJB_VALUE, &v);
423 break;
424 default:
425 elog(ERROR, "unexpected parent of nested structure");
426 }
427 }
428}
429
430/*
431 * JsonbToCString
432 * Converts jsonb value to a C-string.
433 *
434 * If 'out' argument is non-null, the resulting C-string is stored inside the
435 * StringBuffer. The resulting string is always returned.
436 *
437 * A typical case for passing the StringInfo in rather than NULL is where the
438 * caller wants access to the len attribute without having to call strlen, e.g.
439 * if they are converting it to a text* object.
440 */
441char *
442JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len)
443{
444 return JsonbToCStringWorker(out, in, estimated_len, false);
445}
446
447/*
448 * same thing but with indentation turned on
449 */
450char *
451JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
452{
453 return JsonbToCStringWorker(out, in, estimated_len, true);
454}
455
456/*
457 * common worker for above two functions
458 */
459static char *
460JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent)
461{
462 bool first = true;
463 JsonbIterator *it;
464 JsonbValue v;
465 JsonbIteratorToken type = WJB_DONE;
466 int level = 0;
467 bool redo_switch = false;
468
469 /* If we are indenting, don't add a space after a comma */
470 int ispaces = indent ? 1 : 2;
471
472 /*
473 * Don't indent the very first item. This gets set to the indent flag at
474 * the bottom of the loop.
475 */
476 bool use_indent = false;
477 bool raw_scalar = false;
478 bool last_was_key = false;
479
480 if (out == NULL)
481 out = makeStringInfo();
482
483 enlargeStringInfo(out, (estimated_len >= 0) ? estimated_len : 64);
484
485 it = JsonbIteratorInit(in);
486
487 while (redo_switch ||
488 ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE))
489 {
490 redo_switch = false;
491 switch (type)
492 {
493 case WJB_BEGIN_ARRAY:
494 if (!first)
495 appendBinaryStringInfo(out, ", ", ispaces);
496
497 if (!v.val.array.rawScalar)
498 {
499 add_indent(out, use_indent && !last_was_key, level);
500 appendStringInfoCharMacro(out, '[');
501 }
502 else
503 raw_scalar = true;
504
505 first = true;
506 level++;
507 break;
508 case WJB_BEGIN_OBJECT:
509 if (!first)
510 appendBinaryStringInfo(out, ", ", ispaces);
511
512 add_indent(out, use_indent && !last_was_key, level);
513 appendStringInfoCharMacro(out, '{');
514
515 first = true;
516 level++;
517 break;
518 case WJB_KEY:
519 if (!first)
520 appendBinaryStringInfo(out, ", ", ispaces);
521 first = true;
522
523 add_indent(out, use_indent, level);
524
525 /* json rules guarantee this is a string */
526 jsonb_put_escaped_value(out, &v);
527 appendBinaryStringInfo(out, ": ", 2);
528
529 type = JsonbIteratorNext(&it, &v, false);
530 if (type == WJB_VALUE)
531 {
532 first = false;
533 jsonb_put_escaped_value(out, &v);
534 }
535 else
536 {
537 Assert(type == WJB_BEGIN_OBJECT || type == WJB_BEGIN_ARRAY);
538
539 /*
540 * We need to rerun the current switch() since we need to
541 * output the object which we just got from the iterator
542 * before calling the iterator again.
543 */
544 redo_switch = true;
545 }
546 break;
547 case WJB_ELEM:
548 if (!first)
549 appendBinaryStringInfo(out, ", ", ispaces);
550 first = false;
551
552 if (!raw_scalar)
553 add_indent(out, use_indent, level);
554 jsonb_put_escaped_value(out, &v);
555 break;
556 case WJB_END_ARRAY:
557 level--;
558 if (!raw_scalar)
559 {
560 add_indent(out, use_indent, level);
561 appendStringInfoCharMacro(out, ']');
562 }
563 first = false;
564 break;
565 case WJB_END_OBJECT:
566 level--;
567 add_indent(out, use_indent, level);
568 appendStringInfoCharMacro(out, '}');
569 first = false;
570 break;
571 default:
572 elog(ERROR, "unknown jsonb iterator token type");
573 }
574 use_indent = indent;
575 last_was_key = redo_switch;
576 }
577
578 Assert(level == 0);
579
580 return out->data;
581}
582
583static void
584add_indent(StringInfo out, bool indent, int level)
585{
586 if (indent)
587 {
588 int i;
589
590 appendStringInfoCharMacro(out, '\n');
591 for (i = 0; i < level; i++)
592 appendBinaryStringInfo(out, " ", 4);
593 }
594}
595
596
597/*
598 * Determine how we want to render values of a given type in datum_to_jsonb.
599 *
600 * Given the datatype OID, return its JsonbTypeCategory, as well as the type's
601 * output function OID. If the returned category is JSONBTYPE_JSONCAST,
602 * we return the OID of the relevant cast function instead.
603 */
604static void
605jsonb_categorize_type(Oid typoid,
606 JsonbTypeCategory *tcategory,
607 Oid *outfuncoid)
608{
609 bool typisvarlena;
610
611 /* Look through any domain */
612 typoid = getBaseType(typoid);
613
614 *outfuncoid = InvalidOid;
615
616 /*
617 * We need to get the output function for everything except date and
618 * timestamp types, booleans, array and composite types, json and jsonb,
619 * and non-builtin types where there's a cast to json. In this last case
620 * we return the oid of the cast function instead.
621 */
622
623 switch (typoid)
624 {
625 case BOOLOID:
626 *tcategory = JSONBTYPE_BOOL;
627 break;
628
629 case INT2OID:
630 case INT4OID:
631 case INT8OID:
632 case FLOAT4OID:
633 case FLOAT8OID:
634 case NUMERICOID:
635 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
636 *tcategory = JSONBTYPE_NUMERIC;
637 break;
638
639 case DATEOID:
640 *tcategory = JSONBTYPE_DATE;
641 break;
642
643 case TIMESTAMPOID:
644 *tcategory = JSONBTYPE_TIMESTAMP;
645 break;
646
647 case TIMESTAMPTZOID:
648 *tcategory = JSONBTYPE_TIMESTAMPTZ;
649 break;
650
651 case JSONBOID:
652 *tcategory = JSONBTYPE_JSONB;
653 break;
654
655 case JSONOID:
656 *tcategory = JSONBTYPE_JSON;
657 break;
658
659 default:
660 /* Check for arrays and composites */
661 if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
662 || typoid == RECORDARRAYOID)
663 *tcategory = JSONBTYPE_ARRAY;
664 else if (type_is_rowtype(typoid)) /* includes RECORDOID */
665 *tcategory = JSONBTYPE_COMPOSITE;
666 else
667 {
668 /* It's probably the general case ... */
669 *tcategory = JSONBTYPE_OTHER;
670
671 /*
672 * but first let's look for a cast to json (note: not to
673 * jsonb) if it's not built-in.
674 */
675 if (typoid >= FirstNormalObjectId)
676 {
677 Oid castfunc;
678 CoercionPathType ctype;
679
680 ctype = find_coercion_pathway(JSONOID, typoid,
681 COERCION_EXPLICIT, &castfunc);
682 if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
683 {
684 *tcategory = JSONBTYPE_JSONCAST;
685 *outfuncoid = castfunc;
686 }
687 else
688 {
689 /* not a cast type, so just get the usual output func */
690 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
691 }
692 }
693 else
694 {
695 /* any other builtin type */
696 getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
697 }
698 break;
699 }
700 }
701}
702
703/*
704 * Turn a Datum into jsonb, adding it to the result JsonbInState.
705 *
706 * tcategory and outfuncoid are from a previous call to json_categorize_type,
707 * except that if is_null is true then they can be invalid.
708 *
709 * If key_scalar is true, the value is stored as a key, so insist
710 * it's of an acceptable type, and force it to be a jbvString.
711 */
712static void
713datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
714 JsonbTypeCategory tcategory, Oid outfuncoid,
715 bool key_scalar)
716{
717 char *outputstr;
718 bool numeric_error;
719 JsonbValue jb;
720 bool scalar_jsonb = false;
721
722 check_stack_depth();
723
724 /* Convert val to a JsonbValue in jb (in most cases) */
725 if (is_null)
726 {
727 Assert(!key_scalar);
728 jb.type = jbvNull;
729 }
730 else if (key_scalar &&
731 (tcategory == JSONBTYPE_ARRAY ||
732 tcategory == JSONBTYPE_COMPOSITE ||
733 tcategory == JSONBTYPE_JSON ||
734 tcategory == JSONBTYPE_JSONB ||
735 tcategory == JSONBTYPE_JSONCAST))
736 {
737 ereport(ERROR,
738 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
739 errmsg("key value must be scalar, not array, composite, or json")));
740 }
741 else
742 {
743 if (tcategory == JSONBTYPE_JSONCAST)
744 val = OidFunctionCall1(outfuncoid, val);
745
746 switch (tcategory)
747 {
748 case JSONBTYPE_ARRAY:
749 array_to_jsonb_internal(val, result);
750 break;
751 case JSONBTYPE_COMPOSITE:
752 composite_to_jsonb(val, result);
753 break;
754 case JSONBTYPE_BOOL:
755 if (key_scalar)
756 {
757 outputstr = DatumGetBool(val) ? "true" : "false";
758 jb.type = jbvString;
759 jb.val.string.len = strlen(outputstr);
760 jb.val.string.val = outputstr;
761 }
762 else
763 {
764 jb.type = jbvBool;
765 jb.val.boolean = DatumGetBool(val);
766 }
767 break;
768 case JSONBTYPE_NUMERIC:
769 outputstr = OidOutputFunctionCall(outfuncoid, val);
770 if (key_scalar)
771 {
772 /* always quote keys */
773 jb.type = jbvString;
774 jb.val.string.len = strlen(outputstr);
775 jb.val.string.val = outputstr;
776 }
777 else
778 {
779 /*
780 * Make it numeric if it's a valid JSON number, otherwise
781 * a string. Invalid numeric output will always have an
782 * 'N' or 'n' in it (I think).
783 */
784 numeric_error = (strchr(outputstr, 'N') != NULL ||
785 strchr(outputstr, 'n') != NULL);
786 if (!numeric_error)
787 {
788 Datum numd;
789
790 jb.type = jbvNumeric;
791 numd = DirectFunctionCall3(numeric_in,
792 CStringGetDatum(outputstr),
793 ObjectIdGetDatum(InvalidOid),
794 Int32GetDatum(-1));
795 jb.val.numeric = DatumGetNumeric(numd);
796 pfree(outputstr);
797 }
798 else
799 {
800 jb.type = jbvString;
801 jb.val.string.len = strlen(outputstr);
802 jb.val.string.val = outputstr;
803 }
804 }
805 break;
806 case JSONBTYPE_DATE:
807 jb.type = jbvString;
808 jb.val.string.val = JsonEncodeDateTime(NULL, val, DATEOID);
809 jb.val.string.len = strlen(jb.val.string.val);
810 break;
811 case JSONBTYPE_TIMESTAMP:
812 jb.type = jbvString;
813 jb.val.string.val = JsonEncodeDateTime(NULL, val, TIMESTAMPOID);
814 jb.val.string.len = strlen(jb.val.string.val);
815 break;
816 case JSONBTYPE_TIMESTAMPTZ:
817 jb.type = jbvString;
818 jb.val.string.val = JsonEncodeDateTime(NULL, val, TIMESTAMPTZOID);
819 jb.val.string.len = strlen(jb.val.string.val);
820 break;
821 case JSONBTYPE_JSONCAST:
822 case JSONBTYPE_JSON:
823 {
824 /* parse the json right into the existing result object */
825 JsonLexContext *lex;
826 JsonSemAction sem;
827 text *json = DatumGetTextPP(val);
828
829 lex = makeJsonLexContext(json, true);
830
831 memset(&sem, 0, sizeof(sem));
832
833 sem.semstate = (void *) result;
834
835 sem.object_start = jsonb_in_object_start;
836 sem.array_start = jsonb_in_array_start;
837 sem.object_end = jsonb_in_object_end;
838 sem.array_end = jsonb_in_array_end;
839 sem.scalar = jsonb_in_scalar;
840 sem.object_field_start = jsonb_in_object_field_start;
841
842 pg_parse_json(lex, &sem);
843
844 }
845 break;
846 case JSONBTYPE_JSONB:
847 {
848 Jsonb *jsonb = DatumGetJsonbP(val);
849 JsonbIterator *it;
850
851 it = JsonbIteratorInit(&jsonb->root);
852
853 if (JB_ROOT_IS_SCALAR(jsonb))
854 {
855 (void) JsonbIteratorNext(&it, &jb, true);
856 Assert(jb.type == jbvArray);
857 (void) JsonbIteratorNext(&it, &jb, true);
858 scalar_jsonb = true;
859 }
860 else
861 {
862 JsonbIteratorToken type;
863
864 while ((type = JsonbIteratorNext(&it, &jb, false))
865 != WJB_DONE)
866 {
867 if (type == WJB_END_ARRAY || type == WJB_END_OBJECT ||
868 type == WJB_BEGIN_ARRAY || type == WJB_BEGIN_OBJECT)
869 result->res = pushJsonbValue(&result->parseState,
870 type, NULL);
871 else
872 result->res = pushJsonbValue(&result->parseState,
873 type, &jb);
874 }
875 }
876 }
877 break;
878 default:
879 outputstr = OidOutputFunctionCall(outfuncoid, val);
880 jb.type = jbvString;
881 jb.val.string.len = checkStringLen(strlen(outputstr));
882 jb.val.string.val = outputstr;
883 break;
884 }
885 }
886
887 /* Now insert jb into result, unless we did it recursively */
888 if (!is_null && !scalar_jsonb &&
889 tcategory >= JSONBTYPE_JSON && tcategory <= JSONBTYPE_JSONCAST)
890 {
891 /* work has been done recursively */
892 return;
893 }
894 else if (result->parseState == NULL)
895 {
896 /* single root scalar */
897 JsonbValue va;
898
899 va.type = jbvArray;
900 va.val.array.rawScalar = true;
901 va.val.array.nElems = 1;
902
903 result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, &va);
904 result->res = pushJsonbValue(&result->parseState, WJB_ELEM, &jb);
905 result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
906 }
907 else
908 {
909 JsonbValue *o = &result->parseState->contVal;
910
911 switch (o->type)
912 {
913 case jbvArray:
914 result->res = pushJsonbValue(&result->parseState, WJB_ELEM, &jb);
915 break;
916 case jbvObject:
917 result->res = pushJsonbValue(&result->parseState,
918 key_scalar ? WJB_KEY : WJB_VALUE,
919 &jb);
920 break;
921 default:
922 elog(ERROR, "unexpected parent of nested structure");
923 }
924 }
925}
926
927/*
928 * Process a single dimension of an array.
929 * If it's the innermost dimension, output the values, otherwise call
930 * ourselves recursively to process the next dimension.
931 */
932static void
933array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *vals,
934 bool *nulls, int *valcount, JsonbTypeCategory tcategory,
935 Oid outfuncoid)
936{
937 int i;
938
939 Assert(dim < ndims);
940
941 result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL);
942
943 for (i = 1; i <= dims[dim]; i++)
944 {
945 if (dim + 1 == ndims)
946 {
947 datum_to_jsonb(vals[*valcount], nulls[*valcount], result, tcategory,
948 outfuncoid, false);
949 (*valcount)++;
950 }
951 else
952 {
953 array_dim_to_jsonb(result, dim + 1, ndims, dims, vals, nulls,
954 valcount, tcategory, outfuncoid);
955 }
956 }
957
958 result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
959}
960
961/*
962 * Turn an array into JSON.
963 */
964static void
965array_to_jsonb_internal(Datum array, JsonbInState *result)
966{
967 ArrayType *v = DatumGetArrayTypeP(array);
968 Oid element_type = ARR_ELEMTYPE(v);
969 int *dim;
970 int ndim;
971 int nitems;
972 int count = 0;
973 Datum *elements;
974 bool *nulls;
975 int16 typlen;
976 bool typbyval;
977 char typalign;
978 JsonbTypeCategory tcategory;
979 Oid outfuncoid;
980
981 ndim = ARR_NDIM(v);
982 dim = ARR_DIMS(v);
983 nitems = ArrayGetNItems(ndim, dim);
984
985 if (nitems <= 0)
986 {
987 result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL);
988 result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
989 return;
990 }
991
992 get_typlenbyvalalign(element_type,
993 &typlen, &typbyval, &typalign);
994
995 jsonb_categorize_type(element_type,
996 &tcategory, &outfuncoid);
997
998 deconstruct_array(v, element_type, typlen, typbyval,
999 typalign, &elements, &nulls,
1000 &nitems);
1001
1002 array_dim_to_jsonb(result, 0, ndim, dim, elements, nulls, &count, tcategory,
1003 outfuncoid);
1004
1005 pfree(elements);
1006 pfree(nulls);
1007}
1008
1009/*
1010 * Turn a composite / record into JSON.
1011 */
1012static void
1013composite_to_jsonb(Datum composite, JsonbInState *result)
1014{
1015 HeapTupleHeader td;
1016 Oid tupType;
1017 int32 tupTypmod;
1018 TupleDesc tupdesc;
1019 HeapTupleData tmptup,
1020 *tuple;
1021 int i;
1022
1023 td = DatumGetHeapTupleHeader(composite);
1024
1025 /* Extract rowtype info and find a tupdesc */
1026 tupType = HeapTupleHeaderGetTypeId(td);
1027 tupTypmod = HeapTupleHeaderGetTypMod(td);
1028 tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1029
1030 /* Build a temporary HeapTuple control structure */
1031 tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
1032 tmptup.t_data = td;
1033 tuple = &tmptup;
1034
1035 result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_OBJECT, NULL);
1036
1037 for (i = 0; i < tupdesc->natts; i++)
1038 {
1039 Datum val;
1040 bool isnull;
1041 char *attname;
1042 JsonbTypeCategory tcategory;
1043 Oid outfuncoid;
1044 JsonbValue v;
1045 Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1046
1047 if (att->attisdropped)
1048 continue;
1049
1050 attname = NameStr(att->attname);
1051
1052 v.type = jbvString;
1053 /* don't need checkStringLen here - can't exceed maximum name length */
1054 v.val.string.len = strlen(attname);
1055 v.val.string.val = attname;
1056
1057 result->res = pushJsonbValue(&result->parseState, WJB_KEY, &v);
1058
1059 val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
1060
1061 if (isnull)
1062 {
1063 tcategory = JSONBTYPE_NULL;
1064 outfuncoid = InvalidOid;
1065 }
1066 else
1067 jsonb_categorize_type(att->atttypid, &tcategory, &outfuncoid);
1068
1069 datum_to_jsonb(val, isnull, result, tcategory, outfuncoid, false);
1070 }
1071
1072 result->res = pushJsonbValue(&result->parseState, WJB_END_OBJECT, NULL);
1073 ReleaseTupleDesc(tupdesc);
1074}
1075
1076/*
1077 * Append JSON text for "val" to "result".
1078 *
1079 * This is just a thin wrapper around datum_to_jsonb. If the same type will be
1080 * printed many times, avoid using this; better to do the jsonb_categorize_type
1081 * lookups only once.
1082 */
1083
1084static void
1085add_jsonb(Datum val, bool is_null, JsonbInState *result,
1086 Oid val_type, bool key_scalar)
1087{
1088 JsonbTypeCategory tcategory;
1089 Oid outfuncoid;
1090
1091 if (val_type == InvalidOid)
1092 ereport(ERROR,
1093 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1094 errmsg("could not determine input data type")));
1095
1096 if (is_null)
1097 {
1098 tcategory = JSONBTYPE_NULL;
1099 outfuncoid = InvalidOid;
1100 }
1101 else
1102 jsonb_categorize_type(val_type,
1103 &tcategory, &outfuncoid);
1104
1105 datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar);
1106}
1107
1108/*
1109 * SQL function to_jsonb(anyvalue)
1110 */
1111Datum
1112to_jsonb(PG_FUNCTION_ARGS)
1113{
1114 Datum val = PG_GETARG_DATUM(0);
1115 Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
1116 JsonbInState result;
1117 JsonbTypeCategory tcategory;
1118 Oid outfuncoid;
1119
1120 if (val_type == InvalidOid)
1121 ereport(ERROR,
1122 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1123 errmsg("could not determine input data type")));
1124
1125 jsonb_categorize_type(val_type,
1126 &tcategory, &outfuncoid);
1127
1128 memset(&result, 0, sizeof(JsonbInState));
1129
1130 datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
1131
1132 PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1133}
1134
1135/*
1136 * SQL function jsonb_build_object(variadic "any")
1137 */
1138Datum
1139jsonb_build_object(PG_FUNCTION_ARGS)
1140{
1141 int nargs;
1142 int i;
1143 JsonbInState result;
1144 Datum *args;
1145 bool *nulls;
1146 Oid *types;
1147
1148 /* build argument values to build the object */
1149 nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
1150
1151 if (nargs < 0)
1152 PG_RETURN_NULL();
1153
1154 if (nargs % 2 != 0)
1155 ereport(ERROR,
1156 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1157 errmsg("argument list must have even number of elements"),
1158 /* translator: %s is a SQL function name */
1159 errhint("The arguments of %s must consist of alternating keys and values.",
1160 "jsonb_build_object()")));
1161
1162 memset(&result, 0, sizeof(JsonbInState));
1163
1164 result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1165
1166 for (i = 0; i < nargs; i += 2)
1167 {
1168 /* process key */
1169 if (nulls[i])
1170 ereport(ERROR,
1171 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1172 errmsg("argument %d: key must not be null", i + 1)));
1173
1174 add_jsonb(args[i], false, &result, types[i], true);
1175
1176 /* process value */
1177 add_jsonb(args[i + 1], nulls[i + 1], &result, types[i + 1], false);
1178 }
1179
1180 result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1181
1182 PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1183}
1184
1185/*
1186 * degenerate case of jsonb_build_object where it gets 0 arguments.
1187 */
1188Datum
1189jsonb_build_object_noargs(PG_FUNCTION_ARGS)
1190{
1191 JsonbInState result;
1192
1193 memset(&result, 0, sizeof(JsonbInState));
1194
1195 (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1196 result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1197
1198 PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1199}
1200
1201/*
1202 * SQL function jsonb_build_array(variadic "any")
1203 */
1204Datum
1205jsonb_build_array(PG_FUNCTION_ARGS)
1206{
1207 int nargs;
1208 int i;
1209 JsonbInState result;
1210 Datum *args;
1211 bool *nulls;
1212 Oid *types;
1213
1214 /* build argument values to build the array */
1215 nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
1216
1217 if (nargs < 0)
1218 PG_RETURN_NULL();
1219
1220 memset(&result, 0, sizeof(JsonbInState));
1221
1222 result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
1223
1224 for (i = 0; i < nargs; i++)
1225 add_jsonb(args[i], nulls[i], &result, types[i], false);
1226
1227 result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
1228
1229 PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1230}
1231
1232/*
1233 * degenerate case of jsonb_build_array where it gets 0 arguments.
1234 */
1235Datum
1236jsonb_build_array_noargs(PG_FUNCTION_ARGS)
1237{
1238 JsonbInState result;
1239
1240 memset(&result, 0, sizeof(JsonbInState));
1241
1242 (void) pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
1243 result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
1244
1245 PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1246}
1247
1248
1249/*
1250 * SQL function jsonb_object(text[])
1251 *
1252 * take a one or two dimensional array of text as name value pairs
1253 * for a jsonb object.
1254 *
1255 */
1256Datum
1257jsonb_object(PG_FUNCTION_ARGS)
1258{
1259 ArrayType *in_array = PG_GETARG_ARRAYTYPE_P(0);
1260 int ndims = ARR_NDIM(in_array);
1261 Datum *in_datums;
1262 bool *in_nulls;
1263 int in_count,
1264 count,
1265 i;
1266 JsonbInState result;
1267
1268 memset(&result, 0, sizeof(JsonbInState));
1269
1270 (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1271
1272 switch (ndims)
1273 {
1274 case 0:
1275 goto close_object;
1276 break;
1277
1278 case 1:
1279 if ((ARR_DIMS(in_array)[0]) % 2)
1280 ereport(ERROR,
1281 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1282 errmsg("array must have even number of elements")));
1283 break;
1284
1285 case 2:
1286 if ((ARR_DIMS(in_array)[1]) != 2)
1287 ereport(ERROR,
1288 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1289 errmsg("array must have two columns")));
1290 break;
1291
1292 default:
1293 ereport(ERROR,
1294 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1295 errmsg("wrong number of array subscripts")));
1296 }
1297
1298 deconstruct_array(in_array,
1299 TEXTOID, -1, false, 'i',
1300 &in_datums, &in_nulls, &in_count);
1301
1302 count = in_count / 2;
1303
1304 for (i = 0; i < count; ++i)
1305 {
1306 JsonbValue v;
1307 char *str;
1308 int len;
1309
1310 if (in_nulls[i * 2])
1311 ereport(ERROR,
1312 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1313 errmsg("null value not allowed for object key")));
1314
1315 str = TextDatumGetCString(in_datums[i * 2]);
1316 len = strlen(str);
1317
1318 v.type = jbvString;
1319
1320 v.val.string.len = len;
1321 v.val.string.val = str;
1322
1323 (void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
1324
1325 if (in_nulls[i * 2 + 1])
1326 {
1327 v.type = jbvNull;
1328 }
1329 else
1330 {
1331 str = TextDatumGetCString(in_datums[i * 2 + 1]);
1332 len = strlen(str);
1333
1334 v.type = jbvString;
1335
1336 v.val.string.len = len;
1337 v.val.string.val = str;
1338 }
1339
1340 (void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
1341 }
1342
1343 pfree(in_datums);
1344 pfree(in_nulls);
1345
1346close_object:
1347 result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1348
1349 PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1350}
1351
1352/*
1353 * SQL function jsonb_object(text[], text[])
1354 *
1355 * take separate name and value arrays of text to construct a jsonb object
1356 * pairwise.
1357 */
1358Datum
1359jsonb_object_two_arg(PG_FUNCTION_ARGS)
1360{
1361 ArrayType *key_array = PG_GETARG_ARRAYTYPE_P(0);
1362 ArrayType *val_array = PG_GETARG_ARRAYTYPE_P(1);
1363 int nkdims = ARR_NDIM(key_array);
1364 int nvdims = ARR_NDIM(val_array);
1365 Datum *key_datums,
1366 *val_datums;
1367 bool *key_nulls,
1368 *val_nulls;
1369 int key_count,
1370 val_count,
1371 i;
1372 JsonbInState result;
1373
1374 memset(&result, 0, sizeof(JsonbInState));
1375
1376 (void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1377
1378 if (nkdims > 1 || nkdims != nvdims)
1379 ereport(ERROR,
1380 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1381 errmsg("wrong number of array subscripts")));
1382
1383 if (nkdims == 0)
1384 goto close_object;
1385
1386 deconstruct_array(key_array,
1387 TEXTOID, -1, false, 'i',
1388 &key_datums, &key_nulls, &key_count);
1389
1390 deconstruct_array(val_array,
1391 TEXTOID, -1, false, 'i',
1392 &val_datums, &val_nulls, &val_count);
1393
1394 if (key_count != val_count)
1395 ereport(ERROR,
1396 (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1397 errmsg("mismatched array dimensions")));
1398
1399 for (i = 0; i < key_count; ++i)
1400 {
1401 JsonbValue v;
1402 char *str;
1403 int len;
1404
1405 if (key_nulls[i])
1406 ereport(ERROR,
1407 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1408 errmsg("null value not allowed for object key")));
1409
1410 str = TextDatumGetCString(key_datums[i]);
1411 len = strlen(str);
1412
1413 v.type = jbvString;
1414
1415 v.val.string.len = len;
1416 v.val.string.val = str;
1417
1418 (void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
1419
1420 if (val_nulls[i])
1421 {
1422 v.type = jbvNull;
1423 }
1424 else
1425 {
1426 str = TextDatumGetCString(val_datums[i]);
1427 len = strlen(str);
1428
1429 v.type = jbvString;
1430
1431 v.val.string.len = len;
1432 v.val.string.val = str;
1433 }
1434
1435 (void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
1436 }
1437
1438 pfree(key_datums);
1439 pfree(key_nulls);
1440 pfree(val_datums);
1441 pfree(val_nulls);
1442
1443close_object:
1444 result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1445
1446 PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1447}
1448
1449
1450/*
1451 * shallow clone of a parse state, suitable for use in aggregate
1452 * final functions that will only append to the values rather than
1453 * change them.
1454 */
1455static JsonbParseState *
1456clone_parse_state(JsonbParseState *state)
1457{
1458 JsonbParseState *result,
1459 *icursor,
1460 *ocursor;
1461
1462 if (state == NULL)
1463 return NULL;
1464
1465 result = palloc(sizeof(JsonbParseState));
1466 icursor = state;
1467 ocursor = result;
1468 for (;;)
1469 {
1470 ocursor->contVal = icursor->contVal;
1471 ocursor->size = icursor->size;
1472 icursor = icursor->next;
1473 if (icursor == NULL)
1474 break;
1475 ocursor->next = palloc(sizeof(JsonbParseState));
1476 ocursor = ocursor->next;
1477 }
1478 ocursor->next = NULL;
1479
1480 return result;
1481}
1482
1483
1484/*
1485 * jsonb_agg aggregate function
1486 */
1487Datum
1488jsonb_agg_transfn(PG_FUNCTION_ARGS)
1489{
1490 MemoryContext oldcontext,
1491 aggcontext;
1492 JsonbAggState *state;
1493 JsonbInState elem;
1494 Datum val;
1495 JsonbInState *result;
1496 bool single_scalar = false;
1497 JsonbIterator *it;
1498 Jsonb *jbelem;
1499 JsonbValue v;
1500 JsonbIteratorToken type;
1501
1502 if (!AggCheckCallContext(fcinfo, &aggcontext))
1503 {
1504 /* cannot be called directly because of internal-type argument */
1505 elog(ERROR, "jsonb_agg_transfn called in non-aggregate context");
1506 }
1507
1508 /* set up the accumulator on the first go round */
1509
1510 if (PG_ARGISNULL(0))
1511 {
1512 Oid arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
1513
1514 if (arg_type == InvalidOid)
1515 ereport(ERROR,
1516 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1517 errmsg("could not determine input data type")));
1518
1519 oldcontext = MemoryContextSwitchTo(aggcontext);
1520 state = palloc(sizeof(JsonbAggState));
1521 result = palloc0(sizeof(JsonbInState));
1522 state->res = result;
1523 result->res = pushJsonbValue(&result->parseState,
1524 WJB_BEGIN_ARRAY, NULL);
1525 MemoryContextSwitchTo(oldcontext);
1526
1527 jsonb_categorize_type(arg_type, &state->val_category,
1528 &state->val_output_func);
1529 }
1530 else
1531 {
1532 state = (JsonbAggState *) PG_GETARG_POINTER(0);
1533 result = state->res;
1534 }
1535
1536 /* turn the argument into jsonb in the normal function context */
1537
1538 val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
1539
1540 memset(&elem, 0, sizeof(JsonbInState));
1541
1542 datum_to_jsonb(val, PG_ARGISNULL(1), &elem, state->val_category,
1543 state->val_output_func, false);
1544
1545 jbelem = JsonbValueToJsonb(elem.res);
1546
1547 /* switch to the aggregate context for accumulation operations */
1548
1549 oldcontext = MemoryContextSwitchTo(aggcontext);
1550
1551 it = JsonbIteratorInit(&jbelem->root);
1552
1553 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1554 {
1555 switch (type)
1556 {
1557 case WJB_BEGIN_ARRAY:
1558 if (v.val.array.rawScalar)
1559 single_scalar = true;
1560 else
1561 result->res = pushJsonbValue(&result->parseState,
1562 type, NULL);
1563 break;
1564 case WJB_END_ARRAY:
1565 if (!single_scalar)
1566 result->res = pushJsonbValue(&result->parseState,
1567 type, NULL);
1568 break;
1569 case WJB_BEGIN_OBJECT:
1570 case WJB_END_OBJECT:
1571 result->res = pushJsonbValue(&result->parseState,
1572 type, NULL);
1573 break;
1574 case WJB_ELEM:
1575 case WJB_KEY:
1576 case WJB_VALUE:
1577 if (v.type == jbvString)
1578 {
1579 /* copy string values in the aggregate context */
1580 char *buf = palloc(v.val.string.len + 1);
1581
1582 snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
1583 v.val.string.val = buf;
1584 }
1585 else if (v.type == jbvNumeric)
1586 {
1587 /* same for numeric */
1588 v.val.numeric =
1589 DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
1590 NumericGetDatum(v.val.numeric)));
1591 }
1592 result->res = pushJsonbValue(&result->parseState,
1593 type, &v);
1594 break;
1595 default:
1596 elog(ERROR, "unknown jsonb iterator token type");
1597 }
1598 }
1599
1600 MemoryContextSwitchTo(oldcontext);
1601
1602 PG_RETURN_POINTER(state);
1603}
1604
1605Datum
1606jsonb_agg_finalfn(PG_FUNCTION_ARGS)
1607{
1608 JsonbAggState *arg;
1609 JsonbInState result;
1610 Jsonb *out;
1611
1612 /* cannot be called directly because of internal-type argument */
1613 Assert(AggCheckCallContext(fcinfo, NULL));
1614
1615 if (PG_ARGISNULL(0))
1616 PG_RETURN_NULL(); /* returns null iff no input values */
1617
1618 arg = (JsonbAggState *) PG_GETARG_POINTER(0);
1619
1620 /*
1621 * We need to do a shallow clone of the argument in case the final
1622 * function is called more than once, so we avoid changing the argument. A
1623 * shallow clone is sufficient as we aren't going to change any of the
1624 * values, just add the final array end marker.
1625 */
1626
1627 result.parseState = clone_parse_state(arg->res->parseState);
1628
1629 result.res = pushJsonbValue(&result.parseState,
1630 WJB_END_ARRAY, NULL);
1631
1632 out = JsonbValueToJsonb(result.res);
1633
1634 PG_RETURN_POINTER(out);
1635}
1636
1637/*
1638 * jsonb_object_agg aggregate function
1639 */
1640Datum
1641jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
1642{
1643 MemoryContext oldcontext,
1644 aggcontext;
1645 JsonbInState elem;
1646 JsonbAggState *state;
1647 Datum val;
1648 JsonbInState *result;
1649 bool single_scalar;
1650 JsonbIterator *it;
1651 Jsonb *jbkey,
1652 *jbval;
1653 JsonbValue v;
1654 JsonbIteratorToken type;
1655
1656 if (!AggCheckCallContext(fcinfo, &aggcontext))
1657 {
1658 /* cannot be called directly because of internal-type argument */
1659 elog(ERROR, "jsonb_object_agg_transfn called in non-aggregate context");
1660 }
1661
1662 /* set up the accumulator on the first go round */
1663
1664 if (PG_ARGISNULL(0))
1665 {
1666 Oid arg_type;
1667
1668 oldcontext = MemoryContextSwitchTo(aggcontext);
1669 state = palloc(sizeof(JsonbAggState));
1670 result = palloc0(sizeof(JsonbInState));
1671 state->res = result;
1672 result->res = pushJsonbValue(&result->parseState,
1673 WJB_BEGIN_OBJECT, NULL);
1674 MemoryContextSwitchTo(oldcontext);
1675
1676 arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
1677
1678 if (arg_type == InvalidOid)
1679 ereport(ERROR,
1680 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1681 errmsg("could not determine input data type")));
1682
1683 jsonb_categorize_type(arg_type, &state->key_category,
1684 &state->key_output_func);
1685
1686 arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
1687
1688 if (arg_type == InvalidOid)
1689 ereport(ERROR,
1690 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1691 errmsg("could not determine input data type")));
1692
1693 jsonb_categorize_type(arg_type, &state->val_category,
1694 &state->val_output_func);
1695 }
1696 else
1697 {
1698 state = (JsonbAggState *) PG_GETARG_POINTER(0);
1699 result = state->res;
1700 }
1701
1702 /* turn the argument into jsonb in the normal function context */
1703
1704 if (PG_ARGISNULL(1))
1705 ereport(ERROR,
1706 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1707 errmsg("field name must not be null")));
1708
1709 val = PG_GETARG_DATUM(1);
1710
1711 memset(&elem, 0, sizeof(JsonbInState));
1712
1713 datum_to_jsonb(val, false, &elem, state->key_category,
1714 state->key_output_func, true);
1715
1716 jbkey = JsonbValueToJsonb(elem.res);
1717
1718 val = PG_ARGISNULL(2) ? (Datum) 0 : PG_GETARG_DATUM(2);
1719
1720 memset(&elem, 0, sizeof(JsonbInState));
1721
1722 datum_to_jsonb(val, PG_ARGISNULL(2), &elem, state->val_category,
1723 state->val_output_func, false);
1724
1725 jbval = JsonbValueToJsonb(elem.res);
1726
1727 it = JsonbIteratorInit(&jbkey->root);
1728
1729 /* switch to the aggregate context for accumulation operations */
1730
1731 oldcontext = MemoryContextSwitchTo(aggcontext);
1732
1733 /*
1734 * keys should be scalar, and we should have already checked for that
1735 * above when calling datum_to_jsonb, so we only need to look for these
1736 * things.
1737 */
1738
1739 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1740 {
1741 switch (type)
1742 {
1743 case WJB_BEGIN_ARRAY:
1744 if (!v.val.array.rawScalar)
1745 elog(ERROR, "unexpected structure for key");
1746 break;
1747 case WJB_ELEM:
1748 if (v.type == jbvString)
1749 {
1750 /* copy string values in the aggregate context */
1751 char *buf = palloc(v.val.string.len + 1);
1752
1753 snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
1754 v.val.string.val = buf;
1755 }
1756 else
1757 {
1758 ereport(ERROR,
1759 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1760 errmsg("object keys must be strings")));
1761 }
1762 result->res = pushJsonbValue(&result->parseState,
1763 WJB_KEY, &v);
1764 break;
1765 case WJB_END_ARRAY:
1766 break;
1767 default:
1768 elog(ERROR, "unexpected structure for key");
1769 break;
1770 }
1771 }
1772
1773 it = JsonbIteratorInit(&jbval->root);
1774
1775 single_scalar = false;
1776
1777 /*
1778 * values can be anything, including structured and null, so we treat them
1779 * as in json_agg_transfn, except that single scalars are always pushed as
1780 * WJB_VALUE items.
1781 */
1782
1783 while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1784 {
1785 switch (type)
1786 {
1787 case WJB_BEGIN_ARRAY:
1788 if (v.val.array.rawScalar)
1789 single_scalar = true;
1790 else
1791 result->res = pushJsonbValue(&result->parseState,
1792 type, NULL);
1793 break;
1794 case WJB_END_ARRAY:
1795 if (!single_scalar)
1796 result->res = pushJsonbValue(&result->parseState,
1797 type, NULL);
1798 break;
1799 case WJB_BEGIN_OBJECT:
1800 case WJB_END_OBJECT:
1801 result->res = pushJsonbValue(&result->parseState,
1802 type, NULL);
1803 break;
1804 case WJB_ELEM:
1805 case WJB_KEY:
1806 case WJB_VALUE:
1807 if (v.type == jbvString)
1808 {
1809 /* copy string values in the aggregate context */
1810 char *buf = palloc(v.val.string.len + 1);
1811
1812 snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
1813 v.val.string.val = buf;
1814 }
1815 else if (v.type == jbvNumeric)
1816 {
1817 /* same for numeric */
1818 v.val.numeric =
1819 DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
1820 NumericGetDatum(v.val.numeric)));
1821 }
1822 result->res = pushJsonbValue(&result->parseState,
1823 single_scalar ? WJB_VALUE : type,
1824 &v);
1825 break;
1826 default:
1827 elog(ERROR, "unknown jsonb iterator token type");
1828 }
1829 }
1830
1831 MemoryContextSwitchTo(oldcontext);
1832
1833 PG_RETURN_POINTER(state);
1834}
1835
1836Datum
1837jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
1838{
1839 JsonbAggState *arg;
1840 JsonbInState result;
1841 Jsonb *out;
1842
1843 /* cannot be called directly because of internal-type argument */
1844 Assert(AggCheckCallContext(fcinfo, NULL));
1845
1846 if (PG_ARGISNULL(0))
1847 PG_RETURN_NULL(); /* returns null iff no input values */
1848
1849 arg = (JsonbAggState *) PG_GETARG_POINTER(0);
1850
1851 /*
1852 * We need to do a shallow clone of the argument's res field in case the
1853 * final function is called more than once, so we avoid changing the
1854 * aggregate state value. A shallow clone is sufficient as we aren't
1855 * going to change any of the values, just add the final object end
1856 * marker.
1857 */
1858
1859 result.parseState = clone_parse_state(arg->res->parseState);
1860
1861 result.res = pushJsonbValue(&result.parseState,
1862 WJB_END_OBJECT, NULL);
1863
1864 out = JsonbValueToJsonb(result.res);
1865
1866 PG_RETURN_POINTER(out);
1867}
1868
1869
1870/*
1871 * Extract scalar value from raw-scalar pseudo-array jsonb.
1872 */
1873bool
1874JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
1875{
1876 JsonbIterator *it;
1877 JsonbIteratorToken tok PG_USED_FOR_ASSERTS_ONLY;
1878 JsonbValue tmp;
1879
1880 if (!JsonContainerIsArray(jbc) || !JsonContainerIsScalar(jbc))
1881 {
1882 /* inform caller about actual type of container */
1883 res->type = (JsonContainerIsArray(jbc)) ? jbvArray : jbvObject;
1884 return false;
1885 }
1886
1887 /*
1888 * A root scalar is stored as an array of one element, so we get the array
1889 * and then its first (and only) member.
1890 */
1891 it = JsonbIteratorInit(jbc);
1892
1893 tok = JsonbIteratorNext(&it, &tmp, true);
1894 Assert(tok == WJB_BEGIN_ARRAY);
1895 Assert(tmp.val.array.nElems == 1 && tmp.val.array.rawScalar);
1896
1897 tok = JsonbIteratorNext(&it, res, true);
1898 Assert(tok == WJB_ELEM);
1899 Assert(IsAJsonbScalar(res));
1900
1901 tok = JsonbIteratorNext(&it, &tmp, true);
1902 Assert(tok == WJB_END_ARRAY);
1903
1904 tok = JsonbIteratorNext(&it, &tmp, true);
1905 Assert(tok == WJB_DONE);
1906
1907 return true;
1908}
1909
1910/*
1911 * Emit correct, translatable cast error message
1912 */
1913static void
1914cannotCastJsonbValue(enum jbvType type, const char *sqltype)
1915{
1916 static const struct
1917 {
1918 enum jbvType type;
1919 const char *msg;
1920 }
1921 messages[] =
1922 {
1923 {jbvNull, gettext_noop("cannot cast jsonb null to type %s")},
1924 {jbvString, gettext_noop("cannot cast jsonb string to type %s")},
1925 {jbvNumeric, gettext_noop("cannot cast jsonb numeric to type %s")},
1926 {jbvBool, gettext_noop("cannot cast jsonb boolean to type %s")},
1927 {jbvArray, gettext_noop("cannot cast jsonb array to type %s")},
1928 {jbvObject, gettext_noop("cannot cast jsonb object to type %s")},
1929 {jbvBinary, gettext_noop("cannot cast jsonb array or object to type %s")}
1930 };
1931 int i;
1932
1933 for (i = 0; i < lengthof(messages); i++)
1934 if (messages[i].type == type)
1935 ereport(ERROR,
1936 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1937 errmsg(messages[i].msg, sqltype)));
1938
1939 /* should be unreachable */
1940 elog(ERROR, "unknown jsonb type: %d", (int) type);
1941}
1942
1943Datum
1944jsonb_bool(PG_FUNCTION_ARGS)
1945{
1946 Jsonb *in = PG_GETARG_JSONB_P(0);
1947 JsonbValue v;
1948
1949 if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvBool)
1950 cannotCastJsonbValue(v.type, "boolean");
1951
1952 PG_FREE_IF_COPY(in, 0);
1953
1954 PG_RETURN_BOOL(v.val.boolean);
1955}
1956
1957Datum
1958jsonb_numeric(PG_FUNCTION_ARGS)
1959{
1960 Jsonb *in = PG_GETARG_JSONB_P(0);
1961 JsonbValue v;
1962 Numeric retValue;
1963
1964 if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1965 cannotCastJsonbValue(v.type, "numeric");
1966
1967 /*
1968 * v.val.numeric points into jsonb body, so we need to make a copy to
1969 * return
1970 */
1971 retValue = DatumGetNumericCopy(NumericGetDatum(v.val.numeric));
1972
1973 PG_FREE_IF_COPY(in, 0);
1974
1975 PG_RETURN_NUMERIC(retValue);
1976}
1977
1978Datum
1979jsonb_int2(PG_FUNCTION_ARGS)
1980{
1981 Jsonb *in = PG_GETARG_JSONB_P(0);
1982 JsonbValue v;
1983 Datum retValue;
1984
1985 if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1986 cannotCastJsonbValue(v.type, "smallint");
1987
1988 retValue = DirectFunctionCall1(numeric_int2,
1989 NumericGetDatum(v.val.numeric));
1990
1991 PG_FREE_IF_COPY(in, 0);
1992
1993 PG_RETURN_DATUM(retValue);
1994}
1995
1996Datum
1997jsonb_int4(PG_FUNCTION_ARGS)
1998{
1999 Jsonb *in = PG_GETARG_JSONB_P(0);
2000 JsonbValue v;
2001 Datum retValue;
2002
2003 if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2004 cannotCastJsonbValue(v.type, "integer");
2005
2006 retValue = DirectFunctionCall1(numeric_int4,
2007 NumericGetDatum(v.val.numeric));
2008
2009 PG_FREE_IF_COPY(in, 0);
2010
2011 PG_RETURN_DATUM(retValue);
2012}
2013
2014Datum
2015jsonb_int8(PG_FUNCTION_ARGS)
2016{
2017 Jsonb *in = PG_GETARG_JSONB_P(0);
2018 JsonbValue v;
2019 Datum retValue;
2020
2021 if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2022 cannotCastJsonbValue(v.type, "bigint");
2023
2024 retValue = DirectFunctionCall1(numeric_int8,
2025 NumericGetDatum(v.val.numeric));
2026
2027 PG_FREE_IF_COPY(in, 0);
2028
2029 PG_RETURN_DATUM(retValue);
2030}
2031
2032Datum
2033jsonb_float4(PG_FUNCTION_ARGS)
2034{
2035 Jsonb *in = PG_GETARG_JSONB_P(0);
2036 JsonbValue v;
2037 Datum retValue;
2038
2039 if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2040 cannotCastJsonbValue(v.type, "real");
2041
2042 retValue = DirectFunctionCall1(numeric_float4,
2043 NumericGetDatum(v.val.numeric));
2044
2045 PG_FREE_IF_COPY(in, 0);
2046
2047 PG_RETURN_DATUM(retValue);
2048}
2049
2050Datum
2051jsonb_float8(PG_FUNCTION_ARGS)
2052{
2053 Jsonb *in = PG_GETARG_JSONB_P(0);
2054 JsonbValue v;
2055 Datum retValue;
2056
2057 if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2058 cannotCastJsonbValue(v.type, "double precision");
2059
2060 retValue = DirectFunctionCall1(numeric_float8,
2061 NumericGetDatum(v.val.numeric));
2062
2063 PG_FREE_IF_COPY(in, 0);
2064
2065 PG_RETURN_DATUM(retValue);
2066}
2067