diff options
author | Alexander Barkov <bar@mariadb.com> | 2018-04-20 18:11:27 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2018-04-20 18:11:27 +0400 |
commit | 9aaf62d058801ed8226c20d4b4e638d34f1542ef (patch) | |
tree | 34827a984e4d3e8e770f6f1c4a4a05c222cb6916 /sql/sql_show.cc | |
parent | 38c799c9a5e5aadd3f4df157a4151dd1f71d5bcb (diff) | |
download | mariadb-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().
Diffstat (limited to 'sql/sql_show.cc')
-rw-r--r-- | sql/sql_show.cc | 40 |
1 files changed, 7 insertions, 33 deletions
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(); } } |