BitKeeper/etc/ignore:
  auto-union
myisam/myisamdef.h:
  Auto merged
sql/ha_berkeley.cc:
  Auto merged
sql/ha_innodb.h:
  Auto merged
sql/ha_myisam.cc:
  Auto merged
sql/handler.h:
  Auto merged
sql/item.cc:
  Auto merged
sql/item_func.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/mysqld.cc:
  Auto merged
sql/opt_range.cc:
  Auto merged
sql/slave.cc:
  Auto merged
sql/sql_acl.cc:
  Auto merged
sql/sql_base.cc:
  Auto merged
sql/sql_show.cc:
  Auto merged
sql/sql_test.cc:
  Auto merged
sql/table.cc:
  Auto merged
This commit is contained in:
unknown 2003-10-15 12:25:44 +02:00
commit b192ab5edc
45 changed files with 912 additions and 280 deletions

View File

@ -590,6 +590,7 @@ sql/sql_yacc.cc
sql/sql_yacc.h
sql/sql_yacc.output
sql/sql_yacc.yy.orig
sql/udf_example.so
sql_error.cc
sql_prepare.cc
stamp-h

View File

@ -44,8 +44,7 @@ ulong heap_position_old(HP_INFO *info)
/* Note that heap_info does NOT return information about the
current position anymore; Use heap_position instead */
int heap_info(reg1 HP_INFO *info,reg2 HEAPINFO *x,
int flag __attribute__((unused)))
int heap_info(reg1 HP_INFO *info,reg2 HEAPINFO *x, int flag )
{
DBUG_ENTER("heap_info");
x->records = info->s->records;

View File

@ -39,15 +39,23 @@ typedef struct st_bitmap
#ifdef __cplusplus
extern "C" {
#endif
extern my_bool bitmap_init(MY_BITMAP *bitmap, uint bitmap_size,
my_bool thread_safe);
extern void bitmap_free(MY_BITMAP *bitmap);
extern void bitmap_set_bit(MY_BITMAP *bitmap, uint bitmap_bit);
extern uint bitmap_set_next(MY_BITMAP *bitmap);
extern void bitmap_set_all(MY_BITMAP* bitmap);
extern my_bool bitmap_is_set(MY_BITMAP* bitmap, uint bitmap_bit);
extern void bitmap_clear_all(MY_BITMAP* bitmap);
extern void bitmap_clear_bit(MY_BITMAP *bitmap, uint bitmap_bit);
extern my_bool bitmap_cmp(MY_BITMAP *map1, MY_BITMAP *map2);
extern my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, my_bool thread_safe);
extern my_bool bitmap_is_clear_all(MY_BITMAP *map);
extern my_bool bitmap_is_prefix(MY_BITMAP *map, uint prefix_size);
extern my_bool bitmap_is_set(MY_BITMAP *map, uint bitmap_bit);
extern my_bool bitmap_is_set_all(MY_BITMAP *map);
extern my_bool bitmap_is_subset(MY_BITMAP *map1, MY_BITMAP *map2);
extern uint bitmap_set_next(MY_BITMAP *map);
extern void bitmap_clear_all(MY_BITMAP *map);
extern void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit);
extern void bitmap_free(MY_BITMAP *map);
extern void bitmap_intersect(MY_BITMAP *map, MY_BITMAP *map2);
extern void bitmap_set_all(MY_BITMAP *map);
extern void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit);
extern void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size);
extern void bitmap_subtract(MY_BITMAP *map, MY_BITMAP *map2);
extern void bitmap_union(MY_BITMAP *map, MY_BITMAP *map2);
#ifdef __cplusplus
}
#endif

View File

@ -168,7 +168,11 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
ftbw->word[0]=w.len;
if (param.yesno > 0) up->ythresh++;
queue_insert(& ftb->queue, (byte *)ftbw);
#ifdef TO_BE_REMOVED
/* after removing the following line,
ftb->with_scan handling can be simplified (no longer a bitmap) */
ftb->with_scan|=(param.trunc & FTB_FLAG_TRUNC);
#endif
break;
case 2: /* left bracket */
ftbe=(FTB_EXPR *)alloc_root(&ftb->mem_root, sizeof(FTB_EXPR));
@ -387,25 +391,34 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query,
}
/* returns 1 if str0 contain str1 */
/* returns 1 if str0 ~= /\<str1\>/ */
static int _ftb_strstr(const byte *s0, const byte *e0,
const byte *s1, const byte *e1,
CHARSET_INFO *cs)
{
const byte *p;
const byte *p0, *p1;
my_bool s_after, e_before;
while (s0 < e0)
s_after=true_word_char(cs, s1[0]);
e_before=true_word_char(cs, e1[-1]);
p0=s0;
while (p0 < e0)
{
while (s0 < e0 && cs->to_upper[(uint) (uchar) *s0++] !=
while (p0 < e0 && cs->to_upper[(uint) (uchar) *p0++] !=
cs->to_upper[(uint) (uchar) *s1])
/* no-op */;
if (s0 >= e0)
if (p0 >= e0)
return 0;
p=s1+1;
while (s0 < e0 && p < e1 && cs->to_upper[(uint) (uchar) *s0] ==
cs->to_upper[(uint) (uchar) *p])
s0++, p++;
if (p >= e1)
if (s_after && p0-1 > s0 && true_word_char(cs, p0[-2]))
continue;
p1=s1+1;
while (p0 < e0 && p1 < e1 && cs->to_upper[(uint) (uchar) *p0] ==
cs->to_upper[(uint) (uchar) *p1])
p0++, p1++;
if (p1 == e1 && (!e_before || p0 == e0 || !true_word_char(cs, p0[0])))
return 1;
}
return 0;

View File

@ -73,15 +73,6 @@ FT_WORD * ft_linearize(TREE *wtree)
DBUG_RETURN(wlist);
}
#define true_word_char(s,X) (my_isalnum(s,X) || (X)=='_')
#ifdef HYPHEN_IS_DELIM
#define misc_word_char(X) ((X)=='\'')
#else
#define misc_word_char(X) ((X)=='\'' || (X)=='-')
#endif
#define word_char(s,X) (true_word_char(s,X) || misc_word_char(X))
/* returns:
* 0 - eof
* 1 - word found

View File

@ -21,13 +21,6 @@
#include "ftdefs.h"
#include <math.h>
/**************************************************************
This is to make ft-code to ignore keyseg.length at all *
and to index the whole VARCHAR/BLOB instead... */
#undef set_if_smaller
#define set_if_smaller(A,B) /* no op */
/**************************************************************/
void _mi_ft_segiterator_init(MI_INFO *info, uint keynr, const byte *record,
FT_SEG_ITERATOR *ftsi)
{
@ -88,7 +81,6 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
{
ftsi->len=uint2korr(ftsi->pos);
ftsi->pos+=2; /* Skip VARCHAR length */
set_if_smaller(ftsi->len,ftsi->seg->length);
DBUG_RETURN(1);
}
if (ftsi->seg->flag & HA_BLOB_PART)
@ -96,7 +88,6 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi)
ftsi->len=_mi_calc_blob_length(ftsi->seg->bit_start,ftsi->pos);
memcpy_fixed((char*) &ftsi->pos, ftsi->pos+ftsi->seg->bit_start,
sizeof(char*));
set_if_smaller(ftsi->len,ftsi->seg->length);
DBUG_RETURN(1);
}
ftsi->len=ftsi->seg->length;
@ -305,3 +296,53 @@ uint _ft_make_key(MI_INFO *info, uint keynr, byte *keybuf, FT_WORD *wptr,
memcpy(buf+HA_FT_WLEN+2,wptr->pos,wptr->len);
DBUG_RETURN(_mi_make_key(info,keynr,(uchar*) keybuf,buf,filepos));
}
/*
convert key value to ft2
*/
uint _mi_ft_convert_to_ft2(MI_INFO *info, uint keynr, uchar *key)
{
my_off_t root;
DYNAMIC_ARRAY *da=info->ft1_to_ft2;
MI_KEYDEF *keyinfo=&info->s->ft2_keyinfo;
uchar *key_ptr=dynamic_array_ptr(da, 0), *end;
uint length, key_length;
DBUG_ENTER("_mi_ft_convert_to_ft2");
/* we'll generate one pageful at once, and insert the rest one-by-one */
/* calculating the length of this page ...*/
length=(keyinfo->block_length-2) / keyinfo->keylength;
set_if_smaller(length, da->elements);
length=length * keyinfo->keylength;
get_key_full_length_rdonly(key_length, key);
while (_mi_ck_delete(info, keynr, key, key_length) == 0)
/* nothing to do here.
_mi_ck_delete() will populate info->ft1_to_ft2 with deleted keys
*/;
/* creating pageful of keys */
mi_putint(info->buff,length+2,0);
memcpy(info->buff+2, key_ptr, length);
info->buff_used=info->page_changed=1; /* info->buff is used */
if ((root= _mi_new(info,keyinfo)) == HA_OFFSET_ERROR ||
_mi_write_keypage(info,keyinfo,root,info->buff))
DBUG_RETURN(-1);
/* inserting the rest of key values */
end=dynamic_array_ptr(da, da->elements);
for (key_ptr+=length; key_ptr < end; key_ptr+=keyinfo->keylength)
if(_mi_ck_real_write_btree(info, keyinfo, key_ptr, 0, &root, SEARCH_SAME))
DBUG_RETURN(-1);
/* now, writing the word key entry */
ft_intXstore(key+key_length, -da->elements);
_mi_dpointer(info, key+key_length+HA_FT_WLEN, root);
DBUG_RETURN(_mi_ck_real_write_btree(info,
info->s->keyinfo+keynr,
key, 0,
&info->s->state.key_root[keynr],
SEARCH_SAME));
}

