diff options
Diffstat (limited to 'myisam')
-rw-r--r-- | myisam/Makefile.am | 13 | ||||
-rw-r--r-- | myisam/ft_boolean_search.c | 224 | ||||
-rw-r--r-- | myisam/ft_dump.c | 214 | ||||
-rw-r--r-- | myisam/ft_nlq_search.c | 192 | ||||
-rw-r--r-- | myisam/ft_parser.c | 140 | ||||
-rw-r--r-- | myisam/ft_search.c | 173 | ||||
-rw-r--r-- | myisam/ft_static.c | 4 | ||||
-rw-r--r-- | myisam/ft_stopwords.c | 9 | ||||
-rw-r--r-- | myisam/ft_update.c | 71 | ||||
-rw-r--r-- | myisam/ftdefs.h | 47 | ||||
-rw-r--r-- | myisam/fulltext.h | 1 | ||||
-rw-r--r-- | myisam/mi_check.c | 154 | ||||
-rw-r--r-- | myisam/mi_create.c | 80 | ||||
-rw-r--r-- | myisam/mi_dbug.c | 2 | ||||
-rw-r--r-- | myisam/mi_delete_table.c | 4 | ||||
-rw-r--r-- | myisam/mi_extra.c | 32 | ||||
-rw-r--r-- | myisam/mi_info.c | 2 | ||||
-rw-r--r-- | myisam/mi_locking.c | 13 | ||||
-rw-r--r-- | myisam/mi_open.c | 59 | ||||
-rw-r--r-- | myisam/mi_rename.c | 4 | ||||
-rw-r--r-- | myisam/mi_search.c | 1146 | ||||
-rw-r--r-- | myisam/mi_static.c | 4 | ||||
-rw-r--r-- | myisam/mi_statrec.c | 48 | ||||
-rwxr-xr-x | myisam/mi_test_all.sh | 7 | ||||
-rw-r--r-- | myisam/mi_update.c | 4 | ||||
-rw-r--r-- | myisam/mi_write.c | 157 | ||||
-rw-r--r-- | myisam/myisamchk.c | 36 | ||||
-rw-r--r-- | myisam/myisamdef.h | 26 | ||||
-rw-r--r-- | myisam/myisamlog.c | 9 | ||||
-rw-r--r-- | myisam/myisampack.c | 11 | ||||
-rw-r--r-- | myisam/sort.c | 154 |
31 files changed, 2123 insertions, 917 deletions
diff --git a/myisam/Makefile.am b/myisam/Makefile.am index a18ff55ba9e..6781116043f 100644 --- a/myisam/Makefile.am +++ b/myisam/Makefile.am @@ -1,15 +1,15 @@ # Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB -# +# # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -17,7 +17,7 @@ EXTRA_DIST = mi_test_all.sh mi_test_all.res pkgdata_DATA = mi_test_all mi_test_all.res -INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include +INCLUDES = @MT_INCLUDES@ -I$(srcdir)/../include -I../include LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a ../mysys/libmysys.a \ ../dbug/libdbug.a ../strings/libmystrings.a pkglib_LIBRARIES = libmyisam.a @@ -25,13 +25,14 @@ bin_PROGRAMS = myisamchk myisamlog myisampack myisamchk_DEPENDENCIES= $(LIBRARIES) myisamlog_DEPENDENCIES= $(LIBRARIES) myisampack_DEPENDENCIES=$(LIBRARIES) -noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_test1 ft_eval +noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 ft_test1 ft_eval ft_dump noinst_HEADERS = myisamdef.h fulltext.h ftdefs.h ft_test1.h ft_eval.h mi_test1_DEPENDENCIES= $(LIBRARIES) mi_test2_DEPENDENCIES= $(LIBRARIES) mi_test3_DEPENDENCIES= $(LIBRARIES) ft_test1_DEPENDENCIES= $(LIBRARIES) ft_eval_DEPENDENCIES= $(LIBRARIES) +ft_dump_DEPENDENCIES= $(LIBRARIES) libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \ mi_rnext.c mi_rnext_same.c \ mi_search.c mi_page.c mi_key.c mi_locking.c \ @@ -45,7 +46,7 @@ libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \ mi_changed.c mi_static.c mi_delete_all.c \ mi_delete_table.c mi_rename.c mi_check.c \ ft_parser.c ft_search.c ft_stopwords.c ft_static.c \ - ft_update.c sort.c + ft_update.c ft_boolean_search.c ft_nlq_search.c sort.c CLEANFILES = test?.MY? FT?.MY? isam.log mi_test_all DEFS = -DMAP_TO_USE_RAID # Omit dependency for ../mit-pthreads/include/sys that only exits if diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c new file mode 100644 index 00000000000..3562e05006a --- /dev/null +++ b/myisam/ft_boolean_search.c @@ -0,0 +1,224 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Written by Sergei A. Golubchik, who has a shared copyright to this code */ + +#include "ftdefs.h" + +/* search with boolean queries */ + +typedef struct st_all_in_one { + MI_INFO *info; + uint keynr; + uchar *keybuff; + MI_KEYDEF *keyinfo; + my_off_t key_root; + TREE dtree; + byte *start, *end; + uint total_yes, total_no; +} ALL_IN_ONE; + +typedef struct st_ft_superdoc { + FT_DOC doc; + //FT_WORD *word_ptr; + //double tmp_weight; + uint yes; + uint no; + uint wno; + ALL_IN_ONE *aio; +} FT_SUPERDOC; + +static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)), + FT_SUPERDOC *p1, FT_SUPERDOC *p2) +{ + if (p1->doc.dpos < p2->doc.dpos) + return -1; + if (p1->doc.dpos == p2->doc.dpos) + return 0; + return 1; +} + +static int walk_and_copy(FT_SUPERDOC *from, + uint32 count __attribute__((unused)), FT_DOC **to) +{ + if (from->yes == from->aio->total_yes && !from->no) + { + (*to)->dpos=from->doc.dpos; + (*to)->weight=from->doc.weight; + (*to)++; + } + return 0; +} + +static double _wghts[11]={ + 0.131687242798354, + 0.197530864197531, + 0.296296296296296, + 0.444444444444444, + 0.666666666666667, + 1.000000000000000, + 1.500000000000000, + 2.250000000000000, + 3.375000000000000, + 5.062500000000000, + 7.593750000000000}; +static double *wghts=_wghts+5; // wghts[i] = 1.5**i + +static double _nwghts[11]={ + -0.065843621399177, + -0.098765432098766, + -0.148148148148148, + -0.222222222222222, + -0.333333333333334, + -0.500000000000000, + -0.750000000000000, + -1.125000000000000, + -1.687500000000000, + -2.531250000000000, + -3.796875000000000}; +static double *nwghts=_nwghts+5; // nwghts[i] = -0.5*1.5**i + +int do_boolean(ALL_IN_ONE *aio, uint nested __attribute__((unused)), + int yesno __attribute__((unused)), + int plusminus, bool pmsign) +{ + int r, res; + uint keylen, wno; + FT_SUPERDOC sdoc, *sptr; + TREE_ELEMENT *selem; + FT_WORD w; + FTB_PARAM param; + +#ifdef EVAL_RUN + return 1; +#endif /* EVAL_RUN */ + + param.prev=' '; + + for(wno=1; (res=ft_get_word(&aio->start,aio->end,&w,¶m)); wno++) + { + r=plusminus+param.plusminus; + if (param.pmsign^pmsign) + w.weight=nwghts[(r>5)?5:((r<-5)?-5:r)]; + else + w.weight=wghts[(r>5)?5:((r<-5)?-5:r)]; + + if (param.yesno>0) aio->total_yes++; + if (param.yesno<0) aio->total_no++; + + switch (res) { + case FTB_LBR: // ( + //if (do_boolean(aio,nested+1,my_yesno,plusminus+my_plusminus)) + // return 1; + // ??? + break; + case 1: // word + keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,&w,0); + keylen-=HA_FT_WLEN; + + r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, + SEARCH_FIND | SEARCH_PREFIX, aio->key_root); + + while (!r) + { + if (param.trunc) + r=_mi_compare_text(default_charset_info, + aio->info->lastkey+1,keylen-1, + aio->keybuff+1,keylen-1,0); + else + r=_mi_compare_text(default_charset_info, + aio->info->lastkey,keylen, + aio->keybuff,keylen,0); + if (r) break; + + sdoc.doc.dpos=aio->info->lastpos; + + /* saving document matched into dtree */ + if (!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1; + + sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem); + + if (selem->count==1) /* document's first match */ + { + sptr->yes=sptr->no=sptr->doc.weight=0; + sptr->aio=aio; + sptr->wno=0; + } + if (sptr->wno != wno) + { + if (param.yesno>0) sptr->yes++; + if (param.yesno<0) sptr->no++; + sptr->wno=wno; + } + sptr->doc.weight+=w.weight; + + 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 + r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey, + aio->info->lastkey_length, SEARCH_BIGGER, + aio->key_root); + } + break; + case FTB_RBR: // ) + break; + } + } + return 0; +} + +FT_DOCLIST *ft_boolean_search(MI_INFO *info, uint keynr, byte *query, + uint query_len) +{ + ALL_IN_ONE aio; + FT_DOC *dptr; + FT_DOCLIST *dlist=NULL; + + aio.info=info; + aio.keynr=keynr; + aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length; + aio.keyinfo=aio.info->s->keyinfo+keynr; + aio.key_root=aio.info->s->state.key_root[keynr]; + aio.start=query; + aio.end=query+query_len; + aio.total_yes=aio.total_no=0; + + init_tree(&aio.dtree,0,0,sizeof(FT_SUPERDOC),(qsort_cmp2)&FT_SUPERDOC_cmp,0, + NULL, NULL); + + if (do_boolean(&aio,0,0,0,0)) + goto err; + + dlist=(FT_DOCLIST *)my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0)); + if(!dlist) + goto err; + + dlist->ndocs=aio.dtree.elements_in_tree; + dlist->curdoc=-1; + dlist->info=aio.info; + dptr=dlist->doc; + + tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right); + + dlist->ndocs=dptr - dlist->doc; + +err: + delete_tree(&aio.dtree); + return dlist; +} + diff --git a/myisam/ft_dump.c b/myisam/ft_dump.c new file mode 100644 index 00000000000..bb308188969 --- /dev/null +++ b/myisam/ft_dump.c @@ -0,0 +1,214 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Written by Sergei A. Golubchik, who has a shared copyright to this code */ + +#include "ftdefs.h" + +static void get_options(int argc,char *argv[]); +static void usage(char *argv[]); +static void complain(int val); + +static int count=0, stats=0, dump=0, verbose=0; +static char *query=NULL; + +#define MAX (HA_FT_MAXLEN+10) +#define HOW_OFTEN_TO_WRITE 1000 + +int main(int argc,char *argv[]) +{ + int error=0; + uint keylen, inx, doc_cnt=0; + float weight; + double gws, min_gws=0, avg_gws=0; + MI_INFO *info; + char buf[MAX], buf2[MAX], buf_maxlen[MAX], buf_min_gws[MAX]; + ulong total=0, maxlen=0, uniq=0, max_doc_cnt=0; +#ifdef EVAL_RUN + uint cnt; + double sum, sum2, suml; +#endif /* EVAL_RUN */ + struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */ + + MY_INIT(argv[0]); + get_options(argc,argv); + if (count || dump) + verbose=0; + else + stats=1; + + if (verbose) + setbuf(stdout,NULL); + + if (argc-optind < 2) + usage(argv); + + if (!(info=mi_open(argv[optind],2,HA_OPEN_ABORT_IF_LOCKED))) + goto err; + + inx=atoi(argv[optind+1]); + *buf2=0; + aio->info=info; + + if ((inx >= info->s->base.keys) || !(info->s->keyinfo[inx].flag & HA_FULLTEXT)) + { + printf("Key %d in table %s is not a FULLTEXT key\n", inx, info->filename); + goto err; + } + + if (query) + { + FT_DOCLIST *result; + int i; + + ft_init_stopwords(ft_precompiled_stopwords); + + result=ft_init_search(info,inx,query,strlen(query),1); + if(!result) + goto err; + + if (verbose) + printf("%d rows matched\n",result->ndocs); + + for(i=0 ; i<result->ndocs ; i++) + printf("%9qx %20.7f\n",result->doc[i].dpos,result->doc[i].weight); + + ft_close_search(result); + } + else + { + info->lastpos= HA_OFFSET_ERROR; + info->update|= HA_STATE_PREV_FOUND; + + while (!(error=mi_rnext(info,NULL,inx))) + { + keylen=*(info->lastkey); + +#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT +#ifdef EVAL_RUN + mi_float4get(weight,info->lastkey+keylen+2); +#else /* EVAL_RUN */ + mi_float4get(weight,info->lastkey+keylen+1); +#endif /* EVAL_RUN */ +#else +#error +#endif + +#ifdef EVAL_RUN + cnt=*(byte *)(info->lastkey+keylen); +#endif /* EVAL_RUN */ + + snprintf(buf,MAX,"%.*s",(int) keylen,info->lastkey+1); + casedn_str(buf); + total++; + + if (count || stats) + { + doc_cnt++; +#ifdef EVAL_RUN + sum +=cnt; + sum2+=cnt*cnt; + suml+=cnt*log(cnt); +#endif /* EVAL_RUN */ + if (strcmp(buf, buf2)) + { + if (*buf2) + { + uniq++; + avg_gws+=gws=GWS_IN_USE; + if (count) + printf("%9u %20.7f %s\n",doc_cnt,gws,buf2); + if (maxlen<keylen) + { + maxlen=keylen; + strcpy(buf_maxlen, buf2); + } + if (max_doc_cnt < doc_cnt) + { + max_doc_cnt=doc_cnt; + strcpy(buf_min_gws, buf2); + min_gws=gws; + } + } + strcpy(buf2, buf); +#ifdef EVAL_RUN + sum=sum2=suml= +#endif /* EVAL_RUN */ + doc_cnt=0; + } + } + if (dump) + printf("%9qx %20.7f %s\n",info->lastpos,weight,buf); + + if(verbose && (total%HOW_OFTEN_TO_WRITE)==0) + printf("%10ld\r",total); + } + + if (stats) + printf("Total rows: %qu\nTotal words: %lu\n" + "Unique words: %lu\nLongest word: %lu chars (%s)\n" + "Average global weight: %f\n" + "Most common word: %lu times, weight: %f (%s)\n", + (ulonglong)info->state->records, total, uniq, maxlen, buf_maxlen, + avg_gws/uniq, max_doc_cnt, min_gws, buf_min_gws); + } + +err: + if (error && error != HA_ERR_END_OF_FILE) + printf("got error %d\n",my_errno); + if (info) + mi_close(info); + return 0; +} + +const char *options="dscve:h"; + +static void get_options(int argc, char *argv[]) +{ + int c; + + while ((c=getopt(argc,argv,options)) != -1) + { + switch(c) { + case 'd': dump=1; complain(count || query); break; + case 's': stats=1; complain(query!=0); break; + case 'v': verbose=1; break; + case 'c': count=1; complain(dump || query); break; + case 'e': query=my_strdup(optarg,MYF(MY_FAE)); complain(dump || count || stats); break; + case '?': + case 'h': + default: + usage(argv); + } + } + return; +} /* get options */ + +static void usage(char *argv[]) +{ + printf("Use: %s [-%s] <table_name> <key_no>\n", *argv, options); + exit(1); +} + +static void complain(int val) /* Kinda assert :-) */ +{ + if (val) + { + printf("You cannot use these options together!\n"); + exit(1); + } +} + diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c new file mode 100644 index 00000000000..350a60708f6 --- /dev/null +++ b/myisam/ft_nlq_search.c @@ -0,0 +1,192 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* Written by Sergei A. Golubchik, who has a shared copyright to this code */ + +#include "ftdefs.h" + +/* search with natural language queries */ + +typedef struct st_all_in_one { + MI_INFO *info; + uint keynr; + uchar *keybuff; + MI_KEYDEF *keyinfo; + my_off_t key_root; + TREE dtree; +} ALL_IN_ONE; + +typedef struct st_ft_superdoc { + FT_DOC doc; + FT_WORD *word_ptr; + double tmp_weight; +} FT_SUPERDOC; + +static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)), + FT_SUPERDOC *p1, FT_SUPERDOC *p2) +{ + if (p1->doc.dpos < p2->doc.dpos) + return -1; + if (p1->doc.dpos == p2->doc.dpos) + return 0; + return 1; +} + +static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) +{ + uint keylen, r, doc_cnt; +#ifdef EVAL_RUN + uint cnt; + double sum, sum2, suml; +#endif /* EVAL_RUN */ + FT_SUPERDOC sdoc, *sptr; + TREE_ELEMENT *selem; +#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT + float tmp_weight; +#else +#error +#endif + + word->weight=LWS_FOR_QUERY; + + keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0); +#ifdef EVAL_RUN + keylen-=1+HA_FT_WLEN; +#else /* EVAL_RUN */ + keylen-=HA_FT_WLEN; +#endif /* EVAL_RUN */ + +#ifdef EVAL_RUN + sum=sum2=suml= +#endif /* EVAL_RUN */ + doc_cnt=0; + + r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, + SEARCH_FIND | SEARCH_PREFIX, aio->key_root); + + while(!r) + { + if (_mi_compare_text(default_charset_info, + aio->info->lastkey,keylen, + aio->keybuff,keylen,0)) break; + +#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT +#ifdef EVAL_RUN + mi_float4get(tmp_weight,aio->info->lastkey+keylen+1); +#else /* EVAL_RUN */ + mi_float4get(tmp_weight,aio->info->lastkey+keylen); +#endif /* EVAL_RUN */ +#else +#error +#endif + if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */ + +#ifdef EVAL_RUN + cnt=*(byte *)(aio->info->lastkey+keylen); +#endif /* EVAL_RUN */ + + sdoc.doc.dpos=aio->info->lastpos; + + /* saving document matched into dtree */ + if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1; + + sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem); + + if(selem->count==1) /* document's first match */ + sptr->doc.weight=0; + else + sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight; + + sptr->word_ptr=word; + sptr->tmp_weight=tmp_weight; + + doc_cnt++; +#ifdef EVAL_RUN + sum +=cnt; + sum2+=cnt*cnt; + suml+=cnt*log(cnt); +#endif /* EVAL_RUN */ + + if (_mi_test_if_changed(aio->info) == 0) + r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey, + aio->info->lastkey_length, SEARCH_BIGGER, + aio->key_root); + else + r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey, + aio->info->lastkey_length, SEARCH_BIGGER, + aio->key_root); + } + if(doc_cnt) { + word->weight*=GWS_IN_USE; + if(word->weight < 0) word->weight=0; + } + + return 0; +} + +static int walk_and_copy(FT_SUPERDOC *from, + uint32 count __attribute__((unused)), FT_DOC **to) +{ + from->doc.weight+=from->tmp_weight*from->word_ptr->weight; + (*to)->dpos=from->doc.dpos; + (*to)->weight=from->doc.weight; + (*to)++; + return 0; +} + +FT_DOCLIST *ft_nlq_search(MI_INFO *info, uint keynr, byte *query, + uint query_len) +{ + TREE *wtree, allocated_wtree; + ALL_IN_ONE aio; + FT_DOC *dptr; + FT_DOCLIST *dlist=NULL; + + aio.info=info; + aio.keynr=keynr; + aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length; + aio.keyinfo=aio.info->s->keyinfo+keynr; + aio.key_root=aio.info->s->state.key_root[keynr]; + + bzero(&allocated_wtree,sizeof(allocated_wtree)); + + init_tree(&aio.dtree,0,0,sizeof(FT_SUPERDOC),(qsort_cmp2)&FT_SUPERDOC_cmp,0, + NULL, NULL); + + if(!(wtree=ft_parse(&allocated_wtree,query,query_len))) + return NULL; + + if(tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio, + left_root_right)) + goto err; + + dlist=(FT_DOCLIST *)my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)*(aio.dtree.elements_in_tree-1),MYF(0)); + if(!dlist) + goto err; + + dlist->ndocs=aio.dtree.elements_in_tree; + dlist->curdoc=-1; + dlist->info=aio.info; + dptr=dlist->doc; + + tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, left_root_right); + +err: + delete_tree(wtree); + delete_tree(&aio.dtree); + return dlist; +} + diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 7ea2e240c36..73d9eccfd16 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -38,7 +38,8 @@ typedef struct st_ft_docstat { byte *keybuf; } FT_DOCSTAT; -static int FT_WORD_cmp(FT_WORD *w1, FT_WORD *w2) +static int FT_WORD_cmp(void* cmp_arg __attribute__((unused)), + FT_WORD *w1, FT_WORD *w2) { return _mi_compare_text(default_charset_info, (uchar*) w1->pos,w1->len, @@ -83,13 +84,12 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree) tree_walk(wtree,(tree_walk_action)&walk_and_copy,&docstat,left_root_right); } delete_tree(wtree); - my_free((char*) wtree,MYF(0)); if (!wlist) return NULL; docstat.list->pos=NULL; - for(p=wlist;p->pos;p++) + for (p=wlist;p->pos;p++) { p->weight=PRENORM_IN_USE; #ifdef EVAL_RUN @@ -104,7 +104,7 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree) #endif #endif /* EVAL_RUN */ - for(p=wlist;p->pos;p++) + for (p=wlist;p->pos;p++) { p->weight/=NORM_IN_USE; } @@ -112,40 +112,132 @@ FT_WORD * ft_linearize(MI_INFO *info, uint keynr, byte *keybuf, TREE *wtree) return wlist; } +#define true_word_char(X) (isalnum(X) || (X)=='_') #ifdef HYPHEN_IS_DELIM -#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'') +#define misc_word_char(X) ((X)=='\'') #else -#define word_char(X) (isalnum(X) || (X)=='_' || (X)=='\'' || (X)=='-') +#define misc_word_char(X) ((X)=='\'' || (X)=='-') #endif +#define word_char(X) (true_word_char(X) || misc_word_char(X)) -/* this is rather dumb first version of the parser */ -TREE * ft_parse(TREE *wtree, byte *doc, int doclen) +byte ft_get_word(byte **start, byte *end, FT_WORD *word, FTB_PARAM *param) { - byte *end=doc+doclen; - FT_WORD w; + byte *doc=*start; + int mwc; + + param->yesno=param->plusminus=param->pmsign=0; - if (!wtree) + while (doc<end) { - if (!(wtree=(TREE *)my_malloc(sizeof(TREE),MYF(0)))) return NULL; - init_tree(wtree,0,sizeof(FT_WORD),(qsort_cmp)&FT_WORD_cmp,0,NULL); + for (;doc<end;doc++) + { + if (true_word_char(*doc)) break; + if (*doc == FTB_LBR || *doc == FTB_RBR) + { + param->prev=' '; + *start=doc+1; + return *doc; + } + if (param->prev == ' ') + { + switch (*doc) { + case FTB_YES: param->yesno=+1; continue; + case FTB_NO: param->yesno=-1; continue; + case FTB_INC: param->plusminus++; continue; + case FTB_DEC: param->plusminus--; continue; + case FTB_NEG: param->pmsign=!param->pmsign; continue; + default: break; + } + } + param->prev=*doc; + param->yesno=param->plusminus=param->pmsign=0; + } + + mwc=0; + for (word->pos=doc; doc<end; doc++) + if (true_word_char(*doc)) + mwc=0; + else if (!misc_word_char(*doc) || mwc++) + break; + + param->prev='A'; // be sure *prev is true_word_char + word->len= (uint)(doc-word->pos) - mwc; + if ((param->trunc=(doc<end && *doc == FTB_TRUNC))) + doc++; + + if (word->len >= ft_min_word_len && word->len < ft_max_word_len && + !is_stopword(word->pos, word->len)) + { + *start=doc; + return 1; + } } + return 0; +} + +byte ft_simple_get_word(byte **start, byte *end, FT_WORD *word) +{ + byte *doc=*start; + int mwc; - w.weight=0; while (doc<end) { for (;doc<end;doc++) - if (word_char(*doc)) break; - for (w.pos=doc; doc<end; doc++) - if (!word_char(*doc)) break; - if ((w.len= (uint) (doc-w.pos)) < MIN_WORD_LEN) continue; - if (w.len >= HA_FT_MAXLEN) continue; - if (is_stopword(w.pos, w.len)) continue; - if (!tree_insert(wtree, &w, 0)) { - delete_tree(wtree); - my_free((char*) wtree,MYF(0)); - return NULL; + if (true_word_char(*doc)) break; + } + + mwc=0; + for(word->pos=doc; doc<end; doc++) + if (true_word_char(*doc)) + mwc=0; + else if (!misc_word_char(*doc) || mwc++) + break; + + word->len= (uint)(doc-word->pos) - mwc; + + if (word->len >= ft_min_word_len && word->len < ft_max_word_len && + !is_stopword(word->pos, word->len)) + { + *start=doc; + return 1; } } + return 0; +} + +int is_boolean(byte *q, uint len) +{ + if (!len) return 0; + if (*q == FTB_YES || *q == FTB_NO) return 1; + + for (++q; --len; ++q) + { + if ((*q == FTB_YES || *q == FTB_NO) && q[-1] == ' ' && true_word_char(q[1])) + return 1; + } + return 0; +} + +TREE * ft_parse(TREE *wtree, byte *doc, int doclen) +{ + byte *end=doc+doclen; + FT_WORD w; + + if (!is_tree_inited(wtree)) + { + init_tree(wtree,0,0,sizeof(FT_WORD),(qsort_cmp2)&FT_WORD_cmp,0,NULL, NULL); + } + + while (ft_simple_get_word(&doc,end,&w)) + { + if (!tree_insert(wtree, &w, 0)) + goto err; + } return wtree; + +err: + delete_tree(wtree); + return NULL; } + diff --git a/myisam/ft_search.c b/myisam/ft_search.c index 4ca1551e809..711c03722a5 100644 --- a/myisam/ft_search.c +++ b/myisam/ft_search.c @@ -18,146 +18,17 @@ #include "ftdefs.h" -/* queries isam and returns list of documents matched */ - -typedef struct st_all_in_one { - MI_INFO *info; - uint keynr; - uchar *keybuff; - MI_KEYDEF *keyinfo; - my_off_t key_root; - TREE dtree; -} ALL_IN_ONE; - -typedef struct st_ft_superdoc { - FT_DOC doc; - FT_WORD *word_ptr; - double tmp_weight; -} FT_SUPERDOC; - -static int FT_SUPERDOC_cmp(FT_SUPERDOC *p1, FT_SUPERDOC *p2) -{ - if (p1->doc.dpos < p2->doc.dpos) - return -1; - if (p1->doc.dpos == p2->doc.dpos) - return 0; - return 1; -} - -static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) -{ - uint keylen, r, doc_cnt; -#ifdef EVAL_RUN - uint cnt; - double sum, sum2, suml; -#endif /* EVAL_RUN */ - FT_SUPERDOC sdoc, *sptr; - TREE_ELEMENT *selem; -#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT - float tmp_weight; -#else -#error -#endif - - word->weight=LWS_FOR_QUERY; - - keylen=_ft_make_key(aio->info,aio->keynr,(char*) aio->keybuff,word,0); -#ifdef EVAL_RUN - keylen-=1+HA_FT_WLEN; -#else /* EVAL_RUN */ - keylen-=HA_FT_WLEN; -#endif /* EVAL_RUN */ - -#ifdef EVAL_RUN - sum=sum2=suml= -#endif /* EVAL_RUN */ - doc_cnt=0; - - r=_mi_search(aio->info, aio->keyinfo, aio->keybuff, keylen, - SEARCH_FIND | SEARCH_PREFIX, aio->key_root); - - while(!r) - { - if (_mi_compare_text(default_charset_info, - aio->info->lastkey,keylen, - aio->keybuff,keylen,0)) break; - -#if HA_FT_WTYPE == HA_KEYTYPE_FLOAT -#ifdef EVAL_RUN - mi_float4get(tmp_weight,aio->info->lastkey+keylen+1); -#else /* EVAL_RUN */ - mi_float4get(tmp_weight,aio->info->lastkey+keylen); -#endif /* EVAL_RUN */ -#else -#error -#endif - if(tmp_weight==0) return doc_cnt; /* stopword, doc_cnt should be 0 */ - -#ifdef EVAL_RUN - cnt=*(byte *)(aio->info->lastkey+keylen); -#endif /* EVAL_RUN */ - - sdoc.doc.dpos=aio->info->lastpos; - - /* saving document matched into dtree */ - if(!(selem=tree_insert(&aio->dtree, &sdoc, 0))) return 1; - - sptr=(FT_SUPERDOC *)ELEMENT_KEY((&aio->dtree), selem); - - if(selem->count==1) /* document's first match */ - sptr->doc.weight=0; - else - sptr->doc.weight+=sptr->tmp_weight*sptr->word_ptr->weight; - - sptr->word_ptr=word; - sptr->tmp_weight=tmp_weight; - - doc_cnt++; -#ifdef EVAL_RUN - sum +=cnt; - sum2+=cnt*cnt; - suml+=cnt*log(cnt); -#endif /* EVAL_RUN */ - - if (_mi_test_if_changed(aio->info) == 0) - r=_mi_search_next(aio->info, aio->keyinfo, aio->info->lastkey, - aio->info->lastkey_length, SEARCH_BIGGER, - aio->key_root); - else - r=_mi_search(aio->info, aio->keyinfo, aio->info->lastkey, - aio->info->lastkey_length, SEARCH_BIGGER, - aio->key_root); - } - if(doc_cnt) { - word->weight*=GWS_IN_USE; - if(word->weight < 0) word->weight=0; - } - - return 0; -} - -static int walk_and_copy(FT_SUPERDOC *from, - uint32 count __attribute__((unused)), FT_DOC **to) -{ - from->doc.weight+=from->tmp_weight*from->word_ptr->weight; - (*to)->dpos=from->doc.dpos; - (*to)->weight=from->doc.weight; - (*to)++; - return 0; -} +/* queries myisam and returns list of documents matched */ static int FT_DOC_cmp(FT_DOC *a, FT_DOC *b) { return sgn(b->weight - a->weight); } -FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key, - uint key_len, my_bool presort) +FT_DOCLIST *ft_init_search(void *info, uint keynr, byte *query, + uint query_len, my_bool presort) { - TREE *wtree; - ALL_IN_ONE aio; FT_DOCLIST *dlist; - FT_DOC *dptr; my_off_t saved_lastpos=((MI_INFO *)info)->lastpos; /* black magic ON */ @@ -167,44 +38,16 @@ FT_DOCLIST * ft_init_search(void *info, uint keynr, byte *key, return NULL; /* black magic OFF */ - dlist=NULL; - aio.info=(MI_INFO *)info; - aio.keynr=keynr; - aio.keybuff=aio.info->lastkey+aio.info->s->base.max_key_length; - aio.keyinfo=aio.info->s->keyinfo+keynr; - aio.key_root=aio.info->s->state.key_root[keynr]; - - if (!(wtree=ft_parse(NULL,key,key_len))) return NULL; - - init_tree(&aio.dtree,0,sizeof(FT_SUPERDOC),(qsort_cmp)&FT_SUPERDOC_cmp,0, - NULL); - - if (tree_walk(wtree, (tree_walk_action)&walk_and_match, &aio, - left_root_right)) - goto err; - - dlist=(FT_DOCLIST *) my_malloc(sizeof(FT_DOCLIST)+sizeof(FT_DOC)* - (aio.dtree.elements_in_tree-1),MYF(0)); - if (!dlist) - goto err; - - dlist->ndocs=aio.dtree.elements_in_tree; - dlist->curdoc=-1; - dlist->info=aio.info; - dptr=dlist->doc; - - tree_walk(&aio.dtree, (tree_walk_action)&walk_and_copy, &dptr, - left_root_right); + if (is_boolean(query, query_len)) + dlist=ft_boolean_search(info,keynr,query,query_len); + else + dlist=ft_nlq_search(info,keynr,query,query_len); - if (presort) + if(dlist && presort) { qsort(dlist->doc, dlist->ndocs, sizeof(FT_DOC), (qsort_cmp)&FT_DOC_cmp); } -err: - delete_tree(&aio.dtree); - delete_tree(wtree); - my_free((char*) wtree,MYF(0)); ((MI_INFO *)info)->lastpos=saved_lastpos; return dlist; } diff --git a/myisam/ft_static.c b/myisam/ft_static.c index 00d9d4ed19a..09afadec23f 100644 --- a/myisam/ft_static.c +++ b/myisam/ft_static.c @@ -18,6 +18,10 @@ #include "ftdefs.h" +uint ft_min_word_len=4; +uint ft_max_word_len=HA_FT_MAXLEN; +uint ft_max_word_len_for_sort=20; + const MI_KEYSEG ft_keysegs[FT_SEGS]={ { HA_KEYTYPE_VARTEXT, /* type */ diff --git a/myisam/ft_stopwords.c b/myisam/ft_stopwords.c index d796b87ed71..8565a153b81 100644 --- a/myisam/ft_stopwords.c +++ b/myisam/ft_stopwords.c @@ -25,7 +25,8 @@ typedef struct st_ft_stopwords { static TREE *stopwords3=NULL; -static int FT_STOPWORD_cmp(FT_STOPWORD *w1, FT_STOPWORD *w2) +static int FT_STOPWORD_cmp(void* cmp_arg __attribute__((unused)), + FT_STOPWORD *w1, FT_STOPWORD *w2) { return _mi_compare_text(default_charset_info, (uchar *)w1->pos,w1->len, @@ -40,15 +41,15 @@ int ft_init_stopwords(const char **sws) if(!stopwords3) { if(!(stopwords3=(TREE *)my_malloc(sizeof(TREE),MYF(0)))) return -1; - init_tree(stopwords3,0,sizeof(FT_STOPWORD),(qsort_cmp)&FT_STOPWORD_cmp,0, - NULL); + init_tree(stopwords3,0,0,sizeof(FT_STOPWORD),(qsort_cmp2)&FT_STOPWORD_cmp,0, + NULL, NULL); } if(!sws) return 0; for(;*sws;sws++) { - if( (sw.len= (uint) strlen(sw.pos=*sws)) < MIN_WORD_LEN) continue; + if( (sw.len= (uint) strlen(sw.pos=*sws)) < ft_min_word_len) continue; if(!tree_insert(stopwords3, &sw, 0)) { delete_tree(stopwords3); /* purecov: inspected */ diff --git a/myisam/ft_update.c b/myisam/ft_update.c index 753c4dc4029..61c6313ec67 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -29,14 +29,16 @@ /* parses a document i.e. calls _mi_ft_parse for every keyseg */ -static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf, +FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf, const byte *record) { - TREE *parsed=NULL; + TREE *parsed, ptree; MI_KEYSEG *keyseg; byte *pos; uint i; + bzero(parsed=&ptree, sizeof(ptree)); + keyseg=info->s->keyinfo[keynr].seg; for (i=info->s->keyinfo[keynr].keysegs-FT_SEGS ; i-- ; ) { @@ -64,7 +66,7 @@ static FT_WORD * _mi_ft_parserecord(MI_INFO *info, uint keynr, byte *keybuf, return NULL; } /* Handle the case where all columns are NULL */ - if (!parsed && !(parsed=ft_parse(0, (byte*) "", 0))) + if (!is_tree_inited(parsed) && !(parsed=ft_parse(parsed, (byte*) "", 0))) return NULL; return ft_linearize(info, keynr, keybuf, parsed); } @@ -155,6 +157,69 @@ int _mi_ft_cmp(MI_INFO *info, uint keynr, const byte *rec1, const byte *rec2) return GEE_THEY_ARE_ABSOLUTELY_IDENTICAL; } +/* update a document entry */ +int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf, + const byte *oldrec, const byte *newrec, my_off_t pos) +{ + int error= -1; + FT_WORD *oldlist,*newlist, *old_word, *new_word; + uint key_length; + int cmp; + + if (!(old_word=oldlist=_mi_ft_parserecord(info, keynr, keybuf, oldrec))) + goto err0; + if (!(new_word=newlist=_mi_ft_parserecord(info, keynr, keybuf, newrec))) + goto err1; + + while(old_word->pos && new_word->pos) + { + cmp=_mi_compare_text(default_charset_info, + (uchar*) old_word->pos,old_word->len, + (uchar*) new_word->pos,new_word->len,0); + if (cmp==0) + { + double p=(old_word->weight-new_word->weight)/ + (old_word->weight+new_word->weight); + if (p<1e-5) + cmp=0; + else + cmp=sgn(p); + } + else + cmp=sgn(cmp); + + switch (cmp) { + case -1: + key_length=_ft_make_key(info,keynr,keybuf,old_word,pos); + if ((error=_mi_ck_delete(info,keynr,(uchar*) keybuf,key_length))) + goto err2; + old_word++; + break; + case 0: + old_word++; + new_word++; + break; + case 1: + key_length=_ft_make_key(info,keynr,keybuf,new_word,pos); + if ((error=_mi_ck_write(info,keynr,(uchar*) keybuf,key_length))) + goto err2; + new_word++; + break; + } + } + if (old_word->pos) + error=_mi_ft_erase(info,keynr,keybuf,old_word,pos); + else if (new_word->pos) + error=_mi_ft_store(info,keynr,keybuf,new_word,pos); + +err2: + my_free((char*) newlist,MYF(0)); +err1: + my_free((char*) oldlist,MYF(0)); +err0: + return error; +} + /* adds a document to the collection */ int _mi_ft_add(MI_INFO *info, uint keynr, byte *keybuf, const byte *record, my_off_t pos) diff --git a/myisam/ftdefs.h b/myisam/ftdefs.h index ebf99e84d5a..6721d136678 100644 --- a/myisam/ftdefs.h +++ b/myisam/ftdefs.h @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -22,15 +22,18 @@ #include <m_ctype.h> #include <my_tree.h> -#define MIN_WORD_LEN 4 - #define HYPHEN_IS_DELIM #define HYPHEN_IS_CONCAT /* not used for now */ #define COMPILE_STOPWORDS_IN -/* Most of the formulae were shamelessly stolen from SMART distribution - ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z +/* Interested readers may consult SMART + (ftp://ftp.cs.cornell.edu/pub/smart/smart.11.0.tar.Z) + for an excellent implementation of vector space model we use. + It also demonstrate the usage of different weghting techniques. + This code, though, is completely original and is not based on the + SMART code but was in some cases inspired by it. + NORM_PIVOT was taken from the article A.Singhal, C.Buckley, M.Mitra, "Pivoted Document Length Normalization", ACM SIGIR'96, 21-29, 1996 @@ -82,6 +85,19 @@ extern ulong collstat; #define GWS_ENTROPY (1-(suml/sum-log(sum))/log(aio->info->state->records)) /*=================================================================*/ +/* Boolean search operators */ +#define FTB_YES '+' +#define FTB_NO '-' +#define FTB_INC '>' +#define FTB_DEC '<' +#define FTB_LBR '(' +#define FTB_RBR ')' +#define FTB_NEG '~' +#define FTB_TRUNC '*' + +// #define FTB_MAX_SUBEXPR 255 +// #define FTB_MAX_DEPTH 16 + typedef struct st_ft_word { byte * pos; uint len; @@ -91,9 +107,26 @@ typedef struct st_ft_word { #endif /* EVAL_RUN */ } FT_WORD; +typedef struct st_ftb_param { + byte prev; + int yesno; + int plusminus; + bool pmsign; + bool trunc; +} FTB_PARAM; + int is_stopword(char *word, uint len); +int is_boolean(byte *q, uint len); uint _ft_make_key(MI_INFO *, uint , byte *, FT_WORD *, my_off_t); +byte ft_get_word(byte **, byte *, FT_WORD *, FTB_PARAM *); +byte ft_simple_get_word(byte **, byte *, FT_WORD *); + TREE * ft_parse(TREE *, byte *, int); FT_WORD * ft_linearize(MI_INFO *, uint, byte *, TREE *); +FT_WORD * _mi_ft_parserecord(MI_INFO *, uint , byte *, const byte *); + +FT_DOCLIST * ft_nlq_search(MI_INFO *, uint, byte *, uint); +FT_DOCLIST * ft_boolean_search(MI_INFO *, uint, byte *, uint); + diff --git a/myisam/fulltext.h b/myisam/fulltext.h index 8fcac8172b1..f787c9bcfe8 100644 --- a/myisam/fulltext.h +++ b/myisam/fulltext.h @@ -24,7 +24,6 @@ /* shoudn't be def'ed when linking with mysql */ #undef EVAL_RUN -#define HA_FT_MAXLEN 254 #define HA_FT_WTYPE HA_KEYTYPE_FLOAT #define HA_FT_WLEN 4 #ifdef EVAL_RUN diff --git a/myisam/mi_check.c b/myisam/mi_check.c index c6e07445bcf..deb3f2071b3 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -16,7 +16,7 @@ /* Descript, check and repair of ISAM tables */ -#include "fulltext.h" +#include "ftdefs.h" #include <m_ctype.h> #include <stdarg.h> #include <getopt.h> @@ -45,6 +45,7 @@ static int writekeys(MI_INFO *info,byte *buff,my_off_t filepos); static int sort_one_index(MI_CHECK *param, MI_INFO *info,MI_KEYDEF *keyinfo, my_off_t pagepos, File new_file); static int sort_key_read(SORT_INFO *sort_info,void *key); +static int sort_ft_key_read(SORT_INFO *sort_info,void *key); static int sort_get_next_record(SORT_INFO *sort_info); static int sort_key_cmp(SORT_INFO *sort_info, const void *a,const void *b); static int sort_key_write(SORT_INFO *sort_info, const void *a); @@ -53,7 +54,7 @@ static my_off_t get_record_for_key(MI_INFO *info,MI_KEYDEF *keyinfo, static int sort_insert_key(MI_CHECK *param, reg1 SORT_KEY_BLOCKS *key_block, uchar *key, my_off_t prev_block); static int sort_delete_record(MI_CHECK *param); -static int flush_pending_blocks(MI_CHECK *param); +/*static int flush_pending_blocks(MI_CHECK *param);*/ static SORT_KEY_BLOCKS *alloc_key_blocks(MI_CHECK *param, uint blocks, uint buffer_length); static void update_key_parts(MI_KEYDEF *keyinfo, @@ -102,6 +103,7 @@ void myisamchk_init(MI_CHECK *param) int chk_status(MI_CHECK *param, register MI_INFO *info) { MYISAM_SHARE *share=info->s; + if (mi_is_crashed_on_repair(info)) mi_check_print_warning(param, "Table is marked as crashed and last repair failed"); @@ -1100,6 +1102,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, share->pack.header_length; got_error=1; new_file= -1; + sort_info->buff=0; + sort_info->buff_length=0; + sort_info->record=0; + if (!(param->testflag & T_SILENT)) { printf("- recovering (with keycache) MyISAM-table '%s'\n",name); @@ -1112,7 +1118,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, if (init_io_cache(¶m->read_cache,info->dfile, (uint) param->read_buffer_length, READ_CACHE,share->pack.header_length,1,MYF(MY_WME))) + { + bzero(&info->rec_cache,sizeof(info->rec_cache)); goto err; + } if (!rep_quick) if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length, WRITE_CACHE, new_header_length, 1, @@ -1120,7 +1129,6 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, goto err; info->opt_flag|=WRITE_CACHE_USED; sort_info->start_recpos=0; - sort_info->buff=0; sort_info->buff_length=0; if (!(sort_info->record=(byte*) my_malloc((uint) share->base.pack_reclength, MYF(0)))) { @@ -1130,7 +1138,10 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, if (!rep_quick) { - if ((new_file=my_raid_create(fn_format(param->temp_filename,name,"", + /* Get real path for data file */ + fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32); + if ((new_file=my_raid_create(fn_format(param->temp_filename, + param->temp_filename,"", DATA_TMP_EXT, 2+4), 0,param->tmpfile_createflag, @@ -1292,7 +1303,7 @@ err: { my_close(new_file,MYF(0)); info->dfile=new_file= -1; - if (change_to_newfile(share->filename,MI_NAME_DEXT, + if (change_to_newfile(share->data_file_name,MI_NAME_DEXT, DATA_TMP_EXT, share->base.raid_chunks, (param->testflag & T_BACKUP_DATA ? MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || @@ -1476,8 +1487,10 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) if (!(param->testflag & T_SILENT)) printf("- Sorting index for MyISAM-table '%s'\n",name); - if ((new_file=my_create(fn_format(param->temp_filename,name,"", - INDEX_TMP_EXT,2+4), + /* Get real path for index file */ + fn_format(param->temp_filename,name,"", MI_NAME_IEXT,2+4+32); + if ((new_file=my_create(fn_format(param->temp_filename,param->temp_filename, + "", INDEX_TMP_EXT,2+4), 0,param->tmpfile_createflag,MYF(0))) <= 0) { mi_check_print_error(param,"Can't create new tempfile: '%s'", @@ -1497,7 +1510,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) if (share->state.key_root[key] != HA_OFFSET_ERROR) { - index_pos[key]=param->new_file_pos; /* Write first block here */ + index_pos[key]=param->new_file_pos; /* Write first block here */ if (sort_one_index(param,info,keyinfo,share->state.key_root[key], new_file)) goto err; @@ -1518,7 +1531,7 @@ int mi_sort_index(MI_CHECK *param, register MI_INFO *info, my_string name) VOID(my_close(share->kfile,MYF(MY_WME))); share->kfile = -1; VOID(my_close(new_file,MYF(MY_WME))); - if (change_to_newfile(share->filename,MI_NAME_IEXT,INDEX_TMP_EXT,0, + if (change_to_newfile(share->index_file_name,MI_NAME_IEXT,INDEX_TMP_EXT,0, MYF(0)) || mi_open_keyfile(share)) goto err2; @@ -1618,9 +1631,14 @@ err: } /* sort_one_index */ - /* Change to use new file */ - /* Copy stats from old file to new file, deletes orginal and */ - /* changes new file name to old file name */ + /* + Let temporary file replace old file. + This assumes that the new file was created in the same + directory as given by realpath(filename). + This will ensure that any symlinks that are used will still work. + Copy stats from old file to new file, deletes orignal and + changes new file name to old file name + */ int change_to_newfile(const char * filename, const char * old_ext, const char * new_ext, @@ -1635,8 +1653,10 @@ int change_to_newfile(const char * filename, const char * old_ext, raid_chunks, MYF(MY_WME | MY_LINK_WARNING | MyFlags)); #endif - return my_redel(fn_format(old_filename,filename,"",old_ext,2+4), - fn_format(new_filename,filename,"",new_ext,2+4), + /* Get real path to filename */ + (void) fn_format(old_filename,filename,"",old_ext,2+4+32); + return my_redel(old_filename, + fn_format(new_filename,old_filename,"",new_ext,2+4), MYF(MY_WME | MY_LINK_WARNING | MyFlags)); } /* change_to_newfile */ @@ -1727,22 +1747,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, printf("Data records: %s\n", llstr(start_records,llbuff)); } - /* Hmm, repair_by_sort uses find_all_keys, and find_all_keys strictly - implies "one row - one key per keynr", while for ft_key one row/keynr - can produce as many keys as the number of unique words in the text - that's why I disabled repair_by_sort for ft-keys. (serg) - */ - for (i=0 ; i < share->base.keys ; i++) - { - if ((((ulonglong) 1 << i) & key_map) && - (share->keyinfo[i].flag & HA_FULLTEXT)) - { - mi_check_print_error(param, - "Can`t use repair_by_sort with FULLTEXT key"); - DBUG_RETURN(1); - } - } - bzero((char*) sort_info,sizeof(*sort_info)); if (!(sort_info->key_block= alloc_key_blocks(param, @@ -1769,7 +1773,10 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, } if (!rep_quick) { - if ((new_file=my_raid_create(fn_format(param->temp_filename,name,"", + /* Get real path for data file */ + fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32); + if ((new_file=my_raid_create(fn_format(param->temp_filename, + param->temp_filename, "", DATA_TMP_EXT, 2+4), 0,param->tmpfile_createflag, @@ -1834,6 +1841,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, param->read_cache.end_of_file=sort_info->filelength= my_seek(param->read_cache.file,0L,MY_SEEK_END,MYF(0)); + sort_info->wordlist=NULL; + if (share->data_file_type == DYNAMIC_RECORD) length=max(share->base.min_pack_length+1,share->base.min_block_length); else if (share->data_file_type == COMPRESSED_RECORD) @@ -1845,7 +1854,6 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, (ha_rows) (sort_info->filelength/length+1)); sort_param.key_cmp=sort_key_cmp; sort_param.key_write=sort_key_write; - sort_param.key_read=sort_key_read; sort_param.lock_in_memory=lock_memory; sort_param.tmpdir=param->tmpdir; sort_param.myf_rw=param->myf_rw; @@ -1891,6 +1899,17 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, info->state->records=info->state->del=share->state.split=0; info->state->empty=0; + if (sort_info->keyinfo->flag & HA_FULLTEXT) + { + sort_param.max_records=sort_info->max_records= + (ha_rows) (sort_info->filelength/ft_max_word_len_for_sort+1); + + sort_param.key_read=sort_ft_key_read; + sort_param.key_length+=ft_max_word_len_for_sort-ft_max_word_len; + } + else + sort_param.key_read=sort_key_read; + if (_create_index_by_sort(&sort_param, (my_bool) (!(param->testflag & T_VERBOSE)), (uint) param->sort_buffer_length)) @@ -1935,8 +1954,8 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, else info->state->data_file_length=sort_info->max_pos; - if (flush_pending_blocks(param)) - goto err; + /*if (flush_pending_blocks(param)) + goto err;*/ param->read_cache.file=info->dfile; /* re-init read cache */ reinit_io_cache(¶m->read_cache,READ_CACHE,share->pack.header_length,1, @@ -2002,7 +2021,7 @@ err: { my_close(new_file,MYF(0)); info->dfile=new_file= -1; - if (change_to_newfile(share->filename,MI_NAME_DEXT, + if (change_to_newfile(share->data_file_name,MI_NAME_DEXT, DATA_TMP_EXT, share->base.raid_chunks, (param->testflag & T_BACKUP_DATA ? MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || @@ -2060,11 +2079,52 @@ static int sort_key_read(SORT_INFO *sort_info, void *key) "Found too many records; Can`t continue"); DBUG_RETURN(1); } - (void) _mi_make_key(info,sort_info->key,key,sort_info->record, - sort_info->filepos); + sort_info->real_key_length=info->s->rec_reflength+_mi_make_key(info, + sort_info->key,key,sort_info->record,sort_info->filepos); DBUG_RETURN(sort_write_record(sort_info)); } /* sort_key_read */ +static int sort_ft_key_read(SORT_INFO *sort_info, void *key) +{ + int error; + MI_INFO *info; + FT_WORD *wptr; + DBUG_ENTER("sort_ft_key_read"); + + info=sort_info->info; + + if (!sort_info->wordlist) + { + do + { + if ((error=sort_get_next_record(sort_info))) + DBUG_RETURN(error); + if (!(wptr=_mi_ft_parserecord(info,sort_info->key,key,sort_info->record))) + DBUG_RETURN(1); + error=sort_write_record(sort_info); + } + while (!wptr->pos); + sort_info->wordptr=sort_info->wordlist=wptr; + } + else + { + error=0; + wptr=(FT_WORD*)(sort_info->wordptr); + } + + sort_info->real_key_length=info->s->rec_reflength+_ft_make_key(info, + sort_info->key,key,wptr++,sort_info->filepos); + if (!wptr->pos) + { + my_free((char*) sort_info->wordlist, MYF(0)); + sort_info->wordlist=0; + } + else + sort_info->wordptr=(void*)wptr; + + + DBUG_RETURN(error); +} /* sort_ft_key_read */ /* Read next record from file using parameters in sort_info */ /* Return -1 if end of file, 0 if ok and > 0 if error */ @@ -2719,7 +2779,7 @@ static int sort_delete_record(MI_CHECK *param) /* Fix all pending blocks and flush everything to disk */ -static int flush_pending_blocks(MI_CHECK *param) +int flush_pending_blocks(MI_CHECK *param) { uint nod_flag,length; my_off_t filepos,key_file_length; @@ -2813,7 +2873,6 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) MI_STATUS_INFO status_info; uint unpack,key_parts; ha_rows max_records; - char name[FN_REFLEN]; ulonglong file_length,tmp_length; MI_CREATE_INFO create_info; @@ -2922,8 +2981,9 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) create_info.language = (param->language ? param->language : share.state.header.language); - if (mi_create(fn_format(name,filename,"",MI_NAME_IEXT, - 4+ (param->opt_follow_links ? 16 : 0)), + /* We don't have to handle symlinks here because we are using + HA_DONT_TOUCH_DATA */ + if (mi_create(filename, share.base.keys - share.state.header.uniques, keyinfo, share.base.fields, recdef, share.state.header.uniques, uniquedef, @@ -2933,7 +2993,7 @@ int recreate_table(MI_CHECK *param, MI_INFO **org_info, char *filename) mi_check_print_error(param,"Got error %d when trying to recreate indexfile",my_errno); goto end; } - *org_info=mi_open(name,O_RDWR, + *org_info=mi_open(filename,O_RDWR, (param->testflag & T_WAIT_FOREVER) ? HA_OPEN_WAIT_IF_LOCKED : (param->testflag & T_DESCRIPT) ? HA_OPEN_IGNORE_IF_LOCKED : HA_OPEN_ABORT_IF_LOCKED); @@ -3186,15 +3246,7 @@ my_bool mi_test_if_sort_rep(MI_INFO *info, ha_rows rows, return FALSE; /* Can't use sort */ for (i=0 ; i < share->base.keys ; i++,key++) { -/* It's to disable repair_by_sort for ft-keys. - Another solution would be to make ft-keys just too_big_key_for_sort, - but then they won't be disabled by dectivate_non_unique_index - and so they will be created at the first stage. As ft-key creation - is very time-consuming process, it's better to leave it to repair stage - but this repair shouldn't be repair_by_sort (serg) - */ - if ((!force && mi_too_big_key_for_sort(key,rows)) || - (key->flag & HA_FULLTEXT)) + if (!force && mi_too_big_key_for_sort(key,rows)) return FALSE; } return TRUE; diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 6de13f8f84a..d3e5e819742 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -38,12 +38,13 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, register uint i,j; File dfile,file; int errpos,save_errno; + myf create_flag; uint fields,length,max_key_length,packed,pointer, key_length,info_length,key_segs,options,min_key_length_skipp, base_pos,varchar_count,long_varchar_count,varchar_length, max_key_block_length,unique_key_parts,offset; ulong reclength, real_reclength,min_pack_length; - char buff[FN_REFLEN]; + char filename[FN_REFLEN],linkname[FN_REFLEN], *linkname_ptr; ulong pack_reclength; ulonglong tot_length,max_rows; enum en_fieldtype type; @@ -163,6 +164,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, if (packed || (flags & HA_PACK_RECORD)) options|=HA_OPTION_PACK_RECORD; /* Must use packed records */ + /* We can't use checksum with static length rows */ + if (!(options & HA_OPTION_PACK_RECORD)) + options&= ~HA_OPTION_CHECKSUM; if (options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) min_pack_length+=varchar_count; /* Min length to pack */ else @@ -444,7 +448,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, share.base.records=ci->max_rows; share.base.reloc= ci->reloc_rows; share.base.reclength=real_reclength; - share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM);; + share.base.pack_reclength=reclength+ test(options & HA_OPTION_CHECKSUM); share.base.max_pack_length=pack_reclength; share.base.min_pack_length=min_pack_length; share.base.pack_bits=packed; @@ -467,18 +471,41 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, MI_EXTEND_BLOCK_LENGTH; if (! (flags & HA_DONT_TOUCH_DATA)) share.state.create_time= (long) time((time_t*) 0); + + if (ci->index_file_name) + { + fn_format(filename, ci->index_file_name,"",MI_NAME_IEXT,4); + fn_format(linkname,name, "",MI_NAME_IEXT,4); + linkname_ptr=linkname; + /* + Don't create the table if the link or file exists to ensure that one + doesn't accidently destroy another table. + */ + create_flag=0; + } + else + { + fn_format(filename,name,"",MI_NAME_IEXT,(4+ (flags & HA_DONT_TOUCH_DATA) ? + 32 : 0)); + linkname_ptr=0; + /* Replace the current file */ + create_flag=MY_DELETE_OLD; + } - if ((file = my_create(fn_format(buff,name,"",MI_NAME_IEXT,4),0, - O_RDWR | O_TRUNC,MYF(MY_WME))) < 0) + if ((file= my_create_with_symlink(linkname_ptr, + filename, + 0, O_RDWR | O_TRUNC, + MYF(MY_WME | create_flag))) < 0) goto err; errpos=1; - VOID(fn_format(buff,name,"",MI_NAME_DEXT,2+4)); + if (!(flags & HA_DONT_TOUCH_DATA)) { #ifdef USE_RAID if (share.base.raid_type) { - if ((dfile=my_raid_create(buff,0,O_RDWR | O_TRUNC, + (void) fn_format(filename,name,"",MI_NAME_DEXT,2+4); + if ((dfile=my_raid_create(filename,0,O_RDWR | O_TRUNC, share.base.raid_type, share.base.raid_chunks, share.base.raid_chunksize, @@ -487,9 +514,26 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, } else #endif - if ((dfile = my_create(buff,0,O_RDWR | O_TRUNC,MYF(MY_WME))) < 0) - goto err; - + { + if (ci->data_file_name) + { + fn_format(filename, ci->data_file_name,"",MI_NAME_DEXT,4); + fn_format(linkname, name, "",MI_NAME_DEXT,4); + linkname_ptr=linkname; + create_flag=0; + } + else + { + fn_format(filename,name,"",MI_NAME_DEXT,4); + linkname_ptr=0; + create_flag=MY_DELETE_OLD; + } + if ((dfile= + my_create_with_symlink(linkname_ptr, filename, + 0,O_RDWR | O_TRUNC, + MYF(MY_WME | create_flag))) < 0) + goto err; + } errpos=3; } @@ -508,14 +552,14 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, /* Write key and keyseg definitions */ for (i=0 ; i < share.base.keys - uniques; i++) { - uint ft_segs=(keydefs[i].flag & HA_FULLTEXT) ? FT_SEGS : 0; /* SerG */ + uint ft_segs=(keydefs[i].flag & HA_FULLTEXT) ? FT_SEGS : 0; if (mi_keydef_write(file, &keydefs[i])) goto err; for (j=0 ; j < keydefs[i].keysegs-ft_segs ; j++) if (mi_keyseg_write(file, &keydefs[i].seg[j])) goto err; - for (j=0 ; j < ft_segs ; j++) /* SerG */ + for (j=0 ; j < ft_segs ; j++) { MI_KEYSEG seg=ft_keysegs[j]; seg.language= keydefs[i].seg[0].language; @@ -596,20 +640,16 @@ err: VOID(my_close(dfile,MYF(0))); /* fall through */ case 2: - if (! (flags & HA_DONT_TOUCH_DATA)) - { /* QQ: Tõnu should add a call to my_raid_delete() here */ - VOID(fn_format(buff,name,"",MI_NAME_DEXT,2+4)); - my_delete(buff,MYF(0)); - } + if (! (flags & HA_DONT_TOUCH_DATA)) + my_delete_with_symlink(fn_format(filename,name,"",MI_NAME_DEXT,2+4), + MYF(0)); /* fall through */ case 1: VOID(my_close(file,MYF(0))); if (! (flags & HA_DONT_TOUCH_DATA)) - { - VOID(fn_format(buff,name,"",MI_NAME_IEXT,2+4)); - my_delete(buff,MYF(0)); - } + my_delete_with_symlink(fn_format(filename,name,"",MI_NAME_IEXT,2+4), + MYF(0)); } my_free((char*) rec_per_key_part, MYF(0)); DBUG_RETURN(my_errno=save_errno); /* return the fatal errno */ diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c index eda1aafecc8..8c532970dd9 100644 --- a/myisam/mi_dbug.c +++ b/myisam/mi_dbug.c @@ -162,7 +162,7 @@ my_bool check_table_is_closed(const char *name, const char *where) { MI_INFO *info=(MI_INFO*) pos->data; MYISAM_SHARE *share=info->s; - if (!strcmp(share->filename,filename)) + if (!strcmp(share->unique_file_name,filename)) { if (share->last_version) { diff --git a/myisam/mi_delete_table.c b/myisam/mi_delete_table.c index 995106160ef..d8fff51acb6 100644 --- a/myisam/mi_delete_table.c +++ b/myisam/mi_delete_table.c @@ -50,12 +50,12 @@ int mi_delete_table(const char *name) #endif /* USE_RAID */ fn_format(from,name,"",MI_NAME_IEXT,4); - if (my_delete(from, MYF(MY_WME))) + if (my_delete_with_symlink(from, MYF(MY_WME))) DBUG_RETURN(my_errno); fn_format(from,name,"",MI_NAME_DEXT,4); #ifdef USE_RAID if (raid_type) DBUG_RETURN(my_raid_delete(from, raid_chunks, MYF(MY_WME)) ? my_errno : 0); #endif - DBUG_RETURN(my_delete(from, MYF(MY_WME)) ? my_errno : 0); + DBUG_RETURN(my_delete_with_symlink(from, MYF(MY_WME)) ? my_errno : 0); } diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index cf075512ac4..d7f3e4dc04a 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -219,9 +219,17 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function) } if (share->state.key_map) { - share->state.key_map=0; - info->state->key_file_length=share->state.state.key_file_length= - share->base.keystart; + MI_KEYDEF *key=share->keyinfo; + uint i; + for (i=0 ; i < share->base.keys ; i++,key++) + { + if (!(key->flag & HA_NOSAME) && info->s->base.auto_key != i+1) + { + share->state.key_map&= ~ ((ulonglong) 1 << i); + info->update|= HA_STATE_CHANGED; + } + } + if (!share->changed) { share->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED; @@ -328,6 +336,24 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function) case HA_EXTRA_QUICK: info->quick_mode=1; break; + case HA_EXTRA_BULK_INSERT_BEGIN: + error=_mi_init_bulk_insert(info); + break; + case HA_EXTRA_BULK_INSERT_END: + if (info->bulk_insert) + { + uint i; + for (i=0 ; i < share->base.keys ; i++) + { + if (is_tree_inited(& info->bulk_insert[i])) + { + delete_tree(& info->bulk_insert[i]); + } + } + my_free((void *)info->bulk_insert, MYF(0)); + info->bulk_insert=0; + } + break; case HA_EXTRA_NO_ROWS: if (!share->state.header.uniques) info->opt_flag|= OPT_NO_ROWS; diff --git a/myisam/mi_info.c b/myisam/mi_info.c index 6e7abfc0914..867718de326 100644 --- a/myisam/mi_info.c +++ b/myisam/mi_info.c @@ -87,6 +87,8 @@ int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag) x->raid_chunks= share->base.raid_chunks; x->raid_chunksize= share->base.raid_chunksize; x->key_map = share->state.key_map; + x->data_file_name = share->data_file_name; + x->index_file_name = share->index_file_name; } if ((flag & HA_STATUS_TIME) && !my_fstat(info->dfile,&state,MYF(0))) x->update_time=state.st_mtime; diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index e067e80fcf3..8ef5db1d344 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -412,11 +412,14 @@ int _mi_mark_file_changed(MI_INFO *info) share->global_changed=1; share->state.open_count++; } - mi_int2store(buff,share->state.open_count); - buff[2]=1; /* Mark that it's changed */ - return (my_pwrite(share->kfile,buff,sizeof(buff), - sizeof(share->state.header), - MYF(MY_NABP))); + if (!share->temporary) + { + mi_int2store(buff,share->state.open_count); + buff[2]=1; /* Mark that it's changed */ + return (my_pwrite(share->kfile,buff,sizeof(buff), + sizeof(share->state.header), + MYF(MY_NABP))); + } } return 0; } diff --git a/myisam/mi_open.c b/myisam/mi_open.c index de1888bc9b7..4d8a5c2a1d6 100644 --- a/myisam/mi_open.c +++ b/myisam/mi_open.c @@ -49,7 +49,7 @@ static MI_INFO *test_if_reopen(char *filename) { MI_INFO *info=(MI_INFO*) pos->data; MYISAM_SHARE *share=info->s; - if (!strcmp(share->filename,filename) && share->last_version) + if (!strcmp(share->unique_file_name,filename) && share->last_version) return info; } return 0; @@ -69,7 +69,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) int lock_error,kfile,open_mode,save_errno; uint i,j,len,errpos,head_length,base_pos,offset,info_length,extra,keys, key_parts,unique_key_parts,tmp_length,uniques; - char name_buff[FN_REFLEN],*disk_cache,*disk_pos; + char name_buff[FN_REFLEN], org_name [FN_REFLEN], index_name[FN_REFLEN], + data_name[FN_REFLEN]; + char *disk_cache,*disk_pos; MI_INFO info,*m_info,*old_info; MYISAM_SHARE share_buff,*share; ulong rec_per_key_part[MI_MAX_POSSIBLE_KEY*MI_MAX_KEY_SEG]; @@ -84,7 +86,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) head_length=sizeof(share_buff.state.header); bzero((byte*) &info,sizeof(info)); - VOID(fn_format(name_buff,name,"",MI_NAME_IEXT,4+16+32)); + my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0)); pthread_mutex_lock(&THR_LOCK_myisam); if (!(old_info=test_if_reopen(name_buff))) { @@ -128,6 +130,13 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) my_errno=HA_ERR_OLD_FILE; goto err; } + /* Don't call realpath() if the name can't be a link */ + if (strcmp(name_buff, org_name)) + (void) my_readlink(index_name, org_name, MYF(0)); + else + (void) strmov(index_name, org_name); + (void) fn_format(data_name,org_name,"",MI_NAME_DEXT,2+4+16); + info_length=mi_uint2korr(share->state.header.header_length); base_pos=mi_uint2korr(share->state.header.base_pos); if (!(disk_cache=(char*) my_alloca(info_length))) @@ -250,7 +259,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) &share->rec, (share->base.fields+1)*sizeof(MI_COLUMNDEF), &share->blobs,sizeof(MI_BLOB)*share->base.blobs, - &share->filename,strlen(name_buff)+1, + &share->unique_file_name,strlen(name_buff)+1, + &share->index_file_name,strlen(index_name)+1, + &share->data_file_name,strlen(data_name)+1, &share->state.key_root,keys*sizeof(my_off_t), &share->state.key_del, (share->state.header.max_block_size*sizeof(my_off_t)), @@ -268,7 +279,9 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) memcpy((char*) share->state.key_del, (char*) key_del, (sizeof(my_off_t) * share->state.header.max_block_size)); - strmov(share->filename,name_buff); + strmov(share->unique_file_name, name_buff); + strmov(share->index_file_name, index_name); + strmov(share->data_file_name, data_name); share->blocksize=min(IO_SIZE,myisam_block_size); { @@ -438,12 +451,12 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) &info.buff,(share->base.max_key_block_length*2+ share->base.max_key_length), &info.lastkey,share->base.max_key_length*3+1, - &info.filename,strlen(name)+1, + &info.filename,strlen(org_name)+1, NullS)) goto err; errpos=6; - strmov(info.filename,name); + strmov(info.filename,org_name); memcpy(info.blobs,share->blobs,sizeof(MI_BLOB)*share->base.blobs); info.lastkey2=info.lastkey+share->base.max_key_length; @@ -461,6 +474,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) share->options|=HA_OPTION_READ_ONLY_DATA; info.lock_type=F_UNLCK; info.quick_mode=0; + info.bulk_insert=0; info.errkey= -1; info.page_changed=1; pthread_mutex_lock(&share->intern_lock); @@ -514,7 +528,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) pthread_mutex_unlock(&THR_LOCK_myisam); if (myisam_log_file >= 0) { - intern_filename(name_buff,share->filename); + intern_filename(name_buff,share->index_file_name); _myisam_log(MI_LOG_OPEN,m_info,name_buff,(uint) strlen(name_buff)); } DBUG_RETURN(m_info); @@ -625,15 +639,20 @@ static void setup_key_functions(register MI_KEYDEF *keyinfo) } else if (keyinfo->flag & HA_VAR_LENGTH_KEY) { - keyinfo->bin_search=_mi_seq_search; keyinfo->get_key= _mi_get_pack_key; if (keyinfo->seg[0].flag & HA_PACK_KEY) { /* Prefix compression */ + if (!keyinfo->seg->charset || use_strcoll(keyinfo->seg->charset) || + (keyinfo->seg->flag & HA_NULL_PART)) + keyinfo->bin_search=_mi_seq_search; + else + keyinfo->bin_search=_mi_prefix_search; keyinfo->pack_key=_mi_calc_var_pack_key_length; keyinfo->store_key=_mi_store_var_pack_key; } else { + keyinfo->bin_search=_mi_seq_search; keyinfo->pack_key=_mi_calc_var_key_length; /* Variable length key */ keyinfo->store_key=_mi_store_static_key; } @@ -772,14 +791,17 @@ uint mi_state_info_read_dsk(File file, MI_STATE_INFO *state, my_bool pRead) { char buff[MI_STATE_INFO_SIZE + MI_STATE_EXTRA_SIZE]; - if (pRead) + if (!myisam_single_user) { - if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP))) + if (pRead) + { + if (my_pread(file, buff, state->state_length,0L, MYF(MY_NABP))) + return (MY_FILE_ERROR); + } + else if (my_read(file, buff, state->state_length,MYF(MY_NABP))) return (MY_FILE_ERROR); + mi_state_info_read(buff, state); } - else if (my_read(file, buff, state->state_length,MYF(MY_NABP))) - return (MY_FILE_ERROR); - mi_state_info_read(buff, state); return 0; } @@ -992,13 +1014,10 @@ char *mi_recinfo_read(char *ptr, MI_COLUMNDEF *recinfo) int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share) { - char name_buff[FN_REFLEN]; - (void) fn_format(name_buff, share->filename,"",MI_NAME_DEXT, 2+4); - #ifdef USE_RAID if (share->base.raid_type) { - if ((info->dfile=my_raid_open(name_buff, + if ((info->dfile=my_raid_open(share->data_file_name, share->mode | O_SHARE, share->base.raid_type, share->base.raid_chunks, @@ -1008,7 +1027,7 @@ int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share) } else #endif - if ((info->dfile=my_open(name_buff, share->mode | O_SHARE, + if ((info->dfile=my_open(share->data_file_name, share->mode | O_SHARE, MYF(MY_WME))) < 0) return 1; return 0; @@ -1017,7 +1036,7 @@ int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share) int mi_open_keyfile(MYISAM_SHARE *share) { - if ((share->kfile=my_open(share->filename, share->mode | O_SHARE, + if ((share->kfile=my_open(share->unique_file_name, share->mode | O_SHARE, MYF(MY_WME))) < 0) return 1; return 0; diff --git a/myisam/mi_rename.c b/myisam/mi_rename.c index 5c92db3f7ce..4d6250f58f4 100644 --- a/myisam/mi_rename.c +++ b/myisam/mi_rename.c @@ -51,7 +51,7 @@ int mi_rename(const char *old_name, const char *new_name) fn_format(from,old_name,"",MI_NAME_IEXT,4); fn_format(to,new_name,"",MI_NAME_IEXT,4); - if (my_rename(from, to, MYF(MY_WME))) + if (my_rename_with_symlink(from, to, MYF(MY_WME))) DBUG_RETURN(my_errno); fn_format(from,old_name,"",MI_NAME_DEXT,4); fn_format(to,new_name,"",MI_NAME_DEXT,4); @@ -60,5 +60,5 @@ int mi_rename(const char *old_name, const char *new_name) DBUG_RETURN(my_raid_rename(from, to, raid_chunks, MYF(MY_WME)) ? my_errno : 0); #endif - DBUG_RETURN(my_rename(from, to,MYF(MY_WME)) ? my_errno : 0); + DBUG_RETURN(my_rename_with_symlink(from, to,MYF(MY_WME)) ? my_errno : 0); } diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 2c04679ed4c..18d8ea8a4b0 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -22,26 +22,26 @@ #define CMP(a,b) (a<b ? -1 : a == b ? 0 : 1) static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uchar *keypos, - uint *return_key_length); + uchar *key, uchar *keypos, + uint *return_key_length); - /* Check index */ + /* Check index */ int _mi_check_index(MI_INFO *info, int inx) { - if (inx == -1) /* Use last index */ + if (inx == -1) /* Use last index */ inx=info->lastinx; if (inx < 0 || ! (((ulonglong) 1 << inx) & info->s->state.key_map)) { my_errno=HA_ERR_WRONG_INDEX; return -1; } - if (info->lastinx != inx) /* Index changed */ + if (info->lastinx != inx) /* Index changed */ { info->lastinx = inx; info->page_changed=1; info->update= ((info->update & (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED)) | - HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND); + HA_STATE_NEXT_FOUND | HA_STATE_PREV_FOUND); } if (info->opt_flag & WRITE_CACHE_USED && flush_io_cache(&info->rec_cache)) return(-1); @@ -49,15 +49,15 @@ int _mi_check_index(MI_INFO *info, int inx) } /* mi_check_index */ - /* - ** Search after row by a key - ** Position to row is stored in info->lastpos - ** Return: -1 if not found - ** 1 if one should continue search on higher level - */ + /* + ** Search after row by a key + ** Position to row is stored in info->lastpos + ** Return: -1 if not found + ** 1 if one should continue search on higher level + */ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, - uchar *key, uint key_len, uint nextflag, register my_off_t pos) + uchar *key, uint key_len, uint nextflag, register my_off_t pos) { my_bool last_key; int error,flag; @@ -66,25 +66,25 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, uchar lastkey[MI_MAX_KEY_BUFF],*buff; DBUG_ENTER("_mi_search"); DBUG_PRINT("enter",("pos: %ld nextflag: %d lastpos: %ld", - pos,nextflag,info->lastpos)); + pos,nextflag,info->lastpos)); DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_len);); if (pos == HA_OFFSET_ERROR) { - my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ + my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ info->lastpos= HA_OFFSET_ERROR; if (!(nextflag & (SEARCH_SMALLER | SEARCH_BIGGER | SEARCH_LAST))) - DBUG_RETURN(-1); /* Not found ; return error */ - DBUG_RETURN(1); /* Search at upper levels */ + DBUG_RETURN(-1); /* Not found ; return error */ + DBUG_RETURN(1); /* Search at upper levels */ } if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff, - test(!(nextflag & SEARCH_SAVE_BUFF))))) + test(!(nextflag & SEARCH_SAVE_BUFF))))) goto err; DBUG_DUMP("page",(byte*) buff,mi_getint(buff)); flag=(*keyinfo->bin_search)(info,keyinfo,buff,key,key_len,nextflag, - &keypos,lastkey, &last_key); + &keypos,lastkey, &last_key); if (flag == MI_FOUND_WRONG_KEY) DBUG_RETURN(-1); nod_flag=mi_test_if_nod(buff); @@ -93,35 +93,35 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (flag) { if ((error=_mi_search(info,keyinfo,key,key_len,nextflag, - _mi_kpos(nod_flag,keypos))) <= 0) + _mi_kpos(nod_flag,keypos))) <= 0) DBUG_RETURN(error); if (flag >0) { if (nextflag & (SEARCH_SMALLER | SEARCH_LAST) && - keypos == buff+2+nod_flag) - DBUG_RETURN(1); /* Bigger than key */ + keypos == buff+2+nod_flag) + DBUG_RETURN(1); /* Bigger than key */ } else if (nextflag & SEARCH_BIGGER && keypos >= maxpos) - DBUG_RETURN(1); /* Smaller than key */ + DBUG_RETURN(1); /* Smaller than key */ } else { if (nextflag & SEARCH_FIND && (!(keyinfo->flag & HA_NOSAME) - || key_len) && nod_flag) + || key_len) && nod_flag) { if ((error=_mi_search(info,keyinfo,key,key_len,SEARCH_FIND, - _mi_kpos(nod_flag,keypos))) >= 0 || - my_errno != HA_ERR_KEY_NOT_FOUND) - DBUG_RETURN(error); - info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in memory */ + _mi_kpos(nod_flag,keypos))) >= 0 || + my_errno != HA_ERR_KEY_NOT_FOUND) + DBUG_RETURN(error); + info->last_keypage= HA_OFFSET_ERROR; /* Buffer not in memory */ } } if (pos != info->last_keypage) { uchar *old_buff=buff; if (!(buff=_mi_fetch_keypage(info,keyinfo,pos,info->buff, - test(!(nextflag & SEARCH_SAVE_BUFF))))) + test(!(nextflag & SEARCH_SAVE_BUFF))))) goto err; keypos=buff+(keypos-old_buff); maxpos=buff+(maxpos-old_buff); @@ -131,13 +131,13 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, { uint not_used; if (_mi_get_prev_key(info,keyinfo, buff, info->lastkey, keypos, - &info->lastkey_length)) + &info->lastkey_length)) goto err; if ((nextflag & SEARCH_LAST) && - _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND, - ¬_used)) + _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND, + ¬_used)) { - my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ + my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ goto err; } } @@ -156,7 +156,7 @@ int _mi_search(register MI_INFO *info, register MI_KEYDEF *keyinfo, info->int_keytree_version=keyinfo->version; info->last_search_keypage=info->last_keypage; info->page_changed=0; - info->buff_used= (info->buff != buff); /* If we have to reread buff */ + info->buff_used= (info->buff != buff); /* If we have to reread buff */ DBUG_PRINT("exit",("found key at %lu",(ulong) info->lastpos)); DBUG_RETURN(0); @@ -168,14 +168,14 @@ err: } /* _mi_search */ - /* Search after key in page-block */ - /* If packed key puts smaller or identical key in buff */ - /* ret_pos point to where find or bigger key starts */ - /* ARGSUSED */ + /* Search after key in page-block */ + /* If packed key puts smaller or identical key in buff */ + /* ret_pos point to where find or bigger key starts */ + /* ARGSUSED */ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, - uchar *buff __attribute__((unused)), my_bool *last_key) + uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, + uchar *buff __attribute__((unused)), my_bool *last_key) { reg4 int start,mid,end,save_end; int flag; @@ -193,17 +193,17 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, { mid= (start+end)/2; if ((flag=_mi_key_cmp(keyinfo->seg,page+(uint) mid*totlength,key,key_len, - comp_flag,¬_used)) - >= 0) + comp_flag,¬_used)) + >= 0) end=mid; else start=mid+1; } if (mid != start) flag=_mi_key_cmp(keyinfo->seg,page+(uint) start*totlength,key,key_len, - comp_flag,¬_used); + comp_flag,¬_used); if (flag < 0) - start++; /* point at next, bigger key */ + start++; /* point at next, bigger key */ *ret_pos=page+(uint) start*totlength; *last_key= end == save_end; DBUG_PRINT("exit",("flag: %d keypos: %d",flag,start)); @@ -211,13 +211,13 @@ int _mi_bin_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, } /* _mi_bin_search */ - /* Used instead of _mi_bin_search() when key is packed */ - /* Puts smaller or identical key in buff */ - /* Key is searched sequentially */ + /* Used instead of _mi_bin_search() when key is packed */ + /* Puts smaller or identical key in buff */ + /* Key is searched sequentially */ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, - uchar *buff, my_bool *last_key) + uchar *key, uint key_len, uint comp_flag, uchar **ret_pos, + uchar *buff, my_bool *last_key) { int flag; uint nod_flag,length,not_used; @@ -229,7 +229,7 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, nod_flag=mi_test_if_nod(page); page+=2+nod_flag; *ret_pos=page; - t_buff[0]=0; /* Avoid bugs */ + t_buff[0]=0; /* Avoid bugs */ while (page < end) { length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,t_buff); @@ -237,11 +237,11 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, { my_errno=HA_ERR_CRASHED; DBUG_PRINT("error",("Found wrong key: length: %d page: %lx end: %lx", - length,page,end)); + length,page,end)); DBUG_RETURN(MI_FOUND_WRONG_KEY); } if ((flag=_mi_key_cmp(keyinfo->seg,t_buff,key,key_len,comp_flag, - ¬_used)) >= 0) + ¬_used)) >= 0) break; #ifdef EXTRA_DEBUG DBUG_PRINT("loop",("page: %lx key: '%s' flag: %d",page,t_buff,flag)); @@ -250,14 +250,226 @@ int _mi_seq_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, *ret_pos=page; } if (flag == 0) - memcpy(buff,t_buff,length); /* Result is first key */ + memcpy(buff,t_buff,length); /* Result is first key */ *last_key= page == end; DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos)); DBUG_RETURN(flag); } /* _mi_seq_search */ - /* Get pos to a key_block */ +int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, + uchar *key, uint key_len, uint nextflag, uchar **ret_pos, + uchar *buff, my_bool *last_key) +{ + /* my_flag is raw comparison result to be changed according to + SEARCH_NO_FIND,SEARCH_LAST and HA_REVERSE_SORT flags. + flag is the value returned by _mi_key_cmp and as treated as final */ + int flag=0, my_flag=-1; + uint nod_flag, length, len, matched, cmplen, kseg_len; + uint prefix_len,suffix_len; + int key_len_skip, seg_len_pack, key_len_left; + uchar *end, *kseg, *vseg; + uchar *sort_order=keyinfo->seg->charset->sort_order; + uchar tt_buff[MI_MAX_KEY_BUFF+2], *t_buff=tt_buff+2; + uchar *saved_from, *saved_to, *saved_vseg; + uint saved_length=0, saved_prefix_len=0; + DBUG_ENTER("_mi_prefix_search"); + + LINT_INIT(length); + LINT_INIT(prefix_len); + LINT_INIT(seg_len_pack); + LINT_INIT(saved_from); + LINT_INIT(saved_to); + LINT_INIT(saved_vseg); + + t_buff[0]=0; /* Avoid bugs */ + if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST))) + key_len=USE_WHOLE_KEY; + end= page+mi_getint(page); + nod_flag=mi_test_if_nod(page); + page+=2+nod_flag; + *ret_pos=page; + kseg=key; + { + uint lenght_pack; + get_key_pack_length(kseg_len,lenght_pack,kseg); + key_len_skip=lenght_pack+kseg_len; + key_len_left=(int) key_len- (int) key_len_skip; + cmplen=(key_len_left>=0) ? kseg_len : key_len-lenght_pack; + DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg)); + } + +/* + Keys are compressed the following way: + + If the max length of first key segment <= 127 characters the prefix is + 1 byte else it's 2 byte + + prefix The high bit is set if this is a prefix for the prev key + length Packed length if the previous was a prefix byte + [length] Length character of data + next-key-seg Next key segments +*/ + + matched=0; /* how many char's from prefix were alredy matched */ + len=0; /* length of previous key unpacked */ + + while (page < end) + { + uint packed= *page & 128; + + vseg=page; + if (keyinfo->seg->length >= 127) + { + suffix_len=mi_uint2korr(vseg) & 32767; + vseg+=2; + } + else + suffix_len= *vseg++ & 127; + + if (packed) + { + if (suffix_len == 0) /* Same key */ + prefix_len=len; + else + { + prefix_len=suffix_len; + get_key_length(suffix_len,vseg); + } + } + else + prefix_len=0; + + len=prefix_len+suffix_len; + seg_len_pack=get_pack_length(len); + t_buff=tt_buff+3-seg_len_pack; + store_key_length(t_buff,len); + + if (prefix_len > saved_prefix_len) + memcpy(t_buff+seg_len_pack+saved_prefix_len,saved_vseg, + prefix_len-saved_prefix_len); + saved_vseg=vseg; + saved_prefix_len=prefix_len; + + DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,suffix_len,vseg)); + { + uchar *from=vseg+suffix_len; + MI_KEYSEG *keyseg; + uint l; + + for (keyseg=keyinfo->seg+1 ; keyseg->type ; keyseg++ ) + { + + if (keyseg->flag & HA_NULL_PART) + { + if (!(*from++)) + continue; + } + if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) + { + get_key_length(l,from); + } + else + l=keyseg->length; + + from+=l; + } + from+=keyseg->length; + page=from+nod_flag; + length=from-vseg; + } + + if (page > end) + { + my_errno=HA_ERR_CRASHED; + DBUG_PRINT("error",("Found wrong key: length: %d page: %lx end: %lx", + length,page,end)); + DBUG_RETURN(MI_FOUND_WRONG_KEY); + } + + if (matched >= prefix_len) + { + /* We have to compare. But we can still skip part of the key */ + uint left; + uchar *k=kseg+prefix_len; + + left=(len>cmplen) ? cmplen-prefix_len : suffix_len; + + matched=prefix_len+left; + + for(my_flag=0;left;left--) + if ((my_flag= (int) sort_order[*vseg++] - (int) sort_order[*k++])) + break; + + if (my_flag>0) /* mismatch */ + break; + else if (my_flag==0) /* match */ + { /* + ** len cmplen seg_left_len more_segs + ** < matched=len; continue search + ** > = prefix ? found : (matched=len; continue search) + ** > < - ok, found + ** = < - ok, found + ** = = - ok, found + ** = = + next seg + */ + if (len < cmplen) + { + my_flag= -1; + } + else if (len > cmplen) + { + if ((my_flag= (!(nextflag & SEARCH_PREFIX) || key_len_left>0))) + break; + goto fix_flag; + } + else if (key_len_left>0) + { + uint not_used; + if ((flag = _mi_key_cmp(keyinfo->seg+1,vseg, + k,key_len_left,nextflag,¬_used)) >= 0) + break; + } + else + { + /* at this line flag==-1 if the following lines were already + visited and 0 otherwise, i.e. flag <=0 here always !!! */ + fix_flag: + if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) + flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1; + if (flag>=0) break; + } + } + matched-=left; + } + /* else (matched < prefix_len) ---> do nothing. */ + + memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len); + saved_to=buff+saved_length; + saved_from=saved_vseg; + saved_length=length; + *ret_pos=page; + } + if (my_flag) + flag=(keyinfo->seg->flag & HA_REVERSE_SORT) ? -my_flag : my_flag; + if (flag == 0) + { + memcpy(buff,t_buff,saved_length=seg_len_pack+prefix_len); + saved_to=buff+saved_length; + saved_from=saved_vseg; + saved_length=length; + } + if (saved_length) + memcpy(saved_to,saved_from,saved_length); + + *last_key= page == end; + + DBUG_PRINT("exit",("flag: %d ret_pos: %lx",flag,*ret_pos)); + DBUG_RETURN(flag); +} /* _mi_prefix_search */ + + + /* Get pos to a key_block */ my_off_t _mi_kpos(uint nod_flag, uchar *after_key) { @@ -286,14 +498,14 @@ my_off_t _mi_kpos(uint nod_flag, uchar *after_key) return (my_off_t) (mi_uint2korr(after_key)*MI_KEY_BLOCK_LENGTH); case 1: return (uint) (*after_key)*MI_KEY_BLOCK_LENGTH; - case 0: /* At leaf page */ - default: /* Impossible */ + case 0: /* At leaf page */ + default: /* Impossible */ return(HA_OFFSET_ERROR); } } /* _kpos */ - /* Save pos to a key_block */ + /* Save pos to a key_block */ void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos) { @@ -315,12 +527,12 @@ void _mi_kpointer(register MI_INFO *info, register uchar *buff, my_off_t pos) case 3: mi_int3store(buff,pos); break; case 2: mi_int2store(buff,(uint) pos); break; case 1: buff[0]= (uchar) pos; break; - default: abort(); /* impossible */ + default: abort(); /* impossible */ } } /* _mi_kpointer */ - /* Calc pos to a data-record from a key */ + /* Calc pos to a data-record from a key */ my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key) @@ -335,19 +547,19 @@ my_off_t _mi_dpos(MI_INFO *info, uint nod_flag, uchar *after_key) case 5: pos= (my_off_t) mi_uint5korr(after_key); break; #else case 8: pos= (my_off_t) mi_uint4korr(after_key+4); break; - case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break; - case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break; - case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break; + case 7: pos= (my_off_t) mi_uint4korr(after_key+3); break; + case 6: pos= (my_off_t) mi_uint4korr(after_key+2); break; + case 5: pos= (my_off_t) mi_uint4korr(after_key+1); break; #endif case 4: pos= (my_off_t) mi_uint4korr(after_key); break; case 3: pos= (my_off_t) mi_uint3korr(after_key); break; case 2: pos= (my_off_t) mi_uint2korr(after_key); break; default: - pos=0L; /* Shut compiler up */ + pos=0L; /* Shut compiler up */ } return (info->s->options & - (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos : - pos*info->s->base.pack_reclength; + (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos : + pos*info->s->base.pack_reclength; } @@ -361,22 +573,22 @@ my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr) case 8: pos= (my_off_t) mi_uint8korr(ptr); if (pos == HA_OFFSET_ERROR) - return HA_OFFSET_ERROR; /* end of list */ + return HA_OFFSET_ERROR; /* end of list */ break; case 7: pos= (my_off_t) mi_uint7korr(ptr); if (pos == (((my_off_t) 1) << 56) -1) - return HA_OFFSET_ERROR; /* end of list */ + return HA_OFFSET_ERROR; /* end of list */ break; case 6: pos= (my_off_t) mi_uint6korr(ptr); if (pos == (((my_off_t) 1) << 48) -1) - return HA_OFFSET_ERROR; /* end of list */ + return HA_OFFSET_ERROR; /* end of list */ break; case 5: pos= (my_off_t) mi_uint5korr(ptr); if (pos == (((my_off_t) 1) << 40) -1) - return HA_OFFSET_ERROR; /* end of list */ + return HA_OFFSET_ERROR; /* end of list */ break; #else case 8: @@ -401,20 +613,20 @@ my_off_t _mi_rec_pos(MYISAM_SHARE *s, uchar *ptr) if (pos == (my_off_t) (1 << 16) -1) return HA_OFFSET_ERROR; break; - default: abort(); /* Impossible */ + default: abort(); /* Impossible */ } return ((s->options & - (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos : - pos*s->base.pack_reclength); + (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? pos : + pos*s->base.pack_reclength); } - /* save position to record */ + /* save position to record */ void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos) { if (!(info->s->options & - (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) && + (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) && pos != HA_OFFSET_ERROR) pos/=info->s->base.pack_reclength; @@ -437,13 +649,13 @@ void _mi_dpointer(MI_INFO *info, uchar *buff, my_off_t pos) case 4: mi_int4store(buff,pos); break; case 3: mi_int3store(buff,pos); break; case 2: mi_int2store(buff,(uint) pos); break; - default: abort(); /* Impossible */ + default: abort(); /* Impossible */ } } /* _mi_dpointer */ int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length, - uchar *b, uint b_length, my_bool part_key) + uchar *b, uint b_length, my_bool part_key) { uint length= min(a_length,b_length); uchar *end= a+ length; @@ -470,7 +682,7 @@ int _mi_compare_text(CHARSET_INFO *charset_info, uchar *a, uint a_length, static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, - my_bool part_key) + my_bool part_key) { uint length= min(a_length,b_length); uchar *end= a+ length; @@ -485,19 +697,19 @@ static int compare_bin(uchar *a, uint a_length, uchar *b, uint b_length, } - /* - ** Compare two keys with is bigger - ** Returns <0, 0, >0 acording to with is bigger - ** Key_length specifies length of key to use. Number-keys can't - ** be splited - ** If flag <> SEARCH_FIND compare also position - */ + /* + ** Compare two keys + ** Returns <0, 0, >0 acording to which is bigger + ** Key_length specifies length of key to use. Number-keys can't + ** be splited + ** If flag <> SEARCH_FIND compare also position + */ #define FCMP(A,B) ((int) (A) - (int) (B)) int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, - register uchar *b, uint key_length, uint nextflag, - uint *diff_pos) + register uchar *b, uint key_length, uint nextflag, + uint *diff_pos) { int flag; int16 s_1,s_2; @@ -522,106 +734,106 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, key_length--; if (*a != *b) { - flag = (int) *a - (int) *b; - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + flag = (int) *a - (int) *b; + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); } b++; - if (!*a++) /* If key was NULL */ + if (!*a++) /* If key was NULL */ { - if (nextflag == (SEARCH_FIND | SEARCH_UPDATE)) - nextflag=SEARCH_SAME; /* Allow duplicate keys */ - next_key_length=key_length; - continue; /* To next key part */ + if (nextflag == (SEARCH_FIND | SEARCH_UPDATE)) + nextflag=SEARCH_SAME; /* Allow duplicate keys */ + next_key_length=key_length; + continue; /* To next key part */ } } end= a+ min(keyseg->length,key_length); next_key_length=key_length-keyseg->length; switch ((enum ha_base_keytype) keyseg->type) { - case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ + case HA_KEYTYPE_TEXT: /* Ascii; Key is converted */ if (keyseg->flag & HA_SPACE_PACK) { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; + int a_length,b_length,pack_length; + get_key_length(a_length,a); + get_key_pack_length(b_length,pack_length,b); + next_key_length=key_length-b_length-pack_length; + + if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=a_length; + b+=b_length; + break; } else { - uint length=(uint) (end-a); - if ((flag=_mi_compare_text(keyseg->charset,a,length,b,length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a=end; - b+=length; + uint length=(uint) (end-a); + if ((flag=_mi_compare_text(keyseg->charset,a,length,b,length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a=end; + b+=length; } break; case HA_KEYTYPE_BINARY: if (keyseg->flag & HA_SPACE_PACK) { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if ((flag=compare_bin(a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; + int a_length,b_length,pack_length; + get_key_length(a_length,a); + get_key_pack_length(b_length,pack_length,b); + next_key_length=key_length-b_length-pack_length; + + if ((flag=compare_bin(a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=a_length; + b+=b_length; + break; } else { - uint length=keyseg->length; - if ((flag=compare_bin(a,length,b,length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=length; - b+=length; + uint length=keyseg->length; + if ((flag=compare_bin(a,length,b,length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=length; + b+=length; } break; case HA_KEYTYPE_VARTEXT: { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; + int a_length,b_length,pack_length; + get_key_length(a_length,a); + get_key_pack_length(b_length,pack_length,b); + next_key_length=key_length-b_length-pack_length; + + if ((flag=_mi_compare_text(keyseg->charset,a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=a_length; + b+=b_length; + break; } break; case HA_KEYTYPE_VARBINARY: { - int a_length,b_length,pack_length; - get_key_length(a_length,a); - get_key_pack_length(b_length,pack_length,b); - next_key_length=key_length-b_length-pack_length; - - if ((flag=compare_bin(a,a_length,b,b_length, - (my_bool) ((nextflag & SEARCH_PREFIX) && - next_key_length <= 0)))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a+=a_length; - b+=b_length; - break; + int a_length,b_length,pack_length; + get_key_length(a_length,a); + get_key_pack_length(b_length,pack_length,b); + next_key_length=key_length-b_length-pack_length; + + if ((flag=compare_bin(a,a_length,b,b_length, + (my_bool) ((nextflag & SEARCH_PREFIX) && + next_key_length <= 0)))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a+=a_length; + b+=b_length; + break; } break; case HA_KEYTYPE_INT8: @@ -629,7 +841,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, int i_1= (int) *((signed char*) a); int i_2= (int) *((signed char*) b); if ((flag = CMP(i_1,i_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b++; break; @@ -638,26 +850,26 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, s_1= mi_sint2korr(a); s_2= mi_sint2korr(b); if ((flag = CMP(s_1,s_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 2; /* sizeof(short int); */ break; case HA_KEYTYPE_USHORT_INT: { - uint16 us_1,us_2; - us_1= mi_sint2korr(a); - us_2= mi_sint2korr(b); - if ((flag = CMP(us_1,us_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); - a= end; - b+=2; /* sizeof(short int); */ - break; + uint16 us_1,us_2; + us_1= mi_sint2korr(a); + us_2= mi_sint2korr(b); + if ((flag = CMP(us_1,us_2))) + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + a= end; + b+=2; /* sizeof(short int); */ + break; } case HA_KEYTYPE_LONG_INT: l_1= mi_sint4korr(a); l_2= mi_sint4korr(b); if ((flag = CMP(l_1,l_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(long int); */ break; @@ -665,7 +877,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, u_1= mi_sint4korr(a); u_2= mi_sint4korr(b); if ((flag = CMP(u_1,u_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(long int); */ break; @@ -673,7 +885,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, l_1=mi_sint3korr(a); l_2=mi_sint3korr(b); if ((flag = CMP(l_1,l_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 3; break; @@ -681,7 +893,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, l_1=mi_uint3korr(a); l_2=mi_uint3korr(b); if ((flag = CMP(l_1,l_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 3; break; @@ -689,7 +901,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, mi_float4get(f_1,a); mi_float4get(f_2,b); if ((flag = CMP(f_1,f_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 4; /* sizeof(float); */ break; @@ -697,65 +909,65 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, mi_float8get(d_1,a); mi_float8get(d_2,b); if ((flag = CMP(d_1,d_2))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; /* sizeof(double); */ break; - case HA_KEYTYPE_NUM: /* Numeric key */ + case HA_KEYTYPE_NUM: /* Numeric key */ { int swap_flag= 0; int alength,blength; if (keyseg->flag & HA_REVERSE_SORT) { - swap(uchar*,a,b); - swap_flag=1; /* Remember swap of a & b */ + swap(uchar*,a,b); + swap_flag=1; /* Remember swap of a & b */ end= a+ (int) (end-b); } if (keyseg->flag & HA_SPACE_PACK) { - alength= *a++; blength= *b++; - end=a+alength; - next_key_length=key_length-blength-1; + alength= *a++; blength= *b++; + end=a+alength; + next_key_length=key_length-blength-1; } else { - alength= (int) (end-a); - blength=keyseg->length; - /* remove pre space from keys */ - for ( ; alength && *a == ' ' ; a++, alength--) ; - for ( ; blength && *b == ' ' ; b++, blength--) ; + alength= (int) (end-a); + blength=keyseg->length; + /* remove pre space from keys */ + for ( ; alength && *a == ' ' ; a++, alength--) ; + for ( ; blength && *b == ' ' ; b++, blength--) ; } if (*a == '-') { - if (*b != '-') - return -1; - a++; b++; - swap(uchar*,a,b); - swap(int,alength,blength); - swap_flag=1-swap_flag; - alength--; blength--; - end=a+alength; + if (*b != '-') + return -1; + a++; b++; + swap(uchar*,a,b); + swap(int,alength,blength); + swap_flag=1-swap_flag; + alength--; blength--; + end=a+alength; } else if (*b == '-') - return 1; + return 1; while (alength && (*a == '+' || *a == '0')) { - a++; alength--; + a++; alength--; } while (blength && (*b == '+' || *b == '0')) { - b++; blength--; + b++; blength--; } if (alength != blength) - return (alength < blength) ? -1 : 1; + return (alength < blength) ? -1 : 1; while (a < end) - if (*a++ != *b++) - return ((int) a[-1] - (int) b[-1]); + if (*a++ != *b++) + return ((int) a[-1] - (int) b[-1]); - if (swap_flag) /* Restore pointers */ - swap(uchar*,a,b); + if (swap_flag) /* Restore pointers */ + swap(uchar*,a,b); break; } #ifdef HAVE_LONG_LONG @@ -765,7 +977,7 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, ll_a= mi_sint8korr(a); ll_b= mi_sint8korr(b); if ((flag = CMP(ll_a,ll_b))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; break; @@ -776,14 +988,14 @@ int _mi_key_cmp(register MI_KEYSEG *keyseg, register uchar *a, ll_a= mi_uint8korr(a); ll_b= mi_uint8korr(b); if ((flag = CMP(ll_a,ll_b))) - return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); + return ((keyseg->flag & HA_REVERSE_SORT) ? -flag : flag); a= end; b+= 8; break; } #endif - case HA_KEYTYPE_END: /* Ready */ - goto end; /* diff_pos is incremented */ + case HA_KEYTYPE_END: /* Ready */ + goto end; /* diff_pos is incremented */ } } (*diff_pos)++; @@ -798,33 +1010,33 @@ end: { if (*a++ != *b++) { - flag= FCMP(a[-1],b[-1]); - break; + flag= FCMP(a[-1],b[-1]); + break; } } if (nextflag & SEARCH_SAME) - return (flag); /* read same */ + return (flag); /* read same */ if (nextflag & SEARCH_BIGGER) - return (flag <= 0 ? -1 : 1); /* read next */ - return (flag < 0 ? -1 : 1); /* read previous */ + return (flag <= 0 ? -1 : 1); /* read next */ + return (flag < 0 ? -1 : 1); /* read previous */ } return 0; } /* _mi_key_cmp */ - /* Get key from key-block */ - /* page points at previous key; its advanced to point at next key */ - /* key should contain previous key */ - /* Returns length of found key + pointers */ - /* nod_flag is a flag if we are on nod */ + /* Get key from key-block */ + /* page points at previous key; its advanced to point at next key */ + /* key should contain previous key */ + /* Returns length of found key + pointers */ + /* nod_flag is a flag if we are on nod */ - /* same as _mi_get_key but used with fixed length keys */ + /* same as _mi_get_key but used with fixed length keys */ uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag, - register uchar **page, register uchar *key) + register uchar **page, register uchar *key) { memcpy((byte*) key,(byte*) *page, - (size_t) (keyinfo->keylength+nod_flag)); + (size_t) (keyinfo->keylength+nod_flag)); *page+=keyinfo->keylength+nod_flag; return(keyinfo->keylength); } /* _mi_get_static_key */ @@ -833,7 +1045,7 @@ uint _mi_get_static_key(register MI_KEYDEF *keyinfo, uint nod_flag, /* Key with is packed against previous key or key with a NULL column */ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, - register uchar **page_pos, register uchar *key) + register uchar **page_pos, register uchar *key) { reg1 MI_KEYSEG *keyseg; uchar *start_key,*page=*page_pos; @@ -849,11 +1061,11 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, uint packed= *page & 128,tot_length,rest_length; if (keyseg->length >= 127) { - length=mi_uint2korr(page) & 32767; - page+=2; + length=mi_uint2korr(page) & 32767; + page+=2; } else - length= *page++ & 127; + length= *page++ & 127; if (packed) { @@ -914,23 +1126,23 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, } else { - if (keyseg->flag & HA_NULL_PART) - { - if (!length--) /* Null part */ - { - *key++=0; - continue; - } - *key++=1; /* Not null */ - } + if (keyseg->flag & HA_NULL_PART) + { + if (!length--) /* Null part */ + { + *key++=0; + continue; + } + *key++=1; /* Not null */ + } } if (length > (uint) keyseg->length) { - DBUG_PRINT("error",("Found too long packed key: %d of %d at %lx", - length, keyseg->length, *page_pos)); - DBUG_DUMP("key",(char*) *page_pos,16); - my_errno=HA_ERR_CRASHED; - return 0; /* Error */ + DBUG_PRINT("error",("Found too long packed key: %d of %d at %lx", + length, keyseg->length, *page_pos)); + DBUG_DUMP("key",(char*) *page_pos,16); + my_errno=HA_ERR_CRASHED; + return 0; /* Error */ } store_key_length_inc(key,length); } @@ -938,18 +1150,18 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, { if (keyseg->flag & HA_NULL_PART) { - if (!(*key++ = *page++)) - continue; + if (!(*key++ = *page++)) + continue; } if (keyseg->flag & - (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) + (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) { - uchar *tmp=page; - get_key_length(length,tmp); - length+=(uint) (tmp-page); + uchar *tmp=page; + get_key_length(length,tmp); + length+=(uint) (tmp-page); } else - length=keyseg->length; + length=keyseg->length; } memcpy((byte*) key,(byte*) page,(size_t) length); key+=length; @@ -966,7 +1178,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, /* key that is packed relatively to previous */ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, - register uchar **page_pos, register uchar *key) + register uchar **page_pos, register uchar *key) { reg1 MI_KEYSEG *keyseg; uchar *start_key,*page=*page_pos,*page_end,*from,*from_end; @@ -981,16 +1193,16 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, if (length > keyinfo->maxlength) { DBUG_PRINT("error",("Found too long binary packed key: %d of %d at %lx", - length, keyinfo->maxlength, *page_pos)); + length, keyinfo->maxlength, *page_pos)); DBUG_DUMP("key",(char*) *page_pos,16); my_errno=HA_ERR_CRASHED; - return 0; /* Wrong key */ + return 0; /* Wrong key */ } from=key; from_end=key+length; } else { - from=page; from_end=page_end; /* Not packed key */ + from=page; from_end=page_end; /* Not packed key */ } /* @@ -1004,7 +1216,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, { if (from == from_end) { from=page; from_end=page_end; } if (!(*key++ = *from++)) - continue; /* Null part */ + continue; /* Null part */ } if (keyseg->flag & (HA_VAR_LENGTH | HA_BLOB_PART | HA_SPACE_PACK)) { @@ -1012,10 +1224,10 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, if (from == from_end) { from=page; from_end=page_end; } if ((length= (*key++ = *from++)) == 255) { - if (from == from_end) { from=page; from_end=page_end; } - length= (uint) ((*key++ = *from++)) << 8; - if (from == from_end) { from=page; from_end=page_end; } - length+= (uint) ((*key++ = *from++)); + if (from == from_end) { from=page; from_end=page_end; } + length= (uint) ((*key++ = *from++)) << 8; + if (from == from_end) { from=page; from_end=page_end; } + length+= (uint) ((*key++ = *from++)); } } else @@ -1023,7 +1235,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, if ((tmp=(uint) (from_end-from)) <= length) { - key+=tmp; /* Use old key */ + key+=tmp; /* Use old key */ length-=tmp; from=page; from_end=page_end; } @@ -1034,7 +1246,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, length=keyseg->length+nod_flag; if ((tmp=(uint) (from_end-from)) <= length) { - memcpy(key+tmp,page,length-tmp); /* Get last part of key */ + memcpy(key+tmp,page,length-tmp); /* Get last part of key */ *page_pos= page+length-tmp; } else @@ -1043,7 +1255,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, { DBUG_PRINT("error",("Error when unpacking key")); my_errno=HA_ERR_CRASHED; - return 0; /* Error */ + return 0; /* Error */ } memcpy((byte*) key,(byte*) from,(size_t) length); *page_pos= from+length; @@ -1052,11 +1264,11 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, } - /* Get key at position without knowledge of previous key */ - /* Returns pointer to next key */ + /* Get key at position without knowledge of previous key */ + /* Returns pointer to next key */ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uchar *keypos, uint *return_key_length) + uchar *key, uchar *keypos, uint *return_key_length) { uint nod_flag; DBUG_ENTER("_mi_get_key"); @@ -1070,14 +1282,14 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, else { page+=2+nod_flag; - key[0]=0; /* safety */ + key[0]=0; /* safety */ while (page <= keypos) { *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key); if (*return_key_length == 0) { - my_errno=HA_ERR_CRASHED; - DBUG_RETURN(0); + my_errno=HA_ERR_CRASHED; + DBUG_RETURN(0); } } } @@ -1086,12 +1298,12 @@ uchar *_mi_get_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, } /* _mi_get_key */ - /* Get key at position without knowledge of previous key */ - /* Returns 0 if ok */ + /* Get key at position without knowledge of previous key */ + /* Returns 0 if ok */ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - uchar *key, uchar *keypos, - uint *return_key_length) + uchar *key, uchar *keypos, + uint *return_key_length) { uint nod_flag; DBUG_ENTER("_mi_get_prev_key"); @@ -1101,20 +1313,20 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, { *return_key_length=keyinfo->keylength; bmove((byte*) key,(byte*) keypos- *return_key_length-nod_flag, - *return_key_length); + *return_key_length); DBUG_RETURN(0); } else { page+=2+nod_flag; - key[0]=0; /* safety */ + key[0]=0; /* safety */ while (page < keypos) { *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,key); if (*return_key_length == 0) { - my_errno=HA_ERR_CRASHED; - DBUG_RETURN(1); + my_errno=HA_ERR_CRASHED; + DBUG_RETURN(1); } } } @@ -1123,11 +1335,11 @@ static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - /* Get last key from key-page */ - /* Return pointer to where key starts */ + /* Get last key from key-page */ + /* Return pointer to where key starts */ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, - uchar *lastkey, uchar *endpos, uint *return_key_length) + uchar *lastkey, uchar *endpos, uint *return_key_length) { uint nod_flag; uchar *lastpos; @@ -1152,9 +1364,9 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, *return_key_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page,lastkey); if (*return_key_length == 0) { - DBUG_PRINT("error",("Couldn't find last key: page: %lx",page)); - my_errno=HA_ERR_CRASHED; - DBUG_RETURN(0); + DBUG_PRINT("error",("Couldn't find last key: page: %lx",page)); + my_errno=HA_ERR_CRASHED; + DBUG_RETURN(0); } } } @@ -1163,7 +1375,7 @@ uchar *_mi_get_last_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, } /* _mi_get_last_key */ - /* Calculate length of key */ + /* Calculate length of key */ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key) { @@ -1178,7 +1390,7 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key) { if (keyseg->flag & HA_NULL_PART) if (!*key++) - continue; + continue; if (keyseg->flag & (HA_SPACE_PACK | HA_BLOB_PART | HA_VAR_LENGTH)) { uint length; @@ -1192,28 +1404,28 @@ uint _mi_keylength(MI_KEYDEF *keyinfo, register uchar *key) } /* _mi_keylength */ - /* Move a key */ + /* Move a key */ uchar *_mi_move_key(MI_KEYDEF *keyinfo, uchar *to, uchar *from) { reg1 uint length; memcpy((byte*) to, (byte*) from, - (size_t) (length=_mi_keylength(keyinfo,from))); + (size_t) (length=_mi_keylength(keyinfo,from))); return to+length; } - /* Find next/previous record with same key */ - /* This can't be used when database is touched after last read */ + /* Find next/previous record with same key */ + /* This can't be used when database is touched after last read */ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo, - uchar *key, uint key_length, uint nextflag, my_off_t pos) + uchar *key, uint key_length, uint nextflag, my_off_t pos) { int error; uint nod_flag; uchar lastkey[MI_MAX_KEY_BUFF]; DBUG_ENTER("_mi_search_next"); DBUG_PRINT("enter",("nextflag: %d lastpos: %ld int_keypos: %lx", - nextflag,(long) info->lastpos,info->int_keypos)); + nextflag,(long) info->lastpos,info->int_keypos)); DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE,keyinfo->seg,key,key_length);); /* Force full read if we are at last key or if we are not on a leaf @@ -1228,12 +1440,12 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo, (info->int_keytree_version != keyinfo->version && (info->int_nod_flag || info->buff_used))) DBUG_RETURN(_mi_search(info,keyinfo,key,key_length, - nextflag | SEARCH_SAVE_BUFF, pos)); + nextflag | SEARCH_SAVE_BUFF, pos)); if (info->buff_used) { if (!_mi_fetch_keypage(info,keyinfo,info->last_search_keypage, - info->buff,0)) + info->buff,0)) DBUG_RETURN(-1); info->buff_used=0; } @@ -1242,36 +1454,36 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo, nod_flag=mi_test_if_nod(info->buff); memcpy(lastkey,key,key_length); - if (nextflag & SEARCH_BIGGER) /* Next key */ + if (nextflag & SEARCH_BIGGER) /* Next key */ { my_off_t tmp_pos=_mi_kpos(nod_flag,info->int_keypos); if (tmp_pos != HA_OFFSET_ERROR) { if ((error=_mi_search(info,keyinfo,key,key_length, - nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0) - DBUG_RETURN(error); + nextflag | SEARCH_SAVE_BUFF, tmp_pos)) <=0) + DBUG_RETURN(error); } if (!(info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag, - &info->int_keypos,lastkey))) + &info->int_keypos,lastkey))) DBUG_RETURN(-1); } - else /* Previous key */ + else /* Previous key */ { uint length; /* Find start of previous key */ info->int_keypos=_mi_get_last_key(info,keyinfo,info->buff,lastkey, - info->int_keypos, &length); + info->int_keypos, &length); if (!info->int_keypos) DBUG_RETURN(-1); if (info->int_keypos == info->buff+2) DBUG_RETURN(_mi_search(info,keyinfo,key,key_length, - nextflag | SEARCH_SAVE_BUFF, pos)); + nextflag | SEARCH_SAVE_BUFF, pos)); if ((error=_mi_search(info,keyinfo,key,0,nextflag | SEARCH_SAVE_BUFF, - _mi_kpos(nod_flag,info->int_keypos))) <= 0) + _mi_kpos(nod_flag,info->int_keypos))) <= 0) DBUG_RETURN(error); if (! _mi_get_last_key(info,keyinfo,info->buff,lastkey, - info->int_keypos,&info->lastkey_length)) + info->int_keypos,&info->lastkey_length)) DBUG_RETURN(-1); } memcpy(info->lastkey,lastkey,info->lastkey_length); @@ -1281,11 +1493,11 @@ int _mi_search_next(register MI_INFO *info, register MI_KEYDEF *keyinfo, } /* _mi_search_next */ - /* Search after position for the first row in an index */ - /* This is stored in info->lastpos */ + /* Search after position for the first row in an index */ + /* This is stored in info->lastpos */ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo, - register my_off_t pos) + register my_off_t pos) { uint nod_flag; uchar *page; @@ -1310,7 +1522,7 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo, } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR); info->lastkey_length=(*keyinfo->get_key)(keyinfo,nod_flag,&page, - info->lastkey); + info->lastkey); info->int_keypos=page; info->int_maxpos=info->buff+mi_getint(info->buff)-1; info->int_nod_flag=nod_flag; info->int_keytree_version=keyinfo->version; @@ -1323,11 +1535,11 @@ int _mi_search_first(register MI_INFO *info, register MI_KEYDEF *keyinfo, } /* _mi_search_first */ - /* Search after position for the last row in an index */ - /* This is stored in info->lastpos */ + /* Search after position for the last row in an index */ + /* This is stored in info->lastpos */ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo, - register my_off_t pos) + register my_off_t pos) { uint nod_flag; uchar *buff,*page; @@ -1335,7 +1547,7 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo, if (pos == HA_OFFSET_ERROR) { - my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ + my_errno=HA_ERR_KEY_NOT_FOUND; /* Didn't find key */ info->lastpos= HA_OFFSET_ERROR; DBUG_RETURN(-1); } @@ -1353,7 +1565,7 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo, } while ((pos=_mi_kpos(nod_flag,page)) != HA_OFFSET_ERROR); if (!_mi_get_last_key(info,keyinfo,buff,info->lastkey,page, - &info->lastkey_length)) + &info->lastkey_length)) DBUG_RETURN(-1); info->lastpos=_mi_dpos(info,0,info->lastkey+info->lastkey_length); info->int_keypos=info->int_maxpos=page; @@ -1373,22 +1585,22 @@ int _mi_search_last(register MI_INFO *info, register MI_KEYDEF *keyinfo, ** Functions to store and pack a key in a page ** ** mi_calc_xx_key_length takes the following arguments: -** nod_flag If nod: Length of nod-pointer -** next_key Position to pos after the new key in buffer -** org_key Key that was before the next key in buffer -** prev_key Last key before current key -** key Key that will be stored -** s_temp Information how next key will be packed +** nod_flag If nod: Length of nod-pointer +** next_key Position to pos after the new key in buffer +** org_key Key that was before the next key in buffer +** prev_key Last key before current key +** key Key that will be stored +** s_temp Information how next key will be packed ****************************************************************************/ /* Static length key */ int _mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag, - uchar *next_pos __attribute__((unused)), - uchar *org_key __attribute__((unused)), - uchar *prev_key __attribute__((unused)), - uchar *key, MI_KEY_PARAM *s_temp) + uchar *next_pos __attribute__((unused)), + uchar *org_key __attribute__((unused)), + uchar *prev_key __attribute__((unused)), + uchar *key, MI_KEY_PARAM *s_temp) { s_temp->key=key; return (int) (s_temp->totlength=keyinfo->keylength+nod_flag); @@ -1398,10 +1610,10 @@ _mi_calc_static_key_length(MI_KEYDEF *keyinfo,uint nod_flag, int _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag, - uchar *next_pos __attribute__((unused)), - uchar *org_key __attribute__((unused)), - uchar *prev_key __attribute__((unused)), - uchar *key, MI_KEY_PARAM *s_temp) + uchar *next_pos __attribute__((unused)), + uchar *org_key __attribute__((unused)), + uchar *prev_key __attribute__((unused)), + uchar *key, MI_KEY_PARAM *s_temp) { s_temp->key=key; return (int) (s_temp->totlength=_mi_keylength(keyinfo,key)+nod_flag); @@ -1416,10 +1628,10 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag, If the max length of first key segment <= 127 characters the prefix is 1 byte else it's 2 byte - prefix byte The high bit is set if this is a prefix for the prev key - length Packed length if the previous was a prefix byte - [length] Length character of data - next-key-seg Next key segments + prefix byte The high bit is set if this is a prefix for the prev key + length Packed length if the previous was a prefix byte + [length] Length character of data + next-key-seg Next key segments If the first segment can have NULL: The length is 0 for NULLS and 1+length for not null columns. @@ -1428,8 +1640,8 @@ _mi_calc_var_key_length(MI_KEYDEF *keyinfo,uint nod_flag, int _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, - uchar *org_key, uchar *prev_key, uchar *key, - MI_KEY_PARAM *s_temp) + uchar *org_key, uchar *prev_key, uchar *key, + MI_KEY_PARAM *s_temp) { reg1 MI_KEYSEG *keyseg; int length; @@ -1470,15 +1682,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, s_temp->key=key; s_temp->ref_length=s_temp->key_length=0; s_temp->totlength=key_length-1+diff_flag; - s_temp->next_key_pos=0; /* No next key */ + s_temp->next_key_pos=0; /* No next key */ return (s_temp->totlength); } s_temp->store_not_null=1; - key_length--; /* We don't store NULL */ + key_length--; /* We don't store NULL */ if (prev_key && !*prev_key++) - org_key=prev_key=0; /* Can't pack against prev */ + org_key=prev_key=0; /* Can't pack against prev */ else if (org_key) - org_key++; /* Skipp NULL */ + org_key++; /* Skipp NULL */ } else s_temp->store_not_null=0; @@ -1494,14 +1706,14 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, if (prev_key) { get_key_length(org_key_length,prev_key); - s_temp->prev_key=prev_key; /* Pointer at data */ + s_temp->prev_key=prev_key; /* Pointer at data */ /* Don't use key-pack if length == 0 */ if (new_key_length && new_key_length == org_key_length) same_length=1; else if (new_key_length > org_key_length) end=key + org_key_length; - if (sort_order) /* SerG */ + if (sort_order) /* SerG */ { while (key < end && sort_order[*key] == sort_order[*prev_key]) { @@ -1512,7 +1724,7 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, { while (key < end && *key == *prev_key) { - key++; prev_key++; + key++; prev_key++; } } } @@ -1527,15 +1739,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, length=(int) key_length-(int) (key_end-start)-length_pack; length+= diff_flag; if (next_key) - { /* Can't combine with next */ - s_temp->n_length= *next_key; /* Needed by _mi_store_key */ + { /* Can't combine with next */ + s_temp->n_length= *next_key; /* Needed by _mi_store_key */ next_key=0; } } else { if (start != key) - { /* Starts as prev key */ + { /* Starts as prev key */ ref_length= (uint) (key-start); s_temp->ref_length= ref_length + pack_marker; length= (int) (key_length - ref_length); @@ -1546,16 +1758,16 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, } else { - s_temp->key_length+=s_temp->store_not_null; /* If null */ + s_temp->key_length+=s_temp->store_not_null; /* If null */ length= key_length - length_pack+ diff_flag; } } s_temp->totlength=(uint) length; s_temp->prev_length=0; DBUG_PRINT("test",("tot_length: %d length: %d uniq_key_length: %d", - key_length,length,s_temp->key_length)); + key_length,length,s_temp->key_length)); - /* If something after that hasn't length=0, test if we can combine */ + /* If something after that hasn't length=0, test if we can combine */ if ((s_temp->next_key_pos=next_key)) { uint packed,n_length; @@ -1571,134 +1783,134 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, if (!packed) n_length-= s_temp->store_not_null; - if (n_length || packed) /* Don't pack 0 length keys */ + if (n_length || packed) /* Don't pack 0 length keys */ { uint next_length_pack, new_ref_length=s_temp->ref_length; if (packed) { - /* If first key and next key is packed (only on delete) */ - if (!prev_key && org_key) - { - get_key_length(org_key_length,org_key); - key=start; - if (sort_order) /* SerG */ - { - while (key < end && sort_order[*key] == sort_order[*org_key]) - { - key++; org_key++; - } - } - else - { - while (key < end && *key == *org_key) - { - key++; org_key++; - } - } - if ((new_ref_length= (uint) (key - start))) - new_ref_length+=pack_marker; - } - - if (!n_length) - { - /* - We put a different key between two identical variable length keys - Extend next key to have same prefix as this key - */ - if (new_ref_length) /* prefix of previus key */ - { /* make next key longer */ - s_temp->part_of_prev_key= new_ref_length; - s_temp->prev_length= org_key_length - - (new_ref_length-pack_marker); - s_temp->n_ref_length= s_temp->n_length= s_temp->prev_length; - n_length= get_pack_length(s_temp->prev_length); - s_temp->prev_key+= (new_ref_length - pack_marker); - length+= s_temp->prev_length + n_length; - } - else - { /* Can't use prev key */ - s_temp->part_of_prev_key=0; - s_temp->prev_length= org_key_length; - s_temp->n_ref_length=s_temp->n_length= org_key_length; - length+= org_key_length; - /* +get_pack_length(org_key_length); */ - } - return (int) length; - } - - ref_length=n_length; - get_key_pack_length(n_length,next_length_pack,next_key); - - /* Test if new keys has fewer characters that match the previous key */ - if (!new_ref_length) - { /* Can't use prev key */ - s_temp->part_of_prev_key= 0; - s_temp->prev_length= ref_length; - s_temp->n_ref_length= s_temp->n_length= n_length+ref_length; - /* s_temp->prev_key+= get_pack_length(org_key_length); */ - return (int) length+ref_length-next_length_pack; - } - if (ref_length+pack_marker > new_ref_length) - { - uint new_pack_length=new_ref_length-pack_marker; - /* We must copy characters from the original key to the next key */ - s_temp->part_of_prev_key= new_ref_length; - s_temp->prev_length= ref_length - new_pack_length; - s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length; - s_temp->prev_key+= new_pack_length; -/* +get_pack_length(org_key_length); */ - length= length-get_pack_length(ref_length)+ - get_pack_length(new_pack_length); - return (int) length + s_temp->prev_length; - } + /* If first key and next key is packed (only on delete) */ + if (!prev_key && org_key) + { + get_key_length(org_key_length,org_key); + key=start; + if (sort_order) /* SerG */ + { + while (key < end && sort_order[*key] == sort_order[*org_key]) + { + key++; org_key++; + } + } + else + { + while (key < end && *key == *org_key) + { + key++; org_key++; + } + } + if ((new_ref_length= (uint) (key - start))) + new_ref_length+=pack_marker; + } + + if (!n_length) + { + /* + We put a different key between two identical variable length keys + Extend next key to have same prefix as this key + */ + if (new_ref_length) /* prefix of previus key */ + { /* make next key longer */ + s_temp->part_of_prev_key= new_ref_length; + s_temp->prev_length= org_key_length - + (new_ref_length-pack_marker); + s_temp->n_ref_length= s_temp->n_length= s_temp->prev_length; + n_length= get_pack_length(s_temp->prev_length); + s_temp->prev_key+= (new_ref_length - pack_marker); + length+= s_temp->prev_length + n_length; + } + else + { /* Can't use prev key */ + s_temp->part_of_prev_key=0; + s_temp->prev_length= org_key_length; + s_temp->n_ref_length=s_temp->n_length= org_key_length; + length+= org_key_length; + /* +get_pack_length(org_key_length); */ + } + return (int) length; + } + + ref_length=n_length; + get_key_pack_length(n_length,next_length_pack,next_key); + + /* Test if new keys has fewer characters that match the previous key */ + if (!new_ref_length) + { /* Can't use prev key */ + s_temp->part_of_prev_key= 0; + s_temp->prev_length= ref_length; + s_temp->n_ref_length= s_temp->n_length= n_length+ref_length; + /* s_temp->prev_key+= get_pack_length(org_key_length); */ + return (int) length+ref_length-next_length_pack; + } + if (ref_length+pack_marker > new_ref_length) + { + uint new_pack_length=new_ref_length-pack_marker; + /* We must copy characters from the original key to the next key */ + s_temp->part_of_prev_key= new_ref_length; + s_temp->prev_length= ref_length - new_pack_length; + s_temp->n_ref_length=s_temp->n_length=n_length + s_temp->prev_length; + s_temp->prev_key+= new_pack_length; +/* +get_pack_length(org_key_length); */ + length= length-get_pack_length(ref_length)+ + get_pack_length(new_pack_length); + return (int) length + s_temp->prev_length; + } } else { - /* Next key wasn't a prefix of previous key */ - ref_length=0; - next_length_pack=0; + /* Next key wasn't a prefix of previous key */ + ref_length=0; + next_length_pack=0; } DBUG_PRINT("test",("length: %d next_key: %lx",length,next_key)); { - uint tmp_length; - key=(start+=ref_length); - if (key+n_length < key_end) /* Normalize length based */ - key_end=key+n_length; - if (sort_order) /* SerG */ - { + uint tmp_length; + key=(start+=ref_length); + if (key+n_length < key_end) /* Normalize length based */ + key_end=key+n_length; + if (sort_order) /* SerG */ + { while (key < key_end && sort_order[*key] == - sort_order[*next_key]) - { - key++; next_key++; - } - } - else - { - while (key < key_end && *key == *next_key) - { - key++; next_key++; - } - } - if (!(tmp_length=(uint) (key-start))) - { /* Key can't be re-packed */ - s_temp->next_key_pos=0; - return length; - } - ref_length+=tmp_length; - n_length-=tmp_length; - length-=tmp_length+next_length_pack; /* We gained these chars */ + sort_order[*next_key]) + { + key++; next_key++; + } + } + else + { + while (key < key_end && *key == *next_key) + { + key++; next_key++; + } + } + if (!(tmp_length=(uint) (key-start))) + { /* Key can't be re-packed */ + s_temp->next_key_pos=0; + return length; + } + ref_length+=tmp_length; + n_length-=tmp_length; + length-=tmp_length+next_length_pack; /* We gained these chars */ } if (n_length == 0) { - s_temp->n_ref_length=pack_marker; /* Same as prev key */ + s_temp->n_ref_length=pack_marker; /* Same as prev key */ } else { - s_temp->n_ref_length=ref_length | pack_marker; - length+= get_pack_length(n_length); - s_temp->n_length=n_length; + s_temp->n_ref_length=ref_length | pack_marker; + length+= get_pack_length(n_length); + s_temp->n_length=n_length; } } } @@ -1710,15 +1922,15 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, int _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, - uchar *org_key, uchar *prev_key, uchar *key, - MI_KEY_PARAM *s_temp) + uchar *org_key, uchar *prev_key, uchar *key, + MI_KEY_PARAM *s_temp) { uint length,key_length,ref_length; s_temp->totlength=key_length=_mi_keylength(keyinfo,key)+nod_flag; s_temp->key=key; s_temp->prev_key=org_key; - if (prev_key) /* If not first key in block */ + if (prev_key) /* If not first key in block */ { /* pack key against previous key */ /* @@ -1737,7 +1949,7 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, s_temp->ref_length=ref_length=0; length=key_length+1; } - if ((s_temp->next_key_pos=next_key)) /* If another key after */ + if ((s_temp->next_key_pos=next_key)) /* If another key after */ { /* pack key against next key */ uint next_length,next_length_pack; @@ -1748,21 +1960,21 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, { uchar *end; for (key= s_temp->key, end=key+next_length ; - *key == *org_key && key < end; - key++,org_key++) ; + *key == *org_key && key < end; + key++,org_key++) ; ref_length= (uint) (key - s_temp->key); } if (next_length > ref_length) { /* We put a key with different case between two keys with the same prefix - Extend next key to have same prefix as - this key */ + Extend next key to have same prefix as + this key */ s_temp->n_ref_length= ref_length; s_temp->prev_length= next_length-ref_length; s_temp->prev_key+= ref_length; return (int) (length+ s_temp->prev_length - next_length_pack + - get_pack_length(ref_length)); + get_pack_length(ref_length)); } /* Check how many characters are identical to next key */ key= s_temp->key+next_length; @@ -1770,12 +1982,12 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, if ((ref_length= (uint) (key - s_temp->key)-1) == next_length) { s_temp->next_key_pos=0; - return length; /* can't pack next key */ + return length; /* can't pack next key */ } s_temp->prev_length=0; s_temp->n_ref_length=ref_length; return (int) (length-(ref_length - next_length) - next_length_pack + - get_pack_length(ref_length)); + get_pack_length(ref_length)); } return (int) length; } @@ -1788,8 +2000,8 @@ _mi_calc_bin_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, /* store key without compression */ void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)), - register uchar *key_pos, - register MI_KEY_PARAM *s_temp) + register uchar *key_pos, + register MI_KEY_PARAM *s_temp) { memcpy((byte*) key_pos,(byte*) s_temp->key,(size_t) s_temp->totlength); } @@ -1803,8 +2015,8 @@ void _mi_store_static_key(MI_KEYDEF *keyinfo __attribute__((unused)), void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), - register uchar *key_pos, - register MI_KEY_PARAM *s_temp) + register uchar *key_pos, + register MI_KEY_PARAM *s_temp) { uint length; uchar *start; @@ -1825,9 +2037,9 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->key_length); } bmove((byte*) key_pos,(byte*) s_temp->key, - (length=s_temp->totlength-(uint) (key_pos-start))); + (length=s_temp->totlength-(uint) (key_pos-start))); - if (!s_temp->next_key_pos) /* No following key */ + if (!s_temp->next_key_pos) /* No following key */ return; key_pos+=length; @@ -1837,14 +2049,14 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), if (s_temp->part_of_prev_key) { store_pack_length(s_temp->pack_marker == 128,key_pos, - s_temp->part_of_prev_key); + s_temp->part_of_prev_key); store_key_length_inc(key_pos,s_temp->n_length); } else { s_temp->n_length+= s_temp->store_not_null; store_pack_length(s_temp->pack_marker == 128,key_pos, - s_temp->n_length); + s_temp->n_length); } memcpy(key_pos, s_temp->prev_key, s_temp->prev_length); } @@ -1852,7 +2064,7 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), { store_pack_length(s_temp->pack_marker == 128,key_pos,s_temp->n_ref_length); if (s_temp->n_ref_length == s_temp->pack_marker) - return; /* Identical key */ + return; /* Identical key */ store_key_length(key_pos,s_temp->n_length); } else @@ -1866,18 +2078,18 @@ void _mi_store_var_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), /* variable length key with prefix compression */ void _mi_store_bin_pack_key(MI_KEYDEF *keyinfo __attribute__((unused)), - register uchar *key_pos, - register MI_KEY_PARAM *s_temp) + register uchar *key_pos, + register MI_KEY_PARAM *s_temp) { store_key_length_inc(key_pos,s_temp->ref_length); memcpy((char*) key_pos,(char*) s_temp->key+s_temp->ref_length, - (size_t) s_temp->totlength-s_temp->ref_length); + (size_t) s_temp->totlength-s_temp->ref_length); if (s_temp->next_key_pos) { key_pos+=(uint) (s_temp->totlength-s_temp->ref_length); store_key_length_inc(key_pos,s_temp->n_ref_length); - if (s_temp->prev_length) /* If we must extend key */ + if (s_temp->prev_length) /* If we must extend key */ { memcpy(key_pos,s_temp->prev_key,s_temp->prev_length); } diff --git a/myisam/mi_static.c b/myisam/mi_static.c index f790f90ca78..389aac3142a 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -32,7 +32,7 @@ my_string myisam_log_filename=(char*) "myisam.log"; File myisam_log_file= -1; uint myisam_quick_table_bits=9; uint myisam_block_size=MI_KEY_BLOCK_LENGTH; /* Best by test */ -my_bool myisam_flush=0,myisam_delay_key_write=0; +my_bool myisam_flush=0, myisam_delay_key_write=0, myisam_single_user=0; #if defined(THREAD) && !defined(DONT_USE_RW_LOCKS) my_bool myisam_concurrent_insert=1; #else @@ -40,7 +40,7 @@ my_bool myisam_concurrent_insert=0; #endif my_off_t myisam_max_extra_temp_length= MI_MAX_TEMP_LENGTH; my_off_t myisam_max_temp_length= MAX_FILE_SIZE; - +uint myisam_bulk_insert_tree_size=8192*1024; /* read_vec[] is used for converting between P_READ_KEY.. and SEARCH_ */ /* Position is , == , >= , <= , > , < */ diff --git a/myisam/mi_statrec.c b/myisam/mi_statrec.c index 05ff40d8921..e0fce6d3e1c 100644 --- a/myisam/mi_statrec.c +++ b/myisam/mi_statrec.c @@ -27,17 +27,16 @@ int _mi_write_static_record(MI_INFO *info, const byte *record) { my_off_t filepos=info->s->state.dellink; info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,info->s->state.dellink+1,MY_SEEK_SET,MYF(0))); - - if (my_read(info->dfile,(char*) &temp[0],info->s->base.rec_reflength, - MYF(MY_NABP))) + if (my_pread(info->dfile,(char*) &temp[0],info->s->base.rec_reflength, + info->s->state.dellink+1, + MYF(MY_NABP))) goto err; info->s->state.dellink= _mi_rec_pos(info->s,temp); info->state->del--; info->state->empty-=info->s->base.pack_reclength; - VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); - if (my_write(info->dfile, (char*) record, info->s->base.reclength, - MYF(MY_NABP))) + if (my_pwrite(info->dfile, (char*) record, info->s->base.reclength, + filepos, + MYF(MY_NABP))) goto err; } else @@ -64,16 +63,18 @@ int _mi_write_static_record(MI_INFO *info, const byte *record) else { info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,info->state->data_file_length, - MY_SEEK_SET,MYF(0))); - if (my_write(info->dfile,(char*) record,info->s->base.reclength, - info->s->write_flag)) + if (my_pwrite(info->dfile,(char*) record,info->s->base.reclength, + info->state->data_file_length, + info->s->write_flag)) goto err; if (info->s->base.pack_reclength != info->s->base.reclength) { uint length=info->s->base.pack_reclength - info->s->base.reclength; bzero((char*) temp,length); - if (my_write(info->dfile, (byte*) temp,length, info->s->write_flag)) + if (my_pwrite(info->dfile, (byte*) temp,length, + info->state->data_file_length+ + info->s->base.reclength, + info->s->write_flag)) goto err; } } @@ -88,9 +89,10 @@ int _mi_write_static_record(MI_INFO *info, const byte *record) int _mi_update_static_record(MI_INFO *info, my_off_t pos, const byte *record) { info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0))); - return (my_write(info->dfile,(char*) record,info->s->base.reclength, - MYF(MY_NABP)) != 0); + return (my_pwrite(info->dfile, + (char*) record,info->s->base.reclength, + pos, + MYF(MY_NABP)) != 0); } @@ -104,9 +106,8 @@ int _mi_delete_static_record(MI_INFO *info) _mi_dpointer(info,temp+1,info->s->state.dellink); info->s->state.dellink = info->lastpos; info->rec_cache.seek_not_done=1; - VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0))); - return (my_write(info->dfile,(byte*) temp, 1+info->s->rec_reflength, - MYF(MY_NABP)) != 0); + return (my_pwrite(info->dfile,(byte*) temp, 1+info->s->rec_reflength, + info->lastpos, MYF(MY_NABP)) != 0); } @@ -129,9 +130,9 @@ int _mi_cmp_static_record(register MI_INFO *info, register const byte *old) if ((info->opt_flag & READ_CHECK_USED)) { /* If check isn't disabled */ info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,info->lastpos,MY_SEEK_SET,MYF(0))); - if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength, - MYF(MY_NABP))) + if (my_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength, + info->lastpos, + MYF(MY_NABP))) DBUG_RETURN(-1); if (memcmp((byte*) info->rec_buff, (byte*) old, (uint) info->s->base.reclength)) @@ -152,9 +153,8 @@ int _mi_cmp_static_unique(MI_INFO *info, MI_UNIQUEDEF *def, DBUG_ENTER("_mi_cmp_static_unique"); info->rec_cache.seek_not_done=1; /* We have done a seek */ - VOID(my_seek(info->dfile,pos,MY_SEEK_SET,MYF(0))); - if (my_read(info->dfile, (char*) info->rec_buff, info->s->base.reclength, - MYF(MY_NABP))) + if (my_pread(info->dfile, (char*) info->rec_buff, info->s->base.reclength, + pos, MYF(MY_NABP))) DBUG_RETURN(-1); DBUG_RETURN(mi_unique_comp(def, record, info->rec_buff, def->null_are_equal)); diff --git a/myisam/mi_test_all.sh b/myisam/mi_test_all.sh index dfa2e1d0fdd..ccc9c39c64e 100755 --- a/myisam/mi_test_all.sh +++ b/myisam/mi_test_all.sh @@ -1,5 +1,10 @@ +#!/bin/sh +# +# Execute some simple basic test on MyISAM libary to check if things +# works at all. + silent="-s" -suffix=$MACH +if test -f mi_test1$MACH ; then suffix=$MACH else suffix=""; fi mi_test1$suffix $silent myisamchk$suffix -se test1 mi_test1$suffix $silent -N -S diff --git a/myisam/mi_update.c b/myisam/mi_update.c index 185624f3878..ac843dbb6bd 100644 --- a/myisam/mi_update.c +++ b/myisam/mi_update.c @@ -98,9 +98,7 @@ int mi_update(register MI_INFO *info, const byte *oldrec, byte *newrec) if ((int) i == info->lastinx) key_changed|=HA_STATE_WRITTEN; changed|=((ulonglong) 1 << i); - if (_mi_ft_del(info,i,(char*) old_key,oldrec,pos)) - goto err; - if (_mi_ft_add(info,i,(char*) new_key,newrec,pos)) + if (_mi_ft_update(info,i,(char*) old_key,oldrec,newrec,pos)) goto err; } } diff --git a/myisam/mi_write.c b/myisam/mi_write.c index f31e43e52ab..32b767b1433 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -96,27 +96,27 @@ int mi_write(MI_INFO *info, byte *record) { if (((ulonglong) 1 << i) & share->state.key_map) { - if (share->concurrent_insert) + if (share->concurrent_insert && ! info->bulk_insert) { rw_wrlock(&share->key_root_lock[i]); share->keyinfo[i].version++; } - if (share->keyinfo[i].flag & HA_FULLTEXT ) /* SerG */ - { /* SerG */ - if (_mi_ft_add(info,i,(char*) buff,record,filepos)) /* SerG */ - { /* SerG */ + if (share->keyinfo[i].flag & HA_FULLTEXT ) + { + if (_mi_ft_add(info,i,(char*) buff,record,filepos)) + { if (share->concurrent_insert) rw_unlock(&share->key_root_lock[i]); - DBUG_PRINT("error",("Got error: %d on write",my_errno)); /* SerG */ - goto err; /* SerG */ - } /* SerG */ - } /* SerG */ - else /* SerG */ + DBUG_PRINT("error",("Got error: %d on write",my_errno)); + goto err; + } + } + else { uint key_length=_mi_make_key(info,i,buff,record,filepos); if (_mi_ck_write(info,i,buff,key_length)) { - if (share->concurrent_insert) + if (share->concurrent_insert && ! info->bulk_insert) rw_unlock(&share->key_root_lock[i]); DBUG_PRINT("error",("Got error: %d on write",my_errno)); goto err; @@ -156,7 +156,6 @@ err: { if (share->concurrent_insert) rw_wrlock(&share->key_root_lock[i]); - /* The following code block is for text searching by SerG */ if (share->keyinfo[i].flag & HA_FULLTEXT) { if (_mi_ft_del(info,i,(char*) buff,record,filepos)) @@ -196,11 +195,29 @@ err2: /* Write one key to btree */ -int _mi_ck_write(register MI_INFO *info, uint keynr, uchar *key, +int _mi_ck_write(MI_INFO *info, uint keynr, uchar *key, uint key_length) +{ + DBUG_ENTER("_mi_ck_write"); + + if (info->bulk_insert && is_tree_inited(& info->bulk_insert[keynr])) + { + DBUG_RETURN(_mi_ck_write_tree(info, keynr, key, key_length)); + } + else + { + DBUG_RETURN(_mi_ck_write_btree(info, keynr, key, key_length)); + } +} /* _mi_ck_write */ + +/********************************************************************** + * Normal insert code * + **********************************************************************/ + +int _mi_ck_write_btree(register MI_INFO *info, uint keynr, uchar *key, uint key_length) { int error; - DBUG_ENTER("_mi_ck_write"); + DBUG_ENTER("_mi_ck_write_btree"); if (info->s->state.key_root[keynr] == HA_OFFSET_ERROR || (error=w_search(info,info->s->keyinfo+keynr,key, key_length, @@ -208,7 +225,7 @@ int _mi_ck_write(register MI_INFO *info, uint keynr, uchar *key, (my_off_t) 0, 1)) > 0) error=_mi_enlarge_root(info,keynr,key); DBUG_RETURN(error); -} /* _mi_ck_write */ +} /* _mi_ck_write_btree */ /* Make a new root with key as only pointer */ @@ -682,3 +699,113 @@ static int _mi_balance_page(register MI_INFO *info, MI_KEYDEF *keyinfo, err: DBUG_RETURN(-1); } /* _mi_balance_page */ + +/********************************************************************** + * Bulk insert code * + **********************************************************************/ + +typedef struct { + MI_INFO *info; + uint keynr; +} bulk_insert_param; + +int _mi_ck_write_tree(register MI_INFO *info, uint keynr, uchar *key, + uint key_length) +{ + int error; + DBUG_ENTER("_mi_ck_write_tree"); + + error= tree_insert(& info->bulk_insert[keynr], key, + key_length + info->s->rec_reflength) ? 0 : HA_ERR_OUT_OF_MEM ; + + DBUG_RETURN(error); +} /* _mi_ck_write_tree */ + +/* typeof(_mi_keys_compare)=qsort_cmp2 */ +static int keys_compare(bulk_insert_param *param, uchar *key1, uchar *key2) +{ + uint not_used; + return _mi_key_cmp(param->info->s->keyinfo[param->keynr].seg, + key1, key2, USE_WHOLE_KEY, SEARCH_SAME, ¬_used); +} + +static int keys_free(uchar *key, TREE_FREE mode, bulk_insert_param *param) +{ + /* probably I can use info->lastkey here, but I'm not sure, + and to be safe I'd better use local lastkey. + Monty, feel free to comment on this */ + uchar lastkey[MI_MAX_KEY_BUFF]; + uint keylen; + MI_KEYDEF *keyinfo; + + switch (mode) { + case free_init: + if (param->info->s->concurrent_insert) + { + rw_wrlock(¶m->info->s->key_root_lock[param->keynr]); + param->info->s->keyinfo[param->keynr].version++; + } + return 0; + case free_free: + keyinfo=param->info->s->keyinfo+param->keynr; + keylen=_mi_keylength(keyinfo, key); + memcpy(lastkey, key, keylen); + return _mi_ck_write_btree(param->info,param->keynr,lastkey, + keylen - param->info->s->rec_reflength); + case free_end: + if (param->info->s->concurrent_insert) + rw_unlock(¶m->info->s->key_root_lock[param->keynr]); + return 0; + } + return -1; +} + +int _mi_init_bulk_insert(MI_INFO *info) +{ + MYISAM_SHARE *share=info->s; + MI_KEYDEF *key=share->keyinfo; + bulk_insert_param *params; + uint i, num_keys; + ulonglong key_map=0; + + if (info->bulk_insert) + return 0; + + for (i=num_keys=0 ; i < share->base.keys ; i++) + { + if (!(key[i].flag & HA_NOSAME) && share->base.auto_key != i+1 + && test(share->state.key_map & ((ulonglong) 1 << i))) + { + num_keys++; + key_map |=((ulonglong) 1 << i); + } + } + + if (!num_keys) + return 0; + + info->bulk_insert=(TREE *) + my_malloc((sizeof(TREE)*share->base.keys+ + sizeof(bulk_insert_param)*num_keys),MYF(0)); + + if (!info->bulk_insert) + return HA_ERR_OUT_OF_MEM; + + params=(bulk_insert_param *)(info->bulk_insert+share->base.keys); + for (i=0 ; i < share->base.keys ; i++,key++) + { + params->info=info; + params->keynr=i; + if (test(key_map & ((ulonglong) 1 << i))) + { + init_tree(& info->bulk_insert[i], 0, + myisam_bulk_insert_tree_size / num_keys, 0, + (qsort_cmp2)keys_compare, 0, + (tree_element_free) keys_free, (void *)params++); + } + else + info->bulk_insert[i].root=0; + } + + return 0; +} diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index dd23e214ccf..5b1d4b0ed61 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -152,6 +152,12 @@ static CHANGEABLE_VAR changeable_vars[] = { { "sort_key_blocks",(long*) &check_param.sort_key_blocks,BUFFERS_WHEN_SORTING,4L,100L,0L, 1L }, { "decode_bits",(long*) &decode_bits,9L,4L,17L,0L,1L }, + { "ft_min_word_len", (long*) &ft_min_word_len, + 4, 1, HA_FT_MAXLEN, 0, 1 }, + { "ft_max_word_len", (long*) &ft_max_word_len, + HA_FT_MAXLEN, 10, HA_FT_MAXLEN, 0, 1 }, + { "ft_max_word_len_for_sort",(long*) &ft_max_word_len_for_sort, + 20, 4, HA_FT_MAXLEN, 0, 1 }, { NullS,(long*) 0,0L,0L,0L,0L,0L,} }; enum options {OPT_CHARSETS_DIR=256, OPT_SET_CHARSET,OPT_START_CHECK_POS}; @@ -177,7 +183,6 @@ static struct option long_options[] = {"information", no_argument, 0, 'i'}, {"keys-used", required_argument, 0, 'k'}, {"medium-check", no_argument, 0, 'm'}, - {"no-symlinks", no_argument, 0, 'l'}, {"quick", no_argument, 0, 'q'}, {"read-only", no_argument, 0, 'T'}, {"recover", no_argument, 0, 'r'}, @@ -253,8 +258,6 @@ static void usage(void) -k, --keys-used=# Tell MyISAM to update only some specific keys. # is a\n\ bit mask of which keys to use. This can be used to\n\ get faster inserts!\n\ - -l, --no-symlinks Do not follow symbolic links. Normally\n\ - myisamchk repairs the table a symlink points at.\n\ -r, --recover Can fix almost anything except unique keys that aren't\n\ unique.\n\ -n, --sort-recover Force recovering with sorting even if the temporary\n\ @@ -368,9 +371,6 @@ static void get_options(register int *argc,register char ***argv) case 'k': check_param.keys_in_use= (ulonglong) strtoll(optarg,NULL,10); break; - case 'l': - check_param.opt_follow_links=0; - break; case 'm': check_param.testflag|= T_MEDIUM; /* Medium check */ break; @@ -493,7 +493,6 @@ static int myisamchk(MI_CHECK *param, my_string filename) uint raid_chunks; MI_INFO *info; File datafile; - char fixed_name[FN_REFLEN]; char llbuff[22],llbuff2[22]; my_bool state_updated=0; MYISAM_SHARE *share; @@ -670,9 +669,6 @@ static int myisamchk(MI_CHECK *param, my_string filename) if (tmp != share->state.key_map) info->update|=HA_STATE_CHANGED; } - VOID(fn_format(fixed_name,filename,"",MI_NAME_IEXT, - 4+ (param->opt_follow_links ? 16 : 0))); - if (rep_quick && chk_del(&check_param, info, param->testflag & ~T_VERBOSE)) { @@ -697,11 +693,11 @@ static int myisamchk(MI_CHECK *param, my_string filename) info->s->state.key_map, check_param.force_sort)) { - error=mi_repair_by_sort(&check_param,info,fixed_name,rep_quick); + error=mi_repair_by_sort(&check_param,info,filename,rep_quick); state_updated=1; } else if (param->testflag & (T_REP | T_REP_BY_SORT)) - error=mi_repair(&check_param, info,fixed_name,rep_quick); + error=mi_repair(&check_param, info,filename,rep_quick); } if (!error && param->testflag & T_SORT_RECORDS) { @@ -713,7 +709,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) if (param->out_flag & O_NEW_DATA) { /* Change temp file to org file */ VOID(my_close(info->dfile,MYF(MY_WME))); /* Close new file */ - error|=change_to_newfile(fixed_name,MI_NAME_DEXT,DATA_TMP_EXT, + error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT, raid_chunks, MYF(0)); if (mi_open_datafile(info,info->s)) @@ -734,7 +730,7 @@ static int myisamchk(MI_CHECK *param, my_string filename) if (share->keyinfo[key].flag & HA_BINARY_PACK_KEY) update_index=0; - error=mi_sort_records(param,info,fixed_name,param->opt_sort_key, + error=mi_sort_records(param,info,filename,param->opt_sort_key, (my_bool) !(param->testflag & T_REP), update_index); datafile=info->dfile; /* This is now locked */ @@ -742,12 +738,12 @@ static int myisamchk(MI_CHECK *param, my_string filename) { if (check_param.verbose) puts("Table had a compressed index; We must now recreate the index"); - error=mi_repair_by_sort(&check_param,info,fixed_name,1); + error=mi_repair_by_sort(&check_param,info,filename,1); } } } if (!error && param->testflag & T_SORT_INDEX) - error=mi_sort_index(param,info,fixed_name); + error=mi_sort_index(param,info,filename); if (!error) share->state.changed&= ~(STATE_CHANGED | STATE_CRASHED | STATE_CRASHED_ON_REPAIR); @@ -844,12 +840,12 @@ end2: if (error == 0) { if (param->out_flag & O_NEW_DATA) - error|=change_to_newfile(fixed_name,MI_NAME_DEXT,DATA_TMP_EXT, + error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT, raid_chunks, ((param->testflag & T_BACKUP_DATA) ? MYF(MY_REDEL_MAKE_BACKUP) : MYF(0))); if (param->out_flag & O_NEW_INDEX) - error|=change_to_newfile(fixed_name,MI_NAME_IEXT,INDEX_TMP_EXT,0, + error|=change_to_newfile(filename,MI_NAME_IEXT,INDEX_TMP_EXT,0, MYF(0)); } VOID(fflush(stdout)); VOID(fflush(stderr)); @@ -1207,7 +1203,9 @@ static int mi_sort_records(MI_CHECK *param, mi_check_print_error(param,"Not enough memory for record"); goto err; } - new_file=my_raid_create(fn_format(param->temp_filename,name,"", + fn_format(param->temp_filename,name,"", MI_NAME_DEXT,2+4+32); + new_file=my_raid_create(fn_format(param->temp_filename, + param->temp_filename,"", DATA_TMP_EXT,2+4), 0,param->tmpfile_createflag, share->base.raid_type, diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 33fd1b6946f..865c47fb7ea 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -18,6 +18,7 @@ #include "myisam.h" /* Structs & some defines */ #include "myisampack.h" /* packing of keys */ +#include <my_tree.h> #ifdef THREAD #include <my_pthread.h> #include <thr_lock.h> @@ -37,7 +38,7 @@ typedef struct st_mi_status_info my_off_t key_empty; /* lost space in indexfile */ my_off_t key_file_length; my_off_t data_file_length; -} MI_STATUS_INFO; +} MI_STATUS_INFO; typedef struct st_mi_state_info { @@ -159,7 +160,9 @@ typedef struct st_mi_isam_share { /* Shared between opens */ MI_COLUMNDEF *rec; /* Pointer to field information */ MI_PACK pack; /* Data about packed records */ MI_BLOB *blobs; /* Pointer to blobs */ - char *filename; /* Name of indexfile */ + char *unique_file_name; /* realpath() of index file */ + char *data_file_name, /* Resolved path names from symlinks */ + *index_file_name; byte *file_map; /* mem-map of file if possible */ ulong this_process; /* processid */ ulong last_process; /* For table-change-check */ @@ -259,6 +262,7 @@ struct st_myisam_info { my_bool page_changed; /* If info->buff can't be used for rnext */ my_bool buff_used; /* If info->buff has to be reread for rnext */ my_bool use_packed_key; /* For MYISAMMRG */ + TREE *bulk_insert; /* accumulate indexfile changes between mi_write's */ myf lock_wait; /* is 0 or MY_DONT_WAIT */ int (*read_record)(struct st_myisam_info*, my_off_t, byte*); LIST open_list; @@ -285,7 +289,7 @@ struct st_myisam_info { #define STATE_CHANGED 1 #define STATE_CRASHED 2 -#define STATE_CRASHED_ON_REPAIR 4 +#define STATE_CRASHED_ON_REPAIR 4 #define STATE_NOT_ANALYZED 8 #define STATE_NOT_OPTIMIZED_KEYS 16 #define STATE_NOT_SORTED_PAGES 32 @@ -473,6 +477,9 @@ extern int _mi_bin_search(struct st_myisam_info *info,MI_KEYDEF *keyinfo, extern int _mi_seq_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page, uchar *key,uint key_len,uint comp_flag, uchar **ret_pos,uchar *buff, my_bool *was_last_key); +extern int _mi_prefix_search(MI_INFO *info,MI_KEYDEF *keyinfo,uchar *page, + uchar *key,uint key_len,uint comp_flag, + uchar **ret_pos,uchar *buff, my_bool *was_last_key); extern int _mi_compare_text(CHARSET_INFO *, uchar *, uint, uchar *, uint , my_bool); extern my_off_t _mi_kpos(uint nod_flag,uchar *after_key); @@ -528,6 +535,8 @@ extern int _mi_read_rnd_pack_record(MI_INFO*, byte *,my_off_t, my_bool); extern int _mi_pack_rec_unpack(MI_INFO *info,byte *to,byte *from, ulong reclength); extern ulonglong mi_safe_mul(ulonglong a,ulonglong b); +extern int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf, + const byte *oldrec, const byte *newrec, my_off_t pos); struct st_sort_info; @@ -636,10 +645,13 @@ my_bool check_table_is_closed(const char *name, const char *where); int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share); int mi_open_keyfile(MYISAM_SHARE *share); -/* Functions needed by mi_check */ +int _mi_init_bulk_insert(MI_INFO *info); + + /* Functions needed by mi_check */ void mi_check_print_error _VARARGS((MI_CHECK *param, const char *fmt,...)); void mi_check_print_warning _VARARGS((MI_CHECK *param, const char *fmt,...)); void mi_check_print_info _VARARGS((MI_CHECK *param, const char *fmt,...)); +int flush_pending_blocks(MI_CHECK *param); #ifdef __cplusplus } diff --git a/myisam/myisamlog.c b/myisam/myisamlog.c index ca2c4f27a74..78c3faa72ed 100644 --- a/myisam/myisamlog.c +++ b/myisam/myisamlog.c @@ -56,7 +56,7 @@ extern int main(int argc,char * *argv); static void get_options(int *argc,char ***argv); static int examine_log(my_string file_name,char **table_names); static int read_string(IO_CACHE *file,gptr *to,uint length); -static int file_info_compare(void *a,void *b); +static int file_info_compare(void *cmp_arg, void *a,void *b); static int test_if_open(struct file_info *key,element_count count, struct test_if_open_param *param); static void fix_blob_pointers(MI_INFO *isam,byte *record); @@ -331,8 +331,8 @@ static int examine_log(my_string file_name, char **table_names) init_io_cache(&cache,file,0,READ_CACHE,start_offset,0,MYF(0)); bzero((gptr) com_count,sizeof(com_count)); - init_tree(&tree,0,sizeof(file_info),(qsort_cmp) file_info_compare,1, - (void(*)(void*)) file_info_free); + init_tree(&tree,0,0,sizeof(file_info),(qsort_cmp2) file_info_compare,1, + (tree_element_free) file_info_free, NULL); VOID(init_key_cache(KEY_CACHE_SIZE,(uint) (10*4*(IO_SIZE+MALLOC_OVERHEAD)))); files_open=0; access_time=0; @@ -698,7 +698,8 @@ static int read_string(IO_CACHE *file, register gptr *to, register uint length) } /* read_string */ -static int file_info_compare(void *a, void *b) +static int file_info_compare(void* cmp_arg __attribute__((unused)), + void *a, void *b) { long lint; diff --git a/myisam/myisampack.c b/myisam/myisampack.c index 0e4b6eafbde..ee8ef0bb360 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -124,7 +124,8 @@ static void free_counts_and_tree_and_queue(HUFF_TREE *huff_trees, uint trees, HUFF_COUNTS *huff_counts, uint fields); -static int compare_tree(const uchar *s,const uchar *t); +static int compare_tree(void* cmp_arg __attribute__((unused)), + const uchar *s,const uchar *t); static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts); static void check_counts(HUFF_COUNTS *huff_counts,uint trees, my_off_t records); @@ -673,7 +674,7 @@ static HUFF_COUNTS *init_huff_count(MI_INFO *info,my_off_t records) (type == FIELD_NORMAL || type == FIELD_SKIPP_ZERO)) count[i].max_zero_fill= count[i].field_length; - init_tree(&count[i].int_tree,0,-1,(qsort_cmp) compare_tree,0,NULL); + init_tree(&count[i].int_tree,0,0,-1,(qsort_cmp2) compare_tree,0,NULL,NULL); if (records && type != FIELD_BLOB && type != FIELD_VARCHAR) count[i].tree_pos=count[i].tree_buff = my_malloc(count[i].field_length > 1 ? tree_buff_length : 2, @@ -893,7 +894,8 @@ static int get_statistic(MRG_INFO *mrg,HUFF_COUNTS *huff_counts) DBUG_RETURN(error != HA_ERR_END_OF_FILE); } -static int compare_huff_elements(void *not_used, byte *a, byte *b) +static int compare_huff_elements(void* cmp_arg __attribute__((unused)), + byte *a, byte *b) { return *((my_off_t*) a) < *((my_off_t*) b) ? -1 : (*((my_off_t*) a) == *((my_off_t*) b) ? 0 : 1); @@ -1289,7 +1291,8 @@ static int make_huff_tree(HUFF_TREE *huff_tree, HUFF_COUNTS *huff_counts) return 0; } -static int compare_tree(register const uchar *s, register const uchar *t) +static int compare_tree(void* cmp_arg __attribute__((unused)), + register const uchar *s, register const uchar *t) { uint length; for (length=global_count->field_length; length-- ;) diff --git a/myisam/sort.c b/myisam/sort.c index e6c7d61e39a..384c778ab54 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -1,15 +1,15 @@ /* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ @@ -19,7 +19,7 @@ them in sorted order through SORT_INFO functions. */ -#include "myisamdef.h" +#include "fulltext.h" #if defined(MSDOS) || defined(__WIN__) #include <fcntl.h> #else @@ -49,10 +49,12 @@ extern void print_error _VARARGS((const char *fmt,...)); static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info,uint keys, uchar **sort_keys, - BUFFPEK *buffpek,int *maxbuffer, - IO_CACHE *tempfile); + DYNAMIC_ARRAY *buffpek,int *maxbuffer, + IO_CACHE *tempfile, + IO_CACHE *tempfile_for_exceptions); static int NEAR_F write_keys(MI_SORT_PARAM *info,uchar * *sort_keys, uint count, BUFFPEK *buffpek,IO_CACHE *tempfile); +static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile); static int NEAR_F write_index(MI_SORT_PARAM *info,uchar * *sort_keys, uint count); static int NEAR_F merge_many_buff(MI_SORT_PARAM *info,uint keys, @@ -67,7 +69,6 @@ static int NEAR_F merge_buffers(MI_SORT_PARAM *info,uint keys, BUFFPEK *Fb, BUFFPEK *Tb); static int NEAR_F merge_index(MI_SORT_PARAM *,uint,uchar **,BUFFPEK *, int, IO_CACHE *); -static char **make_char_array(uint fields,uint length,myf my_flag); /* Creates a index of sorted keys */ /* Returns 0 if everything went ok */ @@ -77,15 +78,17 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, { int error,maxbuffer,skr; uint memavl,old_memavl,keys,sort_length; - BUFFPEK *buffpek; + DYNAMIC_ARRAY buffpek; ha_rows records; uchar **sort_keys; - IO_CACHE tempfile; + IO_CACHE tempfile, tempfile_for_exceptions; DBUG_ENTER("_create_index_by_sort"); DBUG_PRINT("enter",("sort_length: %d", info->key_length)); my_b_clear(&tempfile); - buffpek= (BUFFPEK *) NULL; sort_keys= (uchar **) NULL; error= 1; + my_b_clear(&tempfile_for_exceptions); + bzero((char*) &buffpek,sizeof(buffpek)); + sort_keys= (uchar **) NULL; error= 1; maxbuffer=1; memavl=max(sortbuff_size,MIN_SORT_MEMORY); @@ -113,14 +116,14 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, } while ((maxbuffer= (int) (records/(keys-1)+1)) != skr); - if ((sort_keys= (uchar **) make_char_array(keys,sort_length,MYF(0)))) + if ((sort_keys=(uchar **)my_malloc(keys*(sort_length+sizeof(char*))+ + HA_FT_MAXLEN, MYF(0)))) { - if ((buffpek = (BUFFPEK*) my_malloc((uint) (sizeof(BUFFPEK)* - (uint) maxbuffer), - MYF(0)))) - break; - else + if (init_dynamic_array(&buffpek, sizeof(BUFFPEK), maxbuffer, + maxbuffer/2)) my_free((gptr) sort_keys,MYF(0)); + else + break; } old_memavl=memavl; if ((memavl=memavl/4*3) < MIN_SORT_MEMORY && old_memavl > MIN_SORT_MEMORY) @@ -136,7 +139,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, if (!no_messages) printf(" - Searching for keys, allocating buffer for %d keys\n",keys); - if ((records=find_all_keys(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile)) + if ((records=find_all_keys(info,keys,sort_keys,&buffpek,&maxbuffer, + &tempfile,&tempfile_for_exceptions)) == HA_POS_ERROR) goto err; /* purecov: tested */ if (maxbuffer == 0) @@ -153,7 +157,8 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, { if (!no_messages) printf(" - Merging %lu keys\n",records); /* purecov: tested */ - if (merge_many_buff(info,keys,sort_keys,buffpek,&maxbuffer,&tempfile)) + if (merge_many_buff(info,keys,sort_keys, + dynamic_element(&buffpek,0,BUFFPEK *),&maxbuffer,&tempfile)) goto err; /* purecov: inspected */ } if (flush_io_cache(&tempfile) || @@ -161,17 +166,39 @@ int _create_index_by_sort(MI_SORT_PARAM *info,my_bool no_messages, goto err; /* purecov: inspected */ if (!no_messages) puts(" - Last merge and dumping keys"); /* purecov: tested */ - if (merge_index(info,keys,sort_keys,buffpek,maxbuffer,&tempfile)) + if (merge_index(info,keys,sort_keys,dynamic_element(&buffpek,0,BUFFPEK *), + maxbuffer,&tempfile)) goto err; /* purecov: inspected */ } + + if (flush_pending_blocks(info->sort_info->param)) + goto err; + + if (my_b_inited(&tempfile_for_exceptions)) + { + MI_INFO *index=info->sort_info->info; + uint keyno=info->sort_info->key; + uint key_length, ref_length=index->s->rec_reflength; + + if (flush_io_cache(&tempfile_for_exceptions) || + reinit_io_cache(&tempfile_for_exceptions,READ_CACHE,0L,0,0)) + goto err; + + while (!my_b_read(&tempfile_for_exceptions,(byte*)&key_length, sizeof(key_length)) + && !my_b_read(&tempfile_for_exceptions,(byte*)sort_keys,(uint)key_length)) + { + if (_mi_ck_write(index,keyno,(byte*)sort_keys,key_length-ref_length)) goto err; + } + } + error =0; err: if (sort_keys) my_free((gptr) sort_keys,MYF(0)); - if (buffpek) - my_free((gptr) buffpek,MYF(0)); + delete_dynamic(&buffpek); close_cached_file(&tempfile); + close_cached_file(&tempfile_for_exceptions); DBUG_RETURN(error ? -1 : 0); } /* _create_index_by_sort */ @@ -180,36 +207,50 @@ err: /* Search after all keys and place them in a temp. file */ static ha_rows NEAR_F find_all_keys(MI_SORT_PARAM *info, uint keys, - uchar **sort_keys, BUFFPEK *buffpek, - int *maxbuffer, IO_CACHE *tempfile) + uchar **sort_keys, DYNAMIC_ARRAY *buffpek, + int *maxbuffer, IO_CACHE *tempfile, + IO_CACHE *tempfile_for_exceptions) { int error; - uint idx,indexpos; + uint idx; DBUG_ENTER("find_all_keys"); - idx=indexpos=error=0; + idx=error=0; + sort_keys[0]=(char*)(sort_keys+keys); - while (!(error=(*info->key_read)(info->sort_info,sort_keys[idx]))) + while(!(error=(*info->key_read)(info->sort_info,sort_keys[idx]))) { - if ((uint) ++idx == keys) + if (info->sort_info->real_key_length > info->key_length) { - if (indexpos >= (uint) *maxbuffer || - write_keys(info,sort_keys,idx-1,buffpek+indexpos,tempfile)) - DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */ + if (write_key(info,sort_keys[idx],tempfile_for_exceptions)) + DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */ + continue; + } + + if (++idx == keys) + { + if (write_keys(info,sort_keys,idx-1,(BUFFPEK *)alloc_dynamic(buffpek),tempfile)) + DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */ + + sort_keys[0]=(char*)(sort_keys+keys); memcpy(sort_keys[0],sort_keys[idx-1],(size_t) info->key_length); - idx=1; indexpos++; + idx=1; } + sort_keys[idx]=sort_keys[idx-1]+info->key_length; } if (error > 0) DBUG_RETURN(HA_POS_ERROR); /* Aborted by get_key */ /* purecov: inspected */ - if (indexpos) - if (indexpos >= (uint) *maxbuffer || - write_keys(info,sort_keys,idx,buffpek+indexpos,tempfile)) + if (buffpek->elements) + { + if (write_keys(info,sort_keys,idx,(BUFFPEK *)alloc_dynamic(buffpek),tempfile)) DBUG_RETURN(HA_POS_ERROR); /* purecov: inspected */ - *maxbuffer=(int) indexpos; - DBUG_RETURN(indexpos*(keys-1)+idx); -} /* find_all_keys */ + *maxbuffer=buffpek->elements-1; + } + else + *maxbuffer=0; + DBUG_RETURN((*maxbuffer)*(keys-1)+idx); +} /* find_all_keys */ /* Write all keys in memory to file for later merge */ @@ -222,11 +263,12 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys, DBUG_ENTER("write_keys"); qsort2((byte*) sort_keys,count,sizeof(byte*),(qsort2_cmp) info->key_cmp, - info->sort_info); + info->sort_info); if (!my_b_inited(tempfile) && open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE, info->myf_rw)) DBUG_RETURN(1); /* purecov: inspected */ + buffpek->file_pos=my_b_tell(tempfile); buffpek->count=count; @@ -237,6 +279,22 @@ static int NEAR_F write_keys(MI_SORT_PARAM *info, register uchar **sort_keys, } /* write_keys */ +static int NEAR_F write_key(MI_SORT_PARAM *info, uchar *key, IO_CACHE *tempfile) +{ + uint key_length=info->sort_info->real_key_length; + DBUG_ENTER("write_key"); + + if (!my_b_inited(tempfile) && + open_cached_file(tempfile, info->tmpdir, "ST", DISK_BUFFER_SIZE, + info->myf_rw)) + DBUG_RETURN(1); + + if (my_b_write(tempfile,(byte*)&key_length,sizeof(key_length)) || + my_b_write(tempfile,(byte*)key,(uint) key_length)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} /* write_key */ + /* Write index */ static int NEAR_F write_index(MI_SORT_PARAM *info, register uchar **sort_keys, @@ -326,7 +384,7 @@ static uint NEAR_F read_to_buffer(IO_CACHE *fromfile, BUFFPEK *buffpek, /* If to_file == 0 then use info->key_write */ static int NEAR_F -merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file, +merge_buffers(MI_SORT_PARAM *info, uint keys, IO_CACHE *from_file, IO_CACHE *to_file, uchar **sort_keys, BUFFPEK *lastbuff, BUFFPEK *Fb, BUFFPEK *Tb) { @@ -472,21 +530,3 @@ merge_index(MI_SORT_PARAM *info, uint keys, uchar **sort_keys, DBUG_RETURN(0); } /* merge_index */ - - /* Make a pointer of arrays to keys */ - -static char **make_char_array(register uint fields, uint length, myf my_flag) -{ - register char **pos; - char **old_pos,*char_pos; - DBUG_ENTER("make_char_array"); - - if ((old_pos= (char**) my_malloc( fields*(length+sizeof(char*)), my_flag))) - { - pos=old_pos; char_pos=((char*) (pos+fields)) -length; - while (fields--) - *(pos++) = (char_pos+= length); - } - - DBUG_RETURN(old_pos); -} /* make_char_array */ |