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

Crash of INSERT SELECT when preparing structures for split optimization

Details

    • Bug
    • Status: Stalled (View Workflow)
    • Critical
    • Resolution: Unresolved
    • 11.3.0, 10.4(EOL), 10.5, 10.6, 10.11, 11.0(EOL), 11.1(EOL), 11.2(EOL)
    • 10.5, 10.6, 10.11, 11.4
    • Optimizer
    • Ubuntu 20.04

    Description

      Run these queries in debug build:

      CREATE TABLE v0 ( v1 INT UNIQUE ) ;
      INSERT INTO v0 ( v1 ) VALUES ( ( SELECT 1 FROM ( SELECT v1 FROM v0 GROUP BY v1 ) AS v6 NATURAL JOIN v0 AS v2 NATURAL JOIN v0 AS v4 NATURAL JOIN v0 AS v3 NATURAL JOIN ( SELECT v1 FROM v0 ) AS v7 ) ) ;
      

      Will trigger Segmentation fault.

      GDB info:
      #0  0x00005555572f3e53 in optimize_keyuse (join=0x62900012e928, keyuse_array=0x62900012ec90)
          at /home/wx/mariadb-11.3.0/sql/sql_select.cc:7667
      #1  0x000055555793d67c in JOIN::add_keyuses_for_splitting (this=0x62900012e928) at /home/wx/mariadb-11.3.0/sql/opt_split.cc:847
      #2  0x000055555793daee in st_join_table::add_keyuses_for_splitting (this=0x62d00000a4a8) at /home/wx/mariadb-11.3.0/sql/opt_split.cc:874
      #3  0x00005555572e509c in make_join_statistics (join=0x62900012e228, tables_list=..., keyuse_array=0x62900012e590)
          at /home/wx/mariadb-11.3.0/sql/sql_select.cc:6020
      #4  0x00005555572c2c36 in JOIN::optimize_inner (this=0x62900012e228) at /home/wx/mariadb-11.3.0/sql/sql_select.cc:2624
      #5  0x00005555572bbba6 in JOIN::optimize (this=0x62900012e228) at /home/wx/mariadb-11.3.0/sql/sql_select.cc:1944
      #6  0x0000555557143851 in st_select_lex::optimize_unflattened_subqueries (this=0x6290000f5d80, const_only=false)
          at /home/wx/mariadb-11.3.0/sql/sql_lex.cc:4916
      #7  0x00005555570f2cc5 in mysql_insert (thd=0x62c0001d0288, table_list=0x6290000f5508, fields=..., values_list=..., update_fields=..., 
          update_values=..., duplic=DUP_ERROR, ignore=false, result=0x0) at /home/wx/mariadb-11.3.0/sql/sql_insert.cc:875
      #8  0x00005555571c1ecb in mysql_execute_command (thd=0x62c0001d0288, is_called_from_prepared_stmt=false)
          at /home/wx/mariadb-11.3.0/sql/sql_parse.cc:4417
      #9  0x00005555571d95e2 in mysql_parse (thd=0x62c0001d0288, 
          rawbuf=0x6290000f52a8 "INSERT INTO v0 ( v1 ) VALUES ( ( SELECT 1 FROM ( SELECT v1 FROM v0 GROUP BY v1 ) AS v6 NATURAL JOIN v0 AS v2 NATURAL JOIN v0 AS v4 NATURAL JOIN v0 AS v3 NATURAL JOIN ( SELECT v1 FROM v0 ) AS v7 ) )", length=197, parser_state=0x7fffe33c0870)
          at /home/wx/mariadb-11.3.0/sql/sql_parse.cc:7734
      #10 0x00005555571b1237 in dispatch_command (command=COM_QUERY, thd=0x62c0001d0288, 
          packet=0x6290000eb289 "INSERT INTO v0 ( v1 ) VALUES ( ( SELECT 1 FROM ( SELECT v1 FROM v0 GROUP BY v1 ) AS v6 NATURAL JOIN v0 AS v2 NATURAL JOIN v0 AS v4 NATURAL JOIN v0 AS v3 NATURAL JOIN ( SELECT v1 FROM v0 ) AS v7 ) )", packet_length=197, blocking=true)
          at /home/wx/mariadb-11.3.0/sql/sql_parse.cc:1893
      #11 0x00005555571adf7c in do_command (thd=0x62c0001d0288, blocking=true) at /home/wx/mariadb-11.3.0/sql/sql_parse.cc:1406
      #12 0x000055555768e557 in do_handle_one_connection (connect=0x61100004df08, put_in_cache=true)
          at /home/wx/mariadb-11.3.0/sql/sql_connect.cc:1445
      #13 0x000055555768deb4 in handle_one_connection (arg=0x61100004df08) at /home/wx/mariadb-11.3.0/sql/sql_connect.cc:1347
      #14 0x00005555582fa350 in pfs_spawn_thread (arg=0x618000005108) at /home/wx/mariadb-11.3.0/storage/perfschema/pfs.cc:2201
      #15 0x00007ffff7115609 in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0
      #16 0x00007ffff6ce8133 in clone () from /lib/x86_64-linux-gnu/libc.so.6
      

      Attachments

        Issue Links

          Activity

            If we use table t2 similar to table t1 and with the same contents in the grouping derived table

            CREATE TABLE t2 ( i int, KEY (i) ) engine=innodb;
            INSERT INTO t2 VALUES (1), (2);
            INSERT INTO t1
            SELECT a.i FROM (SELECT i FROM t2 GROUP BY i) a, (SELECT i FROM t1) c  WHERE c.i = a.i;
            

            we observe the same kind of crash.

            If we add more rows to table t2 in the following way:

            INSERT INTO t2 SELECT i FROM t2;
            INSERT INTO t2 SELECT i+2 FROM t2;
            INSERT INTO t2 SELECT i+4 FROM t2;
            ANALYZE TABLE t2 PERSISTENT FOR ALL;
            

            we have the same crash for both InnoDB and MyISAM engines.

            igor Igor Babaev (Inactive) added a comment - If we use table t2 similar to table t1 and with the same contents in the grouping derived table CREATE TABLE t2 ( i int , KEY (i) ) engine=innodb; INSERT INTO t2 VALUES (1), (2); INSERT INTO t1 SELECT a.i FROM ( SELECT i FROM t2 GROUP BY i) a, ( SELECT i FROM t1) c WHERE c.i = a.i; we observe the same kind of crash. If we add more rows to table t2 in the following way: INSERT INTO t2 SELECT i FROM t2; INSERT INTO t2 SELECT i+2 FROM t2; INSERT INTO t2 SELECT i+4 FROM t2; ANALYZE TABLE t2 PERSISTENT FOR ALL ; we have the same crash for both InnoDB and MyISAM engines.
            igor Igor Babaev (Inactive) added a comment - - edited

            If we introduce a new flag TABLE_LIST::is_forced_to_be_materialized used for derived tables and views with is set to TRUE when a mergeable derived table / view is forced to be materialized and utilize this flag in Item_direct_view_ref::used_tables() in the the following way:

            diff --git a/sql/item.cc b/sql/item.cc
            index 9ba0094..3dd7ffe 100644
            --- a/sql/item.cc
            +++ b/sql/item.cc
            @@ -10939,6 +10939,9 @@ table_map Item_direct_view_ref::used_tables() const
               if (get_depended_from())
                 return OUTER_REF_TABLE_BIT;
             
            +  if (view->is_forced_to_be_materialized)
            +    return (*ref)->used_tables();
            +
               if (view->is_merged_derived() || view->merged || !view->table)
               {
                 table_map used= (*ref)->used_tables();
            diff --git a/sql/sql_base.cc b/sql/sql_base.cc
            index 8738f18..9eb100a 100644
            --- a/sql/sql_base.cc
            +++ b/sql/sql_base.cc
            @@ -1179,6 +1179,7 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
                              ("convert merged to materialization to resolve the conflict"));
                   derived->change_refs_to_fields();
                   derived->set_materialized_derived();
            +      derived->is_forced_to_be_materialized= true;
                   goto retry;
                 }
               }
            diff --git a/sql/table.h b/sql/table.h
            index 6910ff0..79e789c 100644
            --- a/sql/table.h
            +++ b/sql/table.h
            @@ -2611,6 +2611,8 @@ struct TABLE_LIST
               bool          merged;
               bool          merged_for_insert;
               bool          sequence;  /* Part of NEXTVAL/CURVAL/LASTVAL */
            +  /* TRUE <=> materialization of derived tbale / view has been forced */
            +  bool          is_forced_to_be_materialized;
             
               /*
                 Items created by create_view_field and collected to change them in case
            

            then we have the following results for both InnoDB and MyISAM engines:

            MariaDB [test]> EXPLAIN EXTENDED INSERT INTO t1 SELECT a.i FROM (SELECT i FROM t2 GROUP BY i) a, (SELECT i FROM t1) c  WHERE c.i = a.i;
            +------+-----------------+------------+-------+---------------+------+---------+------+------+----------+-------------+
            | id   | select_type     | table      | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
            +------+-----------------+------------+-------+---------------+------+---------+------+------+----------+-------------+
            |    1 | PRIMARY         | <derived3> | ALL   | NULL          | NULL | NULL    | NULL | 2    |   100.00 | Using where |
            |    1 | PRIMARY         | <derived2> | ref   | key0          | key0 | 5       | c.i  | 2    |   100.00 |             |
            |    3 | DERIVED         | t1         | index | NULL          | i    | 5       | NULL | 2    |   100.00 | Using index |
            |    2 | LATERAL DERIVED | t2         | ref   | i             | i    | 5       | c.i  | 2    |    56.25 | Using index |
            +------+-----------------+------------+-------+---------------+------+---------+------+------+----------+-------------+
            4 rows in set, 1 warning (0.008 sec)
             
            MariaDB [test]> INSERT INTO t1 SELECT a.i FROM (SELECT i FROM t2 GROUP BY i) a, (SELECT i FROM t1) c  WHERE c.i = a.i;ERROR 2006 (HY000): MySQL server has gone away
            No connection. Trying to reconnect...
            Connection id:    3
            Current database: test
             
            Query OK, 2 rows affected (0.018 sec)
            Records: 2  Duplicates: 0  Warnings: 0
             
            MariaDB [test]> SELECT * FROM t1;
            +------+
            | i    |
            +------+
            |    1 |
            |    1 |
            |    2 |
            |    2 |
            +------+
            4 rows in set (0.001 sec)
            

            It can be checked that after this patch is applied all mtr tests from the main suite pass (with --ps-protocol and --view-protocol as well)

            igor Igor Babaev (Inactive) added a comment - - edited If we introduce a new flag TABLE_LIST::is_forced_to_be_materialized used for derived tables and views with is set to TRUE when a mergeable derived table / view is forced to be materialized and utilize this flag in Item_direct_view_ref::used_tables() in the the following way: diff --git a/sql/item.cc b/sql/item.cc index 9ba0094..3dd7ffe 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -10939,6 +10939,9 @@ table_map Item_direct_view_ref::used_tables() const if (get_depended_from()) return OUTER_REF_TABLE_BIT; + if (view->is_forced_to_be_materialized) + return (*ref)->used_tables(); + if (view->is_merged_derived() || view->merged || !view->table) { table_map used= (*ref)->used_tables(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8738f18..9eb100a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1179,6 +1179,7 @@ TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, ("convert merged to materialization to resolve the conflict")); derived->change_refs_to_fields(); derived->set_materialized_derived(); + derived->is_forced_to_be_materialized= true; goto retry; } } diff --git a/sql/table.h b/sql/table.h index 6910ff0..79e789c 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2611,6 +2611,8 @@ struct TABLE_LIST bool merged; bool merged_for_insert; bool sequence; /* Part of NEXTVAL/CURVAL/LASTVAL */ + /* TRUE <=> materialization of derived tbale / view has been forced */ + bool is_forced_to_be_materialized; /* Items created by create_view_field and collected to change them in case then we have the following results for both InnoDB and MyISAM engines: MariaDB [test]> EXPLAIN EXTENDED INSERT INTO t1 SELECT a.i FROM (SELECT i FROM t2 GROUP BY i) a, (SELECT i FROM t1) c WHERE c.i = a.i; +------+-----------------+------------+-------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +------+-----------------+------------+-------+---------------+------+---------+------+------+----------+-------------+ | 1 | PRIMARY | <derived3> | ALL | NULL | NULL | NULL | NULL | 2 | 100.00 | Using where | | 1 | PRIMARY | <derived2> | ref | key0 | key0 | 5 | c.i | 2 | 100.00 | | | 3 | DERIVED | t1 | index | NULL | i | 5 | NULL | 2 | 100.00 | Using index | | 2 | LATERAL DERIVED | t2 | ref | i | i | 5 | c.i | 2 | 56.25 | Using index | +------+-----------------+------------+-------+---------------+------+---------+------+------+----------+-------------+ 4 rows in set, 1 warning (0.008 sec)   MariaDB [test]> INSERT INTO t1 SELECT a.i FROM (SELECT i FROM t2 GROUP BY i) a, (SELECT i FROM t1) c WHERE c.i = a.i;ERROR 2006 (HY000): MySQL server has gone away No connection. Trying to reconnect... Connection id: 3 Current database: test   Query OK, 2 rows affected (0.018 sec) Records: 2 Duplicates: 0 Warnings: 0   MariaDB [test]> SELECT * FROM t1; +------+ | i | +------+ | 1 | | 1 | | 2 | | 2 | +------+ 4 rows in set (0.001 sec) It can be checked that after this patch is applied all mtr tests from the main suite pass (with --ps-protocol and --view-protocol as well)
            igor Igor Babaev (Inactive) added a comment - - edited

            It's easy to see that forced materialization is required not only in the function find_dup_table(), but in other functions too. To cover other cases it makes sense to set the flag TABLE_LIST::is_forced_to_be_materialized to TRUE in the function TABLE_LIST::change_refs_to_fields():

            --- a/sql/item.cc
            +++ b/sql/item.cc
            @@ -10939,6 +10939,9 @@ table_map Item_direct_view_ref::used_tables() const
               if (get_depended_from())
                 return OUTER_REF_TABLE_BIT;
             
            +  if (view->is_forced_to_be_materialized)
            +    return (*ref)->used_tables();
            +
               if (view->is_merged_derived() || view->merged || !view->table)
               {
                 table_map used= (*ref)->used_tables();
            diff --git a/sql/table.cc b/sql/table.cc
            index 74b478c..7d8eca1 100644
            --- a/sql/table.cc
            +++ b/sql/table.cc
            @@ -9627,6 +9627,8 @@ bool TABLE_LIST::change_refs_to_fields()
                                       (Item*)(materialized_items + idx));
               }
             
            +  is_forced_to_be_materialized= true;
            +
               return FALSE;
             }
             
            diff --git a/sql/table.h b/sql/table.h
            index 6910ff0..454d40d 100644
            --- a/sql/table.h
            +++ b/sql/table.h
            @@ -2611,6 +2611,8 @@ struct TABLE_LIST
               bool          merged;
               bool          merged_for_insert;
               bool          sequence;  /* Part of NEXTVAL/CURVAL/LASTVAL */
            +  /* TRUE <=> materialization of derived tbale / view is to be forced */
            +  bool          is_forced_to_be_materialized;
             
               /*
                 Items created by create_view_field and collected to change them in case
            

            This patch doesn't break any mtr test from the main suite either and it fixes the bug.

            igor Igor Babaev (Inactive) added a comment - - edited It's easy to see that forced materialization is required not only in the function find_dup_table(), but in other functions too. To cover other cases it makes sense to set the flag TABLE_LIST::is_forced_to_be_materialized to TRUE in the function TABLE_LIST::change_refs_to_fields(): --- a/sql/item.cc +++ b/sql/item.cc @@ -10939,6 +10939,9 @@ table_map Item_direct_view_ref::used_tables() const if (get_depended_from()) return OUTER_REF_TABLE_BIT; + if (view->is_forced_to_be_materialized) + return (*ref)->used_tables(); + if (view->is_merged_derived() || view->merged || !view->table) { table_map used= (*ref)->used_tables(); diff --git a/sql/table.cc b/sql/table.cc index 74b478c..7d8eca1 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -9627,6 +9627,8 @@ bool TABLE_LIST::change_refs_to_fields() (Item*)(materialized_items + idx)); } + is_forced_to_be_materialized= true; + return FALSE; } diff --git a/sql/table.h b/sql/table.h index 6910ff0..454d40d 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2611,6 +2611,8 @@ struct TABLE_LIST bool merged; bool merged_for_insert; bool sequence; /* Part of NEXTVAL/CURVAL/LASTVAL */ + /* TRUE <=> materialization of derived tbale / view is to be forced */ + bool is_forced_to_be_materialized; /* Items created by create_view_field and collected to change them in case This patch doesn't break any mtr test from the main suite either and it fixes the bug.
            igor Igor Babaev (Inactive) added a comment - - edited

            The second execution of the problematic INSERT also works as expected:

            MariaDB [test]> PREPARE stmt FROM "              
            INSERT INTO t1
            SELECT a.i FROM (SELECT i FROM t2 GROUP BY i) a, (SELECT i FROM t1) c  WHERE c.i = a.i;
            ";
            Query OK, 0 rows affected (0.002 sec)
            Statement prepared
             
            MariaDB [test]> EXECUTE stmt;
            Query OK, 2 rows affected (0.009 sec)
            Records: 2  Duplicates: 0  Warnings: 0
             
            MariaDB [test]> SELECT * FROM t1;
            +------+
            | i    |
            +------+
            |    1 |
            |    1 |
            |    2 |
            |    2 |
            +------+
            4 rows in set (0.001 sec)
             
            MariaDB [test]> EXECUTE stmt;
            Query OK, 4 rows affected (0.010 sec)
            Records: 4  Duplicates: 0  Warnings: 0
             
            MariaDB [test]> SELECT * FROM t1;
            +------+
            | i    |
            +------+
            |    1 |
            |    1 |
            |    1 |
            |    1 |
            |    2 |
            |    2 |
            |    2 |
            |    2 |
            +------+
            8 rows in set (0.002 sec)
            

            igor Igor Babaev (Inactive) added a comment - - edited The second execution of the problematic INSERT also works as expected: MariaDB [test]> PREPARE stmt FROM " INSERT INTO t1 SELECT a.i FROM (SELECT i FROM t2 GROUP BY i) a, (SELECT i FROM t1) c WHERE c.i = a.i; "; Query OK, 0 rows affected (0.002 sec) Statement prepared   MariaDB [test]> EXECUTE stmt; Query OK, 2 rows affected (0.009 sec) Records: 2 Duplicates: 0 Warnings: 0   MariaDB [test]> SELECT * FROM t1; +------+ | i | +------+ | 1 | | 1 | | 2 | | 2 | +------+ 4 rows in set (0.001 sec)   MariaDB [test]> EXECUTE stmt; Query OK, 4 rows affected (0.010 sec) Records: 4 Duplicates: 0 Warnings: 0   MariaDB [test]> SELECT * FROM t1; +------+ | i | +------+ | 1 | | 1 | | 1 | | 1 | | 2 | | 2 | | 2 | | 2 | +------+ 8 rows in set (0.002 sec)

            oleg.smirnov if you agree with my analysis and suggestions please construct a test case when forced materialization is used for a mergeable derived table whose specification is a join with more than 62 tables.

            igor Igor Babaev (Inactive) added a comment - oleg.smirnov if you agree with my analysis and suggestions please construct a test case when forced materialization is used for a mergeable derived table whose specification is a join with more than 62 tables.

            People

              sanja Oleksandr Byelkin
              Xin Wen Xin Wen
              Votes:
              1 Vote for this issue
              Watchers:
              11 Start watching this issue

              Dates

                Created:
                Updated:

                Git Integration

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