summaryrefslogtreecommitdiff
path: root/myisam
diff options
context:
space:
mode:
Diffstat (limited to 'myisam')
-rw-r--r--myisam/Makefile.am13
-rw-r--r--myisam/ft_boolean_search.c224
-rw-r--r--myisam/ft_dump.c214
-rw-r--r--myisam/ft_nlq_search.c192
-rw-r--r--myisam/ft_parser.c140
-rw-r--r--myisam/ft_search.c173
-rw-r--r--myisam/ft_static.c4
-rw-r--r--myisam/ft_stopwords.c9
-rw-r--r--myisam/ft_update.c71
-rw-r--r--myisam/ftdefs.h47
-rw-r--r--myisam/fulltext.h1
-rw-r--r--myisam/mi_check.c154
-rw-r--r--myisam/mi_create.c80
-rw-r--r--myisam/mi_dbug.c2
-rw-r--r--myisam/mi_delete_table.c4
-rw-r--r--myisam/mi_extra.c32
-rw-r--r--myisam/mi_info.c2
-rw-r--r--myisam/mi_locking.c13
-rw-r--r--myisam/mi_open.c59
-rw-r--r--myisam/mi_rename.c4
-rw-r--r--myisam/mi_search.c1146
-rw-r--r--myisam/mi_static.c4
-rw-r--r--myisam/mi_statrec.c48
-rwxr-xr-xmyisam/mi_test_all.sh7
-rw-r--r--myisam/mi_update.c4
-rw-r--r--myisam/mi_write.c157
-rw-r--r--myisam/myisamchk.c36
-rw-r--r--myisam/myisamdef.h26
-rw-r--r--myisam/myisamlog.c9
-rw-r--r--myisam/myisampack.c11
-rw-r--r--myisam/sort.c154
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,&param)); 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(&param->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(&param->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,
- &not_used))
+ _mi_key_cmp(keyinfo->seg, info->lastkey, key, key_len, SEARCH_FIND,
+ &not_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,&not_used))
- >= 0)
+ comp_flag,&not_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,&not_used);
+ comp_flag,&not_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,
- &not_used)) >= 0)
+ &not_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,&not_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, &not_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(&param->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(&param->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 */