Skip to content

Commit

Permalink
MDEV-10138 Support for decimals up to 38 digits
Browse files Browse the repository at this point in the history
Decimals with float, double and decimal now works the following way:

- DECIMAL_NOT_SPECIFIED is used when declaring DECIMALS without a firm number
  of decimals.  It's only used in asserts and my_decimal_int_part.
- FLOATING_POINT_DECIMALS (31) is used to mark that a FLOAT or DOUBLE
  was defined without decimals. This is regarded as a floating point value.
- Max decimals allowed for FLOAT and DOUBLE is FLOATING_POINT_DECIMALS-1
- Clients assumes that float and double with decimals >= NOT_FIXED_DEC are
  floating point values (no decimals)
- In the .frm decimals=FLOATING_POINT_DECIMALS are used to define
  floating point for float and double (31, like before)

To ensure compatibility with old clients we do:

- When storing float and double, we change NOT_FIXED_DEC to
  FLOATING_POINT_DECIMALS.
- When creating fields from .frm we change for float and double
  FLOATING_POINT_DEC to NOT_FIXED_DEC
- When sending definition for a float/decimal field without decimals
  to the client as part of a result set we convert NOT_FIXED_DEC to
  FLOATING_POINT_DECIMALS.
- variance() and std() has changed to limit the decimals to
  FLOATING_POINT_DECIMALS -1 to not get the double converted floating point.
  (This was to preserve compatiblity)
- FLOAT and DOUBLE still have 30 as max number of decimals.

Bugs fixed:

variance() printed more decimals than we support for double values.

New behaviour:
- Strings now have 38 decimals instead of 30 when converted to decimal
- CREATE ... SELECT with a decimal with > 30 decimals will create a column
  with a smaller range than before as we are trying to preserve the number of
  decimals.


Other changes
- We are now using the obsolete bit FIELDFLAG_LEFT_FULLSCREEN to specify
  decimals > 31
- NOT_FIXED_DEC is now declared in one place
- For clients, NOT_FIXED_DEC is always 31 (to ensure compatibility).
  On the server NOT_FIXED_DEC is DECIMAL_NOT_SPECIFIED (39)
- AUTO_SEC_PART_DIGITS is taken from DECIMAL_NOT_SPECIFIED
- DOUBLE conversion functions are now using DECIMAL_NOT_SPECIFIED instead of
  NOT_FIXED_DEC
  • Loading branch information
montywi committed Jun 22, 2016
1 parent e4062d4 commit 34eb10e
Show file tree
Hide file tree
Showing 58 changed files with 1,631 additions and 1,426 deletions.
8 changes: 4 additions & 4 deletions include/m_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#define _m_string_h

#include "my_global.h" /* HAVE_* */
#include "my_decimal_limits.h"

#ifndef __USE_GNU
#define __USE_GNU /* We want to use stpcpy */
Expand Down Expand Up @@ -138,14 +139,13 @@ size_t my_fcvt(double x, int precision, char *to, my_bool *error);
size_t my_gcvt(double x, my_gcvt_arg_type type, int width, char *to,
my_bool *error);

#define NOT_FIXED_DEC 31

/*
The longest string my_fcvt can return is 311 + "precision" bytes.
Here we assume that we never cal my_fcvt() with precision >= NOT_FIXED_DEC
Here we assume that we never cal my_fcvt() with
precision >= DECIMAL_NOT_SPECIFIED
(+ 1 byte for the terminating '\0').
*/
#define FLOATING_POINT_BUFFER (311 + NOT_FIXED_DEC)
#define FLOATING_POINT_BUFFER (311 + DECIMAL_NOT_SPECIFIED)

/*
We want to use the 'e' format in some cases even if we have enough space
Expand Down
10 changes: 8 additions & 2 deletions include/my_decimal_limits.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@
digits * number of decimal digits in one our big digit - number of decimal
digits in one our big digit decreased by 1 (because we always put decimal
point on the border of our big digits))
With normal precession we can handle 65 digits. MariaDB can store in
the .frm up to 63 digits. By default we use DECIMAL_NOT_SPECIFIED digits
when converting strings to decimal, so we don't want to set this too high.
To not use up all digits for the scale we limit the number of decimals to
38.
*/
#define DECIMAL_MAX_PRECISION (DECIMAL_MAX_POSSIBLE_PRECISION - 8*2)
#define DECIMAL_MAX_SCALE 30
#define DECIMAL_NOT_SPECIFIED 31
#define DECIMAL_MAX_SCALE 38
#define DECIMAL_NOT_SPECIFIED 39

/**
maximum length of string representation (number of maximum decimal
Expand Down
3 changes: 2 additions & 1 deletion include/my_time.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#define _my_time_h_
#include "my_global.h"
#include "mysql_time.h"
#include "my_decimal_limits.h"

C_MODE_START

Expand Down Expand Up @@ -184,7 +185,7 @@ void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type);
sent using binary protocol fit in this buffer.
*/
#define MAX_DATE_STRING_REP_LENGTH 30
#define AUTO_SEC_PART_DIGITS 31 /* same as NOT_FIXED_DEC */
#define AUTO_SEC_PART_DIGITS DECIMAL_NOT_SPECIFIED

