Merge bk-internal.mysql.com:/home/bk/mysql-5.1

into  janus.mylan:/usr/home/serg/Abk/mysql-5.1
This commit is contained in:
serg@janus.mylan 2007-03-16 20:33:27 +01:00
commit 55a548cf4d
76 changed files with 628 additions and 446 deletions

View File

@ -4,7 +4,7 @@ extra_configs="$extra_configs $local_infile_configs"
configure="./configure $base_configs $extra_configs"
commands="\
$make -k distclean || true
$make -k maintainer-clean || true
/bin/rm -rf */.deps/*.P configure config.cache storage/*/configure storage/*/config.cache autom4te.cache storage/*/autom4te.cache;
path=`dirname $0`

View File

@ -1,5 +1,7 @@
#! /bin/sh
/bin/rm -f */.deps/*.P */*.o
make -k clean
make -k maintainer-clean
/bin/rm -f */.deps/*.P */*.o
/bin/rm -f config.cache mysql-*.tar.gz

View File

@ -1,5 +1,7 @@
#! /bin/sh
/bin/rm -f */.deps/*.P */*.o
make -k clean
make -k maintainer-clean
/bin/rm -f */.deps/*.P */*.o
/bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache mysql-*.tar.gz

View File

@ -1,5 +1,7 @@
#! /bin/sh
/bin/rm -f */.deps/*.P */*.o
make -k clean
make -k maintainer-clean
/bin/rm -f */.deps/*.P */*.o
/bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache mysql-*.tar.gz

View File

@ -6,7 +6,7 @@
# tree can then be picked up by "make dist" to create the "pristine source
# package" that is used as the basis for all other binary builds.
#
test -f Makefile && make distclean
test -f Makefile && make maintainer-clean
(cd storage/innobase && aclocal && autoheader && \
libtoolize --automake --force --copy && \
automake --force --add-missing --copy && autoconf)

View File

@ -61,7 +61,7 @@ done
set -x
make distclean
make maintainer-clean
path=`dirname $0`
. "$path/autorun.sh"

View File

@ -1,4 +1,4 @@
gmake -k clean || true
gmake -k maintainer-clean || true
/bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache
path=`dirname $0`

View File

@ -33,7 +33,7 @@ else
fi
set -x
make distclean
make maintainer-clean
path=`dirname $0`
. "$path/autorun.sh"

View File

@ -1,5 +1,7 @@
#! /bin/sh
AM_MAKEFLAGS="-j 2"
gmake -k clean || true
gmake -k maintainer-clean || true
/bin/rm -f */.deps/*.P config.cache
path=`dirname $0`

View File

@ -5,7 +5,7 @@
PATH=/opt/SUNWspro/bin/:/usr/ccs/bin:$PATH
make -k clean || true
make -k maintainer-clean || true
/bin/rm -f */.deps/*.P config.cache
path=`dirname $0`

View File

@ -31,7 +31,7 @@ do
shift
done
make -k clean || true
make -k maintainer-clean || true
/bin/rm -f */.deps/*.P config.cache
path=`dirname $0`

View File

@ -72,7 +72,7 @@ X-CSetKey: <$CSETKEY>
$BH
EOF
bk changes -v -r+
bk cset -r+ -d
bk rset -r+ -ah | bk gnupatch -h -dup -T
) > $BKROOT/BitKeeper/tmp/dev_public.txt
$SENDMAIL -t < $BKROOT/BitKeeper/tmp/dev_public.txt

View File

@ -1995,12 +1995,14 @@ static char *DbugMalloc(size_t size)
/*
* strtok lookalike - splits on ':', magically handles :\ and :/
* strtok lookalike - splits on ':', magically handles ::, :\ and :/
*/
static const char *DbugStrTok(const char *s)
{
while (s[0] && (s[0] != ':' || (s[1] == '\\' || s[1] == '/')))
const char *start=s;
while (s[0] && (s[0] != ':' ||
(s[1] == '\\' || s[1] == '/' || (s[1] == ':' && s++))))
s++;
return s;
}

View File

@ -908,9 +908,10 @@ via the
.B DBUG_PUSH
or
.B DBUG_SET
macros. Control string consists of colon separate flags. A flag
may take an argument or a list of arguments. If a control string
starts from a '+' sign it works
macros. Control string consists of colon separate flags. Colons
that are part of ':\\', ':/', or '::' are not considered flag
separators. A flag may take an argument or a list of arguments.
If a control string starts from a '+' sign it works
.I incrementally,
that is, it can modify existing state without overriding it. In such a
string every flag may be preceded by a '+' or '-' to enable or disable
@ -923,9 +924,7 @@ optional.
.LI a[,file]
Redirect the debugger output stream and append it to the specified
file. The default output stream is stderr. A null argument list
causes output to be redirected to stdout. A colon that is followed by
the '\\' or '/' is cosidered a part of the path and not a flag
separator.
causes output to be redirected to stdout.
.SP 1
EX: \fCa,C:\\tmp\\log\fR
.LI A[,file]

View File

@ -226,7 +226,7 @@ ha_rows hp_rb_records_in_range(HP_INFO *info, int inx, key_range *min_key,
key_range *max_key);
int hp_panic(enum ha_panic_function flag);
int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
uint key_len, enum ha_rkey_function find_flag);
ulonglong keypart_map, enum ha_rkey_function find_flag);
extern gptr heap_find(HP_INFO *info,int inx,const byte *key);
extern int heap_check_heap(HP_INFO *info, my_bool print_status);
extern byte *heap_position(HP_INFO *info);

View File

@ -134,14 +134,6 @@ make_atomic_swap(ptr)
#undef _atomic_h_cleanup_
#endif
#if SIZEOF_CHARP == SIZEOF_INT
typedef int intptr;
#elif SIZEOF_CHARP == SIZEOF_LONG
typedef long intptr;
#else
#error
#endif
#define MY_ATOMIC_OK 0
#define MY_ATOMIC_NOT_1CPU 1
extern int my_atomic_initialize();

View File

@ -385,9 +385,10 @@ enum ha_base_keytype {
#define HA_ERR_TABLE_NEEDS_UPGRADE 164 /* The table changed in storage engine */
#define HA_ERR_TABLE_READONLY 165 /* The table is not writable */
#define HA_ERR_AUTOINC_READ_FAILED 166/* Failed to get the next autoinc value */
#define HA_ERR_AUTOINC_ERANGE 167 /* Failed to set the row autoinc value */
#define HA_ERR_LAST 167 /*Copy last error nr.*/
#define HA_ERR_AUTOINC_READ_FAILED 166 /* Failed to get next autoinc value */
#define HA_ERR_AUTOINC_ERANGE 167 /* Failed to set row autoinc value */
#define HA_ERR_GENERIC 168 /* Generic error */
#define HA_ERR_LAST 168 /*Copy last error nr.*/
/* Add error numbers before HA_ERR_LAST and change it accordingly. */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
@ -468,6 +469,7 @@ typedef struct st_key_range
{
const byte *key;
uint length;
ulonglong keypart_map;
enum ha_rkey_function flag;
} key_range;

View File

@ -986,7 +986,7 @@ typedef long int32;
typedef unsigned long uint32;
#endif
#else
#error "Neither int or long is of 4 bytes width"
#error Neither int or long is of 4 bytes width
#endif
#if !defined(HAVE_ULONG) && !defined(__USE_MISC)
@ -1016,6 +1016,14 @@ typedef unsigned __int64 my_ulonglong;
typedef unsigned long long my_ulonglong;
#endif
#if SIZEOF_CHARP == SIZEOF_INT
typedef int intptr;
#elif SIZEOF_CHARP == SIZEOF_LONG
typedef long intptr;
#else
#error sizeof(void *) is neither sizeof(int) nor sizeof(long)
#endif
#ifdef USE_RAID
/*
The following is done with a if to not get problems with pre-processors

View File

@ -274,9 +274,8 @@ extern struct st_myisam_info *mi_open(const char *name,int mode,
uint wait_if_locked);
extern int mi_panic(enum ha_panic_function function);
extern int mi_rfirst(struct st_myisam_info *file,byte *buf,int inx);
extern int mi_rkey(struct st_myisam_info *file,byte *buf,int inx,
const byte *key,
uint key_len, enum ha_rkey_function search_flag);
extern int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key,
ulonglong keypart_map, enum ha_rkey_function search_flag);
extern int mi_rlast(struct st_myisam_info *file,byte *buf,int inx);
extern int mi_rnext(struct st_myisam_info *file,byte *buf,int inx);
extern int mi_rnext_same(struct st_myisam_info *info, byte *buf);
@ -303,7 +302,7 @@ extern int mi_extra(struct st_myisam_info *file,
enum ha_extra_function function,
void *extra_arg);
extern int mi_reset(struct st_myisam_info *file);
extern ha_rows mi_records_in_range(struct st_myisam_info *info,int inx,
extern ha_rows mi_records_in_range(MI_INFO *info, int inx,
key_range *min_key, key_range *max_key);
extern int mi_log(int activate_log);
extern int mi_is_changed(struct st_myisam_info *info);

View File

@ -86,8 +86,8 @@ extern int myrg_rlast(MYRG_INFO *file,byte *buf,int inx);
extern int myrg_rnext(MYRG_INFO *file,byte *buf,int inx);
extern int myrg_rprev(MYRG_INFO *file,byte *buf,int inx);
extern int myrg_rnext_same(MYRG_INFO *file,byte *buf);
extern int myrg_rkey(MYRG_INFO *file,byte *buf,int inx,const byte *key,
uint key_len, enum ha_rkey_function search_flag);
extern int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key,
ulonglong keypart_map, enum ha_rkey_function search_flag);
extern int myrg_rrnd(MYRG_INFO *file,byte *buf,ulonglong pos);
extern int myrg_rsame(MYRG_INFO *file,byte *record,int inx);
extern int myrg_update(MYRG_INFO *file,const byte *old,byte *new_rec);
@ -100,7 +100,7 @@ extern int myrg_extra(MYRG_INFO *file,enum ha_extra_function function,
void *extra_arg);
extern int myrg_reset(MYRG_INFO *info);
extern void myrg_extrafunc(MYRG_INFO *info,invalidator_by_filename inv);
extern ha_rows myrg_records_in_range(MYRG_INFO *info,int inx,
extern ha_rows myrg_records_in_range(MYRG_INFO *info, int inx,
key_range *min_key, key_range *max_key);
extern ulonglong myrg_position(MYRG_INFO *info);

0
server-tools/CMakeLists.txt Executable file → Normal file
View File

View File

@ -288,7 +288,7 @@ Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table,
{
key_copy(key_buf, event_table->record[0], key_info, key_len);
if (!(ret= event_table->file->index_read(event_table->record[0], key_buf,
key_len, HA_READ_PREFIX)))
(ulonglong)1, HA_READ_PREFIX)))
{
DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
do
@ -843,8 +843,7 @@ Event_db_repository::find_named_event(THD *thd, LEX_STRING db, LEX_STRING name,
key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0, key,
table->key_info->key_length,
if (table->file->index_read_idx(table->record[0], 0, key, ~ULL(0),
HA_READ_KEY_EXACT))
{
DBUG_PRINT("info", ("Row not found"));

View File

@ -1104,7 +1104,7 @@ int ha_ndbcluster::create_indexes(Ndb *ndb, TABLE *tab)
KEY* key_info= tab->key_info;
const char **key_name= tab->s->keynames.type_names;
DBUG_ENTER("ha_ndbcluster::create_indexes");
for (i= 0; i < tab->s->keys; i++, key_info++, key_name++)
{
index_name= *key_name;
@ -3370,19 +3370,6 @@ int ha_ndbcluster::index_read(byte *buf,
}
int ha_ndbcluster::index_read_idx(byte *buf, uint index_no,
const byte *key, uint key_len,
enum ha_rkey_function find_flag)
{
statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
DBUG_ENTER("ha_ndbcluster::index_read_idx");
DBUG_PRINT("enter", ("index_no: %u, key_len: %u", index_no, key_len));
close_scan();
index_init(index_no, 0);
DBUG_RETURN(index_read(buf, key, key_len, find_flag));
}
int ha_ndbcluster::index_next(byte *buf)
{
DBUG_ENTER("ha_ndbcluster::index_next");
@ -3549,10 +3536,10 @@ int ha_ndbcluster::close_scan()
m_multi_cursor= 0;
if (!m_active_cursor && !m_multi_cursor)
DBUG_RETURN(1);
DBUG_RETURN(0);
NdbScanOperation *cursor= m_active_cursor ? m_active_cursor : m_multi_cursor;
if (m_lock_tuple)
{
/*

View File

@ -642,8 +642,6 @@ class ha_ndbcluster: public handler
int index_end();
int index_read(byte *buf, const byte *key, uint key_len,
enum ha_rkey_function find_flag);
int index_read_idx(byte *buf, uint index, const byte *key, uint key_len,
enum ha_rkey_function find_flag);
int index_next(byte *buf);
int index_prev(byte *buf);
int index_first(byte *buf);

View File

@ -3336,13 +3336,14 @@ int ha_partition::index_end()
*/
int ha_partition::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
DBUG_ENTER("ha_partition::index_read");
end_range= 0;
m_index_scan_type= partition_index_read;
DBUG_RETURN(common_index_read(buf, key, key_len, find_flag));
DBUG_RETURN(common_index_read(buf, key, keypart_map, find_flag));
}
@ -3355,14 +3356,17 @@ int ha_partition::index_read(byte * buf, const byte * key,
see index_read for rest
*/
int ha_partition::common_index_read(byte *buf, const byte *key, uint key_len,
int ha_partition::common_index_read(byte *buf, const byte *key,
ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
int error;
bool reverse_order= FALSE;
uint key_len= calculate_key_len(table, active_index, key, keypart_map);
DBUG_ENTER("ha_partition::common_index_read");
memcpy((void*)m_start_key.key, key, key_len);
m_start_key.keypart_map= keypart_map;
m_start_key.length= key_len;
m_start_key.flag= find_flag;
@ -3490,33 +3494,6 @@ int ha_partition::common_first_last(byte *buf)
}
/*
Perform index read using index where always only one row is returned
SYNOPSIS
index_read_idx()
see index_read for rest of parameters and return values
DESCRIPTION
Positions an index cursor to the index specified in key. Fetches the
row if any. This is only used to read whole keys.
TODO: Optimise this code to avoid index_init and index_end
*/
int ha_partition::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len,
enum ha_rkey_function find_flag)
{
int res;
DBUG_ENTER("ha_partition::index_read_idx");
index_init(index, 0);
res= index_read(buf, key, key_len, find_flag);
index_end();
DBUG_RETURN(res);
}
/*
Read last using key
@ -3535,14 +3512,15 @@ int ha_partition::index_read_idx(byte * buf, uint index, const byte * key,
Can only be used on indexes supporting HA_READ_ORDER
*/
int ha_partition::index_read_last(byte *buf, const byte *key, uint keylen)
int ha_partition::index_read_last(byte *buf, const byte *key,
ulonglong keypart_map)
{
DBUG_ENTER("ha_partition::index_read_last");
m_ordered= TRUE; // Safety measure
end_range= 0;
m_index_scan_type= partition_index_read_last;
DBUG_RETURN(common_index_read(buf, key, keylen, HA_READ_PREFIX_LAST));
DBUG_RETURN(common_index_read(buf, key, keypart_map, HA_READ_PREFIX_LAST));
}
@ -3688,7 +3666,7 @@ int ha_partition::read_range_first(const key_range *start_key,
m_index_scan_type= partition_index_read;
error= common_index_read(m_rec0,
start_key->key,
start_key->length, start_key->flag);
start_key->keypart_map, start_key->flag);
}
DBUG_RETURN(error);
}
@ -3887,7 +3865,7 @@ int ha_partition::handle_unordered_scan_next_partition(byte * buf)
case partition_index_read:
DBUG_PRINT("info", ("index_read on partition %d", i));
error= file->index_read(buf, m_start_key.key,
m_start_key.length,
m_start_key.keypart_map,
m_start_key.flag);
break;
case partition_index_first:
@ -3979,7 +3957,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
case partition_index_read:
error= file->index_read(rec_buf_ptr,
m_start_key.key,
m_start_key.length,
m_start_key.keypart_map,
m_start_key.flag);
break;
case partition_index_first:
@ -3993,7 +3971,7 @@ int ha_partition::handle_ordered_index_scan(byte *buf, bool reverse_order)
case partition_index_read_last:
error= file->index_read_last(rec_buf_ptr,
m_start_key.key,
m_start_key.length);
m_start_key.keypart_map);
reverse_order= TRUE;
break;
default:

