mariadb/storage/myisam/mi_key.c
unknown f4afcec393 Merge hynda.mysql.fi:/home/my/mysql-5.1-main
into  hynda.mysql.fi:/home/my/mysql-maria


BitKeeper/etc/ignore:
  auto-union
BUILD/SETUP.sh:
  Auto merged
BitKeeper/deleted/.del-CMakeLists.txt~99a50df6:
  Auto merged
Makefile.am:
  Auto merged
client/mysqldump.c:
  Auto merged
configure.in:
  Auto merged
include/Makefile.am:
  Auto merged
include/keycache.h:
  Auto merged
include/m_string.h:
  Auto merged
include/my_sys.h:
  Auto merged
libmysqld/Makefile.am:
  Auto merged
mysql-test/extra/rpl_tests/rpl_insert_delayed.test:
  Auto merged
mysql-test/lib/mtr_cases.pl:
  Auto merged
mysql-test/lib/mtr_misc.pl:
  Auto merged
mysql-test/lib/mtr_process.pl:
  Auto merged
mysql-test/lib/mtr_report.pl:
  Auto merged
mysql-test/lib/mtr_timer.pl:
  Auto merged
mysql-test/mysql-test-run.pl:
  Auto merged
mysql-test/r/alter_table.result:
  Auto merged
mysql-test/r/merge.result:
  Auto merged
mysql-test/r/mysqldump.result:
  Auto merged
mysql-test/r/query_cache.result:
  Auto merged
mysql-test/r/subselect.result:
  Auto merged
mysql-test/r/view.result:
  Auto merged
mysql-test/suite/ndb/r/ps_7ndb.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_events.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_insert.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_row_insert_delayed.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_stm_flsh_tbls.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_stm_insert_delayed.result:
  Auto merged
mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result:
  Auto merged
mysql-test/suite/rpl/t/rpl_insert.test:
  Auto merged
mysql-test/suite/rpl/t/rpl_stm_flsh_tbls.test:
  Auto merged
mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test:
  Auto merged
mysql-test/t/alter_table.test:
  Auto merged
mysql-test/t/myisam.test:
  Auto merged
mysql-test/t/mysqldump.test:
  Auto merged
mysql-test/t/query_cache.test:
  Auto merged
mysql-test/t/subselect.test:
  Auto merged
mysql-test/t/view.test:
  Auto merged
mysys/array.c:
  Auto merged
mysys/mf_keycache.c:
  Auto merged
mysys/my_init.c:
  Auto merged
mysys/my_symlink2.c:
  Auto merged
mysys/safemalloc.c:
  Auto merged
mysys/thr_lock.c:
  Auto merged
sql/Makefile.am:
  Auto merged
sql/filesort.cc:
  Auto merged
sql/ha_ndbcluster.cc:
  Auto merged
sql/ha_partition.cc:
  Auto merged
sql/ha_partition.h:
  Auto merged
sql/handler.h:
  Auto merged
sql/item_func.cc:
  Auto merged
sql/item_func.h:
  Auto merged
sql/item_xmlfunc.cc:
  Auto merged
sql/lock.cc:
  Auto merged
sql/log.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/mysqld.cc:
  Auto merged
sql/net_serv.cc:
  Auto merged
sql/opt_range.cc:
  Auto merged
sql/set_var.cc:
  Auto merged
sql/slave.cc:
  Auto merged
sql/slave.h:
  Auto merged
sql/sql_class.cc:
  Auto merged
sql/sql_delete.cc:
  Auto merged
sql/sql_insert.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_table.cc:
  Auto merged
sql/share/errmsg.txt:
  Auto merged
sql/sql_test.cc:
  Auto merged
sql/table.h:
  Auto merged
sql/udf_example.c:
  Auto merged
sql/uniques.cc:
  Auto merged
sql/unireg.cc:
  Auto merged
storage/csv/ha_tina.h:
  Auto merged
storage/myisam/ft_boolean_search.c:
  Auto merged
storage/myisam/ft_nlq_search.c:
  Auto merged
storage/myisam/ft_parser.c:
  Auto merged
storage/myisam/ft_stopwords.c:
  Auto merged
storage/myisam/ha_myisam.cc:
  Auto merged
