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