View File

@ -384,9 +384,8 @@ public:
any end processing needed.
*/
virtual int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
virtual int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
ulonglong keypart_map,
enum ha_rkey_function find_flag);
virtual int index_init(uint idx, bool sorted);
virtual int index_end();
@ -399,7 +398,8 @@ public:
virtual int index_first(byte * buf);
virtual int index_last(byte * buf);
virtual int index_next_same(byte * buf, const byte * key, uint keylen);
virtual int index_read_last(byte * buf, const byte * key, uint keylen);
virtual int index_read_last(byte * buf, const byte * key,
ulonglong keypart_map);
/*
read_first_row is virtual method but is only implemented by
@ -425,7 +425,7 @@ public:
private:
int common_index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
ulonglong keypart_map, enum ha_rkey_function find_flag);
int common_first_last(byte * buf);
int partition_scan_set_up(byte * buf, bool idx_read_flag);
int handle_unordered_next(byte * buf, bool next_same);

View File

@ -1843,7 +1843,7 @@ int handler::update_auto_increment()
nr= compute_next_insert_id(nr-1, variables);
}
if (table->s->next_number_key_offset == 0)
if (table->s->next_number_keypart == 0)
{
/* We must defer the appending until "nr" has been possibly truncated */
append= TRUE;
@ -1963,7 +1963,7 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
table->read_set);
column_bitmaps_signal();
index_init(table->s->next_number_index, 1);
if (!table->s->next_number_key_offset)
if (table->s->next_number_keypart == 0)
{ // Autoincrement at key-start
error=index_last(table->record[1]);
/*
@ -1979,7 +1979,8 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment,
key_copy(key, table->record[0],
table->key_info + table->s->next_number_index,
table->s->next_number_key_offset);
error= index_read(table->record[1], key, table->s->next_number_key_offset,
error= index_read(table->record[1], key,
make_prev_keypart_map(table->s->next_number_keypart),
HA_READ_PREFIX_LAST);
/*
MySQL needs to call us for next row: assume we are inserting ("a",null)
@ -3079,9 +3080,9 @@ int handler::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
multi_range_curr < multi_range_end;
multi_range_curr++)
{
result= read_range_first(multi_range_curr->start_key.length ?
result= read_range_first(multi_range_curr->start_key.keypart_map ?
&multi_range_curr->start_key : 0,
multi_range_curr->end_key.length ?
multi_range_curr->end_key.keypart_map ?
&multi_range_curr->end_key : 0,
test(multi_range_curr->range_flag & EQ_RANGE),
multi_range_sorted);
@ -3146,9 +3147,9 @@ int handler::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
multi_range_curr < multi_range_end;
multi_range_curr++)
{
result= read_range_first(multi_range_curr->start_key.length ?
result= read_range_first(multi_range_curr->start_key.keypart_map ?
&multi_range_curr->start_key : 0,
multi_range_curr->end_key.length ?
multi_range_curr->end_key.keypart_map ?
&multi_range_curr->end_key : 0,
test(multi_range_curr->range_flag & EQ_RANGE),
multi_range_sorted);
@ -3207,7 +3208,7 @@ int handler::read_range_first(const key_range *start_key,
else
result= index_read(table->record[0],
start_key->key,
start_key->length,
start_key->keypart_map,
start_key->flag);
if (result)
DBUG_RETURN((result == HA_ERR_KEY_NOT_FOUND)
@ -3279,15 +3280,19 @@ int handler::compare_key(key_range *range)
return cmp;
}
int handler::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
int error= ha_index_init(index, 0);
int error, error1;
error= index_init(index, 0);
if (!error)
error= index_read(buf, key, key_len, find_flag);
if (!error)
error= ha_index_end();
return error;
{
error= index_read(buf, key, keypart_map, find_flag);
error1= index_end();
}
return error ? error : error1;
}

View File

@ -867,6 +867,18 @@ public:
{}
};
uint calculate_key_len(TABLE *, uint, const byte *, ulonglong);
/*
bitmap with first N+1 bits set
(keypart_map for a key prefix of [0..N] keyparts)
*/
#define make_keypart_map(N) (((ulonglong)2 << (N)) - 1)
/*
bitmap with first N bits set
(keypart_map for a key prefix of [0..N-1] keyparts)
*/
#define make_prev_keypart_map(N) (((ulonglong)1 << (N)) - 1)
/*
The handler class is the interface for dynamically loadable
storage engines. Do not add ifdefs and take care when adding or
@ -1202,11 +1214,20 @@ public:
DBUG_ASSERT(FALSE);
return HA_ERR_WRONG_COMMAND;
}
virtual int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
private:
virtual int index_read(byte * buf, const byte * key, uint key_len,
enum ha_rkey_function find_flag)
{ return HA_ERR_WRONG_COMMAND; }
public:
virtual int index_read(byte * buf, const byte * key, ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
uint key_len= calculate_key_len(table, active_index, key, keypart_map);
return index_read(buf, key, key_len, find_flag);
}
virtual int index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
ulonglong keypart_map,
enum ha_rkey_function find_flag);
virtual int index_next(byte * buf)
{ return HA_ERR_WRONG_COMMAND; }
virtual int index_prev(byte * buf)
@ -1216,8 +1237,16 @@ public:
virtual int index_last(byte * buf)
{ return HA_ERR_WRONG_COMMAND; }
virtual int index_next_same(byte *buf, const byte *key, uint keylen);
private:
virtual int index_read_last(byte * buf, const byte * key, uint key_len)
{ return (my_errno=HA_ERR_WRONG_COMMAND); }
public:
virtual int index_read_last(byte * buf, const byte * key,
ulonglong keypart_map)
{
uint key_len= calculate_key_len(table, active_index, key, keypart_map);
return index_read_last(buf, key, key_len);
}
virtual int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
KEY_MULTI_RANGE *ranges, uint range_count,
bool sorted, HANDLER_BUFFER *buffer);
@ -1243,8 +1272,7 @@ public:
{ return HA_ERR_WRONG_COMMAND; }
virtual int rnd_same(byte *buf, uint inx)
{ return HA_ERR_WRONG_COMMAND; }
virtual ha_rows records_in_range(uint inx, key_range *min_key,
key_range *max_key)
virtual ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key)
{ return (ha_rows) 10; }
virtual void position(const byte *record)=0;
virtual int info(uint)=0; // see my_base.h for full description

View File

@ -2045,7 +2045,8 @@ int subselect_uniquesubquery_engine::exec()
table->file->ha_index_init(tab->ref.key, 0);
error= table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
tab_to_keypart_map(tab),
HA_READ_KEY_EXACT);
if (error &&
error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
error= report_error(table, error);
@ -2154,7 +2155,8 @@ int subselect_indexsubquery_engine::exec()
table->file->ha_index_init(tab->ref.key, 1);
error= table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
tab_to_keypart_map(tab),
HA_READ_KEY_EXACT);
if (error &&
error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
error= report_error(table, error);

View File

@ -29,6 +29,7 @@
field Field to search after
key_length On partial match, contains length of fields before
field
keypart key part # of a field
NOTES
Used when calculating key for NEXT_NUMBER
@ -45,7 +46,7 @@
*/
int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
uint *key_length)
uint *key_length, uint *keypart)
{
reg2 int i;
reg3 KEY *key_info;
@ -60,8 +61,8 @@ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
{
if (key_info->key_part[0].offset == fieldpos)
{ /* Found key. Calc keylength */
*key_length=0;
return(i); /* Use this key */
*key_length= *keypart= 0;
return i; /* Use this key */
}
}
@ -78,8 +79,11 @@ int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
j++, key_part++)
{
if (key_part->offset == fieldpos)
return(i); /* Use this key */
*key_length+=key_part->store_length;
{
*keypart= j;
return i; /* Use this key */
}
*key_length+= key_part->store_length;
}
}
return(-1); /* No key is ok */

View File

@ -3773,7 +3773,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
nb_elements()));
/*
If the auto_increment was second in a table's index (possible with
MyISAM or BDB) (table->next_number_key_offset != 0), such event is
MyISAM or BDB) (table->next_number_keypart != 0), such event is
in fact not necessary. We could avoid logging it.
*/
Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT,

View File

