[MDEV-12594] UNION between fixed length double columns does not always preserve scale Created: 2017-04-27  Updated: 2017-05-17  Resolved: 2017-05-17

Status: Closed
Project: MariaDB Server
Component/s: OTHER
Affects Version/s: 10.1, 10.2, 10.3
Fix Version/s: 10.3.1

Type: Bug Priority: Major
Reporter: Alexander Barkov Assignee: Alexander Barkov
Resolution: Fixed Votes: 0
Labels: datatype

Issue Links:
Blocks
blocks MDEV-4912 Data type plugin API version 1 Closed
Relates
relates to MDEV-12595 UNION converts INT to BIGINT Closed
relates to MDEV-12599 UNION is not symmetric when mixing IN... Closed
relates to MDEV-12775 Reuse data type aggregation code for ... Closed

 Description   

When two double columns with fixed scale are mixed for hybrid functions, e.g. COALESCE, the fixed length nature is always preserved:

DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (a FLOAT(20,4), b FLOAT(20,3), c FLOAT(20,4));
INSERT INTO t1 VALUES (1111,2222,3333);
DROP TABLE IF EXISTS t2;
CREATE TABLE t2 SELECT
  COALESCE(a,8888),
  COALESCE(8888,a),
  COALESCE(a,a),
  COALESCE(a,b),
  COALESCE(a,c),
  COALESCE(b,b),
  COALESCE(b,a),
  COALESCE(b,c),
  COALESCE(c,a),
  COALESCE(c,b),
  COALESCE(c,c)
FROM t1\G
SHOW CREATE TABLE t2;

+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `COALESCE(a,8888)` double(20,4) DEFAULT NULL,
  `COALESCE(8888,a)` double(20,4) DEFAULT NULL,
  `COALESCE(a,a)` double(20,4) DEFAULT NULL,
  `COALESCE(a,b)` double(21,4) DEFAULT NULL,
  `COALESCE(a,c)` double(20,4) DEFAULT NULL,
  `COALESCE(b,b)` double(20,3) DEFAULT NULL,
  `COALESCE(b,a)` double(21,4) DEFAULT NULL,
  `COALESCE(b,c)` double(21,4) DEFAULT NULL,
  `COALESCE(c,a)` double(20,4) DEFAULT NULL,
  `COALESCE(c,b)` double(21,4) DEFAULT NULL,
  `COALESCE(c,c)` double(20,4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Fixed length is also preserved in UNION in case if the columns have exactly the length and scale:

CREATE OR REPLACE TABLE t2 AS SELECT a FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;

+-------+-------------------------------------------------------------------------------------------+
| Table | Create Table                                                                              |
+-------+-------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `a` float(20,4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------+

CREATE OR REPLACE TABLE t2 SELECT a FROM t1 UNION SELECT c FROM t1;
SHOW CREATE TABLE t2;

+-------+-------------------------------------------------------------------------------------------+
| Table | Create Table                                                                              |
+-------+-------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `a` float(20,4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------+

CREATE OR REPLACE TABLE t2 SELECT b FROM t1 UNION SELECT b FROM t1;
SHOW CREATE TABLE t2;

+-------+-------------------------------------------------------------------------------------------+
| Table | Create Table                                                                              |
+-------+-------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `b` float(20,3) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------+

CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT c FROM t1;
SHOW CREATE TABLE t2;

+-------+-------------------------------------------------------------------------------------------+
| Table | Create Table                                                                              |
+-------+-------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `c` float(20,4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------+

CREATE OR REPLACE TABLE t2 SELECT c FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;

+-------+-------------------------------------------------------------------------------------------+
| Table | Create Table                                                                              |
+-------+-------------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `c` float(20,4) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------------+

But fixed length is not preserved in UNION in case if the columns have different definitions. A non-fixed-length column is created:

CREATE OR REPLACE TABLE t2 AS SELECT a FROM t1 UNION SELECT b FROM t1;
SHOW CREATE TABLE t2;

+-------+-------------------------------------------------------------------------------------+
| Table | Create Table                                                                        |
+-------+-------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `a` float DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------+

CREATE OR REPLACE TABLE t2 AS SELECT b FROM t1 UNION SELECT a FROM t1;
SHOW CREATE TABLE t2;

+-------+-------------------------------------------------------------------------------------+
| Table | Create Table                                                                        |
+-------+-------------------------------------------------------------------------------------+
| t2    | CREATE TABLE `t2` (
  `b` float DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+-------+-------------------------------------------------------------------------------------+

Hybrid functions and UNION should return the same column types.

The code in Item_type_holder::join_types was written in 4.1 time and was not changed significantly since that. So it implements simplified data type aggregation rules.
The code in Item_func::count_real_length was notably improved since that and returns more precise data types.

It would be nice to reuse hybrid function aggregation code for UNION.



 Comments   
Comment by Alexander Barkov [ 2017-05-17 ]

This problem was fixed by the patch for MDEV-12775

Generated at Thu Feb 08 07:58:56 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.