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