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

Assertion `range->rows >= s->found_records' failed in best_access_path

Details

    Description

      CREATE TABLE t1 (a INT);
      INSERT INTO t1 VALUES (1),(2);
       
      CREATE TABLE t2 (b VARCHAR(10), pk INT, PRIMARY KEY (pk)) ENGINE=MyISAM;
       
      ANALYZE TABLE t1, t2 PERSISTENT FOR ALL; 
       
      SELECT STRAIGHT_JOIN t2.* FROM t1 JOIN t2 WHERE t2.b IS NULL AND t2.pk > 1;
       
      # Cleanup
      DROP TABLE t1, t2;
      

      bb-11.0-release 0c3404d46d337d13bdbe7ff409af3e13a8fb01a4

      mariadbd: /data/src/bb-11.0-release/sql/sql_select.cc:9384: void best_access_path(JOIN*, JOIN_TAB*, table_map, const POSITION*, uint, bool, double, POSITION*, POSITION*): Assertion `range->rows >= s->found_records' failed.
      231104 19:17:13 [ERROR] mysqld got signal 6 ;
       
      #9  0x00007fc466253e32 in __GI___assert_fail (assertion=0x561066570bc0 "range->rows >= s->found_records", file=0x56106656a3c0 "/data/src/bb-11.0-release/sql/sql_select.cc", line=9384, function=0x561066570480 "void best_access_path(JOIN*, JOIN_TAB*, table_map, const POSITION*, uint, bool, double, POSITION*, POSITION*)") at ./assert/assert.c:101
      #10 0x00005610645dd319 in best_access_path (join=0x6290000e9150, s=0x62900026c6a8, remaining_tables=2, join_positions=0x62900026cd58, idx=1, disable_jbuf=false, record_count=2, pos=0x62900026cea8, loose_scan_pos=0x7fc45e851840) at /data/src/bb-11.0-release/sql/sql_select.cc:9384
      #11 0x00005610645e2baa in optimize_straight_join (join=0x6290000e9150, remaining_tables=2) at /data/src/bb-11.0-release/sql/sql_select.cc:10212
      #12 0x00005610645e16d1 in choose_plan (join=0x6290000e9150, join_tables=3, emb_sjm_nest=0x0) at /data/src/bb-11.0-release/sql/sql_select.cc:9922
      #13 0x00005610645c71e4 in make_join_statistics (join=0x6290000e9150, tables_list=..., keyuse_array=0x6290000e94b8) at /data/src/bb-11.0-release/sql/sql_select.cc:6174
      #14 0x00005610645a2620 in JOIN::optimize_inner (this=0x6290000e9150) at /data/src/bb-11.0-release/sql/sql_select.cc:2615
      #15 0x000056106459b53b in JOIN::optimize (this=0x6290000e9150) at /data/src/bb-11.0-release/sql/sql_select.cc:1937
      #16 0x00005610645bd571 in mysql_select (thd=0x62c0000b0218, tables=0x6290000e69b0, fields=..., conds=0x6290000e8688, og_num=0, order=0x0, group=0x0, having=0x0, proc_param=0x0, select_options=2164525826, result=0x6290000e9120, unit=0x62c0000b46b8, select_lex=0x6290000e6340) at /data/src/bb-11.0-release/sql/sql_select.cc:5199
      #17 0x000056106458cca0 in handle_select (thd=0x62c0000b0218, lex=0x62c0000b45e0, result=0x6290000e9120, setup_tables_done_option=0) at /data/src/bb-11.0-release/sql/sql_select.cc:628
      #18 0x00005610644b3166 in execute_sqlcom_select (thd=0x62c0000b0218, all_tables=0x6290000e69b0) at /data/src/bb-11.0-release/sql/sql_parse.cc:6290
      #19 0x00005610644a1616 in mysql_execute_command (thd=0x62c0000b0218, is_called_from_prepared_stmt=false) at /data/src/bb-11.0-release/sql/sql_parse.cc:3961
      #20 0x00005610644bdca6 in mysql_parse (thd=0x62c0000b0218, rawbuf=0x6290000e6238 "SELECT STRAIGHT_JOIN t2.* FROM t1 JOIN t2 WHERE t2.b IS NULL AND t2.pk > 1", length=74, parser_state=0x7fc45e8539e0) at /data/src/bb-11.0-release/sql/sql_parse.cc:8028
      #21 0x0000561064493a0e in dispatch_command (command=COM_QUERY, thd=0x62c0000b0218, packet=0x629000258219 "SELECT STRAIGHT_JOIN t2.* FROM t1 JOIN t2 WHERE t2.b IS NULL AND t2.pk > 1", packet_length=74, blocking=true) at /data/src/bb-11.0-release/sql/sql_parse.cc:1894
      #22 0x0000561064490727 in do_command (thd=0x62c0000b0218, blocking=true) at /data/src/bb-11.0-release/sql/sql_parse.cc:1407
      #23 0x0000561064958078 in do_handle_one_connection (connect=0x608000002cb8, put_in_cache=true) at /data/src/bb-11.0-release/sql/sql_connect.cc:1416
      #24 0x0000561064957a39 in handle_one_connection (arg=0x608000002c38) at /data/src/bb-11.0-release/sql/sql_connect.cc:1318
      #25 0x000056106553cebc in pfs_spawn_thread (arg=0x617000005b98) at /data/src/bb-11.0-release/storage/perfschema/pfs.cc:2201
      #26 0x00007fc4662a8044 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
      #27 0x00007fc46632861c in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81
      

      The failure started happening on 11.0 after this merge:

      commit dd742c2483137b4f2614da2840ea45e11324446c
      Merge: b333ebd4c11 5fd138a0553
      Author: Oleksandr Byelkin
      Date:   Wed Nov 1 15:16:40 2023 +0100
       
          Merge branch 'bb-10.11-release' into bb-11.0-release
      

      However it is not reproducible on 10.11 with the same test case, so I can't bisect it further.

      Attachments

        Issue Links

          Activity

            elenst Elena Stepanova created issue -

            This makes the crash go away:

            diff --git a/sql/sql_select.cc b/sql/sql_select.cc
            index deeefffc6f0..f952058247f 100644
            --- a/sql/sql_select.cc
            +++ b/sql/sql_select.cc
            @@ -5290,6 +5290,7 @@ static bool get_quick_record_count(THD *thd, SQL_SELECT *select,
                 if (error == SQL_SELECT::IMPOSSIBLE_RANGE)
                 {
                   table->reginfo.impossible_range=1;
            +      *quick_count= 0;
                   DBUG_RETURN(false);
                 }
                 if (unlikely(error == SQL_SELECT::ERROR))
            

            how did we get into this...

            psergei Sergei Petrunia added a comment - This makes the crash go away: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index deeefffc6f0..f952058247f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5290,6 +5290,7 @@ static bool get_quick_record_count(THD *thd, SQL_SELECT *select, if (error == SQL_SELECT::IMPOSSIBLE_RANGE) { table->reginfo.impossible_range=1; + *quick_count= 0; DBUG_RETURN(false); } if (unlikely(error == SQL_SELECT::ERROR)) how did we get into this...
            psergei Sergei Petrunia made changes -
            Field Original Value New Value
            Status Open [ 1 ] In Progress [ 3 ]

            Ok the assert

            range->rows >= s->found_records
            

            is hit because range->rows=0 and s->found_rows=1.

            The number 0 comes from the range optimizer (the table has 0 rows, so range optimizer returns 0 rows too)
            The number 1 is from "make 0 be 1" logic in test_quick_select (and possibly elsewehere) for #rows in the table.

            Initially the discrepancy was introduced in 10.6, but the assert is only in 11.0

            The discrepancy was introduced in 10.6 by:

            commit ec2574fd8fd46da765fd60b0ca9650b729073401 (origin/bb-10.6-MDEV-31983-v4)
            Author: Rex <rex.johnston@mariadb.com>
            Date:   Fri Sep 15 08:44:49 2023 +1100
             
                MDEV-31983 jointable materialization subquery optimization ignoring
                
                ...errors, then failing ASSERT.
            ...
                Reviewed-by: Sergei Petrunia, Oleg Smirnov
            

            Before the patch, get_quick_record() count returned 0 if it got "Impossible condition" from test_quick_select():

            static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select,
                                                  TABLE *table,
                                                  const key_map *keys,ha_rows limit)
            {
              ...
                if (likely((error=
                            select->test_quick_select(thd, *(key_map *)keys,
                                                      (table_map) 0,
                                                      limit, 0, FALSE,
                                                      TRUE,     /* remove_where_parts*/
                                                      FALSE, TRUE)) ==
                           1))
                  DBUG_RETURN(select->quick->records);
                if (unlikely(error == -1))
                {
                  table->reginfo.impossible_range=1;
                  DBUG_RETURN(0);  // <<---
                }
            

            The code in make_join_statistics():

                      records= get_quick_record_count(join->thd, select, s->table,
                                                      &s->const_keys, join->row_limit);
                      impossible_range= records == 0 && s->table->reginfo.impossible_range;
            

            so, records=0, impossible_range=1.

            After the patch:

            get_quick_record_count() doesn't set quick_count when it gets IMPOSSIBLE:

            static bool get_quick_record_count(THD *thd, SQL_SELECT *select,
                                                  TABLE *table,
                                                  const key_map *keys,ha_rows limit,
                                                  ha_rows *quick_count)
            {
                ...
                if (error == SQL_SELECT::IMPOSSIBLE_RANGE)
                {
                  table->reginfo.impossible_range=1;
                  *quick_count= 0;
                  DBUG_RETURN(false);
                } 
            

            but the code that calls it still depends on it:

                    ha_rows records= HA_ROWS_MAX;
            ...
                      if (get_quick_record_count(join->thd, select, s->table,
                                                 &s->const_keys, join->row_limit, &records))
                      ...
                      impossible_range= records == 0 && s->table->reginfo.impossible_range;
            

            here records=HA_ROWS_MAX, and impossible_range= false...

            psergei Sergei Petrunia added a comment - Ok the assert range->rows >= s->found_records is hit because range->rows=0 and s->found_rows=1. The number 0 comes from the range optimizer (the table has 0 rows, so range optimizer returns 0 rows too) The number 1 is from "make 0 be 1" logic in test_quick_select (and possibly elsewehere) for #rows in the table. Initially the discrepancy was introduced in 10.6, but the assert is only in 11.0 The discrepancy was introduced in 10.6 by: commit ec2574fd8fd46da765fd60b0ca9650b729073401 (origin/bb-10.6-MDEV-31983-v4) Author: Rex <rex.johnston@mariadb.com> Date: Fri Sep 15 08:44:49 2023 +1100   MDEV-31983 jointable materialization subquery optimization ignoring ...errors, then failing ASSERT. ... Reviewed-by: Sergei Petrunia, Oleg Smirnov Before the patch, get_quick_record() count returned 0 if it got "Impossible condition" from test_quick_select(): static ha_rows get_quick_record_count(THD *thd, SQL_SELECT *select, TABLE *table, const key_map *keys,ha_rows limit) { ... if (likely((error= select->test_quick_select(thd, *(key_map *)keys, (table_map) 0, limit, 0, FALSE, TRUE, /* remove_where_parts*/ FALSE, TRUE)) == 1)) DBUG_RETURN(select->quick->records); if (unlikely(error == -1)) { table->reginfo.impossible_range=1; DBUG_RETURN(0); // <<--- } The code in make_join_statistics(): records= get_quick_record_count(join->thd, select, s->table, &s->const_keys, join->row_limit); impossible_range= records == 0 && s->table->reginfo.impossible_range; so, records=0, impossible_range=1. After the patch : get_quick_record_count() doesn't set quick_count when it gets IMPOSSIBLE: static bool get_quick_record_count(THD *thd, SQL_SELECT *select, TABLE *table, const key_map *keys,ha_rows limit, ha_rows *quick_count) { ... if (error == SQL_SELECT::IMPOSSIBLE_RANGE) { table->reginfo.impossible_range=1; *quick_count= 0; DBUG_RETURN( false ); } but the code that calls it still depends on it: ha_rows records= HA_ROWS_MAX; ... if (get_quick_record_count(join->thd, select, s->table, &s->const_keys, join->row_limit, &records)) ... impossible_range= records == 0 && s->table->reginfo.impossible_range; here records=HA_ROWS_MAX, and impossible_range= false...
            psergei Sergei Petrunia made changes -

            bb-10.6-MDEV-32682

            psergei Sergei Petrunia added a comment - bb-10.6- MDEV-32682
            psergei Sergei Petrunia made changes -
            Fix Version/s 10.6 [ 24028 ]
            Fix Version/s 10.10 [ 27530 ]
            Fix Version/s 10.11 [ 27614 ]
            oleg.smirnov Oleg Smirnov added a comment -

            Ok to push

            oleg.smirnov Oleg Smirnov added a comment - Ok to push
            serg Sergei Golubchik made changes -
            Status In Progress [ 3 ] In Testing [ 10301 ]
            sanja Oleksandr Byelkin made changes -
            Fix Version/s 10.6.16 [ 29014 ]
            Fix Version/s 10.6 [ 24028 ]
            Fix Version/s 10.10 [ 27530 ]
            Fix Version/s 10.11 [ 27614 ]
            Fix Version/s 11.0 [ 28320 ]
            Resolution Fixed [ 1 ]
            Status In Testing [ 10301 ] Closed [ 6 ]
            JIraAutomate JiraAutomate made changes -
            Fix Version/s 10.10.7 [ 29018 ]
            Fix Version/s 10.11.6 [ 29020 ]
            Fix Version/s 11.0.4 [ 29021 ]
            Fix Version/s 11.1.3 [ 29023 ]
            Fix Version/s 11.2.2 [ 29035 ]

            People

              psergei Sergei Petrunia
              elenst Elena Stepanova
              Votes:
              0 Vote for this issue
              Watchers:
              6 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.