Commit 76078f2c authored by unknown's avatar unknown

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
parent e503a580
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version. version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details. Library General Public License for more details.
You should have received a copy of the GNU Library General Public You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
...@@ -43,6 +43,13 @@ typedef struct st_HA_KEYSEG /* Key-portion */ ...@@ -43,6 +43,13 @@ typedef struct st_HA_KEYSEG /* Key-portion */
{ length=mi_uint2korr((key)+1); (key)+=3; } \ { 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) \ #define get_key_pack_length(length,length_pack,key) \
{ if ((uchar) *(key) != 255) \ { if ((uchar) *(key) != 255) \
{ length= (uint) (uchar) *((key)++); length_pack=1; }\ { length= (uint) (uchar) *((key)++); length_pack=1; }\
......
...@@ -342,6 +342,12 @@ typedef struct st_mi_check_param ...@@ -342,6 +342,12 @@ typedef struct st_mi_check_param
char *op_name; char *op_name;
} MI_CHECK; } 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 typedef struct st_sort_info
{ {
...@@ -354,7 +360,8 @@ typedef struct st_sort_info ...@@ -354,7 +360,8 @@ typedef struct st_sort_info
MI_CHECK *param; MI_CHECK *param;
char *buff; char *buff;
SORT_KEY_BLOCKS *key_block,*key_block_end; SORT_KEY_BLOCKS *key_block,*key_block_end;
/* sync things*/ SORT_FT_BUF *ft_buf;
/* sync things */
uint got_error, threads_running; uint got_error, threads_running;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cond; pthread_cond_t cond;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define FT_CORE #define FT_CORE
#include "ftdefs.h" #include "ftdefs.h"
#include <queues.h> #include <queues.h>
#include <assert.h> /* for DBUG_ASSERT() */
/* search with boolean queries */ /* search with boolean queries */
...@@ -63,42 +64,44 @@ struct st_ftb_expr ...@@ -63,42 +64,44 @@ struct st_ftb_expr
{ {
FTB_EXPR *up; FTB_EXPR *up;
byte *quot, *qend; byte *quot, *qend;
float weight;
uint flags;
my_off_t docid[2]; /* for index search and for scan */ my_off_t docid[2]; /* for index search and for scan */
float weight;
float cur_weight; float cur_weight;
int yesses; /* number of "yes" words matched */ uint flags;
int nos; /* number of "no" words matched */ uint yesses; /* number of "yes" words matched */
int ythresh; /* number of "yes" words in expr */ uint nos; /* number of "no" words matched */
int yweaks; /* number of "yes" words for scan only */ uint ythresh; /* number of "yes" words in expr */
uint yweaks; /* number of "yes" words for scan only */
}; };
typedef struct st_ftb_word typedef struct st_ftb_word
{ {
FTB_EXPR *up; FTB_EXPR *up;
float weight; MI_KEYDEF *keyinfo;
uint flags; my_off_t docid[2]; /* for index search and for scan */
my_off_t docid[2]; /* for index search and for scan */ my_off_t key_root;
uint ndepth; float weight;
int len; uint ndepth;
/* ... docid cache can be added here. SerG */ uint flags;
byte word[1]; uint len;
uchar off;
byte word[1];
} FTB_WORD; } FTB_WORD;
typedef struct st_ft_info typedef struct st_ft_info
{ {
struct _ft_vft *please; struct _ft_vft *please;
MI_INFO *info; MI_INFO *info;
uint keynr;
CHARSET_INFO *charset; CHARSET_INFO *charset;
enum { UNINITIALIZED, READY, INDEX_SEARCH, INDEX_DONE /*, SCAN*/ } state;
uint with_scan;
my_off_t lastpos;
FTB_EXPR *root; FTB_EXPR *root;
QUEUE queue;
TREE no_dupes;
FTB_WORD **list; FTB_WORD **list;
MEM_ROOT mem_root; 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; } FTB;
static int FTB_WORD_cmp(my_off_t *v, FTB_WORD *a, FTB_WORD *b) 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, ...@@ -160,6 +163,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end,
ftbw->up=up; ftbw->up=up;
ftbw->docid[0]=ftbw->docid[1]=HA_POS_ERROR; ftbw->docid[0]=ftbw->docid[1]=HA_POS_ERROR;
ftbw->ndepth= (param.yesno<0) + depth; ftbw->ndepth= (param.yesno<0) + depth;
ftbw->key_root=HA_POS_ERROR;
memcpy(ftbw->word+1, w.pos, w.len); memcpy(ftbw->word+1, w.pos, w.len);
ftbw->word[0]=w.len; ftbw->word[0]=w.len;
if (param.yesno > 0) up->ythresh++; if (param.yesno > 0) up->ythresh++;
...@@ -194,22 +198,98 @@ static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)), ...@@ -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))); 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) static void _ftb_init_index_search(FT_INFO *ftb)
{ {
int i, r; int i;
FTB_WORD *ftbw; FTB_WORD *ftbw;
MI_INFO *info=ftb->info; MI_INFO *info=ftb->info;
MI_KEYDEF *keyinfo;
my_off_t keyroot;
if ((ftb->state != READY && ftb->state !=INDEX_DONE) || if ((ftb->state != READY && ftb->state !=INDEX_DONE) ||
ftb->keynr == NO_SUCH_KEY) ftb->keynr == NO_SUCH_KEY)
return; return;
ftb->state=INDEX_SEARCH; 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--) for (i=ftb->queue.elements; i; i--)
{ {
ftbw=(FTB_WORD *)(ftb->queue.root[i]); ftbw=(FTB_WORD *)(ftb->queue.root[i]);
...@@ -248,34 +328,9 @@ static void _ftb_init_index_search(FT_INFO *ftb) ...@@ -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 (_ft2_search(ftb, ftbw, 1))
if (!r) return;
{
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;
}
} }
queue_fix(& ftb->queue); queue_fix(& ftb->queue);
} }
...@@ -436,10 +491,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) ...@@ -436,10 +491,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record)
FTB_EXPR *ftbe; FTB_EXPR *ftbe;
FTB_WORD *ftbw; FTB_WORD *ftbw;
MI_INFO *info=ftb->info; 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; my_off_t curdoc;
int r;
if (ftb->state != INDEX_SEARCH && ftb->state != INDEX_DONE) if (ftb->state != INDEX_SEARCH && ftb->state != INDEX_DONE)
return -1; return -1;
...@@ -466,34 +518,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) ...@@ -466,34 +518,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record)
_ftb_climb_the_tree(ftb, ftbw, 0); _ftb_climb_the_tree(ftb, ftbw, 0);
/* update queue */ /* update queue */
r=_mi_search(info, keyinfo, (uchar*) ftbw->word, USE_WHOLE_KEY, _ft2_search(ftb, ftbw, 0);
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;
}
queue_replaced(& ftb->queue); queue_replaced(& ftb->queue);
} }
...@@ -503,9 +528,9 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) ...@@ -503,9 +528,9 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record)
{ {
/* curdoc matched ! */ /* curdoc matched ! */
if (is_tree_inited(&ftb->no_dupes) && 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) 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; continue;
info->lastpos=curdoc; info->lastpos=curdoc;
......
...@@ -56,7 +56,7 @@ static struct my_option my_long_options[] = ...@@ -56,7 +56,7 @@ static struct my_option my_long_options[] =
int main(int argc,char *argv[]) int main(int argc,char *argv[])
{ {
int error=0; int error=0, subkeys;
uint keylen, keylen2=0, inx, doc_cnt=0; uint keylen, keylen2=0, inx, doc_cnt=0;
float weight; float weight;
double gws, min_gws=0, avg_gws=0; double gws, min_gws=0, avg_gws=0;
...@@ -125,7 +125,9 @@ int main(int argc,char *argv[]) ...@@ -125,7 +125,9 @@ int main(int argc,char *argv[])
keylen=*(info->lastkey); keylen=*(info->lastkey);
#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT #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 #else
#error #error
#endif #endif
...@@ -164,7 +166,10 @@ int main(int argc,char *argv[]) ...@@ -164,7 +166,10 @@ int main(int argc,char *argv[])
} }
} }
if (dump) 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) if(verbose && (total%HOW_OFTEN_TO_WRITE)==0)
printf("%10ld\r",total); printf("%10ld\r",total);
...@@ -216,18 +221,18 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), ...@@ -216,18 +221,18 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
{ {
switch(optid) { switch(optid) {
case 'd': case 'd':
dump=1; dump=1;
complain(count || query); complain(count || query);
break; break;
case 's': case 's':
stats=1; stats=1;
complain(query!=0); complain(query!=0);
break; break;
case 'c': case 'c':
count= 1; count= 1;
complain(dump || query); complain(dump || query);
break; break;
case 'l': case 'l':
lstats=1; lstats=1;
complain(query!=0); complain(query!=0);
break; break;
......
...@@ -42,8 +42,6 @@ typedef struct st_all_in_one ...@@ -42,8 +42,6 @@ typedef struct st_all_in_one
uint keynr; uint keynr;
CHARSET_INFO *charset; CHARSET_INFO *charset;
uchar *keybuff; uchar *keybuff;
MI_KEYDEF *keyinfo;
my_off_t key_root;
TREE dtree; TREE dtree;
} ALL_IN_ONE; } ALL_IN_ONE;
...@@ -66,13 +64,14 @@ static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)), ...@@ -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) static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
{ {
int subkeys;
uint keylen, r, doc_cnt; uint keylen, r, doc_cnt;
#ifdef EVAL_RUN
uint cnt;
double sum, sum2, suml;
#endif /* EVAL_RUN */
FT_SUPERDOC sdoc, *sptr; FT_SUPERDOC sdoc, *sptr;
TREE_ELEMENT *selem; 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 #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
float tmp_weight; float tmp_weight;
#else #else
...@@ -83,44 +82,45 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) ...@@ -83,44 +82,45 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
word->weight=LWS_FOR_QUERY; word->weight=LWS_FOR_QUERY;
keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0); keylen=_ft_make_key(info,aio->keynr,(char*) keybuff,word,0);
#ifdef EVAL_RUN
keylen-=1+HA_FT_WLEN;
#else /* EVAL_RUN */
keylen-=HA_FT_WLEN; keylen-=HA_FT_WLEN;
#endif /* EVAL_RUN */
#ifdef EVAL_RUN
sum=sum2=suml=
#endif /* EVAL_RUN */
doc_cnt=0; doc_cnt=0;
r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, r=_mi_search(info, keyinfo, keybuff, keylen, SEARCH_FIND, key_root);
SEARCH_FIND | SEARCH_PREFIX, aio->key_root); info->update|= HA_STATE_AKTIV; /* for _mi_test_if_changed() */
while (!r) while (!r)
{ {
if (mi_compare_text(aio->charset,
aio->info->lastkey,keylen, if (keylen &&
aio->keybuff,keylen,0)) mi_compare_text(aio->charset,info->lastkey,keylen, keybuff,keylen,0))
break; 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 #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT
#ifdef EVAL_RUN tmp_weight=*(float*)&subkeys;
mi_float4get(tmp_weight,aio->info->lastkey+keylen+1);
#else /* EVAL_RUN */
mi_float4get(tmp_weight,aio->info->lastkey+keylen);
#endif /* EVAL_RUN */
#else #else
#error #error
#endif #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 sdoc.doc.dpos=info->lastpos;
cnt=*(byte *)(aio->info->lastkey+keylen);
#endif /* EVAL_RUN */
sdoc.doc.dpos=aio->info->lastpos;
/* saving document matched into dtree */ /* saving document matched into dtree */
if (!(selem=tree_insert(&aio->dtree, &sdoc, 0, aio->dtree.custom_arg))) 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) ...@@ -137,20 +137,13 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio)
sptr->tmp_weight=tmp_weight; sptr->tmp_weight=tmp_weight;
doc_cnt++; doc_cnt++;
#ifdef EVAL_RUN
sum +=cnt; if (_mi_test_if_changed(info) == 0)
sum2+=cnt*cnt; r=_mi_search_next(info, keyinfo, info->lastkey, info->lastkey_length,
suml+=cnt*log(cnt); SEARCH_BIGGER, key_root);
#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);
else else
r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey, r=_mi_search(info, keyinfo, info->lastkey, info->lastkey_length,
aio->info->lastkey_length, SEARCH_BIGGER, SEARCH_BIGGER, key_root);
aio->key_root);
} }
if (doc_cnt) if (doc_cnt)
{ {
...@@ -200,10 +193,8 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query, ...@@ -200,10 +193,8 @@ FT_INFO *ft_init_nlq_search(MI_INFO *info, uint keynr, byte *query,
aio.info=info; aio.info=info;
aio.keynr=keynr; aio.keynr=keynr;
aio.keyinfo=info->s->keyinfo+keynr; aio.charset=info->s->keyinfo[keynr].seg->charset;
aio.charset=aio.keyinfo->seg->charset;
aio.keybuff=info->lastkey+info->s->base.max_key_length; 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)); bzero(&allocated_wtree,sizeof(allocated_wtree));
......
...@@ -18,21 +18,10 @@ ...@@ -18,21 +18,10 @@
#include "ftdefs.h" #include "ftdefs.h"
#ifdef EVAL_RUN
#ifdef PIVOT_STAT
ulong collstat=0;
#endif
#endif /* EVAL_RUN */
typedef struct st_ft_docstat { typedef struct st_ft_docstat {
FT_WORD *list; FT_WORD *list;
uint uniq; uint uniq;
double sum; double sum;
#ifdef EVAL_RUN
uint words, totlen;
double max, nsum, nsum2;
#endif /* EVAL_RUN */
} FT_DOCSTAT; } FT_DOCSTAT;
static int FT_WORD_cmp(CHARSET_INFO* cs, FT_WORD *w1, FT_WORD *w2) 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) ...@@ -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) static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat)
{ {
word->weight=LWS_IN_USE; 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; docstat->sum+=word->weight;
memcpy_fixed((docstat->list)++,word,sizeof(FT_WORD)); memcpy_fixed((docstat->list)++,word,sizeof(FT_WORD));
return 0; return 0;
} }
...@@ -70,9 +51,6 @@ FT_WORD * ft_linearize(TREE *wtree) ...@@ -70,9 +51,6 @@ FT_WORD * ft_linearize(TREE *wtree)
{ {
docstat.list=wlist; docstat.list=wlist;
docstat.uniq=wtree->elements_in_tree; 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; docstat.sum=0;
tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right); tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right);
} }
...@@ -85,18 +63,8 @@ FT_WORD * ft_linearize(TREE *wtree) ...@@ -85,18 +63,8 @@ FT_WORD * ft_linearize(TREE *wtree)
for (p=wlist;p->pos;p++) for (p=wlist;p->pos;p++)
{ {
p->weight=PRENORM_IN_USE; 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++) for (p=wlist;p->pos;p++)
{ {
p->weight/=NORM_IN_USE; p->weight/=NORM_IN_USE;
......
...@@ -26,25 +26,21 @@ const char *ft_boolean_syntax="+ -><()~*:\"\"&|"; ...@@ -26,25 +26,21 @@ const char *ft_boolean_syntax="+ -><()~*:\"\"&|";
const HA_KEYSEG ft_keysegs[FT_SEGS]={ const HA_KEYSEG ft_keysegs[FT_SEGS]={
{ {
HA_KEYTYPE_VARTEXT, /* type */ HA_KEYTYPE_VARTEXT, /* type */
7, /* language (will be overwritten) */ 63, /* language (will be overwritten) */
0, 0, 0, /* null_bit, bit_start, bit_end */ 0, 0, 0, /* null_bit, bit_start, bit_end */
HA_VAR_LENGTH | HA_PACK_KEY, /* flag */ HA_VAR_LENGTH | HA_PACK_KEY, /* flag */
HA_FT_MAXLEN, /* length */ HA_FT_MAXLEN, /* length */
#ifdef EVAL_RUN
HA_FT_WLEN+1, /* start */
#else /* EVAL_RUN */
HA_FT_WLEN, /* start */ HA_FT_WLEN, /* start */
#endif /* EVAL_RUN */
0, /* null_pos */ 0, /* null_pos */
NULL /* charset */ NULL /* charset */
}, },
#ifdef EVAL_RUN
{ {
HA_KEYTYPE_INT8, 7, 0, 0, 0, 0, 1, HA_FT_WLEN, 0, NULL /*
}, Note, this (and the last HA_KEYTYPE_END) segment should NOT
#endif /* EVAL_RUN */ be packed in any way, otherwise w_search() won't be able to
{ update key entry 'in vivo'
HA_FT_WTYPE, 7, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, 0, 0, NULL */
HA_FT_WTYPE, 63, 0, 0, 0, HA_NO_SORT, HA_FT_WLEN, 0, 0, NULL
} }
}; };
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
void _mi_ft_segiterator_init(MI_INFO *info, uint keynr, const byte *record, void _mi_ft_segiterator_init(MI_INFO *info, uint keynr, const byte *record,
FT_SEG_ITERATOR *ftsi) 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->seg=info->s->keyinfo[keynr].seg;
ftsi->rec=record; ftsi->rec=record;
} }
...@@ -113,7 +113,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, ...@@ -113,7 +113,7 @@ FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr,
if (_mi_ft_parse(&ptree, info, keynr, record)) if (_mi_ft_parse(&ptree, info, keynr, record))
return NULL; 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, 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, ...@@ -267,13 +267,7 @@ uint _ft_make_key(MI_INFO *info, uint keynr, byte *keybuf, FT_WORD *wptr,
#error #error
#endif #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); int2store(buf+HA_FT_WLEN,wptr->len);
memcpy(buf+HA_FT_WLEN+2,wptr->pos,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); return _mi_make_key(info,keynr,(uchar*) keybuf,buf,filepos);
} }
...@@ -60,16 +60,6 @@ ...@@ -60,16 +60,6 @@
#define NORM_SUM (docstat.nsum) #define NORM_SUM (docstat.nsum)
#define NORM_COS (sqrt(docstat.nsum2)) #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 PIVOT_VAL (0.0115)
#define NORM_PIVOT (1+PIVOT_VAL*docstat.uniq) #define NORM_PIVOT (1+PIVOT_VAL*docstat.uniq)
/*---------------------------------------------------------------*/ /*---------------------------------------------------------------*/
...@@ -102,9 +92,6 @@ typedef struct st_ft_word { ...@@ -102,9 +92,6 @@ typedef struct st_ft_word {
byte * pos; byte * pos;
uint len; uint len;
double weight; double weight;
#ifdef EVAL_RUN
byte cnt;
#endif /* EVAL_RUN */
} FT_WORD; } FT_WORD;
typedef struct st_ftb_param { typedef struct st_ftb_param {
......
...@@ -21,19 +21,16 @@ ...@@ -21,19 +21,16 @@
#include "myisamdef.h" #include "myisamdef.h"
#include "ft_global.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_WTYPE HA_KEYTYPE_FLOAT
#define HA_FT_WLEN 4 #define HA_FT_WLEN 4
#ifdef EVAL_RUN
#define FT_SEGS 3
#else /* EVAL_RUN */
#define FT_SEGS 2 #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]; extern const HA_KEYSEG ft_keysegs[FT_SEGS];
int _mi_ft_cmp(MI_INFO *, uint, const byte *, const byte *); 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_add(MI_INFO *, uint, byte *, const byte *, my_off_t);
int _mi_ft_del(MI_INFO *, uint, byte *, const byte *, my_off_t); int _mi_ft_del(MI_INFO *, uint, byte *, const byte *, my_off_t);
...@@ -49,10 +49,11 @@ static int sort_key_read(MI_SORT_PARAM *sort_param,void *key); ...@@ -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_ft_key_read(MI_SORT_PARAM *sort_param,void *key);
static int sort_get_next_record(MI_SORT_PARAM *sort_param); 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_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 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, static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo,
uchar *key); 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, reg1 SORT_KEY_BLOCKS *key_block,
uchar *key, my_off_t prev_block); uchar *key, my_off_t prev_block);
static int sort_delete_record(MI_SORT_PARAM *sort_param); 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, ...@@ -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 : ((param->testflag & T_CREATE_MISSING_KEYS) ? info->state->records :
(ha_rows) (sort_info.filelength/length+1)); (ha_rows) (sort_info.filelength/length+1));
sort_param.key_cmp=sort_key_cmp; sort_param.key_cmp=sort_key_cmp;
sort_param.key_write=sort_key_write;
sort_param.lock_in_memory=lock_memory; sort_param.lock_in_memory=lock_memory;
sort_param.tmpdir=param->tmpdir; sort_param.tmpdir=param->tmpdir;
sort_param.sort_info=&sort_info; sort_param.sort_info=&sort_info;
...@@ -1943,10 +1943,14 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *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); (ha_rows) (sort_info.filelength/ft_max_word_len_for_sort+1);
sort_param.key_read=sort_ft_key_read; sort_param.key_read=sort_ft_key_read;
sort_param.key_write=sort_ft_key_write;
sort_param.key_length+=ft_max_word_len_for_sort-HA_FT_MAXLEN; sort_param.key_length+=ft_max_word_len_for_sort-HA_FT_MAXLEN;
} }
else else
{
sort_param.key_read=sort_key_read; sort_param.key_read=sort_key_read;
sort_param.key_write=sort_key_write;
}
if (_create_index_by_sort(&sort_param, if (_create_index_by_sort(&sort_param,
(my_bool) (!(param->testflag & T_VERBOSE)), (my_bool) (!(param->testflag & T_VERBOSE)),
...@@ -1992,9 +1996,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, ...@@ -1992,9 +1996,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info,
else else
info->state->data_file_length=sort_param.max_pos; 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 */ param->read_cache.file=info->dfile; /* re-init read cache */
reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length, reinit_io_cache(&param->read_cache,READ_CACHE,share->pack.header_length,
1,1); 1,1);
...@@ -2093,6 +2094,7 @@ err: ...@@ -2093,6 +2094,7 @@ err:
MYF(MY_ALLOW_ZERO_PTR)); MYF(MY_ALLOW_ZERO_PTR));
my_free(sort_param.record,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.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)); my_free(sort_info.buff,MYF(MY_ALLOW_ZERO_PTR));
VOID(end_io_cache(&param->read_cache)); VOID(end_io_cache(&param->read_cache));
info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED); info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
...@@ -2108,7 +2110,7 @@ err: ...@@ -2108,7 +2110,7 @@ err:
Threaded repair of table using sorting Threaded repair of table using sorting
SYNOPSIS SYNOPSIS
mi_repair_by_sort_r() mi_repair_by_sort_parallel()
param Repair parameters param Repair parameters
info MyISAM handler to repair info MyISAM handler to repair
name Name of table (for warnings) name Name of table (for warnings)
...@@ -2280,10 +2282,17 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, ...@@ -2280,10 +2282,17 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info,
} }
if ((!(param->testflag & T_SILENT))) if ((!(param->testflag & T_SILENT)))
printf ("- Fixing index %d\n",key+1); printf ("- Fixing index %d\n",key+1);
sort_param[i].key_read= ((sort_param[i].keyinfo->flag & HA_FULLTEXT) ? if (sort_param[i].keyinfo->flag & HA_FULLTEXT)
sort_ft_key_read : sort_key_read); {
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_cmp=sort_key_cmp;
sort_param[i].key_write=sort_key_write;
sort_param[i].lock_in_memory=lock_memory; sort_param[i].lock_in_memory=lock_memory;
sort_param[i].tmpdir=param->tmpdir; sort_param[i].tmpdir=param->tmpdir;
sort_param[i].sort_info=&sort_info; sort_param[i].sort_info=&sort_info;
...@@ -2476,6 +2485,7 @@ err: ...@@ -2476,6 +2485,7 @@ err:
pthread_cond_destroy (&sort_info.cond); pthread_cond_destroy (&sort_info.cond);
pthread_mutex_destroy(&sort_info.mutex); 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_info.key_block,MYF(MY_ALLOW_ZERO_PTR));
my_free((gptr) sort_param,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)); 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) ...@@ -3110,6 +3120,137 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a)
(uchar*) a, HA_OFFSET_ERROR)); (uchar*) a, HA_OFFSET_ERROR));
} /* sort_key_write */ } /* 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 */ /* get pointer to record from a key */
...@@ -3269,7 +3410,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param) ...@@ -3269,7 +3410,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param)
my_off_t filepos,key_file_length; my_off_t filepos,key_file_length;
SORT_KEY_BLOCKS *key_block; SORT_KEY_BLOCKS *key_block;
SORT_INFO *sort_info= sort_param->sort_info; 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_INFO *info=sort_info->info;
MI_KEYDEF *keyinfo=sort_param->keyinfo; MI_KEYDEF *keyinfo=sort_param->keyinfo;
DBUG_ENTER("flush_pending_blocks"); DBUG_ENTER("flush_pending_blocks");
...@@ -3294,7 +3435,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param) ...@@ -3294,7 +3435,7 @@ int flush_pending_blocks(MI_SORT_PARAM *sort_param)
DBUG_RETURN(1); DBUG_RETURN(1);
} }
else if (my_pwrite(info->s->kfile,(byte*) key_block->buff, 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_RETURN(1);
DBUG_DUMP("buff",(byte*) key_block->buff,length); DBUG_DUMP("buff",(byte*) key_block->buff,length);
nod_flag=1; nod_flag=1;
......
...@@ -44,7 +44,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -44,7 +44,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
uint fields,length,max_key_length,packed,pointer, uint fields,length,max_key_length,packed,pointer,
key_length,info_length,key_segs,options,min_key_length_skipp, key_length,info_length,key_segs,options,min_key_length_skipp,
base_pos,varchar_count,long_varchar_count,varchar_length, 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; ulong reclength, real_reclength,min_pack_length;
char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr; char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr;
ulong pack_reclength; ulong pack_reclength;
...@@ -223,6 +223,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -223,6 +223,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
reclength+=long_varchar_count; /* We need space for this! */ reclength+=long_varchar_count; /* We need space for this! */
max_key_length=0; tot_length=0 ; key_segs=0; max_key_length=0; tot_length=0 ; key_segs=0;
fulltext_keys=0;
max_key_block_length=0; max_key_block_length=0;
share.state.rec_per_key_part=rec_per_key_part; share.state.rec_per_key_part=rec_per_key_part;
share.state.key_root=key_root; share.state.key_root=key_root;
...@@ -242,14 +243,14 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -242,14 +243,14 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if (keydef->flag & HA_SPATIAL) if (keydef->flag & HA_SPATIAL)
{ {
/* BAR TODO to support 3D and more dimensions in the future */ /* 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; keydef->flag=HA_SPATIAL;
if (flags & HA_DONT_TOUCH_DATA) if (flags & HA_DONT_TOUCH_DATA)
{ {
/* /*
called by myisamchk - i.e. table structure was taken from 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 We'd better delete them now
*/ */
keydef->keysegs-=sp_segs; keydef->keysegs-=sp_segs;
...@@ -271,20 +272,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -271,20 +272,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
min_key_length_skipp+=SPLEN*2*SPDIMS; min_key_length_skipp+=SPLEN*2*SPDIMS;
} }
else else
if (keydef->flag & HA_FULLTEXT) /* SerG */ if (keydef->flag & HA_FULLTEXT)
{ {
keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY; keydef->flag=HA_FULLTEXT | HA_PACK_KEY | HA_VAR_LENGTH_KEY;
options|=HA_OPTION_PACK_KEYS; /* Using packed keys */ 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 ; for (j=0, keyseg=keydef->seg ; (int) j < keydef->keysegs ;
j++, keyseg++) j++, keyseg++)
{ {
...@@ -295,19 +287,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -295,19 +287,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
goto err; goto err;
} }
} }
keydef->keysegs+=FT_SEGS;
fulltext_keys++;
key_length+= HA_FT_MAXLEN+HA_FT_WLEN; key_length+= HA_FT_MAXLEN+HA_FT_WLEN;
#ifdef EVAL_RUN
key_length++;
#endif
length++; /* At least one length byte */ length++; /* At least one length byte */
min_key_length_skipp+=HA_FT_MAXLEN; 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 else
{ {
...@@ -473,8 +457,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -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_get_pointer_length((tot_length + max_key_block_length * keys *
MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH, MI_INDEX_BLOCK_MARGIN) / MI_MIN_KEY_BLOCK_LENGTH,
3); 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.uniques= uniques;
share.state.header.fulltext_keys= fulltext_keys;
mi_int2store(share.state.header.key_parts,key_segs); mi_int2store(share.state.header.key_parts,key_segs);
mi_int2store(share.state.header.unique_key_parts,unique_key_parts); 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, ...@@ -566,7 +551,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
linkname_ptr=0; linkname_ptr=0;
create_flag=MY_DELETE_OLD; create_flag=MY_DELETE_OLD;
} }
if ((dfile= if ((dfile=
my_create_with_symlink(linkname_ptr, filename, my_create_with_symlink(linkname_ptr, filename,
0,O_RDWR | O_TRUNC, 0,O_RDWR | O_TRUNC,
MYF(MY_WME | create_flag))) < 0) MYF(MY_WME | create_flag))) < 0)
...@@ -590,21 +575,13 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -590,21 +575,13 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
/* Write key and keyseg definitions */ /* Write key and keyseg definitions */
for (i=0 ; i < share.base.keys - uniques; i++) 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; uint sp_segs=(keydefs[i].flag & HA_SPATIAL) ? 2*SPDIMS : 0;
if (mi_keydef_write(file, &keydefs[i])) if (mi_keydef_write(file, &keydefs[i]))
goto err; 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])) if (mi_keyseg_write(file, &keydefs[i].seg[j]))
goto err; 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++) for (j=0 ; j < sp_segs ; j++)
{ {
HA_KEYSEG sseg; HA_KEYSEG sseg;
......
...@@ -23,13 +23,13 @@ ...@@ -23,13 +23,13 @@
#include <errno.h> #include <errno.h>
#endif #endif
static int d_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, static int d_search(MI_INFO *info,MI_KEYDEF *keyinfo,uint comp_flag,
uint key_length, my_off_t page, uchar *anc_buff); 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, 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 leaf_page,uchar *leaf_buff,uchar *keypos,
my_off_t next_block,uchar *ret_key); my_off_t next_block,uchar *ret_key);
static int underflow(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *anc_buff, 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, static uint remove_key(MI_KEYDEF *keyinfo,uint nod_flag,uchar *keypos,
uchar *lastkey,uchar *page_end, uchar *lastkey,uchar *page_end,
my_off_t *next_block); my_off_t *next_block);
...@@ -73,7 +73,6 @@ int mi_delete(MI_INFO *info,const byte *record) ...@@ -73,7 +73,6 @@ int mi_delete(MI_INFO *info,const byte *record)
if (((ulonglong) 1 << i) & info->s->state.key_map) if (((ulonglong) 1 << i) & info->s->state.key_map)
{ {
info->s->keyinfo[i].version++; info->s->keyinfo[i].version++;
/* The following code block is for text searching by SerG */
if (info->s->keyinfo[i].flag & HA_FULLTEXT ) if (info->s->keyinfo[i].flag & HA_FULLTEXT )
{ {
if (_mi_ft_del(info,i,(char*) old_key,record,info->lastpos)) 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) ...@@ -82,7 +81,7 @@ int mi_delete(MI_INFO *info,const byte *record)
else else
{ {
if (info->s->keyinfo[i].ck_delete(info,i,old_key, 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; goto err;
} }
} }
...@@ -128,19 +127,24 @@ err: ...@@ -128,19 +127,24 @@ err:
int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key, int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key,
uint key_length) 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; int error;
uint nod_flag; uint nod_flag;
my_off_t old_root; my_off_t old_root;
uchar *root_buff; uchar *root_buff;
MI_KEYDEF *keyinfo; DBUG_ENTER("_mi_ck_real_delete");
DBUG_ENTER("_mi_ck_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); DBUG_RETURN(my_errno=HA_ERR_CRASHED);
} }
keyinfo=info->s->keyinfo+keynr;
if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+ if (!(root_buff= (uchar*) my_alloca((uint) keyinfo->block_length+
MI_MAX_KEY_BUFF*2))) MI_MAX_KEY_BUFF*2)))
{ {
...@@ -153,12 +157,15 @@ int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key, ...@@ -153,12 +157,15 @@ int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key,
error= -1; error= -1;
goto err; 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) if (error == 2)
{ {
DBUG_PRINT("test",("Enlarging of root when deleting")); 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 */ else /* error == 1 */
{ {
...@@ -166,10 +173,9 @@ int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key, ...@@ -166,10 +173,9 @@ int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key,
{ {
error=0; error=0;
if (nod_flag) if (nod_flag)
info->s->state.key_root[keynr]=_mi_kpos(nod_flag, *root=_mi_kpos(nod_flag,root_buff+2+nod_flag);
root_buff+2+nod_flag);
else else
info->s->state.key_root[keynr]= HA_OFFSET_ERROR; *root=HA_OFFSET_ERROR;
if (_mi_dispose(info,keyinfo,old_root)) if (_mi_dispose(info,keyinfo,old_root))
error= -1; error= -1;
} }
...@@ -180,7 +186,7 @@ int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key, ...@@ -180,7 +186,7 @@ int _mi_ck_delete(register MI_INFO *info, uint keynr, uchar *key,
err: err:
my_afree((gptr) root_buff); my_afree((gptr) root_buff);
DBUG_RETURN(error); DBUG_RETURN(error);
} /* _mi_ck_delete */ } /* _mi_ck_real_delete */
/* /*
...@@ -192,11 +198,11 @@ err: ...@@ -192,11 +198,11 @@ err:
*/ */
static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
uchar *key, uint key_length, my_off_t page, uint comp_flag, uchar *key, uint key_length,
uchar *anc_buff) my_off_t page, uchar *anc_buff)
{ {
int flag,ret_value,save_flag; int flag,ret_value,save_flag;
uint length,nod_flag; uint length,nod_flag,search_key_length;
my_bool last_key; my_bool last_key;
uchar *leaf_buff,*keypos; uchar *leaf_buff,*keypos;
my_off_t leaf_page,next_block; my_off_t leaf_page,next_block;
...@@ -204,9 +210,9 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, ...@@ -204,9 +210,9 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
DBUG_ENTER("d_search"); DBUG_ENTER("d_search");
DBUG_DUMP("page",(byte*) anc_buff,mi_getint(anc_buff)); DBUG_DUMP("page",(byte*) anc_buff,mi_getint(anc_buff));
flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key, USE_WHOLE_KEY, search_key_length= (comp_flag & SEARCH_FIND) ? key_length : USE_WHOLE_KEY;
SEARCH_SAME, flag=(*keyinfo->bin_search)(info,keyinfo,anc_buff,key, search_key_length,
&keypos, lastkey, &last_key); comp_flag, &keypos, lastkey, &last_key);
if (flag == MI_FOUND_WRONG_KEY) if (flag == MI_FOUND_WRONG_KEY)
{ {
DBUG_PRINT("error",("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, ...@@ -214,6 +220,52 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
} }
nod_flag=mi_test_if_nod(anc_buff); 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; leaf_buff=0;
LINT_INIT(leaf_page); LINT_INIT(leaf_page);
if (nod_flag) if (nod_flag)
...@@ -239,7 +291,8 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, ...@@ -239,7 +291,8 @@ static int d_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
goto err; goto err;
} }
save_flag=0; 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 else
{ /* Found key */ { /* Found key */
......
...@@ -69,7 +69,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -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; int lock_error,kfile,open_mode,save_errno,have_rtree=0;
uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys, 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], char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN],
data_name[FN_REFLEN]; data_name[FN_REFLEN];
char *disk_cache,*disk_pos; char *disk_cache,*disk_pos;
...@@ -126,8 +126,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -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_TEMP_COMPRESS_RECORD | HA_OPTION_CHECKSUM |
HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE)) HA_OPTION_TMP_TABLE | HA_OPTION_DELAY_KEY_WRITE))
{ {
DBUG_PRINT("error",("wrong options: 0x%lx", DBUG_PRINT("error",("wrong options: 0x%lx", share->options));
share->options));
my_errno=HA_ERR_OLD_FILE; my_errno=HA_ERR_OLD_FILE;
goto err; goto err;
} }
...@@ -162,11 +161,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -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); len=mi_uint2korr(share->state.header.state_info_length);
keys= (uint) share->state.header.keys; keys= (uint) share->state.header.keys;
uniques= (uint) share->state.header.uniques; uniques= (uint) share->state.header.uniques;
fulltext_keys= (uint) share->state.header.fulltext_keys;
key_parts= mi_uint2korr(share->state.header.key_parts); key_parts= mi_uint2korr(share->state.header.key_parts);
unique_key_parts= mi_uint2korr(share->state.header.unique_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) if (len != MI_STATE_INFO_SIZE)
{ {
DBUG_PRINT("warning", DBUG_PRINT("warning",
...@@ -203,6 +200,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -203,6 +200,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
goto err; goto err;
} }
key_parts+=fulltext_keys*FT_SEGS;
if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY || if (share->base.max_key_length > MI_MAX_KEY_BUFF || keys > MI_MAX_KEY ||
key_parts >= MI_MAX_KEY * MI_MAX_KEY_SEG) 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) ...@@ -211,7 +209,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
goto err; 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= max_data_file_length=
(share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? (share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ?
(((ulonglong) 1 << (share->base.rec_reflength*8))-1) : (((ulonglong) 1 << (share->base.rec_reflength*8))-1) :
...@@ -290,12 +288,14 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -290,12 +288,14 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
for (i=0 ; i < keys ; i++) for (i=0 ; i < keys ; i++)
{ {
disk_pos=mi_keydef_read(disk_pos, &share->keyinfo[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); set_if_smaller(share->blocksize,share->keyinfo[i].block_length);
share->keyinfo[i].seg=pos; share->keyinfo[i].seg=pos;
for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++) for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
{ {
disk_pos=mi_keyseg_read(disk_pos, pos); disk_pos=mi_keyseg_read(disk_pos, pos);
if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT) if (pos->type == HA_KEYTYPE_TEXT || pos->type == HA_KEYTYPE_VARTEXT)
{ {
if (!pos->language) if (!pos->language)
...@@ -312,11 +312,41 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -312,11 +312,41 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
uint sp_segs=SPDIMS*2; uint sp_segs=SPDIMS*2;
share->keyinfo[i].seg=pos-sp_segs; share->keyinfo[i].seg=pos-sp_segs;
share->keyinfo[i].keysegs--; 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; if (!fulltext_keys)
share->fulltext_index=1; { /* 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; share->keyinfo[i].end=pos;
pos->type=HA_KEYTYPE_END; /* End */ pos->type=HA_KEYTYPE_END; /* End */
pos->length=share->base.rec_reflength; pos->length=share->base.rec_reflength;
...@@ -349,12 +379,6 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) ...@@ -349,12 +379,6 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
pos++; 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++) for (i=j=offset=0 ; i < share->base.fields ; i++)
{ {
...@@ -712,9 +736,9 @@ static void setup_key_functions(register MI_KEYDEF *keyinfo) ...@@ -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) uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite)
{ {
......
...@@ -51,7 +51,7 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx) ...@@ -51,7 +51,7 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx)
case HA_KEY_ALG_BTREE: case HA_KEY_ALG_BTREE:
default: default:
error=_mi_search_first(info,info->s->keyinfo+inx, error=_mi_search_first(info,info->s->keyinfo+inx,
info->s->state.key_root[inx]); info->s->state.key_root[inx]);
break; break;
} }
} }
...@@ -60,17 +60,17 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx) ...@@ -60,17 +60,17 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx)
switch(info->s->keyinfo[inx].key_alg) switch(info->s->keyinfo[inx].key_alg)
{ {
case HA_KEY_ALG_RTREE: case HA_KEY_ALG_RTREE:
/* /*
Note that rtree doesn't support that the table Note that rtree doesn't support that the table
may be changed since last call, so we do need may be changed since last call, so we do need
to skip rows inserted by other threads like in btree to skip rows inserted by other threads like in btree
*/ */
error=rtree_get_next(info,inx,info->lastkey_length); error=rtree_get_next(info,inx,info->lastkey_length);
break; break;
case HA_KEY_ALG_BTREE: case HA_KEY_ALG_BTREE:
default: default:
if (!changed) if (!changed)
{ {
error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey,
info->lastkey_length,flag, info->lastkey_length,flag,
...@@ -81,15 +81,15 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx) ...@@ -81,15 +81,15 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx)
error=_mi_search(info,info->s->keyinfo+inx,info->lastkey, error=_mi_search(info,info->s->keyinfo+inx,info->lastkey,
USE_WHOLE_KEY,flag, info->s->state.key_root[inx]); 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) while (info->lastpos >= info->state->data_file_length)
{ {
/* Skip rows that are inserted by other threads since we got a lock */ /* 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, if ((error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey,
info->lastkey_length, info->lastkey_length,
SEARCH_BIGGER, SEARCH_BIGGER,
info->s->state.key_root[inx]))) info->s->state.key_root[inx])))
break; break;
} }
} }
......
...@@ -91,7 +91,6 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) ...@@ -91,7 +91,6 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec)
{ {
if (((ulonglong) 1 << i) & share->state.key_map) 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 (share->keyinfo[i].flag & HA_FULLTEXT )
{ {
if (_mi_ft_cmp(info,i,oldrec, newrec)) if (_mi_ft_cmp(info,i,oldrec, newrec))
...@@ -175,7 +174,6 @@ err: ...@@ -175,7 +174,6 @@ err:
{ {
if (((ulonglong) 1 << i) & changed) if (((ulonglong) 1 << i) & changed)
{ {
/* The following code block is for text searching by SerG */
if (share->keyinfo[i].flag & HA_FULLTEXT) if (share->keyinfo[i].flag & HA_FULLTEXT)
{ {
if ((flag++ && _mi_ft_del(info,i,(char*) new_key,newrec,pos)) || if ((flag++ && _mi_ft_del(info,i,(char*) new_key,newrec,pos)) ||
......
...@@ -38,9 +38,9 @@ static int _mi_balance_page(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key, ...@@ -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, static uchar *_mi_find_last_pos(MI_KEYDEF *keyinfo, uchar *page,
uchar *key, uint *return_key_length, uchar *key, uint *return_key_length,
uchar **after_key); 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); 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); uint key_length);
/* Write new record to database */ /* Write new record to database */
...@@ -250,11 +250,12 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, ...@@ -250,11 +250,12 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
int error; int error;
uint comp_flag; uint comp_flag;
MI_KEYDEF *keyinfo=info->s->keyinfo+keynr; MI_KEYDEF *keyinfo=info->s->keyinfo+keynr;
my_off_t *root=&info->s->state.key_root[keynr];
DBUG_ENTER("_mi_ck_write_btree"); DBUG_ENTER("_mi_ck_write_btree");
if (keyinfo->flag & HA_SORT_ALLOWS_SAME) if (keyinfo->flag & HA_SORT_ALLOWS_SAME)
comp_flag=SEARCH_BIGGER; /* Put after same key */ 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 */ comp_flag=SEARCH_FIND | SEARCH_UPDATE; /* No dupplicates */
if (keyinfo->flag & HA_NULL_ARE_EQUAL) if (keyinfo->flag & HA_NULL_ARE_EQUAL)
...@@ -263,37 +264,34 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, ...@@ -263,37 +264,34 @@ int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key,
else else
comp_flag=SEARCH_SAME; /* Keys in rec-pos order */ 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, (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) (my_off_t) 0, 1)) > 0)
error=_mi_enlarge_root(info,keynr,key); error=_mi_enlarge_root(info,keyinfo,key,root);
DBUG_RETURN(error); DBUG_RETURN(error);
} /* _mi_ck_write_btree */ } /* _mi_ck_write_btree */
/* Make a new root with key as only pointer */ /* 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; uint t_length,nod_flag;
reg2 MI_KEYDEF *keyinfo;
MI_KEY_PARAM s_temp; MI_KEY_PARAM s_temp;
MYISAM_SHARE *share=info->s; MYISAM_SHARE *share=info->s;
DBUG_ENTER("_mi_enlarge_root"); DBUG_ENTER("_mi_enlarge_root");
nod_flag= (share->state.key_root[keynr] != HA_OFFSET_ERROR) ? nod_flag= (*root != HA_OFFSET_ERROR) ? share->base.key_reflength : 0;
share->base.key_reflength : 0; _mi_kpointer(info,info->buff+2,*root); /* if nod */
_mi_kpointer(info,info->buff+2,share->state.key_root[keynr]); /* if nod */
keyinfo=share->keyinfo+keynr;
t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar*) 0, t_length=(*keyinfo->pack_key)(keyinfo,nod_flag,(uchar*) 0,
(uchar*) 0, (uchar*) 0, key,&s_temp); (uchar*) 0, (uchar*) 0, key,&s_temp);
mi_putint(info->buff,t_length+2+nod_flag,nod_flag); mi_putint(info->buff,t_length+2+nod_flag,nod_flag);
(*keyinfo->store_key)(keyinfo,info->buff+2+nod_flag,&s_temp); (*keyinfo->store_key)(keyinfo,info->buff+2+nod_flag,&s_temp);
info->buff_used=info->page_changed=1; /* info->buff is used */ info->buff_used=info->page_changed=1; /* info->buff is used */
if ((share->state.key_root[keynr]= _mi_new(info,keyinfo)) == if ((*root= _mi_new(info,keyinfo)) == HA_OFFSET_ERROR ||
HA_OFFSET_ERROR || _mi_write_keypage(info,keyinfo,*root,info->buff))
_mi_write_keypage(info,keyinfo,share->state.key_root[keynr],info->buff))
DBUG_RETURN(-1); DBUG_RETURN(-1);
DBUG_RETURN(0); DBUG_RETURN(0);
} /* _mi_enlarge_root */ } /* _mi_enlarge_root */
...@@ -333,15 +331,54 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, ...@@ -333,15 +331,54 @@ static int w_search(register MI_INFO *info, register MI_KEYDEF *keyinfo,
if (flag == 0) if (flag == 0)
{ {
uint tmp_key_length; uint tmp_key_length;
my_errno=HA_ERR_FOUND_DUPP_KEY;
/* get position to record with duplicated key */ /* get position to record with duplicated key */
tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff); tmp_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&keypos,keybuff);
if (tmp_key_length) if (tmp_key_length)
info->dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length); info->dupp_key_pos=_mi_dpos(info,0,keybuff+tmp_key_length);
else else
info->dupp_key_pos= HA_OFFSET_ERROR; info->dupp_key_pos= HA_OFFSET_ERROR;
my_afree((byte*) temp_buff); if (keyinfo->flag & HA_FULLTEXT)
DBUG_RETURN(-1); {
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) if (flag == MI_FOUND_WRONG_KEY)
DBUG_RETURN(-1); DBUG_RETURN(-1);
...@@ -394,7 +431,9 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, ...@@ -394,7 +431,9 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo,
#ifndef DBUG_OFF #ifndef DBUG_OFF
if (key_pos != anc_buff+2+nod_flag && (keyinfo->flag & if (key_pos != anc_buff+2+nod_flag && (keyinfo->flag &
(HA_BINARY_PACK_KEY | HA_PACK_KEY))) (HA_BINARY_PACK_KEY | HA_PACK_KEY)))
{
DBUG_DUMP("prev_key",(byte*) key_buff,_mi_keylength(keyinfo,key_buff)); DBUG_DUMP("prev_key",(byte*) key_buff,_mi_keylength(keyinfo,key_buff));
}
if (keyinfo->flag & HA_PACK_KEY) if (keyinfo->flag & HA_PACK_KEY)
{ {
DBUG_PRINT("test",("t_length: %d ref_len: %d", 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, ...@@ -753,7 +792,7 @@ int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key,
DBUG_ENTER("_mi_ck_write_tree"); DBUG_ENTER("_mi_ck_write_tree");
error= tree_insert(&info->bulk_insert[keynr], key, 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 ; info->bulk_insert[keynr].custom_arg) ? 0 : HA_ERR_OUT_OF_MEM ;
DBUG_RETURN(error); DBUG_RETURN(error);
......
...@@ -874,8 +874,8 @@ static int myisamchk(MI_CHECK *param, my_string filename) ...@@ -874,8 +874,8 @@ static int myisamchk(MI_CHECK *param, my_string filename)
} }
else else
{ {
if (share->fulltext_index) if (share->state.header.fulltext_keys)
ft_init_stopwords(ft_precompiled_stopwords); /* SerG */ ft_init_stopwords(ft_precompiled_stopwords);
if (!(param->testflag & T_READONLY)) if (!(param->testflag & T_READONLY))
lock_type = F_WRLCK; /* table is changed */ lock_type = F_WRLCK; /* table is changed */
......
...@@ -55,7 +55,8 @@ typedef struct st_mi_state_info ...@@ -55,7 +55,8 @@ typedef struct st_mi_state_info
uchar uniques; /* number of UNIQUE definitions */ uchar uniques; /* number of UNIQUE definitions */
uchar language; /* Language for indexes */ uchar language; /* Language for indexes */
uchar max_block_size; /* max keyblock size */ 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; } header;
MI_STATUS_INFO state; MI_STATUS_INFO state;
...@@ -90,7 +91,7 @@ typedef struct st_mi_state_info ...@@ -90,7 +91,7 @@ typedef struct st_mi_state_info
} MI_STATE_INFO; } MI_STATE_INFO;
#define MI_STATE_INFO_SIZE (24+14*8+7*4+2*2+8) #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_KEYBLOCK_SIZE 8
#define MI_STATE_KEYSEG_SIZE 4 #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) #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 { ...@@ -154,6 +155,7 @@ typedef struct st_mi_isam_pack {
typedef struct st_mi_isam_share { /* Shared between opens */ typedef struct st_mi_isam_share { /* Shared between opens */
MI_STATE_INFO state; MI_STATE_INFO state;
MI_BASE_INFO base; MI_BASE_INFO base;
MI_KEYDEF ft2_keyinfo; /* Second-level ft-key definition */
MI_KEYDEF *keyinfo; /* Key definitions */ MI_KEYDEF *keyinfo; /* Key definitions */
MI_UNIQUEDEF *uniqueinfo; /* unique definitions */ MI_UNIQUEDEF *uniqueinfo; /* unique definitions */
HA_KEYSEG *keyparts; /* key part info */ HA_KEYSEG *keyparts; /* key part info */
...@@ -197,8 +199,7 @@ typedef struct st_mi_isam_share { /* Shared between opens */ ...@@ -197,8 +199,7 @@ typedef struct st_mi_isam_share { /* Shared between opens */
global_changed, /* If changed since open */ global_changed, /* If changed since open */
not_flushed, not_flushed,
temporary,delay_key_write, temporary,delay_key_write,
concurrent_insert, concurrent_insert;
fulltext_index;
#ifdef THREAD #ifdef THREAD
THR_LOCK lock; THR_LOCK lock;
pthread_mutex_t intern_lock; /* Locking for use with _locking */ pthread_mutex_t intern_lock; /* Locking for use with _locking */
...@@ -229,6 +230,8 @@ struct st_myisam_info { ...@@ -229,6 +230,8 @@ struct st_myisam_info {
byte *rec_buff; /* Tempbuff for recordpack */ byte *rec_buff; /* Tempbuff for recordpack */
uchar *int_keypos, /* Save position for next/previous */ uchar *int_keypos, /* Save position for next/previous */
*int_maxpos; /* -""- */ *int_maxpos; /* -""- */
uint int_nod_flag; /* -""- */
uint32 int_keytree_version; /* -""- */
int (*read_record)(struct st_myisam_info*, my_off_t, byte*); int (*read_record)(struct st_myisam_info*, my_off_t, byte*);
invalidator_by_filename invalidator; /* query cache invalidator */ invalidator_by_filename invalidator; /* query cache invalidator */
ulong this_unique; /* uniq filenumber or thread */ ulong this_unique; /* uniq filenumber or thread */
...@@ -247,7 +250,6 @@ struct st_myisam_info { ...@@ -247,7 +250,6 @@ struct st_myisam_info {
int dfile; /* The datafile */ int dfile; /* The datafile */
uint opt_flag; /* Optim. for space/speed */ uint opt_flag; /* Optim. for space/speed */
uint update; /* If file changed since open */ uint update; /* If file changed since open */
uint int_nod_flag; /* -""- */
int lastinx; /* Last used index */ int lastinx; /* Last used index */
uint lastkey_length; /* Length of key in lastkey */ uint lastkey_length; /* Length of key in lastkey */
uint last_rkey_length; /* Last length in mi_rkey() */ uint last_rkey_length; /* Last length in mi_rkey() */
...@@ -259,7 +261,6 @@ struct st_myisam_info { ...@@ -259,7 +261,6 @@ struct st_myisam_info {
uint data_changed; /* Somebody has changed data */ uint data_changed; /* Somebody has changed data */
uint save_update; /* When using KEY_READ */ uint save_update; /* When using KEY_READ */
int save_lastinx; int save_lastinx;
uint32 int_keytree_version; /* -""- */
LIST open_list; LIST open_list;
IO_CACHE rec_cache; /* When cacheing records */ IO_CACHE rec_cache; /* When cacheing records */
myf lock_wait; /* is 0 or MY_DONT_WAIT */ myf lock_wait; /* is 0 or MY_DONT_WAIT */
...@@ -372,6 +373,13 @@ typedef struct st_mi_sort_param ...@@ -372,6 +373,13 @@ typedef struct st_mi_sort_param
{ length=mi_uint2korr((key)+1)+3; (key)+=3; } \ { 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 get_pack_length(length) ((length) >= 255 ? 3 : 1)
#define MI_MIN_BLOCK_LENGTH 20 /* Because of delete-link */ #define MI_MIN_BLOCK_LENGTH 20 /* Because of delete-link */
...@@ -395,7 +403,7 @@ typedef struct st_mi_sort_param ...@@ -395,7 +403,7 @@ typedef struct st_mi_sort_param
#define MI_FOUND_WRONG_KEY 32738 /* Impossible value from ha_key_cmp */ #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_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_MAX_KEYPTR_SIZE 5 /* For calculating block lengths */
#define MI_MIN_KEYBLOCK_LENGTH 50 /* When to split delete blocks */ #define MI_MIN_KEYBLOCK_LENGTH 50 /* When to split delete blocks */
...@@ -454,7 +462,7 @@ extern int _mi_delete_static_record(MI_INFO *info); ...@@ -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_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_read_rnd_static_record(MI_INFO*, byte *,my_off_t, my_bool);
extern int _mi_ck_write(MI_INFO *info,uint keynr,uchar *key,uint length); extern int _mi_ck_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, extern int _mi_insert(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *key,
uchar *anc_buff,uchar *key_pos,uchar *key_buff, uchar *anc_buff,uchar *key_pos,uchar *key_buff,
uchar *father_buff, uchar *father_keypos, uchar *father_buff, uchar *father_keypos,
...@@ -691,6 +699,7 @@ void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...)); ...@@ -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_warning _VARARGS((MI_CHECK *param, const char *fmt,...));
void mi_check_print_info _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 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); int thr_write_keys(MI_SORT_PARAM *sort_param);
#ifdef THREAD #ifdef THREAD
pthread_handler_decl(thr_find_all_keys,arg); pthread_handler_decl(thr_find_all_keys,arg);
......
...@@ -71,7 +71,8 @@ static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys, ...@@ -71,7 +71,8 @@ static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys,
BUFFPEK *Fb, BUFFPEK *Tb); BUFFPEK *Fb, BUFFPEK *Tb);
static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int, static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int,
IO_CACHE *); 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, static int NEAR_F write_keys_varlen(MI_SORT_PARAM *info,uchar **sort_keys,
uint count, BUFFPEK *buffpek, uint count, BUFFPEK *buffpek,
IO_CACHE *tempfile); IO_CACHE *tempfile);
...@@ -120,7 +121,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ...@@ -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->read_to_buffer=read_to_buffer;
info->write_key=write_merge_key; info->write_key=write_merge_key;
} }
my_b_clear(&tempfile); my_b_clear(&tempfile);
my_b_clear(&tempfile_for_exceptions); my_b_clear(&tempfile_for_exceptions);
bzero((char*) &buffpek,sizeof(buffpek)); bzero((char*) &buffpek,sizeof(buffpek));
...@@ -207,7 +208,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, ...@@ -207,7 +208,7 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages,
goto err; /* purecov: inspected */ goto err; /* purecov: inspected */
} }
if (flush_pending_blocks(info)) if (flush_ft_buf(info) || flush_pending_blocks(info))
goto err; goto err;
if (my_b_inited(&tempfile_for_exceptions)) if (my_b_inited(&tempfile_for_exceptions))
...@@ -478,7 +479,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) ...@@ -478,7 +479,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param)
fflush(stdout); fflush(stdout);
} }
if (write_index(sinfo, sinfo->sort_keys, sinfo->keys) || if (write_index(sinfo, sinfo->sort_keys, sinfo->keys) ||
flush_pending_blocks(sinfo)) flush_ft_buf(sinfo) || flush_pending_blocks(sinfo))
got_error=1; got_error=1;
} }
} }
...@@ -551,6 +552,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) ...@@ -551,6 +552,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param)
if (merge_index(sinfo, keys, (uchar **)mergebuf, if (merge_index(sinfo, keys, (uchar **)mergebuf,
dynamic_element(&sinfo->buffpek,0,BUFFPEK *), dynamic_element(&sinfo->buffpek,0,BUFFPEK *),
maxbuffer,&sinfo->tempfile) || maxbuffer,&sinfo->tempfile) ||
flush_ft_buf(sinfo) ||
flush_pending_blocks(sinfo)) flush_pending_blocks(sinfo))
{ {
got_error=1; got_error=1;
...@@ -976,3 +978,16 @@ merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys, ...@@ -976,3 +978,16 @@ merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys,
DBUG_RETURN(0); DBUG_RETURN(0);
} /* merge_index */ } /* 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;
}
...@@ -16,6 +16,8 @@ select * from t1 where MATCH(a,b) AGAINST ("indexes collections"); ...@@ -16,6 +16,8 @@ select * from t1 where MATCH(a,b) AGAINST ("indexes collections");
a b a b
Full-text indexes are called collections Full-text indexes are called collections
Only MyISAM tables support collections Only MyISAM tables support collections
select * from t1 where MATCH(a,b) AGAINST ("only");
a b
select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes"); select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes");
a b a b
Only MyISAM tables support collections Only MyISAM tables support collections
......
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;
...@@ -16,6 +16,7 @@ INSERT INTO t1 VALUES('MySQL has now support', 'for full-text search'), ...@@ -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 ("collections");
select * from t1 where MATCH(a,b) AGAINST ("indexes"); 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 ("indexes collections");
select * from t1 where MATCH(a,b) AGAINST ("only");
# UNION of fulltext's # UNION of fulltext's
select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes"); select * from t1 where MATCH(a,b) AGAINST ("collections") UNION ALL select * from t1 where MATCH(a,b) AGAINST ("indexes");
......
#
# 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;
...@@ -19,16 +19,18 @@ ...@@ -19,16 +19,18 @@
/* /*
Malloc many pointers at the same time 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 SYNOPSIS
my_multi_malloc() my_multi_malloc()
myFlags Flags myFlags Flags
... Multiple arguments terminated by null ptr ptr1, length1 Multiple arguments terminated by null ptr
ptr2, length2 ...
ptr, length ...
ptr, length
NULL NULL
*/ */
gptr my_multi_malloc(myf myFlags, ...) gptr my_multi_malloc(myf myFlags, ...)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment