Fix NULL handling in datum_to_jsonb().
The function failed to adhere to its specification that the "tcategory" argument should not be examined when the input value is NULL. This resulted in a crash in some cases. Per bug #13680 from Boyko Yordanov. In passing, re-pgindent some recent changes in jsonb.c, and fix a rather ungrammatical comment. Diagnosis and patch by Michael Paquier, cosmetic changes by me
This commit is contained in:
parent
08fbad0afd
commit
3587cbc34f
@ -61,11 +61,11 @@ typedef enum /* type categories for datum_to_jsonb */
|
|||||||
|
|
||||||
typedef struct JsonbAggState
|
typedef struct JsonbAggState
|
||||||
{
|
{
|
||||||
JsonbInState *res;
|
JsonbInState *res;
|
||||||
JsonbTypeCategory key_category;
|
JsonbTypeCategory key_category;
|
||||||
Oid key_output_func;
|
Oid key_output_func;
|
||||||
JsonbTypeCategory val_category;
|
JsonbTypeCategory val_category;
|
||||||
Oid val_output_func;
|
Oid val_output_func;
|
||||||
} JsonbAggState;
|
} JsonbAggState;
|
||||||
|
|
||||||
static inline Datum jsonb_from_cstring(char *json, int len);
|
static inline Datum jsonb_from_cstring(char *json, int len);
|
||||||
@ -714,6 +714,7 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
|
|
||||||
check_stack_depth();
|
check_stack_depth();
|
||||||
|
|
||||||
|
/* Convert val to a JsonbValue in jb (in most cases) */
|
||||||
if (is_null)
|
if (is_null)
|
||||||
{
|
{
|
||||||
Assert(!key_scalar);
|
Assert(!key_scalar);
|
||||||
@ -936,8 +937,10 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tcategory >= JSONBTYPE_JSON && tcategory <= JSONBTYPE_JSONCAST &&
|
|
||||||
!scalar_jsonb)
|
/* Now insert jb into result, unless we did it recursively */
|
||||||
|
if (!is_null && !scalar_jsonb &&
|
||||||
|
tcategory >= JSONBTYPE_JSON && tcategory <= JSONBTYPE_JSONCAST)
|
||||||
{
|
{
|
||||||
/* work has been done recursively */
|
/* work has been done recursively */
|
||||||
return;
|
return;
|
||||||
@ -1607,8 +1610,7 @@ jsonb_agg_transfn(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
if (PG_ARGISNULL(0))
|
if (PG_ARGISNULL(0))
|
||||||
{
|
{
|
||||||
|
Oid arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
|
||||||
Oid arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
|
|
||||||
|
|
||||||
if (arg_type == InvalidOid)
|
if (arg_type == InvalidOid)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -1762,7 +1764,7 @@ jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
if (PG_ARGISNULL(0))
|
if (PG_ARGISNULL(0))
|
||||||
{
|
{
|
||||||
Oid arg_type;
|
Oid arg_type;
|
||||||
|
|
||||||
oldcontext = MemoryContextSwitchTo(aggcontext);
|
oldcontext = MemoryContextSwitchTo(aggcontext);
|
||||||
state = palloc(sizeof(JsonbAggState));
|
state = palloc(sizeof(JsonbAggState));
|
||||||
@ -1950,8 +1952,9 @@ jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* We need to do a shallow clone of the argument's res field in case the
|
* We need to do a shallow clone of the argument's res field in case the
|
||||||
* final function is called more than once, so we avoid changing the
|
* final function is called more than once, so we avoid changing the
|
||||||
* it. A shallow clone is sufficient as we aren't going to change any of
|
* aggregate state value. A shallow clone is sufficient as we aren't
|
||||||
* the values, just add the final object end marker.
|
* going to change any of the values, just add the final object end
|
||||||
|
* marker.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
result.parseState = clone_parse_state(arg->res->parseState);
|
result.parseState = clone_parse_state(arg->res->parseState);
|
||||||
|
@ -1362,6 +1362,15 @@ SELECT jsonb_build_object(json '{"a":1,"b":2}', 3);
|
|||||||
ERROR: key value must be scalar, not array, composite or json
|
ERROR: key value must be scalar, not array, composite or json
|
||||||
SELECT jsonb_build_object('{1,2,3}'::int[], 3);
|
SELECT jsonb_build_object('{1,2,3}'::int[], 3);
|
||||||
ERROR: key value must be scalar, not array, composite or json
|
ERROR: key value must be scalar, not array, composite or json
|
||||||
|
-- handling of NULL values
|
||||||
|
SELECT jsonb_object_agg(1, NULL::jsonb);
|
||||||
|
jsonb_object_agg
|
||||||
|
------------------
|
||||||
|
{"1": null}
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT jsonb_object_agg(NULL, '{"a":1}');
|
||||||
|
ERROR: field name must not be null
|
||||||
CREATE TEMP TABLE foo (serial_num int, name text, type text);
|
CREATE TEMP TABLE foo (serial_num int, name text, type text);
|
||||||
INSERT INTO foo VALUES (847001,'t15','GE1043');
|
INSERT INTO foo VALUES (847001,'t15','GE1043');
|
||||||
INSERT INTO foo VALUES (847002,'t16','GE1043');
|
INSERT INTO foo VALUES (847002,'t16','GE1043');
|
||||||
|
@ -330,6 +330,10 @@ SELECT jsonb_build_object(json '{"a":1,"b":2}', 3);
|
|||||||
|
|
||||||
SELECT jsonb_build_object('{1,2,3}'::int[], 3);
|
SELECT jsonb_build_object('{1,2,3}'::int[], 3);
|
||||||
|
|
||||||
|
-- handling of NULL values
|
||||||
|
SELECT jsonb_object_agg(1, NULL::jsonb);
|
||||||
|
SELECT jsonb_object_agg(NULL, '{"a":1}');
|
||||||
|
|
||||||
CREATE TEMP TABLE foo (serial_num int, name text, type text);
|
CREATE TEMP TABLE foo (serial_num int, name text, type text);
|
||||||
INSERT INTO foo VALUES (847001,'t15','GE1043');
|
INSERT INTO foo VALUES (847001,'t15','GE1043');
|
||||||
INSERT INTO foo VALUES (847002,'t16','GE1043');
|
INSERT INTO foo VALUES (847002,'t16','GE1043');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user