Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-27018

IF and COALESCE lose "json" property

Details

    • Bug
    • Status: Closed (View Workflow)
    • Critical
    • Resolution: Fixed
    • 10.2(EOL), 10.3(EOL), 10.4(EOL), 10.5, 10.6
    • 10.5.14, 10.6.6, 10.7.2, 10.8.1
    • JSON
    • None

    Description

      MariaDB [test]> select json_object('a', json_object('b', 'c'));
      +-----------------------------------------+
      | json_object('a', json_object('b', 'c')) |
      +-----------------------------------------+
      | {"a": {"b": "c"}}                       |
      +-----------------------------------------+
      1 row in set (0.000 sec)
       
      MariaDB [test]> select json_object('a', if(1, json_object('b', 'c'), json_object('e', 'f')));
      +-----------------------------------------------------------------------+
      | json_object('a', if(1, json_object('b', 'c'), json_object('e', 'f'))) |
      +-----------------------------------------------------------------------+
      | {"a": "{\"b\": \"c\"}"}                                               |
      +-----------------------------------------------------------------------+
      1 row in set (0.001 sec)
       
      MariaDB [test]> select json_object('a', coalesce(json_object('b', 'c')));
      +---------------------------------------------------+
      | json_object('a', coalesce(json_object('b', 'c'))) |
      +---------------------------------------------------+
      | {"a": "{\"b\": \"c\"}"}                           |
      +---------------------------------------------------+
      1 row in set (0.000 sec)
      

      other functions (CASE, NULLIF, IFNULL) are likely affected too.

      Attachments

        Issue Links

          Activity

            serg Sergei Golubchik created issue -
            serg Sergei Golubchik made changes -
            Field Original Value New Value
            Priority Major [ 3 ] Critical [ 2 ]
            salle Alexander Keremidarski added a comment - - edited

            It seems all string functions are affected including no-op functions like CONCAT(x) and LOWER(x)

            ariaDB [test]> SELECT JSON_OBJECT('a', CONCAT(JSON_OBJECT('b', 'c')));
            +-------------------------------------------------+
            | JSON_OBJECT('a', CONCAT(JSON_OBJECT('b', 'c'))) |
            +-------------------------------------------------+
            | {"a": "{\"b\": \"c\"}"}                         |
            +-------------------------------------------------+
            1 row in set (0.000 sec)
             
            MariaDB [test]> SELECT JSON_OBJECT('a', LOWER(JSON_OBJECT('b', 'c')));
            +------------------------------------------------+
            | JSON_OBJECT('a', LOWER(JSON_OBJECT('b', 'c'))) |
            +------------------------------------------------+
            | {"a": "{\"b\": \"c\"}"}                        |
            +------------------------------------------------+
            1 row in set (0.000 sec)
            

            salle Alexander Keremidarski added a comment - - edited It seems all string functions are affected including no-op functions like CONCAT(x) and LOWER(x) ariaDB [test]> SELECT JSON_OBJECT( 'a' , CONCAT(JSON_OBJECT( 'b' , 'c' ))); + -------------------------------------------------+ | JSON_OBJECT( 'a' , CONCAT(JSON_OBJECT( 'b' , 'c' ))) | + -------------------------------------------------+ | { "a" : "{\"b\": \"c\"}" } | + -------------------------------------------------+ 1 row in set (0.000 sec)   MariaDB [test]> SELECT JSON_OBJECT( 'a' , LOWER (JSON_OBJECT( 'b' , 'c' ))); + ------------------------------------------------+ | JSON_OBJECT( 'a' , LOWER (JSON_OBJECT( 'b' , 'c' ))) | + ------------------------------------------------+ | { "a" : "{\"b\": \"c\"}" } | + ------------------------------------------------+ 1 row in set (0.000 sec)

            On the contrary, these two are not bugs, as explained in this comment.

            CONCAT(x) and LOWER(x) are not "no-op functions". Try

            CREATE TABLE t AS SELECT 1, CONCAT(1), LOWER(1);
            SHOW CREATE TABLE t;
            

            and you will see that CONCAT and LOWER change the argument, they convert it to a string. So, when you use CONCAT(json), this JSON value becomes a plain string, not a structured data type. It loses its "json-ness". And a plain string is correctly escaped when used as a JSON value.

            serg Sergei Golubchik added a comment - On the contrary, these two are not bugs, as explained in this comment . CONCAT(x) and LOWER(x) are not "no-op functions". Try CREATE TABLE t AS SELECT 1, CONCAT(1), LOWER (1); SHOW CREATE TABLE t; and you will see that CONCAT and LOWER change the argument, they convert it to a string. So, when you use CONCAT(json), this JSON value becomes a plain string, not a structured data type. It loses its "json-ness". And a plain string is correctly escaped when used as a JSON value.
            serg Sergei Golubchik made changes -
            bar Alexander Barkov made changes -
            Status Open [ 1 ] Confirmed [ 10101 ]

            julien.fritsch, yes this is a bug. I've marked it as Confirmed.

            bar Alexander Barkov added a comment - julien.fritsch , yes this is a bug. I've marked it as Confirmed.
            serg Sergei Golubchik made changes -
            Workflow MariaDB v3 [ 127273 ] MariaDB v4 [ 144427 ]
            bar Alexander Barkov added a comment - - edited

            More bad behavior examples

            Single row subselect

            SELECT json_objectagg(b, c) FROM (SELECT 'b','c') d;
            

            +----------------------+
            | json_objectagg(b, c) |
            +----------------------+
            | {"b":"c"}            |
            +----------------------+
            

            Looks good so far.

            Now I pass the same statement as a subselect to abother json_object:

            SELECT json_object('a', (SELECT json_objectagg(b, c) FROM (SELECT 'b','c') d)) AS j FROM DUAL;
            

            +------------------------+
            | j                      |
            +------------------------+
            | {"a": "{\"b\":\"c\"}"} |
            +------------------------+
            

            The value was erroneously escaped.

            If I run similar queries in Oracle, the value does not get escaped:

            SELECT json_objectagg(b, c) FROM (SELECT 'b' AS b,'c' AS c FROM DUAL) d;
            SELECT json_object('a' VALUE (SELECT json_objectagg(b, c) FROM (SELECT 'b' AS b,'c' AS c FROM DUAL) d)) FROM DUAL;
            

            JSON_OBJECTAGG(B,C)
            {"b" : "c"}
            

            JSON_OBJECT('A'VALUE(SELECTJSON_OBJECTAGG(B,C)FROM(SELECT'B'ASB,'C'ASCFROMDUAL)D))
            {"a" : {"b" : "c"}}
            

            UNION

            It's now reported as a separate issue MDEV-27370

            bar Alexander Barkov added a comment - - edited More bad behavior examples Single row subselect SELECT json_objectagg(b, c) FROM ( SELECT 'b' , 'c' ) d; +----------------------+ | json_objectagg(b, c) | +----------------------+ | {"b":"c"} | +----------------------+ Looks good so far. Now I pass the same statement as a subselect to abother json_object: SELECT json_object( 'a' , ( SELECT json_objectagg(b, c) FROM ( SELECT 'b' , 'c' ) d)) AS j FROM DUAL; +------------------------+ | j | +------------------------+ | {"a": "{\"b\":\"c\"}"} | +------------------------+ The value was erroneously escaped. If I run similar queries in Oracle, the value does not get escaped: SELECT json_objectagg(b, c) FROM ( SELECT 'b' AS b, 'c' AS c FROM DUAL) d; SELECT json_object( 'a' VALUE ( SELECT json_objectagg(b, c) FROM ( SELECT 'b' AS b, 'c' AS c FROM DUAL) d)) FROM DUAL; JSON_OBJECTAGG(B,C) {"b" : "c"} JSON_OBJECT('A'VALUE(SELECTJSON_OBJECTAGG(B,C)FROM(SELECT'B'ASB,'C'ASCFROMDUAL)D)) {"a" : {"b" : "c"}} UNION It's now reported as a separate issue MDEV-27370
            bar Alexander Barkov made changes -
            bar Alexander Barkov made changes -
            bar Alexander Barkov made changes -
            bar Alexander Barkov made changes -
            bar Alexander Barkov made changes -
            bar Alexander Barkov made changes -
            bar Alexander Barkov made changes -
            Status Confirmed [ 10101 ] In Progress [ 3 ]
            bar Alexander Barkov added a comment - serg , please review a patch: https://github.com/MariaDB/server/commit/734aee3cd3c59bb9a9050f32db406803f8237320 or can be found in this branch: https://github.com/mariadb/server/tree/bb-10.5-bar-MDEV-27018 Thanks.
            bar Alexander Barkov made changes -
            Assignee Alexander Barkov [ bar ] Sergei Golubchik [ serg ]
            Status In Progress [ 3 ] In Review [ 10002 ]
            serg Sergei Golubchik made changes -
            Assignee Sergei Golubchik [ serg ] Alexander Barkov [ bar ]
            Status In Review [ 10002 ] Stalled [ 10000 ]

            serg, I replied to your review comments by email. Please have a look.

            bar Alexander Barkov added a comment - serg , I replied to your review comments by email. Please have a look.
            bar Alexander Barkov made changes -
            Status Stalled [ 10000 ] In Review [ 10002 ]
            bar Alexander Barkov made changes -
            serg Sergei Golubchik made changes -
            Assignee Alexander Barkov [ bar ] Sergei Golubchik [ serg ]
            serg Sergei Golubchik made changes -
            Assignee Sergei Golubchik [ serg ] Alexander Barkov [ bar ]
            Status In Review [ 10002 ] Stalled [ 10000 ]
            bar Alexander Barkov made changes -
            bar Alexander Barkov made changes -
            Assignee Alexander Barkov [ bar ] Sergei Golubchik [ serg ]
            Status Stalled [ 10000 ] In Review [ 10002 ]

            0478f474020466 is ok to push

            serg Sergei Golubchik added a comment - 0478f474020466 is ok to push
            serg Sergei Golubchik made changes -
            Assignee Sergei Golubchik [ serg ] Alexander Barkov [ bar ]
            Status In Review [ 10002 ] Stalled [ 10000 ]
            bar Alexander Barkov made changes -
            issue.field.resolutiondate 2022-01-21 17:13:10.0 2022-01-21 17:13:10.371
            bar Alexander Barkov made changes -
            Fix Version/s 10.5.14 [ 26809 ]
            Fix Version/s 10.6.6 [ 26811 ]
            Fix Version/s 10.7.2 [ 26813 ]
            Fix Version/s 10.8.1 [ 26815 ]
            Fix Version/s 10.2 [ 14601 ]
            Fix Version/s 10.3 [ 22126 ]
            Fix Version/s 10.4 [ 22408 ]
            Fix Version/s 10.5 [ 23123 ]
            Fix Version/s 10.6 [ 24028 ]
            Resolution Fixed [ 1 ]
            Status Stalled [ 10000 ] Closed [ 6 ]
            bar Alexander Barkov made changes -
            bar Alexander Barkov made changes -
            Comment [ This script:

            {code:sql}
            SET profiling=1;
            SET profiling_history_size=1;

            CREATE OR REPLACE TABLE stat (state TEXT, types TEXT);

            CREATE OR REPLACE TABLE t1 (a TEXT);
            ALTER TABLE t1 MODIFY a JSON;
            INSERT INTO stat
            SELECT state, '1. TEXT to JSON' AS types FROM INFORMATION_SCHEMA.PROFILING WHERE state LIKE 'Copy to tmp table';

            ALTER TABLE t1 MODIFY a JSON;
            INSERT INTO stat
            SELECT state, '2. JSON to JSON' AS types FROM INFORMATION_SCHEMA.PROFILING WHERE state LIKE 'Copy to tmp table';

            ALTER TABLE t1 MODIFY a TEXT;
            INSERT INTO stat
            SELECT state, '3. JSON to TEXT' AS types FROM INFORMATION_SCHEMA.PROFILING WHERE state LIKE 'Copy to tmp table';

            ALTER TABLE t1 MODIFY a TEXT;
            INSERT INTO stat
            SELECT state, '4. TEXT to TEXT' AS types FROM INFORMATION_SCHEMA.PROFILING WHERE state LIKE 'Copy to tmp table';

            SELECT state, types FROM stat;
            {code}

            in 10.4.26 returns:

            {noformat}
            +-------------------+-----------------+
            | state | types |
            +-------------------+-----------------+
            | Copy to tmp table | 1. TEXT to JSON |
            | Copy to tmp table | 1. TEXT to JSON |
            | Copy to tmp table | 2. JSON to JSON |
            | Copy to tmp table | 2. JSON to JSON |
            | Copy to tmp table | 3. JSON to TEXT |
            | Copy to tmp table | 3. JSON to TEXT |
            +-------------------+-----------------
            {noformat}

            in 10.5.17 returns:
            {noformat}
            +-------------------+-----------------+
            | state | types |
            +-------------------+-----------------+
            | copy to tmp table | 1. TEXT to JSON |
            | copy to tmp table | 3. JSON to TEXT |
            +-------------------+-----------------+
            {noformat}

            Temporary table JSON->JSON conversion:
            - is created in 10.4.26
            - is not created in 10.5.17
            ]
            bar Alexander Barkov made changes -
            mariadb-jira-automation Jira Automation (IT) made changes -
            Zendesk Related Tickets 176096

            People

              bar Alexander Barkov
              serg Sergei Golubchik
              Votes:
              2 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.