diff options
author | Michael Widenius <monty@askmonty.org> | 2013-02-15 20:25:27 +0200 |
---|---|---|
committer | Michael Widenius <monty@askmonty.org> | 2013-02-15 20:25:27 +0200 |
commit | 7042dd38c6bed80bbb7e8ac2c75e5fd689f19836 (patch) | |
tree | 58c5fcb4e6a5d16156bc863ae61a3df9f8eea2c7 /storage/heap | |
parent | a555ceb2fb75c9958e39c963ca2a83e615629711 (diff) | |
download | mariadb-git-7042dd38c6bed80bbb7e8ac2c75e5fd689f19836.tar.gz |
Fixed BUG#51763 Can't delete rows from MEMORY table with HASH key
mysql-test/suite/heap/heap.result:
Added test case
mysql-test/suite/heap/heap.test:
Added test case
storage/heap/hp_delete.c:
Fixed that we don't change order of keys for the current key when we delete them from the hash table.
Fixed that 'current_hash_ptr' is correct after heap_delete_key().
Don't "reset current_hash_ptr" on delete; This will improve time a lot for delete of rows when not all rows matches the search criteria.
Diffstat (limited to 'storage/heap')
-rw-r--r-- | storage/heap/hp_delete.c | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/storage/heap/hp_delete.c b/storage/heap/hp_delete.c index d00ac94a918..2bc7d00bfca 100644 --- a/storage/heap/hp_delete.c +++ b/storage/heap/hp_delete.c @@ -48,7 +48,6 @@ int heap_delete(HP_INFO *info, const uchar *record) pos[share->reclength]=0; /* Record deleted */ share->deleted++; share->key_version++; - info->current_hash_ptr=0; #if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG) DBUG_EXECUTE("check_heap",heap_check_heap(info, 0);); #endif @@ -182,21 +181,50 @@ int hp_delete_key(HP_INFO *info, register HP_KEYDEF *keyinfo, } pos2= hp_mask(lastpos_hashnr, blength, share->records + 1); if (pos2 == hp_mask(pos_hashnr, blength, share->records + 1)) - { /* Identical key-positions */ + { + /* lastpos and the row in the main bucket entry (pos) has the same hash */ if (pos2 != share->records) { - empty[0]=lastpos[0]; + /* + The bucket entry was not deleted. Copy lastpos over the + deleted entry and update previous link to point to it. + */ + empty[0]= lastpos[0]; hp_movelink(lastpos, pos, empty); + if (last_ptr == lastpos) + { + /* + We moved the row that info->current_hash_ptr points to. + Update info->current_hash_ptr to point to the new position. + */ + info->current_hash_ptr= empty; + } DBUG_RETURN(0); } - pos3= pos; /* Link pos->next after lastpos */ - } - else - { - pos3= 0; /* Different positions merge */ - keyinfo->hash_buckets--; + /* + Shrinking the hash table deleted the main bucket entry for this hash. + In this case the last entry was the first key in the key chain. + We move things around so that we keep the original key order to ensure + that heap_rnext() works. + + - Move the row at the main bucket entry to the empty spot. + - Move the last entry first in the new chain. + - Link in the first element of the hash. + */ + empty[0]= pos[0]; + pos[0]= lastpos[0]; + hp_movelink(pos, pos, empty); + + /* Update current_hash_ptr if the entry moved */ + if (last_ptr == lastpos) + info->current_hash_ptr= pos; + else if (last_ptr == pos) + info->current_hash_ptr= empty; + DBUG_RETURN(0); } + pos3= 0; /* Different positions merge */ + keyinfo->hash_buckets--; empty[0]=lastpos[0]; hp_movelink(pos3, empty, pos->next_key); pos->next_key=empty; |