[MDEV-32682] Assertion `range->rows >= s->found_records' failed in best_access_path Created: 2023-11-04  Updated: 2023-11-14  Resolved: 2023-11-09

Status: Closed
Project: MariaDB Server
Component/s: Optimizer
Affects Version/s: 11.0
Fix Version/s: 10.6.16, 10.10.7, 10.11.6, 11.0.4, 11.1.3, 11.2.2

Type: Bug Priority: Blocker
Reporter: Elena Stepanova Assignee: Sergei Petrunia
Resolution: Fixed Votes: 0
Labels: regression

Issue Links:
Problem/Incident
is caused by MDEV-31983 jointable materialization subquery op... Closed

 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.



 Comments   
Comment by Sergei Petrunia [ 2023-11-06 ]

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...

Comment by Sergei Petrunia [ 2023-11-07 ]

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...

Comment by Sergei Petrunia [ 2023-11-07 ]

bb-10.6-MDEV-32682

Comment by Oleg Smirnov [ 2023-11-07 ]

Ok to push

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