int my_time_to_str(const MYSQL_TIME *l_time, char *to, uint digits);
int my_date_to_str(const MYSQL_TIME *l_time, char *to);
Expand Down
17 changes: 16 additions & 1 deletion include/mysql_com.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#ifndef _mysql_com_h
#define _mysql_com_h

#include "my_decimal_limits.h"

#define HOSTNAME_LENGTH 60
#define SYSTEM_CHARSET_MBMAXLEN 3
#define NAME_CHAR_LEN 64 /* Field/table name length */
Expand Down Expand Up @@ -648,5 +650,18 @@ uchar *safe_net_store_length(uchar *pkg, size_t pkg_len, ulonglong length);
#define MYSQL_STMT_HEADER 4
#define MYSQL_LONG_DATA_HEADER 6

#define NOT_FIXED_DEC 31
/*
If a float or double field have more than this number of decimals,
it's regarded as floating point field without any specific number of
decimals
*/

#define FLOATING_POINT_DECIMALS 31

/* Keep client compatible with earlier versions */
#ifdef MYSQL_SERVER
#define NOT_FIXED_DEC DECIMAL_NOT_SPECIFIED
#else
#define NOT_FIXED_DEC FLOATING_POINT_DECIMALS
#endif
#endif
2 changes: 1 addition & 1 deletion libmysql/libmysql.c
Original file line number Diff line number Diff line change
Expand Up @@ -3479,7 +3479,7 @@ static void fetch_float_with_conversion(MYSQL_BIND *param, MYSQL_FIELD *field,
*/
char buff[FLOATING_POINT_BUFFER];
size_t len;
if (field->decimals >= NOT_FIXED_DEC)
if (field->decimals >= FLOATING_POINT_DECIMALS)
len= my_gcvt(value, type,
(int) MY_MIN(sizeof(buff)-1, param->buffer_length),
buff, NULL);
Expand Down
4 changes: 4 additions & 0 deletions libmysqld/lib_sql.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,10 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags)
client_field->type= server_field.type;
client_field->flags= (uint16) server_field.flags;
client_field->decimals= server_field.decimals;
if (server_field.type == MYSQL_TYPE_FLOAT ||
server_field.type == MYSQL_TYPE_DOUBLE)
set_if_smaller(client_field->decimals, FLOATING_POINT_DECIMALS);

