mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
6866ca008c
MERGE engine may return incorrect values when several representations of equal keys are present in the index. For example "groß" and "gross" or "gross" and "gross " (trailing space), which are considered equal, but have different lengths. The problem was that key length was not recalculated after key lookup. Only MERGE engine is affected. myisam/mi_rkey.c: info->lastkey gets rewritten by mi_search. Later we recalculate found lastkey length. This is done to make sure that mi_rnext_same gets true, found (not searched) lastkey length. Searched and found key lengths may be different, for example in case searched key is "groß" and found is "gross" or in case a key has trailing spaces. Unfortunately we recalculate found lastkey length only for first underlying table. To recalculate found key length for non-first underlying table we need to know how much key segments were used to create this key. When mi_rkey is called for first underlying table of a merge table, store offset to last used key segment. Restore last_used_keyseg variable when mi_rkey is called for non-first underlying table. myisam/myisamdef.h: Added last_used_keyseg variable to MI_INFO. It is used by merge engine to calculate key length. myisammrg/myrg_rkey.c: Pass last used key segment returned by first table key read to other table key reads. mysql-test/r/merge.result: A test case for bug#24342. mysql-test/t/merge.test: A test case for bug#24342.
98 lines
3.1 KiB
C
98 lines
3.1 KiB
C
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
|
|
/* Read record based on a key */
|
|
|
|
/*
|
|
* HA_READ_KEY_EXACT => SEARCH_BIGGER
|
|
* HA_READ_KEY_OR_NEXT => SEARCH_BIGGER
|
|
* HA_READ_AFTER_KEY => SEARCH_BIGGER
|
|
* HA_READ_PREFIX => SEARCH_BIGGER
|
|
* HA_READ_KEY_OR_PREV => SEARCH_SMALLER
|
|
* HA_READ_BEFORE_KEY => SEARCH_SMALLER
|
|
* HA_READ_PREFIX_LAST => SEARCH_SMALLER
|
|
*/
|
|
|
|
|
|
#include "myrg_def.h"
|
|
|
|
/* todo: we could store some additional info to speedup lookups:
|
|
column (key, keyseg) can be constant per table
|
|
it can also be increasing (table1.val > table2.val > ...),
|
|
or decreasing, <=, >=, etc.
|
|
SerG
|
|
*/
|
|
|
|
int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key,
|
|
uint key_len, enum ha_rkey_function search_flag)
|
|
{
|
|
byte *key_buff;
|
|
uint pack_key_length;
|
|
uint16 last_used_keyseg;
|
|
MYRG_TABLE *table;
|
|
MI_INFO *mi;
|
|
int err;
|
|
DBUG_ENTER("myrg_rkey");
|
|
LINT_INIT(key_buff);
|
|
LINT_INIT(pack_key_length);
|
|
LINT_INIT(last_used_keyseg);
|
|
|
|
if (_myrg_init_queue(info,inx,search_flag))
|
|
DBUG_RETURN(my_errno);
|
|
|
|
for (table=info->open_tables ; table != info->end_table ; table++)
|
|
{
|
|
mi=table->table;
|
|
|
|
if (table == info->open_tables)
|
|
{
|
|
err=mi_rkey(mi,0,inx,key,key_len,search_flag);
|
|
/* Get the saved packed key and packed key length. */
|
|
key_buff=(byte*) mi->lastkey+mi->s->base.max_key_length;
|
|
pack_key_length=mi->pack_key_length;
|
|
last_used_keyseg= mi->last_used_keyseg;
|
|
}
|
|
else
|
|
{
|
|
mi->once_flags|= USE_PACKED_KEYS;
|
|
mi->last_used_keyseg= last_used_keyseg;
|
|
err=mi_rkey(mi,0,inx,key_buff,pack_key_length,search_flag);
|
|
}
|
|
info->last_used_table=table+1;
|
|
|
|
if (err)
|
|
{
|
|
if (err == HA_ERR_KEY_NOT_FOUND)
|
|
continue;
|
|
DBUG_PRINT("exit", ("err: %d", err));
|
|
DBUG_RETURN(err);
|
|
}
|
|
/* adding to queue */
|
|
queue_insert(&(info->by_key),(byte *)table);
|
|
|
|
}
|
|
|
|
DBUG_PRINT("info", ("tables with matches: %u", info->by_key.elements));
|
|
if (!info->by_key.elements)
|
|
DBUG_RETURN(HA_ERR_KEY_NOT_FOUND);
|
|
|
|
mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table;
|
|
mi->once_flags|= RRND_PRESERVE_LASTINX;
|
|
DBUG_PRINT("info", ("using table no: %d",
|
|
info->current_table - info->open_tables + 1));
|
|
DBUG_DUMP("result key", (byte*) mi->lastkey, mi->lastkey_length);
|
|
DBUG_RETURN(_myrg_mi_read_record(mi,buf));
|
|
}
|