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
jsonb_in(PG_FUNCTION_ARGS)97 jsonb_in(PG_FUNCTION_ARGS)
98 {
99 	char	   *json = PG_GETARG_CSTRING(0);
100 
101 	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
jsonb_recv(PG_FUNCTION_ARGS)113 jsonb_recv(PG_FUNCTION_ARGS)
114 {
115 	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
116 	int			version = pq_getmsgint(buf, 1);
117 	char	   *str;
118 	int			nbytes;
119 
120 	if (version == 1)
121 		str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
122 	else
123 		elog(ERROR, "unsupported jsonb version number %d", version);
124 
125 	return jsonb_from_cstring(str, nbytes);
126 }
127 
128 /*
129  * jsonb type output function
130  */
131 Datum
jsonb_out(PG_FUNCTION_ARGS)132 jsonb_out(PG_FUNCTION_ARGS)
133 {
134 	Jsonb	   *jb = PG_GETARG_JSONB_P(0);
135 	char	   *out;
136 
137 	out = JsonbToCString(NULL, &jb->root, VARSIZE(jb));
138 
139 	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
jsonb_send(PG_FUNCTION_ARGS)148 jsonb_send(PG_FUNCTION_ARGS)
149 {
150 	Jsonb	   *jb = PG_GETARG_JSONB_P(0);
151 	StringInfoData buf;
152 	StringInfo	jtext = makeStringInfo();
153 	int			version = 1;
154 
155 	(void) JsonbToCString(jtext, &jb->root, VARSIZE(jb));
156 
157 	pq_begintypsend(&buf);
158 	pq_sendint8(&buf, version);
159 	pq_sendtext(&buf, jtext->data, jtext->len);
160 	pfree(jtext->data);
161 	pfree(jtext);
162 
163 	PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
164 }
165 
166 /*
167  * Get the type name of a jsonb container.
168  */
169 static const char *
JsonbContainerTypeName(JsonbContainer * jbc)170 JsonbContainerTypeName(JsonbContainer *jbc)
171 {
172 	JsonbValue	scalar;
173 
174 	if (JsonbExtractScalar(jbc, &scalar))
175 		return JsonbTypeName(&scalar);
176 	else if (JsonContainerIsArray(jbc))
177 		return "array";
178 	else if (JsonContainerIsObject(jbc))
179 		return "object";
180 	else
181 	{
182 		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 *
JsonbTypeName(JsonbValue * jbv)191 JsonbTypeName(JsonbValue *jbv)
192 {
193 	switch (jbv->type)
194 	{
195 		case jbvBinary:
196 			return JsonbContainerTypeName(jbv->val.binary.data);
197 		case jbvObject:
198 			return "object";
199 		case jbvArray:
200 			return "array";
201 		case jbvNumeric:
202 			return "number";
203 		case jbvString:
204 			return "string";
205 		case jbvBool:
206 			return "boolean";
207 		case jbvNull:
208 			return "null";
209 		case jbvDatetime:
210 			switch (jbv->val.datetime.typid)
211 			{
212 				case DATEOID:
213 					return "date";
214 				case TIMEOID:
215 					return "time without time zone";
216 				case TIMETZOID:
217 					return "time with time zone";
218 				case TIMESTAMPOID:
219 					return "timestamp without time zone";
220 				case TIMESTAMPTZOID:
221 					return "timestamp with time zone";
222 				default:
223 					elog(ERROR, "unrecognized jsonb value datetime type: %d",
224 						 jbv->val.datetime.typid);
225 			}
226 			return "unknown";
227 		default:
228 			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
jsonb_typeof(PG_FUNCTION_ARGS)240 jsonb_typeof(PG_FUNCTION_ARGS)
241 {
242 	Jsonb	   *in = PG_GETARG_JSONB_P(0);
243 	const char *result = JsonbContainerTypeName(&in->root);
244 
245 	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
jsonb_from_cstring(char * json,int len)256 jsonb_from_cstring(char *json, int len)
257 {
258 	JsonLexContext *lex;
259 	JsonbInState state;
260 	JsonSemAction sem;
261 
262 	memset(&state, 0, sizeof(state));
263 	memset(&sem, 0, sizeof(sem));
264 	lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
265 
266 	sem.semstate = (void *) &state;
267 
268 	sem.object_start = jsonb_in_object_start;
269 	sem.array_start = jsonb_in_array_start;
270 	sem.object_end = jsonb_in_object_end;
271 	sem.array_end = jsonb_in_array_end;
272 	sem.scalar = jsonb_in_scalar;
273 	sem.object_field_start = jsonb_in_object_field_start;
274 
275 	pg_parse_json_or_ereport(lex, &sem);
276 
277 	/* after parsing, the item member has the composed jsonb structure */
278 	PG_RETURN_POINTER(JsonbValueToJsonb(state.res));
279 }
280 
281 static size_t
checkStringLen(size_t len)282 checkStringLen(size_t len)
283 {
284 	if (len > JENTRY_OFFLENMASK)
285 		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 	return len;
292 }
293 
294 static void
jsonb_in_object_start(void * pstate)295 jsonb_in_object_start(void *pstate)
296 {
297 	JsonbInState *_state = (JsonbInState *) pstate;
298 
299 	_state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_OBJECT, NULL);
300 }
301 
302 static void
jsonb_in_object_end(void * pstate)303 jsonb_in_object_end(void *pstate)
304 {
305 	JsonbInState *_state = (JsonbInState *) pstate;
306 
307 	_state->res = pushJsonbValue(&_state->parseState, WJB_END_OBJECT, NULL);
308 }
309 
310 static void
jsonb_in_array_start(void * pstate)311 jsonb_in_array_start(void *pstate)
312 {
313 	JsonbInState *_state = (JsonbInState *) pstate;
314 
315 	_state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, NULL);
316 }
317 
318 static void
jsonb_in_array_end(void * pstate)319 jsonb_in_array_end(void *pstate)
320 {
321 	JsonbInState *_state = (JsonbInState *) pstate;
322 
323 	_state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
324 }
325 
326 static void
jsonb_in_object_field_start(void * pstate,char * fname,bool isnull)327 jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
328 {
329 	JsonbInState *_state = (JsonbInState *) pstate;
330 	JsonbValue	v;
331 
332 	Assert(fname != NULL);
333 	v.type = jbvString;
334 	v.val.string.len = checkStringLen(strlen(fname));
335 	v.val.string.val = fname;
336 
337 	_state->res = pushJsonbValue(&_state->parseState, WJB_KEY, &v);
338 }
339 
340 static void
jsonb_put_escaped_value(StringInfo out,JsonbValue * scalarVal)341 jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal)
342 {
343 	switch (scalarVal->type)
344 	{
345 		case jbvNull:
346 			appendBinaryStringInfo(out, "null", 4);
347 			break;
348 		case jbvString:
349 			escape_json(out, pnstrdup(scalarVal->val.string.val, scalarVal->val.string.len));
350 			break;
351 		case jbvNumeric:
352 			appendStringInfoString(out,
353 								   DatumGetCString(DirectFunctionCall1(numeric_out,
354 																	   PointerGetDatum(scalarVal->val.numeric))));
355 			break;
356 		case jbvBool:
357 			if (scalarVal->val.boolean)
358 				appendBinaryStringInfo(out, "true", 4);
359 			else
360 				appendBinaryStringInfo(out, "false", 5);
361 			break;
362 		default:
363 			elog(ERROR, "unknown jsonb scalar type");
364 	}
365 }
366 
367 /*
368  * For jsonb we always want the de-escaped value - that's what's in token
369  */
370 static void
jsonb_in_scalar(void * pstate,char * token,JsonTokenType tokentype)371 jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
372 {
373 	JsonbInState *_state = (JsonbInState *) pstate;
374 	JsonbValue	v;
375 	Datum		numd;
376 
377 	switch (tokentype)
378 	{
379 
380 		case JSON_TOKEN_STRING:
381 			Assert(token != NULL);
382 			v.type = jbvString;
383 			v.val.string.len = checkStringLen(strlen(token));
384 			v.val.string.val = token;
385 			break;
386 		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 			v.type = jbvNumeric;
394 			numd = DirectFunctionCall3(numeric_in,
395 									   CStringGetDatum(token),
396 									   ObjectIdGetDatum(InvalidOid),
397 									   Int32GetDatum(-1));
398 			v.val.numeric = DatumGetNumeric(numd);
399 			break;
400 		case JSON_TOKEN_TRUE:
401 			v.type = jbvBool;
402 			v.val.boolean = true;
403 			break;
404 		case JSON_TOKEN_FALSE:
405 			v.type = jbvBool;
406 			v.val.boolean = false;
407 			break;
408 		case JSON_TOKEN_NULL:
409 			v.type = jbvNull;
410 			break;
411 		default:
412 			/* should not be possible */
413 			elog(ERROR, "invalid json token type");
414 			break;
415 	}
416 
417 	if (_state->parseState == NULL)
418 	{
419 		/* single scalar */
420 		JsonbValue	va;
421 
422 		va.type = jbvArray;
423 		va.val.array.rawScalar = true;
424 		va.val.array.nElems = 1;
425 
426 		_state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, &va);
427 		_state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
428 		_state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
429 	}
430 	else
431 	{
432 		JsonbValue *o = &_state->parseState->contVal;
433 
434 		switch (o->type)
435 		{
436 			case jbvArray:
437 				_state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
438 				break;
439 			case jbvObject:
440 				_state->res = pushJsonbValue(&_state->parseState, WJB_VALUE, &v);
441 				break;
442 			default:
443 				elog(ERROR, "unexpected parent of nested structure");
444 		}
445 	}
446 }
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 *
JsonbToCString(StringInfo out,JsonbContainer * in,int estimated_len)460 JsonbToCString(StringInfo out, JsonbContainer *in, int estimated_len)
461 {
462 	return JsonbToCStringWorker(out, in, estimated_len, false);
463 }
464 
465 /*
466  * same thing but with indentation turned on
467  */
468 char *
JsonbToCStringIndent(StringInfo out,JsonbContainer * in,int estimated_len)469 JsonbToCStringIndent(StringInfo out, JsonbContainer *in, int estimated_len)
470 {
471 	return JsonbToCStringWorker(out, in, estimated_len, true);
472 }
473 
474 /*
475  * common worker for above two functions
476  */
477 static char *
JsonbToCStringWorker(StringInfo out,JsonbContainer * in,int estimated_len,bool indent)478 JsonbToCStringWorker(StringInfo out, JsonbContainer *in, int estimated_len, bool indent)
479 {
480 	bool		first = true;
481 	JsonbIterator *it;
482 	JsonbValue	v;
483 	JsonbIteratorToken type = WJB_DONE;
484 	int			level = 0;
485 	bool		redo_switch = false;
486 
487 	/* If we are indenting, don't add a space after a comma */
488 	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 	bool		use_indent = false;
495 	bool		raw_scalar = false;
496 	bool		last_was_key = false;
497 
498 	if (out == NULL)
499 		out = makeStringInfo();
500 
501 	enlargeStringInfo(out, (estimated_len >= 0) ? estimated_len : 64);
502 
503 	it = JsonbIteratorInit(in);
504 
505 	while (redo_switch ||
506 		   ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE))
507 	{
508 		redo_switch = false;
509 		switch (type)
510 		{
511 			case WJB_BEGIN_ARRAY:
512 				if (!first)
513 					appendBinaryStringInfo(out, ", ", ispaces);
514 
515 				if (!v.val.array.rawScalar)
516 				{
517 					add_indent(out, use_indent && !last_was_key, level);
518 					appendStringInfoCharMacro(out, '[');
519 				}
520 				else
521 					raw_scalar = true;
522 
523 				first = true;
524 				level++;
525 				break;
526 			case WJB_BEGIN_OBJECT:
527 				if (!first)
528 					appendBinaryStringInfo(out, ", ", ispaces);
529 
530 				add_indent(out, use_indent && !last_was_key, level);
531 				appendStringInfoCharMacro(out, '{');
532 
533 				first = true;
534 				level++;
535 				break;
536 			case WJB_KEY:
537 				if (!first)
538 					appendBinaryStringInfo(out, ", ", ispaces);
539 				first = true;
540 
541 				add_indent(out, use_indent, level);
542 
543 				/* json rules guarantee this is a string */
544 				jsonb_put_escaped_value(out, &v);
545 				appendBinaryStringInfo(out, ": ", 2);
546 
547 				type = JsonbIteratorNext(&it, &v, false);
548 				if (type == WJB_VALUE)
549 				{
550 					first = false;
551 					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 					redo_switch = true;
563 				}
564 				break;
565 			case WJB_ELEM:
566 				if (!first)
567 					appendBinaryStringInfo(out, ", ", ispaces);
568 				first = false;
569 
570 				if (!raw_scalar)
571 					add_indent(out, use_indent, level);
572 				jsonb_put_escaped_value(out, &v);
573 				break;
574 			case WJB_END_ARRAY:
575 				level--;
576 				if (!raw_scalar)
577 				{
578 					add_indent(out, use_indent, level);
579 					appendStringInfoCharMacro(out, ']');
580 				}
581 				first = false;
582 				break;
583 			case WJB_END_OBJECT:
584 				level--;
585 				add_indent(out, use_indent, level);
586 				appendStringInfoCharMacro(out, '}');
587 				first = false;
588 				break;
589 			default:
590 				elog(ERROR, "unknown jsonb iterator token type");
591 		}
592 		use_indent = indent;
593 		last_was_key = redo_switch;
594 	}
595 
596 	Assert(level == 0);
597 
598 	return out->data;
599 }
600 
601 static void
add_indent(StringInfo out,bool indent,int level)602 add_indent(StringInfo out, bool indent, int level)
603 {
604 	if (indent)
605 	{
606 		int			i;
607 
608 		appendStringInfoCharMacro(out, '\n');
609 		for (i = 0; i < level; i++)
610 			appendBinaryStringInfo(out, "    ", 4);
611 	}
612 }
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
jsonb_categorize_type(Oid typoid,JsonbTypeCategory * tcategory,Oid * outfuncoid)623 jsonb_categorize_type(Oid typoid,
624 					  JsonbTypeCategory *tcategory,
625 					  Oid *outfuncoid)
626 {
627 	bool		typisvarlena;
628 
629 	/* Look through any domain */
630 	typoid = getBaseType(typoid);
631 
632 	*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 	switch (typoid)
642 	{
643 		case BOOLOID:
644 			*tcategory = JSONBTYPE_BOOL;
645 			break;
646 
647 		case INT2OID:
648 		case INT4OID:
649 		case INT8OID:
650 		case FLOAT4OID:
651 		case FLOAT8OID:
652 		case NUMERICOID:
653 			getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
654 			*tcategory = JSONBTYPE_NUMERIC;
655 			break;
656 
657 		case DATEOID:
658 			*tcategory = JSONBTYPE_DATE;
659 			break;
660 
661 		case TIMESTAMPOID:
662 			*tcategory = JSONBTYPE_TIMESTAMP;
663 			break;
664 
665 		case TIMESTAMPTZOID:
666 			*tcategory = JSONBTYPE_TIMESTAMPTZ;
667 			break;
668 
669 		case JSONBOID:
670 			*tcategory = JSONBTYPE_JSONB;
671 			break;
672 
673 		case JSONOID:
674 			*tcategory = JSONBTYPE_JSON;
675 			break;
676 
677 		default:
678 			/* Check for arrays and composites */
679 			if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
680 				|| typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
681 				*tcategory = JSONBTYPE_ARRAY;
682 			else if (type_is_rowtype(typoid))	/* includes RECORDOID */
683 				*tcategory = JSONBTYPE_COMPOSITE;
684 			else
685 			{
686 				/* It's probably the general case ... */
687 				*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 				if (typoid >= FirstNormalObjectId)
694 				{
695 					Oid			castfunc;
696 					CoercionPathType ctype;
697 
698 					ctype = find_coercion_pathway(JSONOID, typoid,
699 												  COERCION_EXPLICIT, &castfunc);
700 					if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
701 					{
702 						*tcategory = JSONBTYPE_JSONCAST;
703 						*outfuncoid = castfunc;
704 					}
705 					else
706 					{
707 						/* not a cast type, so just get the usual output func */
708 						getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
709 					}
710 				}
711 				else
712 				{
713 					/* any other builtin type */
714 					getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
715 				}
716 				break;
717 			}
718 	}
719 }
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
datum_to_jsonb(Datum val,bool is_null,JsonbInState * result,JsonbTypeCategory tcategory,Oid outfuncoid,bool key_scalar)731 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 	bool		scalar_jsonb = false;
739 
740 	check_stack_depth();
741 
742 	/* Convert val to a JsonbValue in jb (in most cases) */
743 	if (is_null)
744 	{
745 		Assert(!key_scalar);
746 		jb.type = jbvNull;
747 	}
748 	else if (key_scalar &&
749 			 (tcategory == JSONBTYPE_ARRAY ||
750 			  tcategory == JSONBTYPE_COMPOSITE ||
751 			  tcategory == JSONBTYPE_JSON ||
752 			  tcategory == JSONBTYPE_JSONB ||
753 			  tcategory == JSONBTYPE_JSONCAST))
754 	{
755 		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 		if (tcategory == JSONBTYPE_JSONCAST)
762 			val = OidFunctionCall1(outfuncoid, val);
763 
764 		switch (tcategory)
765 		{
766 			case JSONBTYPE_ARRAY:
767 				array_to_jsonb_internal(val, result);
768 				break;
769 			case JSONBTYPE_COMPOSITE:
770 				composite_to_jsonb(val, result);
771 				break;
772 			case JSONBTYPE_BOOL:
773 				if (key_scalar)
774 				{
775 					outputstr = DatumGetBool(val) ? "true" : "false";
776 					jb.type = jbvString;
777 					jb.val.string.len = strlen(outputstr);
778 					jb.val.string.val = outputstr;
779 				}
780 				else
781 				{
782 					jb.type = jbvBool;
783 					jb.val.boolean = DatumGetBool(val);
784 				}
785 				break;
786 			case JSONBTYPE_NUMERIC:
787 				outputstr = OidOutputFunctionCall(outfuncoid, val);
788 				if (key_scalar)
789 				{
790 					/* always quote keys */
791 					jb.type = jbvString;
792 					jb.val.string.len = strlen(outputstr);
793 					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 					numeric_error = (strchr(outputstr, 'N') != NULL ||
803 									 strchr(outputstr, 'n') != NULL);
804 					if (!numeric_error)
805 					{
806 						Datum		numd;
807 
808 						jb.type = jbvNumeric;
809 						numd = DirectFunctionCall3(numeric_in,
810 												   CStringGetDatum(outputstr),
811 												   ObjectIdGetDatum(InvalidOid),
812 												   Int32GetDatum(-1));
813 						jb.val.numeric = DatumGetNumeric(numd);
814 						pfree(outputstr);
815 					}
816 					else
817 					{
818 						jb.type = jbvString;
819 						jb.val.string.len = strlen(outputstr);
820 						jb.val.string.val = outputstr;
821 					}
822 				}
823 				break;
824 			case JSONBTYPE_DATE:
825 				jb.type = jbvString;
826 				jb.val.string.val = JsonEncodeDateTime(NULL, val,
827 													   DATEOID, NULL);
828 				jb.val.string.len = strlen(jb.val.string.val);
829 				break;
830 			case JSONBTYPE_TIMESTAMP:
831 				jb.type = jbvString;
832 				jb.val.string.val = JsonEncodeDateTime(NULL, val,
833 													   TIMESTAMPOID, NULL);
834 				jb.val.string.len = strlen(jb.val.string.val);
835 				break;
836 			case JSONBTYPE_TIMESTAMPTZ:
837 				jb.type = jbvString;
838 				jb.val.string.val = JsonEncodeDateTime(NULL, val,
839 													   TIMESTAMPTZOID, NULL);
840 				jb.val.string.len = strlen(jb.val.string.val);
841 				break;
842 			case JSONBTYPE_JSONCAST:
843 			case JSONBTYPE_JSON:
844 				{
845 					/* parse the json right into the existing result object */
846 					JsonLexContext *lex;
847 					JsonSemAction sem;
848 					text	   *json = DatumGetTextPP(val);
849 
850 					lex = makeJsonLexContext(json, true);
851 
852 					memset(&sem, 0, sizeof(sem));
853 
854 					sem.semstate = (void *) result;
855 
856 					sem.object_start = jsonb_in_object_start;
857 					sem.array_start = jsonb_in_array_start;
858 					sem.object_end = jsonb_in_object_end;
859 					sem.array_end = jsonb_in_array_end;
860 					sem.scalar = jsonb_in_scalar;
861 					sem.object_field_start = jsonb_in_object_field_start;
862 
863 					pg_parse_json_or_ereport(lex, &sem);
864 
865 				}
866 				break;
867 			case JSONBTYPE_JSONB:
868 				{
869 					Jsonb	   *jsonb = DatumGetJsonbP(val);
870 					JsonbIterator *it;
871 
872 					it = JsonbIteratorInit(&jsonb->root);
873 
874 					if (JB_ROOT_IS_SCALAR(jsonb))
875 					{
876 						(void) JsonbIteratorNext(&it, &jb, true);
877 						Assert(jb.type == jbvArray);
878 						(void) JsonbIteratorNext(&it, &jb, true);
879 						scalar_jsonb = true;
880 					}
881 					else
882 					{
883 						JsonbIteratorToken type;
884 
885 						while ((type = JsonbIteratorNext(&it, &jb, false))
886 							   != WJB_DONE)
887 						{
888 							if (type == WJB_END_ARRAY || type == WJB_END_OBJECT ||
889 								type == WJB_BEGIN_ARRAY || type == WJB_BEGIN_OBJECT)
890 								result->res = pushJsonbValue(&result->parseState,
891 															 type, NULL);
892 							else
893 								result->res = pushJsonbValue(&result->parseState,
894 															 type, &jb);
895 						}
896 					}
897 				}
898 				break;
899 			default:
900 				outputstr = OidOutputFunctionCall(outfuncoid, val);
901 				jb.type = jbvString;
902 				jb.val.string.len = checkStringLen(strlen(outputstr));
903 				jb.val.string.val = outputstr;
904 				break;
905 		}
906 	}
907 
908 	/* Now insert jb into result, unless we did it recursively */
909 	if (!is_null && !scalar_jsonb &&
910 		tcategory >= JSONBTYPE_JSON && tcategory <= JSONBTYPE_JSONCAST)
911 	{
912 		/* work has been done recursively */
913 		return;
914 	}
915 	else if (result->parseState == NULL)
916 	{
917 		/* single root scalar */
918 		JsonbValue	va;
919 
920 		va.type = jbvArray;
921 		va.val.array.rawScalar = true;
922 		va.val.array.nElems = 1;
923 
924 		result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, &va);
925 		result->res = pushJsonbValue(&result->parseState, WJB_ELEM, &jb);
926 		result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
927 	}
928 	else
929 	{
930 		JsonbValue *o = &result->parseState->contVal;
931 
932 		switch (o->type)
933 		{
934 			case jbvArray:
935 				result->res = pushJsonbValue(&result->parseState, WJB_ELEM, &jb);
936 				break;
937 			case jbvObject:
938 				result->res = pushJsonbValue(&result->parseState,
939 											 key_scalar ? WJB_KEY : WJB_VALUE,
940 											 &jb);
941 				break;
942 			default:
943 				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
array_dim_to_jsonb(JsonbInState * result,int dim,int ndims,int * dims,Datum * vals,bool * nulls,int * valcount,JsonbTypeCategory tcategory,Oid outfuncoid)954 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 	result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL);
963 
964 	for (i = 1; i <= dims[dim]; i++)
965 	{
966 		if (dim + 1 == ndims)
967 		{
968 			datum_to_jsonb(vals[*valcount], nulls[*valcount], result, tcategory,
969 						   outfuncoid, false);
970 			(*valcount)++;
971 		}
972 		else
973 		{
974 			array_dim_to_jsonb(result, dim + 1, ndims, dims, vals, nulls,
975 							   valcount, tcategory, outfuncoid);
976 		}
977 	}
978 
979 	result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
980 }
981 
982 /*
983  * Turn an array into JSON.
984  */
985 static void
array_to_jsonb_internal(Datum array,JsonbInState * result)986 array_to_jsonb_internal(Datum array, JsonbInState *result)
987 {
988 	ArrayType  *v = DatumGetArrayTypeP(array);
989 	Oid			element_type = ARR_ELEMTYPE(v);
990 	int		   *dim;
991 	int			ndim;
992 	int			nitems;
993 	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 	ndim = ARR_NDIM(v);
1003 	dim = ARR_DIMS(v);
1004 	nitems = ArrayGetNItems(ndim, dim);
1005 
1006 	if (nitems <= 0)
1007 	{
1008 		result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_ARRAY, NULL);
1009 		result->res = pushJsonbValue(&result->parseState, WJB_END_ARRAY, NULL);
1010 		return;
1011 	}
1012 
1013 	get_typlenbyvalalign(element_type,
1014 						 &typlen, &typbyval, &typalign);
1015 
1016 	jsonb_categorize_type(element_type,
1017 						  &tcategory, &outfuncoid);
1018 
1019 	deconstruct_array(v, element_type, typlen, typbyval,
1020 					  typalign, &elements, &nulls,
1021 					  &nitems);
1022 
1023 	array_dim_to_jsonb(result, 0, ndim, dim, elements, nulls, &count, tcategory,
1024 					   outfuncoid);
1025 
1026 	pfree(elements);
1027 	pfree(nulls);
1028 }
1029 
1030 /*
1031  * Turn a composite / record into JSON.
1032  */
1033 static void
composite_to_jsonb(Datum composite,JsonbInState * result)1034 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 	td = DatumGetHeapTupleHeader(composite);
1045 
1046 	/* Extract rowtype info and find a tupdesc */
1047 	tupType = HeapTupleHeaderGetTypeId(td);
1048 	tupTypmod = HeapTupleHeaderGetTypMod(td);
1049 	tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
1050 
1051 	/* Build a temporary HeapTuple control structure */
1052 	tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
1053 	tmptup.t_data = td;
1054 	tuple = &tmptup;
1055 
1056 	result->res = pushJsonbValue(&result->parseState, WJB_BEGIN_OBJECT, NULL);
1057 
1058 	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 		Form_pg_attribute att = TupleDescAttr(tupdesc, i);
1067 
1068 		if (att->attisdropped)
1069 			continue;
1070 
1071 		attname = NameStr(att->attname);
1072 
1073 		v.type = jbvString;
1074 		/* don't need checkStringLen here - can't exceed maximum name length */
1075 		v.val.string.len = strlen(attname);
1076 		v.val.string.val = attname;
1077 
1078 		result->res = pushJsonbValue(&result->parseState, WJB_KEY, &v);
1079 
1080 		val = heap_getattr(tuple, i + 1, tupdesc, &isnull);
1081 
1082 		if (isnull)
1083 		{
1084 			tcategory = JSONBTYPE_NULL;
1085 			outfuncoid = InvalidOid;
1086 		}
1087 		else
1088 			jsonb_categorize_type(att->atttypid, &tcategory, &outfuncoid);
1089 
1090 		datum_to_jsonb(val, isnull, result, tcategory, outfuncoid, false);
1091 	}
1092 
1093 	result->res = pushJsonbValue(&result->parseState, WJB_END_OBJECT, NULL);
1094 	ReleaseTupleDesc(tupdesc);
1095 }
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
add_jsonb(Datum val,bool is_null,JsonbInState * result,Oid val_type,bool key_scalar)1106 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 	if (val_type == InvalidOid)
1113 		ereport(ERROR,
1114 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1115 				 errmsg("could not determine input data type")));
1116 
1117 	if (is_null)
1118 	{
1119 		tcategory = JSONBTYPE_NULL;
1120 		outfuncoid = InvalidOid;
1121 	}
1122 	else
1123 		jsonb_categorize_type(val_type,
1124 							  &tcategory, &outfuncoid);
1125 
1126 	datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar);
1127 }
1128 
1129 /*
1130  * SQL function to_jsonb(anyvalue)
1131  */
1132 Datum
to_jsonb(PG_FUNCTION_ARGS)1133 to_jsonb(PG_FUNCTION_ARGS)
1134 {
1135 	Datum		val = PG_GETARG_DATUM(0);
1136 	Oid			val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
1137 	JsonbInState result;
1138 	JsonbTypeCategory tcategory;
1139 	Oid			outfuncoid;
1140 
1141 	if (val_type == InvalidOid)
1142 		ereport(ERROR,
1143 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1144 				 errmsg("could not determine input data type")));
1145 
1146 	jsonb_categorize_type(val_type,
1147 						  &tcategory, &outfuncoid);
1148 
1149 	memset(&result, 0, sizeof(JsonbInState));
1150 
1151 	datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
1152 
1153 	PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1154 }
1155 
1156 /*
1157  * SQL function jsonb_build_object(variadic "any")
1158  */
1159 Datum
jsonb_build_object(PG_FUNCTION_ARGS)1160 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 	nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
1171 
1172 	if (nargs < 0)
1173 		PG_RETURN_NULL();
1174 
1175 	if (nargs % 2 != 0)
1176 		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 	memset(&result, 0, sizeof(JsonbInState));
1184 
1185 	result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1186 
1187 	for (i = 0; i < nargs; i += 2)
1188 	{
1189 		/* process key */
1190 		if (nulls[i])
1191 			ereport(ERROR,
1192 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1193 					 errmsg("argument %d: key must not be null", i + 1)));
1194 
1195 		add_jsonb(args[i], false, &result, types[i], true);
1196 
1197 		/* process value */
1198 		add_jsonb(args[i + 1], nulls[i + 1], &result, types[i + 1], false);
1199 	}
1200 
1201 	result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1202 
1203 	PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1204 }
1205 
1206 /*
1207  * degenerate case of jsonb_build_object where it gets 0 arguments.
1208  */
1209 Datum
jsonb_build_object_noargs(PG_FUNCTION_ARGS)1210 jsonb_build_object_noargs(PG_FUNCTION_ARGS)
1211 {
1212 	JsonbInState result;
1213 
1214 	memset(&result, 0, sizeof(JsonbInState));
1215 
1216 	(void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1217 	result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1218 
1219 	PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1220 }
1221 
1222 /*
1223  * SQL function jsonb_build_array(variadic "any")
1224  */
1225 Datum
jsonb_build_array(PG_FUNCTION_ARGS)1226 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 	nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
1237 
1238 	if (nargs < 0)
1239 		PG_RETURN_NULL();
1240 
1241 	memset(&result, 0, sizeof(JsonbInState));
1242 
1243 	result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
1244 
1245 	for (i = 0; i < nargs; i++)
1246 		add_jsonb(args[i], nulls[i], &result, types[i], false);
1247 
1248 	result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
1249 
1250 	PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
1251 }
1252 
1253 /*
1254  * degenerate case of jsonb_build_array where it gets 0 arguments.
1255  */
1256 Datum
jsonb_build_array_noargs(PG_FUNCTION_ARGS)1257 jsonb_build_array_noargs(PG_FUNCTION_ARGS)
1258 {
1259 	JsonbInState result;
1260 
1261 	memset(&result, 0, sizeof(JsonbInState));
1262 
1263 	(void) pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
1264 	result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
1265 
1266 	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
jsonb_object(PG_FUNCTION_ARGS)1278 jsonb_object(PG_FUNCTION_ARGS)
1279 {
1280 	ArrayType  *in_array = PG_GETARG_ARRAYTYPE_P(0);
1281 	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 	memset(&result, 0, sizeof(JsonbInState));
1290 
1291 	(void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1292 
1293 	switch (ndims)
1294 	{
1295 		case 0:
1296 			goto close_object;
1297 			break;
1298 
1299 		case 1:
1300 			if ((ARR_DIMS(in_array)[0]) % 2)
1301 				ereport(ERROR,
1302 						(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1303 						 errmsg("array must have even number of elements")));
1304 			break;
1305 
1306 		case 2:
1307 			if ((ARR_DIMS(in_array)[1]) != 2)
1308 				ereport(ERROR,
1309 						(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1310 						 errmsg("array must have two columns")));
1311 			break;
1312 
1313 		default:
1314 			ereport(ERROR,
1315 					(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1316 					 errmsg("wrong number of array subscripts")));
1317 	}
1318 
1319 	deconstruct_array(in_array,
1320 					  TEXTOID, -1, false, TYPALIGN_INT,
1321 					  &in_datums, &in_nulls, &in_count);
1322 
1323 	count = in_count / 2;
1324 
1325 	for (i = 0; i < count; ++i)
1326 	{
1327 		JsonbValue	v;
1328 		char	   *str;
1329 		int			len;
1330 
1331 		if (in_nulls[i * 2])
1332 			ereport(ERROR,
1333 					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1334 					 errmsg("null value not allowed for object key")));
1335 
1336 		str = TextDatumGetCString(in_datums[i * 2]);
1337 		len = strlen(str);
1338 
1339 		v.type = jbvString;
1340 
1341 		v.val.string.len = len;
1342 		v.val.string.val = str;
1343 
1344 		(void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
1345 
1346 		if (in_nulls[i * 2 + 1])
1347 		{
1348 			v.type = jbvNull;
1349 		}
1350 		else
1351 		{
1352 			str = TextDatumGetCString(in_datums[i * 2 + 1]);
1353 			len = strlen(str);
1354 
1355 			v.type = jbvString;
1356 
1357 			v.val.string.len = len;
1358 			v.val.string.val = str;
1359 		}
1360 
1361 		(void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
1362 	}
1363 
1364 	pfree(in_datums);
1365 	pfree(in_nulls);
1366 
1367 close_object:
1368 	result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1369 
1370 	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
jsonb_object_two_arg(PG_FUNCTION_ARGS)1380 jsonb_object_two_arg(PG_FUNCTION_ARGS)
1381 {
1382 	ArrayType  *key_array = PG_GETARG_ARRAYTYPE_P(0);
1383 	ArrayType  *val_array = PG_GETARG_ARRAYTYPE_P(1);
1384 	int			nkdims = ARR_NDIM(key_array);
1385 	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 	memset(&result, 0, sizeof(JsonbInState));
1396 
1397 	(void) pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
1398 
1399 	if (nkdims > 1 || nkdims != nvdims)
1400 		ereport(ERROR,
1401 				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1402 				 errmsg("wrong number of array subscripts")));
1403 
1404 	if (nkdims == 0)
1405 		goto close_object;
1406 
1407 	deconstruct_array(key_array,
1408 					  TEXTOID, -1, false, TYPALIGN_INT,
1409 					  &key_datums, &key_nulls, &key_count);
1410 
1411 	deconstruct_array(val_array,
1412 					  TEXTOID, -1, false, TYPALIGN_INT,
1413 					  &val_datums, &val_nulls, &val_count);
1414 
1415 	if (key_count != val_count)
1416 		ereport(ERROR,
1417 				(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
1418 				 errmsg("mismatched array dimensions")));
1419 
1420 	for (i = 0; i < key_count; ++i)
1421 	{
1422 		JsonbValue	v;
1423 		char	   *str;
1424 		int			len;
1425 
1426 		if (key_nulls[i])
1427 			ereport(ERROR,
1428 					(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1429 					 errmsg("null value not allowed for object key")));
1430 
1431 		str = TextDatumGetCString(key_datums[i]);
1432 		len = strlen(str);
1433 
1434 		v.type = jbvString;
1435 
1436 		v.val.string.len = len;
1437 		v.val.string.val = str;
1438 
1439 		(void) pushJsonbValue(&result.parseState, WJB_KEY, &v);
1440 
1441 		if (val_nulls[i])
1442 		{
1443 			v.type = jbvNull;
1444 		}
1445 		else
1446 		{
1447 			str = TextDatumGetCString(val_datums[i]);
1448 			len = strlen(str);
1449 
1450 			v.type = jbvString;
1451 
1452 			v.val.string.len = len;
1453 			v.val.string.val = str;
1454 		}
1455 
1456 		(void) pushJsonbValue(&result.parseState, WJB_VALUE, &v);
1457 	}
1458 
1459 	pfree(key_datums);
1460 	pfree(key_nulls);
1461 	pfree(val_datums);
1462 	pfree(val_nulls);
1463 
1464 close_object:
1465 	result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
1466 
1467 	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 *
clone_parse_state(JsonbParseState * state)1477 clone_parse_state(JsonbParseState *state)
1478 {
1479 	JsonbParseState *result,
1480 			   *icursor,
1481 			   *ocursor;
1482 
1483 	if (state == NULL)
1484 		return NULL;
1485 
1486 	result = palloc(sizeof(JsonbParseState));
1487 	icursor = state;
1488 	ocursor = result;
1489 	for (;;)
1490 	{
1491 		ocursor->contVal = icursor->contVal;
1492 		ocursor->size = icursor->size;
1493 		icursor = icursor->next;
1494 		if (icursor == NULL)
1495 			break;
1496 		ocursor->next = palloc(sizeof(JsonbParseState));
1497 		ocursor = ocursor->next;
1498 	}
1499 	ocursor->next = NULL;
1500 
1501 	return result;
1502 }
1503 
1504 
1505 /*
1506  * jsonb_agg aggregate function
1507  */
1508 Datum
jsonb_agg_transfn(PG_FUNCTION_ARGS)1509 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 	bool		single_scalar = false;
1518 	JsonbIterator *it;
1519 	Jsonb	   *jbelem;
1520 	JsonbValue	v;
1521 	JsonbIteratorToken type;
1522 
1523 	if (!AggCheckCallContext(fcinfo, &aggcontext))
1524 	{
1525 		/* cannot be called directly because of internal-type argument */
1526 		elog(ERROR, "jsonb_agg_transfn called in non-aggregate context");
1527 	}
1528 
1529 	/* set up the accumulator on the first go round */
1530 
1531 	if (PG_ARGISNULL(0))
1532 	{
1533 		Oid			arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
1534 
1535 		if (arg_type == InvalidOid)
1536 			ereport(ERROR,
1537 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1538 					 errmsg("could not determine input data type")));
1539 
1540 		oldcontext = MemoryContextSwitchTo(aggcontext);
1541 		state = palloc(sizeof(JsonbAggState));
1542 		result = palloc0(sizeof(JsonbInState));
1543 		state->res = result;
1544 		result->res = pushJsonbValue(&result->parseState,
1545 									 WJB_BEGIN_ARRAY, NULL);
1546 		MemoryContextSwitchTo(oldcontext);
1547 
1548 		jsonb_categorize_type(arg_type, &state->val_category,
1549 							  &state->val_output_func);
1550 	}
1551 	else
1552 	{
1553 		state = (JsonbAggState *) PG_GETARG_POINTER(0);
1554 		result = state->res;
1555 	}
1556 
1557 	/* turn the argument into jsonb in the normal function context */
1558 
1559 	val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
1560 
1561 	memset(&elem, 0, sizeof(JsonbInState));
1562 
1563 	datum_to_jsonb(val, PG_ARGISNULL(1), &elem, state->val_category,
1564 				   state->val_output_func, false);
1565 
1566 	jbelem = JsonbValueToJsonb(elem.res);
1567 
1568 	/* switch to the aggregate context for accumulation operations */
1569 
1570 	oldcontext = MemoryContextSwitchTo(aggcontext);
1571 
1572 	it = JsonbIteratorInit(&jbelem->root);
1573 
1574 	while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1575 	{
1576 		switch (type)
1577 		{
1578 			case WJB_BEGIN_ARRAY:
1579 				if (v.val.array.rawScalar)
1580 					single_scalar = true;
1581 				else
1582 					result->res = pushJsonbValue(&result->parseState,
1583 												 type, NULL);
1584 				break;
1585 			case WJB_END_ARRAY:
1586 				if (!single_scalar)
1587 					result->res = pushJsonbValue(&result->parseState,
1588 												 type, NULL);
1589 				break;
1590 			case WJB_BEGIN_OBJECT:
1591 			case WJB_END_OBJECT:
1592 				result->res = pushJsonbValue(&result->parseState,
1593 											 type, NULL);
1594 				break;
1595 			case WJB_ELEM:
1596 			case WJB_KEY:
1597 			case WJB_VALUE:
1598 				if (v.type == jbvString)
1599 				{
1600 					/* copy string values in the aggregate context */
1601 					char	   *buf = palloc(v.val.string.len + 1);
1602 
1603 					snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
1604 					v.val.string.val = buf;
1605 				}
1606 				else if (v.type == jbvNumeric)
1607 				{
1608 					/* same for numeric */
1609 					v.val.numeric =
1610 						DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
1611 															NumericGetDatum(v.val.numeric)));
1612 				}
1613 				result->res = pushJsonbValue(&result->parseState,
1614 											 type, &v);
1615 				break;
1616 			default:
1617 				elog(ERROR, "unknown jsonb iterator token type");
1618 		}
1619 	}
1620 
1621 	MemoryContextSwitchTo(oldcontext);
1622 
1623 	PG_RETURN_POINTER(state);
1624 }
1625 
1626 Datum
jsonb_agg_finalfn(PG_FUNCTION_ARGS)1627 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 	if (PG_ARGISNULL(0))
1637 		PG_RETURN_NULL();		/* returns null iff no input values */
1638 
1639 	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 	result.parseState = clone_parse_state(arg->res->parseState);
1649 
1650 	result.res = pushJsonbValue(&result.parseState,
1651 								WJB_END_ARRAY, NULL);
1652 
1653 	out = JsonbValueToJsonb(result.res);
1654 
1655 	PG_RETURN_POINTER(out);
1656 }
1657 
1658 /*
1659  * jsonb_object_agg aggregate function
1660  */
1661 Datum
jsonb_object_agg_transfn(PG_FUNCTION_ARGS)1662 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 	if (!AggCheckCallContext(fcinfo, &aggcontext))
1678 	{
1679 		/* cannot be called directly because of internal-type argument */
1680 		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 	if (PG_ARGISNULL(0))
1686 	{
1687 		Oid			arg_type;
1688 
1689 		oldcontext = MemoryContextSwitchTo(aggcontext);
1690 		state = palloc(sizeof(JsonbAggState));
1691 		result = palloc0(sizeof(JsonbInState));
1692 		state->res = result;
1693 		result->res = pushJsonbValue(&result->parseState,
1694 									 WJB_BEGIN_OBJECT, NULL);
1695 		MemoryContextSwitchTo(oldcontext);
1696 
1697 		arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
1698 
1699 		if (arg_type == InvalidOid)
1700 			ereport(ERROR,
1701 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1702 					 errmsg("could not determine input data type")));
1703 
1704 		jsonb_categorize_type(arg_type, &state->key_category,
1705 							  &state->key_output_func);
1706 
1707 		arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
1708 
1709 		if (arg_type == InvalidOid)
1710 			ereport(ERROR,
1711 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1712 					 errmsg("could not determine input data type")));
1713 
1714 		jsonb_categorize_type(arg_type, &state->val_category,
1715 							  &state->val_output_func);
1716 	}
1717 	else
1718 	{
1719 		state = (JsonbAggState *) PG_GETARG_POINTER(0);
1720 		result = state->res;
1721 	}
1722 
1723 	/* turn the argument into jsonb in the normal function context */
1724 
1725 	if (PG_ARGISNULL(1))
1726 		ereport(ERROR,
1727 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1728 				 errmsg("field name must not be null")));
1729 
1730 	val = PG_GETARG_DATUM(1);
1731 
1732 	memset(&elem, 0, sizeof(JsonbInState));
1733 
1734 	datum_to_jsonb(val, false, &elem, state->key_category,
1735 				   state->key_output_func, true);
1736 
1737 	jbkey = JsonbValueToJsonb(elem.res);
1738 
1739 	val = PG_ARGISNULL(2) ? (Datum) 0 : PG_GETARG_DATUM(2);
1740 
1741 	memset(&elem, 0, sizeof(JsonbInState));
1742 
1743 	datum_to_jsonb(val, PG_ARGISNULL(2), &elem, state->val_category,
1744 				   state->val_output_func, false);
1745 
1746 	jbval = JsonbValueToJsonb(elem.res);
1747 
1748 	it = JsonbIteratorInit(&jbkey->root);
1749 
1750 	/* switch to the aggregate context for accumulation operations */
1751 
1752 	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 	while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1761 	{
1762 		switch (type)
1763 		{
1764 			case WJB_BEGIN_ARRAY:
1765 				if (!v.val.array.rawScalar)
1766 					elog(ERROR, "unexpected structure for key");
1767 				break;
1768 			case WJB_ELEM:
1769 				if (v.type == jbvString)
1770 				{
1771 					/* copy string values in the aggregate context */
1772 					char	   *buf = palloc(v.val.string.len + 1);
1773 
1774 					snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
1775 					v.val.string.val = buf;
1776 				}
1777 				else
1778 				{
1779 					ereport(ERROR,
1780 							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1781 							 errmsg("object keys must be strings")));
1782 				}
1783 				result->res = pushJsonbValue(&result->parseState,
1784 											 WJB_KEY, &v);
1785 				break;
1786 			case WJB_END_ARRAY:
1787 				break;
1788 			default:
1789 				elog(ERROR, "unexpected structure for key");
1790 				break;
1791 		}
1792 	}
1793 
1794 	it = JsonbIteratorInit(&jbval->root);
1795 
1796 	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 	while ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)
1805 	{
1806 		switch (type)
1807 		{
1808 			case WJB_BEGIN_ARRAY:
1809 				if (v.val.array.rawScalar)
1810 					single_scalar = true;
1811 				else
1812 					result->res = pushJsonbValue(&result->parseState,
1813 												 type, NULL);
1814 				break;
1815 			case WJB_END_ARRAY:
1816 				if (!single_scalar)
1817 					result->res = pushJsonbValue(&result->parseState,
1818 												 type, NULL);
1819 				break;
1820 			case WJB_BEGIN_OBJECT:
1821 			case WJB_END_OBJECT:
1822 				result->res = pushJsonbValue(&result->parseState,
1823 											 type, NULL);
1824 				break;
1825 			case WJB_ELEM:
1826 			case WJB_KEY:
1827 			case WJB_VALUE:
1828 				if (v.type == jbvString)
1829 				{
1830 					/* copy string values in the aggregate context */
1831 					char	   *buf = palloc(v.val.string.len + 1);
1832 
1833 					snprintf(buf, v.val.string.len + 1, "%s", v.val.string.val);
1834 					v.val.string.val = buf;
1835 				}
1836 				else if (v.type == jbvNumeric)
1837 				{
1838 					/* same for numeric */
1839 					v.val.numeric =
1840 						DatumGetNumeric(DirectFunctionCall1(numeric_uplus,
1841 															NumericGetDatum(v.val.numeric)));
1842 				}
1843 				result->res = pushJsonbValue(&result->parseState,
1844 											 single_scalar ? WJB_VALUE : type,
1845 											 &v);
1846 				break;
1847 			default:
1848 				elog(ERROR, "unknown jsonb iterator token type");
1849 		}
1850 	}
1851 
1852 	MemoryContextSwitchTo(oldcontext);
1853 
1854 	PG_RETURN_POINTER(state);
1855 }
1856 
1857 Datum
jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)1858 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 	if (PG_ARGISNULL(0))
1868 		PG_RETURN_NULL();		/* returns null iff no input values */
1869 
1870 	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 	result.parseState = clone_parse_state(arg->res->parseState);
1881 
1882 	result.res = pushJsonbValue(&result.parseState,
1883 								WJB_END_OBJECT, NULL);
1884 
1885 	out = JsonbValueToJsonb(result.res);
1886 
1887 	PG_RETURN_POINTER(out);
1888 }
1889 
1890 
1891 /*
1892  * Extract scalar value from raw-scalar pseudo-array jsonb.
1893  */
1894 bool
JsonbExtractScalar(JsonbContainer * jbc,JsonbValue * res)1895 JsonbExtractScalar(JsonbContainer *jbc, JsonbValue *res)
1896 {
1897 	JsonbIterator *it;
1898 	JsonbIteratorToken tok PG_USED_FOR_ASSERTS_ONLY;
1899 	JsonbValue	tmp;
1900 
1901 	if (!JsonContainerIsArray(jbc) || !JsonContainerIsScalar(jbc))
1902 	{
1903 		/* inform caller about actual type of container */
1904 		res->type = (JsonContainerIsArray(jbc)) ? jbvArray : jbvObject;
1905 		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 	it = JsonbIteratorInit(jbc);
1913 
1914 	tok = JsonbIteratorNext(&it, &tmp, true);
1915 	Assert(tok == WJB_BEGIN_ARRAY);
1916 	Assert(tmp.val.array.nElems == 1 && tmp.val.array.rawScalar);
1917 
1918 	tok = JsonbIteratorNext(&it, res, true);
1919 	Assert(tok == WJB_ELEM);
1920 	Assert(IsAJsonbScalar(res));
1921 
1922 	tok = JsonbIteratorNext(&it, &tmp, true);
1923 	Assert(tok == WJB_END_ARRAY);
1924 
1925 	tok = JsonbIteratorNext(&it, &tmp, true);
1926 	Assert(tok == WJB_DONE);
1927 
1928 	return true;
1929 }
1930 
1931 /*
1932  * Emit correct, translatable cast error message
1933  */
1934 static void
cannotCastJsonbValue(enum jbvType type,const char * sqltype)1935 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 	for (i = 0; i < lengthof(messages); i++)
1955 		if (messages[i].type == type)
1956 			ereport(ERROR,
1957 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1958 					 errmsg(messages[i].msg, sqltype)));
1959 
1960 	/* should be unreachable */
1961 	elog(ERROR, "unknown jsonb type: %d", (int) type);
1962 }
1963 
1964 Datum
jsonb_bool(PG_FUNCTION_ARGS)1965 jsonb_bool(PG_FUNCTION_ARGS)
1966 {
1967 	Jsonb	   *in = PG_GETARG_JSONB_P(0);
1968 	JsonbValue	v;
1969 
1970 	if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvBool)
1971 		cannotCastJsonbValue(v.type, "boolean");
1972 
1973 	PG_FREE_IF_COPY(in, 0);
1974 
1975 	PG_RETURN_BOOL(v.val.boolean);
1976 }
1977 
1978 Datum
jsonb_numeric(PG_FUNCTION_ARGS)1979 jsonb_numeric(PG_FUNCTION_ARGS)
1980 {
1981 	Jsonb	   *in = PG_GETARG_JSONB_P(0);
1982 	JsonbValue	v;
1983 	Numeric		retValue;
1984 
1985 	if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
1986 		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 	retValue = DatumGetNumericCopy(NumericGetDatum(v.val.numeric));
1993 
1994 	PG_FREE_IF_COPY(in, 0);
1995 
1996 	PG_RETURN_NUMERIC(retValue);
1997 }
1998 
1999 Datum
jsonb_int2(PG_FUNCTION_ARGS)2000 jsonb_int2(PG_FUNCTION_ARGS)
2001 {
2002 	Jsonb	   *in = PG_GETARG_JSONB_P(0);
2003 	JsonbValue	v;
2004 	Datum		retValue;
2005 
2006 	if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2007 		cannotCastJsonbValue(v.type, "smallint");
2008 
2009 	retValue = DirectFunctionCall1(numeric_int2,
2010 								   NumericGetDatum(v.val.numeric));
2011 
2012 	PG_FREE_IF_COPY(in, 0);
2013 
2014 	PG_RETURN_DATUM(retValue);
2015 }
2016 
2017 Datum
jsonb_int4(PG_FUNCTION_ARGS)2018 jsonb_int4(PG_FUNCTION_ARGS)
2019 {
2020 	Jsonb	   *in = PG_GETARG_JSONB_P(0);
2021 	JsonbValue	v;
2022 	Datum		retValue;
2023 
2024 	if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2025 		cannotCastJsonbValue(v.type, "integer");
2026 
2027 	retValue = DirectFunctionCall1(numeric_int4,
2028 								   NumericGetDatum(v.val.numeric));
2029 
2030 	PG_FREE_IF_COPY(in, 0);
2031 
2032 	PG_RETURN_DATUM(retValue);
2033 }
2034 
2035 Datum
jsonb_int8(PG_FUNCTION_ARGS)2036 jsonb_int8(PG_FUNCTION_ARGS)
2037 {
2038 	Jsonb	   *in = PG_GETARG_JSONB_P(0);
2039 	JsonbValue	v;
2040 	Datum		retValue;
2041 
2042 	if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2043 		cannotCastJsonbValue(v.type, "bigint");
2044 
2045 	retValue = DirectFunctionCall1(numeric_int8,
2046 								   NumericGetDatum(v.val.numeric));
2047 
2048 	PG_FREE_IF_COPY(in, 0);
2049 
2050 	PG_RETURN_DATUM(retValue);
2051 }
2052 
2053 Datum
jsonb_float4(PG_FUNCTION_ARGS)2054 jsonb_float4(PG_FUNCTION_ARGS)
2055 {
2056 	Jsonb	   *in = PG_GETARG_JSONB_P(0);
2057 	JsonbValue	v;
2058 	Datum		retValue;
2059 
2060 	if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2061 		cannotCastJsonbValue(v.type, "real");
2062 
2063 	retValue = DirectFunctionCall1(numeric_float4,
2064 								   NumericGetDatum(v.val.numeric));
2065 
2066 	PG_FREE_IF_COPY(in, 0);
2067 
2068 	PG_RETURN_DATUM(retValue);
2069 }
2070 
2071 Datum
jsonb_float8(PG_FUNCTION_ARGS)2072 jsonb_float8(PG_FUNCTION_ARGS)
2073 {
2074 	Jsonb	   *in = PG_GETARG_JSONB_P(0);
2075 	JsonbValue	v;
2076 	Datum		retValue;
2077 
2078 	if (!JsonbExtractScalar(&in->root, &v) || v.type != jbvNumeric)
2079 		cannotCastJsonbValue(v.type, "double precision");
2080 
2081 	retValue = DirectFunctionCall1(numeric_float8,
2082 								   NumericGetDatum(v.val.numeric));
2083 
2084 	PG_FREE_IF_COPY(in, 0);
2085 
2086 	PG_RETURN_DATUM(retValue);
2087 }
2088