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