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