storage/myisam/ha_myisam.h:
  Auto merged
storage/myisam/mi_check.c:
  Auto merged
storage/myisam/mi_create.c:
  Auto merged
storage/myisam/mi_delete.c:
  Auto merged
storage/myisam/mi_dynrec.c:
  Auto merged
storage/myisam/mi_extra.c:
  Auto merged
storage/myisam/mi_key.c:
  Auto merged
storage/myisam/mi_locking.c:
  Auto merged
storage/myisam/mi_log.c:
  Auto merged
storage/myisam/mi_packrec.c:
  Auto merged
storage/myisam/mi_rkey.c:
  Auto merged
storage/myisam/mi_search.c:
  Auto merged
storage/myisam/mi_test1.c:
  Auto merged
storage/myisam/mi_test2.c:
  Auto merged
storage/myisam/mi_update.c:
  Auto merged
storage/myisam/mi_write.c:
  Auto merged
storage/myisam/myisamchk.c:
  Auto merged
storage/myisam/myisamlog.c:
  Auto merged
storage/myisam/myisampack.c:
  Auto merged
storage/myisam/sort.c:
  Auto merged
storage/myisam/sp_test.c:
  Auto merged
storage/myisammrg/ha_myisammrg.cc:
  Auto merged
storage/myisammrg/ha_myisammrg.h:
  Auto merged
storage/ndb/src/mgmapi/mgmapi.cpp:
  Auto merged
support-files/compiler_warnings.supp:
  Auto merged
client/mysqltest.c:
  Manual merge between mysql-5.1 and mysql-maria
include/my_base.h:
  Manual merge between mysql-5.1 and mysql-maria
include/my_global.h:
  Manual merge between mysql-5.1 and mysql-maria
include/myisam.h:
  Manual merge between mysql-5.1 and mysql-maria
libmysql/Makefile.shared:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/r/events_logs_tests.result:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/suite/rpl/r/rpl_row_flsh_tbls.result:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/suite/rpl/t/rpl_row_flsh_tbls.test:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/t/disabled.def:
  Manual merge between mysql-5.1 and mysql-maria
mysql-test/t/events_logs_tests.test:
  Manual merge between mysql-5.1 and mysql-maria
mysys/my_compress.c:
  Manual merge between mysql-5.1 and mysql-maria
mysys/my_getsystime.c:
  Manual merge between mysql-5.1 and mysql-maria
mysys/my_open.c:
  Manual merge between mysql-5.1 and mysql-maria
sql/handler.cc:
  Manual merge between mysql-5.1 and mysql-maria
sql/set_var.h:
  Manual merge between mysql-5.1 and mysql-maria
sql/sql_class.h:
  Manual merge between mysql-5.1 and mysql-maria
sql/sql_show.cc:
  Manual merge between mysql-5.1 and mysql-maria
sql/sql_sort.h:
  Manual merge between mysql-5.1 and mysql-maria
sql/sql_yacc.yy:
  Manual merge between mysql-5.1 and mysql-maria
sql/table.cc:
  Manual merge between mysql-5.1 and mysql-maria
storage/csv/ha_tina.cc:
  Manual merge between mysql-5.1 and mysql-maria
storage/myisam/mi_open.c:
  Manual merge between mysql-5.1 and mysql-maria
storage/myisam/myisamdef.h:
  Manual merge between mysql-5.1 and mysql-maria
unittest/mysys/my_atomic-t.c:
  Manual merge between mysql-5.1 and mysql-maria
2007-09-27 17:05:07 +03:00

568 lines
15 KiB
C

