[MDEV-26506] Over-quoted JSON when combining JSON_ARRAYAGG with JSON_OBJECT Created: 2021-08-30  Updated: 2023-07-04  Resolved: 2023-01-17

Status: Closed
Project: MariaDB Server
Component/s: JSON
Affects Version/s: 10.5
Fix Version/s: 10.6.3

Type: Bug Priority: Major
Reporter: Valerii Kravchuk Assignee: Sergei Golubchik
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
Blocks
is blocked by MDEV-27018 IF and COALESCE lose "json" property Closed
Relates
relates to MDEV-13701 Nesting JSON Closed
relates to MDEV-16620 Add support for JSON_ARRAYAGG and JSO... Closed
relates to MDEV-21902 Nested JSON_ARRAYAGG in JSON_OBJECT s... Closed
relates to MDEV-27018 IF and COALESCE lose "json" property Closed
relates to MDEV-27666 User variable not parsed as geometry ... Closed

 Description   

Run the following query on a fresh installation of MariaDB 10.6.x:

openxs@ao756:~/dbs/maria10.6$ bin/mysql --socket=/tmp/mariadb.sock
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 6
Server version: 10.6.5-MariaDB MariaDB Server
 
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
 
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 
MariaDB [(none)]> select json_object('attr2', ifnull(u.o, json_array())) j from
mysql.user u1 left join (select user, json_arrayagg(json_object('attr1', user))
as o from mysql.user group by user) u on u1.user = u.user where u1.user = 'root';
+--------------------------------------+
| j                                    |
+--------------------------------------+
| {"attr2": "[{\"attr1\": \"root\"}]"} |
+--------------------------------------+
1 row in set (0.007 sec)

It will return a single row for the "root" user, but note that attributes and values in the array have backslash before the ". While with MySQL:

openxs@ao756:~/dbs/maria10.6$ bin/mysql -uroot --socket=/tmp/maysql8.sock
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 8.0.26 Source distribution
 
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
 
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
 
MySQL [(none)]> select json_object('attr2', ifnull(u.o, json_array())) j from mysql.user u1 left join (select user, json_arrayagg(json_object('attr1', user)) as o from mysql.user group by user) u on u1.user = u.user where u1.user = 'root';
+--------------------------------+
| j                              |
+--------------------------------+
| {"attr2": [{"attr1": "root"}]} |
+--------------------------------+
1 row in set (0.002 sec)

we have expected quoting for the values in the array.

Why is this difference, that I consider a bug in MariaDB?



 Comments   
Comment by Alice Sherepa [ 2021-08-30 ]

MariaDB [test]> select json_object("a",dt.x) from (select json_arrayagg(json_object('a1', 'name')) as x) dt ;
+-------------------------------+
| json_object("a",dt.x)         |
+-------------------------------+
| {"a": "[{\"a1\": \"name\"}]"} |
+-------------------------------+
1 row in set (0.006 sec)
 
MariaDB [test]> select json_object("a",json_arrayagg(json_object('a1', 'name')))  ;
+-----------------------------------------------------------+
| json_object("a",json_arrayagg(json_object('a1', 'name'))) |
+-----------------------------------------------------------+
| {"a": [{"a1": "name"}]}                                   |
+-----------------------------------------------------------+
1 row in set (0.001 sec)
 

I guess this is the same as MDEV-13701.
test from comments there:

MariaDB [test]> SELECT JSON_OBJECT("main", JSON_ARRAY("one", 2));
+-------------------------------------------+
| JSON_OBJECT("main", JSON_ARRAY("one", 2)) |
+-------------------------------------------+
| {"main": ["one", 2]}                      |
+-------------------------------------------+
1 row in set (0.001 sec)
 
MariaDB [test]> SET @sub = JSON_ARRAY("one", 2);
Query OK, 0 rows affected (0.001 sec)
 
MariaDB [test]> SELECT JSON_OBJECT("main", @sub);
+---------------------------+
| JSON_OBJECT("main", @sub) |
+---------------------------+
| {"main": "[\"one\", 2]"}  |
+---------------------------+
1 row in set (0.001 sec)

Comment by Alexander Barkov [ 2021-12-30 ]

Also repeatable with this script:

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a VARCHAR(30));
INSERT INTO t1 VALUES ('root');
SELECT JSON_OBJECT('attr2',o) FROM (SELECT a, json_arrayagg(json_object('attr1', a)) as o FROM t1) u;

