diff options
author | unknown <serg@serg.mysql.com> | 2003-01-21 19:24:34 +0100 |
---|---|---|
committer | unknown <serg@serg.mysql.com> | 2003-01-21 19:24:34 +0100 |
commit | 76078f2c8417df4695f14b75fc4711417d1f3c08 (patch) | |
tree | 2c7d9d1b4d148a8335c0f806f6c7bc3dcab8e3ce | |
parent | e503a5807d12c8f08ae4a791d97f8507eb90bb38 (diff) | |
download | mariadb-git-76078f2c8417df4695f14b75fc4711417d1f3c08.tar.gz |
Two-level index structure for FULLTEXT indexes
myisam/ftdefs.h:
intermediate cleanup checkin
myisam/mi_create.c:
intermediate cleanup checkin
myisam/myisamchk.c:
intermediate cleanup checkin
myisam/ft_parser.c:
intermediate cleanup checkin
myisam/ft_update.c:
intermediate cleanup checkin
myisam/mi_update.c:
intermediate cleanup checkin
mysql-test/r/fulltext.result:
stopword test
mysql-test/t/fulltext.test:
stopword test
mysys/mulalloc.c:
function comments clarified
include/my_handler.h:
get_key_length_rdonly utility macro
include/myisam.h:
this kind of hacks bites :)
myisam/ft_dump.c:
bugfix
myisam/mi_open.c:
bugfix
myisam/sort.c:
bugfixing
myisam/mi_rnext.c:
not a solution at all, but a temporary fix to make
mi_rnext to work on ft2 index. (only ft_dump uses mi_rnext
on fulltext indexes for now).
myisam/ft_boolean_search.c:
ft_sintXkorr, ft_intXstore
myisam/ft_nlq_search.c:
ft_sintXkorr, ft_intXstore
myisam/fulltext.h:
ft_sintXkorr, ft_intXstore
myisam/mi_check.c:
ft_sintXkorr, ft_intXstore
myisam/ft_static.c:
two-level tree support in wi_write()
myisam/mi_write.c:
two-level tree support in wi_write()
myisam/myisamdef.h:
two-level tree support in wi_write()
myisam/mi_delete.c:
support for ft2 in mi_delete
mysql-test/r/fulltext2.result:
support for ft2 in mi_delete
mysql-test/t/fulltext2.test:
support for ft2 in mi_delete
-rw-r--r-- | include/my_handler.h | 13 | ||||
-rw-r--r-- | include/myisam.h | 9 | ||||
-rw-r--r-- | myisam/ft_boolean_search.c | 199 | ||||
-rw-r--r-- | myisam/ft_dump.c | 21 | ||||
-rw-r--r-- | myisam/ft_nlq_search.c | 85 | ||||
-rw-r--r-- | myisam/ft_parser.c | 32 | ||||
-rw-r--r-- | myisam/ft_static.c | 18 | ||||
-rw-r--r-- | myisam/ft_update.c | 10 | ||||
-rw-r--r-- | myisam/ftdefs.h | 13 | ||||
-rw-r--r-- | myisam/fulltext.h | 11 | ||||
-rw-r--r-- | myisam/mi_check.c | 163 | ||||
-rw-r--r-- | myisam/mi_create.c | 45 | ||||
-rw-r--r-- | myisam/mi_delete.c | 97 | ||||
-rw-r--r-- | myisam/mi_open.c | 64 | ||||
-rw-r--r-- | myisam/mi_rnext.c | 18 | ||||
-rw-r--r-- | myisam/mi_update.c | 2 | ||||
-rw-r--r-- | myisam/mi_write.c | 77 | ||||
-rw-r--r-- | myisam/myisamchk.c | 4 | ||||
-rw-r--r-- | myisam/myisamdef.h | 25 | ||||
-rw-r--r-- | myisam/sort.c | 23 | ||||
-rw-r--r-- | mysql-test/r/fulltext.result | 2 | ||||
-rw-r--r-- | mysql-test/r/fulltext2.result | 871 | ||||
-rw-r--r-- | mysql-test/t/fulltext.test | 1 | ||||
-rw-r--r-- | mysql-test/t/fulltext2.test | 93 | ||||
-rw-r--r-- | mysys/mulalloc.c | 14 |
25 files changed, 1556 insertions, 354 deletions
diff --git a/include/my_handler.h b/include/my_handler.h index 629a0974d93..618d1df1a6e 100644 --- a/include/my_handler.h +++ b/include/my_handler.h @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. - + You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, @@ -43,6 +43,13 @@ typedef struct st_HA_KEYSEG /* Key-portion */ { length=mi_uint2korr((key)+1); (key)+=3; } \ } +#define get_key_length_rdonly(length,key) \ +{ if ((uchar) *(key) != 255) \ + length= ((uint) (uchar) *((key))); \ + else \ + { length=mi_uint2korr((key)+1); } \ +} + #define get_key_pack_length(length,length_pack,key) \ { if ((uchar) *(key) != 255) \ { length= (uint) (uchar) *((key)++); length_pack=1; }\ diff --git a/include/myisam.h b/include/myisam.h index 4f8fc149ba1..088fcb9c37f 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -342,6 +342,12 @@ typedef struct st_mi_check_param char *op_name; } MI_CHECK; +typedef struct st_sort_ft_buf +{ + uchar *buf, *end; + int count; + uchar lastkey[MI_MAX_KEY_BUFF]; +} SORT_FT_BUF; typedef struct st_sort_info { @@ -354,7 +360,8 @@ typedef struct st_sort_info MI_CHECK *param; char *buff; SORT_KEY_BLOCKS *key_block,*key_block_end; - /* sync things*/ + SORT_FT_BUF *ft_buf; + /* sync things */ uint got_error, threads_running; pthread_mutex_t mutex; pthread_cond_t cond; diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 6749de06ee2..190dc5206b1 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -21,6 +21,7 @@ #define FT_CORE #include "ftdefs.h" #include <queues.h> +#include <assert.h> /* for DBUG_ASSERT() */ /* search with boolean queries */ @@ -63,42 +64,44 @@ struct st_ftb_expr { FTB_EXPR *up; byte *quot, *qend; - float weight; - uint flags; my_off_t docid[2]; /* for index search and for scan */ + float weight; float cur_weight; - int yesses; /* number of "yes" words matched */ - int nos; /* number of "no" words matched */ - int ythresh; /* number of "yes" words in expr */ - int yweaks; /* number of "yes" words for scan only */ + uint flags; + uint yesses; /* number of "yes" words matched */ + uint nos; /* number of "no" words matched */ + uint ythresh; /* number of "yes" words in expr */ + uint yweaks; /* number of "yes" words for scan only */ }; typedef struct st_ftb_word { - FTB_EXPR *up; - float weight; - uint flags; - my_off_t docid[2]; /* for index search and for scan */ - uint ndepth; - int len; - /* ... docid cache can be added here. SerG */ - byte word[1]; + FTB_EXPR *up; + MI_KEYDEF *keyinfo; + my_off_t docid[2]; /* for index search and for scan */ + my_off_t key_root; + float weight; + uint ndepth; + uint flags; + uint len; + uchar off; + byte word[1]; } FTB_WORD; typedef struct st_ft_info { struct _ft_vft *please; MI_INFO *info; - uint keynr; CHARSET_INFO *charset; - enum { UNINITIALIZED, READY, INDEX_SEARCH, INDEX_DONE /*, SCAN*/ } state; - uint with_scan; - my_off_t lastpos; FTB_EXPR *root; - QUEUE queue; - TREE no_dupes; FTB_WORD **list; MEM_ROOT mem_root; + QUEUE queue; + TREE no_dupes; + my_off_t lastpos; + uint keynr; + uchar with_scan; + enum { UNINITIALIZED, READY, INDEX_SEARCH, INDEX_DONE } state; } FTB; static int FTB_WORD_cmp(my_off_t *v, FTB_WORD *a, FTB_WORD *b) @@ -160,6 +163,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, ftbw->up=up; ftbw->docid[0]=ftbw->docid[1]=HA_POS_ERROR; ftbw->ndepth= (param.yesno<0) + depth; + ftbw->key_root=HA_POS_ERROR; memcpy(ftbw->word+1, w.pos, w.len); ftbw->word[0]=w.len; if (param.yesno > 0) up->ythresh++; @@ -194,22 +198,98 @@ static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)), return CMP_NUM((*((my_off_t*)a)), (*((my_off_t*)b))); } +/* returns 1 if the search was finished (must-word wasn't found) */ +static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) +{ + int r; + uint off; + int subkeys; + MI_INFO *info=ftb->info; + + if (init_search) + { + ftbw->key_root=info->s->state.key_root[ftb->keynr]; + ftbw->keyinfo=info->s->keyinfo+ftb->keynr; + ftbw->off=0; + + r=_mi_search(info, ftbw->keyinfo, (uchar*) ftbw->word, ftbw->len, + SEARCH_FIND | SEARCH_BIGGER, ftbw->key_root); + } + else + { + r=_mi_search(info, ftbw->keyinfo, (uchar*) ftbw->word+ftbw->off, + USE_WHOLE_KEY, SEARCH_BIGGER, ftbw->key_root); + } + if (!r && !ftbw->off) + { + r= mi_compare_text(ftb->charset, + info->lastkey + (ftbw->flags & FTB_FLAG_TRUNC), + ftbw->len - (ftbw->flags & FTB_FLAG_TRUNC), + (uchar*) ftbw->word + (ftbw->flags & FTB_FLAG_TRUNC), + ftbw->len - (ftbw->flags & FTB_FLAG_TRUNC), + 0); + } + + if (r) /* not found */ + { + if (!ftbw->off || !(ftbw->flags & FTB_FLAG_TRUNC)) + { + ftbw->docid[0]=HA_POS_ERROR; + if ((ftbw->flags & FTB_FLAG_YES) && ftbw->up->up==0) + { + /* + This word MUST BE present in every document returned, + so we can stop the search right now + */ + ftb->state=INDEX_DONE; + return 1; /* search is done */ + } + else + return 0; + } + + /* going up to the first-level tree to continue search there */ + _mi_dpointer(info, ftbw->word+ftbw->off+HA_FT_WLEN, ftbw->key_root); + ftbw->key_root=info->s->state.key_root[ftb->keynr]; + ftbw->keyinfo=info->s->keyinfo+ftb->keynr; + ftbw->off=0; + return _ft2_search(ftb, ftbw, 0); + } + + /* matching key found */ + memcpy(ftbw->word+ftbw->off, info->lastkey, info->lastkey_length); + if (!ftbw->off && (init_search || (ftbw->flags & FTB_FLAG_TRUNC))) + { + /* going down ? */ + get_key_full_length_rdonly(off, info->lastkey); + subkeys=ft_sintXkorr(info->lastkey+off); + if (subkeys<0) + { + /* yep, going down, to the second-level tree */ + /* TODO here: subkey-based optimization */ + ftbw->off=off; + ftbw->key_root=info->lastpos; + ftbw->keyinfo=& info->s->ft2_keyinfo; + r=_mi_search_first(info, ftbw->keyinfo, ftbw->key_root); + DBUG_ASSERT(r==0); /* found something */ + memcpy(ftbw->word+off, info->lastkey, info->lastkey_length); + } + } + ftbw->docid[0]=info->lastpos; + return 0; +} + static void _ftb_init_index_search(FT_INFO *ftb) { - int i, r; + int i; FTB_WORD *ftbw; MI_INFO *info=ftb->info; - MI_KEYDEF *keyinfo; - my_off_t keyroot; if ((ftb->state != READY && ftb->state !=INDEX_DONE) || ftb->keynr == NO_SUCH_KEY) return; ftb->state=INDEX_SEARCH; - keyinfo=info->s->keyinfo+ftb->keynr; - keyroot=info->s->state.key_root[ftb->keynr]; - for (i=ftb->queue.elements; i; i--) { ftbw=(FTB_WORD *)(ftb->queue.root[i]); @@ -248,34 +328,9 @@ static void _ftb_init_index_search(FT_INFO *ftb) } } } - r=_mi_search(info, keyinfo, (uchar*) ftbw->word, ftbw->len, - SEARCH_FIND | SEARCH_BIGGER, keyroot); - if (!r) - { - r= mi_compare_text(ftb->charset, - info->lastkey + (ftbw->flags&FTB_FLAG_TRUNC), - ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC), - (uchar*) ftbw->word + (ftbw->flags&FTB_FLAG_TRUNC), - ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC), - 0); - } - if (r) /* not found */ - { - if (ftbw->flags&FTB_FLAG_YES && ftbw->up->up==0) - { - /* - This word MUST BE present in every document returned, - so we can abort the search right now - */ - ftb->state=INDEX_DONE; - return; - } - } - else - { - memcpy(ftbw->word, info->lastkey, info->lastkey_length); - ftbw->docid[0]=info->lastpos; - } + + if (_ft2_search(ftb, ftbw, 1)) + return; } queue_fix(& ftb->queue); } @@ -436,10 +491,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) FTB_EXPR *ftbe; FTB_WORD *ftbw; MI_INFO *info=ftb->info; - MI_KEYDEF *keyinfo=info->s->keyinfo+ftb->keynr; - my_off_t keyroot=info->s->state.key_root[ftb->keynr]; my_off_t curdoc; - int r; if (ftb->state != INDEX_SEARCH && ftb->state != INDEX_DONE) return -1; @@ -466,34 +518,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) _ftb_climb_the_tree(ftb, ftbw, 0); /* update queue */ - r=_mi_search(info, keyinfo, (uchar*) ftbw->word, USE_WHOLE_KEY, - SEARCH_BIGGER , keyroot); - if (!r) - { - r= mi_compare_text(ftb->charset, - info->lastkey + (ftbw->flags&FTB_FLAG_TRUNC), - ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC), - (uchar*) ftbw->word + (ftbw->flags&FTB_FLAG_TRUNC), - ftbw->len - (ftbw->flags&FTB_FLAG_TRUNC), - 0); - } - if (r) /* not found */ - { - ftbw->docid[0]=HA_POS_ERROR; - if (ftbw->flags&FTB_FLAG_YES && ftbw->up->up==0) - { - /* - This word MUST BE present in every document returned, - so we can stop the search right now - */ - ftb->state=INDEX_DONE; - } - } - else - { - memcpy(ftbw->word, info->lastkey, info->lastkey_length); - ftbw->docid[0]=info->lastpos; - } + _ft2_search(ftb, ftbw, 0); queue_replaced(& ftb->queue); } @@ -503,9 +528,9 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) { /* curdoc matched ! */ if (is_tree_inited(&ftb->no_dupes) && - tree_insert(&ftb->no_dupes, &curdoc, 0, + tree_insert(&ftb->no_dupes, &curdoc, 0, ftb->no_dupes.custom_arg)->count >1) - /* but it managed to get past this line once */ + /* but it managed already to get past this line once */ continue; info->lastpos=curdoc; diff --git a/myisam/ft_dump.c b/myisam/ft_dump.c index d430b611836..3ecb0652eea 100644 --- a/myisam/ft_dump.c +++ b/myisam/ft_dump.c @@ -56,7 +56,7 @@ static struct my_option my_long_options[] = int main(int argc,char *argv[]) { - int error=0; + int error=0, subkeys; uint keylen, keylen2=0, inx, doc_cnt=0; float weight; double gws, min_gws=0, avg_gws=0; @@ -125,7 +125,9 @@ int main(int argc,char *argv[]) keylen=*(info->lastkey); #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT - mi_float4get(weight,info->lastkey+keylen+1); + subkeys=mi_sint4korr(info->lastkey+keylen+1); + if (subkeys >= 0) + weight=*(float*)&subkeys; #else #error #endif @@ -164,7 +166,10 @@ int main(int argc,char *argv[]) } } if (dump) - printf("%9qx %20.7f %s\n",info->lastpos,weight,buf); + if (subkeys>=0) + printf("%9qx %20.7f %s\n",info->lastpos,weight,buf); + else + printf("%9qx => %17d %s\n",info->lastpos,-subkeys,buf); if(verbose && (total%HOW_OFTEN_TO_WRITE)==0) printf("%10ld\r",total); @@ -216,18 +221,18 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), { switch(optid) { case 'd': - dump=1; + dump=1; complain(count || query); break; - case 's': - stats=1; + case 's': + stats=1; complain(query!=0); break; - case 'c': + case 'c': count= 1; complain(dump || query); break; - case 'l': + case 'l': lstats=1; complain(query!=0); break; diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index f9c276de32f..b1d7d67ae79 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -42,8 +42,6 @@ typedef struct st_all_in_one uint keynr; CHARSET_INFO *charset; uchar *keybuff; - MI_KEYDEF *keyinfo; - my_off_t key_root; TREE dtree; } ALL_IN_ONE; @@ -66,13 +64,14 @@ static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)), static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) { + int subkeys; uint keylen, r, doc_cnt; -#ifdef EVAL_RUN - uint cnt; - double sum, sum2, suml; -#endif /* EVAL_RUN */ FT_SUPERDOC sdoc, *sptr; TREE_ELEMENT *selem; + MI_INFO *info=aio->info; + uchar *keybuff=aio->keybuff; + MI_KEYDEF *keyinfo=info->s->keyinfo+aio->keynr; + my_off_t key_root=info->s->state.key_root[aio->keynr]; #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT float tmp_weight; #else @@ -83,44 +82,45 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) word->weight=LWS_FOR_QUERY; - keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0); -#ifdef EVAL_RUN - keylen-=1+HA_FT_WLEN; -#else /* EVAL_RUN */ + keylen=_ft_make_key(info,aio->keynr,(char*) keybuff,word,0); keylen-=HA_FT_WLEN; -#endif /* EVAL_RUN */ - -#ifdef EVAL_RUN - sum=sum2=suml= -#endif /* EVAL_RUN */ doc_cnt=0; - r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, - SEARCH_FIND | SEARCH_PREFIX, aio->key_root); + r=_mi_search(info, keyinfo, keybuff, keylen, SEARCH_FIND, key_root); + info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */ while (!r) { - if (mi_compare_text(aio->charset, - aio->info->lastkey,keylen, - aio->keybuff,keylen,0)) + + if (keylen && + mi_compare_text(aio->charset,info->lastkey,keylen, keybuff,keylen,0)) break; + subkeys=ft_sintXkorr(info->lastkey+keylen); + if (subkeys<0) + { + if (doc_cnt) + DBUG_RETURN(1); /* index is corrupted */ + /* + TODO here: unsafe optimization, should this word + be skipped (based on subkeys) ? + */ + keybuff+=keylen; + keyinfo=& info->s->ft2_keyinfo; + key_root=info->lastpos; + keylen=0; + r=_mi_search_first(info, keyinfo, key_root); + continue; + } #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT -#ifdef EVAL_RUN - mi_float4get(tmp_weight,aio->info->lastkey+keylen+1); -#else /* EVAL_RUN */ - mi_float4get(tmp_weight,aio->info->lastkey+keylen); -#endif /* EVAL_RUN */ + tmp_weight=*(float*)&subkeys; #else #error #endif - if(tmp_weight==0) DBUG_RETURN(doc_cnt); /* stopword, doc_cnt should be 0 */ + if (tmp_weight==0) + DBUG_RETURN(doc_cnt); /* stopword, doc_cnt should be 0 */ -#ifdef EVAL_RUN - cnt=*(byte *)(aio->info->lastkey+keylen); -#endif /* EVAL_RUN */ - - sdoc.doc.dpos=aio->info->lastpos; + sdoc.doc.dpos=info->lastpos; /* saving document matched into dtree */ if (!(selem=tree_insert(&aio->dtree, &sdoc, 0, aio->dtree.custom_arg))) @@ -137,20 +137,13 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) sptr->tmp_weight=tmp_weight; doc_cnt++; -#ifdef EVAL_RUN - sum +=cnt; - sum2+=cnt*cnt; - suml+=cnt*log(cnt); -#endif /* EVAL_RUN */ - - if (_mi_test_if_changed(aio->info) == 0) - r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey, - aio->info->lastkey_length, SEARCH_BIGGER, - aio->key_root); + + if (_mi_test_if_changed(info) == 0) + r=_mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length, + SEARCH_BIGGER, key_root); else - r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey, - aio->info->lastkey_length, SEARCH_BIGGER, - aio->key_root); + r=_mi_search(info, keyinfo, info->lastkey, info->lastkey_length, + SEARCH_BIGGER, key_root); } if (doc_cnt) { @@ -200,10 +193,8 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, aio.info=info; aio.keynr=keynr; - aio.keyinfo=info->s->keyinfo+keynr; - aio.charset=aio.keyinfo->seg->charset; + aio.charset=info->s->keyinfo[keynr].seg->charset; aio.keybuff=info->lastkey+info->s->base.max_key_length; - aio.key_root=info->s->state.key_root[keynr]; bzero(&allocated_wtree,sizeof(allocated_wtree)); diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 358706a8ffa..14c67333734 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -18,21 +18,10 @@ #include "ftdefs.h" -#ifdef EVAL_RUN -#ifdef PIVOT_STAT -ulong collstat=0; -#endif -#endif /* EVAL_RUN */ - typedef struct st_ft_docstat { FT_WORD *list; uint uniq; double sum; -#ifdef EVAL_RUN - uint words, totlen; - double max, nsum, nsum2; -#endif /* EVAL_RUN */ - } FT_DOCSTAT; static int FT_WORD_cmp(CHARSET_INFO* cs, FT_WORD *w1, FT_WORD *w2) @@ -44,15 +33,7 @@ static int FT_WORD_cmp(CHARSET_INFO* cs, FT_WORD *w1, FT_WORD *w2) static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat) { word->weight=LWS_IN_USE; - -#ifdef EVAL_RUN - word->cnt= (uchar) count; - if(docstat->max < word->weight) docstat->max=word->weight; - docstat->words+=count; - docstat->totlen+=word->len; -#endif /* EVAL_RUN */ docstat->sum+=word->weight; - memcpy_fixed((docstat->list)++,word,sizeof(FT_WORD)); return 0; } @@ -70,9 +51,6 @@ FT_WORD * ft_linearize(TREE *wtree) { docstat.list=wlist; docstat.uniq=wtree->elements_in_tree; -#ifdef EVAL_RUN - docstat.nsum=docstat.nsum2=docstat.max=docstat.words=docstat.totlen= -#endif /* EVAL_RUN */ docstat.sum=0; tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right); } @@ -85,18 +63,8 @@ FT_WORD * ft_linearize(TREE *wtree) for (p=wlist;p->pos;p++) { p->weight=PRENORM_IN_USE; -#ifdef EVAL_RUN - docstat.nsum+=p->weight; - docstat.nsum2+=p->weight*p->weight; -#endif /* EVAL_RUN */ } -#ifdef EVAL_RUN -#ifdef PIVOT_STAT - collstat+=PIVOT_STAT; -#endif -#endif /* EVAL_RUN */ - for (p=wlist;p->pos;p++) { p->weight/=NORM_IN_USE; diff --git a/myisam/ft_static.c b/myisam/ft_static.c index 5c2629e9e9e..b714a7f0c35 100644 --- a/myisam/ft_static.c +++ b/myisam/ft_static.c @@ -26,25 +26,21 @@ const char *ft_boolean_syntax="+ -><()~*:\"\"&|"; const HA_KEYSEG ft_keysegs[FT_SEGS]={ { HA_KEYTYPE_VARTEXT, /* type */ - 7, /* language (will be overwritten) */ + 63, /* language (will be overwritten) */ 0, 0, 0, /* null_bit, bit_start, bit_end */ HA_VAR_LENGTH | HA_PACK_KEY, /* flag */ HA_FT_MAXLEN, /* length */ -#ifdef EVAL_RUN - HA_FT_WLEN+1, /* start */ -#else /* EVAL_RUN */ HA_FT_WLEN, /* start */ -#endif /* EVAL_RUN */ 0, /* null_pos */ NULL /* charset */ }, -#ifdef EVAL_RUN { - HA_KEYTYPE_INT8, 7, 0, 0, 0, 0, 1, HA_FT_WLEN, 0, NULL - }, -#endif /* EVAL_RUN */ - { - HA_FT_WTYPE, 7, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, 0, 0, NULL +/* + Note, this (and the last HA_KEYTYPE_END) segment should NOT + be packed in any way, otherwise w_search() won't be able to + update key entry 'in vivo' +*/ + HA_FT_WTYPE, 63, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, 0, 0, NULL } }; diff --git a/myisam/ft_update.c b/myisam/ft_update.c index 41876028104..4b6d1c4bffc 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -31,7 +31,7 @@ void _mi_ft_segiterator_init(MI_INFO *info, uint keynr, const byte *record, FT_SEG_ITERATOR *ftsi) { - ftsi->num=info->s->keyinfo[keynr].keysegs-FT_SEGS; + ftsi->num=info->s->keyinfo[keynr].keysegs; ftsi->seg=info->s->keyinfo[keynr].seg; ftsi->rec=record; } @@ -113,7 +113,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, if (_mi_ft_parse(&ptree, info, keynr, record)) return NULL; - return ft_linearize(/*info, keynr, keybuf, */ &ptree); + return ft_linearize(&ptree); } static int _mi_ft_store(MI_INFO *info, uint keynr, byte *keybuf, @@ -267,13 +267,7 @@ uint _ft_make_key(MI_INFO *info, uint keynr, byte *keybuf, FT_WORD *wptr, #error #endif -#ifdef EVAL_RUN - *(buf+HA_FT_WLEN)=wptr->cnt; - int2store(buf+HA_FT_WLEN+1,wptr->len); - memcpy(buf+HA_FT_WLEN+3,wptr->pos,wptr->len); -#else /* EVAL_RUN */ int2store(buf+HA_FT_WLEN,wptr->len); memcpy(buf+HA_FT_WLEN+2,wptr->pos,wptr->len); -#endif /* EVAL_RUN */ return _mi_make_key(info,keynr,(uchar*) keybuf,buf,filepos); } diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index 592b60a0133..88d7e79937b 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -60,16 +60,6 @@ #define NORM_SUM (docstat.nsum) #define NORM_COS (sqrt(docstat.nsum2)) -#ifdef EVAL_RUN -/* -extern ulong collstat; -#define PIVOT_STAT (docstat.uniq) -#define PIVOT_SLOPE (0.69) -#define PIVOT_PIVOT ((double)collstat/(info->state->records+1)) -#define NORM_PIVOT ((1-PIVOT_SLOPE)*PIVOT_PIVOT+PIVOT_SLOPE*docstat.uniq) -*/ -#endif /* EVAL_RUN */ - #define PIVOT_VAL (0.0115) #define NORM_PIVOT (1+PIVOT_VAL*docstat.uniq) /*---------------------------------------------------------------*/ @@ -102,9 +92,6 @@ typedef struct st_ft_word { byte * pos; uint len; double weight; -#ifdef EVAL_RUN - byte cnt; -#endif /* EVAL_RUN */ } FT_WORD; typedef struct st_ftb_param { diff --git a/myisam/fulltext.h b/myisam/fulltext.h index 39801c1c87e..ec267eb3e86 100644 --- a/myisam/fulltext.h +++ b/myisam/fulltext.h @@ -21,19 +21,16 @@ #include "myisamdef.h" #include "ft_global.h" -/* shoudn't be def'ed when linking with mysql */ -#undef EVAL_RUN - #define HA_FT_WTYPE HA_KEYTYPE_FLOAT #define HA_FT_WLEN 4 -#ifdef EVAL_RUN -#define FT_SEGS 3 -#else /* EVAL_RUN */ #define FT_SEGS 2 -#endif /* EVAL_RUN */ + +#define ft_sintXkorr(A) mi_sint4korr(A) +#define ft_intXstore(T,A) mi_int4store(T,A) extern const HA_KEYSEG ft_keysegs[FT_SEGS]; 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); + diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 34222a5703b..1502e719b7d 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -49,10 +49,11 @@ static int sort_key_read(MI_SORT_PARAM *sort_param,void *key); static int sort_ft_key_read(MI_SORT_PARAM *sort_param,void *key); static int sort_get_next_record(MI_SORT_PARAM *sort_param); static int sort_key_cmp(MI_SORT_PARAM *sort_param, const void *a,const void *b); +static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a); static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a); static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo, uchar *key); -static int sort_insert_key(MI_SORT_PARAM *sort_param, +static int sort_insert_key(MI_SORT_PARAM *sort_param, reg1 SORT_KEY_BLOCKS *key_block, uchar *key, my_off_t prev_block); static int sort_delete_record(MI_SORT_PARAM *sort_param); @@ -1890,7 +1891,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records : (ha_rows) (sort_info.filelength/length+1)); sort_param.key_cmp=sort_key_cmp; - sort_param.key_write=sort_key_write; sort_param.lock_in_memory=lock_memory; sort_param.tmpdir=param->tmpdir; sort_param.sort_info=&sort_info; @@ -1943,10 +1943,14 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, (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; } else + { sort_param.key_read=sort_key_read; + sort_param.key_write=sort_key_write; + } if (_create_index_by_sort(&sort_param, (my_bool) (!(param->testflag & T_VERBOSE)), @@ -1992,9 +1996,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, else info->state->data_file_length=sort_param.max_pos; - /*if (flush_pending_blocks(param)) - goto err;*/ - param->read_cache.file=info->dfile; /* re-init read cache */ reinit_io_cache(¶m->read_cache,READ_CACHE,share->pack.header_length, 1,1); @@ -2093,6 +2094,7 @@ err: MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_param.record,MYF(MY_ALLOW_ZERO_PTR)); my_free((gptr) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR)); + my_free((gptr) sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR)); VOID(end_io_cache(¶m->read_cache)); info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); @@ -2108,7 +2110,7 @@ err: Threaded repair of table using sorting SYNOPSIS - mi_repair_by_sort_r() + mi_repair_by_sort_parallel() param Repair parameters info MyISAM handler to repair name Name of table (for warnings) @@ -2280,10 +2282,17 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, } if ((!(param->testflag & T_SILENT))) printf ("- Fixing index %d\n",key+1); - sort_param[i].key_read= ((sort_param[i].keyinfo->flag & HA_FULLTEXT) ? - sort_ft_key_read : sort_key_read); + if (sort_param[i].keyinfo->flag & HA_FULLTEXT) + { + sort_param[i].key_read=sort_ft_key_read; + sort_param[i].key_write=sort_ft_key_write; + } + else + { + sort_param[i].key_read=sort_key_read; + sort_param[i].key_write=sort_key_write; + } sort_param[i].key_cmp=sort_key_cmp; - sort_param[i].key_write=sort_key_write; sort_param[i].lock_in_memory=lock_memory; sort_param[i].tmpdir=param->tmpdir; sort_param[i].sort_info=&sort_info; @@ -2476,6 +2485,7 @@ err: pthread_cond_destroy (&sort_info.cond); pthread_mutex_destroy(&sort_info.mutex); + my_free((gptr) sort_info.ft_buf, MYF(MY_ALLOW_ZERO_PTR)); my_free((gptr) sort_info.key_block,MYF(MY_ALLOW_ZERO_PTR)); my_free((gptr) sort_param,MYF(MY_ALLOW_ZERO_PTR)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR)); @@ -3110,6 +3120,137 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) (uchar*) a, HA_OFFSET_ERROR)); } /* sort_key_write */ +int sort_ft_buf_flush(MI_SORT_PARAM *sort_param) +{ + SORT_INFO *sort_info=sort_param->sort_info; + SORT_KEY_BLOCKS *key_block=sort_info->key_block; + MYISAM_SHARE *share=sort_info->info->s; + uint val_off, val_len, error; + SORT_FT_BUF *ft_buf=sort_info->ft_buf; + uchar *from, *to; + + val_len=share->ft2_keyinfo.keylength; + get_key_full_length_rdonly(val_off, ft_buf->lastkey); + to=ft_buf->lastkey+val_off; + + if (ft_buf->buf) + { /* flushing first-level tree */ + error=sort_insert_key(sort_param,key_block,ft_buf->lastkey,HA_OFFSET_ERROR); + for (from=to+val_len; + !error && from < ft_buf->buf; + from+= val_len) + { + memcpy(to, from, val_len); + error=sort_insert_key(sort_param,key_block,ft_buf->lastkey,HA_OFFSET_ERROR); + } + return error; + } + /* flushing second-level tree keyblocks */ + error=flush_pending_blocks(sort_param); + /* updating lastkey with second-level tree info */ + ft_intXstore(ft_buf->lastkey+val_off, -ft_buf->count); + _mi_dpointer(sort_info->info, ft_buf->lastkey+val_off+HA_FT_WLEN, + share->state.key_root[sort_param->key]); + /* restoring first level tree data in sort_info/sort_param */ + sort_info->key_block=sort_info->key_block_end- sort_info->param->sort_key_blocks; + sort_param->keyinfo=share->keyinfo+sort_param->key; + share->state.key_root[sort_param->key]=HA_OFFSET_ERROR; + /* writing lastkey in first-level tree */ + return error ? error : + sort_insert_key(sort_param,sort_info->key_block, + ft_buf->lastkey,HA_OFFSET_ERROR); +} + +static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a) +{ + uint a_len, val_off, val_len, error; + uchar *p; + SORT_INFO *sort_info=sort_param->sort_info; + SORT_FT_BUF *ft_buf=sort_info->ft_buf; + SORT_KEY_BLOCKS *key_block=sort_info->key_block; + + val_len=HA_FT_WLEN+sort_info->info->s->base.rec_reflength; + get_key_full_length_rdonly(a_len, (uchar *)a); + + if (!ft_buf) + { + /* + use two-level tree only if key_reflength fits in rec_reflength place + and row format is NOT static - for _mi_dpointer not to garble offsets + */ + if ((sort_info->info->s->base.key_reflength <= + sort_info->info->s->base.rec_reflength) && + (sort_info->info->s->options & + (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD))) + ft_buf=(SORT_FT_BUF *)my_malloc(sort_param->keyinfo->block_length + + sizeof(SORT_FT_BUF), MYF(MY_WME)); + + if (!ft_buf) + { + sort_param->key_write=sort_key_write; + return sort_key_write(sort_param, a); + } + sort_info->ft_buf=ft_buf; + goto word_init_ft_buf; /* no need to duplicate the code */ + } + get_key_full_length_rdonly(val_off, ft_buf->lastkey); + + if (val_off == a_len && + mi_compare_text(sort_param->keyinfo->seg->charset, + ((uchar *)a)+1,a_len-1, + ft_buf->lastkey+1,val_off-1, 0)==0) + { + if (!ft_buf->buf) /* store in second-level tree */ + { + ft_buf->count++; + return sort_insert_key(sort_param,key_block, + ((uchar *)a)+val_off, HA_OFFSET_ERROR); + } + + /* storing the key in the buffer. */ + memcpy (ft_buf->buf, a+val_off, val_len); + ft_buf->buf+=val_len; + if (ft_buf->buf < ft_buf->end) + return 0; + + /* converting to two-level tree */ + p=ft_buf->lastkey+val_off; + + while (key_block->inited) + key_block++; + sort_info->key_block=key_block; + sort_param->keyinfo=& sort_info->info->s->ft2_keyinfo; + ft_buf->count=(ft_buf->buf - p)/val_len; + + /* flushing buffer to second-level tree */ + for (error=0; !error && p < ft_buf->buf; p+= val_len) + error=sort_insert_key(sort_param,key_block,p,HA_OFFSET_ERROR); + ft_buf->buf=0; + return error; + } + else + { + /* flushing buffer */ + if ((error=sort_ft_buf_flush(sort_param))) + return error; + +word_init_ft_buf: + a_len+=val_len; + memcpy(ft_buf->lastkey, a, a_len); + ft_buf->buf=ft_buf->lastkey+a_len; + ft_buf->end=ft_buf->lastkey+ (sort_param->keyinfo->block_length-32); + /* 32 is just a safety margin here + (at least max(val_len, sizeof(nod_flag)) should be there). + May be better performance could be achieved if we'd put + (sort_info->keyinfo->block_length-32)/XXX + instead. + TODO: benchmark the best value for XXX. + */ + + return 0; + } + return -1; /* impossible */ +} /* sort_ft_key_write */ /* get pointer to record from a key */ @@ -3269,7 +3410,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param) my_off_t filepos,key_file_length; SORT_KEY_BLOCKS *key_block; SORT_INFO *sort_info= sort_param->sort_info; - MI_CHECK *param=sort_info->param; + myf myf_rw=sort_info->param->myf_rw; MI_INFO *info=sort_info->info; MI_KEYDEF *keyinfo=sort_param->keyinfo; DBUG_ENTER("flush_pending_blocks"); @@ -3294,7 +3435,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param) DBUG_RETURN(1); } else if (my_pwrite(info->s->kfile,(byte*) key_block->buff, - (uint) keyinfo->block_length,filepos, param->myf_rw)) + (uint) keyinfo->block_length,filepos, myf_rw)) DBUG_RETURN(1); DBUG_DUMP("buff",(byte*) key_block->buff,length); nod_flag=1; diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 8087d17904a..c270e83a328 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -44,7 +44,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, uint fields,length,max_key_length,packed,pointer, key_length,info_length,key_segs,options,min_key_length_skipp, base_pos,varchar_count,long_varchar_count,varchar_length, - max_key_block_length,unique_key_parts,offset; + max_key_block_length,unique_key_parts,fulltext_keys,offset; ulong reclength, real_reclength,min_pack_length; char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr; ulong pack_reclength; @@ -223,6 +223,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, reclength+=long_varchar_count; /* We need space for this! */ max_key_length=0; tot_length=0 ; key_segs=0; + fulltext_keys=0; max_key_block_length=0; share.state.rec_per_key_part=rec_per_key_part; share.state.key_root=key_root; @@ -242,14 +243,14 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, if (keydef->flag & HA_SPATIAL) { /* BAR TODO to support 3D and more dimensions in the future */ - uint sp_segs=SPDIMS*2; + uint sp_segs=SPDIMS*2; keydef->flag=HA_SPATIAL; if (flags & HA_DONT_TOUCH_DATA) { - /* + /* called by myisamchk - i.e. table structure was taken from - MYI file and SPATIAL key *do has* additional sp_segs keysegs. + MYI file and SPATIAL key *does have* additional sp_segs keysegs. We'd better delete them now */ keydef->keysegs-=sp_segs; @@ -271,20 +272,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, min_key_length_skipp+=SPLEN*2*SPDIMS; } else - if (keydef->flag & HA_FULLTEXT) /* SerG */ + if (keydef->flag & HA_FULLTEXT) { keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY; options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ - if (flags & HA_DONT_TOUCH_DATA) - { - /* called by myisamchk - i.e. table structure was taken from - MYI file and FULLTEXT key *do has* additional FT_SEGS keysegs. - We'd better delete them now - */ - keydef->keysegs-=FT_SEGS; - } - for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ; j++, keyseg++) { @@ -295,19 +287,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, goto err; } } - keydef->keysegs+=FT_SEGS; + fulltext_keys++; key_length+= HA_FT_MAXLEN+HA_FT_WLEN; -#ifdef EVAL_RUN - key_length++; -#endif - length++; /* At least one length byte */ min_key_length_skipp+=HA_FT_MAXLEN; -#if HA_FT_MAXLEN >= 255 - min_key_length_skipp+=2; /* prefix may be 3 bytes */ - length+=2; -#endif } else { @@ -473,8 +457,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, mi_get_pointer_length((tot_length + max_key_block_length * keys * MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH, 3); - share.base.keys= share.state.header.keys = keys; + share.base.keys= share.state.header.keys= keys; share.state.header.uniques= uniques; + share.state.header.fulltext_keys= fulltext_keys; mi_int2store(share.state.header.key_parts,key_segs); mi_int2store(share.state.header.unique_key_parts,unique_key_parts); @@ -566,7 +551,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, linkname_ptr=0; create_flag=MY_DELETE_OLD; } - if ((dfile= + if ((dfile= my_create_with_symlink(linkname_ptr, filename, 0,O_RDWR | O_TRUNC, MYF(MY_WME | create_flag))) < 0) @@ -590,21 +575,13 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, /* Write key and keyseg definitions */ for (i=0 ; i < share.base.keys - uniques; i++) { - uint ft_segs=(keydefs[i].flag & HA_FULLTEXT) ? FT_SEGS : 0; uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0; if (mi_keydef_write(file, &keydefs[i])) goto err; - for (j=0 ; j < keydefs[i].keysegs-ft_segs-sp_segs ; j++) + for (j=0 ; j < keydefs[i].keysegs-sp_segs ; j++) if (mi_keyseg_write(file, &keydefs[i].seg[j])) goto err; - for (j=0 ; j < ft_segs ; j++) - { - HA_KEYSEG seg=ft_keysegs[j]; - seg.language= keydefs[i].seg[0].language; - if (mi_keyseg_write(file, &seg)) - goto err; - } for (j=0 ; j < sp_segs ; j++) { HA_KEYSEG sseg; diff --git a/myisam/mi_delete.c b/myisam/mi_delete.c index ff723303228..2b19139e668 100644 --- a/myisam/mi_delete.c +++ b/myisam/mi_delete.c @@ -23,13 +23,13 @@ #include <errno.h> #endif -static int d_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, - uint key_length, my_off_t page, uchar *anc_buff); +static int d_search(MI_INFO *info,MI_KEYDEF *keyinfo,uint comp_flag, + uchar *key,uint key_length,my_off_t page,uchar *anc_buff); static int del(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,uchar *anc_buff, my_off_t leaf_page,uchar *leaf_buff,uchar *keypos, my_off_t next_block,uchar *ret_key); static int underflow(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *anc_buff, - my_off_t leaf_page, uchar *leaf_buff,uchar *keypos); + my_off_t leaf_page,uchar *leaf_buff,uchar *keypos); static uint remove_key(MI_KEYDEF *keyinfo,uint nod_flag,uchar *keypos, uchar *lastkey,uchar *page_end, my_off_t *next_block); @@ -73,7 +73,6 @@ int mi_delete(MI_INFO *info,const byte *record) if (((ulonglong) 1 << i) & info->s->state.key_map) { info->s->keyinfo[i].version++; - /* The following code block is for text searching by SerG */ if (info->s->keyinfo[i].flag & HA_FULLTEXT ) { if (_mi_ft_del(info,i,(char*) old_key,record,info->lastpos)) @@ -82,7 +81,7 @@ int mi_delete(MI_INFO *info,const byte *record) else { if (info->s->keyinfo[i].ck_delete(info,i,old_key, - _mi_make_key(info,i,old_key,record,info->lastpos))) + _mi_make_key(info,i,old_key,record,info->lastpos))) goto err; } } @@ -129,18 +128,23 @@ err: int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key, uint key_length) { + return _mi_ck_real_delete(info, info->s->keyinfo+keynr, key, key_length, + &info->s->state.key_root[keynr]); +} /* _mi_ck_delete */ + +int _mi_ck_real_delete(register MI_INFO *info, MI_KEYDEF *keyinfo, + uchar *key, uint key_length, my_off_t *root) +{ int error; uint nod_flag; my_off_t old_root; uchar *root_buff; - MI_KEYDEF *keyinfo; - DBUG_ENTER("_mi_ck_delete"); + DBUG_ENTER("_mi_ck_real_delete"); - if ((old_root=info->s->state.key_root[keynr]) == HA_OFFSET_ERROR) + if ((old_root=*root) == HA_OFFSET_ERROR) { DBUG_RETURN(my_errno=HA_ERR_CRASHED); } - keyinfo=info->s->keyinfo+keynr; if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+ MI_MAX_KEY_BUFF*2))) { @@ -153,12 +157,15 @@ int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key, error= -1; goto err; } - if ((error=d_search(info,keyinfo,key,key_length,old_root,root_buff)) >0) + if ((error=d_search(info,keyinfo, + (keyinfo->flag & HA_FULLTEXT ? SEARCH_FIND + : SEARCH_SAME), + key,key_length,old_root,root_buff)) >0) { if (error == 2) { DBUG_PRINT("test",("Enlarging of root when deleting")); - error=_mi_enlarge_root(info,keynr,key); + error=_mi_enlarge_root(info,keyinfo,key,root); } else /* error == 1 */ { @@ -166,10 +173,9 @@ int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key, { error=0; if (nod_flag) - info->s->state.key_root[keynr]=_mi_kpos(nod_flag, - root_buff+2+nod_flag); + *root=_mi_kpos(nod_flag,root_buff+2+nod_flag); else - info->s->state.key_root[keynr]= HA_OFFSET_ERROR; + *root=HA_OFFSET_ERROR; if (_mi_dispose(info,keyinfo,old_root)) error= -1; } @@ -180,7 +186,7 @@ int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key, err: my_afree((gptr) root_buff); DBUG_RETURN(error); -} /* _mi_ck_delete */ +} /* _mi_ck_real_delete */ /* @@ -192,11 +198,11 @@ err: */ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, - uchar *key, uint key_length, my_off_t page, - uchar *anc_buff) + uint comp_flag, uchar *key, uint key_length, + my_off_t page, uchar *anc_buff) { int flag,ret_value,save_flag; - uint length,nod_flag; + uint length,nod_flag,search_key_length; my_bool last_key; uchar *leaf_buff,*keypos; my_off_t leaf_page,next_block; @@ -204,9 +210,9 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, DBUG_ENTER("d_search"); DBUG_DUMP("page",(byte*) anc_buff,mi_getint(anc_buff)); - flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key, USE_WHOLE_KEY, - SEARCH_SAME, - &keypos, lastkey, &last_key); + search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY; + flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key, search_key_length, + comp_flag, &keypos, lastkey, &last_key); if (flag == MI_FOUND_WRONG_KEY) { DBUG_PRINT("error",("Found wrong key")); @@ -214,6 +220,52 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, } nod_flag=mi_test_if_nod(anc_buff); + if (!flag && keyinfo->flag & HA_FULLTEXT) + { + uint off; + int subkeys; + + get_key_full_length_rdonly(off, lastkey); + subkeys=ft_sintXkorr(lastkey+off); + comp_flag=SEARCH_SAME; + if (subkeys >= 0) + { + /* normal word, one-level tree structure */ + flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key,USE_WHOLE_KEY, + comp_flag, &keypos, lastkey, &last_key); + /* fall through to normal delete */ + } + else + { + /* popular word. two-level tree. going down */ + uint tmp_key_length; + my_off_t root; + uchar *kpos=keypos; + + tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&kpos,lastkey); + root=_mi_dpos(info,nod_flag,kpos); + if (subkeys == -1) + { + /* the last entry in sub-tree */ + _mi_dispose(info, keyinfo, root); + /* fall through to normal delete */ + } + else + { + keyinfo=&info->s->ft2_keyinfo; + kpos-=keyinfo->keylength; /* we'll modify key entry 'in vivo' */ + key+=off; + ret_value=_mi_ck_real_delete(info, &info->s->ft2_keyinfo, + key, HA_FT_WLEN, &root); + _mi_dpointer(info, kpos+HA_FT_WLEN, root); + subkeys++; + ft_intXstore(kpos, subkeys); + if (!ret_value) + ret_value=_mi_write_keypage(info,keyinfo,page,anc_buff); + DBUG_RETURN(ret_value); + } + } + } leaf_buff=0; LINT_INIT(leaf_page); if (nod_flag) @@ -239,7 +291,8 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, goto err; } save_flag=0; - ret_value=d_search(info,keyinfo,key,key_length,leaf_page,leaf_buff); + ret_value=d_search(info,keyinfo,comp_flag,key,key_length, + leaf_page,leaf_buff); } else { /* Found key */ diff --git a/myisam/mi_open.c b/myisam/mi_open.c index 8f0da612c3a..fac53bf77e9 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -69,7 +69,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) { int lock_error,kfile,open_mode,save_errno,have_rtree=0; uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys, - key_parts,unique_key_parts,tmp_length,uniques; + key_parts,unique_key_parts,fulltext_keys,uniques; char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN], data_name[FN_REFLEN]; char *disk_cache,*disk_pos; @@ -126,8 +126,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) HA_OPTION_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM | HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE)) { - DBUG_PRINT("error",("wrong options: 0x%lx", - share->options)); + DBUG_PRINT("error",("wrong options: 0x%lx", share->options)); my_errno=HA_ERR_OLD_FILE; goto err; } @@ -162,11 +161,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) len=mi_uint2korr(share->state.header.state_info_length); keys= (uint) share->state.header.keys; uniques= (uint) share->state.header.uniques; + fulltext_keys= (uint) share->state.header.fulltext_keys; key_parts= mi_uint2korr(share->state.header.key_parts); unique_key_parts= mi_uint2korr(share->state.header.unique_key_parts); - tmp_length=(MI_STATE_INFO_SIZE + keys * MI_STATE_KEY_SIZE + - key_parts*MI_STATE_KEYSEG_SIZE + - share->state.header.max_block_size*MI_STATE_KEYBLOCK_SIZE); if (len != MI_STATE_INFO_SIZE) { DBUG_PRINT("warning", @@ -203,6 +200,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) goto err; } + key_parts+=fulltext_keys*FT_SEGS; if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY || key_parts >= MI_MAX_KEY * MI_MAX_KEY_SEG) { @@ -211,7 +209,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) goto err; } - /* Correct max_file_length based on length of sizeof_t */ + /* Correct max_file_length based on length of sizeof(off_t) */ max_data_file_length= (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? (((ulonglong) 1 << (share->base.rec_reflength*8))-1) : @@ -290,12 +288,14 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) for (i=0 ; i < keys ; i++) { disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[i]); + if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE) + have_rtree=1; set_if_smaller(share->blocksize,share->keyinfo[i].block_length); share->keyinfo[i].seg=pos; for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++) { disk_pos=mi_keyseg_read(disk_pos, pos); - + if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT) { if (!pos->language) @@ -312,11 +312,41 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) uint sp_segs=SPDIMS*2; share->keyinfo[i].seg=pos-sp_segs; share->keyinfo[i].keysegs--; - } else if (share->keyinfo[i].flag & HA_FULLTEXT) + } + else if (share->keyinfo[i].flag & HA_FULLTEXT) { - share->keyinfo[i].seg=pos-FT_SEGS; - share->fulltext_index=1; + if (!fulltext_keys) + { /* 4.0 compatibility code, to be removed in 5.0 */ + share->keyinfo[i].seg=pos-FT_SEGS; + share->keyinfo[i].keysegs-=FT_SEGS; + share->state.header.fulltext_keys++; + } + else + { + uint j; + share->keyinfo[i].seg=pos; + for (j=0; j < FT_SEGS; j++) + { + *pos=ft_keysegs[j]; + pos[0].language= pos[-1].language; + pos[0].charset= pos[-1].charset; + pos++; + } + } + if (!share->ft2_keyinfo.seg) + { + memcpy(& share->ft2_keyinfo, & share->keyinfo[i], sizeof(MI_KEYDEF)); + share->ft2_keyinfo.keysegs=1; + share->ft2_keyinfo.flag=0; + share->ft2_keyinfo.keylength= + share->ft2_keyinfo.minlength= + share->ft2_keyinfo.maxlength=HA_FT_WLEN+share->base.rec_reflength; + share->ft2_keyinfo.seg=pos-1; + share->ft2_keyinfo.end=pos; + setup_key_functions(& share->ft2_keyinfo); + } } + setup_key_functions(share->keyinfo+i); share->keyinfo[i].end=pos; pos->type=HA_KEYTYPE_END; /* End */ pos->length=share->base.rec_reflength; @@ -349,12 +379,6 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) pos++; } } - for (i=0 ; i < keys ; i++) - { - if (share->keyinfo[i].key_alg == HA_KEY_ALG_RTREE) - have_rtree=1; - setup_key_functions(share->keyinfo+i); - } for (i=j=offset=0 ; i < share->base.fields ; i++) { @@ -712,9 +736,9 @@ static void setup_key_functions(register MI_KEYDEF *keyinfo) } -/*************************************************************************** -** Function to save and store the header in the index file (.MSI) -***************************************************************************/ +/* + Function to save and store the header in the index file (.MYI) +*/ uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite) { diff --git a/myisam/mi_rnext.c b/myisam/mi_rnext.c index daab7c5f085..e1cf916d6d9 100644 --- a/myisam/mi_rnext.c +++ b/myisam/mi_rnext.c @@ -51,7 +51,7 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx) case HA_KEY_ALG_BTREE: default: error=_mi_search_first(info,info->s->keyinfo+inx, - info->s->state.key_root[inx]); + info->s->state.key_root[inx]); break; } } @@ -60,17 +60,17 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx) switch(info->s->keyinfo[inx].key_alg) { case HA_KEY_ALG_RTREE: - /* + /* Note that rtree doesn't support that the table may be changed since last call, so we do need to skip rows inserted by other threads like in btree */ error=rtree_get_next(info,inx,info->lastkey_length); break; - + case HA_KEY_ALG_BTREE: default: - if (!changed) + if (!changed) { error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, info->lastkey_length,flag, @@ -81,15 +81,15 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx) error=_mi_search(info,info->s->keyinfo+inx,info->lastkey, USE_WHOLE_KEY,flag, info->s->state.key_root[inx]); } - if (!error) + if (!error && info->s->concurrent_insert) { while (info->lastpos >= info->state->data_file_length) { /* Skip rows that are inserted by other threads since we got a lock */ - if ((error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, - info->lastkey_length, - SEARCH_BIGGER, - info->s->state.key_root[inx]))) + if ((error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, + info->lastkey_length, + SEARCH_BIGGER, + info->s->state.key_root[inx]))) break; } } diff --git a/myisam/mi_update.c b/myisam/mi_update.c index 81142ecabac..53c09a1d35c 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -91,7 +91,6 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) { if (((ulonglong) 1 << i) & share->state.key_map) { - /* The following code block is for text searching by SerG */ if (share->keyinfo[i].flag & HA_FULLTEXT ) { if (_mi_ft_cmp(info,i,oldrec, newrec)) @@ -175,7 +174,6 @@ err: { if (((ulonglong) 1 << i) & changed) { - /* The following code block is for text searching by SerG */ if (share->keyinfo[i].flag & HA_FULLTEXT) { if ((flag++ && _mi_ft_del(info,i,(char*) new_key,newrec,pos)) || diff --git a/myisam/mi_write.c b/myisam/mi_write.c index 58f9ebdb735..cd7a4664a22 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -38,9 +38,9 @@ static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page, uchar *key, uint *return_key_length, uchar **after_key); -int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key, +int _mi_ck_write_tree(register MI_INFO *info, uint keynr,uchar *key, uint key_length); -int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, +int _mi_ck_write_btree(register MI_INFO *info, uint keynr,uchar *key, uint key_length); /* Write new record to database */ @@ -250,11 +250,12 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, int error; uint comp_flag; MI_KEYDEF *keyinfo=info->s->keyinfo+keynr; + my_off_t *root=&info->s->state.key_root[keynr]; DBUG_ENTER("_mi_ck_write_btree"); if (keyinfo->flag & HA_SORT_ALLOWS_SAME) comp_flag=SEARCH_BIGGER; /* Put after same key */ - else if (keyinfo->flag & HA_NOSAME) + else if (keyinfo->flag & (HA_NOSAME|HA_FULLTEXT)) { comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No dupplicates */ if (keyinfo->flag & HA_NULL_ARE_EQUAL) @@ -263,37 +264,34 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, else comp_flag=SEARCH_SAME; /* Keys in rec-pos order */ - if (info->s->state.key_root[keynr] == HA_OFFSET_ERROR || + if (*root == HA_OFFSET_ERROR || (error=w_search(info, keyinfo, comp_flag, key, key_length, - info->s->state.key_root[keynr], (uchar *) 0, (uchar*) 0, + *root, (uchar *) 0, (uchar*) 0, (my_off_t) 0, 1)) > 0) - error=_mi_enlarge_root(info,keynr,key); + error=_mi_enlarge_root(info,keyinfo,key,root); DBUG_RETURN(error); } /* _mi_ck_write_btree */ /* Make a new root with key as only pointer */ -int _mi_enlarge_root(register MI_INFO *info, uint keynr, uchar *key) +int _mi_enlarge_root(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key, + my_off_t *root) { uint t_length,nod_flag; - reg2 MI_KEYDEF *keyinfo; MI_KEY_PARAM s_temp; MYISAM_SHARE *share=info->s; DBUG_ENTER("_mi_enlarge_root"); - nod_flag= (share->state.key_root[keynr] != HA_OFFSET_ERROR) ? - share->base.key_reflength : 0; - _mi_kpointer(info,info->buff+2,share->state.key_root[keynr]); /* if nod */ - keyinfo=share->keyinfo+keynr; + nod_flag= (*root != HA_OFFSET_ERROR) ? share->base.key_reflength : 0; + _mi_kpointer(info,info->buff+2,*root); /* if nod */ t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar*) 0, (uchar*) 0, (uchar*) 0, key,&s_temp); mi_putint(info->buff,t_length+2+nod_flag,nod_flag); (*keyinfo->store_key)(keyinfo,info->buff+2+nod_flag,&s_temp); info->buff_used=info->page_changed=1; /* info->buff is used */ - if ((share->state.key_root[keynr]= _mi_new(info,keyinfo)) == - HA_OFFSET_ERROR || - _mi_write_keypage(info,keyinfo,share->state.key_root[keynr],info->buff)) + if ((*root= _mi_new(info,keyinfo)) == HA_OFFSET_ERROR || + _mi_write_keypage(info,keyinfo,*root,info->buff)) DBUG_RETURN(-1); DBUG_RETURN(0); } /* _mi_enlarge_root */ @@ -333,15 +331,54 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (flag == 0) { uint tmp_key_length; - my_errno=HA_ERR_FOUND_DUPP_KEY; /* get position to record with duplicated key */ tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff); if (tmp_key_length) info->dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length); else info->dupp_key_pos= HA_OFFSET_ERROR; - my_afree((byte*) temp_buff); - DBUG_RETURN(-1); + if (keyinfo->flag & HA_FULLTEXT) + { + uint off; + int subkeys; + + get_key_full_length_rdonly(off, keybuff); + subkeys=ft_sintXkorr(keybuff+off); + comp_flag=SEARCH_SAME; + if (subkeys >= 0) + { + /* normal word, one-level tree structure */ + flag=(*keyinfo->bin_search)(info, keyinfo, temp_buff, key, + USE_WHOLE_KEY, comp_flag, + &keypos, keybuff, &was_last_key); + } + else + { + /* popular word. two-level tree. going down */ + my_off_t root=info->dupp_key_pos; + 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); + } + subkeys--; /* should there be underflow protection ? */ + ft_intXstore(keypos, subkeys); + if (!error) + error=_mi_write_keypage(info,keyinfo,page,temp_buff); + my_afree((byte*) temp_buff); + DBUG_RETURN(error); + } + } + else /* not HA_FULLTEXT, normal HA_NOSAME key */ + { + my_afree((byte*) temp_buff); + my_errno=HA_ERR_FOUND_DUPP_KEY; + DBUG_RETURN(-1); + } } if (flag == MI_FOUND_WRONG_KEY) DBUG_RETURN(-1); @@ -394,7 +431,9 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, #ifndef DBUG_OFF if (key_pos != anc_buff+2+nod_flag && (keyinfo->flag & (HA_BINARY_PACK_KEY | HA_PACK_KEY))) + { DBUG_DUMP("prev_key",(byte*) key_buff,_mi_keylength(keyinfo,key_buff)); + } if (keyinfo->flag & HA_PACK_KEY) { DBUG_PRINT("test",("t_length: %d ref_len: %d", @@ -753,7 +792,7 @@ int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key, DBUG_ENTER("_mi_ck_write_tree"); error= tree_insert(&info->bulk_insert[keynr], key, - key_length + info->s->rec_reflength, + key_length + info->s->rec_reflength, info->bulk_insert[keynr].custom_arg) ? 0 : HA_ERR_OUT_OF_MEM ; DBUG_RETURN(error); diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 281cb90d9bf..3da0c3a2b61 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -874,8 +874,8 @@ static int myisamchk(MI_CHECK *param, my_string filename) } else { - if (share->fulltext_index) - ft_init_stopwords(ft_precompiled_stopwords); /* SerG */ + if (share->state.header.fulltext_keys) + ft_init_stopwords(ft_precompiled_stopwords); if (!(param->testflag & T_READONLY)) lock_type = F_WRLCK; /* table is changed */ diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 90aaff46919..5b2a1b7c8e0 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -55,7 +55,8 @@ typedef struct st_mi_state_info uchar uniques; /* number of UNIQUE definitions */ uchar language; /* Language for indexes */ uchar max_block_size; /* max keyblock size */ - uchar not_used[2]; /* To align to 8 */ + uchar fulltext_keys; + uchar not_used; /* To align to 8 */ } header; MI_STATUS_INFO state; @@ -90,7 +91,7 @@ typedef struct st_mi_state_info } MI_STATE_INFO; #define MI_STATE_INFO_SIZE (24+14*8+7*4+2*2+8) -#define MI_STATE_KEY_SIZE 8 +#define MI_STATE_KEY_SIZE 8 #define MI_STATE_KEYBLOCK_SIZE 8 #define MI_STATE_KEYSEG_SIZE 4 #define MI_STATE_EXTRA_SIZE ((MI_MAX_KEY+MI_MAX_KEY_BLOCK_SIZE)*MI_STATE_KEY_SIZE + MI_MAX_KEY*MI_MAX_KEY_SEG*MI_STATE_KEYSEG_SIZE) @@ -154,6 +155,7 @@ typedef struct st_mi_isam_pack { typedef struct st_mi_isam_share { /* Shared between opens */ MI_STATE_INFO state; MI_BASE_INFO base; + MI_KEYDEF ft2_keyinfo; /* Second-level ft-key definition */ MI_KEYDEF *keyinfo; /* Key definitions */ MI_UNIQUEDEF *uniqueinfo; /* unique definitions */ HA_KEYSEG *keyparts; /* key part info */ @@ -197,8 +199,7 @@ typedef struct st_mi_isam_share { /* Shared between opens */ global_changed, /* If changed since open */ not_flushed, temporary,delay_key_write, - concurrent_insert, - fulltext_index; + concurrent_insert; #ifdef THREAD THR_LOCK lock; pthread_mutex_t intern_lock; /* Locking for use with _locking */ @@ -229,6 +230,8 @@ struct st_myisam_info { byte *rec_buff; /* Tempbuff for recordpack */ uchar *int_keypos, /* Save position for next/previous */ *int_maxpos; /* -""- */ + uint int_nod_flag; /* -""- */ + uint32 int_keytree_version; /* -""- */ int (*read_record)(struct st_myisam_info*, my_off_t, byte*); invalidator_by_filename invalidator; /* query cache invalidator */ ulong this_unique; /* uniq filenumber or thread */ @@ -247,7 +250,6 @@ struct st_myisam_info { int dfile; /* The datafile */ uint opt_flag; /* Optim. for space/speed */ uint update; /* If file changed since open */ - uint int_nod_flag; /* -""- */ int lastinx; /* Last used index */ uint lastkey_length; /* Length of key in lastkey */ uint last_rkey_length; /* Last length in mi_rkey() */ @@ -259,7 +261,6 @@ struct st_myisam_info { uint data_changed; /* Somebody has changed data */ uint save_update; /* When using KEY_READ */ int save_lastinx; - uint32 int_keytree_version; /* -""- */ LIST open_list; IO_CACHE rec_cache; /* When cacheing records */ myf lock_wait; /* is 0 or MY_DONT_WAIT */ @@ -372,6 +373,13 @@ typedef struct st_mi_sort_param { length=mi_uint2korr((key)+1)+3; (key)+=3; } \ } +#define get_key_full_length_rdonly(length,key) \ +{ if ((uchar) *(key) != 255) \ + length= ((uint) (uchar) *((key)))+1; \ + else \ + { length=mi_uint2korr((key)+1)+3; } \ +} + #define get_pack_length(length) ((length) >= 255 ? 3 : 1) #define MI_MIN_BLOCK_LENGTH 20 /* Because of delete-link */ @@ -395,7 +403,7 @@ typedef struct st_mi_sort_param #define MI_FOUND_WRONG_KEY 32738 /* Impossible value from ha_key_cmp */ #define MI_MAX_KEY_BLOCK_SIZE (MI_MAX_KEY_BLOCK_LENGTH/MI_MIN_KEY_BLOCK_LENGTH) -#define MI_BLOCK_SIZE(key_length,data_pointer,key_pointer) ((((key_length+data_pointer+key_pointer)*4+key_pointer+2)/myisam_block_size+1)*myisam_block_size) +#define MI_BLOCK_SIZE(key_length,data_pointer,key_pointer) (((((key_length)+(data_pointer)+(key_pointer))*4+(key_pointer)+2)/myisam_block_size+1)*myisam_block_size) #define MI_MAX_KEYPTR_SIZE 5 /* For calculating block lengths */ #define MI_MIN_KEYBLOCK_LENGTH 50 /* When to split delete blocks */ @@ -454,7 +462,7 @@ 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_enlarge_root(MI_INFO *info,uint keynr,uchar *key); +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, uchar *father_buff, uchar *father_keypos, @@ -691,6 +699,7 @@ void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...)); void mi_check_print_warning _VARARGS((MI_CHECK *param, const char *fmt,...)); void mi_check_print_info _VARARGS((MI_CHECK *param, const char *fmt,...)); int flush_pending_blocks(MI_SORT_PARAM *param); +int sort_ft_buf_flush(MI_SORT_PARAM *sort_param); int thr_write_keys(MI_SORT_PARAM *sort_param); #ifdef THREAD pthread_handler_decl(thr_find_all_keys,arg); diff --git a/myisam/sort.c b/myisam/sort.c index 7ad23df9358..d86aeb6aa3b 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -71,7 +71,8 @@ static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys, BUFFPEK *Fb, BUFFPEK *Tb); static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int, IO_CACHE *); - +static int flush_ft_buf(MI_SORT_PARAM *info); + static int NEAR_F write_keys_varlen(MI_SORT_PARAM *info,uchar **sort_keys, uint count, BUFFPEK *buffpek, IO_CACHE *tempfile); @@ -120,7 +121,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, info->read_to_buffer=read_to_buffer; info->write_key=write_merge_key; } - + my_b_clear(&tempfile); my_b_clear(&tempfile_for_exceptions); bzero((char*) &buffpek,sizeof(buffpek)); @@ -207,7 +208,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, goto err; /* purecov: inspected */ } - if (flush_pending_blocks(info)) + if (flush_ft_buf(info) || flush_pending_blocks(info)) goto err; if (my_b_inited(&tempfile_for_exceptions)) @@ -478,7 +479,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) fflush(stdout); } if (write_index(sinfo, sinfo->sort_keys, sinfo->keys) || - flush_pending_blocks(sinfo)) + flush_ft_buf(sinfo) || flush_pending_blocks(sinfo)) got_error=1; } } @@ -551,6 +552,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) if (merge_index(sinfo, keys, (uchar **)mergebuf, dynamic_element(&sinfo->buffpek,0,BUFFPEK *), maxbuffer,&sinfo->tempfile) || + flush_ft_buf(sinfo) || flush_pending_blocks(sinfo)) { got_error=1; @@ -976,3 +978,16 @@ merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys, DBUG_RETURN(0); } /* merge_index */ +static int +flush_ft_buf(MI_SORT_PARAM *info) +{ + int err=0; + if (info->sort_info->ft_buf) + { + err=sort_ft_buf_flush(info); + my_free((gptr)info->sort_info->ft_buf, MYF(0)); + info->sort_info->ft_buf=0; + } + return err; +} + diff --git a/mysql-test/r/fulltext.result b/mysql-test/r/fulltext.result index a991981bf21..2f816ba8fc6 100644 --- a/mysql-test/r/fulltext.result +++ b/mysql-test/r/fulltext.result @@ -16,6 +16,8 @@ select * from t1 where MATCH(a,b) AGAINST ("indexes collections"); a b 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"); a b Only MyISAM tables support collections diff --git a/mysql-test/r/fulltext2.result b/mysql-test/r/fulltext2.result new file mode 100644 index 00000000000..8086faadba4 --- /dev/null +++ b/mysql-test/r/fulltext2.result @@ -0,0 +1,871 @@ +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 ( +i int(10) unsigned not null auto_increment primary key, +a varchar(255) not null, +FULLTEXT KEY (a) +) TYPE=MyISAM; +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaaxxx'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaazzz'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +insert t1 (a) values ('aaayyy'); +repair table t1 quick; +Table Op Msg_type Msg_text +test.t1 repair status OK +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 IF EXISTS t1; diff --git a/mysql-test/t/fulltext.test b/mysql-test/t/fulltext.test index 5a64f2614aa..ed628da6a30 100644 --- a/mysql-test/t/fulltext.test +++ b/mysql-test/t/fulltext.test @@ -16,6 +16,7 @@ INSERT INTO t1 VALUES('MySQL has now support', 'for full-text search'), select * from t1 where MATCH(a,b) AGAINST ("collections"); 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"); diff --git a/mysql-test/t/fulltext2.test b/mysql-test/t/fulltext2.test new file mode 100644 index 00000000000..998747018b4 --- /dev/null +++ b/mysql-test/t/fulltext2.test @@ -0,0 +1,93 @@ +# +# test of new fulltext search features +# + +# +# two-level tree +# + +DROP TABLE IF EXISTS 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 +let $1=260; +while ($1) +{ + eval insert t1 (a) values ('aaaxxx'); + dec $1; +} + +# two-level entry, second-level tree has only one page +let $1=255; +while ($1) +{ + eval insert t1 (a) values ('aaazzz'); + dec $1; +} + +# one-level entry (entries) +let $1=250; +while ($1) +{ + eval insert t1 (a) values ('aaayyy'); + dec $1; +} + +# converting to two-level +repair table t1 quick; + +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'); +# call to enlarge_root() below +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 IF EXISTS t1; + diff --git a/mysys/mulalloc.c b/mysys/mulalloc.c index 6b025bca699..e1eb1c00602 100644 --- a/mysys/mulalloc.c +++ b/mysys/mulalloc.c @@ -19,16 +19,18 @@ /* Malloc many pointers at the same time + Only ptr1 can be free'd, and doing this will free all + the memory allocated. ptr2, etc all point inside big allocated + memory area. SYNOPSIS my_multi_malloc() - myFlags Flags - ... Multiple arguments terminated by null ptr - - ptr, length - ptr, length + myFlags Flags + ptr1, length1 Multiple arguments terminated by null ptr + ptr2, length2 ... + ... NULL -*/ +*/ gptr my_multi_malloc(myf myFlags, ...) { |