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