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