Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 112fdb3

Browse files
committed
Fix finalization for json_objectagg and friends
Commit f4fb45d misguidedly tried to free some state during aggregate finalization for json_objectagg. This resulted in attempts to access freed memory, especially when the function is used as a window function. Commit 4eb9798 attempted to ameliorate that, but in fact it should just be ripped out, which is done here. Also add some regression tests for json_objectagg in various flavors as a window function. Original report from Jaime Casanova, diagnosis by Andres Freund. Discussion: https://postgr.es/m/YkfeMNYRCGhySKyg@ahch-to
1 parent a038679 commit 112fdb3

File tree

3 files changed

+53
-12
lines changed

3 files changed

+53
-12
lines changed

src/backend/utils/adt/json.c

-12
Original file line numberDiff line numberDiff line change
@@ -1002,13 +1002,6 @@ json_unique_builder_init(JsonUniqueBuilderState *cxt)
10021002
cxt->skipped_keys.data = NULL;
10031003
}
10041004

1005-
static void
1006-
json_unique_builder_clean(JsonUniqueBuilderState *cxt)
1007-
{
1008-
if (cxt->skipped_keys.data)
1009-
resetStringInfo(&cxt->skipped_keys);
1010-
}
1011-
10121005
/* On-demand initialization of skipped_keys StringInfo structure */
10131006
static StringInfo
10141007
json_unique_builder_get_skipped_keys(JsonUniqueBuilderState *cxt)
@@ -1216,8 +1209,6 @@ json_object_agg_finalfn(PG_FUNCTION_ARGS)
12161209
if (state == NULL)
12171210
PG_RETURN_NULL();
12181211

1219-
json_unique_builder_clean(&state->unique_check);
1220-
12211212
/* Else return state with appropriate object terminator added */
12221213
PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, " }"));
12231214
}
@@ -1324,9 +1315,6 @@ json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
13241315

13251316
appendStringInfoChar(result, '}');
13261317

1327-
if (unique_keys)
1328-
json_unique_builder_clean(&unique_check);
1329-
13301318
return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
13311319
}
13321320

src/test/regress/expected/sqljson.out

+35
Original file line numberDiff line numberDiff line change
@@ -959,6 +959,41 @@ SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);
959959
CREATE OR REPLACE VIEW public.json_object_view AS
960960
SELECT JSON_OBJECT('foo' : '1'::text FORMAT JSON, 'bar' : 'baz'::text RETURNING json) AS "json_object"
961961
DROP VIEW json_object_view;
962+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k)
963+
FROM (VALUES (1,1), (2,2)) a(k,v);
964+
a | json_objectagg
965+
---------------+----------------------
966+
{"k":1,"v":1} | { "1" : 1 }
967+
{"k":2,"v":2} | { "1" : 1, "2" : 2 }
968+
(2 rows)
969+
970+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k)
971+
FROM (VALUES (1,1), (1,2), (2,2)) a(k,v);
972+
ERROR: duplicate JSON key "1"
973+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL WITH UNIQUE KEYS)
974+
OVER (ORDER BY k)
975+
FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
976+
ERROR: duplicate JSON key "1"
977+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL)
978+
OVER (ORDER BY k)
979+
FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
980+
a | json_objectagg
981+
------------------+----------------------
982+
{"k":1,"v":1} | { "1" : 1 }
983+
{"k":1,"v":null} | { "1" : 1 }
984+
{"k":2,"v":2} | { "1" : 1, "2" : 2 }
985+
(3 rows)
986+
987+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL)
988+
OVER (ORDER BY k RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
989+
FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
990+
a | json_objectagg
991+
------------------+----------------------
992+
{"k":1,"v":1} | { "1" : 1, "2" : 2 }
993+
{"k":1,"v":null} | { "1" : 1, "2" : 2 }
994+
{"k":2,"v":2} | { "1" : 1, "2" : 2 }
995+
(3 rows)
996+
962997
-- Test JSON_ARRAY deparsing
963998
EXPLAIN (VERBOSE, COSTS OFF)
964999
SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json);

src/test/regress/sql/sqljson.sql

+18
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,24 @@ SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);
292292

293293
DROP VIEW json_object_view;
294294

295+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k)
296+
FROM (VALUES (1,1), (2,2)) a(k,v);
297+
298+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v WITH UNIQUE KEYS) OVER (ORDER BY k)
299+
FROM (VALUES (1,1), (1,2), (2,2)) a(k,v);
300+
301+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL WITH UNIQUE KEYS)
302+
OVER (ORDER BY k)
303+
FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
304+
305+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL)
306+
OVER (ORDER BY k)
307+
FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
308+
309+
SELECT to_json(a) AS a, JSON_OBJECTAGG(k : v ABSENT ON NULL)
310+
OVER (ORDER BY k RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
311+
FROM (VALUES (1,1), (1,null), (2,2)) a(k,v);
312+
295313
-- Test JSON_ARRAY deparsing
296314
EXPLAIN (VERBOSE, COSTS OFF)
297315
SELECT JSON_ARRAY('1' FORMAT JSON, 2 RETURNING json);

0 commit comments

Comments
 (0)