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