diff options
Diffstat (limited to 'myisam')
-rw-r--r-- | myisam/Makefile.am | 6 | ||||
-rw-r--r-- | myisam/ft_boolean_search.c | 64 | ||||
-rw-r--r-- | myisam/ft_nlq_search.c | 12 | ||||
-rw-r--r-- | myisam/ft_parser.c | 62 | ||||
-rw-r--r-- | myisam/ft_static.c | 2 | ||||
-rw-r--r-- | myisam/ft_stopwords.c | 2 | ||||
-rw-r--r-- | myisam/ft_update.c | 4 | ||||
-rw-r--r-- | myisam/mi_check.c | 53 | ||||
-rw-r--r-- | myisam/mi_create.c | 8 | ||||
-rw-r--r-- | myisam/mi_dynrec.c | 144 | ||||
-rw-r--r-- | myisam/mi_extra.c | 31 | ||||
-rw-r--r-- | myisam/mi_locking.c | 15 | ||||
-rw-r--r-- | myisam/mi_rnext.c | 64 | ||||
-rw-r--r-- | myisam/mi_rprev.c | 23 | ||||
-rw-r--r-- | myisam/mi_search.c | 124 | ||||
-rw-r--r-- | myisam/mi_unique.c | 2 | ||||
-rw-r--r-- | myisam/mi_write.c | 6 | ||||
-rw-r--r-- | myisam/myisam_ftdump.c (renamed from myisam/ft_dump.c) | 32 | ||||
-rw-r--r-- | myisam/myisamchk.c | 4 | ||||
-rw-r--r-- | myisam/myisamdef.h | 6 | ||||
-rw-r--r-- | myisam/myisamlog.c | 39 |
21 files changed, 437 insertions, 266 deletions
diff --git a/myisam/Makefile.am b/myisam/Makefile.am index fdcfc6d0d41..5aa0740261e 100644 --- a/myisam/Makefile.am +++ b/myisam/Makefile.am @@ -21,18 +21,18 @@ INCLUDES = @MT_INCLUDES@ -I$(top_srcdir)/include LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a ../mysys/libmysys.a \ ../dbug/libdbug.a ../strings/libmystrings.a pkglib_LIBRARIES = libmyisam.a -bin_PROGRAMS = myisamchk myisamlog myisampack +bin_PROGRAMS = myisamchk myisamlog myisampack myisam_ftdump myisamchk_DEPENDENCIES= $(LIBRARIES) myisamlog_DEPENDENCIES= $(LIBRARIES) myisampack_DEPENDENCIES=$(LIBRARIES) -noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 rt_test sp_test ft_dump #ft_test1 ft_eval +noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 rt_test sp_test #ft_test1 ft_eval noinst_HEADERS = myisamdef.h rt_index.h rt_key.h rt_mbr.h sp_defs.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) +myisam_ftdump_DEPENDENCIES= $(LIBRARIES) rt_test_DEPENDENCIES= $(LIBRARIES) sp_test_DEPENDENCIES= $(LIBRARIES) libmyisam_a_SOURCES = mi_open.c mi_extra.c mi_info.c mi_rkey.c \ diff --git a/myisam/ft_boolean_search.c b/myisam/ft_boolean_search.c index 8cbb7a71a43..1d4bfee86a4 100644 --- a/myisam/ft_boolean_search.c +++ b/myisam/ft_boolean_search.c @@ -54,19 +54,20 @@ static double _nwghts[11]= static double *nwghts=_nwghts+5; /* nwghts[i] = -0.5*1.5**i */ #define FTB_FLAG_TRUNC 1 /* MUST be 1 */ -#define FTB_FLAG_YES 2 /* These two - YES and NO */ -#define FTB_FLAG_NO 4 /* should NEVER be set both */ +#define FTB_FLAG_YES 2 /* no two from these three */ +#define FTB_FLAG_NO 4 /* YES, NO, WONLY */ +#define FTB_FLAG_WONLY 8 /* should be ever set both */ typedef struct st_ftb_expr FTB_EXPR; struct st_ftb_expr { FTB_EXPR *up; - my_off_t docid[2]; + uint flags; /* ^^^^^^^^^^^^^^^^^^ FTB_{EXPR,WORD} common section */ + my_off_t docid[2]; float weight; float cur_weight; byte *quot, *qend; - uint flags; uint yesses; /* number of "yes" words matched */ uint nos; /* number of "no" words matched */ uint ythresh; /* number of "yes" words in expr */ @@ -76,13 +77,13 @@ struct st_ftb_expr typedef struct st_ftb_word { FTB_EXPR *up; - MI_KEYDEF *keyinfo; - my_off_t docid[2]; /* for index search and for scan */ + uint flags; /* ^^^^^^^^^^^^^^^^^^ FTB_{EXPR,WORD} common section */ + my_off_t docid[2]; /* for index search and for scan */ my_off_t key_root; + MI_KEYDEF *keyinfo; float weight; uint ndepth; - uint flags; uint len; uchar off; byte word[1]; @@ -123,7 +124,7 @@ static int FTB_WORD_cmp_list(CHARSET_INFO *cs, FTB_WORD **a, FTB_WORD **b) { /* ORDER BY word DESC, ndepth DESC */ int i= mi_compare_text(cs, (uchar*) (*b)->word+1,(*b)->len-1, - (uchar*) (*a)->word+1,(*a)->len-1,0); + (uchar*) (*a)->word+1,(*a)->len-1,0,0); if (!i) i=CMP_NUM((*b)->ndepth,(*a)->ndepth); return i; @@ -193,7 +194,7 @@ static void _ftb_parse_query(FTB *ftb, byte **start, byte *end, } static int _ftb_no_dupes_cmp(void* not_used __attribute__((unused)), - const void *a,const void *b) + const void *a,const void *b) { return CMP_NUM((*((my_off_t*)a)), (*((my_off_t*)b))); } @@ -227,7 +228,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) ftbw->len - (ftbw->flags & FTB_FLAG_TRUNC), (uchar*) ftbw->word + (ftbw->flags & FTB_FLAG_TRUNC), ftbw->len - (ftbw->flags & FTB_FLAG_TRUNC), - 0); + 0,0); } if (r) /* not found */ @@ -238,9 +239,9 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) if ((ftbw->flags & FTB_FLAG_YES) && ftbw->up->up==0) { /* - This word MUST BE present in every document returned, - so we can stop the search right now - */ + This word MUST BE present in every document returned, + so we can stop the search right now + */ ftb->state=INDEX_DONE; return 1; /* search is done */ } @@ -250,7 +251,7 @@ static int _ft2_search(FTB *ftb, FTB_WORD *ftbw, my_bool init_search) /* going up to the first-level tree to continue search there */ _mi_dpointer(info, (uchar*) (ftbw->word+ftbw->off+HA_FT_WLEN), - ftbw->key_root); + ftbw->key_root); ftbw->key_root=info->s->state.key_root[ftb->keynr]; ftbw->keyinfo=info->s->keyinfo+ftb->keynr; ftbw->off=0; @@ -297,7 +298,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) if (ftbw->flags & FTB_FLAG_TRUNC) { /* - special treatment for truncation operator + special treatment for truncation operator 1. there are some (besides this) +words | no need to search in the index, it can never ADD new rows | to the result, and to remove half-matched rows we do scan anyway @@ -348,7 +349,7 @@ static void _ftb_init_index_search(FT_INFO *ftb) FT_INFO * ft_init_boolean_search(MI_INFO *info, uint keynr, byte *query, - uint query_len) + uint query_len) { FTB *ftb; FTB_EXPR *ftbe; @@ -419,7 +420,7 @@ static int _ftb_strstr(const byte *s0, const byte *e0, while (p0 < e0) { while (p0 < e0 && cs->to_upper[(uint) (uchar) *p0++] != - cs->to_upper[(uint) (uchar) *s1]) + cs->to_upper[(uint) (uchar) *s1]) /* no-op */; if (p0 >= e0) return 0; @@ -429,7 +430,7 @@ static int _ftb_strstr(const byte *s0, const byte *e0, p1=s1+1; while (p0 < e0 && p1 < e1 && cs->to_upper[(uint) (uchar) *p0] == - cs->to_upper[(uint) (uchar) *p1]) + cs->to_upper[(uint) (uchar) *p1]) p0++, p1++; if (p1 == e1 && (!e_before || p0 == e0 || !true_word_char(cs, p0[0]))) return 1; @@ -487,12 +488,12 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_ if (yn & FTB_FLAG_NO) { /* - NOTE: special sort function of queue assures that all - (yn & FTB_FLAG_NO) != 0 - events for every particular subexpression will - "auto-magically" happen BEFORE all the - (yn & FTB_FLAG_YES) != 0 events. So no - already matched expression can become not-matched again. + NOTE: special sort function of queue assures that all + (yn & FTB_FLAG_NO) != 0 + events for every particular subexpression will + "auto-magically" happen BEFORE all the + (yn & FTB_FLAG_YES) != 0 events. So no + already matched expression can become not-matched again. */ ++ftbe->nos; break; @@ -500,11 +501,12 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_ else { if (ftbe->ythresh) - weight/=3; + weight/=3; ftbe->cur_weight += weight; if ((int) ftbe->yesses < ythresh) break; - yn= ((int) ftbe->yesses++ == ythresh) ? ftbe->flags : 0 ; + if (!(yn & FTB_FLAG_WONLY)) + yn= ((int) ftbe->yesses++ == ythresh) ? ftbe->flags : FTB_FLAG_WONLY ; weight*= ftbe->weight; } } @@ -535,8 +537,8 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) ftb->queue.first_cmp_arg=(void *)&curdoc; while (ftb->state == INDEX_SEARCH && - (curdoc=((FTB_WORD *)queue_top(& ftb->queue))->docid[0]) != - HA_POS_ERROR) + (curdoc=((FTB_WORD *)queue_top(& ftb->queue))->docid[0]) != + HA_POS_ERROR) { while (curdoc == (ftbw=(FTB_WORD *)queue_top(& ftb->queue))->docid[0]) { @@ -554,7 +556,7 @@ int ft_boolean_read_next(FT_INFO *ftb, char *record) /* curdoc matched ! */ if (is_tree_inited(&ftb->no_dupes) && tree_insert(&ftb->no_dupes, &curdoc, 0, - ftb->no_dupes.custom_arg)->count >1) + ftb->no_dupes.custom_arg)->count >1) /* but it managed already to get past this line once */ continue; @@ -631,7 +633,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) ftbw=ftb->list[c]; if (mi_compare_text(ftb->charset, (uchar*) word.pos, word.len, (uchar*) ftbw->word+1, ftbw->len-1, - (my_bool) (ftbw->flags&FTB_FLAG_TRUNC)) >0) + (my_bool) (ftbw->flags&FTB_FLAG_TRUNC),0) >0) b=c; else a=c; @@ -641,7 +643,7 @@ float ft_boolean_find_relevance(FT_INFO *ftb, byte *record, uint length) ftbw=ftb->list[c]; if (mi_compare_text(ftb->charset, (uchar*) word.pos, word.len, (uchar*) ftbw->word+1,ftbw->len-1, - (my_bool) (ftbw->flags&FTB_FLAG_TRUNC))) + (my_bool) (ftbw->flags&FTB_FLAG_TRUNC),0)) break; if (ftbw->docid[1] == docid) continue; diff --git a/myisam/ft_nlq_search.c b/myisam/ft_nlq_search.c index 1e3d47577d2..03875abe7b0 100644 --- a/myisam/ft_nlq_search.c +++ b/myisam/ft_nlq_search.c @@ -64,8 +64,8 @@ static int FT_SUPERDOC_cmp(void* cmp_arg __attribute__((unused)), static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) { - int subkeys; - uint keylen, r, doc_cnt; + int subkeys, r; + uint keylen, doc_cnt; FT_SUPERDOC sdoc, *sptr; TREE_ELEMENT *selem; double gweight=1; @@ -73,7 +73,7 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) uchar *keybuff=aio->keybuff; MI_KEYDEF *keyinfo=info->s->keyinfo+aio->keynr; my_off_t key_root=info->s->state.key_root[aio->keynr]; - uint extra=HA_FT_WLEN+info->s->base.rec_reflength+1; + uint extra=HA_FT_WLEN+info->s->base.rec_reflength; #if HA_FT_WTYPE == HA_KEYTYPE_FLOAT float tmp_weight; #else @@ -96,10 +96,10 @@ static int walk_and_match(FT_WORD *word, uint32 count, ALL_IN_ONE *aio) if (keylen && mi_compare_text(aio->charset,info->lastkey+1, - info->lastkey_length-extra, keybuff+1,keylen-1,0)) + info->lastkey_length-extra-1, keybuff+1,keylen-1,0,0)) break; - subkeys=ft_sintXkorr(info->lastkey+keylen); + subkeys=ft_sintXkorr(info->lastkey+info->lastkey_length-extra); if (subkeys<0) { if (doc_cnt) @@ -174,7 +174,7 @@ static int walk_and_push(FT_SUPERDOC *from, { DBUG_ENTER("walk_and_copy"); from->doc.weight+=from->tmp_weight*from->word_ptr->weight; - set_if_smaller(best->elements, ft_query_expansion_limit-1) + set_if_smaller(best->elements, ft_query_expansion_limit-1); queue_insert(best, (byte *)& from->doc); DBUG_RETURN(0); } diff --git a/myisam/ft_parser.c b/myisam/ft_parser.c index 0318bcbed10..b0fe180d0fb 100644 --- a/myisam/ft_parser.c +++ b/myisam/ft_parser.c @@ -27,7 +27,7 @@ typedef struct st_ft_docstat { static int FT_WORD_cmp(CHARSET_INFO* cs, FT_WORD *w1, FT_WORD *w2) { return mi_compare_text(cs, (uchar*) w1->pos, w1->len, - (uchar*) w2->pos, w2->len, 0); + (uchar*) w2->pos, w2->len, 0, 0); } static int walk_and_copy(FT_WORD *word,uint32 count,FT_DOCSTAT *docstat) @@ -73,6 +73,26 @@ FT_WORD * ft_linearize(TREE *wtree) DBUG_RETURN(wlist); } +my_bool ft_boolean_check_syntax_string(const byte *str) +{ + uint i, j; + + if (!str || + (strlen(str)+1 != sizeof(ft_boolean_syntax)) || + (str[0] != ' ' && str[1] != ' ')) + return 1; + for (i=0; i<sizeof(ft_boolean_syntax); i++) + { + /* limiting to 7-bit ascii only */ + if ((unsigned char)(str[i]) > 127 || my_isalnum(default_charset_info, str[i])) + return 1; + for (j=0; j<i; j++) + if (str[i] == str[j] && (i != 11 || j != 10)) + return 1; + } + return 0; +} + /* returns: * 0 - eof * 1 - word found @@ -93,27 +113,30 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, for (;doc<end;doc++) { if (true_word_char(cs,*doc)) break; - if (*doc == FTB_RQUOT && param->quot) { + if (*doc == FTB_RQUOT && param->quot) + { param->quot=doc; *start=doc+1; return 3; /* FTB_RBR */ } - if ((*doc == FTB_LBR || *doc == FTB_RBR || *doc == FTB_LQUOT) - && !param->quot) + if (!param->quot) { - /* param->prev=' '; */ - *start=doc+1; - if (*doc == FTB_LQUOT) param->quot=*start; - return (*doc == FTB_RBR)+2; - } - if (param->prev == ' ' && !param->quot) - { - if (*doc == FTB_YES ) { param->yesno=+1; continue; } else - if (*doc == FTB_EGAL) { param->yesno= 0; continue; } else - if (*doc == FTB_NO ) { param->yesno=-1; continue; } else - if (*doc == FTB_INC ) { param->plusminus++; continue; } else - if (*doc == FTB_DEC ) { param->plusminus--; continue; } else - if (*doc == FTB_NEG ) { param->pmsign=!param->pmsign; continue; } + if (*doc == FTB_LBR || *doc == FTB_RBR || *doc == FTB_LQUOT) + { + /* param->prev=' '; */ + *start=doc+1; + if (*doc == FTB_LQUOT) param->quot=*start; + return (*doc == FTB_RBR)+2; + } + if (param->prev == ' ') + { + if (*doc == FTB_YES ) { param->yesno=+1; continue; } else + if (*doc == FTB_EGAL) { param->yesno= 0; continue; } else + if (*doc == FTB_NO ) { param->yesno=-1; continue; } else + if (*doc == FTB_INC ) { param->plusminus++; continue; } else + if (*doc == FTB_DEC ) { param->plusminus--; continue; } else + if (*doc == FTB_NEG ) { param->pmsign=!param->pmsign; continue; } + } } param->prev=*doc; param->yesno=(FTB_YES==' ') ? 1 : (param->quot != 0); @@ -139,6 +162,11 @@ byte ft_get_word(CHARSET_INFO *cs, byte **start, byte *end, return 1; } } + if (param->quot) + { + param->quot=*start=doc; + return 3; /* FTB_RBR */ + } return 0; } diff --git a/myisam/ft_static.c b/myisam/ft_static.c index 0dcea5bec0c..7168406d027 100644 --- a/myisam/ft_static.c +++ b/myisam/ft_static.c @@ -21,7 +21,7 @@ ulong ft_min_word_len=4; ulong ft_max_word_len=HA_FT_MAXCHARLEN; ulong ft_query_expansion_limit=5; -const char *ft_boolean_syntax="+ -><()~*:\"\"&|"; +char ft_boolean_syntax[]="+ -><()~*:\"\"&|"; const HA_KEYSEG ft_keysegs[FT_SEGS]={ { diff --git a/myisam/ft_stopwords.c b/myisam/ft_stopwords.c index 6682de18c65..112af87d201 100644 --- a/myisam/ft_stopwords.c +++ b/myisam/ft_stopwords.c @@ -32,7 +32,7 @@ static int FT_STOPWORD_cmp(void* cmp_arg __attribute__((unused)), { return mi_compare_text(default_charset_info, (uchar *)w1->pos,w1->len, - (uchar *)w2->pos,w2->len,0); + (uchar *)w2->pos,w2->len,0,0); } static void FT_STOPWORD_free(FT_STOPWORD *w, TREE_FREE action, diff --git a/myisam/ft_update.c b/myisam/ft_update.c index 4015abbbeba..beccc062270 100644 --- a/myisam/ft_update.c +++ b/myisam/ft_update.c @@ -179,7 +179,7 @@ int _mi_ft_cmp(MI_INFO *info, uint keynr, const byte *rec1, const byte *rec2) if ((ftsi1.pos != ftsi2.pos) && (!ftsi1.pos || !ftsi2.pos || mi_compare_text(cs, (uchar*) ftsi1.pos,ftsi1.len, - (uchar*) ftsi2.pos,ftsi2.len,0))) + (uchar*) ftsi2.pos,ftsi2.len,0,0))) DBUG_RETURN(THOSE_TWO_DAMN_KEYS_ARE_REALLY_DIFFERENT); } DBUG_RETURN(GEE_THEY_ARE_ABSOLUTELY_IDENTICAL); @@ -207,7 +207,7 @@ int _mi_ft_update(MI_INFO *info, uint keynr, byte *keybuf, while(old_word->pos && new_word->pos) { cmp= mi_compare_text(cs, (uchar*) old_word->pos,old_word->len, - (uchar*) new_word->pos,new_word->len,0); + (uchar*) new_word->pos,new_word->len,0,0); cmp2= cmp ? 0 : (fabs(old_word->weight - new_word->weight) > 1.e-5); if (cmp < 0 || cmp2) diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 762eef15d68..2d89efa61f6 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -98,7 +98,9 @@ int chk_status(MI_CHECK *param, register MI_INFO *info) /* Don't count this as a real warning, as check can correct this ! */ uint save=param->warning_printed; mi_check_print_warning(param, - "%d clients is using or hasn't closed the table properly", + share->state.open_count==1 ? + "%d client is using or hasn't closed the table properly" : + "%d clients are using or haven't closed the table properly", share->state.open_count); /* If this will be fixed by the check, forget the warning */ if (param->testflag & T_UPDATE_STATE) @@ -409,7 +411,7 @@ int chk_key(MI_CHECK *param, register MI_INFO *info) if (chk_index(param,info,keyinfo,share->state.key_root[key],info->buff, &keys, param->key_crc+key,1)) DBUG_RETURN(-1); - if(!(keyinfo->flag & HA_FULLTEXT)) + if(!(keyinfo->flag & (HA_FULLTEXT | HA_SPATIAL))) { if (keys != info->state->records) { @@ -558,6 +560,10 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, DBUG_ENTER("chk_index"); DBUG_DUMP("buff",(byte*) buff,mi_getint(buff)); + /* TODO: implement appropriate check for RTree keys */ + if (keyinfo->flag & HA_SPATIAL) + DBUG_RETURN(0); + if (!(temp_buff=(uchar*) my_alloca((uint) keyinfo->block_length))) { mi_check_print_error(param,"Not enough memory for keyblock"); @@ -947,7 +953,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) info->checksum=mi_checksum(info,record); if (param->testflag & (T_EXTEND | T_MEDIUM | T_VERBOSE)) { - if (_mi_rec_check(info,record, info->rec_buff)) + if (_mi_rec_check(info,record, info->rec_buff,block_info.rec_len)) { mi_check_print_error(param,"Found wrong packed record at %s", llstr(start_recpos,llbuff)); @@ -1073,7 +1079,7 @@ int chk_data_link(MI_CHECK *param, MI_INFO *info,int extend) for (key=0 ; key < info->s->base.keys; key++) { if (key_checksum[key] != param->key_crc[key] && - !(info->s->keyinfo[key].flag & HA_FULLTEXT)) + !(info->s->keyinfo[key].flag & (HA_FULLTEXT | HA_SPATIAL))) { mi_check_print_error(param,"Checksum for key: %2d doesn't match checksum for records", key+1); @@ -1268,11 +1274,12 @@ int mi_repair(MI_CHECK *param, register MI_INFO *info, I think mi_repair and mi_repair_by_sort should do the same (according, e.g. to ha_myisam::repair), but as mi_repair doesn't touch key_map it cannot be used to T_CREATE_MISSING_KEYS. - That is what the next line is for... (serg) + That is what the next line is for */ - share->state.key_map= ((((ulonglong) 1L << share->base.keys)-1) & - param->keys_in_use); + if (param->testflag & T_CREATE_MISSING_KEYS) + share->state.key_map= ((((ulonglong) 1L << share->base.keys)-1) & + param->keys_in_use); info->state->key_file_length=share->base.keystart; @@ -2389,6 +2396,11 @@ int mi_repair_parallel(MI_CHECK *param, register MI_INFO *info, sort_param[i].record= (((char *)(sort_param+share->base.keys))+ (share->base.pack_reclength * i)); + if (!mi_alloc_rec_buff(info, -1, &sort_param[i].rec_buff)) + { + mi_check_print_error(param,"Not enough memory!"); + goto err; + } sort_param[i].key_length=share->rec_reflength; for (keyseg=sort_param[i].seg; keyseg->type != HA_KEYTYPE_END; @@ -2966,7 +2978,8 @@ static int sort_get_next_record(MI_SORT_PARAM *sort_param) info->checksum=mi_checksum(info,sort_param->record); if ((param->testflag & (T_EXTEND | T_REP)) || searching) { - if (_mi_rec_check(info, sort_param->record, sort_param->rec_buff)) + if (_mi_rec_check(info, sort_param->record, sort_param->rec_buff, + sort_param->find_length)) { mi_check_print_info(param,"Found wrong packed record at %s", llstr(sort_param->start_recpos,llbuff)); @@ -3301,7 +3314,7 @@ static int sort_ft_key_write(MI_SORT_PARAM *sort_param, const void *a) if (val_off == a_len && mi_compare_text(sort_param->seg->charset, ((uchar *)a)+1,a_len-1, - ft_buf->lastkey+1,val_off-1, 0)==0) + ft_buf->lastkey+1,val_off-1, 0, 0)==0) { if (!ft_buf->buf) /* store in second-level tree */ { @@ -3823,7 +3836,7 @@ int update_state_info(MI_CHECK *param, MI_INFO *info,uint update) return 0; } err: - mi_check_print_error(param,"%d when updateing keyfile",my_errno); + mi_check_print_error(param,"%d when updating keyfile",my_errno); return 1; } @@ -3953,18 +3966,18 @@ static my_bool mi_too_big_key_for_sort(MI_KEYDEF *key, ha_rows rows) void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows) { MYISAM_SHARE *share=info->s; - uint i; - if (!info->state->records) /* Don't do this if old rows */ + MI_KEYDEF *key=share->keyinfo; + uint i; + + DBUG_ASSERT(info->state->records == 0 && + (!rows || rows >= MI_MIN_ROWS_TO_DISABLE_INDEXES)); + for (i=0 ; i < share->base.keys ; i++,key++) { - MI_KEYDEF *key=share->keyinfo; - for (i=0 ; i < share->base.keys ; i++,key++) + if (!(key->flag & (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY)) && + ! mi_too_big_key_for_sort(key,rows) && info->s->base.auto_key != i+1) { - if (!(key->flag & (HA_NOSAME | HA_SPATIAL | HA_AUTO_KEY)) && - ! mi_too_big_key_for_sort(key,rows) && info->s->base.auto_key != i+1) - { - share->state.key_map&= ~ ((ulonglong) 1 << i); - info->update|= HA_STATE_CHANGED; - } + share->state.key_map&= ~ ((ulonglong) 1 << i); + info->update|= HA_STATE_CHANGED; } } } diff --git a/myisam/mi_create.c b/myisam/mi_create.c index 72633966b54..5682862c39a 100644 --- a/myisam/mi_create.c +++ b/myisam/mi_create.c @@ -383,7 +383,13 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, my_errno=HA_WRONG_CREATE_OPTION; goto err; } - if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME) + /* + key_segs may be 0 in the case when we only want to be able to + add on row into the table. This can happen with some DISTINCT queries + in MySQL + */ + if ((keydef->flag & (HA_NOSAME | HA_NULL_PART_KEY)) == HA_NOSAME && + key_segs) share.state.rec_per_key_part[key_segs-1]=1L; length+=key_length; keydef->block_length= MI_BLOCK_SIZE(length,pointer,MI_MAX_KEYPTR_SIZE); diff --git a/myisam/mi_dynrec.c b/myisam/mi_dynrec.c index 079779bd0ef..30a4762abe0 100644 --- a/myisam/mi_dynrec.c +++ b/myisam/mi_dynrec.c @@ -14,7 +14,15 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - /* Functions to handle space-packed-records and blobs */ +/* + Functions to handle space-packed-records and blobs + + A row may be stored in one or more linked blocks. + The block size is between MI_MIN_BLOCK_LENGTH and MI_MAX_BLOCK_LENGTH. + Each block is aligned on MI_DYN_ALIGN_SIZE. + The reson for the max block size is to not have too many different types + of blocks. For the differnet block types, look at _mi_get_block_info() +*/ #include "myisamdef.h" #include <assert.h> @@ -148,7 +156,7 @@ static int write_dynamic_record(MI_INFO *info, const byte *record, } while (reclength); DBUG_RETURN(0); - err: +err: DBUG_RETURN(1); } @@ -264,37 +272,62 @@ static bool unlink_deleted_block(MI_INFO *info, MI_BLOCK_INFO *block_info) DBUG_RETURN(0); } - /* Delete datarecord from database */ - /* info->rec_cache.seek_not_done is updated in cmp_record */ -static int delete_dynamic_record(MI_INFO *info, my_off_t filepos, - uint second_read) +/* + Add a backward link to delete block + + SYNOPSIS + update_backward_delete_link() + info MyISAM handler + delete_block Position to delete block to update. + If this is 'HA_OFFSET_ERROR', nothing will be done + filepos Position to block that 'delete_block' should point to + + RETURN + 0 ok + 1 error. In this case my_error is set. +*/ + +static int update_backward_delete_link(MI_INFO *info, my_off_t delete_block, + my_off_t filepos) { - uint length,b_type; - MI_BLOCK_INFO block_info,del_block; - int error=0; - my_bool remove_next_block; - DBUG_ENTER("delete_dynamic_record"); + MI_BLOCK_INFO block_info; + DBUG_ENTER("update_backward_delete_link"); - /* First add a link from the last block to the new one */ - if (info->s->state.dellink != HA_OFFSET_ERROR) + if (delete_block != HA_OFFSET_ERROR) { block_info.second_read=0; - if (_mi_get_block_info(&block_info,info->dfile,info->s->state.dellink) + if (_mi_get_block_info(&block_info,info->dfile,delete_block) & BLOCK_DELETED) { char buff[8]; mi_sizestore(buff,filepos); - if (my_pwrite(info->dfile,buff,8,info->s->state.dellink+12, - MYF(MY_NABP))) - error=1; /* Error on write */ + if (my_pwrite(info->dfile,buff, 8, delete_block+12, MYF(MY_NABP))) + DBUG_RETURN(1); /* Error on write */ } else { - error=1; /* Wrong delete link */ my_errno=HA_ERR_WRONG_IN_RECORD; + DBUG_RETURN(1); /* Wrong delete link */ } } + return 0; +} + + /* Delete datarecord from database */ + /* info->rec_cache.seek_not_done is updated in cmp_record */ + +static int delete_dynamic_record(MI_INFO *info, my_off_t filepos, + uint second_read) +{ + uint length,b_type; + MI_BLOCK_INFO block_info,del_block; + int error; + my_bool remove_next_block; + DBUG_ENTER("delete_dynamic_record"); + + /* First add a link from the last block to the new one */ + error= update_backward_delete_link(info, info->s->state.dellink, filepos); block_info.second_read=second_read; do @@ -518,21 +551,11 @@ int _mi_write_part_record(MI_INFO *info, *reclength-=(length-head_length); *flag=6; - if (del_length && next_delete_block != HA_OFFSET_ERROR) + if (del_length) { /* link the next delete block to this */ - MI_BLOCK_INFO del_block; - del_block.second_read=0; - if (!(_mi_get_block_info(&del_block,info->dfile,next_delete_block) - & BLOCK_DELETED)) - { - my_errno=HA_ERR_WRONG_IN_RECORD; - goto err; - } - mi_sizestore(del_block.header+12,info->s->state.dellink); - if (my_pwrite(info->dfile,(char*) del_block.header+12,8, - next_delete_block+12, - MYF(MY_NABP))) + if (update_backward_delete_link(info, next_delete_block, + info->s->state.dellink)) goto err; } @@ -574,6 +597,8 @@ static int update_dynamic_record(MI_INFO *info, my_off_t filepos, byte *record, { uint tmp=MY_ALIGN(reclength - length + 3 + test(reclength >= 65520L),MI_DYN_ALIGN_SIZE); + /* Don't create a block bigger than MI_MAX_BLOCK_LENGTH */ + tmp= min(length+tmp, MI_MAX_BLOCK_LENGTH)-length; /* Check if we can extend this block */ if (block_info.filepos + block_info.block_len == info->state->data_file_length && @@ -588,9 +613,15 @@ static int update_dynamic_record(MI_INFO *info, my_off_t filepos, byte *record, info->update|= HA_STATE_WRITE_AT_END | HA_STATE_EXTEND_BLOCK; length+=tmp; } - else + else if (length < MI_MAX_BLOCK_LENGTH - MI_MIN_BLOCK_LENGTH) { - /* Check if next block is a deleted block */ + /* + Check if next block is a deleted block + Above we have MI_MIN_BLOCK_LENGTH to avoid the problem where + the next block is so small it can't be splited which could + casue problems + */ + MI_BLOCK_INFO del_block; del_block.second_read=0; if (_mi_get_block_info(&del_block,info->dfile, @@ -601,7 +632,35 @@ static int update_dynamic_record(MI_INFO *info, my_off_t filepos, byte *record, DBUG_PRINT("info",("Extending current block")); if (unlink_deleted_block(info,&del_block)) goto err; - length+=del_block.block_len; + if ((length+=del_block.block_len) > MI_MAX_BLOCK_LENGTH) + { + /* + New block was too big, link overflow part back to + delete list + */ + my_off_t next_pos; + ulong rest_length= length-MI_MAX_BLOCK_LENGTH; + set_if_bigger(rest_length, MI_MIN_BLOCK_LENGTH); + next_pos= del_block.filepos+ del_block.block_len - rest_length; + + if (update_backward_delete_link(info, info->s->state.dellink, + next_pos)) + DBUG_RETURN(1); + + /* create delete link for data that didn't fit into the page */ + del_block.header[0]=0; + mi_int3store(del_block.header+1, rest_length); + mi_sizestore(del_block.header+4,info->s->state.dellink); + bfill(del_block.header+12,8,255); + if (my_pwrite(info->dfile,(byte*) del_block.header,20, next_pos, + MYF(MY_NABP))) + DBUG_RETURN(1); + info->s->state.dellink= next_pos; + info->s->state.split++; + info->state->del++; + info->state->empty+= rest_length; + length-= rest_length; + } } } } @@ -615,7 +674,10 @@ static int update_dynamic_record(MI_INFO *info, my_off_t filepos, byte *record, &record,&reclength,&flag)) goto err; if ((filepos=block_info.next_filepos) == HA_OFFSET_ERROR) + { + /* Start writing data on deleted blocks */ filepos=info->s->state.dellink; + } } if (block_info.next_filepos != HA_OFFSET_ERROR) @@ -744,7 +806,8 @@ uint _mi_rec_pack(MI_INFO *info, register byte *to, register const byte *from) Returns 0 if record is ok. */ -my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *rec_buff) +my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *rec_buff, + ulong packed_length) { uint length,new_length,flag,bit,i; char *pos,*end,*packpos,*to; @@ -836,8 +899,7 @@ my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *rec_buff) to+=length; } } - if (info->packed_length != (uint) (to - rec_buff) - + test(info->s->calc_checksum) || + if (packed_length != (uint) (to - rec_buff) + test(info->s->calc_checksum) || (bit != 1 && (flag & ~(bit - 1)))) goto err; if (info->s->calc_checksum) @@ -850,7 +912,7 @@ my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *rec_buff) } DBUG_RETURN(0); - err: +err: DBUG_RETURN(1); } @@ -966,8 +1028,8 @@ ulong _mi_rec_unpack(register MI_INFO *info, register byte *to, byte *from, if (info->s->calc_checksum) from++; if (to == to_end && from == from_end && (bit == 1 || !(flag & ~(bit-1)))) - DBUG_RETURN((info->packed_length=found_length)); - err: + DBUG_RETURN(found_length); +err: my_errno=HA_ERR_RECORD_DELETED; DBUG_PRINT("error",("to_end: %lx -> %lx from_end: %lx -> %lx", to,to_end,from,from_end)); @@ -1210,7 +1272,7 @@ int _mi_cmp_dynamic_record(register MI_INFO *info, register const byte *record) } } my_errno=0; - err: +err: if (buffer != info->rec_buff) my_afree((gptr) buffer); DBUG_RETURN(my_errno); diff --git a/myisam/mi_extra.c b/myisam/mi_extra.c index ce072d7d57e..4b011ca424f 100644 --- a/myisam/mi_extra.c +++ b/myisam/mi_extra.c @@ -19,6 +19,9 @@ #include <sys/mman.h> #endif +static void mi_extra_keyflag(MI_INFO *info, enum ha_extra_function function); + + /* Set options and buffers to optimize table handling @@ -355,6 +358,10 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) case HA_EXTRA_PRELOAD_BUFFER_SIZE: info->preload_buff_size= *((ulong *) extra_arg); break; + case HA_EXTRA_CHANGE_KEY_TO_UNIQUE: + case HA_EXTRA_CHANGE_KEY_TO_DUP: + mi_extra_keyflag(info, function); + break; case HA_EXTRA_KEY_CACHE: case HA_EXTRA_NO_KEY_CACHE: default: @@ -367,3 +374,27 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg) } DBUG_RETURN(error); } /* mi_extra */ + + +/* + Start/Stop Inserting Duplicates Into a Table, WL#1648. + */ +static void mi_extra_keyflag(MI_INFO *info, enum ha_extra_function function) +{ + uint idx; + + for (idx= 0; idx< info->s->base.keys; idx++) + { + switch (function) { + case HA_EXTRA_CHANGE_KEY_TO_UNIQUE: + info->s->keyinfo[idx].flag|= HA_NOSAME; + break; + case HA_EXTRA_CHANGE_KEY_TO_DUP: + info->s->keyinfo[idx].flag&= ~(HA_NOSAME); + break; + default: + break; + } + } +} + diff --git a/myisam/mi_locking.c b/myisam/mi_locking.c index 816748d459a..b13ebfb4cad 100644 --- a/myisam/mi_locking.c +++ b/myisam/mi_locking.c @@ -286,6 +286,21 @@ void mi_copy_status(void* to,void *from) ((MI_INFO*) to)->state= &((MI_INFO*) from)->save_state; } + +/* + Check if should allow concurrent inserts + + IMPLEMENTATION + Don't allow concurrent inserts if we have a hole in the table. + + NOTES + Rtree indexes are disabled in mi_open() + + RETURN + 0 ok to use concurrent inserts + 1 not ok +*/ + my_bool mi_check_status(void* param) { MI_INFO *info=(MI_INFO*) param; diff --git a/myisam/mi_rnext.c b/myisam/mi_rnext.c index e1cf916d6d9..6e6056f98d9 100644 --- a/myisam/mi_rnext.c +++ b/myisam/mi_rnext.c @@ -57,47 +57,45 @@ int mi_rnext(MI_INFO *info, byte *buf, int inx) } else { - switch(info->s->keyinfo[inx].key_alg) - { - case HA_KEY_ALG_RTREE: + switch (info->s->keyinfo[inx].key_alg) { + case HA_KEY_ALG_RTREE: /* - Note that rtree doesn't support that the table - may be changed since last call, so we do need - to skip rows inserted by other threads like in btree + Note that rtree doesn't support that the table + may be changed since last call, so we do need + to skip rows inserted by other threads like in btree */ - error=rtree_get_next(info,inx,info->lastkey_length); - break; + error= rtree_get_next(info,inx,info->lastkey_length); + break; - case HA_KEY_ALG_BTREE: - default: - if (!changed) - { - error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, - info->lastkey_length,flag, - info->s->state.key_root[inx]); - } - else - { - error=_mi_search(info,info->s->keyinfo+inx,info->lastkey, - USE_WHOLE_KEY,flag, info->s->state.key_root[inx]); - } - if (!error && info->s->concurrent_insert) - { - while (info->lastpos >= info->state->data_file_length) - { - /* Skip rows that are inserted by other threads since we got a lock */ - if ((error=_mi_search_next(info,info->s->keyinfo+inx,info->lastkey, - info->lastkey_length, - SEARCH_BIGGER, - info->s->state.key_root[inx]))) - break; - } - } + case HA_KEY_ALG_BTREE: + default: + if (!changed) + error= _mi_search_next(info,info->s->keyinfo+inx,info->lastkey, + info->lastkey_length,flag, + info->s->state.key_root[inx]); + else + error= _mi_search(info,info->s->keyinfo+inx,info->lastkey, + USE_WHOLE_KEY,flag, info->s->state.key_root[inx]); } } if (info->s->concurrent_insert) + { + if (!error) + { + while (info->lastpos >= info->state->data_file_length) + { + /* Skip rows inserted by other threads since we got a lock */ + if ((error=_mi_search_next(info,info->s->keyinfo+inx, + info->lastkey, + info->lastkey_length, + SEARCH_BIGGER, + info->s->state.key_root[inx]))) + break; + } + } rw_unlock(&info->s->key_root_lock[inx]); + } /* Don't clear if database-changed */ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); info->update|= HA_STATE_NEXT_FOUND; diff --git a/myisam/mi_rprev.c b/myisam/mi_rprev.c index 4807e636252..b787210e037 100644 --- a/myisam/mi_rprev.c +++ b/myisam/mi_rprev.c @@ -52,21 +52,22 @@ int mi_rprev(MI_INFO *info, byte *buf, int inx) error=_mi_search(info,share->keyinfo+inx,info->lastkey, USE_WHOLE_KEY, flag, share->state.key_root[inx]); - if (!error) + if (share->concurrent_insert) { - while (info->lastpos >= info->state->data_file_length) + if (!error) { - /* Skip rows that are inserted by other threads since we got a lock */ - if ((error=_mi_search_next(info,share->keyinfo+inx,info->lastkey, - info->lastkey_length, - SEARCH_SMALLER, - share->state.key_root[inx]))) - break; + while (info->lastpos >= info->state->data_file_length) + { + /* Skip rows that are inserted by other threads since we got a lock */ + if ((error=_mi_search_next(info,share->keyinfo+inx,info->lastkey, + info->lastkey_length, + SEARCH_SMALLER, + share->state.key_root[inx]))) + break; + } } - } - - if (share->concurrent_insert) rw_unlock(&share->key_root_lock[inx]); + } info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); info->update|= HA_STATE_PREV_FOUND; if (error) diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 2871633102d..1c4342ff39a 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -18,6 +18,7 @@ #include "fulltext.h" #include "m_ctype.h" +#include <assert.h> static my_bool _mi_get_prev_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, uchar *keypos, @@ -273,7 +274,8 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, 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; + uint saved_length=0, saved_prefix_len=0; + uint length_pack; DBUG_ENTER("_mi_prefix_search"); LINT_INIT(length); @@ -289,26 +291,24 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *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: + get_key_pack_length(kseg_len,length_pack,kseg); + key_len_skip=length_pack+kseg_len; + key_len_left=(int) key_len- (int) key_len_skip; + cmplen=(key_len_left>=0) ? kseg_len : key_len-length_pack; + DBUG_PRINT("info",("key: '%.*s'",kseg_len,kseg)); - If the max length of first key segment <= 127 characters the prefix is - 1 byte else it's 2 byte + /* + Keys are compressed the following way: - 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 -*/ + 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 */ @@ -350,7 +350,8 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, saved_vseg=vseg; saved_prefix_len=prefix_len; - DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack,suffix_len,vseg)); + DBUG_PRINT("loop",("page: '%.*s%.*s'",prefix_len,t_buff+seg_len_pack, + suffix_len,vseg)); { uchar *from=vseg+suffix_len; HA_KEYSEG *keyseg; @@ -396,14 +397,15 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, matched=prefix_len+left; - for(my_flag=0;left;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 */ - { /* + if (my_flag==0) /* match */ + { + /* ** len cmplen seg_left_len more_segs ** < matched=len; continue search ** > = prefix ? found : (matched=len; continue search) @@ -414,30 +416,68 @@ int _mi_prefix_search(MI_INFO *info, register MI_KEYDEF *keyinfo, uchar *page, */ if (len < cmplen) { - my_flag= -1; + if ((keyinfo->seg->type != HA_KEYTYPE_TEXT && + keyinfo->seg->type != HA_KEYTYPE_VARTEXT)) + my_flag= -1; + else + { + /* We have to compare k and vseg as if they where space extended */ + uchar *end= k+ (cmplen - len); + for ( ; k < end && *k == ' '; k++) ; + if (k == end) + goto cmp_rest; /* should never happen */ + if (*k < (uchar) ' ') + { + my_flag= 1; /* Compared string is smaller */ + break; + } + my_flag= -1; /* Continue searching */ + } } 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 = ha_key_cmp(keyinfo->seg+1,vseg, - k,key_len_left,nextflag,¬_used)) >= 0) - break; + uchar *end; + if ((nextflag & SEARCH_PREFIX) && key_len_left == 0) + goto fix_flag; + + /* We have to compare k and vseg as if they where space extended */ + for (end=vseg + (len-cmplen) ; + vseg < end && *vseg == (uchar) ' '; + vseg++) ; + if (vseg == end) + goto cmp_rest; /* should never happen */ + + if (*vseg > (uchar) ' ') + { + my_flag= 1; /* Compared string is smaller */ + break; + } + my_flag= -1; /* Continue searching */ } 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; - } + { + cmp_rest: + if (key_len_left>0) + { + uint not_used; + if ((flag = ha_key_cmp(keyinfo->seg+1,vseg, + k,key_len_left,nextflag,¬_used)) >= 0) + break; + } + else + { + /* + at this line flag==-1 if the following lines were already + visited and 0 otherwise, i.e. flag <=0 here always !!! + */ + fix_flag: + DBUG_ASSERT(flag <= 0); + if (nextflag & (SEARCH_NO_FIND | SEARCH_LAST)) + flag=(nextflag & (SEARCH_BIGGER | SEARCH_LAST)) ? -1 : 1; + if (flag>=0) + break; + } + } } matched-=left; } @@ -1567,7 +1607,7 @@ _mi_calc_var_pack_key_length(MI_KEYDEF *keyinfo,uint nod_flag,uchar *next_key, n_length-=tmp_length; length-=tmp_length+next_length_pack; /* We gained these chars */ } - if (n_length == 0) + if (n_length == 0 && ref_length == new_key_length) { s_temp->n_ref_length=pack_marker; /* Same as prev key */ } diff --git a/myisam/mi_unique.c b/myisam/mi_unique.c index f4ee39e55ca..38b4ed93311 100644 --- a/myisam/mi_unique.c +++ b/myisam/mi_unique.c @@ -180,7 +180,7 @@ int mi_unique_comp(MI_UNIQUEDEF *def, const byte *a, const byte *b, if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT) { if (mi_compare_text(keyseg->charset, (uchar *) pos_a, length, - (uchar *) pos_b, length, 0)) + (uchar *) pos_b, length, 0, 0)) return 1; } else diff --git a/myisam/mi_write.c b/myisam/mi_write.c index 88e7f070642..c17f47fc1ae 100644 --- a/myisam/mi_write.c +++ b/myisam/mi_write.c @@ -500,7 +500,7 @@ int _mi_insert(register MI_INFO *info, register MI_KEYDEF *keyinfo, get_key_length(alen,a); DBUG_ASSERT(info->ft1_to_ft2==0); if (alen == blen && - mi_compare_text(keyinfo->seg->charset, a, alen, b, blen, 0)==0) + mi_compare_text(keyinfo->seg->charset, a, alen, b, blen, 0, 0)==0) { /* yup. converting */ info->ft1_to_ft2=(DYNAMIC_ARRAY *) @@ -916,8 +916,8 @@ int mi_init_bulk_insert(MI_INFO *info, ulong cache_size, ha_rows rows) DBUG_ENTER("_mi_init_bulk_insert"); DBUG_PRINT("enter",("cache_size: %lu", cache_size)); - if (info->bulk_insert || (rows && rows < MI_MIN_ROWS_TO_USE_BULK_INSERT)) - DBUG_RETURN(0); + DBUG_ASSERT(!info->bulk_insert && + (!rows || rows >= MI_MIN_ROWS_TO_USE_BULK_INSERT)); for (i=total_keylength=num_keys=0 ; i < share->base.keys ; i++) { diff --git a/myisam/ft_dump.c b/myisam/myisam_ftdump.c index 47134af71d6..8ab6a7600b2 100644 --- a/myisam/ft_dump.c +++ b/myisam/myisam_ftdump.c @@ -20,9 +20,9 @@ #include "ftdefs.h" #include <my_getopt.h> -static void get_options(int *argc,char **argv[]); static void usage(); static void complain(int val); +static my_bool get_one_option(int, const struct my_option *, char *); static int count=0, stats=0, dump=0, lstats=0; static my_bool verbose; @@ -68,7 +68,8 @@ int main(int argc,char *argv[]) struct { MI_INFO *info; } aio0, *aio=&aio0; /* for GWS_IN_USE */ MY_INIT(argv[0]); - get_options(&argc, &argv); + if ((error=handle_options(&argc, &argv, my_long_options, get_one_option))) + exit(error); if (count || dump) verbose=0; if (!count && !dump && !lstats && !query) @@ -80,12 +81,21 @@ int main(int argc,char *argv[]) if (argc < 2) usage(); + { + char *end; + inx= strtoll(argv[1], &end, 10); + if (*end) + usage(); + } + init_key_cache(dflt_key_cache,MI_KEY_BLOCK_LENGTH,USE_BUFFER_INIT, 0, 0); if (!(info=mi_open(argv[0],2,HA_OPEN_ABORT_IF_LOCKED))) + { + error=my_errno; goto err; + } - inx=atoi(argv[1]); *buf2=0; aio->info=info; @@ -96,6 +106,8 @@ int main(int argc,char *argv[]) goto err; } + mi_lock_database(info, F_EXTRA_LCK); + if (query) { #if 0 @@ -112,7 +124,7 @@ int main(int argc,char *argv[]) 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); + printf("%9lx %20.7f\n",(ulong)result->doc[i].dpos,result->doc[i].weight); ft_nlq_close_search(result); #else @@ -179,6 +191,7 @@ int main(int argc,char *argv[]) if (verbose && (total%HOW_OFTEN_TO_WRITE)==0) printf("%10ld\r",total); } + mi_lock_database(info, F_UNLCK); if (stats) { @@ -252,18 +265,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } -static void get_options(int *argc, char **argv[]) -{ - int ho_error; - - if ((ho_error=handle_options(argc, argv, my_long_options, get_one_option))) - exit(ho_error); -} /* get options */ - - static void usage() { - printf("Use: ft_dump <table_name> <index_no>\n"); + printf("Use: myisam_ftdump <table_name> <index_num>\n"); my_print_help(my_long_options); my_print_variables(my_long_options); exit(1); diff --git a/myisam/myisamchk.c b/myisam/myisamchk.c index 3e50e786089..a96632b4f3c 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -170,7 +170,7 @@ static struct my_option my_long_options[] = 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"character-sets-dir", OPT_CHARSETS_DIR, "Directory where character sets are.", - (gptr*) &set_charset_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &charsets_dir, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"check", 'c', "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -253,7 +253,7 @@ static struct my_option my_long_options[] = 0, GET_ULL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"set-character-set", OPT_SET_CHARSET, "Change the character set used by the index", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + (gptr*) &set_charset_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"set-variable", 'O', "Change the value of a variable. Please note that this option is deprecated; you can set variables directly with --variable-name=value.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 3788eeca1e3..987a9dfc39e 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -249,6 +249,8 @@ struct st_myisam_info { my_off_t last_search_keypage; /* Last keypage when searching */ my_off_t dupp_key_pos; ha_checksum checksum; + /* QQ: the folloing two xxx_length fields should be removed, + as they are not compatible with parallel repair */ ulong packed_length,blob_length; /* Length of found, packed record */ int dfile; /* The datafile */ uint opt_flag; /* Optim. for space/speed */ @@ -414,6 +416,7 @@ typedef struct st_mi_sort_param #define MI_MIN_SIZE_BULK_INSERT_TREE 16384 /* this is per key */ #define MI_MIN_ROWS_TO_USE_BULK_INSERT 100 +#define MI_MIN_ROWS_TO_DISABLE_INDEXES 100 /* The UNIQUE check is done with a hashed long key */ @@ -577,7 +580,8 @@ extern byte *mi_alloc_rec_buff(MI_INFO *,ulong, byte**); extern ulong _mi_rec_unpack(MI_INFO *info,byte *to,byte *from, ulong reclength); -extern my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *packpos); +extern my_bool _mi_rec_check(MI_INFO *info,const char *record, byte *packpos, + ulong reclength); extern int _mi_write_part_record(MI_INFO *info,my_off_t filepos,ulong length, my_off_t next_filepos,byte **record, ulong *reclength,int *flag); diff --git a/myisam/myisamlog.c b/myisam/myisamlog.c index c9b00be7d9e..82f6277ce25 100644 --- a/myisam/myisamlog.c +++ b/myisam/myisamlog.c @@ -60,7 +60,6 @@ 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); -static uint set_maximum_open_files(uint); static int test_when_accessed(struct file_info *key,element_count count, struct st_access_param *access_param); static void file_info_free(struct file_info *info); @@ -89,9 +88,8 @@ int main(int argc, char **argv) log_filename=myisam_log_filename; get_options(&argc,&argv); - /* Nr of isam-files */ - max_files=(set_maximum_open_files(min(max_files,8))-6)/2; - + /* Number of MyISAM files we can have open at one time */ + max_files= (my_set_max_open_files(min(max_files,8))-6)/2; if (update) printf("Trying to %s MyISAM files according to log '%s'\n", (recover ? "recover" : "update"),log_filename); @@ -123,6 +121,7 @@ int main(int argc, char **argv) printf("Had to do %d re-open because of too few possibly open files\n", re_open_count); VOID(mi_panic(HA_PANIC_CLOSE)); + my_free_open_file_info(); my_end(test_info ? MY_CHECK_ERROR | MY_GIVE_INFO : MY_CHECK_ERROR); exit(error); return 0; /* No compiler warning */ @@ -732,38 +731,6 @@ static void fix_blob_pointers(MI_INFO *info, byte *record) } } -static uint set_maximum_open_files(uint maximum_files) -{ -#if defined(HAVE_GETRUSAGE) && defined(RLIMIT_NOFILE) - struct rlimit rlimit; - int old_max; - - if (maximum_files > MY_NFILE) - maximum_files=MY_NFILE; /* Don't crash my_open */ - - if (!getrlimit(RLIMIT_NOFILE,&rlimit)) - { - old_max=rlimit.rlim_max; - if (maximum_files && (int) maximum_files > old_max) - rlimit.rlim_max=maximum_files; - rlimit.rlim_cur=rlimit.rlim_max; - if (setrlimit(RLIMIT_NOFILE,&rlimit)) - { - if (old_max != (int) maximum_files) - { /* Set as much as we can */ - rlimit.rlim_max=rlimit.rlim_cur=old_max; - setrlimit(RLIMIT_NOFILE,&rlimit); - } - } - getrlimit(RLIMIT_NOFILE,&rlimit); /* Read if broken setrlimit */ - if (maximum_files && maximum_files < rlimit.rlim_cur) - VOID(fprintf(stderr,"Warning: Error from setrlimit: Max open files is %d\n",old_max)); - return rlimit.rlim_cur; - } -#endif - return min(maximum_files,MY_NFILE); -} - /* close the file with hasn't been accessed for the longest time */ /* ARGSUSED */ |