aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/json.c20
-rw-r--r--src/test/regress/expected/json.out3
-rw-r--r--src/test/regress/expected/sqljson.out5
-rw-r--r--src/test/regress/sql/json.sql2
-rw-r--r--src/test/regress/sql/sqljson.sql5
5 files changed, 32 insertions, 3 deletions
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 4eeeeaf0a60..058aade2af4 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -1111,7 +1111,14 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
if (unique_keys)
{
- const char *key = &out->data[key_offset];
+ /*
+ * Copy the key first, instead of pointing into the buffer. It will be
+ * added to the hash table, but the buffer may get reallocated as
+ * we're appending more data to it. That would invalidate pointers to
+ * keys in the current buffer.
+ */
+ const char *key = MemoryContextStrdup(aggcontext,
+ &out->data[key_offset]);
if (!json_unique_check_key(&state->unique_check.check, key, 0))
ereport(ERROR,
@@ -1274,8 +1281,15 @@ json_build_object_worker(int nargs, const Datum *args, const bool *nulls, const
if (unique_keys)
{
- /* check key uniqueness after key appending */
- const char *key = &out->data[key_offset];
+ /*
+ * check key uniqueness after key appending
+ *
+ * Copy the key first, instead of pointing into the buffer. It
+ * will be added to the hash table, but the buffer may get
+ * reallocated as we're appending more data to it. That would
+ * invalidate pointers to keys in the current buffer.
+ */
+ const char *key = pstrdup(&out->data[key_offset]);
if (!json_unique_check_key(&unique_check.check, key, 0))
ereport(ERROR,
diff --git a/src/test/regress/expected/json.out b/src/test/regress/expected/json.out
index 7df11c2f385..96c40911cb9 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -2330,6 +2330,9 @@ select json_object('{a,b,"","d e f"}','{1,2,3,"a b c"}');
{"a" : "1", "b" : "2", "" : "3", "d e f" : "a b c"}
(1 row)
+-- json_object_agg_unique requires unique keys
+select json_object_agg_unique(mod(i,100), i) from generate_series(0, 199) i;
+ERROR: duplicate JSON object key value: "0"
-- json_to_record and json_to_recordset
select * from json_to_record('{"a":1,"b":"foo","c":"bar"}')
as x(a int, b text, d text);
diff --git a/src/test/regress/expected/sqljson.out b/src/test/regress/expected/sqljson.out
index 4f91e2117ef..9adfbe15f65 100644
--- a/src/test/regress/expected/sqljson.out
+++ b/src/test/regress/expected/sqljson.out
@@ -537,6 +537,8 @@ SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 ABSENT ON NULL);
{"a" : "1", "c" : 2}
(1 row)
+SELECT JSON_OBJECT(1: 1, '2': NULL, '3': 1, repeat('x', 1000): 1, 2: repeat('a', 100) WITH UNIQUE);
+ERROR: duplicate JSON object key value: "2"
SELECT JSON_OBJECT(1: 1, '1': NULL WITH UNIQUE);
ERROR: duplicate JSON object key value: "1"
SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE);
@@ -921,6 +923,9 @@ FROM (VALUES (1, 1), (0, NULL),(4, null), (5, null),(6, null),(2, 2)) foo(k, v);
{"1": 1, "2": 2}
(1 row)
+SELECT JSON_OBJECTAGG(mod(i,100): (i)::text FORMAT JSON WITH UNIQUE)
+FROM generate_series(0, 199) i;
+ERROR: duplicate JSON object key value: "0"
-- Test JSON_OBJECT deparsing
EXPLAIN (VERBOSE, COSTS OFF)
SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);
diff --git a/src/test/regress/sql/json.sql b/src/test/regress/sql/json.sql
index 5c886cd6b33..8251f4f4006 100644
--- a/src/test/regress/sql/json.sql
+++ b/src/test/regress/sql/json.sql
@@ -755,6 +755,8 @@ select json_object('{a,b,NULL,"d e f"}','{1,2,3,"a b c"}');
select json_object('{a,b,"","d e f"}','{1,2,3,"a b c"}');
+-- json_object_agg_unique requires unique keys
+select json_object_agg_unique(mod(i,100), i) from generate_series(0, 199) i;
-- json_to_record and json_to_recordset
diff --git a/src/test/regress/sql/sqljson.sql b/src/test/regress/sql/sqljson.sql
index bb2487e8649..42dbec26d6f 100644
--- a/src/test/regress/sql/sqljson.sql
+++ b/src/test/regress/sql/sqljson.sql
@@ -138,6 +138,8 @@ SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2);
SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 NULL ON NULL);
SELECT JSON_OBJECT('a': '1', 'b': NULL, 'c': 2 ABSENT ON NULL);
+SELECT JSON_OBJECT(1: 1, '2': NULL, '3': 1, repeat('x', 1000): 1, 2: repeat('a', 100) WITH UNIQUE);
+
SELECT JSON_OBJECT(1: 1, '1': NULL WITH UNIQUE);
SELECT JSON_OBJECT(1: 1, '1': NULL ABSENT ON NULL WITH UNIQUE);
SELECT JSON_OBJECT(1: 1, '1': NULL NULL ON NULL WITH UNIQUE RETURNING jsonb);
@@ -283,6 +285,9 @@ FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb)
FROM (VALUES (1, 1), (0, NULL),(4, null), (5, null),(6, null),(2, 2)) foo(k, v);
+SELECT JSON_OBJECTAGG(mod(i,100): (i)::text FORMAT JSON WITH UNIQUE)
+FROM generate_series(0, 199) i;
+
-- Test JSON_OBJECT deparsing
EXPLAIN (VERBOSE, COSTS OFF)
SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);