mirror of
https://github.com/MariaDB/server.git
synced 2025-11-05 01:43:31 +03:00
Fixed maria_chk to repair BLOCK-ROW tables. Added CREATE options ROW_FORMAT=PAGE & TRANSACTIONAL= 0|1 More DBUG information in a lot of functions Some minor code cleanups Enable handler errors earlier for better clear text error messages at handler startup / standalone usage. Don't print NULL strings in my_create_with_symlink(); Fixes core dump when used with --debug include/maria.h: Added extra variables needed for REPAIR with BLOCK records include/my_base.h: Added argument for opening copy of maria table without a shared object include/my_handler.h: Prototypes for my_handler_error_register() & my_handler_error_unregister() include/pagecache.h: Added PAGECACHE_READ_UNKNOWN_PAGE mysql-test/include/ps_conv.inc: Enforce creation of table as MyISAM (to allow one to use --default-storage-engine) mysql-test/r/maria.result: Moved some things to maria-connect.test Updared results as REPAIR now works Added tests for creation option TRANSACTIONAL mysql-test/r/ps_2myisam.result: Enforce creation of table as MyISAM (to allow one to use --default-storage-engine) mysql-test/r/ps_3innodb.result: Enforce creation of table as MyISAM (to allow one to use --default-storage-engine) mysql-test/r/ps_4heap.result: Enforce creation of table as MyISAM (to allow one to use --default-storage-engine) mysql-test/r/ps_5merge.result: Enforce creation of table as MyISAM (to allow one to use --default-storage-engine) mysql-test/r/ps_7ndb.result: Enforce creation of table as MyISAM (to allow one to use --default-storage-engine) mysql-test/r/ps_maria.result: Enforce creation of table as MyISAM (to allow one to use --default-storage-engine) mysql-test/t/maria.test: Moved some things to maria-connect.test Updared results as REPAIR now works Added tests for creation option TRANSACTIONAL mysys/mf_iocache.c: More debugging mysys/mf_tempfile.c: Added missing close() mysys/my_error.c: init_glob_errs() is now done in my_init() mysys/my_handler.c: Added functions to initialize handler error messages mysys/my_init.c: Moevd init_glob_errs() here. mysys/my_open.c: More comments More debugging Code cleanup (join multiple code paths) and indentation fixes. No change in logic. mysys/my_symlink2.c: Don't print NULL strings sql/handler.cc: Added printing of PAGE row type Moved out initializing of handler errors to allow handler to give better error messages at startup sql/handler.h: ROW_TYPE_PAGES -> ROW_TYPE_PAGE sql/lex.h: Added 'PAGE' and 'TRANSACTIONAL' sql/mysqld.cc: Initialize handler error messages early to get better error messages from handler startup sql/sql_show.cc: ROW_TYPE_PAGES -> ROW_TYPE_PAGE sql/sql_table.cc: Removed not needed initializer sql/sql_yacc.yy: Added CREATE options ROW_FORMAT=PAGE and TRANSACTIONAL=[0|1] sql/table.cc: Store transactional flag in .frm More comments sql-bench/example: Better example sql/table.h: Added transactional table option storage/maria/ha_maria.cc: More debug information Enable REPAIR Detect usage of TRANSACTIONAL table option storage/maria/ma_bitmap.c: More comments (from Guilhem) storage/maria/ma_blockrec.c: SANITY_CHECK -> SANITY_CHECKS (fixed typo) Write out pages on delete even if there is no rows. (Fixed problem with REPAIR) Removed some ASSERTS to runtime checks (for better REPAIR) Fixed bug when scanning rows More DBUG information storage/maria/ma_check.c: Partial rewrite to allow REPAIR of BLOCK/PAGE format. Repair of BLOCK format rows is for now only done with 'maria_repair()' (= repair through key cache) The new logic to repair rows with BLOCK format is: - Create new, unrelated MARIA_HA of the table - Create new datafile and associate it with new handler - Reset all statistic information in new handler - Copy all data to new handler with normal write operations - Move state of new handler to old handler - Close new handler - Close data file in old handler - Rename old data file to new data file. - Reopen data file in old handler storage/maria/ma_close.c: REmoved not needed block storage/maria/ma_create.c: Swap arguments to _ma_initialize_data_file() storage/maria/ma_delete_all.c: Split maria_delete_all_rows() to two functions to allow REPAIR to easily reset all status information. storage/maria/ma_dynrec.c: Added checksum argument to _ma_rec_check (multi-thread fix) storage/maria/ma_info.c: Indentation fix storage/maria/ma_init.c: Register error message to get better error message on init and when using as standalone module. storage/maria/ma_loghandler.c: Fixed typo that disabled some error detection by valgrind storage/maria/ma_open.c: Added 'calc_check_checksum()' Don't log things during repair Added option HA_OPEN_COPY to allow one to open a Maria table with an independent share (required by REPAIR) storage/maria/ma_pagecache.c: Fixed some compiler warnings Added support for PAGECACHE_READ_UNKNOWN_PAGE (used for scanning file without knowing page types) storage/maria/ma_test_all.sh: More test of REPAIR storage/maria/ma_update.c: Optimized checksum code storage/maria/maria_chk.c: Use DBUG_SET_INITIAL() to get DBUG to work with --parallel-repair Ensure we always use maria_repair() for BLOCK format (for now) More DBUG information storage/maria/maria_def.h: For now, always run with more checkings (SANITY_CHECKS) Added share->calc_check_checksum to be used with REPAIR / CHECK table. Swaped arguments to _ma_initialize_data_file() storage/myisam/ft_stopwords.c: Added DBUG information mysql-test/r/maria-connect.result: New BitKeeper file ``mysql-test/r/maria-connect.result'' mysql-test/t/maria-connect.test: New BitKeeper file ``mysql-test/t/maria-connect.test''
632 lines
18 KiB
C
632 lines
18 KiB
C
/* Copyright (C) 2002-2006 MySQL AB
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; version 2
|
|
of the License.
|
|
|
|
This library 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
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
|
MA 02111-1307, USA */
|
|
|
|
#include <my_global.h>
|
|
#include <m_ctype.h>
|
|
#include <my_base.h>
|
|
#include <my_handler.h>
|
|
#include <my_sys.h>
|
|
|
|
int ha_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length,
|
|
uchar *b, uint b_length, my_bool part_key,
|
|
my_bool skip_end_space)
|
|
{
|
|
if (!part_key)
|
|
return charset_info->coll->strnncollsp(charset_info, a, a_length,
|
|
b, b_length, (my_bool)!skip_end_space);
|
|
return charset_info->coll->strnncoll(charset_info, a, a_length,
|
|
b, b_length, part_key);
|
|
}
|
|
|
|
|
|
static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length,
|
|
my_bool part_key, my_bool skip_end_space)
|
|
{
|
|
uint length= min(a_length,b_length);
|
|
uchar *end= a+ length;
|
|
int flag;
|
|
|
|
while (a < end)
|
|
if ((flag= (int) *a++ - (int) *b++))
|
|
return flag;
|
|
if (part_key && b_length < a_length)
|
|
return 0;
|
|
if (skip_end_space && a_length != b_length)
|
|
{
|
|
int swap= 1;
|
|
/*
|
|
We are using space compression. We have to check if longer key
|
|
has next character < ' ', in which case it's less than the shorter
|
|
key that has an implicite space afterwards.
|
|
|
|
This code is identical to the one in
|
|
strings/ctype-simple.c:my_strnncollsp_simple
|
|
*/
|
|
if (a_length < b_length)
|
|
{
|
|
/* put shorter key in a */
|
|
a_length= b_length;
|
|
a= b;
|
|
swap= -1; /* swap sign of result */
|
|
}
|
|
for (end= a + a_length-length; a < end ; a++)
|
|
{
|
|
if (*a != ' ')
|
|
return (*a < ' ') ? -swap : swap;
|
|
}
|
|
return 0;
|
|
}
|
|
return (int) (a_length-b_length);
|
|
}
|
|
|
|
|
|
/*
|
|
Compare two keys
|
|
|
|
SYNOPSIS
|
|
ha_key_cmp()
|
|
keyseg Array of key segments of key to compare
|
|
a First key to compare, in format from _mi_pack_key()
|
|
This is normally key specified by user
|
|
b Second key to compare. This is always from a row
|
|
key_length Length of key to compare. This can be shorter than
|
|
a to just compare sub keys
|
|
next_flag How keys should be compared
|
|
If bit SEARCH_FIND is not set the keys includes the row
|
|
position and this should also be compared
|
|
diff_pos OUT Number of first keypart where values differ, counting
|
|
from one.
|
|
diff_pos[1] OUT (b + diff_pos[1]) points to first value in tuple b
|
|
that is different from corresponding value in tuple a.
|
|
|
|
EXAMPLES
|
|
Example1: if the function is called for tuples
|
|
('aaa','bbb') and ('eee','fff'), then
|
|
diff_pos[0] = 1 (as 'aaa' != 'eee')
|
|
diff_pos[1] = 0 (offset from beggining of tuple b to 'eee' keypart).
|
|
|
|
Example2: if the index function is called for tuples
|
|
('aaa','bbb') and ('aaa','fff'),
|
|
diff_pos[0] = 2 (as 'aaa' != 'eee')
|
|
diff_pos[1] = 3 (offset from beggining of tuple b to 'fff' keypart,
|
|
here we assume that first key part is CHAR(3) NOT NULL)
|
|
|
|
NOTES
|
|
Number-keys can't be splited
|
|
|
|
RETURN VALUES
|
|
<0 If a < b
|
|
0 If a == b
|
|
>0 If a > b
|
|
*/
|
|
|
|
#define FCMP(A,B) ((int) (A) - (int) (B))
|
|
|
|
int ha_key_cmp(register HA_KEYSEG *keyseg, register uchar *a,
|
|
register uchar *b, uint key_length, uint nextflag,
|
|
uint *diff_pos)
|
|
{
|
|
int flag;
|
|
int16 s_1,s_2;
|
|
int32 l_1,l_2;
|
|
uint32 u_1,u_2;
|
|
float f_1,f_2;
|
|
double d_1,d_2;
|
|
uint next_key_length;
|
|
uchar *orig_b= b;
|
|
|
|
*diff_pos=0;
|
|
for ( ; (int) key_length >0 ; key_length=next_key_length, keyseg++)
|
|
{
|
|
uchar *end;
|
|
uint piks=! (keyseg->flag & HA_NO_SORT);
|
|
(*diff_pos)++;
|
|
diff_pos[1]= (uint)(b - orig_b);
|
|
|
|
/* Handle NULL part */
|
|
if (keyseg->null_bit)
|
|
{
|
|
key_length--;
|
|
if (*a != *b && piks)
|
|
{
|
|
flag = (int) *a - (int) *b;
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
}
|
|
b++;
|
|
if (!*a++) /* If key was NULL */
|
|
{
|
|
if (nextflag == (SEARCH_FIND | SEARCH_UPDATE))
|
|
nextflag=SEARCH_SAME; /* Allow duplicate keys */
|
|
else if (nextflag & SEARCH_NULL_ARE_NOT_EQUAL)
|
|
{
|
|
/*
|
|
This is only used from mi_check() to calculate cardinality.
|
|
It can't be used when searching for a key as this would cause
|
|
compare of (a,b) and (b,a) to return the same value.
|
|
*/
|
|
return -1;
|
|
}
|
|
next_key_length=key_length;
|
|
continue; /* To next key part */
|
|
}
|
|
}
|
|
end= a+ min(keyseg->length,key_length);
|
|
next_key_length=key_length-keyseg->length;
|
|
|
|
switch ((enum ha_base_keytype) keyseg->type) {
|
|
case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */
|
|
if (keyseg->flag & HA_SPACE_PACK)
|
|
{
|
|
int a_length,b_length,pack_length;
|
|
get_key_length(a_length,a);
|
|
get_key_pack_length(b_length,pack_length,b);
|
|
next_key_length=key_length-b_length-pack_length;
|
|
|
|
if (piks &&
|
|
(flag=ha_compare_text(keyseg->charset,a,a_length,b,b_length,
|
|
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
|
next_key_length <= 0),
|
|
(my_bool)!(nextflag & SEARCH_PREFIX))))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a+=a_length;
|
|
b+=b_length;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
uint length=(uint) (end-a), a_length=length, b_length=length;
|
|
if (piks &&
|
|
(flag= ha_compare_text(keyseg->charset, a, a_length, b, b_length,
|
|
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
|
next_key_length <= 0),
|
|
(my_bool)!(nextflag & SEARCH_PREFIX))))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a=end;
|
|
b+=length;
|
|
}
|
|
break;
|
|
case HA_KEYTYPE_BINARY:
|
|
case HA_KEYTYPE_BIT:
|
|
if (keyseg->flag & HA_SPACE_PACK)
|
|
{
|
|
int a_length,b_length,pack_length;
|
|
get_key_length(a_length,a);
|
|
get_key_pack_length(b_length,pack_length,b);
|
|
next_key_length=key_length-b_length-pack_length;
|
|
|
|
if (piks &&
|
|
(flag=compare_bin(a,a_length,b,b_length,
|
|
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
|
next_key_length <= 0),1)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a+=a_length;
|
|
b+=b_length;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
uint length=keyseg->length;
|
|
if (piks &&
|
|
(flag=compare_bin(a,length,b,length,
|
|
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
|
next_key_length <= 0),0)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a+=length;
|
|
b+=length;
|
|
}
|
|
break;
|
|
case HA_KEYTYPE_VARTEXT1:
|
|
case HA_KEYTYPE_VARTEXT2:
|
|
{
|
|
int a_length,b_length,pack_length;
|
|
get_key_length(a_length,a);
|
|
get_key_pack_length(b_length,pack_length,b);
|
|
next_key_length=key_length-b_length-pack_length;
|
|
|
|
if (piks &&
|
|
(flag= ha_compare_text(keyseg->charset,a,a_length,b,b_length,
|
|
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
|
next_key_length <= 0),
|
|
(my_bool) ((nextflag & (SEARCH_FIND |
|
|
SEARCH_UPDATE)) ==
|
|
SEARCH_FIND &&
|
|
! (keyseg->flag &
|
|
HA_END_SPACE_ARE_EQUAL)))))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a+= a_length;
|
|
b+= b_length;
|
|
break;
|
|
}
|
|
break;
|
|
case HA_KEYTYPE_VARBINARY1:
|
|
case HA_KEYTYPE_VARBINARY2:
|
|
{
|
|
int a_length,b_length,pack_length;
|
|
get_key_length(a_length,a);
|
|
get_key_pack_length(b_length,pack_length,b);
|
|
next_key_length=key_length-b_length-pack_length;
|
|
|
|
if (piks &&
|
|
(flag=compare_bin(a,a_length,b,b_length,
|
|
(my_bool) ((nextflag & SEARCH_PREFIX) &&
|
|
next_key_length <= 0), 0)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a+=a_length;
|
|
b+=b_length;
|
|
break;
|
|
}
|
|
break;
|
|
case HA_KEYTYPE_INT8:
|
|
{
|
|
int i_1= (int) *((signed char*) a);
|
|
int i_2= (int) *((signed char*) b);
|
|
if (piks && (flag = CMP_NUM(i_1,i_2)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b++;
|
|
break;
|
|
}
|
|
case HA_KEYTYPE_SHORT_INT:
|
|
s_1= mi_sint2korr(a);
|
|
s_2= mi_sint2korr(b);
|
|
if (piks && (flag = CMP_NUM(s_1,s_2)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+= 2; /* sizeof(short int); */
|
|
break;
|
|
case HA_KEYTYPE_USHORT_INT:
|
|
{
|
|
uint16 us_1,us_2;
|
|
us_1= mi_sint2korr(a);
|
|
us_2= mi_sint2korr(b);
|
|
if (piks && (flag = CMP_NUM(us_1,us_2)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+=2; /* sizeof(short int); */
|
|
break;
|
|
}
|
|
case HA_KEYTYPE_LONG_INT:
|
|
l_1= mi_sint4korr(a);
|
|
l_2= mi_sint4korr(b);
|
|
if (piks && (flag = CMP_NUM(l_1,l_2)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+= 4; /* sizeof(long int); */
|
|
break;
|
|
case HA_KEYTYPE_ULONG_INT:
|
|
u_1= mi_sint4korr(a);
|
|
u_2= mi_sint4korr(b);
|
|
if (piks && (flag = CMP_NUM(u_1,u_2)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+= 4; /* sizeof(long int); */
|
|
break;
|
|
case HA_KEYTYPE_INT24:
|
|
l_1=mi_sint3korr(a);
|
|
l_2=mi_sint3korr(b);
|
|
if (piks && (flag = CMP_NUM(l_1,l_2)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+= 3;
|
|
break;
|
|
case HA_KEYTYPE_UINT24:
|
|
l_1=mi_uint3korr(a);
|
|
l_2=mi_uint3korr(b);
|
|
if (piks && (flag = CMP_NUM(l_1,l_2)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+= 3;
|
|
break;
|
|
case HA_KEYTYPE_FLOAT:
|
|
mi_float4get(f_1,a);
|
|
mi_float4get(f_2,b);
|
|
/*
|
|
The following may give a compiler warning about floating point
|
|
comparison not being safe, but this is ok in this context as
|
|
we are bascily doing sorting
|
|
*/
|
|
if (piks && (flag = CMP_NUM(f_1,f_2)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+= 4; /* sizeof(float); */
|
|
break;
|
|
case HA_KEYTYPE_DOUBLE:
|
|
mi_float8get(d_1,a);
|
|
mi_float8get(d_2,b);
|
|
/*
|
|
The following may give a compiler warning about floating point
|
|
comparison not being safe, but this is ok in this context as
|
|
we are bascily doing sorting
|
|
*/
|
|
if (piks && (flag = CMP_NUM(d_1,d_2)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+= 8; /* sizeof(double); */
|
|
break;
|
|
case HA_KEYTYPE_NUM: /* Numeric key */
|
|
{
|
|
int swap_flag= 0;
|
|
int alength,blength;
|
|
|
|
if (keyseg->flag & HA_REVERSE_SORT)
|
|
{
|
|
swap_variables(uchar*, a, b);
|
|
swap_flag=1; /* Remember swap of a & b */
|
|
end= a+ (int) (end-b);
|
|
}
|
|
if (keyseg->flag & HA_SPACE_PACK)
|
|
{
|
|
alength= *a++; blength= *b++;
|
|
end=a+alength;
|
|
next_key_length=key_length-blength-1;
|
|
}
|
|
else
|
|
{
|
|
alength= (int) (end-a);
|
|
blength=keyseg->length;
|
|
/* remove pre space from keys */
|
|
for ( ; alength && *a == ' ' ; a++, alength--) ;
|
|
for ( ; blength && *b == ' ' ; b++, blength--) ;
|
|
}
|
|
if (piks)
|
|
{
|
|
if (*a == '-')
|
|
{
|
|
if (*b != '-')
|
|
return -1;
|
|
a++; b++;
|
|
swap_variables(uchar*, a, b);
|
|
swap_variables(int, alength, blength);
|
|
swap_flag=1-swap_flag;
|
|
alength--; blength--;
|
|
end=a+alength;
|
|
}
|
|
else if (*b == '-')
|
|
return 1;
|
|
while (alength && (*a == '+' || *a == '0'))
|
|
{
|
|
a++; alength--;
|
|
}
|
|
while (blength && (*b == '+' || *b == '0'))
|
|
{
|
|
b++; blength--;
|
|
}
|
|
if (alength != blength)
|
|
return (alength < blength) ? -1 : 1;
|
|
while (a < end)
|
|
if (*a++ != *b++)
|
|
return ((int) a[-1] - (int) b[-1]);
|
|
}
|
|
else
|
|
{
|
|
b+=(end-a);
|
|
a=end;
|
|
}
|
|
|
|
if (swap_flag) /* Restore pointers */
|
|
swap_variables(uchar*, a, b);
|
|
break;
|
|
}
|
|
#ifdef HAVE_LONG_LONG
|
|
case HA_KEYTYPE_LONGLONG:
|
|
{
|
|
longlong ll_a,ll_b;
|
|
ll_a= mi_sint8korr(a);
|
|
ll_b= mi_sint8korr(b);
|
|
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+= 8;
|
|
break;
|
|
}
|
|
case HA_KEYTYPE_ULONGLONG:
|
|
{
|
|
ulonglong ll_a,ll_b;
|
|
ll_a= mi_uint8korr(a);
|
|
ll_b= mi_uint8korr(b);
|
|
if (piks && (flag = CMP_NUM(ll_a,ll_b)))
|
|
return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag);
|
|
a= end;
|
|
b+= 8;
|
|
break;
|
|
}
|
|
#endif
|
|
case HA_KEYTYPE_END: /* Ready */
|
|
goto end; /* diff_pos is incremented */
|
|
}
|
|
}
|
|
(*diff_pos)++;
|
|
end:
|
|
if (!(nextflag & SEARCH_FIND))
|
|
{
|
|
uint i;
|
|
if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) /* Find record after key */
|
|
return (nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1;
|
|
flag=0;
|
|
for (i=keyseg->length ; i-- > 0 ; )
|
|
{
|
|
if (*a++ != *b++)
|
|
{
|
|
flag= FCMP(a[-1],b[-1]);
|
|
break;
|
|
}
|
|
}
|
|
if (nextflag & SEARCH_SAME)
|
|
return (flag); /* read same */
|
|
if (nextflag & SEARCH_BIGGER)
|
|
return (flag <= 0 ? -1 : 1); /* read next */
|
|
return (flag < 0 ? -1 : 1); /* read previous */
|
|
}
|
|
return 0;
|
|
} /* ha_key_cmp */
|
|
|
|
|
|
/*
|
|
Find the first NULL value in index-suffix values tuple
|
|
|
|
SYNOPSIS
|
|
ha_find_null()
|
|
keyseg Array of keyparts for key suffix
|
|
a Key suffix value tuple
|
|
|
|
DESCRIPTION
|
|
Find the first NULL value in index-suffix values tuple.
|
|
|
|
TODO
|
|
Consider optimizing this function or its use so we don't search for
|
|
NULL values in completely NOT NULL index suffixes.
|
|
|
|
RETURN
|
|
First key part that has NULL as value in values tuple, or the last key
|
|
part (with keyseg->type==HA_TYPE_END) if values tuple doesn't contain
|
|
NULLs.
|
|
*/
|
|
|
|
HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
|
|
{
|
|
for (; (enum ha_base_keytype) keyseg->type != HA_KEYTYPE_END; keyseg++)
|
|
{
|
|
uchar *end;
|
|
if (keyseg->null_bit)
|
|
{
|
|
if (!*a++)
|
|
return keyseg;
|
|
}
|
|
end= a+ keyseg->length;
|
|
|
|
switch ((enum ha_base_keytype) keyseg->type) {
|
|
case HA_KEYTYPE_TEXT:
|
|
case HA_KEYTYPE_BINARY:
|
|
case HA_KEYTYPE_BIT:
|
|
if (keyseg->flag & HA_SPACE_PACK)
|
|
{
|
|
int a_length;
|
|
get_key_length(a_length, a);
|
|
a += a_length;
|
|
break;
|
|
}
|
|
else
|
|
a= end;
|
|
break;
|
|
case HA_KEYTYPE_VARTEXT1:
|
|
case HA_KEYTYPE_VARTEXT2:
|
|
case HA_KEYTYPE_VARBINARY1:
|
|
case HA_KEYTYPE_VARBINARY2:
|
|
{
|
|
int a_length;
|
|
get_key_length(a_length, a);
|
|
a+= a_length;
|
|
break;
|
|
}
|
|
case HA_KEYTYPE_NUM:
|
|
if (keyseg->flag & HA_SPACE_PACK)
|
|
{
|
|
int alength= *a++;
|
|
end= a+alength;
|
|
}
|
|
a= end;
|
|
break;
|
|
case HA_KEYTYPE_INT8:
|
|
case HA_KEYTYPE_SHORT_INT:
|
|
case HA_KEYTYPE_USHORT_INT:
|
|
case HA_KEYTYPE_LONG_INT:
|
|
case HA_KEYTYPE_ULONG_INT:
|
|
case HA_KEYTYPE_INT24:
|
|
case HA_KEYTYPE_UINT24:
|
|
#ifdef HAVE_LONG_LONG
|
|
case HA_KEYTYPE_LONGLONG:
|
|
case HA_KEYTYPE_ULONGLONG:
|
|
#endif
|
|
case HA_KEYTYPE_FLOAT:
|
|
case HA_KEYTYPE_DOUBLE:
|
|
a= end;
|
|
break;
|
|
case HA_KEYTYPE_END: /* purecov: inspected */
|
|
/* keep compiler happy */
|
|
DBUG_ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
return keyseg;
|
|
}
|
|
|
|
|
|
/*
|
|
Errors a handler can give you
|
|
*/
|
|
|
|
static const char *handler_error_messages[]=
|
|
{
|
|
"Didn't find key on read or update",
|
|
"Duplicate key on write or update",
|
|
"Undefined handler error 122",
|
|
"Someone has changed the row since it was read (while the table was locked to prevent it)",
|
|
"Wrong index given to function",
|
|
"Undefined handler error 125",
|
|
"Index file is crashed",
|
|
"Record file is crashed",
|
|
"Out of memory in engine",
|
|
"Undefined handler error 129",
|
|
"Incorrect file format",
|
|
"Command not supported by database",
|
|
"Old database file",
|
|
"No record read before update",
|
|
"Record was already deleted (or record file crashed)",
|
|
"No more room in record file",
|
|
"No more room in index file",
|
|
"No more records (read after end of file)",
|
|
"Unsupported extension used for table",
|
|
"Too big row",
|
|
"Wrong create options",
|
|
"Duplicate unique key or constraint on write or update",
|
|
"Unknown character set used in table",
|
|
"Conflicting table definitions in sub-tables of MERGE table",
|
|
"Table is crashed and last repair failed",
|
|
"Table was marked as crashed and should be repaired",
|
|
"Lock timed out; Retry transaction",
|
|
"Lock table is full; Restart program with a larger locktable",
|
|
"Updates are not allowed under a read only transactions",
|
|
"Lock deadlock; Retry transaction",
|
|
"Foreign key constraint is incorrectly formed",
|
|
"Cannot add a child row",
|
|
"Cannot delete a parent row",
|
|
"Unknown handler error"
|
|
};
|
|
|
|
|
|
/*
|
|
Register handler error messages for usage with my_error()
|
|
|
|
NOTES
|
|
This is safe to call multiple times as my_error_register()
|
|
will ignore calls to register already registered error numbers.
|
|
*/
|
|
|
|
|
|
void my_handler_error_register(void)
|
|
{
|
|
my_error_register(handler_error_messages, HA_ERR_FIRST,
|
|
HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
|
|
}
|
|
|
|
|
|
void my_handler_error_unregister(void)
|
|
{
|
|
my_error_unregister(HA_ERR_FIRST,
|
|
HA_ERR_FIRST+ array_elements(handler_error_messages)-1);
|
|
}
|