@ -6854,9 +6854,8 @@ replace_record(THD *thd, TABLE *table,
}
key_copy((byte*)key.get(), table->record[0], table->key_info + keynum, 0);
error= table->file->index_read_idx(table->record[1], keynum,
(const byte*)key.get(),
table->key_info[keynum].key_length,
error= table->file->index_read_idx(table->record[1], keynum,
(const byte*)key.get(), ~ULL(0),
HA_READ_KEY_EXACT);
if (error)
DBUG_RETURN(error);
@ -7041,8 +7040,7 @@ static int find_and_fetch_row(TABLE *table, byte *key)
table->s->null_bytes > 0 ? table->s->null_bytes - 1 : 0;
table->record[1][pos]= 0xFF;
if ((error= table->file->index_read(table->record[1], key,
table->key_info->key_length,
HA_READ_KEY_EXACT)))
~(ulonglong)0, HA_READ_KEY_EXACT)))
{
table->file->print_error(error, MYF(0));
table->file->ha_index_end();

View File

@ -1493,7 +1493,7 @@ void print_plan(JOIN* join,uint idx, double record_count, double read_time,
void mysql_print_status();
/* key.cc */
int find_ref_key(KEY *key, uint key_count, byte *record, Field *field,
uint *key_length);
uint *key_length, uint *keypart);
void key_copy(byte *to_key, byte *from_record, KEY *key_info, uint key_length);
void key_restore(byte *to_record, byte *from_key, KEY *key_info,
uint key_length);

View File

@ -312,7 +312,7 @@ public:
min_value=arg->max_value;
min_flag=arg->max_flag & NEAR_MAX ? 0 : NEAR_MIN;
}
void store_min(uint length,char **min_key,uint min_key_flag)
int store_min(uint length,char **min_key,uint min_key_flag)
{
if ((min_flag & GEOM_FLAG) ||
(!(min_flag & NO_MIN_RANGE) &&
@ -326,12 +326,12 @@ public:
else
memcpy(*min_key,min_value,length);
(*min_key)+= length;
return 1;
}
return 0;
}
void store(uint length,char **min_key,uint min_key_flag,
char **max_key, uint max_key_flag)
int store_max(uint length,char **max_key, uint max_key_flag)
{
store_min(length, min_key, min_key_flag);
if (!(max_flag & NO_MAX_RANGE) &&
!(max_key_flag & (NO_MAX_RANGE | NEAR_MAX)))
{
@ -343,33 +343,45 @@ public:
else
memcpy(*max_key,max_value,length);
(*max_key)+= length;
return 1;
}
return 0;
}
/*void store(uint length,char **min_key,uint min_key_flag,
char **max_key, uint max_key_flag)
{
store_min(length, min_key, min_key_flag);
store_max(length, max_key, max_key_flag);
}*/
void store_min_key(KEY_PART *key,char **range_key, uint *range_key_flag)
int store_min_key(KEY_PART *key,char **range_key, uint *range_key_flag)
{
SEL_ARG *key_tree= first();
key_tree->store(key[key_tree->part].store_length,
range_key,*range_key_flag,range_key,NO_MAX_RANGE);
uint res= key_tree->store_min(key[key_tree->part].store_length,
range_key, *range_key_flag);
*range_key_flag|= key_tree->min_flag;
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
!(*range_key_flag & (NO_MIN_RANGE | NEAR_MIN)) &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
key_tree->next_key_part->store_min_key(key,range_key, range_key_flag);
res+= key_tree->next_key_part->store_min_key(key, range_key,
range_key_flag);
return res;
}
void store_max_key(KEY_PART *key,char **range_key, uint *range_key_flag)
int store_max_key(KEY_PART *key,char **range_key, uint *range_key_flag)
{
SEL_ARG *key_tree= last();
key_tree->store(key[key_tree->part].store_length,
range_key, NO_MIN_RANGE, range_key,*range_key_flag);
uint res=key_tree->store_max(key[key_tree->part].store_length,
range_key, *range_key_flag);
(*range_key_flag)|= key_tree->max_flag;
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
!(*range_key_flag & (NO_MAX_RANGE | NEAR_MAX)) &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
key_tree->next_key_part->store_max_key(key,range_key, range_key_flag);
res+= key_tree->next_key_part->store_max_key(key, range_key,
range_key_flag);
return res;
}
SEL_ARG *insert(SEL_ARG *key);
@ -586,8 +598,8 @@ static bool is_key_scan_ror(PARAM *param, uint keynr, uint8 nparts);
static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree,
bool update_tbl_stats);
static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
char *min_key,uint min_key_flag,
char *max_key, uint max_key_flag);
char *min_key, uint min_key_flag, int,
char *max_key, uint max_key_flag, int);
QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index,
SEL_ARG *key_tree,
@ -1453,6 +1465,7 @@ QUICK_ROR_UNION_SELECT::~QUICK_ROR_UNION_SELECT()
QUICK_RANGE::QUICK_RANGE()
:min_key(0),max_key(0),min_length(0),max_length(0),
min_keypart_map(0), max_keypart_map(0),
flag(NO_MIN_RANGE | NO_MAX_RANGE)
{}
@ -4031,9 +4044,9 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
The calculation is conducted as follows:
Lets denote #records(keypart1, ... keypartK) as n_k. We need to calculate
n_{k1} n_{k_2}
n_{k1} n_{k2}
--------- * --------- * .... (3)
n_{k1-1} n_{k2_1}
n_{k1-1} n_{k2-1}
where k1,k2,... are key parts which fields were not yet marked as fixed
( this is result of application of option b) of the recursion step for
@ -4041,9 +4054,9 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
Since it is reasonable to expect that most of the fields are not marked
as fixed, we calculate (3) as
n_{i1} n_{i_2}
n_{i1} n_{i2}
(3) = n_{max_key_part} / ( --------- * --------- * .... )
n_{i1-1} n_{i2_1}
n_{i1-1} n_{i2-1}
where i1,i2, .. are key parts that were already marked as fixed.
@ -4052,7 +4065,6 @@ void ror_intersect_cpy(ROR_INTERSECT_INFO *dst, const ROR_INTERSECT_INFO *src)
RETURN
Selectivity of given ROR scan.
*/
static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
@ -4063,6 +4075,7 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
byte key_val[MAX_KEY_LENGTH+MAX_FIELD_WIDTH]; /* key values tuple */
char *key_ptr= (char*) key_val;
SEL_ARG *sel_arg, *tuple_arg= NULL;
ulonglong keypart_map= 0;
bool cur_covered;
bool prev_covered= test(bitmap_is_set(&info->covered_fields,
key_part->fieldnr-1));
@ -4073,7 +4086,7 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
max_range.key= (byte*) key_val;
max_range.flag= HA_READ_AFTER_KEY;
ha_rows prev_records= info->param->table->file->stats.records;
DBUG_ENTER("ror_intersect_selectivity");
DBUG_ENTER("ror_scan_selectivity");
for (sel_arg= scan->sel_arg; sel_arg;
sel_arg= sel_arg->next_key_part)
@ -4090,13 +4103,17 @@ static double ror_scan_selectivity(const ROR_INTERSECT_INFO *info,
tuple_arg= scan->sel_arg;
/* Here we use the length of the first key part */
tuple_arg->store_min(key_part->store_length, &key_ptr, 0);
keypart_map= 1;
}
while (tuple_arg->next_key_part != sel_arg)
{
tuple_arg= tuple_arg->next_key_part;
tuple_arg->store_min(key_part[tuple_arg->part].store_length, &key_ptr, 0);
tuple_arg->store_min(key_part[tuple_arg->part].store_length,
&key_ptr, 0);
keypart_map= (keypart_map << 1) | 1;
}
min_range.length= max_range.length= ((char*) key_ptr - (char*) key_val);
min_range.keypart_map= max_range.keypart_map= keypart_map;
records= (info->param->table->file->
records_in_range(scan->keynr, &min_range, &max_range));
if (cur_covered)
@ -5305,12 +5322,11 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
*/
for (uint i= 1 ; i < cond_func->arg_count ; i++)
{
if (cond_func->arguments()[i]->real_item()->type() == Item::FIELD_ITEM)
{
field_item= (Item_field*) (cond_func->arguments()[i]->real_item());
SEL_TREE *tmp= get_full_func_mm_tree(param, cond_func,
field_item, (Item*) i, inv);
field_item, (Item*)(intptr)i, inv);
if (inv)
tree= !tree ? tmp : tree_or(param, tree, tmp);
else
@ -7057,7 +7073,9 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats)
}
param->n_ranges= 0;
records=check_quick_keys(param,idx,tree,param->min_key,0,param->max_key,0);
records= check_quick_keys(param, idx, tree,
param->min_key, 0, -1,
param->max_key, 0, -1);
if (records != HA_POS_ERROR)
{
if (update_tbl_stats)
@ -7120,12 +7138,13 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree, bool update_tbl_stats)
*/
static ha_rows
check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
char *min_key,uint min_key_flag, char *max_key,
uint max_key_flag)
check_quick_keys(PARAM *param, uint idx, SEL_ARG *key_tree,
char *min_key, uint min_key_flag, int min_keypart,
char *max_key, uint max_key_flag, int max_keypart)
{
ha_rows records=0, tmp;
uint tmp_min_flag, tmp_max_flag, keynr, min_key_length, max_key_length;
uint tmp_min_keypart= min_keypart, tmp_max_keypart= max_keypart;
char *tmp_min_key, *tmp_max_key;
uint8 save_first_null_comp= param->first_null_comp;
@ -7139,18 +7158,21 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
This is not a ROR scan if the key is not Clustered Primary Key.
*/
param->is_ror_scan= FALSE;
records=check_quick_keys(param,idx,key_tree->left,min_key,min_key_flag,
max_key,max_key_flag);
records=check_quick_keys(param, idx, key_tree->left,
min_key, min_key_flag, min_keypart,
max_key, max_key_flag, max_keypart);
if (records == HA_POS_ERROR) // Impossible
return records;
}
tmp_min_key= min_key;
tmp_max_key= max_key;
key_tree->store(param->key[idx][key_tree->part].store_length,
&tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
min_key_length= (uint) (tmp_min_key- param->min_key);
max_key_length= (uint) (tmp_max_key- param->max_key);
tmp_min_keypart+= key_tree->store_min(param->key[idx][key_tree->part].store_length,
&tmp_min_key, min_key_flag);
tmp_max_keypart+= key_tree->store_max(param->key[idx][key_tree->part].store_length,
&tmp_max_key, max_key_flag);
min_key_length= (uint) (tmp_min_key - param->min_key);
max_key_length= (uint) (tmp_max_key - param->max_key);
if (param->is_ror_scan)
{
@ -7173,12 +7195,13 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
{ // const key as prefix
if (min_key_length == max_key_length &&
!memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) &&
!memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) &&
!key_tree->min_flag && !key_tree->max_flag)
{
tmp=check_quick_keys(param,idx,key_tree->next_key_part,
tmp_min_key, min_key_flag | key_tree->min_flag,
tmp_max_key, max_key_flag | key_tree->max_flag);
tmp=check_quick_keys(param,idx,key_tree->next_key_part, tmp_min_key,
min_key_flag | key_tree->min_flag, tmp_min_keypart,
tmp_max_key, max_key_flag | key_tree->max_flag,
tmp_max_keypart);
goto end; // Ugly, but efficient
}
else
@ -7190,18 +7213,20 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
tmp_min_flag=key_tree->min_flag;
tmp_max_flag=key_tree->max_flag;
if (!tmp_min_flag)
tmp_min_keypart+=
key_tree->next_key_part->store_min_key(param->key[idx], &tmp_min_key,
&tmp_min_flag);
if (!tmp_max_flag)
tmp_max_keypart+=
key_tree->next_key_part->store_max_key(param->key[idx], &tmp_max_key,
&tmp_max_flag);
min_key_length= (uint) (tmp_min_key- param->min_key);
max_key_length= (uint) (tmp_max_key- param->max_key);
min_key_length= (uint) (tmp_min_key - param->min_key);
max_key_length= (uint) (tmp_max_key - param->max_key);
}
else
{
tmp_min_flag=min_key_flag | key_tree->min_flag;
tmp_max_flag=max_key_flag | key_tree->max_flag;
tmp_min_flag= min_key_flag | key_tree->min_flag;
tmp_max_flag= max_key_flag | key_tree->max_flag;
}
keynr=param->real_keynr[idx];
@ -7209,9 +7234,8 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
if (!tmp_min_flag && ! tmp_max_flag &&
(uint) key_tree->part+1 == param->table->key_info[keynr].key_parts &&
(param->table->key_info[keynr].flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
HA_NOSAME &&
min_key_length == max_key_length &&
!memcmp(param->min_key,param->max_key,min_key_length) &&
HA_NOSAME && min_key_length == max_key_length &&
!memcmp(param->min_key, param->max_key, min_key_length) &&
!param->first_null_comp)
{
tmp=1; // Max one record
@ -7231,7 +7255,7 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
first members of clustered primary key.
*/
if (!(min_key_length == max_key_length &&
!memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) &&
!memcmp(min_key, max_key, (uint) (tmp_max_key - max_key)) &&
!key_tree->min_flag && !key_tree->max_flag &&
is_key_scan_ror(param, keynr, key_tree->part + 1)))
param->is_ror_scan= FALSE;
@ -7243,11 +7267,12 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
key_range min_range;
min_range.key= (byte*) param->min_key;
min_range.length= min_key_length;
min_range.keypart_map= make_keypart_map(tmp_min_keypart);
/* In this case tmp_min_flag contains the handler-read-function */
min_range.flag= (ha_rkey_function) (tmp_min_flag ^ GEOM_FLAG);
tmp= param->table->file->records_in_range(keynr, &min_range,
(key_range*) 0);
tmp= param->table->file->records_in_range(keynr,
&min_range, (key_range*) 0);
}
else
{
@ -7257,10 +7282,12 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
min_range.length= min_key_length;
min_range.flag= (tmp_min_flag & NEAR_MIN ? HA_READ_AFTER_KEY :
HA_READ_KEY_EXACT);
min_range.keypart_map= make_keypart_map(tmp_min_keypart);
max_range.key= (byte*) param->max_key;
max_range.length= max_key_length;
max_range.flag= (tmp_max_flag & NEAR_MAX ?
HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY);
max_range.keypart_map= make_keypart_map(tmp_max_keypart);
tmp=param->table->file->records_in_range(keynr,
(min_key_length ? &min_range :
(key_range*) 0),
@ -7281,8 +7308,9 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
This is not a ROR scan if the key is not Clustered Primary Key.
*/
param->is_ror_scan= FALSE;
tmp=check_quick_keys(param,idx,key_tree->right,min_key,min_key_flag,
max_key,max_key_flag);
tmp=check_quick_keys(param, idx, key_tree->right,
min_key, min_key_flag, min_keypart,
max_key, max_key_flag, max_keypart);
if (tmp == HA_POS_ERROR)
return tmp;
records+=tmp;
@ -7429,6 +7457,7 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
{
QUICK_RANGE *range;
uint flag;
int min_part= key_tree->part-1, max_part=key_tree->part-1;
if (key_tree->left != &null_element)
{
@ -7437,16 +7466,18 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
return 1;
}
char *tmp_min_key=min_key,*tmp_max_key=max_key;
key_tree->store(key[key_tree->part].store_length,
&tmp_min_key,min_key_flag,&tmp_max_key,max_key_flag);
min_part+= key_tree->store_min(key[key_tree->part].store_length,
&tmp_min_key,min_key_flag);
max_part+= key_tree->store_max(key[key_tree->part].store_length,
&tmp_max_key,max_key_flag);
if (key_tree->next_key_part &&
key_tree->next_key_part->part == key_tree->part+1 &&
key_tree->next_key_part->type == SEL_ARG::KEY_RANGE)
{ // const key as prefix
if (!((tmp_min_key - min_key) != (tmp_max_key - max_key) ||
memcmp(min_key,max_key, (uint) (tmp_max_key - max_key)) ||
key_tree->min_flag || key_tree->max_flag))
if ((tmp_min_key - min_key) == (tmp_max_key - max_key) &&
memcmp(min_key, max_key, (uint)(tmp_max_key - max_key))==0 &&
key_tree->min_flag==0 && key_tree->max_flag==0)
{
if (get_quick_keys(param,quick,key,key_tree->next_key_part,
tmp_min_key, min_key_flag | key_tree->min_flag,
@ -7457,11 +7488,15 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
{
uint tmp_min_flag=key_tree->min_flag,tmp_max_flag=key_tree->max_flag;
if (!tmp_min_flag)
key_tree->next_key_part->store_min_key(key, &tmp_min_key,
{
min_part+= key_tree->next_key_part->store_min_key(key, &tmp_min_key,
&tmp_min_flag);
}
if (!tmp_max_flag)
key_tree->next_key_part->store_max_key(key, &tmp_max_key,
{
max_part+= key_tree->next_key_part->store_max_key(key, &tmp_max_key,
&tmp_max_flag);
}
flag=tmp_min_flag | tmp_max_flag;
}
}
@ -7511,13 +7546,15 @@ get_quick_keys(PARAM *param,QUICK_RANGE_SELECT *quick,KEY_PART *key,
/* Get range for retrieving rows in QUICK_SELECT::get_next */
if (!(range= new QUICK_RANGE((const char *) param->min_key,
(uint) (tmp_min_key - param->min_key),
min_part >=0 ? make_keypart_map(min_part) : 0,
(const char *) param->max_key,
(uint) (tmp_max_key - param->max_key),
max_part >=0 ? make_keypart_map(max_part) : 0,
flag)))
return 1; // out of memory
set_if_bigger(quick->max_used_key_length,range->min_length);
set_if_bigger(quick->max_used_key_length,range->max_length);
set_if_bigger(quick->max_used_key_length, range->min_length);
set_if_bigger(quick->max_used_key_length, range->max_length);
set_if_bigger(quick->used_key_parts, (uint) key_tree->part+1);
if (insert_dynamic(&quick->ranges, (gptr)&range))
return 1;
@ -7659,6 +7696,7 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
range->min_key=range->max_key=(char*) ref->key_buff;
range->min_length=range->max_length=ref->key_length;
range->min_keypart_map= range->max_keypart_map= (1 << ref->key_parts) - 1;
range->flag= ((ref->key_length == key_info->key_length &&
(key_info->flags & (HA_NOSAME | HA_END_SPACE_KEY)) ==
HA_NOSAME) ? EQ_RANGE : 0);
@ -7692,8 +7730,10 @@ QUICK_RANGE_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table,
*ref->null_ref_key= 1; // Set null byte then create a range
if (!(null_range= new (alloc) QUICK_RANGE((char*)ref->key_buff,
ref->key_length,
(1 << ref->key_parts) - 1,
(char*)ref->key_buff,
ref->key_length,
(1 << ref->key_parts) - 1,
EQ_RANGE)))
goto err;
*ref->null_ref_key= 0; // Clear null byte
@ -8146,6 +8186,7 @@ int QUICK_RANGE_SELECT::get_next()
start_key->flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
(last_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
start_key->keypart_map= last_range->min_keypart_map;
end_key->key= (const byte*) last_range->max_key;
end_key->length= last_range->max_length;
/*
@ -8154,6 +8195,7 @@ int QUICK_RANGE_SELECT::get_next()
*/
end_key->flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
end_key->keypart_map= last_range->max_keypart_map;
mrange_slot->range_flag= last_range->flag;
}
@ -8203,7 +8245,9 @@ end:
other if some error occurred
*/
int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length,
ulonglong keypart_map,
byte *cur_prefix)
{
DBUG_ENTER("QUICK_RANGE_SELECT::get_next_prefix");
@ -8215,8 +8259,7 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
{
/* Read the next record in the same range with prefix after cur_prefix. */
DBUG_ASSERT(cur_prefix != 0);
result= file->index_read(record, cur_prefix, prefix_length,
HA_READ_AFTER_KEY);
result= file->index_read(record, cur_prefix, keypart_map, HA_READ_AFTER_KEY);
if (result || (file->compare_key(file->end_range) <= 0))
DBUG_RETURN(result);
}
@ -8232,11 +8275,13 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
start_key.key= (const byte*) last_range->min_key;
start_key.length= min(last_range->min_length, prefix_length);
start_key.keypart_map= last_range->min_keypart_map & keypart_map;
start_key.flag= ((last_range->flag & NEAR_MIN) ? HA_READ_AFTER_KEY :
(last_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : HA_READ_KEY_OR_NEXT);
end_key.key= (const byte*) last_range->max_key;
end_key.length= min(last_range->max_length, prefix_length);
end_key.keypart_map= last_range->max_keypart_map & keypart_map;
/*
We use READ_AFTER_KEY here because if we are reading on a key
prefix we want to find all keys with this prefix
@ -8244,8 +8289,8 @@ int QUICK_RANGE_SELECT::get_next_prefix(uint prefix_length, byte *cur_prefix)
end_key.flag= (last_range->flag & NEAR_MAX ? HA_READ_BEFORE_KEY :
HA_READ_AFTER_KEY);
result= file->read_range_first(last_range->min_length ? &start_key : 0,
last_range->max_length ? &end_key : 0,
result= file->read_range_first(last_range->min_keypart_map ? &start_key : 0,
last_range->max_keypart_map ? &end_key : 0,
test(last_range->flag & EQ_RANGE),
sorted);
if (last_range->flag == (UNIQUE_RANGE | EQ_RANGE))
@ -8285,9 +8330,8 @@ int QUICK_RANGE_SELECT_GEOM::get_next()
}
last_range= *(cur_range++);
result= file->index_read(record,
(byte*) last_range->min_key,
last_range->min_length,
result= file->index_read(record, (byte*) last_range->min_key,
last_range->min_keypart_map,
(ha_rkey_function)(last_range->flag ^ GEOM_FLAG));
if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
@ -8419,15 +8463,15 @@ int QUICK_SELECT_DESC::get_next()
if (last_range->flag & EQ_RANGE)
{
result= file->index_read(record, (byte*) last_range->max_key,
last_range->max_length, HA_READ_KEY_EXACT);
result = file->index_read(record, (byte*) last_range->max_key,
last_range->max_keypart_map, HA_READ_KEY_EXACT);
}
else
{
DBUG_ASSERT(last_range->flag & NEAR_MAX ||
range_reads_after_key(last_range));
result=file->index_read(record, (byte*) last_range->max_key,
last_range->max_length,
last_range->max_keypart_map,
((last_range->flag & NEAR_MAX) ?
HA_READ_BEFORE_KEY :
HA_READ_PREFIX_LAST_OR_PREV));
@ -8747,8 +8791,7 @@ void QUICK_ROR_UNION_SELECT::add_keys_and_lengths(String *key_names,
static inline uint get_field_keypart(KEY *index, Field *field);
static inline SEL_ARG * get_index_range_tree(uint index, SEL_TREE* range_tree,
PARAM *param, uint *param_idx);
static bool
get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
static bool get_constant_key_infix(KEY *index_info, SEL_ARG *index_range_tree,
KEY_PART_INFO *first_non_group_part,
KEY_PART_INFO *min_max_arg_part,
KEY_PART_INFO *last_part, THD *thd,
@ -9146,7 +9189,7 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
NULL;
first_non_infix_part= min_max_arg_part ?
(min_max_arg_part < last_part) ?
min_max_arg_part + 1 :
min_max_arg_part :
NULL :
NULL;
if (first_non_group_part &&
@ -9203,7 +9246,9 @@ get_best_group_min_max(PARAM *param, SEL_TREE *tree)
*/
if (first_non_infix_part)
{
for (cur_part= first_non_infix_part; cur_part != last_part; cur_part++)
cur_part= first_non_infix_part +
(min_max_arg_part && (min_max_arg_part < last_part));
for (; cur_part != last_part; cur_part++)
{
if (bitmap_is_set(table->read_set, cur_part->field->field_index))
goto next_index;
@ -9749,7 +9794,7 @@ void cost_group_min_max(TABLE* table, KEY *index_info, uint used_key_parts,
RETURN
New QUICK_GROUP_MIN_MAX_SELECT object if successfully created,
NULL o/w.
NULL otherwise.
*/
QUICK_SELECT_I *
@ -9762,10 +9807,10 @@ TRP_GROUP_MIN_MAX::make_quick(PARAM *param, bool retrieve_full_rows,
quick= new QUICK_GROUP_MIN_MAX_SELECT(param->table,
param->thd->lex->current_select->join,
have_min, have_max, min_max_arg_part,
group_prefix_len, used_key_parts,
index_info, index, read_cost, records,
key_infix_len, key_infix,
parent_alloc);
group_prefix_len, group_key_parts,
used_key_parts, index_info, index,
read_cost, records, key_infix_len,
key_infix, parent_alloc);
if (!quick)
DBUG_RETURN(NULL);
@ -9854,7 +9899,7 @@ QUICK_GROUP_MIN_MAX_SELECT::
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
bool have_max_arg,
KEY_PART_INFO *min_max_arg_part_arg,
uint group_prefix_len_arg,
uint group_prefix_len_arg, uint group_key_parts_arg,
uint used_key_parts_arg, KEY *index_info_arg,
uint use_index, double read_cost_arg,
ha_rows records_arg, uint key_infix_len_arg,
@ -9864,7 +9909,7 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
have_max(have_max_arg), seen_first_key(FALSE),
min_max_arg_part(min_max_arg_part_arg), key_infix(key_infix_arg),
key_infix_len(key_infix_len_arg), min_functions_it(NULL),
max_functions_it(NULL)
max_functions_it(NULL), group_key_parts(group_key_parts_arg)
{
head= table;
file= head->file;
@ -9874,6 +9919,7 @@ QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join_arg, bool have_min_arg,
read_time= read_cost_arg;
records= records_arg;
used_key_parts= used_key_parts_arg;
real_key_parts= used_key_parts_arg;
real_prefix_len= group_prefix_len + key_infix_len;
group_prefix= NULL;
min_max_arg_len= min_max_arg_part ? min_max_arg_part->store_length : 0;
@ -10040,7 +10086,9 @@ bool QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG *sel_range)
range_flag|= EQ_RANGE; /* equality condition */
}
range= new QUICK_RANGE(sel_range->min_value, min_max_arg_len,
make_keypart_map(sel_range->part),
sel_range->max_value, min_max_arg_len,
make_keypart_map(sel_range->part),
range_flag);
if (!range)
return TRUE;
@ -10279,7 +10327,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::get_next()
first sub-group with the extended prefix.
*/
if (!have_min && !have_max && key_infix_len > 0)
result= file->index_read(record, group_prefix, real_prefix_len,
result= file->index_read(record, group_prefix,
make_prev_keypart_map(real_key_parts),
HA_READ_KEY_EXACT);
result= have_min ? min_res : have_max ? max_res : result;
@ -10342,7 +10391,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min()
/* Apply the constant equality conditions to the non-group select fields */
if (key_infix_len > 0)
{
if ((result= file->index_read(record, group_prefix, real_prefix_len,
if ((result= file->index_read(record, group_prefix,
make_prev_keypart_map(real_key_parts),
HA_READ_KEY_EXACT)))
DBUG_RETURN(result);
}
@ -10359,7 +10409,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min()
/* Find the first subsequent record without NULL in the MIN/MAX field. */
key_copy(tmp_record, record, index_info, 0);
result= file->index_read(record, tmp_record,
real_prefix_len + min_max_arg_len,
make_keypart_map(real_key_parts),
HA_READ_AFTER_KEY);
/*
Check if the new record belongs to the current group by comparing its
@ -10415,7 +10465,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max()
if (min_max_ranges.elements > 0)
result= next_max_in_range();
else
result= file->index_read(record, group_prefix, real_prefix_len,
result= file->index_read(record, group_prefix,
make_prev_keypart_map(real_key_parts),
HA_READ_PREFIX_LAST);
DBUG_RETURN(result);
}
@ -10451,7 +10502,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
{
byte *cur_prefix= seen_first_key ? group_prefix : NULL;
if ((result= quick_prefix_select->get_next_prefix(group_prefix_len,
cur_prefix)))
(ULL(1) << group_key_parts) - 1, cur_prefix)))
DBUG_RETURN(result);
seen_first_key= TRUE;
}
@ -10467,7 +10518,8 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_prefix()
else
{
/* Load the first key in this group into record. */
result= file->index_read(record, group_prefix, group_prefix_len,
result= file->index_read(record, group_prefix,
make_prev_keypart_map(group_key_parts),
HA_READ_AFTER_KEY);
if (result)
DBUG_RETURN(result);
@ -10510,6 +10562,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
{
ha_rkey_function find_flag;
uint search_prefix_len;
ulonglong keypart_map;
QUICK_RANGE *cur_range;
bool found_null= FALSE;
int result= HA_ERR_KEY_NOT_FOUND;
@ -10531,8 +10584,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
if (cur_range->flag & NO_MIN_RANGE)
{
find_flag= HA_READ_KEY_EXACT;
search_prefix_len= real_prefix_len;
keypart_map= (ULL(1) << real_key_parts) - 1;
find_flag= HA_READ_KEY_EXACT;
}
else
{
@ -10540,13 +10594,13 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_min_in_range()
memcpy(group_prefix + real_prefix_len, cur_range->min_key,
cur_range->min_length);
search_prefix_len= real_prefix_len + min_max_arg_len;
keypart_map= (ULL(2) << real_key_parts) - 1;
find_flag= (cur_range->flag & (EQ_RANGE | NULL_RANGE)) ?
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MIN) ?
HA_READ_AFTER_KEY : HA_READ_KEY_OR_NEXT;
}
result= file->index_read(record, group_prefix, search_prefix_len,
find_flag);
result= file->index_read(record, group_prefix, keypart_map, find_flag);
if (result)
{
if ((result == HA_ERR_KEY_NOT_FOUND || result == HA_ERR_END_OF_FILE) &&
@ -10644,6 +10698,7 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
{
ha_rkey_function find_flag;
uint search_prefix_len;
ulonglong keypart_map;
QUICK_RANGE *cur_range;
int result;
@ -10665,8 +10720,9 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
if (cur_range->flag & NO_MAX_RANGE)
{
find_flag= HA_READ_PREFIX_LAST;
search_prefix_len= real_prefix_len;
keypart_map= (ULL(1) << real_key_parts) - 1;
find_flag= HA_READ_PREFIX_LAST;
}
else
{
@ -10674,13 +10730,13 @@ int QUICK_GROUP_MIN_MAX_SELECT::next_max_in_range()
memcpy(group_prefix + real_prefix_len, cur_range->max_key,
cur_range->max_length);
search_prefix_len= real_prefix_len + min_max_arg_len;
keypart_map= (ULL(2) << real_key_parts) - 1;
find_flag= (cur_range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT : (cur_range->flag & NEAR_MAX) ?
HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV;
}
result= file->index_read(record, group_prefix, search_prefix_len,
find_flag);
result= file->index_read(record, group_prefix, keypart_map, find_flag);
if (result)
{

View File

@ -37,17 +37,22 @@ class QUICK_RANGE :public Sql_alloc {
public:
char *min_key,*max_key;
uint16 min_length,max_length,flag;
ulonglong min_keypart_map, max_keypart_map;
#ifdef HAVE_purify
uint16 dummy; /* Avoid warnings on 'flag' */
#endif
QUICK_RANGE(); /* Full range */
QUICK_RANGE(const char *min_key_arg,uint min_length_arg,
const char *max_key_arg,uint max_length_arg,
QUICK_RANGE(const char *min_key_arg, uint min_length_arg,
ulonglong min_keypart_map_arg,
const char *max_key_arg, uint max_length_arg,
ulonglong max_keypart_map_arg,
uint flag_arg)
: min_key((char*) sql_memdup(min_key_arg,min_length_arg+1)),
max_key((char*) sql_memdup(max_key_arg,max_length_arg+1)),
min_length((uint16) min_length_arg),
max_length((uint16) max_length_arg),
min_keypart_map(min_keypart_map_arg),
max_keypart_map(max_keypart_map_arg),
flag((uint16) flag_arg)
{
#ifdef HAVE_purify
@ -318,7 +323,8 @@ public:
int reset(void);
int get_next();
void range_end();
int get_next_prefix(uint prefix_length, byte *cur_prefix);
int get_next_prefix(uint prefix_length, ulonglong keypart_map,
byte *cur_prefix);
bool reverse_sorted() { return 0; }
bool unique_key_range();
int init_ror_merged_scan(bool reuse_handler);
@ -605,6 +611,7 @@ private:
byte *tmp_record; /* Temporary storage for next_min(), next_max(). */
byte *group_prefix; /* Key prefix consisting of the GROUP fields. */
uint group_prefix_len; /* Length of the group prefix. */
uint group_key_parts;
byte *last_prefix; /* Prefix of the last group for detecting EOF. */
bool have_min; /* Specify whether we are computing */
bool have_max; /* a MIN, a MAX, or both. */
@ -616,6 +623,7 @@ private:
uint key_infix_len;
DYNAMIC_ARRAY min_max_ranges; /* Array of range ptrs for the MIN/MAX field. */
uint real_prefix_len; /* Length of key prefix extended with key_infix. */
uint real_key_parts;
List<Item_sum> *min_functions;
List<Item_sum> *max_functions;
List_iterator<Item_sum> *min_functions_it;
@ -638,10 +646,11 @@ private:
public:
QUICK_GROUP_MIN_MAX_SELECT(TABLE *table, JOIN *join, bool have_min,
bool have_max, KEY_PART_INFO *min_max_arg_part,
uint group_prefix_len, uint used_key_parts,
KEY *index_info, uint use_index, double read_cost,
ha_rows records, uint key_infix_len,
byte *key_infix, MEM_ROOT *parent_alloc);
uint group_prefix_len, uint group_key_parts,
uint used_key_parts, KEY *index_info, uint
use_index, double read_cost, ha_rows records, uint
key_infix_len, byte *key_infix, MEM_ROOT
*parent_alloc);
~QUICK_GROUP_MIN_MAX_SELECT();
bool add_range(SEL_ARG *sel_range);
void update_key_stat();

View File

@ -251,7 +251,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
error= table->file->index_first(table->record[0]);
else
error= table->file->index_read(table->record[0],key_buff,
ref.key_length,
make_prev_keypart_map(ref.key_parts),
range_fl & NEAR_MIN ?
HA_READ_AFTER_KEY :
HA_READ_KEY_OR_NEXT);
@ -338,11 +338,11 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
error= table->file->index_last(table->record[0]);
else
error= table->file->index_read(table->record[0], key_buff,
ref.key_length,
make_prev_keypart_map(ref.key_parts),
range_fl & NEAR_MAX ?
HA_READ_BEFORE_KEY :
HA_READ_PREFIX_LAST_OR_PREV);
if (!error && reckey_in_range(1, &ref, item_field->field,
if (!error && reckey_in_range(1, &ref, item_field->field,
conds, range_fl, prefix_len))
error= HA_ERR_KEY_NOT_FOUND;
if (table->key_read)
@ -605,15 +605,13 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
/* Check if field is part of the tested partial key */
byte *key_ptr= ref->key_buff;
KEY_PART_INFO *part;
for (part= keyinfo->key_part;
;
key_ptr+= part++->store_length)
for (part= keyinfo->key_part; ; key_ptr+= part++->store_length)
{
if (part > field_part)
return 0; // Field is beyond the tested parts
if (part->field->eq(((Item_field*) args[0])->field))
break; // Found a part od the key for the field
break; // Found a part of the key for the field
}
bool is_field_part= part == field_part;
@ -625,8 +623,11 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
{
uint length= (key_ptr-ref->key_buff)+part->store_length;
if (ref->key_length < length)
{
/* Ultimately ref->key_length will contain the length of the search key */
ref->key_length= length;
ref->key_parts= (part - keyinfo->key_part) + 1;
}
if (!*prefix_len && part+1 == field_part)
*prefix_len= length;
if (is_field_part && eq_type)
@ -773,6 +774,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
{
ref->key= idx;
ref->key_length= 0;
ref->key_parts= 0;
key_part_map key_part_used= 0;
*range_fl= NO_MIN_RANGE | NO_MAX_RANGE;
if (matching_cond(max_fl, ref, keyinfo, part, cond,
@ -788,6 +790,8 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
*/
ref->key_buff[ref->key_length]= 1;
ref->key_length+= part->store_length;
ref->key_parts++;
DBUG_ASSERT(ref->key_parts == jdx+1);
*range_fl&= ~NO_MIN_RANGE;
*range_fl|= NEAR_MIN; // > NULL
}

View File

@ -31,6 +31,8 @@
#include "rpl_tblmap.h"
int queue_event(MASTER_INFO* mi,const char* buf,ulong event_len);
static Log_event* next_event(RELAY_LOG_INFO* rli);
#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")

View File

@ -218,8 +218,7 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
key_copy(key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0,
key, table->key_info->key_length,
if (table->file->index_read_idx(table->record[0], 0, key, ~ULL(0),
HA_READ_KEY_EXACT))
DBUG_RETURN(SP_KEY_NOT_FOUND);
@ -925,7 +924,7 @@ sp_drop_db_routines(THD *thd, char *db)
table->file->ha_index_init(0, 1);
if (! table->file->index_read(table->record[0],
(byte *)table->field[MYSQL_PROC_FIELD_DB]->ptr,
key_len, HA_READ_KEY_EXACT))
(ulonglong)1, HA_READ_KEY_EXACT))
{
int nxtres;
bool deleted= FALSE;

View File

@ -1813,8 +1813,7 @@ static bool update_user_table(THD *thd, TABLE *table,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0,
(byte *) user_key,
table->key_info->key_length,
(byte *) user_key, ~ULL(0),
HA_READ_KEY_EXACT))
{
my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
@ -1905,8 +1904,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0,
user_key, table->key_info->key_length,
if (table->file->index_read_idx(table->record[0], 0, user_key, ~ULL(0),
HA_READ_KEY_EXACT))
{
/* what == 'N' means revoke */
@ -2123,8 +2121,7 @@ static int replace_db_table(TABLE *table, const char *db,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0],0,
user_key, table->key_info->key_length,
if (table->file->index_read_idx(table->record[0],0, user_key, ~ULL(0),
HA_READ_KEY_EXACT))
{
if (what == 'N')
@ -2341,9 +2338,8 @@ GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
col_privs->field[4]->store("",0, &my_charset_latin1);
col_privs->file->ha_index_init(0, 1);
if (col_privs->file->index_read(col_privs->record[0],
(byte*) key,
key_prefix_len, HA_READ_KEY_EXACT))
if (col_privs->file->index_read(col_privs->record[0], (byte*) key,
(ulonglong)15, HA_READ_KEY_EXACT))
{
cols = 0; /* purecov: deadcode */
col_privs->file->ha_index_end();
@ -2479,7 +2475,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
table->field[3]->store(table_name,(uint) strlen(table_name),
system_charset_info);
/* Get length of 3 first key parts */
/* Get length of 4 first key parts */
key_prefix_length= (key_part[0].store_length + key_part[1].store_length +
key_part[2].store_length + key_part[3].store_length);
key_copy(key, table->record[0], table->key_info, key_prefix_length);
@ -2505,8 +2501,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read(table->record[0], user_key,
table->key_info->key_length,
if (table->file->index_read(table->record[0], user_key, ~(ulonglong)0,
HA_READ_KEY_EXACT))
{
if (revoke_grant)
@ -2582,8 +2577,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_copy(user_key, table->record[0], table->key_info,
key_prefix_length);
if (table->file->index_read(table->record[0], user_key,
key_prefix_length,
if (table->file->index_read(table->record[0], user_key, (ulonglong)15,
HA_READ_KEY_EXACT))
goto end;
@ -2684,8 +2678,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
key_copy(user_key, table->record[0], table->key_info,
table->key_info->key_length);
if (table->file->index_read_idx(table->record[0], 0,
user_key, table->key_info->key_length,
if (table->file->index_read_idx(table->record[0], 0, user_key, ~ULL(0),
HA_READ_KEY_EXACT))
{
/*
@ -2808,8 +2801,8 @@ static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
TRUE);
store_record(table,record[1]); // store at pos 1
if (table->file->index_read_idx(table->record[0],0,
(byte*) table->field[0]->ptr,0,
if (table->file->index_read_idx(table->record[0], 0,
(byte*) table->field[0]->ptr, ~ULL(0),
HA_READ_KEY_EXACT))
{
/*
@ -5008,7 +5001,7 @@ static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
key_copy(user_key, table->record[0], table->key_info, key_prefix_length);
if ((error= table->file->index_read_idx(table->record[0], 0,
user_key, key_prefix_length,
user_key, ULL(3),
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)

View File

@ -515,7 +515,8 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
List_iterator<Item> it_ke(*key_expr);
Item *item;
for (key_len=0 ; (item=it_ke++) ; key_part++)
ulonglong keypart_map;
for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++)
{
my_bitmap_map *old_map;
// 'item' can be changed by fix_fields() call
@ -532,6 +533,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
(void) item->save_in_field(key_part->field, 1);
dbug_tmp_restore_column_map(table->write_set, old_map);
key_len+=key_part->store_length;
keypart_map= (keypart_map << 1) | 1;
}
if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
@ -540,7 +542,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
table->file->ha_index_init(keyno, 1);
key_copy(key, table->record[0], table->key_info + keyno, key_len);
error= table->file->index_read(table->record[0],
key,key_len,ha_rkey_mode);
key, keypart_map, ha_rkey_mode);
mode=rkey_to_rnext[(int)ha_rkey_mode];
break;
}

View File

@ -295,8 +295,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
rkey_id->store((longlong) key_id, TRUE);
rkey_id->get_key_image(buff, rkey_id->pack_length(), Field::itRAW);
int key_res= relations->file->index_read(relations->record[0],
(byte *) buff,
rkey_id->pack_length(),
(byte *) buff, (ulonglong)1,
HA_READ_KEY_EXACT);
for ( ;
@ -310,7 +309,7 @@ int get_topics_for_keyword(THD *thd, TABLE *topics, TABLE *relations,
field->get_key_image(topic_id_buff, field->pack_length(), Field::itRAW);
if (!topics->file->index_read(topics->record[0], (byte *)topic_id_buff,
field->pack_length(), HA_READ_KEY_EXACT))
(ulonglong)1, HA_READ_KEY_EXACT))
{
memorize_variant_topic(thd,topics,count,find_fields,
names,name,description,example);

View File

@ -1214,9 +1214,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
}
key_copy((byte*) key,table->record[0],table->key_info+key_nr,0);
if ((error=(table->file->index_read_idx(table->record[1],key_nr,
(byte*) key,
table->key_info[key_nr].
key_length,
(byte*) key, ~ULL(0),
HA_READ_KEY_EXACT))))
goto err;
}

View File

@ -943,8 +943,7 @@ my_bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
table->use_all_columns();
table->field[0]->store(name->str, name->length, system_charset_info);
if (! table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, ~ULL(0),
HA_READ_KEY_EXACT))
{
int error;

View File

@ -10980,7 +10980,8 @@ int safe_index_read(JOIN_TAB *tab)
TABLE *table= tab->table;
if ((error=table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length, HA_READ_KEY_EXACT)))
tab_to_keypart_map(tab),
HA_READ_KEY_EXACT)))
return report_error(table, error);
return 0;
}
@ -11118,7 +11119,8 @@ join_read_const(JOIN_TAB *tab)
{
error=table->file->index_read_idx(table->record[0],tab->ref.key,
(byte*) tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
tab_to_keypart_map(tab),
HA_READ_KEY_EXACT);
}
if (error)
{
@ -11161,7 +11163,8 @@ join_read_key(JOIN_TAB *tab)
}
error=table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT);
tab_to_keypart_map(tab),
HA_READ_KEY_EXACT);
if (error && error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
}
@ -11189,7 +11192,8 @@ join_read_always_key(JOIN_TAB *tab)
return -1;
if ((error=table->file->index_read(table->record[0],
tab->ref.key_buff,
tab->ref.key_length,HA_READ_KEY_EXACT)))
tab_to_keypart_map(tab),
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
@ -11216,7 +11220,7 @@ join_read_last_key(JOIN_TAB *tab)
return -1;
if ((error=table->file->index_read_last(table->record[0],
tab->ref.key_buff,
tab->ref.key_length)))
tab_to_keypart_map(tab))))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
return report_error(table, error);
@ -11757,7 +11761,7 @@ end_update(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
group->buff[-1]= (char) group->field->is_null();
}
if (!table->file->index_read(table->record[1],
join->tmp_table_param.group_buff,0,
join->tmp_table_param.group_buff, ~(ulonglong)0,
HA_READ_KEY_EXACT))
{ /* Update old record */
restore_record(table,record[1]);

View File

@ -202,6 +202,11 @@ typedef struct st_join_table {
}
} JOIN_TAB;
static inline ulonglong tab_to_keypart_map(JOIN_TAB *tab)
{
return (ULL(1) << tab->ref.key_parts) - 1;
}
enum_nested_loop_state sub_select_cache(JOIN *join, JOIN_TAB *join_tab, bool
end_of_records);
enum_nested_loop_state sub_select(JOIN *join,JOIN_TAB *join_tab, bool

View File

@ -25,6 +25,7 @@
#include "sp_head.h"
#include "sp.h"
static my_bool servers_load(THD *thd, TABLE_LIST *tables);
HASH servers_cache;
pthread_mutex_t servers_cache_mutex; // To init the hash
uint servers_cache_initialised=FALSE;
@ -353,8 +354,7 @@ my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options)
system_charset_info);
if ((error= table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, ~(ulonglong)0,
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
@ -554,8 +554,7 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
/* read index until record is that specified in server_name */
if ((error= table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, ~(longlong)0,
HA_READ_KEY_EXACT)))
{
/* if not found, err */
@ -873,8 +872,7 @@ int update_server_record(TABLE *table, FOREIGN_SERVER *server)
system_charset_info);
if ((error= table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, ~(longlong)0,
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
@ -928,8 +926,7 @@ int delete_server_record(TABLE *table,
table->field[0]->store(server_name, server_name_length, system_charset_info);
if ((error= table->file->index_read_idx(table->record[0], 0,
(byte *)table->field[0]->ptr,
table->key_info[0].key_length,
(byte *)table->field[0]->ptr, ~(ulonglong)0,
HA_READ_KEY_EXACT)))
{
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)

View File

@ -514,8 +514,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name)
table->use_all_columns();
table->field[0]->store(exact_name_str, exact_name_len, &my_charset_bin);
if (!table->file->index_read_idx(table->record[0], 0,
(byte*) table->field[0]->ptr,
table->key_info[0].key_length,
(byte*) table->field[0]->ptr, ~ULL(0),
HA_READ_KEY_EXACT))
{
int error;

View File

@ -1222,12 +1222,12 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
if ((int) (share->next_number_index= (uint)
find_ref_key(share->key_info, share->keys,
share->default_values, reg_field,
&share->next_number_key_offset)) < 0)
&share->next_number_key_offset,
&share->next_number_keypart)) < 0)
{
/* Wrong field definition */
DBUG_ASSERT(0);
reg_field->unireg_check= Field::NONE; /* purecov: inspected */
share->found_next_number_field= 0;
error= 4;
goto err;
}
else
reg_field->flags |= AUTO_INCREMENT_FLAG;
@ -2244,6 +2244,30 @@ char *get_field(MEM_ROOT *mem, Field *field)
return to;
}
/*
DESCRIPTION
given a buffer with a key value, and a map of keyparts
that are present in this value, returns the length of the value
*/
uint calculate_key_len(TABLE *table, uint key, const byte *buf,
ulonglong keypart_map)
{
/* works only with key prefixes */
DBUG_ASSERT(((keypart_map + 1) & keypart_map) == 0);
KEY *key_info= table->s->key_info+key;
KEY_PART_INFO *key_part= key_info->key_part;
KEY_PART_INFO *end_key_part= key_part + key_info->key_parts;
uint length= 0;
while (key_part < end_key_part && keypart_map)
{
length+= key_part->store_length;
keypart_map >>= 1;
key_part++;
}
return length;
}
/*
Check if database name is valid
@ -3938,7 +3962,7 @@ void st_table::mark_auto_increment_column()
*/
bitmap_set_bit(read_set, found_next_number_field->field_index);
bitmap_set_bit(write_set, found_next_number_field->field_index);
if (s->next_number_key_offset)
if (s->next_number_keypart)
mark_columns_used_by_index_no_reset(s->next_number_index, read_set);
file->column_bitmaps_signal();
}

View File

@ -199,6 +199,7 @@ typedef struct st_table_share
uint primary_key;
uint next_number_index;
uint next_number_key_offset;
uint next_number_keypart;
uint error, open_errno, errarg; /* error from open_table_def() */
uint column_bitmap_size;
uchar frm_version;

View File

@ -1917,9 +1917,9 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
(void)table->file->ha_index_init(0, 1);
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
~(ulonglong)0, HA_READ_KEY_EXACT))
{
#ifdef EXTRA_DEBUG
#ifdef EXTRA_DEBUG
/*
Most probably user has mistyped time zone name, so no need to bark here
unless we need it for debugging.
@ -1945,7 +1945,7 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
(void)table->file->ha_index_init(0, 1);
if (table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
0, HA_READ_KEY_EXACT))
~(ulonglong)0, HA_READ_KEY_EXACT))
{
sql_print_error("Can't find description of time zone '%u'", tzid);
goto end;
@ -1972,9 +1972,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
// FIXME Is there any better approach than explicitly specifying 4 ???
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
4, HA_READ_KEY_EXACT);
(ulonglong)1, HA_READ_KEY_EXACT);
while (!res)
{
ttid= (uint)table->field[1]->val_int();
@ -2045,9 +2044,8 @@ tz_load_from_open_tables(const String *tz_name, TABLE_LIST *tz_tables)
table->field[0]->store((longlong) tzid, TRUE);
(void)table->file->ha_index_init(0, 1);
// FIXME Is there any better approach than explicitly specifying 4 ???
res= table->file->index_read(table->record[0], (byte*)table->field[0]->ptr,
4, HA_READ_KEY_EXACT);
(ulonglong)1, HA_READ_KEY_EXACT);
while (!res)
{
ttime= (my_time_t)table->field[1]->val_int();

View File

@ -152,7 +152,8 @@ THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd,
int ha_blackhole::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
ulonglong keypart_map, uint key_len,
enum ha_rkey_function find_flag)
{
DBUG_ENTER("ha_blackhole::index_read");
DBUG_RETURN(HA_ERR_END_OF_FILE);
@ -160,14 +161,16 @@ int ha_blackhole::index_read(byte * buf, const byte * key,
int ha_blackhole::index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
ulonglong keypart_map, uint key_len,
enum ha_rkey_function find_flag)
{
DBUG_ENTER("ha_blackhole::index_read_idx");
DBUG_RETURN(HA_ERR_END_OF_FILE);
}
int ha_blackhole::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_blackhole::index_read_last(byte * buf, const byte * key,
ulonglong keypart_map)
{
DBUG_ENTER("ha_blackhole::index_read_last");
DBUG_RETURN(HA_ERR_END_OF_FILE);

View File

@ -64,11 +64,12 @@ public:
int rnd_init(bool scan);
int rnd_next(byte *buf);
int rnd_pos(byte * buf, byte *pos);
int index_read(byte * buf, const byte * key,
int index_read(byte * buf, const byte * key, ulonglong keypart_map,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_last(byte * buf, const byte * key, uint key_len);
ulonglong keypart_map, uint key_len,
enum ha_rkey_function find_flag);
int index_read_last(byte * buf, const byte * key, ulonglong keypart_map);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);

View File

@ -415,7 +415,7 @@ int ha_example::delete_row(const byte * buf)
*/
int ha_example::index_read(byte * buf, const byte * key,
uint key_len __attribute__((unused)),
ulonglong keypart_map __attribute__((unused)),
enum ha_rkey_function find_flag
__attribute__((unused)))
{

View File

@ -191,7 +191,7 @@ public:
skip it and and MySQL will treat it as not implemented.
*/
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
ulonglong keypart_map, enum ha_rkey_function find_flag);
/** @brief
We implement this in ha_example.cc. It's not an obligatory method;

View File

@ -363,7 +363,6 @@ static handler *federated_create_handler(handlerton *hton,
static int federated_commit(handlerton *hton, THD *thd, bool all);
static int federated_rollback(handlerton *hton, THD *thd, bool all);
/* Federated storage engine handlerton */
static handler *federated_create_handler(handlerton *hton,

View File

@ -238,34 +238,35 @@ int ha_heap::delete_row(const byte * buf)
return res;
}
int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
int ha_heap::index_read(byte * buf, const byte * key, ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
DBUG_ASSERT(inited==INDEX);
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error = heap_rkey(file,buf,active_index, key, key_len, find_flag);
int error = heap_rkey(file,buf,active_index, key, keypart_map, find_flag);
table->status = error ? STATUS_NOT_FOUND : 0;
return error;
}
int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len)
int ha_heap::index_read_last(byte *buf, const byte *key, ulonglong keypart_map)
{
DBUG_ASSERT(inited==INDEX);
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error= heap_rkey(file, buf, active_index, key, key_len,
int error= heap_rkey(file, buf, active_index, key, keypart_map,
HA_READ_PREFIX_LAST);
table->status= error ? STATUS_NOT_FOUND : 0;
return error;
}
int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error = heap_rkey(file, buf, index, key, key_len, find_flag);
int error = heap_rkey(file, buf, index, key, keypart_map, find_flag);
table->status = error ? STATUS_NOT_FOUND : 0;
return error;
}

View File

@ -75,11 +75,11 @@ public:
ulonglong nb_desired_values,
ulonglong *first_value,
ulonglong *nb_reserved_values);
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_last(byte * buf, const byte * key, uint key_len);
int index_read(byte * buf, const byte * key, ulonglong keypart_map,
enum ha_rkey_function find_flag);
int index_read_last(byte *buf, const byte *key, ulonglong keypart_map);
int index_read_idx(byte * buf, uint index, const byte * key,
ulonglong keypart_map, enum ha_rkey_function find_flag);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);

View File

@ -100,7 +100,7 @@ extern int hp_close(register HP_INFO *info);
extern void hp_clear(HP_SHARE *info);
extern void hp_clear_keys(HP_SHARE *info);
extern uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
uint k_len);
ulonglong keypart_map);
#ifdef THREAD
extern pthread_mutex_t THR_LOCK_heap;
#else

View File

@ -784,30 +784,26 @@ uint hp_rb_make_key(HP_KEYDEF *keydef, byte *key,
uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
uint k_len)
ulonglong keypart_map)
{
HA_KEYSEG *seg, *endseg;
uchar *start_key= key;
for (seg= keydef->seg, endseg= seg + keydef->keysegs;
seg < endseg && (int) k_len > 0; old+= seg->length, seg++)
seg < endseg && keypart_map; old+= seg->length, seg++)
{
uint char_length;
keypart_map>>= 1;
if (seg->null_bit)
{
k_len--;
if (!(*key++= (char) 1 - *old++))
{
k_len-= seg->length;
continue;
}
}
if (seg->flag & HA_SWAP_KEY)
{
uint length= seg->length;
byte *pos= (byte*) old + length;
k_len-= length;
while (length--)
{
*key++= *--pos;
@ -822,7 +818,6 @@ uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
CHARSET_INFO *cs= seg->charset;
char_length= length/cs->mbmaxlen;
k_len-= 2+length;
old+= 2;
set_if_smaller(length,tmp_length); /* Safety */
FIX_LENGTH(cs, old, length, char_length);
@ -843,7 +838,6 @@ uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old,
}
memcpy(key, old, (size_t) char_length);
key+= seg->length;
k_len-= seg->length;
}
return (uint) (key - start_key);
}

View File

@ -16,7 +16,7 @@
#include "heapdef.h"
int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
uint key_len, enum ha_rkey_function find_flag)
ulonglong keypart_map, enum ha_rkey_function find_flag)
{
byte *pos;
HP_SHARE *share= info->s;
@ -38,7 +38,7 @@ int heap_rkey(HP_INFO *info, byte *record, int inx, const byte *key,
custom_arg.keyseg= info->s->keydef[inx].seg;
custom_arg.key_length= info->lastkey_len=
hp_rb_pack_key(keyinfo, (uchar*) info->lastkey,
(uchar*) key, key_len);
(uchar*) key, keypart_map);
custom_arg.search_flag= SEARCH_FIND | SEARCH_SAME;
/* for next rkey() after deletion */
if (find_flag == HA_READ_AFTER_KEY)

View File

@ -3927,14 +3927,14 @@ statement issued by the user. We also increment trx->n_mysql_tables_in_use.
2) If prebuilt->sql_stat_start == TRUE we 'pre-compile' the MySQL search
instructions to prebuilt->template of the table handle instance in
::index_read. The template is used to save CPU time in large joins.
::index_read_old. The template is used to save CPU time in large joins.
3) In row_search_for_mysql, if prebuilt->sql_stat_start is true, we
allocate a new consistent read view for the trx if it does not yet have one,
or in the case of a locking read, set an InnoDB 'intention' table level
lock on the table.
4) We do the SELECT. MySQL may repeatedly call ::index_read for the
4) We do the SELECT. MySQL may repeatedly call ::index_read_old for the
same table handle instance, if it is a join.
5) When the SELECT ends, MySQL removes its intention table level locks
@ -3948,7 +3948,7 @@ table handler in that case has to execute the COMMIT in ::external_lock.
B) If the user has explicitly set MySQL table level locks, then MySQL
does NOT call ::external_lock at the start of the statement. To determine
when we are at the start of a new SQL statement we at the start of
::index_read also compare the query id to the latest query id where the
::index_read_old also compare the query id to the latest query id where the
table handle instance was used. If it has changed, we know we are at the
start of a new SQL statement. Since the query id can theoretically
overwrap, we use this test only as a secondary way of determining the
@ -3985,7 +3985,7 @@ ha_innobase::index_read(
int error;
ulint ret;
DBUG_ENTER("index_read");
DBUG_ENTER("index_read_old");
ut_a(prebuilt->trx ==
(trx_t*) current_thd->ha_data[ht->slot]);
@ -4067,7 +4067,7 @@ ha_innobase::index_read(
}
/***********************************************************************
The following functions works like index_read, but it find the last
The following functions works like index_read_old, but it find the last
row with the current key value or prefix. */
int
@ -4173,7 +4173,7 @@ ha_innobase::index_read_idx(
/***************************************************************************
Reads the next or previous row from a cursor, which must have previously been
positioned using index_read. */
positioned using index_read_old. */
int
ha_innobase::general_fetch(
@ -4222,7 +4222,7 @@ ha_innobase::general_fetch(
/***************************************************************************
Reads the next row from a cursor, which must have previously been
positioned using index_read. */
positioned using index_read_old. */
int
ha_innobase::index_next(
@ -4258,7 +4258,7 @@ ha_innobase::index_next_same(
/***************************************************************************
Reads the previous row from a cursor, which must have previously been
positioned using index_read. */
positioned using index_read_old. */
int
ha_innobase::index_prev(

View File

@ -1555,34 +1555,37 @@ int ha_myisam::delete_row(const byte * buf)
return mi_delete(file,buf);
}
int ha_myisam::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
int ha_myisam::index_read(byte *buf, const byte *key, ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
DBUG_ASSERT(inited==INDEX);
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error=mi_rkey(file,buf,active_index, key, key_len, find_flag);
int error=mi_rkey(file, buf, active_index, key, keypart_map, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
int ha_myisam::index_read_idx(byte *buf, uint index, const byte *key,
ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error=mi_rkey(file,buf,index, key, key_len, find_flag);
int error=mi_rkey(file, buf, index, key, keypart_map, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
int ha_myisam::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_myisam::index_read_last(byte *buf, const byte *key,
ulonglong keypart_map)
{
DBUG_ENTER("ha_myisam::index_read_last");
DBUG_ASSERT(inited==INDEX);
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error=mi_rkey(file,buf,active_index, key, key_len, HA_READ_PREFIX_LAST);
int error=mi_rkey(file, buf, active_index, key, keypart_map,
HA_READ_PREFIX_LAST);
table->status=error ? STATUS_NOT_FOUND: 0;
DBUG_RETURN(error);
}
@ -1891,8 +1894,9 @@ void ha_myisam::get_auto_increment(ulonglong offset, ulonglong increment,
key_copy(key, table->record[0],
table->key_info + table->s->next_number_index,
table->s->next_number_key_offset);
error= mi_rkey(file,table->record[1],(int) table->s->next_number_index,
key,table->s->next_number_key_offset,HA_READ_PREFIX_LAST);
error= mi_rkey(file, table->record[1], (int) table->s->next_number_index,
key, make_prev_keypart_map(table->s->next_number_keypart),
HA_READ_PREFIX_LAST);
if (error)
nr= 1;
else

View File

@ -69,11 +69,11 @@ class ha_myisam: public handler
int write_row(byte * buf);
int update_row(const byte * old_data, byte * new_data);
int delete_row(const byte * buf);
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_last(byte * buf, const byte * key, uint key_len);
int index_read(byte *buf, const byte *key, ulonglong keypart_map,
enum ha_rkey_function find_flag);
int index_read_idx(byte *buf, uint index, const byte *key,
ulonglong keypart_map, enum ha_rkey_function find_flag);
int index_read_last(byte *buf, const byte *key, ulonglong keypart_map);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);

View File

@ -532,7 +532,7 @@ int chk_key(MI_CHECK *param, register MI_INFO *info)
mi_extra(info,HA_EXTRA_KEYREAD,0);
bzero(info->lastkey,keyinfo->seg->length);
if (!mi_rkey(info, info->rec_buff, key, (const byte*) info->lastkey,
keyinfo->seg->length, HA_READ_KEY_EXACT))
ULL(1), HA_READ_KEY_EXACT))
{
/* Don't count this as a real warning, as myisamchk can't correct it */
uint save=param->warning_printed;

View File

@ -206,7 +206,7 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
uint keynr key number
key Store packed key here
old Not packed key
k_length Length of 'old' to use
keypart_map bitmap of used keyparts
last_used_keyseg out parameter. May be NULL
RETURN
@ -216,34 +216,36 @@ uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
*/
uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
uint k_length, HA_KEYSEG **last_used_keyseg)
ulonglong 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");
for (keyseg=info->s->keyinfo[keynr].seg ;
keyseg->type && (int) k_length > 0;
old+=keyseg->length, keyseg++)
/* "one part" rtree key is 2*SPDIMS part key in MyISAM */
if (info->s->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE)
keypart_map= (ULL(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=min((uint) keyseg->length,(uint) k_length);
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)
{
k_length--;
if (!(*key++= (char) 1-*old++)) /* Copy null marker */
{
k_length-=length;
if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
{
k_length-=2; /* Skip length */
old+= 2;
}
continue; /* Found NULL */
}
}
@ -262,7 +264,6 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
while (pos < end && pos[0] == ' ')
pos++;
}
k_length-=length;
length=(uint) (end-pos);
FIX_LENGTH(cs, pos, length, char_length);
store_key_length_inc(key,char_length);
@ -274,7 +275,6 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
{
/* Length of key-part used with mi_rkey() always 2 */
uint tmp_length=uint2korr(pos);
k_length-= 2+length;
pos+=2;
set_if_smaller(length,tmp_length); /* Safety */
FIX_LENGTH(cs, pos, length, char_length);
@ -287,11 +287,8 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
else if (keyseg->flag & HA_SWAP_KEY)
{ /* Numerical column */
pos+=length;
k_length-=length;
while (length--)
{
*key++ = *--pos;
}
continue;
}
FIX_LENGTH(cs, pos, length, char_length);
@ -299,30 +296,10 @@ uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
if (length > char_length)
cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
key+= length;
k_length-=length;
}
if (last_used_keyseg)
*last_used_keyseg= keyseg;
#ifdef NOT_USED
if (keyseg->type)
{
/* Part-key ; fill with ASCII 0 for easier searching */
length= (uint) -k_length; /* unused part of last key */
do
{
if (keyseg->flag & HA_NULL_PART)
length++;
if (keyseg->flag & HA_SPACE_PACK)
length+=2;
else
length+= keyseg->length;
keyseg++;
} while (keyseg->type);
bzero((byte*) key,length);
key+=length;
}
#endif
DBUG_RETURN((uint) (key-start_key));
} /* _mi_pack_key */

View File

@ -21,13 +21,10 @@
#include "myisamdef.h"
#include "rt_index.h"
static ha_rows _mi_record_pos(MI_INFO *info,const byte *key,uint key_len,
enum ha_rkey_function search_flag);
static double _mi_search_pos(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
uint key_len,uint nextflag,my_off_t pos);
static uint _mi_keynr(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
uchar *keypos,uint *ret_max_key);
static ha_rows _mi_record_pos(MI_INFO *, const byte *, ulonglong,
enum ha_rkey_function);
static double _mi_search_pos(MI_INFO *,MI_KEYDEF *,uchar *, uint,uint,my_off_t);
static uint _mi_keynr(MI_INFO *info,MI_KEYDEF *,uchar *, uchar *,uint *);
/*
Estimate how many records there is in a given range
@ -47,9 +44,8 @@ static uint _mi_keynr(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page,
number Estimated number of rows
*/
ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key,
key_range *max_key)
ha_rows mi_records_in_range(MI_INFO *info, int inx,
key_range *min_key, key_range *max_key)
{
ha_rows start_pos,end_pos,res;
DBUG_ENTER("mi_records_in_range");
@ -87,7 +83,7 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key,
}
key_buff= info->lastkey+info->s->base.max_key_length;
start_key_len= _mi_pack_key(info,inx, key_buff,
(uchar*) min_key->key, min_key->length,
(uchar*) min_key->key, min_key->keypart_map,
(HA_KEYSEG**) 0);
res= rtree_estimate(info, inx, key_buff, start_key_len,
myisam_read_vec[min_key->flag]);
@ -97,14 +93,12 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key,
#endif
case HA_KEY_ALG_BTREE:
default:
start_pos= (min_key ?
_mi_record_pos(info, min_key->key, min_key->length,
min_key->flag) :
(ha_rows) 0);
end_pos= (max_key ?
_mi_record_pos(info, max_key->key, max_key->length,
max_key->flag) :
info->state->records+ (ha_rows) 1);
start_pos= (min_key ? _mi_record_pos(info, min_key->key,
min_key->keypart_map, min_key->flag)
: (ha_rows) 0);
end_pos= (max_key ? _mi_record_pos(info, max_key->key,
max_key->keypart_map, max_key->flag)
: info->state->records + (ha_rows) 1);
res= (end_pos < start_pos ? (ha_rows) 0 :
(end_pos == start_pos ? (ha_rows) 1 : end_pos-start_pos));
if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR)
@ -122,21 +116,21 @@ ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key,
/* Find relative position (in records) for key in index-tree */
static ha_rows _mi_record_pos(MI_INFO *info, const byte *key, uint key_len,
static ha_rows _mi_record_pos(MI_INFO *info, const byte *key,
ulonglong keypart_map,
enum ha_rkey_function search_flag)
{
uint inx=(uint) info->lastinx, nextflag;
uint inx=(uint) info->lastinx, nextflag, key_len;
MI_KEYDEF *keyinfo=info->s->keyinfo+inx;
uchar *key_buff;
double pos;
DBUG_ENTER("_mi_record_pos");
DBUG_PRINT("enter",("search_flag: %d",search_flag));
DBUG_ASSERT(keypart_map);
if (key_len == 0)
key_len=USE_WHOLE_KEY;
key_buff=info->lastkey+info->s->base.max_key_length;
key_len=_mi_pack_key(info,inx,key_buff,(uchar*) key,key_len,
key_len=_mi_pack_key(info,inx,key_buff,(uchar*) key, keypart_map,
(HA_KEYSEG**) 0);
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,
(uchar*) key_buff,key_len););

View File

@ -21,8 +21,8 @@
/* Read a record using key */
/* Ordinary search_flag is 0 ; Give error if no record with key */
int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
enum ha_rkey_function search_flag)
int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key,
ulonglong keypart_map, enum ha_rkey_function search_flag)
{
uchar *key_buff;
MYISAM_SHARE *share=info->s;
@ -47,18 +47,17 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
key is already packed!; This happens when we are using a MERGE TABLE
*/
key_buff=info->lastkey+info->s->base.max_key_length;
pack_key_length= key_len;
bmove(key_buff,key,key_len);
pack_key_length= keypart_map;
bmove(key_buff, key, pack_key_length);
last_used_keyseg= 0;
}
else
{
if (key_len == 0)
key_len=USE_WHOLE_KEY;
DBUG_ASSERT(keypart_map);
/* Save the packed key for later use in the second buffer of lastkey. */
key_buff=info->lastkey+info->s->base.max_key_length;
pack_key_length=_mi_pack_key(info,(uint) inx, key_buff, (uchar*) key,
key_len, &last_used_keyseg);
keypart_map, &last_used_keyseg);
/* Save packed_key_length for use by the MERGE engine. */
info->pack_key_length= pack_key_length;
DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE, keyinfo->seg,

View File

@ -604,8 +604,9 @@ extern int _mi_dispose(MI_INFO *info,MI_KEYDEF *keyinfo,my_off_t pos,
extern my_off_t _mi_new(MI_INFO *info,MI_KEYDEF *keyinfo,int level);
extern uint _mi_make_key(MI_INFO *info,uint keynr,uchar *key,
const byte *record,my_off_t filepos);
extern uint _mi_pack_key(MI_INFO *info,uint keynr,uchar *key,uchar *old,
uint key_length, HA_KEYSEG **last_used_keyseg);
extern uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key,
uchar *old, ulonglong keypart_map,
HA_KEYSEG **last_used_keyseg);
extern int _mi_read_key_record(MI_INFO *info,my_off_t filepos,byte *buf);
extern int _mi_read_cache(IO_CACHE *info,byte *buff,my_off_t pos,
uint length,int re_read_if_possibly);

View File

@ -323,7 +323,7 @@ static int run_test(const char *filename)
range.key= record+1;
range.length= 1000; /* Big enough */
range.flag= HA_READ_MBR_INTERSECT;
hrows= mi_records_in_range(file,0, &range, (key_range*) 0);
hrows= mi_records_in_range(file, 0, &range, (key_range*) 0);
printf(" %ld rows\n", (long) hrows);
if (mi_close(file)) goto err;

View File

@ -255,7 +255,7 @@ int run_test(const char *filename)
max_range.key= record+1;
max_range.length= 1000; /* Big enough */
max_range.flag= HA_READ_KEY_EXACT;
hrows= mi_records_in_range(file,0, &min_range, &max_range);
hrows= mi_records_in_range(file, 0, &min_range, &max_range);
printf(" %ld rows\n", (long) hrows);
if (mi_close(file)) goto err;

View File

@ -179,30 +179,33 @@ int ha_myisammrg::delete_row(const byte * buf)
}
int ha_myisammrg::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error=myrg_rkey(file,buf,active_index, key, key_len, find_flag);
int error=myrg_rkey(file,buf,active_index, key, keypart_map, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
ulonglong keypart_map,
enum ha_rkey_function find_flag)
{
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error=myrg_rkey(file,buf,index, key, key_len, find_flag);
int error=myrg_rkey(file,buf,index, key, keypart_map, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
int ha_myisammrg::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_myisammrg::index_read_last(byte * buf, const byte * key,
ulonglong keypart_map)
{
statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
int error=myrg_rkey(file,buf,active_index, key, key_len,
int error=myrg_rkey(file,buf,active_index, key, keypart_map,
HA_READ_PREFIX_LAST);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;

View File

@ -56,11 +56,11 @@ class ha_myisammrg: public handler
int write_row(byte * buf);
int update_row(const byte * old_data, byte * new_data);
int delete_row(const byte * buf);
int index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint idx, const byte * key,
uint key_len, enum ha_rkey_function find_flag);
int index_read_last(byte * buf, const byte * key, uint key_len);
int index_read(byte * buf, const byte * key, ulonglong keypart_map,
enum ha_rkey_function find_flag);
int index_read_idx(byte * buf, uint index, const byte * key,
ulonglong keypart_map, enum ha_rkey_function find_flag);
int index_read_last(byte * buf, const byte * key, ulonglong keypart_map);
int index_next(byte * buf);
int index_prev(byte * buf);
int index_first(byte * buf);

View File

@ -36,7 +36,7 @@
*/
int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key,
uint key_len, enum ha_rkey_function search_flag)
ulonglong keypart_map, enum ha_rkey_function search_flag)
{
byte *key_buff;
uint pack_key_length;
@ -56,7 +56,7 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key,
if (table == info->open_tables)
{
err=mi_rkey(mi,0,inx,key,key_len,search_flag);
err=mi_rkey(mi, 0, inx, key, keypart_map, 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;
@ -64,7 +64,7 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key,
else
{
mi->once_flags|= USE_PACKED_KEYS;
err=mi_rkey(mi,0,inx,key_buff,pack_key_length,search_flag);
err=mi_rkey(mi, 0, inx, key_buff, pack_key_length, search_flag);
}
info->last_used_table=table+1;

View File

@ -44,6 +44,9 @@ pkgdata_DATA = my-small.cnf \
pkgdata_SCRIPTS = mysql.server
aclocaldir = $(datadir)/aclocal
aclocal_DATA = mysql.m4
noinst_DATA = mysql-@VERSION@.spec \
MySQL-shared-compat.spec

108
support-files/mysql.m4 Normal file
View File

@ -0,0 +1,108 @@
# Copyright (C) 2007 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
AC_DEFUN([_MYSQL_CONFIG],[
AC_ARG_WITH([mysql-config],
AS_HELP_STRING([--with-mysql-config=PATH], [A path to mysql_config script]),
[mysql_config="$withval"], [mysql_config=mysql_config])
])
dnl
dnl Usage:
dnl
dnl MYSQL_CLIENT([version], [client|thread-safe|embedded])
dnl
dnl Two optional arguments:
dnl first: The minimal version of the MySQL to use
dnl if not specified, any version will be accepted.
dnl The version should be specified as three numbers,
dnl without suffixes. E.g. 4.10.15 or 5.0.3
dnl second: force the specified library flavor to be selected,
dnl if not specified, a user will be able to choose
dnl between client (non-thread-safe) and embedded
dnl
dnl On successful execution sets MYSQL_CLIENT_CFLAGS and
dnl MYSQL_CLIENT_LIBS shell variables and makes substitutions
dnl out of them (calls AC_SUBST)
dnl
AC_DEFUN([MYSQL_CLIENT],[
AC_REQUIRE([_MYSQL_CONFIG])
AC_MSG_CHECKING([for MySQL])
ifelse([$2], [client],
[mysql_libs=--libs mysql_cflags=--cflags],
[$2], [thread-safe],
[mysql_libs=--libs_r mysql_cflags=--cflags],
[$2], [embedded],
[mysql_libs=--libmysqld-libs mysql_cflags=--cflags],
[$2], [], [
AC_ARG_WITH([mysql-library],
AS_HELP_STRING([--with-mysql-library], ['client' or 'embedded']),
[mysql_lib="$withval"], [mysql_lib=client])
[
case "$mysql_lib" in
client) mysql_libs=--libs mysql_cflags=--cflags ;;
embedded) mysql_libs=--libmysqld-libs mysql_cflags=--cflags ;;
*) ]AC_MSG_ERROR([Bad value for --with-mysql-library])[
esac
]
],
[AC_FATAL([Bad second (library flavor) argument to MYSQL_CLIENT])])
[
mysql_version=`$mysql_config --version`
if test -z "$mysql_version" ; then
]AC_MSG_ERROR([Cannot execute $mysql_config])[
fi
]
ifelse([$1], [], [], [
ifelse(regexp([$1], [^[0-9][0-9]?\.[0-9][0-9]?\.[0-9][0-9]?$]), -1,
[AC_FATAL([Bad first (version) argument to MYSQL_CLIENT])], [
dnl
dnl Transformation below works as follows:
dnl assume, we have a number 1.2.3-beta
dnl *a* line removes the suffix and adds first and last dot to the version:
dnl .1.2.3.
dnl *b* line adds a 0 to a "single digit surrounded by dots"
dnl .01.2.03.
dnl note that the pattern that matched .1. has eaten the dot for .2.
dnl and 2 still has no 0
dnl *c* we repeat the same replacement as in *b*, matching .2. this time
dnl .01.02.03.
dnl the last replacement removes all dots
dnl 010203
dnl giving us a number we can compare with
dnl
mysql_ver=`echo ${mysql_version}|dnl
sed 's/[[-a-z]].*//; s/.*/.&./;dnl *a*
s/\.\([[0-9]]\)\./.0\1./g;dnl *b*
s/\.\([[0-9]]\)\./.0\1./g;dnl *c*
s/\.//g'`
if test "$mysql_ver" -lt]dnl
dnl the same as sed transformation above, without suffix-stripping, in m4
patsubst(patsubst(patsubst(.[$1]., [\.\([0-9]\)\.], [.0\1.]), [\.\([0-9]\)\.], [.0\1.]), [\.], [])[ ; then
AC_MSG_ERROR([MySQL version $mysql_version is too low, minimum of $1 is required])
fi
])])
MYSQL_CLIENT_CFLAGS=`$mysql_config $mysql_cflags`
MYSQL_CLIENT_LIBS=`$mysql_config $mysql_libs`
AC_SUBST(MYSQL_CLIENT_CFLAGS)
AC_SUBST(MYSQL_CLIENT_LIBS)
# should we try to build a test program ?
AC_MSG_RESULT([$mysql_version])
])

View File

@ -182,9 +182,6 @@ int main()
test_atomic("my_atomic_add32", test_atomic_add_handler, THREADS, CYCLES);
test_atomic("my_atomic_swap32", test_atomic_swap_handler, THREADS, CYCLES);
test_atomic("my_atomic_cas32", test_atomic_cas_handler, THREADS, CYCLES);
/* workaround until we know why this includes dbug but not safemalloc */
if(err) { my_thread_global_init(); my_free(my_malloc(0, MYF(0)), MYF(0)); }
/*
workaround until we know why it crashes randomly on some machine
(BUG#22320).