/* Copyright (C) 2000-2006 MySQL 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; version 2 of the License.
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 */
/* Functions to handle keys */
#include "myisamdef.h"
#include "m_ctype.h"
#include "sp_defs.h"
#ifdef HAVE_IEEEFP_H
#include <ieeefp.h>
#endif
#define CHECK_KEYS /* Enable safety checks */
#define FIX_LENGTH(cs, pos, length, char_length) \
do { \
if (length > char_length) \
char_length= my_charpos(cs, pos, pos+length, char_length); \
set_if_smaller(char_length,length); \
} while(0)
static int _mi_put_key_in_record(MI_INFO *info,uint keynr,uchar *record);
/*
Make a intern key from a record
SYNOPSIS
_mi_make_key()
info MyiSAM handler
keynr key number
key Store created key here
record Record
filepos Position to record in the data file
RETURN
Length of key
*/
uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
const uchar *record, my_off_t filepos)
{
uchar *pos;
uchar *start;
reg1 HA_KEYSEG *keyseg;
my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
DBUG_ENTER("_mi_make_key");
if (info->s->keyinfo[keynr].flag & HA_SPATIAL)
{
/*
TODO: nulls processing
*/
#ifdef HAVE_SPATIAL
DBUG_RETURN(sp_make_key(info,keynr,key,record,filepos));
#else
DBUG_ASSERT(0); /* mi_open should check that this never happens*/
#endif
}
start=key;
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
{
enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
uint length=keyseg->length;
uint char_length;
CHARSET_INFO *cs=keyseg->charset;
if (keyseg->null_bit)
{
if (record[keyseg->null_pos] & keyseg->null_bit)
{
*key++= 0; /* NULL in key */
continue;
}
*key++=1; /* Not NULL */
}
char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
length);
pos= (uchar*) record+keyseg->start;
if (type == HA_KEYTYPE_BIT)
{
if (keyseg->bit_length)
{
uchar bits= get_rec_bits((uchar*) record + keyseg->bit_pos,
keyseg->bit_start, keyseg->bit_length);
*key++= bits;
length--;
}
memcpy((uchar*) key, pos, length);
key+= length;
continue;
}
if (keyseg->flag & HA_SPACE_PACK)
{
if (type != HA_KEYTYPE_NUM)
{
length= cs->cset->lengthsp(cs, (char*) pos, length);
}
else
{
uchar *end= pos + length;
while (pos < end && pos[0] == ' ')
pos++;
length=(uint) (end-pos);
}
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
key+=char_length;
continue;
}
if (keyseg->flag & HA_VAR_LENGTH_PART)
{
uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
uint2korr(pos));
pos+= pack_length; /* Skip VARCHAR length */
set_if_smaller(length,tmp_length);
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
key+= char_length;
continue;
}
else if (keyseg->flag & HA_BLOB_PART)
{
uint tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
memcpy_fixed((uchar*) &pos,pos+keyseg->bit_start,sizeof(char*));
set_if_smaller(length,tmp_length);
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
key+= char_length;
continue;
}
else if (keyseg->flag & HA_SWAP_KEY)
{ /* Numerical column */
#ifdef HAVE_ISNAN
if (type == HA_KEYTYPE_FLOAT)
{
float nr;
float4get(nr,pos);
if (isnan(nr))
{
/* Replace NAN with zero */
bzero(key,length);
key+=length;
continue;
}
}
else if (type == HA_KEYTYPE_DOUBLE)
{
double nr;
float8get(nr,pos);
if (isnan(nr))
{
bzero(key,length);
key+=length;
continue;
}
}
#endif
pos+=length;
while (length--)
{
*key++ = *--pos;
}
continue;
}
FIX_LENGTH(cs, pos, length, char_length);
memcpy((uchar*) key, pos, char_length);
if (length > char_length)
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
key+= length;
}
_mi_dpointer(info,key,filepos);
DBUG_PRINT("exit",("keynr: %d",keynr));
DBUG_DUMP("key",(uchar*) start,(uint) (key-start)+keyseg->length);
DBUG_EXECUTE("key",
_mi_print_key(DBUG_FILE,info->s->keyinfo[keynr].seg,start,
(uint) (key-start)););
DBUG_RETURN((uint) (key-start)); /* Return keylength */
} /* _mi_make_key */
/*
Pack a key to intern format from given format (c_rkey)
SYNOPSIS
_mi_pack_key()
info MyISAM handler
uint keynr key number
key Store packed key here
old Not packed key
keypart_map bitmap of used keyparts
last_used_keyseg out parameter. May be NULL
RETURN
length of packed key
last_use_keyseg Store pointer to the keyseg after the last used one
*/
uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
key_part_map keypart_map, HA_KEYSEG **last_used_keyseg)
{
uchar *start_key=key;
HA_KEYSEG *keyseg;
my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
DBUG_ENTER("_mi_pack_key");
/* "one part" rtree key is 2*SPDIMS part key in MyISAM */
if (info->s->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE)
keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1;
/* only key prefixes are supported */
DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0);
for (keyseg= info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map;
old+= keyseg->length, keyseg++)
{
enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type;
uint length= keyseg->length;
uint char_length;
uchar *pos;
CHARSET_INFO *cs=keyseg->charset;
keypart_map>>= 1;
if (keyseg->null_bit)
{
if (!(*key++= (char) 1-*old++)) /* Copy null marker */
{
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
old+= 2;
continue; /* Found NULL */
}
}
char_length= (!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
pos=old;
if (keyseg->flag & HA_SPACE_PACK)
{
uchar *end=pos+length;
if (type == HA_KEYTYPE_NUM)
{
while (pos < end && pos[0] == ' ')
pos++;
}
else if (type != HA_KEYTYPE_BINARY)
{
while (end > pos && end[-1] == ' ')
end--;
}
length=(uint) (end-pos);
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
memcpy((uchar*) key,pos,(size_t) char_length);
key+= char_length;
continue;
}
else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
{
/* Length of key-part used with mi_rkey() always 2 */
uint tmp_length=uint2korr(pos);
pos+=2;
set_if_smaller(length,tmp_length); /* Safety */
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
old+=2; /* Skip length */
memcpy((uchar*) key, pos,(size_t) char_length);
key+= char_length;
continue;
}
else if (keyseg->flag & HA_SWAP_KEY)
{ /* Numerical column */
pos+=length;
while (length--)
*key++ = *--pos;
continue;
}
FIX_LENGTH(cs, pos, length, char_length);
memcpy((uchar*) key, pos, char_length);
if (length > char_length)
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
key+= length;
}
if (last_used_keyseg)
*last_used_keyseg= keyseg;
DBUG_RETURN((uint) (key-start_key));
} /* _mi_pack_key */
/*
Store found key in record
SYNOPSIS
_mi_put_key_in_record()
info MyISAM handler
keynr Key number that was used
record Store key here
Last read key is in info->lastkey
NOTES
Used when only-keyread is wanted
RETURN
0 ok
1 error
*/
static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
uchar *record)
{
reg2 uchar *key;
uchar *pos,*key_end;
reg1 HA_KEYSEG *keyseg;
uchar *blob_ptr;
DBUG_ENTER("_mi_put_key_in_record");
blob_ptr= (uchar*) info->lastkey2; /* Place to put blob parts */
key=(uchar*) info->lastkey; /* KEy that was read */
key_end=key+info->lastkey_length;
for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
{
if (keyseg->null_bit)
{
if (!*key++)
{
record[keyseg->null_pos]|= keyseg->null_bit;
continue;
}
record[keyseg->null_pos]&= ~keyseg->null_bit;
}
if (keyseg->type == HA_KEYTYPE_BIT)
{
uint length= keyseg->length;
if (keyseg->bit_length)
{
uchar bits= *key++;
set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
keyseg->bit_length);
length--;
}
else
{
clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
keyseg->bit_length);
}
memcpy(record + keyseg->start, (uchar*) key, length);
key+= length;
continue;
}
if (keyseg->flag & HA_SPACE_PACK)
{
uint length;
get_key_length(length,key);
#ifdef CHECK_KEYS
if (length > keyseg->length || key+length > key_end)
goto err;
#endif
pos= record+keyseg->start;
if (keyseg->type != (int) HA_KEYTYPE_NUM)
{
memcpy(pos,key,(size_t) length);
keyseg->charset->cset->fill(keyseg->charset,
(char*) pos + length,
keyseg->length - length,
' ');
}
else
{
bfill(pos,keyseg->length-length,' ');
memcpy(pos+keyseg->length-length,key,(size_t) length);
}
key+=length;
continue;
}
if (keyseg->flag & HA_VAR_LENGTH_PART)
{
uint length;
get_key_length(length,key);
#ifdef CHECK_KEYS
if (length > keyseg->length || key+length > key_end)
goto err;
#endif
/* Store key length */
if (keyseg->bit_start == 1)
*(uchar*) (record+keyseg->start)= (uchar) length;
else
int2store(record+keyseg->start, length);
/* And key data */
memcpy(record+keyseg->start + keyseg->bit_start, (uchar*) key, length);
key+= length;
}
else if (keyseg->flag & HA_BLOB_PART)
{
uint length;
get_key_length(length,key);
#ifdef CHECK_KEYS
if (length > keyseg->length || key+length > key_end)
goto err;
#endif
memcpy(record+keyseg->start+keyseg->bit_start,
(char*) &blob_ptr,sizeof(char*));
memcpy(blob_ptr,key,length);
blob_ptr+=length;
/* The above changed info->lastkey2. Inform mi_rnext_same(). */
info->update&= ~HA_STATE_RNEXT_SAME;
_mi_store_blob_length(record+keyseg->start,
(uint) keyseg->bit_start,length);
key+=length;
}
else if (keyseg->flag & HA_SWAP_KEY)
{
uchar *to= record+keyseg->start+keyseg->length;
uchar *end= key+keyseg->length;
#ifdef CHECK_KEYS
if (end > key_end)
goto err;
#endif
do
{
*--to= *key++;
} while (key != end);
continue;
}
else
{
#ifdef CHECK_KEYS
if (key+keyseg->length > key_end)
goto err;
#endif
memcpy(record+keyseg->start,(uchar*) key,
(size_t) keyseg->length);
key+= keyseg->length;
}
}
DBUG_RETURN(0);
err:
DBUG_RETURN(1); /* Crashed row */
} /* _mi_put_key_in_record */
/* Here when key reads are used */
int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf)
{
fast_mi_writeinfo(info);
if (filepos != HA_OFFSET_ERROR)
{
if (info->lastinx >= 0)
{ /* Read only key */
if (_mi_put_key_in_record(info,(uint) info->lastinx,buf))
{
mi_print_error(info->s, HA_ERR_CRASHED);
my_errno=HA_ERR_CRASHED;
return -1;
}
info->update|= HA_STATE_AKTIV; /* We should find a record */
return 0;
}
my_errno=HA_ERR_WRONG_INDEX;
}
return(-1); /* Wrong data to read */
}
/*
Retrieve auto_increment info
SYNOPSIS
retrieve_auto_increment()
info MyISAM handler
record Row to update
IMPLEMENTATION
For signed columns we don't retrieve the auto increment value if it's
less than zero.
*/
ulonglong retrieve_auto_increment(MI_INFO *info,const uchar *record)
{
ulonglong value= 0; /* Store unsigned values here */
longlong s_value= 0; /* Store signed values here */
HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg;
const uchar *key= (uchar*) record + keyseg->start;
switch (keyseg->type) {
case HA_KEYTYPE_INT8:
s_value= (longlong) *(char*)key;
break;
case HA_KEYTYPE_BINARY:
value=(ulonglong) *(uchar*) key;
break;
case HA_KEYTYPE_SHORT_INT:
s_value= (longlong) sint2korr(key);
break;
case HA_KEYTYPE_USHORT_INT:
value=(ulonglong) uint2korr(key);
break;
case HA_KEYTYPE_LONG_INT:
s_value= (longlong) sint4korr(key);
break;
case HA_KEYTYPE_ULONG_INT:
value=(ulonglong) uint4korr(key);
break;
case HA_KEYTYPE_INT24:
s_value= (longlong) sint3korr(key);
break;
case HA_KEYTYPE_UINT24:
value=(ulonglong) uint3korr(key);
break;
case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
{
float f_1;
float4get(f_1,key);
/* Ignore negative values */
value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
break;
}
case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
{
double f_1;
float8get(f_1,key);
/* Ignore negative values */
value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
break;
}
case HA_KEYTYPE_LONGLONG:
s_value= sint8korr(key);
break;
case HA_KEYTYPE_ULONGLONG:
value= uint8korr(key);
break;
default:
DBUG_ASSERT(0);
value=0; /* Error */
break;
}
/*
The following code works becasue if s_value < 0 then value is 0
and if s_value == 0 then value will contain either s_value or the
correct value.
*/
return (s_value > 0) ? (ulonglong) s_value : value;
}