Skip to content

Commit

Permalink
MDEV-22509: Server crashes in Field_inet6::store_inet6_null_with_warn…
Browse files Browse the repository at this point in the history
… / Field::maybe_null

For field with type INET, during EITS collection the min and max values are store in text
representation in the statistical table.
While retrieving the value from the statistical table, the value is stored back in the original
field using binary form instead of text and this was resulting in the crash.

Introduced 2 functions in the Field structure:
  1) store_to_statistical_minmax_field
  2) store_from_statistical_minmax_field
  • Loading branch information
Varun Gupta committed Jun 2, 2020
1 parent 6df2f2d commit d5e8b4d
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,19 @@ test.t1 analyze status OK
INSERT INTO t1 VALUES ('3::3');
DROP TABLE t1;
#
# MDEV-22509: Server crashes in Field_inet6::store_inet6_null_with_warn / Field::maybe_null
#
CREATE TABLE t1 (a INT, b INET6 NOT NULL);
INSERT INTO t1 VALUES (1,'::'),(2,'::');
ANALYZE TABLE t1 PERSISTENT FOR ALL;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
SELECT t1.a from t1;
a
1
2
DROP TABLE t1;
#
# End of 10.5 tests
#
10 changes: 10 additions & 0 deletions plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.test
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ ANALYZE TABLE t1 PERSISTENT FOR ALL;
INSERT INTO t1 VALUES ('3::3');
DROP TABLE t1;

--echo #
--echo # MDEV-22509: Server crashes in Field_inet6::store_inet6_null_with_warn / Field::maybe_null
--echo #

CREATE TABLE t1 (a INT, b INET6 NOT NULL);
INSERT INTO t1 VALUES (1,'::'),(2,'::');
ANALYZE TABLE t1 PERSISTENT FOR ALL;
SELECT t1.a from t1;
DROP TABLE t1;

--echo #
--echo # End of 10.5 tests
--echo #
17 changes: 17 additions & 0 deletions sql/field.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1967,6 +1967,23 @@ int Field::store_timestamp_dec(const timeval &ts, uint dec)
return store_time_dec(Datetime(get_thd(), ts).get_mysql_time(), dec);
}


int Field::store_to_statistical_minmax_field(Field *field, String *val)
{
val_str(val);
size_t length= Well_formed_prefix(val->charset(), val->ptr(),
MY_MIN(val->length(), field->field_length)).length();
return field->store(val->ptr(), length, &my_charset_bin);
}


int Field::store_from_statistical_minmax_field(Field *stat_field, String *str)
{
stat_field->val_str(str);
return store_text(str->ptr(), str->length(), &my_charset_bin);
}


/**
Pack the field into a format suitable for storage and transfer.
Expand Down
18 changes: 18 additions & 0 deletions sql/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,24 @@ class Field: public Value_source
return store(ls.str, (uint) ls.length, cs);
}

/*
@brief
Store minimum/maximum value of a column in the statistics table.
@param
field statistical table field
str value buffer
*/
virtual int store_to_statistical_minmax_field(Field *field, String *str);

/*
@brief
Store minimum/maximum value of a column from the statistical table.
@param
field statistical table field
str value buffer
*/
virtual int store_from_statistical_minmax_field(Field *field, String *str);

#ifdef HAVE_valgrind_or_MSAN
/**
Mark unused memory in the field as defined. Mainly used to ensure
Expand Down
38 changes: 22 additions & 16 deletions sql/sql_statistics.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1036,27 +1036,31 @@ class Column_stat: public Stat_table
stat_field->set_notnull();
switch (i) {
case COLUMN_STAT_MIN_VALUE:
{
/*
TODO varun: After MDEV-22583 is fixed, add a function in Field_bit
and move this implementation there
*/
if (table_field->type() == MYSQL_TYPE_BIT)
stat_field->store(table_field->collected_stats->min_value->val_int(),true);
else
{
table_field->collected_stats->min_value->val_str(&val);
size_t length= Well_formed_prefix(val.charset(), val.ptr(),
MY_MIN(val.length(), stat_field->field_length)).length();
stat_field->store(val.ptr(), length, &my_charset_bin);
Field *field= table_field->collected_stats->min_value;
field->store_to_statistical_minmax_field(stat_field, &val);
}
break;
}
case COLUMN_STAT_MAX_VALUE:
{
if (table_field->type() == MYSQL_TYPE_BIT)
stat_field->store(table_field->collected_stats->max_value->val_int(),true);
else
{
table_field->collected_stats->max_value->val_str(&val);
size_t length= Well_formed_prefix(val.charset(), val.ptr(),
MY_MIN(val.length(), stat_field->field_length)).length();
stat_field->store(val.ptr(), length, &my_charset_bin);
Field *field= table_field->collected_stats->max_value;
field->store_to_statistical_minmax_field(stat_field, &val);
}
break;
}
case COLUMN_STAT_NULLS_RATIO:
stat_field->store(table_field->collected_stats->get_nulls_ratio());
break;
Expand Down Expand Up @@ -1133,17 +1137,19 @@ class Column_stat: public Stat_table

switch (i) {
case COLUMN_STAT_MIN_VALUE:
table_field->read_stats->min_value->set_notnull();
stat_field->val_str(&val);
table_field->read_stats->min_value->store(val.ptr(), val.length(),
&my_charset_bin);
{
Field *field= table_field->read_stats->min_value;
field->set_notnull();
field->store_from_statistical_minmax_field(stat_field, &val);
break;
}
case COLUMN_STAT_MAX_VALUE:
table_field->read_stats->max_value->set_notnull();
stat_field->val_str(&val);
table_field->read_stats->max_value->store(val.ptr(), val.length(),
&my_charset_bin);
{
Field *field= table_field->read_stats->max_value;
field->set_notnull();
field->store_from_statistical_minmax_field(stat_field, &val);
break;
}
case COLUMN_STAT_NULLS_RATIO:
table_field->read_stats->set_nulls_ratio(stat_field->val_real());
break;
Expand Down

0 comments on commit d5e8b4d

Please sign in to comment.