• unknown's avatar
    Fix for BUG#35351 "Maria: R-tree index does not return all expected rows" · 28131daa
    unknown authored
    
    BitKeeper/triggers/post-commit:
      commits to Maria public list
    mysql-test/r/maria-gis-rtree.result:
      result is good now, similar to MyISAM's (gis-rtree.result)
    storage/maria/ma_rt_index.c:
      R-tree key-reading code used info->buff as a cache for the next key read,
      but between key read and next key read, there is record read, which
      uses info->buff too. In detail, during a SELECT:
      First key read: maria_rfirst() is called, which calls maria_rtree_find_first() which calls 
      maria_rtree_find_req() which comes here
              if (after_key < last)
              {
                // ! the list of keys is copied to info->buff
                // and info->buff is remembered in info->int_keypos
                info->int_keypos= info->buff;
                info->int_maxpos= info->buff + (last - after_key);
                memcpy(info->buff, after_key, last - after_key);
                info->keyread_buff_used= 0;
              }
      Then record read:
      _ma_read_block_record() (as well as some other functions of
      ma_blockrec.c) overwrites info->buff:
        if (!(buff= pagecache_read(share->pagecache,
                                   &info->dfile, ma_recordpos_to_page(record_pos), 0,
                                   info->buff, share->page_type,
                                   PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
      So, this has the effect that the keys saved by maria_rtree_find_req() are now lost:
      info->int_keypos now contains a copy of a data page!
      Then maria_rnext_same() runs (to find second row), calls maria_rtree_find_next() which
      does:
        if (!info->keyread_buff_used)
        {
          uchar *key= info->int_keypos;
          while (key < info->int_maxpos)
          {
            if (!maria_rtree_key_cmp(keyinfo->seg,
                                     info->first_mbr_key, key,
                                     info->last_rkey_length, search_flag))
      
      i.e. maria_rtree_key_cmp() is doing comparisons on values it reads from the data page.
      Naturally this is bad and no row is found.
      Origin of the bug: MARIA_HA::keyread_buff is new in Maria.
      Solution: use keyread_buff instead of buff (like _ma_search_next() does),
      in R-tree code. Note that ma_blockrec.c functions also use keyread_buff
      but they all are write-functions, which should not be running close
      to next-key-read. Also note that some ma_rt_index.c functions still
      use info->buff, but they are about writes too.
      Thanks Monty for the idea.
    28131daa
ma_rt_index.c 34.4 KB