From 60370dd01c677f300c4b2d4219f48a3c1984cf6f Mon Sep 17 00:00:00 2001 From: "serg@sergbook.mysql.com" <> Date: Tue, 16 Sep 2003 15:23:38 +0200 Subject: [PATCH 01/23] minor cleanups --- heap/hp_info.c | 3 +-- sql/item_timefunc.cc | 6 +++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/heap/hp_info.c b/heap/hp_info.c index 3122a665fac..e10d140e1f6 100644 --- a/heap/hp_info.c +++ b/heap/hp_info.c @@ -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; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 31ce2ad9cdc..9a36f8a60a6 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -57,13 +57,13 @@ static String day_names[] = String("Sunday", &my_charset_latin1) }; -enum date_time_format_types -{ +enum date_time_format_types +{ TIME_ONLY= 0, TIME_MICROSECOND, DATE_ONLY, DATE_TIME, DATE_TIME_MICROSECOND }; -typedef struct date_time_format +struct date_time_format { const char* format_str; uint length; From 630eb4aec7cfbf3002a9d39ee42f56e2b8c915d2 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Sun, 28 Sep 2003 18:47:22 +0200 Subject: [PATCH 02/23] set table->charset to default for 3.22 .frm files (bug #1161) --- sql/table.cc | 5 +++-- sql/unireg.cc | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/sql/table.cc b/sql/table.cc index 5e7991436a1..986a82cf9d2 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -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; diff --git a/sql/unireg.cc b/sql/unireg.cc index 3e634f54b4f..be14448bd1d 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -33,7 +33,7 @@ static uchar * pack_screens(List &create_fields, uint *info_length, uint *screens, bool small_file); static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info); -static bool pack_header(uchar *forminfo, enum db_type table_type, +static bool pack_header(uchar *forminfo,enum db_type table_type, List &create_fields, uint info_length, uint screens, uint table_options, handler *file); From 9a057fd0bd392b2e58d68997c93ff6151808d393 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 2 Oct 2003 20:22:29 +0200 Subject: [PATCH 03/23] ft1->ft2 auto-conversion on INSERT (WL#725) --- myisam/ft_update.c | 59 ++++++++++++++++--- myisam/fulltext.h | 2 + myisam/mi_delete.c | 18 ++++-- myisam/mi_open.c | 7 ++- myisam/mi_write.c | 85 +++++++++++++++++++++++---- myisam/myisamdef.h | 6 +- mysql-test/r/fulltext2.result | 104 +++++++++++++++++++++++++++++++++- mysql-test/t/fulltext2.test | 80 +++++++++++++++++++++++++- 8 files changed, 331 insertions(+), 30 deletions(-) diff --git a/myisam/ft_update.c b/myisam/ft_update.c index cdf3b306087..8423b6898cd 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -21,13 +21,6 @@ #include "ftdefs.h" #include -/************************************************************** - 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)); +} + diff --git a/myisam/fulltext.h b/myisam/fulltext.h index ec267eb3e86..d8c74d4e94b 100644 --- a/myisam/fulltext.h +++ b/myisam/fulltext.h @@ -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 *); + diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index 2ab5c5d0319..d8e1aef5eb6 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -18,6 +18,7 @@ #include "fulltext.h" #include "rt_index.h" +#include #ifdef __WIN__ #include @@ -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")); - flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,USE_WHOLE_KEY, - comp_flag, &keypos, lastkey, &last_key); + 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; diff --git a/myisam/mi_open.c b/myisam/mi_open.c index c4b24acdb77..744bb9bb3b6 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -513,8 +513,8 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) NullS)) goto err; errpos=6; - - if (!have_rtree) + + if (!have_rtree) info.rtree_recursion_state= NULL; strmov(info.filename,org_name); @@ -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); @@ -1112,7 +1113,7 @@ char *mi_recinfo_read(char *ptr, MI_COLUMNDEF *recinfo) /************************************************************************** Open data file with or without RAID -We can't use dup() here as the data file descriptors need to have different +We can't use dup() here as the data file descriptors need to have different active seek-positions. The argument file_to_dup is here for the future if there would on some OS diff --git a/myisam/mi_write.c b/myisam/mi_write.c index 8e0b7e3530c..b6a7bf50dd0 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -18,6 +18,7 @@ #include "fulltext.h" #include "rt_index.h" +#include #ifdef __WIN__ #include @@ -124,7 +125,7 @@ int mi_write(MI_INFO *info, byte *record) else { if (share->keyinfo[i].ck_insert(info,i,buff, - _mi_make_key(info,i,buff,record,filepos))) + _mi_make_key(info,i,buff,record,filepos))) { if (local_lock_tree) rw_unlock(&share->key_root_lock[i]); @@ -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); - _mi_dpointer(info, keypos+HA_FT_WLEN, 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; diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 83e28a42797..6ec7908c014 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -222,7 +222,8 @@ struct st_myisam_info { MI_BLOB *blobs; /* Pointer to blobs */ MI_BIT_BUFF bit_buff; /* accumulate indexfile changes between write's */ - TREE *bulk_insert; + 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, diff --git a/mysql-test/r/fulltext2.result b/mysql-test/r/fulltext2.result index a35be210ece..687bc6edfa0 100644 --- a/mysql-test/r/fulltext2.result +++ b/mysql-test/r/fulltext2.result @@ -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; diff --git a/mysql-test/t/fulltext2.test b/mysql-test/t/fulltext2.test index b739d60e3b3..a01ec3a59c9 100644 --- a/mysql-test/t/fulltext2.test +++ b/mysql-test/t/fulltext2.test @@ -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; From fc5dedc6c5f4751977f2e99241a91c7004ed364b Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 2 Oct 2003 21:13:51 +0200 Subject: [PATCH 04/23] WL#1172 - no row scan on trunc* operator --- myisam/ft_boolean_search.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 2fbd6490cfd..dfefaf621c9 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -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)); From 9be83de693748e795ffb7f75ee47f3e7f77145b7 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 2 Oct 2003 23:41:10 +0200 Subject: [PATCH 05/23] minor error messages cleanup --- sql/sql_acl.cc | 5 +++++ sql/sql_update.cc | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 508ff88a0cf..82450704ee0 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3589,8 +3589,13 @@ int mysql_revoke_all(THD *thd, List &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); rw_unlock(&LOCK_grant); close_thread_tables(thd); +#ifdef TO_BE_DELETED + /* XXX this should not be necessary. The error message is already printed */ + /* 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)); +#endif DBUG_RETURN(result); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 7430029a5e5..b322957b20b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -493,8 +493,7 @@ int multi_update::prepare(List ¬_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); } From 8cc3951c8f00bbb4f66322c861cabb123122b4f3 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Sat, 11 Oct 2003 13:06:55 +0200 Subject: [PATCH 06/23] key_map with more that 64 bits width --- .bzrignore | 1 + include/my_bitmap.h | 26 ++++-- mysys/my_bitmap.c | 190 +++++++++++++++++++++++++++++++++++++--- sql/field.cc | 3 +- sql/field.h | 4 +- sql/ha_berkeley.cc | 12 +-- sql/ha_berkeley.h | 2 +- sql/ha_innodb.h | 2 +- sql/ha_isam.cc | 2 +- sql/ha_myisam.cc | 25 +++--- sql/ha_myisammrg.cc | 2 +- sql/handler.h | 2 +- sql/item.cc | 20 ++--- sql/item_func.cc | 2 +- sql/mysql_priv.h | 117 +++++++++++++++++++++++-- sql/mysqld.cc | 2 +- sql/opt_range.cc | 32 +++---- sql/opt_range.h | 2 +- sql/opt_sum.cc | 6 +- sql/slave.cc | 2 +- sql/sql_base.cc | 42 ++++----- sql/sql_delete.cc | 7 +- sql/sql_select.cc | 206 +++++++++++++++++++++++++------------------- sql/sql_select.h | 6 +- sql/sql_show.cc | 2 +- sql/sql_test.cc | 5 +- sql/sql_update.cc | 10 +-- sql/table.cc | 19 ++-- 28 files changed, 534 insertions(+), 217 deletions(-) diff --git a/.bzrignore b/.bzrignore index c2e7d0878e4..630cca684c7 100644 --- a/.bzrignore +++ b/.bzrignore @@ -636,3 +636,4 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl +sql/udf_example.so diff --git a/include/my_bitmap.h b/include/my_bitmap.h index ca0037addfb..d3fcece290b 100644 --- a/include/my_bitmap.h +++ b/include/my_bitmap.h @@ -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 diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index 8834dda98e1..70b15eaa1d8 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -27,7 +27,7 @@ #include #include -inline void bitmap_lock(MY_BITMAP* map) +inline void bitmap_lock(MY_BITMAP *map) { #ifdef THREAD if (map->thread_safe) @@ -35,7 +35,7 @@ inline void bitmap_lock(MY_BITMAP* map) #endif } -inline void bitmap_unlock(MY_BITMAP* map) +inline void bitmap_unlock(MY_BITMAP *map) { #ifdef THREAD if (map->thread_safe) @@ -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) +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); + 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; + (map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7))) : 0; } -void bitmap_clear_all(MY_BITMAP* map) +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); - bzero(map->bitmap,(map->bitmap_size+7)/8); + 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); +} + diff --git a/sql/field.cc b/sql/field.cc index 68c9922e887..bb651835194 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -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; diff --git a/sql/field.h b/sql/field.h index fe5141e9d80..eb0af881121 100644 --- a/sql/field.h +++ b/sql/field.h @@ -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); diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 34915a6020c..ffec47c73e5 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -841,7 +841,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 */ @@ -852,7 +852,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) @@ -865,7 +865,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 @@ -1087,7 +1087,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 */ @@ -1120,7 +1120,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), @@ -1258,7 +1258,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. */ diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index f1669e9b6c7..471145c96bf 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -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); diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 13337f466bf..45990c479ab 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -124,7 +124,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); diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc index 3acc385d251..8025e5169c8 100644 --- a/sql/ha_isam.cc +++ b/sql/ha_isam.cc @@ -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 & diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index cec1aefa2d5..9fa99dc26d5 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -705,20 +705,21 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt) DBUG_ENTER("ha_myisam::preload_keys"); - /* Check validity of the index references */ + /* 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, (void *) &thd->variables.preload_buff_size); @@ -731,16 +732,16 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt) case HA_ERR_OUT_OF_MEM: errmsg= "Failed to allocate buffer"; break; - default: + default: char buf[ERRMSGSIZE+20]; - my_snprintf(buf, ERRMSGSIZE, + my_snprintf(buf, ERRMSGSIZE, "Failed to read from index file (errno: %d)", my_errno); errmsg= buf; } error= HA_ADMIN_FAILED; goto err; } - + DBUG_RETURN(HA_ADMIN_OK); err: @@ -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, diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index a0449e83222..42c2ba10808 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -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; diff --git a/sql/handler.h b/sql/handler.h index b74e06c6edf..e7ca17c8185 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -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; } diff --git a/sql/item.cc b/sql/item.cc index 9d34f299a07..30c4e465544 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -799,11 +799,11 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) not_found_field) { /* - We can't find table field in table list of current select, + We can't find table field in table list of current select, consequently we have to find it in outer subselect(s). - We can't join lists of outer & current select, because of scope - of view rules. For example if both tables (outer & current) have - field 'field' it is not mistake to refer to this field without + We can't join lists of outer & current select, because of scope + of view rules. For example if both tables (outer & current) have + field 'field' it is not mistake to refer to this field without mention of table name, but if we join tables in one list it will cause error ER_NON_UNIQ_ERROR in find_field_in_tables. */ @@ -832,8 +832,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) 0)) != not_found_field) break; if (sl->resolve_mode == SELECT_LEX::SELECT_MODE && - (refer= find_item_in_list(this, sl->item_list, &counter, - REPORT_EXCEPT_NOT_FOUND)) != + (refer= find_item_in_list(this, sl->item_list, &counter, + REPORT_EXCEPT_NOT_FOUND)) != (Item **) not_found_item) break; if (sl->master_unit()->first_select()->linkage == @@ -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; @@ -906,14 +906,14 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) void Item::init_make_field(Send_field *tmp_field, enum enum_field_types field_type) -{ +{ char *empty_name= (char*) ""; - tmp_field->db_name= empty_name; + tmp_field->db_name= empty_name; tmp_field->org_table_name= empty_name; tmp_field->org_col_name= empty_name; tmp_field->table_name= empty_name; tmp_field->col_name= name; - tmp_field->charsetnr= collation.collation->number; + tmp_field->charsetnr= collation.collation->number; tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG; tmp_field->type=field_type; tmp_field->length=max_length; diff --git a/sql/item_func.cc b/sql/item_func.cc index 125f87aecec..ff0a1df2e79 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2561,7 +2561,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; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 1d7dd3aa5bb..da65418620c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -30,9 +30,114 @@ #undef write /* remove pthread.h macro definition for EMX */ #endif -typedef ulonglong table_map; /* Used for table bits in join */ -typedef ulong key_map; /* Used for finding keys */ -typedef ulong key_part_map; /* Used for finding key parts */ +template 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 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 @@ -617,8 +722,8 @@ 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 &items, uint *counter, find_item_error_report_type report_error); -key_map get_key_map_from_key_list(TABLE *table, - List *index_list); +void get_key_map_from_key_list(key_map *map, TABLE *table, + List *index_list); bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator *it); @@ -626,7 +731,7 @@ bool setup_tables(TABLE_LIST *tables); int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, List *sum_func_list, uint wild_num); int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, - List &item, bool set_query_id, + List &item, bool set_query_id, List *sum_func_list, bool allow_sum_func); int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); int setup_ftfuncs(SELECT_LEX* select); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 854fae4f15f..5e90c41b07f 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2100,7 +2100,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; } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 5b1e2c98001..7b1894f42d8 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -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) @@ -661,7 +660,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables, key_parts->null_bit= key_info->key_part[part].null_bit; if (key_parts->field->type() == FIELD_TYPE_BLOB) key_parts->part_length+=HA_KEY_BLOB_LENGTH; - key_parts->image_type = + key_parts->image_type = (key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW; } param.real_keynr[param.keys++]=idx; @@ -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(¶m, 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 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)) diff --git a/sql/opt_range.h b/sql/opt_range.h index 00736bfc22f..4931f6f007e 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -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); diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 34cce98d087..932aceebdbb 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -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); @@ -696,7 +696,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, return 0; } - + /* Check whether found key is in range specified by conditions @@ -707,7 +707,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, field in: Field used the MIN/MAX expression cond in: WHERE condition range_fl in: Says whether there is a condition to to be checked - prefix_len in: Length of the constant part of the key + prefix_len in: Length of the constant part of the key RETURN 0 ok diff --git a/sql/slave.cc b/sql/slave.cc index 641707aab2f..896d11361d7 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -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); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1e44aa6e46d..d417e9a50db 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1678,7 +1678,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, goto found; } } - if (allow_rowid && + if (allow_rowid && !my_strcasecmp(system_charset_info, name, "_rowid") && (field=table->rowid_field)) goto found; @@ -1691,7 +1691,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; @@ -1718,7 +1718,7 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, RETURN VALUES 0 Field is not found or field is not unique- error message is reported - not_found_field Function was called with report_error == FALSE and + not_found_field Function was called with report_error == FALSE and field was not found. no error message reported. found field */ @@ -2027,21 +2027,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; @@ -2059,24 +2059,26 @@ bool setup_tables(TABLE_LIST *tables) } -key_map get_key_map_from_key_list(TABLE *table, - List *index_list) +void get_key_map_from_key_list(key_map *map, TABLE *table, + List *index_list) { - key_map map=0; List_iterator_fast 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; } /**************************************************************************** @@ -2120,7 +2122,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; @@ -2211,8 +2213,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; } } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 48ef5b4b74c..bd76cbd5f36 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -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) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ff41e9fd067..1ba2f52c318 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -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, @@ -820,7 +823,7 @@ JOIN::optimize() conds, 1))); } - + } /* Need to tell Innobase that to play it safe, it should fetch all @@ -1547,7 +1550,7 @@ err: JOIN *curr_join= (join->need_tmp&&join->tmp_join? (join->tmp_join->error=join->error,join->tmp_join): join); - + thd->proc_info="end"; err= join->cleanup(); if (thd->net.report_error) @@ -1564,7 +1567,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"); @@ -1626,9 +1629,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); @@ -1774,24 +1781,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) { @@ -1847,7 +1855,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; @@ -2084,9 +2092,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: @@ -2105,7 +2114,7 @@ add_key_field(KEY_FIELD **key_fields,uint and_level, for (uint i=0; iconst_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. @@ -2236,14 +2245,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) { @@ -2255,7 +2263,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 @@ -2446,7 +2454,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); @@ -2587,7 +2595,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; @@ -2656,7 +2664,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 { @@ -2680,7 +2688,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/ @@ -2707,7 +2715,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 @@ -2759,7 +2767,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/ @@ -2798,7 +2806,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; @@ -2991,7 +2999,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) @@ -3222,7 +3230,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; @@ -3304,13 +3312,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 { @@ -3321,12 +3329,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 /* @@ -3336,9 +3345,9 @@ 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 && - join->unit->select_limit_cnt < + 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))) { @@ -3376,13 +3385,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; @@ -3447,7 +3458,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; @@ -3465,7 +3476,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; @@ -3540,12 +3551,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); @@ -3891,7 +3902,7 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, DBUG_ENTER("return_zero_rows"); if (select_options & SELECT_DESCRIBE) - { + { select_describe(join, false, false, false, info); DBUG_RETURN(0); } @@ -4619,6 +4630,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &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 */ @@ -5812,7 +5829,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; @@ -5849,7 +5866,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; @@ -6547,18 +6564,21 @@ 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 (table->key_info[nr].key_length < min_length) + if (usable_keys.is_set(nr)) { - min_length=table->key_info[nr].key_length; - best=nr; + if (table->key_info[nr].key_length < min_length) + { + min_length=table->key_info[nr].key_length; + best=nr; + } } } } @@ -6604,7 +6624,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; @@ -6612,10 +6632,10 @@ test_if_subkey(ORDER *order, TABLE *table, uint ref, uint ref_key_parts, uint not_used; 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, @@ -6653,15 +6673,16 @@ 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; } - usable_keys&=((Item_field*) (*tmp_order->item))->field->part_of_sortkey; + usable_keys.intersect( + ((Item_field*) (*tmp_order->item))->field->part_of_sortkey); } ref_key= -1; @@ -6686,7 +6707,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 @@ -6696,8 +6717,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) { @@ -6713,10 +6734,10 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, select->quick->init(); } ref_key= new_ref_key; - } + } } /* 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))) { @@ -6767,7 +6788,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 @@ -6775,12 +6796,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, ¬_used))) @@ -6792,7 +6820,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); @@ -6817,7 +6845,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, order How table should be sorted filesort_limit Max number of rows that needs to be sorted select_limit Max number of rows in final output - Used to decide if we should use index or not + Used to decide if we should use index or not IMPLEMENTATION @@ -8646,7 +8674,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, Item *item_null= new Item_null(); CHARSET_INFO *cs= &my_charset_latin1; DBUG_ENTER("select_describe"); - DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s", + DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s", (ulong)join->select_lex, join->select_lex->type, message)); /* Don't log this into the slow query log */ @@ -8680,7 +8708,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, tmp2.length(0); item_list.empty(); - item_list.push_back(new Item_int((int32) + item_list.push_back(new Item_int((int32) join->select_lex->select_number)); item_list.push_back(new Item_string(join->select_lex->type, strlen(join->select_lex->type), @@ -8702,21 +8730,23 @@ 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) - { - if (tmp1.length()) - tmp1.append(','); - tmp1.append(table->key_info[j].name); - } + 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 - item_list.push_back(item_null); + item_list.push_back(item_null); if (tab->ref.key_parts) { KEY *key_info=table->key_info+ tab->ref.key; @@ -8759,10 +8789,9 @@ 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) item_list.push_back(new Item_string(tab->info,strlen(tab->info),cs)); else @@ -8771,8 +8800,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 diff --git a/sql/sql_select.h b/sql/sql_select.h index 6c17a646ee6..aa77722546d 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -29,8 +29,8 @@ typedef struct keyuse_t { Item *val; /* or value if no field */ table_map used_tables; uint key, keypart, optimize; - key_map keypart_map; - ha_rows ref_table_rows; + key_part_map keypart_map; + ha_rows ref_table_rows; } KEYUSE; class store_key; @@ -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; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8ea78e702e5..01178afa0b0 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -930,7 +930,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); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index d2f97640010..37f7942f0e5 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -174,10 +174,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, diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b322957b20b..3942e783a64 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -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(); want_privilege=table->grant.want_privilege; table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); @@ -143,7 +143,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) @@ -158,7 +158,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) @@ -186,7 +186,7 @@ int mysql_update(THD *thd, matching rows before updating the table! */ table->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE); - 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); @@ -524,7 +524,7 @@ int multi_update::prepare(List ¬_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; } } diff --git a/sql/table.cc b/sql/table.cc index 986a82cf9d2..a2518ce6a91 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -157,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); @@ -486,8 +491,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)) @@ -547,7 +552,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)) { @@ -555,11 +560,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) @@ -602,7 +607,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; /* From 5742f29a01873dc61d3ac9d66cc934e813802329 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Tue, 14 Oct 2003 16:19:13 +0200 Subject: [PATCH 07/23] "phrase search" should not match partial words (it should not match 'paraphrase searches') --- myisam/ft_boolean_search.c | 29 +++++++++++++++++++---------- myisam/ft_parser.c | 9 --------- myisam/ftdefs.h | 5 +++-- mysql-test/r/fulltext.result | 3 ++- mysql-test/t/fulltext.test | 1 + 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index dfefaf621c9..104acf02324 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -391,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 ~= /\/ */ 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; diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 14c67333734..57b379cfac0 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -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 diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index 88d7e79937b..c0a19262dcf 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -22,8 +22,9 @@ #include #include -#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 diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index e2d35973383..83c77949e2c 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -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 diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 8c6bb97edf1..5e5d64ced82 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -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: From 261831ddea41c0fa7dac4fb624f3c2b9d4f6d129 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Tue, 14 Oct 2003 16:26:28 +0200 Subject: [PATCH 08/23] #ifdef removed comment clarified --- sql/sql_acl.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 82450704ee0..1db544af64c 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3589,13 +3589,16 @@ int mysql_revoke_all(THD *thd, List &list) VOID(pthread_mutex_unlock(&acl_cache->lock)); rw_unlock(&LOCK_grant); close_thread_tables(thd); -#ifdef TO_BE_DELETED - /* XXX this should not be necessary. The error message is already printed */ + + /* 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)); -#endif + DBUG_RETURN(result); } From 50c8b7c13bf991bf4dbc1c4da3da8c2665df4810 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Wed, 15 Oct 2003 13:40:20 +0200 Subject: [PATCH 09/23] stricter checks on FULLTEXT index creating --- include/mysqld_error.h | 5 +- mysql-test/r/fulltext.result | 6 ++ mysql-test/r/mysqldump.result | 3 - mysql-test/t/fulltext.test | 7 ++ sql/share/czech/errmsg.txt | 1 + sql/share/danish/errmsg.txt | 1 + sql/share/dutch/errmsg.txt | 1 + sql/share/english/errmsg.txt | 4 +- sql/share/estonian/errmsg.txt | 1 + sql/share/french/errmsg.txt | 1 + sql/share/german/errmsg.txt | 1 + sql/share/greek/errmsg.txt | 1 + sql/share/hungarian/errmsg.txt | 1 + sql/share/italian/errmsg.txt | 1 + sql/share/japanese/errmsg.txt | 1 + sql/share/korean/errmsg.txt | 1 + sql/share/norwegian-ny/errmsg.txt | 1 + sql/share/norwegian/errmsg.txt | 1 + sql/share/polish/errmsg.txt | 1 + sql/share/portuguese/errmsg.txt | 1 + sql/share/romanian/errmsg.txt | 1 + sql/share/russian/errmsg.txt | 1 + sql/share/serbian/errmsg.txt | 1 + sql/share/slovak/errmsg.txt | 1 + sql/share/spanish/errmsg.txt | 1 + sql/share/swedish/errmsg.txt | 1 + sql/share/ukrainian/errmsg.txt | 1 + sql/sql_table.cc | 136 ++++++++++++++++++------------ 28 files changed, 121 insertions(+), 62 deletions(-) diff --git a/include/mysqld_error.h b/include/mysqld_error.h index 3c20202603f..8a75ccffe8c 100644 --- a/include/mysqld_error.h +++ b/include/mysqld_error.h @@ -230,7 +230,7 @@ #define ER_NO_PERMISSION_TO_CREATE_USER 1211 #define ER_UNION_TABLES_IN_DIFFERENT_DIR 1212 #define ER_LOCK_DEADLOCK 1213 -#define ER_TABLE_CANT_HANDLE_FULLTEXT 1214 +#define ER_TABLE_CANT_HANDLE_FT 1214 #define ER_CANNOT_ADD_FOREIGN 1215 #define ER_NO_REFERENCED_ROW 1216 #define ER_ROW_IS_REFERENCED 1217 @@ -295,4 +295,5 @@ #define ER_BAD_SLAVE_UNTIL_COND 1276 #define ER_MISSING_SKIP_SLAVE 1277 #define ER_UNTIL_COND_IGNORED 1278 -#define ER_ERROR_MESSAGES 279 +#define ER_BAD_FT_COLUMN 1279 +#define ER_ERROR_MESSAGES 280 diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 83c77949e2c..87416ae97eb 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -191,6 +191,12 @@ ticket inhalt select * from t2 having MATCH inhalt AGAINST ('foobar'); ticket inhalt 3 foobar +CREATE TABLE t3 (t int(11),i text,fulltext tix (t,i)); +ERROR HY000: Column 't' cannot be part of FULLTEXT index +CREATE TABLE t3 (t int(11),i text, +j varchar(200) CHARACTER SET latin2, +fulltext tix (i,j)); +ERROR HY000: Column 'j' cannot be part of FULLTEXT index CREATE TABLE t3 ( ticket int(11), inhalt text, diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index cf1ef55ca69..085cf2788f9 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -4,8 +4,6 @@ INSERT INTO t1 VALUES (1), (2); -DROP TABLE IF EXISTS t1; -LOCK TABLES t1 WRITE; 1 @@ -14,7 +12,6 @@ LOCK TABLES t1 WRITE; 2
-UNLOCK TABLES;
DROP TABLE t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 5e5d64ced82..04b0c1e6afd 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -130,6 +130,13 @@ select * from t2 having MATCH inhalt AGAINST ('foobar'); # check of fulltext errors # +--error 1279 +CREATE TABLE t3 (t int(11),i text,fulltext tix (t,i)); +--error 1279 +CREATE TABLE t3 (t int(11),i text, + j varchar(200) CHARACTER SET latin2, + fulltext tix (i,j)); + CREATE TABLE t3 ( ticket int(11), inhalt text, diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index e7cc54746b5..74027e78c31 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -291,3 +291,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 379865a775b..aa93758bc8b 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -285,3 +285,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index ffe76be0d42..963f040ae86 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -293,3 +293,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index c352b143ef1..7fb93e70e04 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -277,8 +277,10 @@ character-set=latin1 "Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)", "Unknown collation: '%-.64s'", "SSL parameters in CHANGE MASTER are ignored because this MySQL slave was compiled without SSL support. They can be used later when MySQL slave with SSL will be started." -"Server is running in --secure-auth mode, but '%s@%s' has a password in the old format; please change the password to the new format", +"Server is running in --secure-auth mode, but '%s'@'%s' has a password in the old format; please change the password to the new format", "Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d", "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" +"Column '%-.64s' cannot be part of FULLTEXT index" + diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 657c5a24539..91f530585de 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -287,3 +287,4 @@ character-set=latin7 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index ab7936aff48..6ab9529e88d 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -282,3 +282,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index f50169251f7..7750b5292fd 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -294,3 +294,4 @@ character-set=latin1 "Falscher Parameter oder falsche Kombination von Parametern für START SLAVE UNTIL", "Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn der Slave-Server unerwartet neu startet", "SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert" + diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 93f78bf2a93..46fb9ab2425 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -282,3 +282,4 @@ character-set=greek "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index f12fbbc938b..ddf6b3b5347 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -284,3 +284,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 8d44a83ed3b..9043bd009c6 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -282,3 +282,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index dcd3db0d7a9..35e8529070b 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -284,3 +284,4 @@ character-set=ujis "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 363d81e4dea..84e1030c188 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -282,3 +282,4 @@ character-set=euckr "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index e2427327c77..12c697c7019 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -284,3 +284,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 7083bd80085..916f44b10be 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -284,3 +284,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index f770b2e3030..a9ee2b490ed 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -286,3 +286,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 3c265349cdf..b2de951fa31 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -283,3 +283,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index c1c495d39c3..217743e2542 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -286,3 +286,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 572d515453a..6456a585585 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -284,3 +284,4 @@ character-set=koi8r "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index a81b5f56838..a350ab82a98 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -277,3 +277,4 @@ character-set=cp1250 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 6ca9bcecf1c..711a7ec2fb9 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -290,3 +290,4 @@ character-set=latin2 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index 62d32757719..9c8cf5fceab 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -284,3 +284,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index f06a760bb24..95b44366fdf 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -282,3 +282,4 @@ character-set=latin1 "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 675e9899d58..38d0b05a37f 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -287,3 +287,4 @@ character-set=koi8u "Wrong parameter or combination of parameters for START SLAVE UNTIL" "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" + diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9de4ef1a1ac..46dc1191ef8 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -424,7 +424,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, if (!sql_field->charset) sql_field->charset= create_info->table_charset; sql_field->create_length_to_internal_length(); - + /* Don't pack keys in old tables if the user has requested this */ if ((sql_field->flags & BLOB_FLAG) || sql_field->sql_type == FIELD_TYPE_VAR_STRING && @@ -663,12 +663,11 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, key_info->usable_key_parts= key_number; key_info->algorithm=key->algorithm; - /* TODO: Add proper checks if handler supports key_type and algorithm */ if (key->type == Key::FULLTEXT) { if (!(file->table_flags() & HA_CAN_FULLTEXT)) { - my_error(ER_TABLE_CANT_HANDLE_FULLTEXT, MYF(0)); + my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0)); DBUG_RETURN(-1); } } @@ -680,6 +679,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, checking for proper key parts number: */ + /* TODO: Add proper checks if handler supports key_type and algorithm */ if (key_info->flags == HA_SPATIAL) { if (key_info->key_parts != 1) @@ -704,6 +704,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } List_iterator cols(key->columns); + CHARSET_INFO *ft_key_charset=0; // for FULLTEXT for (uint column_nr=0 ; (column=cols++) ; column_nr++) { it.rewind(); @@ -727,64 +728,87 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, from a data prefix, ignoring column->length). */ if (key->type == Key::FULLTEXT) + { + if ((sql_field->sql_type != FIELD_TYPE_STRING && + sql_field->sql_type != FIELD_TYPE_VAR_STRING && + !f_is_blob(sql_field->pack_flag)) || + sql_field->charset == &my_charset_bin || + (ft_key_charset && sql_field->charset != ft_key_charset)) + { + my_printf_error(ER_BAD_FT_COLUMN,ER(ER_BAD_FT_COLUMN),MYF(0), + column->field_name); + DBUG_RETURN(-1); + } + ft_key_charset=sql_field->charset; + /* + for fulltext keys keyseg length is 1 for blobs (it's ignored in ft + code anyway, and 0 (set to column width later) for char's. it has + to be correct col width for char's, as char data are not prefixed + with length (unlike blobs, where ft code takes data length from a + data prefix, ignoring column->length). + */ column->length=test(f_is_blob(sql_field->pack_flag)); + } else + { column->length*= sql_field->charset->mbmaxlen; - if (f_is_blob(sql_field->pack_flag)) - { - if (!(file->table_flags() & HA_BLOB_KEY)) - { - my_printf_error(ER_BLOB_USED_AS_KEY,ER(ER_BLOB_USED_AS_KEY),MYF(0), - column->field_name); - DBUG_RETURN(-1); - } - if (!column->length) - { - my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH, - ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0), - column->field_name); - DBUG_RETURN(-1); - } - } - if (key->type == Key::SPATIAL) - { - if (!column->length ) - { - /* - BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case - Lately we'll extend this code to support more dimensions - */ - column->length=4*sizeof(double); - } - } - if (!(sql_field->flags & NOT_NULL_FLAG)) - { - if (key->type == Key::PRIMARY) - { - /* Implicitly set primary key fields to NOT NULL for ISO conf. */ - sql_field->flags|= NOT_NULL_FLAG; - sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL; - } - else - key_info->flags|= HA_NULL_PART_KEY; - if (!(file->table_flags() & HA_NULL_KEY)) - { - my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX), - MYF(0),column->field_name); - DBUG_RETURN(-1); - } - if (key->type == Key::SPATIAL) - { - my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0)); - DBUG_RETURN(-1); - } - } - if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) - { - if (column_nr == 0 || (file->table_flags() & HA_AUTO_PART_KEY)) - auto_increment--; // Field is used + if (f_is_blob(sql_field->pack_flag)) + { + if (!(file->table_flags() & HA_BLOB_KEY)) + { + my_printf_error(ER_BLOB_USED_AS_KEY,ER(ER_BLOB_USED_AS_KEY),MYF(0), + column->field_name); + DBUG_RETURN(-1); + } + if (!column->length) + { + my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH, + ER(ER_BLOB_KEY_WITHOUT_LENGTH),MYF(0), + column->field_name); + DBUG_RETURN(-1); + } + } + if (key->type == Key::SPATIAL) + { + if (!column->length ) + { + /* + BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case + Lately we'll extend this code to support more dimensions + */ + column->length=4*sizeof(double); + } + } + if (!(sql_field->flags & NOT_NULL_FLAG)) + { + if (key->type == Key::PRIMARY) + { + /* Implicitly set primary key fields to NOT NULL for ISO conf. */ + sql_field->flags|= NOT_NULL_FLAG; + sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL; + } + else + key_info->flags|= HA_NULL_PART_KEY; + if (!(file->table_flags() & HA_NULL_KEY)) + { + my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX), + MYF(0),column->field_name); + DBUG_RETURN(-1); + } + if (key->type == Key::SPATIAL) + { + my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0)); + DBUG_RETURN(-1); + } + } + if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) + { + if (column_nr == 0 || (file->table_flags() & HA_AUTO_PART_KEY)) + auto_increment--; // Field is used + } } + key_part_info->fieldnr= field; key_part_info->offset= (uint16) sql_field->offset; key_part_info->key_type=sql_field->pack_flag; From 0ee817e737f79c91a44cbcdf018b97a2486df3aa Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Wed, 15 Oct 2003 18:05:04 +0200 Subject: [PATCH 10/23] cleanup --- myisam/ft_update.c | 12 +++++------- myisam/ftdefs.h | 2 +- myisam/mi_check.c | 3 +-- mysys/Makefile.am | 2 +- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/myisam/ft_update.c b/myisam/ft_update.c index 8423b6898cd..79892f54002 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -114,9 +114,7 @@ uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record) DBUG_RETURN(0); } -FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, - byte *keybuf __attribute__((unused)), - const byte *record) +FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, const byte *record) { TREE ptree; DBUG_ENTER("_mi_ft_parserecord"); @@ -199,9 +197,9 @@ int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf, int cmp, cmp2; DBUG_ENTER("_mi_ft_update"); - if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, keybuf, oldrec))) + if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, oldrec))) goto err0; - if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, keybuf, newrec))) + if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, newrec))) goto err1; error=0; @@ -249,7 +247,7 @@ int _mi_ft_add(MI_INFO *info, uint keynr, byte *keybuf, const byte *record, FT_WORD *wlist; DBUG_ENTER("_mi_ft_add"); - if ((wlist=_mi_ft_parserecord(info, keynr, keybuf, record))) + if ((wlist=_mi_ft_parserecord(info, keynr, record))) { error=_mi_ft_store(info,keynr,keybuf,wlist,pos); my_free((char*) wlist,MYF(0)); @@ -268,7 +266,7 @@ int _mi_ft_del(MI_INFO *info, uint keynr, byte *keybuf, const byte *record, DBUG_ENTER("_mi_ft_del"); DBUG_PRINT("enter",("keynr: %d",keynr)); - if ((wlist=_mi_ft_parserecord(info, keynr, keybuf, record))) + if ((wlist=_mi_ft_parserecord(info, keynr, record))) { error=_mi_ft_erase(info,keynr,keybuf,wlist,pos); my_free((char*) wlist,MYF(0)); diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index c0a19262dcf..5b260ceb10b 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -124,7 +124,7 @@ uint _mi_ft_segiterator(FT_SEG_ITERATOR *); void ft_parse_init(TREE *, CHARSET_INFO *); int ft_parse(TREE *, byte *, int); FT_WORD * ft_linearize(TREE *); -FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, byte *, const byte *); +FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *); uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record); extern const struct _ft_vft _ft_vft_nlq; diff --git a/myisam/mi_check.c b/myisam/mi_check.c index ceac8f6356c..a6ce3a9c87b 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -2575,8 +2575,7 @@ static int sort_ft_key_read(MI_SORT_PARAM *sort_param, void *key) my_free((char*) wptr, MYF(MY_ALLOW_ZERO_PTR)); if ((error=sort_get_next_record(sort_param))) DBUG_RETURN(error); - if (!(wptr=_mi_ft_parserecord(info,sort_param->key, - key,sort_param->record))) + if (!(wptr=_mi_ft_parserecord(info,sort_param->key,sort_param->record))) DBUG_RETURN(1); if (wptr->pos) break; diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 6ec1e1ec40d..5ff682fbc80 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -39,7 +39,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \ my_symlink.c my_symlink2.c \ mf_pack.c mf_unixpath.c mf_strip.c \ - mf_soundex.c mf_wcomp.c mf_wfile.c \ + mf_wcomp.c mf_wfile.c \ mf_qsort.c mf_qsort2.c mf_sort.c \ ptr_cmp.c mf_radix.c queues.c \ tree.c list.c hash.c array.c string.c typelib.c \ From b3ca82ee2101076049f01b7bcd62fac4ad1d1595 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Wed, 15 Oct 2003 19:01:47 +0200 Subject: [PATCH 11/23] get rid of default_charset_info for index fulltext searches --- myisam/ft_boolean_search.c | 8 ++++---- myisam/ft_parser.c | 20 +++++++++----------- myisam/ft_stopwords.c | 2 +- myisam/ftdefs.h | 4 ++-- 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 104acf02324..0b97eded872 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -144,7 +144,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, param.prev=' '; param.quot=up->quot; - while ((res=ft_get_word(start,end,&w,¶m))) + while ((res=ft_get_word(ftb->charset,start,end,&w,¶m))) { int r=param.plusminus; float weight= (float) (param.pmsign ? nwghts : wghts)[(r>5)?5:((r<-5)?-5:r)]; @@ -354,8 +354,7 @@ FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, ftb->info=info; ftb->keynr=keynr; ftb->charset= ((keynr==NO_SUCH_KEY) ? - default_charset_info : - info->s->keyinfo[keynr].seg->charset); + default_charset_info : info->s->keyinfo[keynr].seg->charset); ftb->with_scan=0; ftb->lastpos=HA_POS_ERROR; bzero(& ftb->no_dupes, sizeof(TREE)); @@ -609,7 +608,8 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) continue; end=ftsi.pos+ftsi.len; - while (ft_simple_get_word((byte **) &ftsi.pos,(byte *) end, &word)) + while (ft_simple_get_word(ftb->charset, + (byte **) &ftsi.pos, (byte *) end, &word)) { int a, b, c; for (a=0, b=ftb->queue.elements, c=(a+b)/2; b-a>1; c=(a+b)/2) diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 57b379cfac0..2cd6afdcbc2 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -79,7 +79,8 @@ FT_WORD * ft_linearize(TREE *wtree) * 2 - left bracket * 3 - right bracket */ -byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param) +byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, + FT_WORD *word, FTB_PARAM *param) { byte *doc=*start; int mwc; @@ -91,11 +92,7 @@ byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param) { for (;docquot) { param->quot=doc; *start=doc+1; @@ -125,7 +122,7 @@ byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param) mwc=0; for (word->pos=doc; docpos=doc; doccustom_arg, &doc,end,&w)) { if (!tree_insert(wtree, &w, 0, wtree->custom_arg)) goto err; diff --git a/myisam/ft_stopwords.c b/myisam/ft_stopwords.c index 5163aca60bd..6682de18c65 100644 --- a/myisam/ft_stopwords.c +++ b/myisam/ft_stopwords.c @@ -81,7 +81,7 @@ int ft_init_stopwords() goto err0; len=my_read(fd, buffer, len, MYF(MY_WME)); end=start+len; - while (ft_simple_get_word(&start, end, &w)) + while (ft_simple_get_word(default_charset_info, &start, end, &w)) { if (ft_add_stopword(my_strdup_with_length(w.pos, w.len, MYF(0)))) goto err1; diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index 5b260ceb10b..6e71f20e17c 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -108,8 +108,8 @@ int is_stopword(char *word, uint len); uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t); -byte ft_get_word(byte **, byte *, FT_WORD *, FTB_PARAM *); -byte ft_simple_get_word(byte **, byte *, FT_WORD *); +byte ft_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *, FTB_PARAM *); +byte ft_simple_get_word(CHARSET_INFO *, byte **, byte *, FT_WORD *); typedef struct _st_ft_seg_iterator { uint num, len; From 4aa99ff7b12896920505c6478b2f6cfeec93bc76 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 16 Oct 2003 21:21:48 +0200 Subject: [PATCH 12/23] fixes for new key_map code --- sql/ha_berkeley.cc | 36 ++++++++++++++++++++---------------- sql/ha_berkeley.h | 2 +- sql/mysql_priv.h | 2 +- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index b2e1ef2fe61..bac037dcfc7 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -884,12 +884,12 @@ int ha_berkeley::write_row(byte * record) DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */ new_error=txn_abort(sub_trans); /* purecov: deadcode */ } - else if (changed_keys) + else if (!changed_keys.is_clear_all()) { new_error = 0; - for (uint keynr=0; changed_keys; keynr++, changed_keys >>= 1) + for (uint keynr=0; keynr < changed_keys.length(); keynr++) { - if (changed_keys & 1) + if (changed_keys.is_set(keynr)) { if ((new_error = remove_key(sub_trans, keynr, record, &prim_key))) @@ -1033,18 +1033,22 @@ int ha_berkeley::restore_keys(DB_TXN *trans, key_map changed_keys, rolled back. The last key set in changed_keys is the one that triggered the duplicate key error (it wasn't inserted), so for that one just put back the old value. */ - for (keynr=0; changed_keys; keynr++, changed_keys >>= 1) + if (!changed_keys.is_clear_all()) { - if (changed_keys & 1) + key_map map1(1); + for (keynr=0; keynr < changed_keys.length(); keynr++) { - if (changed_keys != 1 && - (error = remove_key(trans, keynr, new_row, new_key))) - break; /* purecov: inspected */ - if ((error = key_file[keynr]->put(key_file[keynr], trans, - create_key(&tmp_key, keynr, key_buff2, - old_row), - old_key, key_type[keynr]))) - break; /* purecov: inspected */ + if (changed_keys.is_set(keynr)) + { + if (changed_keys.is_subset(map1) && + (error = remove_key(trans, keynr, new_row, new_key))) + break; /* purecov: inspected */ + if ((error = key_file[keynr]->put(key_file[keynr], trans, + create_key(&tmp_key, keynr, key_buff2, + old_row), + old_key, key_type[keynr]))) + break; /* purecov: inspected */ + } } } @@ -1146,7 +1150,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */ new_error=txn_abort(sub_trans); /* purecov: deadcode */ } - else if (changed_keys) + else if (!changed_keys.is_clear_all()) new_error=restore_keys(transaction, changed_keys, primary_key, old_row, &old_prim_key, new_row, &prim_key, thd_options); @@ -1231,9 +1235,9 @@ int ha_berkeley::remove_keys(DB_TXN *trans, const byte *record, DBT *new_record, DBT *prim_key, key_map keys) { int result = 0; - for (uint keynr=0; keys; keynr++, keys>>=1) + for (uint keynr=0; keynr < keys.length(); keynr++) { - if (keys & 1) + if (keys.is_set(keynr)) { int new_error=remove_key(trans, keynr, record, prim_key); if (new_error) diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index 471145c96bf..850be48258a 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -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;} - const 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); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 05cb026ad66..72e9bbf5bb7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -99,7 +99,7 @@ public: template <> class Bitmap<64> { - longlong map; + ulonglong map; public: Bitmap(uint prefix_to_set=0) { set_prefix(prefix_to_set); } Bitmap<64>& init() { return *this; } From c9640c592a3faa99a0a7cc0f3ec02b04ed462a68 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 17 Oct 2003 13:17:15 +0200 Subject: [PATCH 13/23] uninitialized variable on Windows fixed --- vio/viosocket.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/vio/viosocket.c b/vio/viosocket.c index f631dca5268..31941a64102 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -192,7 +192,7 @@ vio_should_retry(Vio * vio __attribute__((unused))) int vio_close(Vio * vio) { - int r; + int r=0; DBUG_ENTER("vio_close"); #ifdef __WIN__ if (vio->type == VIO_TYPE_NAMEDPIPE) @@ -206,7 +206,6 @@ int vio_close(Vio * vio) else if (vio->type != VIO_CLOSED) #endif /* __WIN__ */ { - r=0; if (shutdown(vio->sd,2)) r= -1; if (closesocket(vio->sd)) @@ -369,9 +368,9 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size) remain_local = size; current_postion=buf; - do + do { - if (vio->shared_memory_remain == 0) + if (vio->shared_memory_remain == 0) { if (WaitForSingleObject(vio->event_server_wrote,vio->net->read_timeout*1000) != WAIT_OBJECT_0) { @@ -384,9 +383,9 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size) length = size; - if (vio->shared_memory_remain < length) + if (vio->shared_memory_remain < length) length = vio->shared_memory_remain; - if (length > remain_local) + if (length > remain_local) length = remain_local; memcpy(current_postion,vio->shared_memory_pos,length); @@ -396,7 +395,7 @@ int vio_read_shared_memory(Vio * vio, gptr buf, int size) current_postion+=length; remain_local-=length; - if (!vio->shared_memory_remain) + if (!vio->shared_memory_remain) if (!SetEvent(vio->event_client_read)) DBUG_RETURN(-1); } while (remain_local); length = size; @@ -419,11 +418,11 @@ int vio_write_shared_memory(Vio * vio, const gptr buf, int size) remain = size; current_postion = buf; - while (remain != 0) + while (remain != 0) { if (WaitForSingleObject(vio->event_server_read,vio->net->write_timeout*1000) != WAIT_OBJECT_0) { - DBUG_RETURN(-1); + DBUG_RETURN(-1); }; sz = remain > shared_memory_buffer_length ? shared_memory_buffer_length: remain; From c60ef8160f7ed3202d4a9f446e4b4de77e16fe6e Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Mon, 20 Oct 2003 15:53:48 +0200 Subject: [PATCH 14/23] FULLTEXT: correct charset support (UTF included, UCS2 - not) code cleanup --- include/m_ctype.h | 1 + mysql-test/r/fulltext.result | 21 ++++++++++ mysql-test/t/fulltext.test | 18 +++++++++ sql/item_cmpfunc.h | 1 - sql/item_func.cc | 75 +++++++++++++++++------------------- sql/item_func.h | 30 ++++++--------- sql/sql_table.cc | 1 + sql/sql_yacc.yy | 18 +++++---- strings/ctype-bin.c | 26 ++++++++----- strings/ctype-latin1.c | 4 +- strings/ctype-simple.c | 2 +- strings/ctype-tis620.c | 2 +- strings/ctype-utf8.c | 8 ++-- 13 files changed, 121 insertions(+), 86 deletions(-) diff --git a/include/m_ctype.h b/include/m_ctype.h index b1557e5293b..f39cbf8b659 100644 --- a/include/m_ctype.h +++ b/include/m_ctype.h @@ -310,6 +310,7 @@ int my_wildcmp_8bit(CHARSET_INFO *, uint my_numchars_8bit(CHARSET_INFO *, const char *b, const char *e); uint my_charpos_8bit(CHARSET_INFO *, const char *b, const char *e, uint pos); +int my_mbcharlen_8bit(CHARSET_INFO *, uint c); /* Functions for multibyte charsets */ diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 87416ae97eb..63338869fdd 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -279,3 +279,24 @@ select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against(' t1_id name t2_id t1_id name 1 data1 1 1 xxfoo drop table t1,t2; +SET NAMES latin1; +CREATE TABLE t1 (t text character set utf8 not null, fulltext(t)); +INSERT t1 VALUES ('Mit freundlichem Grüß'), ('aus Osnabrück'); +SET NAMES koi8r; +INSERT t1 VALUES ("üÔÏ ÍÙ - ÏÐÉÌËÉ"),("ïÔÌÅÚØ, ÇÎÉÄÁ!"), +("îÅ ×ÌÅÚÁÊ, ÕÂØÅÔ!"),("É ÂÕÄÅÔ ÐÒÁ×!"); +SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('ïðéìëé'); +t charset(t) +üÔÏ ÍÙ - ÏÐÉÌËÉ utf8 +SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('ðÒá*' IN BOOLEAN MODE); +t charset(t) +É ÂÕÄÅÔ ÐÒÁ×! utf8 +SELECT * FROM t1 WHERE MATCH t AGAINST ('ÜÔÏ' IN BOOLEAN MODE); +t +SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrück'); +t charset(t) +SET NAMES latin1; +SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrück'); +t charset(t) +aus Osnabrück utf8 +DROP TABLE t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 04b0c1e6afd..56a27c83cf1 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -226,3 +226,21 @@ insert into t2 values (2, 1, 'xxbar'); insert into t2 values (3, 1, 'xxbuz'); select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode); drop table t1,t2; + +# +# UTF8 +# +SET NAMES latin1; +CREATE TABLE t1 (t text character set utf8 not null, fulltext(t)); +INSERT t1 VALUES ('Mit freundlichem Grüß'), ('aus Osnabrück'); +SET NAMES koi8r; +INSERT t1 VALUES ("üÔÏ ÍÙ - ÏÐÉÌËÉ"),("ïÔÌÅÚØ, ÇÎÉÄÁ!"), + ("îÅ ×ÌÅÚÁÊ, ÕÂØÅÔ!"),("É ÂÕÄÅÔ ÐÒÁ×!"); +SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('ïðéìëé'); +SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('ðÒá*' IN BOOLEAN MODE); +SELECT * FROM t1 WHERE MATCH t AGAINST ('ÜÔÏ' IN BOOLEAN MODE); +SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrück'); +SET NAMES latin1; +SELECT t, charset(t) FROM t1 WHERE MATCH t AGAINST ('Osnabrück'); +DROP TABLE t1; + diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 42b73c48606..41e7060335c 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -647,7 +647,6 @@ class Item_func_in :public Item_int_func ~Item_func_in() { delete array; delete in_item; } optimize_type select_optimize() const { return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; } - Item *key_item() const { return args[0]; } void print(String *str); enum Functype functype() const { return IN_FUNC; } const char *func_name() const { return " IN "; } diff --git a/sql/item_func.cc b/sql/item_func.cc index af9fa692f8b..dde830b61c9 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -81,12 +81,12 @@ bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count) } -bool Item_func::agg_arg_collations_for_comparison(DTCollation &c, +bool Item_func::agg_arg_collations_for_comparison(DTCollation &c, Item **av, uint count) { if (agg_arg_collations(c, av, count)) return TRUE; - + if (c.derivation == DERIVATION_NONE) { my_coll_agg_error(av, count, func_name()); @@ -211,7 +211,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) item= *arg; if (item->maybe_null) maybe_null=1; - + with_sum_func= with_sum_func || item->with_sum_func; used_tables_cache|= item->used_tables(); not_null_tables_cache|= item->not_null_tables(); @@ -2545,9 +2545,13 @@ void Item_func_match::init_search(bool no_order) DBUG_VOID_RETURN; if (key == NO_SUCH_KEY) + { + List fields; + for (uint i=1; i < arg_count; i++) + fields.push_back(args[i]); concat=new Item_func_concat_ws(new Item_string(" ",1, - default_charset_info), - fields); + cmp_collation.collation), fields); + } if (master) { @@ -2559,14 +2563,19 @@ void Item_func_match::init_search(bool no_order) } String *ft_tmp= 0; - char tmp1[FT_QUERY_MAXLEN]; - String tmp2(tmp1,sizeof(tmp1),default_charset_info); // MATCH ... AGAINST (NULL) is meaningless, but possible - if (!(ft_tmp=key_item()->val_str(&tmp2))) + if (!(ft_tmp=key_item()->val_str(&value))) { - ft_tmp= &tmp2; - tmp2.set("",0,default_charset_info); + ft_tmp= &value; + value.set("",0,cmp_collation.collation); + } + + if (ft_tmp->charset() != cmp_collation.collation) + { + search_value.copy(ft_tmp->ptr(), ft_tmp->length(), ft_tmp->charset(), + cmp_collation.collation); + ft_tmp= &search_value; } ft_handler=table->file->ft_init_ext(mode, key, @@ -2583,7 +2592,6 @@ void Item_func_match::init_search(bool no_order) bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { - List_iterator li(fields); Item *item; maybe_null=1; @@ -2595,51 +2603,37 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) modifications to find_best and auto_close as complement to auto_init code above. */ - if (Item_func::fix_fields(thd, tlist, ref) || !const_item()) + if (Item_func::fix_fields(thd, tlist, ref) || !args[0]->const_item()) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST"); return 1; } - while ((item=li++)) + const_item_cache=0; + for (uint i=1 ; i < arg_count ; i++) { - if (item->fix_fields(thd, tlist, li.ref()) || item->check_cols(1)) - return 1; + item=args[i]; if (item->type() == Item::REF_ITEM) - li.replace(item= *((Item_ref *)item)->ref); - if (item->type() != Item::FIELD_ITEM || !item->used_tables()) + args[i]= item= *((Item_ref *)item)->ref; + if (item->type() != Item::FIELD_ITEM) key=NO_SUCH_KEY; used_tables_cache|=item->used_tables(); } /* check that all columns come from the same table */ if (my_count_bits(used_tables_cache) != 1) key=NO_SUCH_KEY; - const_item_cache=0; - table=((Item_field *)fields.head())->field->table; - table->fulltext_searched=1; - record=table->record[0]; if (key == NO_SUCH_KEY && mode != FT_BOOL) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH"); return 1; } - - return 0; -} - -bool Item_func_match::walk(Item_processor processor, byte *arg) -{ - List_iterator_fast li(fields); - Item *item; - while ((item= li++)) - if (item->walk(processor, arg)) - return 1; - return Item_func::walk(processor, arg); + table=((Item_field *)item)->field->table; + table->fulltext_searched=1; + return agg_arg_collations_for_comparison(cmp_collation, args+1, arg_count-1); } bool Item_func_match::fix_index() { - List_iterator_fast li(fields); Item_field *item; uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, keynr; uint max_cnt=0, mkeys=0; @@ -2661,8 +2655,9 @@ bool Item_func_match::fix_index() if (!fts) goto err; - while ((item=(Item_field*)(li++))) + for (uint i=1; i < arg_count; i++) { + item=(Item_field*)args[i]; for (keynr=0 ; keynr < fts ; keynr++) { KEY *ft_key=&table->key_info[ft_to_key[keynr]]; @@ -2696,8 +2691,8 @@ bool Item_func_match::fix_index() for (keynr=0 ; keynr <= mkeys ; keynr++) { - // for now, partial keys won't work. SerG - if (max_cnt < fields.elements || + // partial keys doesn't work + if (max_cnt < arg_count-1 || max_cnt < table->key_info[ft_to_key[keynr]].key_parts) continue; @@ -2712,8 +2707,7 @@ err: key=NO_SUCH_KEY; return 0; } - my_printf_error(ER_FT_MATCHING_KEY_NOT_FOUND, - ER(ER_FT_MATCHING_KEY_NOT_FOUND),MYF(0)); + my_error(ER_FT_MATCHING_KEY_NOT_FOUND,MYF(0)); return 1; } @@ -2759,7 +2753,8 @@ double Item_func_match::val() (byte *)a->ptr(), a->length())); } else - DBUG_RETURN(ft_handler->please->find_relevance(ft_handler, record, 0)); + DBUG_RETURN(ft_handler->please->find_relevance(ft_handler, + table->record[0], 0)); } diff --git a/sql/item_func.h b/sql/item_func.h index 8086e65786d..33609694fe9 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -962,20 +962,18 @@ public: class Item_func_match :public Item_real_func { public: - List fields; - String value; - TABLE *table; - Item_func_match *master; - FT_INFO * ft_handler; - Item *concat; - byte *record; uint key, mode; bool join_key; + DTCollation cmp_collation; + FT_INFO *ft_handler; + TABLE *table; + Item_func_match *master; // for master-slave optimization + Item *concat; // Item_func_concat_ws + String value; // value of concat + String search_value; // key_item()'s value converted to cmp_collation - Item_func_match(List &a, Item *b): Item_real_func(b), - fields(a), table(0), master(0), ft_handler(0), - concat(0), key(0), join_key(0) - {} + Item_func_match(List &a): Item_real_func(a), + table(0), master(0), ft_handler(0), concat(0), key(0), join_key(0) { } ~Item_func_match() { if (!master && ft_handler) @@ -999,17 +997,13 @@ public: bool fix_index(); void init_search(bool no_order); - - bool walk(Item_processor processor, byte *arg); }; class Item_func_match_nl :public Item_func_match { public: - Item_func_match_nl(List &a, Item *b) - :Item_func_match(a,b) - { mode=FT_NL; } + Item_func_match_nl(List &a) :Item_func_match(a) { mode=FT_NL; } const char *func_name() const { return "match_nl"; } }; @@ -1017,9 +1011,7 @@ public: class Item_func_match_bool :public Item_func_match { public: - Item_func_match_bool(List &a, Item *b) - :Item_func_match(a,b) - { mode=FT_BOOL; } + Item_func_match_bool(List &a) :Item_func_match(a) { mode=FT_BOOL; } const char *func_name() const { return "match_bool"; } }; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 46dc1191ef8..5112dfb59cd 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -733,6 +733,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, sql_field->sql_type != FIELD_TYPE_VAR_STRING && !f_is_blob(sql_field->pack_flag)) || sql_field->charset == &my_charset_bin || + sql_field->charset->state & MY_CS_NONTEXT || // ucs2 doesn't work yet (ft_key_charset && sql_field->charset != ft_key_charset)) { my_printf_error(ER_BAD_FT_COLUMN,ER(ER_BAD_FT_COLUMN),MYF(0), diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 51df4e358b4..f7cd22545c5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2446,11 +2446,13 @@ simple_expr: | singlerow_subselect { $$= $1; } | '{' ident expr '}' { $$= $3; } | MATCH ident_list_arg AGAINST '(' expr ')' - { Select->add_ftfunc_to_list((Item_func_match *) - ($$=new Item_func_match_nl(*$2,$5))); } + { $2->push_front($5); + Select->add_ftfunc_to_list((Item_func_match *) + ($$=new Item_func_match_nl(*$2))); } | MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')' - { Select->add_ftfunc_to_list((Item_func_match *) - ($$=new Item_func_match_bool(*$2,$5))); } + { $2->push_front($5); + Select->add_ftfunc_to_list((Item_func_match *) + ($$=new Item_func_match_bool(*$2))); } | ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); } | BINARY expr %prec NEG { @@ -2458,10 +2460,10 @@ simple_expr: 6, &my_charset_latin1)); } | CAST_SYM '(' expr AS cast_type ')' - { - $$= create_func_cast($3, $5, + { + $$= create_func_cast($3, $5, Lex->length ? atoi(Lex->length) : -1, - Lex->charset); + Lex->charset); } | CASE_SYM opt_expr WHEN_SYM when_list opt_else END { $$= new Item_func_case(* $4, $2, $5 ); } @@ -2962,7 +2964,7 @@ ident_list2: opt_expr: /* empty */ { $$= NULL; } - | expr { $$= $1; }; + | expr { $$= $1; }; opt_else: /* empty */ { $$= NULL; } diff --git a/strings/ctype-bin.c b/strings/ctype-bin.c index 340084ad848..cd1b1399506 100644 --- a/strings/ctype-bin.c +++ b/strings/ctype-bin.c @@ -118,6 +118,12 @@ static int my_strcasecmp_bin(CHARSET_INFO * cs __attribute__((unused)), return strcmp(s,t); } +int my_mbcharlen_8bit(CHARSET_INFO *cs __attribute__((unused)), + uint c __attribute__((unused))) +{ + return 1; +} + static int my_mb_wc_bin(CHARSET_INFO *cs __attribute__((unused)), my_wc_t *wc, const unsigned char *str, @@ -264,12 +270,12 @@ static int my_strnxfrm_bin(CHARSET_INFO *cs __attribute__((unused)), static uint my_instr_bin(CHARSET_INFO *cs __attribute__((unused)), - const char *big, uint b_length, + const char *big, uint b_length, const char *small, uint s_length, my_match_t *match, uint nmatch) { register const uchar *str, *search, *end, *search_end; - + if (s_length <= b_length) { if (!s_length) @@ -282,32 +288,32 @@ uint my_instr_bin(CHARSET_INFO *cs __attribute__((unused)), } return 1; /* Empty string is always found */ } - + str= (const uchar*) big; search= (const uchar*) small; end= (const uchar*) big+b_length-s_length+1; search_end= (const uchar*) small + s_length; - + skipp: while (str != end) { if ( (*str++) == (*search)) { register const uchar *i,*j; - - i= str; + + i= str; j= search+1; - + while (j != search_end) if ((*i++) != (*j++)) goto skipp; - + if (nmatch > 0) { match[0].beg= 0; match[0].end= str- (const uchar*)big-1; match[0].mblen= match[0].end; - + if (nmatch > 1) { match[1].beg= match[0].end; @@ -338,7 +344,7 @@ MY_COLLATION_HANDLER my_collation_8bit_bin_handler = static MY_CHARSET_HANDLER my_charset_handler= { NULL, /* ismbchar */ - NULL, /* mbcharlen */ + my_mbcharlen_8bit, /* mbcharlen */ my_numchars_8bit, my_charpos_8bit, my_lengthsp_8bit, diff --git a/strings/ctype-latin1.c b/strings/ctype-latin1.c index a8a5329f844..15798abb85b 100644 --- a/strings/ctype-latin1.c +++ b/strings/ctype-latin1.c @@ -170,14 +170,14 @@ int my_wc_mb_latin1(CHARSET_INFO *cs __attribute__((unused)), { if (str >= end) return MY_CS_TOOSMALL; - + return ((wc < 256) && ((str[0]=uni_latin1[wc]) || (!wc))) ? 1 : MY_CS_ILUNI; } static MY_CHARSET_HANDLER my_charset_handler= { NULL, - NULL, + my_mbcharlen_8bit, my_numchars_8bit, my_charpos_8bit, my_lengthsp_8bit, diff --git a/strings/ctype-simple.c b/strings/ctype-simple.c index f85ce5e7a2b..ed1d2c77049 100644 --- a/strings/ctype-simple.c +++ b/strings/ctype-simple.c @@ -1093,7 +1093,7 @@ skipp: MY_CHARSET_HANDLER my_charset_8bit_handler= { NULL, /* ismbchar */ - NULL, /* mbcharlen */ + my_mbcharlen_8bit, /* mbcharlen */ my_numchars_8bit, my_charpos_8bit, my_lengthsp_8bit, diff --git a/strings/ctype-tis620.c b/strings/ctype-tis620.c index a4d8a7d1f79..fd5e58ad8a7 100644 --- a/strings/ctype-tis620.c +++ b/strings/ctype-tis620.c @@ -717,7 +717,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler = static MY_CHARSET_HANDLER my_charset_handler= { NULL, /* ismbchar */ - NULL, /* mbcharlen */ + my_mbcharlen_8bit, /* mbcharlen */ my_numchars_8bit, my_charpos_8bit, my_lengthsp_8bit, diff --git a/strings/ctype-utf8.c b/strings/ctype-utf8.c index 3ede1aa26f6..b5716c53ea2 100644 --- a/strings/ctype-utf8.c +++ b/strings/ctype-utf8.c @@ -1540,10 +1540,10 @@ static uchar ctype_utf8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0 }; static uchar to_lower_utf8[] = { From abb4c363d3c5c5fa9201f276a1587dd5a012145f Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Mon, 20 Oct 2003 21:32:49 +0200 Subject: [PATCH 15/23] oops forgot to commit ft_parser.c :-[] --- myisam/ft_parser.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 2cd6afdcbc2..d6d1378bdae 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -83,7 +83,7 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, FT_WORD *word, FTB_PARAM *param) { byte *doc=*start; - int mwc; + uint mwc, length; param->yesno=(FTB_YES==' ') ? 1 : (param->quot != 0); param->plusminus=param->pmsign=0; @@ -120,8 +120,8 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, param->plusminus=param->pmsign=0; } - mwc=0; - for (word->pos=doc; docpos=doc; doctrunc=(doclen >= ft_min_word_len && !is_stopword(word->pos, word->len)) - || param->trunc) && word->len < ft_max_word_len) + if (((length >= ft_min_word_len && !is_stopword(word->pos, word->len)) + || param->trunc) && length < ft_max_word_len) { *start=doc; return 1; @@ -146,7 +146,7 @@ byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end, FT_WORD *word) { byte *doc=*start; - int mwc; + uint mwc, length; DBUG_ENTER("ft_simple_get_word"); while (docpos=doc; docpos=doc; doclen= (uint)(doc-word->pos) - mwc; - if (word->len >= ft_min_word_len && word->len < ft_max_word_len && + if (length >= ft_min_word_len && length < ft_max_word_len && !is_stopword(word->pos, word->len)) { *start=doc; From 58e9369511972c7de916382d807a2632aa3c2f69 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Tue, 21 Oct 2003 00:13:17 +0200 Subject: [PATCH 16/23] >255 keys support in frm --- sql/table.cc | 17 ++++++++++++++--- sql/unireg.cc | 25 ++++++++++++++++--------- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/sql/table.cc b/sql/table.cc index c6da3432aaa..0281046f6a0 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -156,7 +156,16 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, VOID(my_seek(file,(ulong) uint2korr(head+6),MY_SEEK_SET,MYF(0))); if (read_string(file,(gptr*) &disk_buff,key_info_length)) goto err_not_open; /* purecov: inspected */ - outparam->keys=keys= disk_buff[0]; + if (disk_buff[1] & 0x80) + { + outparam->keys= keys= uint2korr(disk_buff) & 0x7fff; + outparam->key_parts= key_parts= uint2korr(disk_buff+2); + } + else + { + outparam->keys= keys= disk_buff[0]; + outparam->key_parts= key_parts= disk_buff[1]; + } outparam->keys_for_keyread.init().set_prefix(keys); outparam->keys_in_use.init().set_prefix(keys); outparam->read_only_keys.init().clear_all(); @@ -164,7 +173,6 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, 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); if (!(keyinfo = (KEY*) alloc_root(&outparam->mem_root, n_length+uint2korr(disk_buff+4)))) @@ -269,7 +277,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, record[outparam->reclength]=0; // For purify and ->c_ptr() outparam->rec_buff_length=rec_buff_length; if (my_pread(file,(byte*) record,(uint) outparam->reclength, - (ulong) (uint2korr(head+6)+uint2korr(head+14)), + (ulong) (uint2korr(head+6)+ + ((uint2korr(head+14) == 0xffff ? + uint4korr(head+10) : uint2korr(head+14)))), MYF(MY_NABP))) goto err_not_open; /* purecov: inspected */ /* HACK: table->record[2] is used instead of table->default_values here */ @@ -1114,6 +1124,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, key_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16; length=(ulong) next_io_size((ulong) (IO_SIZE+key_length+reclength)); int4store(fileinfo+10,length); + if (key_length > 0xffff) key_length=0xffff; int2store(fileinfo+14,key_length); int2store(fileinfo+16,reclength); int4store(fileinfo+18,create_info->max_rows); diff --git a/sql/unireg.cc b/sql/unireg.cc index be14448bd1d..d95aba97424 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -92,15 +92,15 @@ int rea_create_table(THD *thd, my_string file_name, DBUG_RETURN(1); } - uint key_buff_length=uint2korr(fileinfo+14); - keybuff=(uchar*) my_alloca(key_buff_length); + uint key_buff_length=keys*(7+NAME_LEN+MAX_REF_PARTS*9)+16; + keybuff=(uchar*) my_malloc(key_buff_length, MYF(0)); key_info_length=pack_keys(keybuff,keys,key_info); VOID(get_form_pos(file,fileinfo,&formnames)); if (!(filepos=make_new_entry(file,fileinfo,&formnames,""))) goto err; maxlength=(uint) next_io_size((ulong) (uint2korr(forminfo)+1000)); int2store(forminfo+2,maxlength); - int4store(fileinfo+10,(ulong) (filepos+maxlength)); + int4store(fileinfo+10,key_buff_length); fileinfo[26]= (uchar) test((create_info->max_rows == 1) && (create_info->min_rows == 1) && (keys == 0)); int2store(fileinfo+28,key_info_length); @@ -148,7 +148,7 @@ int rea_create_table(THD *thd, my_string file_name, #endif my_free((gptr) screen_buff,MYF(0)); - my_afree((gptr) keybuff); + my_free((gptr) keybuff, MYF(0)); VOID(my_close(file,MYF(MY_WME))); if (ha_create_table(file_name,create_info,0)) goto err2; @@ -156,7 +156,7 @@ int rea_create_table(THD *thd, my_string file_name, err: my_free((gptr) screen_buff,MYF(0)); - my_afree((gptr) keybuff); + my_free((gptr) keybuff, MYF(0)); VOID(my_close(file,MYF(MY_WME))); err2: my_delete(file_name,MYF(0)); @@ -291,10 +291,17 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo) } *(pos++)=0; - keybuff[0]=(uchar) key_count; - keybuff[1]=(uchar) key_parts; - length=(uint) (keyname_pos-keybuff); - int2store(keybuff+2,length); + if (key_count > 127 || key_parts > 127) + { + key_count|=0x8000; + int2store(keybuff,key_count); + int2store(keybuff+2,key_parts); + } + else + { + keybuff[0]=(uchar) key_count; + keybuff[1]=(uchar) key_parts; + } length=(uint) (pos-keyname_pos); int2store(keybuff+4,length); DBUG_RETURN((uint) (pos-keybuff)); From 2e64ba7aa31cef81a7d6d1aae55d29698113410d Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Tue, 21 Oct 2003 12:00:34 +0200 Subject: [PATCH 17/23] after-merge fix --- sql/share/czech/errmsg.txt | 1 + sql/share/danish/errmsg.txt | 1 + sql/share/dutch/errmsg.txt | 1 + sql/share/estonian/errmsg.txt | 1 + sql/share/french/errmsg.txt | 1 + sql/share/german/errmsg.txt | 1 + sql/share/greek/errmsg.txt | 1 + sql/share/hungarian/errmsg.txt | 1 + sql/share/italian/errmsg.txt | 1 + sql/share/japanese/errmsg.txt | 1 + sql/share/korean/errmsg.txt | 1 + sql/share/norwegian-ny/errmsg.txt | 1 + sql/share/norwegian/errmsg.txt | 1 + sql/share/polish/errmsg.txt | 1 + sql/share/portuguese/errmsg.txt | 1 + sql/share/romanian/errmsg.txt | 1 + sql/share/russian/errmsg.txt | 1 + sql/share/serbian/errmsg.txt | 1 + sql/share/slovak/errmsg.txt | 1 + sql/share/spanish/errmsg.txt | 1 + sql/share/swedish/errmsg.txt | 1 + sql/share/ukrainian/errmsg.txt | 1 + 22 files changed, 22 insertions(+) diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index bb7cd90b4c4..78e47d72cd6 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -292,3 +292,4 @@ character-set=latin2 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index 48a4fee22f8..bd4d5cbee66 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -286,3 +286,4 @@ character-set=latin1 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 98fb9278cc2..6bba37d8341 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -294,3 +294,4 @@ character-set=latin1 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index e596863907f..59cc4baf598 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -288,3 +288,4 @@ character-set=latin7 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index a81b8859692..1405e9025aa 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -283,3 +283,4 @@ character-set=latin1 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 9554822a5ff..16ed9982964 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -295,3 +295,4 @@ character-set=latin1 "Es wird empfohlen, mit --skip-slave-start zu starten, wenn mit START SLAVE UNTIL eine Schritt-für-Schritt-Replikation ausgeführt wird. Ansonsten gibt es Probleme, wenn der Slave-Server unerwartet neu startet", "SQL-Thread soll nicht gestartet werden. Daher werden UNTIL-Optionen ignoriert" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 073289562b3..f42cba3cd67 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -283,3 +283,4 @@ character-set=greek "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index c62a7c7b1ae..ef01f1b5cbf 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -285,3 +285,4 @@ character-set=latin2 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 004d7d00994..8a5f44fc7c4 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -283,3 +283,4 @@ character-set=latin1 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 888ac449a8b..c10302b6271 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -285,3 +285,4 @@ character-set=ujis "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index a72d6c3fdee..2780644c7d7 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -283,3 +283,4 @@ character-set=euckr "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 3c6dca27016..79fc1d9bcd0 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -285,3 +285,4 @@ character-set=latin1 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index bafc635a184..f62e1053842 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -285,3 +285,4 @@ character-set=latin1 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 0aa25aabb44..0df79e2bc82 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -287,3 +287,4 @@ character-set=latin2 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 33d8f68291d..086136b88a7 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -284,3 +284,4 @@ character-set=latin1 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index ff46caf2c6c..ba9b525d62b 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -287,3 +287,4 @@ character-set=latin2 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index f8bdb8bf4a5..1db3b26b6ee 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -285,3 +285,4 @@ character-set=koi8r "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index cede04e36ed..11d83c4da9e 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -278,3 +278,4 @@ character-set=cp1250 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 0759f68a1bb..125eea2bf38 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -291,3 +291,4 @@ character-set=latin2 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index b9c1b297e43..71b57aac07d 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -285,3 +285,4 @@ character-set=latin1 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 456b93fbc4d..63c572c6853 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -283,3 +283,4 @@ character-set=latin1 "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index dba62fd60c8..18fca33c3e2 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -288,3 +288,4 @@ character-set=koi8u "It is recommended to run with --skip-slave-start when doing step-by-step replication with START SLAVE UNTIL, otherwise you are not safe in case of unexpected slave's mysqld restart" "SQL thread is not to be started so UNTIL options are ignored" "Incorrect index name '%-.100s'", +"Column '%-.64s' cannot be part of FULLTEXT index" From 85942f14f4405793c8fcb9083cc8aa0dbcdad40e Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Tue, 21 Oct 2003 23:44:26 +0200 Subject: [PATCH 18/23] ftbench fixes --- myisam/ftbench/Ereport.pl | 6 +--- myisam/ftbench/README | 56 +++++++++++++++++++++++++++++++++++ myisam/ftbench/ft-test-run.sh | 12 +++++--- 3 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 myisam/ftbench/README diff --git a/myisam/ftbench/Ereport.pl b/myisam/ftbench/Ereport.pl index aac06503849..761c707fcda 100755 --- a/myisam/ftbench/Ereport.pl +++ b/myisam/ftbench/Ereport.pl @@ -41,11 +41,7 @@ sub Favg { my $a=shift; $Pavg*$Ravg ? 1/($a/$Pavg+(1-$a)/$Ravg) : 0; } $Ravg/=$B*$A if $B; $Pavg/=$B if $B; - write; -format= -@##### @#.####### -$qid, Favg(0.5) -. + printf "%5d %1.12f\n", $qid, Favg(0.5); } exit 0; diff --git a/myisam/ftbench/README b/myisam/ftbench/README new file mode 100644 index 00000000000..649d06d86bb --- /dev/null +++ b/myisam/ftbench/README @@ -0,0 +1,56 @@ +1. should be run from myisam/ftbench/ +2. myisam/ftdefs.h should NOT be locked (bk get, not bk edit!) +3. there should be ./data/ subdir with test collections, files: + test1.test + test1.relj + test2.test + test2.relj + where test1, test2, etc - are arbitrary test names + + *.test are SQL files of the structure: +===== +DROP TABLE IF EXISTS ft; +CREATE TABLE ft ( + id int(10) unsigned NOT NULL, + text text NOT NULL, + FULLTEXT KEY text (text) +); + +INSERT INTO ft VALUES (1, 'doc1...'),(2, 'doc2...'),... +... + +SELECT COUNT(*) FROM ft; +SELECT 1, id, MATCH text AGAINST ('query1') FROM ft WHERE MATCH text AGAINST ('query1'); +SELECT 2, id, MATCH text AGAINST ('query2') FROM ft WHERE MATCH text AGAINST ('query2'); +... +===== + + *.relj files have the structure: + 1 16 .....blablabla + 1 09 .....blablabla + 2 116 .....blablabla + ... + + that is /^\d+\s+\d+/ + and are sorted by the first number (not necessarily by the second) + +4. there should be ./t/ subdir with test directories + + ./t + ./t/BEST/ + ./t/testdir1/ + ./t/testdir2/ + ... + + there *must* be ./t/BEST/ subdir or a symlink to one of other dirs in ./t + all other names (besides BEST) can be arbitrary + + all test results are compared with BEST results. + + test directories *must* contain ftdefs.h, and *may* contain my.cnf + NOTE: all *.out files in test directories will NOT be overwritten! + delete them to re-test + +5. run ./ft-test-run.sh +6. go make some coffee + diff --git a/myisam/ftbench/ft-test-run.sh b/myisam/ftbench/ft-test-run.sh index 4c81cac6d4f..2c04d24a185 100755 --- a/myisam/ftbench/ft-test-run.sh +++ b/myisam/ftbench/ft-test-run.sh @@ -1,4 +1,4 @@ -#!/bin/sh -x +#!/bin/sh if [ ! -x ./ft-test-run.sh ] ; then echo "Usage: ./ft-test-run.sh" @@ -46,7 +46,7 @@ for batch in t/BEST t/* ; do touch $H OPTS="--defaults-file=$BASE/$batch/my.cnf --socket=$SOCK --character-sets-dir=$ROOT/sql/share/charsets" stop_myslqd - rm $MYSQLD + rm -f $MYSQLD (cd $ROOT; gmake) for prog in $MYSQLD $MYSQL $MYSQLADMIN ; do @@ -65,17 +65,21 @@ for batch in t/BEST t/* ; do --skip-grant-tables --skip-innodb \ --skip-networking --tmpdir=$DATA & - $MYSQLADMIN $OPTS --connect_timeout=60 ping + sleep 60 + $MYSQLADMIN $OPTS ping if [ $? != 0 ] ; then echo "$MYSQLD refused to start" exit 1 fi - for test in `cd data; echo *.test|sed "s/\.test\>//g"` ; do + for test in `cd data; echo *.test|sed "s/\.test//g"` ; do + echo "test $batch/$test" $MYSQL $OPTS --skip-column-names test var/$test.eval + echo "report $batch/$test" ./Ereport.pl var/$test.eval data/$test.relj > $batch/$test.out || exit done stop_myslqd rm -f $H + echo "compare $batch" [ $batch -ef t/BEST ] || ./Ecompare.pl t/BEST $batch >> t/BEST/report.txt done From df69309593b7e377d18d005147b485573f607f70 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Wed, 22 Oct 2003 17:57:09 +0200 Subject: [PATCH 19/23] MATCH ... AGAINST ("..." WITH QUERY EXPANSION) syntax --- include/ft_global.h | 9 ++++++--- myisam/ft_boolean_search.c | 2 +- myisam/ft_nlq_search.c | 4 ++-- myisam/ft_static.c | 10 +++++----- myisam/ftdefs.h | 4 ++-- myisam/mi_write.c | 2 +- mysql-test/t/fulltext.test | 4 ++-- sql/ha_myisam.h | 5 ++--- sql/handler.h | 3 +-- sql/item_func.cc | 14 +++++++------- sql/item_func.h | 21 +++------------------ sql/lex.h | 1 + sql/sql_yacc.yy | 24 ++++++++++++++---------- 13 files changed, 47 insertions(+), 56 deletions(-) diff --git a/include/ft_global.h b/include/ft_global.h index 4aa916e91cf..afaad59ca50 100644 --- a/include/ft_global.h +++ b/include/ft_global.h @@ -57,9 +57,12 @@ extern const char *ft_boolean_syntax; int ft_init_stopwords(void); void ft_free_stopwords(void); -#define FT_NL 0 -#define FT_BOOL 1 -FT_INFO *ft_init_search(uint,void *, uint, byte *, uint, my_bool); +#define FT_NL 0 /* this MUST be 0, see ft_init_search() */ +#define FT_BOOL 1 /* this MUST be 1, see ft_init_search() */ +#define FT_SORTED 2 +#define FT_EXPAND 4 /* query expansion */ + +FT_INFO *ft_init_search(uint,void *, uint, byte *, uint); #ifdef __cplusplus } diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 0b97eded872..bb9c2624691 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -341,7 +341,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, uint query_len, - my_bool presort __attribute__((unused))) + uint flags __attribute__((unused))) { FTB *ftb; FTB_EXPR *ftbe; diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index 690ad0fc453..efe735c3d16 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -175,7 +175,7 @@ static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b) FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, - uint query_len, my_bool presort) + uint query_len, uint flags) { TREE allocated_wtree, *wtree=&allocated_wtree; ALL_IN_ONE aio; @@ -224,7 +224,7 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, tree_walk(&aio.dtree, (tree_walk_action) &walk_and_copy, &dptr, left_root_right); - if (presort) + if (flags & FT_SORTED) qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp); err2: diff --git a/myisam/ft_static.c b/myisam/ft_static.c index 44e80847fd7..ca3054ae977 100644 --- a/myisam/ft_static.c +++ b/myisam/ft_static.c @@ -53,14 +53,14 @@ const struct _ft_vft _ft_vft_boolean = { ft_boolean_get_relevance, ft_boolean_reinit_search }; -FT_INFO *(*_ft_init_vft[2])(MI_INFO *, uint, byte *, uint, my_bool) = +FT_INFO *(*_ft_init_vft[2])(MI_INFO *, uint, byte *, uint, uint) = { ft_init_nlq_search, ft_init_boolean_search }; -FT_INFO *ft_init_search(uint mode, void *info, uint keynr, - byte *query, uint query_len, my_bool presort) +FT_INFO *ft_init_search(uint flags, void *info, uint keynr, + byte *query, uint query_len) { - return (*_ft_init_vft[mode])((MI_INFO *)info, keynr, - query, query_len, presort); + return (*_ft_init_vft[ flags&1 ])((MI_INFO *)info, keynr, + query, query_len, flags); } const char *ft_stopword_file = 0; diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index 6e71f20e17c..2079a60f47d 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -128,7 +128,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *); uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record); extern const struct _ft_vft _ft_vft_nlq; -FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, my_bool); +FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, uint); int ft_nlq_read_next(FT_INFO *, char *); float ft_nlq_find_relevance(FT_INFO *, byte *, uint); void ft_nlq_close_search(FT_INFO *); @@ -137,7 +137,7 @@ my_off_t ft_nlq_get_docid(FT_INFO *); void ft_nlq_reinit_search(FT_INFO *); extern const struct _ft_vft _ft_vft_boolean; -FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint, my_bool); +FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint, uint); int ft_boolean_read_next(FT_INFO *, char *); float ft_boolean_find_relevance(FT_INFO *, byte *, uint); void ft_boolean_close_search(FT_INFO *); diff --git a/myisam/mi_write.c b/myisam/mi_write.c index b6a7bf50dd0..155cf998a33 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -272,7 +272,7 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, 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)); + my_free((gptr)info->ft1_to_ft2, MYF(0)); info->ft1_to_ft2=0; } DBUG_RETURN(error); diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 56a27c83cf1..de706e80d6e 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -130,9 +130,9 @@ select * from t2 having MATCH inhalt AGAINST ('foobar'); # check of fulltext errors # ---error 1279 +--error 1280 CREATE TABLE t3 (t int(11),i text,fulltext tix (t,i)); ---error 1279 +--error 1280 CREATE TABLE t3 (t int(11),i text, j varchar(200) CHARACTER SET latin2, fulltext tix (i,j)); diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index e4e3192af10..8b10ce805da 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -89,9 +89,8 @@ class ha_myisam: public handler ft_handler->please->reinit_search(ft_handler); return 0; } - FT_INFO *ft_init_ext(uint mode, uint inx,const byte *key, uint keylen, - bool presort) - { return ft_init_search(mode, file,inx,(byte*) key,keylen,presort); } + FT_INFO *ft_init_ext(uint flags, uint inx,const byte *key, uint keylen) + { return ft_init_search(flags,file,inx,(byte*) key,keylen); } int ft_read(byte *buf); int rnd_init(bool scan=1); int rnd_next(byte *buf); diff --git a/sql/handler.h b/sql/handler.h index 638125e23d0..26671bb5b11 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -271,8 +271,7 @@ public: } virtual int ft_init() { return -1; } - virtual FT_INFO *ft_init_ext(uint mode,uint inx,const byte *key, uint keylen, - bool presort) + virtual FT_INFO *ft_init_ext(uint flags,uint inx,const byte *key, uint keylen) { return NULL; } virtual int ft_read(byte *buf) { return -1; } virtual int rnd_init(bool scan=1)=0; diff --git a/sql/item_func.cc b/sql/item_func.cc index 5a7aada8c1d..6392032850b 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -2587,10 +2587,10 @@ void Item_func_match::init_search(bool no_order) ft_tmp= &search_value; } - ft_handler=table->file->ft_init_ext(mode, key, + if (join_key && !no_order) flags|=FT_SORTED; + ft_handler=table->file->ft_init_ext(flags, key, (byte*) ft_tmp->ptr(), - ft_tmp->length(), - join_key && !no_order); + ft_tmp->length()); if (join_key) table->file->ft_handler=ft_handler; @@ -2631,7 +2631,7 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) /* check that all columns come from the same table */ if (my_count_bits(used_tables_cache) != 1) key=NO_SUCH_KEY; - if (key == NO_SUCH_KEY && mode != FT_BOOL) + if (key == NO_SUCH_KEY && !(flags & FT_BOOL)) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH"); return 1; @@ -2711,7 +2711,7 @@ bool Item_func_match::fix_index() } err: - if (mode == FT_BOOL) + if (flags & FT_BOOL) { key=NO_SUCH_KEY; return 0; @@ -2723,8 +2723,8 @@ err: bool Item_func_match::eq(const Item *item, bool binary_cmp) const { - if (item->type() != FUNC_ITEM || - func_name() != ((Item_func*)item)->func_name()) + if (item->type() != FUNC_ITEM || ((Item_func*)item)->functype() != FT_FUNC || + flags != ((Item_func_match*)item)->flags) return 0; Item_func_match *ifm=(Item_func_match*) item; diff --git a/sql/item_func.h b/sql/item_func.h index 33609694fe9..55c7a03108e 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -962,7 +962,7 @@ public: class Item_func_match :public Item_real_func { public: - uint key, mode; + uint key, flags; bool join_key; DTCollation cmp_collation; FT_INFO *ft_handler; @@ -972,7 +972,7 @@ public: String value; // value of concat String search_value; // key_item()'s value converted to cmp_collation - Item_func_match(List &a): Item_real_func(a), + Item_func_match(List &a, uint b): Item_real_func(a), flags(b), table(0), master(0), ft_handler(0), concat(0), key(0), join_key(0) { } ~Item_func_match() { @@ -988,6 +988,7 @@ public: delete concat; } enum Functype functype() const { return FT_FUNC; } + const char *func_name() const { return "match"; } void update_used_tables() {} table_map not_null_tables() const { return 0; } bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); @@ -1000,22 +1001,6 @@ public: }; -class Item_func_match_nl :public Item_func_match -{ -public: - Item_func_match_nl(List &a) :Item_func_match(a) { mode=FT_NL; } - const char *func_name() const { return "match_nl"; } -}; - - -class Item_func_match_bool :public Item_func_match -{ -public: - Item_func_match_bool(List &a) :Item_func_match(a) { mode=FT_BOOL; } - const char *func_name() const { return "match_bool"; } -}; - - class Item_func_bit_xor : public Item_int_func { public: diff --git a/sql/lex.h b/sql/lex.h index 5d79e378d4f..7f3328fa7cb 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -153,6 +153,7 @@ static SYMBOL symbols[] = { { "EXECUTE", SYM(EXECUTE_SYM),0,0}, { "EXPLAIN", SYM(DESCRIBE),0,0}, { "EXISTS", SYM(EXISTS),0,0}, + { "EXPANSION", SYM(EXPANSION_SYM),0,0}, { "EXTENDED", SYM(EXTENDED_SYM),0,0}, { "FAST", SYM(FAST_SYM),0,0}, { "FIELDS", SYM(COLUMNS),0,0}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 04f5043839f..42ab755d0ba 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -135,6 +135,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token DROP %token EVENTS_SYM %token EXECUTE_SYM +%token EXPANSION_SYM %token FLUSH_SYM %token HELP_SYM %token INSERT @@ -168,7 +169,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SUPER_SYM %token TRUNCATE_SYM %token UNLOCK_SYM -%token UNTIL_SYM +%token UNTIL_SYM %token UPDATE_SYM %token ACTION @@ -604,8 +605,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %type type int_type real_type order_dir opt_field_spec lock_option udf_type if_exists opt_local opt_table_options table_options - table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type opt_var_ident_type - delete_option opt_temporary all_or_any opt_distinct opt_ignore_leaves + table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type + opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct + opt_ignore_leaves fulltext_options %type ULONG_NUM raid_types merge_insert_types @@ -2448,14 +2450,10 @@ simple_expr: | EXISTS exists_subselect { $$= $2; } | singlerow_subselect { $$= $1; } | '{' ident expr '}' { $$= $3; } - | MATCH ident_list_arg AGAINST '(' expr ')' + | MATCH ident_list_arg AGAINST '(' expr fulltext_options ')' { $2->push_front($5); - Select->add_ftfunc_to_list((Item_func_match *) - ($$=new Item_func_match_nl(*$2))); } - | MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')' - { $2->push_front($5); - Select->add_ftfunc_to_list((Item_func_match *) - ($$=new Item_func_match_bool(*$2))); } + Select->add_ftfunc_to_list((Item_func_match*) + ($$=new Item_func_match(*$2,$6))); } | ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); } | BINARY expr %prec NEG { @@ -2843,6 +2841,12 @@ simple_expr: | EXTRACT_SYM '(' interval FROM expr ')' { $$=new Item_extract( $3, $5); }; +fulltext_options: + /* nothing */ { $$= FT_NL; } + | WITH QUERY_SYM EXPANSION_SYM { $$= FT_NL | FT_EXPAND; } + | IN_SYM BOOLEAN_SYM MODE_SYM { $$= FT_BOOL; } + ; + udf_expr_list: /* empty */ { $$= NULL; } | expr_list { $$= $1;}; From b820d2a3472cd4ce9c8b87c961a0f848e5990557 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 23 Oct 2003 15:21:06 +0200 Subject: [PATCH 20/23] query expansion for fulltext search --- include/ft_global.h | 8 ++--- myisam/ft_boolean_search.c | 5 +-- myisam/ft_nlq_search.c | 62 ++++++++++++++++++++++++-------- myisam/ft_parser.c | 11 +++++- myisam/ft_static.c | 13 ++++--- myisam/ft_update.c | 7 ++-- myisam/ftdefs.h | 14 +++++--- myisam/mi_check.c | 11 +++--- myisam/myisamchk.c | 3 -- mysql-test/r/fulltext.result | 11 +++++- mysql-test/r/fulltext_var.result | 2 +- mysql-test/t/fulltext.test | 7 ++-- sql/ha_myisam.h | 2 +- sql/mysqld.cc | 10 +++--- sql/set_var.cc | 6 ++-- sql/sql_yacc.yy | 1 + 16 files changed, 112 insertions(+), 61 deletions(-) diff --git a/include/ft_global.h b/include/ft_global.h index afaad59ca50..df6860109e4 100644 --- a/include/ft_global.h +++ b/include/ft_global.h @@ -51,18 +51,18 @@ extern const char *ft_precompiled_stopwords[]; extern ulong ft_min_word_len; extern ulong ft_max_word_len; -extern ulong ft_max_word_len_for_sort; +extern ulong ft_query_expansion_limit; extern const char *ft_boolean_syntax; int ft_init_stopwords(void); void ft_free_stopwords(void); -#define FT_NL 0 /* this MUST be 0, see ft_init_search() */ -#define FT_BOOL 1 /* this MUST be 1, see ft_init_search() */ +#define FT_NL 0 +#define FT_BOOL 1 #define FT_SORTED 2 #define FT_EXPAND 4 /* query expansion */ -FT_INFO *ft_init_search(uint,void *, uint, byte *, uint); +FT_INFO *ft_init_search(uint,void *, uint, byte *, uint, byte *); #ifdef __cplusplus } diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index bb9c2624691..95d0149c67d 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -20,8 +20,6 @@ #define FT_CORE #include "ftdefs.h" -#include -#include /* for DBUG_ASSERT() */ /* search with boolean queries */ @@ -340,8 +338,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, - uint query_len, - uint flags __attribute__((unused))) + uint query_len) { FTB *ftb; FTB_EXPR *ftbe; diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index efe735c3d16..a38c52704f7 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -167,17 +167,28 @@ static int walk_and_copy(FT_SUPERDOC *from, DBUG_RETURN(0); } +static int walk_and_push(FT_SUPERDOC *from, + uint32 count __attribute__((unused)), QUEUE *best) +{ + DBUG_ENTER("walk_and_copy"); + from->doc.weight+=from->tmp_weight*from->word_ptr->weight; + set_if_smaller(best->elements, ft_query_expansion_limit-1) + queue_insert(best, (byte *)& from->doc); + DBUG_RETURN(0); +} -static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b) + +static int FT_DOC_cmp(void *unused __attribute__((unused)), + FT_DOC *a, FT_DOC *b) { return sgn(b->weight - a->weight); } FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, - uint query_len, uint flags) + uint query_len, uint flags, byte *record) { - TREE allocated_wtree, *wtree=&allocated_wtree; + TREE wtree; ALL_IN_ONE aio; FT_DOC *dptr; FT_INFO *dlist=NULL; @@ -196,24 +207,47 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, aio.charset=info->s->keyinfo[keynr].seg->charset; aio.keybuff=info->lastkey+info->s->base.max_key_length; - bzero(&allocated_wtree,sizeof(allocated_wtree)); + bzero(&wtree,sizeof(wtree)); init_tree(&aio.dtree,0,0,sizeof(FT_SUPERDOC),(qsort_cmp2)&FT_SUPERDOC_cmp,0, NULL, NULL); - ft_parse_init(&allocated_wtree, aio.charset); - if (ft_parse(&allocated_wtree,query,query_len)) + ft_parse_init(&wtree, aio.charset); + if (ft_parse(&wtree,query,query_len,0)) goto err; - if (tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio, + if (tree_walk(&wtree, (tree_walk_action)&walk_and_match, &aio, left_root_right)) - goto err2; + goto err; + + if (flags & FT_EXPAND && ft_query_expansion_limit) + { + QUEUE best; + init_queue(&best,ft_query_expansion_limit,0,0, &FT_DOC_cmp, 0); + tree_walk(&aio.dtree, (tree_walk_action) &walk_and_push, + &best, left_root_right); + while (best.elements) + { + my_off_t docid=((FT_DOC *)queue_remove(& best, 0))->dpos; + if (!(*info->read_record)(info,docid,record)) + { + info->update|= HA_STATE_AKTIV; + _mi_ft_parse(&wtree, info, keynr, record,1); + } + } + delete_queue(&best); + reset_tree(&aio.dtree); + if (tree_walk(&wtree, (tree_walk_action)&walk_and_match, &aio, + left_root_right)) + goto err; + + } dlist=(FT_INFO *)my_malloc(sizeof(FT_INFO)+ sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1), MYF(0)); - if(!dlist) - goto err2; + if (!dlist) + goto err; dlist->please= (struct _ft_vft *) & _ft_vft_nlq; dlist->ndocs=aio.dtree.elements_in_tree; @@ -225,13 +259,11 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, &dptr, left_root_right); if (flags & FT_SORTED) - qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp); - -err2: - delete_tree(wtree); - delete_tree(&aio.dtree); + qsort2(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort2_cmp)&FT_DOC_cmp, 0); err: + delete_tree(&aio.dtree); + delete_tree(&wtree); info->lastpos=saved_lastpos; DBUG_RETURN(dlist); } diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index d6d1378bdae..8ab67aa9c6f 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -183,7 +183,7 @@ void ft_parse_init(TREE *wtree, CHARSET_INFO *cs) DBUG_VOID_RETURN; } -int ft_parse(TREE *wtree, byte *doc, int doclen) +int ft_parse(TREE *wtree, byte *doc, int doclen, my_bool with_alloc) { byte *end=doc+doclen; FT_WORD w; @@ -191,6 +191,15 @@ int ft_parse(TREE *wtree, byte *doc, int doclen) while (ft_simple_get_word(wtree->custom_arg, &doc,end,&w)) { + if (with_alloc) + { + byte *ptr; + /* allocating the data in the tree - to avoid mallocs and frees */ + DBUG_ASSERT(wtree->with_delete==0); + ptr=(byte *)alloc_root(& wtree->mem_root,w.len); + memcpy(ptr, w.pos, w.len); + w.pos=ptr; + } if (!tree_insert(wtree, &w, 0, wtree->custom_arg)) goto err; } diff --git a/myisam/ft_static.c b/myisam/ft_static.c index ca3054ae977..2edb86679e9 100644 --- a/myisam/ft_static.c +++ b/myisam/ft_static.c @@ -20,7 +20,7 @@ ulong ft_min_word_len=4; ulong ft_max_word_len=HA_FT_MAXLEN; -ulong ft_max_word_len_for_sort=20; +ulong ft_query_expansion_limit=5; const char *ft_boolean_syntax="+ -><()~*:\"\"&|"; const HA_KEYSEG ft_keysegs[FT_SEGS]={ @@ -53,14 +53,13 @@ const struct _ft_vft _ft_vft_boolean = { ft_boolean_get_relevance, ft_boolean_reinit_search }; -FT_INFO *(*_ft_init_vft[2])(MI_INFO *, uint, byte *, uint, uint) = -{ ft_init_nlq_search, ft_init_boolean_search }; - FT_INFO *ft_init_search(uint flags, void *info, uint keynr, - byte *query, uint query_len) + byte *query, uint query_len, byte *record) { - return (*_ft_init_vft[ flags&1 ])((MI_INFO *)info, keynr, - query, query_len, flags); + if (flags & FT_BOOL) + ft_init_boolean_search((MI_INFO *)info, keynr, query, query_len); + else + ft_init_nlq_search((MI_INFO *)info, keynr, query, query_len, flags, record); } const char *ft_stopword_file = 0; diff --git a/myisam/ft_update.c b/myisam/ft_update.c index 79892f54002..2dc397e864f 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -97,7 +97,8 @@ uint _mi_ft_segiterator(register FT_SEG_ITERATOR *ftsi) /* parses a document i.e. calls ft_parse for every keyseg */ -uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record) +uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, + const byte *record, my_bool with_alloc) { FT_SEG_ITERATOR ftsi; DBUG_ENTER("_mi_ft_parse"); @@ -108,7 +109,7 @@ uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record) while (_mi_ft_segiterator(&ftsi)) { if (ftsi.pos) - if (ft_parse(parsed, (byte *)ftsi.pos, ftsi.len)) + if (ft_parse(parsed, (byte *)ftsi.pos, ftsi.len, with_alloc)) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -120,7 +121,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, const byte *record) DBUG_ENTER("_mi_ft_parserecord"); bzero((char*) &ptree, sizeof(ptree)); - if (_mi_ft_parse(&ptree, info, keynr, record)) + if (_mi_ft_parse(&ptree, info, keynr, record,0)) DBUG_RETURN(NULL); DBUG_RETURN(ft_linearize(&ptree)); diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index 2079a60f47d..a97485ec021 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -21,11 +21,15 @@ #include "fulltext.h" #include #include +#include +#include #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 FT_MAX_WORD_LEN_FOR_SORT 20 + #define COMPILE_STOPWORDS_IN /* Interested readers may consult SMART @@ -122,13 +126,15 @@ void _mi_ft_segiterator_dummy_init(const byte *, uint, FT_SEG_ITERATOR *); uint _mi_ft_segiterator(FT_SEG_ITERATOR *); void ft_parse_init(TREE *, CHARSET_INFO *); -int ft_parse(TREE *, byte *, int); +int ft_parse(TREE *, byte *, int, my_bool); FT_WORD * ft_linearize(TREE *); FT_WORD * _mi_ft_parserecord(MI_INFO *, uint, const byte *); -uint _mi_ft_parse(TREE *parsed, MI_INFO *info, uint keynr, const byte *record); +uint _mi_ft_parse(TREE *, MI_INFO *, uint, const byte *, my_bool); + +FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, uint, byte *); +FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint); extern const struct _ft_vft _ft_vft_nlq; -FT_INFO *ft_init_nlq_search(MI_INFO *, uint, byte *, uint, uint); int ft_nlq_read_next(FT_INFO *, char *); float ft_nlq_find_relevance(FT_INFO *, byte *, uint); void ft_nlq_close_search(FT_INFO *); @@ -137,10 +143,10 @@ my_off_t ft_nlq_get_docid(FT_INFO *); void ft_nlq_reinit_search(FT_INFO *); extern const struct _ft_vft _ft_vft_boolean; -FT_INFO *ft_init_boolean_search(MI_INFO *, uint, byte *, uint, uint); int ft_boolean_read_next(FT_INFO *, char *); float ft_boolean_find_relevance(FT_INFO *, byte *, uint); void ft_boolean_close_search(FT_INFO *); float ft_boolean_get_relevance(FT_INFO *); my_off_t ft_boolean_get_docid(FT_INFO *); void ft_boolean_reinit_search(FT_INFO *); + diff --git a/myisam/mi_check.c b/myisam/mi_check.c index a6ce3a9c87b..0fab06ad92a 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -20,7 +20,6 @@ #include #include #include -#include #ifdef HAVE_SYS_VADVISE_H #include #endif @@ -1955,11 +1954,11 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, if (sort_param.keyinfo->flag & HA_FULLTEXT) { sort_info.max_records= - (ha_rows) (sort_info.filelength/ft_max_word_len_for_sort+1); + (ha_rows) (sort_info.filelength/FT_MAX_WORD_LEN_FOR_SORT+1); sort_param.key_read=sort_ft_key_read; sort_param.key_write=sort_ft_key_write; - sort_param.key_length+=ft_max_word_len_for_sort-HA_FT_MAXLEN; + sort_param.key_length+=FT_MAX_WORD_LEN_FOR_SORT-HA_FT_MAXLEN; } else { @@ -2350,7 +2349,7 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, total_key_length+=sort_param[i].key_length; if (sort_param[i].keyinfo->flag & HA_FULLTEXT) - sort_param[i].key_length+=ft_max_word_len_for_sort-ft_max_word_len; + sort_param[i].key_length+=FT_MAX_WORD_LEN_FOR_SORT-ft_max_word_len; } sort_info.total_keys=i; sort_param[0].master= 1; @@ -3875,7 +3874,7 @@ static my_bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows) { uint key_maxlength=key->maxlength; if (key->flag & HA_FULLTEXT) - key_maxlength+=ft_max_word_len_for_sort-HA_FT_MAXLEN; + key_maxlength+=FT_MAX_WORD_LEN_FOR_SORT-HA_FT_MAXLEN; return (key->flag & (HA_BINARY_PACK_KEY | HA_VAR_LENGTH_KEY | HA_FULLTEXT) && ((ulonglong) rows * key_maxlength > (ulonglong) myisam_max_temp_length)); @@ -3891,7 +3890,7 @@ void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows) MI_KEYDEF *key=share->keyinfo; for (i=0 ; i < share->base.keys ; i++,key++) { - if (!(key->flag & (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY)) && + if (!(key->flag & (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY)) && ! mi_too_big_key_for_sort(key,rows) && info->s->base.auto_key != i+1) { share->state.key_map&= ~ ((ulonglong) 1 << i); diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 76d3205dc01..9cc2141ab36 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -314,9 +314,6 @@ static struct my_option my_long_options[] = { "ft_max_word_len", OPT_FT_MAX_WORD_LEN, "", (gptr*) &ft_max_word_len, (gptr*) &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXLEN, 10, HA_FT_MAXLEN, 0, 1, 0}, - { "ft_max_word_len_for_sort", OPT_FT_MAX_WORD_LEN_FOR_SORT, "", - (gptr*) &ft_max_word_len_for_sort, (gptr*) &ft_max_word_len_for_sort, 0, - GET_ULONG, REQUIRED_ARG, 20, 4, HA_FT_MAXLEN, 0, 1, 0}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index 63338869fdd..31ed252b22d 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -18,11 +18,20 @@ Full-text indexes are called collections Only MyISAM tables support collections select * from t1 where MATCH(a,b) AGAINST ("only"); a b -select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes"); +select * from t1 where MATCH(a,b) AGAINST ("collections" WITH QUERY EXPANSION); a b Only MyISAM tables support collections Full-text indexes are called collections +MySQL has now support for full-text search +select * from t1 where MATCH(a,b) AGAINST ("indexes" WITH QUERY EXPANSION); +a b Full-text indexes are called collections +Only MyISAM tables support collections +select * from t1 where MATCH(a,b) AGAINST ("indexes collections" WITH QUERY EXPANSION); +a b +Full-text indexes are called collections +Only MyISAM tables support collections +MySQL has now support for full-text search explain select * from t1 where MATCH(a,b) AGAINST ("collections"); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 fulltext a a 0 1 Using where diff --git a/mysql-test/r/fulltext_var.result b/mysql-test/r/fulltext_var.result index dda8e332fba..f45e18a9591 100644 --- a/mysql-test/r/fulltext_var.result +++ b/mysql-test/r/fulltext_var.result @@ -3,5 +3,5 @@ Variable_name Value ft_boolean_syntax + -><()~*:""&| ft_min_word_len 4 ft_max_word_len 254 -ft_max_word_len_for_sort 20 +ft_query_expansion_limit 20 ft_stopword_file (built-in) diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index de706e80d6e..80655f28d00 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -20,9 +20,11 @@ select * from t1 where MATCH(a,b) AGAINST ("indexes"); select * from t1 where MATCH(a,b) AGAINST ("indexes collections"); select * from t1 where MATCH(a,b) AGAINST ("only"); -# UNION of fulltext's -select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes"); +# query expansion +select * from t1 where MATCH(a,b) AGAINST ("collections" WITH QUERY EXPANSION); +select * from t1 where MATCH(a,b) AGAINST ("indexes" WITH QUERY EXPANSION); +select * from t1 where MATCH(a,b) AGAINST ("indexes collections" WITH QUERY EXPANSION); # add_ft_keys() tests @@ -66,7 +68,6 @@ select * from t1 where MATCH a AGAINST ("search" IN BOOLEAN MODE); select * from t1 where MATCH b AGAINST ("sear*" IN BOOLEAN MODE); # UNION of fulltext's - select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes"); #update/delete with fulltext index diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index 8b10ce805da..38dce25d1fb 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -90,7 +90,7 @@ class ha_myisam: public handler return 0; } FT_INFO *ft_init_ext(uint flags, uint inx,const byte *key, uint keylen) - { return ft_init_search(flags,file,inx,(byte*) key,keylen); } + { return ft_init_search(flags,file,inx,(byte*) key,keylen, table->record[0]); } int ft_read(byte *buf); int rnd_init(bool scan=1); int rnd_next(byte *buf); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6cd61536944..55e022665ad 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3568,7 +3568,7 @@ enum options_mysqld OPT_CONNECT_TIMEOUT, OPT_DELAYED_INSERT_TIMEOUT, OPT_DELAYED_INSERT_LIMIT, OPT_DELAYED_QUEUE_SIZE, OPT_FLUSH_TIME, OPT_FT_MIN_WORD_LEN, - OPT_FT_MAX_WORD_LEN, OPT_FT_MAX_WORD_LEN_FOR_SORT, OPT_FT_STOPWORD_FILE, + OPT_FT_MAX_WORD_LEN, OPT_FT_QUERY_EXPANSION_LIMIT, OPT_FT_STOPWORD_FILE, OPT_INTERACTIVE_TIMEOUT, OPT_JOIN_BUFF_SIZE, OPT_KEY_BUFFER_SIZE, OPT_LONG_QUERY_TIME, OPT_LOWER_CASE_TABLE_NAMES, OPT_MAX_ALLOWED_PACKET, @@ -4210,10 +4210,10 @@ replicating a LOAD DATA INFILE command.", "The maximum length of the word to be included in a FULLTEXT index. Note: FULLTEXT indexes must be rebuilt after changing this variable.", (gptr*) &ft_max_word_len, (gptr*) &ft_max_word_len, 0, GET_ULONG, REQUIRED_ARG, HA_FT_MAXLEN, 10, HA_FT_MAXLEN, 0, 1, 0}, - { "ft_max_word_len_for_sort", OPT_FT_MAX_WORD_LEN_FOR_SORT, - "The maximum length of the word for repair_by_sorting. Longer words are included the slow way. The lower this value, the more words will be put in one sort bucket.", - (gptr*) &ft_max_word_len_for_sort, (gptr*) &ft_max_word_len_for_sort, 0, GET_ULONG, - REQUIRED_ARG, 20, 4, HA_FT_MAXLEN, 0, 1, 0}, + { "ft_query_expansion_limit", OPT_FT_QUERY_EXPANSION_LIMIT, + "Number of best matches to use for query expansion", + (gptr*) &ft_query_expansion_limit, (gptr*) &ft_query_expansion_limit, 0, GET_ULONG, + REQUIRED_ARG, 20, 0, 1000, 0, 1, 0}, { "ft_stopword_file", OPT_FT_STOPWORD_FILE, "Use stopwords from this file instead of built-in list.", (gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR, diff --git a/sql/set_var.cc b/sql/set_var.cc index 48580960399..54d8fd2f563 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -556,15 +556,15 @@ struct show_var_st init_vars[]= { {"ft_boolean_syntax", (char*) ft_boolean_syntax, SHOW_CHAR}, {"ft_min_word_len", (char*) &ft_min_word_len, SHOW_LONG}, {"ft_max_word_len", (char*) &ft_max_word_len, SHOW_LONG}, - {"ft_max_word_len_for_sort",(char*) &ft_max_word_len_for_sort, SHOW_LONG}, + {"ft_query_expansion_limit",(char*) &ft_query_expansion_limit, SHOW_LONG}, {"ft_stopword_file", (char*) &ft_stopword_file, SHOW_CHAR_PTR}, {"have_bdb", (char*) &have_berkeley_db, SHOW_HAVE}, {"have_crypt", (char*) &have_crypt, SHOW_HAVE}, {"have_compress", (char*) &have_compress, SHOW_HAVE}, {"have_innodb", (char*) &have_innodb, SHOW_HAVE}, - {"have_isam", (char*) &have_isam, SHOW_HAVE}, + {"have_isam", (char*) &have_isam, SHOW_HAVE}, {"have_raid", (char*) &have_raid, SHOW_HAVE}, - {"have_symlink", (char*) &have_symlink, SHOW_HAVE}, + {"have_symlink", (char*) &have_symlink, SHOW_HAVE}, {"have_openssl", (char*) &have_openssl, SHOW_HAVE}, {"have_query_cache", (char*) &have_query_cache, SHOW_HAVE}, {"init_file", (char*) &opt_init_file, SHOW_CHAR_PTR}, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 42ab755d0ba..b4c5866a445 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4546,6 +4546,7 @@ keyword: | ESCAPE_SYM {} | EVENTS_SYM {} | EXECUTE_SYM {} + | EXPANSION_SYM {} | EXTENDED_SYM {} | FAST_SYM {} | DISABLE_SYM {} From ad175936ef0b5c0b7af82b1d04dc6992349646a2 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Thu, 23 Oct 2003 23:33:06 +0200 Subject: [PATCH 21/23] ftbench fixes --- myisam/ftbench/Ecompare.pl | 4 +-- myisam/ftbench/Ecreate.pl | 44 ++++++++++++++++++++++++ myisam/ftbench/Ereport.pl | 4 +-- myisam/ftbench/README | 33 ++++++------------ myisam/ftbench/ft-test-run.sh | 65 +++++++++++++++++++++-------------- 5 files changed, 97 insertions(+), 53 deletions(-) create mode 100755 myisam/ftbench/Ecreate.pl diff --git a/myisam/ftbench/Ecompare.pl b/myisam/ftbench/Ecompare.pl index 4bcee1fb588..265534e704d 100755 --- a/myisam/ftbench/Ecompare.pl +++ b/myisam/ftbench/Ecompare.pl @@ -73,14 +73,14 @@ for $file (split) { for (0..$#l1) { $pp[$_]+=$p[$_]; $mm[$_]+=$m[$_]; - $total.=rep($file, ($#l1 ? $_ : undef), $p[$_], $m[$_]); + $total[$_].=rep($file, ($#l1 ? $_ : undef), $p[$_], $m[$_]); } close OUT1; close OUT2; } for (0..$#l1) { - rep($total, ($#l1 ? $_ : undef), $pp[$_], $mm[$_]); + rep($total[$_], ($#l1 ? $_ : undef), $pp[$_], $mm[$_]); } sub rep { diff --git a/myisam/ftbench/Ecreate.pl b/myisam/ftbench/Ecreate.pl new file mode 100755 index 00000000000..d90a6f7a0ad --- /dev/null +++ b/myisam/ftbench/Ecreate.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl + +$test=shift || die "Usage $0 testname [option]"; +$option=shift; + +open(D, ") { chomp; + s/'/\\'/g; ++$N; + print "INSERT $test VALUES ($N, '$_');\n"; +} + +print <<__PREP__; +ALTER TABLE $test ENABLE KEYS; +SELECT $N; +__PREP__ + +$N=0; + +while () { chomp; + s/'/\\'/g; ++$N; + $_="MATCH text AGAINST ('$_' $option)"; + print "SELECT $N, id, $_ FROM $test WHERE $_;\n"; +} + +print <<__FOOTER__; +DROP TABLE $test; +__FOOTER__ + + diff --git a/myisam/ftbench/Ereport.pl b/myisam/ftbench/Ereport.pl index 761c707fcda..5969304da09 100755 --- a/myisam/ftbench/Ereport.pl +++ b/myisam/ftbench/Ereport.pl @@ -29,7 +29,7 @@ sub Favg { my $a=shift; $Pavg*$Ravg ? 1/($a/$Pavg+(1-$a)/$Ravg) : 0; } # F0 : a=0 -- ignore precision # F5 : a=0.5 # F1 : a=1 -- ignore recall - while($eout_str =~ /^$qid\s+(\d+)\s+(\d+\.\d+)/) { + while($eout_str =~ /^$qid\s+(\d+)\s+(\d+(?:\.\d+)?)/) { $B++; $AB++ if $dq{$1+0}; $Ravg+=$AB; @@ -41,7 +41,7 @@ sub Favg { my $a=shift; $Pavg*$Ravg ? 1/($a/$Pavg+(1-$a)/$Ravg) : 0; } $Ravg/=$B*$A if $B; $Pavg/=$B if $B; - printf "%5d %1.12f\n", $qid, Favg(0.5); + printf "%5d %1.12f %1.12f %1.12f\n", $qid, Favg(0),Favg(0.5),Favg(1); } exit 0; diff --git a/myisam/ftbench/README b/myisam/ftbench/README index 649d06d86bb..b1f8b66b15f 100644 --- a/myisam/ftbench/README +++ b/myisam/ftbench/README @@ -1,31 +1,17 @@ 1. should be run from myisam/ftbench/ 2. myisam/ftdefs.h should NOT be locked (bk get, not bk edit!) 3. there should be ./data/ subdir with test collections, files: - test1.test - test1.relj - test2.test - test2.relj + test1.d + test1.q + test1.r + test2.d + test2.q + test2.r where test1, test2, etc - are arbitrary test names - - *.test are SQL files of the structure: -===== -DROP TABLE IF EXISTS ft; -CREATE TABLE ft ( - id int(10) unsigned NOT NULL, - text text NOT NULL, - FULLTEXT KEY text (text) -); -INSERT INTO ft VALUES (1, 'doc1...'),(2, 'doc2...'),... -... + *.[dq] files contain documents/queries one item per line. -SELECT COUNT(*) FROM ft; -SELECT 1, id, MATCH text AGAINST ('query1') FROM ft WHERE MATCH text AGAINST ('query1'); -SELECT 2, id, MATCH text AGAINST ('query2') FROM ft WHERE MATCH text AGAINST ('query2'); -... -===== - - *.relj files have the structure: + *.r files have the structure: 1 16 .....blablabla 1 09 .....blablabla 2 116 .....blablabla @@ -47,7 +33,8 @@ SELECT 2, id, MATCH text AGAINST ('query2') FROM ft WHERE MATCH text AGAINST ('q all test results are compared with BEST results. - test directories *must* contain ftdefs.h, and *may* contain my.cnf + test directories may contain ftdefs.h, my.cnf, ft_mode + (the last one is used as in ... MATCH ... AGAINST ("..." $ft_mode) ...) NOTE: all *.out files in test directories will NOT be overwritten! delete them to re-test diff --git a/myisam/ftbench/ft-test-run.sh b/myisam/ftbench/ft-test-run.sh index 2c04d24a185..ceba818fa5c 100755 --- a/myisam/ftbench/ft-test-run.sh +++ b/myisam/ftbench/ft-test-run.sh @@ -15,12 +15,7 @@ SOCK=$DATA/mysql.sock PID=$DATA/mysql.pid H=../ftdefs.h OPTS="--no-defaults --socket=$SOCK --character-sets-dir=$ROOT/sql/share/charsets" - -# --ft_min_word_len=# -# --ft_max_word_len=# -# --ft_max_word_len_for_sort=# -# --ft_stopword_file=name -# --key_buffer_size=# +DELAY=10 stop_myslqd() { @@ -38,48 +33,66 @@ if [ -w $H ] ; then exit 1 fi -for batch in t/BEST t/* ; do - A=`ls $batch/*.out` - [ ! -d $batch -o -n "$A" ] && continue +stop_myslqd +rm -rf var > /dev/null 2>&1 +mkdir var +mkdir var/test + +for batch in t/* ; do + [ ! -d $batch ] && continue + [ $batch -ef t/BEST -a $batch != t/BEST ] && continue + + rm -rf var/test/* > /dev/null 2>&1 rm -f $H - ln -s $BASE/$batch/ftdefs.h $H - touch $H + if [ -f $BASE/$batch/ftdefs.h ] ; then + cat $BASE/$batch/ftdefs.h > $H + chmod a-wx $H + else + bk get -q $H + fi OPTS="--defaults-file=$BASE/$batch/my.cnf --socket=$SOCK --character-sets-dir=$ROOT/sql/share/charsets" stop_myslqd rm -f $MYSQLD - (cd $ROOT; gmake) + echo "building $batch" + echo "============== $batch ===============" >> var/ft_test.log + (cd $ROOT; gmake) >> var/ft_test.log 2>&1 for prog in $MYSQLD $MYSQL $MYSQLADMIN ; do if [ ! -x $prog ] ; then - echo "No $prog" + echo "build failed: no $prog" exit 1 fi done - rm -rf var 2>&1 >/dev/null - mkdir var - mkdir var/test - + echo "=====================================" >> var/ft_test.log $MYSQLD $OPTS --basedir=$BASE --skip-bdb --pid-file=$PID \ --language=$ROOT/sql/share/english \ --skip-grant-tables --skip-innodb \ - --skip-networking --tmpdir=$DATA & + --skip-networking --tmpdir=$DATA >> var/ft_test.log 2>&1 & - sleep 60 + sleep $DELAY $MYSQLADMIN $OPTS ping if [ $? != 0 ] ; then echo "$MYSQLD refused to start" exit 1 fi - for test in `cd data; echo *.test|sed "s/\.test//g"` ; do - echo "test $batch/$test" - $MYSQL $OPTS --skip-column-names test var/$test.eval - echo "report $batch/$test" - ./Ereport.pl var/$test.eval data/$test.relj > $batch/$test.out || exit + for test in `cd data; echo *.r|sed "s/\.r//g"` ; do + if [ -f $batch/$test.out ] ; then + echo "skipping $batch/$test.out" + continue + fi + echo "testing $batch/$test" + FT_MODE=`cat $batch/ft_mode 2>/dev/null` + ./Ecreate.pl $test "$FT_MODE" | $MYSQL $OPTS --skip-column-names test >var/$test.eval + echo "reporting $batch/$test" + ./Ereport.pl var/$test.eval data/$test.r > $batch/$test.out || exit done stop_myslqd rm -f $H - echo "compare $batch" - [ $batch -ef t/BEST ] || ./Ecompare.pl t/BEST $batch >> t/BEST/report.txt + bk get -q $H + if [ ! $batch -ef t/BEST ] ; then + echo "comparing $batch" + ./Ecompare.pl t/BEST $batch >> t/BEST/report.txt + fi done From d74ecc079f997221941f6631e1335a837469ed5c Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 24 Oct 2003 13:23:06 +0200 Subject: [PATCH 22/23] style fixes --- myisam/ft_parser.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 8ab67aa9c6f..0318bcbed10 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -145,7 +145,7 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end, FT_WORD *word) { - byte *doc=*start; + byte *doc= *start; uint mwc, length; DBUG_ENTER("ft_simple_get_word"); @@ -156,10 +156,10 @@ byte ft_simple_get_word(CHARSET_INFO *cs, byte **start, byte *end, if (true_word_char(cs,*doc)) break; } - mwc=length=0; - for(word->pos=doc; docpos=doc; doc= ft_min_word_len && length < ft_max_word_len && !is_stopword(word->pos, word->len)) { - *start=doc; + *start= doc; DBUG_RETURN(1); } } From 6e17f4f20db21964b1a7802d9f942e0aef8a4d81 Mon Sep 17 00:00:00 2001 From: "serg@serg.mylan" <> Date: Fri, 24 Oct 2003 22:44:48 +0200 Subject: [PATCH 23/23] fixes to Bitmap class --- include/my_bitmap.h | 7 +- mysql-test/r/range.result | 8 +- mysys/my_bitmap.c | 177 +++++++++++++++++--------------------- sql/field.cc | 3 +- sql/field.h | 6 +- sql/ha_berkeley.h | 2 +- sql/ha_innodb.h | 2 +- sql/ha_myisam.cc | 3 +- sql/handler.h | 2 +- sql/mysql_priv.h | 102 +--------------------- sql/opt_range.cc | 21 ++--- sql/opt_range.h | 2 +- sql/sql_bitmap.h | 108 +++++++++++++++++++++++ sql/sql_select.cc | 34 ++++---- sql/table.cc | 6 +- 15 files changed, 237 insertions(+), 246 deletions(-) create mode 100644 sql/sql_bitmap.h diff --git a/include/my_bitmap.h b/include/my_bitmap.h index d3fcece290b..cff2295f45c 100644 --- a/include/my_bitmap.h +++ b/include/my_bitmap.h @@ -25,14 +25,13 @@ typedef struct st_bitmap { uchar *bitmap; uint bitmap_size; - my_bool thread_safe; /* set if several threads access the bitmap */ /* mutex will be acquired for the duration of each bitmap operation if - thread_safe flag is set. Otherwise, we optimize by not acquiring the - mutex + thread_safe flag in bitmap_init was set. Otherwise, we optimize by not + acquiring the mutex */ #ifdef THREAD - pthread_mutex_t mutex; + pthread_mutex_t *mutex; #endif } MY_BITMAP; diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 9f76676ee1a..8c363ef3c89 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -240,11 +240,11 @@ id select_type table type possible_keys key key_len ref rows Extra explain select * from t1, t1 t2 where t1.y = 2 and t2.x between t1.y-1 and t1.y+1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref y y 5 const 1 Using where -1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 1) +1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1) explain select * from t1, t1 t2 where t1.y = 2 and t2.x >= t1.y-1 and t2.x <= t1.y+1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref y y 5 const 1 Using where -1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 1) +1 SIMPLE t2 ALL x NULL NULL NULL 9 Range checked for each record (index map: 0x1) explain select * from t1, t1 t2 where t1.y = 2 and t2.x between 0 and t1.y; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref y y 5 const 1 Using where @@ -267,11 +267,11 @@ INSERT INTO t2 VALUES (0),(0),(1),(1),(2),(2); explain select * from t1, t2 where (t1.key1 thread_safe) - pthread_mutex_lock(&map->mutex); + if (map->mutex) + pthread_mutex_lock(map->mutex); #endif } inline void bitmap_unlock(MY_BITMAP *map) { #ifdef THREAD - if (map->thread_safe) - pthread_mutex_unlock(&map->mutex); + if (map->mutex) + pthread_mutex_unlock(map->mutex); #endif } my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, my_bool thread_safe) { + // for efficiency reasons - MY_BITMAP is heavily used + DBUG_ASSERT((bitmap_size & 7) == 0); + bitmap_size/=8; if (!(map->bitmap=buf) && - !(map->bitmap=(uchar*) my_malloc((bitmap_size+7)/8, - MYF(MY_WME | MY_ZEROFILL)))) + !(map->bitmap=(uchar*)my_malloc(bitmap_size + sizeof(pthread_mutex_t), + MYF(MY_WME | MY_ZEROFILL)))) return 1; - DBUG_ASSERT(bitmap_size != ~(uint) 0); -#ifdef THREAD - if ((map->thread_safe = thread_safe)) - pthread_mutex_init(&map->mutex, MY_MUTEX_INIT_FAST); -#endif map->bitmap_size=bitmap_size; +#ifdef THREAD + if (thread_safe) + { + map->mutex=(pthread_mutex_t *)(map->bitmap+bitmap_size); + pthread_mutex_init(map->mutex, MY_MUTEX_INIT_FAST); + } + else + map->mutex=0; +#endif return 0; } void bitmap_free(MY_BITMAP *map) { +#ifdef THREAD + if (map->mutex) + pthread_mutex_destroy(map->mutex); +#endif if (map->bitmap) { my_free((char*) map->bitmap, MYF(0)); map->bitmap=0; -#ifdef THREAD - if (map->thread_safe) - pthread_mutex_destroy(&map->mutex); -#endif } } void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit) { - DBUG_ASSERT(map->bitmap); - if (bitmap_bit < map->bitmap_size) - { - bitmap_lock(map); - map->bitmap[bitmap_bit / 8] |= (1 << (bitmap_bit & 7)); - bitmap_unlock(map); - } + DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8); + bitmap_lock(map); + map->bitmap[bitmap_bit / 8] |= (1 << (bitmap_bit & 7)); + bitmap_unlock(map); } uint bitmap_set_next(MY_BITMAP *map) { uchar *bitmap=map->bitmap; uint bit_found = MY_BIT_NONE; - uint bitmap_size=map->bitmap_size; + uint bitmap_size=map->bitmap_size*8; uint i; DBUG_ASSERT(map->bitmap); @@ -114,28 +118,25 @@ uint bitmap_set_next(MY_BITMAP *map) void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit) { - DBUG_ASSERT(map->bitmap); - if (bitmap_bit < map->bitmap_size) - { - bitmap_lock(map); - map->bitmap[bitmap_bit / 8] &= ~ (1 << (bitmap_bit & 7)); - bitmap_unlock(map); - } + DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8); + bitmap_lock(map); + map->bitmap[bitmap_bit / 8] &= ~ (1 << (bitmap_bit & 7)); + bitmap_unlock(map); } void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size) { - uint l, m; + uint prefix_bytes, prefix_bits; DBUG_ASSERT(map->bitmap); bitmap_lock(map); - 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); + set_if_smaller(prefix_size, map->bitmap_size*8); + if ((prefix_bytes= prefix_size / 8)) + memset(map->bitmap, 0xff, prefix_bytes); + if ((prefix_bits= prefix_size & 7)) + map->bitmap[prefix_bytes++]= (1 << prefix_bits)-1; + if (prefix_bytes < map->bitmap_size) + bzero(map->bitmap+prefix_bytes, map->bitmap_size-prefix_bytes); bitmap_unlock(map); } @@ -146,27 +147,27 @@ void bitmap_clear_all(MY_BITMAP *map) void bitmap_set_all(MY_BITMAP *map) { - bitmap_set_prefix(map, map->bitmap_size); + bitmap_set_prefix(map, ~0); } my_bool bitmap_is_prefix(MY_BITMAP *map, uint prefix_size) { - uint l=prefix_size/8, m=prefix_size & 7, i, res=0; + uint prefix_bits= prefix_size & 7, res= 0; + uchar *m= map->bitmap, *end_prefix= map->bitmap+prefix_size/8, + *end= map->bitmap+map->bitmap_size; - DBUG_ASSERT(map->bitmap); - if (prefix_size > map->bitmap_size) - return 0; + DBUG_ASSERT(map->bitmap && prefix_size <= map->bitmap_size*8); bitmap_lock(map); - for (i=0; i < l; i++) - if (map->bitmap[i] != 0xff) + while (m < end_prefix) + if (*m++ != 0xff) goto ret; - if (m && map->bitmap[i++] != (1 << m)-1) + if (prefix_bits && *m++ != (1 << prefix_bits)-1) goto ret; - for (m=(map->bitmap_size+7)/8; i < m; i++) - if (map->bitmap[i] != 0) + while (m < end) + if (m++ != 0) goto ret; res=1; @@ -182,38 +183,31 @@ my_bool bitmap_is_clear_all(MY_BITMAP *map) my_bool bitmap_is_set_all(MY_BITMAP *map) { - return bitmap_is_prefix(map, map->bitmap_size); + return bitmap_is_prefix(map, map->bitmap_size*8); } 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; + DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8); + return map->bitmap[bitmap_bit / 8] & (1 << (bitmap_bit & 7)); } my_bool bitmap_is_subset(MY_BITMAP *map1, MY_BITMAP *map2) { - uint l1, l2, i, res=0; - uchar *m1=map1->bitmap, *m2=map2->bitmap; + uint length, res=0; + uchar *m1=map1->bitmap, *m2=map2->bitmap, *end; - DBUG_ASSERT(map1->bitmap); - DBUG_ASSERT(map2->bitmap); + DBUG_ASSERT(map1->bitmap && map2->bitmap && + map1->bitmap_size==map2->bitmap_size); bitmap_lock(map1); bitmap_lock(map2); - l1=(map1->bitmap_size+7)/8; - l2=(map2->bitmap_size+7)/8; - set_if_smaller(l2, l1); + end= m1+map1->bitmap_size; - for (i=0; i < l2; i++) + while (m1 < end) if ((*m1++) & ~(*m2++)) goto ret; - for (; i < l1; i++) - if (*m1++) - goto ret; - res=1; ret: bitmap_unlock(map2); @@ -225,13 +219,12 @@ my_bool bitmap_cmp(MY_BITMAP *map1, MY_BITMAP *map2) { uint res; - DBUG_ASSERT(map1->bitmap); - DBUG_ASSERT(map2->bitmap); + DBUG_ASSERT(map1->bitmap && map2->bitmap && + map1->bitmap_size==map2->bitmap_size); bitmap_lock(map1); bitmap_lock(map2); - res= map1->bitmap_size == map2->bitmap_size && - memcmp(map1->bitmap, map2->bitmap, (map1->bitmap_size+7)/8)==0; + res= memcmp(map1->bitmap, map2->bitmap, map1->bitmap_size)==0; bitmap_unlock(map2); bitmap_unlock(map1); @@ -240,23 +233,17 @@ my_bool bitmap_cmp(MY_BITMAP *map1, MY_BITMAP *map2) void bitmap_intersect(MY_BITMAP *map, MY_BITMAP *map2) { - uint l1, l2, i; - uchar *m=map->bitmap, *m2=map2->bitmap; + uchar *to=map->bitmap, *from=map2->bitmap, *end; - DBUG_ASSERT(map->bitmap); - DBUG_ASSERT(map2->bitmap); + DBUG_ASSERT(map->bitmap && map2->bitmap && + map->bitmap_size==map2->bitmap_size); bitmap_lock(map); bitmap_lock(map2); - l1=(map->bitmap_size+7)/8; - l2=(map2->bitmap_size+7)/8; - set_if_smaller(l2, l1); + end= to+map->bitmap_size; - for (i=0; i < l2; i++) - *m++ &= *m2++; - - if (l1 > l2) - bzero(m, l1-l2); + while (to < end) + *to++ &= *from++; bitmap_unlock(map2); bitmap_unlock(map); @@ -264,20 +251,17 @@ void bitmap_intersect(MY_BITMAP *map, MY_BITMAP *map2) void bitmap_subtract(MY_BITMAP *map, MY_BITMAP *map2) { - uint l1, l2, i; - uchar *m=map->bitmap, *m2=map2->bitmap; + uchar *to=map->bitmap, *from=map2->bitmap, *end; - DBUG_ASSERT(map->bitmap); - DBUG_ASSERT(map2->bitmap); + DBUG_ASSERT(map->bitmap && map2->bitmap && + map->bitmap_size==map2->bitmap_size); bitmap_lock(map); bitmap_lock(map2); - l1=(map->bitmap_size+7)/8; - l2=(map2->bitmap_size+7)/8; - set_if_smaller(l2, l1); + end= to+map->bitmap_size; - for (i=0; i < l2; i++) - *m++ &= ~(*m2++); + while (to < end) + *to++ &= ~(*from++); bitmap_unlock(map2); bitmap_unlock(map); @@ -285,20 +269,17 @@ void bitmap_subtract(MY_BITMAP *map, MY_BITMAP *map2) void bitmap_union(MY_BITMAP *map, MY_BITMAP *map2) { - uint l1, l2, i; - uchar *m=map->bitmap, *m2=map2->bitmap; + uchar *to=map->bitmap, *from=map2->bitmap, *end; - DBUG_ASSERT(map->bitmap); - DBUG_ASSERT(map2->bitmap); + DBUG_ASSERT(map->bitmap && map2->bitmap && + map->bitmap_size==map2->bitmap_size); bitmap_lock(map); bitmap_lock(map2); - l1=(map->bitmap_size+7)/8; - l2=(map2->bitmap_size+7)/8; - set_if_smaller(l2, l1); + end= to+map->bitmap_size; - for (i=0; i < l2; i++) - *m++ |= *m2++; + while (to < end) + *to++ |= *from++; bitmap_unlock(map2); bitmap_unlock(map); diff --git a/sql/field.cc b/sql/field.cc index 98eb0e01f56..c30c06c6395 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -181,7 +181,8 @@ 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),unireg_check(unireg_check_arg), + query_id(0), key_start(0), part_of_key(0), part_of_sortkey(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; diff --git a/sql/field.h b/sql/field.h index eb0af881121..e7d4bb2416a 100644 --- a/sql/field.h +++ b/sql/field.h @@ -151,9 +151,9 @@ public: if (tmp->table->maybe_null) tmp->flags&= ~NOT_NULL_FLAG; tmp->table= new_table; - tmp->key_start.init().clear_all(); - tmp->part_of_key.init().clear_all(); - tmp->part_of_sortkey.init().clear_all(); + tmp->key_start.init(0); + tmp->part_of_key.init(0); + tmp->part_of_sortkey.init(0); tmp->unireg_check=Field::NONE; tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG); diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index 850be48258a..79e52ea71af 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -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;} - const key_map& keys_to_use_for_scanning() { return key_map_full; } + 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); diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 9ef47a105d6..2fa70f27128 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -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;} - const key_map& keys_to_use_for_scanning() { return key_map_full; } + 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); diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index ea356a4f17c..a23e4c55618 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -1023,7 +1023,8 @@ 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_prefix(table->keys).intersect(info.key_map); + table->keys_in_use.set_prefix(table->keys); + table->keys_in_use.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; diff --git a/sql/handler.h b/sql/handler.h index 26671bb5b11..29dea7f213b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -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 const key_map& keys_to_use_for_scanning() { return key_map_empty; } + 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; } diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6bc1031739d..c22ca1c2d3c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -23,113 +23,13 @@ #include #include #include /* Needed by field.h */ -#include +#include #include #ifdef __EMX__ #undef write /* remove pthread.h macro definition for EMX */ #endif -template 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> -{ - ulonglong 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 Bitmap<64> key_map; /* Used for finding keys */ diff --git a/sql/opt_range.cc b/sql/opt_range.cc index cf1838489d0..da6ede8586f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -305,7 +305,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,const 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); @@ -364,6 +364,7 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, SQL_SELECT::SQL_SELECT() :quick(0),cond(0),free_cond(0) { + quick_keys.clear_all(); needed_reg.clear_all(); my_b_clear(&file); } @@ -588,9 +589,9 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, uint idx; double scan_time; DBUG_ENTER("test_quick_select"); -/* DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu", - (ulong) keys_to_use, (ulong) prev_tables, - (ulong) const_tables));*/ + DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu", + keys_to_use.to_ulonglong(), (ulong) prev_tables, + (ulong) const_tables)); delete quick; quick=0; @@ -622,7 +623,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, SEL_TREE *tree; KEY_PART *key_parts; PARAM param; - + /* set up parameter that is passed to all functions */ param.thd= thd; param.baseflag=basflag; @@ -743,7 +744,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, my_pthread_setspecific_ptr(THR_MALLOC,old_root); thd->no_errors=0; } - DBUG_EXECUTE("info",print_quick(quick,needed_reg);); + DBUG_EXECUTE("info",print_quick(quick,&needed_reg);); /* Assume that if the user is using 'limit' we will only need to scan limit rows if we are using a key @@ -2853,7 +2854,7 @@ print_key(KEY_PART *key_part,const char *key,uint used_length) fputc('/',DBUG_FILE); if (field->real_maybe_null()) { - length++; // null byte is not in part_length + length++; // null byte is not in part_length if (*key++) { fwrite("NULL",sizeof(char),4,DBUG_FILE); @@ -2869,7 +2870,7 @@ print_key(KEY_PART *key_part,const char *key,uint used_length) } } -static void print_quick(QUICK_SELECT *quick,const 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]; @@ -2879,8 +2880,8 @@ static void print_quick(QUICK_SELECT *quick,const key_map& needed_reg) List_iterator li(quick->ranges); DBUG_LOCK_FILE; - fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: %s):\n", - quick->index, needed_reg.print(buf)); + fprintf(DBUG_FILE,"Used quick_range on key: %d (other_keys: 0x%s):\n", + quick->index, needed_reg->print(buf)); while ((range=li++)) { if (!(range->flag & NO_MIN_RANGE)) diff --git a/sql/opt_range.h b/sql/opt_range.h index b4d855c0faa..1c209dc7027 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -128,7 +128,7 @@ class SQL_SELECT :public Sql_alloc { SQL_SELECT(); ~SQL_SELECT(); bool check_quick(THD *thd, bool force_quick_range, ha_rows limit) - { return test_quick_select(thd, key_map(~0L),0,limit, force_quick_range) < 0; } + { return test_quick_select(thd, key_map(~0), 0, limit, force_quick_range) < 0; } inline bool skipp_record() { return cond ? cond->val_int() == 0 : 0; } int test_quick_select(THD *thd, key_map keys, table_map prev_tables, ha_rows limit, bool force_quick_range=0); diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h new file mode 100644 index 00000000000..b8e163ce24a --- /dev/null +++ b/sql/sql_bitmap.h @@ -0,0 +1,108 @@ +#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include +#include +#include + +template class Bitmap +{ + MY_BITMAP map; + uchar buffer[(default_width+7)/8]; +public: + Bitmap() { init(); } + Bitmap(uint prefix_to_set) { init(prefix_to_set); } + void init() { bitmap_init(&map, buffer, default_width, 0); } + void init(uint prefix_to_set) { init(); set_prefix(prefix_to_set); } + uint length() const { return default_width; } + Bitmap& operator=(const Bitmap& map2) + { + init(); + memcpy(buffer, map2.buffer, sizeof(buffer)); + } + void set_bit(uint n) { bitmap_set_bit(&map, n); } + void clear_bit(uint n) { bitmap_clear_bit(&map, n); } + void set_prefix(uint n) { bitmap_set_prefix(&map, n); } + void set_all() { bitmap_set_all(&map); } + void clear_all() { bitmap_clear_all(&map); } + void intersect(Bitmap& map2) { bitmap_intersect(&map, &map2.map); } + void intersect(ulonglong map2buff) + { + MY_BITMAP map2; + bitmap_init(&map2, (uchar *)&map2buff, sizeof(ulonglong)*8, 0); + bitmap_intersect(&map, &map2); + } + void subtract(Bitmap& map2) { bitmap_subtract(&map, &map2.map); } + void merge(Bitmap& map2) { bitmap_union(&map, &map2.map); } + my_bool is_set(uint n) const { return bitmap_is_set(&map, n); } + my_bool is_prefix(uint n) const { return bitmap_is_prefix(&map, n); } + my_bool is_clear_all() const { return bitmap_is_clear_all(&map); } + my_bool is_set_all() const { return bitmap_is_set_all(&map); } + my_bool is_subset(const Bitmap& map2) const { return bitmap_is_subset(&map, &map2.map); } + my_bool operator==(const Bitmap& map2) const { return bitmap_cmp(&map, &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) >= 8) + return uint8korr(buffer); + DBUG_ASSERT(sizeof(buffer) >= 4); + uint4korr(buffer); + } +}; + +template <> class Bitmap<64> +{ + ulonglong map; +public: + Bitmap<64>() { } + Bitmap<64>(uint prefix_to_set) { set_prefix(prefix_to_set); } + void init() { } + void init(uint prefix_to_set) { set_prefix(prefix_to_set); } + uint length() const { return 64; } + void set_bit(uint n) { map|= ((ulonglong)1) << n; } + void clear_bit(uint n) { map&= ~(((ulonglong)1) << n); } + void set_prefix(uint n) + { + if (n >= length()) + set_all(); + else + map= (((ulonglong)1) << n)-1; + } + void set_all() { map=~(ulonglong)0; } + void clear_all() { map=(ulonglong)0; } + void intersect(Bitmap<64>& map2) { map&= map2.map; } + void intersect(ulonglong map2) { map&= map2; } + void subtract(Bitmap<64>& map2) { map&= ~map2.map; } + void merge(Bitmap<64>& map2) { map|= map2.map; } + 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; } +}; + diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f25b012a0fa..5c784422bc4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -117,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, const 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, @@ -529,7 +529,7 @@ JOIN::optimize() conds= optimize_cond(conds,&cond_value); if (thd->net.report_error) { - error= 1; + error= 1; DBUG_PRINT("error",("Error from optimize_cond")); DBUG_RETURN(1); } @@ -559,7 +559,7 @@ JOIN::optimize() if (res < 0) { zero_result_cause= "No matching min/max row"; - error=0; + error=0; DBUG_RETURN(0); } zero_result_cause= "Select tables optimized away"; @@ -706,7 +706,7 @@ JOIN::optimize() /* Force MySQL to read the table in sorted order to get result in ORDER BY order. - */ + */ tmp_table_param.quick_group=0; } order=0; @@ -768,7 +768,7 @@ JOIN::optimize() make_join_readinfo(this, (select_options & (SELECT_DESCRIBE | SELECT_NO_JOIN_CACHE)) | - (select_lex->ftfunc_list->elements ? + (select_lex->ftfunc_list->elements ? SELECT_NO_JOIN_CACHE : 0)); /* @@ -1497,7 +1497,7 @@ JOIN::cleanup() int mysql_select(THD *thd, Item ***rref_pointer_array, - TABLE_LIST *tables, uint wild_num, List &fields, + TABLE_LIST *tables, uint wild_num, List &fields, COND *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, ulong select_options, select_result *result, SELECT_LEX_UNIT *unit, @@ -3257,13 +3257,13 @@ make_simple_join(JOIN *join,TABLE *tmp_table) join->row_limit=join->unit->select_limit_cnt; join->do_send_rows = (join->row_limit) ? 1 : 0; - join_tab->cache.buff=0; /* No cacheing */ + join_tab->cache.buff=0; /* No caching */ join_tab->table=tmp_table; join_tab->select=0; join_tab->select_cond=0; join_tab->quick=0; join_tab->type= JT_ALL; /* Map through all records */ - join_tab->keys.init().set_all(); /* test everything in quick */ + join_tab->keys.init(~0); /* test everything in quick */ join_tab->info=0; join_tab->on_expr=0; join_tab->ref.key = -1; @@ -3591,7 +3591,7 @@ make_join_readinfo(JOIN *join, uint options) } 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->index=find_shortest_key(table, & table->used_keys); tab->table->file->index_init(tab->index); tab->read_first_record= join_read_first; tab->type=JT_NEXT; // Read with index_first / index_next @@ -6605,15 +6605,15 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, return reverse; } -static uint find_shortest_key(TABLE *table, const 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; - if (!usable_keys.is_clear_all()) + if (!usable_keys->is_clear_all()) { - for (uint nr=0; nr < usable_keys.length() ; nr++) + for (uint nr=0; nr < table->keys ; nr++) { - if (usable_keys.is_set(nr)) + if (usable_keys->is_set(nr)) { if (table->key_info[nr].key_length < min_length) { @@ -6674,7 +6674,7 @@ 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; nr < usable_keys.length(); nr++) + for (nr= 0 ; nr < table->keys ; nr++) { if (usable_keys.is_set(nr) && table->key_info[nr].key_length < min_length && @@ -6840,7 +6840,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, */ if (select_limit >= table->file->records) { - keys=table->file->keys_to_use_for_scanning(); + keys=*table->file->keys_to_use_for_scanning(); keys.merge(table->used_keys); } else @@ -6848,7 +6848,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, keys.intersect(usable_keys); - for (nr=0; nr < keys.length() ; nr++) + for (nr=0; nr < table->keys ; nr++) { uint not_used; if (keys.is_set(nr)) @@ -8845,7 +8845,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (tab->use_quick == 2) { char buf[MAX_KEY/8+1]; - sprintf(buff_ptr,"; Range checked for each record (index map: %s)", + sprintf(buff_ptr,"; Range checked for each record (index map: 0x%s)", tab->keys.print(buf)); buff_ptr=strend(buff_ptr); } diff --git a/sql/table.cc b/sql/table.cc index 24c5b941c0b..ebe1b51248e 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -166,9 +166,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->keys= keys= disk_buff[0]; outparam->key_parts= key_parts= disk_buff[1]; } - outparam->keys_for_keyread.init().set_prefix(keys); - outparam->keys_in_use.init().set_prefix(keys); - outparam->read_only_keys.init().clear_all(); + outparam->keys_for_keyread.init(keys); + outparam->keys_in_use.init(keys); + outparam->read_only_keys.init(0); outparam->quick_keys.init(); outparam->used_keys.init(); outparam->keys_in_use_for_query.init();