View File

@ -22,8 +22,9 @@
#include <m_ctype.h>
#include <my_tree.h>
#define HYPHEN_IS_DELIM
#define HYPHEN_IS_CONCAT /* not used for now */
#define true_word_char(s,X) (my_isalnum(s,X) || (X)=='_')
#define misc_word_char(X) ((X)=='\'')
#define word_char(s,X) (true_word_char(s,X) || misc_word_char(X))
#define COMPILE_STOPWORDS_IN

View File

@ -34,3 +34,5 @@ int _mi_ft_cmp(MI_INFO *, uint, const byte *, const byte *);
int _mi_ft_add(MI_INFO *, uint, byte *, const byte *, my_off_t);
int _mi_ft_del(MI_INFO *, uint, byte *, const byte *, my_off_t);
uint _mi_ft_convert_to_ft2(MI_INFO *, uint, uchar *);

View File

@ -18,6 +18,7 @@
#include "fulltext.h"
#include "rt_index.h"
#include <assert.h>
#ifdef __WIN__
#include <errno.h>
@ -231,13 +232,22 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
get_key_full_length_rdonly(off, lastkey);
subkeys=ft_sintXkorr(lastkey+off);
DBUG_ASSERT(info->ft1_to_ft2==0 || subkeys >=0);
comp_flag=SEARCH_SAME;
if (subkeys >= 0)
{
/* normal word, one-level tree structure */
DBUG_PRINT("info",("FT1"));
if (info->ft1_to_ft2)
{
/* we're in ft1->ft2 conversion mode. Saving key data */
insert_dynamic(info->ft1_to_ft2, lastkey+off);
}
else
{
/* we need exact match only if not in ft1->ft2 conversion mode */
flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,USE_WHOLE_KEY,
comp_flag, &keypos, lastkey, &last_key);
}
/* fall through to normal delete */
}
else
@ -252,13 +262,11 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (subkeys == -1)
{
/* the last entry in sub-tree */
DBUG_PRINT("info",("FT2: the last entry"));
_mi_dispose(info, keyinfo, root);
/* fall through to normal delete */
}
else
{
DBUG_PRINT("info",("FT2: going down"));
keyinfo=&info->s->ft2_keyinfo;
kpos-=keyinfo->keylength+nod_flag; /* we'll modify key entry 'in vivo' */
key+=off;

View File

@ -536,6 +536,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
info.lock_type=F_UNLCK;
info.quick_mode=0;
info.bulk_insert=0;
info.ft1_to_ft2=0;
info.errkey= -1;
info.page_changed=1;
pthread_mutex_lock(&share->intern_lock);

View File

@ -18,6 +18,7 @@
#include "fulltext.h"
#include "rt_index.h"
#include <assert.h>
#ifdef __WIN__
#include <errno.h>
@ -264,13 +265,32 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
else
comp_flag=SEARCH_SAME; /* Keys in rec-pos order */
error=_mi_ck_real_write_btree(info, keyinfo, key, key_length,
root, comp_flag);
if (info->ft1_to_ft2)
{
if (!error)
error= _mi_ft_convert_to_ft2(info, keynr, key);
delete_dynamic(info->ft1_to_ft2);
my_free(info->ft1_to_ft2, MYF(0));
info->ft1_to_ft2=0;
}
DBUG_RETURN(error);
} /* _mi_ck_write_btree */
int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
uchar *key, uint key_length, my_off_t *root, uint comp_flag)
{
int error;
DBUG_ENTER("_mi_ck_real_write_btree");
/* key_length parameter is used only if comp_flag is SEARCH_FIND */
if (*root == HA_OFFSET_ERROR ||
(error=w_search(info, keyinfo, comp_flag, key, key_length,
*root, (uchar *) 0, (uchar*) 0,
(my_off_t) 0, 1)) > 0)
error=_mi_enlarge_root(info,keyinfo,key,root);
DBUG_RETURN(error);
} /* _mi_ck_write_btree */
} /* _mi_ck_real_write_btree */
/* Make a new root with key as only pointer */
@ -359,13 +379,11 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
keyinfo=&info->s->ft2_keyinfo;
key+=off;
keypos-=keyinfo->keylength; /* we'll modify key entry 'in vivo' */
if ((error=w_search(info, keyinfo, comp_flag, key, HA_FT_WLEN, root,
(uchar *) 0, (uchar*) 0, (my_off_t) 0, 1)) > 0)
{
error=_mi_enlarge_root(info, keyinfo, key, &root);
error=_mi_ck_real_write_btree(info, keyinfo, key, 0,
&root, comp_flag);
_mi_dpointer(info, keypos+HA_FT_WLEN, root);
}
subkeys--; /* should there be underflow protection ? */
DBUG_ASSERT(subkeys < 0);
ft_intXstore(keypos, subkeys);
if (!error)
error=_mi_write_keypage(info,keyinfo,page,temp_buff);
@ -410,7 +428,6 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
uchar *key, uchar *anc_buff, uchar *key_pos, uchar *key_buff,
uchar *father_buff, uchar *father_key_pos, my_off_t father_page,
my_bool insert_last)
{
uint a_length,nod_flag;
int t_length;
@ -464,8 +481,56 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
a_length+=t_length;
mi_putint(anc_buff,a_length,nod_flag);
if (a_length <= keyinfo->block_length)
DBUG_RETURN(0); /* There is room on page */
{
if (keyinfo->block_length - a_length < 32 &&
keyinfo->flag & HA_FULLTEXT && key_pos == endpos &&
info->s->base.key_reflength <= info->s->base.rec_reflength &&
info->s->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))
{
/*
Normal word. One-level tree. Page is almost full.
Let's consider converting.
We'll compare 'key' and the first key at anc_buff
*/
uchar *a=key, *b=anc_buff+2+nod_flag;
uint alen, blen, ft2len=info->s->ft2_keyinfo.keylength;
/* the very first key on the page is always unpacked */
DBUG_ASSERT((*b & 128) == 0);
#if HA_FT_MAXLEN >= 127
blen= mi_uint2korr(b); b+=2;
#else
blen= *b++;
#endif
get_key_length(alen,a);
DBUG_ASSERT(info->ft1_to_ft2==0);
if (alen == blen &&
mi_compare_text(keyinfo->seg->charset, a, alen, b, blen, 0)==0)
{
/* yup. converting */
info->ft1_to_ft2=(DYNAMIC_ARRAY *)
my_malloc(sizeof(DYNAMIC_ARRAY), MYF(MY_WME));
my_init_dynamic_array(info->ft1_to_ft2, ft2len, 300, 50);
/*
now, adding all keys from the page to dynarray
if the page is a leaf (if not keys will be deleted later)
*/
if (!nod_flag)
{
/* let's leave the first key on the page, though, because
we cannot easily dispatch an empty page here */
b+=blen+ft2len+2;
for (a=anc_buff+a_length ; b < a ; b+=ft2len+2)
insert_dynamic(info->ft1_to_ft2, b);
/* fixing the page's length - it contains only one key now */
mi_putint(anc_buff,2+blen+ft2len+2,0);
}
/* the rest will be done when we're back from recursion */
}
}
DBUG_RETURN(0); /* There is room on page */
}
/* Page is full */
if (nod_flag)
insert_last=0;

View File

