revision-id: 60c1b15328165ce215071b4f307fd20bc8a0b545 (mariadb-10.4.28-105-g60c1b15) parent(s): fc6e8a3d3264078bed28632a289130b1dc24daea author: Igor Babaev committer: Igor Babaev timestamp: 2023-04-21 13:46:14 -0700 message: MDEV-31102 Crash when pushing condition into view defined as union This bug could manifest itself at the first execution of prepared statement created for queries using a materialized view defined as union. A crash could happen for sure if the query contained a condition pushable into the view and this condition was over the column defined via a complex string expression requiring implicit conversion from one charset to another for some of its sub-expressions. The bug could cause crashes when executing PS for some other queries whose optimization needed building clones for such expressions. This bug was introduced in the patch for MDEV-29988 where the class Item_direct_ref_to_item was added. The implementations of the virtual methods get_copy() and build_clone() were invalid for the class and this could cause crashes after the method build_clone() was called for expressions containing objects of the Item_direct_ref_to_item type. Approved by Sergei Golubchik <serg@mariadb.com> --- mysql-test/main/derived_cond_pushdown.result | 83 ++++++++++++++++++++++++++++ mysql-test/main/derived_cond_pushdown.test | 30 ++++++++++ sql/item.h | 17 +++++- 3 files changed, 128 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index 41f9ac6..4b202ea 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -18275,4 +18275,87 @@ id select_type table type possible_keys key key_len ref rows Extra 3 DERIVED t1 ALL NULL NULL NULL NULL 3 Using temporary drop view v1; drop table t1; +# +# MDEV-31102: execution of PS for query where pushdown of condition +# into view defined as union is applied +# +create table t1 ( +n int, +lv varchar(31) charset latin1, +mv varchar(31) charset utf8mb3 +) engine=myisam; +insert into t1 values (1,'aa','xxx'), ('2','bb','yyy'), (3,'cc','zzz'); +create view v1 as +select case when n=1 then lv when n=2 then mv else NULL end as r from t1 +union +select 'a'; +select * from v1 where r < 'x'; +r +aa +a +explain extended select * from v1 where r < 'x'; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 PRIMARY <derived2> ALL NULL NULL NULL NULL 3 100.00 Using where +2 DERIVED t1 ALL NULL NULL NULL NULL 3 100.00 Using where +3 UNION NULL NULL NULL NULL NULL NULL NULL NULL No tables used +NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL NULL +Warnings: +Note 1003 /* select#1 */ select `v1`.`r` AS `r` from `test`.`v1` where `v1`.`r` < 'x' +explain format=json select * from v1 where r < 'x'; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "<derived2>", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "v1.r < 'x'", + "materialized": { + "query_block": { + "union_result": { + "table_name": "<union2,3>", + "access_type": "ALL", + "query_specifications": [ + { + "query_block": { + "select_id": 2, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "case when t1.n = 1 then convert(t1.lv using utf8) when t1.n = 2 then t1.mv else NULL end < 'x'" + } + } + }, + { + "query_block": { + "select_id": 3, + "operation": "UNION", + "table": { + "message": "No tables used" + } + } + } + ] + } + } + } + } + } +} +prepare stmt from "select * from v1 where r < 'x'"; +execute stmt; +r +aa +a +execute stmt; +r +aa +a +deallocate prepare stmt; +drop view v1; +drop table t1; # End of 10.4 tests diff --git a/mysql-test/main/derived_cond_pushdown.test b/mysql-test/main/derived_cond_pushdown.test index 6cfe23b..b4e131d 100644 --- a/mysql-test/main/derived_cond_pushdown.test +++ b/mysql-test/main/derived_cond_pushdown.test @@ -3942,4 +3942,34 @@ explain select * from v1; drop view v1; drop table t1; +--echo # +--echo # MDEV-31102: execution of PS for query where pushdown of condition +--echo # into view defined as union is applied +--echo # + +create table t1 ( + n int, + lv varchar(31) charset latin1, + mv varchar(31) charset utf8mb3 +) engine=myisam; +insert into t1 values (1,'aa','xxx'), ('2','bb','yyy'), (3,'cc','zzz'); +create view v1 as +select case when n=1 then lv when n=2 then mv else NULL end as r from t1 +union +select 'a'; + +let $q= +select * from v1 where r < 'x'; + +eval $q; +eval explain extended $q; +eval explain format=json $q; +eval prepare stmt from "$q"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +drop view v1; +drop table t1; + --echo # End of 10.4 tests diff --git a/sql/item.h b/sql/item.h index 31568aa..1e0caaa 100644 --- a/sql/item.h +++ b/sql/item.h @@ -7647,7 +7647,7 @@ class Item_direct_ref_to_item : public Item_direct_ref Item *get_tmp_table_item(THD *thd) { return m_item->get_tmp_table_item(thd); } Item *get_copy(THD *thd) - { return m_item->get_copy(thd); } + { return get_item_copy<Item_direct_ref_to_item>(thd, this); } COND *build_equal_items(THD *thd, COND_EQUAL *inherited, bool link_item_fields, COND_EQUAL **cond_equal_ref) @@ -7715,7 +7715,20 @@ class Item_direct_ref_to_item : public Item_direct_ref bool excl_dep_on_grouping_fields(st_select_lex *sel) { return m_item->excl_dep_on_grouping_fields(sel); } bool is_expensive() { return m_item->is_expensive(); } - Item* build_clone(THD *thd) { return get_copy(thd); } + void set_item(Item *item) { m_item= item; } + Item *build_clone(THD *thd) + { + Item *clone_item= m_item->build_clone(thd); + if (clone_item) + { + Item_direct_ref_to_item *copy= (Item_direct_ref_to_item *) get_copy(thd); + if (!copy) + return 0; + copy->set_item(clone_item); + return copy; + } + return 0; + } void split_sum_func(THD *thd, Ref_ptr_array ref_pointer_array, List<Item> &fields, uint flags)