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

IF() function consults 3rd argument to determine result display

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Not a Bug
    • Affects Version/s: 5.5.33a, 5.3.13, 10.0, 5.5
    • Fix Version/s: 5.5.41
    • Component/s: OTHER
    • Labels:
      None

      Description

      In MariaDB, it seems that the 3rd argument of the IF() function is consulted to determine how a DECIMAL result is zero-padded when sent back to the client. The behavior is different in MySQL. For example:

      In MySQL:

      mysql 5.6.21-log (root) [test]> SELECT IF (1=1, ROUND(0.123451, 3), ROUND(0.123451, 5)) as result;
      --------------
      SELECT IF (1=1, ROUND(0.123451, 3), ROUND(0.123451, 5)) as result
      --------------
      
      Field   1:  `result`
      Catalog:    `def`
      Database:   ``
      Table:      ``
      Org_table:  ``
      Type:       NEWDECIMAL
      Collation:  binary (63)
      Length:     9
      Max_length: 5
      Decimals:   5
      Flags:      NOT_NULL BINARY NUM
      
      +--------+
      | result |
      +--------+
      |  0.123 |
      +--------+
      1 row in set (0.00 sec)
      

      And in MariaDB:

      mysql 10.0.13-MariaDB-log (root) [test]> SELECT IF (1=1, ROUND(0.123451, 3), ROUND(0.123451, 5)) as result;
      --------------
      SELECT IF (1=1, ROUND(0.123451, 3), ROUND(0.123451, 5)) as result
      --------------
      
      Field   1:  `result`
      Catalog:    `def`
      Database:   ``
      Table:      ``
      Org_table:  ``
      Type:       NEWDECIMAL
      Collation:  binary (63)
      Length:     9
      Max_length: 7
      Decimals:   5
      Flags:      NOT_NULL BINARY NUM
      
      +---------+
      | result  |
      +---------+
      | 0.12300 |
      +---------+
      1 row in set (0.00 sec)
      

        Gliffy Diagrams

          Attachments

            Activity

            Hide
            elenst Elena Stepanova added a comment - - edited

            The problem was introduced in 5.3 tree (and further in 5.5.33 and 10.0.5) with the following revision:

            revno: 3689
            revision-id: bar@mnogosearch.org-20130909113225-k56ivrazr3wq1up4
            parent: igor@askmonty.org-20130906165532-5v2ybq2t8f0o9pke
            committer: Alexander Barkov <bar@mnogosearch.org>
            branch nick: maria-5.3.b4863
            timestamp: Mon 2013-09-09 15:32:25 +0400
            message:
              MDEV-4863 COALESCE(time_or_datetime) returns wrong results in numeric context
            
            Show
            elenst Elena Stepanova added a comment - - edited The problem was introduced in 5.3 tree (and further in 5.5.33 and 10.0.5) with the following revision: revno: 3689 revision-id: bar@mnogosearch.org-20130909113225-k56ivrazr3wq1up4 parent: igor@askmonty.org-20130906165532-5v2ybq2t8f0o9pke committer: Alexander Barkov <bar@mnogosearch.org> branch nick: maria-5.3.b4863 timestamp: Mon 2013-09-09 15:32:25 +0400 message: MDEV-4863 COALESCE(time_or_datetime) returns wrong results in numeric context
            Hide
            bar Alexander Barkov added a comment -

            MDEV-4863 was an intentional change, to make behaviour more consistent in different context, and closer to the standard.
            All control functions that are CASE abbreviations, including IF, now aggregate the return choice arguments in the same way, even if the switch argument is a constant.

            Behaviour before the fix was inconsistent:

            mysql> SELECT IF(1=1,ROUND(0.123451, 3), ROUND(0.123451, 5)) AS `IF`, COALESCE (ROUND(0.123451,3),ROUND(0.123451, 5)) AS `COALESCE`, CASE WHEN 1 THEN ROUND(0.123451, 3) ELSE  ROUND(0.123451, 5) END AS `CASE`,IFNULL(ROUND(0.123451, 3), ROUND(0.123451, 5)) AS `IFNULL`;
            +-------+----------+-------+---------+
            | IF    | COALESCE | CASE  | IFNULL  |
            +-------+----------+-------+---------+
            | 0.123 |  0.12300 | 0.123 | 0.12300 |
            +-------+----------+-------+---------+
            

            Notice, all these expressions effectively return the first argument,
            but the output format was different.

            Behaviour after the fix:

            mysql> SELECT IF(1=1,ROUND(0.123451, 3), ROUND(0.123451, 5)) AS `IF`, COALESCE (ROUND(0.123451,3),ROUND(0.123451, 5)) AS `COALESCE`, CASE WHEN 1 THEN ROUND(0.123451, 3) ELSE  ROUND(0.123451, 5) END AS `CASE`,IFNULL(ROUND(0.123451, 3), ROUND(0.123451, 5)) AS `IFNULL`;
            +---------+----------+---------+---------+
            | IF      | COALESCE | CASE    | IFNULL  |
            +---------+----------+---------+---------+
            | 0.12300 |  0.12300 | 0.12300 | 0.12300 |
            +---------+----------+---------+---------+
            

            All CASE and its abbreviations return exactly the same result.

            Show
            bar Alexander Barkov added a comment - MDEV-4863 was an intentional change, to make behaviour more consistent in different context, and closer to the standard. All control functions that are CASE abbreviations, including IF, now aggregate the return choice arguments in the same way, even if the switch argument is a constant. Behaviour before the fix was inconsistent: mysql> SELECT IF(1=1,ROUND(0.123451, 3), ROUND(0.123451, 5)) AS `IF`, COALESCE (ROUND(0.123451,3),ROUND(0.123451, 5)) AS `COALESCE`, CASE WHEN 1 THEN ROUND(0.123451, 3) ELSE ROUND(0.123451, 5) END AS `CASE`,IFNULL(ROUND(0.123451, 3), ROUND(0.123451, 5)) AS `IFNULL`; +-------+----------+-------+---------+ | IF | COALESCE | CASE | IFNULL | +-------+----------+-------+---------+ | 0.123 | 0.12300 | 0.123 | 0.12300 | +-------+----------+-------+---------+ Notice, all these expressions effectively return the first argument, but the output format was different. Behaviour after the fix: mysql> SELECT IF(1=1,ROUND(0.123451, 3), ROUND(0.123451, 5)) AS `IF`, COALESCE (ROUND(0.123451,3),ROUND(0.123451, 5)) AS `COALESCE`, CASE WHEN 1 THEN ROUND(0.123451, 3) ELSE ROUND(0.123451, 5) END AS `CASE`,IFNULL(ROUND(0.123451, 3), ROUND(0.123451, 5)) AS `IFNULL`; +---------+----------+---------+---------+ | IF | COALESCE | CASE | IFNULL | +---------+----------+---------+---------+ | 0.12300 | 0.12300 | 0.12300 | 0.12300 | +---------+----------+---------+---------+ All CASE and its abbreviations return exactly the same result.
            Hide
            bar Alexander Barkov added a comment -

            Intentional behaviour change.

            Show
            bar Alexander Barkov added a comment - Intentional behaviour change.
            Hide
            fredipusrex Fred Rexon added a comment -

            The expected and documented behavior of ROUND(nnn, x) is to return a string with x number of decimals, not x number of decimal precision padded with the maximum x in any ROUND/TRUNCATE that is part of a different clause.

            It seems like you originally got a mix of good and bad results (good - IF/CASE, bad COALESCE/IFNULL) and decided to standardize on the BAD. This is bizarre.

            The only thing I can think of that would cause this decision is that you'd want consistent output out of COALESCE, which could easily have been handled by putting the COALESCE within the ROUND, not by ignoring the plain intent of IF, IFNULL and CASE.

            SELECT ROUND(COALESCE(0.123, 0.12345), 5)

            Works the same in both MySQL and MariaDB.

            Show
            fredipusrex Fred Rexon added a comment - The expected and documented behavior of ROUND(nnn, x) is to return a string with x number of decimals, not x number of decimal precision padded with the maximum x in any ROUND/TRUNCATE that is part of a different clause. It seems like you originally got a mix of good and bad results (good - IF/CASE, bad COALESCE/IFNULL) and decided to standardize on the BAD. This is bizarre. The only thing I can think of that would cause this decision is that you'd want consistent output out of COALESCE, which could easily have been handled by putting the COALESCE within the ROUND, not by ignoring the plain intent of IF, IFNULL and CASE. SELECT ROUND(COALESCE(0.123, 0.12345), 5) Works the same in both MySQL and MariaDB.
            Hide
            bar Alexander Barkov added a comment -

            IF (1=1,ROUND(0.123451, 3), ROUND(0.123451, 5))

            is a CASE abbreviation:

            CASE WHEN 1=1 THEN (0.123451, 3) ELSE ROUND(0.123451, 5) END

            According to the SQL standard, the result type for CASE in this particulate case is
            exact numeric, and the result's scale is the biggest scale of any of the aggregated values,
            which is 5.

            Show
            bar Alexander Barkov added a comment - IF (1=1,ROUND(0.123451, 3), ROUND(0.123451, 5)) is a CASE abbreviation: CASE WHEN 1=1 THEN (0.123451, 3) ELSE ROUND(0.123451, 5) END According to the SQL standard, the result type for CASE in this particulate case is exact numeric, and the result's scale is the biggest scale of any of the aggregated values, which is 5.
            Hide
            kolbe Kolbe Kegel added a comment -

            If the goal is indeed to have variable precision for the result, the condition should be placed inside of the ROUND() function, not around it. For example, instead of this:

            SELECT IF (1=1, ROUND(0.123451, 3), ROUND(0.123451, 5)) as result;
            

            Use this instead:

            SELECT  ROUND(0.123451, IF (1=1, 3, 5)) as result;
            
            Show
            kolbe Kolbe Kegel added a comment - If the goal is indeed to have variable precision for the result, the condition should be placed inside of the ROUND() function, not around it. For example, instead of this: SELECT IF (1=1, ROUND(0.123451, 3), ROUND(0.123451, 5)) as result; Use this instead: SELECT ROUND(0.123451, IF (1=1, 3, 5)) as result;

              People

              • Assignee:
                bar Alexander Barkov
                Reporter:
                kolbe Kolbe Kegel
              • Votes:
                0 Vote for this issue
                Watchers:
                5 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: