summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.com>2018-04-20 18:11:27 +0400
committerAlexander Barkov <bar@mariadb.com>2018-04-20 18:11:27 +0400
commit9aaf62d058801ed8226c20d4b4e638d34f1542ef (patch)
tree34827a984e4d3e8e770f6f1c4a4a05c222cb6916
parent38c799c9a5e5aadd3f4df157a4151dd1f71d5bcb (diff)
downloadmariadb-git-9aaf62d058801ed8226c20d4b4e638d34f1542ef.tar.gz
MDEV-15926 MEDIUMINT returns wrong I_S attributes
Problem: The logic in store_column_type() with a switch on field type was hard to follow. The part for MEDIUMINT (MYSQL_TYPE_INT24) was not correct. It erroneously calculated the precision of MEDIUMINT UNSIGNED as 7 instead of 8. A similar hard-to-follow switch doing some type specific calculations resided in adjust_max_effective_column_length(). It was also wrong for MEDIUMINT (reported as a separate issue in MDEV-15946). Solution: 1. Introducing a new class Information_schema_numeric_attributes 2. Adding a new virtual method Field::information_schema_numeric_attributes() 3. Splitting the logic in store_column_type() into virtual implementations of information_schema_numeric_attributes(). 4. In order to avoid adding duplicate code for the integer data types, adding a new virtual method Field_int::numeric_precision(), which returns the number of digits. Additional changes: 1. Adding the "const" qualifier to Field::max_display_length() 2. Moving the code from adjust_max_effective_column_length() directly to Field::max_display_length(). There was no any sense to have two implementations: - a set of wrong virtual implementations for Field_xxx::max_display_length() - additional code in adjust_max_effective_column_length() fixing bad results of Field_xxx::max_display_length() This change is safe: - The code using Field::max_display_length() in field.cc, sql_show.cc, sql_type.cc is not affected. - The code in rpl_utility.cc is also not affected. See a new DBUG_ASSSERT and new comments explaining why. In the new reduction, Field_xxx::max_display_length() returns correct results for all integer types (except MEDIUMINT, see below). Putting implementations of numeric_precision() and max_display_length() near each other in field.h made the logic much clearer and thus helped to reveal bad results for Field_medium::max_display_length(), which returns 9 instead of 8 for signed MEDIUMINT fields. This problem will be addressed separately (MDEV-15946). Note, this change is also useful for pluggable data types (see MDEV-4912), as now a user defined Field_xxx has a way to control what's returned in INFORMATION_SCHEMA.COLUMNS.NUMERIC_PRECISION and INFORMATION_SCHEMA.COLUMNS.NUMERIC_SCALE by implementing a desired behavior in Field_xxx::information_schema_numeric_attributes().
-rw-r--r--mysql-test/main/type_int.result15
-rw-r--r--mysql-test/main/type_int.test17
-rw-r--r--mysql-test/suite/funcs_1/r/is_columns_innodb.result12
-rw-r--r--mysql-test/suite/funcs_1/r/is_columns_memory.result12
-rw-r--r--mysql-test/suite/funcs_1/r/is_columns_myisam.result12
-rw-r--r--sql/field.cc2
-rw-r--r--sql/field.h126
-rw-r--r--sql/item.cc27
-rw-r--r--sql/rpl_utility.cc16
-rw-r--r--sql/sql_show.cc40
-rw-r--r--sql/sql_type.h40
11 files changed, 224 insertions, 95 deletions
diff --git a/mysql-test/main/type_int.result b/mysql-test/main/type_int.result
index 39e2e91ecc7..bd24641fd65 100644
--- a/mysql-test/main/type_int.result
+++ b/mysql-test/main/type_int.result
@@ -93,3 +93,18 @@ DROP TABLE t1;
#
# End of 10.2 tests
#
+#
+# Start of 10.3 tests
+#
+#
+# MDEV-15926 MEDIUMINT returns wrong I_S attributes
+#
+CREATE TABLE t1 (a MEDIUMINT, b MEDIUMINT UNSIGNED);
+SELECT COLUMN_NAME, NUMERIC_PRECISION FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1' ORDER BY COLUMN_NAME;
+COLUMN_NAME NUMERIC_PRECISION
+a 7
+b 8
+DROP TABLE t1;
+#
+# End of 10.3 tests
+#
diff --git a/mysql-test/main/type_int.test b/mysql-test/main/type_int.test
index 271b4d5862a..f0df08ffa2c 100644
--- a/mysql-test/main/type_int.test
+++ b/mysql-test/main/type_int.test
@@ -76,3 +76,20 @@ DROP TABLE t1;
--echo #
--echo # End of 10.2 tests
--echo #
+
+--echo #
+--echo # Start of 10.3 tests
+--echo #
+
+--echo #
+--echo # MDEV-15926 MEDIUMINT returns wrong I_S attributes
+--echo #
+
+CREATE TABLE t1 (a MEDIUMINT, b MEDIUMINT UNSIGNED);
+SELECT COLUMN_NAME, NUMERIC_PRECISION FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='test' AND TABLE_NAME='t1' ORDER BY COLUMN_NAME;
+DROP TABLE t1;
+
+
+--echo #
+--echo # End of 10.3 tests
+--echo #
diff --git a/mysql-test/suite/funcs_1/r/is_columns_innodb.result b/mysql-test/suite/funcs_1/r/is_columns_innodb.result
index 297dc2d33f8..8f2ba33b591 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_innodb.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_innodb.result
@@ -427,9 +427,9 @@ def test tb1 f19 19 NULL YES smallint NULL NULL 5 0 NULL NULL NULL smallint(5) u
def test tb1 f2 2 NULL YES char 0 0 NULL NULL NULL latin1 latin1_bin char(0) select,insert,update,references NEVER NULL
def test tb1 f20 20 NULL YES smallint NULL NULL 5 0 NULL NULL NULL smallint(5) unsigned zerofill select,insert,update,references NEVER NULL
def test tb1 f21 21 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(9) select,insert,update,references NEVER NULL
-def test tb1 f22 22 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
-def test tb1 f23 23 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
-def test tb1 f24 24 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb1 f22 22 NULL YES mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
+def test tb1 f23 23 NULL YES mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb1 f24 24 NULL YES mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
def test tb1 f25 25 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL
def test tb1 f26 26 NULL YES int NULL NULL 10 0 NULL NULL NULL int(10) unsigned select,insert,update,references NEVER NULL
def test tb1 f27 27 NULL YES int NULL NULL 10 0 NULL NULL NULL int(10) unsigned zerofill select,insert,update,references NEVER NULL
@@ -543,9 +543,9 @@ def test tb3 f135 18 999 NO smallint NULL NULL 5 0 NULL NULL NULL smallint(5) un
def test tb3 f136 19 00999 NO smallint NULL NULL 5 0 NULL NULL NULL smallint(5) unsigned zerofill select,insert,update,references NEVER NULL
def test tb3 f137 20 00999 NO smallint NULL NULL 5 0 NULL NULL NULL smallint(5) unsigned zerofill select,insert,update,references NEVER NULL
def test tb3 f138 21 9999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(9) select,insert,update,references NEVER NULL
-def test tb3 f139 22 9999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
-def test tb3 f140 23 00009999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
-def test tb3 f141 24 00009999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb3 f139 22 9999 NO mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
+def test tb3 f140 23 00009999 NO mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb3 f141 24 00009999 NO mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
def test tb3 f142 25 99999 NO int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL
def test tb3 f143 26 99999 NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned select,insert,update,references NEVER NULL
def test tb3 f144 27 0000099999 NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned zerofill select,insert,update,references NEVER NULL
diff --git a/mysql-test/suite/funcs_1/r/is_columns_memory.result b/mysql-test/suite/funcs_1/r/is_columns_memory.result
index e94d4c9123a..5eaa5b08cc2 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_memory.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_memory.result
@@ -434,9 +434,9 @@ def test tb1 f19 11 NULL YES smallint NULL NULL 5 0 NULL NULL NULL smallint(5) u
def test tb1 f2 2 NULL YES char 1 1 NULL NULL NULL latin1 latin1_bin char(1) select,insert,update,references NEVER NULL
def test tb1 f20 12 NULL YES smallint NULL NULL 5 0 NULL NULL NULL smallint(5) unsigned zerofill select,insert,update,references NEVER NULL
def test tb1 f21 13 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(9) select,insert,update,references NEVER NULL
-def test tb1 f22 14 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
-def test tb1 f23 15 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
-def test tb1 f24 16 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb1 f22 14 NULL YES mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
+def test tb1 f23 15 NULL YES mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb1 f24 16 NULL YES mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
def test tb1 f25 17 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL
def test tb1 f26 18 NULL YES int NULL NULL 10 0 NULL NULL NULL int(10) unsigned select,insert,update,references NEVER NULL
def test tb1 f27 19 NULL YES int NULL NULL 10 0 NULL NULL NULL int(10) unsigned zerofill select,insert,update,references NEVER NULL
@@ -538,9 +538,9 @@ def test tb3 f135 12 999 NO smallint NULL NULL 5 0 NULL NULL NULL smallint(5) un
def test tb3 f136 13 00999 NO smallint NULL NULL 5 0 NULL NULL NULL smallint(5) unsigned zerofill select,insert,update,references NEVER NULL
def test tb3 f137 14 00999 NO smallint NULL NULL 5 0 NULL NULL NULL smallint(5) unsigned zerofill select,insert,update,references NEVER NULL
def test tb3 f138 15 9999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(9) select,insert,update,references NEVER NULL
-def test tb3 f139 16 9999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
-def test tb3 f140 17 00009999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
-def test tb3 f141 18 00009999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb3 f139 16 9999 NO mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
+def test tb3 f140 17 00009999 NO mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb3 f141 18 00009999 NO mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
def test tb3 f142 19 99999 NO int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL
def test tb3 f143 20 99999 NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned select,insert,update,references NEVER NULL
def test tb3 f144 21 0000099999 NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned zerofill select,insert,update,references NEVER NULL
diff --git a/mysql-test/suite/funcs_1/r/is_columns_myisam.result b/mysql-test/suite/funcs_1/r/is_columns_myisam.result
index c4e11e3f48b..4426583ac4c 100644
--- a/mysql-test/suite/funcs_1/r/is_columns_myisam.result
+++ b/mysql-test/suite/funcs_1/r/is_columns_myisam.result
@@ -476,9 +476,9 @@ def test tb1 f19 19 NULL YES smallint NULL NULL 5 0 NULL NULL NULL smallint(5) u
def test tb1 f2 2 NULL YES char 1 1 NULL NULL NULL latin1 latin1_bin char(1) select,insert,update,references NEVER NULL
def test tb1 f20 20 NULL YES smallint NULL NULL 5 0 NULL NULL NULL smallint(5) unsigned zerofill select,insert,update,references NEVER NULL
def test tb1 f21 21 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(9) select,insert,update,references NEVER NULL
-def test tb1 f22 22 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
-def test tb1 f23 23 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
-def test tb1 f24 24 NULL YES mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb1 f22 22 NULL YES mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
+def test tb1 f23 23 NULL YES mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb1 f24 24 NULL YES mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
def test tb1 f25 25 NULL YES int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL
def test tb1 f26 26 NULL YES int NULL NULL 10 0 NULL NULL NULL int(10) unsigned select,insert,update,references NEVER NULL
def test tb1 f27 27 NULL YES int NULL NULL 10 0 NULL NULL NULL int(10) unsigned zerofill select,insert,update,references NEVER NULL
@@ -600,9 +600,9 @@ def test tb3 f135 18 999 NO smallint NULL NULL 5 0 NULL NULL NULL smallint(5) un
def test tb3 f136 19 00999 NO smallint NULL NULL 5 0 NULL NULL NULL smallint(5) unsigned zerofill select,insert,update,references NEVER NULL
def test tb3 f137 20 00999 NO smallint NULL NULL 5 0 NULL NULL NULL smallint(5) unsigned zerofill select,insert,update,references NEVER NULL
def test tb3 f138 21 9999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(9) select,insert,update,references NEVER NULL
-def test tb3 f139 22 9999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
-def test tb3 f140 23 00009999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
-def test tb3 f141 24 00009999 NO mediumint NULL NULL 7 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb3 f139 22 9999 NO mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned select,insert,update,references NEVER NULL
+def test tb3 f140 23 00009999 NO mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
+def test tb3 f141 24 00009999 NO mediumint NULL NULL 8 0 NULL NULL NULL mediumint(8) unsigned zerofill select,insert,update,references NEVER NULL
def test tb3 f142 25 99999 NO int NULL NULL 10 0 NULL NULL NULL int(11) select,insert,update,references NEVER NULL
def test tb3 f143 26 99999 NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned select,insert,update,references NEVER NULL
def test tb3 f144 27 0000099999 NO int NULL NULL 10 0 NULL NULL NULL int(10) unsigned zerofill select,insert,update,references NEVER NULL
diff --git a/sql/field.cc b/sql/field.cc
index 58b8105c00f..fceb3cc17d7 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -11072,7 +11072,7 @@ bool Column_definition::set_compressed(const char *method)
length
*/
-uint32 Field_blob::max_display_length()
+uint32 Field_blob::max_display_length() const
{
switch (packlength)
{
diff --git a/sql/field.h b/sql/field.h
index 7bd79630265..cdb62d6af16 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1116,6 +1116,11 @@ public:
memcpy(ptr, val, len);
}
virtual uint decimals() const { return 0; }
+ virtual Information_schema_numeric_attributes
+ information_schema_numeric_attributes() const
+ {
+ return Information_schema_numeric_attributes();
+ }
/*
Caller beware: sql_type can change str.Ptr, so check
ptr() to see if it changed if you are using your own buffer
@@ -1390,8 +1395,7 @@ public:
}
/* maximum possible display length */
- virtual uint32 max_display_length()= 0;
-
+ virtual uint32 max_display_length() const= 0;
/**
Whether a field being created is compatible with a existing one.
@@ -1726,7 +1730,7 @@ public:
CHARSET_INFO *charset(void) const { return field_charset; }
enum Derivation derivation(void) const { return field_derivation; }
bool binary() const { return field_charset == &my_charset_bin; }
- uint32 max_display_length() { return field_length; }
+ uint32 max_display_length() const { return field_length; }
friend class Create_field;
my_decimal *val_decimal(my_decimal *);
bool val_bool() { return val_real() != 0e0; }
@@ -1817,6 +1821,13 @@ public:
{
return do_field_real;
}
+ Information_schema_numeric_attributes
+ information_schema_numeric_attributes() const
+ {
+ return dec == NOT_FIXED_DEC ?
+ Information_schema_numeric_attributes(field_length) :
+ Information_schema_numeric_attributes(field_length, dec);
+ }
int save_in_field(Field *to) { return to->store(val_real()); }
bool memcpy_field_possible(const Field *from) const
{
@@ -1833,7 +1844,7 @@ public:
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
my_decimal *val_decimal(my_decimal *);
bool val_bool() { return val_real() != 0e0; }
- uint32 max_display_length() { return field_length; }
+ uint32 max_display_length() const { return field_length; }
uint size_of() const { return sizeof(*this); }
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
};
@@ -1852,6 +1863,12 @@ public:
const Type_handler *type_handler() const { return &type_handler_olddecimal; }
enum ha_base_keytype key_type() const
{ return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; }
+ Information_schema_numeric_attributes
+ information_schema_numeric_attributes() const
+ {
+ uint tmp= dec ? 2 : 1; // The sign and the decimal point
+ return Information_schema_numeric_attributes(field_length - tmp, dec);
+ }
Copy_func *get_copy_func(const Field *from) const
{
return eq_def(from) ? get_identical_copy_func() : do_field_string;
@@ -1936,7 +1953,12 @@ public:
void sort_string(uchar *buff, uint length);
bool zero_pack() const { return 0; }
void sql_type(String &str) const;
- uint32 max_display_length() { return field_length; }
+ uint32 max_display_length() const { return field_length; }
+ Information_schema_numeric_attributes
+ information_schema_numeric_attributes() const
+ {
+ return Information_schema_numeric_attributes(precision, dec);
+ }
uint size_of() const { return sizeof(*this); }
uint32 pack_length() const { return (uint32) bin_size; }
uint pack_length_from_metadata(uint field_metadata);
@@ -1954,6 +1976,7 @@ class Field_int :public Field_num
protected:
String *val_str_from_long(String *val_buffer, uint max_char_length,
int radix, long nr);
+ uint32 sign_length() const { return (flags & UNSIGNED_FLAG) ? 0 : 1; }
public:
Field_int(uchar *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, enum utype unireg_check_arg,
@@ -1966,6 +1989,12 @@ public:
bool val_bool() { return val_int() != 0; }
int store_time_dec(const MYSQL_TIME *ltime, uint dec);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
+ virtual uint numeric_precision() const= 0;
+ Information_schema_numeric_attributes
+ information_schema_numeric_attributes() const
+ {
+ return Information_schema_numeric_attributes(numeric_precision(), 0);
+ }
};
@@ -1994,7 +2023,18 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 1; }
void sql_type(String &str) const;
- uint32 max_display_length() { return 4; }
+ /*
+ SIGNED: -128..127 digits=3 nchars=4
+ UNDIGNED: 0..255 digits=3 nchars=3
+ */
+ uint numeric_precision() const
+ {
+ return MAX_TINYINT_WIDTH;
+ }
+ uint32 max_display_length() const
+ {
+ return MAX_TINYINT_WIDTH + sign_length();
+ }
virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
{
@@ -2044,7 +2084,18 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 2; }
void sql_type(String &str) const;
- uint32 max_display_length() { return 6; }
+ /*
+ SIGNED: -32768..32767 digits=5 nchars=6
+ UNDIGNED: 0..65535 digits=5 nchars=5
+ */
+ uint numeric_precision() const
+ {
+ return MAX_SMALLINT_WIDTH;
+ }
+ uint32 max_display_length() const
+ {
+ return MAX_SMALLINT_WIDTH + sign_length();
+ }
virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
{ return pack_int16(to, from); }
@@ -2079,7 +2130,21 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 3; }
void sql_type(String &str) const;
- uint32 max_display_length() { return 8; }
+ /*
+ MEDIUMINT has a different number of digits for signed and unsigned:
+ MEDIUMINT SIGNED: -8388608 .. 8388607 digits=7 char_length=8
+ MEDIUMINT UNSIGNED 0 .. 16777215 digits=8 char_length=8
+ */
+ uint numeric_precision() const
+ {
+ uint ndigits= MAX_MEDIUMINT_WIDTH - 1 + MY_TEST(flags & UNSIGNED_FLAG);
+ return ndigits;
+ }
+ uint32 max_display_length() const
+ {
+ // Looks too long for SIGNED: See MDEV-15946
+ return MAX_MEDIUMINT_WIDTH + sign_length();
+ }
virtual uchar *pack(uchar* to, const uchar *from, uint max_length)
{
@@ -2119,7 +2184,18 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 4; }
void sql_type(String &str) const;
- uint32 max_display_length() { return MY_INT32_NUM_DECIMAL_DIGITS; }
+ /*
+ SIGNED: -2147483648..2147483647 digits=10 nchars=11
+ UNSIGNED: 0..4294967295 digits=10 nchars=10
+ */
+ uint numeric_precision() const
+ {
+ return MAX_INT_WIDTH;
+ }
+ uint32 max_display_length() const
+ {
+ return MAX_INT_WIDTH + sign_length();
+ }
virtual uchar *pack(uchar* to, const uchar *from,
uint max_length __attribute__((unused)))
{
@@ -2169,7 +2245,15 @@ public:
void sort_string(uchar *buff,uint length);
uint32 pack_length() const { return 8; }
void sql_type(String &str) const;
- uint32 max_display_length() { return 20; }
+ /*
+ SIGNED: -9223372036854775808..9223372036854775807 digits=19 nchars=20
+ UNSIGNED: 0..18446744073709551615 digits=20 nchars=20
+ */
+ uint numeric_precision() const
+ {
+ return MAX_BIGINT_WIDTH - sign_length();
+ }
+ uint32 max_display_length() const { return MAX_BIGINT_WIDTH; }
virtual uchar *pack(uchar* to, const uchar *from,
uint max_length __attribute__((unused)))
{
@@ -2361,7 +2445,7 @@ public:
uint32 pack_length() const { return 0; }
void sql_type(String &str) const;
uint size_of() const { return sizeof(*this); }
- uint32 max_display_length() { return 4; }
+ uint32 max_display_length() const { return 4; }
void move_field_offset(my_ptrdiff_t ptr_diff) {}
bool can_optimize_keypart_ref(const Item_bool_func *cond,
const Item *item) const
@@ -2400,7 +2484,7 @@ public:
return to->store_time_dec(&ltime, decimals());
}
bool memcpy_field_possible(const Field *from) const;
- uint32 max_display_length() { return field_length; }
+ uint32 max_display_length() const { return field_length; }
bool str_needs_quotes() { return TRUE; }
enum Derivation derivation(void) const { return DERIVATION_NUMERIC; }
uint repertoire(void) const { return MY_REPERTOIRE_NUMERIC; }
@@ -2700,7 +2784,12 @@ public:
String *val_str(String*,String *);
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate);
bool send_binary(Protocol *protocol);
- uint32 max_display_length() { return field_length; }
+ Information_schema_numeric_attributes
+ information_schema_numeric_attributes() const
+ {
+ return Information_schema_numeric_attributes();
+ }
+ uint32 max_display_length() const { return field_length; }
void sql_type(String &str) const;
};
@@ -3355,7 +3444,7 @@ private:
Field_varstring::sql_type(str);
str.append(STRING_WITH_LEN(" /*!100301 COMPRESSED*/"));
}
- uint32 max_display_length() { return field_length - 1; }
+ uint32 max_display_length() const { return field_length - 1; }
int cmp_max(const uchar *a_ptr, const uchar *b_ptr, uint max_len);
/*
@@ -3635,7 +3724,7 @@ public:
uint size_of() const { return sizeof(*this); }
bool has_charset(void) const
{ return charset() == &my_charset_bin ? FALSE : TRUE; }
- uint32 max_display_length();
+ uint32 max_display_length() const;
uint32 char_length() const;
uint is_equal(Create_field *new_field);
private:
@@ -3915,7 +4004,12 @@ public:
enum ha_base_keytype key_type() const { return HA_KEYTYPE_BIT; }
uint32 key_length() const { return (uint32) (field_length + 7) / 8; }
uint32 max_data_length() const { return (field_length + 7) / 8; }
- uint32 max_display_length() { return field_length; }
+ uint32 max_display_length() const { return field_length; }
+ Information_schema_numeric_attributes
+ information_schema_numeric_attributes() const
+ {
+ return Information_schema_numeric_attributes(field_length);
+ }
uint size_of() const { return sizeof(*this); }
int reset(void) {
bzero(ptr, bytes_in_rec);
diff --git a/sql/item.cc b/sql/item.cc
index 56af69be427..35c5ab8cc3d 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3187,33 +3187,6 @@ inline static uint32
adjust_max_effective_column_length(Field *field_par, uint32 max_length)
{
uint32 new_max_length= field_par->max_display_length();
- uint32 sign_length= (field_par->flags & UNSIGNED_FLAG) ? 0 : 1;
-
- switch (field_par->type())
- {
- case MYSQL_TYPE_INT24:
- /*
- Compensate for MAX_MEDIUMINT_WIDTH being 1 too long (8)
- compared to the actual number of digits that can fit into
- the column.
- */
- new_max_length+= 1;
- /* fall through */
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
-
- /* Take out the sign and add a conditional sign */
- new_max_length= new_max_length - 1 + sign_length;
- break;
-
- /* BINGINT is always 20 no matter the sign */
- case MYSQL_TYPE_LONGLONG:
- /* make gcc happy */
- default:
- break;
- }
-
/* Adjust only if the actual precision based one is bigger than specified */
return new_max_length > max_length ? new_max_length : max_length;
}
diff --git a/sql/rpl_utility.cc b/sql/rpl_utility.cc
index 58711078db6..31035fb5dcc 100644
--- a/sql/rpl_utility.cc
+++ b/sql/rpl_utility.cc
@@ -42,6 +42,12 @@ max_display_length_for_temporal2_field(uint32 int_display_length,
@param sql_type Type of the field
@param metadata The metadata from the master for the field.
@return Maximum length of the field in bytes.
+
+ The precise values calculated by field->max_display_length() and
+ calculated by max_display_length_for_field() can differ (by +1 or -1)
+ for integer data types (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT).
+ This slight difference is not important here, because we call
+ this function only for two *different* integer data types.
*/
static uint32
max_display_length_for_field(enum_field_types sql_type, unsigned int metadata)
@@ -737,6 +743,16 @@ can_convert_field_to(Field *field,
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
+ /*
+ max_display_length_for_field() is not fully precise for the integer
+ data types. So its result cannot be compared to the result of
+ field->max_dispay_length() when the table field and the binlog field
+ are of the same type.
+ This code should eventually be rewritten not to use
+ compare_lengths(), to detect subtype/supetype relations
+ just using the type codes.
+ */
+ DBUG_ASSERT(source_type != field->real_type());
*order_var= compare_lengths(field, source_type, metadata);
DBUG_ASSERT(*order_var != 0);
DBUG_RETURN(is_conversion_ok(*order_var, rli));
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 38a13c49278..a45ca325d1a 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -5636,7 +5636,6 @@ static void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs,
uint offset)
{
bool is_blob;
- int decimals, field_length;
const char *tmp_buff;
char column_type_buff[MAX_FIELD_WIDTH];
String column_type(column_type_buff, sizeof(column_type_buff), cs);
@@ -5686,35 +5685,10 @@ static void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs,
They are set to -1 if they should not be set (we should return NULL)
*/
- field_length= -1;
- decimals= field->decimals();
+ Information_schema_numeric_attributes num=
+ field->information_schema_numeric_attributes();
+
switch (field->type()) {
- case MYSQL_TYPE_NEWDECIMAL:
- field_length= ((Field_new_decimal*) field)->precision;
- break;
- case MYSQL_TYPE_DECIMAL:
- field_length= field->field_length - (decimals ? 2 : 1);
- break;
- case MYSQL_TYPE_TINY:
- case MYSQL_TYPE_SHORT:
- case MYSQL_TYPE_LONG:
- case MYSQL_TYPE_INT24:
- field_length= field->max_display_length() - 1;
- break;
- case MYSQL_TYPE_LONGLONG:
- field_length= field->max_display_length() -
- ((field->flags & UNSIGNED_FLAG) ? 0 : 1);
- break;
- case MYSQL_TYPE_BIT:
- field_length= field->max_display_length();
- decimals= -1; // return NULL
- break;
- case MYSQL_TYPE_FLOAT:
- case MYSQL_TYPE_DOUBLE:
- field_length= field->field_length;
- if (decimals == NOT_FIXED_DEC)
- decimals= -1; // return NULL
- break;
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATETIME:
@@ -5727,15 +5701,15 @@ static void store_column_type(TABLE *table, Field *field, CHARSET_INFO *cs,
}
/* NUMERIC_PRECISION column */
- if (field_length >= 0)
+ if (num.has_precision())
{
- table->field[offset + 3]->store((longlong) field_length, TRUE);
+ table->field[offset + 3]->store((longlong) num.precision(), true);
table->field[offset + 3]->set_notnull();
/* NUMERIC_SCALE column */
- if (decimals >= 0)
+ if (num.has_scale())
{
- table->field[offset + 4]->store((longlong) decimals, TRUE);
+ table->field[offset + 4]->store((longlong) num.scale(), true);
table->field[offset + 4]->set_notnull();
}
}
diff --git a/sql/sql_type.h b/sql/sql_type.h
index dd37e2ba96c..e9307db7125 100644
--- a/sql/sql_type.h
+++ b/sql/sql_type.h
@@ -911,6 +911,46 @@ public:
};
+class Information_schema_numeric_attributes
+{
+ enum enum_attr
+ {
+ ATTR_NONE= 0,
+ ATTR_PRECISION= 1,
+ ATTR_SCALE= 2,
+ ATTR_PRECISION_AND_SCALE= (ATTR_PRECISION|ATTR_SCALE)
+ };
+ uint m_precision;
+ uint m_scale;
+ enum_attr m_available_attributes;
+public:
+ Information_schema_numeric_attributes()
+ :m_precision(0), m_scale(0),
+ m_available_attributes(ATTR_NONE)
+ { }
+ Information_schema_numeric_attributes(uint precision)
+ :m_precision(precision), m_scale(0),
+ m_available_attributes(ATTR_PRECISION)
+ { }
+ Information_schema_numeric_attributes(uint precision, uint scale)
+ :m_precision(precision), m_scale(scale),
+ m_available_attributes(ATTR_PRECISION_AND_SCALE)
+ { }
+ bool has_precision() const { return m_available_attributes & ATTR_PRECISION; }
+ bool has_scale() const { return m_available_attributes & ATTR_SCALE; }
+ uint precision() const
+ {
+ DBUG_ASSERT(has_precision());
+ return (uint) m_precision;
+ }
+ uint scale() const
+ {
+ DBUG_ASSERT(has_scale());
+ return (uint) m_scale;
+ }
+};
+
+
class Type_handler
{
protected: