]> granicus.if.org Git - postgresql/commitdiff
Fix the fastpath rule for jsonb_concat with an empty operand.
authorAndrew Dunstan <andrew@dunslane.net>
Sun, 13 Sep 2015 21:06:45 +0000 (17:06 -0400)
committerAndrew Dunstan <andrew@dunslane.net>
Sun, 13 Sep 2015 21:06:45 +0000 (17:06 -0400)
To prevent perverse results, we now only return the other operand if
it's not scalar, and if both operands are of the same kind (array or
object).

Original bug complaint and patch from Oskari Saarenmaa, extended by me
to cover the cases of different kinds of jsonb.

Backpatch to 9.5 where jsonb_concat was introduced.

src/backend/utils/adt/jsonfuncs.c
src/test/regress/expected/jsonb.out
src/test/regress/expected/jsonb_1.out
src/test/regress/sql/jsonb.sql

index 3b8d42e4d51b7b44e4c9670411ec6071b539cad0..154a8837e1738d578c1ea88a23e1b35cd7e57c78 100644 (file)
@@ -3359,12 +3359,18 @@ jsonb_concat(PG_FUNCTION_ARGS)
                           *it2;
 
        /*
-        * If one of the jsonb is empty, just return other.
+        * If one of the jsonb is empty, just return the other if it's not
+        * scalar and both are of the same kind.  If it's a scalar or they are
+        * of different kinds we need to perform the concatenation even if one is
+        * empty.
         */
-       if (JB_ROOT_COUNT(jb1) == 0)
-               PG_RETURN_JSONB(jb2);
-       else if (JB_ROOT_COUNT(jb2) == 0)
-               PG_RETURN_JSONB(jb1);
+       if (JB_ROOT_IS_OBJECT(jb1) == JB_ROOT_IS_OBJECT(jb2))
+       {
+               if (JB_ROOT_COUNT(jb1) == 0 && !JB_ROOT_IS_SCALAR(jb2))
+                       PG_RETURN_JSONB(jb2);
+               else if (JB_ROOT_COUNT(jb2) == 0 && !JB_ROOT_IS_SCALAR(jb1))
+                       PG_RETURN_JSONB(jb1);
+       }
 
        it1 = JsonbIteratorInit(&jb1->root);
        it2 = JsonbIteratorInit(&jb2->root);
index 17656d4413aed86e29a0361d0f9ca3bb65475a4d..82d1b69bfaa18a4cd12bf9dd5a2818994a4b65da 100644 (file)
@@ -2912,6 +2912,42 @@ select '"c"' || '["a", "b"]'::jsonb;
  ["c", "a", "b"]
 (1 row)
 
+select '[]'::jsonb || '["a"]'::jsonb;
+ ?column? 
+----------
+ ["a"]
+(1 row)
+
+select '[]'::jsonb || '"a"'::jsonb;
+ ?column? 
+----------
+ ["a"]
+(1 row)
+
+select '"b"'::jsonb || '"a"'::jsonb;
+  ?column?  
+------------
+ ["b", "a"]
+(1 row)
+
+select '{}'::jsonb || '{"a":"b"}'::jsonb;
+  ?column?  
+------------
+ {"a": "b"}
+(1 row)
+
+select '[]'::jsonb || '{"a":"b"}'::jsonb;
+   ?column?   
+--------------
+ [{"a": "b"}]
+(1 row)
+
+select '{"a":"b"}'::jsonb || '[]'::jsonb;
+   ?column?   
+--------------
+ [{"a": "b"}]
+(1 row)
+
 select '"a"'::jsonb || '{"a":1}';
 ERROR:  invalid concatenation of jsonb objects
 select '{"a":1}' || '"a"'::jsonb;
index 86b1162ac2946fcc5029e7418e01b75753f7e440..2cbc0c79bba9060d98d1a164b8328cc535c68698 100644 (file)
@@ -2912,6 +2912,42 @@ select '"c"' || '["a", "b"]'::jsonb;
  ["c", "a", "b"]
 (1 row)
 
+select '[]'::jsonb || '["a"]'::jsonb;
+ ?column? 
+----------
+ ["a"]
+(1 row)
+
+select '[]'::jsonb || '"a"'::jsonb;
+ ?column? 
+----------
+ ["a"]
+(1 row)
+
+select '"b"'::jsonb || '"a"'::jsonb;
+  ?column?  
+------------
+ ["b", "a"]
+(1 row)
+
+select '{}'::jsonb || '{"a":"b"}'::jsonb;
+  ?column?  
+------------
+ {"a": "b"}
+(1 row)
+
+select '[]'::jsonb || '{"a":"b"}'::jsonb;
+   ?column?   
+--------------
+ [{"a": "b"}]
+(1 row)
+
+select '{"a":"b"}'::jsonb || '[]'::jsonb;
+   ?column?   
+--------------
+ [{"a": "b"}]
+(1 row)
+
 select '"a"'::jsonb || '{"a":1}';
 ERROR:  invalid concatenation of jsonb objects
 select '{"a":1}' || '"a"'::jsonb;
index 83ed4ebd93f86c0f671fcc2c0cb7b1f71d44c4a6..cb03ada1731d9461586bed21e1fcf47120d15ff4 100644 (file)
@@ -718,6 +718,13 @@ select '["c"]' || '["a", "b"]'::jsonb;
 select '["a", "b"]'::jsonb || '"c"';
 select '"c"' || '["a", "b"]'::jsonb;
 
+select '[]'::jsonb || '["a"]'::jsonb;
+select '[]'::jsonb || '"a"'::jsonb;
+select '"b"'::jsonb || '"a"'::jsonb;
+select '{}'::jsonb || '{"a":"b"}'::jsonb;
+select '[]'::jsonb || '{"a":"b"}'::jsonb;
+select '{"a":"b"}'::jsonb || '[]'::jsonb;
+
 select '"a"'::jsonb || '{"a":1}';
 select '{"a":1}' || '"a"'::jsonb;