+--------------------------------------+
| JSON_OBJECT('attr2',o)               |
+--------------------------------------+
| {"attr2": "[{\"attr1\": \"root\"}]"} |
+--------------------------------------+

Comment by Anders Karlsson [ 2022-05-13 ]

There is a workaround for most of these cases, which is to do a JSON_MERGE() with the offending JSON value that gets treated like a string. So

MariaDB> SELECT JSON_OBJECT('foo', (SELECT JSON_ARRAYAGG(JSON_OBJECT('bar', 1))));
+-------------------------------------------------------------------+
| JSON_OBJECT('foo', (SELECT JSON_ARRAYAGG(JSON_OBJECT('bar', 1)))) |
+-------------------------------------------------------------------+
| {"foo": "[{\"bar\": 1}]"}                                         |
+-------------------------------------------------------------------+

Can be fixed like this:

MariaDB> SELECT JSON_OBJECT('foo', JSON_MERGE('[]', (SELECT JSON_ARRAYAGG(JSON_OBJECT('bar', 1)))));
+-------------------------------------------------------------------------------------+
| JSON_OBJECT('foo', JSON_MERGE('[]', (SELECT JSON_ARRAYAGG(JSON_OBJECT('bar', 1))))) |
+-------------------------------------------------------------------------------------+
| {"foo": [{"bar": 1}]}                                                               |
+-------------------------------------------------------------------------------------+

Comment by Josef Johansson [ 2022-08-23 ]

An interesting fact is that JSON_ARRAYAGG affects JSON_TYPE

CREATE TEMPORARY TABLE temp (id LONG, msg VARCHAR(5) );
 
INSERT INTO temp VALUES
(1, "abcde"),
(2, "bcdea"),
(3, "cdeab"),
(4, "deabc"),
(5, "eabcd");
WITH q1 AS (
		SELECT
		  id,
		  JSON_ARRAY(msg) AS q1a,
		  JSON_ARRAYAGG(msg) AS q1b,
		  JSON_TYPE(JSON_ARRAYAGG(msg)) AS q1c,
		  JSON_TYPE(JSON_ARRAY(msg)) AS q1d
		FROM temp
)
SELECT
  q1c AS s1c,
  JSON_OBJECTAGG(id, q1a) AS s1a,
  q1d AS s1d,
  JSON_OBJECTAGG(id, q1b) AS s1b
FROM q1 \G
 
WITH q2 AS (
		SELECT
		  id,
		  JSON_ARRAY(msg) AS q2a,
		  JSON_TYPE(JSON_ARRAY(msg)) AS q2b,
		  5 AS q2c,
		  JSON_TYPE(5) AS q2d
		FROM temp
)
SELECT
  q2b AS s2b,
  JSON_OBJECTAGG(id, q2a) AS s2a,
  JSON_TYPE(q2c) AS s2c,
  q2d AS s2d
FROM q2 \G
 
WITH q3 AS (
		SELECT
		  id,
		  JSON_ARRAYAGG(msg) AS q3a,
		  JSON_TYPE(JSON_ARRAYAGG(msg)) AS q3b,
		  5 AS q3c,
		  JSON_TYPE(5) AS q3d
		FROM temp
)
SELECT
  q3b AS s3b,
  JSON_OBJECTAGG(id, JSON_MERGE('[]',q3a)) AS s3a,
  JSON_TYPE(q3c) AS s3c,
  q3d AS s3d
FROM q3 \G

*************************** 1. row ***************************
s1c: ARRA
s1a: {"1":"[\"abcde\"]"}
s1d: ARRA
s1b: {"1":"[\"abcde\",\"bcdea\",\"cdeab\",\"deabc\",\"eabcd\"]"}
*************************** 1. row ***************************
s2b: ARRAY
s2a: {"1":["abcde"], "2":["bcdea"], "3":["cdeab"], "4":["deabc"], "5":["eabcd"]}
s2c: INTEGER
s2d: INTEGER
*************************** 1. row ***************************
s3b: ARRA
s3a: {"1":["abcde", "bcdea", "cdeab", "deabc", "eabcd"]}
s3c: INTEGER
s3d: INTE

Could it be that JSON_OBJECTAGG is not detecting it as an ARRAY?

Comment by Sergei Golubchik [ 2023-01-17 ]

Already fixed in 10.6 in commit add782a13e5

Generated at Thu Feb 08 09:45:49 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.