summaryrefslogtreecommitdiff
path: root/storage/heap
diff options
context:
space:
mode:
authorMichael Widenius <monty@askmonty.org>2013-02-28 10:00:07 +0100
committerMichael Widenius <monty@askmonty.org>2013-02-28 10:00:07 +0100
commit6a2d730a7f89726f30dc2eb3a02a9aaa94da6c3c (patch)
treec30c547229e6ef879528404109c9cba97abe16c4 /storage/heap
parent08ba257846e75641304e530b7a4a4ab21b1714d7 (diff)
downloadmariadb-git-6a2d730a7f89726f30dc2eb3a02a9aaa94da6c3c.tar.gz
Fixed BUG#51763 Can't delete rows from MEMORY table with HASH key
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 455996e32ef..7612b896ccc 100644
--- a/storage/heap/hp_delete.c
+++ b/storage/heap/hp_delete.c
@@ -47,7 +47,6 @@ int heap_delete(HP_INFO *info, const uchar *record)
share->del_link=pos;
pos[share->reclength]=0; /* Record deleted */
share->deleted++;
- info->current_hash_ptr=0;
#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
DBUG_EXECUTE("check_heap",heap_check_heap(info, 0););
#endif
@@ -180,21 +179,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;