diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.result index 6d84d105c99..1cbedad1c3c 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.result @@ -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 # diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.test b/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.test index fb092db6bc4..063581b12f5 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.test +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_stat_tables.test @@ -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 # diff --git a/sql/field.cc b/sql/field.cc index 7a2d67876e6..cbed034147d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -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. diff --git a/sql/field.h b/sql/field.h index bef73705f60..1bccff9991f 100644 --- a/sql/field.h +++ b/sql/field.h @@ -978,6 +978,24 @@ public: 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 diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index f51f63020a3..0598698f7e5 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -1036,27 +1036,31 @@ public: 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; @@ -1133,17 +1137,19 @@ public: 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;