• Vasil Dimov's avatar
    Fix Bug#13510739 63775: SERVER CRASH ON HANDLER READ NEXT AFTER DELETE RECORD. · 41f309dd
    Vasil Dimov authored
    CREATE TABLE bug13510739 (c INTEGER NOT NULL, PRIMARY KEY (c)) ENGINE=INNODB;
    INSERT INTO bug13510739 VALUES (1), (2), (3), (4);
    DELETE FROM bug13510739 WHERE c=2;
    HANDLER bug13510739 OPEN;
    HANDLER bug13510739 READ `primary` = (2);
    HANDLER bug13510739 READ `primary` NEXT;  <-- crash
    
    The bug is that in the particular testcase row_search_for_mysql() picked up
    a delete-marked record and quit, leaving the cursor non-positioned state and
    on the subsequent 'get next' call the code crashed because of the
    non-positioned cursor.
    
    In row0sel.cc (line numbers from mysql-trunk):
    
    4653         if (rec_get_deleted_flag(rec, comp)) {
    ...
    4679                 if (index == clust_index && unique_search) {
    4680 
    4681                         err = DB_RECORD_NOT_FOUND;
    4682                         
    4683                         goto normal_return;
    4684                 }       
    
    it quit from here, not storing the cursor position.
    
    In contrast, if the record=2 is not found at all (e.g. sleep(1) after DELETE
    to let the purge wipe it away completely) then 'get = 2' does find record=3
    and quits from here:
    
    4366                 if (0 != cmp_dtuple_rec(search_tuple, rec, offsets)) {
    ...
    4394                         btr_pcur_store_position(pcur, &mtr);
    4395 
    4396                         err = DB_RECORD_NOT_FOUND;
    4397 #if 0
    4398                         ut_print_name(stderr, trx, FALSE, index->name);
    4399                         fputs(" record not found 3\n", stderr);
    4400 #endif
    4401 
    4402                         goto normal_return;
    
    Another fix could be to extend the condition on line 4366 to hold only if
    seach_tuple matches rec AND if rec is not delete marked.
    
    Notice that in the above test case if we wait about 1 second somewhere after
    DELETE and before 'get = 2', then the testcase does not crash and returns 4
    instead. Not sure if this is the correct behavior, but this bugfix removes
    the crash and makes the code return what it also returns in the non-crashing
    case (if rec=2 is not found during 'get = 2', e.g. we have sleep(1) there).
    
    Approved by:	Marko (http://bur03.no.oracle.com/rb/r/863/)
    41f309dd
row0sel.c 125 KB