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