@ -223,6 +223,7 @@ struct st_myisam_info {
MI_BIT_BUFF bit_buff;
/* accumulate indexfile changes between write's */
TREE *bulk_insert;
DYNAMIC_ARRAY *ft1_to_ft2; /* used only in ft1->ft2 conversion */
char *filename; /* parameter to open filename */
uchar *buff, /* Temp area for key */
*lastkey,*lastkey2; /* Last used search key */
@ -464,6 +465,9 @@ extern int _mi_delete_static_record(MI_INFO *info);
extern int _mi_cmp_static_record(MI_INFO *info,const byte *record);
extern int _mi_read_rnd_static_record(MI_INFO*, byte *,my_off_t, my_bool);
extern int _mi_ck_write(MI_INFO *info,uint keynr,uchar *key,uint length);
extern int _mi_ck_real_write_btree(MI_INFO *info, MI_KEYDEF *keyinfo,
uchar *key, uint key_length,
my_off_t *root, uint comp_flag);
extern int _mi_enlarge_root(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, my_off_t *root);
extern int _mi_insert(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
uchar *anc_buff,uchar *key_pos,uchar *key_buff,

View File

@ -119,7 +119,8 @@ a b
MySQL has now support for full-text search
select * from t1 where MATCH a,b AGAINST ('"text i"' IN BOOLEAN MODE);
a b
Full-text indexes are called collections
select * from t1 where MATCH a,b AGAINST ('"xt indexes"' IN BOOLEAN MODE);
a b
select * from t1 where MATCH a AGAINST ("search" IN BOOLEAN MODE);
a b
Full-text search in MySQL implements vector space model

View File

@ -103,4 +103,106 @@ count(*)
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
count(*)
262
DROP TABLE IF EXISTS t1;
drop table t1;
CREATE TABLE t1 (
i int(10) unsigned not null auto_increment primary key,
a varchar(255) not null,
FULLTEXT KEY (a)
) TYPE=MyISAM;
select count(*) from t1 where match a against ('aaaxxx');
count(*)
260
select count(*) from t1 where match a against ('aaayyy');
count(*)
250
select count(*) from t1 where match a against ('aaazzz');
count(*)
255
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
count(*)
260
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
count(*)
250
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
count(*)
255
select count(*) from t1 where match a against ('aaaxxx aaayyy aaazzz');
count(*)
765
select count(*) from t1 where match a against ('aaaxxx aaayyy aaazzz' in boolean mode);
count(*)
765
select count(*) from t1 where match a against ('aaax*' in boolean mode);
count(*)
260
select count(*) from t1 where match a against ('aaay*' in boolean mode);
count(*)
250
select count(*) from t1 where match a against ('aaa*' in boolean mode);
count(*)
765
insert t1 (a) values ('aaaxxx'),('aaayyy');
insert t1 (a) values ('aaazzz'),('aaazzz'),('aaazzz'),('aaazzz'),('aaazzz');
select count(*) from t1 where match a against ('aaaxxx');
count(*)
261
select count(*) from t1 where match a against ('aaayyy');
count(*)
251
select count(*) from t1 where match a against ('aaazzz');
count(*)
260
insert t1 (a) values ('aaaxxx 000000');
select count(*) from t1 where match a against ('000000');
count(*)
1
delete from t1 where match a against ('000000');
select count(*) from t1 where match a against ('000000');
count(*)
0
select count(*) from t1 where match a against ('aaaxxx');
count(*)
261
delete from t1 where match a against ('aaazzz');
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
count(*)
261
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
count(*)
251
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
count(*)
0
select count(*) from t1 where a = 'aaaxxx';
count(*)
261
select count(*) from t1 where a = 'aaayyy';
count(*)
251
select count(*) from t1 where a = 'aaazzz';
count(*)
0
insert t1 (a) values ('aaaxxx 000000');
select count(*) from t1 where match a against ('000000');
count(*)
1
update t1 set a='aaazzz' where match a against ('000000');
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
count(*)
261
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
count(*)
1
update t1 set a='aaazzz' where a = 'aaaxxx';
update t1 set a='aaaxxx' where a = 'aaayyy';
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
count(*)
251
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
count(*)
0
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
count(*)
262
drop table t1;

View File

@ -58,6 +58,7 @@ select * from t1 where MATCH a,b AGAINST ('"text search" "now support"' IN BOOL
select * from t1 where MATCH a,b AGAINST ('"text search" -"now support"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"text search" +"now support"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"text i"' IN BOOLEAN MODE);
select * from t1 where MATCH a,b AGAINST ('"xt indexes"' IN BOOLEAN MODE);
# boolean w/o index:

View File

@ -94,5 +94,83 @@ select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
DROP TABLE IF EXISTS t1;
drop table t1;
CREATE TABLE t1 (
i int(10) unsigned not null auto_increment primary key,
a varchar(255) not null,
FULLTEXT KEY (a)
) TYPE=MyISAM;
# two-level entry, second-level tree with depth 2
--disable_query_log
let $1=260;
while ($1)
{
eval insert t1 (a) values ('aaaxxx');
dec $1;
}
let $1=255;
while ($1)
{
eval insert t1 (a) values ('aaazzz');
dec $1;
}
let $1=250;
while ($1)
{
eval insert t1 (a) values ('aaayyy');
dec $1;
}
--enable_query_log
select count(*) from t1 where match a against ('aaaxxx');
select count(*) from t1 where match a against ('aaayyy');
select count(*) from t1 where match a against ('aaazzz');
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
select count(*) from t1 where match a against ('aaaxxx aaayyy aaazzz');
select count(*) from t1 where match a against ('aaaxxx aaayyy aaazzz' in boolean mode);
select count(*) from t1 where match a against ('aaax*' in boolean mode);
select count(*) from t1 where match a against ('aaay*' in boolean mode);
select count(*) from t1 where match a against ('aaa*' in boolean mode);
# mi_write:
insert t1 (a) values ('aaaxxx'),('aaayyy');
insert t1 (a) values ('aaazzz'),('aaazzz'),('aaazzz'),('aaazzz'),('aaazzz');
select count(*) from t1 where match a against ('aaaxxx');
select count(*) from t1 where match a against ('aaayyy');
select count(*) from t1 where match a against ('aaazzz');
# mi_delete
insert t1 (a) values ('aaaxxx 000000');
select count(*) from t1 where match a against ('000000');
delete from t1 where match a against ('000000');
select count(*) from t1 where match a against ('000000');
select count(*) from t1 where match a against ('aaaxxx');
delete from t1 where match a against ('aaazzz');
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
# double-check without index
select count(*) from t1 where a = 'aaaxxx';
select count(*) from t1 where a = 'aaayyy';
select count(*) from t1 where a = 'aaazzz';
# update
insert t1 (a) values ('aaaxxx 000000');
select count(*) from t1 where match a against ('000000');
update t1 set a='aaazzz' where match a against ('000000');
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
update t1 set a='aaazzz' where a = 'aaaxxx';
update t1 set a='aaaxxx' where a = 'aaayyy';
select count(*) from t1 where match a against ('aaaxxx' in boolean mode);
select count(*) from t1 where match a against ('aaayyy' in boolean mode);
select count(*) from t1 where match a against ('aaazzz' in boolean mode);
drop table t1;

View File

@ -43,9 +43,10 @@ inline void bitmap_unlock(MY_BITMAP* map)
#endif
}
my_bool bitmap_init(MY_BITMAP *map, uint bitmap_size, my_bool thread_safe)
my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, my_bool thread_safe)
{
if (!(map->bitmap=(uchar*) my_malloc((bitmap_size+7)/8,
if (!(map->bitmap=buf) &&
!(map->bitmap=(uchar*) my_malloc((bitmap_size+7)/8,
MYF(MY_WME | MY_ZEROFILL))))
return 1;
DBUG_ASSERT(bitmap_size != ~(uint) 0);
@ -72,6 +73,7 @@ void bitmap_free(MY_BITMAP *map)
void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
{
DBUG_ASSERT(map->bitmap);
if (bitmap_bit < map->bitmap_size)
{
bitmap_lock(map);
@ -80,7 +82,6 @@ void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit)
}
}
uint bitmap_set_next(MY_BITMAP *map)
{
uchar *bitmap=map->bitmap;
@ -88,6 +89,7 @@ uint bitmap_set_next(MY_BITMAP *map)
uint bitmap_size=map->bitmap_size;
uint i;
DBUG_ASSERT(map->bitmap);
bitmap_lock(map);
for (i=0; i < bitmap_size ; i++, bitmap++)
{
@ -110,9 +112,9 @@ uint bitmap_set_next(MY_BITMAP *map)
return bit_found;
}
void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
{
DBUG_ASSERT(map->bitmap);
if (bitmap_bit < map->bitmap_size)
{
bitmap_lock(map);
@ -121,24 +123,184 @@ void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit)
}
}
void bitmap_set_all(MY_BITMAP* map)
void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size)
{
uint l, m;
DBUG_ASSERT(map->bitmap);
bitmap_lock(map);
memset(map->bitmap, 0xff, (map->bitmap_size+7)/8);
set_if_smaller(prefix_size, map->bitmap_size);
if ((l=prefix_size / 8))
memset(map->bitmap, 0xff, l);
if ((m=prefix_size & 7))
map->bitmap[l++]= (1 << m)-1;
if (l < (m=(map->bitmap_size+7)/8))
bzero(map->bitmap+l, m-l);
bitmap_unlock(map);
}
my_bool bitmap_is_set(MY_BITMAP* map, uint bitmap_bit)
{
return (bitmap_bit < map->bitmap_size) ?
(map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7))) :
0;
}
void bitmap_clear_all(MY_BITMAP *map)
{
bitmap_set_prefix(map, 0);
}
void bitmap_set_all(MY_BITMAP *map)
{
bitmap_set_prefix(map, map->bitmap_size);
}
my_bool bitmap_is_prefix(MY_BITMAP *map, uint prefix_size)
{
uint l=prefix_size/8, m=prefix_size & 7, i, res=0;
DBUG_ASSERT(map->bitmap);
if (prefix_size > map->bitmap_size)
return 0;
bitmap_lock(map);
bzero(map->bitmap,(map->bitmap_size+7)/8);
for (i=0; i < l; i++)
if (map->bitmap[i] != 0xff)
goto ret;
if (m && map->bitmap[i++] != (1 << m)-1)
goto ret;
for (m=(map->bitmap_size+7)/8; i < m; i++)
if (map->bitmap[i] != 0)
goto ret;
res=1;
ret:
bitmap_unlock(map);
return res;
}
my_bool bitmap_is_clear_all(MY_BITMAP *map)
{
return bitmap_is_prefix(map, 0);
}
my_bool bitmap_is_set_all(MY_BITMAP *map)
{
return bitmap_is_prefix(map, map->bitmap_size);
}
my_bool bitmap_is_set(MY_BITMAP *map, uint bitmap_bit)
{
DBUG_ASSERT(map->bitmap);
return (bitmap_bit < map->bitmap_size) ?
(map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7))) : 0;
}
my_bool bitmap_is_subset(MY_BITMAP *map1, MY_BITMAP *map2)
{
uint l1, l2, i, res=0;
uchar *m1=map1->bitmap, *m2=map2->bitmap;
DBUG_ASSERT(map1->bitmap);
DBUG_ASSERT(map2->bitmap);
bitmap_lock(map1);
bitmap_lock(map2);
l1=(map1->bitmap_size+7)/8;
l2=(map2->bitmap_size+7)/8;
set_if_smaller(l2, l1);
for (i=0; i < l2; i++)
if ((*m1++) & ~(*m2++))
goto ret;
for (; i < l1; i++)
if (*m1++)
goto ret;
res=1;
ret:
bitmap_unlock(map2);
bitmap_unlock(map1);
return res;
}
my_bool bitmap_cmp(MY_BITMAP *map1, MY_BITMAP *map2)
{
uint res;
DBUG_ASSERT(map1->bitmap);
DBUG_ASSERT(map2->bitmap);
bitmap_lock(map1);
bitmap_lock(map2);
res= map1->bitmap_size == map2->bitmap_size &&
memcmp(map1->bitmap, map2->bitmap, (map1->bitmap_size+7)/8)==0;
bitmap_unlock(map2);
bitmap_unlock(map1);
return res;
}
void bitmap_intersect(MY_BITMAP *map, MY_BITMAP *map2)
{
uint l1, l2, i;
uchar *m=map->bitmap, *m2=map2->bitmap;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(map2->bitmap);
bitmap_lock(map);
bitmap_lock(map2);
l1=(map->bitmap_size+7)/8;
l2=(map2->bitmap_size+7)/8;
set_if_smaller(l2, l1);
for (i=0; i < l2; i++)
*m++ &= *m2++;
if (l1 > l2)
bzero(m, l1-l2);
bitmap_unlock(map2);
bitmap_unlock(map);
}
void bitmap_subtract(MY_BITMAP *map, MY_BITMAP *map2)
{
uint l1, l2, i;
uchar *m=map->bitmap, *m2=map2->bitmap;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(map2->bitmap);
bitmap_lock(map);
bitmap_lock(map2);
l1=(map->bitmap_size+7)/8;
l2=(map2->bitmap_size+7)/8;
set_if_smaller(l2, l1);
for (i=0; i < l2; i++)
*m++ &= ~(*m2++);
bitmap_unlock(map2);
bitmap_unlock(map);
}
void bitmap_union(MY_BITMAP *map, MY_BITMAP *map2)
{
uint l1, l2, i;
uchar *m=map->bitmap, *m2=map2->bitmap;
DBUG_ASSERT(map->bitmap);
DBUG_ASSERT(map2->bitmap);
bitmap_lock(map);
bitmap_lock(map2);
l1=(map->bitmap_size+7)/8;
l2=(map2->bitmap_size+7)/8;
set_if_smaller(l2, l1);
for (i=0; i < l2; i++)
*m++ |= *m2++;
bitmap_unlock(map2);
bitmap_unlock(map);
}

