From 415409579af68ee2e3c55d5294d7bb5e6397b03f Mon Sep 17 00:00:00 2001 From: Monty <monty@mariadb.org> Date: Mon, 1 Mar 2021 14:44:18 +0200 Subject: [PATCH] MDEV-24958 Server crashes in my_strtod ... with DEFAULT(blob) Fixes also: MDEV-24942 Server crashes in _ma_rec_pack... with DEFAULT() on BLOB This was caused by two different bugs, both related to that the default value for the blob was not calculated before it was used: - There where now Item_default_value::..result() wrappers, which is needed as item in HAVING uses these. This causes crashes when using a reference to a DEFAULT(blob_field) in HAVING. It also caused wrong results when used with other fields with default value expressions that are not constants. - create_tmp_field() did not take into account that blob fields with default expressions are not yet initialized. Fixed by treating Item_default_value(blob) like a normal item expression. --- mysql-test/main/having.result | 33 ++++++++++++++++++++++++ mysql-test/main/having.test | 20 +++++++++++++++ sql/item.cc | 47 ++++++++++++++++++++++++++++++++--- sql/item.h | 10 ++++++++ sql/sql_select.cc | 24 ++++++++++++++++-- 5 files changed, 129 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/having.result b/mysql-test/main/having.result index f37cc48772e..233843de36f 100644 --- a/mysql-test/main/having.result +++ b/mysql-test/main/having.result @@ -846,3 +846,36 @@ t r DROP TABLE t1; DROP FUNCTION next_seq_value; DROP TABLE series; +# +# MDEV-24958 Server crashes in my_strtod / +# Value_source::Converter_strntod::Converter_strntod with DEFAULT(blob) +# +# MDEV-24942 Server crashes in _ma_rec_pack / _ma_write_blob_record with +# DEFAULT() on BLOB +# +CREATE TABLE t1 (id INT, f MEDIUMTEXT NOT NULL DEFAULT 'A'); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +SELECT f FROM t1 GROUP BY id ORDER BY DEFAULT(f); +f +foo +bar +SELECT DEFAULT(f) AS h FROM t1 HAVING h > 5; +h +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'A' +SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 0; +h +A +A +Warnings: +Warning 1292 Truncated incorrect DOUBLE value: 'A' +SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 'A'; +h +A +A +alter table t1 add column b int default (rand()+1+3); +select default(b) AS h FROM t1 HAVING h > "2"; +h +# +# +drop table t1; diff --git a/mysql-test/main/having.test b/mysql-test/main/having.test index 179af14559f..8b0cc244f51 100644 --- a/mysql-test/main/having.test +++ b/mysql-test/main/having.test @@ -890,3 +890,23 @@ SELECT t, next_seq_value() r FROM t1 FORCE INDEX(t) DROP TABLE t1; DROP FUNCTION next_seq_value; DROP TABLE series; + +--echo # +--echo # MDEV-24958 Server crashes in my_strtod / +--echo # Value_source::Converter_strntod::Converter_strntod with DEFAULT(blob) +--echo # +--echo # MDEV-24942 Server crashes in _ma_rec_pack / _ma_write_blob_record with +--echo # DEFAULT() on BLOB +--echo # + +CREATE TABLE t1 (id INT, f MEDIUMTEXT NOT NULL DEFAULT 'A'); +INSERT INTO t1 VALUES (1,'foo'),(2,'bar'); +SELECT f FROM t1 GROUP BY id ORDER BY DEFAULT(f); +SELECT DEFAULT(f) AS h FROM t1 HAVING h > 5; +SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 0; +SELECT DEFAULT(f) AS h FROM t1 HAVING h >= 'A'; + +alter table t1 add column b int default (rand()+1+3); +--replace_column 1 # +select default(b) AS h FROM t1 HAVING h > "2"; +drop table t1; diff --git a/sql/item.cc b/sql/item.cc index 522fef57699..7b15c7ddb43 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9341,7 +9341,6 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) } thd->column_usage= save_column_usage; - real_arg= arg->real_item(); if (real_arg->type() != FIELD_ITEM) { @@ -9364,7 +9363,7 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) def_field->reset_fields(); // If non-constant default value expression or a blob if (def_field->default_value && - (def_field->default_value->flags || def_field->flags & BLOB_FLAG)) + (def_field->default_value->flags || (def_field->flags & BLOB_FLAG))) { uchar *newptr= (uchar*) thd->alloc(1+def_field->pack_length()); if (!newptr) @@ -9461,11 +9460,53 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions) return Item_field::save_in_field(field_arg, no_conversions); } +double Item_default_value::val_result() +{ + calculate(); + return Item_field::val_result(); +} + +longlong Item_default_value::val_int_result() +{ + calculate(); + return Item_field::val_int_result(); +} + +String *Item_default_value::str_result(String* tmp) +{ + calculate(); + return Item_field::str_result(tmp); +} + +bool Item_default_value::val_bool_result() +{ + calculate(); + return Item_field::val_bool_result(); +} + +bool Item_default_value::is_null_result() +{ + calculate(); + return Item_field::is_null_result(); +} + +my_decimal *Item_default_value::val_decimal_result(my_decimal *decimal_value) +{ + calculate(); + return Item_field::val_decimal_result(decimal_value); +} + +bool Item_default_value::get_date_result(MYSQL_TIME *ltime,ulonglong fuzzydate) +{ + calculate(); + return Item_field::get_date_result(ltime, fuzzydate); +} + table_map Item_default_value::used_tables() const { if (!field || !field->default_value) return static_cast<table_map>(0); - if (!field->default_value->expr) // not fully parsed field + if (!field->default_value->expr) // not fully parsed field return static_cast<table_map>(RAND_TABLE_BIT); return field->default_value->expr->used_tables(); } diff --git a/sql/item.h b/sql/item.h index 9200dd80ee8..9fa384f0947 100644 --- a/sql/item.h +++ b/sql/item.h @@ -5859,6 +5859,16 @@ class Item_default_value : public Item_field longlong val_int(); my_decimal *val_decimal(my_decimal *decimal_value); bool get_date(MYSQL_TIME *ltime,ulonglong fuzzydate); + + /* Result variants */ + double val_result(); + longlong val_int_result(); + String *str_result(String* tmp); + my_decimal *val_decimal_result(my_decimal *val); + bool val_bool_result(); + bool is_null_result(); + bool get_date_result(MYSQL_TIME *ltime,ulonglong fuzzydate); + bool send(Protocol *protocol, st_value *buffer); int save_in_field(Field *field_arg, bool no_conversions); bool save_in_param(THD *thd, Item_param *param) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7658d843d8b..ce820946908 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -17224,7 +17224,13 @@ Field *Item::create_field_for_schema(THD *thd, TABLE *table) the record in the original table. If modify_item is 0 then fill_record() will update the temporary table - + @param table_cant_handle_bit_fields + Set to 1 if the temporary table cannot handle bit + fields. Only set for heap tables when the bit field + is part of an index. + @param make_copy_field + Set when using with rollup when we want to have + an exact copy of the field. @retval 0 on error @retval @@ -17261,8 +17267,22 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); return result; } - case Item::FIELD_ITEM: case Item::DEFAULT_VALUE_ITEM: + { + Field *field= ((Item_default_value*) item)->field; + if (field->default_value && (field->flags & BLOB_FLAG)) + { + /* + We have to use a copy function when using a blob with default value + as the we have to calcuate the default value before we can use it. + */ + return create_tmp_field_from_item(thd, item, table, + (make_copy_field ? 0 : copy_func), + modify_item); + } + } + /* Fall through */ + case Item::FIELD_ITEM: case Item::CONTEXTUALLY_TYPED_VALUE_ITEM: case Item::INSERT_VALUE_ITEM: case Item::TRIGGER_FIELD_ITEM: -- 2.30.9