Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-24840

Crash caused by query with IN subquery containing union of two table value costructors

Details

    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 |
      

      Attachments

        Activity

          igor Igor Babaev added a comment -

          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.

          igor Igor Babaev added a comment - 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.
          igor Igor Babaev added a comment -

          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;

          igor Igor Babaev added a comment - 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;

          OK to push

          sanja Oleksandr Byelkin added a comment - OK to push

          People

            igor Igor Babaev
            igor Igor Babaev
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Git Integration

                Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.