[MDEV-24840] Crash caused by query with IN subquery containing union of two table value costructors Created: 2021-02-11  Updated: 2021-06-10  Resolved: 2021-02-16

Status: Closed
Project: MariaDB Server
Component/s: Optimizer
Affects Version/s: None
Fix Version/s: 10.3.29, 10.4.19, 10.5.10, 10.6.0

Type: Bug Priority: Major
Reporter: Igor Babaev Assignee: Igor Babaev
Resolution: Fixed Votes: 0
Labels: None


 Description   

The following test case causes a crash of the server:

create table t1 (a int) engine=myisam;
insert into t1 values (3), (7), (1);
select a from t1 where a in (values (7) union values (8));

"mysqld" received signal SIGSEGV, Segmentation fault.
0x0000555555d7a212 in st_select_lex_unit::optimize (this=0x7fff90013f80) at /home/igor/maria-git/10.3-mdev-22786/sql/sql_union.cc:1430:
 
1428         sl->join->select_options=
1429           (select_limit_cnt == HA_POS_ERROR || sl->braces) ?
1430           sl->options & ~OPTION_FOUND_ROWS : sl->options |



 Comments   
Comment by Igor Babaev [ 2021-02-11 ]

The crash happens for the following reason.
The function Item_subselect::fix_fields contains the loop:

  for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
  {
    if (sl->tvc)
    {
      wrap_tvc_into_select(thd, sl);
    }
  }

that is supposed to look trough all union operands at the top level of the processed IN/ALL/ANY subquery and wrap each table value constructor into a select:

<values ...> => select *  from (<value...>) t

This transformation allows us to use all optimizations applied to multi-select IN subqueries.
Apparently this transformation changes the selects of the union. If a TVC is transformed then it is substituted for a <wrapping select> in the union chain. To get the next element in the chain we should have used
<wrapping select> ->next_select() instead of sl ->next_select() that returns 0. As a result the loop ends prematurely and any TVC following the first one in the chain is not wrapped into select.
For the reported test case we have after the above loop:

select a from t1 where a in (select * from (values (7)) tvc_0 union values (8));

Such queries are not expected by the optimizer phase and cause crashes.

Comment by Igor Babaev [ 2021-02-11 ]

The easiest solution for the problem is to use the loop

  SELECT_LEX *next_sl= 0;
  for (SELECT_LEX *sl= unit->first_select(); sl; sl= next_sl)
  {
    next_sl= sl->next_select();
    if (sl->tvc)
    {
      wrap_tvc_into_select(thd, sl);
    }
  } 

Yet I prefer to return the new wrapping select by the function Item_subselect::wrap_tvc_into_select in the case of success. In the case of failure the function will return 0;

Comment by Oleksandr Byelkin [ 2021-02-11 ]

OK to push

Generated at Thu Feb 08 09:33:05 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.