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 7205f4adca8..fab747789ab 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -1181,7 +1181,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,
@@ -1343,8 +1350,15 @@ json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
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 aa29bc597bd..d16c067b22f 100644
--- a/src/test/regress/expected/json.out
+++ b/src/test/regress/expected/json.out
@@ -2282,6 +2282,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 fa2abdb4a7f..ff75ea78ee6 100644
--- a/src/test/regress/expected/sqljson.out
+++ b/src/test/regress/expected/sqljson.out
@@ -247,6 +247,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);
@@ -624,6 +626,9 @@ ERROR: duplicate JSON object key value
SELECT JSON_OBJECTAGG(k: v ABSENT ON NULL WITH UNIQUE KEYS RETURNING jsonb)
FROM (VALUES (1, 1), (1, NULL), (2, 2)) foo(k, v);
ERROR: duplicate JSON object key value
+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 ec57dfe7070..50b4ed67435 100644
--- a/src/test/regress/sql/json.sql
+++ b/src/test/regress/sql/json.sql
@@ -748,6 +748,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 4fd820fd515..6fbcdeed61c 100644
--- a/src/test/regress/sql/sqljson.sql
+++ b/src/test/regress/sql/sqljson.sql
@@ -74,6 +74,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);
@@ -216,6 +218,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), (1, 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);