summaryrefslogtreecommitdiff
path: root/sql/sql_show.cc
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 /sql/sql_show.cc
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().
Diffstat (limited to 'sql/sql_show.cc')
-rw-r--r--sql/sql_show.cc40
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();
}
}