From ba34657cd22fc831bdfd06fd088644b288043652 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Wed, 22 Jan 2025 22:08:56 +0100 Subject: [PATCH] MDEV-35238 (MDEV-34922) Wrong results from a tables with a single record and an aggregate The problem is that copy function was used in field list but never copied in this execution path. So copy should be performed before returning result. Protection against uninitialized copy usage added. --- mysql-test/main/group_by.result | 64 +++++++++++++++++++ mysql-test/main/group_by.test | 22 +++++++ .../type_inet/type_inet6_engines.inc | 13 ++++ .../type_inet/type_inet6_innodb.result | 12 ++++ .../type_inet/type_inet6_memory.result | 12 ++++ .../type_inet/type_inet6_myisam.result | 12 ++++ sql/item.cc | 8 +++ sql/item.h | 22 ++++++- sql/sql_select.cc | 2 + 9 files changed, 166 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/group_by.result b/mysql-test/main/group_by.result index 881febb13a4..27f2c34a6d4 100644 --- a/mysql-test/main/group_by.result +++ b/mysql-test/main/group_by.result @@ -2997,5 +2997,69 @@ UPDATE t1 SET c=1 ORDER BY (SELECT c); ERROR 42S22: Reference 'c' not supported (forward reference in item list) DROP TABLE t1; # +# MDEV-35238: Wrong results from a tables with a single record and an aggregate +# +CREATE OR REPLACE TABLE t1 (a int) ENGINE=myisam; +SELECT 1+0, min(1) FROM t1 WHERE if(uuid_short(), a,1); +1+0 min(1) +1 NULL +explain format=json SELECT 1+0, min(1) FROM t1 WHERE if(uuid_short(), a,1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "message": "Impossible WHERE noticed after reading const tables" + } + } +} +INSERT INTO t1 VALUES (NULL); +SELECT 1+0, min(1) FROM t1 WHERE if(uuid_short(), a,1); +1+0 min(1) +1 NULL +explain format=json SELECT 1+0, min(1) FROM t1 WHERE if(uuid_short(), a,1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "pseudo_bits_condition": "if(uuid_short(),NULL,1)", + "table": { + "table_name": "t1", + "access_type": "system", + "rows": 1, + "filtered": 100 + } + } +} +DROP TABLE t1; +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=myisam; +INSERT INTO t1 VALUES (1); +CREATE TABLE t2 (a int NOT NULL) ENGINE=myisam; +INSERT INTO t2 VALUES (10); +SELECT 1+0, MIN(t1.a) FROM t1,t2 WHERE t2.a = rand(); +1+0 MIN(t1.a) +1 1 +explain format=json SELECT 1+0, MIN(t1.a) FROM t1,t2 WHERE t2.a = rand(); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "pseudo_bits_condition": "10 = rand()", + "table": { + "table_name": "t1", + "access_type": "system", + "rows": 1, + "filtered": 100 + }, + "table": { + "table_name": "t2", + "access_type": "system", + "rows": 1, + "filtered": 100 + } + } +} +DROP TABLE t1,t2; +# # End of 10.5 tests # diff --git a/mysql-test/main/group_by.test b/mysql-test/main/group_by.test index eaa0d060fe9..19f2e6582ae 100644 --- a/mysql-test/main/group_by.test +++ b/mysql-test/main/group_by.test @@ -2152,6 +2152,28 @@ UPDATE t1 SET c=1 ORDER BY (SELECT c); UPDATE t1 SET c=1 ORDER BY (SELECT c); DROP TABLE t1; +--echo # +--echo # MDEV-35238: Wrong results from a tables with a single record and an aggregate +--echo # +CREATE OR REPLACE TABLE t1 (a int) ENGINE=myisam; +SELECT 1+0, min(1) FROM t1 WHERE if(uuid_short(), a,1); +explain format=json SELECT 1+0, min(1) FROM t1 WHERE if(uuid_short(), a,1); +INSERT INTO t1 VALUES (NULL); +SELECT 1+0, min(1) FROM t1 WHERE if(uuid_short(), a,1); +explain format=json SELECT 1+0, min(1) FROM t1 WHERE if(uuid_short(), a,1); +DROP TABLE t1; + +CREATE TABLE t1 (a int PRIMARY KEY) ENGINE=myisam; +INSERT INTO t1 VALUES (1); + +CREATE TABLE t2 (a int NOT NULL) ENGINE=myisam; +INSERT INTO t2 VALUES (10); + +SELECT 1+0, MIN(t1.a) FROM t1,t2 WHERE t2.a = rand(); +explain format=json SELECT 1+0, MIN(t1.a) FROM t1,t2 WHERE t2.a = rand(); + +DROP TABLE t1,t2; + --echo # --echo # End of 10.5 tests --echo # diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_engines.inc b/plugin/type_inet/mysql-test/type_inet/type_inet6_engines.inc index 596036fc0ee..9cf91169528 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6_engines.inc +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_engines.inc @@ -36,3 +36,16 @@ SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6); EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=CAST('::ff' AS INET6); DROP TABLE t1; + +--echo # +--echo # MDEV-34922: Assertion `value.length() == FbtImpl::binary_length()' failed in +--echo # Type_handler_fbt::Field_fbt::store_native, +--echo # Assertion `item->null_value' failed in Type_handler::Item_send_str +--echo # + +CREATE TABLE t1 (a datetime); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM (SELECT cast('::' AS INET6),min(1) FROM t1 WHERE if(uuid_short(), a,1)) dt; +DROP TABLE t1; + +--echo # End of 10.5 tests diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.result index deb1c718b49..dd5e3ba9f7f 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_innodb.result @@ -88,6 +88,18 @@ Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = INET6'::ff' DROP TABLE t1; # +# MDEV-34922: Assertion `value.length() == FbtImpl::binary_length()' failed in +# Type_handler_fbt::Field_fbt::store_native, +# Assertion `item->null_value' failed in Type_handler::Item_send_str +# +CREATE TABLE t1 (a datetime); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM (SELECT cast('::' AS INET6),min(1) FROM t1 WHERE if(uuid_short(), a,1)) dt; +cast('::' AS INET6) min(1) +:: NULL +DROP TABLE t1; +# End of 10.5 tests +# # MDEV-26742 Assertion `field->type_handler() == this' failed in FixedBinTypeBundle::Type_handler_fbt::stored_field_cmp_to_item # CREATE TABLE t1 (pk inet6, c text) engine=myisam; diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.result index e805b167136..9bf8e58fb0b 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_memory.result @@ -155,5 +155,17 @@ Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = INET6'::ff' DROP TABLE t1; # +# MDEV-34922: Assertion `value.length() == FbtImpl::binary_length()' failed in +# Type_handler_fbt::Field_fbt::store_native, +# Assertion `item->null_value' failed in Type_handler::Item_send_str +# +CREATE TABLE t1 (a datetime); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM (SELECT cast('::' AS INET6),min(1) FROM t1 WHERE if(uuid_short(), a,1)) dt; +cast('::' AS INET6) min(1) +:: NULL +DROP TABLE t1; +# End of 10.5 tests +# # End of 10.5 tests # diff --git a/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.result b/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.result index c2577ef44df..c05830f55c7 100644 --- a/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.result +++ b/plugin/type_inet/mysql-test/type_inet/type_inet6_myisam.result @@ -88,6 +88,18 @@ Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = INET6'::ff' DROP TABLE t1; # +# MDEV-34922: Assertion `value.length() == FbtImpl::binary_length()' failed in +# Type_handler_fbt::Field_fbt::store_native, +# Assertion `item->null_value' failed in Type_handler::Item_send_str +# +CREATE TABLE t1 (a datetime); +INSERT INTO t1 VALUES (NULL); +SELECT * FROM (SELECT cast('::' AS INET6),min(1) FROM t1 WHERE if(uuid_short(), a,1)) dt; +cast('::' AS INET6) min(1) +:: NULL +DROP TABLE t1; +# End of 10.5 tests +# # MDEV-26742 Assertion `field->type_handler() == this' failed in FixedBinTypeBundle::Type_handler_fbt::stored_field_cmp_to_item # CREATE TABLE t1 (c varchar(64), key(c)) engine=myisam; diff --git a/sql/item.cc b/sql/item.cc index 7143bced98b..9498d816bb0 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5218,6 +5218,7 @@ bool Item_param::assign_default(Field *field) double Item_copy_string::val_real() { + DBUG_ASSERT(copied_in); int err_not_used; char *end_not_used; return (null_value ? 0.0 : @@ -5228,6 +5229,7 @@ double Item_copy_string::val_real() longlong Item_copy_string::val_int() { + DBUG_ASSERT(copied_in); int err; return null_value ? 0 : str_value.charset()->strntoll(str_value.ptr(), str_value.length(), 10, @@ -5237,6 +5239,7 @@ longlong Item_copy_string::val_int() int Item_copy_string::save_in_field(Field *field, bool no_conversions) { + DBUG_ASSERT(copied_in); return save_str_value_in_field(field, &str_value); } @@ -5247,11 +5250,15 @@ void Item_copy_string::copy() if (res && res != &str_value) str_value.copy(*res); null_value=item->null_value; +#ifndef DBUG_OFF + copied_in= 1; +#endif } /* ARGSUSED */ String *Item_copy_string::val_str(String *str) { + DBUG_ASSERT(copied_in); // Item_copy_string is used without fix_fields call if (null_value) return (String*) 0; @@ -5261,6 +5268,7 @@ String *Item_copy_string::val_str(String *str) my_decimal *Item_copy_string::val_decimal(my_decimal *decimal_value) { + DBUG_ASSERT(copied_in); // Item_copy_string is used without fix_fields call if (null_value) return (my_decimal *) 0; diff --git a/sql/item.h b/sql/item.h index ce02b0edda1..d60d5c01985 100644 --- a/sql/item.h +++ b/sql/item.h @@ -6383,8 +6383,15 @@ protected: Type_std_attributes::set(item); name= item->name; set_handler(item->type_handler()); +#ifndef DBUG_OFF + copied_in= 0; +#endif } +#ifndef DBUG_OFF + bool copied_in; +#endif + public: /** @@ -6451,7 +6458,10 @@ public: double val_real() override; longlong val_int() override; bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override - { return get_date_from_string(thd, ltime, fuzzydate); } + { + DBUG_ASSERT(copied_in); + return get_date_from_string(thd, ltime, fuzzydate); + } void copy() override; int save_in_field(Field *field, bool no_conversions) override; Item *do_get_copy(THD *thd) const override @@ -6481,9 +6491,13 @@ public: null_value= tmp.is_null(); m_value= tmp.is_null() ? Timestamp_or_zero_datetime() : Timestamp_or_zero_datetime(tmp); +#ifndef DBUG_OFF + copied_in=1; +#endif } int save_in_field(Field *field, bool) override { + DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); if (null_value) return set_field_to_null(field); @@ -6492,30 +6506,35 @@ public: } longlong val_int() override { + DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value ? 0 : m_value.to_datetime(current_thd).to_longlong(); } double val_real() override { + DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value ? 0e0 : m_value.to_datetime(current_thd).to_double(); } String *val_str(String *to) override { + DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value ? NULL : m_value.to_datetime(current_thd).to_string(to, decimals); } my_decimal *val_decimal(my_decimal *to) override { + DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value ? NULL : m_value.to_datetime(current_thd).to_decimal(to); } bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { + DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); bool res= m_value.to_TIME(thd, ltime, fuzzydate); DBUG_ASSERT(!res); @@ -6523,6 +6542,7 @@ public: } bool val_native(THD *thd, Native *to) override { + DBUG_ASSERT(copied_in); DBUG_ASSERT(sane()); return null_value || m_value.to_native(to, decimals); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f0da265f86b..bb7cc72e623 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -20788,6 +20788,8 @@ do_select(JOIN *join, Procedure *procedure) */ clear_tables(join, &cleared_tables); } + if (join->tmp_table_param.copy_funcs.elements) + copy_fields(&join->tmp_table_param); if (!join->having || join->having->val_int()) { List *columns_list= (procedure ? &join->procedure_fields_list :