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