Commit 847df79f authored by Varun Gupta's avatar Varun Gupta

MDEV-22509: Server crashes in Field_inet6::store_inet6_null_with_warn / 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
parent 5d85bc08
......@@ -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
#
......@@ -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 #
......@@ -1967,6 +1967,37 @@ 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);
}
int Field_bit::store_to_statistical_minmax_field(Field *field, String *str)
{
longlong nr= val_int();
return field->store(nr, TRUE);
}
int Field_bit::store_from_statistical_minmax_field(Field *stat_field,
String *str __attribute__((unused)))
{
return store(stat_field->val_int(), TRUE);
}
/**
Pack the field into a format suitable for storage and transfer.
......
......@@ -977,6 +977,26 @@ class Field: public Value_source
DBUG_ASSERT(ls.length < UINT_MAX32);
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);
virtual double val_real()=0;
virtual longlong val_int()=0;
/*
......@@ -4946,6 +4966,8 @@ class Field_bit :public Field {
static_cast<uint16>((field_length & 7) |
((field_length / 8) << 8)), 2);
}
int store_to_statistical_minmax_field(Field *fld, String *str) override;
int store_from_statistical_minmax_field(Field *fld, String *str) override;
private:
size_t do_last_null_byte() const override;
......
......@@ -1037,27 +1037,17 @@ class Column_stat: public Stat_table
stat_field->set_notnull();
switch (i) {
case COLUMN_STAT_MIN_VALUE:
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;
......@@ -1134,17 +1124,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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment