summaryrefslogtreecommitdiff
path: root/storage/heap
diff options
context:
space:
mode:
authorMichael Widenius <monty@askmonty.org>2013-02-15 20:25:27 +0200
committerMichael Widenius <monty@askmonty.org>2013-02-15 20:25:27 +0200
commit7042dd38c6bed80bbb7e8ac2c75e5fd689f19836 (patch)
tree58c5fcb4e6a5d16156bc863ae61a3df9f8eea2c7 /storage/heap
parenta555ceb2fb75c9958e39c963ca2a83e615629711 (diff)
downloadmariadb-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.c46
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;