View File

@ -181,8 +181,7 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,
:ptr(ptr_arg),null_ptr(null_ptr_arg),
table(table_arg),table_name(table_arg ? table_arg->table_name : 0),
field_name(field_name_arg),
query_id(0),key_start(0),part_of_key(0),part_of_sortkey(0),
unireg_check(unireg_check_arg),
query_id(0),unireg_check(unireg_check_arg),
field_length(length_arg),null_bit(null_bit_arg),abs_offset(0)
{
flags=null_ptr ? 0: NOT_NULL_FLAG;

View File

@ -151,7 +151,9 @@ public:
if (tmp->table->maybe_null)
tmp->flags&= ~NOT_NULL_FLAG;
tmp->table= new_table;
tmp->key_start= tmp->part_of_key= tmp->part_of_sortkey= 0;
tmp->key_start.init().clear_all();
tmp->part_of_key.init().clear_all();
tmp->part_of_sortkey.init().clear_all();
tmp->unireg_check=Field::NONE;
tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG |
ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG);

View File

@ -843,7 +843,7 @@ int ha_berkeley::write_row(byte * record)
ulong thd_options = table->in_use ? table->in_use->options : 0;
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
key_map changed_keys = 0;
key_map changed_keys;
if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
{
if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */
@ -854,7 +854,7 @@ int ha_berkeley::write_row(byte * record)
key_buff, record),
&row, key_type[primary_key])))
{
changed_keys |= (key_map) 1 << primary_key;
changed_keys.set_bit(primary_key);
for (uint keynr=0 ; keynr < table->keys ; keynr++)
{
if (keynr == primary_key)
@ -867,7 +867,7 @@ int ha_berkeley::write_row(byte * record)
last_dup_key=keynr;
break;
}
changed_keys |= (key_map) 1 << keynr;
changed_keys.set_bit(keynr);
}
}
else
@ -1089,7 +1089,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
sub_trans = transaction;
for (uint retry=0 ; retry < berkeley_trans_retry ; retry++)
{
key_map changed_keys = 0;
key_map changed_keys;
if (using_ignore && (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS))
{
if ((error=txn_begin(db_env, transaction, &sub_trans, 0))) /* purecov: deadcode */
@ -1122,7 +1122,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
}
DBUG_RETURN(error); // Fatal error /* purecov: inspected */
}
changed_keys |= (key_map)1 << keynr;
changed_keys.set_bit(keynr);
if ((error=key_file[keynr]->put(key_file[keynr], sub_trans,
create_key(&key, keynr, key_buff2,
new_row),
@ -1260,7 +1260,7 @@ int ha_berkeley::delete_row(const byte * record)
DBUG_RETURN((error)); /* purecov: inspected */
create_key(&prim_key, primary_key, key_buff, record);
if (hidden_primary_key)
keys|= (key_map) 1 << primary_key;
keys.set_bit(primary_key);
/* Subtransactions may be used in order to retry the delete in
case we get a DB_LOCK_DEADLOCK error. */

View File

@ -107,7 +107,7 @@ class ha_berkeley: public handler
uint extra_rec_buf_length() { return BDB_HIDDEN_PRIMARY_KEY_LENGTH; }
ha_rows estimate_number_of_rows();
bool fast_key_read() { return 1;}
key_map keys_to_use_for_scanning() { return ~(key_map) 0; }
const key_map keys_to_use_for_scanning() { return key_map(~0); }
bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);

View File

@ -125,7 +125,7 @@ class ha_innobase: public handler
uint max_key_length() const { return((MAX_KEY_LENGTH <= 3500) ?
MAX_KEY_LENGTH : 3500);}
bool fast_key_read() { return 1;}
key_map keys_to_use_for_scanning() { return ~(key_map) 0; }
const key_map& keys_to_use_for_scanning() { return key_map_full; }
bool has_transactions() { return 1;}
int open(const char *name, int mode, uint test_if_locked);

View File

@ -202,7 +202,7 @@ void ha_isam::info(uint flag)
sortkey = info.sortkey;
block_size=nisam_block_size;
table->keys = min(table->keys,info.keys);
table->keys_in_use= set_bits(key_map,table->keys);
table->keys_in_use.set_prefix(table->keys);
table->db_options_in_use= info.options;
table->db_record_offset=
(table->db_options_in_use &

View File

@ -708,15 +708,16 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
/* Check validity of the index references */
if (table_list->use_index)
{
key_map kmap= get_key_map_from_key_list(table, table_list->use_index);
if (kmap == ~(key_map) 0)
key_map kmap;
get_key_map_from_key_list(&kmap, table, table_list->use_index);
if (kmap.is_set_all())
{
errmsg= thd->net.last_error;
error= HA_ADMIN_FAILED;
goto err;
}
if (kmap)
map= kmap;
if (!kmap.is_clear_all())
map= kmap.to_ulonglong();
}
mi_extra(file, HA_EXTRA_PRELOAD_BUFFER_SIZE,
@ -1022,9 +1023,9 @@ void ha_myisam::info(uint flag)
ref_length=info.reflength;
table->db_options_in_use = info.options;
block_size=myisam_block_size;
table->keys_in_use= (set_bits(key_map, table->keys) &
(key_map) info.key_map);
table->keys_for_keyread= table->keys_in_use & ~table->read_only_keys;
table->keys_in_use.set_prefix(table->keys).intersect(info.key_map);
table->keys_for_keyread= table->keys_in_use;
table->keys_for_keyread.subtract(table->read_only_keys);
table->db_record_offset=info.record_offset;
if (table->key_parts)
memcpy((char*) table->key_info[0].rec_per_key,

View File

@ -228,7 +228,7 @@ void ha_myisammrg::info(uint flag)
#endif
data_file_length=info.data_file_length;
errkey = info.errkey;
table->keys_in_use= set_bits(key_map, table->keys);
table->keys_in_use.set_prefix(table->keys);
table->db_options_in_use = info.options;
table->is_view=1;
mean_rec_length=info.reclength;

View File

@ -241,7 +241,7 @@ public:
virtual double read_time(uint index, uint ranges, ha_rows rows)
{ return rows2double(ranges+rows); }
virtual bool fast_key_read() { return 0;}
virtual key_map keys_to_use_for_scanning() { return 0; }
virtual const key_map& keys_to_use_for_scanning() { return key_map_empty; }
virtual bool has_transactions(){ return 0;}
virtual uint extra_rec_buf_length() { return 0; }
virtual ha_rows estimate_number_of_rows() { return records+EXTRA_RECORDS; }

View File

@ -897,7 +897,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
TABLE *table=field->table;
field->query_id=thd->query_id;
table->used_fields++;
table->used_keys&=field->part_of_key;
table->used_keys.intersect(field->part_of_key);
}
fixed= 1;
return 0;

View File

@ -2650,7 +2650,7 @@ bool Item_func_match::fix_index()
for (keynr=0 ; keynr < table->keys ; keynr++)
{
if ((table->key_info[keynr].flags & HA_FULLTEXT) &&
(table->keys_in_use_for_query & (((key_map)1) << keynr)))
(table->keys_in_use_for_query.is_set(keynr)))
{
ft_to_key[fts]=keynr;
ft_cnt[fts]=0;

View File

@ -63,7 +63,7 @@ enum date_time_format_types
DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND
};
typedef struct date_time_format
struct date_time_format
{
const char* format_str;
uint length;

View File

@ -30,10 +30,115 @@
#undef write /* remove pthread.h macro definition for EMX */
#endif
template <uint default_width> class Bitmap
{
MY_BITMAP map;
uchar buffer[(default_width+7)/8];
public:
Bitmap(uint prefix_to_set=0) { init(); set_prefix(prefix_to_set); }
Bitmap& init()
{
bitmap_init(&map, buffer, default_width, 0);
return *this;
}
uint length() const { return default_width; }
Bitmap& operator=(const Bitmap& map2)
{
init();
memcpy(buffer, map2.buffer, sizeof(buffer));
return *this;
}
Bitmap& set_bit(uint n) { bitmap_set_bit(&map, n); return *this; }
Bitmap& clear_bit(uint n) { bitmap_clear_bit(&map, n); return *this; }
Bitmap& set_prefix(uint n) { bitmap_set_prefix(&map, n); return *this; }
Bitmap& set_all() { bitmap_set_all(&map); return *this;}
Bitmap& clear_all() { bitmap_clear_all(&map); return *this; }
Bitmap& intersect(Bitmap& map2) { bitmap_intersect(&map, &map2.map); return *this; }
Bitmap& intersect(ulonglong map2buff)
{
MY_BITMAP map2;
bitmap_init(&map2, (uchar *)&map2buff, sizeof(ulonglong)*8, 0);
bitmap_intersect(&map, &map2);
return *this;
}
Bitmap& subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); return *this; }
Bitmap& merge(Bitmap& map2) { bitmap_union(&map, &map2.map); return *this; }
my_bool is_set(uint n) const { return bitmap_is_set((MY_BITMAP*)&map, n); }
my_bool is_prefix(uint n) const { return bitmap_is_prefix((MY_BITMAP*)&map, n); }
my_bool is_clear_all() const { return bitmap_is_clear_all((MY_BITMAP*)&map); }
my_bool is_set_all() const { return bitmap_is_set_all((MY_BITMAP*)&map); }
my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset((MY_BITMAP*)&map, (MY_BITMAP*)&map2.map); }
my_bool operator==(const Bitmap& map2) const { return bitmap_cmp((MY_BITMAP*)&map, (MY_BITMAP*)&map2.map); }
char *print(char *buf) const
{
char *s=buf; int i;
for (i=sizeof(buffer)-1; i>=0 ; i--)
{
if ((*s=_dig_vec[buffer[i] >> 4]) != '0')
break;
if ((*s=_dig_vec[buffer[i] & 15]) != '0')
break;
}
for (s++, i-- ; i>=0 ; i--)
{
*s++=_dig_vec[buffer[i] >> 4];
*s++=_dig_vec[buffer[i] & 15];
}
*s=0;
return buf;
}
ulonglong to_ulonglong() const
{
if (sizeof(buffer) >= sizeof(ulonglong))
return *(ulonglong*)buffer;
ulonglong x=0;
memcpy(&x, buffer, sizeof(buffer));
return x;
}
};
template <> class Bitmap<64>
{
longlong map;
public:
Bitmap(uint prefix_to_set=0) { set_prefix(prefix_to_set); }
Bitmap<64>& init() { return *this; }
uint length() const { return 64; }
Bitmap<64>& set_bit(uint n) { map|= ((ulonglong)1) << n; return *this; }
Bitmap<64>& clear_bit(uint n) { map&= ~(((ulonglong)1) << n); return *this; }
Bitmap<64>& set_prefix(uint n)
{
if (n >= length())
set_all();
else
map= (((ulonglong)1) << n)-1;
return *this;
}
Bitmap<64>& set_all() { map=~(ulonglong)0; return *this;}
Bitmap<64>& clear_all() { map=(ulonglong)0; return *this; }
Bitmap<64>& intersect(Bitmap<64>& map2) { map&= map2.map; return *this; }
Bitmap<64>& intersect(ulonglong map2) { map&= map2; return *this; }
Bitmap<64>& subtract(Bitmap<64>& map2) { map&= ~map2.map; return *this; }
Bitmap<64>& merge(Bitmap<64>& map2) { map|= map2.map; return *this; }
my_bool is_set(uint n) const { return test(map & (((ulonglong)1) << n)); }
my_bool is_prefix(uint n) const { return map == (((ulonglong)1) << n)-1; }
my_bool is_clear_all() const { return map == (ulonglong)0; }
my_bool is_set_all() const { return map == ~(ulonglong)0; }
my_bool is_subset(const Bitmap<64>& map2) const { return !(map & ~map2.map); }
my_bool operator==(const Bitmap<64>& map2) const { return map == map2.map; }
char *print(char *buf) const { longlong2str(map,buf,16); return buf; }
ulonglong to_ulonglong() const { return map; }
};
/* TODO convert all these three maps to Bitmap classes */
typedef ulonglong table_map; /* Used for table bits in join */
typedef ulong key_map; /* Used for finding keys */
typedef Bitmap<64> key_map; /* Used for finding keys */
typedef ulong key_part_map; /* Used for finding key parts */
/* useful constants */
extern const key_map key_map_empty;
extern const key_map key_map_full;
#include "mysql_com.h"
#include <violite.h>
#include "unireg.h"
@ -634,7 +739,7 @@ enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
extern const Item **not_found_item;
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
find_item_error_report_type report_error);
key_map get_key_map_from_key_list(TABLE *table,
void get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,

View File

@ -2114,7 +2114,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
global_system_variables.character_set_results= default_charset_info;
global_system_variables.character_set_client= default_charset_info;
if (use_temp_pool && bitmap_init(&temp_pool,1024,1))
if (use_temp_pool && bitmap_init(&temp_pool,0,1024,1))
return 1;
return 0;
}

View File

@ -304,7 +304,7 @@ static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree,
static QUICK_SELECT *get_quick_select(PARAM *param,uint index,
SEL_ARG *key_tree);
#ifndef DBUG_OFF
static void print_quick(QUICK_SELECT *quick,key_map needed_reg);
static void print_quick(QUICK_SELECT *quick,const key_map& needed_reg);
#endif
static SEL_TREE *tree_and(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
static SEL_TREE *tree_or(PARAM *param,SEL_TREE *tree1,SEL_TREE *tree2);
@ -363,7 +363,6 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0)
{
quick_keys=0; needed_reg=0;
my_b_clear(&file);
}
@ -584,18 +583,18 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
uint idx;
double scan_time;
DBUG_ENTER("test_quick_select");
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
/* DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
(ulong) keys_to_use, (ulong) prev_tables,
(ulong) const_tables));
(ulong) const_tables));*/
delete quick;
quick=0;
needed_reg=0; quick_keys=0;
needed_reg.clear_all(); quick_keys.clear_all();
if (!cond || (specialflag & SPECIAL_SAFE_MODE) && ! force_quick_range ||
!limit)
DBUG_RETURN(0); /* purecov: inspected */
if (!((basflag= head->file->table_flags()) & HA_KEYPOS_TO_RNDPOS) &&
keys_to_use == (uint) ~0 || !keys_to_use)
keys_to_use.is_set_all() || keys_to_use.is_clear_all())
DBUG_RETURN(0); /* Not smart database */
records=head->file->records;
if (!records)
@ -611,8 +610,8 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
DBUG_PRINT("info",("Time to scan table: %g", read_time));
keys_to_use&=head->keys_in_use_for_query;
if (keys_to_use)
keys_to_use.intersect(head->keys_in_use_for_query);
if (!keys_to_use.is_clear_all())
{
MEM_ROOT *old_root,alloc;
SEL_TREE *tree;
@ -645,7 +644,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
for (idx=0 ; idx < head->keys ; idx++)
{
if (!(keys_to_use & ((key_map) 1L << idx)))
if (!keys_to_use.is_set(idx))
continue;
KEY *key_info= &head->key_info[idx];
if (key_info->flags & HA_FULLTEXT)
@ -692,11 +691,11 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
uint keynr= param.real_keynr[idx];
if ((*key)->type == SEL_ARG::MAYBE_KEY ||
(*key)->maybe_flag)
needed_reg|= (key_map) 1 << keynr;
needed_reg.set_bit(keynr);
found_records=check_quick_select(&param, idx, *key);
if (found_records != HA_POS_ERROR && found_records > 2 &&
head->used_keys & ((table_map) 1 << keynr) &&
head->used_keys.is_set(keynr) &&
(head->file->index_flags(keynr) & HA_KEY_READ_ONLY))
{
/*
@ -2100,7 +2099,7 @@ check_quick_select(PARAM *param,uint idx,SEL_ARG *tree)
if (records != HA_POS_ERROR)
{
uint key=param->real_keynr[idx];
param->table->quick_keys|= (key_map) 1 << key;
param->table->quick_keys.set_bit(key);
param->table->quick_rows[key]=records;
param->table->quick_key_parts[key]=param->max_key_part+1;
}
@ -2841,17 +2840,18 @@ print_key(KEY_PART *key_part,const char *key,uint used_length)
}
}
static void print_quick(QUICK_SELECT *quick,key_map needed_reg)
static void print_quick(QUICK_SELECT *quick,const key_map& needed_reg)
{
QUICK_RANGE *range;
char buf[MAX_KEY/8+1];
DBUG_ENTER("print_param");
if (! _db_on_ || !quick)
DBUG_VOID_RETURN;
List_iterator<QUICK_RANGE> li(quick->ranges);
DBUG_LOCK_FILE;
fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: %lu):\n",
quick->index, (ulong) needed_reg);
fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: %s):\n",
quick->index, needed_reg.print(buf));
while ((range=li++))
{
if (!(range->flag & NO_MIN_RANGE))

View File

@ -128,7 +128,7 @@ class SQL_SELECT :public Sql_alloc {
SQL_SELECT();
~SQL_SELECT();
bool check_quick(bool force_quick_range=0, ha_rows limit = HA_POS_ERROR)
{ return test_quick_select(~0L,0,limit, force_quick_range) < 0; }
{ return test_quick_select(key_map(~0),0,limit, force_quick_range) < 0; }
inline bool skipp_record() { return cond ? cond->val_int() == 0 : 0; }
int test_quick_select(key_map keys,table_map prev_tables,ha_rows limit,
bool force_quick_range=0);

View File

@ -683,7 +683,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
The following test is false when the key in the key tree is
converted (for example to upper case)
*/
if (field->part_of_key & ((key_map) 1 << idx))
if (field->part_of_key.is_set(idx))
{
table->key_read= 1;
table->file->extra(HA_EXTRA_KEYREAD);

View File

@ -330,7 +330,7 @@ err:
void init_slave_skip_errors(const char* arg)
{
const char *p;
if (bitmap_init(&slave_error_mask,MAX_SLAVE_ERROR,0))
if (bitmap_init(&slave_error_mask,0,MAX_SLAVE_ERROR,0))
{
fprintf(stderr, "Badly out of memory, please check your system status\n");
exit(1);

View File

@ -3545,8 +3545,16 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
close_thread_tables(thd);
/* XXX this should not be necessary. The error message is already printed
by replace_xxx_table. my_error() should be use above instead of
sql_print_error(), and print ER_NONEXISTING_GRANT - as other grant
commands do */
/* when this code is deleted, the error slot (error 1268) can be reused,
as this error code was not present in any MySQL release */
if (result)
my_error(ER_REVOKE_GRANTS, MYF(0));
DBUG_RETURN(result);
}

View File

@ -1688,7 +1688,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
{
field->query_id=thd->query_id;
table->used_fields++;
table->used_keys&= field->part_of_key;
table->used_keys.intersect(field->part_of_key);
}
else
thd->dupp_field=field;
@ -2041,21 +2041,21 @@ bool setup_tables(TABLE_LIST *tables)
table->used_keys= table->keys_for_keyread;
if (table_list->use_index)
{
key_map map= get_key_map_from_key_list(table,
table_list->use_index);
if (map == ~(key_map) 0)
key_map map;
get_key_map_from_key_list(&map, table, table_list->use_index);
if (map.is_set_all())
DBUG_RETURN(1);
table->keys_in_use_for_query=map;
}
if (table_list->ignore_index)
{
key_map map= get_key_map_from_key_list(table,
table_list->ignore_index);
if (map == ~(key_map) 0)
key_map map;
get_key_map_from_key_list(&map, table, table_list->ignore_index);
if (map.is_set_all())
DBUG_RETURN(1);
table->keys_in_use_for_query &= ~map;
table->keys_in_use_for_query.subtract(map);
}
table->used_keys &= table->keys_in_use_for_query;
table->used_keys.intersect(table->keys_in_use_for_query);
if (table_list->shared || table->clear_query_id)
{
table->clear_query_id= 0;
@ -2073,24 +2073,26 @@ bool setup_tables(TABLE_LIST *tables)
}
key_map get_key_map_from_key_list(TABLE *table,
void get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list)
{
key_map map=0;
List_iterator_fast<String> it(*index_list);
String *name;
uint pos;
map->clear_all();
while ((name=it++))
{
if ((pos=find_type(name->c_ptr(), &table->keynames, 1+2)) <= 0)
{
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
table->real_name);
return (~ (key_map) 0);
map->set_all();
return;
}
map|= ((key_map) 1) << (pos-1);
map->set_bit(pos-1);
}
return map;
return;
}
/****************************************************************************
@ -2135,7 +2137,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
if (field->query_id == thd->query_id)
thd->dupp_field=field;
field->query_id=thd->query_id;
table->used_keys&= field->part_of_key;
table->used_keys.intersect(field->part_of_key);
}
/* All fields are used */
table->used_fields=table->fields;
@ -2226,8 +2228,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
/* Mark field used for table cache */
t1->field[i]->query_id=t2->field[j]->query_id=thd->query_id;
cond_and->list.push_back(tmp);
t1->used_keys&= t1->field[i]->part_of_key;
t2->used_keys&= t2->field[j]->part_of_key;
t1->used_keys.intersect(t1->field[i]->part_of_key);
t2->used_keys.intersect(t2->field[j]->part_of_key);
break;
}
}

View File

@ -85,7 +85,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
/* Handler didn't support fast delete; Delete rows one by one */
}
table->used_keys=table->quick_keys=0; // Can't use 'only index'
table->used_keys.clear_all();
table->quick_keys.clear_all(); // Can't use 'only index'
select=make_select(table,0,0,conds,&error);
if (error)
DBUG_RETURN(-1);
@ -98,7 +99,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
}
/* If running in safe sql mode, don't allow updates without keys */
if (!table->quick_keys)
if (table->quick_keys.is_clear_all())
{
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
if (safe_update && !using_limit)
@ -292,7 +293,7 @@ multi_delete::initialize_tables(JOIN *join)
walk=walk->next;
/* Don't use KEYREAD optimization on this table */
tbl->no_keyread=1;
tbl->used_keys= 0;
tbl->used_keys.clear_all();
if (tbl->file->has_transactions())
log_delayed= transactional_tables= 1;
else if (tbl->tmp_table != NO_TMP_TABLE)

View File

@ -35,6 +35,9 @@ const char *join_type_str[]={ "UNKNOWN","system","const","eq_ref","ref",
"ref_or_null","unique_subquery","index_subquery"
};
const key_map key_map_empty(0);
const key_map key_map_full(~0);
static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array);
static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
DYNAMIC_ARRAY *keyuse);
@ -114,7 +117,7 @@ static int join_read_next_same_or_null(READ_RECORD *info);
static COND *make_cond_for_table(COND *cond,table_map table,
table_map used_table);
static Item* part_of_refkey(TABLE *form,Field *field);
static uint find_shortest_key(TABLE *table, key_map usable_keys);
static uint find_shortest_key(TABLE *table, const key_map& usable_keys);
static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
ha_rows select_limit, bool no_changes);
static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
@ -1575,7 +1578,7 @@ err:
*****************************************************************************/
static ha_rows get_quick_record_count(SQL_SELECT *select,TABLE *table,
key_map keys,ha_rows limit)
const key_map& keys,ha_rows limit)
{
int error;
DBUG_ENTER("get_quick_record_count");
@ -1637,9 +1640,13 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
TABLE *table;
stat_vector[i]=s;
s->keys.init();
s->const_keys.init();
s->checked_keys.init();
s->needed_reg.init();
table_vector[i]=s->table=table=tables->table;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);// record count
table->quick_keys=0;
table->quick_keys.clear_all();
table->reginfo.join_tab=s;
table->reginfo.not_exists_optimize=0;
bzero((char*) table->const_key_parts, sizeof(key_part_map)*table->keys);
@ -1785,24 +1792,25 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
{
start_keyuse=keyuse;
key=keyuse->key;
s->keys|= (key_map) 1 << key; // QQ: remove this ?
s->keys.set_bit(key); // QQ: remove this ?
refs=const_ref=0;
eq_part=0;
refs=0;
const_ref.clear_all();
eq_part.clear_all();
do
{
if (keyuse->val->type() != Item::NULL_ITEM && !keyuse->optimize)
{
if (!((~found_const_table_map) & keyuse->used_tables))
const_ref|= (key_map) 1 << keyuse->keypart;
const_ref.set_bit(keyuse->keypart);
else
refs|=keyuse->used_tables;
eq_part|= (key_map) 1 << keyuse->keypart;
eq_part.set_bit(keyuse->keypart);
}
keyuse++;
} while (keyuse->table == table && keyuse->key == key);
if (eq_part == PREV_BITS(uint,table->key_info[key].key_parts) &&
if (eq_part.is_prefix(table->key_info[key].key_parts) &&
(table->key_info[key].flags & HA_NOSAME) &&
!table->fulltext_searched)
{
@ -1858,7 +1866,7 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0;
if (s->const_keys)
if (! s->const_keys.is_clear_all())
{
ha_rows records;
SQL_SELECT *select;
@ -2095,9 +2103,10 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
else
{
JOIN_TAB *stat=field->table->reginfo.join_tab;
key_map possible_keys= (field->key_start &
field->table->keys_in_use_for_query);
stat[0].keys|= possible_keys; // Add possible keys
key_map possible_keys;
possible_keys=field->key_start;
possible_keys.intersect(field->table->keys_in_use_for_query);
stat[0].keys.merge(possible_keys); // Add possible keys
/*
Save the following cases:
@ -2116,7 +2125,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level,
for (uint i=0; i<num_values; i++)
is_const&= (*value)->const_item();
if (is_const)
stat[0].const_keys |= possible_keys;
stat[0].const_keys.merge(possible_keys);
/*
We can't always use indexes when comparing a string index to a
number. cmp_type() is checked to allow compare of dates to numbers.
@ -2247,14 +2256,13 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
*/
static uint
max_part_bit(key_map bits)
max_part_bit(key_part_map bits)
{
uint found;
for (found=0; bits & 1 ; found++,bits>>=1) ;
return found;
}
static void
add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
@ -2266,7 +2274,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
{
for (uint key=0 ; key < form->keys ; key++)
{
if (!(form->keys_in_use_for_query & (((key_map) 1) << key)))
if (!(form->keys_in_use_for_query.is_set(key)))
continue;
if (form->key_info[key].flags & HA_FULLTEXT)
continue; // ToDo: ft-keys in non-ft queries. SerG
@ -2457,7 +2465,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
/* Save ptr to first use */
if (!use->table->reginfo.join_tab->keyuse)
use->table->reginfo.join_tab->keyuse=save_pos;
use->table->reginfo.join_tab->checked_keys|= (key_map) 1 << use->key;
use->table->reginfo.join_tab->checked_keys.set_bit(use->key);
save_pos++;
}
i=(uint) (save_pos-(KEYUSE*) keyuse->buffer);
@ -2598,7 +2606,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
rec= s->records/MATCHING_ROWS_IN_OTHER_TABLE; // Assumed records/key
for (keyuse=s->keyuse ; keyuse->table == table ;)
{
key_map found_part=0;
key_part_map found_part=0;
table_map found_ref=0;
uint key=keyuse->key;
KEY *keyinfo=table->key_info+key;
@ -2667,7 +2675,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
if (!found_ref)
{ // We found a const key
if (table->quick_keys & ((key_map) 1 << key))
if (table->quick_keys.is_set(key))
records= (double) table->quick_rows[key];
else
{
@ -2691,7 +2699,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
/* Limit the number of matched rows */
tmp= records;
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys & ((key_map) 1 << key))
if (table->used_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
@ -2718,7 +2726,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
Check if quick_range could determinate how many rows we
will match
*/
if (table->quick_keys & ((key_map) 1 << key) &&
if (table->quick_keys.is_set(key) &&
table->quick_key_parts[key] <= max_key_part)
tmp=records= (double) table->quick_rows[key];
else
@ -2770,7 +2778,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
}
/* Limit the number of matched rows */
set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys & ((key_map) 1 << key))
if (table->used_keys.is_set(key))
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
@ -2809,7 +2817,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
!(s->quick && best_key && s->quick->index == best_key->key &&
best_max_key_part >= s->table->quick_key_parts[best_key->key]) &&
!((s->table->file->table_flags() & HA_TABLE_SCAN_ON_INDEX) &&
s->table->used_keys && best_key) &&
! s->table->used_keys.is_clear_all() && best_key) &&
!(s->table->force_index && best_key))
{ // Check full join
ha_rows rnd_records= s->found_records;
@ -3023,7 +3031,7 @@ get_best_combination(JOIN *join)
if (j->type == JT_SYSTEM)
continue;
if (!j->keys || !(keyuse= join->best_positions[tablenr].key))
if (j->keys.is_clear_all() || !(keyuse= join->best_positions[tablenr].key))
{
j->type=JT_ALL;
if (tablenr != join->const_tables)
@ -3254,7 +3262,7 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
join_tab->select_cond=0;
join_tab->quick=0;
join_tab->type= JT_ALL; /* Map through all records */
join_tab->keys= (uint) ~0; /* test everything in quick */
join_tab->keys.init().set_all(); /* test everything in quick */
join_tab->info=0;
join_tab->on_expr=0;
join_tab->ref.key = -1;
@ -3336,13 +3344,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
{
/* Use quick key read if it's a constant and it's not used
with key reading */
if (tab->needed_reg == 0 && tab->type != JT_EQ_REF
if (tab->needed_reg.is_clear_all() && tab->type != JT_EQ_REF
&& tab->type != JT_FT && (tab->type != JT_REF ||
(uint) tab->ref.key == tab->quick->index))
{
sel->quick=tab->quick; // Use value from get_quick_...
sel->quick_keys=0;
sel->needed_reg=0;
sel->quick_keys.clear_all();
sel->needed_reg.clear_all();
}
else
{
@ -3353,12 +3361,13 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
uint ref_key=(uint) sel->head->reginfo.join_tab->ref.key+1;
if (i == join->const_tables && ref_key)
{
if (tab->const_keys && tab->table->reginfo.impossible_range)
if (!tab->const_keys.is_clear_all() &&
tab->table->reginfo.impossible_range)
DBUG_RETURN(1);
}
else if (tab->type == JT_ALL && ! use_quick_range)
{
if (tab->const_keys &&
if (!tab->const_keys.is_clear_all() &&
tab->table->reginfo.impossible_range)
DBUG_RETURN(1); // Impossible range
/*
@ -3368,8 +3377,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
the index if we are using limit and this is the first table
*/
if ((tab->keys & ~ tab->const_keys && i > 0) ||
(tab->const_keys && i == join->const_tables &&
if ((!tab->keys.is_subset(tab->const_keys) && i > 0) ||
(!tab->const_keys.is_clear_all() && i == join->const_tables &&
join->unit->select_limit_cnt <
join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
@ -3408,13 +3417,15 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
else
{
sel->needed_reg=tab->needed_reg;
sel->quick_keys=0;
sel->quick_keys.clear_all();
}
if ((sel->quick_keys | sel->needed_reg) & ~tab->checked_keys)
if (!sel->quick_keys.is_subset(tab->checked_keys) ||
!sel->needed_reg.is_subset(tab->checked_keys))
{
tab->keys=sel->quick_keys | sel->needed_reg;
tab->use_quick= (sel->needed_reg &&
(!select->quick_keys ||
tab->keys=sel->quick_keys;
tab->keys.merge(sel->needed_reg);
tab->use_quick= (!sel->needed_reg.is_clear_all() &&
(select->quick_keys.is_clear_all() ||
(select->quick &&
(select->quick->records >= 100L)))) ?
2 : 1;
@ -3479,7 +3490,7 @@ make_join_readinfo(JOIN *join, uint options)
table->file->index_init(tab->ref.key);
tab->read_first_record= join_read_key;
tab->read_record.read_record= join_no_more_records;
if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -3497,7 +3508,7 @@ make_join_readinfo(JOIN *join, uint options)
delete tab->quick;
tab->quick=0;
table->file->index_init(tab->ref.key);
if (table->used_keys & ((key_map) 1 << tab->ref.key) &&
if (table->used_keys.is_set(tab->ref.key) &&
!table->no_keyread)
{
table->key_read=1;
@ -3572,12 +3583,12 @@ make_join_readinfo(JOIN *join, uint options)
if (!table->no_keyread)
{
if (tab->select && tab->select->quick &&
table->used_keys & ((key_map) 1 << tab->select->quick->index))
table->used_keys.is_set(tab->select->quick->index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
}
else if (table->used_keys && ! (tab->select && tab->select->quick))
else if (!table->used_keys.is_clear_all() && ! (tab->select && tab->select->quick))
{ // Only read index tree
tab->index=find_shortest_key(table, table->used_keys);
tab->table->file->index_init(tab->index);
@ -4653,6 +4664,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->db_low_byte_first=1; // True for HEAP and MyISAM
table->temp_pool_slot = temp_pool_slot;
table->copy_blobs= 1;
table->keys_for_keyread.init();
table->keys_in_use.init();
table->read_only_keys.init();
table->quick_keys.init();
table->used_keys.init();
table->keys_in_use_for_query.init();
/* Calculate which type of fields we will store in the temporary table */
@ -5848,7 +5865,7 @@ join_read_first(JOIN_TAB *tab)
{
int error;
TABLE *table=tab->table;
if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
if (!table->key_read && table->used_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@ -5885,7 +5902,7 @@ join_read_last(JOIN_TAB *tab)
{
TABLE *table=tab->table;
int error;
if (!table->key_read && (table->used_keys & ((key_map) 1 << tab->index)) &&
if (!table->key_read && table->used_keys.is_set(tab->index) &&
!table->no_keyread)
{
table->key_read=1;
@ -6583,13 +6600,15 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx,
return reverse;
}
static uint find_shortest_key(TABLE *table, key_map usable_keys)
static uint find_shortest_key(TABLE *table, const key_map& usable_keys)
{
uint min_length= (uint) ~0;
uint best= MAX_KEY;
for (uint nr=0; usable_keys ; usable_keys>>=1, nr++)
if (!usable_keys.is_clear_all())
{
if (usable_keys & 1)
for (uint nr=0; nr < usable_keys.length() ; nr++)
{
if (usable_keys.is_set(nr))
{
if (table->key_info[nr].key_length < min_length)
{
@ -6598,6 +6617,7 @@ static uint find_shortest_key(TABLE *table, key_map usable_keys)
}
}
}
}
return best;
}
@ -6640,7 +6660,7 @@ is_subkey(KEY_PART_INFO *key_part, KEY_PART_INFO *ref_key_part,
static uint
test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
key_map usable_keys)
const key_map& usable_keys)
{
uint nr;
uint min_length= (uint) ~0;
@ -6649,9 +6669,9 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts,
KEY_PART_INFO *ref_key_part= table->key_info[ref].key_part;
KEY_PART_INFO *ref_key_part_end= ref_key_part + ref_key_parts;
for (nr= 0; usable_keys; usable_keys>>= 1, nr++)
for (nr= 0; nr < usable_keys.length(); nr++)
{
if ((usable_keys & 1) &&
if (usable_keys.is_set(nr) &&
table->key_info[nr].key_length < min_length &&
table->key_info[nr].key_parts >= ref_key_parts &&
is_subkey(table->key_info[nr].key_part, ref_key_part,
@ -6689,16 +6709,17 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
LINT_INIT(ref_key_parts);
/* Check which keys can be used to resolve ORDER BY */
usable_keys= ~(key_map) 0;
usable_keys.set_all();
for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next)
{
if ((*tmp_order->item)->type() != Item::FIELD_ITEM)
{
usable_keys=0;
usable_keys.clear_all();
break;
}
if (!(usable_keys&= (((Item_field*) (*tmp_order->item))->field->
part_of_sortkey)))
usable_keys.intersect(
((Item_field*) (*tmp_order->item))->field->part_of_sortkey);
if (usable_keys.is_clear_all())
break; // No usable keys
}
@ -6724,7 +6745,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
int order_direction;
uint used_key_parts;
if (!(usable_keys & ((key_map) 1 << ref_key)))
if (!usable_keys.is_set(ref_key))
{
/*
We come here when ref_key is not among usable_keys
@ -6734,8 +6755,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
If using index only read, only consider other possible index only
keys
*/
if (table->used_keys & (((key_map) 1 << ref_key)))
usable_keys|= table->used_keys;
if (table->used_keys.is_set(ref_key))
usable_keys.merge(table->used_keys);
if ((new_ref_key= test_if_subkey(order, table, ref_key, ref_key_parts,
usable_keys)) < MAX_KEY)
{
@ -6754,7 +6775,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
}
}
/* Check if we get the rows in requested sorted order by using the key */
if ((usable_keys & ((key_map) 1 << ref_key)) &&
if (usable_keys.is_set(ref_key) &&
(order_direction = test_if_order_by_key(order,table,ref_key,
&used_key_parts)))
{
@ -6805,7 +6826,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
/* check if we can use a key to resolve the group */
/* Tables using JT_NEXT are handled here */
uint nr;
key_map keys=usable_keys;
key_map keys;
/*
If not used with LIMIT, only use keys if the whole query can be
@ -6813,12 +6834,19 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
retrieving all rows through an index.
*/
if (select_limit >= table->file->records)
keys&= (table->used_keys | table->file->keys_to_use_for_scanning());
{
keys=table->file->keys_to_use_for_scanning();
keys.merge(table->used_keys);
}
else
keys.set_all();
for (nr=0; keys ; keys>>=1, nr++)
keys.intersect(usable_keys);
for (nr=0; nr < keys.length() ; nr++)
{
uint not_used;
if (keys & 1)
if (keys.is_set(nr))
{
int flag;
if ((flag=test_if_order_by_key(order, table, nr, &not_used)))
@ -6830,7 +6858,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
join_read_last);
table->file->index_init(nr);
tab->type=JT_NEXT; // Read with index_first(), index_next()
if (table->used_keys & ((key_map) 1 << nr))
if (table->used_keys.is_set(nr))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@ -8740,17 +8768,19 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(new Item_string(join_type_str[tab->type],
strlen(join_type_str[tab->type]),
cs));
key_map bits;
uint j;
for (j=0,bits=tab->keys ; bits ; j++,bits>>=1)
if (!tab->keys.is_clear_all())
{
if (bits & 1)
for (j=0 ; j < tab->keys.length() ; j++)
{
if (tab->keys.is_set(j))
{
if (tmp1.length())
tmp1.append(',');
tmp1.append(table->key_info[j].name);
}
}
}
if (tmp1.length())
item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(),cs));
else
@ -8797,8 +8827,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
join->best_positions[i]. records_read,
21));
my_bool key_read=table->key_read;
if (tab->type == JT_NEXT &&
((table->used_keys & ((key_map) 1 << tab->index))))
if (tab->type == JT_NEXT && table->used_keys.is_set(tab->index))
key_read=1;
if (tab->info)
@ -8809,8 +8838,9 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
{
if (tab->use_quick == 2)
{
sprintf(buff_ptr,"; Range checked for each record (index map: %u)",
tab->keys);
char buf[MAX_KEY/8+1];
sprintf(buff_ptr,"; Range checked for each record (index map: %s)",
tab->keys.print(buf));
buff_ptr=strend(buff_ptr);
}
else

View File

@ -29,7 +29,7 @@ typedef struct keyuse_t {
Item *val; /* or value if no field */
table_map used_tables;
uint key, keypart, optimize;
key_map keypart_map;
key_part_map keypart_map;
ha_rows ref_table_rows;
} KEYUSE;
@ -96,9 +96,9 @@ typedef struct st_join_table {
key_map const_keys; /* Keys with constant part */
key_map checked_keys; /* Keys checked in find_best */
key_map needed_reg;
key_map keys; /* all keys with can be used */
ha_rows records,found_records,read_time;
table_map dependent,key_dependent;
uint keys; /* all keys with can be used */
uint use_quick,index;
uint status; // Save status for cache
uint used_fields,used_fieldlength,used_blobs;

View File

@ -939,7 +939,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list)
protocol->store((const char*) pos, system_charset_info);
protocol->store(table->file->index_type(i), system_charset_info);
/* Comment */
if (!(table->keys_in_use & ((key_map) 1 << i)))
if (!table->keys_in_use.is_set(i))
protocol->store("disabled",8, system_charset_info);
else
protocol->store("", 0, system_charset_info);

View File

@ -172,10 +172,11 @@ TEST_join(JOIN *join)
tab->ref.key_length);
if (tab->select)
{
char buf[MAX_KEY/8+1];
if (tab->use_quick == 2)
fprintf(DBUG_FILE,
" quick select checked for each record (keys: %d)\n",
(int) tab->select->quick_keys);
" quick select checked for each record (keys: %s)\n",
tab->select->quick_keys.print(buf));
else if (tab->select->quick)
fprintf(DBUG_FILE," quick select used on key %s, length: %d\n",
form->key_info[tab->select->quick->index].name,

View File

@ -85,7 +85,7 @@ int mysql_update(THD *thd,
/* Calculate "table->used_keys" based on the WHERE */
table->used_keys=table->keys_in_use;
table->quick_keys=0;
table->quick_keys.clear_all();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
want_privilege=table->grant.want_privilege;
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
@ -149,7 +149,7 @@ int mysql_update(THD *thd,
}
// Don't count on usage of 'only index' when calculating which key to use
table->used_keys=0;
table->used_keys.clear_all();
select=make_select(table,0,0,conds,&error);
if (error ||
(select && select->check_quick(safe_update, limit)) || !limit)
@ -164,7 +164,7 @@ int mysql_update(THD *thd,
DBUG_RETURN(0);
}
/* If running in safe sql mode, don't allow updates without keys */
if (!table->quick_keys)
if (table->quick_keys.is_clear_all())
{
thd->lex.select_lex.options|=QUERY_NO_INDEX_USED;
if (safe_update && !using_limit)
@ -192,7 +192,7 @@ int mysql_update(THD *thd,
matching rows before updating the table!
*/
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (old_used_keys & ((key_map) 1 << used_index))
if (old_used_keys.is_set(used_index))
{
table->key_read=1;
table->file->extra(HA_EXTRA_KEYREAD);
@ -501,8 +501,7 @@ int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
if (!tables_to_update)
{
my_error(ER_NOT_SUPPORTED_YET, MYF(0),
"You didn't specify any tables to UPDATE");
my_error(ER_NO_TABLES_USED, MYF(0));
DBUG_RETURN(1);
}
@ -533,7 +532,7 @@ int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
update.link_in_list((byte*) tl, (byte**) &tl->next);
tl->shared= table_count++;
table->no_keyread=1;
table->used_keys=0;
table->used_keys.clear_all();
table->pos_in_table_list= tl;
}
}

View File

@ -137,10 +137,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->raid_type= head[41];
outparam->raid_chunks= head[42];
outparam->raid_chunksize= uint4korr(head+43);
if (!(outparam->table_charset=get_charset((uint) head[38],MYF(0))))
outparam->table_charset=default_charset_info; // QQ display error message?
outparam->table_charset=get_charset((uint) head[38],MYF(0));
null_field_first=1;
}
if (!outparam->table_charset) /* unknown charset in head[38] or pre-3.23 frm */
outparam->table_charset=default_charset_info;
outparam->db_record_offset=1;
if (db_create_options & HA_OPTION_LONG_BLOB_PTR)
outparam->blob_ptr_size=portable_sizeof_char_ptr;
@ -156,7 +157,12 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (read_string(file,(gptr*) &disk_buff,key_info_length))
goto err_not_open; /* purecov: inspected */
outparam->keys=keys= disk_buff[0];
outparam->keys_for_keyread= outparam->keys_in_use= set_bits(key_map, keys);
outparam->keys_for_keyread.init().set_prefix(keys);
outparam->keys_in_use.init().set_prefix(keys);
outparam->read_only_keys.init().clear_all();
outparam->quick_keys.init();
outparam->used_keys.init();
outparam->keys_in_use_for_query.init();
outparam->key_parts=key_parts=disk_buff[1];
n_length=keys*sizeof(KEY)+key_parts*sizeof(KEY_PART_INFO);
@ -484,8 +490,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
index_flags=outparam->file->index_flags(key);
if (!(index_flags & HA_KEY_READ_ONLY))
{
outparam->read_only_keys|= ((key_map) 1 << key);
outparam->keys_for_keyread&= ~((key_map) 1 << key);
outparam->read_only_keys.set_bit(key);
outparam->keys_for_keyread.clear_bit(key);
}
if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
@ -545,7 +551,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
field->key_length() ==
keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG);
if (i == 0)
field->key_start|= ((key_map) 1 << key);
field->key_start.set_bit(key);
if (field->key_length() == key_part->length &&
!(field->flags & BLOB_FLAG))
{
@ -553,11 +559,11 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
(field->key_type() != HA_KEYTYPE_TEXT ||
(!(ha_option & HA_KEY_READ_WRONG_STR) &&
!(keyinfo->flags & HA_FULLTEXT))))
field->part_of_key|= ((key_map) 1 << key);
field->part_of_key.set_bit(key);
if ((field->key_type() != HA_KEYTYPE_TEXT ||
!(keyinfo->flags & HA_FULLTEXT)) &&
!(index_flags & HA_WRONG_ASCII_ORDER))
field->part_of_sortkey|= ((key_map) 1 << key);
field->part_of_sortkey.set_bit(key);
}
if (!(key_part->key_part_flag & HA_REVERSE_SORT) &&
usable_parts == i)
@ -600,7 +606,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
keyinfo->usable_key_parts=usable_parts; // Filesort
}
if (primary_key < MAX_KEY &&
(outparam->keys_in_use & ((key_map) 1 << primary_key)))
(outparam->keys_in_use.is_set(primary_key)))
{
outparam->primary_key=primary_key;
/*