client_field->db_length= strlen(client_field->db);
client_field->table_length= strlen(client_field->table);
client_field->name_length= strlen(client_field->name);
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/r/bug12427262.result
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/fi
into @count_read_after;
select @count_read_after-@count_read_before;
@count_read_after-@count_read_before
0.000000000000000000000000000000
0.00000000000000000000000000000000000000
show full tables;
Tables_in_show_table_lw_db Table_type
t1 BASE TABLE
Expand All @@ -51,6 +51,6 @@ like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/fi
into @count_read_after;
select @count_read_after-@count_read_before;
@count_read_after-@count_read_before
10.000000000000000000000000000000
10.00000000000000000000000000000000000000
drop table t1;
drop database show_table_lw_db;
4 changes: 2 additions & 2 deletions mysql-test/r/cast.result
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,9 @@ ERROR 42000: Too big precision 66 specified for '1'. Maximum is 65.
select cast(1 as decimal(66,6));
ERROR 42000: Too big precision 66 specified for '1'. Maximum is 65.
select cast(1 as decimal(64,63));
ERROR 42000: Too big scale 63 specified for '1'. Maximum is 30.
ERROR 42000: Too big scale 63 specified for '1'. Maximum is 38.
select cast(1 as double(64,63));
ERROR 42000: Too big scale 63 specified for '1'. Maximum is 30.
ERROR 42000: Too big scale 63 specified for '1'. Maximum is 38.
set names binary;
select cast(_latin1'test' as char character set latin2);
cast(_latin1'test' as char character set latin2)
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/r/ctype_binary.result
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,7 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varbinary(83) DEFAULT NULL,
`c2` decimal(65,30) DEFAULT NULL
`c2` decimal(65,38) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select hex(concat(@@ft_max_word_len));
Expand Down Expand Up @@ -2621,7 +2621,7 @@ GROUP_CONCAT(CASE WHEN a THEN a ELSE '' END)
1234567
SELECT COALESCE(a,'') FROM t1 GROUP BY 1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def COALESCE(a,'') 253 9 7 Y 128 31 63
def COALESCE(a,'') 253 9 7 Y 128 39 63
COALESCE(a,'')
1234567
# All columns must be VARCHAR(9) with the same length:
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/r/ctype_cp1251.result
Original file line number Diff line number Diff line change
Expand Up @@ -1323,7 +1323,7 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(83) CHARACTER SET cp1251 DEFAULT NULL,
`c2` decimal(65,30) DEFAULT NULL
`c2` decimal(65,38) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select hex(concat(@@ft_max_word_len));
Expand Down Expand Up @@ -3030,7 +3030,7 @@ GROUP_CONCAT(CASE WHEN a THEN a ELSE '' END)
1234567
SELECT COALESCE(a,'') FROM t1 GROUP BY 1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def COALESCE(a,'') 253 9 7 Y 0 31 51
def COALESCE(a,'') 253 9 7 Y 0 39 51
COALESCE(a,'')
1234567
# All columns must be VARCHAR(9) with the same length:
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/r/ctype_latin1.result
Original file line number Diff line number Diff line change
Expand Up @@ -1620,7 +1620,7 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(83) DEFAULT NULL,
`c2` decimal(65,30) DEFAULT NULL
`c2` decimal(65,38) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select hex(concat(@@ft_max_word_len));
Expand Down Expand Up @@ -3327,7 +3327,7 @@ GROUP_CONCAT(CASE WHEN a THEN a ELSE '' END)
1234567
SELECT COALESCE(a,'') FROM t1 GROUP BY 1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def COALESCE(a,'') 253 9 7 Y 0 31 8
def COALESCE(a,'') 253 9 7 Y 0 39 8
COALESCE(a,'')
1234567
# All columns must be VARCHAR(9) with the same length:
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/r/ctype_ucs.result
Original file line number Diff line number Diff line change
Expand Up @@ -2523,7 +2523,7 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(83) CHARACTER SET ucs2 DEFAULT NULL,
`c2` decimal(65,30) DEFAULT NULL
`c2` decimal(65,38) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select hex(concat(@@ft_max_word_len));
Expand Down Expand Up @@ -4230,7 +4230,7 @@ GROUP_CONCAT(CASE WHEN a THEN a ELSE '' END)
1234567
SELECT COALESCE(a,'') FROM t1 GROUP BY 1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def COALESCE(a,'') 253 9 7 Y 0 31 8
def COALESCE(a,'') 253 9 7 Y 0 39 8
COALESCE(a,'')
1234567
# All columns must be VARCHAR(9) with the same length:
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/r/ctype_utf32.result
Original file line number Diff line number Diff line change
Expand Up @@ -1575,7 +1575,7 @@ CREATE TABLE t1 AS SELECT format(123,2,'no_NO');
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`format(123,2,'no_NO')` varchar(37) CHARACTER SET utf32 NOT NULL
`format(123,2,'no_NO')` varchar(45) CHARACTER SET utf32 NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
SELECT * FROM t1;
format(123,2,'no_NO')
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/r/ctype_utf8.result
Original file line number Diff line number Diff line change
Expand Up @@ -3365,7 +3365,7 @@ show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`c1` varchar(83) CHARACTER SET utf8 DEFAULT NULL,
`c2` decimal(65,30) DEFAULT NULL
`c2` decimal(65,38) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
select hex(concat(@@ft_max_word_len));
Expand Down Expand Up @@ -5072,7 +5072,7 @@ GROUP_CONCAT(CASE WHEN a THEN a ELSE '' END)
1234567
SELECT COALESCE(a,'') FROM t1 GROUP BY 1;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def COALESCE(a,'') 253 27 7 Y 0 31 33
def COALESCE(a,'') 253 27 7 Y 0 39 33
COALESCE(a,'')
1234567
# All columns must be VARCHAR(9) with the same length:
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/r/dyncol.result
Original file line number Diff line number Diff line change
Expand Up @@ -1458,8 +1458,8 @@ Note 1105 Cast to signed converted positive out-of-range integer to it's negativ
# MDEV-7505 - Too large scale in DECIMAL dynamic column getter crashes
# mysqld
#
SELECT COLUMN_GET(`x`, 'y' AS DECIMAL(5,34));
ERROR 42000: Too big scale 34 specified for ''y''. Maximum is 30.
SELECT COLUMN_GET(`x`, 'y' AS DECIMAL(5,50));
ERROR 42000: Too big scale 50 specified for ''y''. Maximum is 38.
#
# test of symbolic names
#
Expand Down
6 changes: 3 additions & 3 deletions mysql-test/r/func_digest.result
Original file line number Diff line number Diff line change
Expand Up @@ -1411,18 +1411,18 @@ LENGTH(SHA2( 'computed', 512 )) / 2 * 8 = 512
SET NAMES binary;
SELECT sha2('1',224);
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def sha2('1',224) 253 56 56 Y 128 31 63
def sha2('1',224) 253 56 56 Y 128 39 63
sha2('1',224)
e25388fde8290dc286a6164fa2d97e551b53498dcbf7bc378eb1f178
SET NAMES utf8;
SELECT sha2('1',224);
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def sha2('1',224) 253 168 56 Y 0 31 33
def sha2('1',224) 253 168 56 Y 0 39 33
sha2('1',224)
e25388fde8290dc286a6164fa2d97e551b53498dcbf7bc378eb1f178
SET NAMES latin1;
SELECT sha2('1',224);
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def sha2('1',224) 253 56 56 Y 0 31 8
def sha2('1',224) 253 56 56 Y 0 39 8
sha2('1',224)
e25388fde8290dc286a6164fa2d97e551b53498dcbf7bc378eb1f178
Loading

0 comments on commit 34eb10e

Please sign in to comment.