summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Dunstan2015-09-13 21:06:45 +0000
committerAndrew Dunstan2015-09-13 21:06:45 +0000
commite7e3ac2d51130d707792e657facc58c160182342 (patch)
treea7cd0a0c1b4ffe25c4062bacd108d00d4a66d8f5 /src
parentc193b8ca9d05e8167b6deb057c06a7580fa517a3 (diff)
Fix the fastpath rule for jsonb_concat with an empty operand.
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/utils/adt/jsonfuncs.c16
-rw-r--r--src/test/regress/expected/jsonb.out36
-rw-r--r--src/test/regress/expected/jsonb_1.out36
-rw-r--r--src/test/regress/sql/jsonb.sql7
4 files changed, 90 insertions, 5 deletions
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 3b8d42e4d51..154a8837e17 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -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);
diff --git a/src/test/regress/expected/jsonb.out b/src/test/regress/expected/jsonb.out
index 17656d4413a..82d1b69bfaa 100644
--- a/src/test/regress/expected/jsonb.out
+++ b/src/test/regress/expected/jsonb.out
@@ -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;
diff --git a/src/test/regress/expected/jsonb_1.out b/src/test/regress/expected/jsonb_1.out
index 86b1162ac29..2cbc0c79bba 100644
--- a/src/test/regress/expected/jsonb_1.out
+++ b/src/test/regress/expected/jsonb_1.out
@@ -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;
diff --git a/src/test/regress/sql/jsonb.sql b/src/test/regress/sql/jsonb.sql
index 83ed4ebd93f..cb03ada1731 100644
--- a/src/test/regress/sql/jsonb.sql
+++ b/src/test/regress/sql/jsonb.sql
@@ -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;