Fix JSON_OBJECTAGG uniquefying bug
authorAndrew Dunstan <[email protected]>
Thu, 28 Apr 2022 19:28:20 +0000 (15:28 -0400)
committerAndrew Dunstan <[email protected]>
Thu, 28 Apr 2022 19:28:20 +0000 (15:28 -0400)
Commit f4fb45d15c contained a bug in removing items with null values when
unique keys are required, where the leading items that are sorted
contained such values. Fix that and add a test for it.

Discussion: https://postgr.es/m/CAJA4AWQ_XbSmsNbW226UqNyRLJ+wb=iQkQMj77cQyoNkqtf=2Q@mail.gmail.com

src/backend/utils/adt/jsonb_util.c
src/test/regress/expected/sqljson.out
src/test/regress/sql/sqljson.sql

index aa151a53d61e84d4f27598e0e4e82d685774f8df..21d874c098a28b6c919edf8c8221a82935e4529a 100644 (file)
@@ -1959,8 +1959,18 @@ uniqueifyJsonbObject(JsonbValue *object, bool unique_keys, bool skip_nulls)
 
        if (hasNonUniq || skip_nulls)
        {
-               JsonbPair  *ptr = object->val.object.pairs + 1,
-                                  *res = object->val.object.pairs;
+               JsonbPair  *ptr, *res;
+
+               while (skip_nulls && object->val.object.nPairs > 0 &&
+                          object->val.object.pairs->value.type == jbvNull)
+               {
+                       /* If skip_nulls is true, remove leading items with null */
+                       object->val.object.pairs++;
+                       object->val.object.nPairs--;
+               }
+
+               ptr = object->val.object.pairs + 1;
+               res = object->val.object.pairs;
 
                while (ptr - object->val.object.pairs < object->val.object.nPairs)
                {
index 97a72be970c36d91aab69f5018b08675bd4fd198..0883261535d8697f171209e03d653a1c7edc9a4c 100644 (file)
@@ -944,6 +944,13 @@ 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(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);
+  json_objectagg  
+------------------
+ {"1": 1, "2": 2}
+(1 row)
+
 -- Test JSON_OBJECT deparsing
 EXPLAIN (VERBOSE, COSTS OFF)
 SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);
index b422ded97800d6b7f45f577cfdf21d911422bf29..3db81a7ba861bd6fecb951325695aeacc69a08ef 100644 (file)
@@ -281,6 +281,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(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);
+
 -- Test JSON_OBJECT deparsing
 EXPLAIN (VERBOSE, COSTS OFF)
 SELECT JSON_OBJECT('foo' : '1' FORMAT JSON, 'bar' : 'baz' RETURNING json);