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